summaryrefslogtreecommitdiffstats
path: root/testing
diff options
context:
space:
mode:
authorTimo Teras <timo.teras@iki.fi>2009-06-23 18:48:38 +0300
committerTimo Teras <timo.teras@iki.fi>2009-06-23 19:15:40 +0300
commit5a675d6f07425df85a4b0213def3586038b219b3 (patch)
treee8914a4434291f4914c168b0e051f939de8dcce9 /testing
parent30a0a20ab902639b2da7215a524a29fc918c70b9 (diff)
downloadaports-5a675d6f07425df85a4b0213def3586038b219b3.tar.bz2
aports-5a675d6f07425df85a4b0213def3586038b219b3.tar.xz
testing/asterisk: update to 1.6.3.0_pre20090623
This is svn trunk revision 202568 against 1.6.2.0-beta3 dist tarball. APKBUILD updated according to latest extra/asterisk.
Diffstat (limited to 'testing')
-rw-r--r--testing/asterisk/APKBUILD35
-rw-r--r--testing/asterisk/asterisk-02-uclibc-daemon.patch (renamed from testing/asterisk/200-uclibc-daemon.patch)0
-rw-r--r--testing/asterisk/asterisk-03-1.6.2.0-beta1-to-r186562.patch41697
-rw-r--r--testing/asterisk/asterisk-03-1.6.2.0-beta3-to-svn-r202568.patch102239
-rw-r--r--testing/asterisk/asterisk-07-issue14068.patch753
5 files changed, 102257 insertions, 42467 deletions
diff --git a/testing/asterisk/APKBUILD b/testing/asterisk/APKBUILD
index ced7f211..05837d4a 100644
--- a/testing/asterisk/APKBUILD
+++ b/testing/asterisk/APKBUILD
@@ -1,34 +1,34 @@
# Contributor: Timo Teras <timo.teras@iki.fi>
# Maintainer: Timo Teras <timo.teras@iki.fi>
pkgname=asterisk
-pkgver=1.6.2.0_beta1
-_myver=1.6.2.0-beta1
-pkgrel=4
+pkgver=1.6.3.0_pre20090623
+_basever=1.6.2.0-beta3
+pkgrel=0
pkgdesc="Asterisk: A Module Open Source PBX System"
url="http://www.asterisk.org/"
license="GPL"
-depends="ncurses popt zlib newt dahdi-linux dahdi-tools libltdl libpri freetds"
+depends="dahdi-linux"
makedepends="autoconf automake libtool ncurses-dev popt-dev newt-dev zlib-dev
- postgresql-dev unixodbc-dev dahdi-tools-dev libpri-dev g++ tar
- freetds-dev"
+ postgresql-dev unixodbc-dev dahdi-tools-dev libpri-dev tar
+ freetds-dev openssl-dev"
install="$pkgname.pre-install $pkgname.post-install"
subpackages="$pkgname-dev $pkgname-doc $pkgname-pgsql $pkgname-odbc
$pkgname-tds"
-source="http://downloads.digium.com/pub/asterisk/releases/$pkgname-$_myver.tar.gz
+source="http://downloads.digium.com/pub/asterisk/releases/$pkgname-$_basever.tar.gz
asterisk-01-1.6.0-gsm-pic.patch
- asterisk-03-1.6.2.0-beta1-to-r186562.patch
+ asterisk-02-uclibc-daemon.patch
+ asterisk-03-1.6.2.0-beta3-to-svn-r202568.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
- 200-uclibc-daemon.patch
asterisk.pre-install
asterisk.post-install
asterisk.initd
asterisk.confd"
build() {
- cd "$srcdir/$pkgname-$_myver"
+ cd "$srcdir/$pkgname-$_basever"
for i in ../*.patch; do
msg "Apply $i"
patch -p1 < $i || return 1
@@ -47,6 +47,7 @@ build() {
--without-iconv --with-popt --with-z --with-newt \
--with-odbc --with-postgres --with-tds \
--with-dahdi --with-pri --with-tonezone \
+ --without-x11 \
|| return 1
# and figure out which modules to build
@@ -70,31 +71,31 @@ _find_and_move() {
}
pgsql() {
- depends="uclibc asterisk libpq zlib"
+ depends=""
install=
_find_and_move '*_pgsql*'
}
odbc() {
- depends="uclibc asterisk unixodbc"
+ depends=""
install=
_find_and_move '*odbc*'
}
tds() {
- depends="uclibc asterisk freetds"
+ depends=""
install=
_find_and_move '*_tds*'
}
-md5sums="1a44f295fc9e72d19da7f42d095e6c60 asterisk-1.6.2.0-beta1.tar.gz
+md5sums="53989aba01b046a67c6f7754d7a3abcd asterisk-1.6.2.0-beta3.tar.gz
97b39fd9777a2521d4f9f095482b7ac2 asterisk-01-1.6.0-gsm-pic.patch
-9f5d2412feea58ed49e2dff5cfd1fb8f asterisk-03-1.6.2.0-beta1-to-r186562.patch
+b00c9d98ce2ad445501248a197c6e436 asterisk-02-uclibc-daemon.patch
+39f12a80ee2ba70689d7ff244a2b20aa asterisk-03-1.6.2.0-beta3-to-svn-r202568.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
-b00c9d98ce2ad445501248a197c6e436 200-uclibc-daemon.patch
+cc6a11b73f3ba7e98a621540c8e71542 asterisk-07-issue14068.patch
b4a97cb1ec3cc3f71a10ce8c067ab430 asterisk.pre-install
62ecffc90b6714b85f377d1fac73c58b asterisk.post-install
bbcd152417bb7c838b25cb6007db91da asterisk.initd
diff --git a/testing/asterisk/200-uclibc-daemon.patch b/testing/asterisk/asterisk-02-uclibc-daemon.patch
index 4956791d..4956791d 100644
--- a/testing/asterisk/200-uclibc-daemon.patch
+++ b/testing/asterisk/asterisk-02-uclibc-daemon.patch
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
deleted file mode 100644
index 21ff8236..00000000
--- a/testing/asterisk/asterisk-03-1.6.2.0-beta1-to-r186562.patch
+++ /dev/null
@@ -1,41697 +0,0 @@
-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-03-1.6.2.0-beta3-to-svn-r202568.patch b/testing/asterisk/asterisk-03-1.6.2.0-beta3-to-svn-r202568.patch
new file mode 100644
index 00000000..9f8a9cdc
--- /dev/null
+++ b/testing/asterisk/asterisk-03-1.6.2.0-beta3-to-svn-r202568.patch
@@ -0,0 +1,102239 @@
+Index: .version
+===================================================================
+--- a/.version (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/.version (.../trunk) (revision 202568)
+@@ -1 +1 @@
+-1.6.2.0-beta3
++1.6.3.0-r202568
+Index: build_tools/strip_nonapi
+===================================================================
+--- a/build_tools/strip_nonapi (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/build_tools/strip_nonapi (.../trunk) (revision 202568)
+@@ -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: build_tools/cflags.xml
+===================================================================
+--- a/build_tools/cflags.xml (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/build_tools/cflags.xml (.../trunk) (revision 202568)
+@@ -32,8 +32,6 @@
+ <member name="TEST_TANDEM_TRANSCODING" displayname="New ulaw/alaw codec, turn on transcoding tests on init">
+ <depend>G711_NEW_ALGORITHM</depend>
+ </member>
+- <member name="DEBUG_CHANNEL_LOCKS" displayname="Debug Channel Locking">
+- </member>
+ <member name="MALLOC_DEBUG" displayname="Keep Track of Memory Allocations">
+ </member>
+ <member name="BUSYDETECT_TONEONLY" displayname="Enable additional comparision of only the tone duration not the silence part">
+Index: build_tools/menuselect-deps.in
+===================================================================
+--- a/build_tools/menuselect-deps.in (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/build_tools/menuselect-deps.in (.../trunk) (revision 202568)
+@@ -11,6 +11,7 @@
+ GTK=@PBX_GTK@
+ H323=@PBX_H323@
+ HOARD=@PBX_HOARD@
++ICAL=@PBX_ICAL@
+ ICONV=@PBX_ICONV@
+ IKSEMEL=@PBX_IKSEMEL@
+ IMAP_TK=@PBX_IMAP_TK@
+@@ -19,12 +20,14 @@
+ IXJUSER=@PBX_IXJUSER@
+ JACK=@PBX_JACK@
+ LDAP=@PBX_LDAP@
++LIBXML2=@PBX_LIBXML2@
+ LTDL=@PBX_LTDL@
+ LUA=@PBX_LUA@
+ MISDN=@PBX_MISDN@
+ NBS=@PBX_NBS@
+ NETSNMP=@PBX_NETSNMP@
+ NEWT=@PBX_NEWT@
++NEON=@PBX_NEON@
+ OGG=@PBX_OGG@
+ OPENH323=@PBX_OPENH323@
+ OSPTK=@PBX_OSPTK@
+@@ -33,6 +36,7 @@
+ POPT=@PBX_POPT@
+ PORTAUDIO=@PBX_PORTAUDIO@
+ PRI=@PBX_PRI@
++OPENR2=@PBX_OPENR2@
+ RESAMPLE=@PBX_RESAMPLE@
+ AIS=@PBX_AIS@
+ RADIUS=@PBX_RADIUS@
+Index: configure
+===================================================================
+Cannot display: file marked as a binary type.
+svn:mime-type = application/octet-stream
+Index: default.exports
+===================================================================
+--- a/default.exports (.../tags/1.6.2.0-beta3) (revision 0)
++++ b/default.exports (.../trunk) (revision 202568)
+@@ -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_config.c
+===================================================================
+--- a/pbx/pbx_config.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/pbx/pbx_config.c (.../trunk) (revision 202568)
+@@ -328,7 +328,7 @@
+ * Priority input checking ...
+ */
+ if (a->argc == 5) {
+- char *c = a->argv[4];
++ const char *c = a->argv[4];
+
+ /* check for digits in whole parameter for right priority ...
+ * why? because atoi (strtol) returns 0 if any characters in
+@@ -451,8 +451,7 @@
+
+ ast_unlock_contexts();
+ error2:
+- if (exten)
+- free(exten);
++ free(exten);
+ } else if (a->pos == 4) { /* 'dialplan remove extension EXT _X_' (priority) */
+ char *exten = NULL, *context, *cid, *p;
+ struct ast_context *c;
+@@ -509,8 +508,7 @@
+ }
+ ast_unlock_contexts();
+ error3:
+- if (exten)
+- free(exten);
++ free(exten);
+ }
+ return ret;
+ }
+@@ -935,8 +933,7 @@
+ if (strcmp(a->argv[6], "replace"))
+ return CLI_SHOWUSAGE;
+
+- /* XXX overwrite argv[3] */
+- whole_exten = a->argv[3];
++ whole_exten = ast_strdupa(a->argv[3]);
+ exten = strsep(&whole_exten,",");
+ if (strchr(exten, '/')) {
+ cidmatch = exten;
+@@ -1139,8 +1136,7 @@
+ ret = strdup(ast_get_context_name(c));
+ }
+
+- if (ignorepat)
+- free(ignorepat);
++ free(ignorepat);
+ ast_unlock_contexts();
+ return ret;
+ }
+Index: pbx/pbx_spool.c
+===================================================================
+--- a/pbx/pbx_spool.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/pbx/pbx_spool.c (.../trunk) (revision 202568)
+@@ -339,7 +339,7 @@
+ ast_log(LOG_NOTICE, "Call failed to go through, reason (%d) %s\n", reason, ast_channel_reason2str(reason));
+ if (o->retries >= o->maxretries + 1) {
+ /* Max retries exceeded */
+- ast_log(LOG_EVENT, "Queued call to %s/%s expired without completion after %d attempt%s\n", o->tech, o->dest, o->retries - 1, ((o->retries - 1) != 1) ? "s" : "");
++ ast_log(LOG_NOTICE, "Queued call to %s/%s expired without completion after %d attempt%s\n", o->tech, o->dest, o->retries - 1, ((o->retries - 1) != 1) ? "s" : "");
+ remove_from_queue(o, "Expired");
+ } else {
+ /* Notate that the call is still active */
+@@ -347,7 +347,6 @@
+ }
+ } else {
+ ast_log(LOG_NOTICE, "Call completed to %s/%s\n", o->tech, o->dest);
+- ast_log(LOG_EVENT, "Queued call to %s/%s completed\n", o->tech, o->dest);
+ remove_from_queue(o, "Completed");
+ }
+ free_outgoing(o);
+@@ -425,7 +424,7 @@
+ }
+ res = now;
+ } else {
+- ast_log(LOG_EVENT, "Queued call to %s/%s expired without completion after %d attempt%s\n", o->tech, o->dest, o->retries - 1, ((o->retries - 1) != 1) ? "s" : "");
++ ast_log(LOG_NOTICE, "Queued call to %s/%s expired without completion after %d attempt%s\n", o->tech, o->dest, o->retries - 1, ((o->retries - 1) != 1) ? "s" : "");
+ remove_from_queue(o, "Expired");
+ free_outgoing(o);
+ }
+Index: pbx/pbx_ael.c
+===================================================================
+--- a/pbx/pbx_ael.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/pbx/pbx_ael.c (.../trunk) (revision 202568)
+@@ -251,7 +251,7 @@
+ );
+
+ #ifdef AAL_ARGCHECK
+-static char *ael_funclist[] =
++static const char * const ael_funclist[] =
+ {
+ "AGENT",
+ "ARRAY",
+Index: pbx/pbx_lua.c
+===================================================================
+--- a/pbx/pbx_lua.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/pbx/pbx_lua.c (.../trunk) (revision 202568)
+@@ -93,8 +93,8 @@
+ static int exec(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data);
+
+ AST_MUTEX_DEFINE_STATIC(config_file_lock);
+-char *config_file_data = NULL;
+-long config_file_size = 0;
++static char *config_file_data = NULL;
++static long config_file_size = 0;
+
+ static struct ast_context *local_contexts = NULL;
+ static struct ast_hashtab *local_table = NULL;
+Index: pbx/pbx_realtime.c
+===================================================================
+--- a/pbx/pbx_realtime.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/pbx/pbx_realtime.c (.../trunk) (revision 202568)
+@@ -54,9 +54,9 @@
+
+ #define EXT_DATA_SIZE 256
+
+-enum {
++enum option_flags {
+ OPTION_PATTERNS_DISABLED = (1 << 0),
+-} option_flags;
++};
+
+ AST_APP_OPTIONS(switch_opts, {
+ AST_APP_OPTION('p', OPTION_PATTERNS_DISABLED),
+Index: pbx/pbx_dundi.c
+===================================================================
+--- a/pbx/pbx_dundi.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/pbx/pbx_dundi.c (.../trunk) (revision 202568)
+@@ -3876,7 +3876,7 @@
+ AST_APP_OPTION('b', OPT_BYPASS_CACHE),
+ END_OPTIONS );
+
+-unsigned int dundi_result_id;
++static unsigned int dundi_result_id;
+
+ struct dundi_result_datastore {
+ struct dundi_result results[MAX_RESULTS];
+Index: pbx/dundi-parser.c
+===================================================================
+--- a/pbx/dundi-parser.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/pbx/dundi-parser.c (.../trunk) (revision 202568)
+@@ -155,7 +155,7 @@
+
+ static void dump_cause(char *output, int maxlen, void *value, int len)
+ {
+- static char *causes[] = {
++ static const char * const causes[] = {
+ "SUCCESS",
+ "GENERAL",
+ "DYNAMIC",
+Index: channels/h323/ast_h323.cxx
+===================================================================
+--- a/channels/h323/ast_h323.cxx (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/channels/h323/ast_h323.cxx (.../trunk) (revision 202568)
+@@ -572,8 +572,7 @@
+ {
+ #ifdef H323_H450
+ /* Dispatcher will free out all registered handlers */
+- if (h450dispatcher)
+- delete h450dispatcher;
++ delete h450dispatcher;
+ h450dispatcher = new H450xDispatcher(*this);
+ h4502handler = new H4502Handler(*this, *h450dispatcher);
+ h4504handler = new MyH4504Handler(*this, *h450dispatcher);
+@@ -1988,8 +1987,9 @@
+ if (cap && cap->IsUsable(*this)) {
+ lastcap++;
+ lastcap = localCapabilities.SetCapability(0, lastcap, cap);
+- } else if (cap)
++ } else {
+ delete cap; /* Capability is not usable */
++ }
+
+ dtmfMode = dtmf_mode;
+ if (h323debug) {
+@@ -2001,8 +2001,9 @@
+ cap = new H323_UserInputCapability(H323_UserInputCapability::BasicString);
+ if (cap && cap->IsUsable(*this)) {
+ lastcap = localCapabilities.SetCapability(0, lastcap, cap);
+- } else if (cap)
++ } else {
+ delete cap; /* Capability is not usable */
++ }
+ sendUserInputMode = SendUserInputAsString;
+ } else {
+ if ((dtmfMode & H323_DTMF_RFC2833) != 0) {
+@@ -2011,8 +2012,7 @@
+ lastcap = localCapabilities.SetCapability(0, lastcap, cap);
+ else {
+ dtmfMode |= H323_DTMF_SIGNAL;
+- if (cap)
+- delete cap; /* Capability is not usable */
++ delete cap; /* Capability is not usable */
+ }
+ }
+ if ((dtmfMode & H323_DTMF_CISCO) != 0) {
+@@ -2024,8 +2024,7 @@
+ dtmfMode |= H323_DTMF_SIGNAL;
+ } else {
+ dtmfMode |= H323_DTMF_SIGNAL;
+- if (cap)
+- delete cap; /* Capability is not usable */
++ delete cap; /* Capability is not usable */
+ }
+ }
+ if ((dtmfMode & H323_DTMF_SIGNAL) != 0) {
+@@ -2033,7 +2032,7 @@
+ cap = new H323_UserInputCapability(H323_UserInputCapability::SignalToneH245);
+ if (cap && cap->IsUsable(*this))
+ lastcap = localCapabilities.SetCapability(0, lastcap, cap);
+- else if (cap)
++ else
+ delete cap; /* Capability is not usable */
+ }
+ sendUserInputMode = SendUserInputAsTone; /* RFC2833 transmission handled at Asterisk level */
+Index: channels/h323/README
+===================================================================
+--- a/channels/h323/README (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/channels/h323/README (.../trunk) (revision 202568)
+@@ -137,7 +137,7 @@
+
+ If you are motivated to update/fix this code please submit a
+ disclaimer along with the patch to the Asterisk bug
+-tracker: http://bugs.digium.com/
++tracker: https://issues.asterisk.org/
+
+
+ Jeremy McNamara
+Index: channels/misdn_config.c
+===================================================================
+--- a/channels/misdn_config.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/channels/misdn_config.c (.../trunk) (revision 202568)
+@@ -1,6 +1,6 @@
+ /*
+ * Asterisk -- An open source telephony toolkit.
+- *
++ *
+ * Copyright (C) 2005, Christian Richter
+ *
+ * Christian Richter <crich@beronet.com>
+@@ -132,7 +132,7 @@
+ { "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,
+ "Set the method to use for channel selection:\n"
+ "\t standard - Use the first free channel starting from the lowest number.\n"
+@@ -140,62 +140,71 @@
+ "\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"
+@@ -212,6 +221,28 @@
+ "\n"
+ "\tscreen=0, presentation=0 -> callerid presented\n"
+ "\tscreen=1, presentation=1 -> callerid restricted (the remote end doesn't see it!)" },
++ { "outgoing_colp", MISDN_CFG_OUTGOING_COLP, MISDN_CTYPE_INT, "0", NONE,
++ "Select what to do with outgoing COLP information on this port.\n"
++ "\n"
++ "\t0 - Send out COLP information unaltered.\n"
++ "\t1 - Force COLP to restricted on all outgoing COLP information.\n"
++ "\t2 - Do not send COLP information." },
++ { "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"
+@@ -220,7 +251,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"
+@@ -257,17 +288,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"
+@@ -311,13 +342,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"
+@@ -336,6 +367,8 @@
+ "MSN's for TE ports, listen on those numbers on the above ports, and\n"
+ "\tindicate the incoming calls to Asterisk.\n"
+ "\tHere you can give a comma separated list, or simply an '*' for any msn." },
++ { "cc_request_retention", MISDN_CFG_CC_REQUEST_RETENTION, MISDN_CTYPE_BOOL, "yes", NONE,
++ "Enable/Disable call-completion request retention support (ptp)." },
+ };
+
+ static const struct misdn_cfg_spec gen_spec[] = {
+@@ -365,8 +398,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,
+@@ -387,7 +420,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. " \
+@@ -476,7 +509,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) {
+@@ -508,7 +541,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);
+ }
+@@ -567,7 +600,7 @@
+ misdn_cfg_unlock();
+ }
+
+-enum misdn_cfg_elements misdn_cfg_get_elem(char *name)
++enum misdn_cfg_elements misdn_cfg_get_elem(const char *name)
+ {
+ int pos;
+
+@@ -580,11 +613,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;
+ }
+
+@@ -598,7 +631,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"))
+@@ -631,7 +664,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 {
+@@ -660,7 +693,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;
+@@ -689,7 +722,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);
+ }
+ }
+@@ -709,7 +742,7 @@
+ return re;
+ }
+
+-/*!
++/*!
+ * \brief Generate a comma separated list of all active ports
+ */
+ void misdn_cfg_get_ports_string (char *ports)
+@@ -777,10 +810,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);
+@@ -847,7 +880,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) {
+@@ -939,7 +972,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");
+ }
+@@ -961,7 +994,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;
+@@ -972,7 +1005,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) {
+@@ -995,7 +1028,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-beta3) (revision 202568)
++++ b/channels/chan_jingle.c (.../trunk) (revision 202568)
+@@ -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;
+@@ -584,7 +577,7 @@
+ struct jingle_candidate *tmp;
+ struct aji_client *c = client->connection;
+ struct jingle_candidate *ours1 = NULL, *ours2 = NULL;
+- struct sockaddr_in sin;
++ struct sockaddr_in sin = { 0, };
+ struct sockaddr_in dest;
+ struct in_addr us;
+ struct in_addr externaddr;
+@@ -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-beta3) (revision 202568)
++++ b/channels/chan_dahdi.c (.../trunk) (revision 202568)
+@@ -62,6 +62,7 @@
+
+ #include <dahdi/user.h>
+ #include <dahdi/tonezone.h>
++#include "sig_analog.h"
+
+ #ifdef HAVE_PRI
+ #include <libpri.h>
+@@ -154,11 +155,94 @@
+ <para>This application will Accept the R2 call either with charge or no charge.</para>
+ </description>
+ </application>
++ <manager name="DAHDITransfer" language="en_US">
++ <synopsis>
++ Transfer DAHDI Channel.
++ </synopsis>
++ <syntax>
++ <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
++ <parameter name="DAHDIChannel" required="true">
++ <para>DAHDI channel name to transfer.</para>
++ </parameter>
++ </syntax>
++ <description>
++ <para>Transfer a DAHDI channel.</para>
++ </description>
++ </manager>
++ <manager name="DAHDIHangup" language="en_US">
++ <synopsis>
++ Hangup DAHDI Channel.
++ </synopsis>
++ <syntax>
++ <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
++ <parameter name="DAHDIChannel" required="true">
++ <para>DAHDI channel name to hangup.</para>
++ </parameter>
++ </syntax>
++ <description>
++ <para>Hangup a DAHDI channel.</para>
++ </description>
++ </manager>
++ <manager name="DAHDIDialOffhook" language="en_US">
++ <synopsis>
++ Dial over DAHDI channel while offhook.
++ </synopsis>
++ <syntax>
++ <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
++ <parameter name="DAHDIChannel" required="true" />
++ <parameter name="Number" required="true" />
++ </syntax>
++ <description>
++ </description>
++ </manager>
++ <manager name="DAHDIDNDon" language="en_US">
++ <synopsis>
++ Toggle DAHDI channel Do Not Disturb status ON.
++ </synopsis>
++ <syntax>
++ <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
++ <parameter name="DAHDIChannel" required="true" />
++ </syntax>
++ <description>
++ </description>
++ </manager>
++ <manager name="DAHDIDNDoff" language="en_US">
++ <synopsis>
++ Toggle DAHDI channel Do Not Disturb status OFF.
++ </synopsis>
++ <syntax>
++ <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
++ <parameter name="DAHDIChannel" required="true" />
++ </syntax>
++ <description>
++ </description>
++ </manager>
++ <manager name="DAHDIShowChannels" language="en_US">
++ <synopsis>
++ Show status DAHDI channels.
++ </synopsis>
++ <syntax>
++ <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
++ <parameter name="DAHDIChannel" required="true" />
++ </syntax>
++ <description>
++ </description>
++ </manager>
++ <manager name="DAHDIRestart" language="en_US">
++ <synopsis>
++ Fully Restart DAHDI channels (terminates calls).
++ </synopsis>
++ <syntax>
++ <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
++ </syntax>
++ <description>
++ </description>
++ </manager>
+ ***/
+
+ #define SMDI_MD_WAIT_TIMEOUT 1500 /* 1.5 seconds */
+
+-static const char *lbostr[] = {
++static const char * const lbostr[] = {
+ "0 db (CSU)/0-133 feet (DSX-1)",
+ "133-266 feet (DSX-1)",
+ "266-399 feet (DSX-1)",
+@@ -292,6 +376,28 @@
+ #define CALLPROGRESS_FAX_INCOMING 4
+ #define CALLPROGRESS_FAX (CALLPROGRESS_FAX_INCOMING | CALLPROGRESS_FAX_OUTGOING)
+
++#ifdef HAVE_PRI_SERVICE_MESSAGES
++/*! \brief Persistent Service State */
++#define SRVST_DBKEY "service-state"
++/*! \brief The out-of-service SERVICE state */
++#define SRVST_TYPE_OOS "O"
++/*! \brief SRVST_INITIALIZED is used to indicate a channel being out-of-service
++ * The SRVST_INITIALIZED is mostly used maintain backwards compatibility but also may
++ * mean that the channel has not yet received a RESTART message. If a channel is
++ * out-of-service with this reason a RESTART message will result in the channel
++ * being put into service. */
++#define SRVST_INITIALIZED 0
++/*! \brief SRVST_NEAREND is used to indicate that the near end was put out-of-service */
++#define SRVST_NEAREND (1 << 0)
++/*! \brief SRVST_FAREND is used to indicate that the far end was taken out-of-service */
++#define SRVST_FAREND (1 << 1)
++/*! \brief SRVST_BOTH is used to indicate that both sides of the channel are out-of-service */
++#define SRVST_BOTH (SRVST_NEAREND | SRVST_FAREND)
++
++/*! \brief The AstDB family */
++static const char dahdi_db[] = "dahdi/registry";
++#endif
++
+ static char defaultcic[64] = "";
+ static char defaultozz[64] = "";
+
+@@ -363,6 +469,8 @@
+
+ static int dahdi_sendtext(struct ast_channel *c, const char *text);
+
++static int analog_lib_handles(int signalling, int radio, int oprmode);
++
+ static void mwi_event_cb(const struct ast_event *event, void *userdata)
+ {
+ /* This module does not handle MWI in an event-based manner. However, it
+@@ -475,6 +583,9 @@
+ int max_ani;
+ int max_dnis;
+ int get_ani_first:1;
++#if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 1
++ int skip_category_request:1;
++#endif
+ int call_files:1;
+ int allow_collect_calls:1;
+ int charge_calls:1;
+@@ -543,6 +654,9 @@
+ int resetting;
+ /*! \brief Current position during a reset (-1 if not started) */
+ int resetpos;
++#ifdef HAVE_PRI_SERVICE_MESSAGES
++ unsigned int enable_service_message_support:1; /*!< enable SERVICE message support */
++#endif
+ #ifdef HAVE_PRI_INBANDDISCONNECT
+ unsigned int inbanddisconnect:1; /*!< Should we support inband audio after receiving DISCONNECT? */
+ #endif
+@@ -595,7 +709,7 @@
+ struct ringContextData ringContext[3];
+ };
+
+-static char *subnames[] = {
++static const char * const subnames[] = {
+ "Real",
+ "Callwait",
+ "Threeway"
+@@ -645,6 +759,7 @@
+
+ static struct dahdi_pvt {
+ ast_mutex_t lock;
++ struct callerid_state *cs;
+ struct ast_channel *owner; /*!< Our current active owner (if applicable) */
+ /*!< Up to three channels can be associated with this call */
+
+@@ -757,10 +872,10 @@
+ unsigned int echocanon:1;
+ /*! \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 */
++ /*! 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;
++ /*! TRUE while buffer configuration override is in use */
++ unsigned int bufferoverrideinuse:1;
+ /*! \brief TRUE if over a radio and dahdi_read() has been called. */
+ unsigned int firstradio:1;
+ /*!
+@@ -1225,6 +1340,7 @@
+ char begindigit;
+ /*! \brief TRUE if confrence is muted. */
+ int muting;
++ void *sig_pvt;
+ } *iflist = NULL, *ifend = NULL;
+
+ /*! \brief Channel configuration from chan_dahdi.conf .
+@@ -1305,6 +1421,9 @@
+ .max_ani = 10,
+ .max_dnis = 4,
+ .get_ani_first = -1,
++#if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 1
++ .skip_category_request = -1,
++#endif
+ .call_files = 0,
+ .allow_collect_calls = 0,
+ .charge_calls = 1,
+@@ -1356,8 +1475,6 @@
+ .buf_policy = DAHDI_POLICY_IMMEDIATE,
+ .buf_no = numbufs,
+ .usefaxbuffers = 0,
+- .faxbuf_policy = DAHDI_POLICY_IMMEDIATE,
+- .faxbuf_no = numbufs,
+ },
+ .timing = {
+ .prewinktime = -1,
+@@ -1390,8 +1507,10 @@
+ static int dahdi_indicate(struct ast_channel *chan, int condition, const void *data, size_t datalen);
+ static int dahdi_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
+ static int dahdi_setoption(struct ast_channel *chan, int option, void *data, int datalen);
++static int dahdi_queryoption(struct ast_channel *chan, int option, void *data, int *datalen);
+ static int dahdi_func_read(struct ast_channel *chan, const char *function, char *data, char *buf, size_t len);
+ static int handle_init_event(struct dahdi_pvt *i, int event);
++static int dahdi_func_write(struct ast_channel *chan, const char *function, char *data, const char *value);
+
+ static const struct ast_channel_tech dahdi_tech = {
+ .type = "DAHDI",
+@@ -1411,7 +1530,9 @@
+ .indicate = dahdi_indicate,
+ .fixup = dahdi_fixup,
+ .setoption = dahdi_setoption,
++ .queryoption = dahdi_queryoption,
+ .func_channel_read = dahdi_func_read,
++ .func_channel_write = dahdi_func_write,
+ };
+
+ #ifdef HAVE_PRI
+@@ -1420,8 +1541,913 @@
+ #define GET_CHANNEL(p) ((p)->channel)
+ #endif
+
+-struct dahdi_pvt *round_robin[32];
++static enum analog_sigtype dahdisig_to_analogsig(int sig)
++{
++ switch (sig) {
++ case SIG_FXOLS:
++ return ANALOG_SIG_FXOLS;
++ case SIG_FXOGS:
++ return ANALOG_SIG_FXOGS;
++ case SIG_FXOKS:
++ return ANALOG_SIG_FXOKS;
++ case SIG_FXSLS:
++ return ANALOG_SIG_FXSLS;
++ case SIG_FXSGS:
++ return ANALOG_SIG_FXSGS;
++ case SIG_FXSKS:
++ return ANALOG_SIG_FXSKS;
++ case SIG_EMWINK:
++ return ANALOG_SIG_EMWINK;
++ case SIG_EM:
++ return ANALOG_SIG_EM;
++ case SIG_EM_E1:
++ return ANALOG_SIG_EM_E1;
++ case SIG_FEATD:
++ return ANALOG_SIG_FEATD;
++ case SIG_FEATDMF:
++ return ANALOG_SIG_FEATDMF;
++ case SIG_E911:
++ return SIG_E911;
++ case SIG_FGC_CAMA:
++ return ANALOG_SIG_FGC_CAMA;
++ case SIG_FGC_CAMAMF:
++ return ANALOG_SIG_FGC_CAMAMF;
++ case SIG_FEATB:
++ return ANALOG_SIG_FEATB;
++ case SIG_SFWINK:
++ return ANALOG_SIG_SFWINK;
++ case SIG_SF:
++ return ANALOG_SIG_SF;
++ case SIG_SF_FEATD:
++ return ANALOG_SIG_SF_FEATD;
++ case SIG_SF_FEATDMF:
++ return ANALOG_SIG_SF_FEATDMF;
++ case SIG_FEATDMF_TA:
++ return ANALOG_SIG_FEATDMF_TA;
++ case SIG_SF_FEATB:
++ return ANALOG_SIG_FEATB;
++ default:
++ return -1;
++ }
++}
+
++
++static int analog_tone_to_dahditone(enum analog_tone tone)
++{
++ switch (tone) {
++ case ANALOG_TONE_RINGTONE:
++ return DAHDI_TONE_RINGTONE;
++ case ANALOG_TONE_STUTTER:
++ return DAHDI_TONE_STUTTER;
++ case ANALOG_TONE_CONGESTION:
++ return DAHDI_TONE_CONGESTION;
++ case ANALOG_TONE_DIALTONE:
++ return DAHDI_TONE_DIALTONE;
++ case ANALOG_TONE_DIALRECALL:
++ return DAHDI_TONE_DIALRECALL;
++ case ANALOG_TONE_INFO:
++ return DAHDI_TONE_INFO;
++ default:
++ return -1;
++ }
++}
++
++static int analogsub_to_dahdisub(enum analog_sub analogsub)
++{
++ int index;
++
++ switch (analogsub) {
++ case ANALOG_SUB_REAL:
++ index = SUB_REAL;
++ break;
++ case ANALOG_SUB_CALLWAIT:
++ index = SUB_CALLWAIT;
++ break;
++ case ANALOG_SUB_THREEWAY:
++ index = SUB_THREEWAY;
++ break;
++ default:
++ ast_log(LOG_ERROR, "Unidentified sub!\n");
++ index = SUB_REAL;
++ }
++
++ return index;
++}
++
++static enum analog_event dahdievent_to_analogevent(int event);
++static int bump_gains(struct dahdi_pvt *p);
++static int dahdi_setlinear(int dfd, int linear);
++
++static int my_start_cid_detect(void *pvt, int cid_signalling)
++{
++ struct dahdi_pvt *p = pvt;
++ int index = SUB_REAL;
++ p->cs = callerid_new(cid_signalling);
++ if (!p->cs) {
++ ast_log(LOG_ERROR, "Unable to alloc callerid\n");
++ return -1;
++ }
++ bump_gains(p);
++ dahdi_setlinear(p->subs[index].dfd, 0);
++
++ return 0;
++}
++
++static int my_stop_cid_detect(void *pvt)
++{
++ struct dahdi_pvt *p = pvt;
++ int index = SUB_REAL;
++ if (p->cs)
++ callerid_free(p->cs);
++ dahdi_setlinear(p->subs[index].dfd, p->subs[index].linear);
++ return 0;
++}
++
++static int my_get_callerid(void *pvt, char *namebuf, char *numbuf, enum analog_event *ev, size_t timeout)
++{
++ struct dahdi_pvt *p = pvt;
++ struct pollfd poller;
++ char *name, *num;
++ int index = SUB_REAL;
++ int res;
++ unsigned char buf[256];
++ int flags;
++
++ poller.fd = p->subs[SUB_REAL].dfd;
++ poller.events = POLLPRI | POLLIN;
++ poller.revents = 0;
++
++ res = poll(&poller, 1, timeout);
++
++ if (poller.revents & POLLPRI) {
++ *ev = dahdievent_to_analogevent(dahdi_get_event(p->subs[SUB_REAL].dfd));
++ return 1;
++ }
++
++ if (poller.revents & POLLIN) {
++ /*** NOTES ***/
++ /* Change API: remove cid_signalling from get_callerid, add a new start_cid_detect and stop_cid_detect function
++ * to enable slin mode and allocate cid detector. get_callerid should be able to be called any number of times until
++ * either a timeout occurss or CID is detected (returns 0). returning 1 should be event received, and -1 should be fail
++ * and die */
++ res = read(p->subs[index].dfd, buf, sizeof(buf));
++ if (res < 0) {
++ if (errno != ELAST) {
++ ast_log(LOG_WARNING, "read returned error: %s\n", strerror(errno));
++ callerid_free(p->cs);
++ return -1;
++ }
++ }
++ res = callerid_feed(p->cs, buf, res, AST_LAW(p));
++ if (res < 0) {
++ ast_log(LOG_WARNING, "CallerID feed failed: %s\n", strerror(errno));
++ return -1;
++ }
++
++ if (res == 1) {
++ callerid_get(p->cs, &name, &num, &flags);
++ if (name)
++ ast_copy_string(namebuf, name, ANALOG_MAX_CID);
++ if (num)
++ ast_copy_string(numbuf, num, ANALOG_MAX_CID);
++
++ ast_log(LOG_DEBUG, "CallerID number: %s, name: %s, flags=%d\n", num, name, flags);
++ return 0;
++ }
++ }
++
++ *ev = ANALOG_EVENT_NONE;
++ return 1;
++}
++
++static int send_callerid(struct dahdi_pvt *p);
++
++static int my_stop_callwait(void *pvt)
++{
++ struct dahdi_pvt *p = pvt;
++ p->callwaitingrepeat = 0;
++ p->cidcwexpire = 0;
++
++ return 0;
++}
++
++static int save_conference(struct dahdi_pvt *p);
++
++static int my_callwait(void *pvt)
++{
++ struct dahdi_pvt *p = pvt;
++ p->callwaitingrepeat = CALLWAITING_REPEAT_SAMPLES;
++ if (p->cidspill) {
++ ast_log(LOG_WARNING, "Spill already exists?!?\n");
++ free(p->cidspill);
++ }
++ if (!(p->cidspill = ast_malloc(2400 /* SAS */ + 680 /* CAS */ + READ_SIZE * 4)))
++ return -1;
++ save_conference(p);
++ /* Silence */
++ memset(p->cidspill, 0x7f, 2400 + 600 + READ_SIZE * 4);
++ if (!p->callwaitrings && p->callwaitingcallerid) {
++ ast_gen_cas(p->cidspill, 1, 2400 + 680, AST_LAW(p));
++ p->callwaitcas = 1;
++ p->cidlen = 2400 + 680 + READ_SIZE * 4;
++ } else {
++ ast_gen_cas(p->cidspill, 1, 2400, AST_LAW(p));
++ p->callwaitcas = 0;
++ p->cidlen = 2400 + READ_SIZE * 4;
++ }
++ p->cidpos = 0;
++ send_callerid(p);
++
++ return 0;
++}
++
++static int my_send_callerid(void *pvt, int cwcid, struct ast_callerid *cid)
++{
++ struct dahdi_pvt *p = pvt;
++
++ ast_log(LOG_ERROR, "Starting cid spill\n");
++
++ if (p->cidspill) {
++ ast_log(LOG_WARNING, "cidspill already exists??\n");
++ free(p->cidspill);
++ }
++
++ if ((p->cidspill = ast_malloc(MAX_CALLERID_SIZE))) {
++ if (cwcid == 0) {
++ p->cidlen = ast_callerid_generate(p->cidspill, cid->cid_name, cid->cid_num, AST_LAW(p));
++ } else {
++ p->callwaitcas = 0;
++ p->cidcwexpire = 0;
++ p->cidlen = ast_callerid_callwaiting_generate(p->cidspill, cid->cid_name, cid->cid_num, AST_LAW(p));
++ p->cidlen += READ_SIZE * 4;
++ }
++ p->cidpos = 0;
++ send_callerid(p);
++ }
++ return 0;
++}
++
++static int my_dsp_reset_and_flush_digits(void *pvt)
++{
++ struct dahdi_pvt *p = pvt;
++ if (p->dsp)
++ ast_dsp_digitreset(p->dsp);
++
++ return 0;
++}
++
++static int my_dsp_set_digitmode(void *pvt, enum analog_dsp_digitmode mode)
++{
++ struct dahdi_pvt *p = pvt;
++
++ if (p->channel == CHAN_PSEUDO)
++ ast_log(LOG_ERROR, "You have assumed incorrectly sir!\n");
++
++ if (mode == ANALOG_DIGITMODE_DTMF) {
++ /* If we do hardware dtmf, no need for a DSP */
++ if (p->hardwaredtmf) {
++ if (p->dsp) {
++ ast_dsp_free(p->dsp);
++ p->dsp = NULL;
++ }
++ return 0;
++ }
++
++ if (!p->dsp) {
++ p->dsp = ast_dsp_new();
++ if (!p->dsp) {
++ ast_log(LOG_ERROR, "Unable to allocate DSP\n");
++ return -1;
++ }
++ }
++
++ ast_dsp_set_digitmode(p->dsp, DSP_DIGITMODE_DTMF | p->dtmfrelax);
++ } else if (mode == ANALOG_DIGITMODE_MF) {
++ if (!p->dsp) {
++ p->dsp = ast_dsp_new();
++ if (!p->dsp) {
++ ast_log(LOG_ERROR, "Unable to allocate DSP\n");
++ return -1;
++ }
++ }
++ ast_dsp_set_digitmode(p->dsp, DSP_DIGITMODE_MF | p->dtmfrelax);
++ }
++ return 0;
++}
++
++static int dahdi_wink(struct dahdi_pvt *p, int index);
++
++static int my_wink(void *pvt, enum analog_sub sub)
++{
++ struct dahdi_pvt *p = pvt;
++ int index = analogsub_to_dahdisub(sub);
++ if (index != SUB_REAL) {
++ ast_log(LOG_ERROR, "We used a sub other than SUB_REAL (incorrect assumption sir)\n");
++ }
++ return dahdi_wink(p, index);
++}
++
++static void wakeup_sub(struct dahdi_pvt *p, int a, struct dahdi_pri *pri);
++
++static int reset_conf(struct dahdi_pvt *p);
++
++static inline int dahdi_confmute(struct dahdi_pvt *p, int muted);
++
++static void my_handle_dtmfup(void *pvt, struct ast_channel *ast, enum analog_sub analog_index, struct ast_frame **dest)
++{
++ struct ast_frame *f = *dest;
++ struct dahdi_pvt *p = pvt;
++ int idx = analogsub_to_dahdisub(analog_index);
++
++ ast_debug(1, "DTMF digit: %c on %s\n", f->subclass, ast->name);
++
++ if (f->subclass == 'f') {
++ /* Fax tone -- Handle and return NULL */
++ if ((p->callprogress & CALLPROGRESS_FAX) && !p->faxhandled) {
++ /* If faxbuffers are configured, use them for the fax transmission */
++ if (p->usefaxbuffers && !p->bufferoverrideinuse) {
++ 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 buffer policy, reason: %s\n", ast->name, strerror(errno));
++ } else {
++ p->bufferoverrideinuse = 1;
++ }
++ }
++ p->faxhandled = 1;
++ if (strcmp(ast->exten, "fax")) {
++ const char *target_context = S_OR(ast->macrocontext, ast->context);
++
++ /* We need to unlock 'ast' here because ast_exists_extension has the
++ * potential to start autoservice on the channel. Such action is prone
++ * to deadlock.
++ */
++ ast_mutex_unlock(&p->lock);
++ ast_channel_unlock(ast);
++ if (ast_exists_extension(ast, target_context, "fax", 1, ast->cid.cid_num)) {
++ ast_channel_lock(ast);
++ ast_mutex_lock(&p->lock);
++ ast_verb(3, "Redirecting %s to fax extension\n", ast->name);
++ /* 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, target_context, "fax", 1))
++ ast_log(LOG_WARNING, "Failed to async goto '%s' into fax of '%s'\n", ast->name, target_context);
++ } else {
++ ast_channel_lock(ast);
++ ast_mutex_lock(&p->lock);
++ ast_log(LOG_NOTICE, "Fax detected, but no fax extension\n");
++ }
++ } else {
++ ast_debug(1, "Already in a fax extension, not redirecting\n");
++ }
++ } else {
++ ast_debug(1, "Fax already handled\n");
++ }
++ dahdi_confmute(p, 0);
++ p->subs[idx].f.frametype = AST_FRAME_NULL;
++ p->subs[idx].f.subclass = 0;
++ *dest = &p->subs[idx].f;
++ }
++}
++
++static void my_lock_private(void *pvt)
++{
++ struct dahdi_pvt *p = pvt;
++
++ ast_mutex_lock(&p->lock);
++}
++
++static void my_unlock_private(void *pvt)
++{
++ struct dahdi_pvt *p = pvt;
++
++ ast_mutex_unlock(&p->lock);
++}
++
++static void my_increase_ss_count(void)
++{
++ ast_mutex_lock(&ss_thread_lock);
++ ss_thread_count++;
++ ast_mutex_unlock(&ss_thread_lock);
++}
++
++static void my_decrease_ss_count(void)
++{
++ ast_mutex_lock(&ss_thread_lock);
++ ss_thread_count--;
++ ast_cond_signal(&ss_thread_complete);
++ ast_mutex_unlock(&ss_thread_lock);
++}
++
++static void my_all_subchannels_hungup(void *pvt)
++{
++ struct dahdi_pvt *p = pvt;
++ int res, law;
++
++ p->faxhandled = 0;
++ p->didtdd = 0;
++
++ if (p->dsp) {
++ ast_dsp_free(p->dsp);
++ p->dsp = NULL;
++ }
++
++ law = DAHDI_LAW_DEFAULT;
++ res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_SETLAW, &law);
++ if (res < 0)
++ ast_log(LOG_WARNING, "Unable to set law on channel %d to default: %s\n", p->channel, strerror(errno));
++
++ dahdi_setlinear(p->subs[SUB_REAL].dfd, 0);
++
++#if 1
++ {
++ int i;
++ p->owner = NULL;
++ /* Cleanup owners here */
++ for (i = 0; i < 3; i++) {
++ p->subs[i].owner = NULL;
++ }
++ }
++#endif
++
++ reset_conf(p);
++ if (num_restart_pending == 0) {
++ restart_monitor();
++ }
++}
++
++static int conf_del(struct dahdi_pvt *p, struct dahdi_subchannel *c, int index);
++
++static int my_conf_del(void *pvt, enum analog_sub sub)
++{
++ struct dahdi_pvt *p = pvt;
++ int x = analogsub_to_dahdisub(sub);
++
++ return conf_del(p, &p->subs[x], x);
++}
++
++static int conf_add(struct dahdi_pvt *p, struct dahdi_subchannel *c, int index, int slavechannel);
++
++static int my_conf_add(void *pvt, enum analog_sub sub)
++{
++ struct dahdi_pvt *p = pvt;
++ int x = analogsub_to_dahdisub(sub);
++
++ return conf_add(p, &p->subs[x], x, 0);
++}
++
++static int isslavenative(struct dahdi_pvt *p, struct dahdi_pvt **out);
++
++static int my_complete_conference_update(void *pvt, int needconference)
++{
++ struct dahdi_pvt *p = pvt;
++ int needconf = needconference;
++ int x;
++ int useslavenative;
++ struct dahdi_pvt *slave = NULL;
++
++ useslavenative = isslavenative(p, &slave);
++
++ /* If we have a slave, add him to our conference now. or DAX
++ if this is slave native */
++ for (x = 0; x < MAX_SLAVES; x++) {
++ if (p->slaves[x]) {
++ if (useslavenative)
++ conf_add(p, &p->slaves[x]->subs[SUB_REAL], SUB_REAL, GET_CHANNEL(p));
++ else {
++ conf_add(p, &p->slaves[x]->subs[SUB_REAL], SUB_REAL, 0);
++ needconf++;
++ }
++ }
++ }
++ /* If we're supposed to be in there, do so now */
++ if (p->inconference && !p->subs[SUB_REAL].inthreeway) {
++ if (useslavenative)
++ conf_add(p, &p->subs[SUB_REAL], SUB_REAL, GET_CHANNEL(slave));
++ else {
++ conf_add(p, &p->subs[SUB_REAL], SUB_REAL, 0);
++ needconf++;
++ }
++ }
++ /* If we have a master, add ourselves to his conference */
++ if (p->master) {
++ if (isslavenative(p->master, NULL)) {
++ conf_add(p->master, &p->subs[SUB_REAL], SUB_REAL, GET_CHANNEL(p->master));
++ } else {
++ conf_add(p->master, &p->subs[SUB_REAL], SUB_REAL, 0);
++ }
++ }
++ if (!needconf) {
++ /* Nobody is left (or should be left) in our conference.
++ Kill it. */
++ p->confno = -1;
++ }
++
++ return 0;
++}
++
++static int check_for_conference(struct dahdi_pvt *p);
++
++static int my_check_for_conference(void *pvt)
++{
++ struct dahdi_pvt *p = pvt;
++ return check_for_conference(p);
++}
++
++static void my_swap_subchannels(void *pvt, enum analog_sub a, struct ast_channel *ast_a, enum analog_sub b, struct ast_channel *ast_b)
++{
++ struct dahdi_pvt *p = pvt;
++ int da, db;
++ int tchan;
++
++ da = analogsub_to_dahdisub(a);
++ db = analogsub_to_dahdisub(b);
++
++ tchan = p->subs[da].chan;
++
++ p->subs[da].chan = p->subs[db].chan;
++
++ p->subs[db].chan = tchan;
++
++ if (ast_a)
++ ast_a->fds[0] = p->subs[da].dfd;
++ if (ast_b)
++ ast_b->fds[0] = p->subs[db].dfd;
++
++ p->subs[da].owner = ast_a;
++ p->subs[db].owner = ast_b;
++
++ wakeup_sub(p, a, NULL);
++ wakeup_sub(p, b, NULL);
++
++ return;
++}
++
++static struct ast_channel *dahdi_new(struct dahdi_pvt *, int, int, int, int, int);
++
++static struct ast_channel * my_new_analog_ast_channel(void *pvt, int state, int startpbx, enum analog_sub sub)
++{
++ struct dahdi_pvt *p = pvt;
++ int dsub = analogsub_to_dahdisub(sub);
++
++ return dahdi_new(p, state, startpbx, dsub, 0, 0);
++}
++
++static int unalloc_sub(struct dahdi_pvt *p, int x);
++
++static int my_unallocate_sub(void *pvt, enum analog_sub analogsub)
++{
++ struct dahdi_pvt *p = pvt;
++
++ return unalloc_sub(p, analogsub_to_dahdisub(analogsub));
++}
++
++static int alloc_sub(struct dahdi_pvt *p, int x);
++
++static int my_allocate_sub(void *pvt, enum analog_sub analogsub)
++{
++ struct dahdi_pvt *p = pvt;
++
++ return alloc_sub(p, analogsub_to_dahdisub(analogsub));
++}
++
++static int has_voicemail(struct dahdi_pvt *p);
++
++static int my_has_voicemail(void *pvt)
++{
++ struct dahdi_pvt *p = pvt;
++
++ return has_voicemail(p);
++}
++
++static int my_play_tone(void *pvt, enum analog_sub sub, enum analog_tone tone)
++{
++ struct dahdi_pvt *p = pvt;
++ int index;
++
++ index = analogsub_to_dahdisub(sub);
++
++ return tone_zone_play_tone(p->subs[index].dfd, analog_tone_to_dahditone(tone));
++}
++
++static enum analog_event dahdievent_to_analogevent(int event)
++{
++ enum analog_event res = ANALOG_EVENT_ERROR;
++
++ switch (event) {
++ case DAHDI_EVENT_DIALCOMPLETE:
++ res = ANALOG_EVENT_DIALCOMPLETE;
++ break;
++ case DAHDI_EVENT_WINKFLASH:
++ res = ANALOG_EVENT_WINKFLASH;
++ break;
++ case DAHDI_EVENT_ONHOOK:
++ res = ANALOG_EVENT_ONHOOK;
++ break;
++ case DAHDI_EVENT_RINGOFFHOOK:
++ res = ANALOG_EVENT_RINGOFFHOOK;
++ break;
++ case DAHDI_EVENT_ALARM:
++ res = ANALOG_EVENT_ALARM;
++ break;
++ case DAHDI_EVENT_NOALARM:
++ res = ANALOG_EVENT_NOALARM;
++ break;
++ case DAHDI_EVENT_HOOKCOMPLETE:
++ res = ANALOG_EVENT_HOOKCOMPLETE;
++ break;
++ case DAHDI_EVENT_POLARITY:
++ res = ANALOG_EVENT_POLARITY;
++ break;
++ case DAHDI_EVENT_RINGERON:
++ res = ANALOG_EVENT_RINGERON;
++ break;
++ case DAHDI_EVENT_RINGEROFF:
++ res = ANALOG_EVENT_RINGEROFF;
++ break;
++ case DAHDI_EVENT_RINGBEGIN:
++ res = ANALOG_EVENT_RINGBEGIN;
++ break;
++ case DAHDI_EVENT_PULSE_START:
++ res = ANALOG_EVENT_PULSE_START;
++ break;
++ case DAHDI_EVENT_NEONMWI_ACTIVE:
++ res = ANALOG_EVENT_NEONMWI_ACTIVE;
++ break;
++ case DAHDI_EVENT_NEONMWI_INACTIVE:
++ res = ANALOG_EVENT_NEONMWI_INACTIVE;
++ break;
++ }
++
++ return res;
++}
++
++static inline int dahdi_wait_event(int fd);
++
++static int my_wait_event(void *pvt)
++{
++ struct dahdi_pvt *p = pvt;
++
++ return dahdi_wait_event(p->subs[SUB_REAL].dfd);
++}
++
++static int my_get_event(void *pvt)
++{
++ struct dahdi_pvt *p = pvt;
++ int res;
++
++ if (p->fake_event) {
++ res = p->fake_event;
++ p->fake_event = 0;
++ } else
++ res = dahdi_get_event(p->subs[SUB_REAL].dfd);
++
++ return dahdievent_to_analogevent(res);
++}
++
++static int my_is_off_hook(void *pvt)
++{
++ struct dahdi_pvt *p = pvt;
++ int res;
++ struct dahdi_params par;
++
++ if (p->subs[SUB_REAL].dfd > -1)
++ res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_GET_PARAMS, &par);
++ else {
++ /* Assume not off hook on CVRS */
++ res = 0;
++ par.rxisoffhook = 0;
++ }
++ if (res) {
++ ast_log(LOG_WARNING, "Unable to check hook state on channel %d: %s\n", p->channel, strerror(errno));
++ }
++
++ return (par.rxbits > -1) || par.rxisoffhook;
++}
++
++static void dahdi_enable_ec(struct dahdi_pvt *p);
++static void dahdi_disable_ec(struct dahdi_pvt *p);
++
++static int my_set_echocanceller(void *pvt, int enable)
++{
++ struct dahdi_pvt *p = pvt;
++
++ if (enable)
++ dahdi_enable_ec(p);
++ else
++ dahdi_disable_ec(p);
++
++ return 0;
++}
++
++static int dahdi_ring_phone(struct dahdi_pvt *p);
++
++static int my_ring(void *pvt)
++{
++ struct dahdi_pvt *p = pvt;
++
++ return dahdi_ring_phone(p);
++}
++
++static inline int dahdi_set_hook(int fd, int hs);
++
++static int my_off_hook(void *pvt)
++{
++ struct dahdi_pvt *p = pvt;
++ return dahdi_set_hook(p->subs[SUB_REAL].dfd, DAHDI_OFFHOOK);
++}
++
++static int my_start(void *pvt)
++{
++ struct dahdi_pvt *p = pvt;
++ int x = DAHDI_START;
++
++ return ioctl(p->subs[SUB_REAL].dfd, DAHDI_HOOK, &x);
++}
++
++static int my_dial_digits(void *pvt, enum analog_sub sub, struct analog_dialoperation *dop)
++{
++ int index = analogsub_to_dahdisub(sub);
++ int res;
++ struct dahdi_pvt *p = pvt;
++ struct dahdi_dialoperation ddop;
++
++ if (dop->op != ANALOG_DIAL_OP_REPLACE) {
++ ast_log(LOG_ERROR, "Fix the dial_digits callback!\n");
++ return -1;
++ }
++
++ if (sub != ANALOG_SUB_REAL)
++ printf("Trying to dial digits on sub %d\n", sub);
++
++ ddop.op = DAHDI_DIAL_OP_REPLACE;
++ strncpy(ddop.dialstr, dop->dialstr, sizeof(ddop.dialstr));
++
++ printf("Dialing %s on %d\n", ddop.dialstr, p->channel);
++
++ res = ioctl(p->subs[index].dfd, DAHDI_DIAL, &ddop);
++
++ if (res == -1)
++ ast_log(LOG_DEBUG, "DAHDI_DIAL ioctl failed on %s: %s\n", p->owner->name, strerror(errno));
++
++ return res;
++}
++
++static void dahdi_train_ec(struct dahdi_pvt *p);
++
++static int my_train_echocanceller(void *pvt)
++{
++ struct dahdi_pvt *p = pvt;
++
++ dahdi_train_ec(p);
++
++ return 0;
++}
++
++static int my_is_dialing(void *pvt, enum analog_sub sub)
++{
++ struct dahdi_pvt *p = pvt;
++ int index;
++ int x;
++
++ index = analogsub_to_dahdisub(sub);
++
++ if (ioctl(p->subs[index].dfd, DAHDI_DIALING, &x)) {
++ ast_log(LOG_DEBUG, "DAHDI_DIALING ioctl failed!\n");
++ return -1;
++ }
++
++ return x;
++}
++
++static int my_on_hook(void *pvt)
++{
++ struct dahdi_pvt *p = pvt;
++ int x = DAHDI_ONHOOK;
++
++ return ioctl(p->subs[ANALOG_SUB_REAL].dfd, DAHDI_HOOK, &x);
++}
++
++/*!
++ * \brief Send MWI state change
++ *
++ * \arg mailbox_full This is the mailbox associated with the FXO line that the
++ * MWI state has changed on.
++ * \arg thereornot This argument should simply be set to 1 or 0, to indicate
++ * whether there are messages waiting or not.
++ *
++ * \return nothing
++ *
++ * This function does two things:
++ *
++ * 1) It generates an internal Asterisk event notifying any other module that
++ * cares about MWI that the state of a mailbox has changed.
++ *
++ * 2) It runs the script specified by the mwimonitornotify option to allow
++ * some custom handling of the state change.
++ */
++static void notify_message(char *mailbox_full, int thereornot)
++{
++ char s[sizeof(mwimonitornotify) + 80];
++ struct ast_event *event;
++ char *mailbox, *context;
++
++ /* Strip off @default */
++ context = mailbox = ast_strdupa(mailbox_full);
++ strsep(&context, "@");
++ 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, thereornot,
++ AST_EVENT_IE_OLDMSGS, AST_EVENT_IE_PLTYPE_UINT, thereornot,
++ AST_EVENT_IE_END))) {
++ return;
++ }
++
++ 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);
++ ast_safe_system(s);
++ }
++}
++
++static void my_handle_notify_message(struct ast_channel *chan, void *pvt, int cid_flags, int neon_mwievent)
++{
++ struct dahdi_pvt *p = pvt;
++
++ if (neon_mwievent > -1 && !p->mwimonitor_neon)
++ return;
++
++ if (neon_mwievent == ANALOG_EVENT_NEONMWI_ACTIVE || cid_flags & CID_MSGWAITING) {
++ ast_log(LOG_NOTICE, "MWI: Channel %d message waiting, mailbox %s\n", p->channel, p->mailbox);
++ notify_message(p->mailbox, 1);
++ } else if (neon_mwievent == ANALOG_EVENT_NEONMWI_INACTIVE || cid_flags & CID_NOMSGWAITING) {
++ ast_log(LOG_NOTICE, "MWI: Channel %d no message waiting, mailbox %s\n", p->channel, p->mailbox);
++ notify_message(p->mailbox, 0);
++ }
++ /* If the CID had Message waiting payload, assume that this for MWI only and hangup the call */
++ /* If generated using Ring Pulse Alert, then ring has been answered as a call and needs to be hungup */
++ if (neon_mwievent == -1 && p->mwimonitor_rpas) {
++ ast_hangup(chan);
++ return;
++ }
++}
++
++
++static const char *event2str(int event);
++
++static struct analog_callback dahdi_analog_callbacks =
++{
++ .play_tone = my_play_tone,
++ .get_event = my_get_event,
++ .wait_event = my_wait_event,
++ .is_off_hook = my_is_off_hook,
++ .set_echocanceller = my_set_echocanceller,
++ .ring = my_ring,
++ .off_hook = my_off_hook,
++ .dial_digits = my_dial_digits,
++ .train_echocanceller = my_train_echocanceller,
++ .on_hook = my_on_hook,
++ .is_dialing = my_is_dialing,
++ .allocate_sub = my_allocate_sub,
++ .unallocate_sub = my_unallocate_sub,
++ .swap_subs = my_swap_subchannels,
++ .has_voicemail = my_has_voicemail,
++ .check_for_conference = my_check_for_conference,
++ .conf_add = my_conf_add,
++ .conf_del = my_conf_del,
++ .complete_conference_update = my_complete_conference_update,
++ .start = my_start,
++ .all_subchannels_hungup = my_all_subchannels_hungup,
++ .lock_private = my_lock_private,
++ .unlock_private = my_unlock_private,
++ .handle_dtmfup = my_handle_dtmfup,
++ .wink = my_wink,
++ .new_ast_channel = my_new_analog_ast_channel,
++ .dsp_set_digitmode = my_dsp_set_digitmode,
++ .dsp_reset_and_flush_digits = my_dsp_reset_and_flush_digits,
++ .send_callerid = my_send_callerid,
++ .callwait = my_callwait,
++ .stop_callwait = my_stop_callwait,
++ .get_callerid = my_get_callerid,
++ .start_cid_detect = my_start_cid_detect,
++ .stop_cid_detect = my_stop_cid_detect,
++ .handle_notify_message = my_handle_notify_message,
++ .increase_ss_count = my_increase_ss_count,
++ .decrease_ss_count = my_decrease_ss_count,
++};
++
++static struct dahdi_pvt *round_robin[32];
++
+ #if defined(HAVE_PRI)
+ static inline int pri_grab(struct dahdi_pvt *pvt, struct dahdi_pri *pri)
+ {
+@@ -2339,7 +3365,7 @@
+ return res;
+ }
+
+-static char *events[] = {
++static const char * const events[] = {
+ "No event",
+ "On hook",
+ "Ring/Answered",
+@@ -2384,7 +3410,7 @@
+ return alm ? "Unknown Alarm" : "No Alarm";
+ }
+
+-static char *event2str(int event)
++static const char *event2str(int event)
+ {
+ static char buf[256];
+ if ((event < (ARRAY_LEN(events))) && (event > -1))
+@@ -2471,6 +3497,45 @@
+ }
+ }
+
++int analog_lib_handles(int signalling, int radio, int oprmode)
++{
++ switch (signalling) {
++ case SIG_FXOLS:
++ case SIG_FXOGS:
++ case SIG_FXOKS:
++ case SIG_FXSLS:
++ case SIG_FXSGS:
++ case SIG_FXSKS:
++ case SIG_EMWINK:
++ case SIG_EM:
++ case SIG_EM_E1:
++ case SIG_FEATD:
++ case SIG_FEATDMF:
++ case SIG_E911:
++ case SIG_FGC_CAMA:
++ case SIG_FGC_CAMAMF:
++ case SIG_FEATB:
++ case SIG_SFWINK:
++ case SIG_SF:
++ case SIG_SF_FEATD:
++ case SIG_SF_FEATDMF:
++ case SIG_FEATDMF_TA:
++ case SIG_SF_FEATB:
++ break;
++ default:
++ /* The rest of the function should cover the remainder of signalling types */
++ return 0;
++ }
++
++ if (radio)
++ return 0;
++
++ if (oprmode)
++ return 0;
++
++ return 1;
++}
++
+ #define sig2str dahdi_sig2str
+
+ static int conf_add(struct dahdi_pvt *p, struct dahdi_subchannel *c, int idx, int slavechannel)
+@@ -2917,53 +3982,6 @@
+ return 0;
+ }
+
+-/*!
+- * \brief Send MWI state change
+- *
+- * \arg mailbox_full This is the mailbox associated with the FXO line that the
+- * MWI state has changed on.
+- * \arg thereornot This argument should simply be set to 1 or 0, to indicate
+- * whether there are messages waiting or not.
+- *
+- * \return nothing
+- *
+- * This function does two things:
+- *
+- * 1) It generates an internal Asterisk event notifying any other module that
+- * cares about MWI that the state of a mailbox has changed.
+- *
+- * 2) It runs the script specified by the mwimonitornotify option to allow
+- * some custom handling of the state change.
+- */
+-static void notify_message(char *mailbox_full, int thereornot)
+-{
+- char s[sizeof(mwimonitornotify) + 80];
+- struct ast_event *event;
+- char *mailbox, *context;
+-
+- /* Strip off @default */
+- context = mailbox = ast_strdupa(mailbox_full);
+- strsep(&context, "@");
+- 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, thereornot,
+- AST_EVENT_IE_OLDMSGS, AST_EVENT_IE_PLTYPE_UINT, thereornot,
+- AST_EVENT_IE_END))) {
+- return;
+- }
+-
+- 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);
+- ast_safe_system(s);
+- }
+-}
+-
+ static int restore_conference(struct dahdi_pvt *p)
+ {
+ int res;
+@@ -3021,6 +4039,8 @@
+ return new_msgs;
+ }
+
++
++
+ static int send_callerid(struct dahdi_pvt *p)
+ {
+ /* Assumes spill in p->cidspill, p->cidlen in length and we're p->cidpos into it */
+@@ -3135,6 +4155,14 @@
+
+ set_actual_gain(p->subs[SUB_REAL].dfd, 0, p->rxgain, p->txgain, p->law);
+
++ /* If this is analog signalling we can exit here */
++ if (analog_lib_handles(p->sig, p->radio, p->oprmode)) {
++ p->callwaitrings = 0;
++ res = analog_call(p->sig_pvt, ast, rdest, timeout);
++ ast_mutex_unlock(&p->lock);
++ return res;
++ }
++
+ mysig = p->sig;
+ if (p->outsigmod > -1)
+ mysig = p->outsigmod;
+@@ -3156,7 +4184,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);
+ }
+@@ -3197,12 +4225,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 */
+@@ -3214,8 +4242,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
+@@ -3281,14 +4309,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
+@@ -3423,7 +4451,7 @@
+ }
+
+ if (!p->hidecallerid) {
+- l = ast->cid.cid_num;
++ l = ast->connected.id.number;
+ } else {
+ l = NULL;
+ }
+@@ -3472,10 +4500,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);
+@@ -3587,9 +4615,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;
+ }
+ }
+
+@@ -3803,7 +4831,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;
+@@ -3934,11 +4962,25 @@
+ pl = p;
+ p = p->next;
+ x = pl->channel;
++#ifdef HAVE_PRI_SERVICE_MESSAGES
++ {
++ char db_chan_name[20], db_answer[5], state;
++ int why = -1;
++
++ snprintf(db_chan_name, sizeof(db_chan_name), "%s/%d:%d", dahdi_db, pl->span, x);
++ if (!ast_db_get(db_chan_name, SRVST_DBKEY, db_answer, sizeof(db_answer))) {
++ sscanf(db_answer, "%c:%d", &state, &why);
++ }
++ if (!why) {
++ /* SRVST persistence is not required */
++ ast_db_del(db_chan_name, SRVST_DBKEY);
++ }
++ }
++#endif
+ /* Free associated memory */
+ if (pl)
+ destroy_dahdi_pvt(&pl);
+- if (option_verbose > 2)
+- ast_verbose(VERBOSE_PREFIX_2 "Unregistered channel %d\n", x);
++ ast_verb(3, "Unregistered channel %d\n", x);
+ }
+ iflist = NULL;
+ ifcount = 0;
+@@ -3948,11 +4990,11 @@
+ #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)
++static int dahdi_send_keypad_facility_exec(struct ast_channel *chan, const char *data)
+ {
+ /* Data will be our digit string */
+ struct dahdi_pvt *p;
+- char *digits = (char *) data;
++ const char *digits = data;
+
+ if (ast_strlen_zero(digits)) {
+ ast_debug(1, "No digit string sent to application!\n");
+@@ -3993,7 +5035,7 @@
+ #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)
++static int dahdi_send_callrerouting_facility_exec(struct ast_channel *chan, const char *data)
+ {
+ /* Data will be our digit string */
+ struct dahdi_pvt *p;
+@@ -4157,9 +5199,9 @@
+ #endif /* defined(HAVE_PRI) */
+
+ #if defined(HAVE_OPENR2)
+-static const char *dahdi_accept_r2_call_app = "DAHDIAcceptR2Call";
++static const char * const dahdi_accept_r2_call_app = "DAHDIAcceptR2Call";
+
+-static int dahdi_accept_r2_call_exec(struct ast_channel *chan, void *data)
++static int dahdi_accept_r2_call_exec(struct ast_channel *chan, const char *data)
+ {
+ /* data is whether to accept with charge or no charge */
+ openr2_call_mode_t accept_mode;
+@@ -4293,8 +5335,8 @@
+ r2cause = OR2_CAUSE_NORMAL_CLEARING;
+ break;
+ }
+- ast_log(LOG_DEBUG, "dahdi_ast_cause_to_r2_cause returned %d/%s for ast cause %d\n",
+- r2cause, openr2_proto_get_disconnect_string(r2cause), cause);
++ ast_log(LOG_DEBUG, "ast cause %d resulted in openr2 cause %d/%s\n",
++ cause, r2cause, openr2_proto_get_disconnect_string(r2cause));
+ return r2cause;
+ }
+ #endif
+@@ -4315,6 +5357,34 @@
+ return 0;
+ }
+
++ if (analog_lib_handles(p->sig, p->radio, p->oprmode)) {
++ ast_mutex_lock(&p->lock);
++
++ dahdi_confmute(p, 0);
++ restore_gains(p);
++ p->ignoredtmf = 0;
++
++ if (p->bufferoverrideinuse) {
++ /* 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 buffer policy: %s\n", ast->name, strerror(errno));
++ }
++ p->bufferoverrideinuse = 0;
++ }
++
++ res = analog_hangup(p->sig_pvt, ast);
++
++ goto hangup_out;
++ }
++
+ ast_mutex_lock(&p->lock);
+
+ idx = dahdi_get_index(ast, p, 1);
+@@ -4470,7 +5540,7 @@
+ p->dsp = NULL;
+ }
+
+- if (p->faxbuffersinuse) {
++ if (p->bufferoverrideinuse) {
+ /* faxbuffers are in use, revert them */
+ struct dahdi_bufferinfo bi = {
+ .txbufpolicy = p->buf_policy,
+@@ -4481,9 +5551,9 @@
+ 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));
++ ast_log(LOG_WARNING, "Channel '%s' unable to revert buffer policy: %s\n", ast->name, strerror(errno));
+ }
+- p->faxbuffersinuse = 0;
++ p->bufferoverrideinuse = 0;
+ }
+
+ law = DAHDI_LAW_DEFAULT;
+@@ -4623,15 +5693,12 @@
+ default:
+ tone_zone_play_tone(p->subs[SUB_REAL].dfd, -1);
+ }
+- if (p->cidspill)
+- ast_free(p->cidspill);
+ if (p->sig)
+ dahdi_disable_ec(p);
+ x = 0;
+ ast_channel_setoption(ast,AST_OPTION_TONE_VERIFY,&x,sizeof(char),0);
+ ast_channel_setoption(ast,AST_OPTION_TDD,&x,sizeof(char),0);
+ p->didtdd = 0;
+- p->cidspill = NULL;
+ p->callwaitcas = 0;
+ p->callwaiting = p->permcallwaiting;
+ p->hidecallerid = p->permhidecallerid;
+@@ -4667,6 +5734,11 @@
+ p->cidcwexpire = 0;
+ p->oprmode = 0;
+ ast->tech_pvt = NULL;
++hangup_out:
++ if (p->cidspill)
++ ast_free(p->cidspill);
++ p->cidspill = NULL;
++
+ ast_mutex_unlock(&p->lock);
+ ast_module_unref(ast_module_info->self);
+ ast_verb(3, "Hungup '%s'\n", ast->name);
+@@ -4710,6 +5782,13 @@
+ ast_mutex_unlock(&p->lock);
+ return 0;
+ }
++
++ if (analog_lib_handles(p->sig, p->radio, p->oprmode)) {
++ res = analog_answer(p->sig_pvt, ast);
++ ast_mutex_unlock(&p->lock);
++ return res;
++ }
++
+ switch (p->sig) {
+ case SIG_FXSLS:
+ case SIG_FXSGS:
+@@ -4813,6 +5892,66 @@
+ return res;
+ }
+
++static void disable_dtmf_detect(struct dahdi_pvt *p)
++{
++ int val = 0;
++
++ p->ignoredtmf = 1;
++
++ ioctl(p->subs[SUB_REAL].dfd, DAHDI_TONEDETECT, &val);
++
++ if (!p->hardwaredtmf && p->dsp) {
++ p->dsp_features &= ~DSP_FEATURE_DIGIT_DETECT;
++ ast_dsp_set_features(p->dsp, p->dsp_features);
++ }
++}
++
++static void enable_dtmf_detect(struct dahdi_pvt *p)
++{
++ int val = DAHDI_TONEDETECT_ON | DAHDI_TONEDETECT_MUTE;
++
++ if (p->channel == CHAN_PSEUDO)
++ return;
++
++ p->ignoredtmf = 0;
++
++ ioctl(p->subs[SUB_REAL].dfd, DAHDI_TONEDETECT, &val);
++
++ if (!p->hardwaredtmf && p->dsp) {
++ p->dsp_features |= DSP_FEATURE_DIGIT_DETECT;
++ ast_dsp_set_features(p->dsp, p->dsp_features);
++ }
++}
++
++static int dahdi_queryoption(struct ast_channel *chan, int option, void *data, int *datalen)
++{
++ char *cp;
++ struct dahdi_pvt *p = chan->tech_pvt;
++
++ /* all supported options require data */
++ if (!data || (*datalen < 1)) {
++ errno = EINVAL;
++ return -1;
++ }
++
++ switch (option) {
++ case AST_OPTION_DIGIT_DETECT:
++ cp = (char *) data;
++ *cp = p->ignoredtmf ? 0 : 1;
++ ast_debug(1, "Reporting digit detection %sabled on %s\n", *cp ? "en" : "dis", chan->name);
++ break;
++ case AST_OPTION_FAX_DETECT:
++ cp = (char *) data;
++ *cp = (p->callprogress & CALLPROGRESS_FAX) ? 0 : 1;
++ ast_debug(1, "Reporting fax tone detection %sabled on %s\n", *cp ? "en" : "dis", chan->name);
++ break;
++ }
++
++ errno = 0;
++
++ return 0;
++}
++
+ static int dahdi_setoption(struct ast_channel *chan, int option, void *data, int datalen)
+ {
+ char *cp;
+@@ -4995,6 +6134,31 @@
+ dahdi_disable_ec(p);
+ }
+ break;
++ case AST_OPTION_DIGIT_DETECT:
++ cp = (char *) data;
++ ast_debug(1, "%sabling digit detection on %s\n", *cp ? "En" : "Dis", chan->name);
++ if (*cp) {
++ enable_dtmf_detect(p);
++ } else {
++ disable_dtmf_detect(p);
++ }
++ break;
++ case AST_OPTION_FAX_DETECT:
++ cp = (char *) data;
++ if (p->dsp) {
++ ast_debug(1, "%sabling fax tone detection on %s\n", *cp ? "En" : "Dis", chan->name);
++ if (*cp) {
++ p->callprogress |= CALLPROGRESS_FAX;
++ p->dsp_features |= DSP_FEATURE_FAX_DETECT;
++ } else {
++ p->callprogress &= ~CALLPROGRESS_FAX;
++ p->dsp_features &= ~DSP_FEATURE_FAX_DETECT;
++ }
++ ast_dsp_set_features(p->dsp, p->dsp_features);
++ }
++ break;
++ default:
++ return -1;
+ }
+ errno = 0;
+
+@@ -5004,7 +6168,8 @@
+ 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;
+-
++ int res = 0;
++
+ if (!strcasecmp(data, "rxgain")) {
+ ast_mutex_lock(&p->lock);
+ snprintf(buf, len, "%f", p->rxgain);
+@@ -5015,11 +6180,111 @@
+ ast_mutex_unlock(&p->lock);
+ } else {
+ ast_copy_string(buf, "", len);
++ res = -1;
+ }
++
++ return res;
++}
++
++
++static int parse_buffers_policy(const char *parse, int *num_buffers, int *policy)
++{
++ int res;
++ char policy_str[21] = "";
++
++ if ((res = sscanf(parse, "%d,%20s", num_buffers, policy_str)) != 2) {
++ ast_log(LOG_WARNING, "Parsing buffer string '%s' failed.\n", parse);
++ return 1;
++ }
++ if (*num_buffers < 0) {
++ ast_log(LOG_WARNING, "Invalid buffer count given '%d'.\n", *num_buffers);
++ return -1;
++ }
++ if (!strcasecmp(policy_str, "full")) {
++ *policy = DAHDI_POLICY_WHEN_FULL;
++ } else if (!strcasecmp(policy_str, "immediate")) {
++ *policy = DAHDI_POLICY_IMMEDIATE;
++#if defined(HAVE_DAHDI_HALF_FULL)
++ } else if (!strcasecmp(policy_str, "half")) {
++ *policy = DAHDI_POLICY_HALF_FULL;
++#endif
++ } else {
++ ast_log(LOG_WARNING, "Invalid policy name given '%s'.\n", policy_str);
++ return -1;
++ }
++
+ return 0;
+ }
+
++static int dahdi_func_write(struct ast_channel *chan, const char *function, char *data, const char *value)
++{
++ struct dahdi_pvt *p = chan->tech_pvt;
++ int res = 0;
++
++ if (!strcasecmp(data, "buffers")) {
++ int num_bufs, policy;
+
++ if (!(parse_buffers_policy(value, &num_bufs, &policy))) {
++ struct dahdi_bufferinfo bi = {
++ .txbufpolicy = policy,
++ .rxbufpolicy = policy,
++ .bufsize = p->bufsize,
++ .numbufs = num_bufs,
++ };
++ int bpres;
++
++ if ((bpres = ioctl(p->subs[SUB_REAL].dfd, DAHDI_SET_BUFINFO, &bi)) < 0) {
++ ast_log(LOG_WARNING, "Channel '%d' unable to override buffer policy: %s\n", p->channel, strerror(errno));
++ } else {
++ p->bufferoverrideinuse = 1;
++ }
++ } else {
++ res = -1;
++ }
++ } else if (!strcasecmp(data, "echocan_mode")) {
++ if (!strcasecmp(value, "on")) {
++ ast_mutex_lock(&p->lock);
++ dahdi_enable_ec(p);
++ ast_mutex_unlock(&p->lock);
++ } else if (!strcasecmp(value, "off")) {
++ ast_mutex_lock(&p->lock);
++ dahdi_disable_ec(p);
++ ast_mutex_unlock(&p->lock);
++#ifdef HAVE_DAHDI_ECHOCANCEL_FAX_MODE
++ } else if (!strcasecmp(value, "fax")) {
++ int blah = 1;
++
++ ast_mutex_lock(&p->lock);
++ if (!p->echocanon) {
++ dahdi_enable_ec(p);
++ }
++ if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_ECHOCANCEL_FAX_MODE, &blah)) {
++ ast_log(LOG_WARNING, "Unable to place echocan into fax mode on channel %d: %s\n", p->channel, strerror(errno));
++ }
++ ast_mutex_unlock(&p->lock);
++ } else if (!strcasecmp(value, "voice")) {
++ int blah = 0;
++
++ ast_mutex_lock(&p->lock);
++ if (!p->echocanon) {
++ dahdi_enable_ec(p);
++ }
++ if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_ECHOCANCEL_FAX_MODE, &blah)) {
++ ast_log(LOG_WARNING, "Unable to place echocan into voice mode on channel %d: %s\n", p->channel, strerror(errno));
++ }
++ ast_mutex_unlock(&p->lock);
++#endif
++ } else {
++ ast_log(LOG_WARNING, "Unsupported value '%s' provided for '%s' item.\n", value, data);
++ res = -1;
++ }
++ } else {
++ res = -1;
++ }
++
++ return res;
++}
++
+ static void dahdi_unlink(struct dahdi_pvt *slave, struct dahdi_pvt *master, int needlock)
+ {
+ /* Unlink a specific slave or all slaves/masters from a given master */
+@@ -5099,39 +6364,6 @@
+ ast_debug(1, "Making %d slave to master %d at %d\n", slave->channel, master->channel, x);
+ }
+
+-static void disable_dtmf_detect(struct dahdi_pvt *p)
+-{
+- int val;
+-
+- p->ignoredtmf = 1;
+-
+- val = 0;
+- ioctl(p->subs[SUB_REAL].dfd, DAHDI_TONEDETECT, &val);
+-
+- if (!p->hardwaredtmf && p->dsp) {
+- p->dsp_features &= ~DSP_FEATURE_DIGIT_DETECT;
+- ast_dsp_set_features(p->dsp, p->dsp_features);
+- }
+-}
+-
+-static void enable_dtmf_detect(struct dahdi_pvt *p)
+-{
+- int val;
+-
+- if (p->channel == CHAN_PSEUDO)
+- return;
+-
+- p->ignoredtmf = 0;
+-
+- val = DAHDI_TONEDETECT_ON | DAHDI_TONEDETECT_MUTE;
+- ioctl(p->subs[SUB_REAL].dfd, DAHDI_TONEDETECT, &val);
+-
+- if (!p->hardwaredtmf && p->dsp) {
+- p->dsp_features |= DSP_FEATURE_DIGIT_DETECT;
+- ast_dsp_set_features(p->dsp, p->dsp_features);
+- }
+-}
+-
+ static enum ast_bridge_result dahdi_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc, int timeoutms)
+ {
+ struct ast_channel *who;
+@@ -5441,6 +6673,11 @@
+ }
+ if (newchan->_state == AST_STATE_RINGING)
+ dahdi_indicate(newchan, AST_CONTROL_RINGING, NULL, 0);
++
++ if (analog_lib_handles(p->sig, p->radio, p->oprmode)) {
++ analog_fixup(oldchan, newchan, p->sig_pvt);
++ }
++
+ update_conf(p);
+ ast_mutex_unlock(&p->lock);
+ return 0;
+@@ -5476,7 +6713,7 @@
+ return res;
+ }
+
+-static void *ss_thread(void *data);
++static void *analog_ss_thread(void *data);
+
+ static int attempt_transfer(struct dahdi_pvt *p)
+ {
+@@ -5614,7 +6851,7 @@
+ /* Fax tone -- Handle and return NULL */
+ if ((p->callprogress & CALLPROGRESS_FAX) && !p->faxhandled) {
+ /* If faxbuffers are configured, use them for the fax transmission */
+- if (p->usefaxbuffers && !p->faxbuffersinuse) {
++ if (p->usefaxbuffers && !p->bufferoverrideinuse) {
+ struct dahdi_bufferinfo bi = {
+ .txbufpolicy = p->faxbuf_policy,
+ .bufsize = p->bufsize,
+@@ -5623,12 +6860,16 @@
+ 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));
++ ast_log(LOG_WARNING, "Channel '%s' unable to set buffer policy, reason: %s\n", ast->name, strerror(errno));
+ } else {
+- p->faxbuffersinuse = 1;
++ p->bufferoverrideinuse = 1;
+ }
+ }
+ p->faxhandled = 1;
++ p->callprogress &= ~CALLPROGRESS_FAX;
++ p->dsp_features &= ~DSP_FEATURE_FAX_DETECT;
++ ast_dsp_set_features(p->dsp, p->dsp_features);
++ ast_debug(1, "Disabling FAX tone detection on %s after tone received\n", ast->name);
+ if (strcmp(ast->exten, "fax")) {
+ const char *target_context = S_OR(ast->macrocontext, ast->context);
+
+@@ -5736,806 +6977,818 @@
+ }
+
+ switch (res) {
+- case DAHDI_EVENT_EC_DISABLED:
+- ast_verb(3, "Channel %d echo canceler disabled due to CED detection\n", p->channel);
+- p->echocanon = 0;
+- break;
+- case DAHDI_EVENT_BITSCHANGED:
++ case DAHDI_EVENT_EC_DISABLED:
++ ast_verb(3, "Channel %d echo canceler disabled.\n", p->channel);
++ p->echocanon = 0;
++ break;
++#ifdef HAVE_DAHDI_ECHOCANCEL_FAX_MODE
++ case DAHDI_EVENT_TX_CED_DETECTED:
++ ast_verb(3, "Channel %d detected a CED tone towards the network.\n", p->channel);
++ break;
++ case DAHDI_EVENT_RX_CED_DETECTED:
++ ast_verb(3, "Channel %d detected a CED tone from the network.\n", p->channel);
++ break;
++ case DAHDI_EVENT_EC_NLP_DISABLED:
++ ast_verb(3, "Channel %d echo canceler disabled its NLP.\n", p->channel);
++ break;
++ case DAHDI_EVENT_EC_NLP_ENABLED:
++ ast_verb(3, "Channel %d echo canceler enabled its NLP.\n", p->channel);
++ break;
++#endif
++ case DAHDI_EVENT_BITSCHANGED:
+ #ifdef HAVE_OPENR2
+- if (p->sig != SIG_MFCR2) {
+- ast_log(LOG_WARNING, "Recieved bits changed on %s signalling?\n", sig2str(p->sig));
+- } else {
+- ast_log(LOG_DEBUG, "bits changed in chan %d\n", p->channel);
+- openr2_chan_handle_cas(p->r2chan);
+- }
++ if (p->sig != SIG_MFCR2) {
++ ast_log(LOG_WARNING, "Recieved bits changed on %s signalling?\n", sig2str(p->sig));
++ } else {
++ ast_log(LOG_DEBUG, "bits changed in chan %d\n", p->channel);
++ openr2_chan_handle_cas(p->r2chan);
++ }
+ #else
+- ast_log(LOG_WARNING, "Recieved bits changed on %s signalling?\n", sig2str(p->sig));
++ ast_log(LOG_WARNING, "Recieved bits changed on %s signalling?\n", sig2str(p->sig));
+ #endif
+- case DAHDI_EVENT_PULSE_START:
+- /* 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);
++ case DAHDI_EVENT_PULSE_START:
++ /* 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;
++ case DAHDI_EVENT_DIALCOMPLETE:
++#ifdef HAVE_OPENR2
++ if ((p->sig & SIG_MFCR2) && p->r2chan && ast->_state != AST_STATE_UP) {
++ /* we don't need to do anything for this event for R2 signaling
++ if the call is being setup */
+ break;
+- case DAHDI_EVENT_DIALCOMPLETE:
+-#ifdef HAVE_OPENR2
+- if ((p->sig & SIG_MFCR2) && p->r2chan && ast->_state != AST_STATE_UP) {
+- /* we don't need to do anything for this event for R2 signaling
+- if the call is being setup */
+- break;
+- }
++ }
+ #endif
+- if (p->inalarm) break;
+- if ((p->radio || (p->oprmode < 0))) break;
+- if (ioctl(p->subs[idx].dfd,DAHDI_DIALING,&x) == -1) {
+- ast_log(LOG_DEBUG, "DAHDI_DIALING ioctl failed on %s: %s\n",ast->name, strerror(errno));
+- return NULL;
+- }
+- if (!x) { /* if not still dialing in driver */
+- dahdi_enable_ec(p);
+- if (p->echobreak) {
+- dahdi_train_ec(p);
+- ast_copy_string(p->dop.dialstr, p->echorest, sizeof(p->dop.dialstr));
+- p->dop.op = DAHDI_DIAL_OP_REPLACE;
+- res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_DIAL, &p->dop);
+- p->echobreak = 0;
+- } else {
+- p->dialing = 0;
+- if ((mysig == SIG_E911) || (mysig == SIG_FGC_CAMA) || (mysig == SIG_FGC_CAMAMF)) {
+- /* if thru with dialing after offhook */
+- if (ast->_state == AST_STATE_DIALING_OFFHOOK) {
+- ast_setstate(ast, AST_STATE_UP);
+- p->subs[idx].f.frametype = AST_FRAME_CONTROL;
+- p->subs[idx].f.subclass = AST_CONTROL_ANSWER;
+- break;
+- } else { /* if to state wait for offhook to dial rest */
+- /* we now wait for off hook */
+- ast_setstate(ast,AST_STATE_DIALING_OFFHOOK);
+- }
++ if (p->inalarm) break;
++ if ((p->radio || (p->oprmode < 0))) break;
++ if (ioctl(p->subs[idx].dfd,DAHDI_DIALING,&x) == -1) {
++ ast_log(LOG_DEBUG, "DAHDI_DIALING ioctl failed on %s: %s\n",ast->name, strerror(errno));
++ return NULL;
++ }
++ if (!x) { /* if not still dialing in driver */
++ dahdi_enable_ec(p);
++ if (p->echobreak) {
++ dahdi_train_ec(p);
++ ast_copy_string(p->dop.dialstr, p->echorest, sizeof(p->dop.dialstr));
++ p->dop.op = DAHDI_DIAL_OP_REPLACE;
++ res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_DIAL, &p->dop);
++ p->echobreak = 0;
++ } else {
++ p->dialing = 0;
++ if ((mysig == SIG_E911) || (mysig == SIG_FGC_CAMA) || (mysig == SIG_FGC_CAMAMF)) {
++ /* if thru with dialing after offhook */
++ if (ast->_state == AST_STATE_DIALING_OFFHOOK) {
++ ast_setstate(ast, AST_STATE_UP);
++ p->subs[idx].f.frametype = AST_FRAME_CONTROL;
++ p->subs[idx].f.subclass = AST_CONTROL_ANSWER;
++ break;
++ } else { /* if to state wait for offhook to dial rest */
++ /* we now wait for off hook */
++ ast_setstate(ast,AST_STATE_DIALING_OFFHOOK);
+ }
+- 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)))) {
+- ast_setstate(ast, AST_STATE_RINGING);
+- } else if (!p->answeronpolarityswitch) {
+- ast_setstate(ast, AST_STATE_UP);
+- p->subs[idx].f.frametype = AST_FRAME_CONTROL;
+- p->subs[idx].f.subclass = AST_CONTROL_ANSWER;
+- /* If aops=0 and hops=1, this is necessary */
+- p->polarity = POLARITY_REV;
+- } else {
+- /* Start clean, so we can catch the change to REV polarity when party answers */
+- p->polarity = POLARITY_IDLE;
+- }
++ }
++ 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)))) {
++ ast_setstate(ast, AST_STATE_RINGING);
++ } else if (!p->answeronpolarityswitch) {
++ ast_setstate(ast, AST_STATE_UP);
++ p->subs[idx].f.frametype = AST_FRAME_CONTROL;
++ p->subs[idx].f.subclass = AST_CONTROL_ANSWER;
++ /* If aops=0 and hops=1, this is necessary */
++ p->polarity = POLARITY_REV;
++ } else {
++ /* Start clean, so we can catch the change to REV polarity when party answers */
++ p->polarity = POLARITY_IDLE;
+ }
+ }
+ }
+- break;
+- case DAHDI_EVENT_ALARM:
++ }
++ break;
++ case DAHDI_EVENT_ALARM:
+ #ifdef HAVE_PRI
+- if ((p->sig == SIG_PRI) || (p->sig == SIG_BRI) || (p->sig == SIG_BRI_PTMP)) {
+- if (!p->pri || !p->pri->pri || (pri_get_timer(p->pri->pri, PRI_TIMER_T309) < 0)) {
+- /* T309 is not enabled : hangup calls when alarm occurs */
+- if (p->call) {
+- if (p->pri && p->pri->pri) {
+- if (!pri_grab(p, p->pri)) {
+- pri_hangup(p->pri->pri, p->call, -1);
+- pri_destroycall(p->pri->pri, p->call);
+- p->call = NULL;
+- pri_rel(p->pri);
+- } else
+- ast_log(LOG_WARNING, "Failed to grab PRI!\n");
++ if ((p->sig == SIG_PRI) || (p->sig == SIG_BRI) || (p->sig == SIG_BRI_PTMP)) {
++ if (!p->pri || !p->pri->pri || (pri_get_timer(p->pri->pri, PRI_TIMER_T309) < 0)) {
++ /* T309 is not enabled : hangup calls when alarm occurs */
++ if (p->call) {
++ if (p->pri && p->pri->pri) {
++ if (!pri_grab(p, p->pri)) {
++ pri_hangup(p->pri->pri, p->call, -1);
++ pri_destroycall(p->pri->pri, p->call);
++ p->call = NULL;
++ pri_rel(p->pri);
+ } else
+- ast_log(LOG_WARNING, "The PRI Call has not been destroyed\n");
+- }
+- if (p->owner)
+- p->owner->_softhangup |= AST_SOFTHANGUP_DEV;
++ ast_log(LOG_WARNING, "Failed to grab PRI!\n");
++ } else
++ ast_log(LOG_WARNING, "The PRI Call has not been destroyed\n");
+ }
++ if (p->owner)
++ p->owner->_softhangup |= AST_SOFTHANGUP_DEV;
+ }
+- if (p->bearer)
+- p->bearer->inalarm = 1;
+- else
++ }
++ if (p->bearer)
++ p->bearer->inalarm = 1;
++ else
+ #endif
+- p->inalarm = 1;
+- res = get_alarms(p);
+- handle_alarms(p, res);
++ p->inalarm = 1;
++ res = get_alarms(p);
++ handle_alarms(p, res);
+ #ifdef HAVE_PRI
+- if (!p->pri || !p->pri->pri || pri_get_timer(p->pri->pri, PRI_TIMER_T309) < 0) {
+- /* fall through intentionally */
+- } else {
+- break;
+- }
++ if (!p->pri || !p->pri->pri || pri_get_timer(p->pri->pri, PRI_TIMER_T309) < 0) {
++ /* fall through intentionally */
++ } else {
++ break;
++ }
+ #endif
+ #ifdef HAVE_SS7
+- if (p->sig == SIG_SS7)
+- break;
++ if (p->sig == SIG_SS7)
++ break;
+ #endif
+ #ifdef HAVE_OPENR2
+- if (p->sig == SIG_MFCR2)
+- break;
++ if (p->sig == SIG_MFCR2)
++ break;
+ #endif
+- case DAHDI_EVENT_ONHOOK:
+- if (p->radio) {
+- p->subs[idx].f.frametype = AST_FRAME_CONTROL;
+- p->subs[idx].f.subclass = AST_CONTROL_RADIO_UNKEY;
+- break;
+- }
+- if (p->oprmode < 0)
++ case DAHDI_EVENT_ONHOOK:
++ if (p->radio) {
++ p->subs[idx].f.frametype = AST_FRAME_CONTROL;
++ p->subs[idx].f.subclass = AST_CONTROL_RADIO_UNKEY;
++ break;
++ }
++ if (p->oprmode < 0)
++ {
++ if (p->oprmode != -1) break;
++ if ((p->sig == SIG_FXOLS) || (p->sig == SIG_FXOKS) || (p->sig == SIG_FXOGS))
+ {
+- if (p->oprmode != -1) break;
+- if ((p->sig == SIG_FXOLS) || (p->sig == SIG_FXOKS) || (p->sig == SIG_FXOGS))
+- {
+- /* Make sure it starts ringing */
+- dahdi_set_hook(p->subs[SUB_REAL].dfd, DAHDI_RINGOFF);
+- dahdi_set_hook(p->subs[SUB_REAL].dfd, DAHDI_RING);
+- save_conference(p->oprpeer);
+- tone_zone_play_tone(p->oprpeer->subs[SUB_REAL].dfd, DAHDI_TONE_RINGTONE);
+- }
+- break;
++ /* Make sure it starts ringing */
++ dahdi_set_hook(p->subs[SUB_REAL].dfd, DAHDI_RINGOFF);
++ dahdi_set_hook(p->subs[SUB_REAL].dfd, DAHDI_RING);
++ save_conference(p->oprpeer);
++ tone_zone_play_tone(p->oprpeer->subs[SUB_REAL].dfd, DAHDI_TONE_RINGTONE);
+ }
+- switch (p->sig) {
+- case SIG_FXOLS:
+- 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) {
+- /* The normal line was hung up */
+- if (p->subs[SUB_CALLWAIT].owner) {
+- /* 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);
++ break;
++ }
++ switch (p->sig) {
++ case SIG_FXOLS:
++ 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) {
++ /* The normal line was hung up */
++ if (p->subs[SUB_CALLWAIT].owner) {
++ /* 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);
+ #if 0
+- p->subs[idx].needanswer = 0;
+- p->subs[idx].needringing = 0;
++ p->subs[idx].needanswer = 0;
++ p->subs[idx].needringing = 0;
+ #endif
+- p->callwaitingrepeat = 0;
+- p->cidcwexpire = 0;
+- p->owner = NULL;
+- /* Don't start streaming audio yet if the incoming call isn't up yet */
+- if (p->subs[SUB_REAL].owner->_state != AST_STATE_UP)
+- p->dialing = 1;
+- dahdi_ring_phone(p);
+- } else if (p->subs[SUB_THREEWAY].owner) {
+- unsigned int mssinceflash;
+- /* Here we have to retain the lock on both the main channel, the 3-way channel, and
+- the private structure -- not especially easy or clean */
+- while (p->subs[SUB_THREEWAY].owner && ast_channel_trylock(p->subs[SUB_THREEWAY].owner)) {
+- /* Yuck, didn't get the lock on the 3-way, gotta release everything and re-grab! */
+- DLA_UNLOCK(&p->lock);
+- CHANNEL_DEADLOCK_AVOIDANCE(ast);
+- /* We can grab ast and p in that order, without worry. We should make sure
+- nothing seriously bad has happened though like some sort of bizarre double
+- masquerade! */
+- DLA_LOCK(&p->lock);
+- if (p->owner != ast) {
+- ast_log(LOG_WARNING, "This isn't good...\n");
+- return NULL;
+- }
+- }
+- if (!p->subs[SUB_THREEWAY].owner) {
+- ast_log(LOG_NOTICE, "Whoa, threeway disappeared kinda randomly.\n");
++ p->callwaitingrepeat = 0;
++ p->cidcwexpire = 0;
++ p->owner = NULL;
++ /* Don't start streaming audio yet if the incoming call isn't up yet */
++ if (p->subs[SUB_REAL].owner->_state != AST_STATE_UP)
++ p->dialing = 1;
++ dahdi_ring_phone(p);
++ } else if (p->subs[SUB_THREEWAY].owner) {
++ unsigned int mssinceflash;
++ /* Here we have to retain the lock on both the main channel, the 3-way channel, and
++ the private structure -- not especially easy or clean */
++ while (p->subs[SUB_THREEWAY].owner && ast_channel_trylock(p->subs[SUB_THREEWAY].owner)) {
++ /* Yuck, didn't get the lock on the 3-way, gotta release everything and re-grab! */
++ DLA_UNLOCK(&p->lock);
++ CHANNEL_DEADLOCK_AVOIDANCE(ast);
++ /* We can grab ast and p in that order, without worry. We should make sure
++ nothing seriously bad has happened though like some sort of bizarre double
++ masquerade! */
++ DLA_LOCK(&p->lock);
++ if (p->owner != ast) {
++ ast_log(LOG_WARNING, "This isn't good...\n");
+ return NULL;
+ }
+- 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
+- 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);
+- p->subs[SUB_THREEWAY].owner->_softhangup |= AST_SOFTHANGUP_DEV;
+- ast_debug(1, "Looks like a bounced flash, hanging up both calls on %d\n", p->channel);
+- ast_channel_unlock(p->subs[SUB_THREEWAY].owner);
+- } else if ((ast->pbx) || (ast->_state == AST_STATE_UP)) {
+- if (p->transfer) {
+- /* In any case this isn't a threeway call anymore */
+- p->subs[SUB_REAL].inthreeway = 0;
+- p->subs[SUB_THREEWAY].inthreeway = 0;
+- /* Only attempt transfer if the phone is ringing; why transfer to busy tone eh? */
+- if (!p->transfertobusy && ast->_state == AST_STATE_BUSY) {
+- ast_channel_unlock(p->subs[SUB_THREEWAY].owner);
+- /* Swap subs and dis-own channel */
+- swap_subs(p, SUB_THREEWAY, SUB_REAL);
+- p->owner = NULL;
+- /* Ring the phone */
+- dahdi_ring_phone(p);
+- } else {
+- if ((res = attempt_transfer(p)) < 0) {
+- p->subs[SUB_THREEWAY].owner->_softhangup |= AST_SOFTHANGUP_DEV;
+- if (p->subs[SUB_THREEWAY].owner)
+- ast_channel_unlock(p->subs[SUB_THREEWAY].owner);
+- } else if (res) {
+- /* Don't actually hang up at this point */
+- if (p->subs[SUB_THREEWAY].owner)
+- ast_channel_unlock(p->subs[SUB_THREEWAY].owner);
+- break;
+- }
++ }
++ if (!p->subs[SUB_THREEWAY].owner) {
++ ast_log(LOG_NOTICE, "Whoa, threeway disappeared kinda randomly.\n");
++ return NULL;
++ }
++ 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
++ 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);
++ p->subs[SUB_THREEWAY].owner->_softhangup |= AST_SOFTHANGUP_DEV;
++ ast_debug(1, "Looks like a bounced flash, hanging up both calls on %d\n", p->channel);
++ ast_channel_unlock(p->subs[SUB_THREEWAY].owner);
++ } else if ((ast->pbx) || (ast->_state == AST_STATE_UP)) {
++ if (p->transfer) {
++ /* In any case this isn't a threeway call anymore */
++ p->subs[SUB_REAL].inthreeway = 0;
++ p->subs[SUB_THREEWAY].inthreeway = 0;
++ /* Only attempt transfer if the phone is ringing; why transfer to busy tone eh? */
++ if (!p->transfertobusy && ast->_state == AST_STATE_BUSY) {
++ ast_channel_unlock(p->subs[SUB_THREEWAY].owner);
++ /* Swap subs and dis-own channel */
++ swap_subs(p, SUB_THREEWAY, SUB_REAL);
++ p->owner = NULL;
++ /* Ring the phone */
++ dahdi_ring_phone(p);
++ } else {
++ if ((res = attempt_transfer(p)) < 0) {
++ p->subs[SUB_THREEWAY].owner->_softhangup |= AST_SOFTHANGUP_DEV;
++ if (p->subs[SUB_THREEWAY].owner)
++ ast_channel_unlock(p->subs[SUB_THREEWAY].owner);
++ } else if (res) {
++ /* Don't actually hang up at this point */
++ if (p->subs[SUB_THREEWAY].owner)
++ ast_channel_unlock(p->subs[SUB_THREEWAY].owner);
++ break;
+ }
+- } else {
+- p->subs[SUB_THREEWAY].owner->_softhangup |= AST_SOFTHANGUP_DEV;
+- if (p->subs[SUB_THREEWAY].owner)
+- ast_channel_unlock(p->subs[SUB_THREEWAY].owner);
+ }
+ } else {
+- ast_channel_unlock(p->subs[SUB_THREEWAY].owner);
+- /* Swap subs and dis-own channel */
+- swap_subs(p, SUB_THREEWAY, SUB_REAL);
+- p->owner = NULL;
+- /* Ring the phone */
+- dahdi_ring_phone(p);
++ p->subs[SUB_THREEWAY].owner->_softhangup |= AST_SOFTHANGUP_DEV;
++ if (p->subs[SUB_THREEWAY].owner)
++ ast_channel_unlock(p->subs[SUB_THREEWAY].owner);
+ }
++ } else {
++ ast_channel_unlock(p->subs[SUB_THREEWAY].owner);
++ /* Swap subs and dis-own channel */
++ swap_subs(p, SUB_THREEWAY, SUB_REAL);
++ p->owner = NULL;
++ /* Ring the phone */
++ dahdi_ring_phone(p);
+ }
+- } else {
+- ast_log(LOG_WARNING, "Got a hangup and my index is %d?\n", idx);
+ }
+- /* Fall through */
+- default:
+- dahdi_disable_ec(p);
+- return NULL;
++ } else {
++ ast_log(LOG_WARNING, "Got a hangup and my index is %d?\n", idx);
+ }
+- break;
+- case DAHDI_EVENT_RINGOFFHOOK:
+- if (p->inalarm) break;
+- if (p->oprmode < 0)
++ /* Fall through */
++ default:
++ dahdi_disable_ec(p);
++ return NULL;
++ }
++ break;
++ case DAHDI_EVENT_RINGOFFHOOK:
++ if (p->inalarm) break;
++ if (p->oprmode < 0)
++ {
++ if ((p->sig == SIG_FXOLS) || (p->sig == SIG_FXOKS) || (p->sig == SIG_FXOGS))
+ {
+- if ((p->sig == SIG_FXOLS) || (p->sig == SIG_FXOKS) || (p->sig == SIG_FXOGS))
+- {
+- /* Make sure it stops ringing */
+- dahdi_set_hook(p->subs[SUB_REAL].dfd, DAHDI_RINGOFF);
+- tone_zone_play_tone(p->oprpeer->subs[SUB_REAL].dfd, -1);
+- restore_conference(p->oprpeer);
+- }
+- break;
++ /* Make sure it stops ringing */
++ dahdi_set_hook(p->subs[SUB_REAL].dfd, DAHDI_RINGOFF);
++ tone_zone_play_tone(p->oprpeer->subs[SUB_REAL].dfd, -1);
++ restore_conference(p->oprpeer);
+ }
+- if (p->radio)
+- {
+- p->subs[idx].f.frametype = AST_FRAME_CONTROL;
+- p->subs[idx].f.subclass = AST_CONTROL_RADIO_KEY;
+- break;
+- }
+- /* for E911, its supposed to wait for offhook then dial
+- the second half of the dial string */
+- if (((mysig == SIG_E911) || (mysig == SIG_FGC_CAMA) || (mysig == SIG_FGC_CAMAMF)) && (ast->_state == AST_STATE_DIALING_OFFHOOK)) {
+- c = strchr(p->dialdest, '/');
+- if (c)
+- c++;
+- else
+- c = p->dialdest;
+- if (*c) snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), "M*0%s#", c);
+- else ast_copy_string(p->dop.dialstr,"M*2#", sizeof(p->dop.dialstr));
+- if (strlen(p->dop.dialstr) > 4) {
+- memset(p->echorest, 'w', sizeof(p->echorest) - 1);
+- strcpy(p->echorest + (p->echotraining / 401) + 1, p->dop.dialstr + strlen(p->dop.dialstr) - 2);
+- p->echorest[sizeof(p->echorest) - 1] = '\0';
+- p->echobreak = 1;
+- p->dop.dialstr[strlen(p->dop.dialstr)-2] = '\0';
+- } else
+- p->echobreak = 0;
+- if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_DIAL, &p->dop)) {
+- int saveerr = errno;
++ break;
++ }
++ if (p->radio)
++ {
++ p->subs[idx].f.frametype = AST_FRAME_CONTROL;
++ p->subs[idx].f.subclass = AST_CONTROL_RADIO_KEY;
++ break;
++ }
++ /* for E911, its supposed to wait for offhook then dial
++ the second half of the dial string */
++ if (((mysig == SIG_E911) || (mysig == SIG_FGC_CAMA) || (mysig == SIG_FGC_CAMAMF)) && (ast->_state == AST_STATE_DIALING_OFFHOOK)) {
++ c = strchr(p->dialdest, '/');
++ if (c)
++ c++;
++ else
++ c = p->dialdest;
++ if (*c) snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), "M*0%s#", c);
++ else ast_copy_string(p->dop.dialstr,"M*2#", sizeof(p->dop.dialstr));
++ if (strlen(p->dop.dialstr) > 4) {
++ memset(p->echorest, 'w', sizeof(p->echorest) - 1);
++ strcpy(p->echorest + (p->echotraining / 401) + 1, p->dop.dialstr + strlen(p->dop.dialstr) - 2);
++ p->echorest[sizeof(p->echorest) - 1] = '\0';
++ p->echobreak = 1;
++ p->dop.dialstr[strlen(p->dop.dialstr)-2] = '\0';
++ } else
++ p->echobreak = 0;
++ if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_DIAL, &p->dop)) {
++ int saveerr = errno;
+
+- x = DAHDI_ONHOOK;
+- ioctl(p->subs[SUB_REAL].dfd, DAHDI_HOOK, &x);
+- ast_log(LOG_WARNING, "Dialing failed on channel %d: %s\n", p->channel, strerror(saveerr));
+- return NULL;
+- }
+- p->dialing = 1;
+- return &p->subs[idx].f;
+- }
+- switch (p->sig) {
+- case SIG_FXOLS:
+- case SIG_FXOGS:
+- case SIG_FXOKS:
+- p->fxsoffhookstate = 1;
+- switch (ast->_state) {
+- case AST_STATE_RINGING:
+- dahdi_enable_ec(p);
+- dahdi_train_ec(p);
+- p->subs[idx].f.frametype = AST_FRAME_CONTROL;
+- p->subs[idx].f.subclass = AST_CONTROL_ANSWER;
+- /* Make sure it stops ringing */
+- dahdi_set_hook(p->subs[idx].dfd, DAHDI_OFFHOOK);
+- ast_debug(1, "channel %d answered\n", p->channel);
+- if (p->cidspill) {
+- /* Cancel any running CallerID spill */
+- ast_free(p->cidspill);
+- p->cidspill = NULL;
+- }
+- p->dialing = 0;
+- p->callwaitcas = 0;
+- if (p->confirmanswer) {
+- /* Ignore answer if "confirm answer" is enabled */
+- p->subs[idx].f.frametype = AST_FRAME_NULL;
+- p->subs[idx].f.subclass = 0;
+- } else if (!ast_strlen_zero(p->dop.dialstr)) {
+- /* nick@dccinc.com 4/3/03 - fxo should be able to do deferred dialing */
+- 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: %s\n", p->channel, strerror(errno));
+- p->dop.dialstr[0] = '\0';
+- return NULL;
+- } else {
+- ast_debug(1, "Sent FXO deferred digit string: %s\n", p->dop.dialstr);
+- p->subs[idx].f.frametype = AST_FRAME_NULL;
+- p->subs[idx].f.subclass = 0;
+- p->dialing = 1;
+- }
+- p->dop.dialstr[0] = '\0';
+- ast_setstate(ast, AST_STATE_DIALING);
+- } else
+- ast_setstate(ast, AST_STATE_UP);
+- return &p->subs[idx].f;
+- case AST_STATE_DOWN:
+- ast_setstate(ast, AST_STATE_RING);
+- ast->rings = 1;
+- p->subs[idx].f.frametype = AST_FRAME_CONTROL;
+- p->subs[idx].f.subclass = AST_CONTROL_OFFHOOK;
+- ast_debug(1, "channel %d picked up\n", p->channel);
+- return &p->subs[idx].f;
+- case AST_STATE_UP:
+- /* Make sure it stops ringing */
+- dahdi_set_hook(p->subs[idx].dfd, DAHDI_OFFHOOK);
+- /* Okay -- probably call waiting*/
+- if (ast_bridged_channel(p->owner))
+- ast_queue_control(p->owner, AST_CONTROL_UNHOLD);
+- p->subs[idx].needunhold = 1;
+- break;
+- case AST_STATE_RESERVED:
+- /* Start up dialtone */
+- if (has_voicemail(p))
+- res = tone_zone_play_tone(p->subs[SUB_REAL].dfd, DAHDI_TONE_STUTTER);
+- else
+- res = tone_zone_play_tone(p->subs[SUB_REAL].dfd, DAHDI_TONE_DIALTONE);
+- break;
+- default:
+- ast_log(LOG_WARNING, "FXO phone off hook in weird state %d??\n", ast->_state);
++ x = DAHDI_ONHOOK;
++ ioctl(p->subs[SUB_REAL].dfd, DAHDI_HOOK, &x);
++ ast_log(LOG_WARNING, "Dialing failed on channel %d: %s\n", p->channel, strerror(saveerr));
++ return NULL;
+ }
+- break;
+- case SIG_FXSLS:
+- case SIG_FXSGS:
+- case SIG_FXSKS:
+- if (ast->_state == AST_STATE_RING) {
+- p->ringt = p->ringt_base;
++ p->dialing = 1;
++ return &p->subs[idx].f;
++ }
++ switch (p->sig) {
++ case SIG_FXOLS:
++ case SIG_FXOGS:
++ case SIG_FXOKS:
++ p->fxsoffhookstate = 1;
++ switch (ast->_state) {
++ case AST_STATE_RINGING:
++ dahdi_enable_ec(p);
++ dahdi_train_ec(p);
++ p->subs[idx].f.frametype = AST_FRAME_CONTROL;
++ p->subs[idx].f.subclass = AST_CONTROL_ANSWER;
++ /* Make sure it stops ringing */
++ dahdi_set_hook(p->subs[idx].dfd, DAHDI_OFFHOOK);
++ ast_debug(1, "channel %d answered\n", p->channel);
++ if (p->cidspill) {
++ /* Cancel any running CallerID spill */
++ ast_free(p->cidspill);
++ p->cidspill = NULL;
+ }
+-
+- /* 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",
+- p->polarity);
+- p->polarity = POLARITY_IDLE;
+-
+- /* Fall through */
+- case SIG_EM:
+- case SIG_EM_E1:
+- case SIG_EMWINK:
+- case SIG_FEATD:
+- case SIG_FEATDMF:
+- case SIG_FEATDMF_TA:
+- case SIG_E911:
+- case SIG_FGC_CAMA:
+- case SIG_FGC_CAMAMF:
+- case SIG_FEATB:
+- case SIG_SF:
+- case SIG_SFWINK:
+- case SIG_SF_FEATD:
+- case SIG_SF_FEATDMF:
+- case SIG_SF_FEATB:
+- if (ast->_state == AST_STATE_PRERING)
+- ast_setstate(ast, AST_STATE_RING);
+- if ((ast->_state == AST_STATE_DOWN) || (ast->_state == AST_STATE_RING)) {
+- ast_debug(1, "Ring detected\n");
+- p->subs[idx].f.frametype = AST_FRAME_CONTROL;
+- p->subs[idx].f.subclass = AST_CONTROL_RING;
+- } else if (p->outgoing && ((ast->_state == AST_STATE_RINGING) || (ast->_state == AST_STATE_DIALING))) {
+- ast_debug(1, "Line answered\n");
+- if (p->confirmanswer) {
++ p->dialing = 0;
++ p->callwaitcas = 0;
++ if (p->confirmanswer) {
++ /* Ignore answer if "confirm answer" is enabled */
++ p->subs[idx].f.frametype = AST_FRAME_NULL;
++ p->subs[idx].f.subclass = 0;
++ } else if (!ast_strlen_zero(p->dop.dialstr)) {
++ /* nick@dccinc.com 4/3/03 - fxo should be able to do deferred dialing */
++ 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: %s\n", p->channel, strerror(errno));
++ p->dop.dialstr[0] = '\0';
++ return NULL;
++ } else {
++ ast_debug(1, "Sent FXO deferred digit string: %s\n", p->dop.dialstr);
+ p->subs[idx].f.frametype = AST_FRAME_NULL;
+ p->subs[idx].f.subclass = 0;
+- } else {
+- p->subs[idx].f.frametype = AST_FRAME_CONTROL;
+- p->subs[idx].f.subclass = AST_CONTROL_ANSWER;
+- ast_setstate(ast, AST_STATE_UP);
++ p->dialing = 1;
+ }
+- } else if (ast->_state != AST_STATE_RING)
+- ast_log(LOG_WARNING, "Ring/Off-hook in strange state %d on channel %d\n", ast->_state, p->channel);
++ p->dop.dialstr[0] = '\0';
++ ast_setstate(ast, AST_STATE_DIALING);
++ } else
++ ast_setstate(ast, AST_STATE_UP);
++ return &p->subs[idx].f;
++ case AST_STATE_DOWN:
++ ast_setstate(ast, AST_STATE_RING);
++ ast->rings = 1;
++ p->subs[idx].f.frametype = AST_FRAME_CONTROL;
++ p->subs[idx].f.subclass = AST_CONTROL_OFFHOOK;
++ ast_debug(1, "channel %d picked up\n", p->channel);
++ return &p->subs[idx].f;
++ case AST_STATE_UP:
++ /* Make sure it stops ringing */
++ dahdi_set_hook(p->subs[idx].dfd, DAHDI_OFFHOOK);
++ /* Okay -- probably call waiting*/
++ if (ast_bridged_channel(p->owner))
++ ast_queue_control(p->owner, AST_CONTROL_UNHOLD);
++ p->subs[idx].needunhold = 1;
+ break;
++ case AST_STATE_RESERVED:
++ /* Start up dialtone */
++ if (has_voicemail(p))
++ res = tone_zone_play_tone(p->subs[SUB_REAL].dfd, DAHDI_TONE_STUTTER);
++ else
++ res = tone_zone_play_tone(p->subs[SUB_REAL].dfd, DAHDI_TONE_DIALTONE);
++ break;
+ default:
+- ast_log(LOG_WARNING, "Don't know how to handle ring/off hook for signalling %d\n", p->sig);
++ ast_log(LOG_WARNING, "FXO phone off hook in weird state %d??\n", ast->_state);
+ }
+ break;
+- case DAHDI_EVENT_RINGBEGIN:
+- switch (p->sig) {
+- case SIG_FXSLS:
+- case SIG_FXSGS:
+- case SIG_FXSKS:
+- if (ast->_state == AST_STATE_RING) {
+- p->ringt = p->ringt_base;
++ case SIG_FXSLS:
++ case SIG_FXSGS:
++ case SIG_FXSKS:
++ if (ast->_state == AST_STATE_RING) {
++ p->ringt = p->ringt_base;
++ }
++
++ /* 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",
++ p->polarity);
++ p->polarity = POLARITY_IDLE;
++
++ /* Fall through */
++ case SIG_EM:
++ case SIG_EM_E1:
++ case SIG_EMWINK:
++ case SIG_FEATD:
++ case SIG_FEATDMF:
++ case SIG_FEATDMF_TA:
++ case SIG_E911:
++ case SIG_FGC_CAMA:
++ case SIG_FGC_CAMAMF:
++ case SIG_FEATB:
++ case SIG_SF:
++ case SIG_SFWINK:
++ case SIG_SF_FEATD:
++ case SIG_SF_FEATDMF:
++ case SIG_SF_FEATB:
++ if (ast->_state == AST_STATE_PRERING)
++ ast_setstate(ast, AST_STATE_RING);
++ if ((ast->_state == AST_STATE_DOWN) || (ast->_state == AST_STATE_RING)) {
++ ast_debug(1, "Ring detected\n");
++ p->subs[idx].f.frametype = AST_FRAME_CONTROL;
++ p->subs[idx].f.subclass = AST_CONTROL_RING;
++ } else if (p->outgoing && ((ast->_state == AST_STATE_RINGING) || (ast->_state == AST_STATE_DIALING))) {
++ ast_debug(1, "Line answered\n");
++ if (p->confirmanswer) {
++ p->subs[idx].f.frametype = AST_FRAME_NULL;
++ p->subs[idx].f.subclass = 0;
++ } else {
++ p->subs[idx].f.frametype = AST_FRAME_CONTROL;
++ p->subs[idx].f.subclass = AST_CONTROL_ANSWER;
++ ast_setstate(ast, AST_STATE_UP);
+ }
+- break;
+- }
++ } else if (ast->_state != AST_STATE_RING)
++ ast_log(LOG_WARNING, "Ring/Off-hook in strange state %d on channel %d\n", ast->_state, p->channel);
+ break;
+- case DAHDI_EVENT_RINGEROFF:
+- if (p->inalarm) break;
+- if ((p->radio || (p->oprmode < 0))) break;
+- ast->rings++;
+- if ((ast->rings > p->cidrings) && (p->cidspill)) {
+- ast_log(LOG_WARNING, "Didn't finish Caller-ID spill. Cancelling.\n");
+- ast_free(p->cidspill);
+- p->cidspill = NULL;
+- p->callwaitcas = 0;
++ default:
++ ast_log(LOG_WARNING, "Don't know how to handle ring/off hook for signalling %d\n", p->sig);
++ }
++ break;
++ case DAHDI_EVENT_RINGBEGIN:
++ switch (p->sig) {
++ case SIG_FXSLS:
++ case SIG_FXSGS:
++ case SIG_FXSKS:
++ if (ast->_state == AST_STATE_RING) {
++ p->ringt = p->ringt_base;
+ }
+- p->subs[idx].f.frametype = AST_FRAME_CONTROL;
+- p->subs[idx].f.subclass = AST_CONTROL_RINGING;
+ break;
+- case DAHDI_EVENT_RINGERON:
+- break;
+- case DAHDI_EVENT_NOALARM:
+- p->inalarm = 0;
++ }
++ break;
++ case DAHDI_EVENT_RINGEROFF:
++ if (p->inalarm) break;
++ if ((p->radio || (p->oprmode < 0))) break;
++ ast->rings++;
++ if ((ast->rings > p->cidrings) && (p->cidspill)) {
++ ast_log(LOG_WARNING, "Didn't finish Caller-ID spill. Cancelling.\n");
++ ast_free(p->cidspill);
++ p->cidspill = NULL;
++ p->callwaitcas = 0;
++ }
++ p->subs[idx].f.frametype = AST_FRAME_CONTROL;
++ p->subs[idx].f.subclass = AST_CONTROL_RINGING;
++ break;
++ case DAHDI_EVENT_RINGERON:
++ break;
++ case DAHDI_EVENT_NOALARM:
++ p->inalarm = 0;
+ #ifdef HAVE_PRI
+- /* Extremely unlikely but just in case */
+- if (p->bearer)
+- p->bearer->inalarm = 0;
++ /* Extremely unlikely but just in case */
++ if (p->bearer)
++ p->bearer->inalarm = 0;
+ #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);
+- break;
+- case DAHDI_EVENT_WINKFLASH:
+- if (p->inalarm) break;
+- if (p->radio) break;
+- if (p->oprmode < 0) break;
+- if (p->oprmode > 1)
++ ast_log(LOG_NOTICE, "Alarm cleared on channel %d\n", p->channel);
++ manager_event(EVENT_FLAG_SYSTEM, "AlarmClear",
++ "Channel: %d\r\n", p->channel);
++ break;
++ case DAHDI_EVENT_WINKFLASH:
++ if (p->inalarm) break;
++ if (p->radio) break;
++ if (p->oprmode < 0) break;
++ if (p->oprmode > 1)
++ {
++ struct dahdi_params par;
++
++ memset(&par, 0, sizeof(par));
++ if (ioctl(p->oprpeer->subs[SUB_REAL].dfd, DAHDI_GET_PARAMS, &par) != -1)
+ {
+- 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)
+ {
+- if (!par.rxisoffhook)
+- {
+- /* Make sure it stops ringing */
+- dahdi_set_hook(p->oprpeer->subs[SUB_REAL].dfd, DAHDI_RINGOFF);
+- dahdi_set_hook(p->oprpeer->subs[SUB_REAL].dfd, DAHDI_RING);
+- save_conference(p);
+- tone_zone_play_tone(p->subs[SUB_REAL].dfd, DAHDI_TONE_RINGTONE);
+- }
++ /* Make sure it stops ringing */
++ dahdi_set_hook(p->oprpeer->subs[SUB_REAL].dfd, DAHDI_RINGOFF);
++ dahdi_set_hook(p->oprpeer->subs[SUB_REAL].dfd, DAHDI_RING);
++ save_conference(p);
++ tone_zone_play_tone(p->subs[SUB_REAL].dfd, DAHDI_TONE_RINGTONE);
+ }
+- break;
+ }
+- /* Remember last time we got a flash-hook */
+- p->flashtime = ast_tvnow();
+- switch (mysig) {
+- case SIG_FXOLS:
+- case SIG_FXOGS:
+- case SIG_FXOKS:
+- ast_debug(1, "Winkflash, index: %d, normal: %d, callwait: %d, thirdcall: %d\n",
+- idx, p->subs[SUB_REAL].dfd, p->subs[SUB_CALLWAIT].dfd, p->subs[SUB_THREEWAY].dfd);
+- p->callwaitcas = 0;
++ break;
++ }
++ /* Remember last time we got a flash-hook */
++ p->flashtime = ast_tvnow();
++ switch (mysig) {
++ case SIG_FXOLS:
++ case SIG_FXOGS:
++ case SIG_FXOKS:
++ ast_debug(1, "Winkflash, index: %d, normal: %d, callwait: %d, thirdcall: %d\n",
++ idx, p->subs[SUB_REAL].dfd, p->subs[SUB_CALLWAIT].dfd, p->subs[SUB_THREEWAY].dfd);
++ p->callwaitcas = 0;
+
+- if (idx != SUB_REAL) {
+- ast_log(LOG_WARNING, "Got flash hook with index %d on channel %d?!?\n", idx, p->channel);
++ if (idx != SUB_REAL) {
++ 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);
++ tone_zone_play_tone(p->subs[SUB_REAL].dfd, -1);
++ p->owner = p->subs[SUB_REAL].owner;
++ ast_debug(1, "Making %s the new owner\n", p->owner->name);
++ if (p->owner->_state == AST_STATE_RINGING) {
++ ast_setstate(p->owner, AST_STATE_UP);
++ p->subs[SUB_REAL].needanswer = 1;
++ }
++ p->callwaitingrepeat = 0;
++ p->cidcwexpire = 0;
++ /* Start music on hold if appropriate */
++ if (!p->subs[SUB_CALLWAIT].inthreeway && ast_bridged_channel(p->subs[SUB_CALLWAIT].owner)) {
++ 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);
++ }
++ p->subs[SUB_CALLWAIT].needhold = 1;
++ if (ast_bridged_channel(p->subs[SUB_REAL].owner)) {
++ ast_queue_control_data(p->subs[SUB_REAL].owner, AST_CONTROL_HOLD,
++ S_OR(p->mohsuggest, NULL),
++ !ast_strlen_zero(p->mohsuggest) ? strlen(p->mohsuggest) + 1 : 0);
++ }
++ p->subs[SUB_REAL].needunhold = 1;
++ } else if (!p->subs[SUB_THREEWAY].owner) {
++ 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];
+
+- if (p->subs[SUB_CALLWAIT].owner) {
+- /* Swap to call-wait */
+- swap_subs(p, SUB_REAL, SUB_CALLWAIT);
+- tone_zone_play_tone(p->subs[SUB_REAL].dfd, -1);
+- p->owner = p->subs[SUB_REAL].owner;
+- ast_debug(1, "Making %s the new owner\n", p->owner->name);
+- if (p->owner->_state == AST_STATE_RINGING) {
+- ast_setstate(p->owner, AST_STATE_UP);
+- p->subs[SUB_REAL].needanswer = 1;
++ 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));
++ if (p->owner->cid.cid_name)
++ ast_copy_string(cid_name, p->owner->cid.cid_name, sizeof(cid_name));
+ }
+- p->callwaitingrepeat = 0;
+- p->cidcwexpire = 0;
+- /* Start music on hold if appropriate */
+- if (!p->subs[SUB_CALLWAIT].inthreeway && ast_bridged_channel(p->subs[SUB_CALLWAIT].owner)) {
+- 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);
++ /* 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_debug(1, "Flash when call not up or ringing\n");
++ goto winkflashdone;
+ }
+- p->subs[SUB_CALLWAIT].needhold = 1;
+- if (ast_bridged_channel(p->subs[SUB_REAL].owner)) {
+- ast_queue_control_data(p->subs[SUB_REAL].owner, AST_CONTROL_HOLD,
+- S_OR(p->mohsuggest, NULL),
+- !ast_strlen_zero(p->mohsuggest) ? strlen(p->mohsuggest) + 1 : 0);
++ if (alloc_sub(p, SUB_THREEWAY)) {
++ ast_log(LOG_WARNING, "Unable to allocate three-way subchannel\n");
++ goto winkflashdone;
+ }
+- p->subs[SUB_REAL].needunhold = 1;
+- } else if (!p->subs[SUB_THREEWAY].owner) {
+- 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];
++ /* Make new channel */
++ chan = dahdi_new(p, AST_STATE_RESERVED, 0, SUB_THREEWAY, 0, 0);
++ if (p->dahditrcallerid) {
++ if (!p->origcid_num)
++ p->origcid_num = ast_strdup(p->cid_num);
++ if (!p->origcid_name)
++ p->origcid_name = ast_strdup(p->cid_name);
++ ast_copy_string(p->cid_num, cid_num, sizeof(p->cid_num));
++ ast_copy_string(p->cid_name, cid_name, sizeof(p->cid_name));
++ }
++ /* Swap things around between the three-way and real call */
++ swap_subs(p, SUB_THREEWAY, SUB_REAL);
++ /* Disable echo canceller for better dialing */
++ dahdi_disable_ec(p);
++ res = tone_zone_play_tone(p->subs[SUB_REAL].dfd, DAHDI_TONE_DIALRECALL);
++ if (res)
++ ast_log(LOG_WARNING, "Unable to start dial recall tone on channel %d\n", p->channel);
++ p->owner = chan;
++ if (!chan) {
++ ast_log(LOG_WARNING, "Cannot allocate new structure on channel %d\n", p->channel);
++ } else if (ast_pthread_create_detached(&threadid, NULL, analog_ss_thread, chan)) {
++ ast_log(LOG_WARNING, "Unable to start simple switch on channel %d\n", p->channel);
++ res = tone_zone_play_tone(p->subs[SUB_REAL].dfd, DAHDI_TONE_CONGESTION);
++ dahdi_enable_ec(p);
++ ast_hangup(chan);
++ } else {
++ struct ast_channel *other = ast_bridged_channel(p->subs[SUB_THREEWAY].owner);
++ int way3bridge = 0, cdr3way = 0;
+
+- 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));
+- if (p->owner->cid.cid_name)
+- ast_copy_string(cid_name, p->owner->cid.cid_name, sizeof(cid_name));
+- }
+- /* 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_debug(1, "Flash when call not up or ringing\n");
+- goto winkflashdone;
+- }
+- if (alloc_sub(p, SUB_THREEWAY)) {
+- ast_log(LOG_WARNING, "Unable to allocate three-way subchannel\n");
+- goto winkflashdone;
+- }
+- /* Make new channel */
+- chan = dahdi_new(p, AST_STATE_RESERVED, 0, SUB_THREEWAY, 0, 0);
+- if (p->dahditrcallerid) {
+- if (!p->origcid_num)
+- p->origcid_num = ast_strdup(p->cid_num);
+- if (!p->origcid_name)
+- p->origcid_name = ast_strdup(p->cid_name);
+- ast_copy_string(p->cid_num, cid_num, sizeof(p->cid_num));
+- ast_copy_string(p->cid_name, cid_name, sizeof(p->cid_name));
+- }
+- /* Swap things around between the three-way and real call */
+- swap_subs(p, SUB_THREEWAY, SUB_REAL);
+- /* Disable echo canceller for better dialing */
+- dahdi_disable_ec(p);
+- res = tone_zone_play_tone(p->subs[SUB_REAL].dfd, DAHDI_TONE_DIALRECALL);
+- if (res)
+- ast_log(LOG_WARNING, "Unable to start dial recall tone on channel %d\n", p->channel);
+- p->owner = chan;
+- if (!chan) {
+- ast_log(LOG_WARNING, "Cannot allocate new structure on channel %d\n", p->channel);
+- } else if (ast_pthread_create_detached(&threadid, NULL, ss_thread, chan)) {
+- ast_log(LOG_WARNING, "Unable to start simple switch on channel %d\n", p->channel);
+- res = tone_zone_play_tone(p->subs[SUB_REAL].dfd, DAHDI_TONE_CONGESTION);
+- dahdi_enable_ec(p);
+- ast_hangup(chan);
+- } 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 (!other) {
+- other = ast_bridged_channel(p->subs[SUB_REAL].owner);
+- } else
+- way3bridge = 1;
++ if (p->subs[SUB_THREEWAY].owner->cdr)
++ cdr3way = 1;
+
+- if (p->subs[SUB_THREEWAY].owner->cdr)
+- cdr3way = 1;
++ ast_verb(3, "Started three way call on channel %d\n", p->channel);
+
+- ast_verb(3, "Started three way call on channel %d\n", p->channel);
+-
+- /* Start music on hold if appropriate */
+- if (ast_bridged_channel(p->subs[SUB_THREEWAY].owner)) {
+- 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);
+- }
+- p->subs[SUB_THREEWAY].needhold = 1;
++ /* Start music on hold if appropriate */
++ if (ast_bridged_channel(p->subs[SUB_THREEWAY].owner)) {
++ 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);
+ }
++ p->subs[SUB_THREEWAY].needhold = 1;
+ }
++ }
++ } else {
++ /* Already have a 3 way call */
++ if (p->subs[SUB_THREEWAY].inthreeway) {
++ /* Call is already up, drop the last person */
++ ast_debug(1, "Got flash with three way call up, dropping last call on %d\n", p->channel);
++ /* If the primary call isn't answered yet, use it */
++ if ((p->subs[SUB_REAL].owner->_state != AST_STATE_UP) && (p->subs[SUB_THREEWAY].owner->_state == AST_STATE_UP)) {
++ /* Swap back -- we're dropping the real 3-way that isn't finished yet*/
++ swap_subs(p, SUB_THREEWAY, SUB_REAL);
++ p->owner = p->subs[SUB_REAL].owner;
++ }
++ /* Drop the last call and stop the conference */
++ ast_verb(3, "Dropping three-way call on %s\n", p->subs[SUB_THREEWAY].owner->name);
++ p->subs[SUB_THREEWAY].owner->_softhangup |= AST_SOFTHANGUP_DEV;
++ p->subs[SUB_REAL].inthreeway = 0;
++ p->subs[SUB_THREEWAY].inthreeway = 0;
+ } else {
+- /* Already have a 3 way call */
+- if (p->subs[SUB_THREEWAY].inthreeway) {
+- /* Call is already up, drop the last person */
+- ast_debug(1, "Got flash with three way call up, dropping last call on %d\n", p->channel);
+- /* If the primary call isn't answered yet, use it */
+- if ((p->subs[SUB_REAL].owner->_state != AST_STATE_UP) && (p->subs[SUB_THREEWAY].owner->_state == AST_STATE_UP)) {
+- /* Swap back -- we're dropping the real 3-way that isn't finished yet*/
+- swap_subs(p, SUB_THREEWAY, SUB_REAL);
+- p->owner = p->subs[SUB_REAL].owner;
+- }
+- /* Drop the last call and stop the conference */
+- ast_verb(3, "Dropping three-way call on %s\n", p->subs[SUB_THREEWAY].owner->name);
+- p->subs[SUB_THREEWAY].owner->_softhangup |= AST_SOFTHANGUP_DEV;
+- p->subs[SUB_REAL].inthreeway = 0;
+- 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))) {
+- int otherindex = SUB_THREEWAY;
+- struct ast_channel *other = ast_bridged_channel(p->subs[SUB_THREEWAY].owner);
+- int way3bridge = 0, cdr3way = 0;
++ /* Lets see what we're up to */
++ 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 (!other) {
++ other = ast_bridged_channel(p->subs[SUB_REAL].owner);
++ } else
++ way3bridge = 1;
+
+- if (p->subs[SUB_THREEWAY].owner->cdr)
+- cdr3way = 1;
++ if (p->subs[SUB_THREEWAY].owner->cdr)
++ cdr3way = 1;
+
+- ast_verb(3, "Building conference on call on %s and %s\n", p->subs[SUB_THREEWAY].owner->name, p->subs[SUB_REAL].owner->name);
+- /* Put them in the threeway, and flip */
+- p->subs[SUB_THREEWAY].inthreeway = 1;
+- p->subs[SUB_REAL].inthreeway = 1;
+- if (ast->_state == AST_STATE_UP) {
+- swap_subs(p, SUB_THREEWAY, SUB_REAL);
+- otherindex = SUB_REAL;
+- }
+- if (p->subs[otherindex].owner && ast_bridged_channel(p->subs[otherindex].owner))
+- ast_queue_control(p->subs[otherindex].owner, AST_CONTROL_UNHOLD);
+- p->subs[otherindex].needunhold = 1;
+- p->owner = p->subs[SUB_REAL].owner;
+- if (ast->_state == AST_STATE_RINGING) {
+- ast_debug(1, "Enabling ringtone on real and threeway\n");
+- res = tone_zone_play_tone(p->subs[SUB_REAL].dfd, DAHDI_TONE_RINGTONE);
+- res = tone_zone_play_tone(p->subs[SUB_THREEWAY].dfd, DAHDI_TONE_RINGTONE);
+- }
+- } else {
+- ast_verb(3, "Dumping incomplete call on on %s\n", p->subs[SUB_THREEWAY].owner->name);
++ ast_verb(3, "Building conference on call on %s and %s\n", p->subs[SUB_THREEWAY].owner->name, p->subs[SUB_REAL].owner->name);
++ /* Put them in the threeway, and flip */
++ p->subs[SUB_THREEWAY].inthreeway = 1;
++ p->subs[SUB_REAL].inthreeway = 1;
++ if (ast->_state == AST_STATE_UP) {
+ swap_subs(p, SUB_THREEWAY, SUB_REAL);
+- p->subs[SUB_THREEWAY].owner->_softhangup |= AST_SOFTHANGUP_DEV;
+- p->owner = p->subs[SUB_REAL].owner;
+- if (p->subs[SUB_REAL].owner && ast_bridged_channel(p->subs[SUB_REAL].owner))
+- ast_queue_control(p->subs[SUB_REAL].owner, AST_CONTROL_UNHOLD);
+- p->subs[SUB_REAL].needunhold = 1;
+- dahdi_enable_ec(p);
++ otherindex = SUB_REAL;
+ }
++ if (p->subs[otherindex].owner && ast_bridged_channel(p->subs[otherindex].owner))
++ ast_queue_control(p->subs[otherindex].owner, AST_CONTROL_UNHOLD);
++ p->subs[otherindex].needunhold = 1;
++ p->owner = p->subs[SUB_REAL].owner;
++ if (ast->_state == AST_STATE_RINGING) {
++ ast_debug(1, "Enabling ringtone on real and threeway\n");
++ res = tone_zone_play_tone(p->subs[SUB_REAL].dfd, DAHDI_TONE_RINGTONE);
++ res = tone_zone_play_tone(p->subs[SUB_THREEWAY].dfd, DAHDI_TONE_RINGTONE);
++ }
++ } else {
++ ast_verb(3, "Dumping incomplete call on on %s\n", p->subs[SUB_THREEWAY].owner->name);
++ swap_subs(p, SUB_THREEWAY, SUB_REAL);
++ p->subs[SUB_THREEWAY].owner->_softhangup |= AST_SOFTHANGUP_DEV;
++ p->owner = p->subs[SUB_REAL].owner;
++ if (p->subs[SUB_REAL].owner && ast_bridged_channel(p->subs[SUB_REAL].owner))
++ ast_queue_control(p->subs[SUB_REAL].owner, AST_CONTROL_UNHOLD);
++ p->subs[SUB_REAL].needunhold = 1;
++ dahdi_enable_ec(p);
+ }
+ }
++ }
+ winkflashdone:
+- update_conf(p);
+- break;
+- case SIG_EM:
+- case SIG_EM_E1:
+- case SIG_EMWINK:
+- case SIG_FEATD:
+- case SIG_SF:
+- case SIG_SFWINK:
+- case SIG_SF_FEATD:
+- case SIG_FXSLS:
+- case SIG_FXSGS:
+- if (option_debug) {
+- if (p->dialing)
+- ast_debug(1, "Ignoring wink on channel %d\n", p->channel);
+- else
+- ast_debug(1, "Got wink in weird state %d on channel %d\n", ast->_state, p->channel);
+- }
+- break;
+- case SIG_FEATDMF_TA:
+- switch (p->whichwink) {
+- case 0:
+- ast_debug(1, "ANI2 set to '%d' and ANI is '%s'\n", p->owner->cid.cid_ani2, p->owner->cid.cid_ani);
+- snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), "M*%d%s#", p->owner->cid.cid_ani2, p->owner->cid.cid_ani);
+- break;
+- case 1:
+- ast_copy_string(p->dop.dialstr, p->finaldial, sizeof(p->dop.dialstr));
+- break;
+- case 2:
+- ast_log(LOG_WARNING, "Received unexpected wink on channel of type SIG_FEATDMF_TA\n");
+- return NULL;
+- }
+- p->whichwink++;
+- /* Fall through */
+- case SIG_FEATDMF:
+- case SIG_E911:
+- case SIG_FGC_CAMAMF:
+- case SIG_FGC_CAMA:
+- case SIG_FEATB:
+- case SIG_SF_FEATDMF:
+- case SIG_SF_FEATB:
+- /* FGD MF *Must* wait for wink */
+- if (!ast_strlen_zero(p->dop.dialstr)) {
+- 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: %s\n", p->channel, strerror(errno));
+- p->dop.dialstr[0] = '\0';
+- return NULL;
+- } else
+- ast_debug(1, "Sent deferred digit string: %s\n", p->dop.dialstr);
+- }
+- p->dop.dialstr[0] = '\0';
+- break;
+- default:
+- ast_log(LOG_WARNING, "Don't know how to handle ring/off hoook for signalling %d\n", p->sig);
+- }
++ update_conf(p);
+ break;
+- 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:
+- case SIG_FXSKS:
+- case SIG_EM:
+- case SIG_EM_E1:
+- case SIG_EMWINK:
+- case SIG_FEATD:
+- case SIG_SF:
+- case SIG_SFWINK:
+- case SIG_SF_FEATD:
+- if (!ast_strlen_zero(p->dop.dialstr)) {
+- 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: %s\n", p->channel, strerror(errno));
+- p->dop.dialstr[0] = '\0';
+- return NULL;
+- } else
+- ast_debug(1, "Sent deferred digit string: %s\n", p->dop.dialstr);
+- }
+- p->dop.dialstr[0] = '\0';
+- p->dop.op = DAHDI_DIAL_OP_REPLACE;
++ case SIG_EM:
++ case SIG_EM_E1:
++ case SIG_EMWINK:
++ case SIG_FEATD:
++ case SIG_SF:
++ case SIG_SFWINK:
++ case SIG_SF_FEATD:
++ case SIG_FXSLS:
++ case SIG_FXSGS:
++ if (p->dialing)
++ ast_debug(1, "Ignoring wink on channel %d\n", p->channel);
++ else
++ ast_debug(1, "Got wink in weird state %d on channel %d\n", ast->_state, p->channel);
++ break;
++ case SIG_FEATDMF_TA:
++ switch (p->whichwink) {
++ case 0:
++ ast_debug(1, "ANI2 set to '%d' and ANI is '%s'\n", p->owner->cid.cid_ani2, p->owner->cid.cid_ani);
++ snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), "M*%d%s#", p->owner->cid.cid_ani2, p->owner->cid.cid_ani);
+ break;
+- case SIG_FEATDMF:
+- case SIG_FEATDMF_TA:
+- case SIG_E911:
+- case SIG_FGC_CAMA:
+- case SIG_FGC_CAMAMF:
+- case SIG_FEATB:
+- case SIG_SF_FEATDMF:
+- case SIG_SF_FEATB:
+- ast_debug(1, "Got hook complete in MF FGD, waiting for wink now on channel %d\n",p->channel);
++ case 1:
++ ast_copy_string(p->dop.dialstr, p->finaldial, sizeof(p->dop.dialstr));
+ break;
+- default:
+- break;
++ case 2:
++ ast_log(LOG_WARNING, "Received unexpected wink on channel of type SIG_FEATDMF_TA\n");
++ return NULL;
+ }
+- break;
+- case DAHDI_EVENT_POLARITY:
+- /*
+- * If we get a Polarity Switch event, check to see
+- * if we should change the polarity state and
+- * mark the channel as UP or if this is an indication
+- * of remote end disconnect.
+- */
+- if (p->polarity == POLARITY_IDLE) {
+- p->polarity = POLARITY_REV;
+- if (p->answeronpolarityswitch &&
+- ((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) {
+- p->polaritydelaytv = ast_tvnow();
+- }
++ p->whichwink++;
++ /* Fall through */
++ case SIG_FEATDMF:
++ case SIG_E911:
++ case SIG_FGC_CAMAMF:
++ case SIG_FGC_CAMA:
++ case SIG_FEATB:
++ case SIG_SF_FEATDMF:
++ case SIG_SF_FEATB:
++ /* FGD MF *Must* wait for wink */
++ if (!ast_strlen_zero(p->dop.dialstr)) {
++ 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: %s\n", p->channel, strerror(errno));
++ p->dop.dialstr[0] = '\0';
++ return NULL;
+ } else
+- ast_debug(1, "Ignore switch to REVERSED Polarity on channel %d, state %d\n", p->channel, ast->_state);
++ ast_debug(1, "Sent deferred digit string: %s\n", p->dop.dialstr);
+ }
+- /* 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) &&
+- ((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 */
+- 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);
+- p->polarity = POLARITY_IDLE;
++ p->dop.dialstr[0] = '\0';
++ break;
++ default:
++ ast_log(LOG_WARNING, "Don't know how to handle ring/off hoook for signalling %d\n", p->sig);
++ }
++ break;
++ 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:
++ case SIG_FXSKS:
++ case SIG_EM:
++ case SIG_EM_E1:
++ case SIG_EMWINK:
++ case SIG_FEATD:
++ case SIG_SF:
++ case SIG_SFWINK:
++ case SIG_SF_FEATD:
++ if (!ast_strlen_zero(p->dop.dialstr)) {
++ 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: %s\n", p->channel, strerror(errno));
++ p->dop.dialstr[0] = '\0';
++ return NULL;
+ } else
+- ast_debug(1, "Polarity Reversal detected but NOT hanging up (too close to answer event) on channel %d, state %d\n", p->channel, ast->_state);
+-
+- } else {
+- p->polarity = POLARITY_IDLE;
+- ast_debug(1, "Ignoring Polarity switch to IDLE on channel %d, state %d\n", p->channel, ast->_state);
++ ast_debug(1, "Sent deferred digit string: %s\n", p->dop.dialstr);
+ }
+- /* 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) );
++ p->dop.dialstr[0] = '\0';
++ p->dop.op = DAHDI_DIAL_OP_REPLACE;
+ break;
++ case SIG_FEATDMF:
++ case SIG_FEATDMF_TA:
++ case SIG_E911:
++ case SIG_FGC_CAMA:
++ case SIG_FGC_CAMAMF:
++ case SIG_FEATB:
++ case SIG_SF_FEATDMF:
++ case SIG_SF_FEATB:
++ ast_debug(1, "Got hook complete in MF FGD, waiting for wink now on channel %d\n",p->channel);
++ break;
+ default:
+- ast_debug(1, "Dunno what to do with event %d on channel %d\n", res, p->channel);
++ break;
++ }
++ break;
++ case DAHDI_EVENT_POLARITY:
++ /*
++ * If we get a Polarity Switch event, check to see
++ * if we should change the polarity state and
++ * mark the channel as UP or if this is an indication
++ * of remote end disconnect.
++ */
++ if (p->polarity == POLARITY_IDLE) {
++ p->polarity = POLARITY_REV;
++ if (p->answeronpolarityswitch &&
++ ((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) {
++ p->polaritydelaytv = ast_tvnow();
++ }
++ } 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) &&
++ ((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 */
++ 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);
++ p->polarity = POLARITY_IDLE;
++ } else
++ ast_debug(1, "Polarity Reversal detected but NOT hanging up (too close to answer event) on channel %d, state %d\n", p->channel, ast->_state);
++
++ } else {
++ 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 */
++ 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:
++ ast_debug(1, "Dunno what to do with event %d on channel %d\n", res, p->channel);
+ }
+ return &p->subs[idx].f;
+ }
+@@ -6651,7 +7904,12 @@
+ struct dahdi_pvt *p = ast->tech_pvt;
+ struct ast_frame *f;
+ ast_mutex_lock(&p->lock);
+- f = __dahdi_exception(ast);
++ if (analog_lib_handles(p->sig, p->radio, p->oprmode)) {
++ struct analog_pvt *analog_p = p->sig_pvt;
++ f = analog_exception(analog_p, ast);
++ } else {
++ f = __dahdi_exception(ast);
++ }
+ ast_mutex_unlock(&p->lock);
+ return f;
+ }
+@@ -6899,7 +8157,7 @@
+ p->subs[idx].f.datalen = READ_SIZE;
+
+ /* Handle CallerID Transmission */
+- if ((p->owner == ast) && p->cidspill &&((ast->_state == AST_STATE_UP) || (ast->rings == p->cidrings))) {
++ if ((p->owner == ast) && p->cidspill) {
+ send_callerid(p);
+ }
+
+@@ -6912,7 +8170,9 @@
+ #if 0
+ ast_debug(1, "Read %d of voice on %s\n", p->subs[idx].f.datalen, ast->name);
+ #endif
+- if (p->dialing || /* Transmitting something */
++ {
++ struct analog_pvt *ap = p->sig_pvt;
++ if ((analog_lib_handles(p->sig ,p->radio, p->oprmode) && ap->dialing) || p->dialing || p->radio || /* 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 */
+ ) {
+@@ -6926,6 +8186,7 @@
+ p->subs[idx].f.data.ptr = NULL;
+ p->subs[idx].f.datalen= 0;
+ }
++ }
+ 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;
+@@ -6992,8 +8253,12 @@
+ } else
+ f = &p->subs[idx].f;
+
+- if (f && (f->frametype == AST_FRAME_DTMF))
+- dahdi_handle_dtmfup(ast, idx, &f);
++ if (f && (f->frametype == AST_FRAME_DTMF)) {
++ if (analog_lib_handles(p->sig, p->radio, p->oprmode)) {
++ analog_handle_dtmfup(p->sig_pvt, ast, idx, &f);
++ } else
++ dahdi_handle_dtmfup(ast, idx, &f);
++ }
+
+ /* If we have a fake_event, trigger exception to handle it */
+ if (p->fake_event)
+@@ -7064,6 +8329,12 @@
+ ast_log(LOG_WARNING, "Cannot handle frames in %d format\n", frame->subclass);
+ return -1;
+ }
++ if (analog_lib_handles(p->sig, p->radio, p->oprmode)) {
++ struct analog_pvt *ap = p->sig_pvt;
++
++ if (ap->dialing)
++ return 0;
++ }
+ if (p->dialing) {
+ ast_debug(1, "Dropping frame since I'm still dialing on %s...\n",ast->name);
+ return 0;
+@@ -7610,7 +8881,7 @@
+ on? "enabled" : "disabled");
+ }
+
+-static void *ss_thread(void *data)
++static void *analog_ss_thread(void *data)
+ {
+ struct ast_channel *chan = data;
+ struct dahdi_pvt *p = chan->tech_pvt;
+@@ -8769,25 +10040,9 @@
+
+ if (cs)
+ callerid_free(cs);
+- /* If the CID had Message waiting payload, assume that this for MWI only and hangup the call */
+- if (flags & CID_MSGWAITING) {
+- ast_log(LOG_NOTICE, "MWI: Channel %d message waiting!\n", p->channel);
+- notify_message(p->mailbox, 1);
+- /* If generated using Ring Pulse Alert, then ring has been answered as a call and needs to be hungup */
+- if (p->mwimonitor_rpas) {
+- ast_hangup(chan);
+- return NULL;
+- }
+- } else if (flags & CID_NOMSGWAITING) {
+- ast_log(LOG_NOTICE, "MWI: Channel %d no message waiting!\n", p->channel);
+- notify_message(p->mailbox, 0);
+- /* If generated using Ring Pulse Alert, then ring has been answered as a call and needs to be hungup */
+- if (p->mwimonitor_rpas) {
+- ast_hangup(chan);
+- return NULL;
+- }
+- }
+
++ my_handle_notify_message(chan, p, flags, -1);
++
+ ast_setstate(chan, AST_STATE_RING);
+ chan->rings = 1;
+ p->ringt = p->ringt_base;
+@@ -8890,14 +10145,20 @@
+ handle_alarms(mtd->pvt, res);
+ break; /* What to do on channel alarm ???? -- fall thru intentionally?? */
+ default:
+- ast_log(LOG_NOTICE, "Got event %d (%s)... Passing along to ss_thread\n", res, event2str(res));
++ ast_log(LOG_NOTICE, "Got event %d (%s)... Passing along to analog_ss_thread\n", res, event2str(res));
+ callerid_free(cs);
+
+ restore_gains(mtd->pvt);
+ mtd->pvt->ringt = mtd->pvt->ringt_base;
+
+ if ((chan = dahdi_new(mtd->pvt, AST_STATE_RING, 0, SUB_REAL, 0, 0))) {
+- if (ast_pthread_create_detached(&threadid, NULL, ss_thread, chan)) {
++ int result;
++ if (analog_lib_handles(mtd->pvt->sig, mtd->pvt->radio, mtd->pvt->oprmode)) {
++ result = analog_ss_thread_start(mtd->pvt->sig_pvt, chan);
++ } else {
++ result = ast_pthread_create_detached(&threadid, NULL, analog_ss_thread, chan);
++ }
++ if (result) {
+ ast_log(LOG_WARNING, "Unable to start simple switch thread on channel %d\n", mtd->pvt->channel);
+ res = tone_zone_play_tone(mtd->pvt->subs[SUB_REAL].dfd, DAHDI_TONE_CONGESTION);
+ if (res < 0)
+@@ -9017,8 +10278,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
+ }
+@@ -9168,7 +10429,7 @@
+ while (tmp) {
+ if (tmp->channel == channel) {
+ int x = DAHDI_FLASH;
+- ioctl(tmp->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(tmp->subs[SUB_REAL].dfd, DAHDI_HOOK, &x); /* important to create an event for dahdi_wait_event to register so that all analog_ss_threads terminate */
+ destroy_channel(prev, tmp, 1);
+ ast_module_unref(ast_module_info->self);
+ return RESULT_SUCCESS;
+@@ -9232,7 +10493,7 @@
+ res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, DAHDI_TONE_DIALTONE);
+ 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)) {
++ if (ast_pthread_create_detached(&threadid, NULL, analog_ss_thread, chan)) {
+ ast_log(LOG_WARNING, "Unable to start simple switch thread on channel %d\n", i->channel);
+ res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, DAHDI_TONE_CONGESTION);
+ if (res < 0)
+@@ -9274,7 +10535,7 @@
+
+ if (!chan) {
+ ast_log(LOG_WARNING, "Cannot allocate new structure on channel %d\n", i->channel);
+- } else if (ast_pthread_create_detached(&threadid, NULL, ss_thread, chan)) {
++ } else if (ast_pthread_create_detached(&threadid, NULL, analog_ss_thread, chan)) {
+ ast_log(LOG_WARNING, "Unable to start simple switch thread on channel %d\n", i->channel);
+ res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, DAHDI_TONE_CONGESTION);
+ if (res < 0) {
+@@ -9380,7 +10641,7 @@
+ 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);
+- } else if (ast_pthread_create_detached(&threadid, NULL, ss_thread, chan)) {
++ } else if (ast_pthread_create_detached(&threadid, NULL, analog_ss_thread, chan)) {
+ ast_log(LOG_WARNING, "Unable to start simple switch thread on channel %d\n", i->channel);
+ } else {
+ thread_spawned = 1;
+@@ -9458,19 +10719,39 @@
+ count = 0;
+ i = iflist;
+ while (i) {
++ ast_mutex_lock(&i->lock);
+ if ((i->subs[SUB_REAL].dfd > -1) && i->sig && (!i->radio) && !(i->sig & SIG_MFCR2)) {
+- 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->mwisendactive || i->mwimonitor_fsk)
+- pfds[count].events |= POLLIN;
+- count++;
++ if (analog_lib_handles(i->sig, i->radio, i->oprmode)) {
++ struct analog_pvt *p = i->sig_pvt;
++
++ if (!p)
++ ast_log(LOG_ERROR, "No sig_pvt?\n");
++
++ if (!p->owner && !p->subs[SUB_REAL].owner) {
++ /* 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;
++ /* Message waiting or r2 channels also get watched for reading */
++ if (i->cidspill || i->mwisendactive || i->mwimonitor_fsk)
++ pfds[count].events |= POLLIN;
++ count++;
++ }
++ } else {
++ 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->mwisendactive || i->mwimonitor_fsk)
++ pfds[count].events |= POLLIN;
++ count++;
++ }
+ }
+ }
++ ast_mutex_unlock(&i->lock);
+ i = i->next;
+ }
+ /* Okay, now that we know what to do, release the interface lock */
+@@ -9535,7 +10816,10 @@
+ ast_debug(1, "Monitor doohicky got event %s on radio channel %d\n", event2str(res), i->channel);
+ /* Don't hold iflock while handling init events */
+ ast_mutex_unlock(&iflock);
+- handle_init_event(i, res);
++ if (analog_lib_handles(i->sig, i->radio, i->oprmode))
++ analog_handle_init_event(i->sig_pvt, dahdievent_to_analogevent(res));
++ else
++ handle_init_event(i, res);
+ ast_mutex_lock(&iflock);
+ }
+ i = i->next;
+@@ -9601,7 +10885,10 @@
+ /* Don't hold iflock while handling init events */
+ ast_mutex_unlock(&iflock);
+ if (0 == i->mwisendactive || 0 == mwi_send_process_event(i, res)) {
+- handle_init_event(i, res);
++ if (analog_lib_handles(i->sig, i->radio, i->oprmode))
++ analog_handle_init_event(i->sig_pvt, dahdievent_to_analogevent(res));
++ else
++ handle_init_event(i, res);
+ }
+ ast_mutex_lock(&iflock);
+ }
+@@ -9855,6 +11142,9 @@
+ }
+ openr2_context_set_log_level(r2_link->protocol_context, conf->mfcr2.loglevel);
+ openr2_context_set_ani_first(r2_link->protocol_context, conf->mfcr2.get_ani_first);
++#if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 1
++ openr2_context_set_skip_category_request(r2_link->protocol_context, conf->mfcr2.skip_category_request);
++#endif
+ openr2_context_set_mf_threshold(r2_link->protocol_context, threshold);
+ openr2_context_set_mf_back_timeout(r2_link->protocol_context, conf->mfcr2.mfback_timeout);
+ openr2_context_set_metering_pulse_timeout(r2_link->protocol_context, conf->mfcr2.metering_pulse_timeout);
+@@ -9912,6 +11202,7 @@
+ int x;
+ struct dahdi_pvt **wlist;
+ struct dahdi_pvt **wend;
++ struct analog_pvt *analog_p = NULL;
+ struct dahdi_params p;
+
+ wlist = &iflist;
+@@ -9944,8 +11235,6 @@
+
+ if (!here && reloading != 1) {
+ if (!(tmp = ast_calloc(1, sizeof(*tmp)))) {
+- if (tmp)
+- free(tmp);
+ return NULL;
+ }
+ ast_mutex_init(&tmp->lock);
+@@ -9999,6 +11288,20 @@
+ return NULL;
+ }
+ }
++
++ if (analog_lib_handles(chan_sig, tmp->radio, tmp->oprmode)) {
++ if (tmp->sig_pvt) {
++ ast_log(LOG_WARNING, "Private already exists!\n");
++ analog_p = tmp->sig_pvt;
++ } else
++ analog_p = analog_new(dahdisig_to_analogsig(chan_sig), &dahdi_analog_callbacks, tmp);
++ if (!analog_p) {
++ destroy_dahdi_pvt(&tmp);
++ return NULL;
++ }
++ tmp->sig_pvt = analog_p;
++
++ }
+ #ifdef HAVE_SS7
+ if (chan_sig == SIG_SS7) {
+ struct dahdi_ss7 *ss7;
+@@ -10063,7 +11366,8 @@
+ tmp->subs[SUB_REAL].dfd,
+ NULL, NULL);
+ if (!tmp->r2chan) {
+- ast_log(LOG_ERROR, "Cannot create OpenR2 channel.\n");
++ openr2_liberr_t err = openr2_context_get_last_error(r2_link->protocol_context);
++ ast_log(LOG_ERROR, "Cannot create OpenR2 channel: %s\n", openr2_context_error_string(err));
+ destroy_dahdi_pvt(&tmp);
+ return NULL;
+ }
+@@ -10135,7 +11439,6 @@
+ }
+ }
+ }
+- offset = p.chanpos;
+ if (!matchesdchan) {
+ if (pris[span].nodetype && (pris[span].nodetype != conf->pri.nodetype)) {
+ ast_log(LOG_ERROR, "Span %d is already a %s node\n", span + 1, pri_node2str(pris[span].nodetype));
+@@ -10191,6 +11494,9 @@
+ pris[span].overlapdial = conf->pri.overlapdial;
+ pris[span].qsigchannelmapping = conf->pri.qsigchannelmapping;
+ pris[span].discardremoteholdretrieval = conf->pri.discardremoteholdretrieval;
++#ifdef HAVE_PRI_SERVICE_MESSAGES
++ pris[span].enable_service_message_support = conf->pri.enable_service_message_support;
++#endif
+ #ifdef HAVE_PRI_INBANDDISCONNECT
+ pris[span].inbanddisconnect = conf->pri.inbanddisconnect;
+ #endif
+@@ -10205,7 +11511,11 @@
+ pris[span].resetinterval = conf->pri.resetinterval;
+
+ tmp->pri = &pris[span];
+- tmp->prioffset = offset;
++ if (si.spanno != span + 1) { /* in another trunkgroup */
++ tmp->prioffset = pris[span].numchans;
++ } else {
++ tmp->prioffset = p.chanpos;
++ }
+ tmp->call = NULL;
+ } else {
+ ast_log(LOG_ERROR, "Channel %d is reserved for D-channel.\n", offset);
+@@ -10484,11 +11794,57 @@
+ tmp->sendcalleridafter = conf->chan.sendcalleridafter;
+ if (!here) {
+ tmp->locallyblocked = tmp->remotelyblocked = 0;
+- if ((chan_sig == SIG_PRI) || (chan_sig == SIG_BRI) || (chan_sig == SIG_BRI_PTMP) || (chan_sig == SIG_SS7))
++ if ((chan_sig == SIG_PRI) || (chan_sig == SIG_BRI) || (chan_sig == SIG_BRI_PTMP) || (chan_sig == SIG_SS7)) {
+ tmp->inservice = 0;
+- else /* We default to in service on protocols that don't have a reset */
++#ifdef HAVE_PRI_SERVICE_MESSAGES
++ if (chan_sig == SIG_PRI) {
++ char db_chan_name[20], db_answer[5];
++
++ snprintf(db_chan_name, sizeof(db_chan_name), "%s/%d:%d", dahdi_db, tmp->span, tmp->channel);
++ if (ast_db_get(db_chan_name, SRVST_DBKEY, db_answer, sizeof(db_answer))) {
++ snprintf(db_answer, sizeof(db_answer), "%s:%d", SRVST_TYPE_OOS, SRVST_INITIALIZED);
++ ast_db_put(db_chan_name, SRVST_DBKEY, db_answer);
++ }
++ }
++#endif
++ } else {
++ /* We default to in service on protocols that don't have a reset */
+ tmp->inservice = 1;
++ }
+ }
++
++ analog_p = tmp->sig_pvt;
++ if (analog_p) {
++ analog_p->channel = tmp->channel;
++ analog_p->polarityonanswerdelay = conf->chan.polarityonanswerdelay;
++ analog_p->answeronpolarityswitch = conf->chan.answeronpolarityswitch;
++ analog_p->hanguponpolarityswitch = conf->chan.hanguponpolarityswitch;
++ analog_p->sendcalleridafter = conf->chan.sendcalleridafter;
++ analog_p->permcallwaiting = 1;
++ analog_p->callreturn = conf->chan.callreturn;
++ analog_p->cancallforward = conf->chan.cancallforward;
++ analog_p->canpark = conf->chan.canpark;
++ analog_p->dahditrcallerid = conf->chan.dahditrcallerid;
++ analog_p->immediate = conf->chan.immediate;
++ analog_p->permhidecallerid = conf->chan.permhidecallerid;
++ analog_p->pulse = conf->chan.pulse;
++ analog_p->threewaycalling = conf->chan.threewaycalling;
++ analog_p->transfer = conf->chan.transfer;
++ analog_p->transfertobusy = conf->chan.transfertobusy;
++ analog_p->use_callerid = conf->chan.use_callerid;
++ analog_p->outsigmod = ANALOG_SIG_NONE;
++ analog_p->echotraining = conf->chan.echotraining;
++ analog_p->cid_signalling = conf->chan.cid_signalling;
++ analog_p->stripmsd = conf->chan.stripmsd;
++ analog_p->cid_start = ANALOG_CID_START_RING;
++ tmp->callwaitingcallerid = analog_p->callwaitingcallerid = 1;
++
++ ast_copy_string(analog_p->mohsuggest, conf->chan.mohsuggest, sizeof(analog_p->mohsuggest));
++ ast_copy_string(analog_p->cid_num, conf->chan.cid_num, sizeof(analog_p->cid_num));
++ ast_copy_string(analog_p->cid_name, conf->chan.cid_name, sizeof(analog_p->cid_name));
++
++ analog_config_complete(analog_p);
++ }
+ }
+ if (tmp && !here) {
+ /* nothing on the iflist */
+@@ -10537,7 +11893,7 @@
+ return tmp;
+ }
+
+-static inline int available(struct dahdi_pvt *p, int channelmatch, ast_group_t groupmatch, int *busy, int *channelmatched, int *groupmatched)
++static inline int available(struct dahdi_pvt *p, int channelmatch, ast_group_t groupmatch, int *reason, int *channelmatched, int *groupmatched)
+ {
+ int res;
+ struct dahdi_params par;
+@@ -10554,10 +11910,14 @@
+ return 0;
+ *channelmatched = 1;
+ }
++
++ if (analog_lib_handles(p->sig, p->radio, p->oprmode))
++ return analog_available(p->sig_pvt, channelmatch, groupmatch, reason, channelmatched, groupmatched);
++
+ /* We're at least busy at this point */
+- if (busy) {
++ if (reason) {
+ if ((p->sig == SIG_FXOKS) || (p->sig == SIG_FXOLS) || (p->sig == SIG_FXOGS))
+- *busy = 1;
++ *reason = AST_CAUSE_BUSY;
+ }
+ /* If do not disturb, definitely not */
+ if (p->dnd)
+@@ -10574,10 +11934,25 @@
+ #ifdef HAVE_PRI
+ /* Trust PRI */
+ if (p->pri) {
+- if (p->resetting || p->call)
++#ifdef HAVE_PRI_SERVICE_MESSAGES
++ char db_chan_name[20], db_answer[5], state;
++ int why = 0;
++
++ snprintf(db_chan_name, sizeof(db_chan_name), "%s/%d:%d", dahdi_db, p->span, p->channel);
++ if (!ast_db_get(db_chan_name, SRVST_DBKEY, db_answer, sizeof(db_answer))) {
++ sscanf(db_answer, "%c:%d", &state, &why);
++ }
++ if ((p->resetting || p->call) || (why)) {
++ if (why) {
++ *reason = AST_CAUSE_REQUESTED_CHAN_UNAVAIL;
++ }
++#else
++ if (p->resetting || p->call) {
++#endif
+ return 0;
+- else
++ } else {
+ return 1;
++ }
+ }
+ #endif
+ #ifdef HAVE_SS7
+@@ -10737,7 +12112,7 @@
+ int channelmatch = -1;
+ int roundrobin = 0;
+ int callwait = 0;
+- int busy = 0;
++ int unavailreason = 0;
+ struct dahdi_pvt *p;
+ struct ast_channel *tmp = NULL;
+ char *dest=NULL;
+@@ -10866,7 +12241,7 @@
+ ast_verbose("name = %s, %d, %d, %d\n",p->owner ? p->owner->name : "<none>", p->channel, channelmatch, groupmatch);
+ #endif
+
+- if (p && available(p, channelmatch, groupmatch, &busy, &channelmatched, &groupmatched)) {
++ if (p && available(p, channelmatch, groupmatch, &unavailreason, &channelmatched, &groupmatched)) {
+ ast_debug(1, "Using channel %d\n", p->channel);
+ if (p->inalarm)
+ goto next;
+@@ -10922,7 +12297,10 @@
+ }
+ }
+ p->outgoing = 1;
+- tmp = dahdi_new(p, AST_STATE_RESERVED, 0, p->owner ? SUB_CALLWAIT : SUB_REAL, 0, 0);
++ if (analog_lib_handles(p->sig, p->radio, p->oprmode)) {
++ tmp = analog_request(p->sig_pvt, &callwait);
++ } else
++ tmp = dahdi_new(p, AST_STATE_RESERVED, 0, p->owner ? SUB_CALLWAIT : SUB_REAL, 0, 0);
+ #ifdef HAVE_PRI
+ if (p->bearer) {
+ /* Log owner to bearer channel, too */
+@@ -10974,10 +12352,10 @@
+ *cause = AST_CAUSE_BUSY;
+ else if (!tmp) {
+ if (channelmatched) {
+- if (busy)
++ if (unavailreason)
+ *cause = AST_CAUSE_BUSY;
+ } else if (groupmatched) {
+- *cause = AST_CAUSE_CONGESTION;
++ *cause = (unavailreason) ? unavailreason : AST_CAUSE_CONGESTION;
+ }
+ }
+
+@@ -10987,7 +12365,11 @@
+ #if defined(HAVE_PRI) || defined(HAVE_SS7)
+ static int dahdi_setlaw(int dfd, int law)
+ {
+- return ioctl(dfd, DAHDI_SETLAW, &law);
++ int res;
++ res = ioctl(dfd, DAHDI_SETLAW, &law);
++ if (res)
++ return res;
++ return 0;
+ }
+ #endif /* defined(HAVE_PRI) || defined(HAVE_SS7) */
+
+@@ -12002,9 +13384,13 @@
+ 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);
++ char newname[AST_CHANNEL_NAME];
++
++ snprintf(newname, sizeof(newname),
++ "DAHDI/%d:%d-%d", pri->trunkgroup, new->channel, 1);
++
++ ast_change_name(new->owner, newname);
++
+ 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;
+@@ -12190,6 +13576,9 @@
+ #if defined(HAVE_PRI)
+ static int pri_check_restart(struct dahdi_pri *pri)
+ {
++#ifdef HAVE_PRI_SERVICE_MESSAGES
++tryanotherpos:
++#endif
+ do {
+ pri->resetpos++;
+ } while ((pri->resetpos < pri->numchans) &&
+@@ -12197,6 +13586,26 @@
+ pri->pvts[pri->resetpos]->call ||
+ pri->pvts[pri->resetpos]->resetting));
+ if (pri->resetpos < pri->numchans) {
++#ifdef HAVE_PRI_SERVICE_MESSAGES
++ char db_chan_name[20], db_answer[5], state;
++ int why;
++
++ /* check if the channel is out of service */
++ ast_mutex_lock(&pri->pvts[pri->resetpos]->lock);
++ snprintf(db_chan_name, sizeof(db_chan_name), "%s/%d:%d", dahdi_db, pri->pvts[pri->resetpos]->span, pri->pvts[pri->resetpos]->channel);
++ ast_mutex_unlock(&pri->pvts[pri->resetpos]->lock);
++
++ /* if so, try next channel */
++ if (!ast_db_get(db_chan_name, SRVST_DBKEY, db_answer, sizeof(db_answer))) {
++ sscanf(db_answer, "%c:%d", &state, &why);
++ if (why) {
++ ast_log(LOG_NOTICE, "span '%d' channel '%d' out-of-service (reason: %s), not sending RESTART\n", pri->span,
++ pri->pvts[pri->resetpos]->channel, (why & SRVST_FAREND) ? (why & SRVST_NEAREND) ? "both ends" : "far end" : "near end");
++ goto tryanotherpos;
++ }
++ }
++#endif
++
+ /* Mark the channel as resetting and restart it */
+ pri->pvts[pri->resetpos]->resetting = 1;
+ pri_reset(pri->pri, PVT_TO_CHANNEL(pri->pvts[pri->resetpos]));
+@@ -12581,13 +13990,36 @@
+ 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",
+- PRI_SPAN(e->restart.channel), PRI_CHANNEL(e->restart.channel), pri->span);
++#ifdef HAVE_PRI_SERVICE_MESSAGES
++ char db_chan_name[20], db_answer[5], state;
++ int why, skipit = 0;
++
+ ast_mutex_lock(&pri->pvts[chanpos]->lock);
+- if (pri->pvts[chanpos]->call) {
+- pri_destroycall(pri->pri, pri->pvts[chanpos]->call);
+- pri->pvts[chanpos]->call = NULL;
++ snprintf(db_chan_name, sizeof(db_chan_name), "%s/%d:%d", dahdi_db, pri->pvts[chanpos]->span, pri->pvts[chanpos]->channel);
++ ast_mutex_unlock(&pri->pvts[chanpos]->lock);
++
++ if (!ast_db_get(db_chan_name, SRVST_DBKEY, db_answer, sizeof(db_answer))) {
++ sscanf(db_answer, "%c:%d", &state, &why);
++ if (why) {
++ ast_log(LOG_NOTICE, "span '%d' channel '%d' out-of-service (reason: %s), ignoring RESTART\n", pri->span,
++ e->restart.channel, (why & SRVST_FAREND) ? (why & SRVST_NEAREND) ? "both ends" : "far end" : "near end");
++ skipit = 1;
++ } else {
++ ast_db_del(db_chan_name, SRVST_DBKEY);
++ }
+ }
++ if (!skipit) {
++#endif
++ ast_verb(3, "B-channel %d/%d restarted on span %d\n",
++ PRI_SPAN(e->restart.channel), PRI_CHANNEL(e->restart.channel), pri->span);
++ ast_mutex_lock(&pri->pvts[chanpos]->lock);
++ if (pri->pvts[chanpos]->call) {
++ pri_destroycall(pri->pri, pri->pvts[chanpos]->call);
++ pri->pvts[chanpos]->call = NULL;
++ }
++#ifdef HAVE_PRI_SERVICE_MESSAGES
++ }
++#endif
+ /* Force soft hangup if appropriate */
+ if (pri->pvts[chanpos]->realcall)
+ pri_hangup_all(pri->pvts[chanpos]->realcall, pri);
+@@ -12667,6 +14099,62 @@
+ }
+ }
+ break;
++#ifdef HAVE_PRI_SERVICE_MESSAGES
++ case PRI_EVENT_SERVICE:
++ chanpos = pri_find_principle(pri, e->service.channel);
++ if (chanpos < 0) {
++ ast_log(LOG_WARNING, "Received service change status %d on unconfigured channel %d/%d span %d\n",
++ e->service_ack.changestatus, PRI_SPAN(e->service_ack.channel), PRI_CHANNEL(e->service_ack.channel), pri->span);
++ } else {
++ char db_chan_name[20], db_answer[5], state;
++ int ch, why = -1;
++
++ ast_mutex_lock(&pri->pvts[chanpos]->lock);
++ ch = pri->pvts[chanpos]->channel;
++ ast_mutex_unlock(&pri->pvts[chanpos]->lock);
++
++ snprintf(db_chan_name, sizeof(db_chan_name), "%s/%d:%d", dahdi_db, pri->pvts[chanpos]->span, ch);
++ if (!ast_db_get(db_chan_name, SRVST_DBKEY, db_answer, sizeof(db_answer))) {
++ sscanf(db_answer, "%c:%d", &state, &why);
++ ast_db_del(db_chan_name, SRVST_DBKEY);
++ }
++ switch (e->service.changestatus) {
++ case 0: /* in-service */
++ if (why > -1) {
++ if (why & SRVST_NEAREND) {
++ snprintf(db_answer, sizeof(db_answer), "%s:%d", SRVST_TYPE_OOS, SRVST_NEAREND);
++ ast_db_put(db_chan_name, SRVST_DBKEY, db_answer);
++ ast_debug(2, "channel '%d' service state { near: out-of-service, far: in-service }\n", ch);
++ }
++ }
++ break;
++ case 2: /* out-of-service */
++ if (why == -1) {
++ why = SRVST_FAREND;
++ } else {
++ why |= SRVST_FAREND;
++ }
++ snprintf(db_answer, sizeof(db_answer), "%s:%d", SRVST_TYPE_OOS, why);
++ ast_db_put(db_chan_name, SRVST_DBKEY, db_answer);
++ break;
++ default:
++ ast_log(LOG_ERROR, "Huh? changestatus is: %d\n", e->service.changestatus);
++ }
++ ast_log(LOG_NOTICE, "Channel %d/%d span %d (logical: %d) received a change of service message, status '%d'\n",
++ PRI_SPAN(e->service.channel), PRI_CHANNEL(e->service.channel), pri->span, ch, e->service.changestatus);
++ }
++ break;
++ case PRI_EVENT_SERVICE_ACK:
++ chanpos = pri_find_principle(pri, e->service_ack.channel);
++ if (chanpos < 0) {
++ ast_log(LOG_WARNING, "Received service acknowledge change status '%d' on unconfigured channel %d/%d span %d\n",
++ e->service_ack.changestatus, PRI_SPAN(e->service_ack.channel), PRI_CHANNEL(e->service_ack.channel), pri->span);
++ } else {
++ ast_debug(2, "Channel %d/%d span %d received a change os service acknowledgement message, status '%d'\n",
++ PRI_SPAN(e->service_ack.channel), PRI_CHANNEL(e->service_ack.channel), pri->span, e->service_ack.changestatus);
++ }
++ break;
++#endif
+ case PRI_EVENT_RING:
+ crv = NULL;
+ if (e->ring.channel == -1)
+@@ -12842,7 +14330,7 @@
+
+ ast_mutex_lock(&pri->pvts[chanpos]->lock);
+ ast_mutex_lock(&pri->lock);
+- if (c && !ast_pthread_create_detached(&threadid, NULL, ss_thread, c)) {
++ if (c && !ast_pthread_create_detached(&threadid, NULL, analog_ss_thread, c)) {
+ ast_verb(3, "Accepting overlap call from '%s' to '%s' on channel %d/%d, span %d\n",
+ plancallingnum, S_OR(pri->pvts[chanpos]->exten, "<unspecified>"),
+ pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset, pri->span);
+@@ -13464,6 +14952,11 @@
+ break;
+ default:
+ pri->dchans[i] = pri_new(pri->fds[i], pri->nodetype, pri->switchtype);
++#ifdef HAVE_PRI_SERVICE_MESSAGES
++ if (pri->enable_service_message_support) {
++ pri_set_service_message_support(pri->dchans[i], 1);
++ }
++#endif
+ break;
+ }
+ /* Force overlap dial if we're doing GR-303! */
+@@ -13638,6 +15131,149 @@
+ }
+ #endif /* defined(HAVE_PRI) */
+
++#ifdef HAVE_PRI_SERVICE_MESSAGES
++static char *handle_pri_service_generic(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a, int changestatus)
++{
++ int why;
++ int channel;
++ int trunkgroup;
++ int x, y, fd = a->fd;
++ int interfaceid = 0;
++ char *c;
++ char state;
++ char db_chan_name[20], db_answer[5];
++ struct dahdi_pvt *start, *tmp = NULL;
++ struct dahdi_pri *pri = NULL;
++ ast_mutex_t *lock;
++
++ lock = &iflock;
++ start = iflist;
++
++ if (a->argc < 5 || a->argc > 6)
++ return CLI_SHOWUSAGE;
++ if ((c = strchr(a->argv[4], ':'))) {
++ if (sscanf(a->argv[4], "%d:%d", &trunkgroup, &channel) != 2)
++ return CLI_SHOWUSAGE;
++ if ((trunkgroup < 1) || (channel < 1))
++ return CLI_SHOWUSAGE;
++ for (x=0;x<NUM_SPANS;x++) {
++ if (pris[x].trunkgroup == trunkgroup) {
++ pri = pris + x;
++ break;
++ }
++ }
++ if (pri) {
++ start = pri->crvs;
++ lock = &pri->lock;
++ } else {
++ ast_cli(fd, "No such trunk group %d\n", trunkgroup);
++ return CLI_FAILURE;
++ }
++ } else
++ channel = atoi(a->argv[4]);
++
++ if (a->argc == 6)
++ interfaceid = atoi(a->argv[5]);
++
++ /* either servicing a D-Channel */
++ for (x = 0; x < NUM_SPANS; x++) {
++ for (y = 0; y < NUM_DCHANS; y++) {
++ if (pris[x].dchannels[y] == channel) {
++ pri = pris + x;
++ pri_maintenance_service(pri->pri, interfaceid, -1, changestatus);
++ return CLI_SUCCESS;
++ }
++ }
++ }
++
++ /* or servicing a B-Channel */
++ ast_mutex_lock(lock);
++ tmp = start;
++ while (tmp) {
++ if (tmp->pri && tmp->channel == channel) {
++ if (!tmp->pri->enable_service_message_support) {
++ ast_cli(fd, "\n\tThis operation has not been enabled in chan_dahdi.conf, set 'service_message_support=yes' to use this operation.\n\tNote only 4ESS and 5ESS switch types are supported.\n\n");
++ return CLI_SUCCESS;
++ }
++ why = -1;
++ snprintf(db_chan_name, sizeof(db_chan_name), "%s/%d:%d", dahdi_db, tmp->span, channel);
++ if (!ast_db_get(db_chan_name, SRVST_DBKEY, db_answer, sizeof(db_answer))) {
++ sscanf(db_answer, "%c:%d", &state, &why);
++ ast_db_del(db_chan_name, SRVST_DBKEY);
++ }
++ switch(changestatus) {
++ case 0: /* enable */
++ if (why > -1) {
++ if (why & SRVST_FAREND) {
++ why = SRVST_FAREND;
++ snprintf(db_answer, sizeof(db_answer), "%s:%d", SRVST_TYPE_OOS, why);
++ ast_db_put(db_chan_name, SRVST_DBKEY, db_answer);
++ ast_debug(2, "channel '%d' service state { near: in-service, far: out-of-service }\n", channel);
++ }
++ }
++ break;
++ /* case 1: -- loop */
++ case 2: /* disable */
++ if (why == -1) {
++ why = SRVST_NEAREND;
++ } else {
++ why |= SRVST_NEAREND;
++ }
++ snprintf(db_answer, sizeof(db_answer), "%s:%d", SRVST_TYPE_OOS, why);
++ ast_db_put(db_chan_name, SRVST_DBKEY, db_answer);
++ break;
++ /* case 3: -- continuity */
++ /* case 4: -- shutdown */
++ default:
++ ast_log(LOG_WARNING, "Unsupported changestatus: '%d'\n", changestatus);
++ }
++ pri_maintenance_service(tmp->pri->pri, PRI_SPAN(PVT_TO_CHANNEL(tmp)), PVT_TO_CHANNEL(tmp), changestatus);
++ ast_mutex_unlock(lock);
++ return CLI_SUCCESS;
++ }
++ tmp = tmp->next;
++ }
++ ast_mutex_unlock(lock);
++
++ ast_cli(fd, "Unable to find given channel %d, possibly not a PRI\n", channel);
++ return CLI_FAILURE;
++}
++
++static char *handle_pri_service_enable_channel(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
++{
++ switch (cmd) {
++ case CLI_INIT:
++ e->command = "pri service enable channel";
++ e->usage =
++ "Usage: pri service enable channel <channel> [<interface id>]\n"
++ " Send an AT&T / NFAS / CCS ANSI T1.607 maintenance message\n"
++ " to restore a channel to service, with optional interface id\n"
++ " as agreed upon with remote switch operator\n";
++ return NULL;
++ case CLI_GENERATE:
++ return NULL;
++ }
++ return handle_pri_service_generic(e, cmd, a, 0);
++}
++
++static char *handle_pri_service_disable_channel(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
++{
++ switch (cmd) {
++ case CLI_INIT:
++ e->command = "pri service disable channel";
++ e->usage =
++ "Usage: pri service disable channel <chan num> [<interface id>]\n"
++ " Send an AT&T / NFAS / CCS ANSI T1.607 maintenance message\n"
++ " to remove a channel from service, with optional interface id\n"
++ " as agreed upon with remote switch operator\n";
++ return NULL;
++ case CLI_GENERATE:
++ return NULL;
++ }
++ return handle_pri_service_generic(e, cmd, a, 2);
++}
++#endif
++
+ #if defined(HAVE_PRI)
+ static void build_status(char *s, size_t len, int status, int active)
+ {
+@@ -13814,6 +15450,10 @@
+ #if defined(HAVE_PRI)
+ static struct ast_cli_entry dahdi_pri_cli[] = {
+ AST_CLI_DEFINE(handle_pri_debug, "Enables PRI debugging on a span"),
++#ifdef HAVE_PRI_SERVICE_MESSAGES
++ AST_CLI_DEFINE(handle_pri_service_enable_channel, "Return a channel to service"),
++ AST_CLI_DEFINE(handle_pri_service_disable_channel, "Remove a channel from service"),
++#endif
+ 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"),
+@@ -14259,14 +15899,14 @@
+ 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;
+- ast_debug(3, "Waiting on %d ss_thread(s) to finish\n", ss_thread_count);
++ ast_debug(3, "Waiting on %d analog_ss_thread(s) to finish\n", ss_thread_count);
+
+ 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 analog_ss_threads terminate */
+ }
+- ast_cond_wait(&ss_thread_complete, &ss_thread_lock);
+- }
++ ast_cond_wait(&ss_thread_complete, &ss_thread_lock);
++ }
+
+ /* ensure any created channels before monitor threads were stopped are hungup */
+ dahdi_softhangup_all();
+@@ -14619,6 +16259,9 @@
+ ast_cli(a->fd, "MFC/R2 Max ANI: %d\n", openr2_context_get_max_ani(r2context));
+ ast_cli(a->fd, "MFC/R2 Max DNIS: %d\n", openr2_context_get_max_dnis(r2context));
+ ast_cli(a->fd, "MFC/R2 Get ANI First: %s\n", openr2_context_get_ani_first(r2context) ? "Yes" : "No");
++#if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 1
++ ast_cli(a->fd, "MFC/R2 Skip Category Request: %s\n", openr2_context_get_skip_category_request(r2context) ? "Yes" : "No");
++#endif
+ ast_cli(a->fd, "MFC/R2 Immediate Accept: %s\n", openr2_context_get_immediate_accept(r2context) ? "Yes" : "No");
+ ast_cli(a->fd, "MFC/R2 Accept on Offer: %s\n", tmp->mfcr2_accept_on_offer ? "Yes" : "No");
+ ast_cli(a->fd, "MFC/R2 Charge Calls: %s\n", tmp->mfcr2_charge_calls ? "Yes" : "No");
+@@ -15054,14 +16697,14 @@
+ {
+ if (p) {
+ switch (mode) {
+- case TRANSFER:
+- p->fake_event = DAHDI_EVENT_WINKFLASH;
+- break;
+- case HANGUP:
+- 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);
++ case TRANSFER:
++ p->fake_event = DAHDI_EVENT_WINKFLASH;
++ break;
++ case HANGUP:
++ 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);
+ }
+ }
+ return 0;
+@@ -15746,11 +17389,11 @@
+ #endif
+
+ ast_cli_unregister_multiple(dahdi_cli, ARRAY_LEN(dahdi_cli));
+- ast_manager_unregister( "DAHDIDialOffhook" );
+- ast_manager_unregister( "DAHDIHangup" );
+- ast_manager_unregister( "DAHDITransfer" );
+- ast_manager_unregister( "DAHDIDNDoff" );
+- ast_manager_unregister( "DAHDIDNDon" );
++ ast_manager_unregister("DAHDIDialOffhook");
++ ast_manager_unregister("DAHDIHangup");
++ ast_manager_unregister("DAHDITransfer");
++ ast_manager_unregister("DAHDIDNDoff");
++ ast_manager_unregister("DAHDIDNDon");
+ ast_manager_unregister("DAHDIShowChannels");
+ ast_manager_unregister("DAHDIRestart");
+ ast_channel_unregister(&dahdi_tech);
+@@ -15993,49 +17636,15 @@
+ return -1;
+ ast_log(LOG_DEBUG, "Channel '%s' configured.\n", v->value);
+ } else if (!strcasecmp(v->name, "buffers")) {
+- int res;
+- char policy[21] = "";
+-
+- res = sscanf(v->value, "%d,%20s", &confp->chan.buf_no, policy);
+- if (res != 2) {
+- ast_log(LOG_WARNING, "Parsing buffers option data failed, using defaults.\n");
++ if (parse_buffers_policy(v->value, &confp->chan.buf_no, &confp->chan.buf_policy)) {
++ ast_log(LOG_WARNING, "Using default buffer policy.\n");
+ confp->chan.buf_no = numbufs;
+- continue;
+- }
+- if (confp->chan.buf_no < 0)
+- confp->chan.buf_no = numbufs;
+- if (!strcasecmp(policy, "full")) {
+- 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;
++ if (!parse_buffers_policy(v->value, &confp->chan.faxbuf_no, &confp->chan.faxbuf_policy)) {
++ confp->chan.usefaxbuffers = 1;
+ }
+- 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")) {
+@@ -16597,6 +18206,14 @@
+ #endif
+ } else if (!strcasecmp(v->name, "discardremoteholdretrieval")) {
+ confp->pri.discardremoteholdretrieval = ast_true(v->value);
++#ifdef HAVE_PRI_SERVICE_MESSAGES
++ } else if (!strcasecmp(v->name, "service_message_support")) {
++ /* assuming switchtype for this channel group has been configured already */
++ if ((confp->pri.switchtype == PRI_SWITCH_ATT4ESS || confp->pri.switchtype == PRI_SWITCH_LUCENT5E) && ast_true(v->value))
++ confp->pri.enable_service_message_support = 1;
++ else
++ confp->pri.enable_service_message_support = 0;
++#endif
+ #ifdef HAVE_PRI_INBANDDISCONNECT
+ } else if (!strcasecmp(v->name, "inbanddisconnect")) {
+ confp->pri.inbanddisconnect = ast_true(v->value);
+@@ -16619,10 +18236,9 @@
+ }
+ } else
+ ast_log(LOG_WARNING, "'%s' is not a valid ISDN timer configuration string at line %d.\n", v->value, v->lineno);
+-
++#endif /* PRI_GETSET_TIMERS */
+ } else if (!strcasecmp(v->name, "facilityenable")) {
+ confp->pri.facilityenable = ast_true(v->value);
+-#endif /* PRI_GETSET_TIMERS */
+ #endif /* HAVE_PRI */
+ #ifdef HAVE_SS7
+ } else if (!strcasecmp(v->name, "ss7type")) {
+@@ -17220,13 +18836,13 @@
+ 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" );
+- ast_manager_register( "DAHDIDialOffhook", 0, action_dahdidialoffhook, "Dial over DAHDI channel while offhook" );
+- ast_manager_register( "DAHDIDNDon", 0, action_dahdidndon, "Toggle DAHDI channel Do Not Disturb status ON" );
+- ast_manager_register( "DAHDIDNDoff", 0, action_dahdidndoff, "Toggle DAHDI channel Do Not Disturb status OFF" );
+- 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_manager_register_xml("DAHDITransfer", 0, action_transfer);
++ ast_manager_register_xml("DAHDIHangup", 0, action_transferhangup);
++ ast_manager_register_xml("DAHDIDialOffhook", 0, action_dahdidialoffhook);
++ ast_manager_register_xml("DAHDIDNDon", 0, action_dahdidndon);
++ ast_manager_register_xml("DAHDIDNDoff", 0, action_dahdidndoff);
++ ast_manager_register_xml("DAHDIShowChannels", 0, action_dahdishowchannels);
++ ast_manager_register_xml("DAHDIRestart", 0, action_dahdirestart);
+
+ ast_cond_init(&ss_thread_complete, NULL);
+
+@@ -17345,6 +18961,7 @@
+ return 0;
+ }
+
++
+ /* This is a workaround so that menuselect displays a proper description
+ * AST_MODULE_INFO(, , "DAHDI Telephony"
+ */
+Index: channels/chan_phone.c
+===================================================================
+--- a/channels/chan_phone.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/channels/chan_phone.c (.../trunk) (revision 202568)
+@@ -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/sig_analog.c
+===================================================================
+--- a/channels/sig_analog.c (.../tags/1.6.2.0-beta3) (revision 0)
++++ b/channels/sig_analog.c (.../trunk) (revision 202568)
+@@ -0,0 +1,3262 @@
++/*
++ * Asterisk -- An open source telephony toolkit.
++ *
++ * Copyright (C) 1999 - 2009, 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 Analog signaling module
++ *
++ * \author Matthew Fredrickson <creslin@digium.com>
++ */
++
++#include "asterisk.h"
++
++#include <errno.h>
++#include <ctype.h>
++
++#include "asterisk/utils.h"
++#include "asterisk/options.h"
++#include "asterisk/pbx.h"
++#include "asterisk/file.h"
++#include "asterisk/callerid.h"
++#include "asterisk/say.h"
++#include "asterisk/manager.h"
++#include "asterisk/astdb.h"
++#include "asterisk/features.h"
++
++#include "sig_analog.h"
++
++#define POLARITY_IDLE 0
++#define POLARITY_REV 1
++#define MIN_MS_SINCE_FLASH ( (2000) ) /*!< 2000 ms */
++static int analog_matchdigittimeout = 3000;
++static int analog_gendigittimeout = 8000;
++static int analog_firstdigittimeout = 16000;
++static char analog_defaultcic[64] = "";
++static char analog_defaultozz[64] = "";
++
++static const struct {
++ enum analog_sigtype sigtype;
++ const char const *name;
++} sigtypes[] = {
++ { ANALOG_SIG_FXOLS, "fxo_ls" },
++ { ANALOG_SIG_FXOKS, "fxo_ks" },
++ { ANALOG_SIG_FXOGS, "fxo_gs" },
++ { ANALOG_SIG_FXSLS, "fxs_ls" },
++ { ANALOG_SIG_FXSKS, "fxs_ks" },
++ { ANALOG_SIG_FXSGS, "fxs_gs" },
++ { ANALOG_SIG_EMWINK, "em_w" },
++ { ANALOG_SIG_EM, "em" },
++ { ANALOG_SIG_EM_E1, "em_e1" },
++ { ANALOG_SIG_FEATD, "featd" },
++ { ANALOG_SIG_FEATDMF, "featdmf" },
++ { ANALOG_SIG_FEATDMF_TA, "featdmf_ta" },
++ { ANALOG_SIG_FEATB, "featb" },
++ { ANALOG_SIG_FGC_CAMA, "fgccama" },
++ { ANALOG_SIG_FGC_CAMAMF, "fgccamamf" },
++ { ANALOG_SIG_SF, "sf" },
++ { ANALOG_SIG_SFWINK, "sf_w" },
++ { ANALOG_SIG_SF_FEATD, "sf_featd" },
++ { ANALOG_SIG_SF_FEATDMF, "sf_featdmf" },
++ { ANALOG_SIG_SF_FEATB, "sf_featb" },
++ { ANALOG_SIG_E911, "e911" },
++};
++
++static const struct {
++ unsigned int cid_type;
++ const char const *name;
++} cidtypes[] = {
++ { CID_SIG_BELL, "bell" },
++ { CID_SIG_V23, "v23" },
++ { CID_SIG_V23_JP, "v23_jp" },
++ { CID_SIG_DTMF, "dtmf" },
++ /* "smdi" is intentionally not supported here, as there is a much better
++ * way to do this in the dialplan now. */
++};
++
++enum analog_sigtype analog_str_to_sigtype(const char *name)
++{
++ int i;
++
++ for (i = 0; i < ARRAY_LEN(sigtypes); i++) {
++ if (!strcasecmp(sigtypes[i].name, name)) {
++ return sigtypes[i].sigtype;
++ }
++ }
++
++ return 0;
++}
++
++const char *analog_sigtype_to_str(enum analog_sigtype sigtype)
++{
++ int i;
++
++ for (i = 0; i < ARRAY_LEN(sigtypes); i++) {
++ if (sigtype == sigtypes[i].sigtype) {
++ return sigtypes[i].name;
++ }
++ }
++
++ return "Unknown";
++}
++
++unsigned int analog_str_to_cidtype(const char *name)
++{
++ int i;
++
++ for (i = 0; i < ARRAY_LEN(cidtypes); i++) {
++ if (!strcasecmp(cidtypes[i].name, name)) {
++ return cidtypes[i].cid_type;
++ }
++ }
++
++ return 0;
++}
++
++const char *analog_cidtype_to_str(unsigned int cid_type)
++{
++ int i;
++
++ for (i = 0; i < ARRAY_LEN(cidtypes); i++) {
++ if (cid_type == cidtypes[i].cid_type) {
++ return cidtypes[i].name;
++ }
++ }
++
++ return "Unknown";
++}
++
++static int analog_start_cid_detect(struct analog_pvt *p, int cid_signalling)
++{
++ if (p->calls->start_cid_detect)
++ return p->calls->start_cid_detect(p->chan_pvt, cid_signalling);
++ else
++ return -1;
++}
++
++static int analog_stop_cid_detect(struct analog_pvt *p)
++{
++ if (p->calls->stop_cid_detect)
++ return p->calls->stop_cid_detect(p->chan_pvt);
++ else
++ return -1;
++}
++
++static int analog_get_callerid(struct analog_pvt *p, char *name, char *number, enum analog_event *ev, size_t timeout)
++{
++ if (p->calls->get_callerid)
++ return p->calls->get_callerid(p->chan_pvt, name, number, ev, timeout);
++ else
++ return -1;
++}
++
++static int analog_get_event(struct analog_pvt *p)
++{
++ if (p->calls->get_event)
++ return p->calls->get_event(p->chan_pvt);
++ else
++ return -1;
++}
++
++static int analog_wait_event(struct analog_pvt *p)
++{
++ if (p->calls->wait_event)
++ return p->calls->wait_event(p->chan_pvt);
++ else
++ return -1;
++}
++
++enum analog_cid_start analog_str_to_cidstart(const char *value)
++{
++ if (!strcasecmp(value, "ring")) {
++ return ANALOG_CID_START_RING;
++ } else if (!strcasecmp(value, "polarity")) {
++ return ANALOG_CID_START_POLARITY;
++ } else if (!strcasecmp(value, "polarity_in")) {
++ return ANALOG_CID_START_POLARITY_IN;
++ }
++
++ return 0;
++}
++
++const char *analog_cidstart_to_str(enum analog_cid_start cid_start)
++{
++ switch (cid_start) {
++ case ANALOG_CID_START_RING:
++ return "Ring";
++ case ANALOG_CID_START_POLARITY:
++ return "Polarity";
++ case ANALOG_CID_START_POLARITY_IN:
++ return "Polarity_In";
++ }
++
++ return "Unknown";
++}
++
++static char *analog_event2str(enum analog_event event)
++{
++ char *res;
++ switch (event) {
++ case ANALOG_EVENT_DIALCOMPLETE:
++ res = "ANALOG_EVENT_DIALCOMPLETE";
++ break;
++ case ANALOG_EVENT_WINKFLASH:
++ res = "ANALOG_EVENT_WINKFLASH";
++ break;
++ case ANALOG_EVENT_ONHOOK:
++ res = "ANALOG_EVENT_ONHOOK";
++ break;
++ case ANALOG_EVENT_RINGOFFHOOK:
++ res = "ANALOG_EVENT_RINGOFFHOOK";
++ break;
++ case ANALOG_EVENT_ALARM:
++ res = "ANALOG_EVENT_ALARM";
++ break;
++ case ANALOG_EVENT_NOALARM:
++ res = "ANALOG_EVENT_NOALARM";
++ break;
++ case ANALOG_EVENT_HOOKCOMPLETE:
++ res = "ANALOG_EVENT_HOOKCOMPLETE";
++ break;
++ case ANALOG_EVENT_POLARITY:
++ res = "ANALOG_EVENT_POLARITY";
++ break;
++ case ANALOG_EVENT_RINGERON:
++ res = "ANALOG_EVENT_RINGERON";
++ break;
++ case ANALOG_EVENT_RINGEROFF:
++ res = "ANALOG_EVENT_RINGEROFF";
++ break;
++ case ANALOG_EVENT_RINGBEGIN:
++ res = "ANALOG_EVENT_RINGBEGIN";
++ break;
++ case ANALOG_EVENT_PULSE_START:
++ res = "ANALOG_EVENT_PULSE_START";
++ break;
++ case ANALOG_EVENT_NEONMWI_ACTIVE:
++ res = "ANALOG_EVENT_NEONMWI_ACTIVE";
++ break;
++ case ANALOG_EVENT_NEONMWI_INACTIVE:
++ res = "ANALOG_EVENT_NEONMWI_INACTIVE";
++ break;
++ default:
++ res = "UNKNOWN/OTHER";
++ break;
++ }
++
++ return res;
++}
++
++static void analog_swap_subs(struct analog_pvt *p, enum analog_sub a, enum analog_sub b)
++{
++ int tinthreeway;
++ struct ast_channel *towner;
++
++ ast_debug(1, "Swapping %d and %d\n", a, b);
++
++ towner = p->subs[a].owner;
++ tinthreeway = p->subs[a].inthreeway;
++
++ p->subs[a].owner = p->subs[b].owner;
++ p->subs[a].inthreeway = p->subs[b].inthreeway;
++
++ p->subs[b].owner = towner;
++ p->subs[b].inthreeway = tinthreeway;
++
++ if (p->calls->swap_subs)
++ p->calls->swap_subs(p->chan_pvt, a, p->subs[a].owner, b, p->subs[b].owner);
++
++}
++
++static int analog_alloc_sub(struct analog_pvt *p, enum analog_sub x)
++{
++ p->subs[x].allocd = 1;
++ if (p->calls->allocate_sub)
++ return p->calls->allocate_sub(p->chan_pvt, x);
++
++ return 0;
++}
++
++static int analog_unalloc_sub(struct analog_pvt *p, enum analog_sub x)
++{
++ p->subs[x].allocd = 0;
++ p->subs[x].owner = NULL;
++ if (p->calls->unallocate_sub)
++ return p->calls->unallocate_sub(p->chan_pvt, x);
++
++ return 0;
++}
++
++static int analog_send_callerid(struct analog_pvt *p, int cwcid, struct ast_callerid *cid)
++{
++ ast_debug(1, "Sending callerid. CID_NAME: '%s' CID_NUM: '%s'\n", cid->cid_name, cid->cid_num);
++
++ if (cwcid) {
++ p->callwaitcas = 0;
++ }
++
++ if (p->calls->send_callerid)
++ return p->calls->send_callerid(p->chan_pvt, cwcid, cid);
++ else
++ return 0;
++}
++
++static int analog_get_index(struct ast_channel *ast, struct analog_pvt *p, int nullok)
++{
++ int res;
++ if (p->subs[ANALOG_SUB_REAL].owner == ast)
++ res = ANALOG_SUB_REAL;
++ else if (p->subs[ANALOG_SUB_CALLWAIT].owner == ast)
++ res = ANALOG_SUB_CALLWAIT;
++ else if (p->subs[ANALOG_SUB_THREEWAY].owner == ast)
++ res = ANALOG_SUB_THREEWAY;
++ else {
++ res = -1;
++ if (!nullok)
++ ast_log(LOG_WARNING, "Unable to get index, and nullok is not asserted\n");
++ }
++ return res;
++}
++
++static int analog_dsp_reset_and_flush_digits(struct analog_pvt *p)
++{
++ if (p->calls->dsp_reset_and_flush_digits)
++ return p->calls->dsp_reset_and_flush_digits(p->chan_pvt);
++ else
++ /* Return 0 since I think this is unnecessary to do in most cases it is used. Mostly only for ast_dsp */
++ return 0;
++}
++
++static int analog_play_tone(struct analog_pvt *p, enum analog_sub sub, enum analog_tone tone)
++{
++ if (p->calls->play_tone)
++ return p->calls->play_tone(p->chan_pvt, sub, tone);
++ else
++ return -1;
++}
++
++static struct ast_channel * analog_new_ast_channel(struct analog_pvt *p, int state, int startpbx, enum analog_sub sub)
++{
++ struct ast_channel *c;
++
++ if (p->calls->new_ast_channel)
++ c = p->calls->new_ast_channel(p->chan_pvt, state, startpbx, sub);
++ else
++ return NULL;
++
++ p->subs[sub].owner = c;
++ if (!p->owner)
++ p->owner = c;
++ return c;
++}
++
++static int analog_set_echocanceller(struct analog_pvt *p, int enable)
++{
++ if (p->calls->set_echocanceller)
++ return p->calls->set_echocanceller(p->chan_pvt, enable);
++ else
++ return -1;
++}
++
++static int analog_train_echocanceller(struct analog_pvt *p)
++{
++ if (p->calls->train_echocanceller)
++ return p->calls->train_echocanceller(p->chan_pvt);
++ else
++ return -1;
++}
++
++static int analog_is_off_hook(struct analog_pvt *p)
++{
++ if (p->calls->is_off_hook)
++ return p->calls->is_off_hook(p->chan_pvt);
++ else
++ return -1;
++}
++
++static int analog_ring(struct analog_pvt *p)
++{
++ if (p->calls->ring)
++ return p->calls->ring(p->chan_pvt);
++ else
++ return -1;
++}
++
++static int analog_start(struct analog_pvt *p)
++{
++ if (p->calls->start)
++ return p->calls->start(p->chan_pvt);
++ else
++ return -1;
++}
++
++static int analog_dial_digits(struct analog_pvt *p, enum analog_sub sub, struct analog_dialoperation *dop)
++{
++ if (p->calls->dial_digits)
++ return p->calls->dial_digits(p->chan_pvt, sub, dop);
++ else
++ return -1;
++}
++
++static int analog_on_hook(struct analog_pvt *p)
++{
++ if (p->calls->on_hook)
++ return p->calls->on_hook(p->chan_pvt);
++ else
++ return -1;
++}
++
++static int analog_check_for_conference(struct analog_pvt *p)
++{
++ if (p->calls->check_for_conference)
++ return p->calls->check_for_conference(p->chan_pvt);
++ else
++ return -1;
++}
++
++static void analog_all_subchannels_hungup(struct analog_pvt *p)
++{
++ if (p->calls->all_subchannels_hungup)
++ p->calls->all_subchannels_hungup(p->chan_pvt);
++}
++
++static void analog_unlock_private(struct analog_pvt *p)
++{
++ if (p->calls->unlock_private)
++ p->calls->unlock_private(p->chan_pvt);
++}
++
++static void analog_lock_private(struct analog_pvt *p)
++{
++ if (p->calls->lock_private)
++ p->calls->lock_private(p->chan_pvt);
++}
++
++static int analog_off_hook(struct analog_pvt *p)
++{
++ if (p->calls->off_hook)
++ return p->calls->off_hook(p->chan_pvt);
++ else
++ return -1;
++}
++
++static int analog_dsp_set_digitmode(struct analog_pvt *p, enum analog_dsp_digitmode mode)
++{
++ if (p->calls->dsp_set_digitmode)
++ return p->calls->dsp_set_digitmode(p->chan_pvt, mode);
++ else
++ return -1;
++}
++
++static void analog_cb_handle_dtmfup(struct analog_pvt *p, struct ast_channel *ast, enum analog_sub analog_index, struct ast_frame **dest)
++{
++ if (p->calls->handle_dtmfup)
++ p->calls->handle_dtmfup(p->chan_pvt, ast, analog_index, dest);
++}
++
++static int analog_wink(struct analog_pvt *p, enum analog_sub index)
++{
++ if (p->calls->wink)
++ return p->calls->wink(p->chan_pvt, index);
++ else
++ return -1;
++}
++
++static int analog_has_voicemail(struct analog_pvt *p)
++{
++ if (p->calls->has_voicemail)
++ return p->calls->has_voicemail(p->chan_pvt);
++ else
++ return -1;
++}
++
++static int analog_is_dialing(struct analog_pvt *p, enum analog_sub index)
++{
++ if (p->calls->is_dialing)
++ return p->calls->is_dialing(p->chan_pvt, index);
++ else
++ return -1;
++}
++
++static int analog_attempt_transfer(struct analog_pvt *p)
++{
++ /* In order to transfer, we need at least one of the channels to
++ actually be in a call bridge. We can't conference two applications
++ together (but then, why would we want to?) */
++ if (ast_bridged_channel(p->subs[ANALOG_SUB_REAL].owner)) {
++ /* The three-way person we're about to transfer to could still be in MOH, so
++ stop if now if appropriate */
++ if (ast_bridged_channel(p->subs[ANALOG_SUB_THREEWAY].owner))
++ ast_queue_control(p->subs[ANALOG_SUB_THREEWAY].owner, AST_CONTROL_UNHOLD);
++ if (p->subs[ANALOG_SUB_REAL].owner->_state == AST_STATE_RINGING) {
++ ast_indicate(ast_bridged_channel(p->subs[ANALOG_SUB_REAL].owner), AST_CONTROL_RINGING);
++ }
++ if (p->subs[ANALOG_SUB_THREEWAY].owner->_state == AST_STATE_RING) {
++ analog_play_tone(p, ANALOG_SUB_THREEWAY, ANALOG_TONE_RINGTONE);
++ }
++ if (ast_channel_masquerade(p->subs[ANALOG_SUB_THREEWAY].owner, ast_bridged_channel(p->subs[ANALOG_SUB_REAL].owner))) {
++ ast_log(LOG_WARNING, "Unable to masquerade %s as %s\n",
++ ast_bridged_channel(p->subs[ANALOG_SUB_REAL].owner)->name, p->subs[ANALOG_SUB_THREEWAY].owner->name);
++ return -1;
++ }
++ /* Orphan the channel after releasing the lock */
++ ast_channel_unlock(p->subs[ANALOG_SUB_THREEWAY].owner);
++ analog_unalloc_sub(p, ANALOG_SUB_THREEWAY);
++ } else if (ast_bridged_channel(p->subs[ANALOG_SUB_THREEWAY].owner)) {
++ ast_queue_control(p->subs[ANALOG_SUB_REAL].owner, AST_CONTROL_UNHOLD);
++ if (p->subs[ANALOG_SUB_THREEWAY].owner->_state == AST_STATE_RINGING) {
++ ast_indicate(ast_bridged_channel(p->subs[ANALOG_SUB_THREEWAY].owner), AST_CONTROL_RINGING);
++ }
++ if (p->subs[ANALOG_SUB_REAL].owner->_state == AST_STATE_RING) {
++ analog_play_tone(p, ANALOG_SUB_REAL, ANALOG_TONE_RINGTONE);
++ }
++ if (ast_channel_masquerade(p->subs[ANALOG_SUB_REAL].owner, ast_bridged_channel(p->subs[ANALOG_SUB_THREEWAY].owner))) {
++ ast_log(LOG_WARNING, "Unable to masquerade %s as %s\n",
++ ast_bridged_channel(p->subs[ANALOG_SUB_THREEWAY].owner)->name, p->subs[ANALOG_SUB_REAL].owner->name);
++ return -1;
++ }
++ /* Three-way is now the REAL */
++ analog_swap_subs(p, ANALOG_SUB_THREEWAY, ANALOG_SUB_REAL);
++ ast_channel_unlock(p->subs[ANALOG_SUB_THREEWAY].owner);
++ analog_unalloc_sub(p, ANALOG_SUB_THREEWAY);
++ /* Tell the caller not to hangup */
++ return 1;
++ } else {
++ ast_debug(1, "Neither %s nor %s are in a bridge, nothing to transfer\n",
++ p->subs[ANALOG_SUB_REAL].owner->name, p->subs[ANALOG_SUB_THREEWAY].owner->name);
++ ast_softhangup_nolock(p->subs[ANALOG_SUB_THREEWAY].owner, AST_SOFTHANGUP_DEV);
++ return -1;
++ }
++ return 0;
++}
++
++static int analog_update_conf(struct analog_pvt *p)
++{
++ int x;
++ int needconf = 0;
++
++ /* Start with the obvious, general stuff */
++ for (x = 0; x < 3; x++) {
++ /* Look for three way calls */
++ if ((p->subs[x].allocd) && p->subs[x].inthreeway) {
++ if (p->calls->conf_add)
++ p->calls->conf_add(p->chan_pvt, x);
++ needconf++;
++ } else {
++ if (p->calls->conf_del)
++ p->calls->conf_del(p->chan_pvt, x);
++ }
++ }
++ ast_debug(1, "Updated conferencing on %d, with %d conference users\n", p->channel, needconf);
++
++ if (p->calls->complete_conference_update)
++ p->calls->complete_conference_update(p->chan_pvt, needconf);
++ return 0;
++}
++
++struct ast_channel * analog_request(struct analog_pvt *p, int *callwait)
++{
++ ast_log(LOG_DEBUG, "%s %d\n", __FUNCTION__, p->channel);
++ *callwait = (p->owner != NULL);
++
++ if (p->owner) {
++ if (analog_alloc_sub(p, ANALOG_SUB_CALLWAIT)) {
++ ast_log(LOG_ERROR, "Unable to alloc subchannel\n");
++ return NULL;
++ }
++ }
++
++ return analog_new_ast_channel(p, AST_STATE_RESERVED, 0, p->owner ? ANALOG_SUB_CALLWAIT : ANALOG_SUB_REAL);
++}
++
++int analog_available(struct analog_pvt *p, int channelmatch, ast_group_t groupmatch, int *busy, int *channelmatched, int *groupmatched)
++{
++ int offhook;
++
++ ast_log(LOG_DEBUG, "%s %d\n", __FUNCTION__, p->channel);
++ /* We're at least busy at this point */
++ if (busy) {
++ if ((p->sig == ANALOG_SIG_FXOKS) || (p->sig == ANALOG_SIG_FXOLS) || (p->sig == ANALOG_SIG_FXOGS))
++ *busy = 1;
++ }
++ /* If do not disturb, definitely not */
++ if (p->dnd)
++ return 0;
++ /* If guard time, definitely not */
++ if (p->guardtime && (time(NULL) < p->guardtime))
++ return 0;
++
++ /* If no owner definitely available */
++ if (!p->owner) {
++ if (p->sig == ANALOG_SIG_FXSLS)
++ return 1;
++
++ offhook = analog_is_off_hook(p);
++
++ if ((p->sig == ANALOG_SIG_FXSKS) || (p->sig == ANALOG_SIG_FXSGS)) {
++ /* When "onhook" that means no battery on the line, and thus
++ it is out of service..., if it's on a TDM card... If it's a channel
++ bank, there is no telling... */
++ if (offhook)
++ return 1;
++ else
++ return 0;
++ } else if (offhook) {
++ ast_debug(1, "Channel %d off hook, can't use\n", p->channel);
++ /* Not available when the other end is off hook */
++ return 0;
++ }
++ return 1;
++ }
++
++ /* If it's not an FXO, forget about call wait */
++ if ((p->sig != ANALOG_SIG_FXOKS) && (p->sig != ANALOG_SIG_FXOLS) && (p->sig != ANALOG_SIG_FXOGS))
++ return 0;
++
++ if (!p->callwaiting) {
++ /* If they don't have call waiting enabled, then for sure they're unavailable at this point */
++ return 0;
++ }
++
++ if (p->subs[ANALOG_SUB_CALLWAIT].allocd) {
++ /* 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)) {
++ /* If the current call is not up, then don't allow the call */
++ return 0;
++ }
++ if ((p->subs[ANALOG_SUB_THREEWAY].owner) && (!p->subs[ANALOG_SUB_THREEWAY].inthreeway)) {
++ /* Can't take a call wait when the three way calling hasn't been merged yet. */
++ return 0;
++ }
++ /* We're cool */
++ return 1;
++}
++
++static int analog_stop_callwait(struct analog_pvt *p)
++{
++ if (p->callwaitingcallerid)
++ p->callwaitcas = 0;
++
++ if (p->calls->stop_callwait)
++ return p->calls->stop_callwait(p->chan_pvt);
++ else
++ return 0;
++}
++
++static int analog_callwait(struct analog_pvt *p)
++{
++ if (p->callwaitingcallerid)
++ p->callwaitcas = 1;
++ if (p->calls->callwait)
++ return p->calls->callwait(p->chan_pvt);
++ else
++ return 0;
++}
++
++int analog_call(struct analog_pvt *p, struct ast_channel *ast, char *rdest, int timeout)
++{
++ int res, index,mysig;
++ char *c, *n, *l;
++ char dest[256]; /* must be same length as p->dialdest */
++
++ ast_log(LOG_DEBUG, "CALLING CID_NAME: %s CID_NUM:: %s\n", ast->connected.id.name, ast->connected.id.number);
++
++ ast_copy_string(dest, rdest, sizeof(dest));
++ ast_copy_string(p->dialdest, rdest, sizeof(p->dialdest));
++
++ if ((ast->_state == AST_STATE_BUSY)) {
++ ast_queue_control(p->subs[ANALOG_SUB_REAL].owner, AST_CONTROL_BUSY);
++ return 0;
++ }
++
++ if ((ast->_state != AST_STATE_DOWN) && (ast->_state != AST_STATE_RESERVED)) {
++ ast_log(LOG_WARNING, "analog_call called on %s, neither down nor reserved\n", ast->name);
++ return -1;
++ }
++
++ p->dialednone = 0;
++
++ mysig = p->sig;
++ if (p->outsigmod > -1)
++ mysig = p->outsigmod;
++
++ switch (mysig) {
++ case ANALOG_SIG_FXOLS:
++ case ANALOG_SIG_FXOGS:
++ case ANALOG_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;
++ /* XXX */
++#if 0
++ /* Choose proper cadence */
++ if ((p->distinctivering > 0) && (p->distinctivering <= num_cadence)) {
++ if (ioctl(p->subs[ANALOG_SUB_REAL].dfd, DAHDI_SETCADENCE, &cadences[p->distinctivering - 1]))
++ ast_log(LOG_WARNING, "Unable to set distinctive ring cadence %d on '%s': %s\n", p->distinctivering, ast->name, strerror(errno));
++ p->cidrings = cidrings[p->distinctivering - 1];
++ } else {
++ if (ioctl(p->subs[ANALOG_SUB_REAL].dfd, DAHDI_SETCADENCE, NULL))
++ ast_log(LOG_WARNING, "Unable to reset default ring on '%s': %s\n", ast->name, strerror(errno));
++ p->cidrings = p->sendcalleridafter;
++ }
++#endif
++ p->cidrings = p->sendcalleridafter;
++
++ /* nick@dccinc.com 4/3/03 mods to allow for deferred dialing */
++ c = strchr(dest, '/');
++ if (c)
++ c++;
++ if (c && (strlen(c) < p->stripmsd)) {
++ ast_log(LOG_WARNING, "Number '%s' is shorter than stripmsd (%d)\n", c, p->stripmsd);
++ c = NULL;
++ }
++ if (c) {
++ p->dop.op = ANALOG_DIAL_OP_REPLACE;
++ snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), "Tw%s", c);
++ ast_debug(1, "FXO: setup deferred dialstring: %s\n", c);
++ } else {
++ p->dop.dialstr[0] = '\0';
++ }
++
++ if (analog_ring(p)) {
++ ast_log(LOG_WARNING, "Unable to ring phone: %s\n", strerror(errno));
++ return -1;
++ }
++ p->dialing = 1;
++ } else {
++ 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->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 */
++ if (analog_callwait(p)) {
++ return -1;
++ }
++ /* Make ring-back */
++ if (analog_play_tone(p, ANALOG_SUB_CALLWAIT, ANALOG_TONE_RINGTONE))
++ ast_log(LOG_WARNING, "Unable to generate call-wait ring-back on channel %s\n", ast->name);
++
++ }
++ n = ast->connected.id.name;
++ l = ast->connected.id.number;
++ if (l)
++ ast_copy_string(p->lastcid_num, l, sizeof(p->lastcid_num));
++ else
++ p->lastcid_num[0] = '\0';
++ if (n)
++ ast_copy_string(p->lastcid_name, n, sizeof(p->lastcid_name));
++ else
++ p->lastcid_name[0] = '\0';
++
++ if (p->use_callerid) {
++ //p->callwaitcas = 0;
++ p->cid.cid_name = p->lastcid_name;
++ p->cid.cid_num = p->lastcid_num;
++ }
++
++
++ ast_setstate(ast, AST_STATE_RINGING);
++ index = analog_get_index(ast, p, 0);
++ if (index > -1) {
++ ast_queue_control(p->subs[index].owner, AST_CONTROL_RINGING);
++ }
++ break;
++ case ANALOG_SIG_FXSLS:
++ case ANALOG_SIG_FXSGS:
++ case ANALOG_SIG_FXSKS:
++ case ANALOG_SIG_EMWINK:
++ case ANALOG_SIG_EM:
++ case ANALOG_SIG_EM_E1:
++ case ANALOG_SIG_FEATD:
++ case ANALOG_SIG_FEATDMF:
++ case ANALOG_SIG_E911:
++ case ANALOG_SIG_FGC_CAMA:
++ case ANALOG_SIG_FGC_CAMAMF:
++ case ANALOG_SIG_FEATB:
++ case ANALOG_SIG_SFWINK:
++ case ANALOG_SIG_SF:
++ case ANALOG_SIG_SF_FEATD:
++ case ANALOG_SIG_SF_FEATDMF:
++ case ANALOG_SIG_FEATDMF_TA:
++ case ANALOG_SIG_SF_FEATB:
++ c = strchr(dest, '/');
++ if (c)
++ c++;
++ else
++ c = "";
++ if (strlen(c) < p->stripmsd) {
++ ast_log(LOG_WARNING, "Number '%s' is shorter than stripmsd (%d)\n", c, p->stripmsd);
++ return -1;
++ }
++ res = analog_start(p);
++ if (res < 0) {
++ if (errno != EINPROGRESS) {
++ return -1;
++ }
++ }
++ ast_log(LOG_DEBUG, "Dialing '%s'\n", c);
++ p->dop.op = ANALOG_DIAL_OP_REPLACE;
++
++ c += p->stripmsd;
++
++ switch (mysig) {
++ case ANALOG_SIG_FEATD:
++ 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 ANALOG_SIG_FEATDMF:
++ 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);
++ break;
++ case ANALOG_SIG_FEATDMF_TA:
++ {
++ const char *cic = "", *ozz = "";
++
++ /* If you have to go through a Tandem Access point you need to use this */
++#ifndef STANDALONE
++ ozz = pbx_builtin_getvar_helper(p->owner, "FEATDMF_OZZ");
++ if (!ozz)
++ ozz = analog_defaultozz;
++ cic = pbx_builtin_getvar_helper(p->owner, "FEATDMF_CIC");
++ if (!cic)
++ cic = analog_defaultcic;
++#endif
++ if (!ozz || !cic) {
++ ast_log(LOG_WARNING, "Unable to dial channel of type feature group D MF tandem access without CIC or OZZ set\n");
++ return -1;
++ }
++ snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), "M*%s%s#", ozz, cic);
++ snprintf(p->finaldial, sizeof(p->finaldial), "M*%s#", c);
++ p->whichwink = 0;
++ }
++ break;
++ case ANALOG_SIG_E911:
++ ast_copy_string(p->dop.dialstr, "M*911#", sizeof(p->dop.dialstr));
++ break;
++ case ANALOG_SIG_FGC_CAMA:
++ snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), "P%s", c);
++ break;
++ case ANALOG_SIG_FGC_CAMAMF:
++ case ANALOG_SIG_FEATB:
++ snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), "M*%s#", c);
++ break;
++ default:
++ if (p->pulse)
++ snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), "P%sw", c);
++ else
++ snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), "T%sw", c);
++ break;
++ }
++
++ if (p->echotraining && (strlen(p->dop.dialstr) > 4)) {
++ memset(p->echorest, 'w', sizeof(p->echorest) - 1);
++ strcpy(p->echorest + (p->echotraining / 400) + 1, p->dop.dialstr + strlen(p->dop.dialstr) - 2);
++ p->echorest[sizeof(p->echorest) - 1] = '\0';
++ p->echobreak = 1;
++ p->dop.dialstr[strlen(p->dop.dialstr)-2] = '\0';
++ } else
++ p->echobreak = 0;
++ if (!res) {
++ if (analog_dial_digits(p, ANALOG_SUB_REAL, &p->dop)) {
++ int saveerr = errno;
++
++ analog_on_hook(p);
++ ast_log(LOG_WARNING, "Dialing failed on channel %d: %s\n", p->channel, strerror(saveerr));
++ return -1;
++ }
++ } else
++ ast_debug(1, "Deferring dialing...\n");
++ p->dialing = 1;
++ if (ast_strlen_zero(c))
++ p->dialednone = 1;
++ ast_setstate(ast, AST_STATE_DIALING);
++ break;
++ default:
++ ast_debug(1, "not yet implemented\n");
++ return -1;
++ }
++ return 0;
++}
++
++int analog_hangup(struct analog_pvt *p, struct ast_channel *ast)
++{
++ int res;
++ int index, x;
++
++ ast_log(LOG_DEBUG, "%s %d\n", __FUNCTION__, p->channel);
++ if (!ast->tech_pvt) {
++ ast_log(LOG_WARNING, "Asked to hangup channel not connected\n");
++ return 0;
++ }
++
++ index = analog_get_index(ast, p, 1);
++
++ x = 0;
++ if (p->origcid_num) {
++ ast_copy_string(p->cid_num, p->origcid_num, sizeof(p->cid_num));
++ 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));
++ free(p->origcid_name);
++ p->origcid_name = NULL;
++ }
++
++ analog_dsp_set_digitmode(p, ANALOG_DIGITMODE_DTMF);
++
++ ast_debug(1, "Hangup: channel: %d index = %d, normal = %d, callwait = %d, thirdcall = %d\n",
++ p->channel, index, p->subs[ANALOG_SUB_REAL].allocd, p->subs[ANALOG_SUB_CALLWAIT].allocd, p->subs[ANALOG_SUB_THREEWAY].allocd);
++ if (index > -1) {
++ /* Real channel, do some fixup */
++ p->subs[index].owner = NULL;
++ p->subs[index].needcallerid = 0;
++ p->polarity = POLARITY_IDLE;
++ if (index == ANALOG_SUB_REAL) {
++ if (p->subs[ANALOG_SUB_CALLWAIT].allocd && p->subs[ANALOG_SUB_THREEWAY].allocd) {
++ ast_debug(1, "Normal call hung up with both three way call and a call waiting call in place?\n");
++ if (p->subs[ANALOG_SUB_CALLWAIT].inthreeway) {
++ /* We had flipped over to answer a callwait and now it's gone */
++ ast_debug(1, "We were flipped over to the callwait, moving back and unowning.\n");
++ /* Move to the call-wait, but un-own us until they flip back. */
++ analog_swap_subs(p, ANALOG_SUB_CALLWAIT, ANALOG_SUB_REAL);
++ analog_unalloc_sub(p, ANALOG_SUB_CALLWAIT);
++ p->owner = NULL;
++ } else {
++ /* The three way hung up, but we still have a call wait */
++ ast_debug(1, "We were in the threeway and have a callwait still. Ditching the threeway.\n");
++ analog_swap_subs(p, ANALOG_SUB_THREEWAY, ANALOG_SUB_REAL);
++ analog_unalloc_sub(p, ANALOG_SUB_THREEWAY);
++ if (p->subs[ANALOG_SUB_REAL].inthreeway) {
++ /* This was part of a three way call. Immediately make way for
++ another call */
++ ast_debug(1, "Call was complete, setting owner to former third call\n");
++ p->owner = p->subs[ANALOG_SUB_REAL].owner;
++ } else {
++ /* This call hasn't been completed yet... Set owner to NULL */
++ ast_debug(1, "Call was incomplete, setting owner to NULL\n");
++ p->owner = NULL;
++ }
++ p->subs[ANALOG_SUB_REAL].inthreeway = 0;
++ }
++ } else if (p->subs[ANALOG_SUB_CALLWAIT].allocd) {
++ /* Move to the call-wait and switch back to them. */
++ analog_swap_subs(p, ANALOG_SUB_CALLWAIT, ANALOG_SUB_REAL);
++ analog_unalloc_sub(p, ANALOG_SUB_CALLWAIT);
++ p->owner = p->subs[ANALOG_SUB_REAL].owner;
++ if (p->owner->_state != AST_STATE_UP)
++ ast_queue_control(p->subs[ANALOG_SUB_REAL].owner, AST_CONTROL_ANSWER);
++ if (ast_bridged_channel(p->subs[ANALOG_SUB_REAL].owner))
++ ast_queue_control(p->subs[ANALOG_SUB_REAL].owner, AST_CONTROL_UNHOLD);
++ } else if (p->subs[ANALOG_SUB_THREEWAY].allocd) {
++ analog_swap_subs(p, ANALOG_SUB_THREEWAY, ANALOG_SUB_REAL);
++ analog_unalloc_sub(p, ANALOG_SUB_THREEWAY);
++ if (p->subs[ANALOG_SUB_REAL].inthreeway) {
++ /* This was part of a three way call. Immediately make way for
++ another call */
++ ast_debug(1, "Call was complete, setting owner to former third call\n");
++ p->owner = p->subs[ANALOG_SUB_REAL].owner;
++ } else {
++ /* This call hasn't been completed yet... Set owner to NULL */
++ ast_debug(1, "Call was incomplete, setting owner to NULL\n");
++ p->owner = NULL;
++ }
++ p->subs[ANALOG_SUB_REAL].inthreeway = 0;
++ }
++ } else if (index == ANALOG_SUB_CALLWAIT) {
++ /* Ditch the holding callwait call, and immediately make it availabe */
++ if (p->subs[ANALOG_SUB_CALLWAIT].inthreeway) {
++ /* This is actually part of a three way, placed on hold. Place the third part
++ on music on hold now */
++ if (p->subs[ANALOG_SUB_THREEWAY].owner && ast_bridged_channel(p->subs[ANALOG_SUB_THREEWAY].owner)) {
++ ast_queue_control_data(p->subs[ANALOG_SUB_THREEWAY].owner, AST_CONTROL_HOLD,
++ S_OR(p->mohsuggest, NULL),
++ !ast_strlen_zero(p->mohsuggest) ? strlen(p->mohsuggest) + 1 : 0);
++ }
++ p->subs[ANALOG_SUB_THREEWAY].inthreeway = 0;
++ /* Make it the call wait now */
++ analog_swap_subs(p, ANALOG_SUB_CALLWAIT, ANALOG_SUB_THREEWAY);
++ analog_unalloc_sub(p, ANALOG_SUB_THREEWAY);
++ } else
++ analog_unalloc_sub(p, ANALOG_SUB_CALLWAIT);
++ } else if (index == ANALOG_SUB_THREEWAY) {
++ if (p->subs[ANALOG_SUB_CALLWAIT].inthreeway) {
++ /* 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[ANALOG_SUB_CALLWAIT].owner && ast_bridged_channel(p->subs[ANALOG_SUB_CALLWAIT].owner)) {
++ ast_queue_control_data(p->subs[ANALOG_SUB_CALLWAIT].owner, AST_CONTROL_HOLD,
++ S_OR(p->mohsuggest, NULL),
++ !ast_strlen_zero(p->mohsuggest) ? strlen(p->mohsuggest) + 1 : 0);
++ }
++ p->subs[ANALOG_SUB_CALLWAIT].inthreeway = 0;
++ }
++ p->subs[ANALOG_SUB_REAL].inthreeway = 0;
++ /* If this was part of a three way call index, let us make
++ another three way call */
++ analog_unalloc_sub(p, ANALOG_SUB_THREEWAY);
++ } else {
++ /* This wasn't any sort of call, but how are we an index? */
++ ast_log(LOG_WARNING, "Index found but not any type of call?\n");
++ }
++ }
++
++ if (!p->subs[ANALOG_SUB_REAL].owner && !p->subs[ANALOG_SUB_CALLWAIT].owner && !p->subs[ANALOG_SUB_THREEWAY].owner) {
++ p->owner = NULL;
++#if 0
++ p->ringt = 0;
++#endif
++#if 0 /* Since we set it in _call */
++ p->cidrings = 1;
++#endif
++ p->outgoing = 0;
++
++ /* Perform low level hangup if no owner left */
++ res = analog_on_hook(p);
++ if (res < 0) {
++ ast_log(LOG_WARNING, "Unable to hangup line %s\n", ast->name);
++ }
++ switch (p->sig) {
++ case ANALOG_SIG_FXOGS:
++ case ANALOG_SIG_FXOLS:
++ case ANALOG_SIG_FXOKS:
++ /* If they're off hook, try playing congestion */
++ if (analog_is_off_hook(p))
++ analog_play_tone(p, ANALOG_SUB_REAL, ANALOG_TONE_CONGESTION);
++ else
++ analog_play_tone(p, ANALOG_SUB_REAL, -1);
++ break;
++ case ANALOG_SIG_FXSGS:
++ case ANALOG_SIG_FXSLS:
++ case ANALOG_SIG_FXSKS:
++ /* Make sure we're not made available for at least two seconds assuming
++ we were actually used for an inbound or outbound call. */
++ if (ast->_state != AST_STATE_RESERVED) {
++ time(&p->guardtime);
++ p->guardtime += 2;
++ }
++ break;
++ default:
++ analog_play_tone(p, ANALOG_SUB_REAL, -1);
++ }
++
++
++ analog_set_echocanceller(p, 0);
++
++ x = 0;
++ ast_channel_setoption(ast,AST_OPTION_TONE_VERIFY,&x,sizeof(char),0);
++ ast_channel_setoption(ast,AST_OPTION_TDD,&x,sizeof(char),0);
++ p->callwaitcas = 0;
++ p->callwaiting = p->permcallwaiting;
++ p->hidecallerid = p->permhidecallerid;
++ p->dialing = 0;
++ analog_update_conf(p);
++ analog_all_subchannels_hungup(p);
++ }
++
++ analog_stop_callwait(p);
++ ast->tech_pvt = NULL;
++
++ if (option_verbose > 2) {
++ ast_verbose(VERBOSE_PREFIX_3 "Hanging up on '%s'\n", ast->name);
++ }
++
++ return 0;
++}
++
++int analog_answer(struct analog_pvt *p, struct ast_channel *ast)
++{
++ int res = 0;
++ int index;
++ int oldstate = ast->_state;
++ ast_log(LOG_DEBUG, "%s %d\n", __FUNCTION__, p->channel);
++ ast_setstate(ast, AST_STATE_UP);
++ index = analog_get_index(ast, p, 1);
++ if (index < 0)
++ index = ANALOG_SUB_REAL;
++ switch (p->sig) {
++ case ANALOG_SIG_FXSLS:
++ case ANALOG_SIG_FXSGS:
++ case ANALOG_SIG_FXSKS:
++#if 0
++ p->ringt = 0;
++#endif
++ /* Fall through */
++ case ANALOG_SIG_EM:
++ case ANALOG_SIG_EM_E1:
++ case ANALOG_SIG_EMWINK:
++ case ANALOG_SIG_FEATD:
++ case ANALOG_SIG_FEATDMF:
++ case ANALOG_SIG_FEATDMF_TA:
++ case ANALOG_SIG_E911:
++ case ANALOG_SIG_FGC_CAMA:
++ case ANALOG_SIG_FGC_CAMAMF:
++ case ANALOG_SIG_FEATB:
++ case ANALOG_SIG_SF:
++ case ANALOG_SIG_SFWINK:
++ case ANALOG_SIG_SF_FEATD:
++ case ANALOG_SIG_SF_FEATDMF:
++ case ANALOG_SIG_SF_FEATB:
++ case ANALOG_SIG_FXOLS:
++ case ANALOG_SIG_FXOGS:
++ case ANALOG_SIG_FXOKS:
++ /* Pick up the line */
++ ast_debug(1, "Took %s off hook\n", ast->name);
++ if (p->hanguponpolarityswitch) {
++ gettimeofday(&p->polaritydelaytv, NULL);
++ }
++ res = analog_off_hook(p);
++ analog_play_tone(p, index, -1);
++ p->dialing = 0;
++ if ((index == ANALOG_SUB_REAL) && p->subs[ANALOG_SUB_THREEWAY].inthreeway) {
++ if (oldstate == AST_STATE_RINGING) {
++ ast_debug(1, "Finally swapping real and threeway\n");
++ analog_play_tone(p, ANALOG_SUB_THREEWAY, -1);
++ analog_swap_subs(p, ANALOG_SUB_THREEWAY, ANALOG_SUB_REAL);
++ p->owner = p->subs[ANALOG_SUB_REAL].owner;
++ }
++ }
++ if ((p->sig == ANALOG_SIG_FXSLS) || (p->sig == ANALOG_SIG_FXSKS) || (p->sig == ANALOG_SIG_FXSGS)) {
++ analog_set_echocanceller(p, 1);
++ analog_train_echocanceller(p);
++ }
++ break;
++ default:
++ ast_log(LOG_WARNING, "Don't know how to answer signalling %d (channel %d)\n", p->sig, p->channel);
++ res = -1;
++ }
++ ast_setstate(ast, AST_STATE_UP);
++ return res;
++}
++
++static int analog_handles_digit(struct ast_frame *f)
++{
++ char subclass = toupper(f->subclass);
++
++ switch (subclass) {
++ case '1':
++ case '2':
++ case '3':
++ case '4':
++ case '5':
++ case '6':
++ case '7':
++ case '9':
++ case 'A':
++ case 'B':
++ case 'C':
++ case 'D':
++ case 'E':
++ case 'F':
++ return 1;
++ default:
++ return 0;
++ }
++}
++
++void analog_handle_dtmfup(struct analog_pvt *p, struct ast_channel *ast, enum analog_sub index, struct ast_frame **dest)
++{
++ struct ast_frame *f = *dest;
++
++ if (p->callwaitcas) {
++ if ((f->subclass == 'A') || (f->subclass == 'D')) {
++ ast_log(LOG_ERROR, "Got some DTMF, but it's for the CAS\n");
++ p->cid.cid_name = p->callwait_name;
++ p->cid.cid_num = p->callwait_num;
++ analog_send_callerid(p, 1, &p->cid);
++ }
++ if (analog_handles_digit(f))
++ p->callwaitcas = 0;
++ p->subs[index].f.frametype = AST_FRAME_NULL;
++ p->subs[index].f.subclass = 0;
++ *dest = &p->subs[index].f;
++ } else {
++ analog_cb_handle_dtmfup(p, ast, index, dest);
++ }
++}
++
++static int analog_my_getsigstr(struct ast_channel *chan, char *str, const char *term, int ms)
++{
++ char c;
++
++ *str = 0; /* start with empty output buffer */
++ for (;;)
++ {
++ /* Wait for the first digit (up to specified ms). */
++ c = ast_waitfordigit(chan, ms);
++ /* if timeout, hangup or error, return as such */
++ if (c < 1)
++ return c;
++ *str++ = c;
++ *str = 0;
++ if (strchr(term, c))
++ return 1;
++ }
++}
++
++static int analog_handle_notify_message(struct ast_channel *chan, struct analog_pvt *p, int cid_flags, int neon_mwievent)
++{
++ if (p->calls->handle_notify_message) {
++ p->calls->handle_notify_message(chan, p->chan_pvt, cid_flags, neon_mwievent);
++ return 0;
++ }
++ else
++ return -1;
++}
++
++static int analog_increase_ss_count(struct analog_pvt *p)
++{
++ if (p->calls->increase_ss_count) {
++ p->calls->increase_ss_count();
++ return 0;
++ } else
++ return -1;
++}
++
++static int analog_decrease_ss_count(struct analog_pvt *p)
++{
++ if (p->calls->decrease_ss_count) {
++ p->calls->decrease_ss_count();
++ return 0;
++ } else
++ return -1;
++}
++
++#define ANALOG_NEED_MFDETECT(p) (((p)->sig == ANALOG_SIG_FEATDMF) || ((p)->sig == ANALOG_SIG_FEATDMF_TA) || ((p)->sig == ANALOG_SIG_E911) || ((p)->sig == ANALOG_SIG_FGC_CAMA) || ((p)->sig == ANALOG_SIG_FGC_CAMAMF) || ((p)->sig == ANALOG_SIG_FEATB))
++
++/* Note by jpeeler: This function has a rather large section of code ifdefed
++ * away. I'd like to leave the code there until more testing is done and I
++ * know for sure that nothing got left out. The plan is at the latest for this
++ * comment and code below to be removed shortly after the merging of sig_pri.
++ */
++static void *__analog_ss_thread(void *data)
++{
++ struct analog_pvt *p = data;
++ struct ast_channel *chan = p->ss_astchan;
++ char exten[AST_MAX_EXTENSION] = "";
++ char exten2[AST_MAX_EXTENSION] = "";
++ char dtmfcid[300];
++ char dtmfbuf[300];
++ char namebuf[ANALOG_MAX_CID];
++ char numbuf[ANALOG_MAX_CID];
++ struct callerid_state *cs = NULL;
++ char *name = NULL, *number = NULL;
++ int flags;
++#if 0
++ unsigned char buf[256];
++ int distMatches;
++ int curRingData[3];
++ int receivedRingT;
++ int samples = 0;
++ int counter1;
++ int counter;
++ int i;
++#endif
++ int timeout;
++ int getforward = 0;
++ char *s1, *s2;
++ int len = 0;
++ int res;
++ int index;
++
++ analog_increase_ss_count(p);
++
++ ast_log(LOG_DEBUG, "%s %d\n", __FUNCTION__, p->channel);
++
++ /* in the bizarre case where the channel has become a zombie before we
++ even get started here, abort safely
++ */
++ if (!p) {
++ ast_log(LOG_WARNING, "Channel became a zombie before simple switch could be started (%s)\n", chan->name);
++ ast_hangup(chan);
++ goto quit;
++ }
++
++ ast_verb(3, "Starting simple switch on '%s'\n", chan->name);
++ index = analog_get_index(chan, p, 1);
++ if (index < 0) {
++ ast_log(LOG_WARNING, "Huh?\n");
++ ast_hangup(chan);
++ goto quit;
++ }
++ analog_dsp_reset_and_flush_digits(p);
++ switch (p->sig) {
++ case ANALOG_SIG_FEATD:
++ case ANALOG_SIG_FEATDMF:
++ case ANALOG_SIG_FEATDMF_TA:
++ case ANALOG_SIG_E911:
++ case ANALOG_SIG_FGC_CAMAMF:
++ case ANALOG_SIG_FEATB:
++ case ANALOG_SIG_EMWINK:
++ case ANALOG_SIG_SF_FEATD:
++ case ANALOG_SIG_SF_FEATDMF:
++ case ANALOG_SIG_SF_FEATB:
++ case ANALOG_SIG_SFWINK:
++ if (analog_wink(p, index))
++ goto quit;
++ /* Fall through */
++ case ANALOG_SIG_EM:
++ case ANALOG_SIG_EM_E1:
++ case ANALOG_SIG_SF:
++ case ANALOG_SIG_FGC_CAMA:
++ res = analog_play_tone(p, index, -1);
++
++ analog_dsp_reset_and_flush_digits(p);
++
++ if (ANALOG_NEED_MFDETECT(p)) {
++ analog_dsp_set_digitmode(p, ANALOG_DIGITMODE_MF);
++ } else
++ analog_dsp_set_digitmode(p, ANALOG_DIGITMODE_DTMF);
++
++ memset(dtmfbuf, 0, sizeof(dtmfbuf));
++ /* Wait for the first digit only if immediate=no */
++ if (!p->immediate)
++ /* Wait for the first digit (up to 5 seconds). */
++ res = ast_waitfordigit(chan, 5000);
++ else
++ res = 0;
++ if (res > 0) {
++ /* save first char */
++ dtmfbuf[0] = res;
++ switch (p->sig) {
++ case ANALOG_SIG_FEATD:
++ case ANALOG_SIG_SF_FEATD:
++ res = analog_my_getsigstr(chan, dtmfbuf + 1, "*", 3000);
++ if (res > 0)
++ res = analog_my_getsigstr(chan, dtmfbuf + strlen(dtmfbuf), "*", 3000);
++ if (res < 1)
++ analog_dsp_reset_and_flush_digits(p);
++ break;
++ case ANALOG_SIG_FEATDMF_TA:
++ res = analog_my_getsigstr(chan, dtmfbuf + 1, "#", 3000);
++ if (res < 1)
++ analog_dsp_reset_and_flush_digits(p);
++ if (analog_wink(p, index)) goto quit;
++ dtmfbuf[0] = 0;
++ /* Wait for the first digit (up to 5 seconds). */
++ res = ast_waitfordigit(chan, 5000);
++ if (res <= 0) break;
++ dtmfbuf[0] = res;
++ /* fall through intentionally */
++ case ANALOG_SIG_FEATDMF:
++ case ANALOG_SIG_E911:
++ case ANALOG_SIG_FGC_CAMAMF:
++ case ANALOG_SIG_SF_FEATDMF:
++ res = analog_my_getsigstr(chan, dtmfbuf + 1, "#", 3000);
++ /* if international caca, do it again to get real ANO */
++ if ((p->sig == ANALOG_SIG_FEATDMF) && (dtmfbuf[1] != '0') && (strlen(dtmfbuf) != 14))
++ {
++ if (analog_wink(p, index)) goto quit;
++ dtmfbuf[0] = 0;
++ /* Wait for the first digit (up to 5 seconds). */
++ res = ast_waitfordigit(chan, 5000);
++ if (res <= 0) break;
++ dtmfbuf[0] = res;
++ res = analog_my_getsigstr(chan, dtmfbuf + 1, "#", 3000);
++ }
++ if (res > 0) {
++ /* if E911, take off hook */
++ if (p->sig == ANALOG_SIG_E911)
++ analog_off_hook(p);
++ res = analog_my_getsigstr(chan, dtmfbuf + strlen(dtmfbuf), "#", 3000);
++ }
++ if (res < 1)
++ analog_dsp_reset_and_flush_digits(p);
++ break;
++ case ANALOG_SIG_FEATB:
++ case ANALOG_SIG_SF_FEATB:
++ res = analog_my_getsigstr(chan, dtmfbuf + 1, "#", 3000);
++ if (res < 1)
++ analog_dsp_reset_and_flush_digits(p);
++ break;
++ case ANALOG_SIG_EMWINK:
++ /* if we received a '*', we are actually receiving Feature Group D
++ dial syntax, so use that mode; otherwise, fall through to normal
++ mode
++ */
++ if (res == '*') {
++ res = analog_my_getsigstr(chan, dtmfbuf + 1, "*", 3000);
++ if (res > 0)
++ res = analog_my_getsigstr(chan, dtmfbuf + strlen(dtmfbuf), "*", 3000);
++ if (res < 1)
++ analog_dsp_reset_and_flush_digits(p);
++ break;
++ }
++ default:
++ /* If we got the first digit, get the rest */
++ len = 1;
++ dtmfbuf[len] = '\0';
++ while ((len < AST_MAX_EXTENSION-1) && ast_matchmore_extension(chan, chan->context, dtmfbuf, 1, p->cid_num)) {
++ if (ast_exists_extension(chan, chan->context, dtmfbuf, 1, p->cid_num)) {
++ timeout = analog_matchdigittimeout;
++ } else {
++ timeout = analog_gendigittimeout;
++ }
++ res = ast_waitfordigit(chan, timeout);
++ if (res < 0) {
++ ast_debug(1, "waitfordigit returned < 0...\n");
++ ast_hangup(chan);
++ goto quit;
++ } else if (res) {
++ dtmfbuf[len++] = res;
++ dtmfbuf[len] = '\0';
++ } else {
++ break;
++ }
++ }
++ break;
++ }
++ }
++ if (res == -1) {
++ ast_log(LOG_WARNING, "getdtmf on channel %d: %s\n", p->channel, strerror(errno));
++ ast_hangup(chan);
++ goto quit;
++ } else if (res < 0) {
++ ast_debug(1, "Got hung up before digits finished\n");
++ ast_hangup(chan);
++ goto quit;
++ }
++
++ if (p->sig == ANALOG_SIG_FGC_CAMA) {
++ char anibuf[100];
++
++ if (ast_safe_sleep(chan,1000) == -1) {
++ ast_hangup(chan);
++ goto quit;
++ }
++ analog_off_hook(p);
++ analog_dsp_set_digitmode(p, ANALOG_DIGITMODE_MF);
++ res = analog_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);
++ }
++ analog_dsp_set_digitmode(p, ANALOG_DIGITMODE_DTMF);
++ }
++
++ ast_copy_string(exten, dtmfbuf, sizeof(exten));
++ if (ast_strlen_zero(exten))
++ ast_copy_string(exten, "s", sizeof(exten));
++ if (p->sig == ANALOG_SIG_FEATD || p->sig == ANALOG_SIG_EMWINK) {
++ /* Look for Feature Group D on all E&M Wink and Feature Group D trunks */
++ if (exten[0] == '*') {
++ char *stringp=NULL;
++ ast_copy_string(exten2, exten, sizeof(exten2));
++ /* Parse out extension and callerid */
++ stringp=exten2 +1;
++ s1 = strsep(&stringp, "*");
++ s2 = strsep(&stringp, "*");
++ if (s2) {
++ if (!ast_strlen_zero(p->cid_num))
++ ast_set_callerid(chan, p->cid_num, NULL, p->cid_num);
++ else
++ ast_set_callerid(chan, s1, NULL, s1);
++ ast_copy_string(exten, s2, sizeof(exten));
++ } else
++ ast_copy_string(exten, s1, sizeof(exten));
++ } else if (p->sig == ANALOG_SIG_FEATD)
++ ast_log(LOG_WARNING, "Got a non-Feature Group D input on channel %d. Assuming E&M Wink instead\n", p->channel);
++ }
++ if ((p->sig == ANALOG_SIG_FEATDMF) || (p->sig == ANALOG_SIG_FEATDMF_TA)) {
++ if (exten[0] == '*') {
++ char *stringp=NULL;
++ ast_copy_string(exten2, exten, sizeof(exten2));
++ /* Parse out extension and callerid */
++ stringp=exten2 +1;
++ s1 = strsep(&stringp, "#");
++ s2 = strsep(&stringp, "#");
++ if (s2) {
++ if (!ast_strlen_zero(p->cid_num))
++ ast_set_callerid(chan, p->cid_num, NULL, p->cid_num);
++ else
++ if (*(s1 + 2))
++ ast_set_callerid(chan, s1 + 2, NULL, s1 + 2);
++ ast_copy_string(exten, s2 + 1, sizeof(exten));
++ } else
++ ast_copy_string(exten, s1 + 2, sizeof(exten));
++ } else
++ ast_log(LOG_WARNING, "Got a non-Feature Group D input on channel %d. Assuming E&M Wink instead\n", p->channel);
++ }
++ if ((p->sig == ANALOG_SIG_E911) || (p->sig == ANALOG_SIG_FGC_CAMAMF)) {
++ if (exten[0] == '*') {
++ char *stringp=NULL;
++ ast_copy_string(exten2, exten, sizeof(exten2));
++ /* Parse out extension and callerid */
++ stringp=exten2 +1;
++ s1 = strsep(&stringp, "#");
++ s2 = strsep(&stringp, "#");
++ if (s2 && (*(s2 + 1) == '0')) {
++ if (*(s2 + 2))
++ ast_set_callerid(chan, s2 + 2, NULL, s2 + 2);
++ }
++ if (s1) ast_copy_string(exten, s1, sizeof(exten));
++ else ast_copy_string(exten, "911", sizeof(exten));
++ } else
++ ast_log(LOG_WARNING, "Got a non-E911/FGC CAMA input on channel %d. Assuming E&M Wink instead\n", p->channel);
++ }
++ if (p->sig == ANALOG_SIG_FEATB) {
++ if (exten[0] == '*') {
++ char *stringp=NULL;
++ ast_copy_string(exten2, exten, sizeof(exten2));
++ /* Parse out extension and callerid */
++ stringp=exten2 +1;
++ s1 = strsep(&stringp, "#");
++ ast_copy_string(exten, exten2 + 1, sizeof(exten));
++ } else
++ ast_log(LOG_WARNING, "Got a non-Feature Group B input on channel %d. Assuming E&M Wink instead\n", p->channel);
++ }
++ if ((p->sig == ANALOG_SIG_FEATDMF) || (p->sig == ANALOG_SIG_FEATDMF_TA)) {
++ analog_wink(p, index);
++ /* 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;
++ }
++ analog_set_echocanceller(p, 1);
++
++ analog_dsp_set_digitmode(p, ANALOG_DIGITMODE_DTMF);
++
++ if (ast_exists_extension(chan, chan->context, exten, 1, chan->cid.cid_num)) {
++ ast_copy_string(chan->exten, exten, sizeof(chan->exten));
++ analog_dsp_reset_and_flush_digits(p);
++ res = ast_pbx_run(chan);
++ if (res) {
++ ast_log(LOG_WARNING, "PBX exited non-zero\n");
++ res = analog_play_tone(p, index, ANALOG_TONE_CONGESTION);
++ }
++ goto quit;
++ } else {
++ if (option_verbose > 2)
++ ast_verbose(VERBOSE_PREFIX_2 "Unknown extension '%s' in context '%s' requested\n", exten, chan->context);
++ sleep(2);
++ res = analog_play_tone(p, index, ANALOG_TONE_INFO);
++ if (res < 0)
++ ast_log(LOG_WARNING, "Unable to start special tone on %d\n", p->channel);
++ else
++ sleep(1);
++ res = ast_streamfile(chan, "ss-noservice", chan->language);
++ if (res >= 0)
++ ast_waitstream(chan, "");
++ res = analog_play_tone(p, index, ANALOG_TONE_CONGESTION);
++ ast_hangup(chan);
++ goto quit;
++ }
++ break;
++ case ANALOG_SIG_FXOLS:
++ case ANALOG_SIG_FXOGS:
++ case ANALOG_SIG_FXOKS:
++ /* Read the first digit */
++ timeout = analog_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[ANALOG_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)
++ res = 's';
++ else
++ res = ast_waitfordigit(chan, timeout);
++ timeout = 0;
++ if (res < 0) {
++ ast_debug(1, "waitfordigit returned < 0...\n");
++ res = analog_play_tone(p, index, -1);
++ ast_hangup(chan);
++ goto quit;
++ } else if (res) {
++ exten[len++]=res;
++ exten[len] = '\0';
++ }
++ if (!ast_ignore_pattern(chan->context, exten))
++ analog_play_tone(p, index, -1);
++ else
++ analog_play_tone(p, index, ANALOG_TONE_DIALTONE);
++ if (ast_exists_extension(chan, chan->context, exten, 1, p->cid_num) && strcmp(exten, ast_parking_ext())) {
++ 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));
++ if (option_verbose > 2)
++ ast_verbose(VERBOSE_PREFIX_3 "Setting call forward to '%s' on channel %d\n", p->call_forward, p->channel);
++ res = analog_play_tone(p, index, ANALOG_TONE_DIALRECALL);
++ if (res)
++ break;
++ usleep(500000);
++ res = analog_play_tone(p, index, -1);
++ sleep(1);
++ memset(exten, 0, sizeof(exten));
++ res = analog_play_tone(p, index, ANALOG_TONE_DIALTONE);
++ len = 0;
++ getforward = 0;
++ } else {
++ res = analog_play_tone(p, index, -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);
++ else
++ ast_set_callerid(chan, NULL, NULL, p->cid_num);
++ }
++ if (!ast_strlen_zero(p->cid_name)) {
++ if (!p->hidecallerid)
++ ast_set_callerid(chan, NULL, p->cid_name, NULL);
++ }
++ ast_setstate(chan, AST_STATE_RING);
++ analog_set_echocanceller(p, 1);
++ res = ast_pbx_run(chan);
++ if (res) {
++ ast_log(LOG_WARNING, "PBX exited non-zero\n");
++ res = analog_play_tone(p, index, ANALOG_TONE_CONGESTION);
++ }
++ goto quit;
++ }
++ } else {
++ /* It's a match, but they just typed a digit, and there is an ambiguous match,
++ so just set the timeout to analog_matchdigittimeout and wait some more */
++ timeout = analog_matchdigittimeout;
++ }
++ } else if (res == 0) {
++ ast_debug(1, "not enough digits (and no ambiguous match)...\n");
++ res = analog_play_tone(p, index, ANALOG_TONE_CONGESTION);
++ analog_wait_event(p);
++ ast_hangup(chan);
++ goto quit;
++ } else if (p->callwaiting && !strcmp(exten, "*70")) {
++ if (option_verbose > 2)
++ ast_verbose(VERBOSE_PREFIX_3 "Disabling call waiting on %s\n", chan->name);
++ /* Disable call waiting if enabled */
++ p->callwaiting = 0;
++ res = analog_play_tone(p, index, ANALOG_TONE_DIALRECALL);
++ if (res) {
++ 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 = analog_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
++ */
++ if (index == ANALOG_SUB_REAL) {
++ /* Switch us from Third call to Call Wait */
++ if (p->subs[ANALOG_SUB_THREEWAY].owner) {
++ /* If you make a threeway call and the *8# a call, it should actually
++ look like a callwait */
++ analog_alloc_sub(p, ANALOG_SUB_CALLWAIT);
++ analog_swap_subs(p, ANALOG_SUB_CALLWAIT, ANALOG_SUB_THREEWAY);
++ analog_unalloc_sub(p, ANALOG_SUB_THREEWAY);
++ }
++ analog_set_echocanceller(p, 1);
++ if (ast_pickup_call(chan)) {
++ ast_debug(1, "No call pickup possible...\n");
++ res = analog_play_tone(p, index, ANALOG_TONE_CONGESTION);
++ analog_wait_event(p);
++ }
++ ast_hangup(chan);
++ goto quit;
++ } else {
++ ast_log(LOG_WARNING, "Huh? Got *8# on call not on real\n");
++ ast_hangup(chan);
++ goto quit;
++ }
++ } else if (!p->hidecallerid && !strcmp(exten, "*67")) {
++ if (option_verbose > 2)
++ ast_verbose(VERBOSE_PREFIX_3 "Disabling Caller*ID on %s\n", chan->name);
++ /* Disable Caller*ID if enabled */
++ p->hidecallerid = 1;
++ if (chan->cid.cid_num)
++ free(chan->cid.cid_num);
++ chan->cid.cid_num = NULL;
++ if (chan->cid.cid_name)
++ free(chan->cid.cid_name);
++ chan->cid.cid_name = NULL;
++ res = analog_play_tone(p, index, ANALOG_TONE_DIALRECALL);
++ if (res) {
++ 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 = analog_firstdigittimeout;
++ } else if (p->callreturn && !strcmp(exten, "*69")) {
++ res = 0;
++ if (!ast_strlen_zero(p->lastcid_num)) {
++ res = ast_say_digit_str(chan, p->lastcid_num, "", chan->language);
++ }
++ if (!res)
++ res = analog_play_tone(p, index, ANALOG_TONE_DIALRECALL);
++ break;
++ } else if (!strcmp(exten, "*78")) {
++ /* Do not disturb */
++ if (option_verbose > 2)
++ ast_verbose(VERBOSE_PREFIX_3 "Enabled DND on channel %d\n", p->channel);
++#if 0
++ manager_event(EVENT_FLAG_SYSTEM, "DNDState",
++ "Channel: %s/%d\r\n"
++ "Status: enabled\r\n", dahdi_chan_name, p->channel);
++#endif
++ res = analog_play_tone(p, index, ANALOG_TONE_DIALRECALL);
++ p->dnd = 1;
++ getforward = 0;
++ memset(exten, 0, sizeof(exten));
++ len = 0;
++ } else if (!strcmp(exten, "*79")) {
++ /* Do not disturb */
++ if (option_verbose > 2)
++ ast_verbose(VERBOSE_PREFIX_3 "Disabled DND on channel %d\n", p->channel);
++#if 0
++ manager_event(EVENT_FLAG_SYSTEM, "DNDState",
++ "Channel: %s/%d\r\n"
++ "Status: disabled\r\n", dahdi_chan_name, p->channel);
++#endif
++ res = analog_play_tone(p, index, ANALOG_TONE_DIALRECALL);
++ p->dnd = 0;
++ getforward = 0;
++ memset(exten, 0, sizeof(exten));
++ len = 0;
++ } else if (p->cancallforward && !strcmp(exten, "*72")) {
++ res = analog_play_tone(p, index, ANALOG_TONE_DIALRECALL);
++ getforward = 1;
++ memset(exten, 0, sizeof(exten));
++ len = 0;
++ } else if (p->cancallforward && !strcmp(exten, "*73")) {
++ if (option_verbose > 2)
++ ast_verbose(VERBOSE_PREFIX_3 "Cancelling call forwarding on channel %d\n", p->channel);
++ res = analog_play_tone(p, index, ANALOG_TONE_DIALRECALL);
++ memset(p->call_forward, 0, sizeof(p->call_forward));
++ getforward = 0;
++ memset(exten, 0, sizeof(exten));
++ len = 0;
++ } else if ((p->transfer || p->canpark) && !strcmp(exten, ast_parking_ext()) &&
++ p->subs[ANALOG_SUB_THREEWAY].owner &&
++ ast_bridged_channel(p->subs[ANALOG_SUB_THREEWAY].owner)) {
++ /* 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[ANALOG_SUB_THREEWAY].owner), chan, 0, NULL);
++ if (option_verbose > 2)
++ ast_verbose(VERBOSE_PREFIX_3 "Parking call to '%s'\n", chan->name);
++ break;
++ } else if (!ast_strlen_zero(p->lastcid_num) && !strcmp(exten, "*60")) {
++ if (option_verbose > 2)
++ ast_verbose(VERBOSE_PREFIX_3 "Blacklisting number %s\n", p->lastcid_num);
++ res = ast_db_put("blacklist", p->lastcid_num, "1");
++ if (!res) {
++ res = analog_play_tone(p, index, ANALOG_TONE_DIALRECALL);
++ memset(exten, 0, sizeof(exten));
++ len = 0;
++ }
++ } else if (p->hidecallerid && !strcmp(exten, "*82")) {
++ if (option_verbose > 2)
++ ast_verbose(VERBOSE_PREFIX_3 "Enabling Caller*ID on %s\n", chan->name);
++ /* Enable Caller*ID if enabled */
++ p->hidecallerid = 0;
++ if (chan->cid.cid_num)
++ free(chan->cid.cid_num);
++ chan->cid.cid_num = NULL;
++ if (chan->cid.cid_name)
++ free(chan->cid.cid_name);
++ chan->cid.cid_name = NULL;
++ ast_set_callerid(chan, p->cid_num, p->cid_name, NULL);
++ res = analog_play_tone(p, index, ANALOG_TONE_DIALRECALL);
++ if (res) {
++ 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 = analog_firstdigittimeout;
++ } else if (!strcmp(exten, "*0")) {
++#ifdef XXX
++ struct ast_channel *nbridge = p->subs[ANALOG_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))
++ pbridge = ast_bridged_channel(nbridge)->tech_pvt;
++ if (nbridge && pbridge &&
++ (nbridge->tech == chan_tech) &&
++ (ast_bridged_channel(nbridge)->tech == chan_tech) &&
++ ISTRUNK(pbridge)) {
++ int func = DAHDI_FLASH;
++ /* Clear out the dial buffer */
++ p->dop.dialstr[0] = '\0';
++ /* flash hookswitch */
++ if ((ioctl(pbridge->subs[ANALOG_SUB_REAL].dfd,DAHDI_HOOK,&func) == -1) && (errno != EINPROGRESS)) {
++ ast_log(LOG_WARNING, "Unable to flash external trunk on channel %s: %s\n",
++ nbridge->name, strerror(errno));
++ }
++ analog_swap_subs(p, ANALOG_SUB_REAL, ANALOG_SUB_THREEWAY);
++ analog_unalloc_sub(p, ANALOG_SUB_THREEWAY);
++ p->owner = p->subs[ANALOG_SUB_REAL].owner;
++ if (ast_bridged_channel(p->subs[ANALOG_SUB_REAL].owner))
++ ast_queue_control(p->subs[ANALOG_SUB_REAL].owner, AST_CONTROL_UNHOLD);
++ ast_hangup(chan);
++ goto quit;
++ } else {
++ analog_play_tone(p, index, ANALOG_TONE_CONGESTION);
++ analog_wait_event(p);
++ analog_play_tone(p, index, -1);
++ analog_swap_subs(p, ANALOG_SUB_REAL, ANALOG_SUB_THREEWAY);
++ analog_unalloc_sub(p, ANALOG_SUB_THREEWAY);
++ p->owner = p->subs[ANALOG_SUB_REAL].owner;
++ ast_hangup(chan);
++ goto quit;
++ }
++#endif
++ } 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);
++ break;
++ }
++ if (!timeout)
++ timeout = analog_gendigittimeout;
++ if (len && !ast_ignore_pattern(chan->context, exten))
++ analog_play_tone(p, index, -1);
++ }
++ break;
++ case ANALOG_SIG_FXSLS:
++ case ANALOG_SIG_FXSGS:
++ case ANALOG_SIG_FXSKS:
++
++ /* If we want caller id, we're in a prering state due to a polarity reversal
++ * and we're set to use a polarity reversal to trigger the start of caller id,
++ * grab the caller id and wait for ringing to start... */
++ if (p->use_callerid && (chan->_state == AST_STATE_PRERING && (p->cid_start == ANALOG_CID_START_POLARITY || p->cid_start == ANALOG_CID_START_POLARITY_IN))) {
++ /* If set to use DTMF CID signalling, listen for DTMF */
++ if (p->cid_signalling == CID_SIG_DTMF) {
++ int i = 0;
++ cs = NULL;
++ ast_debug(1, "Receiving DTMF cid on "
++ "channel %s\n", chan->name);
++#if 0
++ dahdi_setlinear(p->subs[index].dfd, 0);
++#endif
++ 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;
++ }
++ f = ast_read(chan);
++ if (!f)
++ break;
++ if (f->frametype == AST_FRAME_DTMF) {
++ dtmfbuf[i++] = f->subclass;
++ ast_debug(1, "CID got digit '%c'\n", f->subclass);
++ res = 2000;
++ }
++ ast_frfree(f);
++ if (chan->_state == AST_STATE_RING ||
++ chan->_state == AST_STATE_RINGING)
++ break; /* Got ring */
++ }
++ dtmfbuf[i] = '\0';
++#if 0
++ dahdi_setlinear(p->subs[index].dfd, p->subs[index].linear);
++#endif
++ /* 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",
++ dtmfcid, flags);
++ /* If first byte is NULL, we have no cid */
++ if (!ast_strlen_zero(dtmfcid))
++ number = dtmfcid;
++ else
++ number = NULL;
++#if 0
++ /* If set to use V23 Signalling, launch our FSK gubbins and listen for it */
++ } else if ((p->cid_signalling == CID_SIG_V23) || (p->cid_signalling == CID_SIG_V23_JP)) {
++ cs = callerid_new(p->cid_signalling);
++ if (cs) {
++ samples = 0;
++#if 1
++ bump_gains(p);
++#endif
++ /* Take out of linear mode for Caller*ID processing */
++ dahdi_setlinear(p->subs[index].dfd, 0);
++
++ /* First we wait and listen for the Caller*ID */
++ for (;;) {
++ i = DAHDI_IOMUX_READ | DAHDI_IOMUX_SIGEVENT;
++ if ((res = ioctl(p->subs[index].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[index].dfd);
++ ast_log(LOG_NOTICE, "Got event %d (%s)...\n", res, event2str(res));
++
++ if (p->cid_signalling == CID_SIG_V23_JP) {
++#ifdef DAHDI_EVENT_RINGBEGIN
++ if (res == ANALOG_EVENT_RINGBEGIN) {
++ res = analog_off_hook(p);
++ usleep(1);
++ }
++#endif
++ } else {
++ res = 0;
++ break;
++ }
++ } else if (i & DAHDI_IOMUX_READ) {
++ res = read(p->subs[index].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;
++ }
++ samples += res;
++
++ 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));
++ }
++
++ if (res < 0) {
++ ast_log(LOG_WARNING, "CallerID feed failed on channel '%s'\n", chan->name);
++ break;
++ } else if (res)
++ break;
++ else if (samples > (8000 * 10))
++ break;
++ }
++ }
++ if (res == 1) {
++ callerid_get(cs, &name, &number, &flags);
++ ast_log(LOG_NOTICE, "CallerID number: %s, name: %s, flags=%d\n", number, name, flags);
++ }
++
++ if (p->cid_signalling == CID_SIG_V23_JP) {
++ res = analog_on_hook(p);
++ usleep(1);
++ res = 4000;
++ } else {
++
++ /* Finished with Caller*ID, now wait for a ring to make sure there really is a call coming */
++ res = 2000;
++ }
++
++ for (;;) {
++ struct ast_frame *f;
++ res = ast_waitfor(chan, res);
++ if (res <= 0) {
++ ast_log(LOG_WARNING, "CID timed out waiting for ring. "
++ "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);
++ goto quit;
++ }
++ ast_frfree(f);
++ if (chan->_state == AST_STATE_RING ||
++ chan->_state == AST_STATE_RINGING)
++ break; /* Got ring */
++ }
++
++ /* Restore linear mode (if appropriate) for Caller*ID processing */
++ dahdi_setlinear(p->subs[index].dfd, p->subs[index].linear);
++#if 1
++ restore_gains(p);
++#endif
++ } else
++ ast_log(LOG_WARNING, "Unable to get caller ID space\n");
++#endif
++ } 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",
++ chan->name);
++ ast_hangup(chan);
++ goto quit;
++ }
++ } else if (p->use_callerid && p->cid_start == ANALOG_CID_START_RING) {
++ int timeout = 10000; /* Ten seconds */
++ struct timeval start = ast_tvnow();
++ enum analog_event ev;
++
++ namebuf[0] = 0;
++ numbuf[0] = 0;
++
++ if (!analog_start_cid_detect(p, p->cid_signalling)) {
++ while (1) {
++ res = analog_get_callerid(p, namebuf, numbuf, &ev, timeout - ast_tvdiff_ms(ast_tvnow(), start));
++
++ if (res == 0) {
++ break;
++ }
++
++ if (res == 1) {
++ if (ev == ANALOG_EVENT_POLARITY && p->hanguponpolarityswitch && p->polarity == POLARITY_REV) {
++ ast_debug(1, "Hanging up due to polarity reversal on channel %d while detecting callerid\n", p->channel);
++ p->polarity = POLARITY_IDLE;
++ ast_hangup(chan);
++ goto quit;
++ } else if (ev != ANALOG_EVENT_NONE) {
++ break;
++ }
++ }
++
++ if (ast_tvdiff_ms(ast_tvnow(), start) > timeout)
++ break;
++
++ }
++ name = namebuf;
++ number = numbuf;
++
++ analog_stop_cid_detect(p);
++
++#if 0
++ /* XXX */
++ 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));
++ }
++
++ analog_get_callerid(p, name, number);
++ /* 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 < (sizeof(curRingData) / sizeof(curRingData[0])); 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. */
++
++ /* Take out of linear mode for Caller*ID processing */
++ dahdi_setlinear(p->subs[index].dfd, 0);
++ for (;;) {
++ i = DAHDI_IOMUX_READ | DAHDI_IOMUX_SIGEVENT;
++ if ((res = ioctl(p->subs[index].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[index].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 == ANALOG_EVENT_POLARITY && p->hanguponpolarityswitch && p->polarity == POLARITY_REV) {
++ ast_debug(1, "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 */
++
++ 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 == (sizeof(curRingData) / sizeof(curRingData[0])))
++ break;
++ } else if (i & DAHDI_IOMUX_READ) {
++ res = read(p->subs[index].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 (res == 1) {
++ callerid_get(cs, &name, &number, &flags);
++ ast_debug(1, "CallerID number: %s, name: %s, flags=%d\n", number, name, flags);
++ }
++ /* Restore linear mode (if appropriate) for Caller*ID processing */
++ dahdi_setlinear(p->subs[index].dfd, p->subs[index].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");
++#endif
++ } else
++ ast_log(LOG_WARNING, "Unable to get caller ID space\n");
++ }
++ else
++ cs = NULL;
++
++ if (number)
++ ast_shrink_phone_number(number);
++ ast_set_callerid(chan, number, name, number);
++
++ if (cs)
++ callerid_free(cs);
++
++ analog_handle_notify_message(chan, p, flags, -1);
++
++ ast_setstate(chan, AST_STATE_RING);
++ chan->rings = 1;
++#if 0
++ p->ringt = p->ringt_base;
++#endif
++ res = ast_pbx_run(chan);
++ if (res) {
++ ast_hangup(chan);
++ ast_log(LOG_WARNING, "PBX exited non-zero\n");
++ }
++ goto quit;
++ default:
++ ast_log(LOG_WARNING, "Don't know how to handle simple switch with signalling %s on channel %d\n", analog_sigtype_to_str(p->sig), p->channel);
++ res = analog_play_tone(p, index, ANALOG_TONE_CONGESTION);
++ if (res < 0)
++ ast_log(LOG_WARNING, "Unable to play congestion tone on channel %d\n", p->channel);
++ }
++ res = analog_play_tone(p, index, ANALOG_TONE_CONGESTION);
++ if (res < 0)
++ ast_log(LOG_WARNING, "Unable to play congestion tone on channel %d\n", p->channel);
++ ast_hangup(chan);
++quit:
++ analog_decrease_ss_count(p);
++ return NULL;
++}
++
++int analog_ss_thread_start(struct analog_pvt *p, struct ast_channel *chan)
++{
++ pthread_t threadid;
++ return ast_pthread_create_detached(&threadid, NULL, __analog_ss_thread, chan);
++}
++
++static struct ast_frame *__analog_handle_event(struct analog_pvt *p, struct ast_channel *ast)
++{
++ int res, x;
++ int mysig;
++ enum analog_sub index;
++ char *c;
++ pthread_t threadid;
++ pthread_attr_t attr;
++ struct ast_channel *chan;
++ struct ast_frame *f;
++ ast_log(LOG_DEBUG, "%s %d\n", __FUNCTION__, p->channel);
++
++ index = analog_get_index(ast, p, 0);
++ mysig = p->sig;
++ if (p->outsigmod > -1)
++ mysig = p->outsigmod;
++ p->subs[index].f.frametype = AST_FRAME_NULL;
++ p->subs[index].f.subclass = 0;
++ p->subs[index].f.datalen = 0;
++ p->subs[index].f.samples = 0;
++ p->subs[index].f.mallocd = 0;
++ p->subs[index].f.offset = 0;
++ p->subs[index].f.src = "dahdi_handle_event";
++ p->subs[index].f.data.ptr = NULL;
++ f = &p->subs[index].f;
++
++ if (index < 0)
++ return &p->subs[index].f;
++
++ if (index != ANALOG_SUB_REAL) {
++ ast_log(LOG_ERROR, "We got an event on a non real sub. Fix it!\n");
++ }
++
++ res = analog_get_event(p);
++
++ ast_debug(1, "Got event %s(%d) on channel %d (index %d)\n", analog_event2str(res), res, p->channel, index);
++
++ switch (res) {
++#ifdef ANALOG_EVENT_EC_DISABLED
++ case ANALOG_EVENT_EC_DISABLED:
++ if (option_verbose > 2)
++ ast_verbose(VERBOSE_PREFIX_3 "Channel %d echo canceler disabled due to CED detection\n", p->channel);
++ p->echocanon = 0;
++ break;
++#endif
++ case ANALOG_EVENT_PULSE_START:
++ /* Stop tone if there's a pulse start and the PBX isn't started */
++ if (!ast->pbx)
++ analog_play_tone(p, ANALOG_SUB_REAL, -1);
++ break;
++ case ANALOG_EVENT_DIALCOMPLETE:
++ if (p->inalarm) break;
++ x = analog_is_dialing(p, index);
++ if (!x) { /* if not still dialing in driver */
++ analog_set_echocanceller(p, 1);
++ if (p->echobreak) {
++ analog_train_echocanceller(p);
++ ast_copy_string(p->dop.dialstr, p->echorest, sizeof(p->dop.dialstr));
++ p->dop.op = ANALOG_DIAL_OP_REPLACE;
++ analog_dial_digits(p, ANALOG_SUB_REAL, &p->dop);
++ p->echobreak = 0;
++ } else {
++ p->dialing = 0;
++ if ((mysig == ANALOG_SIG_E911) || (mysig == ANALOG_SIG_FGC_CAMA) || (mysig == ANALOG_SIG_FGC_CAMAMF)) {
++ /* if thru with dialing after offhook */
++ if (ast->_state == AST_STATE_DIALING_OFFHOOK) {
++ ast_setstate(ast, AST_STATE_UP);
++ p->subs[index].f.frametype = AST_FRAME_CONTROL;
++ p->subs[index].f.subclass = AST_CONTROL_ANSWER;
++ break;
++ } else { /* if to state wait for offhook to dial rest */
++ /* we now wait for off hook */
++ ast_setstate(ast,AST_STATE_DIALING_OFFHOOK);
++ }
++ }
++ if (ast->_state == AST_STATE_DIALING) {
++ if ((!p->dialednone && ((mysig == ANALOG_SIG_EM) || (mysig == ANALOG_SIG_EM_E1) || (mysig == ANALOG_SIG_EMWINK) || (mysig == ANALOG_SIG_FEATD) || (mysig == ANALOG_SIG_FEATDMF_TA) || (mysig == ANALOG_SIG_FEATDMF) || (mysig == ANALOG_SIG_E911) || (mysig == ANALOG_SIG_FGC_CAMA) || (mysig == ANALOG_SIG_FGC_CAMAMF) || (mysig == ANALOG_SIG_FEATB) || (mysig == ANALOG_SIG_SF) || (mysig == ANALOG_SIG_SFWINK) || (mysig == ANALOG_SIG_SF_FEATD) || (mysig == ANALOG_SIG_SF_FEATDMF) || (mysig == ANALOG_SIG_SF_FEATB)))) {
++ ast_setstate(ast, AST_STATE_RINGING);
++ } else if (!p->answeronpolarityswitch) {
++ ast_setstate(ast, AST_STATE_UP);
++ p->subs[index].f.frametype = AST_FRAME_CONTROL;
++ p->subs[index].f.subclass = AST_CONTROL_ANSWER;
++ /* If aops=0 and hops=1, this is necessary */
++ p->polarity = POLARITY_REV;
++ } else {
++ /* Start clean, so we can catch the change to REV polarity when party answers */
++ p->polarity = POLARITY_IDLE;
++ }
++ }
++ }
++ }
++ break;
++ case ANALOG_EVENT_ALARM:
++ p->inalarm = 1;
++#if 0
++ res = get_alarms(p);
++ handle_alarms(p, res);
++#endif
++ case ANALOG_EVENT_ONHOOK:
++ switch (p->sig) {
++ case ANALOG_SIG_FXOLS:
++ case ANALOG_SIG_FXOGS:
++ case ANALOG_SIG_FXOKS:
++ /* Check for some special conditions regarding call waiting */
++ if (index == ANALOG_SUB_REAL) {
++ /* The normal line was hung up */
++ if (p->subs[ANALOG_SUB_CALLWAIT].owner) {
++ /* There's a call waiting call, so ring the phone, but make it unowned in the mean time */
++ analog_swap_subs(p, ANALOG_SUB_CALLWAIT, ANALOG_SUB_REAL);
++ if (option_verbose > 2)
++ ast_verbose(VERBOSE_PREFIX_3 "Channel %d still has (callwait) call, ringing phone\n", p->channel);
++ analog_unalloc_sub(p, ANALOG_SUB_CALLWAIT);
++ analog_stop_callwait(p);
++ p->owner = NULL;
++ /* Don't start streaming audio yet if the incoming call isn't up yet */
++ if (p->subs[ANALOG_SUB_REAL].owner->_state != AST_STATE_UP)
++ p->dialing = 1;
++ analog_ring(p);
++ } else if (p->subs[ANALOG_SUB_THREEWAY].owner) {
++ unsigned int mssinceflash;
++ /* Here we have to retain the lock on both the main channel, the 3-way channel, and
++ the private structure -- not especially easy or clean */
++ while (p->subs[ANALOG_SUB_THREEWAY].owner && ast_channel_trylock(p->subs[ANALOG_SUB_THREEWAY].owner)) {
++ /* Yuck, didn't get the lock on the 3-way, gotta release everything and re-grab! */
++ analog_unlock_private(p);
++ CHANNEL_DEADLOCK_AVOIDANCE(ast);
++ /* We can grab ast and p in that order, without worry. We should make sure
++ nothing seriously bad has happened though like some sort of bizarre double
++ masquerade! */
++ analog_lock_private(p);
++ if (p->owner != ast) {
++ ast_log(LOG_WARNING, "This isn't good...\n");
++ return NULL;
++ }
++ }
++ if (!p->subs[ANALOG_SUB_THREEWAY].owner) {
++ ast_log(LOG_NOTICE, "Whoa, threeway disappeared kinda randomly.\n");
++ return NULL;
++ }
++ 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
++ hanging up. Hangup both channels now */
++ if (p->subs[ANALOG_SUB_THREEWAY].owner)
++ ast_queue_hangup(p->subs[ANALOG_SUB_THREEWAY].owner);
++ ast_softhangup_nolock(p->subs[ANALOG_SUB_THREEWAY].owner, AST_SOFTHANGUP_DEV);
++ ast_debug(1, "Looks like a bounced flash, hanging up both calls on %d\n", p->channel);
++ ast_channel_unlock(p->subs[ANALOG_SUB_THREEWAY].owner);
++ } else if ((ast->pbx) || (ast->_state == AST_STATE_UP)) {
++ if (p->transfer) {
++ /* In any case this isn't a threeway call anymore */
++ p->subs[ANALOG_SUB_REAL].inthreeway = 0;
++ p->subs[ANALOG_SUB_THREEWAY].inthreeway = 0;
++ /* Only attempt transfer if the phone is ringing; why transfer to busy tone eh? */
++ if (!p->transfertobusy && ast->_state == AST_STATE_BUSY) {
++ ast_channel_unlock(p->subs[ANALOG_SUB_THREEWAY].owner);
++ /* Swap subs and dis-own channel */
++ analog_swap_subs(p, ANALOG_SUB_THREEWAY, ANALOG_SUB_REAL);
++ p->owner = NULL;
++ /* Ring the phone */
++ analog_ring(p);
++ } else {
++ if ((res = analog_attempt_transfer(p)) < 0) {
++ ast_softhangup_nolock(p->subs[ANALOG_SUB_THREEWAY].owner, AST_SOFTHANGUP_DEV);
++ if (p->subs[ANALOG_SUB_THREEWAY].owner)
++ ast_channel_unlock(p->subs[ANALOG_SUB_THREEWAY].owner);
++ } else if (res) {
++ /* Don't actually hang up at this point */
++ if (p->subs[ANALOG_SUB_THREEWAY].owner)
++ ast_channel_unlock(&p->subs[ANALOG_SUB_THREEWAY].owner);
++ break;
++ }
++ }
++ } else {
++ ast_softhangup_nolock(p->subs[ANALOG_SUB_THREEWAY].owner, AST_SOFTHANGUP_DEV);
++ if (p->subs[ANALOG_SUB_THREEWAY].owner)
++ ast_channel_unlock(p->subs[ANALOG_SUB_THREEWAY].owner);
++ }
++ } else {
++ ast_channel_unlock(p->subs[ANALOG_SUB_THREEWAY].owner);
++ /* Swap subs and dis-own channel */
++ analog_swap_subs(p, ANALOG_SUB_THREEWAY, ANALOG_SUB_REAL);
++ p->owner = NULL;
++ /* Ring the phone */
++ analog_ring(p);
++ }
++ }
++ } else {
++ ast_log(LOG_WARNING, "Got a hangup and my index is %d?\n", index);
++ }
++ /* Fall through */
++ default:
++ analog_set_echocanceller(p, 0);
++ return NULL;
++ }
++ break;
++ case ANALOG_EVENT_RINGOFFHOOK:
++ if (p->inalarm) break;
++ /* for E911, its supposed to wait for offhook then dial
++ the second half of the dial string */
++ if (((mysig == ANALOG_SIG_E911) || (mysig == ANALOG_SIG_FGC_CAMA) || (mysig == ANALOG_SIG_FGC_CAMAMF)) && (ast->_state == AST_STATE_DIALING_OFFHOOK)) {
++ c = strchr(p->dialdest, '/');
++ if (c)
++ c++;
++ else
++ c = p->dialdest;
++ if (*c) snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), "M*0%s#", c);
++ else ast_copy_string(p->dop.dialstr,"M*2#", sizeof(p->dop.dialstr));
++ if (strlen(p->dop.dialstr) > 4) {
++ memset(p->echorest, 'w', sizeof(p->echorest) - 1);
++ strcpy(p->echorest + (p->echotraining / 401) + 1, p->dop.dialstr + strlen(p->dop.dialstr) - 2);
++ p->echorest[sizeof(p->echorest) - 1] = '\0';
++ p->echobreak = 1;
++ p->dop.dialstr[strlen(p->dop.dialstr)-2] = '\0';
++ } else
++ p->echobreak = 0;
++ if (analog_dial_digits(p, ANALOG_SUB_REAL, &p->dop)) {
++ int saveerr = errno;
++ analog_on_hook(p);
++ ast_log(LOG_WARNING, "Dialing failed on channel %d: %s\n", p->channel, strerror(saveerr));
++ return NULL;
++ }
++ p->dialing = 1;
++ return &p->subs[index].f;
++ }
++ switch (p->sig) {
++ case ANALOG_SIG_FXOLS:
++ case ANALOG_SIG_FXOGS:
++ case ANALOG_SIG_FXOKS:
++ switch (ast->_state) {
++ case AST_STATE_RINGING:
++ analog_set_echocanceller(p, 1);
++ analog_train_echocanceller(p);
++ p->subs[index].f.frametype = AST_FRAME_CONTROL;
++ p->subs[index].f.subclass = AST_CONTROL_ANSWER;
++ /* Make sure it stops ringing */
++ analog_off_hook(p);
++ ast_debug(1, "channel %d answered\n", p->channel);
++ p->dialing = 0;
++ p->callwaitcas = 0;
++ if (!ast_strlen_zero(p->dop.dialstr)) {
++ /* nick@dccinc.com 4/3/03 - fxo should be able to do deferred dialing */
++ res = analog_dial_digits(p, ANALOG_SUB_REAL, &p->dop);
++ if (res < 0) {
++ 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 {
++ ast_debug(1, "Sent FXO deferred digit string: %s\n", p->dop.dialstr);
++ p->subs[index].f.frametype = AST_FRAME_NULL;
++ p->subs[index].f.subclass = 0;
++ p->dialing = 1;
++ }
++ p->dop.dialstr[0] = '\0';
++ ast_setstate(ast, AST_STATE_DIALING);
++ } else
++ ast_setstate(ast, AST_STATE_UP);
++ return &p->subs[index].f;
++ case AST_STATE_DOWN:
++ ast_setstate(ast, AST_STATE_RING);
++ ast->rings = 1;
++ p->subs[index].f.frametype = AST_FRAME_CONTROL;
++ p->subs[index].f.subclass = AST_CONTROL_OFFHOOK;
++ ast_debug(1, "channel %d picked up\n", p->channel);
++ return &p->subs[index].f;
++ case AST_STATE_UP:
++ /* Make sure it stops ringing */
++ analog_off_hook(p);
++ /* Okay -- probably call waiting*/
++ if (ast_bridged_channel(p->owner))
++ ast_queue_control(p->owner, AST_CONTROL_UNHOLD);
++ break;
++ case AST_STATE_RESERVED:
++ /* Start up dialtone */
++ if (analog_has_voicemail(p))
++ res = analog_play_tone(p, ANALOG_SUB_REAL, ANALOG_TONE_STUTTER);
++ else
++ res = analog_play_tone(p, ANALOG_SUB_REAL, ANALOG_TONE_DIALTONE);
++ break;
++ default:
++ ast_log(LOG_WARNING, "FXO phone off hook in weird state %d??\n", ast->_state);
++ }
++ break;
++ case ANALOG_SIG_FXSLS:
++ case ANALOG_SIG_FXSGS:
++ case ANALOG_SIG_FXSKS:
++#if 0
++ if (ast->_state == AST_STATE_RING) {
++ p->ringt = p->ringt_base;
++ }
++#endif
++
++ /* Fall through */
++ case ANALOG_SIG_EM:
++ case ANALOG_SIG_EM_E1:
++ case ANALOG_SIG_EMWINK:
++ case ANALOG_SIG_FEATD:
++ case ANALOG_SIG_FEATDMF:
++ case ANALOG_SIG_FEATDMF_TA:
++ case ANALOG_SIG_E911:
++ case ANALOG_SIG_FGC_CAMA:
++ case ANALOG_SIG_FGC_CAMAMF:
++ case ANALOG_SIG_FEATB:
++ case ANALOG_SIG_SF:
++ case ANALOG_SIG_SFWINK:
++ case ANALOG_SIG_SF_FEATD:
++ case ANALOG_SIG_SF_FEATDMF:
++ case ANALOG_SIG_SF_FEATB:
++ if (ast->_state == AST_STATE_PRERING)
++ ast_setstate(ast, AST_STATE_RING);
++ if ((ast->_state == AST_STATE_DOWN) || (ast->_state == AST_STATE_RING)) {
++ ast_debug(1, "Ring detected\n");
++ p->subs[index].f.frametype = AST_FRAME_CONTROL;
++ p->subs[index].f.subclass = AST_CONTROL_RING;
++ } else if (p->outgoing && ((ast->_state == AST_STATE_RINGING) || (ast->_state == AST_STATE_DIALING))) {
++ ast_debug(1, "Line answered\n");
++ p->subs[index].f.frametype = AST_FRAME_CONTROL;
++ p->subs[index].f.subclass = AST_CONTROL_ANSWER;
++ ast_setstate(ast, AST_STATE_UP);
++ } else if (ast->_state != AST_STATE_RING)
++ ast_log(LOG_WARNING, "Ring/Off-hook in strange state %d on channel %d\n", ast->_state, p->channel);
++ break;
++ default:
++ ast_log(LOG_WARNING, "Don't know how to handle ring/off hook for signalling %d\n", p->sig);
++ }
++ break;
++#ifdef ANALOG_EVENT_RINGBEGIN
++ case ANALOG_EVENT_RINGBEGIN:
++ switch (p->sig) {
++ case ANALOG_SIG_FXSLS:
++ case ANALOG_SIG_FXSGS:
++ case ANALOG_SIG_FXSKS:
++#if 0
++ if (ast->_state == AST_STATE_RING) {
++ p->ringt = p->ringt_base;
++ }
++#endif
++ break;
++ }
++ break;
++#endif
++ case ANALOG_EVENT_RINGEROFF:
++ if (p->inalarm) break;
++ ast->rings++;
++ if (ast->rings == p->cidrings) {
++ analog_send_callerid(p, 0, &p->cid);
++ }
++
++ if (ast->rings > p->cidrings) {
++ p->callwaitcas = 0;
++ }
++ p->subs[index].f.frametype = AST_FRAME_CONTROL;
++ p->subs[index].f.subclass = AST_CONTROL_RINGING;
++ break;
++ case ANALOG_EVENT_RINGERON:
++ break;
++ case ANALOG_EVENT_NOALARM:
++ p->inalarm = 0;
++ if (!p->unknown_alarm) {
++ ast_log(LOG_NOTICE, "Alarm cleared on channel %d\n", p->channel);
++ manager_event(EVENT_FLAG_SYSTEM, "AlarmClear",
++ "Channel: %d\r\n", p->channel);
++ } else {
++ p->unknown_alarm = 0;
++ }
++ break;
++ case ANALOG_EVENT_WINKFLASH:
++ if (p->inalarm) break;
++ /* Remember last time we got a flash-hook */
++ gettimeofday(&p->flashtime, NULL);
++ switch (mysig) {
++ case ANALOG_SIG_FXOLS:
++ case ANALOG_SIG_FXOGS:
++ case ANALOG_SIG_FXOKS:
++#if 0
++ ast_debug(1, "Winkflash, index: %d, normal: %d, callwait: %d, thirdcall: %d\n",
++ index, p->subs[ANALOG_SUB_REAL].dfd, p->subs[ANALOG_SUB_CALLWAIT].dfd, p->subs[ANALOG_SUB_THREEWAY].dfd);
++#endif
++ p->callwaitcas = 0;
++
++ if (index != ANALOG_SUB_REAL) {
++ ast_log(LOG_WARNING, "Got flash hook with index %d on channel %d?!?\n", index, p->channel);
++ goto winkflashdone;
++ }
++
++ if (p->subs[ANALOG_SUB_CALLWAIT].owner) {
++ /* Swap to call-wait */
++ int previous_state = p->subs[ANALOG_SUB_CALLWAIT].owner->_state;
++ if (p->subs[ANALOG_SUB_CALLWAIT].owner->_state == AST_STATE_RINGING) {
++ ast_setstate(p->subs[ANALOG_SUB_CALLWAIT].owner, AST_STATE_UP);
++ }
++ analog_swap_subs(p, ANALOG_SUB_REAL, ANALOG_SUB_CALLWAIT);
++ analog_play_tone(p, ANALOG_SUB_REAL, -1);
++ p->owner = p->subs[ANALOG_SUB_REAL].owner;
++ ast_debug(1, "Making %s the new owner\n", p->owner->name);
++ if (previous_state == AST_STATE_RINGING) {
++ ast_queue_control(p->subs[ANALOG_SUB_REAL].owner, AST_CONTROL_ANSWER);
++ }
++ analog_stop_callwait(p);
++ /* Start music on hold if appropriate */
++ if (!p->subs[ANALOG_SUB_CALLWAIT].inthreeway && ast_bridged_channel(p->subs[ANALOG_SUB_CALLWAIT].owner)) {
++ ast_queue_control_data(p->subs[ANALOG_SUB_CALLWAIT].owner, AST_CONTROL_HOLD,
++ S_OR(p->mohsuggest, NULL),
++ !ast_strlen_zero(p->mohsuggest) ? strlen(p->mohsuggest) + 1 : 0);
++ }
++ ast_queue_control(p->subs[ANALOG_SUB_REAL].owner, AST_CONTROL_ANSWER);
++ if (ast_bridged_channel(p->subs[ANALOG_SUB_REAL].owner)) {
++ ast_queue_control_data(p->subs[ANALOG_SUB_REAL].owner, AST_CONTROL_HOLD,
++ S_OR(p->mohsuggest, NULL),
++ !ast_strlen_zero(p->mohsuggest) ? strlen(p->mohsuggest) + 1 : 0);
++ }
++ ast_queue_control(p->subs[ANALOG_SUB_REAL].owner, AST_CONTROL_UNHOLD);
++ } else if (!p->subs[ANALOG_SUB_THREEWAY].owner) {
++ char cid_num[256];
++ char cid_name[256];
++
++ if (!p->threewaycalling) {
++ /* Just send a flash if no 3-way calling */
++ ast_queue_control(p->subs[ANALOG_SUB_REAL].owner, AST_CONTROL_FLASH);
++ goto winkflashdone;
++ } else if (!analog_check_for_conference(p)) {
++ if (p->dahditrcallerid && p->owner) {
++ if (p->owner->cid.cid_num)
++ ast_copy_string(cid_num, p->owner->cid.cid_num, sizeof(cid_num));
++ if (p->owner->cid.cid_name)
++ ast_copy_string(cid_name, p->owner->cid.cid_name, sizeof(cid_name));
++ }
++ /* 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_debug(1, "Flash when call not up or ringing\n");
++ goto winkflashdone;
++ }
++ if (analog_alloc_sub(p, ANALOG_SUB_THREEWAY)) {
++ ast_log(LOG_WARNING, "Unable to allocate three-way subchannel\n");
++ goto winkflashdone;
++ }
++ /* Make new channel */
++ chan = analog_new_ast_channel(p, AST_STATE_RESERVED, 0, ANALOG_SUB_THREEWAY);
++ if (p->dahditrcallerid) {
++ if (!p->origcid_num)
++ p->origcid_num = ast_strdup(p->cid_num);
++ if (!p->origcid_name)
++ p->origcid_name = ast_strdup(p->cid_name);
++ ast_copy_string(p->cid_num, cid_num, sizeof(p->cid_num));
++ ast_copy_string(p->cid_name, cid_name, sizeof(p->cid_name));
++ }
++ /* Swap things around between the three-way and real call */
++ analog_swap_subs(p, ANALOG_SUB_THREEWAY, ANALOG_SUB_REAL);
++ /* Disable echo canceller for better dialing */
++ analog_set_echocanceller(p, 0);
++ res = analog_play_tone(p, ANALOG_SUB_REAL, ANALOG_TONE_DIALRECALL);
++ if (res)
++ ast_log(LOG_WARNING, "Unable to start dial recall tone on channel %d\n", p->channel);
++ p->ss_astchan = p->owner = chan;
++ pthread_attr_init(&attr);
++ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
++ if (!chan) {
++ ast_log(LOG_WARNING, "Cannot allocate new structure on channel %d\n", p->channel);
++ } else if (ast_pthread_create(&threadid, &attr, __analog_ss_thread, p)) {
++ ast_log(LOG_WARNING, "Unable to start simple switch on channel %d\n", p->channel);
++ res = analog_play_tone(p, ANALOG_SUB_REAL, ANALOG_TONE_CONGESTION);
++ analog_set_echocanceller(p, 1);
++ ast_hangup(chan);
++ } else {
++ struct ast_channel *other = ast_bridged_channel(p->subs[ANALOG_SUB_THREEWAY].owner);
++ int way3bridge = 0, cdr3way = 0;
++
++ if (!other) {
++ other = ast_bridged_channel(p->subs[ANALOG_SUB_REAL].owner);
++ } else
++ way3bridge = 1;
++
++ if (p->subs[ANALOG_SUB_THREEWAY].owner->cdr)
++ cdr3way = 1;
++
++ if (option_verbose > 2)
++ ast_verbose(VERBOSE_PREFIX_3 "Started three way call on channel %d\n", p->channel);
++ /* Start music on hold if appropriate */
++ if (ast_bridged_channel(p->subs[ANALOG_SUB_THREEWAY].owner)) {
++ ast_queue_control_data(p->subs[ANALOG_SUB_THREEWAY].owner, AST_CONTROL_HOLD,
++ S_OR(p->mohsuggest, NULL),
++ !ast_strlen_zero(p->mohsuggest) ? strlen(p->mohsuggest) + 1 : 0);
++ }
++ }
++ pthread_attr_destroy(&attr);
++ }
++ } else {
++ /* Already have a 3 way call */
++ if (p->subs[ANALOG_SUB_THREEWAY].inthreeway) {
++ /* Call is already up, drop the last person */
++ ast_debug(1, "Got flash with three way call up, dropping last call on %d\n", p->channel);
++ /* If the primary call isn't answered yet, use it */
++ if ((p->subs[ANALOG_SUB_REAL].owner->_state != AST_STATE_UP) && (p->subs[ANALOG_SUB_THREEWAY].owner->_state == AST_STATE_UP)) {
++ /* Swap back -- we're dropping the real 3-way that isn't finished yet*/
++ analog_swap_subs(p, ANALOG_SUB_THREEWAY, ANALOG_SUB_REAL);
++ p->owner = p->subs[ANALOG_SUB_REAL].owner;
++ }
++ /* Drop the last call and stop the conference */
++ if (option_verbose > 2)
++ ast_verbose(VERBOSE_PREFIX_3 "Dropping three-way call on %s\n", p->subs[ANALOG_SUB_THREEWAY].owner->name);
++ ast_softhangup_nolock(p->subs[ANALOG_SUB_THREEWAY].owner, AST_SOFTHANGUP_DEV);
++ p->subs[ANALOG_SUB_REAL].inthreeway = 0;
++ p->subs[ANALOG_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))) {
++ int otherindex = ANALOG_SUB_THREEWAY;
++ struct ast_channel *other = ast_bridged_channel(p->subs[ANALOG_SUB_THREEWAY].owner);
++ int way3bridge = 0, cdr3way = 0;
++
++ if (!other) {
++ other = ast_bridged_channel(p->subs[ANALOG_SUB_REAL].owner);
++ } else
++ way3bridge = 1;
++
++ if (p->subs[ANALOG_SUB_THREEWAY].owner->cdr)
++ cdr3way = 1;
++
++ if (option_verbose > 2)
++ ast_verbose(VERBOSE_PREFIX_3 "Building conference on call on %s and %s\n", p->subs[ANALOG_SUB_THREEWAY].owner->name, p->subs[ANALOG_SUB_REAL].owner->name);
++ /* Put them in the threeway, and flip */
++ p->subs[ANALOG_SUB_THREEWAY].inthreeway = 1;
++ p->subs[ANALOG_SUB_REAL].inthreeway = 1;
++ if (ast->_state == AST_STATE_UP) {
++ analog_swap_subs(p, ANALOG_SUB_THREEWAY, ANALOG_SUB_REAL);
++ otherindex = ANALOG_SUB_REAL;
++ }
++ if (p->subs[otherindex].owner && ast_bridged_channel(p->subs[otherindex].owner))
++ ast_queue_control(p->subs[otherindex].owner, AST_CONTROL_UNHOLD);
++ p->owner = p->subs[ANALOG_SUB_REAL].owner;
++ if (ast->_state == AST_STATE_RINGING) {
++ ast_debug(1, "Enabling ringtone on real and threeway\n");
++ analog_play_tone(p, ANALOG_SUB_REAL, ANALOG_TONE_RINGTONE);
++ analog_play_tone(p, ANALOG_SUB_THREEWAY, ANALOG_TONE_RINGTONE);
++ }
++ } else {
++ if (option_verbose > 2)
++ ast_verbose(VERBOSE_PREFIX_3 "Dumping incomplete call on on %s\n", p->subs[ANALOG_SUB_THREEWAY].owner->name);
++ analog_swap_subs(p, ANALOG_SUB_THREEWAY, ANALOG_SUB_REAL);
++ ast_softhangup_nolock(p->subs[ANALOG_SUB_THREEWAY].owner, AST_SOFTHANGUP_DEV);
++ p->owner = p->subs[ANALOG_SUB_REAL].owner;
++ if (p->subs[ANALOG_SUB_REAL].owner && ast_bridged_channel(p->subs[ANALOG_SUB_REAL].owner))
++ ast_queue_control(p->subs[ANALOG_SUB_REAL].owner, AST_CONTROL_UNHOLD);
++ analog_set_echocanceller(p, 1);
++ }
++ }
++ }
++ winkflashdone:
++ analog_update_conf(p);
++ break;
++ case ANALOG_SIG_EM:
++ case ANALOG_SIG_EM_E1:
++ case ANALOG_SIG_EMWINK:
++ case ANALOG_SIG_FEATD:
++ case ANALOG_SIG_SF:
++ case ANALOG_SIG_SFWINK:
++ case ANALOG_SIG_SF_FEATD:
++ case ANALOG_SIG_FXSLS:
++ case ANALOG_SIG_FXSGS:
++ if (p->dialing)
++ ast_debug(1, "Ignoring wink on channel %d\n", p->channel);
++ else
++ ast_debug(1, "Got wink in weird state %d on channel %d\n", ast->_state, p->channel);
++ break;
++ case ANALOG_SIG_FEATDMF_TA:
++ switch (p->whichwink) {
++ case 0:
++ ast_debug(1, "ANI2 set to '%d' and ANI is '%s'\n", p->owner->cid.cid_ani2, p->owner->cid.cid_ani);
++ snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), "M*%d%s#", p->owner->cid.cid_ani2, p->owner->cid.cid_ani);
++ break;
++ case 1:
++ ast_copy_string(p->dop.dialstr, p->finaldial, sizeof(p->dop.dialstr));
++ break;
++ case 2:
++ ast_log(LOG_WARNING, "Received unexpected wink on channel of type ANALOG_SIG_FEATDMF_TA\n");
++ return NULL;
++ }
++ p->whichwink++;
++ /* Fall through */
++ case ANALOG_SIG_FEATDMF:
++ case ANALOG_SIG_E911:
++ case ANALOG_SIG_FGC_CAMAMF:
++ case ANALOG_SIG_FGC_CAMA:
++ case ANALOG_SIG_FEATB:
++ case ANALOG_SIG_SF_FEATDMF:
++ case ANALOG_SIG_SF_FEATB:
++ /* FGD MF *Must* wait for wink */
++ if (!ast_strlen_zero(p->dop.dialstr)) {
++ res = analog_dial_digits(p, ANALOG_SUB_REAL, &p->dop);
++ if (res < 0) {
++ 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
++ ast_debug(1, "Sent deferred digit string on channel %d: %s\n", p->channel, p->dop.dialstr);
++ }
++ p->dop.dialstr[0] = '\0';
++ break;
++ default:
++ ast_log(LOG_WARNING, "Don't know how to handle ring/off hoook for signalling %d\n", p->sig);
++ }
++ break;
++ case ANALOG_EVENT_HOOKCOMPLETE:
++ if (p->inalarm) break;
++ switch (mysig) {
++ case ANALOG_SIG_FXSLS: /* only interesting for FXS */
++ case ANALOG_SIG_FXSGS:
++ case ANALOG_SIG_FXSKS:
++ case ANALOG_SIG_EM:
++ case ANALOG_SIG_EM_E1:
++ case ANALOG_SIG_EMWINK:
++ case ANALOG_SIG_FEATD:
++ case ANALOG_SIG_SF:
++ case ANALOG_SIG_SFWINK:
++ case ANALOG_SIG_SF_FEATD:
++ if (!ast_strlen_zero(p->dop.dialstr)) {
++ res = analog_dial_digits(p, ANALOG_SUB_REAL, &p->dop);
++ if (res < 0) {
++ 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
++ ast_debug(1, "Sent deferred digit string on channel %d: %s\n", p->channel, p->dop.dialstr);
++ }
++ p->dop.dialstr[0] = '\0';
++ p->dop.op = ANALOG_DIAL_OP_REPLACE;
++ break;
++ case ANALOG_SIG_FEATDMF:
++ case ANALOG_SIG_FEATDMF_TA:
++ case ANALOG_SIG_E911:
++ case ANALOG_SIG_FGC_CAMA:
++ case ANALOG_SIG_FGC_CAMAMF:
++ case ANALOG_SIG_FEATB:
++ case ANALOG_SIG_SF_FEATDMF:
++ case ANALOG_SIG_SF_FEATB:
++ ast_debug(1, "Got hook complete in MF FGD, waiting for wink now on channel %d\n",p->channel);
++ break;
++ default:
++ break;
++ }
++ break;
++ case ANALOG_EVENT_POLARITY:
++ /*
++ * If we get a Polarity Switch event, check to see
++ * if we should change the polarity state and
++ * mark the channel as UP or if this is an indication
++ * of remote end disconnect.
++ */
++ if (p->polarity == POLARITY_IDLE) {
++ p->polarity = POLARITY_REV;
++ if (p->answeronpolarityswitch &&
++ ((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) {
++ gettimeofday(&p->polaritydelaytv, NULL);
++ }
++ } 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) &&
++ ((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 */
++ 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);
++ p->polarity = POLARITY_IDLE;
++ } else {
++ ast_debug(1, "Polarity Reversal detected but NOT hanging up (too close to answer event) on channel %d, state %d\n", p->channel, ast->_state);
++ }
++ } else {
++ 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 */
++ 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:
++ ast_debug(1, "Dunno what to do with event %d on channel %d\n", res, p->channel);
++ }
++ return &p->subs[index].f;
++}
++
++struct ast_frame *analog_exception(struct analog_pvt *p, struct ast_channel *ast)
++{
++ int res;
++ int usedindex=-1;
++ int index;
++ struct ast_frame *f;
++
++ ast_log(LOG_DEBUG, "%s %d\n", __FUNCTION__, p->channel);
++
++ index = analog_get_index(ast, p, 1);
++
++ p->subs[index].f.frametype = AST_FRAME_NULL;
++ p->subs[index].f.datalen = 0;
++ p->subs[index].f.samples = 0;
++ p->subs[index].f.mallocd = 0;
++ p->subs[index].f.offset = 0;
++ p->subs[index].f.subclass = 0;
++ p->subs[index].f.delivery = ast_tv(0,0);
++ p->subs[index].f.src = "dahdi_exception";
++ p->subs[index].f.data.ptr = NULL;
++
++
++ if (!p->owner) {
++ /* If nobody owns us, absorb the event appropriately, otherwise
++ we loop indefinitely. This occurs when, during call waiting, the
++ other end hangs up our channel so that it no longer exists, but we
++ have neither FLASH'd nor ONHOOK'd to signify our desire to
++ change to the other channel. */
++ res = analog_get_event(p);
++
++ /* Switch to real if there is one and this isn't something really silly... */
++ if ((res != ANALOG_EVENT_RINGEROFF) && (res != ANALOG_EVENT_RINGERON) &&
++ (res != ANALOG_EVENT_HOOKCOMPLETE)) {
++ ast_debug(1, "Restoring owner of channel %d on event %d\n", p->channel, res);
++ p->owner = p->subs[ANALOG_SUB_REAL].owner;
++ if (p->owner && ast_bridged_channel(p->owner))
++ ast_queue_control(p->owner, AST_CONTROL_UNHOLD);
++ }
++ switch (res) {
++ case ANALOG_EVENT_ONHOOK:
++ analog_set_echocanceller(p, 0);
++ if (p->owner) {
++ if (option_verbose > 2)
++ ast_verbose(VERBOSE_PREFIX_3 "Channel %s still has call, ringing phone\n", p->owner->name);
++ analog_ring(p);
++ analog_stop_callwait(p);
++ } else
++ ast_log(LOG_WARNING, "Absorbed on hook, but nobody is left!?!?\n");
++ analog_update_conf(p);
++ break;
++ case ANALOG_EVENT_RINGOFFHOOK:
++ analog_set_echocanceller(p, 1);
++ analog_off_hook(p);
++ if (p->owner && (p->owner->_state == AST_STATE_RINGING)) {
++ ast_queue_control(p->subs[ANALOG_SUB_REAL].owner, AST_CONTROL_ANSWER);
++ p->dialing = 0;
++ }
++ break;
++ case ANALOG_EVENT_HOOKCOMPLETE:
++ case ANALOG_EVENT_RINGERON:
++ case ANALOG_EVENT_RINGEROFF:
++ /* Do nothing */
++ break;
++ case ANALOG_EVENT_WINKFLASH:
++ gettimeofday(&p->flashtime, NULL);
++ if (p->owner) {
++ if (option_verbose > 2)
++ ast_verbose(VERBOSE_PREFIX_3 "Channel %d flashed to other channel %s\n", p->channel, p->owner->name);
++ if (p->owner->_state != AST_STATE_UP) {
++ /* Answer if necessary */
++ usedindex = analog_get_index(p->owner, p, 0);
++ if (usedindex > -1) {
++ ast_queue_control(p->subs[usedindex].owner, AST_CONTROL_ANSWER);
++ }
++ ast_setstate(p->owner, AST_STATE_UP);
++ }
++ analog_stop_callwait(p);
++ if (ast_bridged_channel(p->owner))
++ ast_queue_control(p->owner, AST_CONTROL_UNHOLD);
++ } else
++ ast_log(LOG_WARNING, "Absorbed on hook, but nobody is left!?!?\n");
++ analog_update_conf(p);
++ break;
++ default:
++ ast_log(LOG_WARNING, "Don't know how to absorb event %s\n", analog_event2str(res));
++ }
++ f = &p->subs[index].f;
++ return f;
++ }
++ 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) {
++ ast_log(LOG_WARNING, "We're %s, not %s\n", ast->name, p->owner->name);
++ f = &p->subs[index].f;
++ return f;
++ }
++ f = __analog_handle_event(p, ast);
++ return f;
++}
++
++int analog_handle_init_event(struct analog_pvt *i, int event)
++{
++ int res;
++ pthread_t threadid;
++ pthread_attr_t attr;
++ struct ast_channel *chan;
++
++ ast_debug(1, "channel (%d) - signaling (%d) - event (%s)\n",
++ i->channel, i->sig, analog_event2str(event));
++
++ pthread_attr_init(&attr);
++ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
++ /* Handle an event on a given channel for the monitor thread. */
++ switch (event) {
++ case ANALOG_EVENT_WINKFLASH:
++ case ANALOG_EVENT_RINGOFFHOOK:
++ if (i->inalarm) break;
++ /* Got a ring/answer. What kind of channel are we? */
++ switch (i->sig) {
++ case ANALOG_SIG_FXOLS:
++ case ANALOG_SIG_FXOGS:
++ case ANALOG_SIG_FXOKS:
++ res = analog_off_hook(i);
++ if (res && (errno == EBUSY))
++ break;
++ if (i->immediate) {
++ analog_set_echocanceller(i, 1);
++ /* The channel is immediately up. Start right away */
++ res = analog_play_tone(i, ANALOG_SUB_REAL, ANALOG_TONE_RINGTONE);
++ chan = analog_new_ast_channel(i, AST_STATE_RING, 1, ANALOG_SUB_REAL);
++ if (!chan) {
++ ast_log(LOG_WARNING, "Unable to start PBX on channel %d\n", i->channel);
++ res = analog_play_tone(i, ANALOG_SUB_REAL, ANALOG_TONE_CONGESTION);
++ if (res < 0)
++ ast_log(LOG_WARNING, "Unable to play congestion tone on channel %d\n", i->channel);
++ }
++ } else {
++ /* Check for callerid, digits, etc */
++ chan = analog_new_ast_channel(i, AST_STATE_RESERVED, 0, ANALOG_SUB_REAL);
++ i->ss_astchan = chan;
++ if (chan) {
++ if (analog_has_voicemail(i))
++ res = analog_play_tone(i, ANALOG_SUB_REAL, ANALOG_TONE_STUTTER);
++ else
++ res = analog_play_tone(i, ANALOG_SUB_REAL, ANALOG_TONE_DIALTONE);
++ 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(&threadid, &attr, __analog_ss_thread, i)) {
++ ast_log(LOG_WARNING, "Unable to start simple switch thread on channel %d\n", i->channel);
++ res = analog_play_tone(i, ANALOG_SUB_REAL, ANALOG_TONE_CONGESTION);
++ if (res < 0)
++ ast_log(LOG_WARNING, "Unable to play congestion tone on channel %d\n", i->channel);
++ ast_hangup(chan);
++ }
++ } else
++ ast_log(LOG_WARNING, "Unable to create channel\n");
++ }
++ break;
++ case ANALOG_SIG_FXSLS:
++ case ANALOG_SIG_FXSGS:
++ case ANALOG_SIG_FXSKS:
++#if 0
++ i->ringt = i->ringt_base;
++#endif
++ /* Fall through */
++ case ANALOG_SIG_EMWINK:
++ case ANALOG_SIG_FEATD:
++ case ANALOG_SIG_FEATDMF:
++ case ANALOG_SIG_FEATDMF_TA:
++ case ANALOG_SIG_E911:
++ case ANALOG_SIG_FGC_CAMA:
++ case ANALOG_SIG_FGC_CAMAMF:
++ case ANALOG_SIG_FEATB:
++ case ANALOG_SIG_EM:
++ case ANALOG_SIG_EM_E1:
++ case ANALOG_SIG_SFWINK:
++ case ANALOG_SIG_SF_FEATD:
++ case ANALOG_SIG_SF_FEATDMF:
++ case ANALOG_SIG_SF_FEATB:
++ case ANALOG_SIG_SF:
++ /* Check for callerid, digits, etc */
++ if (i->cid_start == ANALOG_CID_START_POLARITY_IN) {
++ chan = analog_new_ast_channel(i, AST_STATE_PRERING, 0, ANALOG_SUB_REAL);
++ } else {
++ chan = analog_new_ast_channel(i, AST_STATE_RING, 0, ANALOG_SUB_REAL);
++ }
++ i->ss_astchan = chan;
++ if (chan && ast_pthread_create(&threadid, &attr, __analog_ss_thread, i)) {
++ ast_log(LOG_WARNING, "Unable to start simple switch thread on channel %d\n", i->channel);
++ res = analog_play_tone(i, ANALOG_SUB_REAL, ANALOG_TONE_CONGESTION);
++ if (res < 0)
++ ast_log(LOG_WARNING, "Unable to play congestion tone on channel %d\n", i->channel);
++ ast_hangup(chan);
++ } else if (!chan) {
++ ast_log(LOG_WARNING, "Cannot allocate new structure on channel %d\n", i->channel);
++ }
++ break;
++ default:
++ ast_log(LOG_WARNING, "Don't know how to handle ring/answer with signalling %s on channel %d\n", analog_sigtype_to_str(i->sig), i->channel);
++ res = analog_play_tone(i, ANALOG_SUB_REAL, ANALOG_TONE_CONGESTION);
++ if (res < 0)
++ ast_log(LOG_WARNING, "Unable to play congestion tone on channel %d\n", i->channel);
++ return -1;
++ }
++ break;
++ case ANALOG_EVENT_NOALARM:
++ i->inalarm = 0;
++ if (!i->unknown_alarm) {
++ ast_log(LOG_NOTICE, "Alarm cleared on channel %d\n", i->channel);
++ manager_event(EVENT_FLAG_SYSTEM, "AlarmClear",
++ "Channel: %d\r\n", i->channel);
++ } else {
++ i->unknown_alarm = 0;
++ }
++ break;
++ case ANALOG_EVENT_ALARM:
++ i->inalarm = 1;
++#if 0
++ res = get_alarms(i);
++ handle_alarms(i, res);
++#endif
++ /* fall thru intentionally */
++ case ANALOG_EVENT_ONHOOK:
++ /* Back on hook. Hang up. */
++ switch (i->sig) {
++ case ANALOG_SIG_FXOLS:
++ case ANALOG_SIG_FXOGS:
++ case ANALOG_SIG_FEATD:
++ case ANALOG_SIG_FEATDMF:
++ case ANALOG_SIG_FEATDMF_TA:
++ case ANALOG_SIG_E911:
++ case ANALOG_SIG_FGC_CAMA:
++ case ANALOG_SIG_FGC_CAMAMF:
++ case ANALOG_SIG_FEATB:
++ case ANALOG_SIG_EM:
++ case ANALOG_SIG_EM_E1:
++ case ANALOG_SIG_EMWINK:
++ case ANALOG_SIG_SF_FEATD:
++ case ANALOG_SIG_SF_FEATDMF:
++ case ANALOG_SIG_SF_FEATB:
++ case ANALOG_SIG_SF:
++ case ANALOG_SIG_SFWINK:
++ case ANALOG_SIG_FXSLS:
++ case ANALOG_SIG_FXSGS:
++ case ANALOG_SIG_FXSKS:
++ analog_set_echocanceller(i, 0);
++ res = analog_play_tone(i, ANALOG_SUB_REAL, -1);
++ analog_on_hook(i);
++ break;
++ case ANALOG_SIG_FXOKS:
++ analog_set_echocanceller(i, 0);
++ /* Diddle the battery for the zhone */
++#ifdef ZHONE_HACK
++ analog_off_hook(i);
++ usleep(1);
++#endif
++ res = analog_play_tone(i, ANALOG_SUB_REAL, -1);
++ analog_on_hook(i);
++ break;
++ default:
++ ast_log(LOG_WARNING, "Don't know how to handle on hook with signalling %s on channel %d\n", analog_sigtype_to_str(i->sig), i->channel);
++ res = analog_play_tone(i, ANALOG_SUB_REAL, -1);
++ return -1;
++ }
++ break;
++ case ANALOG_EVENT_POLARITY:
++ switch (i->sig) {
++ case ANALOG_SIG_FXSLS:
++ case ANALOG_SIG_FXSKS:
++ case ANALOG_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.
++ At least in Spain */
++ if (i->hanguponpolarityswitch)
++ i->polarity = POLARITY_REV;
++
++ if (i->cid_start == ANALOG_CID_START_POLARITY || i->cid_start == ANALOG_CID_START_POLARITY_IN) {
++ i->polarity = POLARITY_REV;
++ ast_verbose(VERBOSE_PREFIX_2 "Starting post polarity "
++ "CID detection on channel %d\n",
++ i->channel);
++ chan = analog_new_ast_channel(i, AST_STATE_PRERING, 0, ANALOG_SUB_REAL);
++ i->ss_astchan = chan;
++ if (chan && ast_pthread_create(&threadid, &attr, __analog_ss_thread, i)) {
++ ast_log(LOG_WARNING, "Unable to start simple switch thread on channel %d\n", i->channel);
++ }
++ }
++ break;
++ default:
++ ast_log(LOG_WARNING, "handle_init_event detected "
++ "polarity reversal on non-FXO (ANALOG_SIG_FXS) "
++ "interface %d\n", i->channel);
++ }
++ break;
++ case ANALOG_EVENT_NEONMWI_ACTIVE:
++ analog_handle_notify_message(NULL, i, -1, ANALOG_EVENT_NEONMWI_ACTIVE);
++ break;
++ case ANALOG_EVENT_NEONMWI_INACTIVE:
++ analog_handle_notify_message(NULL, i, -1, ANALOG_EVENT_NEONMWI_INACTIVE);
++ break;
++ }
++ pthread_attr_destroy(&attr);
++ return 0;
++}
++
++
++struct analog_pvt * analog_new(enum analog_sigtype signallingtype, struct analog_callback *c, void *private_data)
++{
++ struct analog_pvt *p;
++
++ p = ast_calloc(1, sizeof(*p));
++
++ if (!p)
++ return p;
++
++ p->calls = c;
++ p->outsigmod = ANALOG_SIG_NONE;
++ p->sig = signallingtype;
++ p->chan_pvt = private_data;
++
++ /* Some defaults for values */
++ p->sendcalleridafter = 1;
++ p->cid_start = ANALOG_CID_START_RING;
++ p->cid_signalling = CID_SIG_BELL;
++ /* Sub real is assumed to always be alloc'd */
++ p->subs[ANALOG_SUB_REAL].allocd = 1;
++
++ return p;
++}
++
++int analog_config_complete(struct analog_pvt *p)
++{
++ /* No call waiting on non FXS channels */
++ if ((p->sig != ANALOG_SIG_FXOKS) && (p->sig != ANALOG_SIG_FXOLS) && (p->sig != ANALOG_SIG_FXOGS))
++ p->permcallwaiting = 0;
++
++ p->callwaiting = p->permcallwaiting;
++
++ return 0;
++}
++
++void analog_free(struct analog_pvt *p)
++{
++ free(p);
++}
++
++/* called while dahdi_pvt is locked in dahdi_fixup */
++int analog_fixup(struct ast_channel *oldchan, struct ast_channel *newchan, void *newp)
++{
++ struct analog_pvt *new_pvt = newp;
++ int x;
++ ast_debug(1, "New owner for channel %d is %s\n", new_pvt->channel, newchan->name);
++ if (new_pvt->owner == oldchan) {
++ new_pvt->owner = newchan;
++ }
++ for (x = 0; x < 3; x++)
++ if (new_pvt->subs[x].owner == oldchan) {
++ new_pvt->subs[x].owner = newchan;
++ }
++
++ analog_update_conf(new_pvt);
++ return 0;
++}
+
+Property changes on: channels/sig_analog.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+Added: svn:mime-type
+ + text/plain
+Added: svn:keywords
+ + Author Date Id Revision
+
+Index: channels/chan_h323.c
+===================================================================
+--- a/channels/chan_h323.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/channels/chan_h323.c (.../trunk) (revision 202568)
+@@ -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"
+@@ -147,7 +147,7 @@
+ static call_options_t global_options;
+
+ /*! \brief Private structure of a OpenH323 channel */
+-struct oh323_pvt {
++static struct oh323_pvt {
+ ast_mutex_t lock; /*!< Channel private lock */
+ call_options_t options; /*!<!< Options to be used during call setup */
+ int alreadygone; /*!< Whether or not we've already been destroyed by our peer */
+@@ -163,7 +163,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 */
+@@ -256,7 +256,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)
+@@ -383,8 +383,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;
+@@ -446,7 +446,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 */
+@@ -512,7 +512,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 */
+@@ -551,7 +551,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 */
+@@ -608,18 +608,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"))
+@@ -749,11 +749,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;
+@@ -810,7 +810,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;
+@@ -844,7 +844,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);
+ }
+@@ -912,7 +912,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:
+@@ -948,17 +948,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));
+@@ -967,24 +967,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
+@@ -1030,13 +1030,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
+@@ -1114,7 +1114,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;
+ }
+@@ -1916,7 +1916,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));
+@@ -1935,7 +1935,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;
+
+@@ -1957,7 +1956,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;
+@@ -1966,13 +1965,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;
+@@ -1982,7 +1981,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) {
+@@ -2363,7 +2362,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 */
+@@ -2425,7 +2424,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);
+@@ -2458,10 +2457,10 @@
+ if (pvt->rtp) {
+ if (pvt->options.autoframing) {
+ ast_debug(2, "Autoframing option set, using peer's packetization settings\n");
+- 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);
+ } else {
+ ast_debug(2, "Autoframing option not set, ignoring peer's packetization settings\n");
+- ast_rtp_codec_setpref(pvt->rtp, &pvt->options.prefs);
++ ast_rtp_codecs_packetization_set(ast_rtp_instance_get_codecs(pvt->rtp), pvt->rtp, &pvt->options.prefs);
+ }
+ }
+ }
+@@ -3132,19 +3131,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);
+@@ -3152,11 +3151,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) {
+@@ -3184,12 +3178,12 @@
+ }
+ }
+
+-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;
+- struct sockaddr_in them;
+- struct sockaddr_in us;
++ struct sockaddr_in them = { 0, };
++ struct sockaddr_in us = { 0, };
+ char *mode;
+
+ if (!rtp) {
+@@ -3202,19 +3196,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)
+@@ -3269,7 +3262,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,
+@@ -3290,7 +3283,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();
+@@ -3329,7 +3322,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/sig_analog.h
+===================================================================
+--- a/channels/sig_analog.h (.../tags/1.6.2.0-beta3) (revision 0)
++++ b/channels/sig_analog.h (.../trunk) (revision 202568)
+@@ -0,0 +1,329 @@
++#ifndef _SIG_ANALOG_H
++#define _SIG_ANALOG_H
++/*
++ * Asterisk -- An open source telephony toolkit.
++ *
++ * Copyright (C) 1999 - 2009, 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 Interface header for analog signaling module
++ *
++ * \author Matthew Fredrickson <creslin@digium.com>
++ */
++
++#include "asterisk/channel.h"
++#include "asterisk/frame.h"
++
++/* Signalling types supported */
++enum analog_sigtype {
++ ANALOG_SIG_NONE = -1,
++ ANALOG_SIG_FXOLS = 1,
++ ANALOG_SIG_FXOKS,
++ ANALOG_SIG_FXOGS,
++ ANALOG_SIG_FXSLS,
++ ANALOG_SIG_FXSKS,
++ ANALOG_SIG_FXSGS,
++ ANALOG_SIG_EMWINK,
++ ANALOG_SIG_EM,
++ ANALOG_SIG_EM_E1,
++ ANALOG_SIG_FEATD,
++ ANALOG_SIG_FEATDMF,
++ ANALOG_SIG_E911,
++ ANALOG_SIG_FGC_CAMA,
++ ANALOG_SIG_FGC_CAMAMF,
++ ANALOG_SIG_FEATB,
++ ANALOG_SIG_SFWINK,
++ ANALOG_SIG_SF,
++ ANALOG_SIG_SF_FEATD,
++ ANALOG_SIG_SF_FEATDMF,
++ ANALOG_SIG_FEATDMF_TA,
++ ANALOG_SIG_SF_FEATB,
++};
++
++enum analog_tone {
++ ANALOG_TONE_RINGTONE = 0,
++ ANALOG_TONE_STUTTER,
++ ANALOG_TONE_CONGESTION,
++ ANALOG_TONE_DIALTONE,
++ ANALOG_TONE_DIALRECALL,
++ ANALOG_TONE_INFO,
++};
++
++enum analog_event {
++ ANALOG_EVENT_NONE = 0,
++ ANALOG_EVENT_DIALCOMPLETE,
++ ANALOG_EVENT_WINKFLASH,
++ ANALOG_EVENT_ONHOOK,
++ ANALOG_EVENT_RINGOFFHOOK,
++ ANALOG_EVENT_ALARM,
++ ANALOG_EVENT_NOALARM,
++ ANALOG_EVENT_HOOKCOMPLETE,
++ ANALOG_EVENT_POLARITY,
++ ANALOG_EVENT_RINGERON,
++ ANALOG_EVENT_RINGEROFF,
++ ANALOG_EVENT_RINGBEGIN,
++ ANALOG_EVENT_PULSE_START,
++ ANALOG_EVENT_ERROR,
++ ANALOG_EVENT_NEONMWI_ACTIVE,
++ ANALOG_EVENT_NEONMWI_INACTIVE,
++};
++
++enum analog_sub {
++ ANALOG_SUB_REAL = 0, /*!< Active call */
++ ANALOG_SUB_CALLWAIT, /*!< Call-Waiting call on hold */
++ ANALOG_SUB_THREEWAY, /*!< Three-way call */
++};
++
++enum analog_dsp_digitmode {
++ ANALOG_DIGITMODE_DTMF = 1,
++ ANALOG_DIGITMODE_MF,
++};
++
++enum analog_cid_start {
++ ANALOG_CID_START_POLARITY = 1,
++ ANALOG_CID_START_POLARITY_IN,
++ ANALOG_CID_START_RING,
++};
++
++#define ANALOG_MAX_CID 300
++
++enum dialop {
++ ANALOG_DIAL_OP_REPLACE = 2,
++};
++
++
++struct analog_dialoperation {
++ enum dialop op;
++ char dialstr[256];
++};
++
++struct analog_callback {
++ /* Unlock the private in the signalling private structure. This is used for three way calling madness. */
++ void (* const unlock_private)(void *pvt);
++ /* Lock the private in the signalling private structure. ... */
++ void (* const lock_private)(void *pvt);
++ /* Function which is called back to handle any other DTMF up events that are received. Called by analog_handle_event. Why is this
++ * important to use, instead of just directly using events received before they are passed into the library? Because sometimes,
++ * (CWCID) the library absorbs DTMF events received. */
++ void (* const handle_dtmfup)(void *pvt, struct ast_channel *ast, enum analog_sub analog_index, struct ast_frame **dest);
++
++ int (* const get_event)(void *pvt);
++ int (* const wait_event)(void *pvt);
++ int (* const is_off_hook)(void *pvt);
++ int (* const is_dialing)(void *pvt, enum analog_sub sub);
++ /* Start a trunk type signalling protocol (everything except phone ports basically */
++ int (* const start)(void *pvt);
++ int (* const ring)(void *pvt);
++ int (* const flash)(void *pvt);
++ /*! \brief Set channel on hook */
++ int (* const on_hook)(void *pvt);
++ /*! \brief Set channel off hook */
++ int (* const off_hook)(void *pvt);
++ /* We're assuming that we're going to only wink on ANALOG_SUB_REAL - even though in the code there's an argument to the index
++ * function */
++ int (* const wink)(void *pvt, enum analog_sub sub);
++ int (* const dial_digits)(void *pvt, enum analog_sub sub, struct analog_dialoperation *dop);
++ int (* const send_fsk)(void *pvt, struct ast_channel *ast, char *fsk);
++ int (* const play_tone)(void *pvt, enum analog_sub sub, enum analog_tone tone);
++
++ int (* const set_echocanceller)(void *pvt, int enable);
++ int (* const train_echocanceller)(void *pvt);
++ int (* const dsp_set_digitmode)(void *pvt, enum analog_dsp_digitmode mode);
++ int (* const dsp_reset_and_flush_digits)(void *pvt);
++ int (* const send_callerid)(void *pvt, int cwcid, struct ast_callerid *cid);
++ /* Returns 0 if CID received. Returns 1 if event received, and -1 if error. name and num are size ANALOG_MAX_CID */
++ int (* const get_callerid)(void *pvt, char *name, char *num, enum analog_event *ev, size_t timeout);
++ /* Start CID detection */
++ int (* const start_cid_detect)(void *pvt, int cid_signalling);
++ /* Stop CID detection */
++ int (* const stop_cid_detect)(void *pvt);
++
++ /* Play the CAS callwait tone on the REAL sub, then repeat after 10 seconds, and then stop */
++ int (* const callwait)(void *pvt);
++ /* Stop playing any CAS call waiting announcement tones that might be running on the REAL sub */
++ int (* const stop_callwait)(void *pvt);
++
++ /* Bearer control related (non signalling) callbacks */
++ int (* const allocate_sub)(void *pvt, enum analog_sub sub);
++ int (* const unallocate_sub)(void *pvt, enum analog_sub sub);
++ /*! This function is for swapping of the owners with the underlying subs. Typically it means you need to change the fds
++ * of the new owner to be the fds of the sub specified, for each of the two subs given */
++ void (* const swap_subs)(void *pvt, enum analog_sub a, struct ast_channel *new_a_owner, enum analog_sub b, struct ast_channel *new_b_owner);
++ struct ast_channel * (* const new_ast_channel)(void *pvt, int state, int startpbx, enum analog_sub sub);
++
++ /* Add the given sub to a conference */
++ int (* const conf_add)(void *pvt, enum analog_sub sub);
++ /* Delete the given sub from any conference that might be running on the channels */
++ int (* const conf_del)(void *pvt, enum analog_sub sub);
++
++ /* If you would like to do any optimizations after the conference members have been added and removed,
++ * you can do so here */
++ int (* const complete_conference_update)(void *pvt, int needconf);
++
++ /* This is called when there are no more subchannels on the given private that are left up,
++ * for any cleanup or whatever else you would like to do. Called from analog_hangup() */
++ void (* const all_subchannels_hungup)(void *pvt);
++
++ int (* const has_voicemail)(void *pvt);
++ int (* const check_for_conference)(void *pvt);
++ void (* const handle_notify_message)(struct ast_channel *chan, void *pvt, int cid_flags, int neon_mwievent);
++
++ /* callbacks for increasing and decreasing ss_thread_count, will handle locking and condition signal */
++ void (* const increase_ss_count)(void);
++ void (* const decrease_ss_count)(void);
++};
++
++
++
++#define READ_SIZE 160
++
++struct analog_subchannel {
++ struct ast_channel *owner;
++ struct ast_frame f; /*!< One frame for each channel. How did this ever work before? */
++ unsigned int needcallerid:1;
++ unsigned int inthreeway:1;
++ /* Have we allocated a subchannel yet or not */
++ unsigned int allocd:1;
++};
++
++struct analog_pvt {
++ /* Analog signalling type used in this private */
++ enum analog_sigtype sig;
++ /* To contain the private structure passed into the channel callbacks */
++ void *chan_pvt;
++ /* Callbacks for various functions needed by the analog API */
++ struct analog_callback *calls;
++ /* All members after this are giong to be transient, and most will probably change */
++ struct ast_channel *owner; /*!< Our current active owner (if applicable) */
++
++ struct analog_subchannel subs[3]; /*!< Sub-channels */
++ struct analog_dialoperation dop;
++
++ /* XXX: Option Variables - Set by allocator of private structure */
++ unsigned int answeronpolarityswitch:1;
++ unsigned int callreturn:1;
++ unsigned int cancallforward:1;
++ unsigned int canpark:1;
++ unsigned int dahditrcallerid:1; /*!< should we use the callerid from incoming call on dahdi transfer or not */
++ unsigned int hanguponpolarityswitch:1;
++ unsigned int immediate:1;
++ unsigned int permcallwaiting:1;
++ unsigned int permhidecallerid:1; /*!< Whether to hide our outgoing caller ID or not */
++ unsigned int pulse:1;
++ unsigned int threewaycalling:1;
++ unsigned int transfer:1;
++ unsigned int transfertobusy:1; /*!< allow flash-transfers to busy channels */
++ unsigned int use_callerid:1; /*!< Whether or not to use caller id on this channel */
++
++ /* Not used for anything but log messages. Could be just the TCID */
++ int channel; /*!< Channel Number or CRV */
++ enum analog_sigtype outsigmod;
++ int echotraining;
++ int cid_signalling; /*!< Asterisk callerid type we're using */
++ int polarityonanswerdelay;
++ int stripmsd;
++ enum analog_cid_start cid_start;
++ /* Number of rings to wait to send callerid on FXS. Set to 1 for US */
++ int sendcalleridafter;
++ int callwaitingcallerid;
++ char mohsuggest[MAX_MUSICCLASS];
++ char cid_num[AST_MAX_EXTENSION];
++ char cid_name[AST_MAX_EXTENSION];
++
++
++ /* XXX: All variables after this are internal */
++ unsigned int callwaiting:1;
++ unsigned int dialednone:1;
++ unsigned int dialing:1;
++ unsigned int dnd:1;
++ unsigned int echobreak:1;
++ unsigned int hidecallerid:1;
++ unsigned int outgoing:1;
++ unsigned int pulsedial:1; /*!< whether a pulse dial phone is detected */
++
++ char callwait_num[AST_MAX_EXTENSION];
++ char callwait_name[AST_MAX_EXTENSION];
++ char lastcid_num[AST_MAX_EXTENSION];
++ char lastcid_name[AST_MAX_EXTENSION];
++ struct ast_callerid cid;
++ int cidrings; /*!< Which ring to deliver CID on */
++ char echorest[20];
++ int polarity;
++ struct timeval polaritydelaytv;
++ char dialdest[256];
++ time_t guardtime; /*!< Must wait this much time before using for new call */
++ struct timeval flashtime; /*!< Last flash-hook time */
++ int whichwink; /*!< SIG_FEATDMF_TA Which wink are we on? */
++ char finaldial[64];
++ char *origcid_num; /*!< malloced original callerid */
++ char *origcid_name; /*!< malloced original callerid */
++ char call_forward[AST_MAX_EXTENSION];
++
++ /* Ast channel to pass to __ss_analog_thread */
++ void *ss_astchan;
++
++ /* All variables after this are definitely going to be audited */
++ unsigned int inalarm:1; //
++ unsigned int unknown_alarm:1;//
++
++ int callwaitcas;
++
++#if 0
++ int ringt; //
++ int ringt_base;
++#endif
++};
++
++struct analog_pvt * analog_new(enum analog_sigtype signallingtype, struct analog_callback *c, void *private_data);
++
++void analog_free(struct analog_pvt *p);
++
++int analog_call(struct analog_pvt *p, struct ast_channel *ast, char *rdest, int timeout);
++
++int analog_hangup(struct analog_pvt *p, struct ast_channel *ast);
++
++int analog_answer(struct analog_pvt *p, struct ast_channel *ast);
++
++struct ast_frame *analog_exception(struct analog_pvt *p, struct ast_channel *ast);
++
++struct ast_channel * analog_request(struct analog_pvt *p, int *callwait);
++
++int analog_available(struct analog_pvt *p, int channelmatch, ast_group_t groupmatch, int *busy, int *channelmatched, int *groupmatched);
++
++int analog_handle_init_event(struct analog_pvt *i, int event);
++
++int analog_config_complete(struct analog_pvt *p);
++
++void analog_handle_dtmfup(struct analog_pvt *p, struct ast_channel *ast, enum analog_sub index, struct ast_frame **dest);
++
++enum analog_cid_start analog_str_to_cidstart(const char *value);
++
++const char *analog_cidstart_to_str(enum analog_cid_start cid_start);
++
++enum analog_sigtype analog_str_to_sigtype(const char *name);
++
++const char *analog_sigtype_to_str(enum analog_sigtype sigtype);
++
++unsigned int analog_str_to_cidtype(const char *name);
++
++const char *analog_cidtype_to_str(unsigned int cid_type);
++
++int analog_ss_thread_start(struct analog_pvt *p, struct ast_channel *ast);
++
++int analog_fixup(struct ast_channel *oldchan, struct ast_channel *newchan, void *newp);
++
++#endif /* _SIG_ANSLOG_H */
+
+Property changes on: channels/sig_analog.h
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+Added: svn:mime-type
+ + text/plain
+Added: svn:keywords
+ + Author Date Id Revision
+
+Index: channels/chan_sip.c
+===================================================================
+--- a/channels/chan_sip.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/channels/chan_sip.c (.../trunk) (revision 202568)
+@@ -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">
+@@ -472,6 +473,79 @@
+ Check the <literal>domain=</literal> configuration in <filename>sip.conf</filename>.</para>
+ </description>
+ </function>
++ <manager name="SIPpeers" language="en_US">
++ <synopsis>
++ List SIP peers (text format).
++ </synopsis>
++ <syntax>
++ <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
++ </syntax>
++ <description>
++ <para>Lists SIP peers in text format with details on current status.
++ Peerlist will follow as separate events, followed by a final event called
++ PeerlistComplete.</para>
++ </description>
++ </manager>
++ <manager name="SIPshowpeer" language="en_US">
++ <synopsis>
++ show SIP peer (text format).
++ </synopsis>
++ <syntax>
++ <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
++ <parameter name="Peer" required="true">
++ <para>The peer name you want to check.</para>
++ </parameter>
++ </syntax>
++ <description>
++ <para>Show one SIP peer with details on current status.</para>
++ </description>
++ </manager>
++ <manager name="SIPqualifypeer" language="en_US">
++ <synopsis>
++ Qualify SIP peers.
++ </synopsis>
++ <syntax>
++ <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
++ <parameter name="Peer" required="true">
++ <para>The peer name you want to qualify.</para>
++ </parameter>
++ </syntax>
++ <description>
++ <para>Qualify a SIP peer.</para>
++ </description>
++ </manager>
++ <manager name="SIPshowregistry" language="en_US">
++ <synopsis>
++ Show SIP registrations (text format).
++ </synopsis>
++ <syntax>
++ <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
++ </syntax>
++ <description>
++ <para>Lists all registration requests and status. Registrations will follow as separate
++ events. followed by a final event called RegistrationsComplete.</para>
++ </description>
++ </manager>
++ <manager name="SIPnotify" language="en_US">
++ <synopsis>
++ Send a SIP notify.
++ </synopsis>
++ <syntax>
++ <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
++ <parameter name="Channel" required="true">
++ <para>Peer to receive the notify.</para>
++ </parameter>
++ <parameter name="Variable" required="true">
++ <para>At least one variable pair must be specified.
++ <replaceable>name</replaceable>=<replaceable>value</replaceable></para>
++ </parameter>
++ </syntax>
++ <description>
++ <para>Sends a SIP Notify event.</para>
++ <para>All parameters for this event must be specified in the body of this request
++ via multiple Variable: name=value sequences.</para>
++ </description>
++ </manager>
+ ***/
+
+ #ifndef FALSE
+@@ -691,6 +765,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,12 +1015,60 @@
+ { 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.
+ */
+-#define ALLOWED_METHODS "INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, SUBSCRIBE, NOTIFY"
++#define ALLOWED_METHODS "INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, SUBSCRIBE, NOTIFY, INFO"
+
+ /*! \brief SIP Extensions we support
+ \note This should be generated based on the previous array
+@@ -980,6 +1103,7 @@
+ #define DEFAULT_MOHSUGGEST ""
+ #define DEFAULT_VMEXTEN "asterisk" /*!< Default voicemail extension */
+ #define DEFAULT_CALLERID "asterisk" /*!< Default caller ID */
++#define DEFAULT_MWI_FROM ""
+ #define DEFAULT_NOTIFYMIME "application/simple-message-summary"
+ #define DEFAULT_ALLOWGUEST TRUE
+ #define DEFAULT_RTPKEEPALIVE 0 /*!< Default RTPkeepalive setting */
+@@ -1011,6 +1135,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
+ /*@}*/
+
+@@ -1021,6 +1146,7 @@
+ /*@{*/
+ static char default_language[MAX_LANGUAGE];
+ static char default_callerid[AST_MAX_EXTENSION];
++static char default_mwi_from[80];
+ static char default_fromdomain[AST_MAX_EXTENSION];
+ static char default_notifymime[AST_MAX_EXTENSION];
+ static int default_qualify; /*!< Default Qualify= setting */
+@@ -1029,6 +1155,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 */
+@@ -1095,8 +1222,8 @@
+ 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 recordhistory; /*!< Record SIP history. Off by default */
+-static int dumphistory; /*!< Dump history to verbose before destroying SIP dialog */
++static unsigned int recordhistory; /*!< Record SIP history. Off by default */
++static unsigned int dumphistory; /*!< Dump history to verbose before destroying SIP dialog */
+ 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 */
+@@ -1105,7 +1232,7 @@
+ 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_autoframing; /*!< Turn autoframing on or off. */
++static unsigned int global_autoframing; /*!< Turn autoframing on or off. */
+ 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 */
+@@ -1350,7 +1477,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 */
+@@ -1366,10 +1496,14 @@
+ /* realtime flags */
+ #define SIP_PAGE2_RTCACHEFRIENDS (1 << 0) /*!< GP: Should we keep RT objects in memory for extended time? */
+ #define SIP_PAGE2_RTAUTOCLEAR (1 << 2) /*!< GP: Should we clean memory from peers after expiry? */
++#define SIP_PAGE2_RPID_UPDATE (1 << 3)
+ /* 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_RPORT_PRESENT (1 << 10) /*!< Was rport received in the Via header? */
++#define SIP_PAGE2_CONNECTLINEUPDATE_PEND (1 << 10)
++#define SIP_PAGE2_RPID_IMMEDIATE (1 << 11)
++#define SIP_PAGE2_RPORT_PRESENT (1 << 12) /*!< Was rport received in the Via header? */
++#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? */
+@@ -1399,7 +1533,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 | SIP_PAGE2_RPID_UPDATE)
+
+ /*@}*/
+
+@@ -1604,13 +1739,13 @@
+ AST_STRING_FIELD(peermd5secret);
+ AST_STRING_FIELD(cid_num); /*!< Caller*ID number */
+ AST_STRING_FIELD(cid_name); /*!< Caller*ID name */
++ AST_STRING_FIELD(mwi_from); /*!< Name to place in the From header in outgoing NOTIFY requests */
+ 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 */
+@@ -1622,15 +1757,21 @@
+ int lastnoninvite; /*!< Last Cseq of non-invite */
+ struct ast_flags flags[2]; /*!< SIP_ flags */
+
+- /* boolean or small integers that don't belong in flags */
+- char do_history; /*!< Set if we want to record history */
+- char alreadygone; /*!< already destroyed by our peer */
+- char needdestroy; /*!< need to be destroyed by the monitor thread */
+- char outgoing_call; /*!< this is an outgoing call */
+- char answered_elsewhere; /*!< This call is cancelled due to answer on another channel */
+- char novideo; /*!< Didn't get video in invite, don't offer */
+- char notext; /*!< Text not supported (?) */
+-
++ /* boolean flags that don't belong in flags */
++ unsigned short do_history:1; /*!< Set if we want to record history */
++ unsigned short alreadygone:1; /*!< already destroyed by our peer */
++ unsigned short needdestroy:1; /*!< need to be destroyed by the monitor thread */
++ unsigned short outgoing_call:1; /*!< this is an outgoing call */
++ unsigned short answered_elsewhere:1; /*!< This call is cancelled due to answer on another channel */
++ unsigned short novideo:1; /*!< Didn't get video in invite, don't offer */
++ unsigned short notext:1; /*!< Text not supported (?) */
++ unsigned short session_modify:1; /*!< Session modification request true/false */
++ unsigned short route_persistent:1; /*!< Is this the "real" route? */
++ unsigned short autoframing:1; /*!< Whether to use our local configuration for frame sizes (off)
++ * or respect the other endpoint's request for frame sizes (on)
++ * for incoming calls
++ */
++ char tag[11]; /*!< Our tag for this session */
+ int timer_t1; /*!< SIP timer T1, ms rtt */
+ int timer_b; /*!< SIP timer B, ms */
+ unsigned int sipoptions; /*!< Supported SIP options on the other end */
+@@ -1644,20 +1785,19 @@
+ int jointnoncodeccapability; /*!< Joint Non codec capability */
+ int redircodecs; /*!< Redirect codecs */
+ int maxcallbitrate; /*!< Maximum Call Bitrate for Video Calls */
++ int request_queue_sched_id; /*!< Scheduler ID of any scheduled action to process queued requests */
++ int authtries; /*!< Times we've tried to authenticate */
+ 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 */
+ int callingpres; /*!< Calling presentation */
+- int authtries; /*!< Times we've tried to authenticate */
+ int expiry; /*!< How long we take to expire */
++ int sessionversion; /*!< SDP Session Version */
++ int sessionid; /*!< SDP Session ID */
+ long branch; /*!< The branch identifier of this session */
+ long invite_branch; /*!< The branch used when we sent the initial INVITE */
+- char tag[11]; /*!< Our tag for this session */
+- int sessionid; /*!< SDP Session ID */
+- int sessionversion; /*!< SDP Session Version */
+- uint64_t sessionversion_remote; /*!< Remote UA's SDP Session Version */
+- int session_modify; /*!< Session modification request true/false */
++ int64_t sessionversion_remote; /*!< Remote UA's SDP Session Version */
+ struct sockaddr_in sa; /*!< Our peer */
+ struct sockaddr_in redirip; /*!< Where our RTP should be going if not to us */
+ struct sockaddr_in vredirip; /*!< Where our Video RTP should be going if not to us */
+@@ -1667,9 +1807,9 @@
+ int rtptimeout; /*!< RTP timeout time */
+ struct sockaddr_in recv; /*!< Received as */
+ struct sockaddr_in ourip; /*!< Our IP (as seen from the outside) */
++ enum transfermodes allowtransfer; /*!< REFER: restriction scheme */
+ 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 sip_auth *peerauth; /*!< Realm authentication */
+ int noncecount; /*!< Nonce-count */
+@@ -1687,38 +1827,37 @@
+ int waitid; /*!< Wait ID for scheduler after 491 or other delays */
+ int autokillid; /*!< Auto-kill ID (scheduler) */
+ int t38id; /*!< T.38 Response ID */
+- enum transfermodes allowtransfer; /*!< REFER: restriction scheme */
+ struct sip_refer *refer; /*!< REFER: SIP transfer data structure */
+ enum subscriptiontype subscribed; /*!< SUBSCRIBE: Is this dialog a subscription? */
+ 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 ast_dsp *dsp; /*!< 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 */
+ struct ast_variable *chanvars; /*!< Channel variables to set for inbound call */
+ AST_LIST_HEAD_NOLOCK(request_queue, sip_request) request_queue; /*!< Requests that arrived but could not be processed immediately */
+- int request_queue_sched_id; /*!< Scheduler ID of any scheduled action to process queued requests */
+ struct sip_invite_param *options; /*!< Options for INVITE */
+- int autoframing; /*!< The number of Asters we group in a Pyroflax
+- before strolling to the Grokyzpå
+- (A bit unsure of this, please correct if
+- you know more) */
+ struct sip_st_dlg *stimer; /*!< SIP Session-Timers */
+
+ 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) */
+
+ struct sip_subscription_mwi *mwi; /*!< If this is a subscription MWI dialog, to which subscription */
++ /*! The SIP methods allowed on this dialog. We get this information from the Allow header present in
++ * the peer's REGISTER. If peer does not register with us, then we will use the first transaction we
++ * have with this peer to determine its allowed methods.
++ */
++ unsigned int allowed_methods;
+ };
+
+
+@@ -1730,7 +1869,7 @@
+ * the container and individual items, and functions to add/remove
+ * references to the individual items.
+ */
+-struct ao2_container *dialogs;
++static struct ao2_container *dialogs;
+
+ #define sip_pvt_lock(x) ao2_lock(x)
+ #define sip_pvt_trylock(x) ao2_trylock(x)
+@@ -1791,6 +1930,7 @@
+ int seqno; /*!< Sequence number */
+ char is_resp; /*!< 1 if this is a response packet (e.g. 200 OK), 0 if it is a request */
+ char is_fatal; /*!< non-zero if there is a fatal error */
++ int response_code; /*!< If this is a response, the response code */
+ struct sip_pvt *owner; /*!< Owner AST call */
+ int retransid; /*!< Retransmission ID */
+ int timer_a; /*!< SIP timer A, retransmission timer */
+@@ -1844,11 +1984,23 @@
+ 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(mwi_from); /*!< Name to place in From header for outgoing NOTIFY requests */
++ AST_STRING_FIELD(engine); /*!< RTP Engine to use */
+ );
+ struct sip_socket socket; /*!< Socket used for this peer */
+ enum sip_transport default_outbound_transport; /*!< Peer Registration may change the default outbound transport.
+- If register expires, default should be reset. to this value */
+- unsigned int transports:3; /*!< Transports (enum sip_transport) that are acceptable for this peer */
++ If register expires, default should be reset. to this value */
++ /* things that don't belong in flags */
++ unsigned short transports:3; /*!< Transports (enum sip_transport) that are acceptable for this peer */
++ unsigned short is_realtime:1; /*!< this is a 'realtime' peer */
++ unsigned short rt_fromcontact:1;/*!< copy fromcontact from realtime */
++ unsigned short host_dynamic:1; /*!< Dynamic Peers register with Asterisk */
++ unsigned short selfdestruct:1; /*!< Automatic peers need to destruct themselves */
++ unsigned short the_mark:1; /*!< moved out of ASTOBJ into struct proper; That which bears the_mark should be deleted! */
++ unsigned short autoframing:1; /*!< Whether to use our local configuration for frame sizes (off)
++ * or respect the other endpoint's request for frame sizes (on)
++ * for incoming calls
++ */
+ struct sip_auth *auth; /*!< Realm authentication list */
+ int amaflags; /*!< AMA Flags (for billing) */
+ int callingpres; /*!< Calling id presentation */
+@@ -1866,13 +2018,7 @@
+ /*! Mailboxes that this peer cares about */
+ AST_LIST_HEAD_NOLOCK(, sip_mailbox) mailboxes;
+
+- /* things that don't belong in flags */
+- char is_realtime; /*!< this is a 'realtime' 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 maxcallbitrate; /*!< Maximum Bitrate for a video call */
+ int expire; /*!< When to expire this peer registration */
+ int capability; /*!< Codec capability */
+ int rtptimeout; /*!< RTP timeout */
+@@ -1883,8 +2029,6 @@
+ struct sip_proxy *outboundproxy; /*!< Outbound proxy for this peer */
+ struct ast_dnsmgr_entry *dnsmgr;/*!< DNS refresh manager for peer */
+ struct sockaddr_in addr; /*!< IP address of peer */
+- int maxcallbitrate; /*!< Maximum Bitrate for a video call */
+-
+ /* Qualification */
+ struct sip_pvt *call; /*!< Call pointer */
+ int pokeexpire; /*!< When to expire poke (qualify= checking) */
+@@ -1897,7 +2041,6 @@
+ struct ast_ha *contactha; /*!< Restrict what IPs are allowed in the Contact header (for registration) */
+ struct ast_variable *chanvars; /*!< Variables to set for channel created by user */
+ struct sip_pvt *mwipvt; /*!< Subscription for MWI */
+- int autoframing;
+ struct sip_st_cfg stimer; /*!< SIP Session-Timers */
+ int timer_t1; /*!< The maximum T1 value for the peer */
+ int timer_b; /*!< The maximum timer B (transaction timeouts) */
+@@ -1905,6 +2048,7 @@
+
+ /*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 */
++ unsigned int allowed_methods;
+ };
+
+
+@@ -1919,12 +2063,6 @@
+ * or once the previously completed registration one expires).
+ * The registration can be in one of many states, though at the moment
+ * the handling is a bit mixed.
+- *
+- * XXX \todo Reference count handling for this object has some problems with
+- * respect to scheduler entries. The ref count is handled in some places,
+- * but not all of them. There are some places where references get leaked
+- * when this scheduler entry gets cancelled. At worst, this would cause
+- * memory leaks on reloads if registrations get removed from configuration.
+ */
+ struct sip_registry {
+ ASTOBJ_COMPONENTS_FULL(struct sip_registry,1,1);
+@@ -2005,8 +2143,8 @@
+ static AST_LIST_HEAD_STATIC(threadl, sip_threadinfo);
+
+ /*! \brief The peer list: Users, Peers and Friends */
+-struct ao2_container *peers;
+-struct ao2_container *peers_by_ip;
++static struct ao2_container *peers;
++static struct ao2_container *peers_by_ip;
+
+ /*! \brief The register list: Other SIP proxies we register with and place calls to */
+ static struct ast_register_list {
+@@ -2215,6 +2353,7 @@
+ static int sip_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
+ static int sip_senddigit_begin(struct ast_channel *ast, char digit);
+ static int sip_senddigit_end(struct ast_channel *ast, char digit, unsigned int duration);
++static int sip_setoption(struct ast_channel *chan, int option, void *data, int datalen);
+ static int sip_queryoption(struct ast_channel *chan, int option, void *data, int *datalen);
+ static const char *sip_get_callid(struct ast_channel *chan);
+
+@@ -2233,7 +2372,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);
+@@ -2254,12 +2393,12 @@
+ 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 */
+ static struct sip_pvt *sip_alloc(ast_string_field callid, struct sockaddr_in *sin,
+- int useglobal_nat, const int intended_method);
++ int useglobal_nat, const int intended_method, struct sip_request *req);
+ static int __sip_autodestruct(const void *data);
+ static void sip_scheddestroy(struct sip_pvt *p, int ms);
+ static int sip_cancel_destroy(struct sip_pvt *p);
+@@ -2279,7 +2418,7 @@
+ static void list_route(struct sip_route *route);
+ static void build_route(struct sip_pvt *p, struct sip_request *req, int backwards);
+ static enum check_auth_result register_verify(struct sip_pvt *p, struct sockaddr_in *sin,
+- struct sip_request *req, char *uri);
++ struct sip_request *req, const char *uri);
+ static struct sip_pvt *get_sip_pvt_byid_locked(const char *callid, const char *totag, const char *fromtag);
+ static void check_pendings(struct sip_pvt *p);
+ static void *sip_park_thread(void *stuff);
+@@ -2307,11 +2446,11 @@
+ static int build_reply_digest(struct sip_pvt *p, int method, char *digest, int digest_len);
+ static enum check_auth_result check_auth(struct sip_pvt *p, struct sip_request *req, const char *username,
+ const char *secret, const char *md5secret, int sipmethod,
+- char *uri, enum xmittype reliable, int ignore);
++ const char *uri, enum xmittype reliable, int ignore);
+ static enum check_auth_result check_user_full(struct sip_pvt *p, struct sip_request *req,
+- int sipmethod, char *uri, enum xmittype reliable,
++ int sipmethod, const char *uri, enum xmittype reliable,
+ struct sockaddr_in *sin, struct sip_peer **authpeer);
+-static int check_user(struct sip_pvt *p, struct sip_request *req, int sipmethod, char *uri, enum xmittype reliable, struct sockaddr_in *sin);
++static int check_user(struct sip_pvt *p, struct sip_request *req, int sipmethod, const char *uri, enum xmittype reliable, struct sockaddr_in *sin);
+
+ /*--- Domain handling */
+ static int check_sip_domain(const char *domain, char *context, size_t len); /* Check if domain is one of our local domains */
+@@ -2416,13 +2555,13 @@
+ static char *sip_show_channel(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
+ static char *sip_show_channelstats(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
+ static char *sip_show_history(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
+-static char *sip_do_debug_ip(int fd, char *arg);
+-static char *sip_do_debug_peer(int fd, char *arg);
++static char *sip_do_debug_ip(int fd, const char *arg);
++static char *sip_do_debug_peer(int fd, const 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_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);
++static int sip_dtmfmode(struct ast_channel *chan, const char *data);
++static int sip_addheader(struct ast_channel *chan, const char *data);
+ static int sip_do_reload(enum channelreloadreason reason);
+ static char *sip_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
+ static int acf_channel_read(struct ast_channel *chan, const char *funcname, char *preparse, char *buf, size_t buflen);
+@@ -2443,7 +2582,6 @@
+ static void sip_dump_history(struct sip_pvt *dialog);
+
+ /*--- Device object handling */
+-static struct sip_peer *temp_peer(const char *name);
+ static struct sip_peer *build_peer(const char *name, struct ast_variable *v, struct ast_variable *alt, int realtime);
+ static int update_call_counter(struct sip_pvt *fup, int event);
+ static void sip_destroy_peer(struct sip_peer *peer);
+@@ -2458,6 +2596,7 @@
+ static void destroy_association(struct sip_peer *peer);
+ static void set_insecure_flags(struct ast_flags *flags, const char *value, int lineno);
+ static int handle_common_options(struct ast_flags *flags, struct ast_flags *mask, struct ast_variable *v);
++static void set_socket_transport(struct sip_socket *socket, int transport);
+
+ /* 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, int lastms);
+@@ -2468,7 +2607,7 @@
+ static char *sip_prune_realtime(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
+
+ /*--- Internal UA client handling (outbound registrations) */
+-static void ast_sip_ouraddrfor(struct in_addr *them, struct sockaddr_in *us);
++static void ast_sip_ouraddrfor(struct in_addr *them, struct sockaddr_in *us, struct sip_pvt *p);
+ static void sip_registry_destroy(struct sip_registry *reg);
+ static int sip_register(const char *value, int lineno);
+ static const char *regstate2str(enum sipregistrystate regstate) attribute_const;
+@@ -2485,6 +2624,8 @@
+ static const char *gettag(const struct sip_request *req, const char *header, char *tagbuf, int tagbufsize);
+ static int find_sip_method(const char *msg);
+ static unsigned int parse_sip_options(struct sip_pvt *pvt, const char *supported);
++static unsigned int parse_allowed_methods(struct sip_request *req);
++static unsigned int set_pvt_allowed_methods(struct sip_pvt *pvt, struct sip_request *req);
+ static int parse_request(struct sip_request *req);
+ static const char *get_header(const struct sip_request *req, const char *name);
+ static const char *referstatus2str(enum referstatus rstatus) attribute_pure;
+@@ -2502,11 +2643,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);
+@@ -2533,6 +2677,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);
+@@ -2541,39 +2686,31 @@
+ 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);
+-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);
++static int handle_request_update(struct sip_pvt *p, struct sip_request *req);
++static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int debug, int seqno, struct sockaddr_in *sin, int *recount, const char *e, int *nounlock);
+ static int handle_request_refer(struct sip_pvt *p, struct sip_request *req, int debug, int seqno, int *nounlock);
+ static int handle_request_bye(struct sip_pvt *p, struct sip_request *req);
+-static int handle_request_register(struct sip_pvt *p, struct sip_request *req, struct sockaddr_in *sin, char *e);
++static int handle_request_register(struct sip_pvt *p, struct sip_request *req, struct sockaddr_in *sin, const char *e);
+ static int handle_request_cancel(struct sip_pvt *p, struct sip_request *req);
+ static int handle_request_message(struct sip_pvt *p, struct sip_request *req);
+-static int handle_request_subscribe(struct sip_pvt *p, struct sip_request *req, struct sockaddr_in *sin, int seqno, char *e);
++static int handle_request_subscribe(struct sip_pvt *p, struct sip_request *req, struct sockaddr_in *sin, int seqno, const char *e);
+ static void handle_request_info(struct sip_pvt *p, struct sip_request *req);
+ static int handle_request_options(struct sip_pvt *p, struct sip_request *req);
+ static int handle_invite_replaces(struct sip_pvt *p, struct sip_request *req, int debug, int seqno, struct sockaddr_in *sin);
+-static int handle_request_notify(struct sip_pvt *p, struct sip_request *req, struct sockaddr_in *sin, int seqno, char *e);
++static int handle_request_notify(struct sip_pvt *p, struct sip_request *req, struct sockaddr_in *sin, int seqno, const char *e);
+ static int local_attended_transfer(struct sip_pvt *transferer, struct sip_dual *current, struct sip_request *req, int seqno);
+
+ /*------Response handling functions */
+-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);
++static void handle_response_invite(struct sip_pvt *p, int resp, const char *rest, struct sip_request *req, int seqno);
++static void handle_response_notify(struct sip_pvt *p, int resp, const char *rest, struct sip_request *req, int seqno);
++static void handle_response_refer(struct sip_pvt *p, int resp, const char *rest, struct sip_request *req, int seqno);
++static void handle_response_subscribe(struct sip_pvt *p, int resp, const char *rest, struct sip_request *req, int seqno);
++static int handle_response_register(struct sip_pvt *p, int resp, const char *rest, struct sip_request *req, int seqno);
++static void handle_response(struct sip_pvt *p, int resp, const 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);
+@@ -2594,6 +2731,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);
+@@ -2622,10 +2762,11 @@
+ .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,
++ .setoption = sip_setoption,
+ .queryoption = sip_queryoption,
+ .get_pvt_uniqueid = sip_get_callid,
+ };
+@@ -2696,17 +2837,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.
+ */
+@@ -2777,14 +2907,14 @@
+ reqcpy.data = str_save;
+ ast_str_reset(reqcpy.data);
+
+- req.socket.fd = tcptls_session->fd;
+ if (tcptls_session->ssl) {
+- req.socket.type = SIP_TRANSPORT_TLS;
++ set_socket_transport(&req.socket, SIP_TRANSPORT_TLS);
+ req.socket.port = htons(ourport_tls);
+ } else {
+- req.socket.type = SIP_TRANSPORT_TCP;
++ set_socket_transport(&req.socket, SIP_TRANSPORT_TCP);
+ req.socket.port = htons(ourport_tcp);
+ }
++ req.socket.fd = tcptls_session->fd;
+ res = ast_wait_for_input(tcptls_session->fd, -1);
+ if (res < 0) {
+ ast_debug(2, "SIP %s server :: ast_wait_for_input returned %d\n", tcptls_session->ssl ? "SSL": "TCP", res);
+@@ -3270,8 +3400,9 @@
+ */
+ static inline const char *get_transport_pvt(struct sip_pvt *p)
+ {
+- if (p->outboundproxy && p->outboundproxy->transport)
+- p->socket.type = p->outboundproxy->transport;
++ if (p->outboundproxy && p->outboundproxy->transport) {
++ set_socket_transport(&p->socket, p->outboundproxy->transport);
++ }
+
+ return get_transport(p->socket.type);
+ }
+@@ -3346,7 +3477,7 @@
+ * externip or can get away with our internal bindaddr
+ * 'us' is always overwritten.
+ */
+-static void ast_sip_ouraddrfor(struct in_addr *them, struct sockaddr_in *us)
++static void ast_sip_ouraddrfor(struct in_addr *them, struct sockaddr_in *us, struct sip_pvt *p)
+ {
+ struct sockaddr_in theirs;
+ /* Set want_remap to non-zero if we want to remap 'us' to an externally
+@@ -3390,10 +3521,34 @@
+ ast_log(LOG_WARNING, "stun failed\n");
+ ast_debug(1, "Target address %s is not local, substituting externip\n",
+ ast_inet_ntoa(*(struct in_addr *)&them->s_addr));
++ } else if (p) {
++ /* no remapping, but we bind to a specific address, so use it. */
++ switch (p->socket.type) {
++ case SIP_TRANSPORT_TCP:
++ if (sip_tcp_desc.local_address.sin_addr.s_addr) {
++ *us = sip_tcp_desc.local_address;
++ } else {
++ us->sin_port = sip_tcp_desc.local_address.sin_port;
++ }
++ break;
++ case SIP_TRANSPORT_TLS:
++ if (sip_tls_desc.local_address.sin_addr.s_addr) {
++ *us = sip_tls_desc.local_address;
++ } else {
++ us->sin_port = sip_tls_desc.local_address.sin_port;
++ }
++ break;
++ case SIP_TRANSPORT_UDP:
++ /* fall through on purpose */
++ default:
++ if (bindaddr.sin_addr.s_addr) {
++ *us = bindaddr;
++ }
++ }
+ } else if (bindaddr.sin_addr.s_addr) {
+- /* no remapping, but we bind to a specific address, so use it. */
+ *us = bindaddr;
+ }
++ ast_debug(3, "Setting SIP_TRANSPORT_%s with address %s:%d\n", get_transport(p->socket.type), ast_inet_ntoa(us->sin_addr), ntohs(us->sin_port));
+ }
+
+ /*! \brief Append to SIP dialog history with arg list */
+@@ -3573,6 +3728,7 @@
+ struct sip_pkt *pkt = NULL;
+ int siptimer_a = DEFAULT_RETRANS;
+ int xmitres = 0;
++ int respid;
+
+ if (sipmethod == SIP_INVITE) {
+ /* Note this is a pending invite */
+@@ -3609,6 +3765,12 @@
+ pkt->owner = dialog_ref(p, "__sip_reliable_xmit: setting pkt->owner");
+ pkt->next = p->packets;
+ p->packets = pkt; /* Add it to the queue */
++ if (resp) {
++ /* Parse out the response code */
++ if (sscanf(ast_str_buffer(pkt->data), "SIP/2.0 %d", &respid) == 1) {
++ pkt->response_code = respid;
++ }
++ }
+ pkt->timer_t1 = p->timer_t1; /* Set SIP timer T1 */
+ pkt->retransid = -1;
+ if (pkt->timer_t1)
+@@ -3916,12 +4078,74 @@
+ return res;
+ }
+
++static void enable_digit_detect(struct sip_pvt *p)
++{
++ if (p->dsp) {
++ return;
++ }
++
++ if (!(p->dsp = ast_dsp_new())) {
++ return;
++ }
++
++ ast_dsp_set_features(p->dsp, DSP_FEATURE_DIGIT_DETECT);
++ if (global_relaxdtmf) {
++ ast_dsp_set_digitmode(p->dsp, DSP_DIGITMODE_DTMF | DSP_DIGITMODE_RELAXDTMF);
++ }
++}
++
++static void disable_digit_detect(struct sip_pvt *p)
++{
++ if (p->dsp) {
++ ast_dsp_free(p->dsp);
++ p->dsp = NULL;
++ }
++}
++
++/*! \brief Set an option on a SIP dialog */
++static int sip_setoption(struct ast_channel *chan, int option, void *data, int datalen)
++{
++ int res = -1;
++ struct sip_pvt *p = chan->tech_pvt;
++
++ switch (option) {
++ case AST_OPTION_FORMAT_READ:
++ res = ast_rtp_instance_set_read_format(p->rtp, *(int *) data);
++ break;
++ case AST_OPTION_FORMAT_WRITE:
++ res = ast_rtp_instance_set_write_format(p->rtp, *(int *) data);
++ break;
++ case AST_OPTION_MAKE_COMPATIBLE:
++ res = ast_rtp_instance_make_compatible(chan, p->rtp, (struct ast_channel *) data);
++ break;
++ case AST_OPTION_DIGIT_DETECT:
++ if ((ast_test_flag(&p->flags[0], SIP_DTMF) == SIP_DTMF_INBAND) ||
++ (ast_test_flag(&p->flags[0], SIP_DTMF) == SIP_DTMF_AUTO)) {
++ char *cp = (char *) data;
++
++ ast_debug(1, "%sabling digit detection on %s\n", *cp ? "En" : "Dis", chan->name);
++ if (*cp) {
++ enable_digit_detect(p);
++ } else {
++ disable_digit_detect(p);
++ }
++ res = 0;
++ }
++ break;
++ default:
++ break;
++ }
++
++ return res;
++}
++
+ /*! \brief Query an option on a SIP dialog */
+ static int sip_queryoption(struct ast_channel *chan, int option, void *data, int *datalen)
+ {
+ int res = -1;
+ enum ast_t38_state state = T38_STATE_UNAVAILABLE;
+ struct sip_pvt *p = (struct sip_pvt *) chan->tech_pvt;
++ char *cp;
+
+ switch (option) {
+ case AST_OPTION_T38_STATE:
+@@ -3955,6 +4179,11 @@
+ res = 0;
+
+ break;
++ case AST_OPTION_DIGIT_DETECT:
++ cp = (char *) data;
++ *cp = p->dsp ? 1 : 0;
++ ast_debug(1, "Reporting digit detection %sabled on %s\n", *cp ? "en" : "dis", chan->name);
++ break;
+ default:
+ break;
+ }
+@@ -4642,11 +4871,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);
+@@ -4654,7 +4883,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);
+ }
+ }
+
+@@ -4746,6 +4975,53 @@
+ *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");
++
++ do_setnat(dialog, ast_test_flag(&dialog->flags[0], SIP_NAT) & SIP_NAT_ROUTE);
++
++ 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.
+@@ -4773,17 +5049,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) {
+@@ -4797,31 +5062,29 @@
+ ast_udptl_destroy(dialog->udptl);
+ dialog->udptl = NULL;
+ }
+- 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);
+@@ -4834,7 +5097,11 @@
+ 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, mwi_from, peer->mwi_from);
+ 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;
+@@ -4843,6 +5110,7 @@
+ dialog->rtptimeout = peer->rtptimeout;
+ dialog->peerauth = peer->auth;
+ dialog->maxcallbitrate = peer->maxcallbitrate;
++ dialog->allowed_methods = peer->allowed_methods;
+ if (ast_strlen_zero(dialog->tohost))
+ ast_string_field_set(dialog, tohost, ast_inet_ntoa(dialog->sa.sin_addr));
+ if (!ast_strlen_zero(peer->fromdomain)) {
+@@ -4918,8 +5186,9 @@
+
+ if (peer) {
+ int res;
+- if (newdialog)
+- dialog->socket.type = 0;
++ if (newdialog) {
++ set_socket_transport(&dialog->socket, 0);
++ }
+ res = create_addr_from_peer(dialog, peer);
+ if (!ast_strlen_zero(port)) {
+ if ((portno = atoi(port))) {
+@@ -4930,7 +5199,9 @@
+ return res;
+ }
+
+- do_setnat(dialog, ast_test_flag(&dialog->flags[0], SIP_NAT) & SIP_NAT_ROUTE);
++ if (dialog_initialize_rtp(dialog)) {
++ return -1;
++ }
+
+ ast_string_field_set(dialog, tohost, peername);
+
+@@ -4981,7 +5252,7 @@
+ }
+
+ if (!dialog->socket.type)
+- dialog->socket.type = SIP_TRANSPORT_UDP;
++ set_socket_transport(&dialog->socket, SIP_TRANSPORT_UDP);
+ if (!dialog->socket.port)
+ dialog->socket.port = bindaddr.sin_port;
+ dialog->sa.sin_port = htons(portno);
+@@ -5075,7 +5346,7 @@
+ return res;
+ }
+ p->callingpres = ast->cid.cid_pres;
+- p->jointcapability = ast_translate_available_formats(p->capability, p->prefcodec);
++ p->jointcapability = ast_rtp_instance_available_formats(p->rtp, p->capability, p->prefcodec);
+ p->jointnoncodeccapability = p->noncodeccapability;
+
+ /* If there are no audio formats left to offer, punt */
+@@ -5088,11 +5359,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"),
+@@ -5199,15 +5472,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);
+@@ -5506,6 +5777,16 @@
+ case 606: /* Not acceptable */
+ return AST_CAUSE_BEARERCAPABILITY_NOTAVAIL;
+ default:
++ if (cause < 500 && cause >= 400) {
++ /* 4xx class error that is unknown - someting wrong with our request */
++ return AST_CAUSE_INTERWORKING;
++ } else if (cause < 600 && cause >= 500) {
++ /* 5xx class error - problem in the remote end */
++ return AST_CAUSE_CONGESTION;
++ } else if (cause < 700 && cause >= 600) {
++ /* 6xx - global errors in the 4xx class */
++ return AST_CAUSE_INTERWORKING;
++ }
+ return AST_CAUSE_NORMAL;
+ }
+ /* Never reached */
+@@ -5591,7 +5872,6 @@
+ return 0;
+ }
+
+-
+ /*! \brief sip_hangup: Hangup SIP call
+ * Part of PBX interface, called from ast_hangup */
+ static int sip_hangup(struct ast_channel *ast)
+@@ -5670,8 +5950,7 @@
+ append_history(p, needcancel ? "Cancel" : "Hangup", "Cause %s", p->owner ? ast_cause2str(p->hangupcause) : "Unknown");
+
+ /* Disconnect */
+- if (p->vad)
+- ast_dsp_free(p->vad);
++ disable_digit_detect(p);
+
+ p->owner = NULL;
+ ast->tech_pvt = dialog_unref(ast->tech_pvt, "unref ast->tech_pvt");
+@@ -5726,58 +6005,62 @@
+
+ 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;
+
+- /* We need to get the lock on bridge because ast_rtp_set_vars will attempt
++ /* We need to get the lock on bridge because ast_rtp_instance_set_stats_vars will attempt
+ * to lock the bridge. This may get hairy...
+ */
+ while (bridge && ast_channel_trylock(bridge)) {
+- struct ast_channel *chan = p->owner;
+ sip_pvt_unlock(p);
+ do {
+- /* Use chan since p->owner could go NULL on us
+- * while p is unlocked
+- */
+- CHANNEL_DEADLOCK_AVOIDANCE(chan);
++ CHANNEL_DEADLOCK_AVOIDANCE(oldowner);
+ } while (sip_pvt_trylock(p));
+- bridge = p->owner ? ast_bridged_channel(p->owner) : NULL;
++ bridge = ast_bridged_channel(oldowner);
+ }
+
+- 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 && q->rtp)
+- ast_rtp_set_vars(bridge, q->rtp);
++ if (IS_SIP_TECH(bridge->tech) && q && q->rtp) {
++ ast_rtp_instance_set_stats_vars(bridge, q->rtp);
++ }
+ ast_channel_unlock(bridge);
+ }
+
+- 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. */
+@@ -5801,9 +6084,27 @@
+ {
+ int fmt;
+ const char *codec;
++ struct ast_channel* chan;
+
+- codec = pbx_builtin_getvar_helper(p->owner, "SIP_CODEC");
+- if (!codec)
++ chan = ast_channel_ref(p->owner);
++ while (ast_channel_trylock(chan)) {
++ sip_pvt_unlock(p);
++ sched_yield();
++ sip_pvt_lock(p);
++ }
++
++ if (p->outgoing_call) {
++ codec = pbx_builtin_getvar_helper(p->owner, "SIP_CODEC_OUTBOUND");
++ } else if (!(codec = pbx_builtin_getvar_helper(p->owner, "SIP_CODEC_INBOUND"))) {
++ codec = pbx_builtin_getvar_helper(p->owner, "SIP_CODEC");
++ }
++
++ codec = ast_strdupa(S_OR(codec, ""));
++
++ ast_channel_unlock(chan);
++ chan = ast_channel_unref(chan);
++
++ if (ast_strlen_zero(codec))
+ return;
+
+ fmt = ast_getformatbyname(codec);
+@@ -5832,8 +6133,11 @@
+
+ ast_setstate(ast, AST_STATE_UP);
+ ast_debug(1, "SIP answering channel: %s\n", ast->name);
+- ast_rtp_new_source(p->rtp);
+- res = transmit_response_with_sdp(p, "200 OK", &p->initreq, XMIT_CRITICAL, FALSE);
++ if (p->t38.state == T38_PEER_DIRECT) {
++ change_t38_state(p, T38_ENABLED);
++ }
++ 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);
+@@ -5867,16 +6171,16 @@
+ 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_write(p->rtp, frame);
++ res = ast_rtp_instance_write(p->rtp, frame);
+ }
+ }
+ sip_pvt_unlock(p);
+@@ -5891,11 +6195,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);
+ }
+@@ -5904,7 +6208,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 */
+@@ -5912,11 +6216,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);
+@@ -6004,11 +6308,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;
+@@ -6033,10 +6341,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);
+@@ -6124,18 +6436,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 */
+@@ -6181,8 +6493,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;
+@@ -6195,7 +6513,6 @@
+ return res;
+ }
+
+-
+ /*! \brief Initiate a call in the SIP channel
+ called from sip_request_call (calls from the pbx ) for outbound channels
+ and from handle_request_invite for inbound channels
+@@ -6294,24 +6611,28 @@
+ else
+ 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 ((ast_test_flag(&i->flags[0], SIP_DTMF) == SIP_DTMF_INBAND) ||
++ (ast_test_flag(&i->flags[0], SIP_DTMF) == SIP_DTMF_AUTO)) {
++ if (!i->rtp || ast_rtp_instance_dtmf_mode_set(i->rtp, AST_RTP_DTMF_MODE_INBAND)) {
++ enable_digit_detect(i);
++ }
++ } 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));
+
+@@ -6493,9 +6814,9 @@
+ for (pass = 0; name && pass < 2;pass++) {
+ int x, len = strlen(name);
+ for (x = *start; x < req->headers; x++) {
+- char *header = REQ_OFFSET_TO_STR(req, header[x]);
++ const char *header = REQ_OFFSET_TO_STR(req, header[x]);
+ if (!strncasecmp(header, name, len)) {
+- char *r = header + len; /* skip name */
++ const char *r = header + len; /* skip name */
+ if (sip_cfg.pedanticsipchecking)
+ r = ast_skip_blanks(r);
+
+@@ -6535,19 +6856,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;
+@@ -6589,8 +6910,8 @@
+ ast_set_write_format(p->owner, p->owner->writeformat);
+ }
+
+- if (f && (ast_test_flag(&p->flags[0], SIP_DTMF) == SIP_DTMF_INBAND) && p->vad) {
+- f = ast_dsp_process(p->owner, p->vad, f);
++ if (f && p->dsp) {
++ f = ast_dsp_process(p->owner, p->dsp, f);
+ if (f && f->frametype == AST_FRAME_DTMF) {
+ if (ast_test_flag(&p->t38.t38support, SIP_PAGE2_T38SUPPORT_UDPTL) && f->subclass == 'f') {
+ ast_debug(1, "Fax CNG detected on %s\n", ast->name);
+@@ -6706,7 +7027,7 @@
+ * remember to release the reference.
+ */
+ static struct sip_pvt *sip_alloc(ast_string_field callid, struct sockaddr_in *sin,
+- int useglobal_nat, const int intended_method)
++ int useglobal_nat, const int intended_method, struct sip_request *req)
+ {
+ struct sip_pvt *p;
+
+@@ -6718,8 +7039,13 @@
+ return NULL;
+ }
+
++ if (req) {
++ set_socket_transport(&p->socket, req->socket.type); /* Later in ast_sip_ouraddrfor we need this to choose the right ip and port for the specific transport */
++ } else {
++ set_socket_transport(&p->socket, SIP_TRANSPORT_UDP);
++ }
++
+ p->socket.fd = -1;
+- p->socket.type = SIP_TRANSPORT_UDP;
+ p->method = intended_method;
+ p->initid = -1;
+ p->waitid = -1;
+@@ -6742,7 +7068,7 @@
+ p->ourip = internip;
+ else {
+ p->sa = *sin;
+- ast_sip_ouraddrfor(&p->sa.sin_addr, &p->ourip);
++ ast_sip_ouraddrfor(&p->sa.sin_addr, &p->ourip, p);
+ }
+
+ /* Copy global flags to this PVT at setup. */
+@@ -6756,50 +7082,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) {
+@@ -6831,6 +7118,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);
+
+@@ -6985,7 +7273,7 @@
+ transmit_response_using_temp(callid, sin, 1, intended_method, req, "489 Bad event");
+ } else {
+ /* Ok, time to create a new SIP dialog object, a pvt */
+- if ((p = sip_alloc(callid, sin, 1, intended_method))) {
++ if ((p = sip_alloc(callid, sin, 1, intended_method, req))) {
+ /* Ok, we've created a dialog, let's go and process it */
+ sip_pvt_lock(p);
+ } else {
+@@ -7027,19 +7315,20 @@
+ enum sip_transport transport = SIP_TRANSPORT_UDP;
+ char buf[256] = "";
+ char *username = NULL;
+- char *hostname=NULL, *secret=NULL, *authuser=NULL, *expire=NULL;
++ char *hostname=NULL, *secret=NULL, *authuser=NULL, *expire=NULL, *buf2=NULL;
+ char *callback=NULL;
+
+ if (!value)
+ return -1;
+
+ ast_copy_string(buf, value, sizeof(buf));
++ buf2 = strrchr(buf, '@');
+
+- /* split [/contact][~expiry] */
+- expire = strchr(buf, '~');
++ /* split [/extension][~expiry] */
++ expire = strchr(buf2, '~');
+ if (expire)
+ *expire++ = '\0';
+- callback = strrchr(buf, '/');
++ callback = strrchr(buf2, '/');
+ if (callback)
+ *callback++ = '\0';
+ if (ast_strlen_zero(callback))
+@@ -7182,6 +7471,97 @@
+ return 0;
+ }
+
++static void mark_method_allowed(unsigned int *allowed_methods, enum sipmethod method)
++{
++ (*allowed_methods) |= (1 << method);
++}
++
++static void mark_method_unallowed(unsigned int *allowed_methods, enum sipmethod method)
++{
++ (*allowed_methods) &= ~(1 << method);
++}
++
++static int is_method_allowed(unsigned int *allowed_methods, enum sipmethod method)
++{
++ return ((*allowed_methods) >> method) & 1;
++}
++
++/*!
++ * \brief parse the Allow header to see what methods the endpoint we
++ * are communicating with allows.
++ *
++ * We parse the allow header on incoming Registrations and save the
++ * result to the SIP peer that is registering. When the registration
++ * expires, we clear what we know about the peer's allowed methods.
++ * When the peer re-registers, we once again parse to see if the
++ * list of allowed methods has changed.
++ *
++ * For peers that do not register, we parse the first message we receive
++ * during a call to see what is allowed, and save the information
++ * for the duration of the call.
++ * \param req The SIP request we are parsing
++ * \retval The methods allowed
++ */
++static unsigned int parse_allowed_methods(struct sip_request *req)
++{
++ char *allow = ast_strdupa(get_header(req, "Allow"));
++ char *method;
++ unsigned int allowed_methods = SIP_UNKNOWN;
++
++ if (ast_strlen_zero(allow)) {
++ /* I have witnessed that REGISTER requests from Polycom phones do not
++ * place the phone's allowed methods in an Allow header. Instead, they place the
++ * allowed methods in a methods= parameter in the Contact header.
++ */
++ char *contact = ast_strdupa(get_header(req, "Contact"));
++ char *methods = strstr(contact, ";methods=");
++
++ if (ast_strlen_zero(methods)) {
++ /* RFC 3261 states:
++ *
++ * "The absence of an Allow header field MUST NOT be
++ * interpreted to mean that the UA sending the message supports no
++ * methods. Rather, it implies that the UA is not providing any
++ * information on what methods it supports."
++ *
++ * For simplicity, we'll assume that the peer allows all known
++ * SIP methods if they have no Allow header. We can then clear out the necessary
++ * bits if the peer lets us know that we have sent an unsupported method.
++ */
++ return UINT_MAX;
++ }
++ allow = ast_strip_quoted(methods + 9, "\"", "\"");
++ }
++ for (method = strsep(&allow, ","); !ast_strlen_zero(method); method = strsep(&allow, ",")) {
++ int id = find_sip_method(ast_skip_blanks(method));
++ if (id == SIP_UNKNOWN) {
++ continue;
++ }
++ mark_method_allowed(&allowed_methods, id);
++ }
++ return allowed_methods;
++}
++
++/*! A wrapper for parse_allowed_methods geared toward sip_pvts
++ *
++ * This function, in addition to setting the allowed methods for a sip_pvt
++ * also will take into account the setting of the SIP_PAGE2_RPID_UPDATE flag.
++ *
++ * \param pvt The sip_pvt we are setting the allowed_methods for
++ * \param req The request which we are parsing
++ * \retval The methods alloweded by the sip_pvt
++ */
++static unsigned int set_pvt_allowed_methods(struct sip_pvt *pvt, struct sip_request *req)
++{
++ pvt->allowed_methods = parse_allowed_methods(req);
++
++ if (ast_test_flag(&pvt->flags[1], SIP_PAGE2_RPID_UPDATE)) {
++ mark_method_allowed(&pvt->allowed_methods, SIP_UPDATE);
++ }
++
++ return pvt->allowed_methods;
++}
++
+ /*! \brief Parse multiline SIP headers into one header
+ This is enabled if pedanticsipchecking is enabled */
+ static int lws2sws(char *msgbuf, int len)
+@@ -7397,7 +7777,7 @@
+ sdp part and the end boundry if it exists */
+
+ for (x = 0; x < (req->lines); x++) {
+- char *line = REQ_OFFSET_TO_STR(req, line[x]);
++ const char *line = REQ_OFFSET_TO_STR(req, line[x]);
+ if (!strncasecmp(line, boundary, strlen(boundary))){
+ if (found_application_sdp && found_end_of_headers) {
+ req->sdp_end = x-1;
+@@ -7446,7 +7826,7 @@
+ /* Continue since there may be a valid host in a c= line specific to the audio stream */
+ }
+ /* We only want the m and c lines for audio */
+- while ((m = get_sdp_iterate(&miterator, req, "m"))) {
++ for (m = get_sdp_iterate(&miterator, req, "m"); !ast_strlen_zero(m); m = get_sdp_iterate(&miterator, req, "m")) {
+ if ((media == SDP_AUDIO && ((sscanf(m, "audio %d/%d RTP/AVP %n", &x, &numberofports, &len) == 2 && len > 0) ||
+ (sscanf(m, "audio %d RTP/AVP %n", &x, &len) == 1 && len > 0))) ||
+ (media == SDP_VIDEO && ((sscanf(m, "video %d/%d RTP/AVP %n", &x, &numberofports, &len) == 2 && len > 0) ||
+@@ -7522,7 +7902,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;
+@@ -7533,7 +7913,7 @@
+ int last_rtpmap_codec=0;
+
+ char buf[SIPBUFSIZE];
+- uint64_t rua_version;
++ int64_t rua_version;
+
+ int red_data_pt[10];
+ int red_num_gen = 0;
+@@ -7547,34 +7927,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 ? */
+
+@@ -7609,21 +7966,44 @@
+ ast_log(LOG_WARNING, "SDP syntax error in o= line\n");
+ return -1;
+ }
+- if (!sscanf(token, "%" SCNu64, &rua_version)) {
++ if (!sscanf(token, "%" SCNd64, &rua_version)) {
+ ast_log(LOG_WARNING, "SDP syntax error in o= line version\n");
+ return -1;
+ }
+
+- if (ast_test_flag(&p->flags[1], SIP_PAGE2_IGNORESDPVERSION)
+- || p->sessionversion_remote < 0
+- || p->sessionversion_remote != rua_version) {
+-
++ /* we need to check the SDP version number the other end sent us;
++ * our rules for deciding what to accept are a bit complex.
++ *
++ * 1) if 'ignoresdpversion' has been set for this dialog, then
++ * we will just accept whatever they sent and assume it is
++ * a modification of the session, even if it is not
++ * 2) otherwise, if this is the first SDP we've seen from them
++ * we accept it
++ * 3) otherwise, if the new SDP version number is higher than the
++ * old one, we accept it
++ * 4) otherwise, if this SDP is in response to us requesting a switch
++ * to T.38, we accept the SDP, but also generate a warning message
++ * that this peer should have the 'ignoresdpversion' option set,
++ * because it is not following the SDP offer/answer RFC; if we did
++ * not request a switch to T.38, then we stop parsing the SDP, as it
++ * has not changed from the previous 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. Not parsing this SDP.\n");
+- return 0;
++ } else {
++ if (p->t38.state == T38_LOCAL_REINVITE) {
++ p->sessionversion_remote = rua_version;
++ p->session_modify = TRUE;
++ ast_log(LOG_WARNING, "Call %s responded to our T.38 reinvite without changing SDP version; 'ignoresdpversion' should be set for this peer.\n", p->callid);
++ } else {
++ p->session_modify = FALSE;
++ ast_debug(2, "Call %s responded to our reinvite without changing SDP version; ignoring SDP.\n", p->callid);
++ return 0;
++ }
+ }
+
+ /* Try to find first media stream */
+@@ -7655,12 +8035,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;
+@@ -7684,7 +8066,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)) {
+@@ -7700,7 +8083,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)) {
+@@ -7716,7 +8099,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) )) {
+@@ -7781,10 +8164,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 = { 0, };
++ 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));
+ }
+@@ -7804,7 +8187,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 {
+@@ -7812,7 +8195,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);
+ }
+@@ -7895,18 +8278,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;
+ }
+@@ -7918,7 +8300,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, "/");
+ }
+@@ -7927,15 +8309,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) {
+@@ -7943,7 +8325,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;
+ }
+@@ -7953,7 +8335,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;
+ }
+@@ -7975,24 +8357,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);
+
+@@ -8000,15 +8382,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);
+ }
+@@ -8147,15 +8528,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];
+@@ -8166,11 +8546,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... */
+@@ -8190,18 +8576,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);
+@@ -8209,8 +8601,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);
+ }
+@@ -8218,21 +8610,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));
+ }
+@@ -8279,7 +8671,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);
+@@ -8749,7 +9141,7 @@
+ * Similarly, if we need to re-send an INVITE with auth credentials, then we
+ * need to use the same branch as we did the first time we sent the INVITE.
+ */
+- if (sipmethod == SIP_CANCEL || (sipmethod == SIP_INVITE && !ast_strlen_zero(p->options->auth))) {
++ if (sipmethod == SIP_CANCEL || (sipmethod == SIP_INVITE && p->options && !ast_strlen_zero(p->options->auth))) {
+ p->branch = p->invite_branch;
+ build_via(p);
+ } else if (newbranch) {
+@@ -8830,9 +9222,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);
+@@ -8870,6 +9259,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 */
+@@ -8924,7 +9321,7 @@
+ p->ourip = internip;
+ else {
+ p->sa = *sin;
+- ast_sip_ouraddrfor(&p->sa.sin_addr, &p->ourip);
++ ast_sip_ouraddrfor(&p->sa.sin_addr, &p->ourip, p);
+ }
+
+ p->branch = ast_random();
+@@ -9089,6 +9486,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)
+@@ -9120,19 +9600,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:
+@@ -9179,13 +9659,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 */
+ }
+
+@@ -9202,20 +9682,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);
+
+ }
+ }
+@@ -9258,14 +9739,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);
+ }
+@@ -9278,11 +9759,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 */
+@@ -9317,11 +9798,11 @@
+ int len = 0;
+ int alreadysent = 0;
+
+- struct sockaddr_in sin;
+- struct sockaddr_in vsin;
+- struct sockaddr_in tsin;
+- struct sockaddr_in dest;
+- struct sockaddr_in udptlsin;
++ struct sockaddr_in sin = { 0, };
++ struct sockaddr_in vsin = { 0, };
++ struct sockaddr_in tsin = { 0, };
++ struct sockaddr_in dest = { 0, };
++ struct sockaddr_in udptlsin = { 0, };
+ struct sockaddr_in vdest = { 0, };
+ struct sockaddr_in tdest = { 0, };
+ struct sockaddr_in udptldest = { 0, };
+@@ -9701,7 +10182,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;
+@@ -9710,10 +10191,13 @@
+ 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);
+ if (p->t38.state == T38_PEER_DIRECT || p->t38.state == T38_ENABLED) {
+@@ -9799,8 +10283,13 @@
+ add_header(&req, "X-asterisk-Info", "SIP re-invite (External RTP bridge)");
+ }
+
++ if (ast_test_flag(&p->flags[1], SIP_SENDRPID))
++ add_rpid(&req, p);
++
+ if (p->do_history)
+ append_history(p, "ReInv", "Re-invite sent");
++
++ try_suggested_sip_codec(p);
+ if (t38version)
+ add_sdp(&req, p, oldsdp, FALSE, TRUE);
+ else
+@@ -9847,95 +10336,18 @@
+ {
+
+ int ourport = ntohs(p->ourip.sin_port);
+-
+- if (p->socket.type & SIP_TRANSPORT_UDP) {
+- if (!sip_standard_port(p->socket.type, ourport))
++ /* only add port if it's non-standard for the transport type */
++ if (!sip_standard_port(p->socket.type, ourport)) {
++ if (p->socket.type == SIP_TRANSPORT_UDP)
+ 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:%d;transport=%s>", p->exten, ast_strlen_zero(p->exten) ? "" : "@", ast_inet_ntoa(p->ourip.sin_addr), ourport, get_transport(p->socket.type));
++ } else {
++ if (p->socket.type == SIP_TRANSPORT_UDP)
+ 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 {
+- /*! \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;
++ ast_string_field_build(p, our_contact, "<sip:%s%s%s;transport=%s>", p->exten, ast_strlen_zero(p->exten) ? "" : "@", ast_inet_ntoa(p->ourip.sin_addr), get_transport(p->socket.type));
+ }
+-
+- 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 */
+@@ -9973,16 +10385,21 @@
+
+ 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;
++
++ /* Hey, it's a NOTIFY! See if they've configured a mwi_from.
++ * XXX Right now, this logic works because the only place that mwi_from
++ * is set on the sip_pvt is in sip_send_mwi_to_peer. If things changed, then
++ * we might end up putting the mwi_from setting into other types of NOTIFY
++ * messages as well.
++ */
++ if (sipmethod == SIP_NOTIFY && !ast_strlen_zero(p->mwi_from)) {
++ l = p->mwi_from;
+ }
++
+ if (ast_strlen_zero(l))
+ l = default_callerid;
+ if (ast_strlen_zero(n))
+@@ -10070,12 +10487,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);
+@@ -10084,10 +10496,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
+@@ -10206,13 +10654,20 @@
+
+ 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_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_sdp(&req, p, FALSE, FALSE, TRUE);
+- } else if (p->rtp)
++ } else if (p->rtp) {
++ try_suggested_sip_codec(p);
+ add_sdp(&req, p, FALSE, TRUE, FALSE);
++ }
+ } else {
+ if (!p->notify_headers) {
+ add_header_contentLength(&req, 0);
+@@ -10221,7 +10676,9 @@
+
+ if (!p->initreq.headers || init > 2)
+ initialize_initreq(p, &req);
+- p->lastinvite = p->ocseq;
++ if (sipmethod == SIP_INVITE) {
++ p->lastinvite = p->ocseq;
++ }
+ return send_request(p, &req, init ? XMIT_CRITICAL : XMIT_RELIABLE, p->ocseq);
+ }
+
+@@ -10258,7 +10715,7 @@
+ }
+
+ /* Create a dialog that we will use for the subscription */
+- if (!(mwi->call = sip_alloc(NULL, NULL, 0, SIP_SUBSCRIBE))) {
++ if (!(mwi->call = sip_alloc(NULL, NULL, 0, SIP_SUBSCRIBE, NULL))) {
+ return -1;
+ }
+
+@@ -10296,9 +10753,9 @@
+ if (!ast_strlen_zero(mwi->secret)) {
+ ast_string_field_set(mwi->call, peersecret, mwi->secret);
+ }
+- mwi->call->socket.type = mwi->transport;
++ set_socket_transport(&mwi->call->socket, mwi->transport);
+ mwi->call->socket.port = htons(mwi->portno);
+- ast_sip_ouraddrfor(&mwi->call->sa.sin_addr, &mwi->call->ourip);
++ ast_sip_ouraddrfor(&mwi->call->sa.sin_addr, &mwi->call->ourip, mwi->call);
+ build_contact(mwi->call);
+ build_via(mwi->call);
+ build_callid_pvt(mwi->call);
+@@ -10313,30 +10770,31 @@
+ return 0;
+ }
+
+-static int find_calling_channel(struct ast_channel *c, void *data) {
++static int find_calling_channel(void *obj, void *arg, void *data, int flags)
++{
++ struct ast_channel *c = obj;
+ struct sip_pvt *p = data;
++ int res;
+
+- return (c->pbx &&
++ ast_channel_lock(c);
++
++ res = (c->pbx &&
+ (!strcasecmp(c->macroexten, p->exten) || !strcasecmp(c->exten, p->exten)) &&
+ (sip_cfg.notifycid == IGNORE_CONTEXT || !strcasecmp(c->context, p->context)));
++
++ ast_channel_unlock(c);
++
++ return res ? CMP_MATCH | CMP_STOP : 0;
+ }
+
+-/*! \brief Used in the SUBSCRIBE notification subsystem (RFC3265) */
+-static int transmit_state_notify(struct sip_pvt *p, int state, int full, int timeout)
++/*! \brief Builds XML portion of state NOTIFY messages */
++static void state_notify_build_xml(int state, int full, const char *exten, const char *context, struct ast_str **tmp, struct sip_pvt *p, int subscribed, const char *mfrom, const char *mto)
+ {
+- struct ast_str *tmp = ast_str_alloca(4000);
+- char from[256], to[256];
+- char *c, *mfrom, *mto;
+- struct sip_request req;
++ enum state { NOTIFY_OPEN, NOTIFY_INUSE, NOTIFY_CLOSED } local_state = NOTIFY_OPEN;
++ const char *statestring = "terminated";
++ const char *pidfstate = "--";
++ const char *pidfnote= "Ready";
+ char hint[AST_MAX_EXTENSION];
+- char *statestring = "terminated";
+- const struct cfsubscription_types *subscriptiontype;
+- enum state { NOTIFY_OPEN, NOTIFY_INUSE, NOTIFY_CLOSED } local_state = NOTIFY_OPEN;
+- char *pidfstate = "--";
+- char *pidfnote= "Ready";
+-
+- memset(from, 0, sizeof(from));
+- memset(to, 0, sizeof(to));
+
+ switch (state) {
+ case (AST_EXTENSION_RINGING | AST_EXTENSION_INUSE):
+@@ -10381,10 +10839,8 @@
+ break;
+ }
+
+- subscriptiontype = find_subscription_type(p->subscribed);
+-
+ /* Check which device/devices we are watching and if they are registered */
+- if (ast_get_hint(hint, sizeof(hint), NULL, 0, NULL, p->context, p->exten)) {
++ if (ast_get_hint(hint, sizeof(hint), NULL, 0, NULL, context, exten)) {
+ char *hint2 = hint, *individual_hint = NULL;
+ int hint_count = 0, unavailable_count = 0;
+
+@@ -10405,103 +10861,64 @@
+ }
+ }
+
+- ast_copy_string(from, get_header(&p->initreq, "From"), sizeof(from));
+- c = get_in_brackets(from);
+- if (strncasecmp(c, "sip:", 4) && strncasecmp(c, "sips:", 5)) {
+- ast_log(LOG_WARNING, "Huh? Not a SIP header (%s)?\n", c);
+- return -1;
+- }
+-
+- mfrom = remove_uri_parameters(c);
+-
+- ast_copy_string(to, get_header(&p->initreq, "To"), sizeof(to));
+- c = get_in_brackets(to);
+- if (strncasecmp(c, "sip:", 4) && strncasecmp(c, "sips:", 5)) {
+- ast_log(LOG_WARNING, "Huh? Not a SIP header (%s)?\n", c);
+- return -1;
+- }
+- mto = remove_uri_parameters(c);
+-
+- reqprep(&req, p, SIP_NOTIFY, 0, 1);
+-
+-
+- add_header(&req, "Event", subscriptiontype->event);
+- add_header(&req, "Content-Type", subscriptiontype->mediatype);
+- switch(state) {
+- case AST_EXTENSION_DEACTIVATED:
+- if (timeout)
+- add_header(&req, "Subscription-State", "terminated;reason=timeout");
+- else {
+- add_header(&req, "Subscription-State", "terminated;reason=probation");
+- add_header(&req, "Retry-After", "60");
+- }
+- break;
+- case AST_EXTENSION_REMOVED:
+- add_header(&req, "Subscription-State", "terminated;reason=noresource");
+- break;
+- default:
+- if (p->expiry)
+- add_header(&req, "Subscription-State", "active");
+- else /* Expired */
+- add_header(&req, "Subscription-State", "terminated;reason=timeout");
+- }
+- switch (p->subscribed) {
++ switch (subscribed) {
+ case XPIDF_XML:
+ case CPIM_PIDF_XML:
+- ast_str_append(&tmp, 0,
++ ast_str_append(tmp, 0,
+ "<?xml version=\"1.0\"?>\n"
+ "<!DOCTYPE presence PUBLIC \"-//IETF//DTD RFCxxxx XPIDF 1.0//EN\" \"xpidf.dtd\">\n"
+ "<presence>\n");
+- ast_str_append(&tmp, 0, "<presentity uri=\"%s;method=SUBSCRIBE\" />\n", mfrom);
+- ast_str_append(&tmp, 0, "<atom id=\"%s\">\n", p->exten);
+- ast_str_append(&tmp, 0, "<address uri=\"%s;user=ip\" priority=\"0.800000\">\n", mto);
+- ast_str_append(&tmp, 0, "<status status=\"%s\" />\n", (local_state == NOTIFY_OPEN) ? "open" : (local_state == NOTIFY_INUSE) ? "inuse" : "closed");
+- ast_str_append(&tmp, 0, "<msnsubstatus substatus=\"%s\" />\n", (local_state == NOTIFY_OPEN) ? "online" : (local_state == NOTIFY_INUSE) ? "onthephone" : "offline");
+- ast_str_append(&tmp, 0, "</address>\n</atom>\n</presence>\n");
++ ast_str_append(tmp, 0, "<presentity uri=\"%s;method=SUBSCRIBE\" />\n", mfrom);
++ ast_str_append(tmp, 0, "<atom id=\"%s\">\n", exten);
++ ast_str_append(tmp, 0, "<address uri=\"%s;user=ip\" priority=\"0.800000\">\n", mto);
++ ast_str_append(tmp, 0, "<status status=\"%s\" />\n", (local_state == NOTIFY_OPEN) ? "open" : (local_state == NOTIFY_INUSE) ? "inuse" : "closed");
++ ast_str_append(tmp, 0, "<msnsubstatus substatus=\"%s\" />\n", (local_state == NOTIFY_OPEN) ? "online" : (local_state == NOTIFY_INUSE) ? "onthephone" : "offline");
++ ast_str_append(tmp, 0, "</address>\n</atom>\n</presence>\n");
+ break;
+ case PIDF_XML: /* Eyebeam supports this format */
+- ast_str_append(&tmp, 0,
++ ast_str_append(tmp, 0,
+ "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n"
+ "<presence xmlns=\"urn:ietf:params:xml:ns:pidf\" \nxmlns:pp=\"urn:ietf:params:xml:ns:pidf:person\"\nxmlns:es=\"urn:ietf:params:xml:ns:pidf:rpid:status:rpid-status\"\nxmlns:ep=\"urn:ietf:params:xml:ns:pidf:rpid:rpid-person\"\nentity=\"%s\">\n", mfrom);
+- ast_str_append(&tmp, 0, "<pp:person><status>\n");
++ ast_str_append(tmp, 0, "<pp:person><status>\n");
+ if (pidfstate[0] != '-')
+- ast_str_append(&tmp, 0, "<ep:activities><ep:%s/></ep:activities>\n", pidfstate);
+- ast_str_append(&tmp, 0, "</status></pp:person>\n");
+- ast_str_append(&tmp, 0, "<note>%s</note>\n", pidfnote); /* Note */
+- ast_str_append(&tmp, 0, "<tuple id=\"%s\">\n", p->exten); /* Tuple start */
+- ast_str_append(&tmp, 0, "<contact priority=\"1\">%s</contact>\n", mto);
++ ast_str_append(tmp, 0, "<ep:activities><ep:%s/></ep:activities>\n", pidfstate);
++ ast_str_append(tmp, 0, "</status></pp:person>\n");
++ ast_str_append(tmp, 0, "<note>%s</note>\n", pidfnote); /* Note */
++ ast_str_append(tmp, 0, "<tuple id=\"%s\">\n", exten); /* Tuple start */
++ ast_str_append(tmp, 0, "<contact priority=\"1\">%s</contact>\n", mto);
+ if (pidfstate[0] == 'b') /* Busy? Still open ... */
+- ast_str_append(&tmp, 0, "<status><basic>open</basic></status>\n");
++ ast_str_append(tmp, 0, "<status><basic>open</basic></status>\n");
+ else
+- ast_str_append(&tmp, 0, "<status><basic>%s</basic></status>\n", (local_state != NOTIFY_CLOSED) ? "open" : "closed");
+- ast_str_append(&tmp, 0, "</tuple>\n</presence>\n");
++ ast_str_append(tmp, 0, "<status><basic>%s</basic></status>\n", (local_state != NOTIFY_CLOSED) ? "open" : "closed");
++ ast_str_append(tmp, 0, "</tuple>\n</presence>\n");
+ 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);
++ ast_str_append(tmp, 0, "<?xml version=\"1.0\"?>");
++ ast_str_append(tmp, 0, "<dialog-info xmlns=\"urn:ietf:params:xml:ns:dialog-info\" version=\"%d\" state=\"%s\" entity=\"%s\">", p->dialogver, full ? "full" : "partial", mto);
+ if ((state & AST_EXTENSION_RINGING) && sip_cfg.notifyringing) {
+- const char *local_display = p->exten;
+- char *local_target = mto;
++ const char *local_display = exten;
++ char *local_target = ast_strdupa(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);
++ struct ast_channel *caller;
+
+- if (caller) {
++ if ((caller = ast_channel_callback(find_calling_channel, NULL, p, 0))) {
+ int need = strlen(caller->cid.cid_num) + strlen(p->fromdomain) + sizeof("sip:@");
+ local_target = alloca(need);
++ ast_channel_lock(caller);
+ 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;
++ caller = ast_channel_unref(caller);
+ }
+ }
+
+ /* 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,
++ 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
+@@ -10513,23 +10930,102 @@
+ "<identity>%s</identity>\n"
+ "<target uri=\"%s\"/>\n"
+ "</local>\n",
+- p->exten, p->callid, local_display, local_target, local_target, mto, mto);
++ 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, "<dialog id=\"%s\">", exten);
+ }
+- ast_str_append(&tmp, 0, "<state>%s</state>\n", statestring);
++ 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"
+- "<param pname=\"+sip.rendering\" pvalue=\"no\"/>\n"
+- "</target>\n</local>\n", mto);
++ ast_str_append(tmp, 0, "<local>\n<target uri=\"%s\">\n"
++ "<param pname=\"+sip.rendering\" pvalue=\"no\"/>\n"
++ "</target>\n</local>\n", mto);
+ }
+- ast_str_append(&tmp, 0, "</dialog>\n</dialog-info>\n");
++ ast_str_append(tmp, 0, "</dialog>\n</dialog-info>\n");
+ break;
+ case NONE:
+ default:
+ break;
+ }
++}
+
++
++/*! \brief Used in the SUBSCRIBE notification subsystem (RFC3265) */
++static int transmit_state_notify(struct sip_pvt *p, int state, int full, int timeout)
++{
++ struct ast_str *tmp = ast_str_alloca(4000);
++ char from[256], to[256];
++ char *c, *mfrom, *mto;
++ struct sip_request req;
++ const struct cfsubscription_types *subscriptiontype;
++
++ memset(from, 0, sizeof(from));
++ memset(to, 0, sizeof(to));
++
++ subscriptiontype = find_subscription_type(p->subscribed);
++
++ ast_copy_string(from, get_header(&p->initreq, "From"), sizeof(from));
++ c = get_in_brackets(from);
++ if (strncasecmp(c, "sip:", 4) && strncasecmp(c, "sips:", 5)) {
++ ast_log(LOG_WARNING, "Huh? Not a SIP header (%s)?\n", c);
++ return -1;
++ }
++
++ mfrom = remove_uri_parameters(c);
++
++ ast_copy_string(to, get_header(&p->initreq, "To"), sizeof(to));
++ c = get_in_brackets(to);
++ if (strncasecmp(c, "sip:", 4) && strncasecmp(c, "sips:", 5)) {
++ ast_log(LOG_WARNING, "Huh? Not a SIP header (%s)?\n", c);
++ return -1;
++ }
++ mto = remove_uri_parameters(c);
++
++ reqprep(&req, p, SIP_NOTIFY, 0, 1);
++
++ switch(state) {
++ case AST_EXTENSION_DEACTIVATED:
++ if (timeout)
++ add_header(&req, "Subscription-State", "terminated;reason=timeout");
++ else {
++ add_header(&req, "Subscription-State", "terminated;reason=probation");
++ add_header(&req, "Retry-After", "60");
++ }
++ break;
++ case AST_EXTENSION_REMOVED:
++ add_header(&req, "Subscription-State", "terminated;reason=noresource");
++ break;
++ default:
++ if (p->expiry)
++ add_header(&req, "Subscription-State", "active");
++ else /* Expired */
++ add_header(&req, "Subscription-State", "terminated;reason=timeout");
++ }
++
++ switch (p->subscribed) {
++ case XPIDF_XML:
++ case CPIM_PIDF_XML:
++ add_header(&req, "Event", subscriptiontype->event);
++ state_notify_build_xml(state, full, p->exten, p->context, &tmp, p, p->subscribed, mfrom, mto);
++ add_header(&req, "Content-Type", subscriptiontype->mediatype);
++ p->dialogver++;
++ break;
++ case PIDF_XML: /* Eyebeam supports this format */
++ add_header(&req, "Event", subscriptiontype->event);
++ state_notify_build_xml(state, full, p->exten, p->context, &tmp, p, p->subscribed, mfrom, mto);
++ add_header(&req, "Content-Type", subscriptiontype->mediatype);
++ p->dialogver++;
++ break;
++ case DIALOG_INFO_XML: /* SNOM subscribes in this format */
++ add_header(&req, "Event", subscriptiontype->event);
++ state_notify_build_xml(state, full, p->exten, p->context, &tmp, p, p->subscribed, mfrom, mto);
++ add_header(&req, "Content-Type", subscriptiontype->mediatype);
++ p->dialogver++;
++ break;
++ case NONE:
++ default:
++ break;
++ }
++
+ add_header_contentLength(&req, tmp->used);
+ add_line(&req, tmp->str);
+
+@@ -10644,7 +11140,7 @@
+ channame += 4;
+ }
+
+- if (!(p = sip_alloc(NULL, NULL, 0, SIP_NOTIFY))) {
++ if (!(p = sip_alloc(NULL, NULL, 0, SIP_NOTIFY, NULL))) {
+ astman_send_error(s, m, "Unable to build sip pvt data for notify (memory/socket error)");
+ return 0;
+ }
+@@ -10662,7 +11158,7 @@
+ ast_set_flag(&p->flags[0], SIP_OUTGOING);
+
+ /* Recalculate our side, and recalculate Call ID */
+- ast_sip_ouraddrfor(&p->sa.sin_addr, &p->ourip);
++ ast_sip_ouraddrfor(&p->sa.sin_addr, &p->ourip, p);
+ build_via(p);
+ ao2_t_unlink(dialogs, p, "About to change the callid -- remove the old name");
+ build_callid_pvt(p);
+@@ -10679,15 +11175,85 @@
+ return 0;
+ }
+
+-static char mandescr_sipnotify[] =
+-"Description: Sends a SIP Notify event\n"
+-"All parameters for this event must be specified in the body of this request\n"
+-"via multiple Variable: name=value sequences.\n"
+-"Variables: \n"
+-" *Channel: <peername> Peer to receive the notify. Required.\n"
+-" *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);
++ p->invitestate = INV_CALLING;
++ send_request(p, &req, XMIT_CRITICAL, p->ocseq);
++ } else if (is_method_allowed(&p->allowed_methods, SIP_UPDATE)) {
++ reqprep(&req, p, SIP_UPDATE, 0, 1);
++ add_rpid(&req, p);
++ add_header(&req, "X-Asterisk-rpid-update", "Yes");
++ add_header_contentLength(&req, 0);
++ send_request(p, &req, XMIT_CRITICAL, p->ocseq);
++ } else {
++ /* We cannot send the update yet, so we have to wait until we can */
++ ast_set_flag(&p->flags[0], SIP_NEEDREINVITE);
++ }
++ } 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"},
+@@ -10715,7 +11281,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)
+@@ -10730,7 +11296,7 @@
+
+ r->expire = -1;
+ __sip_do_register(r);
+- registry_unref(r, "unreg the re-registered");
++ registry_unref(r, "unref the re-register scheduled event");
+ return 0;
+ }
+
+@@ -10849,7 +11415,7 @@
+ r->callid_valid = TRUE;
+ }
+ /* Allocate SIP dialog for registration */
+- if (!(p = sip_alloc( r->callid, NULL, 0, SIP_REGISTER))) {
++ if (!(p = sip_alloc( r->callid, NULL, 0, SIP_REGISTER, NULL))) {
+ ast_log(LOG_WARNING, "Unable to allocate registration transaction (memory or socket error)\n");
+ return 0;
+ }
+@@ -10916,7 +11482,7 @@
+ ast_string_field_set(p, exten, r->callback);
+
+ /* Set transport and port so the correct contact is built */
+- p->socket.type = r->transport;
++ set_socket_transport(&p->socket, r->transport);
+ if (r->transport == SIP_TRANSPORT_TLS || r->transport == SIP_TRANSPORT_TCP) {
+ p->socket.port = sip_tcp_desc.local_address.sin_port;
+ }
+@@ -10926,7 +11492,7 @@
+ based on whether the remote host is on the external or
+ internal network so we can register through nat
+ */
+- ast_sip_ouraddrfor(&p->sa.sin_addr, &p->ourip);
++ ast_sip_ouraddrfor(&p->sa.sin_addr, &p->ourip, p);
+ build_contact(p);
+ }
+
+@@ -11248,19 +11814,20 @@
+ ast_update_realtime(tablename, "name", peer->name, "fullcontact", "", "ipaddr", "", "port", "", "regseconds", "0", peer->deprecated_username ? "username" : "defaultuser", "", "regserver", "", "useragent", "", "lastms", "", SENTINEL);
+ } else {
+ ast_db_del("SIP/Registry", peer->name);
++ ast_db_del("SIP/PeerMethods", peer->name);
+ }
+ }
+ }
+
+-static void set_peer_transport(struct sip_peer *peer, int transport)
++static void set_socket_transport(struct sip_socket *socket, int transport)
+ {
+ /* if the transport type changes, clear all socket data */
+- if (peer->socket.type != transport) {
+- peer->socket.type = transport;
+- peer->socket.fd = -1;
+- if (peer->socket.tcptls_session) {
+- ao2_ref(peer->socket.tcptls_session, -1);
+- peer->socket.tcptls_session = NULL;
++ if (socket->type != transport) {
++ socket->fd = -1;
++ socket->type = transport;
++ if (socket->tcptls_session) {
++ ao2_ref(socket->tcptls_session, -1);
++ socket->tcptls_session = NULL;
+ }
+ }
+ }
+@@ -11277,11 +11844,12 @@
+ memset(&peer->addr, 0, sizeof(peer->addr));
+
+ destroy_association(peer); /* remove registration data from storage */
+- set_peer_transport(peer, peer->default_outbound_transport);
++ set_socket_transport(&peer->socket, peer->default_outbound_transport);
+
+ manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "ChannelType: SIP\r\nPeer: SIP/%s\r\nPeerStatus: Unregistered\r\nCause: Expired\r\n", peer->name);
+ register_peer_exten(peer, FALSE); /* Remove regexten */
+ ast_devstate_changed(AST_DEVICE_UNKNOWN, "SIP/%s", peer->name);
++ peer->allowed_methods = SIP_UNKNOWN;
+
+ /* Do we need to release this peer from memory?
+ Only for realtime peers and autocreated peers
+@@ -11324,11 +11892,13 @@
+ int expire;
+ int port;
+ char *scan, *addr, *port_str, *expiry_str, *username, *contact;
++ char allowed_methods_str[256] = "";
+
+ if (peer->rt_fromcontact)
+ return;
+ if (ast_db_get("SIP/Registry", peer->name, data, sizeof(data)))
+ return;
++ ast_db_get("SIP/PeerMethods", peer->name, allowed_methods_str, sizeof(allowed_methods_str));
+
+ scan = data;
+ addr = strsep(&scan, ":");
+@@ -11355,6 +11925,10 @@
+ if (contact)
+ ast_string_field_set(peer, fullcontact, contact);
+
++ if (!ast_strlen_zero(allowed_methods_str)) {
++ peer->allowed_methods = atoi(allowed_methods_str);
++ }
++
+ 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);
+
+@@ -11524,7 +12098,7 @@
+ } else if (!strcasecmp(curi, "*") || !expire) { /* Unregister this peer */
+ /* This means remove all registrations and return OK */
+ memset(&peer->addr, 0, sizeof(peer->addr));
+- set_peer_transport(peer, peer->default_outbound_transport);
++ set_socket_transport(&peer->socket, peer->default_outbound_transport);
+
+ AST_SCHED_DEL_UNREF(sched, peer->expire,
+ unref_peer(peer, "remove register expire ref"));
+@@ -11579,7 +12153,7 @@
+ * transport type, change it. If it got this far, it is a
+ * supported type, but check just in case */
+ if ((peer->socket.type != transport_type) && (peer->transports & transport_type)) {
+- set_peer_transport(peer, transport_type);
++ set_socket_transport(&peer->socket, transport_type);
+ }
+
+ oldsin = peer->addr;
+@@ -11712,8 +12286,8 @@
+ int len;
+ const char *rr, *contact, *c;
+
+- /* Once a persistant route is set, don't fool with it */
+- if (p->route && p->route_persistant) {
++ /* Once a persistent route is set, don't fool with it */
++ if (p->route && p->route_persistent) {
+ ast_debug(1, "build_route: Retaining previous route: <%s>\n", p->route->hop);
+ return;
+ }
+@@ -11724,7 +12298,7 @@
+ }
+
+ /* We only want to create the route set the first time this is called */
+- p->route_persistant = 1;
++ p->route_persistent = 1;
+
+ /* Build a tailq, then assign it to p->route when done.
+ * If backwards, we add entries from the head so they end up
+@@ -11817,7 +12391,7 @@
+ */
+ static enum check_auth_result check_auth(struct sip_pvt *p, struct sip_request *req, const char *username,
+ const char *secret, const char *md5secret, int sipmethod,
+- char *uri, enum xmittype reliable, int ignore)
++ const char *uri, enum xmittype reliable, int ignore)
+ {
+ const char *response;
+ char *reqheader, *respheader;
+@@ -12182,15 +12756,16 @@
+ - Registration requests are only matched with peers that are marked as "dynamic"
+ */
+ static enum check_auth_result register_verify(struct sip_pvt *p, struct sockaddr_in *sin,
+- struct sip_request *req, char *uri)
++ struct sip_request *req, const char *uri)
+ {
+ enum check_auth_result res = AUTH_NOT_FOUND;
+ struct sip_peer *peer;
+ char tmp[256];
+ char *name, *c;
+ char *domain;
++ char *uri2 = ast_strdupa(uri);
+
+- terminate_uri(uri); /* warning, overwrite the string */
++ terminate_uri(uri2);
+
+ ast_copy_string(tmp, get_header(req, "To"), sizeof(tmp));
+ if (sip_cfg.pedanticsipchecking)
+@@ -12242,12 +12817,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);
+- p->autoframing = peer->autoframing;
+- }
++ ao2_lock(peer);
+ 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;
+@@ -12255,7 +12825,7 @@
+ ast_copy_flags(&p->flags[0], &peer->flags[0], SIP_NAT);
+ if (ast_test_flag(&p->flags[1], SIP_PAGE2_REGISTERTRYING))
+ transmit_response(p, "100 Trying", req);
+- if (!(res = check_auth(p, req, peer->name, peer->secret, peer->md5secret, SIP_REGISTER, uri, XMIT_UNRELIABLE, req->ignore))) {
++ if (!(res = check_auth(p, req, peer->name, peer->secret, peer->md5secret, SIP_REGISTER, uri2, XMIT_UNRELIABLE, req->ignore))) {
+ if (sip_cancel_destroy(p))
+ ast_log(LOG_WARNING, "Unable to cancel SIP destruction. Expect bad things.\n");
+
+@@ -12292,6 +12862,7 @@
+
+ }
+ }
++ ao2_unlock(peer);
+ }
+ if (!peer && sip_cfg.autocreatepeer) {
+ /* Create peer if we have autocreate mode enabled */
+@@ -12301,7 +12872,7 @@
+ if (peer->addr.sin_addr.s_addr) {
+ ao2_t_link(peers_by_ip, peer, "link peer into peers-by-ip table");
+ }
+-
++ ao2_lock(peer);
+ if (sip_cancel_destroy(p))
+ ast_log(LOG_WARNING, "Unable to cancel SIP destruction. Expect bad things.\n");
+ switch (parse_register_contact(p, peer, req)) {
+@@ -12324,6 +12895,7 @@
+ res = 0;
+ break;
+ }
++ ao2_unlock(peer);
+ }
+ }
+ if (!peer && sip_cfg.alwaysauthreject) {
+@@ -12386,8 +12958,19 @@
+ break;
+ }
+ }
+- if (peer)
++ if (peer) {
++ ao2_lock(peer);
++ if (peer->allowed_methods == SIP_UNKNOWN) {
++ peer->allowed_methods = set_pvt_allowed_methods(p, req);
++ }
++ if (!peer->rt_fromcontact) {
++ char allowed_methods_str[256];
++ snprintf(allowed_methods_str, sizeof(allowed_methods_str), "%u", peer->allowed_methods);
++ ast_db_put("SIP/PeerMethods", peer->name, allowed_methods_str);
++ }
++ ao2_unlock(peer);
+ unref_peer(peer, "register_verify: unref_peer: tossing stack peer pointer at end of func");
++ }
+
+ return res;
+ }
+@@ -12422,23 +13005,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)) {
+@@ -12457,16 +13216,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);
+ }
+ }
+ }
+@@ -12474,14 +13233,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;
+ }
+
+@@ -13093,58 +13871,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);
+@@ -13195,7 +13927,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;
+ }
+
+@@ -13208,7 +13940,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);
+@@ -13217,6 +13948,12 @@
+ 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->allowed_methods == SIP_UNKNOWN) {
++ set_pvt_allowed_methods(p, req);
++ } else {
++ p->allowed_methods = peer->allowed_methods;
++ }
+ if (peer->callingpres) /* Peer calling pres setting will override RPID */
+ p->callingpres = peer->callingpres;
+ if (peer->maxms && peer->lastms)
+@@ -13260,14 +13997,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);
+@@ -13284,17 +14025,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;
+@@ -13303,6 +14033,14 @@
+ p->jointnoncodeccapability = p->noncodeccapability;
+ if (p->t38.peercapability)
+ p->t38.jointcapability &= p->t38.peercapability;
++ if (!dialog_initialize_rtp(p)) {
++ if (p->rtp) {
++ 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;
+@@ -13315,15 +14053,13 @@
+ \return 0 on success, non-zero on failure
+ */
+ static enum check_auth_result check_user_full(struct sip_pvt *p, struct sip_request *req,
+- int sipmethod, char *uri, enum xmittype reliable,
++ int sipmethod, const char *uri, enum xmittype reliable,
+ struct sockaddr_in *sin, struct sip_peer **authpeer)
+ {
+ char from[256];
+ 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);
+@@ -13339,11 +14075,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;
+@@ -13417,14 +14148,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
+@@ -13441,7 +14176,7 @@
+ /*! \brief Find user
+ If we get a match, this will add a reference pointer to the user object in ASTOBJ, that needs to be unreferenced
+ */
+-static int check_user(struct sip_pvt *p, struct sip_request *req, int sipmethod, char *uri, enum xmittype reliable, struct sockaddr_in *sin)
++static int check_user(struct sip_pvt *p, struct sip_request *req, int sipmethod, const char *uri, enum xmittype reliable, struct sockaddr_in *sin)
+ {
+ return check_user_full(p, req, sipmethod, uri, reliable, sin, NULL);
+ }
+@@ -13458,7 +14193,7 @@
+ if (y < 0)
+ y = 0;
+ for (x = 0; x < req->lines; x++) {
+- char *line = REQ_OFFSET_TO_STR(req, line[x]);
++ const char *line = REQ_OFFSET_TO_STR(req, line[x]);
+ strncat(buf, line, y); /* safe */
+ y -= strlen(line) + 1;
+ if (y < 0)
+@@ -13577,7 +14312,7 @@
+ return "strict";
+ }
+
+-static struct _map_x_s natmodes[] = {
++static const struct _map_x_s natmodes[] = {
+ { SIP_NAT_NEVER, "No"},
+ { SIP_NAT_ROUTE, "Route"},
+ { SIP_NAT_ALWAYS, "Always"},
+@@ -13596,7 +14331,7 @@
+ delete it. Keeping it enabled generates compiler warnings.
+ */
+
+-static struct _map_x_s natcfgmodes[] = {
++static const struct _map_x_s natcfgmodes[] = {
+ { SIP_NAT_NEVER, "never"},
+ { SIP_NAT_ROUTE, "route"},
+ { SIP_NAT_ALWAYS, "yes"},
+@@ -13617,7 +14352,7 @@
+
+
+ /* Session-Timer Modes */
+-static struct _map_x_s stmodes[] = {
++static const struct _map_x_s stmodes[] = {
+ { SESSION_TIMER_MODE_ACCEPT, "Accept"},
+ { SESSION_TIMER_MODE_ORIGINATE, "Originate"},
+ { SESSION_TIMER_MODE_REFUSE, "Refuse"},
+@@ -13635,7 +14370,7 @@
+ }
+
+ /* Session-Timer Refreshers */
+-static struct _map_x_s strefreshers[] = {
++static const struct _map_x_s strefreshers[] = {
+ { SESSION_TIMER_REFRESHER_AUTO, "auto"},
+ { SESSION_TIMER_REFRESHER_UAC, "uac"},
+ { SESSION_TIMER_REFRESHER_UAS, "uas"},
+@@ -13793,14 +14528,6 @@
+ #undef FORMAT
+ }
+
+-/*! \brief Manager Action SIPShowRegistry description */
+-static char mandescr_show_registry[] =
+-"Description: Lists all registration requests and status\n"
+-"Registrations will follow as separate events. followed by a final event called\n"
+-"RegistrationsComplete.\n"
+-"Variables: \n"
+-" ActionID: <id> Action ID for this transaction. Will be returned.\n";
+-
+ /*! \brief Show SIP registrations in the manager API */
+ static int manager_show_registry(struct mansession *s, const struct message *m)
+ {
+@@ -13839,13 +14566,6 @@
+ return 0;
+ }
+
+-static char mandescr_show_peers[] =
+-"Description: Lists SIP peers in text format with details on current status.\n"
+-"Peerlist will follow as separate events, followed by a final event called\n"
+-"PeerlistComplete.\n"
+-"Variables: \n"
+-" ActionID: <id> Action ID for this transaction. Will be returned.\n";
+-
+ /*! \brief Show SIP peers in the manager API */
+ /* Inspired from chan_iax2 */
+ static int manager_sip_show_peers(struct mansession *s, const struct message *m)
+@@ -14075,10 +14795,10 @@
+ {
+ struct sip_peer *peer = userobj;
+ int refc = ao2_t_ref(userobj, 0, "");
+- int *fd = arg;
++ struct ast_cli_args *a = (struct ast_cli_args *) arg;
+
+- ast_cli(*fd, "name: %s\ntype: peer\nobjflags: %d\nrefcount: %d\n\n",
+- peer->name, 0, refc);
++ ast_cli(a->fd, "name: %s\ntype: peer\nobjflags: %d\nrefcount: %d\n\n",
++ peer->name, 0, refc);
+ return 0;
+ }
+
+@@ -14086,10 +14806,10 @@
+ {
+ struct sip_pvt *pvt = userobj;
+ int refc = ao2_t_ref(userobj, 0, "");
+- int *fd = arg;
++ struct ast_cli_args *a = (struct ast_cli_args *) arg;
+
+- ast_cli(*fd, "name: %s\ntype: dialog\nobjflags: %d\nrefcount: %d\n\n",
+- pvt->callid, 0, refc);
++ ast_cli(a->fd, "name: %s\ntype: dialog\nobjflags: %d\nrefcount: %d\n\n",
++ pvt->callid, 0, refc);
+ return 0;
+ }
+
+@@ -14113,22 +14833,22 @@
+ if (a->argc != 3)
+ return CLI_SHOWUSAGE;
+ ast_cli(a->fd, "-= Peer objects: %d static, %d realtime, %d autocreate =-\n\n", speerobjs, rpeerobjs, apeerobjs);
+- ao2_t_callback(peers, OBJ_NODATA, peer_dump_func, &a->fd, "initiate ao2_callback to dump peers");
++ ao2_t_callback(peers, OBJ_NODATA, peer_dump_func, a, "initiate ao2_callback to dump peers");
+ ast_cli(a->fd, "-= Registry objects: %d =-\n\n", regobjs);
+ ASTOBJ_CONTAINER_DUMP(a->fd, tmp, sizeof(tmp), &regl);
+ ast_cli(a->fd, "-= Dialog objects:\n\n");
+- ao2_t_callback(dialogs, OBJ_NODATA, dialog_dump_func, &a->fd, "initiate ao2_callback to dump dialogs");
++ ao2_t_callback(dialogs, OBJ_NODATA, dialog_dump_func, a, "initiate ao2_callback to dump dialogs");
+ return CLI_SUCCESS;
+ }
+ /*! \brief Print call group and pickup group */
+-static void print_group(int fd, ast_group_t group, int crlf)
++static void print_group(int fd, ast_group_t group, int crlf)
+ {
+ char buf[256];
+ ast_cli(fd, crlf ? "%s\r\n" : "%s\n", ast_print_group(buf, sizeof(buf), group) );
+ }
+
+ /*! \brief mapping between dtmf flags and strings */
+-static struct _map_x_s dtmfstr[] = {
++static const struct _map_x_s dtmfstr[] = {
+ { SIP_DTMF_RFC2833, "rfc2833" },
+ { SIP_DTMF_INFO, "info" },
+ { SIP_DTMF_SHORTINFO, "shortinfo" },
+@@ -14149,7 +14869,7 @@
+ return map_s_x(dtmfstr, str, -1);
+ }
+
+-static struct _map_x_s insecurestr[] = {
++static const struct _map_x_s insecurestr[] = {
+ { SIP_INSECURE_PORT, "port" },
+ { SIP_INSECURE_INVITE, "invite" },
+ { SIP_INSECURE_PORT | SIP_INSECURE_INVITE, "port,invite" },
+@@ -14211,7 +14931,20 @@
+ * that we can wait for the next time around. */
+ 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);
+
+@@ -14220,13 +14953,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;
+@@ -14259,10 +14992,10 @@
+ struct sip_peer *peer, *pi;
+ int prunepeer = FALSE;
+ int multi = FALSE;
+- char *name = NULL;
++ const char *name = NULL;
+ regex_t regexbuf;
+ struct ao2_iterator i;
+- static char *choices[] = { "all", "like", NULL };
++ static const char * const choices[] = { "all", "like", NULL };
+ char *cmplt;
+
+ if (cmd == CLI_INIT) {
+@@ -14451,12 +15184,6 @@
+ }
+ #undef FORMAT
+
+-static char mandescr_show_peer[] =
+-"Description: Show one SIP peer with details on current status.\n"
+-"Variables: \n"
+-" Peer: <name> The peer name you want to check.\n"
+-" ActionID: <id> Optional action ID for this AMI transaction.\n";
+-
+ /*! \brief Show SIP peers in the manager API */
+ static int manager_sip_show_peer(struct mansession *s, const struct message *m)
+ {
+@@ -14716,6 +15443,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 */
+@@ -14763,6 +15491,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)));
+@@ -14895,6 +15624,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);
+@@ -15051,11 +15781,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;
+@@ -15069,10 +15798,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;
+@@ -15082,21 +15810,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++;
+
+@@ -16009,14 +16737,14 @@
+ }
+
+ /*! \brief Enable SIP Debugging for a single IP */
+-static char *sip_do_debug_ip(int fd, char *arg)
++static char *sip_do_debug_ip(int fd, const char *arg)
+ {
+ struct hostent *hp;
+ struct ast_hostent ahp;
+ int port = 0;
+ char *p;
+
+- p = arg;
++ p = ast_strdupa(arg);
+ strsep(&p, ":");
+ if (p)
+ port = atoi(p);
+@@ -16038,7 +16766,7 @@
+ }
+
+ /*! \brief Turn on SIP debugging for a given peer */
+-static char *sip_do_debug_peer(int fd, char *arg)
++static char *sip_do_debug_peer(int fd, const char *arg)
+ {
+ struct sip_peer *peer = find_peer(arg, NULL, TRUE, FINDPEERS, FALSE);
+ if (!peer)
+@@ -16062,7 +16790,7 @@
+ static char *sip_do_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+ {
+ int oldsipdebug = sipdebug & sip_debug_console;
+- char *what;
++ const char *what;
+
+ if (cmd == CLI_INIT) {
+ e->command = "sip set debug {on|off|ip|peer}";
+@@ -16137,7 +16865,7 @@
+ for (i = 3; i < a->argc; i++) {
+ struct sip_pvt *p;
+
+- if (!(p = sip_alloc(NULL, NULL, 0, SIP_NOTIFY))) {
++ if (!(p = sip_alloc(NULL, NULL, 0, SIP_NOTIFY, NULL))) {
+ ast_log(LOG_WARNING, "Unable to build sip pvt data for notify (memory/socket error)\n");
+ return CLI_FAILURE;
+ }
+@@ -16155,7 +16883,7 @@
+ ast_set_flag(&p->flags[0], SIP_OUTGOING);
+
+ /* Recalculate our side, and recalculate Call ID */
+- ast_sip_ouraddrfor(&p->sa.sin_addr, &p->ourip);
++ ast_sip_ouraddrfor(&p->sa.sin_addr, &p->ourip, p);
+ build_via(p);
+ ao2_t_unlink(dialogs, p, "About to change the callid -- remove the old name");
+ build_callid_pvt(p);
+@@ -16639,29 +17367,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;
+@@ -16669,66 +17518,84 @@
+ 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);
+ p->socket.tcptls_session = NULL;
+ }
+
+- p->socket.fd = -1;
+- p->socket.type = transport;
++ set_socket_transport(&p->socket, 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 */
+@@ -16781,9 +17648,23 @@
+ return 0;
+ }
+
++/*!
++ * \brief Handle authentication challenge for SIP UPDATE
++ *
++ * This function is only called upon the receipt of a 401/407 response to an UPDATE.
++ */
++static void handle_response_update(struct sip_pvt *p, int resp, const char *rest, struct sip_request *req, int seqno)
++{
++ if (p->options) {
++ p->options->auth_type = (resp == 401 ? WWW_AUTH : PROXY_AUTH);
++ }
++ if ((p->authtries == MAX_AUTHTRIES) || do_proxy_auth(p, req, resp, SIP_UPDATE, 1)) {
++ ast_log(LOG_NOTICE, "Failed to authenticate on UPDATE to '%s'\n", get_header(&p->initreq, "From"));
++ }
++}
+
+ /*! \brief Handle SIP response to INVITE dialogue */
+-static void handle_response_invite(struct sip_pvt *p, int resp, char *rest, struct sip_request *req, int seqno)
++static void handle_response_invite(struct sip_pvt *p, int resp, const char *rest, struct sip_request *req, int seqno)
+ {
+ int outgoing = ast_test_flag(&p->flags[0], SIP_OUTGOING);
+ int res = 0;
+@@ -16791,12 +17672,28 @@
+ 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
+ ast_debug(4, "SIP response %d to standard invite\n", resp);
+
++ /* If this is a response to our initial INVITE, we need to set what we can use
++ * for this peer.
++ */
++ if (!reinvite && p->allowed_methods == SIP_UNKNOWN) {
++ struct sip_peer *peer = find_peer(p->peername, NULL, 1, FINDPEERS, FALSE);
++ if (!peer || peer->allowed_methods == SIP_UNKNOWN) {
++ set_pvt_allowed_methods(p, req);
++ } else {
++ p->allowed_methods = peer->allowed_methods;
++ }
++ if (peer) {
++ unref_peer(peer, "handle_response_invite: Getting supported methods from peer");
++ }
++ }
++
+ if (p->alreadygone) { /* This call is already gone */
+ ast_debug(1, "Got response on call that is already terminated: %s (ignoring)\n", p->callid);
+ return;
+@@ -16809,7 +17706,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 */
+@@ -16837,6 +17734,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);
+@@ -16854,10 +17759,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;
+@@ -16879,9 +17806,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) || !reinvite)) {
++ /* 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 */
+@@ -17043,7 +17980,7 @@
+ 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);
+@@ -17082,6 +18019,7 @@
+ }
+ break;
+
++ case 405: /* Not allowed */
+ case 501: /* Not implemented */
+ xmitres = transmit_request(p, SIP_ACK, seqno, XMIT_UNRELIABLE, FALSE);
+ if (p->owner)
+@@ -17095,7 +18033,7 @@
+ /* \brief Handle SIP response in NOTIFY transaction
+ We've sent a NOTIFY, now handle responses to it
+ */
+-static void handle_response_notify(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, const char *rest, struct sip_request *req, int seqno)
+ {
+ switch (resp) {
+ case 200: /* Notify accepted */
+@@ -17138,8 +18076,9 @@
+ }
+
+ /* \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)
++static void handle_response_subscribe(struct sip_pvt *p, int resp, const char *rest, struct sip_request *req, int seqno)
+ {
++ struct sip_peer *peer;
+ if (!p->mwi) {
+ return;
+ }
+@@ -17147,6 +18086,15 @@
+ switch (resp) {
+ case 200: /* Subscription accepted */
+ ast_debug(3, "Got 200 OK on subscription for MWI\n");
++ peer = find_peer(p->peername, NULL, 1, FINDPEERS, FALSE);
++ if (!peer || peer->allowed_methods == SIP_UNKNOWN) {
++ set_pvt_allowed_methods(p, req);
++ } else {
++ p->allowed_methods = peer->allowed_methods;
++ }
++ if (peer) {
++ unref_peer(peer, "handle_response_subscribe: Getting supported methods");
++ }
+ if (p->options) {
+ ast_free(p->options);
+ p->options = NULL;
+@@ -17199,8 +18147,10 @@
+ /* \brief Handle SIP response in REFER transaction
+ We've sent a REFER, now handle responses to it
+ */
+-static void handle_response_refer(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, const 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;
+@@ -17220,14 +18170,32 @@
+ 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 405: /* Method not allowed */
++ /* Return to the current call onhold */
++ /* Status flag needed to be reset */
++ ast_log(LOG_NOTICE, "SIP transfer to %s failed, REFER not allowed. \n", p->refer->refer_to);
++ pvt_set_needdestroy(p, "received 405 response");
++ p->refer->status = REFER_FAILED;
++ if (p->owner) {
++ ast_queue_control_data(p->owner, AST_CONTROL_TRANSFER, &message, sizeof(message));
++ }
++ break;
++
+ case 481: /* Call leg does not exist */
+
+ /* A transfer with Replaces did not work */
+@@ -17246,17 +18214,23 @@
+ 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;
+ }
+ }
+
+ /*! \brief Handle responses on REGISTER to services */
+-static int handle_response_register(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, const char *rest, struct sip_request *req, int seqno)
+ {
+ int expires, expires_ms;
+ struct sip_registry *r;
+@@ -17271,7 +18245,7 @@
+ 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);
++ AST_SCHED_DEL_UNREF(sched, r->timeout, registry_unref(r, "reg ptr unref from handle_response_register 403"));
+ r->regstate = REG_STATE_NOAUTH;
+ pvt_set_needdestroy(p, "received 403 response");
+ break;
+@@ -17281,7 +18255,7 @@
+ if (r->call)
+ r->call = dialog_unref(r->call, "unsetting registry->call pointer-- case 404");
+ r->regstate = REG_STATE_REJECTED;
+- AST_SCHED_DEL(sched, r->timeout);
++ AST_SCHED_DEL_UNREF(sched, r->timeout, registry_unref(r, "reg ptr unref from handle_response_register 404"));
+ break;
+ case 407: /* Proxy auth */
+ if (p->authtries == MAX_AUTHTRIES || do_register_auth(p, req, resp)) {
+@@ -17300,8 +18274,7 @@
+ case 423: /* Interval too brief */
+ r->expiry = atoi(get_header(req, "Min-Expires"));
+ ast_log(LOG_WARNING, "Got 423 Interval too brief for service %s@%s, minimum is %d seconds\n", p->registry->username, p->registry->hostname, r->expiry);
+- AST_SCHED_DEL(sched, r->timeout);
+- r->timeout = -1;
++ AST_SCHED_DEL_UNREF(sched, r->timeout, registry_unref(r, "reg ptr unref from handle_response_register 423"));
+ if (r->call) {
+ r->call = dialog_unref(r->call, "unsetting registry->call pointer-- case 423");
+ pvt_set_needdestroy(p, "received 423 response");
+@@ -17322,7 +18295,7 @@
+ if (r->call)
+ r->call = dialog_unref(r->call, "unsetting registry->call pointer-- case 479");
+ r->regstate = REG_STATE_REJECTED;
+- AST_SCHED_DEL(sched, r->timeout);
++ AST_SCHED_DEL_UNREF(sched, r->timeout, registry_unref(r, "reg ptr unref from handle_response_register 479"));
+ break;
+ case 200: /* 200 OK */
+ if (!r) {
+@@ -17339,7 +18312,7 @@
+ if (r->timeout > -1) {
+ ast_debug(1, "Cancelling timeout %d\n", r->timeout);
+ }
+- AST_SCHED_DEL(sched, r->timeout);
++ AST_SCHED_DEL_UNREF(sched, r->timeout, registry_unref(r, "reg ptr unref from handle_response_register 200"));
+ if (r->call)
+ r->call = dialog_unref(r->call, "unsetting registry->call pointer-- case 200");
+ p->registry = registry_unref(p->registry, "unref registry entry p->registry");
+@@ -17347,14 +18320,12 @@
+ sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
+ /* p->needdestroy = 1; */
+
+- /* set us up for re-registering */
+- /* figure out how long we got registered for */
+- AST_SCHED_DEL(sched, r->expire);
+-
+- /* according to section 6.13 of RFC, contact headers override
+- expires headers, so check those first */
++ /* set us up for re-registering
++ * figure out how long we got registered for
++ * according to section 6.13 of RFC, contact headers override
++ * expires headers, so check those first */
+ expires = 0;
+-
++
+ /* XXX todo: try to save the extra call */
+ if (!ast_strlen_zero(get_header(req, "Contact"))) {
+ const char *contact = NULL;
+@@ -17398,9 +18369,6 @@
+ registry_unref(_data,"unref in REPLACE del fail"),
+ registry_unref(r,"unref in REPLACE add fail"),
+ registry_addref(r,"The Addition side of REPLACE"));
+- /* it is clear that we would not want to destroy the registry entry if we just
+- scheduled a callback and recorded it in there! */
+- /* since we never bumped the count, we shouldn't decrement it! registry_unref(r, "unref registry ptr r"); if this gets deleted, p->registry will be a bad pointer! */
+ }
+ return 1;
+ }
+@@ -17445,6 +18413,12 @@
+ 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) {
++ peer->allowed_methods = SIP_UNKNOWN;
++ } else {
++ set_pvt_allowed_methods(p, req);
++ peer->allowed_methods = p->allowed_methods;
++ }
+ if (is_reachable && sip_cfg.regextenonqualify)
+ register_peer_exten(peer, TRUE);
+ }
+@@ -17465,18 +18439,18 @@
+ {
+ /* 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);
+ }
+
+ /*! \brief Handle SIP response in dialogue
+ \note only called by handle_incoming */
+-static void handle_response(struct sip_pvt *p, int resp, char *rest, struct sip_request *req, int seqno)
++static void handle_response(struct sip_pvt *p, int resp, const char *rest, struct sip_request *req, int seqno)
+ {
+ struct ast_channel *owner;
+ int sipmethod;
+@@ -17486,6 +18460,7 @@
+ char *c_copy = ast_strdupa(c);
+ /* Skip the Cseq and its subsequent spaces */
+ const char *msg = ast_skip_blanks(ast_skip_nonblanks(c_copy));
++ struct sip_peer *peer;
+
+ if (!msg)
+ msg = "";
+@@ -17546,6 +18521,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;
+@@ -17585,7 +18561,9 @@
+ 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) {
++ else if (sipmethod == SIP_UPDATE) {
++ handle_response_update(p, resp, rest, req, seqno);
++ } else if (sipmethod == SIP_BYE) {
+ if (p->options)
+ p->options->auth_type = resp;
+ if (ast_strlen_zero(p->authname)) {
+@@ -17684,7 +18662,13 @@
+ pvt_set_needdestroy(p, "received 491 response");
+ }
+ break;
++ case 405:
+ case 501: /* Not Implemented */
++ mark_method_unallowed(&p->allowed_methods, sipmethod);
++ if ((peer = find_peer(p->peername, 0, 1, FINDPEERS, FALSE))) {
++ peer->allowed_methods = p->allowed_methods;
++ unref_peer(peer, "handle_response: marking a specific method as unallowed");
++ }
+ if (sipmethod == SIP_INVITE)
+ handle_response_invite(p, resp, rest, req, seqno);
+ else if (sipmethod == SIP_REFER)
+@@ -17713,7 +18697,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 */
+@@ -18173,7 +19161,7 @@
+ }
+
+ /*! \brief Handle incoming notifications */
+-static int handle_request_notify(struct sip_pvt *p, struct sip_request *req, struct sockaddr_in *sin, int seqno, char *e)
++static int handle_request_notify(struct sip_pvt *p, struct sip_request *req, struct sockaddr_in *sin, int seqno, const char *e)
+ {
+ /* This is mostly a skeleton for future improvements */
+ /* Mostly created to return proper answers on notifications on outbound REFER's */
+@@ -18287,7 +19275,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")) {
+@@ -18405,7 +19397,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);
+@@ -18439,7 +19431,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);
+
+@@ -18839,13 +19831,44 @@
+ return 0;
+ }
+
+-/*! \brief Handle incoming INVITE request
+-\note If the INVITE has a Replaces header, it is part of an
++/*!
++ * \brief bare-bones support for SIP UPDATE
++ *
++ * XXX This is not even close to being RFC 3311-compliant. We don't advertise
++ * that we support the UPDATE method, so no one should ever try sending us
++ * an UPDATE anyway. However, Asterisk can send an UPDATE to change connected
++ * line information, so we need to be prepared to handle this. The way we distinguish
++ * such an UPDATE is through the X-Asterisk-rpid-update header.
++ *
++ * Actually updating the media session may be some future work.
++ */
++static int handle_request_update(struct sip_pvt *p, struct sip_request *req)
++{
++ if (ast_strlen_zero(get_header(req, "X-Asterisk-rpid-update"))) {
++ transmit_response(p, "501 Method Not Implemented", req);
++ return 0;
++ }
++ 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);
++ }
++ transmit_response(p, "200 OK", req);
++ 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)
++static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int debug, int seqno, struct sockaddr_in *sin, int *recount, const char *e, int *nounlock)
+ {
+ int res = 1;
+ int gotdest;
+@@ -18908,8 +19931,8 @@
+ /* If pedantic is on, we need to check the tags. If they're different, this is
+ in fact a forked call through a SIP proxy somewhere. */
+ int different;
+- char *initial_rlPart2 = REQ_OFFSET_TO_STR(&p->initreq, rlPart2);
+- char *this_rlPart2 = REQ_OFFSET_TO_STR(req, rlPart2);
++ const char *initial_rlPart2 = REQ_OFFSET_TO_STR(&p->initreq, rlPart2);
++ const char *this_rlPart2 = REQ_OFFSET_TO_STR(req, rlPart2);
+ if (sip_cfg.pedanticsipchecking)
+ different = sip_uri_cmp(initial_rlPart2, this_rlPart2);
+ else
+@@ -18961,19 +19984,19 @@
+ __sip_ack(p, p->lastinvite, 1, 0);
+ } else {
+ /* 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 */
++ p->glareinvite = seqno;
+ if (p->rtp && find_sdp(req)) {
+ struct sockaddr_in sin;
+ if (get_ip_and_port_from_sdp(req, SDP_AUDIO, &sin)) {
+ ast_log(LOG_WARNING, "Failed to set an alternate media source on glared reinvite. Audio may not work properly on this call.\n");
+ } else {
+- ast_rtp_set_alt_peer(p->rtp, &sin);
++ ast_rtp_instance_set_alt_remote_address(p->rtp, &sin);
+ }
+ if (p->vrtp) {
+ if (get_ip_and_port_from_sdp(req, SDP_VIDEO, &sin)) {
+ ast_log(LOG_WARNING, "Failed to set an alternate media source on glared reinvite. Video may not work properly on this call.\n");
+ } else {
+- ast_rtp_set_alt_peer(p->vrtp, &sin);
++ ast_rtp_instance_set_alt_remote_address(p->vrtp, &sin);
+ }
+ }
+ }
+@@ -19136,6 +20159,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)) {
+@@ -19158,6 +20191,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 */
+@@ -19220,13 +20254,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 */
+@@ -19264,9 +20298,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);
+@@ -19276,6 +20312,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 */
+@@ -19486,7 +20526,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;
+@@ -19528,7 +20567,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;
+@@ -19564,6 +20603,8 @@
+ /* Chan 2: Call from Asterisk to target */
+ int res = 0;
+ struct sip_pvt *targetcall_pvt;
++ struct ast_party_connected_line connected_to_transferee;
++ struct ast_party_connected_line connected_to_target;
+
+ /* Check if the call ID of the replaces header does exist locally */
+ if (!(targetcall_pvt = get_sip_pvt_byid_locked(transferer->refer->replaces_callid, transferer->refer->replaces_callid_totag,
+@@ -19631,6 +20672,13 @@
+ transferer->callid,
+ target.chan1->name,
+ target.chan1->uniqueid);
++ ast_party_connected_line_init(&connected_to_transferee);
++ ast_party_connected_line_init(&connected_to_target);
++ /* No need to lock current->chan1 here since it was locked in sipsock_read */
++ ast_party_connected_line_copy(&connected_to_transferee, &current->chan1->connected);
++ /* No need to lock target.chan1 here since it was locked in get_sip_pvt_byid_locked */
++ ast_party_connected_line_copy(&connected_to_target, &target.chan1->connected);
++ connected_to_target.source = connected_to_transferee.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER;
+ res = attempt_transfer(current, &target);
+ sip_pvt_unlock(targetcall_pvt);
+ if (res) {
+@@ -19655,7 +20703,30 @@
+ ast_debug(1, "SIP attended transfer: Unlocking channel %s\n", targetcall_pvt->owner->name);
+ ast_channel_unlock(targetcall_pvt->owner);
+ }
++
++ /* By forcing the masquerade, we know that target.chan1 and target.chan2 are bridged. We then
++ * can queue connected line updates where they need to go.
++ *
++ * No need to lock target.chan1 here since it was previously locked in get_sip_pvt_byid_locked
++ */
++ if (target.chan1->masq) {
++ /* If the channel thread already did the masquerade, then we don't need to do anything */
++ ast_do_masquerade(target.chan1);
++ }
++ if (target.chan2) {
++ ast_channel_queue_connected_line_update(target.chan1, &connected_to_transferee);
++ ast_channel_queue_connected_line_update(target.chan2, &connected_to_target);
++ } else {
++ /* Since target.chan1 isn't actually connected to another channel, there is no way for us
++ * to queue a frame so that its connected line status will be updated. Instead, we have to
++ * change it directly. Since we are not the channel thread, we cannot run a connected line
++ * interception macro on target.chan1
++ */
++ ast_channel_update_connected_line(target.chan1, &connected_to_target);
++ }
+ }
++ ast_party_connected_line_free(&connected_to_target);
++ ast_party_connected_line_free(&connected_to_transferee);
+ if (targetcall_pvt)
+ ao2_t_ref(targetcall_pvt, -1, "drop targetcall_pvt");
+ return 1;
+@@ -20040,6 +21111,30 @@
+ else
+ sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
+ if (p->initreq.len > 0) {
++ struct sip_pkt *pkt, *prev_pkt;
++ /* If the CANCEL we are receiving is a retransmission, and we already have scheduled
++ * a reliable 487, then we don't want to schedule another one on top of the previous
++ * one.
++ *
++ * As odd as this may sound, we can't rely on the previously-transmitted "reliable"
++ * response in this situation. What if we've sent all of our reliable responses
++ * already and now all of a sudden, we get this second CANCEL?
++ *
++ * The only way to do this correctly is to cancel our previously-scheduled reliably-
++ * transmitted response and send a new one in its place.
++ */
++ for (pkt = p->packets, prev_pkt = NULL; pkt; prev_pkt = pkt, pkt = pkt->next) {
++ if (pkt->seqno == p->lastinvite && pkt->response_code == 487) {
++ AST_SCHED_DEL(sched, pkt->retransid);
++ if (prev_pkt) {
++ prev_pkt->next = pkt->next;
++ } else {
++ p->packets = pkt->next;
++ }
++ ast_free(pkt);
++ break;
++ }
++ }
+ transmit_response_reliable(p, "487 Request Terminated", &p->initreq);
+ transmit_response(p, "200 OK", req);
+ return 1;
+@@ -20052,7 +21147,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);
+@@ -20069,6 +21164,10 @@
+
+ memset(buf, 0, buflen);
+
++ if (p == NULL) {
++ return -1;
++ }
++
+ if (!strcasecmp(args.param, "peerip")) {
+ ast_copy_string(buf, p->sa.sin_addr.s_addr ? ast_inet_ntoa(p->sa.sin_addr) : "", buflen);
+ } else if (!strcasecmp(args.param, "recvip")) {
+@@ -20090,61 +21189,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;
+@@ -20176,10 +21284,10 @@
+
+ /* Get RTCP quality before end of call */
+ if (p->do_history || p->owner) {
+- struct ast_channel *bridge = p->owner ? ast_bridged_channel(p->owner) : NULL;
+- char *videoqos, *textqos;
++ char quality_buf[AST_MAX_USER_FIELD], *quality;
++ struct ast_channel *bridge = p->owner ? ast_bridged_channel(p->owner) : NULL;
+
+- /* We need to get the lock on bridge because ast_rtp_set_vars will attempt
++ /* We need to get the lock on bridge because ast_rtp_instance_set_stats_vars will attempt
+ * to lock the bridge. This may get hairy...
+ */
+ while (bridge && ast_channel_trylock(bridge)) {
+@@ -20193,51 +21301,52 @@
+ bridge = p->owner ? ast_bridged_channel(p->owner) : NULL;
+ }
+
+- 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 && q->rtp)
+- ast_rtp_set_vars(bridge, q->rtp);
++ if (IS_SIP_TECH(bridge->tech) && q && q->rtp) {
++ ast_rtp_instance_set_stats_vars(bridge, q->rtp);
++ }
+ ast_channel_unlock(bridge);
+ }
+
+- 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);
++ }
+ }
+ }
+
+@@ -20304,7 +21413,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)
++static int handle_request_subscribe(struct sip_pvt *p, struct sip_request *req, struct sockaddr_in *sin, int seqno, const char *e)
+ {
+ int gotdest = 0;
+ int res = 0;
+@@ -20435,16 +21544,20 @@
+ make_our_tag(p->tag, sizeof(p->tag));
+
+ if (!strcmp(event, "presence") || !strcmp(event, "dialog")) { /* Presence, RFC 3842 */
++ unsigned int pidf_xml;
++
+ if (authpeer) /* We do not need the authpeer any more */
+ unref_peer(authpeer, "unref_peer, from handle_request_subscribe (authpeer 2)");
+
+ /* Header from Xten Eye-beam Accept: multipart/related, application/rlmi+xml, application/pidf+xml, application/xpidf+xml */
+- /* Polycom phones only handle xpidf+xml, even if they say they can
+- handle pidf+xml as well
+- */
+- if (strstr(p->useragent, "Polycom")) {
++
++ pidf_xml = strstr(acceptheader, "application/pidf+xml") ? 1 : 0;
++
++ /* Older versions of Polycom firmware will claim pidf+xml, but really
++ * they only support xpidf+xml. */
++ if (pidf_xml && strstr(p->useragent, "Polycom")) {
+ p->subscribed = XPIDF_XML;
+- } else if (strstr(acceptheader, "application/pidf+xml")) {
++ } else if (pidf_xml) {
+ p->subscribed = PIDF_XML; /* RFC 3863 format */
+ } else if (strstr(acceptheader, "application/dialog-info+xml")) {
+ p->subscribed = DIALOG_INFO_XML;
+@@ -20624,7 +21737,7 @@
+ }
+
+ /*! \brief Handle incoming REGISTER request */
+-static int handle_request_register(struct sip_pvt *p, struct sip_request *req, struct sockaddr_in *sin, char *e)
++static int handle_request_register(struct sip_pvt *p, struct sip_request *req, struct sockaddr_in *sin, const char *e)
+ {
+ enum check_auth_result res;
+
+@@ -20692,7 +21805,7 @@
+ int respid;
+ int res = 0;
+ int debug = sip_debug_test_pvt(p);
+- char *e;
++ const char *e;
+ int error = 0;
+
+ /* Get Method and Cseq */
+@@ -20734,10 +21847,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
+@@ -20869,6 +21982,9 @@
+ case SIP_NOTIFY:
+ res = handle_request_notify(p, req, sin, seqno, e);
+ break;
++ case SIP_UPDATE:
++ res = handle_request_update(p, req);
++ break;
+ case SIP_ACK:
+ /* Make sure we don't ignore this */
+ if (seqno == p->pendinginvite) {
+@@ -21029,8 +22145,8 @@
+ }
+
+ req.len = res;
+- req.socket.fd = sipsock;
+- req.socket.type = SIP_TRANSPORT_UDP;
++ req.socket.fd = sipsock;
++ set_socket_transport(&req.socket, SIP_TRANSPORT_UDP);
+ req.socket.tcptls_session = NULL;
+ req.socket.port = bindaddr.sin_port;
+
+@@ -21378,13 +22494,13 @@
+ p = dialog_ref(peer->mwipvt, "sip_send_mwi_to_peer: Setting dialog ptr p from peer->mwipvt-- should this be done?");
+ } else {
+ /* Build temporary dialog for this message */
+- if (!(p = sip_alloc(NULL, NULL, 0, SIP_NOTIFY)))
++ if (!(p = sip_alloc(NULL, NULL, 0, SIP_NOTIFY, NULL)))
+ return -1;
+ /* If we don't set the socket type to 0, then create_addr_from_peer will fail immediately if the peer
+ * uses any transport other than UDP. We set the type to 0 here and then let create_addr_from_peer copy
+ * the peer's socket information to the sip_pvt we just allocated
+ */
+- p->socket.type = 0;
++ set_socket_transport(&p->socket, 0);
+ if (create_addr_from_peer(p, peer)) {
+ /* Maybe they're not registered, etc. */
+ dialog_unlink_all(p, TRUE, TRUE);
+@@ -21393,10 +22509,15 @@
+ return 0;
+ }
+ /* Recalculate our side, and recalculate Call ID */
+- ast_sip_ouraddrfor(&p->sa.sin_addr, &p->ourip);
++ ast_sip_ouraddrfor(&p->sa.sin_addr, &p->ourip, p);
+ build_via(p);
+ ao2_t_unlink(dialogs, p, "About to change the callid -- remove the old name");
+ build_callid_pvt(p);
++ if (!ast_strlen_zero(peer->mwi_from)) {
++ ast_string_field_set(p, mwi_from, peer->mwi_from);
++ } else if (!ast_strlen_zero(default_mwi_from)) {
++ ast_string_field_set(p, mwi_from, default_mwi_from);
++ }
+ ao2_t_link(dialogs, p, "Linking in under new name");
+ /* Destroy this session after 32 secs */
+ sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
+@@ -21426,15 +22547,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
+@@ -21444,16 +22558,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);
+@@ -21468,11 +22576,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);
+ }
+ }
+ }
+@@ -21959,7 +23067,7 @@
+ peer->call = dialog_unref(peer->call, "unref dialog peer->call");
+ /* peer->call = sip_destroy(peer->call); */
+ }
+- if (!(p = sip_alloc(NULL, NULL, 0, SIP_OPTIONS))) {
++ if (!(p = sip_alloc(NULL, NULL, 0, SIP_OPTIONS, NULL))) {
+ return -1;
+ }
+ peer->call = dialog_ref(p, "copy sip alloc from p to peer->call");
+@@ -21980,7 +23088,7 @@
+ ast_string_field_set(p, tohost, ast_inet_ntoa(peer->addr.sin_addr));
+
+ /* Recalculate our side, and recalculate Call ID */
+- ast_sip_ouraddrfor(&p->sa.sin_addr, &p->ourip);
++ ast_sip_ouraddrfor(&p->sa.sin_addr, &p->ourip, p);
+ build_via(p);
+ ao2_t_unlink(dialogs, p, "About to change the callid -- remove the old name");
+ build_callid_pvt(p);
+@@ -22154,7 +23262,7 @@
+ }
+ ast_debug(1, "Asked to create a SIP channel with formats: %s\n", ast_getformatname_multiple(tmp, sizeof(tmp), oldformat));
+
+- if (!(p = sip_alloc(NULL, NULL, 0, SIP_INVITE))) {
++ if (!(p = sip_alloc(NULL, NULL, 0, SIP_INVITE, NULL))) {
+ ast_log(LOG_ERROR, "Unable to build sip pvt data for '%s' (Out of memory or socket error)\n", dest);
+ *cause = AST_CAUSE_SWITCH_CONGESTION;
+ return NULL;
+@@ -22223,8 +23331,7 @@
+ host = tmp;
+ }
+
+- p->socket.fd = -1;
+- p->socket.type = transport;
++ set_socket_transport(&p->socket, transport);
+
+ /* We now have
+ host = peer name, DNS host name or DNS domain (for SRV)
+@@ -22242,7 +23349,7 @@
+ if (ast_strlen_zero(p->peername) && ext)
+ ast_string_field_set(p, peername, ext);
+ /* Recalculate our side, and recalculate Call ID */
+- ast_sip_ouraddrfor(&p->sa.sin_addr, &p->ourip);
++ ast_sip_ouraddrfor(&p->sa.sin_addr, &p->ourip, p);
+ build_via(p);
+ ao2_t_unlink(dialogs, p, "About to change the callid -- remove the old name");
+ build_callid_pvt(p);
+@@ -22326,7 +23433,19 @@
+ 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_update")) {
++ ast_set_flag(&mask[1], SIP_PAGE2_RPID_UPDATE);
++ ast_set2_flag(&flags[1], ast_true(v->value), SIP_PAGE2_RPID_UPDATE);
++ } 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);
+@@ -22623,8 +23742,7 @@
+ peer->expire = -1;
+ peer->pokeexpire = -1;
+ peer->addr.sin_port = htons(STANDARD_SIP_PORT);
+- peer->socket.type = SIP_TRANSPORT_UDP;
+- peer->socket.fd = -1;
++ set_socket_transport(&peer->socket, SIP_TRANSPORT_UDP);
+ }
+ peer->type = SIP_TYPE_PEER;
+ ast_copy_flags(&peer->flags[0], &global_flags[0], SIP_FLAGS_TO_COPY);
+@@ -22634,6 +23752,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;
+@@ -22861,6 +23980,8 @@
+ 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, "mwi_from")) {
++ ast_string_field_set(peer, mwi_from, v->value);
+ } else if (!strcasecmp(v->name, "fullname")) {
+ ast_string_field_set(peer, cid_name, v->value);
+ } else if (!strcasecmp(v->name, "cid_number")) {
+@@ -22984,6 +24105,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")) {
+@@ -23010,6 +24133,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")) {
+@@ -23128,7 +24253,7 @@
+ if (((peer->socket.type != peer->default_outbound_transport) && (peer->expire == -1)) ||
+ !(peer->socket.type & peer->transports) || !(peer->socket.type)) {
+
+- set_peer_transport(peer, peer->default_outbound_transport);
++ set_socket_transport(&peer->socket, peer->default_outbound_transport);
+ }
+
+ if (fullcontact->used > 0) {
+@@ -23308,21 +24433,21 @@
+ /* First, destroy all outstanding registry calls */
+ /* This is needed, since otherwise active registry entries will not be destroyed */
+ ASTOBJ_CONTAINER_TRAVERSE(&regl, 1, do { /* regl is locked */
+-
+- /* avoid a deadlock in the unlink_all call, if iterator->call's (a dialog) registry entry
+- is this registry entry. In other words, if the dialog we are pointing to points back to
+- us, then if we get a lock on this object, and try to UNREF it, we will deadlock, because
+- we already ... NO. This is not the problem. */
++
+ ASTOBJ_RDLOCK(iterator); /* now regl is locked, and the object is also locked */
+ if (iterator->call) {
+ ast_debug(3, "Destroying active SIP dialog for registry %s@%s\n", iterator->username, iterator->hostname);
+ /* This will also remove references to the registry */
+ dialog_unlink_all(iterator->call, TRUE, TRUE);
+ iterator->call = dialog_unref(iterator->call, "remove iterator->call from registry traversal");
+- /* iterator->call = sip_destroy(iterator->call); */
+ }
++ if (iterator->expire > -1) {
++ AST_SCHED_DEL_UNREF(sched, iterator->expire, registry_unref(iterator, "reg ptr unref from reload config"));
++ }
++ if (iterator->timeout > -1) {
++ AST_SCHED_DEL_UNREF(sched, iterator->timeout, registry_unref(iterator, "reg ptr unref from reload config"));
++ }
+ ASTOBJ_UNLOCK(iterator);
+-
+ } while(0));
+
+ /* Then, actually destroy users and registry */
+@@ -23330,20 +24455,21 @@
+ ast_debug(4, "--------------- Done destroying registry list\n");
+ ao2_t_callback(peers, OBJ_NODATA, peer_markall_func, NULL, "callback to mark all peers");
+ }
+-
++
+ /* Reset certificate handling for TLS sessions */
+ if (reason != CHANNEL_MODULE_LOAD) {
+ ast_free(default_tls_cfg.certfile);
++ ast_free(default_tls_cfg.pvtfile);
+ ast_free(default_tls_cfg.cipher);
+ ast_free(default_tls_cfg.cafile);
+ ast_free(default_tls_cfg.capath);
+ }
+ default_tls_cfg.certfile = ast_strdup(AST_CERTFILE); /*XXX Not sure if this is useful */
++ default_tls_cfg.pvtfile = ast_strdup("");
+ 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));
+ oldregcontext = oldcontexts;
+@@ -23403,6 +24529,7 @@
+ ast_copy_string(default_notifymime, DEFAULT_NOTIFYMIME, sizeof(default_notifymime));
+ 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));
++ ast_copy_string(default_mwi_from, DEFAULT_MWI_FROM, sizeof(default_mwi_from));
+ sip_cfg.compactheaders = DEFAULT_COMPACTHEADERS;
+ global_reg_timeout = DEFAULT_REGISTRATION_TIMEOUT;
+ global_regattempts_max = 0;
+@@ -23444,6 +24571,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;
+@@ -23478,13 +24606,18 @@
+ if (!ast_jb_read_conf(&global_jbconf, v->name, v->value))
+ continue;
+
++ /* handle tls conf */
++ if (!ast_tls_read_conf(&default_tls_cfg, &sip_tls_desc, v->name, v->value)) {
++ continue;
++ }
++
+ if (!strcasecmp(v->name, "context")) {
+ ast_copy_string(sip_cfg.default_context, v->value, sizeof(sip_cfg.default_context));
+ } else if (!strcasecmp(v->name, "subscribecontext")) {
+ ast_copy_string(sip_cfg.default_subscribecontext, v->value, sizeof(sip_cfg.default_subscribecontext));
+- } else if (!strcasecmp(v->name, "callcounter")) {
++ } else if (!strcasecmp(v->name, "callcounter")) {
+ global_callcounter = ast_true(v->value) ? 1 : 0;
+- } else if (!strcasecmp(v->name, "allowguest")) {
++ } else if (!strcasecmp(v->name, "allowguest")) {
+ sip_cfg.allowguest = ast_true(v->value) ? 1 : 0;
+ } else if (!strcasecmp(v->name, "realm")) {
+ ast_copy_string(sip_cfg.realm, v->value, sizeof(sip_cfg.realm));
+@@ -23502,7 +24635,7 @@
+ } else if (!strcasecmp(v->name, "allowtransfer")) {
+ 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);
++ ast_set2_flag(&global_flags[1], ast_true(v->value), SIP_PAGE2_RTCACHEFRIENDS);
+ } else if (!strcasecmp(v->name, "rtsavesysname")) {
+ sip_cfg.rtsave_sysname = ast_true(v->value);
+ } else if (!strcasecmp(v->name, "rtupdate")) {
+@@ -23525,7 +24658,7 @@
+ while ((trans = strsep(&val, ","))) {
+ trans = ast_skip_blanks(trans);
+
+- if (!strncasecmp(trans, "udp", 3))
++ if (!strncasecmp(trans, "udp", 3))
+ default_transports |= SIP_TRANSPORT_UDP;
+ else if (!strncasecmp(trans, "tcp", 3))
+ default_transports |= SIP_TRANSPORT_TCP;
+@@ -23546,28 +24679,6 @@
+ ast_log(LOG_WARNING, "Invalid %s '%s' at line %d of %s\n", v->name, v->value, v->lineno, config);
+ sip_tcp_desc.local_address.sin_family = family;
+ ast_debug(2, "Setting TCP socket address to %s\n", v->value);
+- } else if (!strcasecmp(v->name, "tlsenable")) {
+- default_tls_cfg.enabled = ast_true(v->value) ? TRUE : FALSE;
+- sip_tls_desc.local_address.sin_family = AF_INET;
+- } else if (!strcasecmp(v->name, "tlscertfile")) {
+- ast_free(default_tls_cfg.certfile);
+- default_tls_cfg.certfile = ast_strdup(v->value);
+- } else if (!strcasecmp(v->name, "tlscipher")) {
+- ast_free(default_tls_cfg.cipher);
+- default_tls_cfg.cipher = ast_strdup(v->value);
+- } else if (!strcasecmp(v->name, "tlscafile")) {
+- ast_free(default_tls_cfg.cafile);
+- default_tls_cfg.cafile = ast_strdup(v->value);
+- } else if (!strcasecmp(v->name, "tlscapath")) {
+- ast_free(default_tls_cfg.capath);
+- default_tls_cfg.capath = ast_strdup(v->value);
+- } else if (!strcasecmp(v->name, "tlsverifyclient")) {
+- ast_set2_flag(&default_tls_cfg.flags, ast_true(v->value), AST_SSL_VERIFY_CLIENT);
+- } else if (!strcasecmp(v->name, "tlsdontverifyserver")) {
+- ast_set2_flag(&default_tls_cfg.flags, ast_true(v->value), AST_SSL_DONT_VERIFY_SERVER);
+- } else if (!strcasecmp(v->name, "tlsbindaddr")) {
+- if (ast_parse_arg(v->value, PARSE_INADDR, &sip_tls_desc.local_address))
+- ast_log(LOG_WARNING, "Invalid %s '%s' at line %d of %s\n", v->name, v->value, v->lineno, config);
+ } else if (!strcasecmp(v->name, "dynamic_exclude_static") || !strcasecmp(v->name, "dynamic_excludes_static")) {
+ global_dynamic_exclude_static = ast_true(v->value);
+ } else if (!strcasecmp(v->name, "contactpermit") || !strcasecmp(v->name, "contactdeny")) {
+@@ -23584,7 +24695,7 @@
+ i = 0;
+ ast_set2_flag(&global_flags[1], i || ast_true(v->value), SIP_PAGE2_RTAUTOCLEAR);
+ } else if (!strcasecmp(v->name, "usereqphone")) {
+- ast_set2_flag(&global_flags[0], ast_true(v->value), SIP_USEREQPHONE);
++ ast_set2_flag(&global_flags[0], ast_true(v->value), SIP_USEREQPHONE);
+ } else if (!strcasecmp(v->name, "relaxdtmf")) {
+ global_relaxdtmf = ast_true(v->value);
+ } else if (!strcasecmp(v->name, "vmexten")) {
+@@ -23643,6 +24754,8 @@
+ 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, "mwi_from")) {
++ ast_copy_string(default_mwi_from, v->value, sizeof(default_mwi_from));
+ } else if (!strcasecmp(v->name, "fromdomain")) {
+ ast_copy_string(default_fromdomain, v->value, sizeof(default_fromdomain));
+ } else if (!strcasecmp(v->name, "outboundproxy")) {
+@@ -23758,6 +24871,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")) {
+@@ -24182,165 +25297,183 @@
+ 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 | SIP_CAN_REINVITE_NAT)) {
++ 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 (!ast_bridged_channel(chan) && !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";
+
+ /*! \brief Set the DTMFmode for an outbound SIP call (application) */
+-static int sip_dtmfmode(struct ast_channel *chan, void *data)
++static int sip_dtmfmode(struct ast_channel *chan, const char *data)
+ {
+ struct sip_pvt *p;
+- char *mode = data;
++ const char *mode = data;
+
+ if (!data) {
+ ast_log(LOG_WARNING, "This application requires the argument: info, inband, rfc2833\n");
+@@ -24377,17 +25510,12 @@
+ } 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);
+- if (ast_test_flag(&p->flags[0], SIP_DTMF) == SIP_DTMF_INBAND) {
+- if (!p->vad) {
+- p->vad = ast_dsp_new();
+- ast_dsp_set_features(p->vad, DSP_FEATURE_DIGIT_DETECT);
+- }
++ 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) ||
++ (ast_test_flag(&p->flags[0], SIP_DTMF) == SIP_DTMF_AUTO)) {
++ enable_digit_detect(p);
+ } else {
+- if (p->vad) {
+- ast_dsp_free(p->vad);
+- p->vad = NULL;
+- }
++ disable_digit_detect(p);
+ }
+ sip_pvt_unlock(p);
+ ast_channel_unlock(chan);
+@@ -24395,12 +25523,13 @@
+ }
+
+ /*! \brief Add a SIP header to an outbound INVITE */
+-static int sip_addheader(struct ast_channel *chan, void *data)
++static int sip_addheader(struct ast_channel *chan, const char *data)
+ {
+ int no = 0;
+ int ok = FALSE;
+ char varbuf[30];
+- char *inbuf = data, *subbuf;
++ const char *inbuf = data;
++ char *subbuf;
+
+ if (ast_strlen_zero(inbuf)) {
+ ast_log(LOG_WARNING, "This application requires the argument: Header\n");
+@@ -24434,7 +25563,7 @@
+ }
+
+ /*! \brief Remove SIP headers added previously with SipAddHeader application */
+-static int sip_removeheader(struct ast_channel *chan, void *data)
++static int sip_removeheader(struct ast_channel *chan, const char *data)
+ {
+ struct ast_var_t *newvariable;
+ struct varshead *headp;
+@@ -24521,17 +25650,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)
+ {
+@@ -24739,12 +25866,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);
+@@ -24757,16 +25884,11 @@
+ ast_custom_function_register(&checksipdomain_function);
+
+ /* Register manager commands */
+- ast_manager_register2("SIPpeers", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, manager_sip_show_peers,
+- "List SIP peers (text format)", mandescr_show_peers);
+- ast_manager_register2("SIPshowpeer", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, manager_sip_show_peer,
+- "Show SIP peer (text format)", mandescr_show_peer);
+- ast_manager_register2("SIPqualifypeer", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, manager_sip_qualify_peer,
+- "Show SIP peer (text format)", mandescr_show_peer); /*! \todo Fix this XXX This must be all wrong XXXX */
+- ast_manager_register2("SIPshowregistry", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, manager_show_registry,
+- "Show SIP registrations (text format)", mandescr_show_registry);
+- ast_manager_register2("SIPnotify", EVENT_FLAG_SYSTEM, manager_sipnotify,
+- "Send a SIP notify", mandescr_sipnotify);
++ ast_manager_register_xml("SIPpeers", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, manager_sip_show_peers);
++ ast_manager_register_xml("SIPshowpeer", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, manager_sip_show_peer);
++ ast_manager_register_xml("SIPqualifypeer", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, manager_sip_qualify_peer);
++ ast_manager_register_xml("SIPshowregistry", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, manager_show_registry);
++ ast_manager_register_xml("SIPnotify", EVENT_FLAG_SYSTEM, manager_sipnotify);
+ sip_poke_all_peers();
+ sip_send_all_registers();
+ sip_send_all_mwi_subscriptions();
+@@ -24816,12 +25938,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");
+@@ -24880,6 +26002,8 @@
+
+ if (default_tls_cfg.certfile)
+ ast_free(default_tls_cfg.certfile);
++ if (default_tls_cfg.pvtfile)
++ ast_free(default_tls_cfg.pvtfile);
+ if (default_tls_cfg.cipher)
+ ast_free(default_tls_cfg.cipher);
+ if (default_tls_cfg.cafile)
+Index: channels/chan_agent.c
+===================================================================
+--- a/channels/chan_agent.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/channels/chan_agent.c (.../trunk) (revision 202568)
+@@ -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"
+@@ -157,9 +156,6 @@
+ <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>
+@@ -168,6 +164,34 @@
+ </syntax>
+ <description />
+ </function>
++ <manager name="Agents" language="en_US">
++ <synopsis>
++ Lists agents and their status.
++ </synopsis>
++ <syntax>
++ <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
++ </syntax>
++ <description>
++ <para>Will list info about all possible agents.</para>
++ </description>
++ </manager>
++ <manager name="AgentLogoff" language="en_US">
++ <synopsis>
++ Sets an agent as no longer logged in.
++ </synopsis>
++ <syntax>
++ <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
++ <parameter name="Agent" required="true">
++ <para>Agent ID of the agent to log off.</para>
++ </parameter>
++ <parameter name="Soft">
++ <para>Set to <literal>true</literal> to not hangup existing calls.</para>
++ </parameter>
++ </syntax>
++ <description>
++ <para>Sets an agent as no longer logged in.</para>
++ </description>
++ </manager>
+ ***/
+
+ static const char tdesc[] = "Call Agent Proxy Channel";
+@@ -176,16 +200,6 @@
+ static const char app[] = "AgentLogin";
+ static const char app3[] = "AgentMonitorOutgoing";
+
+-static const char mandescr_agents[] =
+-"Description: Will list info about all possible agents.\n"
+-"Variables: NONE\n";
+-
+-static const char mandescr_agent_logoff[] =
+-"Description: Sets an agent as no longer logged in.\n"
+-"Variables: (Names marked with * are required)\n"
+-" *Agent: Agent ID of the agent to log off\n"
+-" Soft: Set to 'true' to not hangup existing calls\n";
+-
+ static char moh[80] = "default";
+
+ #define AST_MAX_AGENT 80 /*!< Agent ID or Password max length */
+@@ -195,9 +209,6 @@
+ static const char pa_family[] = "Agents"; /*!< Persistent Agents astdb family */
+ #define PA_MAX_LEN 2048 /*!< The maximum length of each persistent member agent database entry */
+
+-static int persistent_agents = 0; /*!< queues.conf [general] option */
+-static void dump_agents(void);
+-
+ #define DEFAULT_ACCEPTDTMF '#'
+ #define DEFAULT_ENDDTMF '*'
+
+@@ -258,7 +269,6 @@
+ ast_cond_t app_complete_cond;
+ volatile int app_sleep_cond; /**< Sleep condition for the login app */
+ struct ast_channel *owner; /**< Agent */
+- char loginchan[80]; /**< channel they logged in from */
+ char logincallerid[80]; /**< Caller ID they had when they logged in */
+ struct ast_channel *chan; /**< Channel we use */
+ unsigned int flags; /**< Flags show if settings were applied with channel vars */
+@@ -302,7 +312,6 @@
+ /*--- Forward declarations */
+ static struct ast_channel *agent_request(const char *type, int format, void *data, int *cause);
+ static int agent_devicestate(void *data);
+-static void agent_logoff_maintenance(struct agent_pvt *p, char *loginchan, long logintime, const char *uniqueid, char *logcommand);
+ static int agent_digit_begin(struct ast_channel *ast, char digit);
+ static int agent_digit_end(struct ast_channel *ast, char digit, unsigned int duration);
+ static int agent_call(struct ast_channel *ast, char *dest, int timeout);
+@@ -315,7 +324,6 @@
+ static int agent_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen);
+ static int agent_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
+ static struct ast_channel *agent_bridgedchannel(struct ast_channel *chan, struct ast_channel *bridge);
+-static void set_agentbycallerid(const char *callerid, const char *agent);
+ static char *complete_agent_logoff_cmd(const char *line, const char *word, int pos, int state);
+ static struct ast_channel* agent_get_base_channel(struct ast_channel *chan);
+ static int agent_set_base_channel(struct ast_channel *chan, struct ast_channel *base);
+@@ -464,8 +472,9 @@
+ /* Release ownership of the agent to other threads (presumably running the login app). */
+ p->app_lock_flag = 0;
+ ast_cond_signal(&p->app_complete_cond);
+- if (chan)
+- ast_channel_free(chan);
++ if (chan) {
++ chan = ast_channel_release(chan);
++ }
+ if (p->dead) {
+ ast_mutex_destroy(&p->lock);
+ ast_mutex_destroy(&p->app_lock);
+@@ -521,7 +530,6 @@
+ struct agent_pvt *p = ast->tech_pvt;
+ struct ast_frame *f = NULL;
+ static struct ast_frame answer_frame = { AST_FRAME_CONTROL, AST_CONTROL_ANSWER };
+- const char *status;
+ int cur_time = time(NULL);
+ ast_mutex_lock(&p->lock);
+ CHECK_FORMATS(ast, p);
+@@ -535,33 +543,9 @@
+ } else
+ f = &ast_null_frame;
+ if (!f) {
+- /* If there's a channel, hang it up (if it's on a callback) make it NULL */
++ /* If there's a channel, make it NULL */
+ if (p->chan) {
+ p->chan->_bridge = NULL;
+- /* Note that we don't hangup if it's not a callback because Asterisk will do it
+- for us when the PBX instance that called login finishes */
+- if (!ast_strlen_zero(p->loginchan)) {
+- if (p->chan)
+- ast_debug(1, "Bridge on '%s' being cleared (2)\n", p->chan->name);
+- if (p->owner->_state != AST_STATE_UP) {
+- int howlong = cur_time - p->start;
+- if (p->autologoff && howlong >= p->autologoff) {
+- p->loginstart = 0;
+- ast_log(LOG_NOTICE, "Agent '%s' didn't answer/confirm within %d seconds (waited %d)\n", p->name, p->autologoff, howlong);
+- agent_logoff_maintenance(p, p->loginchan, (cur_time = p->loginstart), ast->uniqueid, "Autologoff");
+- }
+- }
+- status = pbx_builtin_getvar_helper(p->chan, "CHANLOCALSTATUS");
+- if (autologoffunavail && status && !strcasecmp(status, "CHANUNAVAIL")) {
+- long logintime = cur_time - p->loginstart;
+- p->loginstart = 0;
+- ast_log(LOG_NOTICE, "Agent read: '%s' is not available now, auto logoff\n", p->name);
+- agent_logoff_maintenance(p, p->loginchan, logintime, ast->uniqueid, "Chanunavail");
+- }
+- ast_hangup(p->chan);
+- if (p->wrapuptime && p->acknowledged)
+- p->lastdisc = ast_tvadd(ast_tvnow(), ast_samp2tv(p->wrapuptime, 1000));
+- }
+ p->chan = NULL;
+ ast_devstate_changed(AST_DEVICE_UNAVAILABLE, "Agent/%s", p->agent);
+ p->acknowledged = 0;
+@@ -577,7 +561,6 @@
+ int howlong = cur_time - p->start;
+ if (p->autologoff && (howlong >= p->autologoff)) {
+ ast_log(LOG_NOTICE, "Agent '%s' didn't answer/confirm within %d seconds (waited %d)\n", p->name, p->autologoff, howlong);
+- agent_logoff_maintenance(p, p->loginchan, (cur_time - p->loginstart), ast->uniqueid, "Autologoff");
+ agent_logoff(p->agent, 0);
+ }
+ }
+@@ -766,17 +749,6 @@
+ if (newstate)
+ ast_setstate(ast, newstate);
+ return res;
+- } else if (!ast_strlen_zero(p->loginchan)) {
+- 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_inherit_variables(ast, p->chan);
+- res = ast_call(p->chan, p->loginchan, 0);
+- CLEANUP(ast,p);
+- ast_mutex_unlock(&p->lock);
+- return res;
+ }
+ ast_verb(3, "agent_call, call to agent '%s' call on '%s'\n", p->agent, p->chan->name);
+ ast_debug(3, "Playing beep, lang '%s'\n", p->chan->language);
+@@ -805,9 +777,9 @@
+ }
+ if(!res) {
+ /* Call is immediately up, or might need ack */
+- if (p->ackcall > 1)
++ if (p->ackcall) {
+ newstate = AST_STATE_RINGING;
+- else {
++ } else {
+ newstate = AST_STATE_UP;
+ if (recordagentcalls)
+ agent_start_monitoring(ast, 0);
+@@ -822,19 +794,6 @@
+ return res;
+ }
+
+-/*! \brief store/clear the global variable that stores agentid based on the callerid */
+-static void set_agentbycallerid(const char *callerid, const char *agent)
+-{
+- char buf[AST_MAX_BUF];
+-
+- /* if there is no Caller ID, nothing to do */
+- if (ast_strlen_zero(callerid))
+- return;
+-
+- snprintf(buf, sizeof(buf), "%s_%s", GETAGENTBYCALLERID, callerid);
+- pbx_builtin_setvar_helper(NULL, buf, agent);
+-}
+-
+ /*! \brief return the channel or base channel if one exists. This function assumes the channel it is called on is already locked */
+ struct ast_channel* agent_get_base_channel(struct ast_channel *chan)
+ {
+@@ -873,7 +832,7 @@
+ {
+ struct agent_pvt *p = ast->tech_pvt;
+ int howlong = 0;
+- const char *status;
++
+ ast_mutex_lock(&p->lock);
+ p->owner = NULL;
+ ast->tech_pvt = NULL;
+@@ -898,37 +857,7 @@
+ if (p->chan) {
+ p->chan->_bridge = NULL;
+ /* If they're dead, go ahead and hang up on the agent now */
+- if (!ast_strlen_zero(p->loginchan)) {
+- /* Store last disconnect time */
+- if (p->wrapuptime)
+- p->lastdisc = ast_tvadd(ast_tvnow(), ast_samp2tv(p->wrapuptime, 1000));
+- else
+- p->lastdisc = ast_tv(0,0);
+- if (p->chan) {
+- status = pbx_builtin_getvar_helper(p->chan, "CHANLOCALSTATUS");
+- if (autologoffunavail && status && !strcasecmp(status, "CHANUNAVAIL")) {
+- long logintime = time(NULL) - p->loginstart;
+- p->loginstart = 0;
+- ast_log(LOG_NOTICE, "Agent hangup: '%s' is not available now, auto logoff\n", p->name);
+- agent_logoff_maintenance(p, p->loginchan, logintime, ast->uniqueid, "Chanunavail");
+- }
+- /* Recognize the hangup and pass it along immediately */
+- ast_hangup(p->chan);
+- p->chan = NULL;
+- ast_devstate_changed(AST_DEVICE_UNAVAILABLE, "Agent/%s", p->agent);
+- }
+- ast_debug(1, "Hungup, howlong is %d, autologoff is %d\n", howlong, p->autologoff);
+- if ((p->deferlogoff) || (howlong && p->autologoff && (howlong > p->autologoff))) {
+- long logintime = time(NULL) - p->loginstart;
+- p->loginstart = 0;
+- if (!p->deferlogoff)
+- ast_log(LOG_NOTICE, "Agent '%s' didn't answer/confirm within %d seconds (waited %d)\n", p->name, p->autologoff, howlong);
+- p->deferlogoff = 0;
+- agent_logoff_maintenance(p, p->loginchan, logintime, ast->uniqueid, "Autologoff");
+- if (persistent_agents)
+- dump_agents();
+- }
+- } else if (p->dead) {
++ if (p->dead) {
+ ast_channel_lock(p->chan);
+ ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
+ ast_channel_unlock(p->chan);
+@@ -944,10 +873,7 @@
+
+ /* Only register a device state change if the agent is still logged in */
+ if (!p->loginstart) {
+- p->loginchan[0] = '\0';
+ p->logincallerid[0] = '\0';
+- if (persistent_agents)
+- dump_agents();
+ } else {
+ ast_devstate_changed(AST_DEVICE_NOT_INUSE, "Agent/%s", p->agent);
+ }
+@@ -975,10 +901,8 @@
+ ast_mutex_unlock(&p->lock);
+ }
+ /* Release ownership of the agent to other threads (presumably running the login app). */
+- if (ast_strlen_zero(p->loginchan)) {
+- p->app_lock_flag = 0;
+- ast_cond_signal(&p->app_complete_cond);
+- }
++ p->app_lock_flag = 0;
++ ast_cond_signal(&p->app_complete_cond);
+ }
+ return 0;
+ }
+@@ -1115,7 +1039,7 @@
+ alreadylocked = p->app_lock_flag;
+ p->app_lock_flag = 1;
+
+- if(ast_strlen_zero(p->loginchan) && alreadylocked) {
++ if (alreadylocked) {
+ if (p->chan) {
+ ast_queue_frame(p->chan, &ast_null_frame);
+ ast_mutex_unlock(&p->lock); /* For other thread to read the condition. */
+@@ -1126,24 +1050,12 @@
+ p->owner = NULL;
+ tmp->tech_pvt = NULL;
+ p->app_sleep_cond = 1;
+- ast_channel_free( tmp );
++ tmp = ast_channel_release(tmp);
+ ast_mutex_unlock(&p->lock); /* For other thread to read the condition. */
+ p->app_lock_flag = 0;
+ ast_cond_signal(&p->app_complete_cond);
+ return NULL;
+ }
+- } else if (!ast_strlen_zero(p->loginchan)) {
+- if (p->chan)
+- ast_queue_frame(p->chan, &ast_null_frame);
+- if (!p->chan) {
+- ast_log(LOG_WARNING, "Agent disconnected while we were connecting the call\n");
+- p->owner = NULL;
+- tmp->tech_pvt = NULL;
+- p->app_sleep_cond = 1;
+- ast_channel_free( tmp );
+- ast_mutex_unlock(&p->lock); /* For other thread to read the condition. */
+- return NULL;
+- }
+ }
+ if (p->chan)
+ ast_indicate(p->chan, AST_CONTROL_UNHOLD);
+@@ -1162,7 +1074,6 @@
+ struct ast_config *ucfg;
+ struct ast_variable *v;
+ struct agent_pvt *p;
+- const char *general_val;
+ const char *catname;
+ const char *hasagent;
+ int genhasagent;
+@@ -1205,8 +1116,6 @@
+ savecallsin[0] = '\0';
+
+ /* Read in [general] section for persistence */
+- if ((general_val = ast_variable_retrieve(cfg, "general", "persistentagents")))
+- persistent_agents = ast_true(general_val);
+ multiplelogin = ast_true(ast_variable_retrieve(cfg, "general", "multiplelogin"));
+
+ /* Read in the [agents] section */
+@@ -1222,12 +1131,9 @@
+ if (autologoff < 0)
+ autologoff = 0;
+ } else if (!strcasecmp(v->name, "ackcall")) {
+- if (!strcasecmp(v->value, "always"))
+- ackcall = 2;
+- else if (ast_true(v->value))
++ if (ast_true(v->value) || !strcasecmp(v->value, "always")) {
+ ackcall = 1;
+- else
+- ackcall = 0;
++ }
+ } else if (!strcasecmp(v->name, "endcall")) {
+ endcall = ast_true(v->value);
+ } else if (!strcasecmp(v->name, "acceptdtmf")) {
+@@ -1354,7 +1260,7 @@
+ if (needlock)
+ AST_LIST_UNLOCK(&agents);
+ if (parent && chan) {
+- if (newlyavailable->ackcall > 1) {
++ if (newlyavailable->ackcall) {
+ /* Don't do beep here */
+ res = 0;
+ } else {
+@@ -1452,8 +1358,7 @@
+ AST_LIST_LOCK(&agents);
+ AST_LIST_TRAVERSE(&agents, p, list) {
+ ast_mutex_lock(&p->lock);
+- if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent)) &&
+- ast_strlen_zero(p->loginchan)) {
++ if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) {
+ if (p->chan)
+ hasagent++;
+ now = ast_tvnow();
+@@ -1476,23 +1381,16 @@
+ AST_LIST_TRAVERSE(&agents, p, list) {
+ ast_mutex_lock(&p->lock);
+ if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) {
+- if (p->chan || !ast_strlen_zero(p->loginchan))
++ if (p->chan) {
+ hasagent++;
++ }
+ now = ast_tvnow();
+-#if 0
+- ast_log(LOG_NOTICE, "Time now: %ld, Time of lastdisc: %ld\n", now.tv_sec, p->lastdisc.tv_sec);
+-#endif
+ if (!p->lastdisc.tv_sec || (now.tv_sec >= p->lastdisc.tv_sec)) {
+ p->lastdisc = ast_tv(0, 0);
+ /* Agent must be registered, but not have any active call, and not be in a waiting state */
+ if (!p->owner && p->chan) {
+ /* Could still get a fixed agent */
+ chan = agent_new(p, AST_STATE_DOWN);
+- } else if (!p->owner && !ast_strlen_zero(p->loginchan)) {
+- /* Adjustable agent */
+- p->chan = ast_request("Local", format, p->loginchan, cause);
+- if (p->chan)
+- chan = agent_new(p, AST_STATE_DOWN);
+ }
+ if (chan) {
+ ast_mutex_unlock(&p->lock);
+@@ -1545,7 +1443,6 @@
+ {
+ const char *id = astman_get_header(m,"ActionID");
+ char idText[256] = "";
+- char chanbuf[256];
+ struct agent_pvt *p;
+ char *username = NULL;
+ char *loginChan = NULL;
+@@ -1571,16 +1468,7 @@
+ /* Set a default status. It 'should' get changed. */
+ status = "AGENT_UNKNOWN";
+
+- if (!ast_strlen_zero(p->loginchan) && !p->chan) {
+- loginChan = p->loginchan;
+- talkingto = "n/a";
+- talkingtoChan = "n/a";
+- status = "AGENT_IDLE";
+- if (p->acknowledged) {
+- snprintf(chanbuf, sizeof(chanbuf), " %s (Confirmed)", p->loginchan);
+- loginChan = chanbuf;
+- }
+- } else if (p->chan) {
++ if (p->chan) {
+ loginChan = ast_strdupa(p->chan->name);
+ if (p->owner && p->owner->_bridge) {
+ talkingto = p->chan->cid.cid_num;
+@@ -1621,49 +1509,9 @@
+ return 0;
+ }
+
+-static void agent_logoff_maintenance(struct agent_pvt *p, char *loginchan, long logintime, const char *uniqueid, char *logcommand)
+-{
+- char *tmp = NULL;
+- char agent[AST_MAX_AGENT];
+-
+- if (!ast_strlen_zero(logcommand))
+- tmp = logcommand;
+- else
+- tmp = ast_strdupa("");
+-
+- snprintf(agent, sizeof(agent), "Agent/%s", p->agent);
+-
+- if (!ast_strlen_zero(uniqueid)) {
+- manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogoff",
+- "Agent: %s\r\n"
+- "Reason: %s\r\n"
+- "Loginchan: %s\r\n"
+- "Logintime: %ld\r\n"
+- "Uniqueid: %s\r\n",
+- p->agent, tmp, loginchan, logintime, uniqueid);
+- } else {
+- manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogoff",
+- "Agent: %s\r\n"
+- "Reason: %s\r\n"
+- "Loginchan: %s\r\n"
+- "Logintime: %ld\r\n",
+- p->agent, tmp, loginchan, logintime);
+- }
+-
+- ast_queue_log("NONE", ast_strlen_zero(uniqueid) ? "NONE" : uniqueid, agent, "AGENTCALLBACKLOGOFF", "%s|%ld|%s", loginchan, logintime, tmp);
+- set_agentbycallerid(p->logincallerid, NULL);
+- p->loginchan[0] ='\0';
+- p->logincallerid[0] = '\0';
+- ast_devstate_changed(AST_DEVICE_UNAVAILABLE, "Agent/%s", p->agent);
+- if (persistent_agents)
+- dump_agents();
+-
+-}
+-
+ static int agent_logoff(const char *agent, int soft)
+ {
+ struct agent_pvt *p;
+- long logintime;
+ int ret = -1; /* Return -1 if no agent if found */
+
+ AST_LIST_LOCK(&agents);
+@@ -1693,10 +1541,6 @@
+ ast_mutex_unlock(&p->lock);
+ } else
+ p->deferlogoff = 1;
+- } else {
+- logintime = time(NULL) - p->loginstart;
+- p->loginstart = 0;
+- agent_logoff_maintenance(p, p->loginchan, logintime, NULL, "CommandLogoff");
+ }
+ break;
+ }
+@@ -1709,7 +1553,7 @@
+ static char *agent_logoff_cmd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+ {
+ int ret;
+- char *agent;
++ const char *agent;
+
+ switch (cmd) {
+ case CLI_INIT:
+@@ -1838,15 +1682,6 @@
+ else
+ strcpy(talkingto, " is idle");
+ online_agents++;
+- } else if (!ast_strlen_zero(p->loginchan)) {
+- if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > 0 || !(p->lastdisc.tv_sec))
+- snprintf(location, sizeof(location) - 20, "available at '%s'", p->loginchan);
+- else
+- snprintf(location, sizeof(location) - 20, "wrapping up at '%s'", p->loginchan);
+- talkingto[0] = '\0';
+- online_agents++;
+- if (p->acknowledged)
+- strncat(location, " (Confirmed)", sizeof(location) - strlen(location) - 1);
+ } else {
+ strcpy(location, "not logged in");
+ talkingto[0] = '\0';
+@@ -1912,13 +1747,6 @@
+ strcpy(talkingto, " is idle");
+ agent_status = 1;
+ online_agents++;
+- } else if (!ast_strlen_zero(p->loginchan)) {
+- snprintf(location, sizeof(location) - 20, "available at '%s'", p->loginchan);
+- talkingto[0] = '\0';
+- agent_status = 1;
+- online_agents++;
+- if (p->acknowledged)
+- strncat(location, " (Confirmed)", sizeof(location) - strlen(location) - 1);
+ }
+ if (!ast_strlen_zero(p->moh))
+ snprintf(music, sizeof(music), " (musiconhold is '%s')", p->moh);
+@@ -1957,7 +1785,7 @@
+ * \returns
+ * \sa agentmonitoroutgoing_exec(), load_module().
+ */
+-static int login_exec(struct ast_channel *chan, void *data)
++static int login_exec(struct ast_channel *chan, const char *data)
+ {
+ int res=0;
+ int tries = 0;
+@@ -2066,12 +1894,11 @@
+
+ /* Set Channel Specific Agent Overrides */
+ if (!ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"))) {
+- if (!strcasecmp(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"), "always"))
+- p->ackcall = 2;
+- else if (ast_true(pbx_builtin_getvar_helper(chan, "AGENTACKCALL")))
++ if (ast_true(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"))) {
+ p->ackcall = 1;
+- else
++ } else {
+ p->ackcall = 0;
++ }
+ tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTACKCALL");
+ ast_verb(3, "Saw variable AGENTACKCALL=%s, setting ackcall to: %d for Agent '%s'.\n", tmpoptions, p->ackcall, p->agent);
+ ast_set_flag(p, AGENT_FLAG_ACKCALL);
+@@ -2117,7 +1944,6 @@
+ long logintime;
+ snprintf(agent, sizeof(agent), "Agent/%s", p->agent);
+
+- p->loginchan[0] = '\0';
+ p->logincallerid[0] = '\0';
+ p->acknowledged = 0;
+
+@@ -2160,10 +1986,11 @@
+ ast_getformatname(chan->readformat), ast_getformatname(chan->writeformat));
+ /* Login this channel and wait for it to go away */
+ p->chan = chan;
+- if (p->ackcall > 1)
++ if (p->ackcall) {
+ check_beep(p, 0);
+- else
++ } else {
+ check_availability(p, 0);
++ }
+ ast_mutex_unlock(&p->lock);
+ AST_LIST_UNLOCK(&agents);
+ ast_devstate_changed(AST_DEVICE_NOT_INUSE, "Agent/%s", p->agent);
+@@ -2188,10 +2015,11 @@
+ ast_debug(1, "Wrapup time for %s expired!\n", p->agent);
+ p->lastdisc = ast_tv(0, 0);
+ ast_devstate_changed(AST_DEVICE_NOT_INUSE, "Agent/%s", p->agent);
+- if (p->ackcall > 1)
++ if (p->ackcall) {
+ check_beep(p, 0);
+- else
++ } else {
+ check_availability(p, 0);
++ }
+ }
+ }
+ ast_mutex_unlock(&p->lock);
+@@ -2204,11 +2032,12 @@
+ ast_mutex_unlock(&p->app_lock);
+ ast_mutex_lock(&p->lock);
+ ast_mutex_unlock(&p->lock);
+- if (p->ackcall > 1)
++ if (p->ackcall) {
+ res = agent_ack_sleep(p);
+- else
++ } else {
+ res = ast_safe_sleep_conditional( chan, 1000, agent_cont_sleep, p );
+- if ((p->ackcall > 1) && (res == 1)) {
++ }
++ if (p->ackcall && (res == 1)) {
+ AST_LIST_LOCK(&agents);
+ ast_mutex_lock(&p->lock);
+ check_availability(p, 0);
+@@ -2285,7 +2114,7 @@
+ * \returns
+ * \sa login_exec(), load_module().
+ */
+-static int agentmonitoroutgoing_exec(struct ast_channel *chan, void *data)
++static int agentmonitoroutgoing_exec(struct ast_channel *chan, const char *data)
+ {
+ int exitifnoagentid = 0;
+ int nowarnings = 0;
+@@ -2335,84 +2164,6 @@
+ return 0;
+ }
+
+-/*!
+- * \brief Dump AgentCallbackLogin agents to the ASTdb database for persistence
+- */
+-static void dump_agents(void)
+-{
+- struct agent_pvt *cur_agent = NULL;
+- char buf[256];
+-
+- AST_LIST_TRAVERSE(&agents, cur_agent, list) {
+- if (cur_agent->chan)
+- continue;
+-
+- if (!ast_strlen_zero(cur_agent->loginchan)) {
+- snprintf(buf, sizeof(buf), "%s;%s", cur_agent->loginchan, cur_agent->logincallerid);
+- if (ast_db_put(pa_family, cur_agent->agent, buf))
+- ast_log(LOG_WARNING, "failed to create persistent entry in ASTdb for %s!\n", buf);
+- else
+- ast_debug(1, "Saved Agent: %s on %s\n", cur_agent->agent, cur_agent->loginchan);
+- } else {
+- /* Delete - no agent or there is an error */
+- ast_db_del(pa_family, cur_agent->agent);
+- }
+- }
+-}
+-
+-/*!
+- * \brief Reload the persistent agents from astdb.
+- */
+-static void reload_agents(void)
+-{
+- char *agent_num;
+- struct ast_db_entry *db_tree;
+- struct ast_db_entry *entry;
+- struct agent_pvt *cur_agent;
+- char agent_data[256];
+- char *parse;
+- char *agent_chan;
+- char *agent_callerid;
+-
+- db_tree = ast_db_gettree(pa_family, NULL);
+-
+- AST_LIST_LOCK(&agents);
+- for (entry = db_tree; entry; entry = entry->next) {
+- agent_num = entry->key + strlen(pa_family) + 2;
+- AST_LIST_TRAVERSE(&agents, cur_agent, list) {
+- ast_mutex_lock(&cur_agent->lock);
+- if (strcmp(agent_num, cur_agent->agent) == 0)
+- break;
+- ast_mutex_unlock(&cur_agent->lock);
+- }
+- if (!cur_agent) {
+- ast_db_del(pa_family, agent_num);
+- continue;
+- } else
+- ast_mutex_unlock(&cur_agent->lock);
+- if (!ast_db_get(pa_family, agent_num, agent_data, sizeof(agent_data)-1)) {
+- ast_debug(1, "Reload Agent from AstDB: %s on %s\n", cur_agent->agent, agent_data);
+- parse = agent_data;
+- agent_chan = strsep(&parse, ";");
+- agent_callerid = strsep(&parse, ";");
+- ast_copy_string(cur_agent->loginchan, agent_chan, sizeof(cur_agent->loginchan));
+- if (agent_callerid) {
+- ast_copy_string(cur_agent->logincallerid, agent_callerid, sizeof(cur_agent->logincallerid));
+- set_agentbycallerid(cur_agent->logincallerid, cur_agent->agent);
+- } else
+- cur_agent->logincallerid[0] = '\0';
+- if (cur_agent->loginstart == 0)
+- time(&cur_agent->loginstart);
+- ast_devstate_changed(AST_DEVICE_UNKNOWN, "Agent/%s", cur_agent->agent);
+- }
+- }
+- AST_LIST_UNLOCK(&agents);
+- if (db_tree) {
+- ast_log(LOG_NOTICE, "Agents successfully reloaded from database.\n");
+- ast_db_freetree(db_tree);
+- }
+-}
+-
+ /*! \brief Part of PBX channel interface */
+ static int agent_devicestate(void *data)
+ {
+@@ -2441,7 +2192,7 @@
+ } else {
+ if (res == AST_DEVICE_BUSY)
+ res = AST_DEVICE_INUSE;
+- if (p->chan || !ast_strlen_zero(p->loginchan)) {
++ if (p->chan) {
+ if (res == AST_DEVICE_INVALID)
+ res = AST_DEVICE_UNKNOWN;
+ } else if (res == AST_DEVICE_INVALID)
+@@ -2506,8 +2257,9 @@
+
+ if (!strcasecmp(args.item, "status")) {
+ char *status = "LOGGEDOUT";
+- if (agent->chan || !ast_strlen_zero(agent->loginchan))
+- status = "LOGGEDIN";
++ if (agent->chan) {
++ status = "LOGGEDIN";
++ }
+ ast_copy_string(buf, status, len);
+ } else if (!strcasecmp(args.item, "password"))
+ ast_copy_string(buf, agent->password, len);
+@@ -2522,15 +2274,16 @@
+ if (tmp)
+ *tmp = '\0';
+ }
+- } else if (!strcasecmp(args.item, "exten"))
+- ast_copy_string(buf, agent->loginchan, len);
++ } else if (!strcasecmp(args.item, "exten")) {
++ buf[0] = '\0';
++ }
+
+ AST_LIST_UNLOCK(&agents);
+
+ return 0;
+ }
+
+-struct ast_custom_function agent_function = {
++static struct ast_custom_function agent_function = {
+ .name = "AGENT",
+ .read = function_agent,
+ };
+@@ -2553,15 +2306,13 @@
+ /* Read in the config */
+ if (!read_agent_config(0))
+ return AST_MODULE_LOAD_DECLINE;
+- if (persistent_agents)
+- reload_agents();
+ /* Dialplan applications */
+ 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);
++ ast_manager_register_xml("Agents", EVENT_FLAG_AGENT, action_agents);
++ ast_manager_register_xml("AgentLogoff", EVENT_FLAG_AGENT, action_agent_logoff);
+
+ /* CLI Commands */
+ ast_cli_register_multiple(cli_agents, ARRAY_LEN(cli_agents));
+@@ -2574,11 +2325,7 @@
+
+ static int reload(void)
+ {
+- if (!read_agent_config(1)) {
+- if (persistent_agents)
+- reload_agents();
+- }
+- return 0;
++ return read_agent_config(1);
+ }
+
+ static int unload_module(void)
+Index: channels/chan_console.c
+===================================================================
+--- a/channels/chan_console.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/channels/chan_console.c (.../trunk) (revision 202568)
+@@ -797,6 +797,7 @@
+ if (pvt->owner) { /* already in a call */
+ int i;
+ struct ast_frame f = { AST_FRAME_DTMF, 0 };
++ const char *s;
+
+ if (a->argc == e->args) { /* argument is mandatory here */
+ ast_cli(a->fd, "Already in a call. You can only dial digits until you hangup.\n");
+@@ -837,8 +838,7 @@
+ } else
+ ast_cli(a->fd, "No such extension '%s' in context '%s'\n", mye, myc);
+
+- if (s)
+- free(s);
++ free(s);
+
+ unref_pvt(pvt);
+
+@@ -883,7 +883,7 @@
+
+ static char *cli_console_mute(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+ {
+- char *s;
++ const char *s;
+ struct console_pvt *pvt = get_active_pvt();
+ char *res = CLI_SUCCESS;
+
+Index: channels/Makefile
+===================================================================
+--- a/channels/Makefile (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/channels/Makefile (.../trunk) (revision 202568)
+@@ -69,6 +69,7 @@
+ rm -f h323/Makefile
+
+ $(if $(filter chan_iax2,$(EMBEDDED_MODS)),modules.link,chan_iax2.so): iax2-parser.o iax2-provision.o
++$(if $(filter chan_dahdi,$(EMBEDDED_MODS)),modules.link,chan_dahdi.so): sig_analog.o
+
+ ifneq ($(filter chan_h323,$(EMBEDDED_MODS)),)
+ modules.link: h323/libchanh323.a
+Index: channels/chan_iax2.c
+===================================================================
+--- a/channels/chan_iax2.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/channels/chan_iax2.c (.../trunk) (revision 202568)
+@@ -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"
+@@ -174,6 +175,47 @@
+ </syntax>
+ <description />
+ </function>
++ <manager name="IAXpeers" language="en_US">
++ <synopsis>
++ List IAX peers.
++ </synopsis>
++ <syntax>
++ <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
++ </syntax>
++ <description>
++ </description>
++ </manager>
++ <manager name="IAXpeerlist" language="en_US">
++ <synopsis>
++ List IAX Peers.
++ </synopsis>
++ <syntax>
++ <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
++ </syntax>
++ <description>
++ <para>List all the IAX peers.</para>
++ </description>
++ </manager>
++ <manager name="IAXnetstats" language="en_US">
++ <synopsis>
++ Show IAX Netstats.
++ </synopsis>
++ <syntax />
++ <description>
++ <para>Show IAX channels network statistics.</para>
++ </description>
++ </manager>
++ <manager name="IAXregistry" language="en_US">
++ <synopsis>
++ Show IAX registrations.
++ </synopsis>
++ <syntax>
++ <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
++ </syntax>
++ <description>
++ <para>Show IAX registrations.</para>
++ </description>
++ </manager>
+ ***/
+
+ /* Define SCHED_MULTITHREADED to run the scheduler in a special
+@@ -212,10 +254,10 @@
+
+ /*! \brief Maximum transmission unit for the UDP packet in the trunk not to be
+ fragmented. This is based on 1516 - ethernet - ip - udp - iax minus one g711 frame = 1240 */
+-#define MAX_TRUNK_MTU 1240
++#define MAX_TRUNK_MTU 1240
+
+-static int global_max_trunk_mtu; /*!< Maximum MTU, 0 if not used */
+-static int trunk_timed, trunk_untimed, trunk_maxmtu, trunk_nmaxmtu ; /*!< Trunk MTU statistics */
++static int global_max_trunk_mtu; /*!< Maximum MTU, 0 if not used */
++static int trunk_timed, trunk_untimed, trunk_maxmtu, trunk_nmaxmtu ; /*!< Trunk MTU statistics */
+
+ #define DEFAULT_CONTEXT "default"
+
+@@ -263,27 +305,27 @@
+ static struct ast_netsock_list *outsock; /*!< used if sourceaddress specified and bindaddr == INADDR_ANY */
+ static int defaultsockfd = -1;
+
+-int (*iax2_regfunk)(const char *username, int onoff) = NULL;
++static int (*iax2_regfunk)(const char *username, int onoff) = NULL;
+
+ /* Ethernet, etc */
+-#define IAX_CAPABILITY_FULLBANDWIDTH 0xFFFF
++#define IAX_CAPABILITY_FULLBANDWIDTH 0xFFFF
+ /* 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)
++#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)
+ /* A modem */
+-#define IAX_CAPABILITY_LOWBANDWIDTH (IAX_CAPABILITY_MEDBANDWIDTH & \
+- ~AST_FORMAT_G726 & \
+- ~AST_FORMAT_G726_AAL2 & \
+- ~AST_FORMAT_ADPCM)
++#define IAX_CAPABILITY_LOWBANDWIDTH (IAX_CAPABILITY_MEDBANDWIDTH & \
++ ~AST_FORMAT_G726 & \
++ ~AST_FORMAT_G726_AAL2 & \
++ ~AST_FORMAT_ADPCM)
+
+-#define IAX_CAPABILITY_LOWFREE (IAX_CAPABILITY_LOWBANDWIDTH & \
+- ~AST_FORMAT_G723_1)
++#define IAX_CAPABILITY_LOWFREE (IAX_CAPABILITY_LOWBANDWIDTH & \
++ ~AST_FORMAT_G723_1)
+
+
+ #define DEFAULT_MAXMS 2000 /* Must be faster than 2 seconds by default */
+@@ -292,7 +334,7 @@
+
+ /* if a pvt has encryption setup done and is running on the call */
+ #define IAX_CALLENCRYPTED(pvt) \
+- (ast_test_flag(pvt, IAX_ENCRYPTED) && ast_test_flag(pvt, IAX_KEYPOPULATED))
++ (ast_test_flag64(pvt, IAX_ENCRYPTED) && ast_test_flag64(pvt, IAX_KEYPOPULATED))
+
+ #define IAX_DEBUGDIGEST(msg, key) do { \
+ int idx; \
+@@ -332,7 +374,7 @@
+ static int delayreject = 0;
+ static int iax2_encryption = 0;
+
+-static struct ast_flags globalflags = { 0 };
++static struct ast_flags64 globalflags = { 0 };
+
+ static pthread_t netthreadid = AST_PTHREADT_NULL;
+
+@@ -347,40 +389,39 @@
+ struct iax2_context *next;
+ };
+
+-enum iax2_flags {
+- IAX_HASCALLERID = (1 << 0), /*!< CallerID has been specified */
+- IAX_DELME = (1 << 1), /*!< Needs to be deleted */
+- IAX_TEMPONLY = (1 << 2), /*!< Temporary (realtime) */
+- IAX_TRUNK = (1 << 3), /*!< Treat as a trunk */
+- IAX_NOTRANSFER = (1 << 4), /*!< Don't native bridge */
+- IAX_USEJITTERBUF = (1 << 5), /*!< Use jitter buffer */
+- IAX_DYNAMIC = (1 << 6), /*!< dynamic peer */
+- IAX_SENDANI = (1 << 7), /*!< Send ANI along with CallerID */
+- /* (1 << 8) is currently unused due to the deprecation of an old option. Go ahead, take it! */
+- IAX_ALREADYGONE = (1 << 9), /*!< Already disconnected */
+- IAX_PROVISION = (1 << 10), /*!< This is a provisioning request */
+- IAX_QUELCH = (1 << 11), /*!< Whether or not we quelch audio */
+- IAX_ENCRYPTED = (1 << 12), /*!< Whether we should assume encrypted tx/rx */
+- IAX_KEYPOPULATED = (1 << 13), /*!< Whether we have a key populated */
+- IAX_CODEC_USER_FIRST = (1 << 14), /*!< are we willing to let the other guy choose the codec? */
+- IAX_CODEC_NOPREFS = (1 << 15), /*!< Force old behaviour by turning off prefs */
+- IAX_CODEC_NOCAP = (1 << 16), /*!< only consider requested format and ignore capabilities*/
+- IAX_RTCACHEFRIENDS = (1 << 17), /*!< let realtime stay till your reload */
+- IAX_RTUPDATE = (1 << 18), /*!< Send a realtime update */
+- IAX_RTAUTOCLEAR = (1 << 19), /*!< erase me on expire */
+- 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_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_IMMEDIATE = (1 << 27), /*!< Allow immediate off-hook to extension s */
+- IAX_FORCE_ENCRYPT = (1 << 28), /*!< Forces call encryption, if encryption not possible hangup */
+-};
+
++#define IAX_HASCALLERID (uint64_t)(1 << 0) /*!< CallerID has been specified */
++#define IAX_DELME (uint64_t)(1 << 1) /*!< Needs to be deleted */
++#define IAX_TEMPONLY (uint64_t)(1 << 2) /*!< Temporary (realtime) */
++#define IAX_TRUNK (uint64_t)(1 << 3) /*!< Treat as a trunk */
++#define IAX_NOTRANSFER (uint64_t)(1 << 4) /*!< Don't native bridge */
++#define IAX_USEJITTERBUF (uint64_t)(1 << 5) /*!< Use jitter buffer */
++#define IAX_DYNAMIC (uint64_t)(1 << 6) /*!< dynamic peer */
++#define IAX_SENDANI (uint64_t)(1 << 7) /*!< Send ANI along with CallerID */
++#define IAX_RTSAVE_SYSNAME (uint64_t)(1 << 8) /*!< Save Systname on Realtime Updates */
++#define IAX_ALREADYGONE (uint64_t)(1 << 9) /*!< Already disconnected */
++#define IAX_PROVISION (uint64_t)(1 << 10) /*!< This is a provisioning request */
++#define IAX_QUELCH (uint64_t)(1 << 11) /*!< Whether or not we quelch audio */
++#define IAX_ENCRYPTED (uint64_t)(1 << 12) /*!< Whether we should assume encrypted tx/rx */
++#define IAX_KEYPOPULATED (uint64_t)(1 << 13) /*!< Whether we have a key populated */
++#define IAX_CODEC_USER_FIRST (uint64_t)(1 << 14) /*!< are we willing to let the other guy choose the codec? */
++#define IAX_CODEC_NOPREFS (uint64_t)(1 << 15) /*!< Force old behaviour by turning off prefs */
++#define IAX_CODEC_NOCAP (uint64_t)(1 << 16) /*!< only consider requested format and ignore capabilities*/
++#define IAX_RTCACHEFRIENDS (uint64_t)(1 << 17) /*!< let realtime stay till your reload */
++#define IAX_RTUPDATE (uint64_t)(1 << 18) /*!< Send a realtime update */
++#define IAX_RTAUTOCLEAR (uint64_t)(1 << 19) /*!< erase me on expire */
++#define IAX_FORCEJITTERBUF (uint64_t)(1 << 20) /*!< Force jitterbuffer, even when bridged to a channel that can take jitter */
++#define IAX_RTIGNOREREGEXPIRE (uint64_t)(1 << 21) /*!< When using realtime, ignore registration expiration */
++#define IAX_TRUNKTIMESTAMPS (uint64_t)(1 << 22) /*!< Send trunk timestamps */
++#define IAX_TRANSFERMEDIA (uint64_t)(1 << 23) /*!< When doing IAX2 transfers, transfer media only */
++#define IAX_MAXAUTHREQ (uint64_t)(1 << 24) /*!< Maximum outstanding AUTHREQ restriction is in place */
++#define IAX_DELAYPBXSTART (uint64_t)(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 */
++#define IAX_ALLOWFWDOWNLOAD (uint64_t)(1 << 26) /*!< Allow the FWDOWNL command? */
++#define IAX_IMMEDIATE (uint64_t)(1 << 27) /*!< Allow immediate off-hook to extension s */
++#define IAX_SENDCONNECTEDLINE (uint64_t)(1 << 28) /*!< Allow sending of connected line updates */
++#define IAX_RECVCONNECTEDLINE (uint64_t)(1 << 29) /*!< Allow receiving of connected line updates */
++#define IAX_FORCE_ENCRYPT (uint64_t)(1 << 30) /*!< Forces call encryption, if encryption not possible hangup */
++
+ static int global_rtautoclear = 120;
+
+ static int reload_config(void);
+@@ -399,12 +440,12 @@
+ AST_STRING_FIELD(cid_name);
+ AST_STRING_FIELD(parkinglot); /*!< Default parkinglot for device */
+ );
+-
++
+ int authmethods;
+ int encmethods;
+ int amaflags;
+ int adsi;
+- unsigned int flags;
++ uint64_t flags;
+ int capability;
+ int maxauthreq; /*!< Maximum allowed outstanding AUTHREQs */
+ int curauthreq; /*!< Current number of outstanding AUTHREQs */
+@@ -442,7 +483,7 @@
+ int sockfd; /*!< Socket to use for transmission */
+ struct in_addr mask;
+ int adsi;
+- unsigned int flags;
++ uint64_t flags;
+
+ /* Dynamic Registration fields */
+ struct sockaddr_in defaddr; /*!< Default address if there is one */
+@@ -543,10 +584,10 @@
+
+ /* Don't retry more frequently than every 10 ms, or less frequently than every 5 seconds */
+ #define MIN_RETRY_TIME 100
+-#define MAX_RETRY_TIME 10000
++#define MAX_RETRY_TIME 10000
+
+-#define MAX_JITTER_BUFFER 50
+-#define MIN_JITTER_BUFFER 10
++#define MAX_JITTER_BUFFER 50
++#define MIN_JITTER_BUFFER 10
+
+ #define DEFAULT_TRUNKDATA 640 * 10 /*!< 40ms, uncompressed linear * 10 channels */
+
+@@ -632,7 +673,7 @@
+ /*! The jitterbuffer */
+ jitterbuf *jb;
+ /*! active jb read scheduler id */
+- int jbid;
++ int jbid;
+ /*! LAG */
+ int lag;
+ /*! Error, as discovered by the manager */
+@@ -714,7 +755,7 @@
+ /*! Associated peer for poking */
+ struct iax2_peer *peerpoke;
+ /*! IAX_ flags */
+- unsigned int flags;
++ uint64_t flags;
+ int adsi;
+
+ /*! Transferring status */
+@@ -733,7 +774,7 @@
+
+ /*! Who we are bridged to */
+ unsigned short bridgecallno;
+-
++
+ int pingid; /*!< Transmit PING request */
+ int lagid; /*!< Retransmit lag request */
+ int autoid; /*!< Auto hangup for Dialplan requestor */
+@@ -765,9 +806,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.
+@@ -824,7 +869,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, int flags);
++static char *complete_iax2_peers(const char *line, const char *word, int pos, int state, uint64_t flags);
+ static char *complete_iax2_unregister(const char *line, const char *word, int pos, int state);
+
+ enum iax2_thread_iostate {
+@@ -1045,7 +1090,7 @@
+ static int iax2_hangup(struct ast_channel *c);
+ 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_provision(struct sockaddr_in *end, int sockfd, const 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);
+ 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);
+@@ -1545,7 +1590,7 @@
+ static void iax2_destroy_helper(struct chan_iax2_pvt *pvt)
+ {
+ /* Decrement AUTHREQ count if needed */
+- if (ast_test_flag(pvt, IAX_MAXAUTHREQ)) {
++ if (ast_test_flag64(pvt, IAX_MAXAUTHREQ)) {
+ struct iax2_user *user;
+ struct iax2_user tmp_user = {
+ .name = pvt->username,
+@@ -1554,10 +1599,10 @@
+ user = ao2_find(users, &tmp_user, OBJ_POINTER);
+ if (user) {
+ ast_atomic_fetchadd_int(&user->curauthreq, -1);
+- user_unref(user);
++ user_unref(user);
+ }
+
+- ast_clear_flag(pvt, IAX_MAXAUTHREQ);
++ ast_clear_flag64(pvt, IAX_MAXAUTHREQ);
+ }
+ /* No more pings or lagrq's */
+ AST_SCHED_DEL_SPINLOCK(ast_sched_thread_get_context(sched), pvt->pingid, &iaxsl[pvt->callno]);
+@@ -1595,21 +1640,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_flag64(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;
+ }
+@@ -1954,7 +1997,7 @@
+ break;
+ }
+ ast_mutex_unlock(&iaxsl[x]);
+-
++
+ if (x == start - 1) {
+ break;
+ }
+@@ -1980,7 +2023,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_flags64(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);
+@@ -2202,7 +2245,7 @@
+ return -1;
+ }
+ fwh = (struct ast_iax2_firmware_header*)mmap(NULL, stbuf.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+- if (fwh == (void *) -1) {
++ if (fwh == MAP_FAILED) {
+ ast_log(LOG_WARNING, "mmap failed: %s\n", strerror(errno));
+ close(fd);
+ return -1;
+@@ -2367,7 +2410,7 @@
+ struct iax_frame *fr = data;
+ fr->retrans = -1;
+ ast_clear_flag(&fr->af, AST_FRFLAG_HAS_TIMING_INFO);
+- if (iaxs[fr->callno] && !ast_test_flag(iaxs[fr->callno], IAX_ALREADYGONE))
++ if (iaxs[fr->callno] && !ast_test_flag64(iaxs[fr->callno], IAX_ALREADYGONE))
+ iax2_queue_frame(fr->callno, &fr->af);
+ /* Free our iax frame */
+ iax2_frame_free(fr);
+@@ -2466,9 +2509,9 @@
+ if (!pvt)
+ return -1;
+
+- if (!ast_test_flag(pvt, IAX_ALREADYGONE)) {
++ if (!ast_test_flag64(pvt, IAX_ALREADYGONE)) {
+ iax2_destroy_helper(pvt);
+- ast_set_flag(pvt, IAX_ALREADYGONE);
++ ast_set_flag64(pvt, IAX_ALREADYGONE);
+ }
+
+ if ((c = pvt->owner)) {
+@@ -2630,17 +2673,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]);
+ }
+ }
+
+@@ -2657,7 +2699,7 @@
+ {
+ struct iax2_peer *peer = NULL;
+ struct iax2_user *user = NULL;
+- static char *choices[] = { "all", NULL };
++ static const char * const choices[] = { "all", NULL };
+ char *cmplt;
+
+ switch (cmd) {
+@@ -2688,8 +2730,8 @@
+ user = find_user(a->argv[3]);
+ if (peer || user) {
+ if (peer) {
+- if (ast_test_flag(peer, IAX_RTCACHEFRIENDS)) {
+- ast_set_flag(peer, IAX_RTAUTOCLEAR);
++ if (ast_test_flag64(peer, IAX_RTCACHEFRIENDS)) {
++ ast_set_flag64(peer, IAX_RTAUTOCLEAR);
+ expire_registry(peer_ref(peer));
+ ast_cli(a->fd, "Peer %s was removed from the cache.\n", a->argv[3]);
+ } else {
+@@ -2698,8 +2740,8 @@
+ peer_unref(peer);
+ }
+ if (user) {
+- if (ast_test_flag(user, IAX_RTCACHEFRIENDS)) {
+- ast_set_flag(user, IAX_RTAUTOCLEAR);
++ if (ast_test_flag64(user, IAX_RTCACHEFRIENDS)) {
++ ast_set_flag64(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]);
+@@ -2864,8 +2906,8 @@
+ ast_cli(a->fd, " Context : %s\n", peer->context);
+ 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, " Dynamic : %s\n", ast_test_flag64(peer, IAX_DYNAMIC) ? "Yes" : "No");
++ ast_cli(a->fd, " Trunk : %s\n", ast_test_flag64(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);
+@@ -2905,7 +2947,7 @@
+ return CLI_SUCCESS;
+ }
+
+-static char *complete_iax2_peers(const char *line, const char *word, int pos, int state, int flags)
++static char *complete_iax2_peers(const char *line, const char *word, int pos, int state, uint64_t flags)
+ {
+ int which = 0;
+ struct iax2_peer *peer;
+@@ -2916,7 +2958,7 @@
+ i = ao2_iterator_init(peers, 0);
+ while ((peer = ao2_iterator_next(&i))) {
+ if (!strncasecmp(peer->name, word, wordlen) && ++which > state
+- && (!flags || ast_test_flag(peer, flags))) {
++ && (!flags || ast_test_flag64(peer, flags))) {
+ res = ast_strdup(peer->name);
+ peer_unref(peer);
+ break;
+@@ -2930,7 +2972,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:
+@@ -2946,15 +2988,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");
+@@ -3188,7 +3232,7 @@
+
+ /* queue the frame: For consistency, we would call __do_deliver here, but __do_deliver wants an iax_frame,
+ * which we'd need to malloc, and then it would free it. That seems like a drag */
+- if (!ast_test_flag(iaxs[callno], IAX_ALREADYGONE)) {
++ if (!ast_test_flag64(iaxs[callno], IAX_ALREADYGONE)) {
+ iax2_queue_frame(callno, &af);
+ /* iax2_queue_frame() could cause the call to disappear */
+ pvt = iaxs[callno];
+@@ -3258,7 +3302,7 @@
+ type = JB_TYPE_SILENCE;
+ }
+
+- if ( (!ast_test_flag(iaxs[fr->callno], IAX_USEJITTERBUF)) ) {
++ if ( (!ast_test_flag64(iaxs[fr->callno], IAX_USEJITTERBUF)) ) {
+ if (tsout)
+ *tsout = fr->ts;
+ __do_deliver(fr);
+@@ -3270,7 +3314,7 @@
+
+ /* if the user hasn't requested we force the use of the jitterbuffer, and we're bridged to
+ * a channel that can accept jitter, then flush and suspend the jb, and send this frame straight through */
+- if ( (!ast_test_flag(iaxs[fr->callno], IAX_FORCEJITTERBUF)) && owner && bridge && (bridge->tech->properties & AST_CHAN_TP_WANTSJITTER) ) {
++ if ( (!ast_test_flag64(iaxs[fr->callno], IAX_FORCEJITTERBUF)) && owner && bridge && (bridge->tech->properties & AST_CHAN_TP_WANTSJITTER) ) {
+ jb_frame frame;
+
+ /* deliver any frames in the jb */
+@@ -3311,23 +3355,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)
+ {
+@@ -3422,8 +3482,8 @@
+ if (!var)
+ return NULL;
+
+- peer = build_peer(peername, var, NULL, ast_test_flag((&globalflags), IAX_RTCACHEFRIENDS) ? 0 : 1);
+-
++ peer = build_peer(peername, var, NULL, ast_test_flag64((&globalflags), IAX_RTCACHEFRIENDS) ? 0 : 1);
++
+ if (!peer) {
+ ast_variables_destroy(var);
+ return NULL;
+@@ -3455,27 +3515,27 @@
+ if (!peer)
+ return NULL;
+
+- if (ast_test_flag((&globalflags), IAX_RTCACHEFRIENDS)) {
+- ast_copy_flags(peer, &globalflags, IAX_RTAUTOCLEAR|IAX_RTCACHEFRIENDS);
+- if (ast_test_flag(peer, IAX_RTAUTOCLEAR)) {
+- if (peer->expire > -1) {
+- if (!ast_sched_thread_del(sched, peer->expire)) {
+- peer->expire = -1;
+- peer_unref(peer);
+- }
+- }
+- peer->expire = iax2_sched_add(sched, (global_rtautoclear) * 1000, expire_registry, peer_ref(peer));
+- if (peer->expire == -1)
+- peer_unref(peer);
++ if (ast_test_flag64((&globalflags), IAX_RTCACHEFRIENDS)) {
++ ast_copy_flags64(peer, &globalflags, IAX_RTAUTOCLEAR|IAX_RTCACHEFRIENDS);
++ if (ast_test_flag64(peer, IAX_RTAUTOCLEAR)) {
++ if (peer->expire > -1) {
++ if (!ast_sched_thread_del(sched, peer->expire)) {
++ peer->expire = -1;
++ peer_unref(peer);
++ }
++ }
++ peer->expire = iax2_sched_add(sched, (global_rtautoclear) * 1000, expire_registry, peer_ref(peer));
++ if (peer->expire == -1)
++ peer_unref(peer);
+ }
+ ao2_link(peers, peer);
+- if (ast_test_flag(peer, IAX_DYNAMIC))
++ if (ast_test_flag64(peer, IAX_DYNAMIC))
+ reg_source_db(peer);
+ } else {
+- ast_set_flag(peer, IAX_TEMPONLY);
++ ast_set_flag64(peer, IAX_TEMPONLY);
+ }
+
+- if (!ast_test_flag(&globalflags, IAX_RTIGNOREREGEXPIRE) && dynamic) {
++ if (!ast_test_flag64(&globalflags, IAX_RTIGNOREREGEXPIRE) && dynamic) {
+ time(&nowtime);
+ if ((nowtime - regseconds) > IAX_DEFAULT_REG_EXPIRE) {
+ memset(&peer->addr, 0, sizeof(peer->addr));
+@@ -3546,18 +3606,18 @@
+ tmp = tmp->next;
+ }
+
+- user = build_user(username, var, NULL, !ast_test_flag((&globalflags), IAX_RTCACHEFRIENDS));
++ user = build_user(username, var, NULL, !ast_test_flag64((&globalflags), IAX_RTCACHEFRIENDS));
+
+ ast_variables_destroy(var);
+
+ if (!user)
+ return NULL;
+
+- if (ast_test_flag((&globalflags), IAX_RTCACHEFRIENDS)) {
+- ast_set_flag(user, IAX_RTCACHEFRIENDS);
++ if (ast_test_flag64((&globalflags), IAX_RTCACHEFRIENDS)) {
++ ast_set_flag64(user, IAX_RTCACHEFRIENDS);
+ ao2_link(users, user);
+ } else {
+- ast_set_flag(user, IAX_TEMPONLY);
++ ast_set_flag64(user, IAX_TEMPONLY);
+ }
+
+ return user;
+@@ -3567,17 +3627,24 @@
+ {
+ char port[10];
+ char regseconds[20];
+-
++ const char *sysname = ast_config_AST_SYSTEM_NAME;
++ char *syslabel = NULL;
++
++ if (ast_strlen_zero(sysname)) /* No system name, disable this */
++ sysname = NULL;
++ else if (ast_test_flag64(&globalflags, IAX_RTSAVE_SYSNAME))
++ syslabel = "regserver";
++
+ snprintf(regseconds, sizeof(regseconds), "%d", (int)regtime);
+ snprintf(port, sizeof(port), "%d", ntohs(sin->sin_port));
+ ast_update_realtime("iaxpeers", "name", peername,
+ "ipaddr", ast_inet_ntoa(sin->sin_addr), "port", port,
+- "regseconds", regseconds, SENTINEL);
++ "regseconds", regseconds, syslabel, sysname, SENTINEL); /* note syslable can be NULL */
+ }
+
+ struct create_addr_info {
+ int capability;
+- unsigned int flags;
++ uint64_t flags;
+ int maxtime;
+ int encmethods;
+ int found;
+@@ -3588,6 +3655,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];
+@@ -3600,7 +3669,7 @@
+ int res = -1;
+ struct ast_codec_pref ourprefs;
+
+- ast_clear_flag(cai, IAX_SENDANI | IAX_TRUNK);
++ ast_clear_flag64(cai, IAX_SENDANI | IAX_TRUNK);
+ cai->sockfd = defaultsockfd;
+ cai->maxtime = 0;
+ sin->sin_family = AF_INET;
+@@ -3631,7 +3700,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_flags64(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;
+@@ -3649,6 +3718,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)) {
+@@ -3838,7 +3909,7 @@
+ 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)) {
++ if (ast_strlen_zero(cai.secret) && ast_test_flag64(iaxs[callno], IAX_FORCE_ENCRYPT)) {
+ ast_log(LOG_WARNING, "Call terminated. No secret given and force encrypt enabled\n");
+ return -1;
+ }
+@@ -3857,8 +3928,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));
+@@ -3875,21 +3946,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_flag64(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);
+@@ -3999,7 +4070,7 @@
+ ast_mutex_lock(&iaxsl[callno]);
+ if (callno && iaxs[callno]) {
+ ast_debug(1, "We're hanging up %s now...\n", c->name);
+- alreadygone = ast_test_flag(iaxs[callno], IAX_ALREADYGONE);
++ alreadygone = ast_test_flag64(iaxs[callno], IAX_ALREADYGONE);
+ /* Send the hangup unless we have had a transmission error or are already gone */
+ iax_ie_append_byte(&ied, IAX_IE_CAUSECODE, (unsigned char)c->hangupcause);
+ if (!iaxs[callno]->error && !alreadygone) {
+@@ -4068,6 +4139,10 @@
+ /* these two cannot be sent, because they require a result */
+ errno = ENOSYS;
+ return -1;
++ case AST_OPTION_FORMAT_READ:
++ case AST_OPTION_FORMAT_WRITE:
++ case AST_OPTION_MAKE_COMPATIBLE:
++ return -1;
+ case AST_OPTION_OPRMODE:
+ errno = EINVAL;
+ return -1;
+@@ -4150,8 +4225,8 @@
+
+ if (IAX_CALLENCRYPTED(iaxs[callno0]) || IAX_CALLENCRYPTED(iaxs[callno1])) {
+ ast_debug(1, "transfers are not supported for encrypted calls at this time");
+- ast_set_flag(iaxs[callno0], IAX_NOTRANSFER);
+- ast_set_flag(iaxs[callno1], IAX_NOTRANSFER);
++ ast_set_flag64(iaxs[callno0], IAX_NOTRANSFER);
++ ast_set_flag64(iaxs[callno1], IAX_NOTRANSFER);
+ return 0;
+ }
+
+@@ -4257,10 +4332,10 @@
+ return AST_BRIDGE_FAILED_NOWARN;
+ }
+ /* 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)) {
++ if (!transferstarted && !ast_test_flag64(iaxs[callno0], IAX_NOTRANSFER) && !ast_test_flag64(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_test_flag64(iaxs[callno0], IAX_TRANSFERMEDIA) | ast_test_flag64(iaxs[callno1], IAX_TRANSFERMEDIA)))
+ ast_log(LOG_WARNING, "Unable to start the transfer\n");
+ transferstarted = 1;
+ }
+@@ -4385,6 +4460,11 @@
+ ast_moh_stop(c);
+ goto done;
+ }
++ break;
++ case AST_CONTROL_CONNECTED_LINE:
++ if (!ast_test_flag64(pvt, IAX_SENDCONNECTEDLINE))
++ goto done;
++ break;
+ }
+
+ res = send_command(pvt, AST_FRAME_CONTROL, condition, 0, data, datalen, -1);
+@@ -4400,6 +4480,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) {
+@@ -4410,6 +4491,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);
+ }
+
+@@ -4423,7 +4505,7 @@
+ while ((peer = ao2_iterator_next(&i))) {
+ if ((peer->addr.sin_addr.s_addr == sin.sin_addr.s_addr) &&
+ (peer->addr.sin_port == sin.sin_port)) {
+- res = ast_test_flag(peer, IAX_TRUNK);
++ res = ast_test_flag64(peer, IAX_TRUNK);
+ peer_unref(peer);
+ break;
+ }
+@@ -4453,7 +4535,7 @@
+ if (tmp) {
+ /* unlock and relock iaxsl[callno] to preserve locking order */
+ ast_mutex_unlock(&iaxsl[callno]);
+- ast_channel_free(tmp);
++ tmp = ast_channel_release(tmp);
+ ast_mutex_lock(&iaxsl[callno]);
+ }
+ return NULL;
+@@ -4835,7 +4917,7 @@
+
+ /* Append to meta frame */
+ ptr = tpeer->trunkdata + IAX2_TRUNK_PREFACE + tpeer->trunkdatalen;
+- if (ast_test_flag(&globalflags, IAX_TRUNKTIMESTAMPS)) {
++ if (ast_test_flag64(&globalflags, IAX_TRUNKTIMESTAMPS)) {
+ mtm = (struct ast_iax2_meta_trunk_mini *)ptr;
+ mtm->len = htons(f->datalen);
+ mtm->mini.callno = htons(pvt->callno);
+@@ -5038,7 +5120,7 @@
+ static int decrypt_frame(int callno, struct ast_iax2_full_hdr *fh, struct ast_frame *f, int *datalen)
+ {
+ int res=-1;
+- if (!ast_test_flag(iaxs[callno], IAX_KEYPOPULATED)) {
++ if (!ast_test_flag64(iaxs[callno], IAX_KEYPOPULATED)) {
+ /* Search for possible keys, given secrets */
+ struct MD5Context md5;
+ unsigned char digest[16];
+@@ -5054,7 +5136,7 @@
+ build_encryption_keys(digest, iaxs[callno]);
+ res = decode_frame(&iaxs[callno]->dcx, fh, f, datalen);
+ if (!res) {
+- ast_set_flag(iaxs[callno], IAX_KEYPOPULATED);
++ ast_set_flag64(iaxs[callno], IAX_KEYPOPULATED);
+ break;
+ }
+ }
+@@ -5110,7 +5192,7 @@
+ iax2_key_rotate(pvt);
+ }
+
+- if ((ast_test_flag(pvt, IAX_TRUNK) ||
++ if ((ast_test_flag64(pvt, IAX_TRUNK) ||
+ (((fts & 0xFFFF0000L) == (lastsent & 0xFFFF0000L)) ||
+ ((fts & 0xFFFF0000L) == ((lastsent + 0x10000) & 0xFFFF0000L))))
+ /* High two bytes are the same on timestamp, or sending on a trunk */ &&
+@@ -5151,7 +5233,7 @@
+ if (now) {
+ fr = &frb.fr2;
+ } else
+- fr = iax_frame_new(DIRECTION_OUTGRESS, ast_test_flag(pvt, IAX_ENCRYPTED) ? f->datalen + 32 : f->datalen, (f->frametype == AST_FRAME_VOICE) || (f->frametype == AST_FRAME_VIDEO));
++ fr = iax_frame_new(DIRECTION_OUTGRESS, ast_test_flag64(pvt, IAX_ENCRYPTED) ? f->datalen + 32 : f->datalen, (f->frametype == AST_FRAME_VOICE) || (f->frametype == AST_FRAME_VIDEO));
+ if (!fr) {
+ ast_log(LOG_WARNING, "Out of memory\n");
+ return -1;
+@@ -5208,8 +5290,8 @@
+ pvt->svoiceformat = f->subclass;
+ else if (f->frametype == AST_FRAME_VIDEO)
+ pvt->svideoformat = f->subclass & ~0x1;
+- if (ast_test_flag(pvt, IAX_ENCRYPTED)) {
+- if (ast_test_flag(pvt, IAX_KEYPOPULATED)) {
++ if (ast_test_flag64(pvt, IAX_ENCRYPTED)) {
++ if (ast_test_flag64(pvt, IAX_KEYPOPULATED)) {
+ if (fr->transfer)
+ iax_outputframe(fr, NULL, 2, &pvt->transfer, fr->datalen - sizeof(struct ast_iax2_full_hdr));
+ else
+@@ -5228,7 +5310,7 @@
+ } else
+ res = iax2_transmit(fr);
+ } else {
+- if (ast_test_flag(pvt, IAX_TRUNK)) {
++ if (ast_test_flag64(pvt, IAX_TRUNK)) {
+ iax2_trunk_queue(pvt, fr);
+ res = 0;
+ } else if (fr->af.frametype == AST_FRAME_VIDEO) {
+@@ -5256,8 +5338,8 @@
+ fr->retries = -1;
+ if (pvt->transferring == TRANSFER_MEDIAPASS)
+ fr->transfer = 1;
+- if (ast_test_flag(pvt, IAX_ENCRYPTED)) {
+- if (ast_test_flag(pvt, IAX_KEYPOPULATED)) {
++ if (ast_test_flag64(pvt, IAX_ENCRYPTED)) {
++ if (ast_test_flag64(pvt, IAX_KEYPOPULATED)) {
+ encrypt_frame(&pvt->ecx, (struct ast_iax2_full_hdr *)mh, pvt->semirand, &fr->datalen);
+ } else
+ ast_log(LOG_WARNING, "Supposed to send packet encrypted, but no key?\n");
+@@ -5313,21 +5395,21 @@
+ user_unref(user), user = ao2_iterator_next(&i)) {
+ if (havepattern && regexec(&regexbuf, user->name, 0, NULL, 0))
+ continue;
+-
++
+ if (!ast_strlen_zero(user->secret)) {
+- ast_copy_string(auth,user->secret, sizeof(auth));
++ ast_copy_string(auth,user->secret, sizeof(auth));
+ } else if (!ast_strlen_zero(user->inkeys)) {
+- snprintf(auth, sizeof(auth), "Key: %-15.15s ", user->inkeys);
+- } else
++ snprintf(auth, sizeof(auth), "Key: %-15.15s ", user->inkeys);
++ } else
+ ast_copy_string(auth, "-no secret-", sizeof(auth));
+-
+- if(ast_test_flag(user,IAX_CODEC_NOCAP))
++
++ if(ast_test_flag64(user, IAX_CODEC_NOCAP))
+ pstr = "REQ Only";
+- else if(ast_test_flag(user,IAX_CODEC_NOPREFS))
++ else if(ast_test_flag64(user, IAX_CODEC_NOPREFS))
+ pstr = "Disabled";
+ else
+- pstr = ast_test_flag(user,IAX_CODEC_USER_FIRST) ? "Caller" : "Host";
+-
++ pstr = ast_test_flag64(user, IAX_CODEC_USER_FIRST) ? "Caller" : "Host";
++
+ ast_cli(a->fd, FORMAT2, user->name, auth, user->authmethods,
+ user->contexts ? user->contexts->context : DEFAULT_CONTEXT,
+ user->ha ? "Yes" : "No", pstr);
+@@ -5341,7 +5423,7 @@
+ #undef FORMAT2
+ }
+
+-static int __iax2_show_peers(int manager, int fd, struct mansession *s, int argc, char *argv[])
++static int __iax2_show_peers(int manager, int fd, struct mansession *s, const int argc, const char * const argv[])
+ {
+ regex_t regexbuf;
+ int havepattern = 0;
+@@ -5441,17 +5523,17 @@
+ 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",
++ ast_test_flag64(peer, IAX_DYNAMIC) ? "yes" : "no",
++ ast_test_flag64(peer, IAX_TRUNK) ? "yes" : "no",
+ peer->encmethods ? ast_str_buffer(encmethods) : "no",
+ status);
+ } 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)",
++ ast_test_flag64(peer, IAX_DYNAMIC) ? "(D)" : "(S)",
+ nm,
+ ntohs(peer->addr.sin_port),
+- ast_test_flag(peer, IAX_TRUNK) ? "(T)" : " ",
++ ast_test_flag64(peer, IAX_TRUNK) ? "(T)" : " ",
+ peer->encmethods ? "(E)" : " ",
+ status,
+ term);
+@@ -5672,14 +5754,14 @@
+ /*! \brief callback to display iax peers in manager */
+ static int manager_iax2_show_peers(struct mansession *s, const struct message *m)
+ {
+- char *a[] = { "iax2", "show", "users" };
++ static const char * const a[] = { "iax2", "show", "peers" };
+ const char *id = astman_get_header(m,"ActionID");
+ char idtext[256] = "";
+
+ if (!ast_strlen_zero(id))
+ snprintf(idtext, sizeof(idtext), "ActionID: %s\r\n", id);
+ astman_send_ack(s, m, "Peer status list will follow");
+- return __iax2_show_peers(1, -1, s, 3, a );
++ return __iax2_show_peers(1, -1, s, 3, a);
+ }
+
+ /*! \brief callback to display iax peers in manager format */
+@@ -5714,8 +5796,8 @@
+ ast_copy_string(nm, ast_inet_ntoa(peer->mask), sizeof(nm));
+ 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, "Dynamic: %s\r\n", ast_test_flag64(peer, IAX_DYNAMIC) ? "Yes" : "No");
++ astman_append(s, "Trunk: %s\r\n", ast_test_flag64(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);
+@@ -5868,7 +5950,7 @@
+ if (iaxs[x]) {
+ int lag, jitter, localdelay;
+ jb_info jbinfo;
+- if (ast_test_flag(iaxs[x], IAX_USEJITTERBUF)) {
++ if (ast_test_flag64(iaxs[x], IAX_USEJITTERBUF)) {
+ jb_getinfo(iaxs[x]->jb, &jbinfo);
+ jitter = jbinfo.jitter;
+ localdelay = jbinfo.current - jbinfo.min;
+@@ -5921,7 +6003,7 @@
+ iax_frame_subclass2str(iaxs[x]->first_iax_message & ~MARK_IAX_SUBCLASS_TX, first_message, sizeof(first_message));
+ iax_frame_subclass2str(iaxs[x]->last_iax_message & ~MARK_IAX_SUBCLASS_TX, last_message, sizeof(last_message));
+
+- if(ast_test_flag(iaxs[x], IAX_USEJITTERBUF)) {
++ if(ast_test_flag64(iaxs[x], IAX_USEJITTERBUF)) {
+ jb_getinfo(iaxs[x]->jb, &jbinfo);
+ localjitter = jbinfo.jitter;
+ localdelay = jbinfo.current - jbinfo.min;
+@@ -6121,12 +6203,12 @@
+ if (iaxs[callno]) {
+ /* If there's an outstanding error, return failure now */
+ if (!iaxs[callno]->error) {
+- if (ast_test_flag(iaxs[callno], IAX_ALREADYGONE))
++ if (ast_test_flag64(iaxs[callno], IAX_ALREADYGONE))
+ res = 0;
+ /* Don't waste bandwidth sending null frames */
+ else if (f->frametype == AST_FRAME_NULL)
+ res = 0;
+- else if ((f->frametype == AST_FRAME_VOICE) && ast_test_flag(iaxs[callno], IAX_QUELCH))
++ else if ((f->frametype == AST_FRAME_VOICE) && ast_test_flag64(iaxs[callno], IAX_QUELCH))
+ res = 0;
+ else if (!ast_test_flag(&iaxs[callno]->state, IAX_STATE_STARTED))
+ res = 0;
+@@ -6347,15 +6429,15 @@
+ }
+ /* If a max AUTHREQ restriction is in place, activate it */
+ if (user->maxauthreq > 0)
+- ast_set_flag(iaxs[callno], IAX_MAXAUTHREQ);
++ ast_set_flag64(iaxs[callno], IAX_MAXAUTHREQ);
+ iaxs[callno]->prefs = user->prefs;
+- ast_copy_flags(iaxs[callno], user, IAX_CODEC_USER_FIRST | IAX_IMMEDIATE | IAX_CODEC_NOPREFS | IAX_CODEC_NOCAP | IAX_FORCE_ENCRYPT);
++ ast_copy_flags64(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))
+ ast_string_field_set(iaxs[callno], username, user->name);
+ /* Store whether this is a trunked call, too, of course, and move if appropriate */
+- ast_copy_flags(iaxs[callno], user, IAX_TRUNK);
++ ast_copy_flags64(iaxs[callno], user, IAX_TRUNK);
+ iaxs[callno]->capability = user->capability;
+ /* And use the default context */
+ if (ast_strlen_zero(iaxs[callno]->context)) {
+@@ -6370,7 +6452,7 @@
+ iaxs[callno]->authmethods = user->authmethods;
+ iaxs[callno]->adsi = user->adsi;
+ /* If the user has callerid, override the remote caller id. */
+- if (ast_test_flag(user, IAX_HASCALLERID)) {
++ if (ast_test_flag64(user, IAX_HASCALLERID)) {
+ iaxs[callno]->calling_tns = 0;
+ iaxs[callno]->calling_ton = 0;
+ ast_string_field_set(iaxs[callno], cid_num, user->cid_num);
+@@ -6392,7 +6474,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_flags64(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;
+@@ -6424,7 +6506,7 @@
+ res = 0;
+ }
+ }
+- ast_set2_flag(iaxs[callno], iax2_getpeertrunk(*sin), IAX_TRUNK);
++ ast_set2_flag64(iaxs[callno], iax2_getpeertrunk(*sin), IAX_TRUNK);
+ return res;
+ }
+
+@@ -6478,7 +6560,7 @@
+ memset(&ied, 0, sizeof(ied));
+
+ /* If an AUTHREQ restriction is in place, make sure we can send an AUTHREQ back */
+- if (ast_test_flag(p, IAX_MAXAUTHREQ)) {
++ if (ast_test_flag64(p, IAX_MAXAUTHREQ)) {
+ struct iax2_user *user, tmp_user = {
+ .name = p->username,
+ };
+@@ -6516,7 +6598,7 @@
+ res = send_command(p, AST_FRAME_IAX, IAX_COMMAND_AUTHREQ, 0, ied.buf, ied.pos, -1);
+
+ if (p->encmethods)
+- ast_set_flag(p, IAX_ENCRYPTED);
++ ast_set_flag64(p, IAX_ENCRYPTED);
+
+ return res;
+ }
+@@ -6538,14 +6620,14 @@
+ }
+ user = ao2_find(users, &tmp_user, OBJ_POINTER);
+ if (user) {
+- if (ast_test_flag(p, IAX_MAXAUTHREQ)) {
++ if (ast_test_flag64(p, IAX_MAXAUTHREQ)) {
+ ast_atomic_fetchadd_int(&user->curauthreq, -1);
+- ast_clear_flag(p, IAX_MAXAUTHREQ);
++ ast_clear_flag64(p, IAX_MAXAUTHREQ);
+ }
+ ast_string_field_set(p, host, user->name);
+ user = user_unref(user);
+ }
+- if (ast_test_flag(p, IAX_FORCE_ENCRYPT) && !p->encmethods) {
++ if (ast_test_flag64(p, IAX_FORCE_ENCRYPT) && !p->encmethods) {
+ ast_log(LOG_NOTICE, "Call Terminated, Incomming call is unencrypted while force encrypt is enabled.");
+ return res;
+ }
+@@ -6663,7 +6745,7 @@
+ goto return_unref;
+ }
+
+- if (!ast_test_flag(p, IAX_DYNAMIC)) {
++ if (!ast_test_flag64(p, IAX_DYNAMIC)) {
+ if (authdebug)
+ ast_log(LOG_NOTICE, "Peer '%s' is not dynamic (from %s)\n", peer, ast_inet_ntoa(sin->sin_addr));
+ goto return_unref;
+@@ -6885,8 +6967,8 @@
+ }
+
+ if (ies->encmethods) {
+- ast_set_flag(p, IAX_ENCRYPTED | IAX_KEYPOPULATED);
+- } else if (ast_test_flag(iaxs[callno], IAX_FORCE_ENCRYPT)) {
++ ast_set_flag64(p, IAX_ENCRYPTED | IAX_KEYPOPULATED);
++ } else if (ast_test_flag64(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 */
+ }
+@@ -7072,16 +7154,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 */
+@@ -7258,21 +7337,21 @@
+ peer->expire = -1;
+
+ ast_debug(1, "Expiring registration for peer '%s'\n", peer->name);
+- if (ast_test_flag((&globalflags), IAX_RTUPDATE) && (ast_test_flag(peer, IAX_TEMPONLY|IAX_RTCACHEFRIENDS)))
++ if (ast_test_flag64((&globalflags), IAX_RTUPDATE) && (ast_test_flag64(peer, IAX_TEMPONLY|IAX_RTCACHEFRIENDS)))
+ realtime_update_peer(peer->name, &peer->addr, 0);
+ manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "ChannelType: IAX2\r\nPeer: IAX2/%s\r\nPeerStatus: Unregistered\r\nCause: Expired\r\n", peer->name);
+ /* Reset the address */
+ memset(&peer->addr, 0, sizeof(peer->addr));
+ /* Reset expiry value */
+ peer->expiry = min_reg_expire;
+- if (!ast_test_flag(peer, IAX_TEMPONLY))
++ if (!ast_test_flag64(peer, IAX_TEMPONLY))
+ ast_db_del("IAX/Registry", peer->name);
+ register_peer_exten(peer, 0);
+ ast_devstate_changed(AST_DEVICE_UNAVAILABLE, "IAX2/%s", peer->name); /* Activate notification */
+ if (iax2_regfunk)
+ iax2_regfunk(peer->name, 0);
+
+- if (ast_test_flag(peer, IAX_RTAUTOCLEAR))
++ if (ast_test_flag64(peer, IAX_RTAUTOCLEAR))
+ unlink_peer(peer);
+
+ peer_unref(peer);
+@@ -7294,7 +7373,7 @@
+ char data[80];
+ struct in_addr in;
+ char *c, *d;
+- if (!ast_test_flag(p, IAX_TEMPONLY) && (!ast_db_get("IAX/Registry", p->name, data, sizeof(data)))) {
++ if (!ast_test_flag64(p, IAX_TEMPONLY) && (!ast_db_get("IAX/Registry", p->name, data, sizeof(data)))) {
+ c = strchr(data, ':');
+ if (c) {
+ *c = '\0';
+@@ -7364,7 +7443,7 @@
+ if (!iaxs[callno])
+ goto return_unref;
+
+- if (ast_test_flag((&globalflags), IAX_RTUPDATE) && (ast_test_flag(p, IAX_TEMPONLY|IAX_RTCACHEFRIENDS))) {
++ if (ast_test_flag64((&globalflags), IAX_RTUPDATE) && (ast_test_flag64(p, IAX_TEMPONLY|IAX_RTCACHEFRIENDS))) {
+ if (sin->sin_addr.s_addr) {
+ time_t nowtime;
+ time(&nowtime);
+@@ -7379,14 +7458,14 @@
+ /* Stash the IP address from which they registered */
+ memcpy(&p->addr, sin, sizeof(p->addr));
+ snprintf(data, sizeof(data), "%s:%d:%d", ast_inet_ntoa(sin->sin_addr), ntohs(sin->sin_port), p->expiry);
+- if (!ast_test_flag(p, IAX_TEMPONLY) && sin->sin_addr.s_addr) {
++ if (!ast_test_flag64(p, IAX_TEMPONLY) && sin->sin_addr.s_addr) {
+ ast_db_put("IAX/Registry", p->name, data);
+ ast_verb(3, "Registered IAX2 '%s' (%s) at %s:%d\n", p->name,
+ ast_test_flag(&iaxs[callno]->state, IAX_STATE_AUTHENTICATED) ? "AUTHENTICATED" : "UNAUTHENTICATED", ast_inet_ntoa(sin->sin_addr), ntohs(sin->sin_port));
+ manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "ChannelType: IAX2\r\nPeer: IAX2/%s\r\nPeerStatus: Registered\r\n", p->name);
+ register_peer_exten(p, 1);
+ ast_devstate_changed(AST_DEVICE_UNKNOWN, "IAX2/%s", p->name); /* Activate notification */
+- } else if (!ast_test_flag(p, IAX_TEMPONLY)) {
++ } else if (!ast_test_flag64(p, IAX_TEMPONLY)) {
+ ast_verb(3, "Unregistered IAX2 '%s' (%s)\n", p->name,
+ ast_test_flag(&iaxs[callno]->state, IAX_STATE_AUTHENTICATED) ? "AUTHENTICATED" : "UNAUTHENTICATED");
+ manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "ChannelType: IAX2\r\nPeer: IAX2/%s\r\nPeerStatus: Unregistered\r\n", p->name);
+@@ -7470,7 +7549,7 @@
+
+ iax_ie_append_short(&ied, IAX_IE_MSGCOUNT, msgcount);
+ }
+- if (ast_test_flag(p, IAX_HASCALLERID)) {
++ if (ast_test_flag64(p, IAX_HASCALLERID)) {
+ iax_ie_append_str(&ied, IAX_IE_CALLING_NUMBER, p->cid_num);
+ iax_ie_append_str(&ied, IAX_IE_CALLING_NAME, p->cid_name);
+ }
+@@ -7687,16 +7766,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)
+@@ -7734,7 +7810,7 @@
+ /* We're actually sending a frame, so fill the meta trunk header and meta header */
+ meta->zeros = 0;
+ meta->metacmd = IAX_META_TRUNK;
+- if (ast_test_flag(&globalflags, IAX_TRUNKTIMESTAMPS))
++ if (ast_test_flag64(&globalflags, IAX_TRUNKTIMESTAMPS))
+ meta->cmddata = IAX_META_TRUNK_MINI;
+ else
+ meta->cmddata = IAX_META_TRUNK_SUPERMINI;
+@@ -7972,9 +8048,6 @@
+ return -1;
+ }
+
+-
+-static int iax2_provision(struct sockaddr_in *end, int sockfd, char *dest, const char *template, int force);
+-
+ static int check_provisioning(struct sockaddr_in *sin, int sockfd, char *si, unsigned int ver)
+ {
+ unsigned int ourver;
+@@ -8052,7 +8125,7 @@
+
+ ast_mutex_lock(&iaxsl[callno]);
+ if (iaxs[callno] && iaxs[callno]->owner && iaxs[callno]->owner->name) {
+- if(ast_test_flag(iaxs[callno], IAX_USEJITTERBUF)) {
++ if(ast_test_flag64(iaxs[callno], IAX_USEJITTERBUF)) {
+ jb_getinfo(iaxs[callno]->jb, &jbinfo);
+ localjitter = jbinfo.jitter;
+ localdelay = jbinfo.current - jbinfo.min;
+@@ -8518,7 +8591,7 @@
+ /* Deal with POKE/PONG without allocating a callno */
+ if (f.frametype == AST_FRAME_IAX && f.subclass == IAX_COMMAND_POKE) {
+ /* Reply back with a PONG, but don't care about the result. */
+- send_apathetic_reply(1, ntohs(fh->scallno), &sin, IAX_COMMAND_PONG, ntohs(fh->ts), fh->iseqno + 1);
++ send_apathetic_reply(1, ntohs(fh->scallno), &sin, IAX_COMMAND_PONG, ntohl(fh->ts), fh->iseqno + 1);
+ return 1;
+ } else if (f.frametype == AST_FRAME_IAX && f.subclass == IAX_COMMAND_ACK && dcallno == 1) {
+ /* Ignore */
+@@ -8577,7 +8650,7 @@
+ ast_mutex_unlock(&iaxsl[fr->callno]);
+ return 1;
+ }
+- if (ast_test_flag(iaxs[fr->callno], IAX_ENCRYPTED)) {
++ if (ast_test_flag64(iaxs[fr->callno], IAX_ENCRYPTED)) {
+ if (decrypt_frame(fr->callno, fh, &f, &res)) {
+ ast_log(LOG_NOTICE, "Packet Decrypt Failed!\n");
+ ast_mutex_unlock(&iaxsl[fr->callno]);
+@@ -8713,17 +8786,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);
+@@ -8780,8 +8851,8 @@
+ if ((f.frametype == AST_FRAME_VOICE) ||
+ (f.frametype == AST_FRAME_VIDEO) ||
+ (f.frametype == AST_FRAME_IAX)) {
+- if (ast_test_flag(iaxs[fr->callno], IAX_DELAYPBXSTART)) {
+- ast_clear_flag(iaxs[fr->callno], IAX_DELAYPBXSTART);
++ if (ast_test_flag64(iaxs[fr->callno], IAX_DELAYPBXSTART)) {
++ ast_clear_flag64(iaxs[fr->callno], IAX_DELAYPBXSTART);
+ if (!ast_iax2_new(fr->callno, AST_STATE_RING, iaxs[fr->callno]->chosenformat)) {
+ ast_mutex_unlock(&iaxsl[fr->callno]);
+ return 1;
+@@ -8928,7 +8999,7 @@
+ iaxs[fr->callno]->owner->uniqueid);
+ }
+
+- ast_set_flag(iaxs[fr->callno], IAX_QUELCH);
++ ast_set_flag64(iaxs[fr->callno], IAX_QUELCH);
+ if (ies.musiconhold) {
+ if (iaxs[fr->callno]->owner && ast_bridged_channel(iaxs[fr->callno]->owner)) {
+ const char *moh_suggest = iaxs[fr->callno]->mohsuggest;
+@@ -8946,7 +9017,7 @@
+ case IAX_COMMAND_UNQUELCH:
+ if (ast_test_flag(&iaxs[fr->callno]->state, IAX_STATE_STARTED)) {
+ /* Generate Manager Unhold event, if necessary*/
+- if (iaxs[fr->callno]->owner && ast_test_flag(iaxs[fr->callno], IAX_QUELCH)) {
++ if (iaxs[fr->callno]->owner && ast_test_flag64(iaxs[fr->callno], IAX_QUELCH)) {
+ manager_event(EVENT_FLAG_CALL, "Hold",
+ "Status: Off\r\n"
+ "Channel: %s\r\n"
+@@ -8955,7 +9026,7 @@
+ iaxs[fr->callno]->owner->uniqueid);
+ }
+
+- ast_clear_flag(iaxs[fr->callno], IAX_QUELCH);
++ ast_clear_flag64(iaxs[fr->callno], IAX_QUELCH);
+ if (iaxs[fr->callno]->owner && ast_bridged_channel(iaxs[fr->callno]->owner)) {
+ iax2_queue_control_data(fr->callno, AST_CONTROL_UNHOLD, NULL, 0);
+ if (!iaxs[fr->callno]) {
+@@ -8968,13 +9039,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);
+@@ -8995,7 +9065,7 @@
+ }
+ }
+ /* If we're in trunk mode, do it now, and update the trunk number in our frame before continuing */
+- if (ast_test_flag(iaxs[fr->callno], IAX_TRUNK)) {
++ if (ast_test_flag64(iaxs[fr->callno], IAX_TRUNK)) {
+ int new_callno;
+ if ((new_callno = make_trunk(fr->callno, 1)) != -1)
+ fr->callno = new_callno;
+@@ -9010,7 +9080,7 @@
+ 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)) {
++ if (ast_strlen_zero(iaxs[fr->callno]->secret) && ast_test_flag64(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;
+@@ -9050,8 +9120,8 @@
+ } else {
+ /* Select an appropriate format */
+
+- if(ast_test_flag(iaxs[fr->callno], IAX_CODEC_NOPREFS)) {
+- if(ast_test_flag(iaxs[fr->callno], IAX_CODEC_NOCAP)) {
++ if(ast_test_flag64(iaxs[fr->callno], IAX_CODEC_NOPREFS)) {
++ if(ast_test_flag64(iaxs[fr->callno], IAX_CODEC_NOCAP)) {
+ using_prefs = "reqonly";
+ } else {
+ using_prefs = "disabled";
+@@ -9067,7 +9137,7 @@
+ ast_codec_pref_convert(&iaxs[fr->callno]->rprefs, ies.codec_prefs, 32, 0);
+ if (ast_codec_pref_index(&iaxs[fr->callno]->rprefs, 0)) {
+ /* If we are codec_first_choice we let the caller have the 1st shot at picking the codec.*/
+- if (ast_test_flag(iaxs[fr->callno], IAX_CODEC_USER_FIRST)) {
++ if (ast_test_flag64(iaxs[fr->callno], IAX_CODEC_USER_FIRST)) {
+ pref = iaxs[fr->callno]->rprefs;
+ using_prefs = "caller";
+ } else {
+@@ -9075,13 +9145,13 @@
+ }
+ } else
+ pref = iaxs[fr->callno]->prefs;
+-
++
+ format = ast_codec_choose(&pref, iaxs[fr->callno]->capability & iaxs[fr->callno]->peercapability, 0);
+ ast_codec_pref_string(&iaxs[fr->callno]->rprefs, caller_pref_buf, sizeof(caller_pref_buf) - 1);
+ ast_codec_pref_string(&iaxs[fr->callno]->prefs, host_pref_buf, sizeof(host_pref_buf) - 1);
+ }
+ if (!format) {
+- if(!ast_test_flag(iaxs[fr->callno], IAX_CODEC_NOCAP))
++ if(!ast_test_flag64(iaxs[fr->callno], IAX_CODEC_NOCAP))
+ format = iaxs[fr->callno]->peercapability & iaxs[fr->callno]->capability;
+ if (!format) {
+ memset(&ied0, 0, sizeof(ied0));
+@@ -9093,19 +9163,19 @@
+ return 1;
+ }
+ if (authdebug) {
+- if(ast_test_flag(iaxs[fr->callno], IAX_CODEC_NOCAP))
++ if(ast_test_flag64(iaxs[fr->callno], IAX_CODEC_NOCAP))
+ ast_log(LOG_NOTICE, "Rejected connect attempt from %s, requested 0x%x incompatible with our capability 0x%x.\n", ast_inet_ntoa(sin.sin_addr), iaxs[fr->callno]->peerformat, iaxs[fr->callno]->capability);
+ else
+ ast_log(LOG_NOTICE, "Rejected connect attempt from %s, requested/capability 0x%x/0x%x incompatible with our capability 0x%x.\n", ast_inet_ntoa(sin.sin_addr), iaxs[fr->callno]->peerformat, iaxs[fr->callno]->peercapability, iaxs[fr->callno]->capability);
+ }
+ } else {
+ /* Pick one... */
+- if(ast_test_flag(iaxs[fr->callno], IAX_CODEC_NOCAP)) {
++ if(ast_test_flag64(iaxs[fr->callno], IAX_CODEC_NOCAP)) {
+ if(!(iaxs[fr->callno]->peerformat & iaxs[fr->callno]->capability))
+ format = 0;
+ } else {
+- if(ast_test_flag(iaxs[fr->callno], IAX_CODEC_NOPREFS)) {
+- using_prefs = ast_test_flag(iaxs[fr->callno], IAX_CODEC_NOCAP) ? "reqonly" : "disabled";
++ if(ast_test_flag64(iaxs[fr->callno], IAX_CODEC_NOPREFS)) {
++ using_prefs = ast_test_flag64(iaxs[fr->callno], IAX_CODEC_NOCAP) ? "reqonly" : "disabled";
+ memset(&pref, 0, sizeof(pref));
+ format = ast_best_codec(iaxs[fr->callno]->peercapability & iaxs[fr->callno]->capability);
+ strcpy(caller_pref_buf,"disabled");
+@@ -9114,16 +9184,15 @@
+ using_prefs = "mine";
+ if (ast_codec_pref_index(&iaxs[fr->callno]->rprefs, 0)) {
+ /* Do the opposite of what we tried above. */
+- if (ast_test_flag(iaxs[fr->callno], IAX_CODEC_USER_FIRST)) {
+- pref = iaxs[fr->callno]->prefs;
++ if (ast_test_flag64(iaxs[fr->callno], IAX_CODEC_USER_FIRST)) {
++ pref = iaxs[fr->callno]->prefs;
+ } else {
+ pref = iaxs[fr->callno]->rprefs;
+ using_prefs = "caller";
+ }
+ format = ast_codec_choose(&pref, iaxs[fr->callno]->peercapability & iaxs[fr->callno]->capability, 1);
+-
+ } else /* if no codec_prefs IE do it the old way */
+- format = ast_best_codec(iaxs[fr->callno]->peercapability & iaxs[fr->callno]->capability);
++ format = ast_best_codec(iaxs[fr->callno]->peercapability & iaxs[fr->callno]->capability);
+ }
+ }
+
+@@ -9139,7 +9208,7 @@
+ }
+ if (authdebug)
+ ast_log(LOG_NOTICE, "Rejected connect attempt from %s, requested/capability 0x%x/0x%x incompatible with our capability 0x%x.\n", ast_inet_ntoa(sin.sin_addr), iaxs[fr->callno]->peerformat, iaxs[fr->callno]->peercapability, iaxs[fr->callno]->capability);
+- ast_set_flag(iaxs[fr->callno], IAX_ALREADYGONE);
++ ast_set_flag64(iaxs[fr->callno], IAX_ALREADYGONE);
+ break;
+ }
+ }
+@@ -9168,9 +9237,9 @@
+ host_pref_buf,
+ VERBOSE_PREFIX_4,
+ using_prefs);
+-
++
+ iaxs[fr->callno]->chosenformat = format;
+- ast_set_flag(iaxs[fr->callno], IAX_DELAYPBXSTART);
++ ast_set_flag64(iaxs[fr->callno], IAX_DELAYPBXSTART);
+ } else {
+ ast_set_flag(&iaxs[fr->callno]->state, IAX_STATE_TBD);
+ /* If this is a TBD call, we're ready but now what... */
+@@ -9205,7 +9274,7 @@
+ }
+ break;
+ case IAX_COMMAND_HANGUP:
+- ast_set_flag(iaxs[fr->callno], IAX_ALREADYGONE);
++ ast_set_flag64(iaxs[fr->callno], IAX_ALREADYGONE);
+ ast_debug(1, "Immediately destroying %d, having received hangup\n", fr->callno);
+ /* Set hangup cause according to remote */
+ if (ies.causecode && iaxs[fr->callno]->owner)
+@@ -9219,7 +9288,7 @@
+ if (ies.causecode && iaxs[fr->callno]->owner)
+ iaxs[fr->callno]->owner->hangupcause = ies.causecode;
+
+- if (!ast_test_flag(iaxs[fr->callno], IAX_PROVISION)) {
++ if (!ast_test_flag64(iaxs[fr->callno], IAX_PROVISION)) {
+ if (iaxs[fr->callno]->owner && authdebug)
+ ast_log(LOG_WARNING, "Call rejected by %s: %s\n",
+ ast_inet_ntoa(iaxs[fr->callno]->addr.sin_addr),
+@@ -9230,7 +9299,7 @@
+ /* Send ack immediately, before we destroy */
+ send_command_immediate(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_ACK,
+ fr->ts, NULL, 0, fr->iseqno);
+- if (!ast_test_flag(iaxs[fr->callno], IAX_PROVISION))
++ if (!ast_test_flag64(iaxs[fr->callno], IAX_PROVISION))
+ iaxs[fr->callno]->error = EPERM;
+ iax2_destroy(fr->callno);
+ break;
+@@ -9278,7 +9347,7 @@
+ /* Ignore if call is already up or needs authentication or is a TBD */
+ if (ast_test_flag(&iaxs[fr->callno]->state, IAX_STATE_STARTED | IAX_STATE_TBD | IAX_STATE_AUTHENTICATED))
+ break;
+- if (ast_test_flag(iaxs[fr->callno], IAX_PROVISION)) {
++ if (ast_test_flag64(iaxs[fr->callno], IAX_PROVISION)) {
+ /* Send ack immediately, before we destroy */
+ send_command_immediate(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_ACK, fr->ts, NULL, 0,fr->iseqno);
+ iax2_destroy(fr->callno);
+@@ -9479,8 +9548,8 @@
+ }
+ } else {
+ /* Select an appropriate format */
+- if(ast_test_flag(iaxs[fr->callno], IAX_CODEC_NOPREFS)) {
+- if(ast_test_flag(iaxs[fr->callno], IAX_CODEC_NOCAP)) {
++ if(ast_test_flag64(iaxs[fr->callno], IAX_CODEC_NOPREFS)) {
++ if(ast_test_flag64(iaxs[fr->callno], IAX_CODEC_NOCAP)) {
+ using_prefs = "reqonly";
+ } else {
+ using_prefs = "disabled";
+@@ -9494,7 +9563,7 @@
+ if (ies.codec_prefs)
+ ast_codec_pref_convert(&iaxs[fr->callno]->rprefs, ies.codec_prefs, 32, 0);
+ if (ast_codec_pref_index(&iaxs[fr->callno]->rprefs, 0)) {
+- if (ast_test_flag(iaxs[fr->callno], IAX_CODEC_USER_FIRST)) {
++ if (ast_test_flag64(iaxs[fr->callno], IAX_CODEC_USER_FIRST)) {
+ pref = iaxs[fr->callno]->rprefs;
+ using_prefs = "caller";
+ } else {
+@@ -9502,19 +9571,18 @@
+ }
+ } else /* if no codec_prefs IE do it the old way */
+ pref = iaxs[fr->callno]->prefs;
+-
+ format = ast_codec_choose(&pref, iaxs[fr->callno]->capability & iaxs[fr->callno]->peercapability, 0);
+ ast_codec_pref_string(&iaxs[fr->callno]->rprefs, caller_pref_buf, sizeof(caller_pref_buf) - 1);
+ ast_codec_pref_string(&iaxs[fr->callno]->prefs, host_pref_buf, sizeof(host_pref_buf) - 1);
+ }
+ if (!format) {
+- if(!ast_test_flag(iaxs[fr->callno], IAX_CODEC_NOCAP)) {
++ if(!ast_test_flag64(iaxs[fr->callno], IAX_CODEC_NOCAP)) {
+ ast_debug(1, "We don't do requested format %s, falling back to peer capability %d\n", ast_getformatname(iaxs[fr->callno]->peerformat), iaxs[fr->callno]->peercapability);
+ format = iaxs[fr->callno]->peercapability & iaxs[fr->callno]->capability;
+ }
+ if (!format) {
+ if (authdebug) {
+- if(ast_test_flag(iaxs[fr->callno], IAX_CODEC_NOCAP))
++ if(ast_test_flag64(iaxs[fr->callno], IAX_CODEC_NOCAP))
+ ast_log(LOG_NOTICE, "Rejected connect attempt from %s, requested 0x%x incompatible with our capability 0x%x.\n", ast_inet_ntoa(sin.sin_addr), iaxs[fr->callno]->peerformat, iaxs[fr->callno]->capability);
+ else
+ ast_log(LOG_NOTICE, "Rejected connect attempt from %s, requested/capability 0x%x/0x%x incompatible with our capability 0x%x.\n", ast_inet_ntoa(sin.sin_addr), iaxs[fr->callno]->peerformat, iaxs[fr->callno]->peercapability, iaxs[fr->callno]->capability);
+@@ -9529,14 +9597,14 @@
+ }
+ } else {
+ /* Pick one... */
+- if(ast_test_flag(iaxs[fr->callno], IAX_CODEC_NOCAP)) {
++ if(ast_test_flag64(iaxs[fr->callno], IAX_CODEC_NOCAP)) {
+ if(!(iaxs[fr->callno]->peerformat & iaxs[fr->callno]->capability))
+ format = 0;
+ } else {
+- if(ast_test_flag(iaxs[fr->callno], IAX_CODEC_NOPREFS)) {
+- using_prefs = ast_test_flag(iaxs[fr->callno], IAX_CODEC_NOCAP) ? "reqonly" : "disabled";
++ if(ast_test_flag64(iaxs[fr->callno], IAX_CODEC_NOPREFS)) {
++ using_prefs = ast_test_flag64(iaxs[fr->callno], IAX_CODEC_NOCAP) ? "reqonly" : "disabled";
+ memset(&pref, 0, sizeof(pref));
+- format = ast_test_flag(iaxs[fr->callno], IAX_CODEC_NOCAP) ?
++ format = ast_test_flag64(iaxs[fr->callno], IAX_CODEC_NOCAP) ?
+ iaxs[fr->callno]->peerformat : ast_best_codec(iaxs[fr->callno]->peercapability & iaxs[fr->callno]->capability);
+ strcpy(caller_pref_buf,"disabled");
+ strcpy(host_pref_buf,"disabled");
+@@ -9544,8 +9612,8 @@
+ using_prefs = "mine";
+ if (ast_codec_pref_index(&iaxs[fr->callno]->rprefs, 0)) {
+ /* Do the opposite of what we tried above. */
+- if (ast_test_flag(iaxs[fr->callno], IAX_CODEC_USER_FIRST)) {
+- pref = iaxs[fr->callno]->prefs;
++ if (ast_test_flag64(iaxs[fr->callno], IAX_CODEC_USER_FIRST)) {
++ pref = iaxs[fr->callno]->prefs;
+ } else {
+ pref = iaxs[fr->callno]->rprefs;
+ using_prefs = "caller";
+@@ -9558,7 +9626,7 @@
+ if (!format) {
+ ast_log(LOG_ERROR, "No best format in 0x%x???\n", iaxs[fr->callno]->peercapability & iaxs[fr->callno]->capability);
+ if (authdebug) {
+- if(ast_test_flag(iaxs[fr->callno], IAX_CODEC_NOCAP))
++ if(ast_test_flag64(iaxs[fr->callno], IAX_CODEC_NOCAP))
+ ast_log(LOG_NOTICE, "Rejected connect attempt from %s, requested 0x%x incompatible with our capability 0x%x.\n", ast_inet_ntoa(sin.sin_addr), iaxs[fr->callno]->peerformat, iaxs[fr->callno]->capability);
+ else
+ ast_log(LOG_NOTICE, "Rejected connect attempt from %s, requested/capability 0x%x/0x%x incompatible with our capability 0x%x.\n", ast_inet_ntoa(sin.sin_addr), iaxs[fr->callno]->peerformat, iaxs[fr->callno]->peercapability, iaxs[fr->callno]->capability);
+@@ -9641,7 +9709,7 @@
+ 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)) {
++ if (ast_test_flag64(iaxs[fr->callno], IAX_IMMEDIATE)) {
+ goto immediatedial;
+ }
+ }
+@@ -9840,8 +9908,8 @@
+
+ iaxs[iaxs[fr->callno]->bridgecallno]->transferring = TRANSFER_RELEASED;
+ iaxs[fr->callno]->transferring = TRANSFER_RELEASED;
+- ast_set_flag(iaxs[iaxs[fr->callno]->bridgecallno], IAX_ALREADYGONE);
+- ast_set_flag(iaxs[fr->callno], IAX_ALREADYGONE);
++ ast_set_flag64(iaxs[iaxs[fr->callno]->bridgecallno], IAX_ALREADYGONE);
++ ast_set_flag64(iaxs[fr->callno], IAX_ALREADYGONE);
+
+ /* Stop doing lag & ping requests */
+ stop_stuff(fr->callno);
+@@ -9874,13 +9942,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;
+ }
+@@ -9906,7 +9973,7 @@
+ break;
+ case IAX_COMMAND_FWDOWNL:
+ /* Firmware download */
+- if (!ast_test_flag(&globalflags, IAX_ALLOWFWDOWNLOAD)) {
++ if (!ast_test_flag64(&globalflags, IAX_ALLOWFWDOWNLOAD)) {
+ send_command_final(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_UNSUPPORT, 0, NULL, 0, -1);
+ break;
+ }
+@@ -10006,6 +10073,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_flag64(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;
+@@ -10243,7 +10335,7 @@
+ return 0;
+ }
+
+-static int iax2_provision(struct sockaddr_in *end, int sockfd, char *dest, const char *template, int force)
++static int iax2_provision(struct sockaddr_in *end, int sockfd, const char *dest, const char *template, int force)
+ {
+ /* Returns 1 if provisioned, -1 if not able to find destination, or 0 if no provisioning
+ is found for template */
+@@ -10281,7 +10373,7 @@
+ /* Schedule autodestruct in case they don't ever give us anything back */
+ iaxs[callno]->autoid = iax2_sched_replace(iaxs[callno]->autoid,
+ sched, 15000, auto_hangup, (void *)(long)callno);
+- ast_set_flag(iaxs[callno], IAX_PROVISION);
++ ast_set_flag64(iaxs[callno], IAX_PROVISION);
+ /* Got a call number now, so go ahead and send the provisioning information */
+ send_command(iaxs[callno], AST_FRAME_IAX, IAX_COMMAND_PROVISION, 0, ied.buf, ied.pos, -1);
+ }
+@@ -10295,7 +10387,7 @@
+ /*! iax2provision
+ \ingroup applications
+ */
+-static int iax2_prov_app(struct ast_channel *chan, void *data)
++static int iax2_prov_app(struct ast_channel *chan, const char *data)
+ {
+ int res;
+ char *sdata;
+@@ -10501,7 +10593,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_flags64(&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)) {
+@@ -10520,8 +10612,8 @@
+ }
+
+ /* 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);
+- if (ast_test_flag(&cai, IAX_TRUNK)) {
++ ast_copy_flags64(iaxs[callno], &cai, IAX_TRUNK | IAX_SENDANI | IAX_NOTRANSFER | IAX_TRANSFERMEDIA | IAX_USEJITTERBUF | IAX_FORCEJITTERBUF | IAX_SENDCONNECTEDLINE | IAX_RECVCONNECTEDLINE);
++ if (ast_test_flag64(&cai, IAX_TRUNK)) {
+ int new_callno;
+ if ((new_callno = make_trunk(callno, 1)) != -1)
+ callno = new_callno;
+@@ -10559,66 +10651,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)
++ if (timer) {
+ ast_io_add(io, ast_timer_fd(timer), timing_read, AST_IO_IN | AST_IO_PRI, NULL);
+-
+- for(;;) {
+- pthread_testcancel();
++ }
+
+- /* 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);
+-
++ for (;;) {
+ pthread_testcancel();
+- if (count >= 20)
+- ast_debug(1, "chan_iax2: Sent %d queued outbound frames all at once\n", count);
++ /* 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);
++ }
+
+- /* 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;
+ }
+
+@@ -10810,7 +10854,7 @@
+
+ if (!temponly) {
+ peer = ao2_find(peers, &tmp_peer, OBJ_POINTER);
+- if (peer && !ast_test_flag(peer, IAX_DELME))
++ if (peer && !ast_test_flag64(peer, IAX_DELME))
+ firstpass = 0;
+ }
+
+@@ -10831,7 +10875,7 @@
+
+ if (peer) {
+ if (firstpass) {
+- ast_copy_flags(peer, &globalflags, IAX_USEJITTERBUF | IAX_FORCEJITTERBUF | IAX_FORCE_ENCRYPT);
++ ast_copy_flags64(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,"");
+@@ -10847,7 +10891,7 @@
+ peer->pokefreqnotok = DEFAULT_FREQ_NOTOK;
+ ast_string_field_set(peer,context,"");
+ ast_string_field_set(peer,peercontext,"");
+- ast_clear_flag(peer, IAX_HASCALLERID);
++ ast_clear_flag64(peer, IAX_HASCALLERID);
+ ast_string_field_set(peer, cid_name, "");
+ ast_string_field_set(peer, cid_num, "");
+ ast_string_field_set(peer, mohinterpret, mohinterpret);
+@@ -10874,42 +10918,42 @@
+ } else if (!strcasecmp(v->name, "dbsecret")) {
+ 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) && !timer) {
++ ast_set2_flag64(peer, ast_true(v->value), IAX_TRUNK);
++ if (ast_test_flag64(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);
++ ast_clear_flag64(peer, IAX_TRUNK);
+ }
+ } 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);
+ if (!peer->encmethods) {
+- ast_clear_flag(peer, IAX_FORCE_ENCRYPT);
++ ast_clear_flag64(peer, IAX_FORCE_ENCRYPT);
+ }
+ } else if (!strcasecmp(v->name, "forceencryption")) {
+ if (ast_false(v->value)) {
+- ast_clear_flag(peer, IAX_FORCE_ENCRYPT);
++ ast_clear_flag64(peer, IAX_FORCE_ENCRYPT);
+ } else {
+ peer->encmethods |= get_encrypt_methods(v->value);
+ if (peer->encmethods) {
+- ast_set_flag(peer, IAX_FORCE_ENCRYPT);
++ ast_set_flag64(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);
++ ast_set_flags_to64(peer, IAX_NOTRANSFER|IAX_TRANSFERMEDIA, IAX_TRANSFERMEDIA);
+ } else if (ast_true(v->value)) {
+- ast_set_flags_to(peer, IAX_NOTRANSFER|IAX_TRANSFERMEDIA, 0);
+- } else
+- ast_set_flags_to(peer, IAX_NOTRANSFER|IAX_TRANSFERMEDIA, IAX_NOTRANSFER);
++ ast_set_flags_to64(peer, IAX_NOTRANSFER|IAX_TRANSFERMEDIA, 0);
++ } else
++ ast_set_flags_to64(peer, IAX_NOTRANSFER|IAX_TRANSFERMEDIA, IAX_NOTRANSFER);
+ } else if (!strcasecmp(v->name, "jitterbuffer")) {
+- ast_set2_flag(peer, ast_true(v->value), IAX_USEJITTERBUF);
++ ast_set2_flag64(peer, ast_true(v->value), IAX_USEJITTERBUF);
+ } else if (!strcasecmp(v->name, "forcejitterbuffer")) {
+- ast_set2_flag(peer, ast_true(v->value), IAX_FORCEJITTERBUF);
++ ast_set2_flag64(peer, ast_true(v->value), IAX_FORCEJITTERBUF);
+ } else if (!strcasecmp(v->name, "host")) {
+ if (!strcasecmp(v->value, "dynamic")) {
+ /* They'll register with us */
+- ast_set_flag(peer, IAX_DYNAMIC);
++ ast_set_flag64(peer, IAX_DYNAMIC);
+ if (!found) {
+ /* Initialize stuff iff we're not found, otherwise
+ we keep going with what we had */
+@@ -10923,7 +10967,7 @@
+ } else {
+ /* Non-dynamic. Make sure we become that way if we're not */
+ ast_sched_thread_del(sched, peer->expire);
+- ast_clear_flag(peer, IAX_DYNAMIC);
++ ast_clear_flag64(peer, IAX_DYNAMIC);
+ if (ast_dnsmgr_lookup(v->value, &peer->addr, &peer->dnsmgr, srvlookup ? "_iax._udp" : NULL))
+ return peer_unref(peer);
+ if (!peer->addr.sin_port)
+@@ -10949,7 +10993,7 @@
+ } else if (!strcasecmp(v->name, "peercontext")) {
+ ast_string_field_set(peer, peercontext, v->value);
+ } else if (!strcasecmp(v->name, "port")) {
+- if (ast_test_flag(peer, IAX_DYNAMIC))
++ if (ast_test_flag64(peer, IAX_DYNAMIC))
+ peer->defaddr.sin_port = htons(atoi(v->value));
+ else
+ peer->addr.sin_port = htons(atoi(v->value));
+@@ -10970,15 +11014,15 @@
+ ast_string_field_set(peer, cid_name, "");
+ ast_string_field_set(peer, cid_num, "");
+ }
+- ast_set_flag(peer, IAX_HASCALLERID);
++ ast_set_flag64(peer, IAX_HASCALLERID);
+ } else if (!strcasecmp(v->name, "fullname")) {
+ ast_string_field_set(peer, cid_name, S_OR(v->value, ""));
+- ast_set_flag(peer, IAX_HASCALLERID);
++ ast_set_flag64(peer, IAX_HASCALLERID);
+ } else if (!strcasecmp(v->name, "cid_number")) {
+ ast_string_field_set(peer, cid_num, S_OR(v->value, ""));
+- ast_set_flag(peer, IAX_HASCALLERID);
++ ast_set_flag64(peer, IAX_HASCALLERID);
+ } else if (!strcasecmp(v->name, "sendani")) {
+- ast_set2_flag(peer, ast_true(v->value), IAX_SENDANI);
++ ast_set2_flag64(peer, ast_true(v->value), IAX_SENDANI);
+ } else if (!strcasecmp(v->name, "inkeys")) {
+ ast_string_field_set(peer, inkeys, v->value);
+ } else if (!strcasecmp(v->name, "outkey")) {
+@@ -11006,6 +11050,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_flag64(peer, IAX_SENDCONNECTEDLINE | IAX_RECVCONNECTEDLINE);
++ } else if (!strcasecmp(v->value, "send")) {
++ ast_clear_flag64(peer, IAX_RECVCONNECTEDLINE);
++ ast_set_flag64(peer, IAX_SENDCONNECTEDLINE);
++ } else if (!strcasecmp(v->value, "receive")) {
++ ast_clear_flag64(peer, IAX_SENDCONNECTEDLINE);
++ ast_set_flag64(peer, IAX_RECVCONNECTEDLINE);
++ } else {
++ ast_clear_flag64(peer, IAX_SENDCONNECTEDLINE | IAX_RECVCONNECTEDLINE);
++ }
+ }/* else if (strcasecmp(v->name,"type")) */
+ /* ast_log(LOG_WARNING, "Ignoring %s\n", v->name); */
+ v = v->next;
+@@ -11016,7 +11072,7 @@
+ }
+ if (!peer->authmethods)
+ peer->authmethods = IAX_AUTH_MD5 | IAX_AUTH_PLAINTEXT;
+- ast_clear_flag(peer, IAX_DELME);
++ ast_clear_flag64(peer, IAX_DELME);
+ /* Make sure these are IPv4 addresses */
+ peer->addr.sin_family = AF_INET;
+ }
+@@ -11070,7 +11126,7 @@
+
+ if (!temponly) {
+ user = ao2_find(users, &tmp_user, OBJ_POINTER);
+- if (user && !ast_test_flag(user, IAX_DELME))
++ if (user && !ast_test_flag64(user, IAX_DELME))
+ firstpass = 0;
+ }
+
+@@ -11104,8 +11160,8 @@
+ 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_clear_flag(user, IAX_HASCALLERID);
++ ast_copy_flags64(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_flag64(user, IAX_HASCALLERID);
+ ast_string_field_set(user, cid_name, "");
+ ast_string_field_set(user, cid_num, "");
+ ast_string_field_set(user, accountcode, accountcode);
+@@ -11144,49 +11200,49 @@
+ } else if (!strcasecmp(v->name, "disallow")) {
+ 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) && !timer) {
++ ast_set2_flag64(user, ast_true(v->value), IAX_TRUNK);
++ if (ast_test_flag64(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);
++ ast_clear_flag64(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);
+ if (!user->encmethods) {
+- ast_clear_flag(user, IAX_FORCE_ENCRYPT);
++ ast_clear_flag64(user, IAX_FORCE_ENCRYPT);
+ }
+ } else if (!strcasecmp(v->name, "forceencryption")) {
+ if (ast_false(v->value)) {
+- ast_clear_flag(user, IAX_FORCE_ENCRYPT);
++ ast_clear_flag64(user, IAX_FORCE_ENCRYPT);
+ } else {
+ user->encmethods |= get_encrypt_methods(v->value);
+ if (user->encmethods) {
+- ast_set_flag(user, IAX_FORCE_ENCRYPT);
++ ast_set_flag64(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);
++ ast_set_flags_to64(user, IAX_NOTRANSFER|IAX_TRANSFERMEDIA, IAX_TRANSFERMEDIA);
+ } else if (ast_true(v->value)) {
+- ast_set_flags_to(user, IAX_NOTRANSFER|IAX_TRANSFERMEDIA, 0);
+- } else
+- ast_set_flags_to(user, IAX_NOTRANSFER|IAX_TRANSFERMEDIA, IAX_NOTRANSFER);
++ ast_set_flags_to64(user, IAX_NOTRANSFER|IAX_TRANSFERMEDIA, 0);
++ } else
++ ast_set_flags_to64(user, IAX_NOTRANSFER|IAX_TRANSFERMEDIA, IAX_NOTRANSFER);
+ } else if (!strcasecmp(v->name, "codecpriority")) {
+ if(!strcasecmp(v->value, "caller"))
+- ast_set_flag(user, IAX_CODEC_USER_FIRST);
++ ast_set_flag64(user, IAX_CODEC_USER_FIRST);
+ else if(!strcasecmp(v->value, "disabled"))
+- ast_set_flag(user, IAX_CODEC_NOPREFS);
++ ast_set_flag64(user, IAX_CODEC_NOPREFS);
+ else if(!strcasecmp(v->value, "reqonly")) {
+- ast_set_flag(user, IAX_CODEC_NOCAP);
+- ast_set_flag(user, IAX_CODEC_NOPREFS);
++ ast_set_flag64(user, IAX_CODEC_NOCAP);
++ ast_set_flag64(user, IAX_CODEC_NOPREFS);
+ }
+ } else if (!strcasecmp(v->name, "immediate")) {
+- ast_set2_flag(user, ast_true(v->value), IAX_IMMEDIATE);
++ ast_set2_flag64(user, ast_true(v->value), IAX_IMMEDIATE);
+ } else if (!strcasecmp(v->name, "jitterbuffer")) {
+- ast_set2_flag(user, ast_true(v->value), IAX_USEJITTERBUF);
++ ast_set2_flag64(user, ast_true(v->value), IAX_USEJITTERBUF);
+ } else if (!strcasecmp(v->name, "forcejitterbuffer")) {
+- ast_set2_flag(user, ast_true(v->value), IAX_FORCEJITTERBUF);
++ ast_set2_flag64(user, ast_true(v->value), IAX_FORCEJITTERBUF);
+ } else if (!strcasecmp(v->name, "dbsecret")) {
+ ast_string_field_set(user, dbsecret, v->value);
+ } else if (!strcasecmp(v->name, "secret")) {
+@@ -11203,29 +11259,29 @@
+ ast_callerid_split(v->value, name2, sizeof(name2), num2, sizeof(num2));
+ ast_string_field_set(user, cid_name, name2);
+ ast_string_field_set(user, cid_num, num2);
+- ast_set_flag(user, IAX_HASCALLERID);
++ ast_set_flag64(user, IAX_HASCALLERID);
+ } else {
+- ast_clear_flag(user, IAX_HASCALLERID);
++ ast_clear_flag64(user, IAX_HASCALLERID);
+ ast_string_field_set(user, cid_name, "");
+ ast_string_field_set(user, cid_num, "");
+ }
+ } else if (!strcasecmp(v->name, "fullname")) {
+ if (!ast_strlen_zero(v->value)) {
+ ast_string_field_set(user, cid_name, v->value);
+- ast_set_flag(user, IAX_HASCALLERID);
++ ast_set_flag64(user, IAX_HASCALLERID);
+ } else {
+ ast_string_field_set(user, cid_name, "");
+ if (ast_strlen_zero(user->cid_num))
+- ast_clear_flag(user, IAX_HASCALLERID);
++ ast_clear_flag64(user, IAX_HASCALLERID);
+ }
+ } else if (!strcasecmp(v->name, "cid_number")) {
+ if (!ast_strlen_zero(v->value)) {
+ ast_string_field_set(user, cid_num, v->value);
+- ast_set_flag(user, IAX_HASCALLERID);
++ ast_set_flag64(user, IAX_HASCALLERID);
+ } else {
+ ast_string_field_set(user, cid_num, "");
+ if (ast_strlen_zero(user->cid_name))
+- ast_clear_flag(user, IAX_HASCALLERID);
++ ast_clear_flag64(user, IAX_HASCALLERID);
+ }
+ } else if (!strcasecmp(v->name, "accountcode")) {
+ ast_string_field_set(user, accountcode, v->value);
+@@ -11252,6 +11308,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_flag64(user, IAX_SENDCONNECTEDLINE | IAX_RECVCONNECTEDLINE);
++ } else if (!strcasecmp(v->value, "send")) {
++ ast_clear_flag64(user, IAX_RECVCONNECTEDLINE);
++ ast_set_flag64(user, IAX_SENDCONNECTEDLINE);
++ } else if (!strcasecmp(v->value, "receive")) {
++ ast_clear_flag64(user, IAX_SENDCONNECTEDLINE);
++ ast_set_flag64(user, IAX_RECVCONNECTEDLINE);
++ } else {
++ ast_clear_flag64(user, IAX_SENDCONNECTEDLINE | IAX_RECVCONNECTEDLINE);
++ }
+ }/* else if (strcasecmp(v->name,"type")) */
+ /* ast_log(LOG_WARNING, "Ignoring %s\n", v->name); */
+ v = v->next;
+@@ -11271,7 +11339,7 @@
+ user->authmethods = IAX_AUTH_MD5 | IAX_AUTH_PLAINTEXT;
+ }
+ }
+- ast_clear_flag(user, IAX_DELME);
++ ast_clear_flag64(user, IAX_DELME);
+ }
+ cleanup:
+ if (oldha)
+@@ -11285,7 +11353,7 @@
+ {
+ struct iax2_peer *peer = obj;
+
+- ast_set_flag(peer, IAX_DELME);
++ ast_set_flag64(peer, IAX_DELME);
+
+ return 0;
+ }
+@@ -11294,7 +11362,7 @@
+ {
+ struct iax2_user *user = obj;
+
+- ast_set_flag(user, IAX_DELME);
++ ast_set_flag64(user, IAX_DELME);
+
+ return 0;
+ }
+@@ -11335,7 +11403,7 @@
+
+ i = ao2_iterator_init(users, 0);
+ while ((user = ao2_iterator_next(&i))) {
+- if (ast_test_flag(user, IAX_DELME) || ast_test_flag(user, IAX_RTCACHEFRIENDS)) {
++ if (ast_test_flag64(user, IAX_DELME) || ast_test_flag64(user, IAX_RTCACHEFRIENDS)) {
+ ao2_unlink(users, user);
+ }
+ user_unref(user);
+@@ -11350,7 +11418,7 @@
+
+ i = ao2_iterator_init(peers, 0);
+ while ((peer = ao2_iterator_next(&i))) {
+- if (ast_test_flag(peer, IAX_DELME) || ast_test_flag(peer, IAX_RTCACHEFRIENDS)) {
++ if (ast_test_flag64(peer, IAX_DELME) || ast_test_flag64(peer, IAX_RTCACHEFRIENDS)) {
+ unlink_peer(peer);
+ }
+ peer_unref(peer);
+@@ -11366,10 +11434,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_flag64((&globalflags), IAX_NOTRANSFER | IAX_TRANSFERMEDIA | IAX_USEJITTERBUF |
++ IAX_FORCEJITTERBUF | IAX_SENDCONNECTEDLINE | IAX_RECVCONNECTEDLINE);
+ delete_users();
+ }
+
+@@ -11426,13 +11492,13 @@
+ set_config_destroy();
+ }
+
+- /* Reset global codec prefs */
++ /* Reset global codec prefs */
+ memset(&prefs, 0 , sizeof(struct ast_codec_pref));
+-
++
+ /* Reset Global Flags */
+ memset(&globalflags, 0, sizeof(globalflags));
+- ast_set_flag(&globalflags, IAX_RTUPDATE);
+-
++ ast_set_flag64(&globalflags, IAX_RTUPDATE);
++
+ #ifdef SO_NO_CHECK
+ nochecksums = 0;
+ #endif
+@@ -11544,67 +11610,69 @@
+ } else if (!strcasecmp(v->name, "encryption")) {
+ iax2_encryption |= get_encrypt_methods(v->value);
+ if (!iax2_encryption) {
+- ast_clear_flag((&globalflags), IAX_FORCE_ENCRYPT);
++ ast_clear_flag64((&globalflags), IAX_FORCE_ENCRYPT);
+ }
+ } else if (!strcasecmp(v->name, "forceencryption")) {
+ if (ast_false(v->value)) {
+- ast_clear_flag((&globalflags), IAX_FORCE_ENCRYPT);
++ ast_clear_flag64((&globalflags), IAX_FORCE_ENCRYPT);
+ } else {
+ iax2_encryption |= get_encrypt_methods(v->value);
+ if (iax2_encryption) {
+- ast_set_flag((&globalflags), IAX_FORCE_ENCRYPT);
++ ast_set_flag64((&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);
++ ast_set_flags_to64((&globalflags), IAX_NOTRANSFER|IAX_TRANSFERMEDIA, IAX_TRANSFERMEDIA);
+ } else if (ast_true(v->value)) {
+- ast_set_flags_to((&globalflags), IAX_NOTRANSFER|IAX_TRANSFERMEDIA, 0);
+- } else
+- ast_set_flags_to((&globalflags), IAX_NOTRANSFER|IAX_TRANSFERMEDIA, IAX_NOTRANSFER);
++ ast_set_flags_to64((&globalflags), IAX_NOTRANSFER|IAX_TRANSFERMEDIA, 0);
++ } else
++ ast_set_flags_to64((&globalflags), IAX_NOTRANSFER|IAX_TRANSFERMEDIA, IAX_NOTRANSFER);
+ } else if (!strcasecmp(v->name, "codecpriority")) {
+ if(!strcasecmp(v->value, "caller"))
+- ast_set_flag((&globalflags), IAX_CODEC_USER_FIRST);
++ ast_set_flag64((&globalflags), IAX_CODEC_USER_FIRST);
+ else if(!strcasecmp(v->value, "disabled"))
+- ast_set_flag((&globalflags), IAX_CODEC_NOPREFS);
++ ast_set_flag64((&globalflags), IAX_CODEC_NOPREFS);
+ else if(!strcasecmp(v->value, "reqonly")) {
+- ast_set_flag((&globalflags), IAX_CODEC_NOCAP);
+- ast_set_flag((&globalflags), IAX_CODEC_NOPREFS);
++ ast_set_flag64((&globalflags), IAX_CODEC_NOCAP);
++ ast_set_flag64((&globalflags), IAX_CODEC_NOPREFS);
+ }
+ } else if (!strcasecmp(v->name, "jitterbuffer"))
+- ast_set2_flag((&globalflags), ast_true(v->value), IAX_USEJITTERBUF);
++ ast_set2_flag64((&globalflags), ast_true(v->value), IAX_USEJITTERBUF);
+ else if (!strcasecmp(v->name, "forcejitterbuffer"))
+- ast_set2_flag((&globalflags), ast_true(v->value), IAX_FORCEJITTERBUF);
++ ast_set2_flag64((&globalflags), ast_true(v->value), IAX_FORCEJITTERBUF);
+ else if (!strcasecmp(v->name, "delayreject"))
+ delayreject = ast_true(v->value);
+ else if (!strcasecmp(v->name, "allowfwdownload"))
+- ast_set2_flag((&globalflags), ast_true(v->value), IAX_ALLOWFWDOWNLOAD);
++ ast_set2_flag64((&globalflags), ast_true(v->value), IAX_ALLOWFWDOWNLOAD);
+ else if (!strcasecmp(v->name, "rtcachefriends"))
+- ast_set2_flag((&globalflags), ast_true(v->value), IAX_RTCACHEFRIENDS);
++ ast_set2_flag64((&globalflags), ast_true(v->value), IAX_RTCACHEFRIENDS);
+ else if (!strcasecmp(v->name, "rtignoreregexpire"))
+- ast_set2_flag((&globalflags), ast_true(v->value), IAX_RTIGNOREREGEXPIRE);
++ ast_set2_flag64((&globalflags), ast_true(v->value), IAX_RTIGNOREREGEXPIRE);
+ else if (!strcasecmp(v->name, "rtupdate"))
+- ast_set2_flag((&globalflags), ast_true(v->value), IAX_RTUPDATE);
++ ast_set2_flag64((&globalflags), ast_true(v->value), IAX_RTUPDATE);
++ else if (!strcasecmp(v->name, "rtsavesysname"))
++ ast_set2_flag64((&globalflags), ast_true(v->value), IAX_RTSAVE_SYSNAME);
+ else if (!strcasecmp(v->name, "trunktimestamps"))
+- ast_set2_flag(&globalflags, ast_true(v->value), IAX_TRUNKTIMESTAMPS);
++ ast_set2_flag64(&globalflags, ast_true(v->value), IAX_TRUNKTIMESTAMPS);
+ else if (!strcasecmp(v->name, "rtautoclear")) {
+ int i = atoi(v->value);
+ if(i > 0)
+ global_rtautoclear = i;
+ else
+ i = 0;
+- ast_set2_flag((&globalflags), i || ast_true(v->value), IAX_RTAUTOCLEAR);
++ ast_set2_flag64((&globalflags), i || ast_true(v->value), IAX_RTAUTOCLEAR);
+ } else if (!strcasecmp(v->name, "trunkfreq")) {
+ trunkfreq = atoi(v->value);
+ if (trunkfreq < 10)
+ trunkfreq = 10;
+ } else if (!strcasecmp(v->name, "trunkmtu")) {
+ mtuv = atoi(v->value);
+- if (mtuv == 0 )
+- global_max_trunk_mtu = 0;
+- else if (mtuv >= 172 && mtuv < 4000)
+- global_max_trunk_mtu = mtuv;
+- else
++ if (mtuv == 0 )
++ global_max_trunk_mtu = 0;
++ else if (mtuv >= 172 && mtuv < 4000)
++ global_max_trunk_mtu = mtuv;
++ else
+ ast_log(LOG_NOTICE, "trunkmtu value out of bounds (%d) at line %d\n",
+ mtuv, v->lineno);
+ } else if (!strcasecmp(v->name, "trunkmaxsize")) {
+@@ -11674,6 +11742,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_flag64((&globalflags), IAX_SENDCONNECTEDLINE | IAX_RECVCONNECTEDLINE);
++ } else if (!strcasecmp(v->value, "send")) {
++ ast_clear_flag64((&globalflags), IAX_RECVCONNECTEDLINE);
++ ast_set_flag64((&globalflags), IAX_SENDCONNECTEDLINE);
++ } else if (!strcasecmp(v->value, "receive")) {
++ ast_clear_flag64((&globalflags), IAX_SENDCONNECTEDLINE);
++ ast_set_flag64((&globalflags), IAX_RECVCONNECTEDLINE);
++ } else {
++ ast_clear_flag64((&globalflags), IAX_SENDCONNECTEDLINE | IAX_RECVCONNECTEDLINE);
++ }
+ } /*else if (strcasecmp(v->name,"type")) */
+ /* ast_log(LOG_WARNING, "Ignoring %s\n", v->name); */
+ v = v->next;
+@@ -11728,7 +11808,7 @@
+ }
+ peer = build_peer(cat, gen, ast_variable_browse(ucfg, cat), 0);
+ if (peer) {
+- if (ast_test_flag(peer, IAX_DYNAMIC))
++ if (ast_test_flag64(peer, IAX_DYNAMIC))
+ reg_source_db(peer);
+ ao2_link(peers, peer);
+ peer = peer_unref(peer);
+@@ -11774,7 +11854,7 @@
+ if (!strcasecmp(utype, "peer") || !strcasecmp(utype, "friend")) {
+ peer = build_peer(cat, ast_variable_browse(cfg, cat), NULL, 0);
+ if (peer) {
+- if (ast_test_flag(peer, IAX_DYNAMIC))
++ if (ast_test_flag64(peer, IAX_DYNAMIC))
+ reg_source_db(peer);
+ ao2_link(peers, peer);
+ peer = peer_unref(peer);
+@@ -12211,7 +12291,7 @@
+ } else if (!strcasecmp(colname, "expire")) {
+ snprintf(buf, len, "%d", peer->expire);
+ } else if (!strcasecmp(colname, "dynamic")) {
+- ast_copy_string(buf, (ast_test_flag(peer, IAX_DYNAMIC) ? "yes" : "no"), len);
++ ast_copy_string(buf, (ast_test_flag64(peer, IAX_DYNAMIC) ? "yes" : "no"), len);
+ } else if (!strcasecmp(colname, "callerid_name")) {
+ ast_copy_string(buf, peer->cid_name, len);
+ } else if (!strcasecmp(colname, "callerid_num")) {
+@@ -12242,7 +12322,7 @@
+ return 0;
+ }
+
+-struct ast_custom_function iaxpeer_function = {
++static struct ast_custom_function iaxpeer_function = {
+ .name = "IAXPEER",
+ .read = function_iaxpeer,
+ };
+@@ -12495,19 +12575,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)))
+@@ -12558,6 +12633,7 @@
+ if (timer) {
+ ast_timer_close(timer);
+ }
++ transmit_processor = ast_taskprocessor_unreference(transmit_processor);
+
+ con = ast_context_find(regcontext);
+ if (con)
+@@ -12626,19 +12702,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);
+@@ -12646,6 +12726,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);
+
+@@ -12691,10 +12781,10 @@
+
+ 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");
++ ast_manager_register_xml("IAXpeers", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, manager_iax2_show_peers);
++ ast_manager_register_xml("IAXpeerlist", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, manager_iax2_show_peer_list);
++ ast_manager_register_xml("IAXnetstats", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, manager_iax2_show_netstats);
++ ast_manager_register_xml("IAXregistry", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, manager_iax2_show_registry);
+
+ if ((timer = ast_timer_open())) {
+ ast_timer_set_rate(timer, trunkfreq);
+Index: channels/chan_oss.c
+===================================================================
+--- a/channels/chan_oss.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/channels/chan_oss.c (.../trunk) (revision 202568)
+@@ -305,7 +305,7 @@
+ };
+
+ /*! forward declaration */
+-static struct chan_oss_pvt *find_desc(char *dev);
++static struct chan_oss_pvt *find_desc(const char *dev);
+
+ static char *oss_active; /*!< the active device */
+
+@@ -367,7 +367,7 @@
+ /*!
+ * \brief returns a pointer to the descriptor with the given name
+ */
+-static struct chan_oss_pvt *find_desc(char *dev)
++static struct chan_oss_pvt *find_desc(const char *dev)
+ {
+ struct chan_oss_pvt *o = NULL;
+
+@@ -1075,7 +1075,8 @@
+
+ static char *console_dial(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+ {
+- char *s = NULL, *mye = NULL, *myc = NULL;
++ char *s = NULL;
++ char *mye = NULL, *myc = NULL;
+ struct chan_oss_pvt *o = find_desc(oss_active);
+
+ if (cmd == CLI_INIT) {
+@@ -1092,6 +1093,7 @@
+ if (o->owner) { /* already in a call */
+ int i;
+ struct ast_frame f = { AST_FRAME_DTMF, 0 };
++ const char *s;
+
+ if (a->argc == e->args) { /* argument is mandatory here */
+ ast_cli(a->fd, "Already in a call. You can only dial digits until you hangup.\n");
+@@ -1126,7 +1128,7 @@
+ static char *console_mute(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+ {
+ struct chan_oss_pvt *o = find_desc(oss_active);
+- char *s;
++ const char *s;
+ int toggle = 0;
+
+ if (cmd == CLI_INIT) {
+Index: channels/chan_misdn.c
+===================================================================
+--- a/channels/chan_misdn.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/channels/chan_misdn.c (.../trunk) (revision 202568)
+@@ -1,6 +1,6 @@
+ /*
+ * Asterisk -- An open source telephony toolkit.
+- *
++ *
+ * Copyright (C) 2004 - 2006, Christian Richter
+ *
+ * Christian Richter <crich@beronet.com>
+@@ -29,6 +29,26 @@
+ * \ingroup channel_drivers
+ */
+
++/*!
++ * \note
++ * To use the CCBS/CCNR supplementary service feature and other
++ * supplementary services using FACILITY messages requires a
++ * modified version of mISDN.
++ *
++ * \note
++ * The latest modified mISDN v1.1.x based version is available at:
++ * http://svn.digium.com/svn/thirdparty/mISDN/trunk
++ * http://svn.digium.com/svn/thirdparty/mISDNuser/trunk
++ *
++ * \note
++ * Taged versions of the modified mISDN code are available under:
++ * http://svn.digium.com/svn/thirdparty/mISDN/tags
++ * http://svn.digium.com/svn/thirdparty/mISDNuser/tags
++ */
++
++/* Define to enable cli commands to generate canned CCBS messages. */
++// #define CCBS_TEST_MESSAGES 1
++
+ /*** MODULEINFO
+ <depend>isdnnet</depend>
+ <depend>misdn</depend>
+@@ -47,6 +67,8 @@
+ #include <signal.h>
+ #include <sys/file.h>
+ #include <semaphore.h>
++#include <ctype.h>
++#include <time.h>
+
+ #include "asterisk/channel.h"
+ #include "asterisk/config.h"
+@@ -72,7 +94,7 @@
+ #include "chan_misdn_config.h"
+ #include "isdn_lib.h"
+
+-char global_tracefile[BUFFERSIZE + 1];
++static char global_tracefile[BUFFERSIZE + 1];
+
+ static int g_config_initialized = 0;
+
+@@ -88,8 +110,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);
+
+@@ -111,8 +131,167 @@
+
+ /* BEGIN: chan_misdn.h */
+
+-ast_mutex_t release_lock;
++#if defined(AST_MISDN_ENHANCEMENTS)
++/*
++ * This timeout duration is to clean up any call completion records that
++ * are forgotten about by the switch.
++ */
++#define MISDN_CC_RECORD_AGE_MAX (6UL * 60 * 60) /* seconds */
+
++#define MISDN_CC_REQUEST_WAIT_MAX 5 /* seconds */
++
++/*!
++ * \brief Caller that initialized call completion services
++ *
++ * \details
++ * This data is the payload for a datastore that is put on the channel that
++ * initializes call completion services. This datastore is set to be inherited
++ * by the outbound mISDN channel. When one of these channels hangs up, the
++ * channel pointer will be set to NULL. That way, we can ensure that we do not
++ * touch this channel after it gets destroyed.
++ */
++struct misdn_cc_caller {
++ /*! \brief The channel that initialized call completion services */
++ struct ast_channel *chan;
++};
++
++struct misdn_cc_notify {
++ /*! \brief Dialplan: Notify extension priority */
++ int priority;
++
++ /*! \brief Dialplan: Notify extension context */
++ char context[AST_MAX_CONTEXT];
++
++ /*! \brief Dialplan: Notify extension number (User-A) */
++ char exten[AST_MAX_EXTENSION];
++};
++
++/*! \brief mISDN call completion record */
++struct misdn_cc_record {
++ /*! \brief Call completion record linked list */
++ AST_LIST_ENTRY(misdn_cc_record) list;
++
++ /*! \brief Time the record was created. */
++ time_t time_created;
++
++ /*! \brief MISDN_CC_RECORD_ID value */
++ long record_id;
++
++ /*!
++ * \brief Logical Layer 1 port associated with this
++ * call completion record
++ */
++ int port;
++
++ /*! \brief TRUE if point-to-point mode (CCBS-T/CCNR-T mode) */
++ int ptp;
++
++ /*! \brief Mode specific parameters */
++ union {
++ /*! \brief point-to-point specific parameters. */
++ struct {
++ /*!
++ * \brief Call-completion signaling link.
++ * NULL if signaling link not established.
++ */
++ struct misdn_bchannel *bc;
++
++ /*!
++ * \brief TRUE if we requested the request retention option
++ * to be enabled.
++ */
++ int requested_retention;
++
++ /*!
++ * \brief TRUE if the request retention option is enabled.
++ */
++ int retention_enabled;
++ } ptp;
++
++ /*! \brief point-to-multi-point specific parameters. */
++ struct {
++ /*! \brief CallLinkageID (valid when port determined) */
++ int linkage_id;
++
++ /*! \breif CCBSReference (valid when activated is TRUE) */
++ int reference_id;
++
++ /*! \brief globalRecall(0), specificRecall(1) */
++ int recall_mode;
++ } ptmp;
++ } mode;
++
++ /*! \brief TRUE if call completion activated */
++ int activated;
++
++ /*! \brief Outstanding message ID (valid when outstanding_message) */
++ int invoke_id;
++
++ /*! \brief TRUE if waiting for a response from a message (invoke_id is valid) */
++ int outstanding_message;
++
++ /*! \brief TRUE if activation has been requested */
++ int activation_requested;
++
++ /*!
++ * \brief TRUE if User-A is free
++ * \note PTMP - Used to answer CCBSStatusRequest.
++ * PTP - Determines how to respond to CCBS_T_RemoteUserFree.
++ */
++ int party_a_free;
++
++ /*! \brief Error code received from last outstanding message. */
++ enum FacErrorCode error_code;
++
++ /*! \brief Reject code received from last outstanding message. */
++ enum FacRejectCode reject_code;
++
++ /*!
++ * \brief Saved struct misdn_bchannel call information when
++ * attempted to call User-B
++ */
++ struct {
++ /*! \brief User-A caller id information */
++ struct misdn_party_id caller;
++
++ /*! \brief User-B number information */
++ struct misdn_party_dialing dialed;
++
++ /*! \brief The BC, HLC (optional) and LLC (optional) contents from the SETUP message. */
++ struct Q931_Bc_Hlc_Llc setup_bc_hlc_llc;
++
++ /*! \brief SETUP message bearer capability field code value */
++ int capability;
++
++ /*! \brief TRUE if call made in digital HDLC mode */
++ int hdlc;
++ } redial;
++
++ /*! \brief Dialplan location to indicate User-B free and User-A is free */
++ struct misdn_cc_notify remote_user_free;
++
++ /*! \brief Dialplan location to indicate User-B free and User-A is busy */
++ struct misdn_cc_notify b_free;
++};
++
++/*! \brief mISDN call completion record database */
++static AST_LIST_HEAD_STATIC(misdn_cc_records_db, misdn_cc_record);
++/*! \brief Next call completion record ID to use */
++static __u16 misdn_cc_record_id;
++/*! \brief Next invoke ID to use */
++static __s16 misdn_invoke_id;
++
++static const char misdn_no_response_from_network[] = "No response from network";
++static const char misdn_cc_record_not_found[] = "Call completion record not found";
++
++/* mISDN channel variable names */
++#define MISDN_CC_RECORD_ID "MISDN_CC_RECORD_ID"
++#define MISDN_CC_STATUS "MISDN_CC_STATUS"
++#define MISDN_ERROR_MSG "MISDN_ERROR_MSG"
++#endif /* defined(AST_MISDN_ENHANCEMENTS) */
++
++static ast_mutex_t release_lock;
++
+ enum misdn_chan_state {
+ MISDN_NOTHING = 0, /*!< at beginning */
+ MISDN_WAITING4DIGS, /*!< when waiting for info */
+@@ -126,7 +305,7 @@
+ MISDN_ALERTING, /*!< when Alerting */
+ MISDN_BUSY, /*!< when BUSY */
+ MISDN_CONNECTED, /*!< when connected */
+- MISDN_PRECONNECTED, /*!< when connected */
++ MISDN_PRECONNECTED, /*!< when connected (Noone sets this state) */
+ MISDN_DISCONNECTED, /*!< when connected */
+ MISDN_RELEASED, /*!< when connected */
+ MISDN_BRIDGED, /*!< when bridged */
+@@ -135,21 +314,22 @@
+ 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 */
+-
+ };
+
++/*! Asterisk created the channel (outgoing call) */
+ #define ORG_AST 1
++/*! mISDN created the channel (incoming call) */
+ #define ORG_MISDN 2
+
+ 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 +339,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 +364,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 +402,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,48 +462,56 @@
+ /*!
+ * \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.
+ */
+ struct misdn_bchannel *bc;
+
++#if defined(AST_MISDN_ENHANCEMENTS)
+ /*!
++ * \brief Peer channel for which call completion was initialized.
++ */
++ struct misdn_cc_caller *peer;
++
++ /*! \brief Associated call completion record ID (-1 if not associated) */
++ long record_id;
++#endif /* defined(AST_MISDN_ENHANCEMENTS) */
++
++ /*!
+ * \brief HOLDED channel information
+ */
+ 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 +529,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 +547,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 +586,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 +600,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 +627,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;
+@@ -481,13 +658,12 @@
+ __attribute__((format(printf, 3, 4)));
+
+ static struct ast_channel *misdn_new(struct chan_list *cl, int state, char *exten, char *callerid, int format, int port, int c);
+-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 void hangup_chan(struct chan_list *ch);
+ static int pbx_start_chan(struct chan_list *ch);
+
+ #define MISDN_ASTERISK_TECH_PVT(ast) ast->tech_pvt
+-#define MISDN_ASTERISK_PVT(ast) 1
+
+ #include "asterisk/strings.h"
+
+@@ -507,13 +683,11 @@
+ static int *misdn_in_calls;
+ static int *misdn_out_calls;
+
+-struct chan_list dummy_cl;
+-
+ /*!
+ * \brief Global channel call record list head.
+ */
+-struct chan_list *cl_te=NULL;
+-ast_mutex_t cl_te_lock;
++static struct chan_list *cl_te=NULL;
++static ast_mutex_t cl_te_lock;
+
+ static enum event_response_e
+ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data);
+@@ -533,13 +707,17 @@
+ static int stop_bc_tones(struct chan_list *cl);
+ static void release_chan(struct misdn_bchannel *bc);
+
+-static int misdn_check_l2l1(struct ast_channel *chan, void *data);
+-static int misdn_set_opt_exec(struct ast_channel *chan, void *data);
+-static int misdn_facility_exec(struct ast_channel *chan, void *data);
++#if defined(AST_MISDN_ENHANCEMENTS)
++static const char misdn_command_name[] = "misdn_command";
++static int misdn_command_exec(struct ast_channel *chan, const char *data);
++#endif /* defined(AST_MISDN_ENHANCEMENTS) */
++static int misdn_check_l2l1(struct ast_channel *chan, const char *data);
++static int misdn_set_opt_exec(struct ast_channel *chan, const char *data);
++static int misdn_facility_exec(struct ast_channel *chan, const char *data);
+
+ 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);
+@@ -555,34 +733,1583 @@
+
+ /*************** Helpers *****************/
+
+-static struct chan_list * get_chan_by_ast(struct ast_channel *ast)
++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)
++static struct chan_list *get_chan_by_ast_name(const 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;
+ }
+
++#if defined(AST_MISDN_ENHANCEMENTS)
++/*!
++ * \internal
++ * \brief Destroy the misdn_cc_ds_info datastore payload
++ *
++ * \param[in] data the datastore payload, a reference to an misdn_cc_caller
++ *
++ * \details
++ * Since the payload is a reference to an astobj2 object, we just decrement its
++ * reference count. Before doing so, we NULL out the channel pointer inside of
++ * the misdn_cc_caller instance. This function will be called in one of two
++ * cases. In both cases, we no longer need the channel pointer:
++ *
++ * - The original channel that initialized call completion services, the same
++ * channel that is stored here, has been destroyed early. This could happen
++ * if it transferred the mISDN channel, for example.
++ *
++ * - The mISDN channel that had this datastore inherited on to it is now being
++ * destroyed. If this is the case, then the call completion events have
++ * already occurred and the appropriate channel variables have already been
++ * set on the original channel that requested call completion services.
++ *
++ * \return Nothing
++ */
++static void misdn_cc_ds_destroy(void *data)
++{
++ struct misdn_cc_caller *cc_caller = data;
+
++ ao2_lock(cc_caller);
++ cc_caller->chan = NULL;
++ ao2_unlock(cc_caller);
+
++ ao2_ref(cc_caller, -1);
++}
++#endif /* defined(AST_MISDN_ENHANCEMENTS) */
++
++#if defined(AST_MISDN_ENHANCEMENTS)
++/*!
++ * \internal
++ * \brief Duplicate the misdn_cc_ds_info datastore payload
++ *
++ * \param[in] data the datastore payload, a reference to an misdn_cc_caller
++ *
++ * \details
++ * All we need to do is bump the reference count and return the same instance.
++ *
++ * \return A reference to an instance of a misdn_cc_caller
++ */
++static void *misdn_cc_ds_duplicate(void *data)
++{
++ struct misdn_cc_caller *cc_caller = data;
++
++ ao2_ref(cc_caller, +1);
++
++ return cc_caller;
++}
++#endif /* defined(AST_MISDN_ENHANCEMENTS) */
++
++#if defined(AST_MISDN_ENHANCEMENTS)
++static const struct ast_datastore_info misdn_cc_ds_info = {
++ .type = "misdn_cc",
++ .destroy = misdn_cc_ds_destroy,
++ .duplicate = misdn_cc_ds_duplicate,
++};
++#endif /* defined(AST_MISDN_ENHANCEMENTS) */
++
++#if defined(AST_MISDN_ENHANCEMENTS)
++/*!
++ * \internal
++ * \brief Set a channel var on the peer channel for call completion services
++ *
++ * \param[in] peer The peer that initialized call completion services
++ * \param[in] var The variable name to set
++ * \param[in] value The variable value to set
++ *
++ * This function may be called from outside of the channel thread. It handles
++ * the fact that the peer channel may be hung up and destroyed at any time.
++ *
++ * \return nothing
++ */
++static void misdn_cc_set_peer_var(struct misdn_cc_caller *peer, const char *var,
++ const char *value)
++{
++ ao2_lock(peer);
++
++ /*! \todo XXX This nastiness can go away once ast_channel is ref counted! */
++ while (peer->chan && ast_channel_trylock(peer->chan)) {
++ ao2_unlock(peer);
++ sched_yield();
++ ao2_lock(peer);
++ }
++
++ if (peer->chan) {
++ pbx_builtin_setvar_helper(peer->chan, var, value);
++ ast_channel_unlock(peer->chan);
++ }
++
++ ao2_unlock(peer);
++}
++#endif /* defined(AST_MISDN_ENHANCEMENTS) */
++
++#if defined(AST_MISDN_ENHANCEMENTS)
++/*!
++ * \internal
++ * \brief Get a reference to the CC caller if it exists
++ */
++static struct misdn_cc_caller *misdn_cc_caller_get(struct ast_channel *chan)
++{
++ struct ast_datastore *datastore;
++ struct misdn_cc_caller *cc_caller;
++
++ ast_channel_lock(chan);
++
++ if (!(datastore = ast_channel_datastore_find(chan, &misdn_cc_ds_info, NULL))) {
++ ast_channel_unlock(chan);
++ return NULL;
++ }
++
++ ao2_ref(datastore->data, +1);
++ cc_caller = datastore->data;
++
++ ast_channel_unlock(chan);
++
++ return cc_caller;
++}
++#endif /* defined(AST_MISDN_ENHANCEMENTS) */
++
++#if defined(AST_MISDN_ENHANCEMENTS)
++/*!
++ * \internal
++ * \brief Find the call completion record given the record id.
++ *
++ * \param record_id
++ *
++ * \retval pointer to found call completion record
++ * \retval NULL if not found
++ *
++ * \note Assumes the misdn_cc_records_db lock is already obtained.
++ */
++static struct misdn_cc_record *misdn_cc_find_by_id(long record_id)
++{
++ struct misdn_cc_record *current;
++
++ AST_LIST_TRAVERSE(&misdn_cc_records_db, current, list) {
++ if (current->record_id == record_id) {
++ /* Found the record */
++ break;
++ }
++ }
++
++ return current;
++}
++#endif /* defined(AST_MISDN_ENHANCEMENTS) */
++
++#if defined(AST_MISDN_ENHANCEMENTS)
++/*!
++ * \internal
++ * \brief Find the call completion record given the port and call linkage id.
++ *
++ * \param port Logical port number
++ * \param linkage_id Call linkage ID number from switch.
++ *
++ * \retval pointer to found call completion record
++ * \retval NULL if not found
++ *
++ * \note Assumes the misdn_cc_records_db lock is already obtained.
++ */
++static struct misdn_cc_record *misdn_cc_find_by_linkage(int port, int linkage_id)
++{
++ struct misdn_cc_record *current;
++
++ AST_LIST_TRAVERSE(&misdn_cc_records_db, current, list) {
++ if (current->port == port
++ && !current->ptp
++ && current->mode.ptmp.linkage_id == linkage_id) {
++ /* Found the record */
++ break;
++ }
++ }
++
++ return current;
++}
++#endif /* defined(AST_MISDN_ENHANCEMENTS) */
++
++#if defined(AST_MISDN_ENHANCEMENTS)
++/*!
++ * \internal
++ * \brief Find the call completion record given the port and outstanding invocation id.
++ *
++ * \param port Logical port number
++ * \param invoke_id Outstanding message invocation ID number.
++ *
++ * \retval pointer to found call completion record
++ * \retval NULL if not found
++ *
++ * \note Assumes the misdn_cc_records_db lock is already obtained.
++ */
++static struct misdn_cc_record *misdn_cc_find_by_invoke(int port, int invoke_id)
++{
++ struct misdn_cc_record *current;
++
++ AST_LIST_TRAVERSE(&misdn_cc_records_db, current, list) {
++ if (current->outstanding_message
++ && current->invoke_id == invoke_id
++ && current->port == port) {
++ /* Found the record */
++ break;
++ }
++ }
++
++ return current;
++}
++#endif /* defined(AST_MISDN_ENHANCEMENTS) */
++
++#if defined(AST_MISDN_ENHANCEMENTS)
++/*!
++ * \internal
++ * \brief Find the call completion record given the port and CCBS reference id.
++ *
++ * \param port Logical port number
++ * \param reference_id CCBS reference ID number from switch.
++ *
++ * \retval pointer to found call completion record
++ * \retval NULL if not found
++ *
++ * \note Assumes the misdn_cc_records_db lock is already obtained.
++ */
++static struct misdn_cc_record *misdn_cc_find_by_reference(int port, int reference_id)
++{
++ struct misdn_cc_record *current;
++
++ AST_LIST_TRAVERSE(&misdn_cc_records_db, current, list) {
++ if (current->activated
++ && current->port == port
++ && !current->ptp
++ && current->mode.ptmp.reference_id == reference_id) {
++ /* Found the record */
++ break;
++ }
++ }
++
++ return current;
++}
++#endif /* defined(AST_MISDN_ENHANCEMENTS) */
++
++#if defined(AST_MISDN_ENHANCEMENTS)
++/*!
++ * \internal
++ * \brief Find the call completion record given the B channel pointer
++ *
++ * \param bc B channel control structure pointer.
++ *
++ * \retval pointer to found call completion record
++ * \retval NULL if not found
++ *
++ * \note Assumes the misdn_cc_records_db lock is already obtained.
++ */
++static struct misdn_cc_record *misdn_cc_find_by_bc(const struct misdn_bchannel *bc)
++{
++ struct misdn_cc_record *current;
++
++ if (bc) {
++ AST_LIST_TRAVERSE(&misdn_cc_records_db, current, list) {
++ if (current->ptp
++ && current->mode.ptp.bc == bc) {
++ /* Found the record */
++ break;
++ }
++ }
++ } else {
++ current = NULL;
++ }
++
++ return current;
++}
++#endif /* defined(AST_MISDN_ENHANCEMENTS) */
++
++#if defined(AST_MISDN_ENHANCEMENTS)
++/*!
++ * \internal
++ * \brief Delete the given call completion record
++ *
++ * \param doomed Call completion record to destroy
++ *
++ * \return Nothing
++ *
++ * \note Assumes the misdn_cc_records_db lock is already obtained.
++ */
++static void misdn_cc_delete(struct misdn_cc_record *doomed)
++{
++ struct misdn_cc_record *current;
++
++ AST_LIST_TRAVERSE_SAFE_BEGIN(&misdn_cc_records_db, current, list) {
++ if (current == doomed) {
++ AST_LIST_REMOVE_CURRENT(list);
++ ast_free(current);
++ return;
++ }
++ }
++ AST_LIST_TRAVERSE_SAFE_END;
++
++ /* The doomed node is not in the call completion database */
++}
++#endif /* defined(AST_MISDN_ENHANCEMENTS) */
++
++#if defined(AST_MISDN_ENHANCEMENTS)
++/*!
++ * \internal
++ * \brief Delete all old call completion records
++ *
++ * \return Nothing
++ *
++ * \note Assumes the misdn_cc_records_db lock is already obtained.
++ */
++static void misdn_cc_remove_old(void)
++{
++ struct misdn_cc_record *current;
++ time_t now;
++
++ now = time(NULL);
++ AST_LIST_TRAVERSE_SAFE_BEGIN(&misdn_cc_records_db, current, list) {
++ if (MISDN_CC_RECORD_AGE_MAX < now - current->time_created) {
++ if (current->ptp && current->mode.ptp.bc) {
++ /* Close the old call-completion signaling link */
++ current->mode.ptp.bc->fac_out.Function = Fac_None;
++ current->mode.ptp.bc->out_cause = AST_CAUSE_NORMAL_CLEARING;
++ misdn_lib_send_event(current->mode.ptp.bc, EVENT_RELEASE_COMPLETE);
++ }
++
++ /* Remove the old call completion record */
++ AST_LIST_REMOVE_CURRENT(list);
++ ast_free(current);
++ }
++ }
++ AST_LIST_TRAVERSE_SAFE_END;
++}
++#endif /* defined(AST_MISDN_ENHANCEMENTS) */
++
++#if defined(AST_MISDN_ENHANCEMENTS)
++/*!
++ * \internal
++ * \brief Allocate the next record id.
++ *
++ * \retval New record id on success.
++ * \retval -1 on error.
++ *
++ * \note Assumes the misdn_cc_records_db lock is already obtained.
++ */
++static long misdn_cc_record_id_new(void)
++{
++ long record_id;
++ long first_id;
++
++ record_id = ++misdn_cc_record_id;
++ first_id = record_id;
++ while (misdn_cc_find_by_id(record_id)) {
++ record_id = ++misdn_cc_record_id;
++ if (record_id == first_id) {
++ /*
++ * We have a resource leak.
++ * We should never need to allocate 64k records.
++ */
++ chan_misdn_log(0, 0, " --> ERROR Too many call completion records!\n");
++ record_id = -1;
++ break;
++ }
++ }
++
++ return record_id;
++}
++#endif /* defined(AST_MISDN_ENHANCEMENTS) */
++
++#if defined(AST_MISDN_ENHANCEMENTS)
++/*!
++ * \internal
++ * \brief Create a new call completion record
++ *
++ * \retval pointer to new call completion record
++ * \retval NULL if failed
++ *
++ * \note Assumes the misdn_cc_records_db lock is already obtained.
++ */
++static struct misdn_cc_record *misdn_cc_new(void)
++{
++ struct misdn_cc_record *cc_record;
++ long record_id;
++
++ misdn_cc_remove_old();
++
++ cc_record = ast_calloc(1, sizeof(*cc_record));
++ if (cc_record) {
++ record_id = misdn_cc_record_id_new();
++ if (record_id < 0) {
++ ast_free(cc_record);
++ return NULL;
++ }
++
++ /* Initialize the new record */
++ cc_record->record_id = record_id;
++ cc_record->port = -1;/* Invalid port so it will never be found this way */
++ cc_record->invoke_id = ++misdn_invoke_id;
++ cc_record->party_a_free = 1;/* Default User-A as free */
++ cc_record->error_code = FacError_None;
++ cc_record->reject_code = FacReject_None;
++ cc_record->time_created = time(NULL);
++
++ /* Insert the new record into the database */
++ AST_LIST_INSERT_HEAD(&misdn_cc_records_db, cc_record, list);
++ }
++ return cc_record;
++}
++#endif /* defined(AST_MISDN_ENHANCEMENTS) */
++
++#if defined(AST_MISDN_ENHANCEMENTS)
++/*!
++ * \internal
++ * \brief Destroy the call completion record database
++ *
++ * \return Nothing
++ */
++static void misdn_cc_destroy(void)
++{
++ struct misdn_cc_record *current;
++
++ while ((current = AST_LIST_REMOVE_HEAD(&misdn_cc_records_db, list))) {
++ /* Do a misdn_cc_delete(current) inline */
++ ast_free(current);
++ }
++}
++#endif /* defined(AST_MISDN_ENHANCEMENTS) */
++
++#if defined(AST_MISDN_ENHANCEMENTS)
++/*!
++ * \internal
++ * \brief Initialize the call completion record database
++ *
++ * \return Nothing
++ */
++static void misdn_cc_init(void)
++{
++ misdn_cc_record_id = 0;
++}
++#endif /* defined(AST_MISDN_ENHANCEMENTS) */
++
++#if defined(AST_MISDN_ENHANCEMENTS)
++/*!
++ * \internal
++ * \brief Check the status of an outstanding invocation request.
++ *
++ * \param data Points to an integer containing the call completion record id.
++ *
++ * \retval 0 if got a response.
++ * \retval -1 if no response yet.
++ */
++static int misdn_cc_response_check(void *data)
++{
++ int not_responded;
++ struct misdn_cc_record *cc_record;
++
++ AST_LIST_LOCK(&misdn_cc_records_db);
++ cc_record = misdn_cc_find_by_id(*(long *) data);
++ if (cc_record) {
++ if (cc_record->outstanding_message) {
++ not_responded = -1;
++ } else {
++ not_responded = 0;
++ }
++ } else {
++ /* No record so there is no response to check. */
++ not_responded = 0;
++ }
++ AST_LIST_UNLOCK(&misdn_cc_records_db);
++
++ return not_responded;
++}
++#endif /* defined(AST_MISDN_ENHANCEMENTS) */
++
++#if defined(AST_MISDN_ENHANCEMENTS)
++/*!
++ * \internal
++ * \brief Wait for a response from the switch for an outstanding
++ * invocation request.
++ *
++ * \param chan Asterisk channel to operate upon.
++ * \param wait_seconds Number of seconds to wait
++ * \param record_id Call completion record ID.
++ *
++ * \return Nothing
++ */
++static void misdn_cc_response_wait(struct ast_channel *chan, int wait_seconds, long record_id)
++{
++ unsigned count;
++
++ for (count = 2 * MISDN_CC_REQUEST_WAIT_MAX; count--;) {
++ /* Sleep in 500 ms increments */
++ if (ast_safe_sleep_conditional(chan, 500, misdn_cc_response_check, &record_id) != 0) {
++ /* We got hung up or our response came in. */
++ break;
++ }
++ }
++}
++#endif /* defined(AST_MISDN_ENHANCEMENTS) */
++
++#if defined(AST_MISDN_ENHANCEMENTS)
++/*!
++ * \internal
++ * \brief Convert the mISDN reject code to a string
++ *
++ * \param code mISDN reject code.
++ *
++ * \return The mISDN reject code as a string
++ */
++static const char *misdn_to_str_reject_code(enum FacRejectCode code)
++{
++ static const struct {
++ enum FacRejectCode code;
++ char *name;
++ } arr[] = {
++/* *INDENT-OFF* */
++ { FacReject_None, "No reject occurred" },
++ { FacReject_Unknown, "Unknown reject code" },
++
++ { FacReject_Gen_UnrecognizedComponent, "General: Unrecognized Component" },
++ { FacReject_Gen_MistypedComponent, "General: Mistyped Component" },
++ { FacReject_Gen_BadlyStructuredComponent, "General: Badly Structured Component" },
++
++ { FacReject_Inv_DuplicateInvocation, "Invoke: Duplicate Invocation" },
++ { FacReject_Inv_UnrecognizedOperation, "Invoke: Unrecognized Operation" },
++ { FacReject_Inv_MistypedArgument, "Invoke: Mistyped Argument" },
++ { FacReject_Inv_ResourceLimitation, "Invoke: Resource Limitation" },
++ { FacReject_Inv_InitiatorReleasing, "Invoke: Initiator Releasing" },
++ { FacReject_Inv_UnrecognizedLinkedID, "Invoke: Unrecognized Linked ID" },
++ { FacReject_Inv_LinkedResponseUnexpected, "Invoke: Linked Response Unexpected" },
++ { FacReject_Inv_UnexpectedChildOperation, "Invoke: Unexpected Child Operation" },
++
++ { FacReject_Res_UnrecognizedInvocation, "Result: Unrecognized Invocation" },
++ { FacReject_Res_ResultResponseUnexpected, "Result: Result Response Unexpected" },
++ { FacReject_Res_MistypedResult, "Result: Mistyped Result" },
++
++ { FacReject_Err_UnrecognizedInvocation, "Error: Unrecognized Invocation" },
++ { FacReject_Err_ErrorResponseUnexpected, "Error: Error Response Unexpected" },
++ { FacReject_Err_UnrecognizedError, "Error: Unrecognized Error" },
++ { FacReject_Err_UnexpectedError, "Error: Unexpected Error" },
++ { FacReject_Err_MistypedParameter, "Error: Mistyped Parameter" },
++/* *INDENT-ON* */
++ };
++
++ unsigned index;
++
++ for (index = 0; index < ARRAY_LEN(arr); ++index) {
++ if (arr[index].code == code) {
++ return arr[index].name;
++ }
++ }
++
++ return "unknown";
++}
++#endif /* defined(AST_MISDN_ENHANCEMENTS) */
++
++#if defined(AST_MISDN_ENHANCEMENTS)
++/*!
++ * \internal
++ * \brief Convert the mISDN error code to a string
++ *
++ * \param code mISDN error code.
++ *
++ * \return The mISDN error code as a string
++ */
++static const char *misdn_to_str_error_code(enum FacErrorCode code)
++{
++ static const struct {
++ enum FacErrorCode code;
++ char *name;
++ } arr[] = {
++/* *INDENT-OFF* */
++ { FacError_None, "No error occurred" },
++ { FacError_Unknown, "Unknown OID error code" },
++
++ { FacError_Gen_NotSubscribed, "General: Not Subscribed" },
++ { FacError_Gen_NotAvailable, "General: Not Available" },
++ { FacError_Gen_NotImplemented, "General: Not Implemented" },
++ { FacError_Gen_InvalidServedUserNr, "General: Invalid Served User Number" },
++ { FacError_Gen_InvalidCallState, "General: Invalid Call State" },
++ { FacError_Gen_BasicServiceNotProvided, "General: Basic Service Not Provided" },
++ { FacError_Gen_NotIncomingCall, "General: Not Incoming Call" },
++ { FacError_Gen_SupplementaryServiceInteractionNotAllowed,"General: Supplementary Service Interaction Not Allowed" },
++ { FacError_Gen_ResourceUnavailable, "General: Resource Unavailable" },
++
++ { FacError_Div_InvalidDivertedToNr, "Diversion: Invalid Diverted To Number" },
++ { FacError_Div_SpecialServiceNr, "Diversion: Special Service Number" },
++ { FacError_Div_DiversionToServedUserNr, "Diversion: Diversion To Served User Number" },
++ { FacError_Div_IncomingCallAccepted, "Diversion: Incoming Call Accepted" },
++ { FacError_Div_NumberOfDiversionsExceeded, "Diversion: Number Of Diversions Exceeded" },
++ { FacError_Div_NotActivated, "Diversion: Not Activated" },
++ { FacError_Div_RequestAlreadyAccepted, "Diversion: Request Already Accepted" },
++
++ { FacError_AOC_NoChargingInfoAvailable, "AOC: No Charging Info Available" },
++
++ { FacError_CCBS_InvalidCallLinkageID, "CCBS: Invalid Call Linkage ID" },
++ { FacError_CCBS_InvalidCCBSReference, "CCBS: Invalid CCBS Reference" },
++ { FacError_CCBS_LongTermDenial, "CCBS: Long Term Denial" },
++ { FacError_CCBS_ShortTermDenial, "CCBS: Short Term Denial" },
++ { FacError_CCBS_IsAlreadyActivated, "CCBS: Is Already Activated" },
++ { FacError_CCBS_AlreadyAccepted, "CCBS: Already Accepted" },
++ { FacError_CCBS_OutgoingCCBSQueueFull, "CCBS: Outgoing CCBS Queue Full" },
++ { FacError_CCBS_CallFailureReasonNotBusy, "CCBS: Call Failure Reason Not Busy" },
++ { FacError_CCBS_NotReadyForCall, "CCBS: Not Ready For Call" },
++
++ { FacError_CCBS_T_LongTermDenial, "CCBS-T: Long Term Denial" },
++ { FacError_CCBS_T_ShortTermDenial, "CCBS-T: Short Term Denial" },
++
++ { FacError_ECT_LinkIdNotAssignedByNetwork, "ECT: Link ID Not Assigned By Network" },
++/* *INDENT-ON* */
++ };
++
++ unsigned index;
++
++ for (index = 0; index < ARRAY_LEN(arr); ++index) {
++ if (arr[index].code == code) {
++ return arr[index].name;
++ }
++ }
++
++ return "unknown";
++}
++#endif /* defined(AST_MISDN_ENHANCEMENTS) */
++
++#if defined(AST_MISDN_ENHANCEMENTS)
++/*!
++ * \internal
++ * \brief Convert mISDN redirecting reason to diversion reason.
++ *
++ * \param reason mISDN redirecting reason code.
++ *
++ * \return Supported diversion reason code.
++ */
++static unsigned misdn_to_diversion_reason(enum mISDN_REDIRECTING_REASON reason)
++{
++ unsigned diversion_reason;
++
++ switch (reason) {
++ case mISDN_REDIRECTING_REASON_CALL_FWD:
++ diversion_reason = 1;/* cfu */
++ break;
++ case mISDN_REDIRECTING_REASON_CALL_FWD_BUSY:
++ diversion_reason = 2;/* cfb */
++ break;
++ case mISDN_REDIRECTING_REASON_NO_REPLY:
++ diversion_reason = 3;/* cfnr */
++ break;
++ default:
++ diversion_reason = 0;/* unknown */
++ break;
++ }
++
++ return diversion_reason;
++}
++#endif /* defined(AST_MISDN_ENHANCEMENTS) */
++
++#if defined(AST_MISDN_ENHANCEMENTS)
++/*!
++ * \internal
++ * \brief Convert diversion reason to mISDN redirecting reason
++ *
++ * \param diversion_reason Diversion reason to convert
++ *
++ * \return Supported redirecting reason code.
++ */
++static enum mISDN_REDIRECTING_REASON diversion_reason_to_misdn(unsigned diversion_reason)
++{
++ enum mISDN_REDIRECTING_REASON reason;
++
++ switch (diversion_reason) {
++ case 1:/* cfu */
++ reason = mISDN_REDIRECTING_REASON_CALL_FWD;
++ break;
++ case 2:/* cfb */
++ reason = mISDN_REDIRECTING_REASON_CALL_FWD_BUSY;
++ break;
++ case 3:/* cfnr */
++ reason = mISDN_REDIRECTING_REASON_NO_REPLY;
++ break;
++ default:
++ reason = mISDN_REDIRECTING_REASON_UNKNOWN;
++ break;
++ }
++
++ return reason;
++}
++#endif /* defined(AST_MISDN_ENHANCEMENTS) */
++
++#if defined(AST_MISDN_ENHANCEMENTS)
++/*!
++ * \internal
++ * \brief Convert the mISDN presentation to PresentedNumberUnscreened type
++ *
++ * \param presentation mISDN presentation to convert
++ * \param number_present TRUE if the number is present
++ *
++ * \return PresentedNumberUnscreened type
++ */
++static unsigned misdn_to_PresentedNumberUnscreened_type(int presentation, int number_present)
++{
++ unsigned type;
++
++ switch (presentation) {
++ case 0:/* allowed */
++ if (number_present) {
++ type = 0;/* presentationAllowedNumber */
++ } else {
++ type = 2;/* numberNotAvailableDueToInterworking */
++ }
++ break;
++ case 1:/* restricted */
++ if (number_present) {
++ type = 3;/* presentationRestrictedNumber */
++ } else {
++ type = 1;/* presentationRestricted */
++ }
++ break;
++ default:
++ type = 2;/* numberNotAvailableDueToInterworking */
++ break;
++ }
++
++ return type;
++}
++#endif /* defined(AST_MISDN_ENHANCEMENTS) */
++
++#if defined(AST_MISDN_ENHANCEMENTS)
++/*!
++ * \internal
++ * \brief Convert the PresentedNumberUnscreened type to mISDN presentation
++ *
++ * \param type PresentedNumberUnscreened type
++ *
++ * \return mISDN presentation
++ */
++static int PresentedNumberUnscreened_to_misdn_pres(unsigned type)
++{
++ int presentation;
++
++ switch (type) {
++ default:
++ case 0:/* presentationAllowedNumber */
++ presentation = 0;/* allowed */
++ break;
++
++ case 1:/* presentationRestricted */
++ case 3:/* presentationRestrictedNumber */
++ presentation = 1;/* restricted */
++ break;
++
++ case 2:/* numberNotAvailableDueToInterworking */
++ presentation = 2;/* unavailable */
++ break;
++ }
++
++ return presentation;
++}
++#endif /* defined(AST_MISDN_ENHANCEMENTS) */
++
++#if defined(AST_MISDN_ENHANCEMENTS)
++/*!
++ * \internal
++ * \brief Convert the mISDN numbering plan to PartyNumber numbering plan
++ *
++ * \param number_plan mISDN numbering plan
++ *
++ * \return PartyNumber numbering plan
++ */
++static unsigned misdn_to_PartyNumber_plan(enum mISDN_NUMBER_PLAN number_plan)
++{
++ unsigned party_plan;
++
++ switch (number_plan) {
++ default:
++ case NUMPLAN_UNKNOWN:
++ party_plan = 0;/* unknown */
++ break;
++
++ case NUMPLAN_ISDN:
++ party_plan = 1;/* public */
++ break;
++
++ case NUMPLAN_DATA:
++ party_plan = 3;/* data */
++ break;
++
++ case NUMPLAN_TELEX:
++ party_plan = 4;/* telex */
++ break;
++
++ case NUMPLAN_NATIONAL:
++ party_plan = 8;/* nationalStandard */
++ break;
++
++ case NUMPLAN_PRIVATE:
++ party_plan = 5;/* private */
++ break;
++ }
++
++ return party_plan;
++}
++#endif /* defined(AST_MISDN_ENHANCEMENTS) */
++
++#if defined(AST_MISDN_ENHANCEMENTS)
++/*!
++ * \internal
++ * \brief Convert PartyNumber numbering plan to mISDN numbering plan
++ *
++ * \param party_plan PartyNumber numbering plan
++ *
++ * \return mISDN numbering plan
++ */
++static enum mISDN_NUMBER_PLAN PartyNumber_to_misdn_plan(unsigned party_plan)
++{
++ enum mISDN_NUMBER_PLAN number_plan;
++
++ switch (party_plan) {
++ default:
++ case 0:/* unknown */
++ number_plan = NUMPLAN_UNKNOWN;
++ break;
++ case 1:/* public */
++ number_plan = NUMPLAN_ISDN;
++ break;
++ case 3:/* data */
++ number_plan = NUMPLAN_DATA;
++ break;
++ case 4:/* telex */
++ number_plan = NUMPLAN_TELEX;
++ break;
++ case 8:/* nationalStandard */
++ number_plan = NUMPLAN_NATIONAL;
++ break;
++ case 5:/* private */
++ number_plan = NUMPLAN_PRIVATE;
++ break;
++ }
++
++ return number_plan;
++}
++#endif /* defined(AST_MISDN_ENHANCEMENTS) */
++
++#if defined(AST_MISDN_ENHANCEMENTS)
++/*!
++ * \internal
++ * \brief Convert mISDN type-of-number to PartyNumber public type-of-number
++ *
++ * \param ton mISDN type-of-number
++ *
++ * \return PartyNumber public type-of-number
++ */
++static unsigned misdn_to_PartyNumber_ton_public(enum mISDN_NUMBER_TYPE ton)
++{
++ unsigned party_ton;
++
++ switch (ton) {
++ default:
++ case NUMTYPE_UNKNOWN:
++ party_ton = 0;/* unknown */
++ break;
++
++ case NUMTYPE_INTERNATIONAL:
++ party_ton = 1;/* internationalNumber */
++ break;
++
++ case NUMTYPE_NATIONAL:
++ party_ton = 2;/* nationalNumber */
++ break;
++
++ case NUMTYPE_NETWORK_SPECIFIC:
++ party_ton = 3;/* networkSpecificNumber */
++ break;
++
++ case NUMTYPE_SUBSCRIBER:
++ party_ton = 4;/* subscriberNumber */
++ break;
++
++ case NUMTYPE_ABBREVIATED:
++ party_ton = 6;/* abbreviatedNumber */
++ break;
++ }
++
++ return party_ton;
++}
++#endif /* defined(AST_MISDN_ENHANCEMENTS) */
++
++#if defined(AST_MISDN_ENHANCEMENTS)
++/*!
++ * \internal
++ * \brief Convert the PartyNumber public type-of-number to mISDN type-of-number
++ *
++ * \param party_ton PartyNumber public type-of-number
++ *
++ * \return mISDN type-of-number
++ */
++static enum mISDN_NUMBER_TYPE PartyNumber_to_misdn_ton_public(unsigned party_ton)
++{
++ enum mISDN_NUMBER_TYPE ton;
++
++ switch (party_ton) {
++ default:
++ case 0:/* unknown */
++ ton = NUMTYPE_UNKNOWN;
++ break;
++
++ case 1:/* internationalNumber */
++ ton = NUMTYPE_INTERNATIONAL;
++ break;
++
++ case 2:/* nationalNumber */
++ ton = NUMTYPE_NATIONAL;
++ break;
++
++ case 3:/* networkSpecificNumber */
++ ton = NUMTYPE_NETWORK_SPECIFIC;
++ break;
++
++ case 4:/* subscriberNumber */
++ ton = NUMTYPE_SUBSCRIBER;
++ break;
++
++ case 6:/* abbreviatedNumber */
++ ton = NUMTYPE_ABBREVIATED;
++ break;
++ }
++
++ return ton;
++}
++#endif /* defined(AST_MISDN_ENHANCEMENTS) */
++
++#if defined(AST_MISDN_ENHANCEMENTS)
++/*!
++ * \internal
++ * \brief Convert mISDN type-of-number to PartyNumber private type-of-number
++ *
++ * \param ton mISDN type-of-number
++ *
++ * \return PartyNumber private type-of-number
++ */
++static unsigned misdn_to_PartyNumber_ton_private(enum mISDN_NUMBER_TYPE ton)
++{
++ unsigned party_ton;
++
++ switch (ton) {
++ default:
++ case NUMTYPE_UNKNOWN:
++ party_ton = 0;/* unknown */
++ break;
++
++ case NUMTYPE_INTERNATIONAL:
++ party_ton = 1;/* level2RegionalNumber */
++ break;
++
++ case NUMTYPE_NATIONAL:
++ party_ton = 2;/* level1RegionalNumber */
++ break;
++
++ case NUMTYPE_NETWORK_SPECIFIC:
++ party_ton = 3;/* pTNSpecificNumber */
++ break;
++
++ case NUMTYPE_SUBSCRIBER:
++ party_ton = 4;/* localNumber */
++ break;
++
++ case NUMTYPE_ABBREVIATED:
++ party_ton = 6;/* abbreviatedNumber */
++ break;
++ }
++
++ return party_ton;
++}
++#endif /* defined(AST_MISDN_ENHANCEMENTS) */
++
++#if defined(AST_MISDN_ENHANCEMENTS)
++/*!
++ * \internal
++ * \brief Convert the PartyNumber private type-of-number to mISDN type-of-number
++ *
++ * \param party_ton PartyNumber private type-of-number
++ *
++ * \return mISDN type-of-number
++ */
++static enum mISDN_NUMBER_TYPE PartyNumber_to_misdn_ton_private(unsigned party_ton)
++{
++ enum mISDN_NUMBER_TYPE ton;
++
++ switch (party_ton) {
++ default:
++ case 0:/* unknown */
++ ton = NUMTYPE_UNKNOWN;
++ break;
++
++ case 1:/* level2RegionalNumber */
++ ton = NUMTYPE_INTERNATIONAL;
++ break;
++
++ case 2:/* level1RegionalNumber */
++ ton = NUMTYPE_NATIONAL;
++ break;
++
++ case 3:/* pTNSpecificNumber */
++ ton = NUMTYPE_NETWORK_SPECIFIC;
++ break;
++
++ case 4:/* localNumber */
++ ton = NUMTYPE_SUBSCRIBER;
++ break;
++
++ case 6:/* abbreviatedNumber */
++ ton = NUMTYPE_ABBREVIATED;
++ break;
++ }
++
++ return ton;
++}
++#endif /* defined(AST_MISDN_ENHANCEMENTS) */
++
++/*!
++ * \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 +2318,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,30 +2337,594 @@
+ if (allowed_bearers_array[index].cap == cap) {
+ return allowed_bearers_array[index].display;
+ }
+- } /* end for */
++ }
+
+ return "Unknown Bearer";
+ }
+
++#if defined(AST_MISDN_ENHANCEMENTS)
++/*!
++ * \internal
++ * \brief Fill in facility PartyNumber information
++ *
++ * \param party PartyNumber structure to fill in.
++ * \param id Information to put in PartyNumber structure.
++ *
++ * \return Nothing
++ */
++static void misdn_PartyNumber_fill(struct FacPartyNumber *party, const struct misdn_party_id *id)
++{
++ ast_copy_string((char *) party->Number, id->number, sizeof(party->Number));
++ party->LengthOfNumber = strlen((char *) party->Number);
++ party->Type = misdn_to_PartyNumber_plan(id->number_plan);
++ switch (party->Type) {
++ case 1:/* public */
++ party->TypeOfNumber = misdn_to_PartyNumber_ton_public(id->number_type);
++ break;
++ case 5:/* private */
++ party->TypeOfNumber = misdn_to_PartyNumber_ton_private(id->number_type);
++ break;
++ default:
++ party->TypeOfNumber = 0;/* Dont't care */
++ break;
++ }
++}
++#endif /* defined(AST_MISDN_ENHANCEMENTS) */
+
+-static void print_facility(struct FacParm *fac, struct misdn_bchannel *bc)
++#if defined(AST_MISDN_ENHANCEMENTS)
++/*!
++ * \internal
++ * \brief Extract the information from PartyNumber
++ *
++ * \param id Where to put extracted PartyNumber information
++ * \param party PartyNumber information to extract
++ *
++ * \return Nothing
++ */
++static void misdn_PartyNumber_extract(struct misdn_party_id *id, const struct FacPartyNumber *party)
+ {
++ if (party->LengthOfNumber) {
++ ast_copy_string(id->number, (char *) party->Number, sizeof(id->number));
++ id->number_plan = PartyNumber_to_misdn_plan(party->Type);
++ switch (party->Type) {
++ case 1:/* public */
++ id->number_type = PartyNumber_to_misdn_ton_public(party->TypeOfNumber);
++ break;
++ case 5:/* private */
++ id->number_type = PartyNumber_to_misdn_ton_private(party->TypeOfNumber);
++ break;
++ default:
++ id->number_type = NUMTYPE_UNKNOWN;
++ break;
++ }
++ } else {
++ /* Number not present */
++ id->number_type = NUMTYPE_UNKNOWN;
++ id->number_plan = NUMPLAN_ISDN;
++ id->number[0] = 0;
++ }
++}
++#endif /* defined(AST_MISDN_ENHANCEMENTS) */
++
++#if defined(AST_MISDN_ENHANCEMENTS)
++/*!
++ * \internal
++ * \brief Fill in facility Address information
++ *
++ * \param Address Address structure to fill in.
++ * \param id Information to put in Address structure.
++ *
++ * \return Nothing
++ */
++static void misdn_Address_fill(struct FacAddress *Address, const struct misdn_party_id *id)
++{
++ misdn_PartyNumber_fill(&Address->Party, id);
++
++ /* Subaddresses are not supported yet */
++ Address->Subaddress.Length = 0;
++}
++#endif /* defined(AST_MISDN_ENHANCEMENTS) */
++
++#if defined(AST_MISDN_ENHANCEMENTS)
++/*!
++ * \internal
++ * \brief Fill in facility PresentedNumberUnscreened information
++ *
++ * \param presented PresentedNumberUnscreened structure to fill in.
++ * \param id Information to put in PresentedNumberUnscreened structure.
++ *
++ * \return Nothing
++ */
++static void misdn_PresentedNumberUnscreened_fill(struct FacPresentedNumberUnscreened *presented, const struct misdn_party_id *id)
++{
++ presented->Type = misdn_to_PresentedNumberUnscreened_type(id->presentation, id->number[0] ? 1 : 0);
++ misdn_PartyNumber_fill(&presented->Unscreened, id);
++}
++#endif /* defined(AST_MISDN_ENHANCEMENTS) */
++
++#if defined(AST_MISDN_ENHANCEMENTS)
++/*!
++ * \internal
++ * \brief Extract the information from PartyNumber
++ *
++ * \param id Where to put extracted PresentedNumberUnscreened information
++ * \param presented PresentedNumberUnscreened information to extract
++ *
++ * \return Nothing
++ */
++static void misdn_PresentedNumberUnscreened_extract(struct misdn_party_id *id, const struct FacPresentedNumberUnscreened *presented)
++{
++ id->presentation = PresentedNumberUnscreened_to_misdn_pres(presented->Type);
++ id->screening = 0;/* unscreened */
++ misdn_PartyNumber_extract(id, &presented->Unscreened);
++}
++#endif /* defined(AST_MISDN_ENHANCEMENTS) */
++
++#if defined(AST_MISDN_ENHANCEMENTS)
++static const char Level_Spacing[] = " ";/* Work for up to 10 levels */
++#endif /* defined(AST_MISDN_ENHANCEMENTS) */
++
++#if defined(AST_MISDN_ENHANCEMENTS)
++static void print_facility_PartyNumber(unsigned Level, const struct FacPartyNumber *Party, const struct misdn_bchannel *bc)
++{
++ if (Party->LengthOfNumber) {
++ const char *Spacing;
++
++ Spacing = &Level_Spacing[sizeof(Level_Spacing) - 1 - Level];
++ chan_misdn_log(1, bc->port, " -->%s PartyNumber: Type:%d\n",
++ Spacing, Party->Type);
++ switch (Party->Type) {
++ case 0: /* Unknown PartyNumber */
++ chan_misdn_log(1, bc->port, " -->%s Unknown: %s\n",
++ Spacing, Party->Number);
++ break;
++ case 1: /* Public PartyNumber */
++ chan_misdn_log(1, bc->port, " -->%s Public TON:%d %s\n",
++ Spacing, Party->TypeOfNumber, Party->Number);
++ break;
++ case 2: /* NSAP encoded PartyNumber */
++ chan_misdn_log(1, bc->port, " -->%s NSAP: %s\n",
++ Spacing, Party->Number);
++ break;
++ case 3: /* Data PartyNumber (Not used) */
++ chan_misdn_log(1, bc->port, " -->%s Data: %s\n",
++ Spacing, Party->Number);
++ break;
++ case 4: /* Telex PartyNumber (Not used) */
++ chan_misdn_log(1, bc->port, " -->%s Telex: %s\n",
++ Spacing, Party->Number);
++ break;
++ case 5: /* Private PartyNumber */
++ chan_misdn_log(1, bc->port, " -->%s Private TON:%d %s\n",
++ Spacing, Party->TypeOfNumber, Party->Number);
++ break;
++ case 8: /* National Standard PartyNumber (Not used) */
++ chan_misdn_log(1, bc->port, " -->%s National: %s\n",
++ Spacing, Party->Number);
++ break;
++ default:
++ break;
++ }
++ }
++}
++#endif /* defined(AST_MISDN_ENHANCEMENTS) */
++
++#if defined(AST_MISDN_ENHANCEMENTS)
++static void print_facility_Subaddress(unsigned Level, const struct FacPartySubaddress *Subaddress, const struct misdn_bchannel *bc)
++{
++ if (Subaddress->Length) {
++ const char *Spacing;
++
++ Spacing = &Level_Spacing[sizeof(Level_Spacing) - 1 - Level];
++ chan_misdn_log(1, bc->port, " -->%s Subaddress: Type:%d\n",
++ Spacing, Subaddress->Type);
++ switch (Subaddress->Type) {
++ case 0: /* UserSpecified */
++ if (Subaddress->u.UserSpecified.OddCountPresent) {
++ chan_misdn_log(1, bc->port, " -->%s User BCD OddCount:%d NumOctets:%d\n",
++ Spacing, Subaddress->u.UserSpecified.OddCount, Subaddress->Length);
++ } else {
++ chan_misdn_log(1, bc->port, " -->%s User: %s\n",
++ Spacing, Subaddress->u.UserSpecified.Information);
++ }
++ break;
++ case 1: /* NSAP */
++ chan_misdn_log(1, bc->port, " -->%s NSAP: %s\n",
++ Spacing, Subaddress->u.Nsap);
++ break;
++ default:
++ break;
++ }
++ }
++}
++#endif /* defined(AST_MISDN_ENHANCEMENTS) */
++
++#if defined(AST_MISDN_ENHANCEMENTS)
++static void print_facility_Address(unsigned Level, const struct FacAddress *Address, const struct misdn_bchannel *bc)
++{
++ print_facility_PartyNumber(Level, &Address->Party, bc);
++ print_facility_Subaddress(Level, &Address->Subaddress, bc);
++}
++#endif /* defined(AST_MISDN_ENHANCEMENTS) */
++
++#if defined(AST_MISDN_ENHANCEMENTS)
++static void print_facility_PresentedNumberUnscreened(unsigned Level, const struct FacPresentedNumberUnscreened *Presented, const struct misdn_bchannel *bc)
++{
++ const char *Spacing;
++
++ Spacing = &Level_Spacing[sizeof(Level_Spacing) - 1 - Level];
++ chan_misdn_log(1, bc->port, " -->%s Unscreened Type:%d\n", Spacing, Presented->Type);
++ switch (Presented->Type) {
++ case 0: /* presentationAllowedNumber */
++ chan_misdn_log(1, bc->port, " -->%s Allowed:\n", Spacing);
++ print_facility_PartyNumber(Level + 2, &Presented->Unscreened, bc);
++ break;
++ case 1: /* presentationRestricted */
++ chan_misdn_log(1, bc->port, " -->%s Restricted\n", Spacing);
++ break;
++ case 2: /* numberNotAvailableDueToInterworking */
++ chan_misdn_log(1, bc->port, " -->%s Not Available\n", Spacing);
++ break;
++ case 3: /* presentationRestrictedNumber */
++ chan_misdn_log(1, bc->port, " -->%s Restricted:\n", Spacing);
++ print_facility_PartyNumber(Level + 2, &Presented->Unscreened, bc);
++ break;
++ default:
++ break;
++ }
++}
++#endif /* defined(AST_MISDN_ENHANCEMENTS) */
++
++#if defined(AST_MISDN_ENHANCEMENTS)
++static void print_facility_AddressScreened(unsigned Level, const struct FacAddressScreened *Address, const struct misdn_bchannel *bc)
++{
++ const char *Spacing;
++
++ Spacing = &Level_Spacing[sizeof(Level_Spacing) - 1 - Level];
++ chan_misdn_log(1, bc->port, " -->%s ScreeningIndicator:%d\n", Spacing, Address->ScreeningIndicator);
++ print_facility_PartyNumber(Level, &Address->Party, bc);
++ print_facility_Subaddress(Level, &Address->Subaddress, bc);
++}
++#endif /* defined(AST_MISDN_ENHANCEMENTS) */
++
++#if defined(AST_MISDN_ENHANCEMENTS)
++static void print_facility_PresentedAddressScreened(unsigned Level, const struct FacPresentedAddressScreened *Presented, const struct misdn_bchannel *bc)
++{
++ const char *Spacing;
++
++ Spacing = &Level_Spacing[sizeof(Level_Spacing) - 1 - Level];
++ chan_misdn_log(1, bc->port, " -->%s Screened Type:%d\n", Spacing, Presented->Type);
++ switch (Presented->Type) {
++ case 0: /* presentationAllowedAddress */
++ chan_misdn_log(1, bc->port, " -->%s Allowed:\n", Spacing);
++ print_facility_AddressScreened(Level + 2, &Presented->Address, bc);
++ break;
++ case 1: /* presentationRestricted */
++ chan_misdn_log(1, bc->port, " -->%s Restricted\n", Spacing);
++ break;
++ case 2: /* numberNotAvailableDueToInterworking */
++ chan_misdn_log(1, bc->port, " -->%s Not Available\n", Spacing);
++ break;
++ case 3: /* presentationRestrictedAddress */
++ chan_misdn_log(1, bc->port, " -->%s Restricted:\n", Spacing);
++ print_facility_AddressScreened(Level + 2, &Presented->Address, bc);
++ break;
++ default:
++ break;
++ }
++}
++#endif /* defined(AST_MISDN_ENHANCEMENTS) */
++
++#if defined(AST_MISDN_ENHANCEMENTS)
++static void print_facility_Q931_Bc_Hlc_Llc(unsigned Level, const struct Q931_Bc_Hlc_Llc *Q931ie, const struct misdn_bchannel *bc)
++{
++ const char *Spacing;
++
++ Spacing = &Level_Spacing[sizeof(Level_Spacing) - 1 - Level];
++ chan_misdn_log(1, bc->port, " -->%s Q931ie:\n", Spacing);
++ if (Q931ie->Bc.Length) {
++ chan_misdn_log(1, bc->port, " -->%s Bc Len:%d\n", Spacing, Q931ie->Bc.Length);
++ }
++ if (Q931ie->Hlc.Length) {
++ chan_misdn_log(1, bc->port, " -->%s Hlc Len:%d\n", Spacing, Q931ie->Hlc.Length);
++ }
++ if (Q931ie->Llc.Length) {
++ chan_misdn_log(1, bc->port, " -->%s Llc Len:%d\n", Spacing, Q931ie->Llc.Length);
++ }
++}
++#endif /* defined(AST_MISDN_ENHANCEMENTS) */
++
++#if defined(AST_MISDN_ENHANCEMENTS)
++static void print_facility_Q931_Bc_Hlc_Llc_Uu(unsigned Level, const struct Q931_Bc_Hlc_Llc_Uu *Q931ie, const struct misdn_bchannel *bc)
++{
++ const char *Spacing;
++
++ Spacing = &Level_Spacing[sizeof(Level_Spacing) - 1 - Level];
++ chan_misdn_log(1, bc->port, " -->%s Q931ie:\n", Spacing);
++ if (Q931ie->Bc.Length) {
++ chan_misdn_log(1, bc->port, " -->%s Bc Len:%d\n", Spacing, Q931ie->Bc.Length);
++ }
++ if (Q931ie->Hlc.Length) {
++ chan_misdn_log(1, bc->port, " -->%s Hlc Len:%d\n", Spacing, Q931ie->Hlc.Length);
++ }
++ if (Q931ie->Llc.Length) {
++ chan_misdn_log(1, bc->port, " -->%s Llc Len:%d\n", Spacing, Q931ie->Llc.Length);
++ }
++ if (Q931ie->UserInfo.Length) {
++ chan_misdn_log(1, bc->port, " -->%s UserInfo Len:%d\n", Spacing, Q931ie->UserInfo.Length);
++ }
++}
++#endif /* defined(AST_MISDN_ENHANCEMENTS) */
++
++#if defined(AST_MISDN_ENHANCEMENTS)
++static void print_facility_CallInformation(unsigned Level, const struct FacCallInformation *CallInfo, const struct misdn_bchannel *bc)
++{
++ const char *Spacing;
++
++ Spacing = &Level_Spacing[sizeof(Level_Spacing) - 1 - Level];
++ chan_misdn_log(1, bc->port, " -->%s CCBSReference:%d\n",
++ Spacing, CallInfo->CCBSReference);
++ chan_misdn_log(1, bc->port, " -->%s AddressOfB:\n", Spacing);
++ print_facility_Address(Level + 1, &CallInfo->AddressOfB, bc);
++ print_facility_Q931_Bc_Hlc_Llc(Level, &CallInfo->Q931ie, bc);
++ if (CallInfo->SubaddressOfA.Length) {
++ chan_misdn_log(1, bc->port, " -->%s SubaddressOfA:\n", Spacing);
++ print_facility_Subaddress(Level + 1, &CallInfo->SubaddressOfA, bc);
++ }
++}
++#endif /* defined(AST_MISDN_ENHANCEMENTS) */
++
++#if defined(AST_MISDN_ENHANCEMENTS)
++static void print_facility_ServedUserNr(unsigned Level, const struct FacPartyNumber *Party, const struct misdn_bchannel *bc)
++{
++ const char *Spacing;
++
++ Spacing = &Level_Spacing[sizeof(Level_Spacing) - 1 - Level];
++ if (Party->LengthOfNumber) {
++ print_facility_PartyNumber(Level, Party, bc);
++ } else {
++ chan_misdn_log(1, bc->port, " -->%s All Numbers\n", Spacing);
++ }
++}
++#endif /* defined(AST_MISDN_ENHANCEMENTS) */
++
++#if defined(AST_MISDN_ENHANCEMENTS)
++static void print_facility_IntResult(unsigned Level, const struct FacForwardingRecord *ForwardingRecord, const struct misdn_bchannel *bc)
++{
++ const char *Spacing;
++
++ Spacing = &Level_Spacing[sizeof(Level_Spacing) - 1 - Level];
++ chan_misdn_log(1, bc->port, " -->%s Procedure:%d BasicService:%d\n",
++ Spacing,
++ ForwardingRecord->Procedure,
++ ForwardingRecord->BasicService);
++ chan_misdn_log(1, bc->port, " -->%s ForwardedTo:\n", Spacing);
++ print_facility_Address(Level + 1, &ForwardingRecord->ForwardedTo, bc);
++ chan_misdn_log(1, bc->port, " -->%s ServedUserNr:\n", Spacing);
++ print_facility_ServedUserNr(Level + 1, &ForwardingRecord->ServedUser, bc);
++}
++#endif /* defined(AST_MISDN_ENHANCEMENTS) */
++
++static void print_facility(const struct FacParm *fac, const const struct misdn_bchannel *bc)
++{
++#if defined(AST_MISDN_ENHANCEMENTS)
++ unsigned Index;
++#endif /* defined(AST_MISDN_ENHANCEMENTS) */
++
+ switch (fac->Function) {
+-#ifdef HAVE_MISDN_FAC_RESULT
+- case Fac_RESULT:
+- chan_misdn_log(0, bc->port, " --> Received RESULT Operation\n");
++#if defined(AST_MISDN_ENHANCEMENTS)
++ case Fac_ActivationDiversion:
++ chan_misdn_log(1, bc->port, " --> ActivationDiversion: InvokeID:%d\n",
++ fac->u.ActivationDiversion.InvokeID);
++ switch (fac->u.ActivationDiversion.ComponentType) {
++ case FacComponent_Invoke:
++ chan_misdn_log(1, bc->port, " --> Invoke: Procedure:%d BasicService:%d\n",
++ fac->u.ActivationDiversion.Component.Invoke.Procedure,
++ fac->u.ActivationDiversion.Component.Invoke.BasicService);
++ chan_misdn_log(1, bc->port, " --> ForwardedTo:\n");
++ print_facility_Address(3, &fac->u.ActivationDiversion.Component.Invoke.ForwardedTo, bc);
++ chan_misdn_log(1, bc->port, " --> ServedUserNr:\n");
++ print_facility_ServedUserNr(3, &fac->u.ActivationDiversion.Component.Invoke.ServedUser, bc);
++ break;
++ case FacComponent_Result:
++ chan_misdn_log(1, bc->port, " --> Result\n");
++ break;
++ default:
++ break;
++ }
+ 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);
++ case Fac_DeactivationDiversion:
++ chan_misdn_log(1, bc->port, " --> DeactivationDiversion: InvokeID:%d\n",
++ fac->u.DeactivationDiversion.InvokeID);
++ switch (fac->u.DeactivationDiversion.ComponentType) {
++ case FacComponent_Invoke:
++ chan_misdn_log(1, bc->port, " --> Invoke: Procedure:%d BasicService:%d\n",
++ fac->u.DeactivationDiversion.Component.Invoke.Procedure,
++ fac->u.DeactivationDiversion.Component.Invoke.BasicService);
++ chan_misdn_log(1, bc->port, " --> ServedUserNr:\n");
++ print_facility_ServedUserNr(3, &fac->u.DeactivationDiversion.Component.Invoke.ServedUser, bc);
++ break;
++ case FacComponent_Result:
++ chan_misdn_log(1, bc->port, " --> Result\n");
++ break;
++ default:
++ break;
++ }
+ break;
+-#endif
++ case Fac_ActivationStatusNotificationDiv:
++ chan_misdn_log(1, bc->port, " --> ActivationStatusNotificationDiv: InvokeID:%d Procedure:%d BasicService:%d\n",
++ fac->u.ActivationStatusNotificationDiv.InvokeID,
++ fac->u.ActivationStatusNotificationDiv.Procedure,
++ fac->u.ActivationStatusNotificationDiv.BasicService);
++ chan_misdn_log(1, bc->port, " --> ForwardedTo:\n");
++ print_facility_Address(2, &fac->u.ActivationStatusNotificationDiv.ForwardedTo, bc);
++ chan_misdn_log(1, bc->port, " --> ServedUserNr:\n");
++ print_facility_ServedUserNr(2, &fac->u.ActivationStatusNotificationDiv.ServedUser, bc);
++ break;
++ case Fac_DeactivationStatusNotificationDiv:
++ chan_misdn_log(1, bc->port, " --> DeactivationStatusNotificationDiv: InvokeID:%d Procedure:%d BasicService:%d\n",
++ fac->u.DeactivationStatusNotificationDiv.InvokeID,
++ fac->u.DeactivationStatusNotificationDiv.Procedure,
++ fac->u.DeactivationStatusNotificationDiv.BasicService);
++ chan_misdn_log(1, bc->port, " --> ServedUserNr:\n");
++ print_facility_ServedUserNr(2, &fac->u.DeactivationStatusNotificationDiv.ServedUser, bc);
++ break;
++ case Fac_InterrogationDiversion:
++ chan_misdn_log(1, bc->port, " --> InterrogationDiversion: InvokeID:%d\n",
++ fac->u.InterrogationDiversion.InvokeID);
++ switch (fac->u.InterrogationDiversion.ComponentType) {
++ case FacComponent_Invoke:
++ chan_misdn_log(1, bc->port, " --> Invoke: Procedure:%d BasicService:%d\n",
++ fac->u.InterrogationDiversion.Component.Invoke.Procedure,
++ fac->u.InterrogationDiversion.Component.Invoke.BasicService);
++ chan_misdn_log(1, bc->port, " --> ServedUserNr:\n");
++ print_facility_ServedUserNr(3, &fac->u.InterrogationDiversion.Component.Invoke.ServedUser, bc);
++ break;
++ case FacComponent_Result:
++ chan_misdn_log(1, bc->port, " --> Result:\n");
++ if (fac->u.InterrogationDiversion.Component.Result.NumRecords) {
++ for (Index = 0; Index < fac->u.InterrogationDiversion.Component.Result.NumRecords; ++Index) {
++ chan_misdn_log(1, bc->port, " --> IntResult[%d]:\n", Index);
++ print_facility_IntResult(3, &fac->u.InterrogationDiversion.Component.Result.List[Index], bc);
++ }
++ }
++ break;
++ default:
++ break;
++ }
++ break;
++ case Fac_DiversionInformation:
++ chan_misdn_log(1, bc->port, " --> DiversionInformation: InvokeID:%d Reason:%d BasicService:%d\n",
++ fac->u.DiversionInformation.InvokeID,
++ fac->u.DiversionInformation.DiversionReason,
++ fac->u.DiversionInformation.BasicService);
++ if (fac->u.DiversionInformation.ServedUserSubaddress.Length) {
++ chan_misdn_log(1, bc->port, " --> ServedUserSubaddress:\n");
++ print_facility_Subaddress(2, &fac->u.DiversionInformation.ServedUserSubaddress, bc);
++ }
++ if (fac->u.DiversionInformation.CallingAddressPresent) {
++ chan_misdn_log(1, bc->port, " --> CallingAddress:\n");
++ print_facility_PresentedAddressScreened(2, &fac->u.DiversionInformation.CallingAddress, bc);
++ }
++ if (fac->u.DiversionInformation.OriginalCalledPresent) {
++ chan_misdn_log(1, bc->port, " --> OriginalCalledNr:\n");
++ print_facility_PresentedNumberUnscreened(2, &fac->u.DiversionInformation.OriginalCalled, bc);
++ }
++ if (fac->u.DiversionInformation.LastDivertingPresent) {
++ chan_misdn_log(1, bc->port, " --> LastDivertingNr:\n");
++ print_facility_PresentedNumberUnscreened(2, &fac->u.DiversionInformation.LastDiverting, bc);
++ }
++ if (fac->u.DiversionInformation.LastDivertingReasonPresent) {
++ chan_misdn_log(1, bc->port, " --> LastDivertingReason:%d\n", fac->u.DiversionInformation.LastDivertingReason);
++ }
++ if (fac->u.DiversionInformation.UserInfo.Length) {
++ chan_misdn_log(1, bc->port, " --> UserInfo Length:%d\n", fac->u.DiversionInformation.UserInfo.Length);
++ }
++ break;
++ case Fac_CallDeflection:
++ chan_misdn_log(1, bc->port, " --> CallDeflection: InvokeID:%d\n",
++ fac->u.CallDeflection.InvokeID);
++ switch (fac->u.CallDeflection.ComponentType) {
++ case FacComponent_Invoke:
++ chan_misdn_log(1, bc->port, " --> Invoke:\n");
++ if (fac->u.CallDeflection.Component.Invoke.PresentationAllowedToDivertedToUserPresent) {
++ chan_misdn_log(1, bc->port, " --> PresentationAllowed:%d\n",
++ fac->u.CallDeflection.Component.Invoke.PresentationAllowedToDivertedToUser);
++ }
++ chan_misdn_log(1, bc->port, " --> DeflectionAddress:\n");
++ print_facility_Address(3, &fac->u.CallDeflection.Component.Invoke.Deflection, bc);
++ break;
++ case FacComponent_Result:
++ chan_misdn_log(1, bc->port, " --> Result\n");
++ break;
++ default:
++ break;
++ }
++ break;
++ case Fac_CallRerouteing:
++ chan_misdn_log(1, bc->port, " --> CallRerouteing: InvokeID:%d\n",
++ fac->u.CallRerouteing.InvokeID);
++ switch (fac->u.CallRerouteing.ComponentType) {
++ case FacComponent_Invoke:
++ chan_misdn_log(1, bc->port, " --> Invoke: Reason:%d Counter:%d\n",
++ fac->u.CallRerouteing.Component.Invoke.ReroutingReason,
++ fac->u.CallRerouteing.Component.Invoke.ReroutingCounter);
++ chan_misdn_log(1, bc->port, " --> CalledAddress:\n");
++ print_facility_Address(3, &fac->u.CallRerouteing.Component.Invoke.CalledAddress, bc);
++ print_facility_Q931_Bc_Hlc_Llc_Uu(2, &fac->u.CallRerouteing.Component.Invoke.Q931ie, bc);
++ chan_misdn_log(1, bc->port, " --> LastReroutingNr:\n");
++ print_facility_PresentedNumberUnscreened(3, &fac->u.CallRerouteing.Component.Invoke.LastRerouting, bc);
++ chan_misdn_log(1, bc->port, " --> SubscriptionOption:%d\n",
++ fac->u.CallRerouteing.Component.Invoke.SubscriptionOption);
++ if (fac->u.CallRerouteing.Component.Invoke.CallingPartySubaddress.Length) {
++ chan_misdn_log(1, bc->port, " --> CallingParty:\n");
++ print_facility_Subaddress(3, &fac->u.CallRerouteing.Component.Invoke.CallingPartySubaddress, bc);
++ }
++ break;
++ case FacComponent_Result:
++ chan_misdn_log(1, bc->port, " --> Result\n");
++ break;
++ default:
++ break;
++ }
++ break;
++ case Fac_InterrogateServedUserNumbers:
++ chan_misdn_log(1, bc->port, " --> InterrogateServedUserNumbers: InvokeID:%d\n",
++ fac->u.InterrogateServedUserNumbers.InvokeID);
++ switch (fac->u.InterrogateServedUserNumbers.ComponentType) {
++ case FacComponent_Invoke:
++ chan_misdn_log(1, bc->port, " --> Invoke\n");
++ break;
++ case FacComponent_Result:
++ chan_misdn_log(1, bc->port, " --> Result:\n");
++ if (fac->u.InterrogateServedUserNumbers.Component.Result.NumRecords) {
++ for (Index = 0; Index < fac->u.InterrogateServedUserNumbers.Component.Result.NumRecords; ++Index) {
++ chan_misdn_log(1, bc->port, " --> ServedUserNr[%d]:\n", Index);
++ print_facility_PartyNumber(3, &fac->u.InterrogateServedUserNumbers.Component.Result.List[Index], bc);
++ }
++ }
++ break;
++ default:
++ break;
++ }
++ break;
++ case Fac_DivertingLegInformation1:
++ chan_misdn_log(1, bc->port, " --> DivertingLegInformation1: InvokeID:%d Reason:%d SubscriptionOption:%d\n",
++ fac->u.DivertingLegInformation1.InvokeID,
++ fac->u.DivertingLegInformation1.DiversionReason,
++ fac->u.DivertingLegInformation1.SubscriptionOption);
++ if (fac->u.DivertingLegInformation1.DivertedToPresent) {
++ chan_misdn_log(1, bc->port, " --> DivertedToNr:\n");
++ print_facility_PresentedNumberUnscreened(2, &fac->u.DivertingLegInformation1.DivertedTo, bc);
++ }
++ break;
++ case Fac_DivertingLegInformation2:
++ chan_misdn_log(1, bc->port, " --> DivertingLegInformation2: InvokeID:%d Reason:%d Count:%d\n",
++ fac->u.DivertingLegInformation2.InvokeID,
++ fac->u.DivertingLegInformation2.DiversionReason,
++ fac->u.DivertingLegInformation2.DiversionCounter);
++ if (fac->u.DivertingLegInformation2.DivertingPresent) {
++ chan_misdn_log(1, bc->port, " --> DivertingNr:\n");
++ print_facility_PresentedNumberUnscreened(2, &fac->u.DivertingLegInformation2.Diverting, bc);
++ }
++ if (fac->u.DivertingLegInformation2.OriginalCalledPresent) {
++ chan_misdn_log(1, bc->port, " --> OriginalCalledNr:\n");
++ print_facility_PresentedNumberUnscreened(2, &fac->u.DivertingLegInformation2.OriginalCalled, bc);
++ }
++ break;
++ case Fac_DivertingLegInformation3:
++ chan_misdn_log(1, bc->port, " --> DivertingLegInformation3: InvokeID:%d PresentationAllowed:%d\n",
++ fac->u.DivertingLegInformation3.InvokeID,
++ fac->u.DivertingLegInformation3.PresentationAllowedIndicator);
++ break;
++
++#else /* !defined(AST_MISDN_ENHANCEMENTS) */
++
+ case Fac_CD:
+ chan_misdn_log(1, bc->port, " --> calldeflect to: %s, presentable: %s\n", fac->u.CDeflection.DeflectedToNumber,
+ fac->u.CDeflection.PresentationAllowed ? "yes" : "no");
+ break;
++#endif /* !defined(AST_MISDN_ENHANCEMENTS) */
+ case Fac_AOCDCurrency:
+ if (fac->u.AOCDcur.chargeNotAvailable) {
+ chan_misdn_log(1, bc->port, " --> AOCD currency: charge not available\n");
+@@ -662,17 +2953,355 @@
+ fac->u.AOCDchu.recordedUnits, (fac->u.AOCDchu.typeOfChargingInfo == 0) ? "subTotal" : "total");
+ }
+ break;
++#if defined(AST_MISDN_ENHANCEMENTS)
++ case Fac_ERROR:
++ chan_misdn_log(1, bc->port, " --> ERROR: InvokeID:%d, Code:0x%02x\n",
++ fac->u.ERROR.invokeId, fac->u.ERROR.errorValue);
++ break;
++ case Fac_RESULT:
++ chan_misdn_log(1, bc->port, " --> RESULT: InvokeID:%d\n",
++ fac->u.RESULT.InvokeID);
++ break;
++ case Fac_REJECT:
++ if (fac->u.REJECT.InvokeIDPresent) {
++ chan_misdn_log(1, bc->port, " --> REJECT: InvokeID:%d, Code:0x%02x\n",
++ fac->u.REJECT.InvokeID, fac->u.REJECT.Code);
++ } else {
++ chan_misdn_log(1, bc->port, " --> REJECT: Code:0x%02x\n",
++ fac->u.REJECT.Code);
++ }
++ break;
++ case Fac_EctExecute:
++ chan_misdn_log(1, bc->port, " --> EctExecute: InvokeID:%d\n",
++ fac->u.EctExecute.InvokeID);
++ break;
++ case Fac_ExplicitEctExecute:
++ chan_misdn_log(1, bc->port, " --> ExplicitEctExecute: InvokeID:%d LinkID:%d\n",
++ fac->u.ExplicitEctExecute.InvokeID,
++ fac->u.ExplicitEctExecute.LinkID);
++ break;
++ case Fac_RequestSubaddress:
++ chan_misdn_log(1, bc->port, " --> RequestSubaddress: InvokeID:%d\n",
++ fac->u.RequestSubaddress.InvokeID);
++ break;
++ case Fac_SubaddressTransfer:
++ chan_misdn_log(1, bc->port, " --> SubaddressTransfer: InvokeID:%d\n",
++ fac->u.SubaddressTransfer.InvokeID);
++ print_facility_Subaddress(1, &fac->u.SubaddressTransfer.Subaddress, bc);
++ break;
++ case Fac_EctLinkIdRequest:
++ chan_misdn_log(1, bc->port, " --> EctLinkIdRequest: InvokeID:%d\n",
++ fac->u.EctLinkIdRequest.InvokeID);
++ switch (fac->u.EctLinkIdRequest.ComponentType) {
++ case FacComponent_Invoke:
++ chan_misdn_log(1, bc->port, " --> Invoke\n");
++ break;
++ case FacComponent_Result:
++ chan_misdn_log(1, bc->port, " --> Result: LinkID:%d\n",
++ fac->u.EctLinkIdRequest.Component.Result.LinkID);
++ break;
++ default:
++ break;
++ }
++ break;
++ case Fac_EctInform:
++ chan_misdn_log(1, bc->port, " --> EctInform: InvokeID:%d Status:%d\n",
++ fac->u.EctInform.InvokeID,
++ fac->u.EctInform.Status);
++ if (fac->u.EctInform.RedirectionPresent) {
++ chan_misdn_log(1, bc->port, " --> Redirection Number\n");
++ print_facility_PresentedNumberUnscreened(2, &fac->u.EctInform.Redirection, bc);
++ }
++ break;
++ case Fac_EctLoopTest:
++ chan_misdn_log(1, bc->port, " --> EctLoopTest: InvokeID:%d\n",
++ fac->u.EctLoopTest.InvokeID);
++ switch (fac->u.EctLoopTest.ComponentType) {
++ case FacComponent_Invoke:
++ chan_misdn_log(1, bc->port, " --> Invoke: CallTransferID:%d\n",
++ fac->u.EctLoopTest.Component.Invoke.CallTransferID);
++ break;
++ case FacComponent_Result:
++ chan_misdn_log(1, bc->port, " --> Result: LoopResult:%d\n",
++ fac->u.EctLoopTest.Component.Result.LoopResult);
++ break;
++ default:
++ break;
++ }
++ break;
++ case Fac_StatusRequest:
++ chan_misdn_log(1, bc->port, " --> StatusRequest: InvokeID:%d\n",
++ fac->u.StatusRequest.InvokeID);
++ switch (fac->u.StatusRequest.ComponentType) {
++ case FacComponent_Invoke:
++ chan_misdn_log(1, bc->port, " --> Invoke: Compatibility:%d\n",
++ fac->u.StatusRequest.Component.Invoke.CompatibilityMode);
++ break;
++ case FacComponent_Result:
++ chan_misdn_log(1, bc->port, " --> Result: Status:%d\n",
++ fac->u.StatusRequest.Component.Result.Status);
++ break;
++ default:
++ break;
++ }
++ break;
++ case Fac_CallInfoRetain:
++ chan_misdn_log(1, bc->port, " --> CallInfoRetain: InvokeID:%d, LinkageID:%d\n",
++ fac->u.CallInfoRetain.InvokeID, fac->u.CallInfoRetain.CallLinkageID);
++ break;
++ case Fac_CCBSDeactivate:
++ chan_misdn_log(1, bc->port, " --> CCBSDeactivate: InvokeID:%d\n",
++ fac->u.CCBSDeactivate.InvokeID);
++ switch (fac->u.CCBSDeactivate.ComponentType) {
++ case FacComponent_Invoke:
++ chan_misdn_log(1, bc->port, " --> Invoke: CCBSReference:%d\n",
++ fac->u.CCBSDeactivate.Component.Invoke.CCBSReference);
++ break;
++ case FacComponent_Result:
++ chan_misdn_log(1, bc->port, " --> Result\n");
++ break;
++ default:
++ break;
++ }
++ break;
++ case Fac_CCBSErase:
++ chan_misdn_log(1, bc->port, " --> CCBSErase: InvokeID:%d, CCBSReference:%d RecallMode:%d, Reason:%d\n",
++ fac->u.CCBSErase.InvokeID, fac->u.CCBSErase.CCBSReference,
++ fac->u.CCBSErase.RecallMode, fac->u.CCBSErase.Reason);
++ chan_misdn_log(1, bc->port, " --> AddressOfB\n");
++ print_facility_Address(2, &fac->u.CCBSErase.AddressOfB, bc);
++ print_facility_Q931_Bc_Hlc_Llc(1, &fac->u.CCBSErase.Q931ie, bc);
++ break;
++ case Fac_CCBSRemoteUserFree:
++ chan_misdn_log(1, bc->port, " --> CCBSRemoteUserFree: InvokeID:%d, CCBSReference:%d RecallMode:%d\n",
++ fac->u.CCBSRemoteUserFree.InvokeID, fac->u.CCBSRemoteUserFree.CCBSReference,
++ fac->u.CCBSRemoteUserFree.RecallMode);
++ chan_misdn_log(1, bc->port, " --> AddressOfB\n");
++ print_facility_Address(2, &fac->u.CCBSRemoteUserFree.AddressOfB, bc);
++ print_facility_Q931_Bc_Hlc_Llc(1, &fac->u.CCBSRemoteUserFree.Q931ie, bc);
++ break;
++ case Fac_CCBSCall:
++ chan_misdn_log(1, bc->port, " --> CCBSCall: InvokeID:%d, CCBSReference:%d\n",
++ fac->u.CCBSCall.InvokeID, fac->u.CCBSCall.CCBSReference);
++ break;
++ case Fac_CCBSStatusRequest:
++ chan_misdn_log(1, bc->port, " --> CCBSStatusRequest: InvokeID:%d\n",
++ fac->u.CCBSStatusRequest.InvokeID);
++ switch (fac->u.CCBSStatusRequest.ComponentType) {
++ case FacComponent_Invoke:
++ chan_misdn_log(1, bc->port, " --> Invoke: CCBSReference:%d RecallMode:%d\n",
++ fac->u.CCBSStatusRequest.Component.Invoke.CCBSReference,
++ fac->u.CCBSStatusRequest.Component.Invoke.RecallMode);
++ print_facility_Q931_Bc_Hlc_Llc(2, &fac->u.CCBSStatusRequest.Component.Invoke.Q931ie, bc);
++ break;
++ case FacComponent_Result:
++ chan_misdn_log(1, bc->port, " --> Result: Free:%d\n",
++ fac->u.CCBSStatusRequest.Component.Result.Free);
++ break;
++ default:
++ break;
++ }
++ break;
++ case Fac_CCBSBFree:
++ chan_misdn_log(1, bc->port, " --> CCBSBFree: InvokeID:%d, CCBSReference:%d RecallMode:%d\n",
++ fac->u.CCBSBFree.InvokeID, fac->u.CCBSBFree.CCBSReference,
++ fac->u.CCBSBFree.RecallMode);
++ chan_misdn_log(1, bc->port, " --> AddressOfB\n");
++ print_facility_Address(2, &fac->u.CCBSBFree.AddressOfB, bc);
++ print_facility_Q931_Bc_Hlc_Llc(1, &fac->u.CCBSBFree.Q931ie, bc);
++ break;
++ case Fac_EraseCallLinkageID:
++ chan_misdn_log(1, bc->port, " --> EraseCallLinkageID: InvokeID:%d, LinkageID:%d\n",
++ fac->u.EraseCallLinkageID.InvokeID, fac->u.EraseCallLinkageID.CallLinkageID);
++ break;
++ case Fac_CCBSStopAlerting:
++ chan_misdn_log(1, bc->port, " --> CCBSStopAlerting: InvokeID:%d, CCBSReference:%d\n",
++ fac->u.CCBSStopAlerting.InvokeID, fac->u.CCBSStopAlerting.CCBSReference);
++ break;
++ case Fac_CCBSRequest:
++ chan_misdn_log(1, bc->port, " --> CCBSRequest: InvokeID:%d\n",
++ fac->u.CCBSRequest.InvokeID);
++ switch (fac->u.CCBSRequest.ComponentType) {
++ case FacComponent_Invoke:
++ chan_misdn_log(1, bc->port, " --> Invoke: LinkageID:%d\n",
++ fac->u.CCBSRequest.Component.Invoke.CallLinkageID);
++ break;
++ case FacComponent_Result:
++ chan_misdn_log(1, bc->port, " --> Result: CCBSReference:%d RecallMode:%d\n",
++ fac->u.CCBSRequest.Component.Result.CCBSReference,
++ fac->u.CCBSRequest.Component.Result.RecallMode);
++ break;
++ default:
++ break;
++ }
++ break;
++ case Fac_CCBSInterrogate:
++ chan_misdn_log(1, bc->port, " --> CCBSInterrogate: InvokeID:%d\n",
++ fac->u.CCBSInterrogate.InvokeID);
++ switch (fac->u.CCBSInterrogate.ComponentType) {
++ case FacComponent_Invoke:
++ chan_misdn_log(1, bc->port, " --> Invoke\n");
++ if (fac->u.CCBSInterrogate.Component.Invoke.CCBSReferencePresent) {
++ chan_misdn_log(1, bc->port, " --> CCBSReference:%d\n",
++ fac->u.CCBSInterrogate.Component.Invoke.CCBSReference);
++ }
++ if (fac->u.CCBSInterrogate.Component.Invoke.AParty.LengthOfNumber) {
++ chan_misdn_log(1, bc->port, " --> AParty\n");
++ print_facility_PartyNumber(3, &fac->u.CCBSInterrogate.Component.Invoke.AParty, bc);
++ }
++ break;
++ case FacComponent_Result:
++ chan_misdn_log(1, bc->port, " --> Result: RecallMode:%d\n",
++ fac->u.CCBSInterrogate.Component.Result.RecallMode);
++ if (fac->u.CCBSInterrogate.Component.Result.NumRecords) {
++ for (Index = 0; Index < fac->u.CCBSInterrogate.Component.Result.NumRecords; ++Index) {
++ chan_misdn_log(1, bc->port, " --> CallDetails[%d]:\n", Index);
++ print_facility_CallInformation(3, &fac->u.CCBSInterrogate.Component.Result.CallDetails[Index], bc);
++ }
++ }
++ break;
++ default:
++ break;
++ }
++ break;
++ case Fac_CCNRRequest:
++ chan_misdn_log(1, bc->port, " --> CCNRRequest: InvokeID:%d\n",
++ fac->u.CCNRRequest.InvokeID);
++ switch (fac->u.CCNRRequest.ComponentType) {
++ case FacComponent_Invoke:
++ chan_misdn_log(1, bc->port, " --> Invoke: LinkageID:%d\n",
++ fac->u.CCNRRequest.Component.Invoke.CallLinkageID);
++ break;
++ case FacComponent_Result:
++ chan_misdn_log(1, bc->port, " --> Result: CCBSReference:%d RecallMode:%d\n",
++ fac->u.CCNRRequest.Component.Result.CCBSReference,
++ fac->u.CCNRRequest.Component.Result.RecallMode);
++ break;
++ default:
++ break;
++ }
++ break;
++ case Fac_CCNRInterrogate:
++ chan_misdn_log(1, bc->port, " --> CCNRInterrogate: InvokeID:%d\n",
++ fac->u.CCNRInterrogate.InvokeID);
++ switch (fac->u.CCNRInterrogate.ComponentType) {
++ case FacComponent_Invoke:
++ chan_misdn_log(1, bc->port, " --> Invoke\n");
++ if (fac->u.CCNRInterrogate.Component.Invoke.CCBSReferencePresent) {
++ chan_misdn_log(1, bc->port, " --> CCBSReference:%d\n",
++ fac->u.CCNRInterrogate.Component.Invoke.CCBSReference);
++ }
++ if (fac->u.CCNRInterrogate.Component.Invoke.AParty.LengthOfNumber) {
++ chan_misdn_log(1, bc->port, " --> AParty\n");
++ print_facility_PartyNumber(3, &fac->u.CCNRInterrogate.Component.Invoke.AParty, bc);
++ }
++ break;
++ case FacComponent_Result:
++ chan_misdn_log(1, bc->port, " --> Result: RecallMode:%d\n",
++ fac->u.CCNRInterrogate.Component.Result.RecallMode);
++ if (fac->u.CCNRInterrogate.Component.Result.NumRecords) {
++ for (Index = 0; Index < fac->u.CCNRInterrogate.Component.Result.NumRecords; ++Index) {
++ chan_misdn_log(1, bc->port, " --> CallDetails[%d]:\n", Index);
++ print_facility_CallInformation(3, &fac->u.CCNRInterrogate.Component.Result.CallDetails[Index], bc);
++ }
++ }
++ break;
++ default:
++ break;
++ }
++ break;
++ case Fac_CCBS_T_Call:
++ chan_misdn_log(1, bc->port, " --> CCBS_T_Call: InvokeID:%d\n",
++ fac->u.CCBS_T_Call.InvokeID);
++ break;
++ case Fac_CCBS_T_Suspend:
++ chan_misdn_log(1, bc->port, " --> CCBS_T_Suspend: InvokeID:%d\n",
++ fac->u.CCBS_T_Suspend.InvokeID);
++ break;
++ case Fac_CCBS_T_Resume:
++ chan_misdn_log(1, bc->port, " --> CCBS_T_Resume: InvokeID:%d\n",
++ fac->u.CCBS_T_Resume.InvokeID);
++ break;
++ case Fac_CCBS_T_RemoteUserFree:
++ chan_misdn_log(1, bc->port, " --> CCBS_T_RemoteUserFree: InvokeID:%d\n",
++ fac->u.CCBS_T_RemoteUserFree.InvokeID);
++ break;
++ case Fac_CCBS_T_Available:
++ chan_misdn_log(1, bc->port, " --> CCBS_T_Available: InvokeID:%d\n",
++ fac->u.CCBS_T_Available.InvokeID);
++ break;
++ case Fac_CCBS_T_Request:
++ chan_misdn_log(1, bc->port, " --> CCBS_T_Request: InvokeID:%d\n",
++ fac->u.CCBS_T_Request.InvokeID);
++ switch (fac->u.CCBS_T_Request.ComponentType) {
++ case FacComponent_Invoke:
++ chan_misdn_log(1, bc->port, " --> Invoke\n");
++ chan_misdn_log(1, bc->port, " --> DestinationAddress:\n");
++ print_facility_Address(3, &fac->u.CCBS_T_Request.Component.Invoke.Destination, bc);
++ print_facility_Q931_Bc_Hlc_Llc(2, &fac->u.CCBS_T_Request.Component.Invoke.Q931ie, bc);
++ if (fac->u.CCBS_T_Request.Component.Invoke.RetentionSupported) {
++ chan_misdn_log(1, bc->port, " --> RetentionSupported:1\n");
++ }
++ if (fac->u.CCBS_T_Request.Component.Invoke.PresentationAllowedIndicatorPresent) {
++ chan_misdn_log(1, bc->port, " --> PresentationAllowed:%d\n",
++ fac->u.CCBS_T_Request.Component.Invoke.PresentationAllowedIndicator);
++ }
++ if (fac->u.CCBS_T_Request.Component.Invoke.Originating.Party.LengthOfNumber) {
++ chan_misdn_log(1, bc->port, " --> OriginatingAddress:\n");
++ print_facility_Address(3, &fac->u.CCBS_T_Request.Component.Invoke.Originating, bc);
++ }
++ break;
++ case FacComponent_Result:
++ chan_misdn_log(1, bc->port, " --> Result: RetentionSupported:%d\n",
++ fac->u.CCBS_T_Request.Component.Result.RetentionSupported);
++ break;
++ default:
++ break;
++ }
++ break;
++ case Fac_CCNR_T_Request:
++ chan_misdn_log(1, bc->port, " --> CCNR_T_Request: InvokeID:%d\n",
++ fac->u.CCNR_T_Request.InvokeID);
++ switch (fac->u.CCNR_T_Request.ComponentType) {
++ case FacComponent_Invoke:
++ chan_misdn_log(1, bc->port, " --> Invoke\n");
++ chan_misdn_log(1, bc->port, " --> DestinationAddress:\n");
++ print_facility_Address(3, &fac->u.CCNR_T_Request.Component.Invoke.Destination, bc);
++ print_facility_Q931_Bc_Hlc_Llc(2, &fac->u.CCNR_T_Request.Component.Invoke.Q931ie, bc);
++ if (fac->u.CCNR_T_Request.Component.Invoke.RetentionSupported) {
++ chan_misdn_log(1, bc->port, " --> RetentionSupported:1\n");
++ }
++ if (fac->u.CCNR_T_Request.Component.Invoke.PresentationAllowedIndicatorPresent) {
++ chan_misdn_log(1, bc->port, " --> PresentationAllowed:%d\n",
++ fac->u.CCNR_T_Request.Component.Invoke.PresentationAllowedIndicator);
++ }
++ if (fac->u.CCNR_T_Request.Component.Invoke.Originating.Party.LengthOfNumber) {
++ chan_misdn_log(1, bc->port, " --> OriginatingAddress:\n");
++ print_facility_Address(3, &fac->u.CCNR_T_Request.Component.Invoke.Originating, bc);
++ }
++ break;
++ case FacComponent_Result:
++ chan_misdn_log(1, bc->port, " --> Result: RetentionSupported:%d\n",
++ fac->u.CCNR_T_Request.Component.Result.RetentionSupported);
++ break;
++ default:
++ break;
++ }
++ break;
++#endif /* defined(AST_MISDN_ENHANCEMENTS) */
+ case Fac_None:
++ /* No facility so print nothing */
++ break;
+ default:
+ chan_misdn_log(1, bc->port, " --> unknown facility\n");
+ break;
+ }
+ }
+
+-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 +3312,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 +3410,8 @@
+ }
+
+ if (originator == ORG_AST) {
+- if (!(ast = ast_bridged_channel(ast))) {
++ ast = ast_bridged_channel(ast);
++ if (!ast) {
+ return;
+ }
+ }
+@@ -739,14 +3458,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 +3478,7 @@
+ sigemptyset(&sa.sa_mask);
+ sigaddset(&sa.sa_mask, SIGUSR1);
+ sigaction(SIGUSR1, &sa, NULL);
+-
++
+ sem_post((sem_t *)data);
+
+ while (1) {
+@@ -785,11 +3505,12 @@
+ }
+
+ 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);
+
+- while (sem_wait(&blocker) && --i);
++ while (sem_wait(&blocker) && --i) {
++ }
+ sem_destroy(&blocker);
+ }
+
+@@ -797,7 +3518,7 @@
+ {
+ if (misdn_tasks) {
+ chan_misdn_log(4, 0, "Killing misdn_tasks thread\n");
+- if ( pthread_cancel(misdn_tasks_thread) == 0 ) {
++ if (pthread_cancel(misdn_tasks_thread) == 0) {
+ cb_log(4, 0, "Joining misdn_tasks thread\n");
+ pthread_join(misdn_tasks_thread, NULL);
+ }
+@@ -841,6 +3562,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 +3589,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");
+@@ -900,7 +3623,8 @@
+
+ static void send_digit_to_chan(struct chan_list *cl, char digit)
+ {
+- static const char *dtmf_tones[] = {
++ static const char * const dtmf_tones[] = {
++/* *INDENT-OFF* */
+ "!941+1336/100,!0/100", /* 0 */
+ "!697+1209/100,!0/100", /* 1 */
+ "!697+1336/100,!0/100", /* 2 */
+@@ -917,9 +3641,10 @@
+ "!941+1633/100,!0/100", /* D */
+ "!941+1209/100,!0/100", /* * */
+ "!941+1477/100,!0/100", /* # */
++/* *INDENT-ON* */
+ };
+- 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 +3683,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 +3702,7 @@
+ only = 1;
+ }
+ }
+-
++
+ for (i = 0; i <= max_ports; i++) {
+ misdn_debug[i] = level;
+ misdn_debug_only[i] = only;
+@@ -1251,7 +3978,9 @@
+ ast_cli(a->fd, "Unknown option: %s\n", a->argv[3]);
+ return CLI_SHOWUSAGE;
+ }
+- } else if (a->argc == 3 || onlyport == 0) {
++ }
++
++ if (a->argc == 3 || onlyport == 0) {
+ ast_cli(a->fd, "mISDN General-Config:\n");
+ for (elem = MISDN_GEN_FIRST + 1, linebreak = 1; elem < MISDN_GEN_LAST; elem++, linebreak++) {
+ misdn_cfg_get_config_string(0, elem, buffer, sizeof(buffer));
+@@ -1262,23 +3991,24 @@
+
+ if (onlyport < 0) {
+ int port = misdn_cfg_get_next_port(0);
++
+ for (; port > 0; port = misdn_cfg_get_next_port(port)) {
+ ast_cli(a->fd, "\n[PORT %d]\n", port);
+ 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);
+@@ -1293,39 +4023,41 @@
+ char txt[255];
+ };
+
+-static struct state_struct state_array[] = {
++static const 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 +4078,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();
+@@ -1382,21 +4114,30 @@
+ return CLI_SUCCESS;
+ }
+
+-static void print_bc_info (int fd, struct chan_list *help, struct misdn_bchannel *bc)
++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-from:\"%s\" <%s>\n"
++ " --> redirecting-to:\"%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,
++ bc->redirecting.to.name,
++ bc->redirecting.to.number,
++ ast ? ast->context : "",
++ misdn_get_ch_state(help));
+ if (misdn_debug[bc->port] > 0) {
+ ast_cli(fd,
+ " --> astname: %s\n"
+@@ -1419,21 +4160,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 +4195,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 +4219,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 +4263,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;
+ }
+ }
+ }
+@@ -1580,8 +4320,9 @@
+
+ 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)) {
++ 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)" : "");
+ }
+@@ -1610,7 +4351,7 @@
+
+ ast_cli(a->fd, "Port\tin_calls\tout_calls\n");
+ for (port = misdn_cfg_get_next_port(0); port > 0;
+- port = misdn_cfg_get_next_port(port)) {
++ port = misdn_cfg_get_next_port(port)) {
+ ast_cli(a->fd, "%d\t%d\t\t%d\n", port, misdn_in_calls[port], misdn_out_calls[port]);
+ }
+ ast_cli(a->fd, "\n");
+@@ -1639,7 +4380,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)" : "");
+@@ -1647,15 +4388,749 @@
+ return CLI_SUCCESS;
+ }
+
++#if defined(AST_MISDN_ENHANCEMENTS) && defined(CCBS_TEST_MESSAGES)
++static const struct FacParm Fac_Msgs[] = {
++/* *INDENT-OFF* */
++ [0].Function = Fac_ERROR,
++ [0].u.ERROR.invokeId = 8,
++ [0].u.ERROR.errorValue = FacError_CCBS_AlreadyAccepted,
++
++ [1].Function = Fac_RESULT,
++ [1].u.RESULT.InvokeID = 9,
++
++ [2].Function = Fac_REJECT,
++ [2].u.REJECT.Code = FacReject_Gen_BadlyStructuredComponent,
++
++ [3].Function = Fac_REJECT,
++ [3].u.REJECT.InvokeIDPresent = 1,
++ [3].u.REJECT.InvokeID = 10,
++ [3].u.REJECT.Code = FacReject_Inv_InitiatorReleasing,
++
++ [4].Function = Fac_REJECT,
++ [4].u.REJECT.InvokeIDPresent = 1,
++ [4].u.REJECT.InvokeID = 11,
++ [4].u.REJECT.Code = FacReject_Res_MistypedResult,
++
++ [5].Function = Fac_REJECT,
++ [5].u.REJECT.InvokeIDPresent = 1,
++ [5].u.REJECT.InvokeID = 12,
++ [5].u.REJECT.Code = FacReject_Err_ErrorResponseUnexpected,
++
++ [6].Function = Fac_StatusRequest,
++ [6].u.StatusRequest.InvokeID = 13,
++ [6].u.StatusRequest.ComponentType = FacComponent_Invoke,
++ [6].u.StatusRequest.Component.Invoke.Q931ie.Bc.Length = 2,
++ [6].u.StatusRequest.Component.Invoke.Q931ie.Bc.Contents = "AB",
++ [6].u.StatusRequest.Component.Invoke.Q931ie.Llc.Length = 3,
++ [6].u.StatusRequest.Component.Invoke.Q931ie.Llc.Contents = "CDE",
++ [6].u.StatusRequest.Component.Invoke.Q931ie.Hlc.Length = 4,
++ [6].u.StatusRequest.Component.Invoke.Q931ie.Hlc.Contents = "FGHI",
++ [6].u.StatusRequest.Component.Invoke.CompatibilityMode = 1,
++
++ [7].Function = Fac_StatusRequest,
++ [7].u.StatusRequest.InvokeID = 14,
++ [7].u.StatusRequest.ComponentType = FacComponent_Result,
++ [7].u.StatusRequest.Component.Result.Status = 2,
++
++ [8].Function = Fac_CallInfoRetain,
++ [8].u.CallInfoRetain.InvokeID = 15,
++ [8].u.CallInfoRetain.CallLinkageID = 115,
++
++ [9].Function = Fac_EraseCallLinkageID,
++ [9].u.EraseCallLinkageID.InvokeID = 16,
++ [9].u.EraseCallLinkageID.CallLinkageID = 105,
++
++ [10].Function = Fac_CCBSDeactivate,
++ [10].u.CCBSDeactivate.InvokeID = 17,
++ [10].u.CCBSDeactivate.ComponentType = FacComponent_Invoke,
++ [10].u.CCBSDeactivate.Component.Invoke.CCBSReference = 2,
++
++ [11].Function = Fac_CCBSDeactivate,
++ [11].u.CCBSDeactivate.InvokeID = 18,
++ [11].u.CCBSDeactivate.ComponentType = FacComponent_Result,
++
++ [12].Function = Fac_CCBSErase,
++ [12].u.CCBSErase.InvokeID = 19,
++ [12].u.CCBSErase.Q931ie.Bc.Length = 2,
++ [12].u.CCBSErase.Q931ie.Bc.Contents = "JK",
++ [12].u.CCBSErase.AddressOfB.Party.Type = 0,
++ [12].u.CCBSErase.AddressOfB.Party.LengthOfNumber = 5,
++ [12].u.CCBSErase.AddressOfB.Party.Number = "33403",
++ [12].u.CCBSErase.AddressOfB.Subaddress.Type = 0,
++ [12].u.CCBSErase.AddressOfB.Subaddress.Length = 4,
++ [12].u.CCBSErase.AddressOfB.Subaddress.u.UserSpecified.Information = "3748",
++ [12].u.CCBSErase.RecallMode = 1,
++ [12].u.CCBSErase.CCBSReference = 102,
++ [12].u.CCBSErase.Reason = 3,
++
++ [13].Function = Fac_CCBSErase,
++ [13].u.CCBSErase.InvokeID = 20,
++ [13].u.CCBSErase.Q931ie.Bc.Length = 2,
++ [13].u.CCBSErase.Q931ie.Bc.Contents = "JK",
++ [13].u.CCBSErase.AddressOfB.Party.Type = 1,
++ [13].u.CCBSErase.AddressOfB.Party.LengthOfNumber = 11,
++ [13].u.CCBSErase.AddressOfB.Party.TypeOfNumber = 1,
++ [13].u.CCBSErase.AddressOfB.Party.Number = "18003020102",
++ [13].u.CCBSErase.AddressOfB.Subaddress.Type = 0,
++ [13].u.CCBSErase.AddressOfB.Subaddress.Length = 4,
++ [13].u.CCBSErase.AddressOfB.Subaddress.u.UserSpecified.OddCountPresent = 1,
++ [13].u.CCBSErase.AddressOfB.Subaddress.u.UserSpecified.OddCount = 1,
++ [13].u.CCBSErase.AddressOfB.Subaddress.u.UserSpecified.Information = "3748",
++ [13].u.CCBSErase.RecallMode = 1,
++ [13].u.CCBSErase.CCBSReference = 102,
++ [13].u.CCBSErase.Reason = 3,
++
++ [14].Function = Fac_CCBSErase,
++ [14].u.CCBSErase.InvokeID = 21,
++ [14].u.CCBSErase.Q931ie.Bc.Length = 2,
++ [14].u.CCBSErase.Q931ie.Bc.Contents = "JK",
++ [14].u.CCBSErase.AddressOfB.Party.Type = 2,
++ [14].u.CCBSErase.AddressOfB.Party.LengthOfNumber = 4,
++ [14].u.CCBSErase.AddressOfB.Party.Number = "1803",
++ [14].u.CCBSErase.AddressOfB.Subaddress.Type = 1,
++ [14].u.CCBSErase.AddressOfB.Subaddress.Length = 4,
++ [14].u.CCBSErase.AddressOfB.Subaddress.u.Nsap = "6492",
++ [14].u.CCBSErase.RecallMode = 1,
++ [14].u.CCBSErase.CCBSReference = 102,
++ [14].u.CCBSErase.Reason = 3,
++
++ [15].Function = Fac_CCBSErase,
++ [15].u.CCBSErase.InvokeID = 22,
++ [15].u.CCBSErase.Q931ie.Bc.Length = 2,
++ [15].u.CCBSErase.Q931ie.Bc.Contents = "JK",
++ [15].u.CCBSErase.AddressOfB.Party.Type = 3,
++ [15].u.CCBSErase.AddressOfB.Party.LengthOfNumber = 4,
++ [15].u.CCBSErase.AddressOfB.Party.Number = "1803",
++ [15].u.CCBSErase.RecallMode = 1,
++ [15].u.CCBSErase.CCBSReference = 102,
++ [15].u.CCBSErase.Reason = 3,
++
++ [16].Function = Fac_CCBSErase,
++ [16].u.CCBSErase.InvokeID = 23,
++ [16].u.CCBSErase.Q931ie.Bc.Length = 2,
++ [16].u.CCBSErase.Q931ie.Bc.Contents = "JK",
++ [16].u.CCBSErase.AddressOfB.Party.Type = 4,
++ [16].u.CCBSErase.AddressOfB.Party.LengthOfNumber = 4,
++ [16].u.CCBSErase.AddressOfB.Party.Number = "1803",
++ [16].u.CCBSErase.RecallMode = 1,
++ [16].u.CCBSErase.CCBSReference = 102,
++ [16].u.CCBSErase.Reason = 3,
++
++ [17].Function = Fac_CCBSErase,
++ [17].u.CCBSErase.InvokeID = 24,
++ [17].u.CCBSErase.Q931ie.Bc.Length = 2,
++ [17].u.CCBSErase.Q931ie.Bc.Contents = "JK",
++ [17].u.CCBSErase.AddressOfB.Party.Type = 5,
++ [17].u.CCBSErase.AddressOfB.Party.LengthOfNumber = 11,
++ [17].u.CCBSErase.AddressOfB.Party.TypeOfNumber = 4,
++ [17].u.CCBSErase.AddressOfB.Party.Number = "18003020102",
++ [17].u.CCBSErase.RecallMode = 1,
++ [17].u.CCBSErase.CCBSReference = 102,
++ [17].u.CCBSErase.Reason = 3,
++
++ [18].Function = Fac_CCBSErase,
++ [18].u.CCBSErase.InvokeID = 25,
++ [18].u.CCBSErase.Q931ie.Bc.Length = 2,
++ [18].u.CCBSErase.Q931ie.Bc.Contents = "JK",
++ [18].u.CCBSErase.AddressOfB.Party.Type = 8,
++ [18].u.CCBSErase.AddressOfB.Party.LengthOfNumber = 4,
++ [18].u.CCBSErase.AddressOfB.Party.Number = "1803",
++ [18].u.CCBSErase.RecallMode = 1,
++ [18].u.CCBSErase.CCBSReference = 102,
++ [18].u.CCBSErase.Reason = 3,
++
++ [19].Function = Fac_CCBSRemoteUserFree,
++ [19].u.CCBSRemoteUserFree.InvokeID = 26,
++ [19].u.CCBSRemoteUserFree.Q931ie.Bc.Length = 2,
++ [19].u.CCBSRemoteUserFree.Q931ie.Bc.Contents = "JK",
++ [19].u.CCBSRemoteUserFree.AddressOfB.Party.Type = 8,
++ [19].u.CCBSRemoteUserFree.AddressOfB.Party.LengthOfNumber = 4,
++ [19].u.CCBSRemoteUserFree.AddressOfB.Party.Number = "1803",
++ [19].u.CCBSRemoteUserFree.RecallMode = 1,
++ [19].u.CCBSRemoteUserFree.CCBSReference = 102,
++
++ [20].Function = Fac_CCBSCall,
++ [20].u.CCBSCall.InvokeID = 27,
++ [20].u.CCBSCall.CCBSReference = 115,
++
++ [21].Function = Fac_CCBSStatusRequest,
++ [21].u.CCBSStatusRequest.InvokeID = 28,
++ [21].u.CCBSStatusRequest.ComponentType = FacComponent_Invoke,
++ [21].u.CCBSStatusRequest.Component.Invoke.Q931ie.Bc.Length = 2,
++ [21].u.CCBSStatusRequest.Component.Invoke.Q931ie.Bc.Contents = "JK",
++ [21].u.CCBSStatusRequest.Component.Invoke.RecallMode = 1,
++ [21].u.CCBSStatusRequest.Component.Invoke.CCBSReference = 102,
++
++ [22].Function = Fac_CCBSStatusRequest,
++ [22].u.CCBSStatusRequest.InvokeID = 29,
++ [22].u.CCBSStatusRequest.ComponentType = FacComponent_Result,
++ [22].u.CCBSStatusRequest.Component.Result.Free = 1,
++
++ [23].Function = Fac_CCBSBFree,
++ [23].u.CCBSBFree.InvokeID = 30,
++ [23].u.CCBSBFree.Q931ie.Bc.Length = 2,
++ [23].u.CCBSBFree.Q931ie.Bc.Contents = "JK",
++ [23].u.CCBSBFree.AddressOfB.Party.Type = 8,
++ [23].u.CCBSBFree.AddressOfB.Party.LengthOfNumber = 4,
++ [23].u.CCBSBFree.AddressOfB.Party.Number = "1803",
++ [23].u.CCBSBFree.RecallMode = 1,
++ [23].u.CCBSBFree.CCBSReference = 14,
++
++ [24].Function = Fac_CCBSStopAlerting,
++ [24].u.CCBSStopAlerting.InvokeID = 31,
++ [24].u.CCBSStopAlerting.CCBSReference = 37,
++
++ [25].Function = Fac_CCBSRequest,
++ [25].u.CCBSRequest.InvokeID = 32,
++ [25].u.CCBSRequest.ComponentType = FacComponent_Invoke,
++ [25].u.CCBSRequest.Component.Invoke.CallLinkageID = 57,
++
++ [26].Function = Fac_CCBSRequest,
++ [26].u.CCBSRequest.InvokeID = 33,
++ [26].u.CCBSRequest.ComponentType = FacComponent_Result,
++ [26].u.CCBSRequest.Component.Result.RecallMode = 1,
++ [26].u.CCBSRequest.Component.Result.CCBSReference = 102,
++
++ [27].Function = Fac_CCBSInterrogate,
++ [27].u.CCBSInterrogate.InvokeID = 34,
++ [27].u.CCBSInterrogate.ComponentType = FacComponent_Invoke,
++ [27].u.CCBSInterrogate.Component.Invoke.AParty.Type = 8,
++ [27].u.CCBSInterrogate.Component.Invoke.AParty.LengthOfNumber = 4,
++ [27].u.CCBSInterrogate.Component.Invoke.AParty.Number = "1803",
++ [27].u.CCBSInterrogate.Component.Invoke.CCBSReferencePresent = 1,
++ [27].u.CCBSInterrogate.Component.Invoke.CCBSReference = 76,
++
++ [28].Function = Fac_CCBSInterrogate,
++ [28].u.CCBSInterrogate.InvokeID = 35,
++ [28].u.CCBSInterrogate.ComponentType = FacComponent_Invoke,
++ [28].u.CCBSInterrogate.Component.Invoke.AParty.Type = 8,
++ [28].u.CCBSInterrogate.Component.Invoke.AParty.LengthOfNumber = 4,
++ [28].u.CCBSInterrogate.Component.Invoke.AParty.Number = "1803",
++
++ [29].Function = Fac_CCBSInterrogate,
++ [29].u.CCBSInterrogate.InvokeID = 36,
++ [29].u.CCBSInterrogate.ComponentType = FacComponent_Invoke,
++ [29].u.CCBSInterrogate.Component.Invoke.CCBSReferencePresent = 1,
++ [29].u.CCBSInterrogate.Component.Invoke.CCBSReference = 76,
++
++ [30].Function = Fac_CCBSInterrogate,
++ [30].u.CCBSInterrogate.InvokeID = 37,
++ [30].u.CCBSInterrogate.ComponentType = FacComponent_Invoke,
++
++ [31].Function = Fac_CCBSInterrogate,
++ [31].u.CCBSInterrogate.InvokeID = 38,
++ [31].u.CCBSInterrogate.ComponentType = FacComponent_Result,
++ [31].u.CCBSInterrogate.Component.Result.RecallMode = 1,
++
++ [32].Function = Fac_CCBSInterrogate,
++ [32].u.CCBSInterrogate.InvokeID = 39,
++ [32].u.CCBSInterrogate.ComponentType = FacComponent_Result,
++ [32].u.CCBSInterrogate.Component.Result.RecallMode = 1,
++ [32].u.CCBSInterrogate.Component.Result.NumRecords = 1,
++ [32].u.CCBSInterrogate.Component.Result.CallDetails[0].CCBSReference = 12,
++ [32].u.CCBSInterrogate.Component.Result.CallDetails[0].Q931ie.Bc.Length = 2,
++ [32].u.CCBSInterrogate.Component.Result.CallDetails[0].Q931ie.Bc.Contents = "JK",
++ [32].u.CCBSInterrogate.Component.Result.CallDetails[0].AddressOfB.Party.Type = 8,
++ [32].u.CCBSInterrogate.Component.Result.CallDetails[0].AddressOfB.Party.LengthOfNumber = 4,
++ [32].u.CCBSInterrogate.Component.Result.CallDetails[0].AddressOfB.Party.Number = "1803",
++ [32].u.CCBSInterrogate.Component.Result.CallDetails[0].SubaddressOfA.Type = 1,
++ [32].u.CCBSInterrogate.Component.Result.CallDetails[0].SubaddressOfA.Length = 4,
++ [32].u.CCBSInterrogate.Component.Result.CallDetails[0].SubaddressOfA.u.Nsap = "6492",
++
++ [33].Function = Fac_CCBSInterrogate,
++ [33].u.CCBSInterrogate.InvokeID = 40,
++ [33].u.CCBSInterrogate.ComponentType = FacComponent_Result,
++ [33].u.CCBSInterrogate.Component.Result.RecallMode = 1,
++ [33].u.CCBSInterrogate.Component.Result.NumRecords = 2,
++ [33].u.CCBSInterrogate.Component.Result.CallDetails[0].CCBSReference = 12,
++ [33].u.CCBSInterrogate.Component.Result.CallDetails[0].Q931ie.Bc.Length = 2,
++ [33].u.CCBSInterrogate.Component.Result.CallDetails[0].Q931ie.Bc.Contents = "JK",
++ [33].u.CCBSInterrogate.Component.Result.CallDetails[0].AddressOfB.Party.Type = 8,
++ [33].u.CCBSInterrogate.Component.Result.CallDetails[0].AddressOfB.Party.LengthOfNumber = 4,
++ [33].u.CCBSInterrogate.Component.Result.CallDetails[0].AddressOfB.Party.Number = "1803",
++ [33].u.CCBSInterrogate.Component.Result.CallDetails[1].CCBSReference = 102,
++ [33].u.CCBSInterrogate.Component.Result.CallDetails[1].Q931ie.Bc.Length = 2,
++ [33].u.CCBSInterrogate.Component.Result.CallDetails[1].Q931ie.Bc.Contents = "LM",
++ [33].u.CCBSInterrogate.Component.Result.CallDetails[1].AddressOfB.Party.Type = 8,
++ [33].u.CCBSInterrogate.Component.Result.CallDetails[1].AddressOfB.Party.LengthOfNumber = 4,
++ [33].u.CCBSInterrogate.Component.Result.CallDetails[1].AddressOfB.Party.Number = "6229",
++ [33].u.CCBSInterrogate.Component.Result.CallDetails[1].AddressOfB.Subaddress.Type = 1,
++ [33].u.CCBSInterrogate.Component.Result.CallDetails[1].AddressOfB.Subaddress.Length = 4,
++ [33].u.CCBSInterrogate.Component.Result.CallDetails[1].AddressOfB.Subaddress.u.Nsap = "8592",
++ [33].u.CCBSInterrogate.Component.Result.CallDetails[1].SubaddressOfA.Type = 1,
++ [33].u.CCBSInterrogate.Component.Result.CallDetails[1].SubaddressOfA.Length = 4,
++ [33].u.CCBSInterrogate.Component.Result.CallDetails[1].SubaddressOfA.u.Nsap = "6492",
++
++ [34].Function = Fac_CCNRRequest,
++ [34].u.CCNRRequest.InvokeID = 512,
++ [34].u.CCNRRequest.ComponentType = FacComponent_Invoke,
++ [34].u.CCNRRequest.Component.Invoke.CallLinkageID = 57,
++
++ [35].Function = Fac_CCNRRequest,
++ [35].u.CCNRRequest.InvokeID = 150,
++ [35].u.CCNRRequest.ComponentType = FacComponent_Result,
++ [35].u.CCNRRequest.Component.Result.RecallMode = 1,
++ [35].u.CCNRRequest.Component.Result.CCBSReference = 102,
++
++ [36].Function = Fac_CCNRInterrogate,
++ [36].u.CCNRInterrogate.InvokeID = -129,
++ [36].u.CCNRInterrogate.ComponentType = FacComponent_Invoke,
++
++ [37].Function = Fac_CCNRInterrogate,
++ [37].u.CCNRInterrogate.InvokeID = -3,
++ [37].u.CCNRInterrogate.ComponentType = FacComponent_Result,
++ [37].u.CCNRInterrogate.Component.Result.RecallMode = 1,
++
++ [38].Function = Fac_CCBS_T_Call,
++ [38].u.EctExecute.InvokeID = 41,
++
++ [39].Function = Fac_CCBS_T_Suspend,
++ [39].u.EctExecute.InvokeID = 42,
++
++ [40].Function = Fac_CCBS_T_Resume,
++ [40].u.EctExecute.InvokeID = 43,
++
++ [41].Function = Fac_CCBS_T_RemoteUserFree,
++ [41].u.EctExecute.InvokeID = 44,
++
++ [42].Function = Fac_CCBS_T_Available,
++ [42].u.EctExecute.InvokeID = 45,
++
++ [43].Function = Fac_CCBS_T_Request,
++ [43].u.CCBS_T_Request.InvokeID = 46,
++ [43].u.CCBS_T_Request.ComponentType = FacComponent_Invoke,
++ [43].u.CCBS_T_Request.Component.Invoke.Destination.Party.Type = 8,
++ [43].u.CCBS_T_Request.Component.Invoke.Destination.Party.LengthOfNumber = 4,
++ [43].u.CCBS_T_Request.Component.Invoke.Destination.Party.Number = "6229",
++ [43].u.CCBS_T_Request.Component.Invoke.Q931ie.Bc.Length = 2,
++ [43].u.CCBS_T_Request.Component.Invoke.Q931ie.Bc.Contents = "LM",
++ [43].u.CCBS_T_Request.Component.Invoke.RetentionSupported = 1,
++ [43].u.CCBS_T_Request.Component.Invoke.PresentationAllowedIndicatorPresent = 1,
++ [43].u.CCBS_T_Request.Component.Invoke.PresentationAllowedIndicator = 1,
++ [43].u.CCBS_T_Request.Component.Invoke.Originating.Party.Type = 8,
++ [43].u.CCBS_T_Request.Component.Invoke.Originating.Party.LengthOfNumber = 4,
++ [43].u.CCBS_T_Request.Component.Invoke.Originating.Party.Number = "9864",
++
++ [44].Function = Fac_CCBS_T_Request,
++ [44].u.CCBS_T_Request.InvokeID = 47,
++ [44].u.CCBS_T_Request.ComponentType = FacComponent_Invoke,
++ [44].u.CCBS_T_Request.Component.Invoke.Destination.Party.Type = 8,
++ [44].u.CCBS_T_Request.Component.Invoke.Destination.Party.LengthOfNumber = 4,
++ [44].u.CCBS_T_Request.Component.Invoke.Destination.Party.Number = "6229",
++ [44].u.CCBS_T_Request.Component.Invoke.Q931ie.Bc.Length = 2,
++ [44].u.CCBS_T_Request.Component.Invoke.Q931ie.Bc.Contents = "LM",
++ [44].u.CCBS_T_Request.Component.Invoke.PresentationAllowedIndicatorPresent = 1,
++ [44].u.CCBS_T_Request.Component.Invoke.PresentationAllowedIndicator = 1,
++ [44].u.CCBS_T_Request.Component.Invoke.Originating.Party.Type = 8,
++ [44].u.CCBS_T_Request.Component.Invoke.Originating.Party.LengthOfNumber = 4,
++ [44].u.CCBS_T_Request.Component.Invoke.Originating.Party.Number = "9864",
++
++ [45].Function = Fac_CCBS_T_Request,
++ [45].u.CCBS_T_Request.InvokeID = 48,
++ [45].u.CCBS_T_Request.ComponentType = FacComponent_Invoke,
++ [45].u.CCBS_T_Request.Component.Invoke.Destination.Party.Type = 8,
++ [45].u.CCBS_T_Request.Component.Invoke.Destination.Party.LengthOfNumber = 4,
++ [45].u.CCBS_T_Request.Component.Invoke.Destination.Party.Number = "6229",
++ [45].u.CCBS_T_Request.Component.Invoke.Q931ie.Bc.Length = 2,
++ [45].u.CCBS_T_Request.Component.Invoke.Q931ie.Bc.Contents = "LM",
++ [45].u.CCBS_T_Request.Component.Invoke.Originating.Party.Type = 8,
++ [45].u.CCBS_T_Request.Component.Invoke.Originating.Party.LengthOfNumber = 4,
++ [45].u.CCBS_T_Request.Component.Invoke.Originating.Party.Number = "9864",
++
++ [46].Function = Fac_CCBS_T_Request,
++ [46].u.CCBS_T_Request.InvokeID = 49,
++ [46].u.CCBS_T_Request.ComponentType = FacComponent_Invoke,
++ [46].u.CCBS_T_Request.Component.Invoke.Destination.Party.Type = 8,
++ [46].u.CCBS_T_Request.Component.Invoke.Destination.Party.LengthOfNumber = 4,
++ [46].u.CCBS_T_Request.Component.Invoke.Destination.Party.Number = "6229",
++ [46].u.CCBS_T_Request.Component.Invoke.Q931ie.Bc.Length = 2,
++ [46].u.CCBS_T_Request.Component.Invoke.Q931ie.Bc.Contents = "LM",
++ [46].u.CCBS_T_Request.Component.Invoke.PresentationAllowedIndicatorPresent = 1,
++ [46].u.CCBS_T_Request.Component.Invoke.PresentationAllowedIndicator = 1,
++
++ [47].Function = Fac_CCBS_T_Request,
++ [47].u.CCBS_T_Request.InvokeID = 50,
++ [47].u.CCBS_T_Request.ComponentType = FacComponent_Invoke,
++ [47].u.CCBS_T_Request.Component.Invoke.Destination.Party.Type = 8,
++ [47].u.CCBS_T_Request.Component.Invoke.Destination.Party.LengthOfNumber = 4,
++ [47].u.CCBS_T_Request.Component.Invoke.Destination.Party.Number = "6229",
++ [47].u.CCBS_T_Request.Component.Invoke.Q931ie.Bc.Length = 2,
++ [47].u.CCBS_T_Request.Component.Invoke.Q931ie.Bc.Contents = "LM",
++
++ [48].Function = Fac_CCBS_T_Request,
++ [48].u.CCBS_T_Request.InvokeID = 51,
++ [48].u.CCBS_T_Request.ComponentType = FacComponent_Result,
++ [48].u.CCBS_T_Request.Component.Result.RetentionSupported = 1,
++
++ [49].Function = Fac_CCNR_T_Request,
++ [49].u.CCNR_T_Request.InvokeID = 52,
++ [49].u.CCNR_T_Request.ComponentType = FacComponent_Invoke,
++ [49].u.CCNR_T_Request.Component.Invoke.Destination.Party.Type = 8,
++ [49].u.CCNR_T_Request.Component.Invoke.Destination.Party.LengthOfNumber = 4,
++ [49].u.CCNR_T_Request.Component.Invoke.Destination.Party.Number = "6229",
++ [49].u.CCNR_T_Request.Component.Invoke.Q931ie.Bc.Length = 2,
++ [49].u.CCNR_T_Request.Component.Invoke.Q931ie.Bc.Contents = "LM",
++
++ [50].Function = Fac_CCNR_T_Request,
++ [50].u.CCNR_T_Request.InvokeID = 53,
++ [50].u.CCNR_T_Request.ComponentType = FacComponent_Result,
++ [50].u.CCNR_T_Request.Component.Result.RetentionSupported = 1,
++
++ [51].Function = Fac_EctExecute,
++ [51].u.EctExecute.InvokeID = 54,
++
++ [52].Function = Fac_ExplicitEctExecute,
++ [52].u.ExplicitEctExecute.InvokeID = 55,
++ [52].u.ExplicitEctExecute.LinkID = 23,
++
++ [53].Function = Fac_RequestSubaddress,
++ [53].u.RequestSubaddress.InvokeID = 56,
++
++ [54].Function = Fac_SubaddressTransfer,
++ [54].u.SubaddressTransfer.InvokeID = 57,
++ [54].u.SubaddressTransfer.Subaddress.Type = 1,
++ [54].u.SubaddressTransfer.Subaddress.Length = 4,
++ [54].u.SubaddressTransfer.Subaddress.u.Nsap = "6492",
++
++ [55].Function = Fac_EctLinkIdRequest,
++ [55].u.EctLinkIdRequest.InvokeID = 58,
++ [55].u.EctLinkIdRequest.ComponentType = FacComponent_Invoke,
++
++ [56].Function = Fac_EctLinkIdRequest,
++ [56].u.EctLinkIdRequest.InvokeID = 59,
++ [56].u.EctLinkIdRequest.ComponentType = FacComponent_Result,
++ [56].u.EctLinkIdRequest.Component.Result.LinkID = 76,
++
++ [57].Function = Fac_EctInform,
++ [57].u.EctInform.InvokeID = 60,
++ [57].u.EctInform.Status = 1,
++ [57].u.EctInform.RedirectionPresent = 1,
++ [57].u.EctInform.Redirection.Type = 0,
++ [57].u.EctInform.Redirection.Unscreened.Type = 8,
++ [57].u.EctInform.Redirection.Unscreened.LengthOfNumber = 4,
++ [57].u.EctInform.Redirection.Unscreened.Number = "6229",
++
++ [58].Function = Fac_EctInform,
++ [58].u.EctInform.InvokeID = 61,
++ [58].u.EctInform.Status = 1,
++ [58].u.EctInform.RedirectionPresent = 1,
++ [58].u.EctInform.Redirection.Type = 1,
++
++ [59].Function = Fac_EctInform,
++ [59].u.EctInform.InvokeID = 62,
++ [59].u.EctInform.Status = 1,
++ [59].u.EctInform.RedirectionPresent = 1,
++ [59].u.EctInform.Redirection.Type = 2,
++
++ [60].Function = Fac_EctInform,
++ [60].u.EctInform.InvokeID = 63,
++ [60].u.EctInform.Status = 1,
++ [60].u.EctInform.RedirectionPresent = 1,
++ [60].u.EctInform.Redirection.Type = 3,
++ [60].u.EctInform.Redirection.Unscreened.Type = 8,
++ [60].u.EctInform.Redirection.Unscreened.LengthOfNumber = 4,
++ [60].u.EctInform.Redirection.Unscreened.Number = "3340",
++
++ [61].Function = Fac_EctInform,
++ [61].u.EctInform.InvokeID = 64,
++ [61].u.EctInform.Status = 1,
++ [61].u.EctInform.RedirectionPresent = 0,
++
++ [62].Function = Fac_EctLoopTest,
++ [62].u.EctLoopTest.InvokeID = 65,
++ [62].u.EctLoopTest.ComponentType = FacComponent_Invoke,
++ [62].u.EctLoopTest.Component.Invoke.CallTransferID = 7,
++
++ [63].Function = Fac_EctLoopTest,
++ [63].u.EctLoopTest.InvokeID = 66,
++ [63].u.EctLoopTest.ComponentType = FacComponent_Result,
++ [63].u.EctLoopTest.Component.Result.LoopResult = 2,
++
++ [64].Function = Fac_ActivationDiversion,
++ [64].u.ActivationDiversion.InvokeID = 67,
++ [64].u.ActivationDiversion.ComponentType = FacComponent_Invoke,
++ [64].u.ActivationDiversion.Component.Invoke.Procedure = 2,
++ [64].u.ActivationDiversion.Component.Invoke.BasicService = 3,
++ [64].u.ActivationDiversion.Component.Invoke.ForwardedTo.Party.Type = 4,
++ [64].u.ActivationDiversion.Component.Invoke.ForwardedTo.Party.LengthOfNumber = 4,
++ [64].u.ActivationDiversion.Component.Invoke.ForwardedTo.Party.Number = "1803",
++ [64].u.ActivationDiversion.Component.Invoke.ServedUser.Type = 4,
++ [64].u.ActivationDiversion.Component.Invoke.ServedUser.LengthOfNumber = 4,
++ [64].u.ActivationDiversion.Component.Invoke.ServedUser.Number = "5398",
++
++ [65].Function = Fac_ActivationDiversion,
++ [65].u.ActivationDiversion.InvokeID = 68,
++ [65].u.ActivationDiversion.ComponentType = FacComponent_Invoke,
++ [65].u.ActivationDiversion.Component.Invoke.Procedure = 1,
++ [65].u.ActivationDiversion.Component.Invoke.BasicService = 5,
++ [65].u.ActivationDiversion.Component.Invoke.ForwardedTo.Party.Type = 4,
++ [65].u.ActivationDiversion.Component.Invoke.ForwardedTo.Party.LengthOfNumber = 4,
++ [65].u.ActivationDiversion.Component.Invoke.ForwardedTo.Party.Number = "1803",
++
++ [66].Function = Fac_ActivationDiversion,
++ [66].u.ActivationDiversion.InvokeID = 69,
++ [66].u.ActivationDiversion.ComponentType = FacComponent_Result,
++
++ [67].Function = Fac_DeactivationDiversion,
++ [67].u.DeactivationDiversion.InvokeID = 70,
++ [67].u.DeactivationDiversion.ComponentType = FacComponent_Invoke,
++ [67].u.DeactivationDiversion.Component.Invoke.Procedure = 1,
++ [67].u.DeactivationDiversion.Component.Invoke.BasicService = 5,
++
++ [68].Function = Fac_DeactivationDiversion,
++ [68].u.DeactivationDiversion.InvokeID = 71,
++ [68].u.DeactivationDiversion.ComponentType = FacComponent_Result,
++
++ [69].Function = Fac_ActivationStatusNotificationDiv,
++ [69].u.ActivationStatusNotificationDiv.InvokeID = 72,
++ [69].u.ActivationStatusNotificationDiv.Procedure = 1,
++ [69].u.ActivationStatusNotificationDiv.BasicService = 5,
++ [69].u.ActivationStatusNotificationDiv.ForwardedTo.Party.Type = 4,
++ [69].u.ActivationStatusNotificationDiv.ForwardedTo.Party.LengthOfNumber = 4,
++ [69].u.ActivationStatusNotificationDiv.ForwardedTo.Party.Number = "1803",
++
++ [70].Function = Fac_DeactivationStatusNotificationDiv,
++ [70].u.DeactivationStatusNotificationDiv.InvokeID = 73,
++ [70].u.DeactivationStatusNotificationDiv.Procedure = 1,
++ [70].u.DeactivationStatusNotificationDiv.BasicService = 5,
++
++ [71].Function = Fac_InterrogationDiversion,
++ [71].u.InterrogationDiversion.InvokeID = 74,
++ [71].u.InterrogationDiversion.ComponentType = FacComponent_Invoke,
++ [71].u.InterrogationDiversion.Component.Invoke.Procedure = 1,
++ [71].u.InterrogationDiversion.Component.Invoke.BasicService = 5,
++
++ [72].Function = Fac_InterrogationDiversion,
++ [72].u.InterrogationDiversion.InvokeID = 75,
++ [72].u.InterrogationDiversion.ComponentType = FacComponent_Invoke,
++ [72].u.InterrogationDiversion.Component.Invoke.Procedure = 1,
++
++ [73].Function = Fac_InterrogationDiversion,
++ [73].u.InterrogationDiversion.InvokeID = 76,
++ [73].u.InterrogationDiversion.ComponentType = FacComponent_Result,
++ [73].u.InterrogationDiversion.Component.Result.NumRecords = 2,
++ [73].u.InterrogationDiversion.Component.Result.List[0].Procedure = 2,
++ [73].u.InterrogationDiversion.Component.Result.List[0].BasicService = 5,
++ [73].u.InterrogationDiversion.Component.Result.List[0].ForwardedTo.Party.Type = 4,
++ [73].u.InterrogationDiversion.Component.Result.List[0].ForwardedTo.Party.LengthOfNumber = 4,
++ [73].u.InterrogationDiversion.Component.Result.List[0].ForwardedTo.Party.Number = "1803",
++ [73].u.InterrogationDiversion.Component.Result.List[1].Procedure = 1,
++ [73].u.InterrogationDiversion.Component.Result.List[1].BasicService = 3,
++ [73].u.InterrogationDiversion.Component.Result.List[1].ForwardedTo.Party.Type = 4,
++ [73].u.InterrogationDiversion.Component.Result.List[1].ForwardedTo.Party.LengthOfNumber = 4,
++ [73].u.InterrogationDiversion.Component.Result.List[1].ForwardedTo.Party.Number = "1903",
++ [73].u.InterrogationDiversion.Component.Result.List[1].ServedUser.Type = 4,
++ [73].u.InterrogationDiversion.Component.Result.List[1].ServedUser.LengthOfNumber = 4,
++ [73].u.InterrogationDiversion.Component.Result.List[1].ServedUser.Number = "5398",
++
++ [74].Function = Fac_DiversionInformation,
++ [74].u.DiversionInformation.InvokeID = 77,
++ [74].u.DiversionInformation.DiversionReason = 3,
++ [74].u.DiversionInformation.BasicService = 5,
++ [74].u.DiversionInformation.ServedUserSubaddress.Type = 1,
++ [74].u.DiversionInformation.ServedUserSubaddress.Length = 4,
++ [74].u.DiversionInformation.ServedUserSubaddress.u.Nsap = "6492",
++ [74].u.DiversionInformation.CallingAddressPresent = 1,
++ [74].u.DiversionInformation.CallingAddress.Type = 0,
++ [74].u.DiversionInformation.CallingAddress.Address.ScreeningIndicator = 3,
++ [74].u.DiversionInformation.CallingAddress.Address.Party.Type = 4,
++ [74].u.DiversionInformation.CallingAddress.Address.Party.LengthOfNumber = 4,
++ [74].u.DiversionInformation.CallingAddress.Address.Party.Number = "1803",
++ [74].u.DiversionInformation.OriginalCalledPresent = 1,
++ [74].u.DiversionInformation.OriginalCalled.Type = 1,
++ [74].u.DiversionInformation.LastDivertingPresent = 1,
++ [74].u.DiversionInformation.LastDiverting.Type = 2,
++ [74].u.DiversionInformation.LastDivertingReasonPresent = 1,
++ [74].u.DiversionInformation.LastDivertingReason = 3,
++ [74].u.DiversionInformation.UserInfo.Length = 5,
++ [74].u.DiversionInformation.UserInfo.Contents = "79828",
++
++ [75].Function = Fac_DiversionInformation,
++ [75].u.DiversionInformation.InvokeID = 78,
++ [75].u.DiversionInformation.DiversionReason = 3,
++ [75].u.DiversionInformation.BasicService = 5,
++ [75].u.DiversionInformation.CallingAddressPresent = 1,
++ [75].u.DiversionInformation.CallingAddress.Type = 1,
++ [75].u.DiversionInformation.OriginalCalledPresent = 1,
++ [75].u.DiversionInformation.OriginalCalled.Type = 2,
++ [75].u.DiversionInformation.LastDivertingPresent = 1,
++ [75].u.DiversionInformation.LastDiverting.Type = 1,
++
++ [76].Function = Fac_DiversionInformation,
++ [76].u.DiversionInformation.InvokeID = 79,
++ [76].u.DiversionInformation.DiversionReason = 2,
++ [76].u.DiversionInformation.BasicService = 3,
++ [76].u.DiversionInformation.CallingAddressPresent = 1,
++ [76].u.DiversionInformation.CallingAddress.Type = 2,
++
++ [77].Function = Fac_DiversionInformation,
++ [77].u.DiversionInformation.InvokeID = 80,
++ [77].u.DiversionInformation.DiversionReason = 3,
++ [77].u.DiversionInformation.BasicService = 5,
++ [77].u.DiversionInformation.CallingAddressPresent = 1,
++ [77].u.DiversionInformation.CallingAddress.Type = 3,
++ [77].u.DiversionInformation.CallingAddress.Address.ScreeningIndicator = 2,
++ [77].u.DiversionInformation.CallingAddress.Address.Party.Type = 4,
++ [77].u.DiversionInformation.CallingAddress.Address.Party.LengthOfNumber = 4,
++ [77].u.DiversionInformation.CallingAddress.Address.Party.Number = "1803",
++
++ [78].Function = Fac_DiversionInformation,
++ [78].u.DiversionInformation.InvokeID = 81,
++ [78].u.DiversionInformation.DiversionReason = 2,
++ [78].u.DiversionInformation.BasicService = 4,
++ [78].u.DiversionInformation.UserInfo.Length = 5,
++ [78].u.DiversionInformation.UserInfo.Contents = "79828",
++
++ [79].Function = Fac_DiversionInformation,
++ [79].u.DiversionInformation.InvokeID = 82,
++ [79].u.DiversionInformation.DiversionReason = 2,
++ [79].u.DiversionInformation.BasicService = 4,
++
++ [80].Function = Fac_CallDeflection,
++ [80].u.CallDeflection.InvokeID = 83,
++ [80].u.CallDeflection.ComponentType = FacComponent_Invoke,
++ [80].u.CallDeflection.Component.Invoke.Deflection.Party.Type = 4,
++ [80].u.CallDeflection.Component.Invoke.Deflection.Party.LengthOfNumber = 4,
++ [80].u.CallDeflection.Component.Invoke.Deflection.Party.Number = "1803",
++ [80].u.CallDeflection.Component.Invoke.PresentationAllowedToDivertedToUserPresent = 1,
++ [80].u.CallDeflection.Component.Invoke.PresentationAllowedToDivertedToUser = 1,
++
++ [81].Function = Fac_CallDeflection,
++ [81].u.CallDeflection.InvokeID = 84,
++ [81].u.CallDeflection.ComponentType = FacComponent_Invoke,
++ [81].u.CallDeflection.Component.Invoke.Deflection.Party.Type = 4,
++ [81].u.CallDeflection.Component.Invoke.Deflection.Party.LengthOfNumber = 4,
++ [81].u.CallDeflection.Component.Invoke.Deflection.Party.Number = "1803",
++ [81].u.CallDeflection.Component.Invoke.PresentationAllowedToDivertedToUserPresent = 1,
++ [81].u.CallDeflection.Component.Invoke.PresentationAllowedToDivertedToUser = 0,
++
++ [82].Function = Fac_CallDeflection,
++ [82].u.CallDeflection.InvokeID = 85,
++ [82].u.CallDeflection.ComponentType = FacComponent_Invoke,
++ [82].u.CallDeflection.Component.Invoke.Deflection.Party.Type = 4,
++ [82].u.CallDeflection.Component.Invoke.Deflection.Party.LengthOfNumber = 4,
++ [82].u.CallDeflection.Component.Invoke.Deflection.Party.Number = "1803",
++
++ [83].Function = Fac_CallDeflection,
++ [83].u.CallDeflection.InvokeID = 86,
++ [83].u.CallDeflection.ComponentType = FacComponent_Result,
++
++ [84].Function = Fac_CallRerouteing,
++ [84].u.CallRerouteing.InvokeID = 87,
++ [84].u.CallRerouteing.ComponentType = FacComponent_Invoke,
++ [84].u.CallRerouteing.Component.Invoke.ReroutingReason = 3,
++ [84].u.CallRerouteing.Component.Invoke.ReroutingCounter = 2,
++ [84].u.CallRerouteing.Component.Invoke.CalledAddress.Party.Type = 4,
++ [84].u.CallRerouteing.Component.Invoke.CalledAddress.Party.LengthOfNumber = 4,
++ [84].u.CallRerouteing.Component.Invoke.CalledAddress.Party.Number = "1803",
++ [84].u.CallRerouteing.Component.Invoke.Q931ie.Bc.Length = 2,
++ [84].u.CallRerouteing.Component.Invoke.Q931ie.Bc.Contents = "RT",
++ [84].u.CallRerouteing.Component.Invoke.Q931ie.Hlc.Length = 3,
++ [84].u.CallRerouteing.Component.Invoke.Q931ie.Hlc.Contents = "RTG",
++ [84].u.CallRerouteing.Component.Invoke.Q931ie.Llc.Length = 2,
++ [84].u.CallRerouteing.Component.Invoke.Q931ie.Llc.Contents = "MY",
++ [84].u.CallRerouteing.Component.Invoke.Q931ie.UserInfo.Length = 5,
++ [84].u.CallRerouteing.Component.Invoke.Q931ie.UserInfo.Contents = "YEHAW",
++ [84].u.CallRerouteing.Component.Invoke.LastRerouting.Type = 1,
++ [84].u.CallRerouteing.Component.Invoke.SubscriptionOption = 2,
++ [84].u.CallRerouteing.Component.Invoke.CallingPartySubaddress.Type = 1,
++ [84].u.CallRerouteing.Component.Invoke.CallingPartySubaddress.Length = 4,
++ [84].u.CallRerouteing.Component.Invoke.CallingPartySubaddress.u.Nsap = "6492",
++
++ [85].Function = Fac_CallRerouteing,
++ [85].u.CallRerouteing.InvokeID = 88,
++ [85].u.CallRerouteing.ComponentType = FacComponent_Invoke,
++ [85].u.CallRerouteing.Component.Invoke.ReroutingReason = 3,
++ [85].u.CallRerouteing.Component.Invoke.ReroutingCounter = 2,
++ [85].u.CallRerouteing.Component.Invoke.CalledAddress.Party.Type = 4,
++ [85].u.CallRerouteing.Component.Invoke.CalledAddress.Party.LengthOfNumber = 4,
++ [85].u.CallRerouteing.Component.Invoke.CalledAddress.Party.Number = "1803",
++ [85].u.CallRerouteing.Component.Invoke.Q931ie.Bc.Length = 2,
++ [85].u.CallRerouteing.Component.Invoke.Q931ie.Bc.Contents = "RT",
++ [85].u.CallRerouteing.Component.Invoke.LastRerouting.Type = 1,
++ [85].u.CallRerouteing.Component.Invoke.SubscriptionOption = 2,
++
++ [86].Function = Fac_CallRerouteing,
++ [86].u.CallRerouteing.InvokeID = 89,
++ [86].u.CallRerouteing.ComponentType = FacComponent_Invoke,
++ [86].u.CallRerouteing.Component.Invoke.ReroutingReason = 3,
++ [86].u.CallRerouteing.Component.Invoke.ReroutingCounter = 2,
++ [86].u.CallRerouteing.Component.Invoke.CalledAddress.Party.Type = 4,
++ [86].u.CallRerouteing.Component.Invoke.CalledAddress.Party.LengthOfNumber = 4,
++ [86].u.CallRerouteing.Component.Invoke.CalledAddress.Party.Number = "1803",
++ [86].u.CallRerouteing.Component.Invoke.Q931ie.Bc.Length = 2,
++ [86].u.CallRerouteing.Component.Invoke.Q931ie.Bc.Contents = "RT",
++ [86].u.CallRerouteing.Component.Invoke.LastRerouting.Type = 2,
++
++ [87].Function = Fac_CallRerouteing,
++ [87].u.CallRerouteing.InvokeID = 90,
++ [87].u.CallRerouteing.ComponentType = FacComponent_Result,
++
++ [88].Function = Fac_InterrogateServedUserNumbers,
++ [88].u.InterrogateServedUserNumbers.InvokeID = 91,
++ [88].u.InterrogateServedUserNumbers.ComponentType = FacComponent_Invoke,
++
++ [89].Function = Fac_InterrogateServedUserNumbers,
++ [89].u.InterrogateServedUserNumbers.InvokeID = 92,
++ [89].u.InterrogateServedUserNumbers.ComponentType = FacComponent_Result,
++ [89].u.InterrogateServedUserNumbers.Component.Result.NumRecords = 2,
++ [89].u.InterrogateServedUserNumbers.Component.Result.List[0].Type = 4,
++ [89].u.InterrogateServedUserNumbers.Component.Result.List[0].LengthOfNumber = 4,
++ [89].u.InterrogateServedUserNumbers.Component.Result.List[0].Number = "1803",
++ [89].u.InterrogateServedUserNumbers.Component.Result.List[1].Type = 4,
++ [89].u.InterrogateServedUserNumbers.Component.Result.List[1].LengthOfNumber = 4,
++ [89].u.InterrogateServedUserNumbers.Component.Result.List[1].Number = "5786",
++
++ [90].Function = Fac_DivertingLegInformation1,
++ [90].u.DivertingLegInformation1.InvokeID = 93,
++ [90].u.DivertingLegInformation1.DiversionReason = 4,
++ [90].u.DivertingLegInformation1.SubscriptionOption = 1,
++ [90].u.DivertingLegInformation1.DivertedToPresent = 1,
++ [90].u.DivertingLegInformation1.DivertedTo.Type = 2,
++
++ [91].Function = Fac_DivertingLegInformation1,
++ [91].u.DivertingLegInformation1.InvokeID = 94,
++ [91].u.DivertingLegInformation1.DiversionReason = 4,
++ [91].u.DivertingLegInformation1.SubscriptionOption = 1,
++
++ [92].Function = Fac_DivertingLegInformation2,
++ [92].u.DivertingLegInformation2.InvokeID = 95,
++ [92].u.DivertingLegInformation2.DiversionCounter = 3,
++ [92].u.DivertingLegInformation2.DiversionReason = 2,
++ [92].u.DivertingLegInformation2.DivertingPresent = 1,
++ [92].u.DivertingLegInformation2.Diverting.Type = 2,
++ [92].u.DivertingLegInformation2.OriginalCalledPresent = 1,
++ [92].u.DivertingLegInformation2.OriginalCalled.Type = 1,
++
++ [93].Function = Fac_DivertingLegInformation2,
++ [93].u.DivertingLegInformation2.InvokeID = 96,
++ [93].u.DivertingLegInformation2.DiversionCounter = 3,
++ [93].u.DivertingLegInformation2.DiversionReason = 2,
++ [93].u.DivertingLegInformation2.OriginalCalledPresent = 1,
++ [93].u.DivertingLegInformation2.OriginalCalled.Type = 1,
++
++ [94].Function = Fac_DivertingLegInformation2,
++ [94].u.DivertingLegInformation2.InvokeID = 97,
++ [94].u.DivertingLegInformation2.DiversionCounter = 1,
++ [94].u.DivertingLegInformation2.DiversionReason = 2,
++
++ [95].Function = Fac_DivertingLegInformation3,
++ [95].u.DivertingLegInformation3.InvokeID = 98,
++ [95].u.DivertingLegInformation3.PresentationAllowedIndicator = 1,
++/* *INDENT-ON* */
++};
++#endif /* defined(AST_MISDN_ENHANCEMENTS) && defined(CCBS_TEST_MESSAGES) */
++
+ static char *handle_cli_misdn_send_facility(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+ {
+- char *channame;
+- char *nr;
++ const char *channame;
++ const char *nr;
+ struct chan_list *tmp;
+- int port;
+- char *served_nr;
++ int port;
++ const char *served_nr;
+ struct misdn_bchannel dummy, *bc=&dummy;
+-
++ unsigned max_len;
++
+ switch (cmd) {
+ case CLI_INIT:
+ e->command = "misdn send facility";
+@@ -1673,7 +5148,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 +5161,42 @@
+ 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;
++#if defined(AST_MISDN_ENHANCEMENTS)
++ max_len = sizeof(tmp->bc->fac_out.u.CallDeflection.Component.Invoke.Deflection.Party.Number) - 1;
++ if (max_len < strlen(nr)) {
++ ast_verbose("Sending CD with nr %s to %s failed: Number too long (up to %u digits are allowed).\n",
++ nr, channame, max_len);
++ return 0;
+ }
++ tmp->bc->fac_out.Function = Fac_CallDeflection;
++ tmp->bc->fac_out.u.CallDeflection.InvokeID = ++misdn_invoke_id;
++ tmp->bc->fac_out.u.CallDeflection.ComponentType = FacComponent_Invoke;
++ tmp->bc->fac_out.u.CallDeflection.Component.Invoke.PresentationAllowedToDivertedToUserPresent = 1;
++ tmp->bc->fac_out.u.CallDeflection.Component.Invoke.PresentationAllowedToDivertedToUser = 0;
++ tmp->bc->fac_out.u.CallDeflection.Component.Invoke.Deflection.Party.Type = 0;/* unknown */
++ tmp->bc->fac_out.u.CallDeflection.Component.Invoke.Deflection.Party.LengthOfNumber = strlen(nr);
++ strcpy((char *) tmp->bc->fac_out.u.CallDeflection.Component.Invoke.Deflection.Party.Number, nr);
++ tmp->bc->fac_out.u.CallDeflection.Component.Invoke.Deflection.Subaddress.Length = 0;
++
++#else /* !defined(AST_MISDN_ENHANCEMENTS) */
++
++ max_len = sizeof(tmp->bc->fac_out.u.CDeflection.DeflectedToNumber) - 1;
++ if (max_len < strlen(nr)) {
++ ast_verbose("Sending CD with nr %s to %s failed: Number too long (up to %u digits are allowed).\n",
++ nr, channame, max_len);
++ 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));
++ tmp->bc->fac_out.u.CDeflection.PresentationAllowed = 0;
++ //tmp->bc->fac_out.u.CDeflection.DeflectedToSubaddress[0] = 0;
++ strcpy((char *) tmp->bc->fac_out.u.CDeflection.DeflectedToNumber, nr);
++#endif /* !defined(AST_MISDN_ENHANCEMENTS) */
++
++ /* Send message */
++ print_facility(&tmp->bc->fac_out, tmp->bc);
+ misdn_lib_send_event(tmp->bc, EVENT_FACILITY);
+ } else if (strstr(a->argv[3], "CFActivate")) {
+ if (a->argc < 7) {
+@@ -1709,31 +5211,135 @@
+
+ ast_verbose("Sending CFActivate Port:(%d) FromNr. (%s) to Nr. (%s)\n", port, served_nr, nr);
+
++#if defined(AST_MISDN_ENHANCEMENTS)
++ bc->fac_out.Function = Fac_ActivationDiversion;
++ bc->fac_out.u.ActivationDiversion.InvokeID = ++misdn_invoke_id;
++ bc->fac_out.u.ActivationDiversion.ComponentType = FacComponent_Invoke;
++ bc->fac_out.u.ActivationDiversion.Component.Invoke.BasicService = 0;/* allServices */
++ bc->fac_out.u.ActivationDiversion.Component.Invoke.Procedure = 0;/* cfu (Call Forward Unconditional) */
++ ast_copy_string((char *) bc->fac_out.u.ActivationDiversion.Component.Invoke.ServedUser.Number,
++ served_nr, sizeof(bc->fac_out.u.ActivationDiversion.Component.Invoke.ServedUser.Number));
++ bc->fac_out.u.ActivationDiversion.Component.Invoke.ServedUser.LengthOfNumber =
++ strlen((char *) bc->fac_out.u.ActivationDiversion.Component.Invoke.ServedUser.Number);
++ bc->fac_out.u.ActivationDiversion.Component.Invoke.ServedUser.Type = 0;/* unknown */
++ ast_copy_string((char *) bc->fac_out.u.ActivationDiversion.Component.Invoke.ForwardedTo.Party.Number,
++ nr, sizeof(bc->fac_out.u.ActivationDiversion.Component.Invoke.ForwardedTo.Party.Number));
++ bc->fac_out.u.ActivationDiversion.Component.Invoke.ForwardedTo.Party.LengthOfNumber =
++ strlen((char *) bc->fac_out.u.ActivationDiversion.Component.Invoke.ForwardedTo.Party.Number);
++ bc->fac_out.u.ActivationDiversion.Component.Invoke.ForwardedTo.Party.Type = 0;/* unknown */
++ bc->fac_out.u.ActivationDiversion.Component.Invoke.ForwardedTo.Subaddress.Length = 0;
++
++#else /* !defined(AST_MISDN_ENHANCEMENTS) */
++
+ bc->fac_out.Function = Fac_CFActivate;
+ 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));
++ 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));
++#endif /* !defined(AST_MISDN_ENHANCEMENTS) */
+
++ /* Send message */
++ print_facility(&bc->fac_out, bc);
+ misdn_lib_send_event(bc, EVENT_FACILITY);
+ } 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);
+
++#if defined(AST_MISDN_ENHANCEMENTS)
++ bc->fac_out.Function = Fac_DeactivationDiversion;
++ bc->fac_out.u.DeactivationDiversion.InvokeID = ++misdn_invoke_id;
++ bc->fac_out.u.DeactivationDiversion.ComponentType = FacComponent_Invoke;
++ bc->fac_out.u.DeactivationDiversion.Component.Invoke.BasicService = 0;/* allServices */
++ bc->fac_out.u.DeactivationDiversion.Component.Invoke.Procedure = 0;/* cfu (Call Forward Unconditional) */
++ ast_copy_string((char *) bc->fac_out.u.DeactivationDiversion.Component.Invoke.ServedUser.Number,
++ served_nr, sizeof(bc->fac_out.u.DeactivationDiversion.Component.Invoke.ServedUser.Number));
++ bc->fac_out.u.DeactivationDiversion.Component.Invoke.ServedUser.LengthOfNumber =
++ strlen((char *) bc->fac_out.u.DeactivationDiversion.Component.Invoke.ServedUser.Number);
++ bc->fac_out.u.DeactivationDiversion.Component.Invoke.ServedUser.Type = 0;/* unknown */
++
++#else /* !defined(AST_MISDN_ENHANCEMENTS) */
++
+ 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));
++#endif /* !defined(AST_MISDN_ENHANCEMENTS) */
++
++ /* Send message */
++ print_facility(&bc->fac_out, bc);
+ misdn_lib_send_event(bc, EVENT_FACILITY);
++#if defined(AST_MISDN_ENHANCEMENTS) && defined(CCBS_TEST_MESSAGES)
++ } else if (strstr(a->argv[3], "test")) {
++ int msg_number;
++
++ if (a->argc < 5) {
++ ast_verbose("test (<port> [<msg#>]) | (<channel-name> <msg#>)\n\n");
++ return 0;
++ }
++ port = atoi(a->argv[4]);
++
++ channame = argv[4];
++ tmp = get_chan_by_ast_name(channame);
++ if (tmp) {
++ /* We are going to send this FACILITY message out on an existing connection */
++ msg_number = atoi(argv[5]);
++ if (msg_number < ARRAY_LEN(Fac_Msgs)) {
++ tmp->bc->fac_out = Fac_Msgs[msg_number];
++
++ /* Send message */
++ print_facility(&tmp->bc->fac_out, tmp->bc);
++ misdn_lib_send_event(tmp->bc, EVENT_FACILITY);
++ } else {
++ ast_verbose("test <channel-name> <msg#>\n\n");
++ }
++ } else if (a->argc < 6) {
++ for (msg_number = 0; msg_number < ARRAY_LEN(Fac_Msgs); ++msg_number) {
++ misdn_make_dummy(bc, port, 0, misdn_lib_port_is_nt(port), 0);
++ bc->fac_out = Fac_Msgs[msg_number];
++
++ /* Send message */
++ print_facility(&bc->fac_out, bc);
++ misdn_lib_send_event(bc, EVENT_FACILITY);
++ sleep(1);
++ }
++ } else {
++ msg_number = atoi(a->argv[5]);
++ if (msg_number < ARRAY_LEN(Fac_Msgs)) {
++ misdn_make_dummy(bc, port, 0, misdn_lib_port_is_nt(port), 0);
++ bc->fac_out = Fac_Msgs[msg_number];
++
++ /* Send message */
++ print_facility(&bc->fac_out, bc);
++ misdn_lib_send_event(bc, EVENT_FACILITY);
++ } else {
++ ast_verbose("test <port> [<msg#>]\n\n");
++ }
++ }
++ } else if (strstr(argv[3], "register")) {
++ if (argc < 5) {
++ ast_cli(fd, "register <port>\n\n");
++ return 0;
++ }
++ port = atoi(argv[4]);
++
++ bc = misdn_lib_get_register_bc(port);
++ if (!bc) {
++ ast_cli(fd, "Could not allocate REGISTER bc struct\n\n");
++ return 0;
++ }
++ bc->fac_out = Fac_Msgs[45];
++
++ /* Send message */
++ print_facility(&bc->fac_out, bc);
++ misdn_lib_send_event(bc, EVENT_REGISTER);
++#endif /* defined(AST_MISDN_ENHANCEMENTS) && defined(CCBS_TEST_MESSAGES) */
+ }
+
+ return CLI_SUCCESS;
+@@ -1773,8 +5379,8 @@
+
+ static char *handle_cli_misdn_send_digit(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+ {
+- char *channame;
+- char *msg;
++ const char *channame;
++ const char *msg;
+ struct chan_list *tmp;
+ int i, msglen;
+
+@@ -1803,7 +5409,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++) {
+@@ -1822,7 +5428,7 @@
+
+ static char *handle_cli_misdn_toggle_echocancel(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+ {
+- char *channame;
++ const char *channame;
+ struct chan_list *tmp;
+
+ switch (cmd) {
+@@ -1841,9 +5447,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);
+@@ -1868,8 +5474,8 @@
+
+ static char *handle_cli_misdn_send_display(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+ {
+- char *channame;
+- char *msg;
++ const char *channame;
++ const char *msg;
+ struct chan_list *tmp;
+
+ switch (cmd) {
+@@ -1893,7 +5499,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);
+@@ -1986,6 +5592,7 @@
+ }
+
+ static struct ast_cli_entry chan_misdn_clis[] = {
++/* *INDENT-OFF* */
+ AST_CLI_DEFINE(handle_cli_misdn_port_block, "Block the given port"),
+ AST_CLI_DEFINE(handle_cli_misdn_port_down, "Try to deactivate the L1 on the given port"),
+ AST_CLI_DEFINE(handle_cli_misdn_port_unblock, "Unblock the given port"),
+@@ -2007,26 +5614,29 @@
+ AST_CLI_DEFINE(handle_cli_misdn_set_debug, "Set Debuglevel of chan_misdn"),
+ AST_CLI_DEFINE(handle_cli_misdn_set_tics, "???"),
+ AST_CLI_DEFINE(handle_cli_misdn_toggle_echocancel, "Toggle EchoCancel on mISDN Channel"),
++/* *INDENT-ON* */
+ };
+
+ /*! \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 +5644,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,63 +5658,33 @@
+ 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;
+ }
+
+
+ static void config_jitterbuffer(struct chan_list *ch)
+ {
+ struct misdn_bchannel *bc = ch->bc;
+- int len = ch->jb_len, threshold = ch->jb_upper_threshold;
+-
++ int len = ch->jb_len;
++ int threshold = ch->jb_upper_threshold;
++
+ chan_misdn_log(5, bc->port, "config_jb: Called\n");
+-
+- if (! len) {
++
++ if (!len) {
+ chan_misdn_log(1, bc->port, "config_jb: Deactivating Jitterbuffer\n");
+- bc->nojitter=1;
++ bc->nojitter = 1;
+ } else {
+ if (len <= 100 || len > 8000) {
+ chan_misdn_log(0, bc->port, "config_jb: Jitterbuffer out of Bounds, setting to 1000\n");
+@@ -2116,7 +5695,7 @@
+ chan_misdn_log(0, bc->port, "config_jb: Jitterbuffer Threshold > Jitterbuffer setting to Jitterbuffer -1\n");
+ }
+
+- if ( ch->jb) {
++ if (ch->jb) {
+ cb_log(0, bc->port, "config_jb: We've got a Jitterbuffer Already on this port.\n");
+ misdn_jb_destroy(ch->jb);
+ ch->jb = NULL;
+@@ -2131,20 +5710,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 +5779,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 +5803,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 +5818,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 +5836,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 +5844,7 @@
+ bc->hdlc = 1;
+ break;
+ }
+-
++
+ }
+ /*Initialize new Jitterbuffer*/
+ misdn_cfg_get(port, MISDN_CFG_JITTERBUFFER, &ch->jb_len, sizeof(ch->jb_len));
+@@ -2281,14 +5864,17 @@
+
+ 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_OUTGOING_COLP, &bc->outgoing_colp, sizeof(bc->outgoing_colp));
++
+ 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 +5887,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 +5953,289 @@
+ return 0;
+ }
+
++/*!
++ * \internal
++ * \brief Send a connected line update to the other channel
++ *
++ * \param ast Current Asterisk channel
++ * \param id Party id information to send to the other side
++ * \param source Why are we sending this update
++ *
++ * \return Nothing
++ */
++static void misdn_queue_connected_line_update(struct ast_channel *ast, const struct misdn_party_id *id, enum AST_CONNECTED_LINE_UPDATE_SOURCE source)
++{
++ struct ast_party_connected_line connected;
+
++ ast_party_connected_line_init(&connected);
++ connected.id.number = (char *) id->number;
++ connected.id.number_type = misdn_to_ast_ton(id->number_type)
++ | misdn_to_ast_plan(id->number_plan);
++ connected.id.number_presentation = misdn_to_ast_pres(id->presentation)
++ | misdn_to_ast_screen(id->screening);
++ connected.source = source;
++ ast_channel_queue_connected_line_update(ast, &connected);
++}
++
++/*!
++ * \internal
++ * \brief Get the connected line information out of the Asterisk channel.
++ *
++ * \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_get_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 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)
++{
++ struct chan_list *ch;
++
++ misdn_get_connected_line(ast, bc, originator);
++ if (originator == ORG_MISDN) {
++ bc->redirecting.to = bc->connected;
++ } else {
++ bc->redirecting.to = bc->caller;
++ }
++ switch (bc->outgoing_colp) {
++ case 1:/* restricted */
++ case 2:/* blocked */
++ bc->redirecting.to.presentation = 1;/* restricted */
++ break;
++ default:
++ break;
++ }
++
++ ch = MISDN_ASTERISK_TECH_PVT(ast);
++ if (ch->state == MISDN_CONNECTED
++ || originator != ORG_MISDN) {
++ int is_ptmp;
++
++ is_ptmp = !misdn_lib_is_ptp(bc->port);
++ if (is_ptmp) {
++ /* Send NOTIFY(transfer-active, redirecting.to data) */
++ bc->redirecting.to_changed = 1;
++ bc->notify_description_code = mISDN_NOTIFY_CODE_CALL_TRANSFER_ACTIVE;
++ misdn_lib_send_event(bc, EVENT_NOTIFY);
++#if defined(AST_MISDN_ENHANCEMENTS)
++ } else {
++ /* Send EctInform(transfer-active, redirecting.to data) */
++ bc->fac_out.Function = Fac_EctInform;
++ bc->fac_out.u.EctInform.InvokeID = ++misdn_invoke_id;
++ bc->fac_out.u.EctInform.Status = 1;/* active */
++ bc->fac_out.u.EctInform.RedirectionPresent = 1;/* Must be present when status is active */
++ misdn_PresentedNumberUnscreened_fill(&bc->fac_out.u.EctInform.Redirection,
++ &bc->redirecting.to);
++ switch (bc->outgoing_colp) {
++ case 2:/* blocked */
++ /* Block the number going out */
++ bc->fac_out.u.EctInform.Redirection.Type = 1;/* presentationRestricted */
++ break;
++ default:
++ break;
++ }
++
++ /* Send message */
++ print_facility(&bc->fac_out, bc);
++ misdn_lib_send_event(bc, EVENT_FACILITY);
++#endif /* defined(AST_MISDN_ENHANCEMENTS) */
++ }
++ }
++}
++
++/*!
++ * \internal
++ * \brief Copy the redirecting information 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);
++
++ ast_copy_string(bc->redirecting.to.name, S_OR(ast->redirecting.to.name, ""), sizeof(bc->redirecting.to.name));
++ ast_copy_string(bc->redirecting.to.number, S_OR(ast->redirecting.to.number, ""), sizeof(bc->redirecting.to.number));
++ bc->redirecting.to.presentation = ast_to_misdn_pres(ast->redirecting.to.number_presentation);
++ bc->redirecting.to.screening = ast_to_misdn_screen(ast->redirecting.to.number_presentation);
++ bc->redirecting.to.number_type = ast_to_misdn_ton(ast->redirecting.to.number_type);
++ bc->redirecting.to.number_plan = ast_to_misdn_plan(ast->redirecting.to.number_type);
++
++ bc->redirecting.reason = ast_to_misdn_reason(ast->redirecting.reason);
++ bc->redirecting.count = ast->redirecting.count;
++}
++
++/*!
++ * \internal
++ * \brief Copy the redirecting info into the Asterisk channel
++ *
++ * \param ast Current Asterisk channel
++ * \param redirect Associated B channel redirecting info
++ *
++ * \return Nothing
++ */
++static void misdn_copy_redirecting_to_ast(struct ast_channel *ast, const struct misdn_party_redirecting *redirect)
++{
++ struct ast_party_redirecting redirecting;
++
++ ast_party_redirecting_set_init(&redirecting, &ast->redirecting);
++
++ redirecting.from.number = (char *) redirect->from.number;
++ redirecting.from.number_type =
++ misdn_to_ast_ton(redirect->from.number_type)
++ | misdn_to_ast_plan(redirect->from.number_plan);
++ redirecting.from.number_presentation =
++ misdn_to_ast_pres(redirect->from.presentation)
++ | misdn_to_ast_screen(redirect->from.screening);
++
++ redirecting.to.number = (char *) redirect->to.number;
++ redirecting.to.number_type =
++ misdn_to_ast_ton(redirect->to.number_type)
++ | misdn_to_ast_plan(redirect->to.number_plan);
++ redirecting.to.number_presentation =
++ misdn_to_ast_pres(redirect->to.presentation)
++ | misdn_to_ast_screen(redirect->to.screening);
++
++ redirecting.reason = misdn_to_ast_reason(redirect->reason);
++ redirecting.count = redirect->count;
++
++ ast_channel_set_redirecting(ast, &redirecting);
++}
++
++/*!
++ * \internal
++ * \brief Notify peer that the redirecting information 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_redirecting(struct ast_channel *ast, struct misdn_bchannel *bc, int originator)
++{
++ int is_ptmp;
++
++ misdn_copy_redirecting_from_ast(bc, ast);
++ switch (bc->outgoing_colp) {
++ case 1:/* restricted */
++ case 2:/* blocked */
++ bc->redirecting.to.presentation = 1;/* restricted */
++ break;
++ default:
++ break;
++ }
++
++ if (originator != ORG_MISDN) {
++ return;
++ }
++
++ is_ptmp = !misdn_lib_is_ptp(bc->port);
++ if (is_ptmp) {
++ /* Send NOTIFY(call-is-diverting, redirecting.to data) */
++ bc->redirecting.to_changed = 1;
++ bc->notify_description_code = mISDN_NOTIFY_CODE_CALL_IS_DIVERTING;
++ misdn_lib_send_event(bc, EVENT_NOTIFY);
++#if defined(AST_MISDN_ENHANCEMENTS)
++ } else {
++ int match; /* TRUE if the dialed number matches the redirecting to number */
++
++ match = (strcmp(ast->exten, bc->redirecting.to.number) == 0) ? 1 : 0;
++ if (!bc->div_leg_3_tx_pending
++ || !match) {
++ /* Send DivertingLegInformation1 */
++ bc->fac_out.Function = Fac_DivertingLegInformation1;
++ bc->fac_out.u.DivertingLegInformation1.InvokeID = ++misdn_invoke_id;
++ bc->fac_out.u.DivertingLegInformation1.DiversionReason =
++ misdn_to_diversion_reason(bc->redirecting.reason);
++ bc->fac_out.u.DivertingLegInformation1.SubscriptionOption = 2;/* notificationWithDivertedToNr */
++ bc->fac_out.u.DivertingLegInformation1.DivertedToPresent = 1;
++ misdn_PresentedNumberUnscreened_fill(&bc->fac_out.u.DivertingLegInformation1.DivertedTo, &bc->redirecting.to);
++ switch (bc->outgoing_colp) {
++ case 2:/* blocked */
++ /* Block the number going out */
++ bc->fac_out.u.DivertingLegInformation1.DivertedTo.Type = 1;/* presentationRestricted */
++ break;
++ default:
++ break;
++ }
++ print_facility(&bc->fac_out, bc);
++ misdn_lib_send_event(bc, EVENT_FACILITY);
++ }
++ bc->div_leg_3_tx_pending = 0;
++
++ /* Send DivertingLegInformation3 */
++ bc->fac_out.Function = Fac_DivertingLegInformation3;
++ bc->fac_out.u.DivertingLegInformation3.InvokeID = ++misdn_invoke_id;
++ bc->fac_out.u.DivertingLegInformation3.PresentationAllowedIndicator =
++ bc->redirecting.to.presentation == 0 ? 1 : 0;
++ print_facility(&bc->fac_out, bc);
++ misdn_lib_send_event(bc, EVENT_FACILITY);
++#endif /* defined(AST_MISDN_ENHANCEMENTS) */
++ }
++}
++
++
+ /*****************************/
+ /*** AST Indications Start ***/
+ /*****************************/
+@@ -2412,22 +6246,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,87 +6269,212 @@
+ 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;
+ }
+-
++
+ port = newbc->port;
+
+- if ((exceed = add_out_calls(port))) {
+- char tmp[16];
+- snprintf(tmp, sizeof(tmp), "%d", exceed);
+- pbx_builtin_setvar_helper(ast, "MAX_OVERFLOW", tmp);
+- return -1;
++#if defined(AST_MISDN_ENHANCEMENTS)
++ if ((ch->peer = misdn_cc_caller_get(ast))) {
++ chan_misdn_log(3, port, " --> Found CC caller data, peer:%s\n",
++ ch->peer->chan ? "available" : "NULL");
+ }
+-
+- 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) {
++
++ if (ch->record_id != -1) {
++ struct misdn_cc_record *cc_record;
++
++ /* This is a call completion retry call */
++ AST_LIST_LOCK(&misdn_cc_records_db);
++ cc_record = misdn_cc_find_by_id(ch->record_id);
++ if (!cc_record) {
++ AST_LIST_UNLOCK(&misdn_cc_records_db);
++ ast_log(LOG_WARNING, " --> ! misdn_call called on %s, cc_record==NULL\n", ast->name);
++ ast->hangupcause = AST_CAUSE_NORMAL_TEMPORARY_FAILURE;
++ ast_setstate(ast, AST_STATE_DOWN);
++ return -1;
++ }
++
++ /* Setup calling parameters to retry the call. */
++ newbc->dialed = cc_record->redial.dialed;
++ newbc->caller = cc_record->redial.caller;
++ memset(&newbc->redirecting, 0, sizeof(newbc->redirecting));
++ newbc->capability = cc_record->redial.capability;
++ newbc->hdlc = cc_record->redial.hdlc;
++ newbc->sending_complete = 1;
++
++ if (cc_record->ptp) {
++ newbc->fac_out.Function = Fac_CCBS_T_Call;
++ newbc->fac_out.u.CCBS_T_Call.InvokeID = ++misdn_invoke_id;
++ } else {
++ newbc->fac_out.Function = Fac_CCBSCall;
++ newbc->fac_out.u.CCBSCall.InvokeID = ++misdn_invoke_id;
++ newbc->fac_out.u.CCBSCall.CCBSReference = cc_record->mode.ptmp.reference_id;
++ }
++ AST_LIST_UNLOCK(&misdn_cc_records_db);
++
++ ast_copy_string(ast->exten, newbc->dialed.number, sizeof(ast->exten));
++
++ chan_misdn_log(1, port, "* Call completion to: %s\n", newbc->dialed.number);
++ chan_misdn_log(2, port, " --> * tech:%s context:%s\n", ast->name, ast->context);
++ } else
++#endif /* defined(AST_MISDN_ENHANCEMENTS) */
++ {
++ /*
++ * 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 = "";
++ }
++
++ chan_misdn_log(1, port, "* CALL: %s\n", dest);
++ chan_misdn_log(2, port, " --> * dialed:%s tech:%s context:%s\n", args.ext, ast->name, ast->context);
++
+ ast_copy_string(ast->exten, args.ext, sizeof(ast->exten));
+- ast_copy_string(newbc->dad, args.ext, sizeof(newbc->dad));
+- }
++ ast_copy_string(newbc->dialed.number, args.ext, sizeof(newbc->dialed.number));
+
+- ast_copy_string(newbc->rad, S_OR(ast->cid.cid_rdnis, ""), sizeof(newbc->rad));
++ 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);
++ }
+
+- 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));
+- if ( ast->transfercapability == INFO_CAPABILITY_DIGITAL_UNRESTRICTED) {
+- chan_misdn_log(2, port, " --> * Call with flag Digital\n");
+- }
++ 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 */
+- import_ch(ast, newbc, ch);
++ /* update caller screening and presentation */
++ update_config(ch);
+
+- /* Finally The Options Override Everything */
+- if (!ast_strlen_zero(args.opts)) {
+- misdn_set_opt_exec(ast, args.opts);
+- } else {
+- chan_misdn_log(2, port, "NO OPTS GIVEN\n");
+- }
++ /* fill in some ies from channel dialplan variables */
++ import_ch(ast, newbc, ch);
+
+- /*check for bridging*/
+- misdn_cfg_get(0, MISDN_GEN_BRIDGING, &bridging, sizeof(bridging));
+- if (bridging && ch->other_ch) {
++ /* Finally The Options Override Everything */
++ 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);
++ switch (newbc->outgoing_colp) {
++ case 1:/* restricted */
++ case 2:/* blocked */
++ newbc->redirecting.from.presentation = 1;/* restricted */
++ break;
++ default:
++ break;
++ }
++#if defined(AST_MISDN_ENHANCEMENTS)
++ if (newbc->redirecting.from.number[0] && misdn_lib_is_ptp(port)) {
++ /* Create DivertingLegInformation2 facility */
++ newbc->fac_out.Function = Fac_DivertingLegInformation2;
++ newbc->fac_out.u.DivertingLegInformation2.InvokeID = ++misdn_invoke_id;
++ newbc->fac_out.u.DivertingLegInformation2.DiversionCounter =
++ newbc->redirecting.count;
++ newbc->fac_out.u.DivertingLegInformation2.DiversionReason =
++ misdn_to_diversion_reason(newbc->redirecting.reason);
++ newbc->fac_out.u.DivertingLegInformation2.DivertingPresent = 1;
++ misdn_PresentedNumberUnscreened_fill(
++ &newbc->fac_out.u.DivertingLegInformation2.Diverting,
++ &newbc->redirecting.from);
++ switch (newbc->outgoing_colp) {
++ case 2:/* blocked */
++ /* Block the number going out */
++ newbc->fac_out.u.DivertingLegInformation2.Diverting.Type = 1;/* presentationRestricted */
++ break;
++ default:
++ break;
++ }
++ newbc->fac_out.u.DivertingLegInformation2.OriginalCalledPresent = 0;
++ if (1 < newbc->redirecting.count) {
++ newbc->fac_out.u.DivertingLegInformation2.OriginalCalledPresent = 1;
++ newbc->fac_out.u.DivertingLegInformation2.OriginalCalled.Type = 2;/* numberNotAvailableDueToInterworking */
++ }
++
++ /*
++ * Expect a DivertingLegInformation3 to update the COLR of the
++ * redirecting-to party we are attempting to call now.
++ */
++ newbc->div_leg_3_rx_wanted = 1;
++ }
++#endif /* defined(AST_MISDN_ENHANCEMENTS) */
++
++ /*check for bridging*/
++ misdn_cfg_get(0, MISDN_GEN_BRIDGING, &bridging, sizeof(bridging));
++ if (bridging && ch->other_ch) {
+ #ifdef MISDN_1_2
+- chan_misdn_log(1, port, "Disabling EC (aka Pipeline) on both Sides\n");
+- *ch->bc->pipeline = 0;
+- *ch->other_ch->bc->pipeline = 0;
++ chan_misdn_log(1, port, "Disabling EC (aka Pipeline) on both Sides\n");
++ *ch->bc->pipeline = 0;
++ *ch->other_ch->bc->pipeline = 0;
+ #else
+- chan_misdn_log(1, port, "Disabling EC on both Sides\n");
+- ch->bc->ec_enable = 0;
+- ch->other_ch->bc->ec_enable = 0;
++ chan_misdn_log(1, port, "Disabling EC on both Sides\n");
++ ch->bc->ec_enable = 0;
++ ch->other_ch->bc->ec_enable = 0;
+ #endif
++ }
+ }
+
++ 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;
++ }
++
++#if defined(AST_MISDN_ENHANCEMENTS)
++ if (newbc->fac_out.Function != Fac_None) {
++ print_facility(&newbc->fac_out, newbc);
++ }
++#endif /* defined(AST_MISDN_ENHANCEMENTS) */
+ 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;
+@@ -2538,8 +6492,8 @@
+ }
+
+ ch->state = MISDN_CALLING;
+-
+- return 0;
++
++ return 0;
+ }
+
+
+@@ -2551,9 +6505,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,11 +6540,42 @@
+ 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;
+ }
+
++ switch (p->bc->outgoing_colp) {
++ case 1:/* restricted */
++ case 2:/* blocked */
++ p->bc->connected.presentation = 1;/* restricted */
++ break;
++ default:
++ break;
++ }
++
++#if defined(AST_MISDN_ENHANCEMENTS)
++ if (p->bc->div_leg_3_tx_pending) {
++ p->bc->div_leg_3_tx_pending = 0;
++
++ /* Send DivertingLegInformation3 */
++ p->bc->fac_out.Function = Fac_DivertingLegInformation3;
++ p->bc->fac_out.u.DivertingLegInformation3.InvokeID = ++misdn_invoke_id;
++ p->bc->fac_out.u.DivertingLegInformation3.PresentationAllowedIndicator =
++ (p->bc->connected.presentation == 0) ? 1 : 0;
++ print_facility(&p->bc->fac_out, p->bc);
++ }
++#endif /* defined(AST_MISDN_ENHANCEMENTS) */
+ misdn_lib_send_event(p->bc, EVENT_CONNECT);
+ start_bc_tones(p);
+
+@@ -2615,13 +6600,13 @@
+
+ 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 ) {
++
++ switch (p->state) {
+ case MISDN_CALLING:
+ if (strlen(bc->infos_pending) < sizeof(bc->infos_pending) - 1) {
+ strncat(bc->infos_pending, buf, sizeof(bc->infos_pending) - strlen(bc->infos_pending) - 1);
+@@ -2629,15 +6614,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;
+ }
+@@ -2673,48 +6658,48 @@
+ {
+ struct chan_list *p;
+
+- if (!ast || ! (p=MISDN_ASTERISK_TECH_PVT(ast))) {
++ if (!ast || !(p = MISDN_ASTERISK_TECH_PVT(ast))) {
+ ast_log(LOG_WARNING, "Returned -1 in misdn_indication\n");
+ return -1;
+ }
+-
+- if (!p->bc ) {
++
++ 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;
+ if (p->state != MISDN_CONNECTED) {
+ start_bc_tones(p);
+- misdn_lib_send_event( p->bc, EVENT_DISCONNECT);
++ misdn_lib_send_event(p->bc, EVENT_DISCONNECT);
+ } else {
+ chan_misdn_log(-1, p->bc->port, " --> !! Got Busy in Connected State !?! ast:%s\n", ast->name);
+ }
+ 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);
+- misdn_lib_send_event( p->bc, EVENT_ALERTING);
++ 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)) {
+@@ -2728,7 +6713,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,39 +6724,39 @@
+ }
+ 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);
+- misdn_lib_send_event( p->bc, EVENT_PROGRESS);
++ 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);
+- misdn_lib_send_event( p->bc, EVENT_PROCEEDING);
++ 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);
+- misdn_lib_send_event( p->bc, EVENT_DISCONNECT);
++ misdn_lib_send_event(p->bc, EVENT_DISCONNECT);
+
+ if (p->bc->nt) {
+ hanguptone_indicate(p);
+ }
+ 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 +6765,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_update_redirecting(ast, p->bc, p->originator);
++ 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 +6809,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 +6823,16 @@
+ MISDN_ASTERISK_TECH_PVT(ast) = NULL;
+ p->ast = NULL;
+
+- if (ast->_state == AST_STATE_RESERVED ||
+- p->state == MISDN_NOTHING ||
+- p->state == MISDN_HOLDED ||
+- p->state == MISDN_HOLD_DISCONNECT ) {
++ if (ast->_state == AST_STATE_RESERVED ||
++ p->state == MISDN_NOTHING ||
++ p->state == MISDN_HOLDED ||
++ p->state == MISDN_HOLD_DISCONNECT) {
+
+- CLEAN_CH:
++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]);
+@@ -2872,20 +6868,27 @@
+ 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;
+ }
+ 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:
+ 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 INCOMING_SETUP state.. no other events happened\n");
+@@ -2970,7 +6973,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);
+@@ -2980,6 +6983,13 @@
+
+ p->state = MISDN_CLEANING;
+
++#if defined(AST_MISDN_ENHANCEMENTS)
++ if (p->peer) {
++ ao2_ref(p->peer, -1);
++ p->peer = NULL;
++ }
++#endif /* AST_MISDN_ENHANCEMENTS */
++
+ chan_misdn_log(3, bc->port, " --> Channel: %s hanguped new state:%s\n", ast->name, misdn_get_ch_state(p));
+
+ return 0;
+@@ -2989,7 +6999,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 +7010,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 +7045,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");
+@@ -3044,12 +7054,14 @@
+ case 2:
+ ast_verb(3, "Not redirecting %s to fax extension, nojump is set.\n", ast->name);
+ break;
++ default:
++ break;
+ }
+ } else {
+ 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 +7094,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;
+ }
+@@ -3100,7 +7113,6 @@
+ chan_misdn_log(2, tmp->bc->port, "misdn_read: Pipe closed, hanging up\n");
+ return NULL;
+ }
+-
+ } else {
+ return NULL;
+ }
+@@ -3151,7 +7163,7 @@
+ {
+ struct chan_list *ch;
+ int i = 0;
+-
++
+ if (!ast || !(ch = MISDN_ASTERISK_TECH_PVT(ast))) {
+ return -1;
+ }
+@@ -3160,12 +7172,12 @@
+ chan_misdn_log(7, 0, "misdn_write: Returning because holded\n");
+ return 0;
+ }
+-
+- if (!ch->bc ) {
++
++ 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 +7188,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 ) {
++
++ 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,10 +7215,11 @@
+ 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;
++ int i;
++ int max = 5 > frame->samples ? frame->samples : 5;
+
+ ast_debug(1, "write2mISDN %p %d bytes: ", p, frame->samples);
+
+@@ -3222,9 +7235,11 @@
+ break;
+ default:
+ 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);
++ 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,24 +7256,20 @@
+ cb_log(0, ch->bc->port, "Misdn Jitterbuffer Overflow.\n");
+ }
+ }
+-
++
+ } else {
+- /*transmit without jitterbuffer*/
++ /* transmit without jitterbuffer */
+ i = misdn_lib_tx2misdn_frm(ch->bc, frame->data.ptr, frame->samples);
+ }
+
+ 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 +7277,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,13 +7305,17 @@
+
+ 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);
+-
+- if (! (flags & AST_BRIDGE_DTMF_CHANNEL_0) ) {
++ 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;
+ }
+
+- if (! (flags & AST_BRIDGE_DTMF_CHANNEL_1) ) {
++ if (!(flags & AST_BRIDGE_DTMF_CHANNEL_1)) {
+ ch2->ignore_dtmf = 1;
+ }
+
+@@ -3317,33 +7332,34 @@
+ 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
++ } else {
+ chan_misdn_log(4, ch1->bc->port, "Read Frame Control class:%d\n", f->subclass);
++ }
+
+ *fo = f;
+ *rc = who;
+ break;
+ }
+-
+- if ( f->frametype == AST_FRAME_DTMF ) {
++
++ if (f->frametype == AST_FRAME_DTMF) {
+ chan_misdn_log(1, 0, "Read DTMF %d from %s\n", f->subclass, who->exten);
+
+ *fo = f;
+ *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 +7387,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 +7445,7 @@
+
+ cl->notxtone = 1;
+ cl->norxtone = 1;
+-
++
+ return 0;
+ }
+
+@@ -3438,59 +7454,121 @@
+ {
+ 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;
+ cl->need_busy = 1;
+ cl->overlap_dial_task = -1;
++#if defined(AST_MISDN_ENHANCEMENTS)
++ cl->record_id = -1;
++#endif /* defined(AST_MISDN_ENHANCEMENTS) */
+
+ return cl;
+ }
+
+ static struct ast_channel *misdn_request(const char *type, int format, void *data, int *cause)
+ {
+- struct ast_channel *tmp = NULL;
++ struct ast_channel *ast;
+ 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;
++#if defined(AST_MISDN_ENHANCEMENTS)
++ int cc_retry_call = 0; /* TRUE if this is a call completion retry call */
++ long record_id = -1;
++ struct misdn_cc_record *cc_record;
++ const char *err_msg;
++#endif /* defined(AST_MISDN_ENHANCEMENTS) */
++ 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]])
++ * Dial(mISDN/cc/cc-record-id)
++ *
++ * 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, ':'))) {
++#if defined(AST_MISDN_ENHANCEMENTS)
++ } else if (strcmp(args.intf, "cc") == 0) {
++ cc_retry_call = 1;
++#endif /* defined(AST_MISDN_ENHANCEMENTS) */
++ } 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 defined(AST_MISDN_ENHANCEMENTS)
++ if (cc_retry_call) {
++ if (ast_strlen_zero(args.ext)) {
++ ast_log(LOG_WARNING, " --> ! IND : Dial(%s) WITHOUT cc-record-id, check extensions.conf\n", dial_str);
++ return NULL;
++ }
++ if (!isdigit(*args.ext)) {
++ ast_log(LOG_WARNING, " --> ! IND : Dial(%s) cc-record-id must be a number.\n", dial_str);
++ return NULL;
++ }
++ record_id = atol(args.ext);
++
++ AST_LIST_LOCK(&misdn_cc_records_db);
++ cc_record = misdn_cc_find_by_id(record_id);
++ if (!cc_record) {
++ AST_LIST_UNLOCK(&misdn_cc_records_db);
++ err_msg = misdn_cc_record_not_found;
++ ast_log(LOG_WARNING, " --> ! IND : Dial(%s) %s.\n", dial_str, err_msg);
++ return NULL;
++ }
++ if (!cc_record->activated) {
++ AST_LIST_UNLOCK(&misdn_cc_records_db);
++ err_msg = "Call completion has not been activated";
++ ast_log(LOG_WARNING, " --> ! IND : Dial(%s) %s.\n", dial_str, err_msg);
++ return NULL;
++ }
++ port = cc_record->port;
++ AST_LIST_UNLOCK(&misdn_cc_records_db);
++ }
++#endif /* defined(AST_MISDN_ENHANCEMENTS) */
++
+ if (misdn_cfg_is_group_method(group, METHOD_STANDARD_DEC)) {
+ chan_misdn_log(4, port, " --> STARTING STANDARD DEC...\n");
+ dec = 1;
+@@ -3524,9 +7602,10 @@
+ if (port >= port_start) {
+ next_chan = 1;
+ }
+-
++
+ if (port <= port_start && next_chan) {
+- int maxbchans=misdn_lib_get_maxchans(port);
++ int maxbchans = misdn_lib_get_maxchans(port);
++
+ if (++robin_channel >= maxbchans) {
+ robin_channel = 1;
+ }
+@@ -3538,13 +7617,14 @@
+ if (!strcasecmp(cfg_group, group)) {
+ int port_up;
+ int check;
++
+ misdn_cfg_get(port, MISDN_CFG_PMP_L1_CHECK, &check, sizeof(check));
+ port_up = misdn_lib_port_up(port, check);
+
+ 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,37 +7644,38 @@
+ }
+ }
+ } 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)) {
+-
++ port = misdn_cfg_get_next_port(port)) {
+ misdn_cfg_get(port, MISDN_CFG_GROUPNAME, cfg_group, sizeof(cfg_group));
+
+ chan_misdn_log(3, port, "Group [%s] Port [%d]\n", group, port);
+ if (!strcasecmp(cfg_group, group)) {
+ int port_up;
+ int check;
++
+ misdn_cfg_get(port, MISDN_CFG_PMP_L1_CHECK, &check, sizeof(check));
+ port_up = misdn_lib_port_up(port, check);
+
+ 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,
+- "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"
+- , group);
++ 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",
++ group);
+ return NULL;
+ }
+ } else {
+@@ -3603,42 +7684,48 @@
+ 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_ERROR, "Could not create call record for Dial(%s)\n", dial_str);
++ return NULL;
++ }
+ cl->bc = newbc;
+-
+- tmp = misdn_new(cl, AST_STATE_RESERVED, ext, NULL, format, port, channel);
+- if (!tmp) {
+- ast_log(LOG_ERROR, "Could not create Asterisk object\n");
++
++ ast = misdn_new(cl, AST_STATE_RESERVED, args.ext, NULL, format, port, channel);
++ if (!ast) {
++ ast_log(LOG_ERROR, "Could not create Asterisk channel for Dial(%s)\n", dial_str);
+ return NULL;
+ }
++ cl->ast = ast;
+
+- cl->ast = tmp;
+-
++#if defined(AST_MISDN_ENHANCEMENTS)
++ cl->record_id = record_id;
++#endif /* defined(AST_MISDN_ENHANCEMENTS) */
++
+ /* 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;
++
++ return ast;
+ }
+
+
+ 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,19 +7733,19 @@
+ ast_log(LOG_WARNING, "No chan_list but send_text request?\n");
+ return -1;
+ }
+-
++
+ return 0;
+ }
+
+ static struct ast_channel_tech misdn_tech = {
+- .type = "mISDN",
++ .type = misdn_type,
+ .description = "Channel driver for mISDN Support (Bri/Pri)",
+ .capabilities = AST_FORMAT_ALAW ,
+ .requester = misdn_request,
+ .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,
+@@ -3670,7 +7757,7 @@
+ };
+
+ static struct ast_channel_tech misdn_tech_wo_bridge = {
+- .type = "mISDN",
++ .type = misdn_type,
+ .description = "Channel driver for mISDN Support (Bri/Pri)",
+ .capabilities = AST_FORMAT_ALAW ,
+ .requester = misdn_request,
+@@ -3690,16 +7777,17 @@
+
+ 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);
+ char newname[255];
++
+ for (; tmp_port > 0; tmp_port = misdn_cfg_get_next_port(tmp_port)) {
+ 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;
+@@ -3708,7 +7796,9 @@
+ snprintf(newname, sizeof(newname), "%s/%d-", misdn_type, chan_offset + c);
+ if (strncmp(tmp->name, newname, strlen(newname))) {
+ snprintf(newname, sizeof(newname), "%s/%d-u%d", misdn_type, chan_offset + c, glob_channel++);
++ ast_channel_lock(tmp);
+ ast_change_name(tmp, newname);
++ ast_channel_unlock(tmp);
+ chan_misdn_log(3, port, " --> updating channel name to [%s]\n", tmp->name);
+ }
+ }
+@@ -3737,7 +7827,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,11 +7835,10 @@
+ tmp->rawreadformat = format;
+ tmp->writeformat = format;
+ tmp->rawwriteformat = format;
+-
++
+ tmp->tech_pvt = chlist;
+
+ misdn_cfg_get(0, MISDN_GEN_BRIDGING, &bridging, sizeof(bridging));
+-
+ tmp->tech = bridging ? &misdn_tech : &misdn_tech_wo_bridge;
+
+ tmp->writeformat = format;
+@@ -3779,20 +7868,25 @@
+ } else {
+ chan_misdn_log(-1, 0, "Unable to allocate channel structure\n");
+ }
+-
++
+ return tmp;
+ }
+
+ static struct chan_list *find_chan_by_bc(struct chan_list *list, struct misdn_bchannel *bc)
+ {
+ struct chan_list *help = list;
++
+ for (; help; help = help->next) {
+ 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;
+ }
+@@ -3800,13 +7894,14 @@
+ static struct chan_list *find_chan_by_pid(struct chan_list *list, int pid)
+ {
+ struct chan_list *help = list;
++
+ for (; help; help = help->next) {
+ 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;
+ }
+@@ -3819,21 +7914,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 +7953,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 +7982,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 +7996,7 @@
+ return;
+ }
+ }
+-
++
+ ast_mutex_unlock(&cl_te_lock);
+ }
+
+@@ -3902,7 +8005,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;
+
+@@ -3911,12 +8014,14 @@
+
+ static void hangup_chan(struct chan_list *ch)
+ {
+- int port = ch ? (ch->bc ? ch->bc->port : 0) : 0;
++ int port;
++
+ if (!ch) {
+ cb_log(1, 0, "Cannot hangup chan, no ch\n");
+ return;
+ }
+
++ port = ch->bc ? ch->bc->port : 0;
+ cb_log(5, port, "hangup_chan called\n");
+
+ if (ch->need_hangup) {
+@@ -3948,25 +8053,24 @@
+ }
+
+ /** 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 chan_list *ch;
++ struct ast_channel *ast;
+
+ 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;
+ }
+
+- 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 {
+@@ -3984,35 +8088,39 @@
+ }
+
+ if (ch->originator == ORG_AST) {
+- misdn_out_calls[bc->port]--;
++ --misdn_out_calls[bc->port];
+ } else {
+- misdn_in_calls[bc->port]--;
++ --misdn_in_calls[bc->port];
+ }
+
+- if (ch) {
+- close(ch->pipe[0]);
+- close(ch->pipe[1]);
++ 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;
++ ast = ch->ast;
++ 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_free(ch);
++
+ ast_mutex_unlock(&release_lock);
+-/*** release end **/
+ }
+
+ static void misdn_transfer_bc(struct chan_list *tmp_ch, struct chan_list *holded_chan)
+@@ -4040,25 +8148,28 @@
+
+ if (!ch->noautorespond_on_setup) {
+ if (bc->nt) {
+- int ret;
+- ret = misdn_lib_send_event(bc, EVENT_SETUP_ACKNOWLEDGE );
++ misdn_lib_send_event(bc, EVENT_SETUP_ACKNOWLEDGE);
+ } else {
+- int ret;
+- if ( misdn_lib_is_ptp(bc->port)) {
+- ret = misdn_lib_send_event(bc, EVENT_SETUP_ACKNOWLEDGE );
++ if (misdn_lib_is_ptp(bc->port)) {
++ misdn_lib_send_event(bc, EVENT_SETUP_ACKNOWLEDGE);
+ } else {
+- ret = misdn_lib_send_event(bc, EVENT_PROCEEDING );
++ misdn_lib_send_event(bc, EVENT_PROCEEDING);
+ }
+ }
+ } else {
+ 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);
+-
+- if (!ast_canmatch_extension(ast, ast->context, ast->exten, 1, bc->oad) || pbx_start_chan(ch) < 0) {
++ 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 (!ast_canmatch_extension(ast, ast->context, ast->exten, 1, bc->caller.number) || pbx_start_chan(ch) < 0) {
+ ast = NULL;
+ bc->out_cause = AST_CAUSE_UNALLOCATED;
+ hangup_chan(ch);
+@@ -4066,9 +8177,9 @@
+
+ misdn_lib_send_event(bc, bc->nt ? EVENT_RELEASE_COMPLETE : EVENT_DISCONNECT);
+ }
+-
+-
+- while (!ast_strlen_zero(predial) ) {
++
++
++ while (!ast_strlen_zero(predial)) {
+ fr.frametype = AST_FRAME_DTMF;
+ fr.subclass = *predial;
+ fr.src = NULL;
+@@ -4079,7 +8190,7 @@
+ fr.offset = 0;
+ fr.delivery = ast_tv(0,0);
+
+- if (ch->ast && MISDN_ASTERISK_PVT(ch->ast) && MISDN_ASTERISK_TECH_PVT(ch->ast)) {
++ if (ch->ast && MISDN_ASTERISK_TECH_PVT(ch->ast)) {
+ ast_queue_frame(ch->ast, &fr);
+ }
+ predial++;
+@@ -4119,7 +8230,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;
+@@ -4134,11 +8245,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;
+ }
+ }
+@@ -4185,6 +8296,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);
+@@ -4211,7 +8323,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]++;
+
+@@ -4219,14 +8331,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]) {
+@@ -4235,11 +8347,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");
+@@ -4252,36 +8365,967 @@
+ }
+ }
+
+-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]) {
++ misdn_lib_send_event(bc, EVENT_SETUP_ACKNOWLEDGE);
++ if (bc->nt && !bc->dialed.number[0]) {
+ dialtone_indicate(ch);
+ }
+ }
+
++#if defined(AST_MISDN_ENHANCEMENTS)
++/*!
++ * \internal
++ * \brief Handle the FACILITY CCBSStatusRequest message.
++ *
++ * \param port Logical port number.
++ * \param facility Facility ie contents.
++ *
++ * \return Nothing
++ */
++static void misdn_cc_handle_ccbs_status_request(int port, const struct FacParm *facility)
++{
++ struct misdn_cc_record *cc_record;
++ struct misdn_bchannel dummy;
+
++ switch (facility->u.CCBSStatusRequest.ComponentType) {
++ case FacComponent_Invoke:
++ /* Build message */
++ misdn_make_dummy(&dummy, port, 0, misdn_lib_port_is_nt(port), 0);
++ dummy.fac_out.Function = Fac_CCBSStatusRequest;
++ dummy.fac_out.u.CCBSStatusRequest.InvokeID = facility->u.CCBSStatusRequest.InvokeID;
++ dummy.fac_out.u.CCBSStatusRequest.ComponentType = FacComponent_Result;
++
++ /* Answer User-A free question */
++ AST_LIST_LOCK(&misdn_cc_records_db);
++ cc_record = misdn_cc_find_by_reference(port, facility->u.CCBSStatusRequest.Component.Invoke.CCBSReference);
++ if (cc_record) {
++ dummy.fac_out.u.CCBSStatusRequest.Component.Result.Free = cc_record->party_a_free;
++ } else {
++ /* No record so say User-A is free */
++ dummy.fac_out.u.CCBSStatusRequest.Component.Result.Free = 1;
++ }
++ AST_LIST_UNLOCK(&misdn_cc_records_db);
++
++ /* Send message */
++ print_facility(&dummy.fac_out, &dummy);
++ misdn_lib_send_event(&dummy, EVENT_FACILITY);
++ break;
++
++ default:
++ chan_misdn_log(0, port, " --> not yet handled: facility type:0x%04X\n", facility->Function);
++ break;
++ }
++}
++#endif /* defined(AST_MISDN_ENHANCEMENTS) */
++
++#if defined(AST_MISDN_ENHANCEMENTS)
++/*!
++ * \internal
++ * \brief Start a PBX to notify that User-B is available.
++ *
++ * \param record_id Call completion record ID
++ * \param notify Dialplan location to start processing.
++ *
++ * \return Nothing
++ */
++static void misdn_cc_pbx_notify(long record_id, const struct misdn_cc_notify *notify)
++{
++ struct ast_channel *chan;
++ char id_str[32];
++
++ static unsigned short sequence = 0;
++
++ /* Create a channel to notify with */
++ snprintf(id_str, sizeof(id_str), "%ld", record_id);
++ chan = ast_channel_alloc(0, AST_STATE_DOWN, id_str, NULL, NULL,
++ notify->exten, notify->context, 0,
++ "mISDN-CC/%ld-%X", record_id, (unsigned) ++sequence);
++ if (!chan) {
++ ast_log(LOG_ERROR, "Unable to allocate channel!\n");
++ return;
++ }
++ chan->priority = notify->priority;
++ if (chan->cid.cid_dnid) {
++ ast_free(chan->cid.cid_dnid);
++ }
++ chan->cid.cid_dnid = ast_strdup(notify->exten);
++
++ if (ast_pbx_start(chan)) {
++ ast_log(LOG_WARNING, "Unable to start pbx channel %s!\n", chan->name);
++ ast_channel_release(chan);
++ } else {
++ ast_verb(1, "Started pbx for call completion notify channel %s\n", chan->name);
++ }
++}
++#endif /* defined(AST_MISDN_ENHANCEMENTS) */
++
++#if defined(AST_MISDN_ENHANCEMENTS)
++/*!
++ * \internal
++ * \brief Handle the FACILITY CCBS_T_RemoteUserFree message.
++ *
++ * \param bc B channel control structure message came in on
++ *
++ * \return Nothing
++ */
++static void misdn_cc_handle_T_remote_user_free(struct misdn_bchannel *bc)
++{
++ struct misdn_cc_record *cc_record;
++ struct misdn_cc_notify notify;
++ long record_id;
++
++ AST_LIST_LOCK(&misdn_cc_records_db);
++ cc_record = misdn_cc_find_by_bc(bc);
++ if (cc_record) {
++ if (cc_record->party_a_free) {
++ notify = cc_record->remote_user_free;
++ } else {
++ /* Send CCBS_T_Suspend message */
++ bc->fac_out.Function = Fac_CCBS_T_Suspend;
++ bc->fac_out.u.CCBS_T_Suspend.InvokeID = ++misdn_invoke_id;
++ print_facility(&bc->fac_out, bc);
++ misdn_lib_send_event(bc, EVENT_FACILITY);
++
++ notify = cc_record->b_free;
++ }
++ record_id = cc_record->record_id;
++ AST_LIST_UNLOCK(&misdn_cc_records_db);
++ if (notify.context[0]) {
++ /* Party A is free or B-Free notify has been setup. */
++ misdn_cc_pbx_notify(record_id, &notify);
++ }
++ } else {
++ AST_LIST_UNLOCK(&misdn_cc_records_db);
++ }
++}
++#endif /* defined(AST_MISDN_ENHANCEMENTS) */
++
++#if defined(AST_MISDN_ENHANCEMENTS)
++/*!
++ * \internal
++ * \brief Handle the FACILITY CCBSRemoteUserFree message.
++ *
++ * \param port Logical port number.
++ * \param facility Facility ie contents.
++ *
++ * \return Nothing
++ */
++static void misdn_cc_handle_remote_user_free(int port, const struct FacParm *facility)
++{
++ struct misdn_cc_record *cc_record;
++ struct misdn_cc_notify notify;
++ long record_id;
++
++ AST_LIST_LOCK(&misdn_cc_records_db);
++ cc_record = misdn_cc_find_by_reference(port, facility->u.CCBSRemoteUserFree.CCBSReference);
++ if (cc_record) {
++ notify = cc_record->remote_user_free;
++ record_id = cc_record->record_id;
++ AST_LIST_UNLOCK(&misdn_cc_records_db);
++ misdn_cc_pbx_notify(record_id, &notify);
++ } else {
++ AST_LIST_UNLOCK(&misdn_cc_records_db);
++ }
++}
++#endif /* defined(AST_MISDN_ENHANCEMENTS) */
++
++#if defined(AST_MISDN_ENHANCEMENTS)
++/*!
++ * \internal
++ * \brief Handle the FACILITY CCBSBFree message.
++ *
++ * \param port Logical port number.
++ * \param facility Facility ie contents.
++ *
++ * \return Nothing
++ */
++static void misdn_cc_handle_b_free(int port, const struct FacParm *facility)
++{
++ struct misdn_cc_record *cc_record;
++ struct misdn_cc_notify notify;
++ long record_id;
++
++ AST_LIST_LOCK(&misdn_cc_records_db);
++ cc_record = misdn_cc_find_by_reference(port, facility->u.CCBSBFree.CCBSReference);
++ if (cc_record && cc_record->b_free.context[0]) {
++ /* B-Free notify has been setup. */
++ notify = cc_record->b_free;
++ record_id = cc_record->record_id;
++ AST_LIST_UNLOCK(&misdn_cc_records_db);
++ misdn_cc_pbx_notify(record_id, &notify);
++ } else {
++ AST_LIST_UNLOCK(&misdn_cc_records_db);
++ }
++}
++#endif /* defined(AST_MISDN_ENHANCEMENTS) */
++
++/*!
++ * \internal
++ * \brief Handle the incoming facility ie contents
++ *
++ * \param event Message type facility ie came in on
++ * \param bc B channel control structure message came in on
++ * \param ch Associated channel call record
++ *
++ * \return Nothing
++ */
++static void misdn_facility_ie_handler(enum event_e event, struct misdn_bchannel *bc, struct chan_list *ch)
++{
++#if defined(AST_MISDN_ENHANCEMENTS)
++ const char *diagnostic_msg;
++ struct misdn_cc_record *cc_record;
++ char buf[32];
++ struct misdn_party_id party_id;
++ long new_record_id;
++#endif /* defined(AST_MISDN_ENHANCEMENTS) */
++
++ print_facility(&bc->fac_in, bc);
++ switch (bc->fac_in.Function) {
++#if defined(AST_MISDN_ENHANCEMENTS)
++ case Fac_ActivationDiversion:
++ switch (bc->fac_in.u.ActivationDiversion.ComponentType) {
++ case FacComponent_Result:
++ /* Positive ACK to activation */
++ /* We don't handle this yet */
++ break;
++ default:
++ chan_misdn_log(0, bc->port," --> not yet handled: facility type:0x%04X\n",
++ bc->fac_in.Function);
++ break;
++ }
++ break;
++ case Fac_DeactivationDiversion:
++ switch (bc->fac_in.u.DeactivationDiversion.ComponentType) {
++ case FacComponent_Result:
++ /* Positive ACK to deactivation */
++ /* We don't handle this yet */
++ break;
++ default:
++ chan_misdn_log(0, bc->port," --> not yet handled: facility type:0x%04X\n",
++ bc->fac_in.Function);
++ break;
++ }
++ break;
++ case Fac_ActivationStatusNotificationDiv:
++ /* Sent to other MSN numbers on the line when a user activates call forwarding. */
++ /* Sent in the first call control message of an outgoing call from the served user. */
++ /* We do not have anything to do for this message. */
++ break;
++ case Fac_DeactivationStatusNotificationDiv:
++ /* Sent to other MSN numbers on the line when a user deactivates call forwarding. */
++ /* We do not have anything to do for this message. */
++ break;
++#if 0 /* We don't handle this yet */
++ case Fac_InterrogationDiversion:
++ /* We don't handle this yet */
++ break;
++ case Fac_InterrogateServedUserNumbers:
++ /* We don't handle this yet */
++ break;
++#endif /* We don't handle this yet */
++ case Fac_DiversionInformation:
++ /* Sent to the served user when a call is forwarded. */
++ /* We do not have anything to do for this message. */
++ break;
++ case Fac_CallDeflection:
++ if (ch && ch->ast) {
++ switch (bc->fac_in.u.CallDeflection.ComponentType) {
++ case FacComponent_Invoke:
++ ast_copy_string(bc->redirecting.from.number, bc->dialed.number,
++ sizeof(bc->redirecting.from.number));
++ bc->redirecting.from.name[0] = 0;
++ bc->redirecting.from.number_plan = bc->dialed.number_plan;
++ bc->redirecting.from.number_type = bc->dialed.number_type;
++ bc->redirecting.from.screening = 0;/* Unscreened */
++ if (bc->fac_in.u.CallDeflection.Component.Invoke.PresentationAllowedToDivertedToUserPresent) {
++ bc->redirecting.from.presentation =
++ bc->fac_in.u.CallDeflection.Component.Invoke.PresentationAllowedToDivertedToUser
++ ? 0 /* Allowed */ : 1 /* Restricted */;
++ } else {
++ bc->redirecting.from.presentation = 0;/* Allowed */
++ }
++
++ /* Add configured prefix to the call deflection number */
++ memset(&party_id, 0, sizeof(party_id));
++ misdn_PartyNumber_extract(&party_id,
++ &bc->fac_in.u.CallDeflection.Component.Invoke.Deflection.Party);
++ misdn_add_number_prefix(bc->port, party_id.number_type,
++ party_id.number, sizeof(party_id.number));
++ //party_id.presentation = 0;/* Allowed */
++ //party_id.screening = 0;/* Unscreened */
++ bc->redirecting.to = party_id;
++
++ ++bc->redirecting.count;
++ bc->redirecting.reason = mISDN_REDIRECTING_REASON_DEFLECTION;
++
++ misdn_copy_redirecting_to_ast(ch->ast, &bc->redirecting);
++ ast_string_field_set(ch->ast, call_forward, bc->redirecting.to.number);
++
++ /* Send back positive ACK */
++ bc->fac_out.Function = Fac_CallDeflection;
++ bc->fac_out.u.CallDeflection.InvokeID = bc->fac_in.u.CallDeflection.InvokeID;
++ bc->fac_out.u.CallDeflection.ComponentType = FacComponent_Result;
++ print_facility(&bc->fac_out, bc);
++ misdn_lib_send_event(bc, EVENT_DISCONNECT);
++
++ /* This line is BUSY to further attempts by this dialing attempt. */
++ ast_queue_control(ch->ast, AST_CONTROL_BUSY);
++ break;
++
++ case FacComponent_Result:
++ /* Positive ACK to call deflection */
++ /*
++ * Sent in DISCONNECT or FACILITY message depending upon network option.
++ * It is in the FACILITY message if the call is still offered to the user
++ * while trying to alert the deflected to party.
++ */
++ /* Ignore the ACK */
++ break;
++
++ default:
++ break;
++ }
++ }
++ break;
++#if 0 /* We don't handle this yet */
++ case Fac_CallRerouteing:
++ /* Private-Public ISDN interworking message */
++ /* We don't handle this yet */
++ break;
++#endif /* We don't handle this yet */
++ case Fac_DivertingLegInformation1:
++ /* Private-Public ISDN interworking message */
++ bc->div_leg_3_rx_wanted = 0;
++ if (ch && ch->ast) {
++ bc->redirecting.reason =
++ diversion_reason_to_misdn(bc->fac_in.u.DivertingLegInformation1.DiversionReason);
++ if (bc->fac_in.u.DivertingLegInformation1.DivertedToPresent) {
++ misdn_PresentedNumberUnscreened_extract(&bc->redirecting.to,
++ &bc->fac_in.u.DivertingLegInformation1.DivertedTo);
++
++ /* Add configured prefix to redirecting.to.number */
++ misdn_add_number_prefix(bc->port, bc->redirecting.to.number_type,
++ bc->redirecting.to.number, sizeof(bc->redirecting.to.number));
++ } else {
++ bc->redirecting.to.number[0] = '\0';
++ bc->redirecting.to.number_plan = NUMPLAN_ISDN;
++ bc->redirecting.to.number_type = NUMTYPE_UNKNOWN;
++ bc->redirecting.to.presentation = 1;/* restricted */
++ bc->redirecting.to.screening = 0;/* unscreened */
++ }
++ misdn_copy_redirecting_to_ast(ch->ast, &bc->redirecting);
++ bc->div_leg_3_rx_wanted = 1;
++ }
++ break;
++ case Fac_DivertingLegInformation2:
++ /* Private-Public ISDN interworking message */
++ switch (event) {
++ case EVENT_SETUP:
++ /* Comes in on a SETUP with redirecting.from information */
++ bc->div_leg_3_tx_pending = 1;
++ if (ch && ch->ast) {
++ /*
++ * Setup the redirecting.to informtion so we can identify
++ * if the user wants to manually supply the COLR for this
++ * redirected to number if further redirects could happen.
++ *
++ * All the user needs to do is set the REDIRECTING(to-pres)
++ * to the COLR and REDIRECTING(to-num) = ${EXTEN} to be safe
++ * after determining that the incoming call was redirected by
++ * checking if there is a REDIRECTING(from-num).
++ */
++ ast_copy_string(bc->redirecting.to.number, bc->dialed.number,
++ sizeof(bc->redirecting.to.number));
++ bc->redirecting.to.number_plan = bc->dialed.number_plan;
++ bc->redirecting.to.number_type = bc->dialed.number_type;
++ bc->redirecting.to.presentation = 1;/* restricted */
++ bc->redirecting.to.screening = 0;/* unscreened */
++
++ bc->redirecting.reason =
++ diversion_reason_to_misdn(bc->fac_in.u.DivertingLegInformation2.DiversionReason);
++ bc->redirecting.count = bc->fac_in.u.DivertingLegInformation2.DiversionCounter;
++ if (bc->fac_in.u.DivertingLegInformation2.DivertingPresent) {
++ /* This information is redundant if there was a redirecting ie in the SETUP. */
++ misdn_PresentedNumberUnscreened_extract(&bc->redirecting.from,
++ &bc->fac_in.u.DivertingLegInformation2.Diverting);
++
++ /* 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));
++ }
++#if 0
++ if (bc->fac_in.u.DivertingLegInformation2.OriginalCalledPresent) {
++ /* We have no place to put the OriginalCalled number */
++ }
++#endif
++ misdn_copy_redirecting_to_ast(ch->ast, &bc->redirecting);
++ }
++ break;
++ default:
++ chan_misdn_log(0, bc->port," --> Expected in a SETUP message: facility type:0x%04X\n",
++ bc->fac_in.Function);
++ break;
++ }
++ break;
++ case Fac_DivertingLegInformation3:
++ /* Private-Public ISDN interworking message */
++ if (bc->div_leg_3_rx_wanted) {
++ bc->div_leg_3_rx_wanted = 0;
++
++ if (ch && ch->ast) {
++ ch->ast->redirecting.to.number_presentation =
++ bc->fac_in.u.DivertingLegInformation3.PresentationAllowedIndicator
++ ? AST_PRES_ALLOWED | AST_PRES_USER_NUMBER_UNSCREENED
++ : AST_PRES_RESTRICTED | AST_PRES_USER_NUMBER_UNSCREENED;
++ ast_channel_queue_redirecting_update(ch->ast, &ch->ast->redirecting);
++ }
++ }
++ break;
++
++#else /* !defined(AST_MISDN_ENHANCEMENTS) */
++
++ case Fac_CD:
++ if (ch && ch->ast) {
++ ast_copy_string(bc->redirecting.from.number, bc->dialed.number,
++ sizeof(bc->redirecting.from.number));
++ bc->redirecting.from.name[0] = 0;
++ bc->redirecting.from.number_plan = bc->dialed.number_plan;
++ bc->redirecting.from.number_type = bc->dialed.number_type;
++ bc->redirecting.from.screening = 0;/* Unscreened */
++ bc->redirecting.from.presentation =
++ bc->fac_in.u.CDeflection.PresentationAllowed
++ ? 0 /* Allowed */ : 1 /* Restricted */;
++
++ ast_copy_string(bc->redirecting.to.number,
++ (char *) bc->fac_in.u.CDeflection.DeflectedToNumber,
++ sizeof(bc->redirecting.to.number));
++ bc->redirecting.to.name[0] = 0;
++ bc->redirecting.to.number_plan = NUMPLAN_UNKNOWN;
++ bc->redirecting.to.number_type = NUMTYPE_UNKNOWN;
++ bc->redirecting.to.presentation = 0;/* Allowed */
++ bc->redirecting.to.screening = 0;/* Unscreened */
++
++ ++bc->redirecting.count;
++ bc->redirecting.reason = mISDN_REDIRECTING_REASON_DEFLECTION;
++
++ misdn_copy_redirecting_to_ast(ch->ast, &bc->redirecting);
++ ast_string_field_set(ch->ast, call_forward, bc->redirecting.to.number);
++
++ misdn_lib_send_event(bc, EVENT_DISCONNECT);
++
++ /* This line is BUSY to further attempts by this dialing attempt. */
++ ast_queue_control(ch->ast, AST_CONTROL_BUSY);
++ }
++ break;
++#endif /* !defined(AST_MISDN_ENHANCEMENTS) */
++ case Fac_AOCDCurrency:
++ if (ch && ch->ast) {
++ bc->AOCDtype = Fac_AOCDCurrency;
++ memcpy(&bc->AOCD.currency, &bc->fac_in.u.AOCDcur, sizeof(bc->AOCD.currency));
++ bc->AOCD_need_export = 1;
++ export_aoc_vars(ch->originator, ch->ast, bc);
++ }
++ break;
++ case Fac_AOCDChargingUnit:
++ if (ch && ch->ast) {
++ bc->AOCDtype = Fac_AOCDChargingUnit;
++ memcpy(&bc->AOCD.chargingUnit, &bc->fac_in.u.AOCDchu, sizeof(bc->AOCD.chargingUnit));
++ bc->AOCD_need_export = 1;
++ export_aoc_vars(ch->originator, ch->ast, bc);
++ }
++ break;
++#if defined(AST_MISDN_ENHANCEMENTS)
++ case Fac_ERROR:
++ diagnostic_msg = misdn_to_str_error_code(bc->fac_in.u.ERROR.errorValue);
++ chan_misdn_log(1, bc->port, " --> Facility error code: %s\n", diagnostic_msg);
++ switch (event) {
++ case EVENT_DISCONNECT:
++ case EVENT_RELEASE:
++ case EVENT_RELEASE_COMPLETE:
++ /* Possible call failure as a result of Fac_CCBSCall/Fac_CCBS_T_Call */
++ if (ch && ch->peer) {
++ misdn_cc_set_peer_var(ch->peer, MISDN_ERROR_MSG, diagnostic_msg);
++ }
++ break;
++ default:
++ break;
++ }
++ AST_LIST_LOCK(&misdn_cc_records_db);
++ cc_record = misdn_cc_find_by_invoke(bc->port, bc->fac_in.u.ERROR.invokeId);
++ if (cc_record) {
++ cc_record->outstanding_message = 0;
++ cc_record->error_code = bc->fac_in.u.ERROR.errorValue;
++ }
++ AST_LIST_UNLOCK(&misdn_cc_records_db);
++ break;
++ case Fac_REJECT:
++ diagnostic_msg = misdn_to_str_reject_code(bc->fac_in.u.REJECT.Code);
++ chan_misdn_log(1, bc->port, " --> Facility reject code: %s\n", diagnostic_msg);
++ switch (event) {
++ case EVENT_DISCONNECT:
++ case EVENT_RELEASE:
++ case EVENT_RELEASE_COMPLETE:
++ /* Possible call failure as a result of Fac_CCBSCall/Fac_CCBS_T_Call */
++ if (ch && ch->peer) {
++ misdn_cc_set_peer_var(ch->peer, MISDN_ERROR_MSG, diagnostic_msg);
++ }
++ break;
++ default:
++ break;
++ }
++ if (bc->fac_in.u.REJECT.InvokeIDPresent) {
++ AST_LIST_LOCK(&misdn_cc_records_db);
++ cc_record = misdn_cc_find_by_invoke(bc->port, bc->fac_in.u.REJECT.InvokeID);
++ if (cc_record) {
++ cc_record->outstanding_message = 0;
++ cc_record->reject_code = bc->fac_in.u.REJECT.Code;
++ }
++ AST_LIST_UNLOCK(&misdn_cc_records_db);
++ }
++ break;
++ case Fac_RESULT:
++ AST_LIST_LOCK(&misdn_cc_records_db);
++ cc_record = misdn_cc_find_by_invoke(bc->port, bc->fac_in.u.RESULT.InvokeID);
++ if (cc_record) {
++ cc_record->outstanding_message = 0;
++ }
++ AST_LIST_UNLOCK(&misdn_cc_records_db);
++ break;
++#if 0 /* We don't handle this yet */
++ case Fac_EctExecute:
++ /* We don't handle this yet */
++ break;
++ case Fac_ExplicitEctExecute:
++ /* We don't handle this yet */
++ break;
++ case Fac_EctLinkIdRequest:
++ /* We don't handle this yet */
++ break;
++#endif /* We don't handle this yet */
++ case Fac_SubaddressTransfer:
++ /* We do not have anything to do for this message since we do not handle subaddreses. */
++ break;
++ case Fac_RequestSubaddress:
++ /* We do not have anything to do for this message since we do not handle subaddreses. */
++ break;
++ case Fac_EctInform:
++ /* Private-Public ISDN interworking message */
++ if (ch && ch->ast && bc->fac_in.u.EctInform.RedirectionPresent) {
++ /* Add configured prefix to the redirection number */
++ memset(&party_id, 0, sizeof(party_id));
++ misdn_PresentedNumberUnscreened_extract(&party_id,
++ &bc->fac_in.u.EctInform.Redirection);
++ misdn_add_number_prefix(bc->port, party_id.number_type,
++ party_id.number, sizeof(party_id.number));
++
++ /*
++ * It would be preferable to update the connected line information
++ * only when the message callStatus is active. However, the
++ * optional redirection number may not be present in the active
++ * message if an alerting message were received earlier.
++ *
++ * The consequences if we wind up sending two updates is benign.
++ * The other end will think that it got transferred twice.
++ */
++ misdn_queue_connected_line_update(ch->ast, &party_id,
++ (bc->fac_in.u.EctInform.Status == 0 /* alerting */)
++ ? AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER_ALERTING
++ : AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER);
++ }
++ break;
++#if 0 /* We don't handle this yet */
++ case Fac_EctLoopTest:
++ /* The use of this message is unclear on how it works to detect loops. */
++ /* We don't handle this yet */
++ break;
++#endif /* We don't handle this yet */
++ case Fac_CallInfoRetain:
++ switch (event) {
++ case EVENT_ALERTING:
++ case EVENT_DISCONNECT:
++ /* CCBS/CCNR is available */
++ if (ch && ch->peer) {
++ AST_LIST_LOCK(&misdn_cc_records_db);
++ if (ch->record_id == -1) {
++ cc_record = misdn_cc_new();
++ } else {
++ /*
++ * We are doing a call-completion attempt
++ * or the switch is sending us extra call-completion
++ * availability indications (erroneously?).
++ *
++ * Assume that the network request retention option
++ * is not on and that the current call-completion
++ * request is disabled.
++ */
++ cc_record = misdn_cc_find_by_id(ch->record_id);
++ if (cc_record) {
++ if (cc_record->ptp && cc_record->mode.ptp.bc) {
++ /*
++ * What? We are getting mixed messages from the
++ * switch. We are currently setup for
++ * point-to-point. Now we are switching to
++ * point-to-multipoint.
++ *
++ * Close the call-completion signaling link
++ */
++ cc_record->mode.ptp.bc->fac_out.Function = Fac_None;
++ cc_record->mode.ptp.bc->out_cause = AST_CAUSE_NORMAL_CLEARING;
++ misdn_lib_send_event(cc_record->mode.ptp.bc, EVENT_RELEASE_COMPLETE);
++ }
++
++ /*
++ * Resetup the existing record for a possible new
++ * call-completion request.
++ */
++ new_record_id = misdn_cc_record_id_new();
++ if (new_record_id < 0) {
++ /* Looks like we must keep the old id anyway. */
++ } else {
++ cc_record->record_id = new_record_id;
++ ch->record_id = new_record_id;
++ }
++ cc_record->ptp = 0;
++ cc_record->port = bc->port;
++ memset(&cc_record->mode, 0, sizeof(cc_record->mode));
++ cc_record->mode.ptmp.linkage_id = bc->fac_in.u.CallInfoRetain.CallLinkageID;
++ cc_record->invoke_id = ++misdn_invoke_id;
++ cc_record->activated = 0;
++ cc_record->outstanding_message = 0;
++ cc_record->activation_requested = 0;
++ cc_record->error_code = FacError_None;
++ cc_record->reject_code = FacReject_None;
++ memset(&cc_record->remote_user_free, 0, sizeof(cc_record->remote_user_free));
++ memset(&cc_record->b_free, 0, sizeof(cc_record->b_free));
++ cc_record->time_created = time(NULL);
++
++ cc_record = NULL;
++ } else {
++ /*
++ * Where did the record go? We will have to recapture
++ * the call setup information. Unfortunately, some
++ * setup information may have been changed.
++ */
++ ch->record_id = -1;
++ cc_record = misdn_cc_new();
++ }
++ }
++ if (cc_record) {
++ ch->record_id = cc_record->record_id;
++ cc_record->ptp = 0;
++ cc_record->port = bc->port;
++ cc_record->mode.ptmp.linkage_id = bc->fac_in.u.CallInfoRetain.CallLinkageID;
++
++ /* Record call information for possible call-completion attempt. */
++ cc_record->redial.caller = bc->caller;
++ cc_record->redial.dialed = bc->dialed;
++ cc_record->redial.setup_bc_hlc_llc = bc->setup_bc_hlc_llc;
++ cc_record->redial.capability = bc->capability;
++ cc_record->redial.hdlc = bc->hdlc;
++ }
++ AST_LIST_UNLOCK(&misdn_cc_records_db);
++
++ /* Set MISDN_CC_RECORD_ID in original channel */
++ if (ch->record_id != -1) {
++ snprintf(buf, sizeof(buf), "%ld", ch->record_id);
++ } else {
++ buf[0] = 0;
++ }
++ misdn_cc_set_peer_var(ch->peer, MISDN_CC_RECORD_ID, buf);
++ }
++ break;
++ default:
++ chan_misdn_log(0, bc->port,
++ " --> Expected in a DISCONNECT or ALERTING message: facility type:0x%04X\n",
++ bc->fac_in.Function);
++ break;
++ }
++ break;
++ case Fac_CCBS_T_Call:
++ case Fac_CCBSCall:
++ switch (event) {
++ case EVENT_SETUP:
++ /*
++ * This is a call completion retry call.
++ * If we had anything to do we would do it here.
++ */
++ break;
++ default:
++ chan_misdn_log(0, bc->port, " --> Expected in a SETUP message: facility type:0x%04X\n",
++ bc->fac_in.Function);
++ break;
++ }
++ break;
++ case Fac_CCBSDeactivate:
++ switch (bc->fac_in.u.CCBSDeactivate.ComponentType) {
++ case FacComponent_Result:
++ AST_LIST_LOCK(&misdn_cc_records_db);
++ cc_record = misdn_cc_find_by_invoke(bc->port, bc->fac_in.u.CCBSDeactivate.InvokeID);
++ if (cc_record) {
++ cc_record->outstanding_message = 0;
++ }
++ AST_LIST_UNLOCK(&misdn_cc_records_db);
++ break;
++
++ default:
++ chan_misdn_log(0, bc->port, " --> not yet handled: facility type:0x%04X\n",
++ bc->fac_in.Function);
++ break;
++ }
++ break;
++ case Fac_CCBSErase:
++ AST_LIST_LOCK(&misdn_cc_records_db);
++ cc_record = misdn_cc_find_by_reference(bc->port, bc->fac_in.u.CCBSErase.CCBSReference);
++ if (cc_record) {
++ misdn_cc_delete(cc_record);
++ }
++ AST_LIST_UNLOCK(&misdn_cc_records_db);
++ break;
++ case Fac_CCBSRemoteUserFree:
++ misdn_cc_handle_remote_user_free(bc->port, &bc->fac_in);
++ break;
++ case Fac_CCBSBFree:
++ misdn_cc_handle_b_free(bc->port, &bc->fac_in);
++ break;
++ case Fac_CCBSStatusRequest:
++ misdn_cc_handle_ccbs_status_request(bc->port, &bc->fac_in);
++ break;
++ case Fac_EraseCallLinkageID:
++ AST_LIST_LOCK(&misdn_cc_records_db);
++ cc_record = misdn_cc_find_by_linkage(bc->port,
++ bc->fac_in.u.EraseCallLinkageID.CallLinkageID);
++ if (cc_record && !cc_record->activation_requested) {
++ /*
++ * The T-RETENTION timer expired before we requested
++ * call completion activation. Call completion is no
++ * longer available.
++ */
++ misdn_cc_delete(cc_record);
++ }
++ AST_LIST_UNLOCK(&misdn_cc_records_db);
++ break;
++ case Fac_CCBSStopAlerting:
++ /* We do not have anything to do for this message. */
++ break;
++ case Fac_CCBSRequest:
++ case Fac_CCNRRequest:
++ switch (bc->fac_in.u.CCBSRequest.ComponentType) {
++ case FacComponent_Result:
++ AST_LIST_LOCK(&misdn_cc_records_db);
++ cc_record = misdn_cc_find_by_invoke(bc->port, bc->fac_in.u.CCBSRequest.InvokeID);
++ if (cc_record && !cc_record->ptp) {
++ cc_record->outstanding_message = 0;
++ cc_record->activated = 1;
++ cc_record->mode.ptmp.recall_mode = bc->fac_in.u.CCBSRequest.Component.Result.RecallMode;
++ cc_record->mode.ptmp.reference_id = bc->fac_in.u.CCBSRequest.Component.Result.CCBSReference;
++ }
++ AST_LIST_UNLOCK(&misdn_cc_records_db);
++ break;
++
++ default:
++ chan_misdn_log(0, bc->port, " --> not yet handled: facility type:0x%04X\n",
++ bc->fac_in.Function);
++ break;
++ }
++ break;
++#if 0 /* We don't handle this yet */
++ case Fac_CCBSInterrogate:
++ case Fac_CCNRInterrogate:
++ /* We don't handle this yet */
++ break;
++ case Fac_StatusRequest:
++ /* We don't handle this yet */
++ break;
++#endif /* We don't handle this yet */
++#if 0 /* We don't handle this yet */
++ case Fac_CCBS_T_Suspend:
++ case Fac_CCBS_T_Resume:
++ /* We don't handle this yet */
++ break;
++#endif /* We don't handle this yet */
++ case Fac_CCBS_T_RemoteUserFree:
++ misdn_cc_handle_T_remote_user_free(bc);
++ break;
++ case Fac_CCBS_T_Available:
++ switch (event) {
++ case EVENT_ALERTING:
++ case EVENT_DISCONNECT:
++ /* CCBS-T/CCNR-T is available */
++ if (ch && ch->peer) {
++ int set_id = 1;
++
++ AST_LIST_LOCK(&misdn_cc_records_db);
++ if (ch->record_id == -1) {
++ cc_record = misdn_cc_new();
++ } else {
++ /*
++ * We are doing a call-completion attempt
++ * or the switch is sending us extra call-completion
++ * availability indications (erroneously?).
++ */
++ cc_record = misdn_cc_find_by_id(ch->record_id);
++ if (cc_record) {
++ if (cc_record->ptp && cc_record->mode.ptp.retention_enabled) {
++ /*
++ * Call-completion is still activated.
++ * The user does not have to request it again.
++ */
++ chan_misdn_log(1, bc->port, " --> Call-completion request retention option is enabled\n");
++
++ set_id = 0;
++ } else {
++ if (cc_record->ptp && cc_record->mode.ptp.bc) {
++ /*
++ * The network request retention option
++ * is not on and the current call-completion
++ * request is to be disabled.
++ *
++ * We should get here only if EVENT_DISCONNECT
++ *
++ * Close the call-completion signaling link
++ */
++ cc_record->mode.ptp.bc->fac_out.Function = Fac_None;
++ cc_record->mode.ptp.bc->out_cause = AST_CAUSE_NORMAL_CLEARING;
++ misdn_lib_send_event(cc_record->mode.ptp.bc, EVENT_RELEASE_COMPLETE);
++ }
++
++ /*
++ * Resetup the existing record for a possible new
++ * call-completion request.
++ */
++ new_record_id = misdn_cc_record_id_new();
++ if (new_record_id < 0) {
++ /* Looks like we must keep the old id anyway. */
++ } else {
++ cc_record->record_id = new_record_id;
++ ch->record_id = new_record_id;
++ }
++ cc_record->ptp = 1;
++ cc_record->port = bc->port;
++ memset(&cc_record->mode, 0, sizeof(cc_record->mode));
++ cc_record->invoke_id = ++misdn_invoke_id;
++ cc_record->activated = 0;
++ cc_record->outstanding_message = 0;
++ cc_record->activation_requested = 0;
++ cc_record->error_code = FacError_None;
++ cc_record->reject_code = FacReject_None;
++ memset(&cc_record->remote_user_free, 0, sizeof(cc_record->remote_user_free));
++ memset(&cc_record->b_free, 0, sizeof(cc_record->b_free));
++ cc_record->time_created = time(NULL);
++ }
++ cc_record = NULL;
++ } else {
++ /*
++ * Where did the record go? We will have to recapture
++ * the call setup information. Unfortunately, some
++ * setup information may have been changed.
++ */
++ ch->record_id = -1;
++ cc_record = misdn_cc_new();
++ }
++ }
++ if (cc_record) {
++ ch->record_id = cc_record->record_id;
++ cc_record->ptp = 1;
++ cc_record->port = bc->port;
++
++ /* Record call information for possible call-completion attempt. */
++ cc_record->redial.caller = bc->caller;
++ cc_record->redial.dialed = bc->dialed;
++ cc_record->redial.setup_bc_hlc_llc = bc->setup_bc_hlc_llc;
++ cc_record->redial.capability = bc->capability;
++ cc_record->redial.hdlc = bc->hdlc;
++ }
++ AST_LIST_UNLOCK(&misdn_cc_records_db);
++
++ /* Set MISDN_CC_RECORD_ID in original channel */
++ if (ch->record_id != -1 && set_id) {
++ snprintf(buf, sizeof(buf), "%ld", ch->record_id);
++ } else {
++ buf[0] = 0;
++ }
++ misdn_cc_set_peer_var(ch->peer, MISDN_CC_RECORD_ID, buf);
++ }
++ break;
++ default:
++ chan_misdn_log(0, bc->port,
++ " --> Expected in a DISCONNECT or ALERTING message: facility type:0x%04X\n",
++ bc->fac_in.Function);
++ break;
++ }
++ break;
++ case Fac_CCBS_T_Request:
++ case Fac_CCNR_T_Request:
++ switch (bc->fac_in.u.CCBS_T_Request.ComponentType) {
++ case FacComponent_Result:
++ AST_LIST_LOCK(&misdn_cc_records_db);
++ cc_record = misdn_cc_find_by_invoke(bc->port, bc->fac_in.u.CCBS_T_Request.InvokeID);
++ if (cc_record && cc_record->ptp) {
++ cc_record->outstanding_message = 0;
++ cc_record->activated = 1;
++ cc_record->mode.ptp.retention_enabled =
++ cc_record->mode.ptp.requested_retention
++ ? bc->fac_in.u.CCBS_T_Request.Component.Result.RetentionSupported
++ ? 1 : 0
++ : 0;
++ }
++ AST_LIST_UNLOCK(&misdn_cc_records_db);
++ break;
++
++ case FacComponent_Invoke:
++ /* We cannot be User-B in ptp mode. */
++ default:
++ chan_misdn_log(0, bc->port, " --> not yet handled: facility type:0x%04X\n",
++ bc->fac_in.Function);
++ break;
++ }
++ break;
++
++#endif /* defined(AST_MISDN_ENHANCEMENTS) */
++ case Fac_None:
++ break;
++ default:
++ chan_misdn_log(0, bc->port, " --> not yet handled: facility type:0x%04X\n",
++ bc->fac_in.Function);
++ break;
++ }
++}
++
+ /************************************************************/
+ /* Receive Events from isdn_lib here */
+ /************************************************************/
+ static enum event_response_e
+ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data)
+ {
++#if defined(AST_MISDN_ENHANCEMENTS)
++ struct misdn_cc_record *cc_record;
++#endif /* defined(AST_MISDN_ENHANCEMENTS) */
+ struct chan_list *ch = find_chan_by_bc(cl_te, bc);
+-
+- if (event != EVENT_BCHAN_DATA && event != EVENT_TONE_GENERATE) { /* Debug Only Non-Bchan */
++
++ if (event != EVENT_BCHAN_DATA && event != EVENT_TONE_GENERATE) {
+ int debuglevel = 1;
+- if ( event == EVENT_CLEANUP && !user_data) {
++
++ /* Debug Only Non-Bchan */
++ 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:
+@@ -4290,6 +9334,7 @@
+ case EVENT_RETRIEVE:
+ case EVENT_NEW_BC:
+ case EVENT_FACILITY:
++ case EVENT_REGISTER:
+ break;
+ case EVENT_RELEASE_COMPLETE:
+ chan_misdn_log(1, bc->port, " --> no Ch, so we've already released.\n");
+@@ -4303,7 +9348,7 @@
+ return -1;
+ }
+ }
+-
++
+ if (ch) {
+ switch (event) {
+ case EVENT_TONE_GENERATE:
+@@ -4318,16 +9363,17 @@
+ }
+ break;
+ default:
+- if (!ch->ast || !MISDN_ASTERISK_PVT(ch->ast) || !MISDN_ASTERISK_TECH_PVT(ch->ast)) {
++ if (!ch->ast || !MISDN_ASTERISK_TECH_PVT(ch->ast)) {
+ 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;
+ }
++ break;
+ }
+ }
+-
+-
++
++
+ switch (event) {
+ case EVENT_PORT_ALARM:
+ {
+@@ -4335,17 +9381,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;
+@@ -4355,17 +9401,17 @@
+ if (!ch) {
+ ch = find_holded(cl_te,bc);
+ }
+-
++
+ if (!ch) {
+ ast_log(LOG_WARNING, "NEW_BC without chan_list?\n");
+ break;
+ }
+
+ if (bc) {
+- ch->bc = (struct misdn_bchannel *)user_data;
++ ch->bc = (struct misdn_bchannel *) user_data;
+ }
+ break;
+-
++
+ case EVENT_DTMF_TONE:
+ {
+ /* sending INFOS as DTMF-Frames :) */
+@@ -4381,56 +9427,54 @@
+ 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);
+ } else {
+ chan_misdn_log(2, bc->port, " --> Ignoring DTMF:%c due to bridge flags\n", bc->dtmf);
+ }
++ break;
+ }
+- break;
+ case EVENT_STATUS:
+ break;
+-
++
+ case EVENT_INFORMATION:
+ if (ch->state != MISDN_CONNECTED) {
+ stop_indicate(ch);
+ }
+-
++
+ if (!ch->ast) {
+ break;
+ }
+
+- if (ch->state == MISDN_WAITING4DIGS ) {
++ if (ch->state == MISDN_WAITING4DIGS) {
+ /* Ok, incomplete Setup, waiting till extension exists */
+ if (ast_strlen_zero(bc->info_dad) && ! ast_strlen_zero(bc->keypad)) {
+ chan_misdn_log(1, bc->port, " --> using keypad as info\n");
+ 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 '%s@%s' can never match. Jumping to 'i' extension. port:%d\n",
+- bc->dad, ch->context, bc->port);
++ bc->dialed.number, ch->context, bc->port);
+ strcpy(ch->ast->exten, "i");
+
+ ch->state = MISDN_DIALING;
+@@ -4441,7 +9485,7 @@
+ ast_log(LOG_WARNING,
+ "Extension '%s@%s' can never match. Disconnecting. port:%d\n"
+ "\tMaybe you want to add an 'i' extension to catch this case.\n",
+- bc->dad, ch->context, bc->port);
++ bc->dialed.number, ch->context, bc->port);
+
+ if (bc->nt) {
+ hanguptone_indicate(ch);
+@@ -4458,13 +9502,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);
+ }
+@@ -4485,13 +9529,13 @@
+ fr.delivery = ast_tv(0,0);
+
+ misdn_cfg_get(0, MISDN_GEN_APPEND_DIGITS2EXTEN, &digits, sizeof(digits));
+- if (ch->state != MISDN_CONNECTED ) {
++ 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);
+ }
+ }
+@@ -4499,10 +9543,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;
+
+@@ -4533,7 +9576,6 @@
+ print_bearer(bc);
+
+ ch = init_chan_list(ORG_MISDN);
+-
+ if (!ch) {
+ chan_misdn_log(-1, bc->port, "cb_events: malloc for chan_list failed!\n");
+ return 0;
+@@ -4542,13 +9584,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;
+ }
+
+@@ -4560,50 +9600,34 @@
+ 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)) {
++ /* 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 */
++ misdn_copy_redirecting_to_ast(chan, &bc->redirecting);
+ }
+
+- chan->cid.cid_pres = pres | screen;
+-
+ pbx_builtin_setvar_helper(chan, "TRANSFERCAPABILITY", ast_transfercapability2str(bc->capability));
+ chan->transfercapability = bc->capability;
+
+@@ -4613,6 +9637,7 @@
+ break;
+ default:
+ pbx_builtin_setvar_helper(chan, "CALLTYPE", "SPEECH");
++ break;
+ }
+
+ /** queue new chan **/
+@@ -4632,7 +9657,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",
+@@ -4645,11 +9670,15 @@
+ }
+ }
+
++ if (bc->fac_in.Function != Fac_None) {
++ misdn_facility_ie_handler(event, bc, ch);
++ }
++
+ /* Check for Pickup Request first */
+ if (!strcmp(chan->exten, ast_pickup_ext())) {
+ if (!ch->noautorespond_on_setup) {
+- int ret;/** Sending SETUP_ACK**/
+- ret = misdn_lib_send_event(bc, EVENT_SETUP_ACKNOWLEDGE );
++ /* Sending SETUP_ACK */
++ misdn_lib_send_event(bc, EVENT_SETUP_ACKNOWLEDGE);
+ } else {
+ ch->state = MISDN_INCOMING_SETUP;
+ }
+@@ -4657,7 +9686,6 @@
+ hangup_chan(ch);
+ } else {
+ ch->state = MISDN_CALLING_ACKNOWLEDGE;
+- ast_setstate(chan, AST_STATE_DOWN);
+ hangup_chan(ch);
+ ch->ast = NULL;
+ break;
+@@ -4674,19 +9702,19 @@
+ 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 '%s@%s' can never match. Jumping to 'i' extension. port:%d\n",
+- bc->dad, ch->context, bc->port);
++ bc->dialed.number, ch->context, bc->port);
+ strcpy(ch->ast->exten, "i");
+ misdn_lib_send_event(bc, EVENT_SETUP_ACKNOWLEDGE);
+ ch->state = MISDN_DIALING;
+@@ -4697,7 +9725,7 @@
+ ast_log(LOG_WARNING,
+ "Extension '%s@%s' can never match. Disconnecting. port:%d\n"
+ "\tMaybe you want to add an 'i' extension to catch this case.\n",
+- bc->dad, ch->context, bc->port);
++ bc->dialed.number, ch->context, bc->port);
+ if (bc->nt) {
+ hanguptone_indicate(ch);
+ }
+@@ -4706,17 +9734,16 @@
+ bc->out_cause = AST_CAUSE_UNALLOCATED;
+
+ misdn_lib_send_event(bc, bc->nt ? EVENT_RELEASE_COMPLETE : EVENT_RELEASE);
+-
+ 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) {
+ ch->state=MISDN_DIALING;
+- misdn_lib_send_event(bc, EVENT_PROCEEDING );
++ misdn_lib_send_event(bc, EVENT_PROCEEDING);
+ } else {
+ ch->state = MISDN_INCOMING_SETUP;
+ }
+@@ -4726,17 +9753,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) {
+@@ -4746,16 +9773,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;
+ }
+@@ -4763,29 +9790,50 @@
+ /*
+ * 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;
+ }
++#if defined(AST_MISDN_ENHANCEMENTS)
++ case EVENT_REGISTER:
++ if (bc->fac_in.Function != Fac_None) {
++ misdn_facility_ie_handler(event, bc, ch);
++ }
++ /*
++ * Shut down this connection immediately.
++ * The current design of chan_misdn data structures
++ * does not allow the proper handling of inbound call records
++ * without an assigned B channel. Therefore, we cannot
++ * be the CCBS User-B party in a point-to-point setup.
++ */
++ bc->fac_out.Function = Fac_None;
++ bc->out_cause = AST_CAUSE_NORMAL_CLEARING;
++ misdn_lib_send_event(bc, EVENT_RELEASE_COMPLETE);
+ break;
+-
++#endif /* defined(AST_MISDN_ENHANCEMENTS) */
+ case EVENT_SETUP_ACKNOWLEDGE:
+ ch->state = MISDN_CALLING_ACKNOWLEDGE;
+
+- if (bc->channel)
++ if (bc->channel) {
+ update_name(ch->ast,bc->port,bc->channel);
+-
++ }
++
++ if (bc->fac_in.Function != Fac_None) {
++ misdn_facility_ie_handler(event, bc, ch);
++ }
++
+ 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));
+
+@@ -4794,12 +9842,16 @@
+ break;
+ case EVENT_PROCEEDING:
+ if (misdn_cap_is_speech(bc->capability) &&
+- misdn_inband_avail(bc) ) {
++ misdn_inband_avail(bc)) {
+ start_bc_tones(ch);
+ }
+
+ ch->state = MISDN_PROCEEDING;
+-
++
++ if (bc->fac_in.Function != Fac_None) {
++ misdn_facility_ie_handler(event, bc, ch);
++ }
++
+ if (!ch->ast) {
+ break;
+ }
+@@ -4811,12 +9863,16 @@
+ update_name(ch->ast, bc->port, bc->channel);
+ }
+
+- if (!bc->nt ) {
++ if (bc->fac_in.Function != Fac_None) {
++ misdn_facility_ie_handler(event, bc, ch);
++ }
++
++ if (!bc->nt) {
+ if (misdn_cap_is_speech(bc->capability) &&
+ misdn_inband_avail(bc)) {
+ start_bc_tones(ch);
+ }
+-
++
+ ch->state = MISDN_PROGRESS;
+
+ if (!ch->ast) {
+@@ -4827,16 +9883,20 @@
+ break;
+ case EVENT_ALERTING:
+ ch->state = MISDN_ALERTING;
+-
++
+ if (!ch->ast) {
+ break;
+ }
+
++ if (bc->fac_in.Function != Fac_None) {
++ misdn_facility_ie_handler(event, bc, ch);
++ }
++
+ 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);
+@@ -4850,36 +9910,73 @@
+ }
+ break;
+ case EVENT_CONNECT:
+- {
+- struct ast_channel *bridged;
++ if (bc->fac_in.Function != Fac_None) {
++ misdn_facility_ie_handler(event, bc, ch);
++ }
++#if defined(AST_MISDN_ENHANCEMENTS)
++ if (bc->div_leg_3_rx_wanted) {
++ bc->div_leg_3_rx_wanted = 0;
+
+- /*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) {
++ ch->ast->redirecting.to.number_presentation =
++ AST_PRES_RESTRICTED | AST_PRES_USER_NUMBER_UNSCREENED;
++ ast_channel_queue_redirecting_update(ch->ast, &ch->ast->redirecting);
+ }
++ }
++#endif /* defined(AST_MISDN_ENHANCEMENTS) */
+
+- bridged = ast_bridged_channel(ch->ast);
+- stop_indicate(ch);
++ /* we answer when we've got our very new L3 ID from the NT stack */
++ misdn_lib_send_event(bc, EVENT_CONNECT_ACKNOWLEDGE);
+
+- if (bridged && !strcasecmp(bridged->tech->type, "mISDN")) {
+- struct chan_list *bridged_ch = MISDN_ASTERISK_TECH_PVT(bridged);
++ if (!ch->ast) {
++ break;
++ }
+
+- 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));
++ stop_indicate(ch);
++
++#if defined(AST_MISDN_ENHANCEMENTS)
++ if (ch->record_id != -1) {
++ /*
++ * We will delete the associated call completion
++ * record since we now have a completed call.
++ * We will not wait/depend on the network to tell
++ * us to delete it.
++ */
++ AST_LIST_LOCK(&misdn_cc_records_db);
++ cc_record = misdn_cc_find_by_id(ch->record_id);
++ if (cc_record) {
++ if (cc_record->ptp && cc_record->mode.ptp.bc) {
++ /* Close the call-completion signaling link */
++ cc_record->mode.ptp.bc->fac_out.Function = Fac_None;
++ cc_record->mode.ptp.bc->out_cause = AST_CAUSE_NORMAL_CLEARING;
++ misdn_lib_send_event(cc_record->mode.ptp.bc, EVENT_RELEASE_COMPLETE);
+ }
++ misdn_cc_delete(cc_record);
+ }
++ AST_LIST_UNLOCK(&misdn_cc_records_db);
++ ch->record_id = -1;
++ if (ch->peer) {
++ misdn_cc_set_peer_var(ch->peer, MISDN_CC_RECORD_ID, "");
++
++ ao2_ref(ch->peer, -1);
++ ch->peer = NULL;
++ }
+ }
++#endif /* defined(AST_MISDN_ENHANCEMENTS) */
++
++ /* Add configured prefix to connected.number */
++ misdn_add_number_prefix(bc->port, bc->connected.number_type, bc->connected.number, sizeof(bc->connected.number));
++
++ /* Update the connected line information on the other channel */
++ misdn_queue_connected_line_update(ch->ast, &bc->connected, AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER);
++
+ 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:
+@@ -4895,6 +9992,10 @@
+ if (ch) {
+ struct chan_list *holded_ch = find_holded(cl_te, bc);
+
++ if (bc->fac_in.Function != Fac_None) {
++ misdn_facility_ie_handler(event, bc, ch);
++ }
++
+ chan_misdn_log(3, bc->port, " --> org:%d nt:%d, inbandavail:%d state:%d\n", ch->originator, bc->nt, misdn_inband_avail(bc), ch->state);
+ if (ch->originator == ORG_AST && !bc->nt && misdn_inband_avail(bc) && ch->state != MISDN_CONNECTED) {
+ /* If there's inband information available (e.g. a
+@@ -4903,7 +10004,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);
+
+@@ -4941,6 +10042,10 @@
+ }
+ break;
+ case EVENT_RELEASE:
++ if (bc->fac_in.Function != Fac_None) {
++ misdn_facility_ie_handler(event, bc, ch);
++ }
++
+ bc->need_disconnect = 0;
+ bc->need_release = 0;
+
+@@ -4948,22 +10053,41 @@
+ release_chan(bc);
+ break;
+ case EVENT_RELEASE_COMPLETE:
++ if (bc->fac_in.Function != Fac_None) {
++ misdn_facility_ie_handler(event, bc, ch);
++ }
++
+ bc->need_disconnect = 0;
+ bc->need_release = 0;
+ bc->need_release_complete = 0;
+
+- stop_bc_tones(ch);
+- hangup_chan(ch);
+-
+- if (ch)
++ if (ch) {
++ stop_bc_tones(ch);
++ hangup_chan(ch);
+ ch->state = MISDN_CLEANING;
++#if defined(AST_MISDN_ENHANCEMENTS)
++ } else {
++ /*
++ * A call-completion signaling link established with
++ * REGISTER does not have a struct chan_list record
++ * associated with it.
++ */
++ AST_LIST_LOCK(&misdn_cc_records_db);
++ cc_record = misdn_cc_find_by_bc(bc);
++ if (cc_record) {
++ /* The call-completion signaling link is closed. */
++ misdn_cc_delete(cc_record);
++ }
++ AST_LIST_UNLOCK(&misdn_cc_records_db);
++#endif /* defined(AST_MISDN_ENHANCEMENTS) */
++ }
+
+ 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;
+@@ -4971,7 +10095,7 @@
+ default:
+ break;
+ }
+-
++
+ hangup_chan(ch);
+ release_chan(bc);
+ break;
+@@ -4997,30 +10121,30 @@
+ ast->generatordata = NULL;
+ generate = ast->generator->generate;
+
+- if (tone_len < 0 || tone_len > 512 ) {
++ if (tone_len < 0 || tone_len > 512) {
+ ast_log(LOG_NOTICE, "TONE_GEN: len was %d, set to 128\n", tone_len);
+ tone_len = 128;
+ }
+
+ 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;
+@@ -5031,8 +10155,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 };
+@@ -5042,17 +10167,16 @@
+ FD_SET(ch->pipe[1], &wrfs);
+
+ t = select(FD_SETSIZE, NULL, &wrfs, NULL, &tv);
+-
+ if (!t) {
+ 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) {
+@@ -5102,11 +10226,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;
+
+@@ -5140,13 +10265,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;
+@@ -5164,7 +10289,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
+@@ -5179,61 +10304,80 @@
+ 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:
++ }
++ case EVENT_NOTIFY:
++ if (bc->redirecting.to_changed) {
++ /* Add configured prefix to redirecting.to.number */
++ misdn_add_number_prefix(bc->port, bc->redirecting.to.number_type,
++ bc->redirecting.to.number, sizeof(bc->redirecting.to.number));
++ }
++ switch (bc->notify_description_code) {
++ case mISDN_NOTIFY_CODE_DIVERSION_ACTIVATED:
++ /* Ignore for now. */
++ bc->redirecting.to_changed = 0;
+ break;
+-#endif
+- case Fac_CD:
+- if (ch) {
+- struct ast_channel *bridged = ast_bridged_channel(ch->ast);
+- struct chan_list *ch_br;
+- if (bridged && MISDN_ASTERISK_TECH_PVT(bridged)) {
+- 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)) {
+- 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");
+- }
+- }
++ case mISDN_NOTIFY_CODE_CALL_IS_DIVERTING:
++ if (bc->redirecting.to_changed) {
++ bc->redirecting.to_changed = 0;
++ if (ch && ch->ast) {
++ switch (ch->state) {
++ case MISDN_ALERTING:
++ /* Call is deflecting after we have seen an ALERTING message */
++ bc->redirecting.reason = mISDN_REDIRECTING_REASON_NO_REPLY;
++ break;
++ default:
++ /* Call is deflecting for call forwarding unconditional or busy reason. */
++ bc->redirecting.reason = mISDN_REDIRECTING_REASON_UNKNOWN;
++ break;
+ }
++ misdn_copy_redirecting_to_ast(ch->ast, &bc->redirecting);
++ ast_channel_queue_redirecting_update(ch->ast, &ch->ast->redirecting);
+ }
+- misdn_lib_send_event(bc, EVENT_DISCONNECT);
+- }
++ }
+ break;
+- case Fac_AOCDCurrency:
+- if (ch) {
+- bc->AOCDtype = Fac_AOCDCurrency;
+- memcpy(&(bc->AOCD.currency), &(bc->fac_in.u.AOCDcur), sizeof(bc->AOCD.currency));
+- bc->AOCD_need_export = 1;
+- export_aoc_vars(ch->originator, ch->ast, bc);
++ case mISDN_NOTIFY_CODE_CALL_TRANSFER_ALERTING:
++ /*
++ * It would be preferable to update the connected line information
++ * only when the message callStatus is active. However, the
++ * optional redirection number may not be present in the active
++ * message if an alerting message were received earlier.
++ *
++ * The consequences if we wind up sending two updates is benign.
++ * The other end will think that it got transferred twice.
++ */
++ if (bc->redirecting.to_changed) {
++ bc->redirecting.to_changed = 0;
++ if (ch && ch->ast) {
++ misdn_queue_connected_line_update(ch->ast, &bc->redirecting.to,
++ AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER_ALERTING);
++ }
+ }
+ break;
+- case Fac_AOCDChargingUnit:
+- if (ch) {
+- bc->AOCDtype = Fac_AOCDChargingUnit;
+- memcpy(&(bc->AOCD.chargingUnit), &(bc->fac_in.u.AOCDchu), sizeof(bc->AOCD.chargingUnit));
+- bc->AOCD_need_export = 1;
+- export_aoc_vars(ch->originator, ch->ast, bc);
++ case mISDN_NOTIFY_CODE_CALL_TRANSFER_ACTIVE:
++ if (bc->redirecting.to_changed) {
++ bc->redirecting.to_changed = 0;
++ if (ch && ch->ast) {
++ misdn_queue_connected_line_update(ch->ast, &bc->redirecting.to,
++ AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER);
++ }
+ }
+ break;
+- case Fac_None:
+-#ifdef HAVE_MISDN_FAC_ERROR
+- case Fac_ERROR:
+-#endif
++ default:
++ bc->redirecting.to_changed = 0;
++ chan_misdn_log(0, bc->port," --> not yet handled: notify code:0x%02X\n",
++ bc->notify_description_code);
+ break;
+- default:
+- chan_misdn_log(0, bc->port," --> not yet handled: facility type:%d\n", bc->fac_in.Function);
+ }
+-
+ break;
++ case EVENT_FACILITY:
++ if (bc->fac_in.Function == Fac_None) {
++ /* This is a FACILITY message so we MUST have a facility ie */
++ chan_misdn_log(0, bc->port," --> Missing facility ie or unknown facility ie contents.\n");
++ } else {
++ misdn_facility_ie_handler(event, bc, ch);
++ }
++ break;
+ case EVENT_RESTART:
+ if (!bc->dummy) {
+ stop_bc_tones(ch);
+@@ -5244,12 +10388,140 @@
+ chan_misdn_log(1, 0, "Got Unknown Event\n");
+ break;
+ }
+-
++
+ return RESPONSE_OK;
+ }
+
+ /** TE STUFF END **/
+
++#if defined(AST_MISDN_ENHANCEMENTS)
++/*!
++ * \internal
++ * \brief Get call completion record information.
++ *
++ * \param chan Asterisk channel to operate upon. (Not used)
++ * \param function_name Name of the function that called us.
++ * \param function_args Argument string passed to function (Could be NULL)
++ * \param buf Buffer to put returned string.
++ * \param size Size of the supplied buffer including the null terminator.
++ *
++ * \retval 0 on success.
++ * \retval -1 on error.
++ */
++static int misdn_cc_read(struct ast_channel *chan, const char *function_name,
++ char *function_args, char *buf, size_t size)
++{
++ char *parse;
++ struct misdn_cc_record *cc_record;
++
++ AST_DECLARE_APP_ARGS(args,
++ AST_APP_ARG(cc_id); /* Call completion record ID value. */
++ AST_APP_ARG(get_name); /* Name of what to get */
++ AST_APP_ARG(other); /* Any extraneous garbage arguments */
++ );
++
++ /* Ensure that the buffer is empty */
++ *buf = 0;
++
++ if (ast_strlen_zero(function_args)) {
++ ast_log(LOG_ERROR, "Function '%s' requires arguments.\n", function_name);
++ return -1;
++ }
++
++ parse = ast_strdupa(function_args);
++ AST_STANDARD_APP_ARGS(args, parse);
++
++ if (!args.argc || ast_strlen_zero(args.cc_id)) {
++ ast_log(LOG_ERROR, "Function '%s' missing call completion record ID.\n",
++ function_name);
++ return -1;
++ }
++ if (!isdigit(*args.cc_id)) {
++ ast_log(LOG_ERROR, "Function '%s' call completion record ID must be numeric.\n",
++ function_name);
++ return -1;
++ }
++
++ if (ast_strlen_zero(args.get_name)) {
++ ast_log(LOG_ERROR, "Function '%s' missing what-to-get parameter.\n",
++ function_name);
++ return -1;
++ }
++
++ AST_LIST_LOCK(&misdn_cc_records_db);
++ cc_record = misdn_cc_find_by_id(atoi(args.cc_id));
++ if (cc_record) {
++ if (!strcasecmp("a-all", args.get_name)) {
++ snprintf(buf, size, "\"%s\" <%s>", cc_record->redial.caller.name,
++ cc_record->redial.caller.number);
++ } else if (!strcasecmp("a-name", args.get_name)) {
++ ast_copy_string(buf, cc_record->redial.caller.name, size);
++ } else if (!strncasecmp("a-num", args.get_name, 5)) {
++ ast_copy_string(buf, cc_record->redial.caller.number, size);
++ } else if (!strcasecmp("a-ton", args.get_name)) {
++ snprintf(buf, size, "%d",
++ misdn_to_ast_plan(cc_record->redial.caller.number_plan)
++ | misdn_to_ast_ton(cc_record->redial.caller.number_type));
++ } else if (!strncasecmp("a-pres", args.get_name, 6)) {
++ ast_copy_string(buf, ast_named_caller_presentation(
++ misdn_to_ast_pres(cc_record->redial.caller.presentation)
++ | misdn_to_ast_screen(cc_record->redial.caller.screening)), size);
++ } else if (!strcasecmp("a-busy", args.get_name)) {
++ ast_copy_string(buf, cc_record->party_a_free ? "no" : "yes", size);
++ } else if (!strncasecmp("b-num", args.get_name, 5)) {
++ ast_copy_string(buf, cc_record->redial.dialed.number, size);
++ } else if (!strcasecmp("b-ton", args.get_name)) {
++ snprintf(buf, size, "%d",
++ misdn_to_ast_plan(cc_record->redial.dialed.number_plan)
++ | misdn_to_ast_ton(cc_record->redial.dialed.number_type));
++ } else if (!strcasecmp("port", args.get_name)) {
++ snprintf(buf, size, "%d", cc_record->port);
++ } else if (!strcasecmp("available-notify-priority", args.get_name)) {
++ snprintf(buf, size, "%d", cc_record->remote_user_free.priority);
++ } else if (!strcasecmp("available-notify-exten", args.get_name)) {
++ ast_copy_string(buf, cc_record->remote_user_free.exten, size);
++ } else if (!strcasecmp("available-notify-context", args.get_name)) {
++ ast_copy_string(buf, cc_record->remote_user_free.context, size);
++ } else if (!strcasecmp("busy-notify-priority", args.get_name)) {
++ snprintf(buf, size, "%d", cc_record->b_free.priority);
++ } else if (!strcasecmp("busy-notify-exten", args.get_name)) {
++ ast_copy_string(buf, cc_record->b_free.exten, size);
++ } else if (!strcasecmp("busy-notify-context", args.get_name)) {
++ ast_copy_string(buf, cc_record->b_free.context, size);
++ } else {
++ AST_LIST_UNLOCK(&misdn_cc_records_db);
++ ast_log(LOG_ERROR, "Function '%s': Unknown what-to-get '%s'.\n", function_name, args.get_name);
++ return -1;
++ }
++ }
++ AST_LIST_UNLOCK(&misdn_cc_records_db);
++
++ return 0;
++}
++#endif /* defined(AST_MISDN_ENHANCEMENTS) */
++
++#if defined(AST_MISDN_ENHANCEMENTS)
++static struct ast_custom_function misdn_cc_function = {
++ .name = "mISDN_CC",
++ .synopsis = "Get call completion record information.",
++ .syntax = "mISDN_CC(${MISDN_CC_RECORD_ID},<what-to-get>)",
++ .desc =
++ "mISDN_CC(${MISDN_CC_RECORD_ID},<what-to-get>)\n"
++ "The following can be retrieved:\n"
++ "\"a-num\", \"a-name\", \"a-all\", \"a-ton\", \"a-pres\", \"a-busy\",\n"
++ "\"b-num\", \"b-ton\", \"port\",\n"
++ " User-A is available for call completion:\n"
++ " \"available-notify-priority\",\n"
++ " \"available-notify-exten\",\n"
++ " \"available-notify-context\",\n"
++ " User-A is busy:\n"
++ " \"busy-notify-priority\",\n"
++ " \"busy-notify-exten\",\n"
++ " \"busy-notify-context\"\n",
++ .read = misdn_cc_read,
++};
++#endif /* defined(AST_MISDN_ENHANCEMENTS) */
++
+ /******************************************
+ *
+ * Asterisk Channel Endpoint END
+@@ -5265,24 +10537,28 @@
+ 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"); */
+ ast_unregister_application("misdn_set_opt");
+ ast_unregister_application("misdn_facility");
+ ast_unregister_application("misdn_check_l2l1");
++#if defined(AST_MISDN_ENHANCEMENTS)
++ ast_unregister_application(misdn_command_name);
++ ast_custom_function_unregister(&misdn_cc_function);
++#endif /* defined(AST_MISDN_ENHANCEMENTS) */
+
+ ast_channel_unregister(&misdn_tech);
+
+ free_robin_list();
+ misdn_cfg_destroy();
+ misdn_lib_destroy();
+-
++
+ if (misdn_debug) {
+ ast_free(misdn_debug);
+ }
+@@ -5290,7 +10566,11 @@
+ ast_free(misdn_debug_only);
+ }
+ ast_free(misdn_ports);
+-
++
++#if defined(AST_MISDN_ENHANCEMENTS)
++ misdn_cc_destroy();
++#endif /* defined(AST_MISDN_ENHANCEMENTS) */
++
+ return 0;
+ }
+
+@@ -5308,18 +10588,22 @@
+ };
+
+ 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;
+-
++
++#if defined(AST_MISDN_ENHANCEMENTS)
++ misdn_cc_init();
++#endif /* defined(AST_MISDN_ENHANCEMENTS) */
++
+ misdn_debug = ast_malloc(sizeof(int) * (max_ports + 1));
+ if (!misdn_debug) {
+ ast_log(LOG_ERROR, "Out of memory for misdn_debug\n");
+@@ -5366,7 +10650,7 @@
+
+ misdn_cfg_get(0, MISDN_GEN_NTDEBUGFLAGS, &ntflags, sizeof(ntflags));
+ misdn_cfg_get(0, MISDN_GEN_NTDEBUGFILE, &ntfile, sizeof(ntfile));
+- misdn_cfg_get( 0, MISDN_GEN_NTKEEPCALLS, &ntkc, sizeof(ntkc));
++ misdn_cfg_get(0, MISDN_GEN_NTKEEPCALLS, &ntkc, sizeof(ntkc));
+
+ misdn_lib_nt_keepcalls(ntkc);
+ misdn_lib_nt_debug_init(ntflags, ntfile);
+@@ -5376,7 +10660,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",
+@@ -5407,45 +10691,71 @@
+ " 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"
+- "the given Arguments to the current ISDN Channel\n"
+- "Supported Facilities are:\n"
+- "\n"
+- "type=calldeflect args=Nr where to deflect\n"
++ "misdn_facility(<FACILITY_TYPE>|<ARG1>|..)\n"
++ "Sends the Facility Message FACILITY_TYPE with \n"
++ "the given Arguments to the current ISDN Channel\n"
++ "Supported Facilities are:\n"
++ "\n"
++ "type=calldeflect args=Nr where to deflect\n"
+ );
+
+
+ ast_register_application("misdn_check_l2l1", misdn_check_l2l1, "misdn_check_l2l1",
+- "misdn_check_l2l1(<port>||g:<groupname>,timeout)"
+- "Checks if the L2 and L1 are up on either the given <port> or\n"
+- "on the ports in the group with <groupname>\n"
+- "If the L1/L2 are down, check_l2l1 gets up the L1/L2 and waits\n"
+- "for <timeout> seconds that this happens. Otherwise, nothing happens\n"
+- "\n"
+- "This application, ensures the L1/L2 state of the Ports in a group\n"
+- "it is intended to make the pmp_l1_check option redundant and to\n"
+- "fix a buggy switch config from your provider\n"
+- "\n"
+- "a sample dialplan would look like:\n\n"
+- "exten => _X.,1,misdn_check_l2l1(g:out|2)\n"
+- "exten => _X.,n,dial(mISDN/g:out/${EXTEN})\n"
+- "\n"
++ "misdn_check_l2l1(<port>||g:<groupname>,timeout)\n"
++ "Checks if the L2 and L1 are up on either the given <port> or\n"
++ "on the ports in the group with <groupname>\n"
++ "If the L1/L2 are down, check_l2l1 gets up the L1/L2 and waits\n"
++ "for <timeout> seconds that this happens. Otherwise, nothing happens\n"
++ "\n"
++ "This application, ensures the L1/L2 state of the Ports in a group\n"
++ "it is intended to make the pmp_l1_check option redundant and to\n"
++ "fix a buggy switch config from your provider\n"
++ "\n"
++ "a sample dialplan would look like:\n\n"
++ "exten => _X.,1,misdn_check_l2l1(g:out|2)\n"
++ "exten => _X.,n,dial(mISDN/g:out/${EXTEN})\n"
+ );
+
++#if defined(AST_MISDN_ENHANCEMENTS)
++ ast_register_application(misdn_command_name, misdn_command_exec, misdn_command_name,
++ "misdn_command(<command>[,<options>])\n"
++ "The following commands are defined:\n"
++ "cc-initialize\n"
++ " Setup mISDN support for call completion\n"
++ " Must call before doing any Dial() involving call completion.\n"
++ "ccnr-request,${MISDN_CC_RECORD_ID},<notify-context>,<user-a-extension>,<priority>\n"
++ " Request Call Completion No Reply activation\n"
++ "ccbs-request,${MISDN_CC_RECORD_ID},<notify-context>,<user-a-extension>,<priority>\n"
++ " Request Call Completion Busy Subscriber activation\n"
++ "cc-b-free,${MISDN_CC_RECORD_ID},<notify-context>,<user-a-extension>,<priority>\n"
++ " Set the dialplan location to notify when User-B is available but User-A is busy.\n"
++ " Setting this dialplan location is optional.\n"
++ "cc-a-busy,${MISDN_CC_RECORD_ID},<yes/no>\n"
++ " Set the busy status of call completion User-A\n"
++ "cc-deactivate,${MISDN_CC_RECORD_ID}\n"
++ " Deactivate the identified call completion request\n"
++ "\n"
++ "MISDN_CC_RECORD_ID is set when Dial() returns and call completion is possible\n"
++ "MISDN_CC_STATUS is set to ACTIVATED or ERROR after the call completion\n"
++ "activation request.\n"
++ "MISDN_ERROR_MSG is set to a descriptive message on error.\n"
++ );
+
++ ast_custom_function_register(&misdn_cc_function);
++#endif /* defined(AST_MISDN_ENHANCEMENTS) */
++
+ 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]);
+ }
+ }
+
+@@ -5465,23 +10775,646 @@
+
+ /*** SOME APPS ;)***/
+
+-static int misdn_facility_exec(struct ast_channel *chan, void *data)
++#if defined(AST_MISDN_ENHANCEMENTS)
++/*!
++* \brief misdn_command arguments container.
++*/
++AST_DEFINE_APP_ARGS_TYPE(misdn_command_args,
++ AST_APP_ARG(name); /* Subcommand name */
++ AST_APP_ARG(arg)[10 + 1]; /* Subcommand arguments */
++);
++#endif /* defined(AST_MISDN_ENHANCEMENTS) */
++
++#if defined(AST_MISDN_ENHANCEMENTS)
++static void misdn_cc_caller_destroy(void *obj)
+ {
++ /* oh snap! */
++}
++#endif /* defined(AST_MISDN_ENHANCEMENTS) */
++
++#if defined(AST_MISDN_ENHANCEMENTS)
++static struct misdn_cc_caller *misdn_cc_caller_alloc(struct ast_channel *chan)
++{
++ struct misdn_cc_caller *cc_caller;
++
++ if (!(cc_caller = ao2_alloc(sizeof(*cc_caller), misdn_cc_caller_destroy))) {
++ return NULL;
++ }
++
++ cc_caller->chan = chan;
++
++ return cc_caller;
++}
++#endif /* defined(AST_MISDN_ENHANCEMENTS) */
++
++#if defined(AST_MISDN_ENHANCEMENTS)
++/*!
++ * \internal
++ * \brief misdn_command(cc-initialize) subcommand handler
++ *
++ * \param chan Asterisk channel to operate upon.
++ * \param subcommand Arguments for the subcommand
++ *
++ * \retval 0 on success.
++ * \retval -1 on error.
++ */
++static int misdn_command_cc_initialize(struct ast_channel *chan, struct misdn_command_args *subcommand)
++{
++ struct misdn_cc_caller *cc_caller;
++ struct ast_datastore *datastore;
++
++ if (!(cc_caller = misdn_cc_caller_alloc(chan))) {
++ return -1;
++ }
++
++ if (!(datastore = ast_datastore_alloc(&misdn_cc_ds_info, NULL))) {
++ ao2_ref(cc_caller, -1);
++ return -1;
++ }
++
++ ast_channel_lock(chan);
++
++ /* Inherit reference */
++ datastore->data = cc_caller;
++ cc_caller = NULL;
++
++ datastore->inheritance = DATASTORE_INHERIT_FOREVER;
++
++ ast_channel_datastore_add(chan, datastore);
++
++ ast_channel_unlock(chan);
++
++ return 0;
++}
++#endif /* defined(AST_MISDN_ENHANCEMENTS) */
++
++#if defined(AST_MISDN_ENHANCEMENTS)
++/*!
++ * \internal
++ * \brief misdn_command(cc-deactivate) subcommand handler
++ *
++ * \details
++ * misdn_command(cc-deactivate,${MISDN_CC_RECORD_ID})
++ * Deactivate a call completion service instance.
++ *
++ * \param chan Asterisk channel to operate upon.
++ * \param subcommand Arguments for the subcommand
++ *
++ * \retval 0 on success.
++ * \retval -1 on error.
++ */
++static int misdn_command_cc_deactivate(struct ast_channel *chan, struct misdn_command_args *subcommand)
++{
++ long record_id;
++ const char *error_str;
++ struct misdn_cc_record *cc_record;
++ struct misdn_bchannel *bc;
++ struct misdn_bchannel dummy;
++
++ static const char cmd_help[] = "%s(%s,${MISDN_CC_RECORD_ID})\n";
++
++ if (ast_strlen_zero(subcommand->arg[0]) || !isdigit(*subcommand->arg[0])) {
++ ast_log(LOG_WARNING, cmd_help, misdn_command_name, subcommand->name);
++ return -1;
++ }
++ record_id = atol(subcommand->arg[0]);
++
++ AST_LIST_LOCK(&misdn_cc_records_db);
++ cc_record = misdn_cc_find_by_id(record_id);
++ if (cc_record && 0 <= cc_record->port) {
++ if (cc_record->ptp) {
++ if (cc_record->mode.ptp.bc) {
++ /* Close the call-completion signaling link */
++ bc = cc_record->mode.ptp.bc;
++ bc->fac_out.Function = Fac_None;
++ bc->out_cause = AST_CAUSE_NORMAL_CLEARING;
++ misdn_lib_send_event(bc, EVENT_RELEASE_COMPLETE);
++ }
++ misdn_cc_delete(cc_record);
++ } else if (cc_record->activated) {
++ cc_record->error_code = FacError_None;
++ cc_record->reject_code = FacReject_None;
++ cc_record->invoke_id = ++misdn_invoke_id;
++ cc_record->outstanding_message = 1;
++
++ /* Build message */
++ misdn_make_dummy(&dummy, cc_record->port, 0, misdn_lib_port_is_nt(cc_record->port), 0);
++ dummy.fac_out.Function = Fac_CCBSDeactivate;
++ dummy.fac_out.u.CCBSDeactivate.InvokeID = cc_record->invoke_id;
++ dummy.fac_out.u.CCBSDeactivate.ComponentType = FacComponent_Invoke;
++ dummy.fac_out.u.CCBSDeactivate.Component.Invoke.CCBSReference = cc_record->mode.ptmp.reference_id;
++
++ /* Send message */
++ print_facility(&dummy.fac_out, &dummy);
++ misdn_lib_send_event(&dummy, EVENT_FACILITY);
++ }
++ }
++ AST_LIST_UNLOCK(&misdn_cc_records_db);
++
++ /* Wait for the response to the call completion deactivation request. */
++ misdn_cc_response_wait(chan, MISDN_CC_REQUEST_WAIT_MAX, record_id);
++
++ AST_LIST_LOCK(&misdn_cc_records_db);
++ cc_record = misdn_cc_find_by_id(record_id);
++ if (cc_record) {
++ if (cc_record->port < 0) {
++ /* The network did not tell us that call completion was available. */
++ error_str = NULL;
++ } else if (cc_record->outstanding_message) {
++ cc_record->outstanding_message = 0;
++ error_str = misdn_no_response_from_network;
++ } else if (cc_record->reject_code != FacReject_None) {
++ error_str = misdn_to_str_reject_code(cc_record->reject_code);
++ } else if (cc_record->reject_code != FacError_None) {
++ error_str = misdn_to_str_error_code(cc_record->error_code);
++ } else {
++ error_str = NULL;
++ }
++
++ misdn_cc_delete(cc_record);
++ } else {
++ error_str = NULL;
++ }
++ AST_LIST_UNLOCK(&misdn_cc_records_db);
++ if (error_str) {
++ ast_verb(1, "%s(%s) diagnostic '%s' on channel %s\n",
++ misdn_command_name, subcommand->name, error_str, chan->name);
++ pbx_builtin_setvar_helper(chan, MISDN_ERROR_MSG, error_str);
++ }
++
++ return 0;
++}
++#endif /* defined(AST_MISDN_ENHANCEMENTS) */
++
++#if defined(AST_MISDN_ENHANCEMENTS)
++/*!
++ * \internal
++ * \brief misdn_command(cc-a-busy) subcommand handler
++ *
++ * \details
++ * misdn_command(cc-a-busy,${MISDN_CC_RECORD_ID},<yes/no>)
++ * Set the status of User-A for a call completion service instance.
++ *
++ * \param chan Asterisk channel to operate upon.
++ * \param subcommand Arguments for the subcommand
++ *
++ * \retval 0 on success.
++ * \retval -1 on error.
++ */
++static int misdn_command_cc_a_busy(struct ast_channel *chan, struct misdn_command_args *subcommand)
++{
++ long record_id;
++ int party_a_free;
++ struct misdn_cc_record *cc_record;
++ struct misdn_bchannel *bc;
++
++ static const char cmd_help[] = "%s(%s,${MISDN_CC_RECORD_ID},<yes/no>)\n";
++
++ if (ast_strlen_zero(subcommand->arg[0]) || !isdigit(*subcommand->arg[0])) {
++ ast_log(LOG_WARNING, cmd_help, misdn_command_name, subcommand->name);
++ return -1;
++ }
++ record_id = atol(subcommand->arg[0]);
++
++ if (ast_true(subcommand->arg[1])) {
++ party_a_free = 0;
++ } else if (ast_false(subcommand->arg[1])) {
++ party_a_free = 1;
++ } else {
++ ast_log(LOG_WARNING, cmd_help, misdn_command_name, subcommand->name);
++ return -1;
++ }
++
++ AST_LIST_LOCK(&misdn_cc_records_db);
++ cc_record = misdn_cc_find_by_id(record_id);
++ if (cc_record && cc_record->party_a_free != party_a_free) {
++ /* User-A's status has changed */
++ cc_record->party_a_free = party_a_free;
++
++ if (cc_record->ptp && cc_record->mode.ptp.bc) {
++ cc_record->error_code = FacError_None;
++ cc_record->reject_code = FacReject_None;
++
++ /* Build message */
++ bc = cc_record->mode.ptp.bc;
++ if (cc_record->party_a_free) {
++ bc->fac_out.Function = Fac_CCBS_T_Resume;
++ bc->fac_out.u.CCBS_T_Resume.InvokeID = ++misdn_invoke_id;
++ } else {
++ bc->fac_out.Function = Fac_CCBS_T_Suspend;
++ bc->fac_out.u.CCBS_T_Suspend.InvokeID = ++misdn_invoke_id;
++ }
++
++ /* Send message */
++ print_facility(&bc->fac_out, bc);
++ misdn_lib_send_event(bc, EVENT_FACILITY);
++ }
++ }
++ AST_LIST_UNLOCK(&misdn_cc_records_db);
++
++ return 0;
++}
++#endif /* defined(AST_MISDN_ENHANCEMENTS) */
++
++#if defined(AST_MISDN_ENHANCEMENTS)
++/*!
++ * \internal
++ * \brief misdn_command(cc-b-free) subcommand handler
++ *
++ * \details
++ * misdn_command(cc-b-free,${MISDN_CC_RECORD_ID},<notify-context>,<user-a-extension>,<priority>)
++ * Set the dialplan location to notify when User-B is free and User-A is busy.
++ *
++ * \param chan Asterisk channel to operate upon.
++ * \param subcommand Arguments for the subcommand
++ *
++ * \retval 0 on success.
++ * \retval -1 on error.
++ */
++static int misdn_command_cc_b_free(struct ast_channel *chan, struct misdn_command_args *subcommand)
++{
++ unsigned index;
++ long record_id;
++ int priority;
++ char *context;
++ char *exten;
++ struct misdn_cc_record *cc_record;
++
++ static const char cmd_help[] = "%s(%s,${MISDN_CC_RECORD_ID},<notify-context>,<user-a-extension>,<priority>)\n";
++
++ /* Check that all arguments are present */
++ for (index = 0; index < 4; ++index) {
++ if (ast_strlen_zero(subcommand->arg[index])) {
++ ast_log(LOG_WARNING, cmd_help, misdn_command_name, subcommand->name);
++ return -1;
++ }
++ }
++
++ /* These must be numeric */
++ if (!isdigit(*subcommand->arg[0]) || !isdigit(*subcommand->arg[3])) {
++ ast_log(LOG_WARNING, cmd_help, misdn_command_name, subcommand->name);
++ return -1;
++ }
++
++ record_id = atol(subcommand->arg[0]);
++ context = subcommand->arg[1];
++ exten = subcommand->arg[2];
++ priority = atoi(subcommand->arg[3]);
++
++ AST_LIST_LOCK(&misdn_cc_records_db);
++ cc_record = misdn_cc_find_by_id(record_id);
++ if (cc_record) {
++ /* Save User-B free information */
++ ast_copy_string(cc_record->b_free.context, context, sizeof(cc_record->b_free.context));
++ ast_copy_string(cc_record->b_free.exten, exten, sizeof(cc_record->b_free.exten));
++ cc_record->b_free.priority = priority;
++ }
++ AST_LIST_UNLOCK(&misdn_cc_records_db);
++
++ return 0;
++}
++#endif /* defined(AST_MISDN_ENHANCEMENTS) */
++
++#if defined(AST_MISDN_ENHANCEMENTS)
++struct misdn_cc_request {
++ enum FacFunction ptmp;
++ enum FacFunction ptp;
++};
++#endif /* defined(AST_MISDN_ENHANCEMENTS) */
++
++#if defined(AST_MISDN_ENHANCEMENTS)
++/*!
++ * \internal
++ * \brief misdn_command(ccbs-request/ccnr-request) subcommand handler helper
++ *
++ * \details
++ * misdn_command(ccbs-request,${MISDN_CC_RECORD_ID},<notify-context>,<user-a-extension>,<priority>)
++ * misdn_command(ccnr-request,${MISDN_CC_RECORD_ID},<notify-context>,<user-a-extension>,<priority>)
++ * Set the dialplan location to notify when User-B is free and User-A is free.
++ *
++ * \param chan Asterisk channel to operate upon.
++ * \param subcommand Arguments for the subcommand
++ * \param request Which call-completion request message to generate.
++ *
++ * \retval 0 on success.
++ * \retval -1 on error.
++ */
++static int misdn_command_cc_request(struct ast_channel *chan, struct misdn_command_args *subcommand, const struct misdn_cc_request *request)
++{
++ unsigned index;
++ int request_retention;
++ long record_id;
++ int priority;
++ char *context;
++ char *exten;
++ const char *error_str;
++ struct misdn_cc_record *cc_record;
++ struct misdn_bchannel *bc;
++ struct misdn_bchannel dummy;
++ struct misdn_party_id id;
++
++ static const char cmd_help[] = "%s(%s,${MISDN_CC_RECORD_ID},<notify-context>,<user-a-extension>,<priority>)\n";
++
++ /* Check that all arguments are present */
++ for (index = 0; index < 4; ++index) {
++ if (ast_strlen_zero(subcommand->arg[index])) {
++ ast_log(LOG_WARNING, cmd_help, misdn_command_name, subcommand->name);
++ return -1;
++ }
++ }
++
++ /* These must be numeric */
++ if (!isdigit(*subcommand->arg[0]) || !isdigit(*subcommand->arg[3])) {
++ ast_log(LOG_WARNING, cmd_help, misdn_command_name, subcommand->name);
++ return -1;
++ }
++
++ record_id = atol(subcommand->arg[0]);
++ context = subcommand->arg[1];
++ exten = subcommand->arg[2];
++ priority = atoi(subcommand->arg[3]);
++
++ AST_LIST_LOCK(&misdn_cc_records_db);
++ cc_record = misdn_cc_find_by_id(record_id);
++ if (cc_record) {
++ /* Save User-B free information */
++ ast_copy_string(cc_record->remote_user_free.context, context,
++ sizeof(cc_record->remote_user_free.context));
++ ast_copy_string(cc_record->remote_user_free.exten, exten,
++ sizeof(cc_record->remote_user_free.exten));
++ cc_record->remote_user_free.priority = priority;
++
++ if (0 <= cc_record->port) {
++ if (cc_record->ptp) {
++ if (!cc_record->mode.ptp.bc) {
++ bc = misdn_lib_get_register_bc(cc_record->port);
++ if (bc) {
++ cc_record->mode.ptp.bc = bc;
++ cc_record->error_code = FacError_None;
++ cc_record->reject_code = FacReject_None;
++ cc_record->invoke_id = ++misdn_invoke_id;
++ cc_record->outstanding_message = 1;
++ cc_record->activation_requested = 1;
++
++ misdn_cfg_get(bc->port, MISDN_CFG_CC_REQUEST_RETENTION,
++ &request_retention, sizeof(request_retention));
++ cc_record->mode.ptp.requested_retention = request_retention ? 1 : 0;
++
++ /* Build message */
++ bc->fac_out.Function = request->ptp;
++ bc->fac_out.u.CCBS_T_Request.InvokeID = cc_record->invoke_id;
++ bc->fac_out.u.CCBS_T_Request.ComponentType = FacComponent_Invoke;
++ bc->fac_out.u.CCBS_T_Request.Component.Invoke.Q931ie =
++ cc_record->redial.setup_bc_hlc_llc;
++ memset(&id, 0, sizeof(id));
++ id.number_plan = cc_record->redial.dialed.number_plan;
++ id.number_type = cc_record->redial.dialed.number_type;
++ ast_copy_string(id.number, cc_record->redial.dialed.number,
++ sizeof(id.number));
++ misdn_Address_fill(
++ &bc->fac_out.u.CCBS_T_Request.Component.Invoke.Destination,
++ &id);
++ misdn_Address_fill(
++ &bc->fac_out.u.CCBS_T_Request.Component.Invoke.Originating,
++ &cc_record->redial.caller);
++ bc->fac_out.u.CCBS_T_Request.Component.Invoke.PresentationAllowedIndicatorPresent = 1;
++ bc->fac_out.u.CCBS_T_Request.Component.Invoke.PresentationAllowedIndicator =
++ (cc_record->redial.caller.presentation != 0) ? 0 : 1;
++ bc->fac_out.u.CCBS_T_Request.Component.Invoke.RetentionSupported =
++ request_retention ? 1 : 0;
++
++ /* Send message */
++ print_facility(&bc->fac_out, bc);
++ misdn_lib_send_event(bc, EVENT_REGISTER);
++ }
++ }
++ } else {
++ cc_record->error_code = FacError_None;
++ cc_record->reject_code = FacReject_None;
++ cc_record->invoke_id = ++misdn_invoke_id;
++ cc_record->outstanding_message = 1;
++ cc_record->activation_requested = 1;
++
++ /* Build message */
++ misdn_make_dummy(&dummy, cc_record->port, 0,
++ misdn_lib_port_is_nt(cc_record->port), 0);
++ dummy.fac_out.Function = request->ptmp;
++ dummy.fac_out.u.CCBSRequest.InvokeID = cc_record->invoke_id;
++ dummy.fac_out.u.CCBSRequest.ComponentType = FacComponent_Invoke;
++ dummy.fac_out.u.CCBSRequest.Component.Invoke.CallLinkageID =
++ cc_record->mode.ptmp.linkage_id;
++
++ /* Send message */
++ print_facility(&dummy.fac_out, &dummy);
++ misdn_lib_send_event(&dummy, EVENT_FACILITY);
++ }
++ }
++ }
++ AST_LIST_UNLOCK(&misdn_cc_records_db);
++
++ /* Wait for the response to the call completion request. */
++ misdn_cc_response_wait(chan, MISDN_CC_REQUEST_WAIT_MAX, record_id);
++
++ AST_LIST_LOCK(&misdn_cc_records_db);
++ cc_record = misdn_cc_find_by_id(record_id);
++ if (cc_record) {
++ if (!cc_record->activated) {
++ if (cc_record->port < 0) {
++ /* The network did not tell us that call completion was available. */
++ error_str = "No port number";
++ } else if (cc_record->outstanding_message) {
++ cc_record->outstanding_message = 0;
++ error_str = misdn_no_response_from_network;
++ } else if (cc_record->reject_code != FacReject_None) {
++ error_str = misdn_to_str_reject_code(cc_record->reject_code);
++ } else if (cc_record->error_code != FacError_None) {
++ error_str = misdn_to_str_error_code(cc_record->error_code);
++ } else if (cc_record->ptp) {
++ if (cc_record->mode.ptp.bc) {
++ error_str = "Call-completion already requested";
++ } else {
++ error_str = "Could not allocate call-completion signaling link";
++ }
++ } else {
++ /* Should never happen. */
++ error_str = "Unexpected error";
++ }
++
++ /* No need to keep the call completion record. */
++ if (cc_record->ptp && cc_record->mode.ptp.bc) {
++ /* Close the call-completion signaling link */
++ bc = cc_record->mode.ptp.bc;
++ bc->fac_out.Function = Fac_None;
++ bc->out_cause = AST_CAUSE_NORMAL_CLEARING;
++ misdn_lib_send_event(bc, EVENT_RELEASE_COMPLETE);
++ }
++ misdn_cc_delete(cc_record);
++ } else {
++ error_str = NULL;
++ }
++ } else {
++ error_str = misdn_cc_record_not_found;
++ }
++ AST_LIST_UNLOCK(&misdn_cc_records_db);
++ if (error_str) {
++ ast_verb(1, "%s(%s) diagnostic '%s' on channel %s\n",
++ misdn_command_name, subcommand->name, error_str, chan->name);
++ pbx_builtin_setvar_helper(chan, MISDN_ERROR_MSG, error_str);
++ pbx_builtin_setvar_helper(chan, MISDN_CC_STATUS, "ERROR");
++ } else {
++ pbx_builtin_setvar_helper(chan, MISDN_CC_STATUS, "ACTIVATED");
++ }
++
++ return 0;
++}
++#endif /* defined(AST_MISDN_ENHANCEMENTS) */
++
++#if defined(AST_MISDN_ENHANCEMENTS)
++/*!
++ * \internal
++ * \brief misdn_command(ccbs-request) subcommand handler
++ *
++ * \details
++ * misdn_command(ccbs-request,${MISDN_CC_RECORD_ID},<notify-context>,<user-a-extension>,<priority>)
++ * Set the dialplan location to notify when User-B is free and User-A is free.
++ *
++ * \param chan Asterisk channel to operate upon.
++ * \param subcommand Arguments for the subcommand
++ *
++ * \retval 0 on success.
++ * \retval -1 on error.
++ */
++static int misdn_command_ccbs_request(struct ast_channel *chan, struct misdn_command_args *subcommand)
++{
++ static const struct misdn_cc_request request = {
++ .ptmp = Fac_CCBSRequest,
++ .ptp = Fac_CCBS_T_Request
++ };
++
++ return misdn_command_cc_request(chan, subcommand, &request);
++}
++#endif /* defined(AST_MISDN_ENHANCEMENTS) */
++
++#if defined(AST_MISDN_ENHANCEMENTS)
++/*!
++ * \internal
++ * \brief misdn_command(ccnr-request) subcommand handler
++ *
++ * \details
++ * misdn_command(ccnr-request,${MISDN_CC_RECORD_ID},<notify-context>,<user-a-extension>,<priority>)
++ * Set the dialplan location to notify when User-B is free and User-A is free.
++ *
++ * \param chan Asterisk channel to operate upon.
++ * \param subcommand Arguments for the subcommand
++ *
++ * \retval 0 on success.
++ * \retval -1 on error.
++ */
++static int misdn_command_ccnr_request(struct ast_channel *chan, struct misdn_command_args *subcommand)
++{
++ static const struct misdn_cc_request request = {
++ .ptmp = Fac_CCNRRequest,
++ .ptp = Fac_CCNR_T_Request
++ };
++
++ return misdn_command_cc_request(chan, subcommand, &request);
++}
++#endif /* defined(AST_MISDN_ENHANCEMENTS) */
++
++#if defined(AST_MISDN_ENHANCEMENTS)
++struct misdn_command_table {
++ /*! \brief subcommand name */
++ const char *name;
++
++ /*! \brief subcommand handler */
++ int (*func)(struct ast_channel *chan, struct misdn_command_args *subcommand);
++
++ /*! \brief TRUE if the subcommand can only be executed on mISDN channels */
++ int misdn_only;
++};
++static const struct misdn_command_table misdn_commands[] = {
++/* *INDENT-OFF* */
++ /* subcommand-name subcommand-handler mISDN only */
++ { "cc-initialize", misdn_command_cc_initialize, 0 },
++ { "cc-deactivate", misdn_command_cc_deactivate, 0 },
++ { "cc-a-busy", misdn_command_cc_a_busy, 0 },
++ { "cc-b-free", misdn_command_cc_b_free, 0 },
++ { "ccbs-request", misdn_command_ccbs_request, 0 },
++ { "ccnr-request", misdn_command_ccnr_request, 0 },
++/* *INDENT-ON* */
++};
++#endif /* defined(AST_MISDN_ENHANCEMENTS) */
++
++#if defined(AST_MISDN_ENHANCEMENTS)
++/*!
++ * \internal
++ * \brief misdn_command() dialplan application.
++ *
++ * \param chan Asterisk channel to operate upon.
++ * \param data Application options string.
++ *
++ * \retval 0 on success.
++ * \retval -1 on error.
++ */
++static int misdn_command_exec(struct ast_channel *chan, const char *data)
++{
++ char *parse;
++ unsigned index;
++ struct misdn_command_args subcommand;
++
++ if (ast_strlen_zero((char *) data)) {
++ ast_log(LOG_ERROR, "%s requires arguments\n", misdn_command_name);
++ return -1;
++ }
++
++ ast_log(LOG_DEBUG, "%s(%s)\n", misdn_command_name, (char *) data);
++
++ parse = ast_strdupa(data);
++ AST_STANDARD_APP_ARGS(subcommand, parse);
++ if (!subcommand.argc || ast_strlen_zero(subcommand.name)) {
++ ast_log(LOG_ERROR, "%s requires a subcommand\n", misdn_command_name);
++ return -1;
++ }
++
++ for (index = 0; index < ARRAY_LEN(misdn_commands); ++index) {
++ if (strcasecmp(misdn_commands[index].name, subcommand.name) == 0) {
++ strcpy(subcommand.name, misdn_commands[index].name);
++ if (misdn_commands[index].misdn_only
++ && strcasecmp(chan->tech->type, misdn_type) != 0) {
++ ast_log(LOG_WARNING,
++ "%s(%s) only makes sense with %s channels!\n",
++ misdn_command_name, subcommand.name, misdn_type);
++ return -1;
++ }
++ return misdn_commands[index].func(chan, &subcommand);
++ }
++ }
++
++ ast_log(LOG_WARNING, "%s(%s) subcommand is unknown\n", misdn_command_name,
++ subcommand.name);
++ return -1;
++}
++#endif /* defined(AST_MISDN_ENHANCEMENTS) */
++
++static int misdn_facility_exec(struct ast_channel *chan, const char *data)
++{
+ struct chan_list *ch = MISDN_ASTERISK_TECH_PVT(chan);
+ char *parse;
++ unsigned max_len;
++
+ 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");
++
++ if (strcasecmp(chan->tech->type, misdn_type)) {
++ ast_log(LOG_WARNING, "misdn_facility only makes sense with %s channels!\n", misdn_type);
+ 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;
+ }
+@@ -5499,12 +11432,41 @@
+ ast_log(LOG_WARNING, "Facility: Call Deflection requires an argument: Number\n");
+ }
+
+- 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));
++#if defined(AST_MISDN_ENHANCEMENTS)
++ max_len = sizeof(ch->bc->fac_out.u.CallDeflection.Component.Invoke.Deflection.Party.Number) - 1;
++ if (max_len < strlen(args.arg[0])) {
++ ast_log(LOG_WARNING,
++ "Facility: Number argument too long (up to %u digits are allowed). Ignoring.\n",
++ max_len);
+ return 0;
+ }
++ ch->bc->fac_out.Function = Fac_CallDeflection;
++ ch->bc->fac_out.u.CallDeflection.InvokeID = ++misdn_invoke_id;
++ ch->bc->fac_out.u.CallDeflection.ComponentType = FacComponent_Invoke;
++ ch->bc->fac_out.u.CallDeflection.Component.Invoke.PresentationAllowedToDivertedToUserPresent = 1;
++ ch->bc->fac_out.u.CallDeflection.Component.Invoke.PresentationAllowedToDivertedToUser = 0;
++ ch->bc->fac_out.u.CallDeflection.Component.Invoke.Deflection.Party.Type = 0;/* unknown */
++ ch->bc->fac_out.u.CallDeflection.Component.Invoke.Deflection.Party.LengthOfNumber = strlen(args.arg[0]);
++ strcpy((char *) ch->bc->fac_out.u.CallDeflection.Component.Invoke.Deflection.Party.Number, args.arg[0]);
++ ch->bc->fac_out.u.CallDeflection.Component.Invoke.Deflection.Subaddress.Length = 0;
++
++#else /* !defined(AST_MISDN_ENHANCEMENTS) */
++
++ max_len = sizeof(ch->bc->fac_out.u.CDeflection.DeflectedToNumber) - 1;
++ if (max_len < strlen(args.arg[0])) {
++ ast_log(LOG_WARNING,
++ "Facility: Number argument too long (up to %u digits are allowed). Ignoring.\n",
++ max_len);
++ return 0;
++ }
+ ch->bc->fac_out.Function = Fac_CD;
+- ast_copy_string((char *)ch->bc->fac_out.u.CDeflection.DeflectedToNumber, args.arg[0], sizeof(ch->bc->fac_out.u.CDeflection.DeflectedToNumber));
++ ch->bc->fac_out.u.CDeflection.PresentationAllowed = 0;
++ //ch->bc->fac_out.u.CDeflection.DeflectedToSubaddress[0] = 0;
++ strcpy((char *) ch->bc->fac_out.u.CDeflection.DeflectedToNumber, args.arg[0]);
++#endif /* !defined(AST_MISDN_ENHANCEMENTS) */
++
++ /* Send message */
++ print_facility(&ch->bc->fac_out, ch->bc);
+ misdn_lib_send_event(ch->bc, EVENT_FACILITY);
+ } else {
+ chan_misdn_log(1, ch->bc->port, "Unknown Facility: %s\n", args.facility_type);
+@@ -5513,7 +11475,7 @@
+ return 0;
+ }
+
+-static int misdn_check_l2l1(struct ast_channel *chan, void *data)
++static int misdn_check_l2l1(struct ast_channel *chan, const char *data)
+ {
+ char *parse;
+ char group[BUFFERSIZE + 1];
+@@ -5524,11 +11486,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;
+ }
+@@ -5545,13 +11507,13 @@
+ timeout = atoi(args.timeout);
+ port_str = args.grouppar;
+
+- if (port_str[0] == 'g' && port_str[1] == ':' ) {
++ if (port_str[0] == 'g' && port_str[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));
+ 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];
+@@ -5562,7 +11524,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);
+@@ -5570,10 +11531,9 @@
+ }
+ }
+ }
+-
+ } else {
+ port = atoi(port_str);
+- chan_misdn_log(2, 0, "Checking Port: %d\n",port);
++ chan_misdn_log(2, 0, "Checking Port: %d\n", port);
+ port_up = misdn_lib_port_up(port, 1);
+ if (!port_up) {
+ misdn_lib_get_port_up(port);
+@@ -5589,54 +11549,53 @@
+ return 0;
+ }
+
+-static int misdn_set_opt_exec(struct ast_channel *chan, void *data)
++static int misdn_set_opt_exec(struct ast_channel *chan, const char *data)
+ {
+ struct chan_list *ch = MISDN_ASTERISK_TECH_PVT(chan);
+- char *tok, *tokb, *parse;
+- int keyidx = 0;
++ char *tok;
++ char *tokb;
++ char *parse;
++ int keyidx = 0;
+ int rxgain = 0;
+ int txgain = 0;
+ int change_jitter = 0;
+
+- if (strcasecmp(chan->tech->type, "mISDN")) {
+- ast_log(LOG_WARNING, "misdn_set_opt makes only sense with chan_misdn channels!\n");
++ if (strcasecmp(chan->tech->type, misdn_type)) {
++ ast_log(LOG_WARNING, "misdn_set_opt makes sense only with %s channels!\n", misdn_type);
+ return -1;
+ }
+-
+- if (ast_strlen_zero((char *)data)) {
++
++ if (ast_strlen_zero((char *) data)) {
+ ast_log(LOG_WARNING, "misdn_set_opt Requires arguments\n");
+ return -1;
+ }
+
+ parse = ast_strdupa(data);
+ for (tok = strtok_r(parse, ":", &tokb);
+- tok;
+- tok = strtok_r(NULL, ":", &tokb) ) {
++ tok;
++ tok = strtok_r(NULL, ":", &tokb)) {
+ int neglect = 0;
+
+- if (tok[0] == '!' ) {
++ if (tok[0] == '!') {
+ 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;
+ break;
+-
+ case 'j':
+ chan_misdn_log(1, ch->bc->port, "SETOPT: jitter\n");
+ tok++;
+ change_jitter = 1;
+
+- switch ( tok[0] ) {
++ switch (tok[0]) {
+ case 'b':
+ ch->jb_len = atoi(++tok);
+ chan_misdn_log(1, ch->bc->port, " --> buffer_len:%d\n", ch->jb_len);
+@@ -5654,6 +11613,7 @@
+ ch->jb_upper_threshold = 0;
+ chan_misdn_log(1, ch->bc->port, " --> buffer_len:%d (default)\n", ch->jb_len);
+ chan_misdn_log(1, ch->bc->port, " --> upper_threshold:%d (default)\n", ch->jb_upper_threshold);
++ break;
+ }
+ break;
+ case 'v':
+@@ -5684,13 +11644,14 @@
+ break;
+ }
+ break;
+-
+ case 'c':
+ keyidx = atoi(++tok);
+ {
+ char keys[4096];
+- char *key = NULL, *tmp = keys;
++ char *key = NULL;
++ char *tmp = keys;
+ int i;
++
+ misdn_cfg_get(0, MISDN_GEN_CRYPT_KEYS, keys, sizeof(keys));
+
+ for (i = 0; i < keyidx; i++) {
+@@ -5706,7 +11667,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
+@@ -5726,11 +11687,10 @@
+ }
+ #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) {
+@@ -5739,38 +11699,37 @@
+ }
+ 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;
+ misdn_cfg_get(ch->bc->port, MISDN_CFG_FAXDETECT_TIMEOUT, &ch->faxdetect_timeout, sizeof(ch->faxdetect_timeout));
+ break;
+-
+ case 'a':
+ chan_misdn_log(1, ch->bc->port, "SETOPT: AST_DSP (for DTMF)\n");
+ ch->ast_dsp = 1;
+ break;
+-
+ 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;
++ 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' :
+ chan_misdn_log(1, ch->bc->port, "Ignoring dtmf tones, just use them inband\n");
+- ch->ignore_dtmf=1;
++ ch->ignore_dtmf = 1;
+ break;
+ default:
+ break;
+@@ -5797,19 +11756,19 @@
+ chan_misdn_log(1, ch->bc->port, "SETOPT: with AST_DSP we deactivate mISDN_dsp\n");
+ ch->bc->nodsp = 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;
+ }
+
+@@ -5866,7 +11825,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);
+@@ -5876,17 +11835,20 @@
+ error (buffer overflow). */
+ int misdn_jb_fill(struct misdn_jb *jb, const char *data, int len)
+ {
+- int i, j, rp, wp;
++ int i;
++ int j;
++ int rp;
++ int wp;
+
+ if (!jb || ! data) {
+ return 0;
+ }
+
+ 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;
+@@ -5930,7 +11892,7 @@
+ jb->wp = wp;
+
+ ast_mutex_unlock(&jb->mutexjb);
+-
++
+ return 0;
+ }
+
+@@ -5939,14 +11901,17 @@
+ of data. */
+ int misdn_jb_empty(struct misdn_jb *jb, char *data, int len)
+ {
+- int i, wp, rp, read = 0;
++ int i;
++ int wp;
++ int rp;
++ int read = 0;
+
+ ast_mutex_lock(&jb->mutexjb);
+
+ 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;
+@@ -5982,66 +11947,70 @@
+ return read;
+ }
+
+-
+-
+-
+ /*******************************************************/
+ /*************** JITTERBUFFER END *********************/
+ /*******************************************************/
+
+-
+-
+-
+ static void chan_misdn_log(int level, int port, char *tmpl, ...)
+ {
+ va_list ap;
+ char buf[1024];
+ char port_buf[8];
+
+- if (! ((0 <= port) && (port <= max_ports))) {
++ if (!(0 <= port && port <= max_ports)) {
+ ast_log(LOG_WARNING, "cb_log called with out-of-range port number! (%d)\n", port);
+ port = 0;
+ level = -1;
++ } else if (!(level == -1
++ || (misdn_debug_only[port]
++ ? (level == 1 && misdn_debug[port]) || level == misdn_debug[port]
++ : level <= misdn_debug[port])
++ || (level <= misdn_debug[0] && !ast_strlen_zero(global_tracefile)))) {
++ /*
++ * We are not going to print anything so lets not
++ * go to all the work of generating a string.
++ */
++ return;
+ }
+
+ snprintf(port_buf, sizeof(port_buf), "P[%2d] ", port);
+-
+ va_start(ap, tmpl);
+ vsnprintf(buf, sizeof(buf), tmpl, ap);
+ va_end(ap);
+
+ 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) ) {
++
++ if (level <= misdn_debug[0] && !ast_strlen_zero(global_tracefile)) {
+ char ctimebuf[30];
+- time_t tm = time(NULL);
+- char *tmp = ctime_r(&tm, ctimebuf), *p;
++ time_t tm;
++ char *tmp;
++ char *p;
++ FILE *fp;
+
+- FILE *fp = fopen(global_tracefile, "a+");
+-
+- if ((p = strchr(tmp, '\n'))) {
+- *p = ':';
+- }
+-
++ fp = fopen(global_tracefile, "a+");
+ 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 ;
++ return;
+ }
+-
++
++ tm = time(NULL);
++ tmp = ctime_r(&tm, ctimebuf);
++ p = strchr(tmp, '\n');
++ if (p) {
++ *p = ':';
++ }
+ fputs(tmp, fp);
+ fputs(" ", fp);
+ fputs(port_buf, fp);
+Index: channels/chan_skinny.c
+===================================================================
+--- a/channels/chan_skinny.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/channels/chan_skinny.c (.../trunk) (revision 202568)
+@@ -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"
+@@ -71,6 +71,63 @@
+ #include "asterisk/indications.h"
+ #include "asterisk/linkedlists.h"
+
++/*** DOCUMENTATION
++ <manager name="SKINNYdevices" language="en_US">
++ <synopsis>
++ List SKINNY devices (text format).
++ </synopsis>
++ <syntax>
++ <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
++ </syntax>
++ <description>
++ <para>Lists Skinny devices in text format with details on current status.
++ Devicelist will follow as separate events, followed by a final event called
++ DevicelistComplete.</para>
++ </description>
++ </manager>
++ <manager name="SKINNYshowdevice" language="en_US">
++ <synopsis>
++ Show SKINNY device (text format).
++ </synopsis>
++ <syntax>
++ <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
++ <parameter name="Device" required="true">
++ <para>The device name you want to check.</para>
++ </parameter>
++ </syntax>
++ <description>
++ <para>Show one SKINNY device with details on current status.</para>
++ </description>
++ </manager>
++ <manager name="SKINNYlines" language="en_US">
++ <synopsis>
++ List SKINNY lines (text format).
++ </synopsis>
++ <syntax>
++ <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
++ </syntax>
++ <description>
++ <para>Lists Skinny lines in text format with details on current status.
++ Linelist will follow as separate events, followed by a final event called
++ LinelistComplete.</para>
++ </description>
++ </manager>
++ <manager name="SKINNYshowline" language="en_US">
++ <synopsis>
++ Show SKINNY line (text format).
++ </synopsis>
++ <syntax>
++ <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
++ <parameter name="Line" required="true">
++ <para>The line name you want to check.</para>
++ </parameter>
++ </syntax>
++ <description>
++ <para>Show one SKINNY line with details on current status.</para>
++ </description>
++ </manager>
++ ***/
++
+ #ifdef SKINNY_DEVMODE
+ #define SKINNY_DEVONLY(code) \
+ code
+@@ -585,7 +642,7 @@
+ #define SOFTKEY_DND 0x13
+ #define SOFTKEY_IDIVERT 0x14
+
+-struct soft_key_template_definition soft_key_template_default[] = {
++static struct soft_key_template_definition soft_key_template_default[] = {
+ { "\200\001", SOFTKEY_REDIAL },
+ { "\200\002", SOFTKEY_NEWCALL },
+ { "\200\003", SOFTKEY_HOLD },
+@@ -963,7 +1020,7 @@
+ /* XXX This is the combined size of the variables above. (len, res, e)
+ If more are added, this MUST change.
+ (sizeof(skinny_req) - sizeof(skinny_data)) DOES NOT WORK on all systems (amd64?). */
+-int skinny_header_size = 12;
++static int skinny_header_size = 12;
+
+ /*****************************
+ * Asterisk specific globals *
+@@ -977,8 +1034,8 @@
+ static char ourhost[256];
+ static int ourport;
+ static struct in_addr __ourip;
+-struct ast_hostent ahp;
+-struct hostent *hp;
++static struct ast_hostent ahp;
++static struct hostent *hp;
+ static int skinnysock = -1;
+ static pthread_t accept_t;
+ static int callnums = 1;
+@@ -1076,7 +1133,7 @@
+ #define SKINNY_CX_INACTIVE 4
+
+ #if 0
+-static char *skinny_cxmodes[] = {
++static const char * const skinny_cxmodes[] = {
+ "sendonly",
+ "recvonly",
+ "sendrecv",
+@@ -1111,8 +1168,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;
+@@ -1198,7 +1255,7 @@
+ int newmsgs;
+ };
+
+-struct skinny_line_options{
++static struct skinny_line_options{
+ SKINNY_LINE_OPTIONS
+ } default_line_struct = {
+ .callwaiting = 1,
+@@ -1217,7 +1274,7 @@
+ .prune = 0,
+ .hookstate = SKINNY_ONHOOK,
+ };
+-struct skinny_line_options *default_line = &default_line_struct;
++static struct skinny_line_options *default_line = &default_line_struct;
+
+ static AST_LIST_HEAD_STATIC(lines, skinny_line);
+
+@@ -1278,7 +1335,7 @@
+ AST_LIST_ENTRY(skinny_device) list;
+ };
+
+-struct skinny_device_options{
++static struct skinny_device_options {
+ SKINNY_DEVICE_OPTIONS
+ } default_device_struct = {
+ .transfer = 1,
+@@ -1290,7 +1347,7 @@
+ .capability = 0,
+ .prune = 0,
+ };
+-struct skinny_device_options *default_device = &default_device_struct;
++static struct skinny_device_options *default_device = &default_device_struct;
+
+ static AST_LIST_HEAD_STATIC(devices, skinny_device);
+
+@@ -1347,7 +1404,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 +2573,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 +2651,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,15 +2701,15 @@
+
+ }
+
+-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;
+ struct skinny_device *d;
+ struct skinnysession *s;
+ struct ast_format_list fmt;
+- struct sockaddr_in us;
+- struct sockaddr_in them;
++ struct sockaddr_in us = { 0, };
++ struct sockaddr_in them = { 0, };
+ struct skinny_req *req;
+
+ sub = c->tech_pvt;
+@@ -2630,7 +2726,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 +2750,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 +2771,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)
+@@ -3010,13 +3106,6 @@
+ return CLI_SUCCESS;
+ }
+
+-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)
+@@ -3155,12 +3244,6 @@
+ return CLI_SUCCESS;
+ }
+
+-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)
+ {
+ const char *a[4];
+@@ -3271,13 +3354,6 @@
+ return CLI_SUCCESS;
+ }
+
+-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)
+@@ -3463,12 +3539,6 @@
+ 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];
+@@ -3559,29 +3629,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 +3678,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 +3843,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 +3931,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 +3970,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 +3992,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 +4058,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 +4165,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 +4276,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 +4317,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 +4336,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 +4398,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;
+@@ -5509,8 +5595,8 @@
+ struct skinny_line *l;
+ struct skinny_subchannel *sub;
+ struct ast_format_list fmt;
+- struct sockaddr_in sin;
+- struct sockaddr_in us;
++ struct sockaddr_in sin = { 0, };
++ struct sockaddr_in us = { 0, };
+ uint32_t addr;
+ int port;
+ int status;
+@@ -5537,8 +5623,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,17 +7375,13 @@
+ 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,
+- "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);
++ ast_manager_register_xml("SKINNYdevices", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, manager_skinny_show_devices);
++ ast_manager_register_xml("SKINNYshowdevice", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, manager_skinny_show_device);
++ ast_manager_register_xml("SKINNYlines", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, manager_skinny_show_lines);
++ ast_manager_register_xml("SKINNYshowline", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, manager_skinny_show_line);
+
+ sched = sched_context_create();
+ if (!sched) {
+@@ -7323,7 +7405,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/xpmr/xpmr.c
+===================================================================
+--- a/channels/xpmr/xpmr.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/channels/xpmr/xpmr.c (.../trunk) (revision 202568)
+@@ -157,7 +157,7 @@
+ TRACEJ(2,(" source len = %i\n",slen));
+
+ pd=*dest;
+- if(pd) free(pd);
++ free(pd);
+ pd=calloc(slen+1,1);
+ memcpy(pd,src,slen);
+ *dest=pd;
+Index: channels/console_gui.c
+===================================================================
+--- a/channels/console_gui.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/channels/console_gui.c (.../trunk) (revision 202568)
+@@ -832,7 +832,7 @@
+ * use a translation table, below - one line per entry,
+ * plain, shift, ctrl, ... using the first char as key.
+ */
+-static const char *us_kbd_map[] = {
++static const char * const us_kbd_map[] = {
+ "`~", "1!", "2@", "3#", "4$", "5%", "6^",
+ "7&", "8*", "9(", "0)", "-_", "=+", "[{",
+ "]}", "\\|", ";:", "'\"", ",<", ".>", "/?",
+@@ -1505,7 +1505,7 @@
+ }
+
+ struct _s_k { const char *s; int k; };
+-static struct _s_k gui_key_map[] = {
++static const struct _s_k gui_key_map[] = {
+ {"FREEZE", KEY_FREEZE},
+ {"PIP", KEY_PIP},
+ {"PICK_UP", KEY_PICK_UP },
+Index: channels/chan_alsa.c
+===================================================================
+--- a/channels/chan_alsa.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/channels/chan_alsa.c (.../trunk) (revision 202568)
+@@ -782,7 +782,7 @@
+ {
+ char tmp[256], *tmp2;
+ char *mye, *myc;
+- char *d;
++ const char *d;
+ char *res = CLI_SUCCESS;
+
+ switch (cmd) {
+Index: channels/chan_nbs.c
+===================================================================
+--- a/channels/chan_nbs.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/channels/chan_nbs.c (.../trunk) (revision 202568)
+@@ -53,7 +53,7 @@
+ static int prefformat = AST_FORMAT_SLINEAR;
+
+ static char context[AST_MAX_EXTENSION] = "default";
+-static char type[] = "NBS";
++static const char type[] = "NBS";
+
+ /* NBS creates private structures on demand */
+
+Index: channels/chan_mgcp.c
+===================================================================
+--- a/channels/chan_mgcp.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/channels/chan_mgcp.c (.../trunk) (revision 202568)
+@@ -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"
+@@ -119,7 +119,7 @@
+ #define MGCP_CX_INACTIVE 4
+ /*! } */
+
+-static char *mgcp_cxmodes[] = {
++static const char * const mgcp_cxmodes[] = {
+ "sendonly",
+ "recvonly",
+ "sendrecv",
+@@ -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)
+@@ -503,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 */
+@@ -915,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)) {
+@@ -1003,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;
+ }
+
+@@ -1098,7 +1098,7 @@
+ if (a->argc != 4)
+ return CLI_SHOWUSAGE;
+ /* split the name into parts by null */
+- ename = a->argv[3];
++ ename = ast_strdupa(a->argv[3]);
+ gname = ename;
+ while (*gname) {
+ if (*gname == '@') {
+@@ -1203,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;
+@@ -1261,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);
+@@ -1297,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);
+ }
+@@ -1324,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);
+ }
+@@ -1453,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, "");
+@@ -1479,9 +1479,8 @@
+ if (!tmp->nativeformats)
+ tmp->nativeformats = capability;
+ 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);
+@@ -1874,12 +1873,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) {
+@@ -1888,7 +1887,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;
+ }
+@@ -1901,11 +1900,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",
+@@ -1920,7 +1919,7 @@
+ return 0;
+ }
+
+-static int add_header(struct mgcp_request *req, char *var, char *value)
++static int add_header(struct mgcp_request *req, const char *var, const char *value)
+ {
+ if (req->len >= sizeof(req->data) - 4) {
+ ast_log(LOG_WARNING, "Out of space, can't add anymore\n");
+@@ -2043,7 +2042,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;
+@@ -2057,7 +2056,7 @@
+ char m[256] = "";
+ char a[1024] = "";
+ int x;
+- struct sockaddr_in dest;
++ struct sockaddr_in dest = { 0, };
+ struct mgcp_endpoint *p = sub->parent;
+ /* XXX We break with the "recommendation" and send our IP, in order that our
+ peer doesn't have to ast_gethostbyname() us XXX */
+@@ -2066,9 +2065,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;
+@@ -2094,11 +2093,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);
+ }
+ }
+@@ -2108,11 +2107,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,
+@@ -2136,7 +2135,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];
+@@ -2147,13 +2146,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);
+ }
+ }
+@@ -2172,7 +2171,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];
+@@ -2183,7 +2182,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);
+ }
+ }
+@@ -2611,21 +2610,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 */
+@@ -3940,22 +3935,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;
+@@ -3967,10 +3962,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)
+@@ -3984,7 +3979,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));
+@@ -4276,7 +4271,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 */
+@@ -4379,7 +4374,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-beta3) (revision 202568)
++++ b/channels/chan_unistim.c (.../trunk) (revision 202568)
+@@ -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;
+@@ -502,7 +502,7 @@
+
+ static const unsigned char packet_rcv_discovery[] =
+ { 0xff, 0xff, 0xff, 0xff, 0x02, 0x02, 0xff, 0xff, 0xff, 0xff, 0x9e, 0x03, 0x08 };
+-static unsigned char packet_send_discovery_ack[] =
++static const unsigned char packet_send_discovery_ack[] =
+ { 0x00, 0x00, /*Initial Seq (2 bytes) */ 0x00, 0x00, 0x00, 0x01 };
+
+ static const unsigned char packet_recv_firm_version[] =
+@@ -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)
+@@ -733,8 +733,8 @@
+ }
+
+ /* Send data to a phone without retransmit nor buffering */
+-static void send_raw_client(int size, unsigned char *data, struct sockaddr_in *addr_to,
+- const struct sockaddr_in *addr_ourip)
++static void send_raw_client(int size, const unsigned char *data, struct sockaddr_in *addr_to,
++ const struct sockaddr_in *addr_ourip)
+ {
+ #ifdef HAVE_PKTINFO
+ struct iovec msg_iov;
+@@ -743,7 +743,12 @@
+ struct cmsghdr *ip_msg = (struct cmsghdr *) buffer;
+ struct in_pktinfo *pki = (struct in_pktinfo *) CMSG_DATA(ip_msg);
+
+- msg_iov.iov_base = data;
++ /* cast this to a non-const pointer, since the sendmsg() API
++ * does not provide read-only and write-only flavors of the
++ * structures used for its arguments, but in this case we know
++ * the data will not be modified
++ */
++ msg_iov.iov_base = (char *) data;
+ msg_iov.iov_len = size;
+
+ msg.msg_name = addr_to; /* optional address */
+@@ -1854,7 +1859,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)
+@@ -2027,11 +2032,11 @@
+ static void start_rtp(struct unistim_subchannel *sub)
+ {
+ BUFFSEND;
+- struct sockaddr_in us;
+- struct sockaddr_in public;
+- struct sockaddr_in sin;
++ struct sockaddr_in us = { 0, };
++ struct sockaddr_in public = { 0, };
++ struct sockaddr_in sin = { 0, };
+ int codec;
+- struct sockaddr_in sout;
++ struct sockaddr_in sout = { 0, };
+
+ /* Sanity checks */
+ if (!sub) {
+@@ -2056,30 +2061,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 +2095,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 */
+@@ -3671,16 +3675,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);
+@@ -3723,7 +3727,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;
+@@ -3768,7 +3772,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;
+@@ -3793,7 +3797,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");
+@@ -3920,10 +3924,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;
+@@ -3989,7 +3993,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);
+ }
+@@ -4433,8 +4437,8 @@
+ return NULL;
+ }
+ l = sub->parent;
+- tmp = ast_channel_alloc(1, state, l->cid_num, NULL, l->accountcode, l->exten,
+- l->context, l->amaflags, "%s-%08x", l->fullname, (int) (long) sub);
++ tmp = ast_channel_alloc(1, state, l->cid_num, NULL, l->accountcode, l->exten,
++ l->context, l->amaflags, "%s@%s-%d", l->name, l->parent->name, sub->subtype);
+ if (unistimdebug)
+ ast_verb(0, "unistim_new sub=%d (%p) chan=%p\n", sub->subtype, sub, tmp);
+ if (!tmp) {
+@@ -4449,13 +4453,11 @@
+ if (unistimdebug)
+ ast_verb(0, "Best codec = %d from nativeformats %d (line cap=%d global=%d)\n", fmt,
+ tmp->nativeformats, l->capability, CAPABILITY);
+- ast_string_field_build(tmp, name, "USTM/%s@%s-%d", l->name, l->parent->name,
+- sub->subtype);
+ 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);
+@@ -5525,51 +5527,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 ---*/
+@@ -5602,7 +5572,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));
+
+@@ -5633,7 +5603,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-beta3) (revision 202568)
++++ b/channels/chan_local.c (.../trunk) (revision 202568)
+@@ -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,40 @@
+ 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.*/
++ ast_mutex_lock(&p->lock);
++ 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 {
++ ast_mutex_unlock(&p->lock);
++ }
+ } else {
+ /* Queue up a frame representing the indication as a control frame */
+ ast_mutex_lock(&p->lock);
+@@ -510,22 +543,53 @@
+
+ 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->owner->cid.cid_rdnis) {
++ if (!(p->chan->cid.cid_rdnis = ast_strdup(p->owner->cid.cid_rdnis))) {
++ ast_mutex_unlock(&p->lock);
++ ast_channel_unlock(p->chan);
++ return -1;
++ }
++ }
++ ast_party_redirecting_copy(&p->chan->redirecting, &p->owner->redirecting);
++
++ if (p->owner->cid.cid_dnid) {
++ if (!(p->chan->cid.cid_dnid = ast_strdup(p->owner->cid.cid_dnid))) {
++ ast_mutex_unlock(&p->lock);
++ ast_channel_unlock(p->chan);
++ 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);
+@@ -535,6 +599,7 @@
+ if (!ast_exists_extension(NULL, p->chan->context, p->chan->exten, 1, p->owner->cid.cid_num)) {
+ ast_log(LOG_NOTICE, "No such extension/context %s@%s while calling Local channel\n", p->chan->exten, p->chan->context);
+ ast_mutex_unlock(&p->lock);
++ ast_channel_unlock(p->chan);
+ return -1;
+ }
+
+@@ -561,6 +626,7 @@
+ ast_set_flag(p, LOCAL_LAUNCHED_PBX);
+
+ ast_mutex_unlock(&p->lock);
++ ast_channel_unlock(p->chan);
+ return res;
+ }
+
+@@ -734,13 +800,12 @@
+ ama = 0;
+ if (!(tmp = ast_channel_alloc(1, state, 0, 0, t, p->exten, p->context, ama, "Local/%s@%s-%04x;1", p->exten, p->context, randnum))
+ || !(tmp2 = ast_channel_alloc(1, AST_STATE_RING, 0, 0, t, p->exten, p->context, ama, "Local/%s@%s-%04x;2", p->exten, p->context, randnum))) {
+- if (tmp)
+- ast_channel_free(tmp);
+- if (tmp2)
+- ast_channel_free(tmp2);
++ if (tmp) {
++ tmp = ast_channel_release(tmp);
++ }
+ ast_log(LOG_WARNING, "Unable to allocate channel structure(s)\n");
+ return NULL;
+- }
++ }
+
+ tmp2->tech = tmp->tech = &local_tech;
+
+Index: channels/chan_bridge.c
+===================================================================
+--- a/channels/chan_bridge.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/channels/chan_bridge.c (.../trunk) (revision 202568)
+@@ -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"
+@@ -205,7 +204,7 @@
+ return NULL;
+ }
+ if (!(p->output = ast_channel_alloc(1, AST_STATE_UP, 0, 0, "", "", "", 0, "Bridge/%p-output", p))) {
+- ast_channel_free(p->input);
++ p->input = ast_channel_release(p->input);
+ ast_free(p);
+ return NULL;
+ }
+Index: channels/vcodecs.c
+===================================================================
+--- a/channels/vcodecs.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/channels/vcodecs.c (.../trunk) (revision 202568)
+@@ -1113,7 +1113,7 @@
+ //struct video_codec_desc *codec_desc;
+ };
+
+-static struct _cm video_formats[] = {
++static const struct _cm video_formats[] = {
+ { AST_FORMAT_H263_PLUS, CODEC_ID_H263, CM_RD }, /* incoming H263P ? */
+ { AST_FORMAT_H263_PLUS, CODEC_ID_H263P, CM_WR },
+ { AST_FORMAT_H263, CODEC_ID_H263, CM_RD },
+@@ -1137,7 +1137,7 @@
+ }
+
+ /* pointers to supported codecs. We assume the first one to be non null. */
+-static struct video_codec_desc *supported_codecs[] = {
++static const struct video_codec_desc *supported_codecs[] = {
+ &h263p_codec,
+ &h264_codec,
+ &h263_codec,
+Index: channels/misdn/isdn_msg_parser.c
+===================================================================
+--- a/channels/misdn/isdn_msg_parser.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/channels/misdn/isdn_msg_parser.c (.../trunk) (revision 202568)
+@@ -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,131 @@
+
+ #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;
++ }
++}
++
++/*!
++ * \internal
++ * \brief Encode the Facility IE and put it into the message structure.
++ *
++ * \param ntmode Where the encoded facility was put when in NT mode.
++ * \param msg General message structure
++ * \param fac Data to encode into the facility ie.
++ * \param nt TRUE if in NT mode.
++ *
++ * \return Nothing
++ */
++static void enc_ie_facility(unsigned char **ntmode, msg_t *msg, struct FacParm *fac, int nt)
++{
++ int len;
++ Q931_info_t *qi;
++ unsigned char *p;
++ unsigned char buf[256];
++
++ len = encodeFac(buf, fac);
++ if (len <= 0) {
++ /*
++ * mISDN does not know how to build the requested facility structure
++ * Clear facility information
++ */
++ fac->Function = Fac_None;
++ return;
++ }
++
++ p = msg_put(msg, len);
++ if (nt) {
++ *ntmode = p + 1;
++ } else {
++ qi = (Q931_info_t *) (msg->data + mISDN_HEADER_LEN);
++ qi->QI_ELEMENT(facility) = p - (unsigned char *) qi - sizeof(Q931_info_t);
++ }
++
++ memcpy(p, buf, len);
++
++ /* Clear facility information */
++ fac->Function = Fac_None;
++}
++
++/*!
++ * \internal
++ * \brief Decode the Facility IE.
++ *
++ * \param p Encoded facility ie data to decode. (NT mode)
++ * \param qi Encoded facility ie data to decode. (TE mode)
++ * \param fac Where to put the decoded facility ie data if it is available.
++ * \param nt TRUE if in NT mode.
++ * \param bc Associated B channel
++ *
++ * \return Nothing
++ */
++static void dec_ie_facility(unsigned char *p, Q931_info_t *qi, struct FacParm *fac, int nt, struct misdn_bchannel *bc)
++{
++ fac->Function = Fac_None;
++
++ if (!nt) {
++ p = NULL;
++ if (qi->QI_ELEMENT(facility)) {
++ p = (unsigned char *) qi + sizeof(Q931_info_t) + qi->QI_ELEMENT(facility) + 1;
++ }
++ }
++ if (!p) {
++ return;
++ }
++
++ if (decodeFac(p, fac)) {
++ cb_log(3, bc->port, "Decoding facility ie failed! Unrecognized facility message?\n");
++ }
++}
++
++
++
+ 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 +157,289 @@
+ 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);
++ CALL_PROCEEDING_t *proceeding = (CALL_PROCEEDING_t *) (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");
++
++ dec_ie_facility(proceeding->FACILITY, (Q931_info_t *) proceeding, &bc->fac_in, nt, bc);
++
++ /* dec_ie_redir_dn */
++
++#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");
++ if (bc->fac_out.Function != Fac_None) {
++ enc_ie_facility(&proceeding->FACILITY, msg, &bc->fac_out, nt);
++ }
++
++ /* enc_ie_redir_dn */
++
++#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;
+- ALERTING_t *alerting=(ALERTING_t*)((unsigned long)(msg->data+HEADER_LEN));
++ int HEADER_LEN = nt?mISDNUSER_HEAD_SIZE:mISDN_HEADER_LEN;
++ ALERTING_t *alerting = (ALERTING_t *) (msg->data + HEADER_LEN);
+ //Q931_info_t *qi=(Q931_info_t*)(msg->data+HEADER_LEN);
+-
++
++ dec_ie_facility(alerting->FACILITY, (Q931_info_t *) alerting, &bc->fac_in, nt, bc);
++
++ /* dec_ie_redir_dn */
++
+ 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");
++
++ if (bc->fac_out.Function != Fac_None) {
++ enc_ie_facility(&alerting->FACILITY, msg, &bc->fac_out, nt);
++ }
++
++ /* enc_ie_redir_dn */
++
++#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 *) (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");
++
++ dec_ie_facility(progress->FACILITY, (Q931_info_t *) progress, &bc->fac_in, nt, bc);
++
++#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));
++
++ if (bc->fac_out.Function != Fac_None) {
++ enc_ie_facility(&progress->FACILITY, msg, &bc->fac_out, nt);
++ }
++
++#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)
+-{
+- 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);
++#if defined(AST_MISDN_ENHANCEMENTS)
++/*!
++ * \internal
++ * \brief Extract the SETUP message's BC, HLC, and LLC encoded ie contents.
++ *
++ * \param setup Indexed setup message contents
++ * \param nt TRUE if in NT mode.
++ * \param bc Associated B channel
++ *
++ * \return Nothing
++ */
++static void extract_setup_Bc_Hlc_Llc(SETUP_t *setup, int nt, struct misdn_bchannel *bc)
++{
++ __u8 *p;
++ Q931_info_t *qi;
+
+-#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);
++ qi = (Q931_info_t *) setup;
+
+- 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;
++ /* Extract Bearer Capability */
++ if (nt) {
++ p = (__u8 *) setup->BEARER;
++ } else {
++ if (qi->QI_ELEMENT(bearer_capability)) {
++ p = (__u8 *) qi + sizeof(Q931_info_t) + qi->QI_ELEMENT(bearer_capability) + 1;
++ } else {
++ p = NULL;
+ }
+- switch (screen) {
+- case 0:
+- break;
+- default:
+- ;
+- }
+ }
+- {
+- 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 (!p || *p == 0 || sizeof(bc->setup_bc_hlc_llc.Bc.Contents) < *p) {
++ bc->setup_bc_hlc_llc.Bc.Length = 0;
++ } else {
++ bc->setup_bc_hlc_llc.Bc.Length = *p;
++ memcpy(bc->setup_bc_hlc_llc.Bc.Contents, p + 1, *p);
+ }
+- {
+- char keypad[32];
+- dec_ie_keypad(setup->KEYPAD, (Q931_info_t *)setup, keypad, sizeof(keypad)-1, nt,bc);
+- strcpy(bc->keypad, keypad);
++
++ /* Extract Low Layer Compatibility */
++ if (nt) {
++ p = (__u8 *) setup->LLC;
++ } else {
++ if (qi->QI_ELEMENT(llc)) {
++ p = (__u8 *) qi + sizeof(Q931_info_t) + qi->QI_ELEMENT(llc) + 1;
++ } else {
++ p = NULL;
++ }
+ }
++ if (!p || *p == 0 || sizeof(bc->setup_bc_hlc_llc.Llc.Contents) < *p) {
++ bc->setup_bc_hlc_llc.Llc.Length = 0;
++ } else {
++ bc->setup_bc_hlc_llc.Llc.Length = *p;
++ memcpy(bc->setup_bc_hlc_llc.Llc.Contents, p + 1, *p);
++ }
+
+- {
+- dec_ie_complete(setup->COMPLETE, (Q931_info_t *)setup, &bc->sending_complete, nt,bc);
+-
++ /* Extract High Layer Compatibility */
++ if (nt) {
++ p = (__u8 *) setup->HLC;
++ } else {
++ if (qi->QI_ELEMENT(hlc)) {
++ p = (__u8 *) qi + sizeof(Q931_info_t) + qi->QI_ELEMENT(hlc) + 1;
++ } else {
++ p = NULL;
++ }
+ }
+-
+- {
+- 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 (!p || *p == 0 || sizeof(bc->setup_bc_hlc_llc.Hlc.Contents) < *p) {
++ bc->setup_bc_hlc_llc.Hlc.Length = 0;
++ } else {
++ bc->setup_bc_hlc_llc.Hlc.Length = *p;
++ memcpy(bc->setup_bc_hlc_llc.Hlc.Contents, p + 1, *p);
+ }
++}
++#endif /* defined(AST_MISDN_ENHANCEMENTS) */
++
++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 *) (msg->data + HEADER_LEN);
++ Q931_info_t *qi = (Q931_info_t *) (msg->data + HEADER_LEN);
++ int type;
++ int plan;
++ int present;
++ int screen;
++ int reason;
++
++#ifdef DEBUG
++ printf("Parsing SETUP Msg\n");
++#endif
++
++ dec_ie_calling_pn(setup->CALLING_PN, qi, &type, &plan, &present, &screen, bc->caller.number, sizeof(bc->caller.number), 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;
++ }
++ if (0 <= screen) {
++ bc->caller.screening = screen;
++ } else {
++ bc->caller.screening = 0; /* Unscreened */
++ }
++
++ dec_ie_facility(setup->FACILITY, (Q931_info_t *) setup, &bc->fac_in, nt, bc);
++
++ dec_ie_called_pn(setup->CALLED_PN, (Q931_info_t *) setup, &type, &plan, bc->dialed.number, sizeof(bc->dialed.number), 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), 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), 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;
++ case -1: bc->capability=INFO_CAPABILITY_DIGITAL_UNRESTRICTED;
+ break;
+ case 0: bc->capability=INFO_CAPABILITY_SPEECH;
+ break;
+@@ -228,7 +448,7 @@
+ case 8: bc->capability=INFO_CAPABILITY_DIGITAL_UNRESTRICTED;
+ bc->user1 = user;
+ bc->urate = urate;
+-
++
+ bc->rate = rate;
+ bc->mode = mode;
+ break;
+@@ -237,7 +457,7 @@
+ default:
+ break;
+ }
+-
++
+ switch(user) {
+ case 2:
+ bc->law=INFO_CODEC_ULAW;
+@@ -247,15 +467,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 +486,85 @@
+ 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);
+-
++
++#if defined(AST_MISDN_ENHANCEMENTS)
++ extract_setup_Bc_Hlc_Llc(setup, nt, bc);
++#endif /* defined(AST_MISDN_ENHANCEMENTS) */
+ }
+
+-#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);
++
++ if (bc->fac_out.Function != Fac_None) {
++ enc_ie_facility(&setup->FACILITY, msg, &bc->fac_out, nt);
+ }
+-
+- {
+- if (bc->dad[0])
+- enc_ie_called_pn(&setup->CALLED_PN, msg, bc->dnumplan, 1, bc->dad, 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->rad[0])
+- enc_ie_redir_nr(&setup->REDIR_NR, msg, 1, 1, bc->pres, bc->screen, 0, bc->rad, nt,bc);
++ switch (bc->outgoing_colp) {
++ case 0:/* pass */
++ case 1:/* restricted */
++ if (bc->redirecting.from.number[0]) {
++#if 1
++ /* ETSI and Q.952 do not define the screening field */
++ enc_ie_redir_nr(&setup->REDIR_NR, msg, bc->redirecting.from.number_type,
++ bc->redirecting.from.number_plan, bc->redirecting.from.presentation, 0,
++ bc->redirecting.reason, bc->redirecting.from.number, nt, bc);
++#else
++ /* Q.931 defines the screening field */
++ 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);
++#endif
++ }
++ break;
++ default:
++ break;
+ }
+
+- {
+- 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 +574,7 @@
+ default:
+ user=3;
+ }
+-
++
+ switch (bc->capability) {
+ case INFO_CAPABILITY_SPEECH: capability = 0;
+ break;
+@@ -337,84 +587,129 @@
+ 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");
++#if defined(AST_MISDN_ENHANCEMENTS)
++ extract_setup_Bc_Hlc_Llc(setup, nt, bc);
++#endif /* defined(AST_MISDN_ENHANCEMENTS) */
++
++#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;
+-
++ CONNECT_t *connect = (CONNECT_t *) (msg->data + HEADER_LEN);
++ 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), 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 */
++ }
+
++ dec_ie_facility(connect->FACILITY, (Q931_info_t *) connect, &bc->fac_in, nt, bc);
++
+ /*
+ 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);
++
++ switch (bc->outgoing_colp) {
++ case 0:/* pass */
++ case 1:/* restricted */
++ 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);
++ break;
++ default:
++ break;
+ }
+
+-#ifdef DEBUG
+- printf("Building CONNECT Msg\n");
++ 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);
++ }
++ }
++
++ if (bc->fac_out.Function != Fac_None) {
++ enc_ie_facility(&connect->FACILITY, msg, &bc->fac_out, nt);
++ }
++
++#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));
++ SETUP_ACKNOWLEDGE_t *setup_acknowledge = (SETUP_ACKNOWLEDGE_t *) (msg->data + HEADER_LEN);
+
+ {
+ int exclusive, channel;
+@@ -423,428 +718,443 @@
+
+ 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");
++
++ dec_ie_facility(setup_acknowledge->FACILITY, (Q931_info_t *) setup_acknowledge, &bc->fac_in, nt, bc);
++
++#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");
++
++ if (bc->fac_out.Function != Fac_None) {
++ enc_ie_facility(&setup_acknowledge->FACILITY, msg, &bc->fac_out, nt);
++ }
++
++#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));
++ DISCONNECT_t *disconnect = (DISCONNECT_t *) (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_facility(disconnect->FACILITY, (Q931_info_t *) disconnect, &bc->fac_in, nt, bc);
++
+ 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);
++ if (nt) {
++ enc_ie_progress(&disconnect->PROGRESS, msg, 0, nt ? 1 : 5, 8, nt, bc);
++ }
+
++ if (bc->fac_out.Function != Fac_None) {
++ enc_ie_facility(&disconnect->FACILITY, msg, &bc->fac_out, nt);
++ }
++
+ if (bc->uulen) {
+ int protocol=4;
+ 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));
++ RESTART_t *restart = (RESTART_t *) (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,52 +1165,59 @@
+ }
+
+ 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));
++ RELEASE_t *release = (RELEASE_t *) (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");
++
++ dec_ie_facility(release->FACILITY, (Q931_info_t *) release, &bc->fac_in, nt, bc);
++
++#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);
+
++ if (bc->fac_out.Function != Fac_None) {
++ enc_ie_facility(&release->FACILITY, msg, &bc->fac_out, nt);
++ }
++
+ if (bc->uulen) {
+ int protocol=4;
+ 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));
++ RELEASE_COMPLETE_t *release_complete = (RELEASE_COMPLETE_t *) (msg->data + HEADER_LEN);
+ int location;
+ int cause;
+ iframe_t *frm = (iframe_t*) msg->data;
+@@ -926,45 +1243,52 @@
+ 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");
++ dec_ie_facility(release_complete->FACILITY, (Q931_info_t *) release_complete, &bc->fac_in, nt, bc);
++
++#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->fac_out.Function != Fac_None) {
++ enc_ie_facility(&release_complete->FACILITY, msg, &bc->fac_out, nt);
++ }
++
+ if (bc->uulen) {
+ int protocol=4;
+ 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
+
++ bc->fac_in.Function = Fac_None;
++
+ if (!bc->nt) {
+ if (qi->QI_ELEMENT(facility))
+ p = (unsigned char *)qi + sizeof(Q931_info_t) + qi->QI_ELEMENT(facility) + 1;
+@@ -973,31 +1297,40 @@
+ }
+ if (!p)
+ return;
+-
+- err = decodeFac(p, &(bc->fac_in));
+- if (err) {
+- cb_log(5, bc->port, "Decoding FACILITY failed! (%d)\n", err);
++
++ if (decodeFac(p, &bc->fac_in)) {
++ cb_log(3, bc->port, "Decoding facility ie failed! Unrecognized facility message?\n");
+ }
+ }
+
+-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
++ * Clear facility information
++ */
++ bc->fac_out.Function = Fac_None;
+ 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;
+@@ -1008,148 +1341,259 @@
+
+ memcpy(ie_fac, fac_tmp, len);
+
++ /* Clear facility information */
++ bc->fac_out.Function = Fac_None;
++
+ 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)
++#if defined(AST_MISDN_ENHANCEMENTS)
++/*!
++ * \internal
++ * \brief Parse a received REGISTER message
++ *
++ * \param msgs Search table entry that called us.
++ * \param msg Received message contents
++ * \param bc Associated B channel
++ * \param nt TRUE if in NT mode.
++ *
++ * \return Nothing
++ */
++static void parse_register(struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt)
+ {
+-#ifdef DEBUG
+- printf("Parsing NOTIFY Msg\n");
++ int HEADER_LEN;
++ REGISTER_t *reg;
++
++ HEADER_LEN = nt ? mISDNUSER_HEAD_SIZE : mISDN_HEADER_LEN;
++ reg = (REGISTER_t *) (msg->data + HEADER_LEN);
++
++ /*
++ * A facility ie is optional.
++ * The peer may just be establishing a connection to send
++ * messages later.
++ */
++ dec_ie_facility(reg->FACILITY, (Q931_info_t *) reg, &bc->fac_in, nt, bc);
++}
++#endif /* defined(AST_MISDN_ENHANCEMENTS) */
++
++#if defined(AST_MISDN_ENHANCEMENTS)
++/*!
++ * \internal
++ * \brief Construct a REGISTER message
++ *
++ * \param msgs Search table entry that called us.
++ * \param bc Associated B channel
++ * \param nt TRUE if in NT mode.
++ *
++ * \return Allocated built message
++ */
++static msg_t *build_register(struct isdn_msg msgs[], struct misdn_bchannel *bc, int nt)
++{
++ int HEADER_LEN;
++ REGISTER_t *reg;
++ msg_t *msg;
++
++ msg = (msg_t *) create_l3msg(CC_REGISTER | REQUEST, MT_REGISTER, bc ? bc->l3_id : -1, sizeof(REGISTER_t), nt);
++ HEADER_LEN = nt ? mISDNUSER_HEAD_SIZE : mISDN_HEADER_LEN;
++ reg = (REGISTER_t *) (msg->data + HEADER_LEN);
++
++ if (bc->fac_out.Function != Fac_None) {
++ enc_ie_facility(&reg->FACILITY, msg, &bc->fac_out, nt);
++ }
++
++ return msg;
++}
++#endif /* defined(AST_MISDN_ENHANCEMENTS) */
++
++static void parse_notify (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt)
++{
++ int HEADER_LEN = nt ? mISDNUSER_HEAD_SIZE : mISDN_HEADER_LEN;
++ NOTIFY_t *notify = (NOTIFY_t *) (msg->data + HEADER_LEN);
++ int description_code;
++ int type;
++ int plan;
++ int present;
++ char number[sizeof(bc->redirecting.to.number)];
++
++#ifdef DEBUG
++ printf("Parsing NOTIFY Msg\n");
+ #endif
++
++ dec_ie_notify(notify->NOTIFY, (Q931_info_t *) notify, &description_code, nt, bc);
++ if (description_code < 0) {
++ bc->notify_description_code = mISDN_NOTIFY_CODE_INVALID;
++ } else {
++ bc->notify_description_code = description_code;
++ }
++
++ dec_ie_redir_dn(notify->REDIR_DN, (Q931_info_t *) notify, &type, &plan, &present, number, sizeof(number), nt, bc);
++ if (0 <= type) {
++ bc->redirecting.to_changed = 1;
++
++ bc->redirecting.to.number_type = type;
++ bc->redirecting.to.number_plan = plan;
++ switch (present) {
++ default:
++ case 0:
++ bc->redirecting.to.presentation = 0; /* presentation allowed */
++ break;
++ case 1:
++ bc->redirecting.to.presentation = 1; /* presentation restricted */
++ break;
++ case 2:
++ bc->redirecting.to.presentation = 2; /* Number not available */
++ break;
++ }
++ bc->redirecting.to.screening = 0; /* Unscreened */
++ strcpy(bc->redirecting.to.number, number);
++ }
+ }
+
+-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");
++#ifdef DEBUG
++ printf("Building NOTIFY Msg\n");
+ #endif
+- return msg;
++
++ notify = (NOTIFY_t *) (msg->data + HEADER_LEN);
++
++ enc_ie_notify(&notify->NOTIFY, msg, bc->notify_description_code, nt, bc);
++
++ if (bc->redirecting.to_changed) {
++ bc->redirecting.to_changed = 0;
++ switch (bc->outgoing_colp) {
++ case 0:/* pass */
++ case 1:/* restricted */
++ enc_ie_redir_dn(&notify->REDIR_DN, msg, bc->redirecting.to.number_type,
++ bc->redirecting.to.number_plan, bc->redirecting.to.presentation,
++ bc->redirecting.to.number, nt, bc);
++ break;
++ default:
++ break;
++ }
++ }
++ 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");
++ INFORMATION_t *information = (INFORMATION_t *) (msg->data + HEADER_LEN);
++ int type, plan;
++
++ dec_ie_called_pn(information->CALLED_PN, (Q931_info_t *) information, &type, &plan, bc->info_dad, sizeof(bc->info_dad), nt, bc);
++ dec_ie_keypad(information->KEYPAD, (Q931_info_t *) information, bc->keypad, sizeof(bc->keypad), 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));
++ STATUS_t *status = (STATUS_t *) (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 +1605,43 @@
+ /** 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" },
++#if defined(AST_MISDN_ENHANCEMENTS)
++ { CC_REGISTER, EVENT_REGISTER, parse_register, build_register, "REGISTER" },
++#endif /* defined(AST_MISDN_ENHANCEMENTS) */
++ { 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 +1653,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 +1671,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 +1708,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 +1721,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 +1738,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-beta3) (revision 202568)
++++ b/channels/misdn/portinfo.c (.../trunk) (revision 202568)
+@@ -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-beta3) (revision 202568)
++++ b/channels/misdn/isdn_lib.c (.../trunk) (revision 202568)
+@@ -11,7 +11,7 @@
+ * the GNU General Public License
+ */
+
+-/*! \file
++/*! \file
+ * \brief Interface to mISDN
+ * \author Christian Richter <crich@beronet.com>
+ */
+@@ -25,15 +25,15 @@
+ #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);
++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, ...)
++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"
+ */
+@@ -48,12 +48,8 @@
+
+ int misdn_lib_get_l2_up(struct misdn_stack *stack);
+
+-struct misdn_stack* get_misdn_stack( void );
++struct misdn_stack *get_misdn_stack(void);
+
+-static int set_chan_in_stack(struct misdn_stack *stack, int channel);
+-
+-int release_cr(struct misdn_stack *stack, mISDNuser_head_t *hh);
+-
+ int misdn_lib_port_is_pri(int port)
+ {
+ struct misdn_stack *stack=get_misdn_stack();
+@@ -62,7 +58,7 @@
+ return stack->pri;
+ }
+ }
+-
++
+ return -1;
+ }
+
+@@ -74,15 +70,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 +115,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 +134,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 +155,7 @@
+
+ if (!bc)
+ return NULL;
+-
++
+ for ( ; stack; stack = stack->next) {
+ if (bc->port == stack->port)
+ return stack;
+@@ -171,19 +167,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 +220,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 +249,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
+@@ -263,7 +264,7 @@
+ #define TONE_BUSY_CNT 20 /* ? */
+ #define TONE_BUSY_SILENCE_CNT 48 /* ? */
+
+-static int entity;
++static int entity;
+
+ static struct misdn_lib *glob_mgr;
+
+@@ -280,7 +281,6 @@
+
+ /* from isdn_lib.h */
+ /* user iface */
+-int te_lib_init( void ) ; /* returns midev */
+ void te_lib_destroy(int midev) ;
+ struct misdn_bchannel *manager_find_bc_by_pid(int pid);
+ struct misdn_bchannel *manager_find_bc_holded(struct misdn_bchannel* bc);
+@@ -304,7 +304,7 @@
+ "Res Digital",
+ "Unknown Bearer"
+ };
+-
++
+ switch (cap) {
+ case INFO_CAPABILITY_SPEECH:
+ return bearers[0];
+@@ -330,7 +330,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 +344,11 @@
+ {
+ int i;
+ char * start = buf;
+-
++
+ for (i = 0 ; i < len; i++) {
+ buf[i] = flip_table[(unsigned char)buf[i]];
+ }
+-
++
+ return start;
+ }
+
+@@ -359,13 +359,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 +383,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 +406,7 @@
+ return(dmsg);
+ }
+ }
+-
++
+ if (!i) printf("cannot allocate memory, trying again...\n");
+ i++;
+ usleep(300000);
+@@ -425,11 +425,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 +457,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:
+@@ -474,9 +474,18 @@
+ {
+ int i;
+
+- for (i=0; i <= stack->b_num; i++) {
+- cb_log(6, stack->port, "Idx:%d stack->cchan:%d in_use:%d Chan:%d\n",i,stack->channels[i], stack->bc[i].in_use, i+1);
++ for (i = 0; i <= stack->b_num; ++i) {
++ cb_log(6, stack->port, "Idx:%d stack->cchan:%d in_use:%d Chan:%d\n",
++ i, stack->channels[i], stack->bc[i].in_use, i + 1);
+ }
++#if defined(AST_MISDN_ENHANCEMENTS)
++ for (i = MAX_BCHANS + 1; i < ARRAY_LEN(stack->bc); ++i) {
++ if (stack->bc[i].in_use) {
++ cb_log(6, stack->port, "Idx:%d stack->cchan:%d REGISTER Chan:%d in_use\n",
++ i, stack->channels[i], i + 1);
++ }
++ }
++#endif /* defined(AST_MISDN_ENHANCEMENTS) */
+ }
+
+
+@@ -491,10 +500,9 @@
+
+ static int set_chan_in_stack(struct misdn_stack *stack, int channel)
+ {
+-
+ cb_log(4,stack->port,"set_chan_in_stack: %d\n",channel);
+ dump_chan_list(stack);
+- if (channel >=1 && channel <= MAX_BCHANS) {
++ if (1 <= channel && channel <= ARRAY_LEN(stack->channels)) {
+ if (!stack->channels[channel-1])
+ stack->channels[channel-1] = 1;
+ else {
+@@ -505,7 +513,7 @@
+ cb_log(0,stack->port,"couldn't set channel %d in\n", channel );
+ return -1;
+ }
+-
++
+ return 0;
+ }
+
+@@ -514,78 +522,92 @@
+ static int find_free_chan_in_stack(struct misdn_stack *stack, struct misdn_bchannel *bc, int channel, int dec)
+ {
+ int i;
+- int chan=0;
+- int bnums = stack->pri ? stack->b_num : stack->b_num - 1;
++ int chan = 0;
++ int bnums;
+
+- 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);
++ bc->channel_found = 1;
+
+- if (channel < 0 || channel > MAX_BCHANS) {
+- cb_log(0, stack->port, " !! out of bound call to find_free_chan_in_stack! (ch:%d)\n", channel);
+- return 0;
+- }
+-
+- channel--;
++#if defined(AST_MISDN_ENHANCEMENTS)
++ if (bc->is_register_pool) {
++ for (i = MAX_BCHANS + 1; i < ARRAY_LEN(stack->channels); ++i) {
++ if (!stack->channels[i]) {
++ chan = i + 1;
++ cb_log(3, stack->port, " --> found REGISTER chan: %d\n", chan);
++ break;
++ }
++ }
++ } else
++#endif /* defined(AST_MISDN_ENHANCEMENTS) */
++ {
++ cb_log(5, stack->port, "find_free_chan: req_chan:%d\n", channel);
+
+- if (dec) {
+- for (i = bnums; i >=0; i--) {
+- 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;
+- break;
++ if (channel < 0 || channel > MAX_BCHANS) {
++ cb_log(0, stack->port, " !! out of bound call to find_free_chan_in_stack! (ch:%d)\n", channel);
++ return 0;
++ }
++
++ --channel;
++
++ bnums = stack->pri ? stack->b_num : stack->b_num - 1;
++ if (dec) {
++ for (i = bnums; i >= 0; --i) {
++ if (i != 15 && (channel < 0 || i == channel)) { /* skip E1 D channel ;) and work with chan preselection */
++ if (!stack->channels[i]) {
++ chan = i + 1;
++ cb_log(3, stack->port, " --> found chan%s: %d\n", channel >= 0 ? " (preselected)" : "", chan);
++ break;
++ }
+ }
+ }
+- }
+- } else {
+- for (i = 0; i <= bnums; i++) {
+- 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;
+- break;
++ } else {
++ for (i = 0; i <= bnums; ++i) {
++ if (i != 15 && (channel < 0 || i == channel)) { /* skip E1 D channel ;) and work with chan preselection */
++ if (!stack->channels[i]) {
++ chan = i + 1;
++ cb_log(3, stack->port, " --> found chan%s: %d\n", channel >= 0 ? " (preselected)" : "", chan);
++ break;
++ }
+ }
+ }
+ }
+ }
+
+ if (!chan) {
+- cb_log (1, stack->port, " !! NO FREE CHAN IN STACK\n");
++ cb_log(1, stack->port, " !! NO FREE CHAN IN STACK\n");
+ 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);
++ if (set_chan_in_stack(stack, chan) < 0) {
++ cb_log(0, stack->port, "Channel Already in use:%d\n", chan);
+ bc->out_cause = AST_CAUSE_REQUESTED_CHAN_UNAVAIL;
+ return -1;
+ }
+
+- bc->channel=chan;
++ bc->channel = chan;
+ return 0;
+ }
+
+-static int empty_chan_in_stack(struct misdn_stack *stack, int channel)
++static void empty_chan_in_stack(struct misdn_stack *stack, int channel)
+ {
+- if (channel<=0 || channel>MAX_BCHANS) {
+- cb_log(0,stack?stack->port:0, "empty_chan_in_stack: cannot empty channel %d\n",channel);
+- return -1;
++ if (channel < 1 || ARRAY_LEN(stack->channels) < channel) {
++ cb_log(0, stack->port, "empty_chan_in_stack: cannot empty channel %d\n", channel);
++ return;
+ }
+-
+- cb_log (4, stack?stack->port:0, "empty_chan_in_stack: %d\n",channel);
+- stack->channels[channel-1] = 0;
++
++ cb_log(4, stack->port, "empty_chan_in_stack: %d\n", channel);
++ stack->channels[channel - 1] = 0;
+ dump_chan_list(stack);
+- return 0;
+ }
+
+ char *bc_state2str(enum bchannel_state state) {
+ int i;
+-
++
+ struct bchan_state_s {
+ char *n;
+ enum bchannel_state s;
+@@ -604,7 +626,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 +640,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 +666,38 @@
+
+ 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.to.presentation = 0; /* allowed */
++ bc->redirecting.to.number_plan = NUMPLAN_ISDN;
++ bc->redirecting.to.number_type = NUMTYPE_UNKNOWN;
++ bc->redirecting.to.name[0] = 0;
++ bc->redirecting.to.number[0] = 0;
++ bc->redirecting.to.subaddress[0] = 0;
++
++ bc->redirecting.reason = mISDN_REDIRECTING_REASON_UNKNOWN;
++ bc->redirecting.count = 0;
++ bc->redirecting.to_changed = 0;
++
+ bc->dummy=0;
+
+ bc->bframe_len=0;
+@@ -656,38 +710,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 +746,31 @@
+ 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->outgoing_colp = 0;/* pass */
++
++ bc->presentation = 0; /* allowed */
++ bc->set_presentation = 0;
++
++ bc->notify_description_code = mISDN_NOTIFY_CODE_INVALID;
++
+ bc->evq=EVENT_NOTHING;
+
+ bc->progress_coding=0;
+ bc->progress_location=0;
+ bc->progress_indicator=0;
+-
++
++#if defined(AST_MISDN_ENHANCEMENTS)
++ bc->div_leg_3_rx_wanted = 0;
++ bc->div_leg_3_tx_pending = 0;
++#endif /* defined(AST_MISDN_ENHANCEMENTS) */
++
+ /** Set Default Bearer Caps **/
+ bc->capability=INFO_CAPABILITY_SPEECH;
+ bc->law=INFO_CODEC_ALAW;
+@@ -716,24 +778,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 +809,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;
+ }
+
+@@ -783,27 +844,31 @@
+ {
+ int i;
+
+- for (i=0; i<=stack->b_num; i++) {
+- if (global_state == MISDN_INITIALIZED) {
+- cb_event(EVENT_CLEANUP, &stack->bc[i], NULL);
+- empty_chan_in_stack(stack,i+1);
++ if (global_state == MISDN_INITIALIZED) {
++ for (i = 0; i <= stack->b_num; ++i) {
++ 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;
+ }
+-
+- }
++#if defined(AST_MISDN_ENHANCEMENTS)
++ for (i = MAX_BCHANS + 1; i < ARRAY_LEN(stack->bc); ++i) {
++ empty_chan_in_stack(stack, i + 1);
++ empty_bc(&stack->bc[i]);
++ stack->bc[i].in_use = 0;
++ }
++#endif /* defined(AST_MISDN_ENHANCEMENTS) */
++ }
+ }
+
+ static int new_te_id = 0;
+
+-#define MAXPROCS 0x100
+-
+ 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 +880,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 +921,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 +948,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 +962,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 +994,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;
+@@ -996,7 +1061,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 +1073,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 +1083,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 +1096,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 +1109,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 +1129,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 +1138,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 +1168,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 +1188,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 +1201,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;
+@@ -1152,70 +1217,65 @@
+
+
+ /** IFACE **/
+-static 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)
+ {
+- unsigned char buff[1025] = "";
+- iframe_t *frm = (iframe_t *)buff;
+- int ret;
+-
+- if (!bc) return -1;
+-
++ 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));
+ if (!bc->send_lock) {
+ 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);
+-
++
+ }
+-
+- {
++
++#if 0 /* This code does not seem to do anything useful */
++ if (bidx <= stack->b_num) {
++ unsigned char buff[1025];
++ iframe_t *frm = (iframe_t *) buff;
+ stack_info_t *stinf;
++ int ret;
++
+ ret = mISDN_get_stack_info(midev, stack->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 -1;
+ }
+-
++
+ stinf = (stack_info_t *)&frm->data.p;
+-
++
+ cb_log(8, port, " --> Child %x\n",stinf->child[bidx]);
+ }
+-
++#endif
++
+ return 0;
+ }
+
+@@ -1227,36 +1287,34 @@
+ unsigned char buff[1025];
+ iframe_t *frm = (iframe_t *)buff;
+ stack_info_t *stinf;
+- int i;
++ struct misdn_stack *stack;
++ int i;
+ layer_info_t li;
+
+- struct misdn_stack *stack = malloc(sizeof(struct misdn_stack));
+- if (!stack ) return NULL;
++ stack = calloc(1, sizeof(struct misdn_stack));
++ if (!stack) {
++ return NULL;
++ }
+
++ cb_log(8, port, "Init. Stack.\n");
+
+- 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 +1322,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 +1341,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 +1349,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 +1373,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,60 +1389,55 @@
+ 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*/
+- stack->l1link=0;
++
+ }
++
+ stack->l1link=0;
+ stack->l2link=0;
+-#if 0
++#if 0
+ if (!stack->nt) {
+ misdn_lib_get_short_status(stack);
+ } else {
+@@ -1396,12 +1449,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 +1468,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,59 +1480,85 @@
+ 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;
+
++ for (stack = glob_mgr->stack_list; stack; stack = stack->next) {
++ if ((stack->upper_id & STACK_ID_MASK) == (addr & STACK_ID_MASK)) {
++ /* Found the stack */
++ break;
++ }
+ }
+-
+- return NULL;
++
++ return stack;
+ }
+
+
+-static struct misdn_stack * find_stack_by_port(int port)
++static struct misdn_stack *find_stack_by_port(int port)
+ {
+ struct misdn_stack *stack;
+-
+- for (stack=glob_mgr->stack_list;
+- stack;
+- stack=stack->next)
+- if (stack->port == port) return stack;
+-
+- return NULL;
++
++ for (stack = glob_mgr->stack_list; stack; stack = stack->next) {
++ if (stack->port == port) {
++ /* Found the stack */
++ break;
++ }
++ }
++
++ return stack;
+ }
+
+-static struct misdn_stack * find_stack_by_mgr(manager_t* mgr_nt)
++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)
+- if ( &stack->mgr == mgr_nt) return stack;
+-
+- return NULL;
++
++ for (stack = glob_mgr->stack_list; stack; stack = stack->next) {
++ if (&stack->mgr == mgr_nt) {
++ /* Found the stack */
++ break;
++ }
++ }
++
++ return stack;
+ }
+
+ static struct misdn_bchannel *find_bc_by_masked_l3id(struct misdn_stack *stack, unsigned long l3id, unsigned long mask)
+ {
+ int i;
+- for (i=0; i<=stack->b_num; i++) {
+- if ( (stack->bc[i].l3_id & mask) == (l3id & mask)) return &stack->bc[i] ;
++
++ for (i = 0; i <= stack->b_num; ++i) {
++ if ((stack->bc[i].l3_id & mask) == (l3id & mask)) {
++ return &stack->bc[i];
++ }
+ }
+- return stack_holder_find(stack,l3id);
++#if defined(AST_MISDN_ENHANCEMENTS)
++ /* Search the B channel records for a REGISTER signaling link. */
++ for (i = MAX_BCHANS + 1; i < ARRAY_LEN(stack->bc); ++i) {
++ if ((stack->bc[i].l3_id & mask) == (l3id & mask)) {
++ return &stack->bc[i];
++ }
++ }
++#endif /* defined(AST_MISDN_ENHANCEMENTS) */
++ return stack_holder_find(stack, l3id);
+ }
+
+
+ struct misdn_bchannel *find_bc_by_l3id(struct misdn_stack *stack, unsigned long l3id)
+ {
+ int i;
+- for (i=0; i<=stack->b_num; i++) {
+- if (stack->bc[i].l3_id == l3id) return &stack->bc[i] ;
++
++ for (i = 0; i <= stack->b_num; ++i) {
++ if (stack->bc[i].l3_id == l3id) {
++ return &stack->bc[i];
++ }
+ }
+- return stack_holder_find(stack,l3id);
++#if defined(AST_MISDN_ENHANCEMENTS)
++ /* Search the B channel records for a REGISTER signaling link. */
++ for (i = MAX_BCHANS + 1; i < ARRAY_LEN(stack->bc); ++i) {
++ if (stack->bc[i].l3_id == l3id) {
++ return &stack->bc[i];
++ }
++ }
++#endif /* defined(AST_MISDN_ENHANCEMENTS) */
++ return stack_holder_find(stack, l3id);
+ }
+
+ static struct misdn_bchannel *find_bc_holded(struct misdn_stack *stack)
+@@ -1506,7 +1585,7 @@
+ }
+ }
+ }
+-
++
+ return NULL;
+ }
+
+@@ -1514,7 +1593,7 @@
+ {
+ struct misdn_stack* stack;
+ int i;
+-
++
+ for (stack=glob_mgr->stack_list;
+ stack;
+ stack=stack->next) {
+@@ -1533,14 +1612,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 +1630,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 +1668,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:
+@@ -1600,25 +1693,28 @@
+ break;
+ }
+
+- if (!bc->channel)
++ if (!bc->channel) {
+ cb_log(0, stack->port, "Any Channel Requested, but we have no more!!\n");
+- else
+- cb_log(0, stack->port, "Requested Channel Already in Use releasing this call with cause 34!!!!\n");
++ } else {
++ cb_log(0, stack->port,
++ "Requested Channel Already in Use releasing this call with cause %d!!!!\n",
++ bc->out_cause);
++ }
+
+ /* 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;
+
+ misdn_lib_send_event(bc,EVENT_RELEASE_COMPLETE);
+ return -1;
+ }
++
++ setup_bc(bc);
++ break;
+ }
+
+- setup_bc(bc);
+- break;
+-
+ case EVENT_RELEASE_COMPLETE:
+ case EVENT_RELEASE:
+ break;
+@@ -1626,17 +1722,19 @@
+ break;
+ }
+ } else { /** NT MODE **/
+-
++
+ }
+ return 0;
+ }
+
+ static int handle_cr ( struct misdn_stack *stack, iframe_t *frm)
+ {
++ struct misdn_bchannel dummybc;
+ struct misdn_bchannel *bc;
++ int channel;
+
+ 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 +1744,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;
+@@ -1659,54 +1757,44 @@
+ case CC_RELEASE_CR|CONFIRM:
+ break;
+ case CC_RELEASE_CR|INDICATION:
+- cb_log(4, stack->port, " --> lib: RELEASE_CR Ind with l3id:%x\n",frm->dinfo);
+- {
+- 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;
+- }
+-
+- if (bc) {
+- int channel = bc->channel;
+- cb_log(4, stack->port, " --> lib: CLEANING UP l3id: %x\n",frm->dinfo);
++ cb_log(4, stack->port, " --> lib: RELEASE_CR Ind with l3id:%x\n", frm->dinfo);
++ bc = find_bc_by_l3id(stack, frm->dinfo);
++ 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->pid = 0;*/
+- bc->need_disconnect=0;
+- bc->need_release=0;
+- bc->need_release_complete=0;
++ channel = bc->channel;
++ cb_log(4, stack->port, " --> lib: CLEANING UP l3id: %x\n", frm->dinfo);
+
+- cb_event(EVENT_CLEANUP, bc, glob_mgr->user_data);
++ /* bc->pid = 0; */
++ bc->need_disconnect = 0;
++ bc->need_release = 0;
++ bc->need_release_complete = 0;
+
+- empty_bc(bc);
+- clean_up_bc(bc);
++ cb_event(EVENT_CLEANUP, bc, glob_mgr->user_data);
+
+- if (channel>0)
+- empty_chan_in_stack(stack,channel);
+- bc->in_use=0;
++ empty_bc(bc);
++ clean_up_bc(bc);
+
+- dump_chan_list(stack);
++ if (channel > 0)
++ empty_chan_in_stack(stack, channel);
++ bc->in_use = 0;
+
+- if (bc->stack_holder) {
+- cb_log(4,stack->port, "REMOVING Holder\n");
+- stack_holder_remove( stack, bc);
+- free(bc);
+- }
+- }
+- else {
+- 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;
++ dump_chan_list(stack);
++
++ if (bc->stack_holder) {
++ cb_log(4, stack->port, "REMOVING Holder\n");
++ stack_holder_remove(stack, bc);
++ free(bc);
+ }
++
++ return 1;
++ default:
+ break;
+ }
+-
++
+ return 0;
+ }
+
+@@ -1720,10 +1808,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 +1820,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 +1842,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 +1866,7 @@
+ for (stack=glob_mgr->stack_list;
+ stack;
+ stack=stack->next) {
+-
++
+ if (stack->port == port) {
+
+ if (stack->blocked) {
+@@ -1805,36 +1893,33 @@
+ }
+ }
+ }
+-
++
+ return -1;
+ }
+
+
+-int release_cr(struct misdn_stack *stack, mISDNuser_head_t *hh)
++static int release_cr(struct misdn_stack *stack, mISDNuser_head_t *hh)
+ {
+ struct misdn_bchannel *bc=find_bc_by_l3id(stack, hh->dinfo);
+ struct misdn_bchannel dummybc;
+ iframe_t frm; /* fake te frm to remove callref from global callreflist */
++
+ frm.dinfo = hh->dinfo;
+-
+ frm.addr=stack->upper_id | FLG_MSG_DOWN;
+-
+ frm.prim = CC_RELEASE_CR|INDICATION;
+ 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 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) {
+- if ( (bc->l3_id & 0xff00) == 0xff00) {
+- cb_log(4, stack->port, " --> Removing Process Id:%x on this port.\n", bc->l3_id&0xff);
+- stack->procids[bc->l3_id&0xff] = 0 ;
+- }
++ if ((bc->l3_id & 0xff00) == 0xff00) {
++ cb_log(4, stack->port, " --> Removing Process Id:%x on this port.\n", bc->l3_id & 0xff);
++ stack->procids[bc->l3_id & 0xff] = 0;
+ }
+- 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) {
+ }
+@@ -1842,318 +1927,319 @@
+ return 0 ;
+ }
+
+-static int
+-handle_event_nt(void *dat, void *arg)
++static int handle_event_nt(void *dat, void *arg)
+ {
++ struct misdn_bchannel dummybc;
++ struct misdn_bchannel *bc;
+ manager_t *mgr = (manager_t *)dat;
+ msg_t *msg = (msg_t *)arg;
++ msg_t *dmsg;
+ mISDNuser_head_t *hh;
++ struct misdn_stack *stack;
++ enum event_e event;
+ int reject=0;
+-
+- struct misdn_stack *stack=find_stack_by_mgr(mgr);
+ int port;
++ int l3id;
++ int channel;
++ int tmpcause;
+
+ if (!msg || !mgr)
+ return(-EINVAL);
+
++ stack = find_stack_by_mgr(mgr);
+ 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) {
++ case CC_RETRIEVE|INDICATION:
+ {
+- switch(hh->prim){
+- case CC_RETRIEVE|INDICATION:
+- {
+- struct misdn_bchannel *bc;
+- struct misdn_bchannel *hold_bc;
++ struct misdn_bchannel *hold_bc;
++ iframe_t frm; /* fake te frm to add callref to global callreflist */
+
+- iframe_t frm; /* fake te frm to add callref to global callreflist */
+- frm.dinfo = hh->dinfo;
++ frm.dinfo = hh->dinfo;
++ frm.addr=stack->upper_id | FLG_MSG_DOWN;
++ frm.prim = CC_NEW_CR|INDICATION;
++ if (handle_cr( stack, &frm)< 0) {
++ goto ERR_NO_CHANNEL;
++ }
+
+- frm.addr=stack->upper_id | FLG_MSG_DOWN;
++ 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);
+
+- 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);
+- dmsg = create_l3msg(CC_RELEASE_COMPLETE | REQUEST,MT_RELEASE_COMPLETE, hh->dinfo,sizeof(RELEASE_COMPLETE_t), 1);
+- stack->nst.manager_l3(&stack->nst, dmsg);
+- 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);
++ if (hold_bc) {
++ cb_log(4, stack->port, "REMOVING Holder\n");
+
+- if (hold_bc) {
+- cb_log(4, stack->port, "REMOVING Holder\n");
++ /* swap the backup to our new channel back */
++ stack_holder_remove(stack, hold_bc);
++ memcpy(bc, hold_bc, sizeof(*bc));
++ free(hold_bc);
+
+- /*swap the backup to our new channel back*/
+- stack_holder_remove(stack, hold_bc);
+- memcpy(bc, hold_bc, sizeof(*bc));
+- free(hold_bc);
++ bc->holded=0;
++ bc->b_stid=0;
++ }
++ break;
++ }
+
+- 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;
++ case CC_SETUP | CONFIRM:
++ l3id = *((int *) (msg->data + mISDNUSER_HEAD_SIZE));
++
++ cb_log(4, stack->port, " --> lib: Event_ind:SETUP CONFIRM [NT] : new L3ID is %x\n", l3id);
++
++ bc = find_bc_by_l3id(stack, hh->dinfo);
++ if (bc) {
++ 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;
+ cb_event(EVENT_NEW_L3ID, bc, glob_mgr->user_data);
++ } else {
++ cb_log(4, stack->port, "Bc Not found (after SETUP CONFIRM)\n");
+ }
+ 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)
+- ERR_NO_CHANNEL:
+- {
+- msg_t *dmsg;
+- cb_log(4, stack->port, "Patch from MEIDANIS:Sending RELEASE_COMPLETE %x (No free Chan for you..)\n", hh->dinfo);
+- dmsg = create_l3msg(CC_RELEASE_COMPLETE | REQUEST,MT_RELEASE_COMPLETE, hh->dinfo,sizeof(RELEASE_COMPLETE_t), 1);
+- stack->nst.manager_l3(&stack->nst, dmsg);
+- free_msg(msg);
+- return 0;
+- }
+-
+- cb_log(4, stack->port, " --> new_process: New L3Id: %x\n",hh->dinfo);
+- bc->l3_id=hh->dinfo;
++
++ case CC_SETUP | INDICATION:
++ bc = misdn_lib_get_free_bc(stack->port, 0, 1, 0);
++ if (!bc) {
++ goto ERR_NO_CHANNEL;
+ }
++
++ cb_log(4, stack->port, " --> new_process: New L3Id: %x\n",hh->dinfo);
++ bc->l3_id=hh->dinfo;
+ break;
+
+- case CC_CONNECT_ACKNOWLEDGE|INDICATION:
++#if defined(AST_MISDN_ENHANCEMENTS)
++ case CC_REGISTER | CONFIRM:
++ l3id = *((int *) (msg->data + mISDNUSER_HEAD_SIZE));
++
++ cb_log(4, stack->port, " --> lib: Event_ind:REGISTER CONFIRM [NT] : new L3ID is %x\n", l3id);
++
++ bc = find_bc_by_l3id(stack, hh->dinfo);
++ if (bc) {
++ cb_log (2, bc->port, "I IND :CC_REGISTER|CONFIRM: old l3id:%x new l3id:%x\n", bc->l3_id, l3id);
++ bc->l3_id = l3id;
++ } else {
++ cb_log(4, stack->port, "Bc Not found (after REGISTER CONFIRM)\n");
++ }
++ free_msg(msg);
++ return 0;
++#endif /* defined(AST_MISDN_ENHANCEMENTS) */
++
++#if defined(AST_MISDN_ENHANCEMENTS)
++ case CC_REGISTER | INDICATION:
++ bc = misdn_lib_get_register_bc(stack->port);
++ if (!bc) {
++ goto ERR_NO_CHANNEL;
++ }
++
++ cb_log(4, stack->port, " --> new_process: New L3Id: %x\n",hh->dinfo);
++ bc->l3_id=hh->dinfo;
+ break;
+-
+- case CC_ALERTING|INDICATION:
+- case CC_PROCEEDING|INDICATION:
+- case CC_SETUP_ACKNOWLEDGE|INDICATION:
+- if(!stack->ptp) break;
+- case CC_CONNECT|INDICATION:
++#endif /* defined(AST_MISDN_ENHANCEMENTS) */
++
++ case CC_CONNECT_ACKNOWLEDGE|INDICATION:
+ break;
+- case CC_DISCONNECT|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) {
+- 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;
+- }
++
++ case CC_ALERTING|INDICATION:
++ case CC_PROCEEDING|INDICATION:
++ case CC_SETUP_ACKNOWLEDGE|INDICATION:
++ case CC_CONNECT|INDICATION:
++ break;
++ case CC_DISCONNECT|INDICATION:
++ bc = find_bc_by_l3id(stack, hh->dinfo);
++ if (!bc) {
++ bc=find_bc_by_masked_l3id(stack, hh->dinfo, 0xffff0000);
++ 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;
+ }
+ }
+ 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) {
+- 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);
+- }
++
++ case CC_FACILITY|INDICATION:
++ bc = find_bc_by_l3id(stack, hh->dinfo);
++ if (!bc) {
++ bc=find_bc_by_masked_l3id(stack, hh->dinfo, 0xffff0000);
++ 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);
+ }
+ }
+ break;
+-
+- case CC_RELEASE_COMPLETE|INDICATION:
+- break;
+
+- case CC_SUSPEND|INDICATION:
+- {
+- msg_t *dmsg;
+- cb_log(4, stack->port, " --> Got Suspend, sending Reject for now\n");
+- dmsg = create_l3msg(CC_SUSPEND_REJECT | REQUEST,MT_SUSPEND_REJECT, hh->dinfo,sizeof(RELEASE_COMPLETE_t), 1);
+- stack->nst.manager_l3(&stack->nst, dmsg);
+- free_msg(msg);
+- return 0;
++ case CC_RELEASE_COMPLETE|INDICATION:
++ break;
++
++ case CC_SUSPEND|INDICATION:
++ cb_log(4, stack->port, " --> Got Suspend, sending Reject for now\n");
++ dmsg = create_l3msg(CC_SUSPEND_REJECT | REQUEST,MT_SUSPEND_REJECT, hh->dinfo,sizeof(RELEASE_COMPLETE_t), 1);
++ stack->nst.manager_l3(&stack->nst, dmsg);
++ free_msg(msg);
++ return 0;
++
++ case CC_RESUME|INDICATION:
++ break;
++
++ case CC_RELEASE|CONFIRM:
++ bc = find_bc_by_l3id(stack, hh->dinfo);
++ 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_RESUME|INDICATION:
+- break;
+
+- case CC_RELEASE|CONFIRM:
+- {
+- struct misdn_bchannel *bc=find_bc_by_l3id(stack, hh->dinfo);
++ case CC_RELEASE|INDICATION:
++ break;
+
+- 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;
++ case CC_RELEASE_CR|INDICATION:
++ release_cr(stack, hh);
++ free_msg(msg);
++ return 0;
+
+- case CC_RELEASE_CR|INDICATION:
+- release_cr(stack, hh);
+- 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 */
+- {
+- struct misdn_bchannel *bc=find_bc_by_l3id(stack, hh->dinfo);
+- int l3id = *((int *)(((u_char *)msg->data)+ mISDNUSER_HEAD_SIZE));
+- if (!bc) { cb_log(0, stack->port, " --> In NEW_CR: didn't found bc ??\n"); return -1;};
+- if (((l3id&0xff00)!=0xff00) && ((bc->l3_id&0xff00)==0xff00)) {
+- cb_log(4, stack->port, " --> Removing Process Id:%x on this port.\n", 0xff&bc->l3_id);
+- 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;
++ case CC_NEW_CR|INDICATION:
++ /* Got New CR for bchan, for now I handle this one in */
++ /* connect_ack, Need to be changed */
++ l3id = *((int *) (msg->data + mISDNUSER_HEAD_SIZE));
++
++ bc = find_bc_by_l3id(stack, hh->dinfo);
++ if (!bc) {
++ cb_log(0, stack->port, " --> In NEW_CR: didn't found bc ??\n");
++ return -1;
++ }
++ if (((l3id&0xff00)!=0xff00) && ((bc->l3_id&0xff00)==0xff00)) {
++ cb_log(4, stack->port, " --> Removing Process Id:%x on this port.\n", 0xff&bc->l3_id);
++ 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;
++ if (!bc->is_register_pool) {
+ 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
+- * other side */
+- stack->restart_sent=1;
+- misdn_lib_send_restart(stack->port, -1);
++ free_msg(msg);
++ return 0;
+
+- }
+-
+- /* when we get the L2 UP, the L1 is UP definitely too*/
+- stack->l2link = 1;
+- stack->l2upcnt=0;
+-
+- 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);
+ }
+- break;
+
++ if (stack->ptp && !stack->restart_sent) {
++ /* make sure we restart the interface of the
++ * other side */
++ stack->restart_sent=1;
++ misdn_lib_send_restart(stack->port, -1);
+
+- case DL_RELEASE | INDICATION:
+- case DL_RELEASE | CONFIRM:
+- {
+- if (stack->ptp) {
+- 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 Attempts!!!\n");
+- } else {
++ /* when we get the L2 UP, the L1 is UP definitely too*/
++ stack->l2link = 1;
++ stack->l2upcnt=0;
++
++ free_msg(msg);
++ return 0;
++
++ case DL_RELEASE | INDICATION:
++ case DL_RELEASE | CONFIRM:
++ if (stack->ptp) {
++ 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 Attempts!!!\n");
++ } else {
+ #if 0
+- if (stack->nt) misdn_lib_reinit_nt_stack(stack->port);
++ if (stack->nt)
++ misdn_lib_reinit_nt_stack(stack->port);
+ #endif
+- if (stack->l1link) {
+- misdn_lib_get_l2_up(stack);
+- stack->l2upcnt++;
+- }
++ if (stack->l1link) {
++ misdn_lib_get_l2_up(stack);
++ stack->l2upcnt++;
+ }
+-
+- } else
+- cb_log(3, stack->port, "%% GOT L2 DeActivate Info.\n");
+-
+- stack->l2link = 0;
+- free_msg(msg);
+- return 0;
+- }
++ }
++
++ } else
++ cb_log(3, stack->port, "%% GOT L2 DeActivate Info.\n");
++
++ stack->l2link = 0;
++ free_msg(msg);
++ return 0;
++
++ default:
+ 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;
++
++ /* Parse Events and fire_up to App. */
++ 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;
++ }
++
++ isdn_msg_parse_event(msgs_g, msg, bc, 1);
++
++ switch (event) {
++ case EVENT_SETUP:
++ if (bc->channel <= 0 || bc->channel == 0xff) {
++ bc->channel = 0;
+ }
+- if (bc ) {
+- isdn_msg_parse_event(msgs_g,msg,bc, 1);
+
+- switch (event) {
+- case EVENT_SETUP:
+- if (bc->channel<=0 || bc->channel==0xff)
+- bc->channel=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;
+- empty_bc(bc);
+- bc->cause=tmpcause;
+- clean_up_bc(bc);
++ if (find_free_chan_in_stack(stack, bc, bc->channel, 0) < 0) {
++ goto ERR_NO_CHANNEL;
++ }
++ break;
++ case EVENT_RELEASE:
++ case EVENT_RELEASE_COMPLETE:
++ channel = bc->channel;
++ tmpcause = bc->cause;
+
+- if (channel>0)
+- empty_chan_in_stack(stack,channel);
+- bc->in_use=0;
+- }
+- break;
++ empty_bc(bc);
++ bc->cause = tmpcause;
++ clean_up_bc(bc);
+
+- default:
++ if (channel > 0)
++ empty_chan_in_stack(stack, channel);
++ bc->in_use = 0;
++ break;
++ 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 {
++ if (reject) {
++ switch(bc->cause) {
++ case AST_CAUSE_USER_BUSY:
++ cb_log(1, stack->port, "Siemens Busy reject..\n");
+ break;
++ 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 {
+- if (reject) {
+- switch(bc->cause){
+- case AST_CAUSE_USER_BUSY:
+- cb_log(1, stack->port, "Siemens Busy reject..\n");
+-
+- break;
+- default:
+- break;
+- }
+- }
+- cb_event(event, bc, glob_mgr->user_data);
+- }
+- } else {
+- cb_log(4, stack->port, "No BC found with l3id: prim %x dinfo %x\n",hh->prim, hh->dinfo);
+ }
+-
+- free_msg(msg);
++ cb_event(event, bc, glob_mgr->user_data);
+ }
+
++ free_msg(msg);
++ return 0;
+
++ERR_NO_CHANNEL:
++ cb_log(4, stack->port, "Patch from MEIDANIS:Sending RELEASE_COMPLETE %x (No free Chan for you..)\n", hh->dinfo);
++ dmsg = create_l3msg(CC_RELEASE_COMPLETE | REQUEST, MT_RELEASE_COMPLETE, hh->dinfo, sizeof(RELEASE_COMPLETE_t), 1);
++ stack->nst.manager_l3(&stack->nst, dmsg);
++ free_msg(msg);
+ return 0;
+ }
+
+@@ -2161,8 +2247,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 +2258,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 +2287,12 @@
+ return 1;
+ }
+ }
+-
++
+ cb_log(0, 0, "Timer Msg without Timer ??\n");
+ free_msg(msg);
+ return 1;
+ }
+-
++
+ return 0;
+ }
+
+@@ -2226,23 +2312,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 +2336,21 @@
+ 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));
++ if (rx)
++ fclose(rx);
++ if (tx)
++ fclose(tx);
+ return ;
+ }
+-
++
+ fwrite(p1,1,l1,rx);
+ fwrite(p2,1,l2,tx);
+-
++
+ fclose(rx);
+ fclose(tx);
+
+@@ -2273,25 +2363,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(1, bc->port, "Jitterbuffer Underrun. Got %d of expected %d\n", jlen, len);
+ }
+-
++
+ 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);
+
+@@ -2337,25 +2427,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;
+@@ -2368,9 +2458,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;
+@@ -2378,12 +2468,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);
+@@ -2400,31 +2490,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];
+@@ -2440,33 +2530,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;
+ }
+@@ -2487,11 +2584,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:
+ {
+@@ -2499,10 +2596,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);
+@@ -2514,12 +2611,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;
+
+@@ -2533,7 +2630,7 @@
+ #endif
+ if ( !t ) {
+ int i;
+-
++
+ if ( misdn_cap_is_speech(bc->capability)) {
+ if ( !bc->nojitter ) {
+ #ifdef MISDN_B_DEBUG
+@@ -2546,15 +2643,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);*/
+@@ -2587,7 +2684,7 @@
+ #endif
+ break;
+ }
+-
++
+ return 0;
+ }
+
+@@ -2601,187 +2698,173 @@
+
+ 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;
+ }
+
+
+ static int handle_frm(msg_t *msg)
+ {
+- iframe_t *frm = (iframe_t*) msg->data;
+-
+- struct misdn_stack *stack=find_stack_by_addr(frm->addr);
++ struct misdn_bchannel dummybc;
++ struct misdn_bchannel *bc;
++ iframe_t *frm;
++ struct misdn_stack *stack;
++ enum event_e event;
++ enum event_response_e response;
++ int ret;
++ int channel;
++ int tmpcause;
++ int tmp_out_cause;
+
++ frm = (iframe_t*) msg->data;
++ 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);
+
+- {
+- struct misdn_bchannel dummybc;
+- struct misdn_bchannel *bc;
+- int ret=handle_cr(stack, frm);
++ cb_log(4, stack ? stack->port : 0, "handle_frm: frm->addr:%x frm->prim:%x\n", frm->addr, frm->prim);
+
+- if (ret<0) {
+- cb_log(3,stack?stack->port:0,"handle_frm: handle_cr <0 prim:%x addr:%x\n", frm->prim, frm->addr);
++ ret = handle_cr(stack, frm);
++ if (ret < 0) {
++ cb_log(3, stack ? stack->port : 0, "handle_frm: handle_cr <0 prim:%x addr:%x\n", frm->prim, frm->addr);
++ }
++ if (ret) {
++ free_msg(msg);
++ return 1;
++ }
+
++ bc = find_bc_by_l3id(stack, frm->dinfo);
++ if (!bc) {
++ misdn_make_dummy(&dummybc, stack->port, 0, stack->nt, 0);
++ switch (frm->prim) {
++ case CC_RESTART | CONFIRM:
++ dummybc.l3_id = MISDN_ID_GLOBAL;
++ bc = &dummybc;
++ break;
++ case CC_SETUP | INDICATION:
++ dummybc.l3_id = frm->dinfo;
++ bc = &dummybc;
+
+- }
++ misdn_lib_send_event(bc, EVENT_RELEASE_COMPLETE);
+
+- if(ret) {
+ free_msg(msg);
+ return 1;
++ default:
++ if (frm->prim == (CC_FACILITY | INDICATION)) {
++ cb_log(5, stack->port, " --> Using Dummy BC for FACILITY\n");
++ } else {
++ cb_log(0, stack->port, " --> Didn't find BC so temporarily creating dummy BC (l3id:%x) on this port.\n", frm->dinfo);
++ dummybc.l3_id = frm->dinfo;
++ }
++ bc = &dummybc;
++ break;
+ }
+-
+- bc=find_bc_by_l3id(stack, frm->dinfo);
++ }
+
+- if (!bc && (frm->prim==(CC_RESTART|CONFIRM)) ) {
+- misdn_make_dummy(&dummybc, stack->port, MISDN_ID_GLOBAL, stack->nt, 0);
+- bc=&dummybc;
+- }
++ event = isdn_msg_get_event(msgs_g, msg, 0);
++ isdn_msg_parse_event(msgs_g, msg, bc, 0);
+
+- if (!bc && (frm->prim==(CC_SETUP|INDICATION)) ) {
+- misdn_make_dummy(&dummybc, stack->port, MISDN_ID_GLOBAL, stack->nt, 0);
+- dummybc.port=stack->port;
+- dummybc.l3_id=frm->dinfo;
+- bc=&dummybc;
++ /* Preprocess some Events */
++ ret = handle_event(bc, event, frm);
++ if (ret < 0) {
++ cb_log(0, stack->port, "couldn't handle event\n");
++ free_msg(msg);
++ return 1;
++ }
+
+- misdn_lib_send_event(bc,EVENT_RELEASE_COMPLETE);
++ /* 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);
+
+- free_msg(msg);
+- return 1;
+- }
++ 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);
++ response = RESPONSE_OK;
++ } else {
++ response = cb_event(event, bc, glob_mgr->user_data);
++ }
+
+-
+-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) {
+- cb_log(0,stack->port,"couldn't handle event\n");
+- free_msg(msg);
+- return 1;
++ switch (event) {
++ case EVENT_SETUP:
++ switch (response) {
++ case RESPONSE_IGNORE_SETUP_WITHOUT_CLOSE:
++ 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;
++ /* fall through */
++ case RESPONSE_RELEASE_SETUP:
++ misdn_lib_send_event(bc, EVENT_RELEASE_COMPLETE);
++ if (bc->channel > 0) {
++ empty_chan_in_stack(stack, bc->channel);
+ }
+- /* 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))
+- 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);
+-#if 1
+- if (event == EVENT_SETUP) {
+- switch (response) {
+- case RESPONSE_IGNORE_SETUP_WITHOUT_CLOSE:
++ empty_bc(bc);
++ bc_state_change(bc, BCHAN_CLEANED);
++ bc->in_use = 0;
+
+- 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)
+- empty_chan_in_stack(stack, bc->channel);
+- empty_bc(bc);
+- bc_state_change(bc,BCHAN_CLEANED);
+- bc->in_use=0;
++ cb_log(0, stack->port, "GOT IGNORE SETUP\n");
++ break;
++ case RESPONSE_OK:
++ cb_log(4, stack->port, "GOT SETUP OK\n");
++ break;
++ default:
++ break;
++ }
++ break;
++ case EVENT_RELEASE_COMPLETE:
++ /* release bchannel only after we've announced the RELEASE_COMPLETE */
++ channel = bc->channel;
++ tmpcause = bc->cause;
++ tmp_out_cause = bc->out_cause;
+
+- cb_log(0, stack->port, "GOT IGNORE SETUP\n");
+- break;
+- case RESPONSE_OK:
+- cb_log(4, stack->port, "GOT SETUP OK\n");
++ empty_bc(bc);
++ bc->cause = tmpcause;
++ bc->out_cause = tmp_out_cause;
++ clean_up_bc(bc);
+
+-
+- break;
+- default:
+- break;
+- }
+- }
+-
+- 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;
+- 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");
+- set_chan_in_stack(stack, channel);
+- bc->channel=channel;
+- misdn_lib_send_restart(stack->port, channel);
+- } else {
+- if (channel>0)
+- empty_chan_in_stack(stack, channel);
+- }
+- bc->in_use=0;
+- }
+-
+- if (event == EVENT_RESTART) {
+- cb_log(0, stack->port, "**** Received RESTART_ACK channel:%d\n", bc->restart_channel);
+- empty_chan_in_stack(stack, bc->restart_channel);
+- }
+-
+- 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))
+- 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");
+-
+- memset (&dummybc,0,sizeof(dummybc));
+- dummybc.port=stack->port;
+- dummybc.l3_id=frm->dinfo;
+- bc=&dummybc;
+- goto handle_frm_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");
++ set_chan_in_stack(stack, channel);
++ bc->channel = channel;
++ misdn_lib_send_restart(stack->port, channel);
++ } else if (channel > 0) {
++ empty_chan_in_stack(stack, channel);
+ }
++ bc->in_use = 0;
++ break;
++ case EVENT_RESTART:
++ cb_log(0, stack->port, "**** Received RESTART_ACK channel:%d\n", bc->restart_channel);
++ empty_chan_in_stack(stack, bc->restart_channel);
++ break;
++ default:
++ break;
+ }
+
+- cb_log(4, stack->port, "TE_FRM_HANDLER: Returning 0 on prim:%x \n",frm->prim);
+- return 0;
++ cb_log(5, stack->port, "Freeing Msg on prim:%x \n", frm->prim);
++ free_msg(msg);
++ return 1;
+ }
+
+
+@@ -2790,7 +2873,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) {
+@@ -2798,9 +2881,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);
+
+@@ -2809,14 +2892,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;
+
+@@ -2824,16 +2907,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) {
+@@ -2841,19 +2924,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;
+ }
+
+@@ -2862,11 +2945,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:
+@@ -2875,13 +2958,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;
+@@ -2889,13 +2972,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;
+ }
+@@ -2914,9 +2997,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",
+@@ -2924,20 +3007,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");
+@@ -2951,16 +3034,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);
+@@ -2969,21 +3052,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;
+@@ -2996,7 +3079,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");
+@@ -3010,8 +3093,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
+@@ -3029,12 +3112,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);
+ }
+ }
+ }
+@@ -3046,19 +3129,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 {
+@@ -3067,10 +3150,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 {
+@@ -3079,7 +3162,7 @@
+ fff_frm = 0 ;
+ }
+ }
+-
++
+ manager_isdn_handler(frm, msg);
+ }
+
+@@ -3088,31 +3171,29 @@
+
+ /** App Interface **/
+
+-int te_lib_init(void) {
++static int te_lib_init(void)
++{
+ char buff[1025] = "";
+- iframe_t *frm=(iframe_t*)buff;
+- int midev=mISDN_open();
++ iframe_t *frm = (iframe_t *) buff;
++ int midev;
+ int ret;
+
+- if (midev<=0) return midev;
+-
+-/* create entity for layer 3 TE-mode */
++ midev = mISDN_open();
++ 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));
++ entity = frm->dinfo & 0xffff;
++ if (ret < mISDN_HEADER_LEN || !entity) {
++ 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)
+@@ -3136,14 +3217,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;
+ }
+
+@@ -3158,18 +3239,20 @@
+ static int test_inuse(struct misdn_bchannel *bc)
+ {
+ struct timeval now;
+- gettimeofday(&now, NULL);
++
+ if (!bc->in_use) {
+- if (misdn_lib_port_is_pri(bc->port) && bc->last_used.tv_sec == now.tv_sec ) {
+- 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);
++ gettimeofday(&now, NULL);
++ if (bc->last_used.tv_sec == now.tv_sec
++ && misdn_lib_port_is_pri(bc->port)) {
++ 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;
+ }
+@@ -3195,88 +3278,125 @@
+ #endif
+ }
+
+-struct misdn_bchannel* misdn_lib_get_free_bc(int port, int channel, int inout, int dec)
++struct misdn_bchannel *misdn_lib_get_free_bc(int port, int channel, int inout, int dec)
+ {
+ struct misdn_stack *stack;
+ int i;
+-
++ int maxnum;
++
+ if (channel < 0 || channel > MAX_BCHANS) {
+- cb_log(0,port,"Requested channel out of bounds (%d)\n",channel);
++ cb_log(0, port, "Requested channel out of bounds (%d)\n", channel);
+ return NULL;
+ }
+
+ usleep(1000);
+
+- for (stack=glob_mgr->stack_list; stack; stack=stack->next) {
+-
+- if (stack->port == port) {
+- int maxnum;
++ /* Find the port stack structure */
++ stack = find_stack_by_port(port);
++ if (!stack) {
++ cb_log(0, port, "Port is not configured (%d)\n", port);
++ return NULL;
++ }
+
+- if (stack->blocked) {
+- 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])) {
+- cb_log(0,port,"Requested channel:%d on port:%d is already in use\n",channel, port);
+- return NULL;
++ if (stack->blocked) {
++ cb_log(0, port, "Port is blocked\n");
++ return NULL;
++ }
+
+- } else {
+- prepare_bc(&stack->bc[i], channel);
+- return &stack->bc[i];
+- }
+- }
++ 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])) {
++ cb_log(0, port, "Requested channel:%d on port:%d is already in use\n", channel, port);
++ return NULL;
++ } else {
++ prepare_bc(&stack->bc[i], channel);
++ return &stack->bc[i];
+ }
+- } else {
+- cb_log(0,port,"Requested channel:%d is out of bounds on port:%d\n",channel, port);
+- return NULL;
+ }
+ }
++ } else {
++ cb_log(0, port, "Requested channel:%d is out of bounds on port:%d\n", channel, port);
++ return NULL;
++ }
++ }
+
+- maxnum = inout && !stack->pri && !stack->ptp ? stack->b_num + 1 : stack->b_num;
++ /* Note: channel == 0 here */
++ maxnum = (inout && !stack->pri && !stack->ptp) ? stack->b_num + 1 : stack->b_num;
++ if (dec) {
++ for (i = maxnum - 1; i >= 0; --i) {
++ if (!test_inuse(&stack->bc[i])) {
++ /* 3. channel on bri means CW*/
++ if (!stack->pri && i == stack->b_num) {
++ stack->bc[i].cw = 1;
++ }
+
+- if (dec) {
+- for (i = maxnum-1; i>=0; i--) {
+- if (!test_inuse(&stack->bc[i])) {
+- /* 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];
+- }
++ prepare_bc(&stack->bc[i], channel);
++ stack->bc[i].dec = 1;
++ return &stack->bc[i];
++ }
++ }
++ } else {
++ for (i = 0; i < maxnum; ++i) {
++ if (!test_inuse(&stack->bc[i])) {
++ /* 3. channel on bri means CW */
++ if (!stack->pri && i == stack->b_num) {
++ stack->bc[i].cw = 1;
+ }
+- } else {
+- for (i = 0; i <maxnum; i++) {
+- if (!test_inuse(&stack->bc[i])) {
+- /* 3. channel on bri means CW*/
+- if (!stack->pri && i==stack->b_num)
+- stack->bc[i].cw=1;
+
+- prepare_bc(&stack->bc[i], channel);
+- return &stack->bc[i];
+- }
+- }
++ prepare_bc(&stack->bc[i], channel);
++ return &stack->bc[i];
+ }
+-
+- cb_log(1,port,"There is no free channel on port (%d)\n",port);
+- return NULL;
+ }
+ }
+
+- cb_log(0,port,"Port is not configured (%d)\n",port);
++ cb_log(1, port, "There is no free channel on port (%d)\n", port);
+ return NULL;
+ }
+
++#if defined(AST_MISDN_ENHANCEMENTS)
++/*!
++ * \brief Allocate a B channel struct from the REGISTER pool
++ *
++ * \param port Logical port number
++ *
++ * \retval B channel struct on success.
++ * \retval NULL on error.
++ */
++struct misdn_bchannel *misdn_lib_get_register_bc(int port)
++{
++ struct misdn_stack *stack;
++ struct misdn_bchannel *bc;
++ unsigned index;
+
++ /* Find the port stack structure */
++ stack = find_stack_by_port(port);
++ if (!stack) {
++ cb_log(0, port, "Port is not configured (%d)\n", port);
++ return NULL;
++ }
+
++ if (stack->blocked) {
++ cb_log(0, port, "Port is blocked\n");
++ return NULL;
++ }
+
+-/* ******************************************************************* */
++ for (index = MAX_BCHANS + 1; index < ARRAY_LEN(stack->bc); ++index) {
++ bc = &stack->bc[index];
++ if (!test_inuse(bc)) {
++ prepare_bc(bc, 0);
++ bc->need_disconnect = 0;
++ bc->need_release = 0;
++ return bc;
++ }
++ }
++
++ cb_log(1, port, "There is no free REGISTER link on port (%d)\n", port);
++ return NULL;
++}
++#endif /* defined(AST_MISDN_ENHANCEMENTS) */
++
+ /*!
+ * \internal
+ * \brief Convert the facility function enum value into a string.
+@@ -3285,36 +3405,96 @@
+ */
+ 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" },
++#if defined(AST_MISDN_ENHANCEMENTS)
++ { Fac_ERROR, "Fac_ERROR" },
++ { Fac_RESULT, "Fac_RESULT" },
++ { Fac_REJECT, "Fac_REJECT" },
++
++ { Fac_ActivationDiversion, "Fac_ActivationDiversion" },
++ { Fac_DeactivationDiversion, "Fac_DeactivationDiversion" },
++ { Fac_ActivationStatusNotificationDiv, "Fac_ActivationStatusNotificationDiv" },
++ { Fac_DeactivationStatusNotificationDiv, "Fac_DeactivationStatusNotificationDiv" },
++ { Fac_InterrogationDiversion, "Fac_InterrogationDiversion" },
++ { Fac_DiversionInformation, "Fac_DiversionInformation" },
++ { Fac_CallDeflection, "Fac_CallDeflection" },
++ { Fac_CallRerouteing, "Fac_CallRerouteing" },
++ { Fac_DivertingLegInformation2, "Fac_DivertingLegInformation2" },
++ { Fac_InterrogateServedUserNumbers, "Fac_InterrogateServedUserNumbers" },
++ { Fac_DivertingLegInformation1, "Fac_DivertingLegInformation1" },
++ { Fac_DivertingLegInformation3, "Fac_DivertingLegInformation3" },
++
++ { Fac_EctExecute, "Fac_EctExecute" },
++ { Fac_ExplicitEctExecute, "Fac_ExplicitEctExecute" },
++ { Fac_RequestSubaddress, "Fac_RequestSubaddress" },
++ { Fac_SubaddressTransfer, "Fac_SubaddressTransfer" },
++ { Fac_EctLinkIdRequest, "Fac_EctLinkIdRequest" },
++ { Fac_EctInform, "Fac_EctInform" },
++ { Fac_EctLoopTest, "Fac_EctLoopTest" },
++
++ { Fac_ChargingRequest, "Fac_ChargingRequest" },
++ { Fac_AOCSCurrency, "Fac_AOCSCurrency" },
++ { Fac_AOCSSpecialArr, "Fac_AOCSSpecialArr" },
++ { Fac_AOCDCurrency, "Fac_AOCDCurrency" },
++ { Fac_AOCDChargingUnit, "Fac_AOCDChargingUnit" },
++ { Fac_AOCECurrency, "Fac_AOCECurrency" },
++ { Fac_AOCEChargingUnit, "Fac_AOCEChargingUnit" },
++
++ { Fac_StatusRequest, "Fac_StatusRequest" },
++
++ { Fac_CallInfoRetain, "Fac_CallInfoRetain" },
++ { Fac_EraseCallLinkageID, "Fac_EraseCallLinkageID" },
++ { Fac_CCBSDeactivate, "Fac_CCBSDeactivate" },
++ { Fac_CCBSErase, "Fac_CCBSErase" },
++ { Fac_CCBSRemoteUserFree, "Fac_CCBSRemoteUserFree" },
++ { Fac_CCBSCall, "Fac_CCBSCall" },
++ { Fac_CCBSStatusRequest, "Fac_CCBSStatusRequest" },
++ { Fac_CCBSBFree, "Fac_CCBSBFree" },
++ { Fac_CCBSStopAlerting, "Fac_CCBSStopAlerting" },
++
++ { Fac_CCBSRequest, "Fac_CCBSRequest" },
++ { Fac_CCBSInterrogate, "Fac_CCBSInterrogate" },
++
++ { Fac_CCNRRequest, "Fac_CCNRRequest" },
++ { Fac_CCNRInterrogate, "Fac_CCNRInterrogate" },
++
++ { Fac_CCBS_T_Call, "Fac_CCBS_T_Call" },
++ { Fac_CCBS_T_Suspend, "Fac_CCBS_T_Suspend" },
++ { Fac_CCBS_T_Resume, "Fac_CCBS_T_Resume" },
++ { Fac_CCBS_T_RemoteUserFree, "Fac_CCBS_T_RemoteUserFree" },
++ { Fac_CCBS_T_Available, "Fac_CCBS_T_Available" },
++
++ { Fac_CCBS_T_Request, "Fac_CCBS_T_Request" },
++
++ { Fac_CCNR_T_Request, "Fac_CCNR_T_Request" },
++
++#else
++
+ { 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" },
++#endif /* defined(AST_MISDN_ENHANCEMENTS) */
+ /* *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)
+ {
+@@ -3326,27 +3506,68 @@
+
+ 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-from:\"%s\" <%s> type:%d plan:%d pres:%d screen:%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);
++ cb_log(2, stack->port,
++ " --> redirecting-to:\"%s\" <%s> type:%d plan:%d pres:%d screen:%d\n",
++ bc->redirecting.to.name,
++ bc->redirecting.to.number,
++ bc->redirecting.to.number_type,
++ bc->redirecting.to.number_plan,
++ bc->redirecting.to.presentation,
++ bc->redirecting.to.screening);
++ cb_log(2, stack->port,
++ " --> redirecting reason:%d count:%d\n",
++ bc->redirecting.reason,
++ bc->redirecting.count);
++
++ 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(4, stack->port, " --> facility in:%s out:%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);
+ }
+
+@@ -3369,19 +3590,29 @@
+
+ int misdn_lib_send_event(struct misdn_bchannel *bc, enum event_e event )
+ {
+- msg_t *msg;
+- int retval=0;
++ msg_t *msg;
++ struct misdn_bchannel *bc2;
++ struct misdn_bchannel *holded_bc;
+ struct misdn_stack *stack;
+-
+- if (!bc) RETURN(-1,OUT_POST_UNLOCK);
+-
++ int retval = 0;
++ int channel;
++ int tmpcause;
++ int tmp_out_cause;
++
++ 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);
+
+
+@@ -3394,15 +3625,22 @@
+ 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_REGISTER:
+ case EVENT_SETUP:
+- if (create_process(glob_mgr->midev, bc)<0) {
+- cb_log(0, stack->port, " No free channel at the moment @ send_event\n");
++ if (create_process(glob_mgr->midev, bc) < 0) {
++ cb_log(0, stack->port, " No free channel at the moment @ send_event\n");
+
+ RETURN(-ENOCHAN,OUT);
+ }
+@@ -3413,10 +3651,10 @@
+ case EVENT_PROCEEDING:
+ case EVENT_SETUP_ACKNOWLEDGE:
+ case EVENT_CONNECT:
+- if (!stack->nt) break;
++ if (!stack->nt)
++ break;
+
+ case EVENT_RETRIEVE_ACKNOWLEDGE:
+-
+ if (stack->nt) {
+ if (bc->channel <=0 ) { /* else we have the channel already */
+ if (find_free_chan_in_stack(stack, bc, 0, 0)<0) {
+@@ -3436,19 +3674,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);
+@@ -3458,8 +3703,7 @@
+ break;
+
+ case EVENT_HOLD_ACKNOWLEDGE:
+- {
+- struct misdn_bchannel *holded_bc=malloc(sizeof(struct misdn_bchannel));
++ holded_bc = malloc(sizeof(struct misdn_bchannel));
+ if (!holded_bc) {
+ cb_log(0,bc->port, "Could not allocate holded_bc!!!\n");
+ RETURN(-1,OUT);
+@@ -3471,13 +3715,10 @@
+ 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;
+ if (bc->bc_state == BCHAN_BRIDGED) {
+- struct misdn_bchannel *bc2;
+-
+ misdn_split_conf(bc,bc->conf_id);
+ bc2 = find_bc_by_confid(bc->conf_id);
+ if (!bc2) {
+@@ -3486,7 +3727,7 @@
+ misdn_split_conf(bc2,bc->conf_id);
+ }
+ }
+-
++
+ channel = bc->channel;
+
+ empty_bc(bc);
+@@ -3495,24 +3736,22 @@
+ if (channel>0)
+ empty_chan_in_stack(stack,channel);
+
+- bc->in_use=0;
++ bc->in_use=0;
+ }
+-
+- }
+- break;
++ break;
+
+ /* finishing the channel eh ? */
+ case EVENT_DISCONNECT:
+ if (!bc->need_disconnect) {
+- cb_log(0,bc->port," --> we have already send Disconnect\n");
++ cb_log(0, bc->port, " --> we have already sent DISCONNECT\n");
+ RETURN(-1,OUT);
+ }
+-
++
+ bc->need_disconnect=0;
+ break;
+ case EVENT_RELEASE:
+ if (!bc->need_release) {
+- cb_log(0,bc->port," --> we have already send Release\n");
++ cb_log(0, bc->port, " --> we have already sent RELEASE\n");
+ RETURN(-1,OUT);
+ }
+ bc->need_disconnect=0;
+@@ -3520,7 +3759,7 @@
+ break;
+ case EVENT_RELEASE_COMPLETE:
+ if (!bc->need_release_complete) {
+- cb_log(0,bc->port," --> we have already send Release_complete\n");
++ cb_log(0, bc->port, " --> we have already sent RELEASE_COMPLETE\n");
+ RETURN(-1,OUT);
+ }
+ bc->need_disconnect=0;
+@@ -3528,33 +3767,32 @@
+ bc->need_release_complete=0;
+
+ if (!stack->nt) {
+- /*create cleanup in TE*/
+- int channel=bc->channel;
++ /* create cleanup in TE */
++ channel = bc->channel;
++ tmpcause = bc->cause;
++ 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);
+@@ -3569,21 +3807,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;
+ }
+
+
+@@ -3601,12 +3850,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);
+@@ -3614,7 +3863,7 @@
+
+ case MGR_SETSTACK|CONFIRM:
+ case MGR_CLEARSTACK|CONFIRM:
+- free_msg(msg) ;
++ free_msg(msg) ;
+ return 1;
+ break;
+
+@@ -3635,13 +3884,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) {
+@@ -3652,7 +3901,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);
+@@ -3663,7 +3912,7 @@
+ free_msg(msg);
+ return 1;
+ }
+-
++
+ cb_log(3,port," --> BC in state:%s\n", bc_state2str(bc->bc_state));
+ }
+ }
+@@ -3678,7 +3927,7 @@
+ struct misdn_stack *stack;
+ stack=find_stack_by_addr( frm->addr );
+
+-
++
+ if (!stack) {
+ return 0;
+ }
+@@ -3690,7 +3939,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");
+@@ -3701,35 +3950,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;
+ }
+@@ -3742,10 +3991,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;
+ }
+
+@@ -3773,16 +4022,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;
+@@ -3799,15 +4048,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);
+
+@@ -3824,7 +4073,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*/
+@@ -3860,11 +4109,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);
+@@ -3874,7 +4123,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 */
+@@ -3889,7 +4138,7 @@
+
+ if (stack->nt)
+ misdn_lib_reinit_nt_stack(stack->port);
+-
++
+ }
+
+ return 0;
+@@ -3897,25 +4146,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) {
+@@ -3930,7 +4179,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");
+@@ -3939,7 +4188,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 */
+@@ -3952,10 +4201,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)) {
+@@ -3965,16 +4214,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);
+@@ -4003,14 +4252,14 @@
+
+ int i = mISDN_open();
+ int max=0;
+-
++
+ if (i<0)
+ return -1;
+
+ max = mISDN_get_stack_count(i);
+-
++
+ mISDN_close(i);
+-
++
+ return max;
+ }
+
+@@ -4027,12 +4276,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;
+@@ -4053,50 +4302,52 @@
+ 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;
++ struct misdn_stack *help;
+ int ptp=0;
+-
++ int i;
++ int r;
++
+ if (strstr(tok, "ptp"))
+ ptp=1;
+
+@@ -4104,53 +4355,59 @@
+ cb_log(0, port, "Couldn't Initialize this port since we have only %d ports\n", port_count);
+ exit(1);
+ }
+- stack=stack_init(midev, port, ptp);
+-
++
++ stack = stack_init(midev, port, ptp);
+ if (!stack) {
+ perror("stack_init");
+ exit(1);
+ }
+-
+- {
+- int i;
+- for(i=0;i<=stack->b_num; i++) {
+- int r;
+- if ((r=init_bc(stack, &stack->bc[i], stack->midev,port,i, "", 1))<0) {
+- cb_log(0, port, "Got Err @ init_bc :%d\n",r);
+- exit(1);
+- }
++
++ /* Initialize the B channel records for real B channels. */
++ for (i = 0; i <= stack->b_num; i++) {
++ r = init_bc(stack, &stack->bc[i], stack->midev, port, i);
++ if (r < 0) {
++ cb_log(0, port, "Got Err @ init_bc :%d\n", r);
++ exit(1);
+ }
+ }
++#if defined(AST_MISDN_ENHANCEMENTS)
++ /* Initialize the B channel records for REGISTER signaling links. */
++ for (i = MAX_BCHANS + 1; i < ARRAY_LEN(stack->bc); ++i) {
++ r = init_bc(stack, &stack->bc[i], stack->midev, port, i);
++ if (r < 0) {
++ cb_log(0, port, "Got Err @ init_bc :%d\n", r);
++ exit(1);
++ }
++ stack->bc[i].is_register_pool = 1;
++ }
++#endif /* defined(AST_MISDN_ENHANCEMENTS) */
+
+- if (stack && first) {
+- mgr->stack_list=stack;
+- first=0;
+- continue;
++ /* Add the new stack to the end of the list */
++ help = mgr->stack_list;
++ if (!help) {
++ mgr->stack_list = stack;
++ } else {
++ while (help->next) {
++ help = help->next;
++ }
++ help->next = stack;
+ }
+-
+- if (stack) {
+- struct misdn_stack * help;
+- 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);
+ }
+
+@@ -4158,7 +4415,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];
+@@ -4168,21 +4425,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);
+ }
+@@ -4202,12 +4459,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 ;
+@@ -4218,7 +4475,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:
+@@ -4231,11 +4488,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;
+@@ -4243,9 +4500,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;
+ }
+
+@@ -4265,19 +4522,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;
+@@ -4294,9 +4551,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;
+@@ -4345,7 +4602,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;
+@@ -4361,13 +4618,14 @@
+ void manager_clean_bc(struct misdn_bchannel *bc )
+ {
+ struct misdn_stack *stack=get_stack_by_bc(bc);
+-
+- if (bc->channel>0)
++
++ if (stack && 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);
+ }
+
+
+@@ -4375,15 +4633,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) {
+@@ -4392,7 +4650,7 @@
+ break;
+ }
+ }
+-
++
+ }
+
+ void stack_holder_remove(struct misdn_stack *stack, struct misdn_bchannel *holder)
+@@ -4400,17 +4658,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) {
+@@ -4426,9 +4684,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) {
+@@ -4448,9 +4706,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) {
+@@ -4466,34 +4724,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);
+ }
+
+@@ -4501,7 +4759,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)) {
+@@ -4518,7 +4776,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:
+@@ -4535,10 +4793,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
+@@ -4550,7 +4808,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)) {
+@@ -4568,7 +4826,8 @@
+ #endif
+ }
+
+-struct misdn_stack* get_misdn_stack(void) {
++struct misdn_stack *get_misdn_stack(void)
++{
+ return glob_mgr->stack_list;
+ }
+
+@@ -4605,10 +4864,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);
+@@ -4627,15 +4886,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));
+ }
+ }
+-
++
+ }
+
+
+@@ -4651,37 +4910,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-beta3) (revision 202568)
++++ b/channels/misdn/isdn_lib_intern.h (.../trunk) (revision 202568)
+@@ -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);
+@@ -52,7 +51,15 @@
+ /* for isdn_msg_parser.c */
+ msg_t *create_l3msg(int prim, int mt, int dinfo , int size, int nt);
+
++#if defined(AST_MISDN_ENHANCEMENTS)
++/* Max call-completion REGISTER signaling links per stack/port */
++#define MISDN_MAX_REGISTER_LINKS MAX_BCHANS
++#else
++/* Max call-completion REGISTER signaling links per stack/port */
++#define MISDN_MAX_REGISTER_LINKS 0
++#endif /* defined(AST_MISDN_ENHANCEMENTS) */
+
++#define MAXPROCS 0x100
+
+ struct misdn_stack {
+ /** is first element because &nst equals &mISDNlist **/
+@@ -88,8 +95,6 @@
+ /*! \brief TRUE if Layer 2 is UP */
+ int l2link;
+
+- time_t l2establish; /* Not used */
+-
+ /*! \brief TRUE if Layer 1 is UP */
+ int l1link;
+
+@@ -106,7 +111,7 @@
+ int pri;
+
+ /*! \brief CR Process ID allocation table. TRUE if ID allocated */
+- int procids[0x100+1];
++ int procids[MAXPROCS];
+
+ /*! \brief Queue of Event messages to send to mISDN */
+ msg_queue_t downqueue;
+@@ -116,14 +121,18 @@
+ /*! \brief Logical Layer 1 port associated with this stack */
+ int port;
+
+- /*! \brief B Channel record pool array */
+- struct misdn_bchannel bc[MAX_BCHANS + 1];
++ /*!
++ * \brief B Channel record pool array
++ * (Must be dimensioned the same as struct misdn_stack.channels[])
++ */
++ struct misdn_bchannel bc[MAX_BCHANS + 1 + MISDN_MAX_REGISTER_LINKS];
+
+- struct misdn_bchannel* bc_list; /* Not used */
++ /*!
++ * \brief Array of B channels in use (a[0] = B1). TRUE if B channel in use.
++ * (Must be dimensioned the same as struct misdn_stack.bc[])
++ */
++ char channels[MAX_BCHANS + 1 + MISDN_MAX_REGISTER_LINKS];
+
+- /*! \brief Array of B channels in use (a[0] = B1). TRUE if B channel in use */
+- int channels[MAX_BCHANS + 1];
+-
+ /*! \brief List of holded channels */
+ struct misdn_bchannel *holding;
+
+Index: channels/misdn/isdn_lib.h
+===================================================================
+--- a/channels/misdn/isdn_lib.h (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/channels/misdn/isdn_lib.h (.../trunk) (revision 202568)
+@@ -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,
+@@ -125,6 +133,7 @@
+ EVENT_PROCEEDING,
+ EVENT_PROGRESS,
+ EVENT_SETUP,
++ EVENT_REGISTER,
+ EVENT_ALERTING,
+ EVENT_CONNECT,
+ EVENT_SETUP_ACKNOWLEDGE,
+@@ -189,6 +198,44 @@
+ INFO_PI_INTERWORKING_NO_RELEASE_POST_ANSWER =0x13
+ };
+
++/*!
++ * \brief Q.931 encoded redirecting reason
++ */
++enum mISDN_REDIRECTING_REASON {
++ mISDN_REDIRECTING_REASON_UNKNOWN = 0x0,
++ /*! Call forwarding busy or called DTE busy */
++ mISDN_REDIRECTING_REASON_CALL_FWD_BUSY = 0x1,
++ /*! Call forwarding no reply */
++ mISDN_REDIRECTING_REASON_NO_REPLY = 0x2,
++ /*! Call deflection */
++ mISDN_REDIRECTING_REASON_DEFLECTION = 0x4,
++ /*! Called DTE out of order */
++ mISDN_REDIRECTING_REASON_OUT_OF_ORDER = 0x9,
++ /*! Call forwarding by the called DTE */
++ mISDN_REDIRECTING_REASON_CALL_FWD_DTE = 0xA,
++ /*! Call forwarding unconditional or systematic call redirection */
++ mISDN_REDIRECTING_REASON_CALL_FWD = 0xF
++};
++
++/*!
++ * \brief Notification description code enumeration
++ */
++enum mISDN_NOTIFY_CODE {
++ mISDN_NOTIFY_CODE_INVALID = -1,
++ /*! Call is placed on hold (Q.931) */
++ mISDN_NOTIFY_CODE_USER_SUSPEND = 0x00,
++ /*! Call is taken off of hold (Q.931) */
++ mISDN_NOTIFY_CODE_USER_RESUME = 0x01,
++ /*! Call is diverting (EN 300 207-1 Section 7.2.1) */
++ mISDN_NOTIFY_CODE_CALL_IS_DIVERTING = 0x7B,
++ /*! Call diversion is enabled (cfu, cfb, cfnr) (EN 300 207-1 Section 7.2.1) */
++ mISDN_NOTIFY_CODE_DIVERSION_ACTIVATED = 0x68,
++ /*! Call transfer, alerting (EN 300 369-1 Section 7.2) */
++ mISDN_NOTIFY_CODE_CALL_TRANSFER_ALERTING = 0x69,
++ /*! Call transfer, active(answered) (EN 300 369-1 Section 7.2) */
++ mISDN_NOTIFY_CODE_CALL_TRANSFER_ACTIVE = 0x6A,
++};
++
+ enum { /*CODECS*/
+ INFO_CODEC_ULAW=2,
+ INFO_CODEC_ALAW=3
+@@ -202,12 +249,116 @@
+ 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 Dialed/Called information struct */
++struct misdn_party_dialing {
++ /*! \brief Type-of-number in ISDN terms for the dialed/called number */
++ 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];
++};
++
++/*! \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 Where the call is being redirected toward (Sent to the calling party) */
++ struct misdn_party_id to;
++
++ /*! \brief Reason a call is being redirected (Q.931 field value) */
++ enum mISDN_REDIRECTING_REASON reason;
++
++ /*! \brief Number of times the call has been redirected */
++ int count;
++
++ /*! \brief TRUE if the redirecting.to information has changed */
++ int to_changed;
++};
++
++
++/*! \brief B channel control structure */
+ struct misdn_bchannel {
+ /*! \brief B channel send locking structure */
+ struct send_lock *send_lock;
+
++#if defined(AST_MISDN_ENHANCEMENTS)
++ /*! \brief The BC, HLC (optional) and LLC (optional) contents from the SETUP message. */
++ struct Q931_Bc_Hlc_Llc setup_bc_hlc_llc;
++#endif /* defined(AST_MISDN_ENHANCEMENTS) */
++
++ /*!
++ * \brief Dialed/Called information struct
++ * \note The number_type element is set to "dialplan" in /etc/asterisk/misdn.conf for outgoing calls
++ */
++ struct misdn_party_dialing dialed;
++
++ /*! \brief Originating/Caller ID information struct
++ * \note The number_type element can be 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 can be 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;
+
+@@ -264,6 +415,9 @@
+ /*! \brief TRUE if the B channel number is preselected */
+ int channel_preselected;
+
++ /*! \brief TRUE if the B channel is allocated from the REGISTER pool */
++ int is_register_pool;
++
+ /*! \brief TRUE if B channel record is in use */
+ int in_use;
+
+@@ -286,8 +440,6 @@
+ /*! \brief Not used. Contents are setup but not used. */
+ void *astbuf;
+
+- 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
+ */
+@@ -326,26 +478,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.
+ */
+@@ -361,6 +493,18 @@
+ */
+ int progress_indicator;
+
++#if defined(AST_MISDN_ENHANCEMENTS)
++ /*!
++ * \brief TRUE if waiting for DivertingLegInformation3 to queue redirecting update.
++ */
++ int div_leg_3_rx_wanted;
++
++ /*!
++ * \brief TRUE if a DivertingLegInformation3 needs to be sent with CONNECT.
++ */
++ int div_leg_3_tx_pending;
++#endif /* defined(AST_MISDN_ENHANCEMENTS) */
++
+ /*! \brief Inbound FACILITY message function type and contents */
+ struct FacParm fac_in;
+
+@@ -421,17 +565,51 @@
+ */
+ 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 Select what to do with outgoing COLP information.
++ * \details
++ * 0 - pass (Send out COLP information unaltered.)
++ * 1 - restricted (Force COLP to restricted on all outgoing COLP information.)
++ * 2 - block (Do not send COLP information.)
++ */
++ int outgoing_colp;
++
++ /*! \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 Notification indicator ie description code */
++ enum mISDN_NOTIFY_CODE notify_description_code;
++
+ /*! \brief SETUP message bearer capability field code value */
+ int capability;
+
+@@ -468,40 +646,18 @@
+ */
+ char display[84];
+
+- /*! \brief Not used. Contents are setup but not used. */
+- char msn[32];
+-
+- /*! \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]; */
+
+@@ -600,6 +756,9 @@
+ void misdn_lib_transfer(struct misdn_bchannel* holded_bc);
+
+ struct misdn_bchannel* misdn_lib_get_free_bc(int port, int channel, int inout, int dec);
++#if defined(AST_MISDN_ENHANCEMENTS)
++struct misdn_bchannel *misdn_lib_get_register_bc(int port);
++#endif /* defined(AST_MISDN_ENHANCEMENTS) */
+
+ void manager_bchannel_activate(struct misdn_bchannel *bc);
+ void manager_bchannel_deactivate(struct misdn_bchannel * bc);
+@@ -679,4 +838,4 @@
+ void misdn_make_dummy(struct misdn_bchannel *dummybc, int port, int l3id, int nt, int channel);
+
+
+-#endif
++#endif /* TE_LIB */
+Index: channels/misdn/Makefile
+===================================================================
+--- a/channels/misdn/Makefile (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/channels/misdn/Makefile (.../trunk) (revision 202568)
+@@ -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-beta3) (revision 202568)
++++ b/channels/misdn/chan_misdn_config.h (.../trunk) (revision 202568)
+@@ -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) */
+@@ -59,6 +65,8 @@
+ MISDN_CFG_EARLY_BCONNECT, /* int (bool) */
+ MISDN_CFG_INCOMING_EARLY_AUDIO, /* int (bool) */
+ MISDN_CFG_ECHOCANCEL, /* int */
++ MISDN_CFG_CC_REQUEST_RETENTION,/* bool */
++ MISDN_CFG_OUTGOING_COLP, /* int */
+ #ifdef MISDN_1_2
+ MISDN_CFG_PIPELINE, /* char[] */
+ #endif
+@@ -89,7 +97,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,19 +124,19 @@
+ };
+
+ /* 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);
+
+ /* returns the enum element for the given name, returns MISDN_CFG_FIRST if none was found */
+-enum misdn_cfg_elements misdn_cfg_get_elem (char *name);
++enum misdn_cfg_elements misdn_cfg_get_elem (const char *name);
+
+ /* fills the buffer with the name of the given config element */
+ void misdn_cfg_get_name (enum misdn_cfg_elements elem, void *buf, int bufsize);
+Index: channels/misdn/ie.c
+===================================================================
+--- a/channels/misdn/ie.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/channels/misdn/ie.c (.../trunk) (revision 202568)
+@@ -1,4 +1,3 @@
+-
+ /*
+ * Chan_Misdn -- Channel Driver for Asterisk
+ *
+@@ -15,7 +14,7 @@
+ * the GNU General Public License
+ */
+
+-/*! \file
++/*! \file
+ * \brief Interface to mISDN
+ * \author Christian Richter <crich@beronet.com>
+ */
+@@ -39,11 +38,11 @@
+ #define MISDN_IE_DEBG 0
+
+ /* support stuff */
+-static void strnncpy(char *dest, char *src, int len, int dst_len)
++static void strnncpy(char *dest, const char *src, size_t len, size_t dst_len)
+ {
+ if (len > dst_len-1)
+ len = dst_len-1;
+- strncpy((char *)dest, (char *)src, len);
++ strncpy(dest, src, len);
+ dest[len] = '\0';
+ }
+
+@@ -153,7 +152,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 +167,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 +188,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 +220,7 @@
+
+ if (p[0] <= octet)
+ goto done;
+-
++
+ if (p[octet++] & 0x80)
+ goto l2;
+
+@@ -231,7 +230,7 @@
+
+ if (p[0] <= octet)
+ goto done;
+-
++
+ if (p[octet++] & 0x80)
+ goto l2;
+
+@@ -239,7 +238,7 @@
+
+ if (p[0] <= octet)
+ goto done;
+-
++
+ if (p[octet++] & 0x80)
+ goto l2;
+
+@@ -247,20 +246,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 +291,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 +337,7 @@
+ if (MISDN_IE_DEBG) printf(debug+(i*3), " %02x", callid[i]);
+ i++;
+ }
+-
++
+ if (MISDN_IE_DEBG) printf(" callid%s\n", debug);
+ }
+ #endif
+@@ -380,7 +379,7 @@
+ strncpy((char *)p+3, (char *)number, strlen((char *)number));
+ }
+
+-static void dec_ie_called_pn(unsigned char *p, Q931_info_t *qi, int *type, int *plan, char *number, int number_len, int nt, struct misdn_bchannel *bc)
++static void dec_ie_called_pn(unsigned char *p, Q931_info_t *qi, int *type, int *plan, char *number, size_t number_len, int nt, struct misdn_bchannel *bc)
+ {
+ *type = -1;
+ *plan = -1;
+@@ -464,7 +463,7 @@
+ }
+ }
+
+-static void dec_ie_calling_pn(unsigned char *p, Q931_info_t *qi, int *type, int *plan, int *present, int *screen, char *number, int number_len, int nt, struct misdn_bchannel *bc)
++static void dec_ie_calling_pn(unsigned char *p, Q931_info_t *qi, int *type, int *plan, int *present, int *screen, char *number, size_t number_len, int nt, struct misdn_bchannel *bc)
+ {
+ *type = -1;
+ *plan = -1;
+@@ -501,7 +500,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); */
+ }
+@@ -566,7 +565,7 @@
+ }
+ }
+
+-static void dec_ie_connected_pn(unsigned char *p, Q931_info_t *qi, int *type, int *plan, int *present, int *screen, char *number, int number_len, int nt, struct misdn_bchannel *bc)
++static void dec_ie_connected_pn(unsigned char *p, Q931_info_t *qi, int *type, int *plan, int *present, int *screen, char *number, size_t number_len, int nt, struct misdn_bchannel *bc)
+ {
+ *type = -1;
+ *plan = -1;
+@@ -691,7 +690,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 +706,8 @@
+ }
+
+ /* if (MISDN_IE_DEBG) printf(" exclusive=%d channel=%d\n", exclusive, channel); */
+-
+
++
+ if (!pri)
+ {
+ /* BRI */
+@@ -884,7 +883,7 @@
+ static void enc_ie_display(unsigned char **ntmode, msg_t *msg, char *display, int nt, struct misdn_bchannel *bc)
+ {
+ unsigned char *p;
+- Q931_info_t *qi = (Q931_info_t *)(msg->data + mISDN_HEADER_LEN);
++ Q931_info_t *qi = (Q931_info_t *) (msg->data + mISDN_HEADER_LEN);
+ int l;
+
+ if (!display[0])
+@@ -893,27 +892,28 @@
+ return;
+ }
+
+- if (strlen((char *)display) > 80)
++ l = strlen(display);
++ if (80 < l)
+ {
+- printf("%s: WARNING: display text too long (max 80 chars), cutting.\n", __FUNCTION__);
+- display[80] = '\0';
++ l = 80;
++ printf("%s: WARNING: display text too long (max %d chars), cutting.\n", __FUNCTION__, l);
++ display[l] = '\0';
+ }
+
+- /* if (MISDN_IE_DEBG) printf(" display='%s' (len=%d)\n", display, strlen((char *)display)); */
++ /* if (MISDN_IE_DEBG) printf(" display='%s' (len=%d)\n", display, l); */
+
+- l = strlen((char *)display);
+- p = msg_put(msg, l+2);
++ p = msg_put(msg, l + 2);
+ if (nt)
+- *ntmode = p+1;
++ *ntmode = p + 1;
+ else
+- qi->QI_ELEMENT(display) = p - (unsigned char *)qi - sizeof(Q931_info_t);
++ qi->QI_ELEMENT(display) = p - (unsigned char *) qi - sizeof(Q931_info_t);
+ p[0] = IE_DISPLAY;
+ p[1] = l;
+- strncpy((char *)p+2, (char *)display, strlen((char *)display));
++ strncpy((char *) p + 2, display, l);
+ }
+
+ #if 0
+-static void dec_ie_display(unsigned char *p, Q931_info_t *qi, char *display, int display_len, int nt, struct misdn_bchannel *bc)
++static void dec_ie_display(unsigned char *p, Q931_info_t *qi, char *display, size_t display_len, int nt, struct misdn_bchannel *bc)
+ {
+ *display = '\0';
+
+@@ -965,7 +965,7 @@
+ }
+ #endif
+
+-static void dec_ie_keypad(unsigned char *p, Q931_info_t *qi, char *keypad, int keypad_len, int nt, struct misdn_bchannel *bc)
++static void dec_ie_keypad(unsigned char *p, Q931_info_t *qi, char *keypad, size_t keypad_len, int nt, struct misdn_bchannel *bc)
+ {
+ *keypad = '\0';
+
+@@ -990,7 +990,6 @@
+
+
+ /* IE_NOTIFY */
+-#if 0
+ static void enc_ie_notify(unsigned char **ntmode, msg_t *msg, int notify, int nt, struct misdn_bchannel *bc)
+ {
+ unsigned char *p;
+@@ -1015,9 +1014,7 @@
+ p[1] = l;
+ p[2] = 0x80 + notify;
+ }
+-#endif
+
+-#if 0
+ static void dec_ie_notify(unsigned char *p, Q931_info_t *qi, int *notify, int nt, struct misdn_bchannel *bc)
+ {
+ *notify = -1;
+@@ -1040,7 +1037,6 @@
+
+ if (MISDN_IE_DEBG) printf(" notify=%d\n", *notify);
+ }
+-#endif
+
+
+ /* IE_PROGRESS */
+@@ -1086,7 +1082,7 @@
+ *location = -1;
+ //*progress = -1;
+ *progress = 0;
+-
++
+ if (!nt)
+ {
+ p = NULL;
+@@ -1184,7 +1180,7 @@
+ }
+ }
+
+-static void dec_ie_redir_nr(unsigned char *p, Q931_info_t *qi, int *type, int *plan, int *present, int *screen, int *reason, char *number, int number_len, int nt, struct misdn_bchannel *bc)
++static void dec_ie_redir_nr(unsigned char *p, Q931_info_t *qi, int *type, int *plan, int *present, int *screen, int *reason, char *number, size_t number_len, int nt, struct misdn_bchannel *bc)
+ {
+ *type = -1;
+ *plan = -1;
+@@ -1231,11 +1227,10 @@
+
+
+ /* IE_REDIR_DN (redirection = during MT_NOTIFY) */
+-#if 0
+ static void enc_ie_redir_dn(unsigned char **ntmode, msg_t *msg, int type, int plan, int present, char *number, int nt, struct misdn_bchannel *bc)
+ {
+ unsigned char *p;
+-/* Q931_info_t *qi = (Q931_info_t *)(msg->data + mISDN_HEADER_LEN); */
++ Q931_info_t *qi = (Q931_info_t *)(msg->data + mISDN_HEADER_LEN);
+ int l;
+
+ if (type<0 || type>7)
+@@ -1264,9 +1259,9 @@
+ p = msg_put(msg, l+2);
+ if (nt)
+ *ntmode = p+1;
+- else
+-/* #warning REINSERT redir_dn, when included in te-mode */
+- /*qi->QI_ELEMENT(redir_dn) = p - (unsigned char *)qi - sizeof(Q931_info_t)*/;
++ else {
++ qi->QI_ELEMENT(redirect_dn) = p - (unsigned char *)qi - sizeof(Q931_info_t);
++ }
+ p[0] = IE_REDIR_DN;
+ p[1] = l;
+ if (present >= 0)
+@@ -1282,10 +1277,8 @@
+ strncpy((char *)p+3, (char *)number, strlen((char *)number));
+ }
+ }
+-#endif
+
+-#if 0
+-static void dec_ie_redir_dn(unsigned char *p, Q931_info_t *qi, int *type, int *plan, int *present, char *number, int number_len, int nt, struct misdn_bchannel *bc)
++static void dec_ie_redir_dn(unsigned char *p, Q931_info_t *qi, int *type, int *plan, int *present, char *number, size_t number_len, int nt, struct misdn_bchannel *bc)
+ {
+ *type = -1;
+ *plan = -1;
+@@ -1295,9 +1288,8 @@
+ if (!nt)
+ {
+ p = NULL;
+-/* #warning REINSERT redir_dn, when included in te-mode */
+-/* if (qi->QI_ELEMENT(redir_dn)) */
+-/* p = (unsigned char *)qi + sizeof(Q931_info_t) + qi->QI_ELEMENT(redir_dn) + 1; */
++ if (qi->QI_ELEMENT(redirect_dn))
++ p = (unsigned char *)qi + sizeof(Q931_info_t) + qi->QI_ELEMENT(redirect_dn) + 1;
+ }
+ if (!p)
+ return;
+@@ -1320,7 +1312,6 @@
+
+ if (MISDN_IE_DEBG) printf(" type=%d plan=%d present=%d number='%s'\n", *type, *plan, *present, number);
+ }
+-#endif
+
+
+ /* IE_USERUSER */
+@@ -1331,9 +1322,6 @@
+ Q931_info_t *qi = (Q931_info_t *)(msg->data + mISDN_HEADER_LEN);
+ int l;
+
+- char debug[768];
+- int i;
+-
+ if (protocol<0 || protocol>127)
+ {
+ printf("%s: ERROR: protocol(%d) is out of range.\n", __FUNCTION__, protocol);
+@@ -1344,14 +1332,16 @@
+ return;
+ }
+
+- i = 0;
+- while(i < user_len)
+- {
+- if (MISDN_IE_DEBG) sprintf(debug+(i*3), " %02x", user[i]);
+- i++;
++ if (MISDN_IE_DEBG) {
++ size_t i;
++ char debug[768];
++
++ for (i = 0; i < user_len; ++i) {
++ sprintf(debug + (i * 3), " %02x", user[i]);
++ }
++ debug[i * 3] = 0;
++ printf(" protocol=%d user-user%s\n", protocol, debug);
+ }
+-
+- if (MISDN_IE_DEBG) printf(" protocol=%d user-user%s\n", protocol, debug);
+
+ l = user_len+1;
+ p = msg_put(msg, l+3);
+@@ -1369,9 +1359,6 @@
+ #if 1
+ static void dec_ie_useruser(unsigned char *p, Q931_info_t *qi, int *protocol, char *user, int *user_len, int nt, struct misdn_bchannel *bc)
+ {
+- char debug[768];
+- int i;
+-
+ *user_len = 0;
+ *protocol = -1;
+
+@@ -1390,15 +1377,16 @@
+ *protocol = p[1];
+ memcpy(user, p+2, (*user_len<=128)?*(user_len):128); /* clip to 128 maximum */
+
+- i = 0;
+- while(i < *user_len)
+- {
+- if (MISDN_IE_DEBG) sprintf(debug+(i*3), " %02x", user[i]);
+- i++;
++ if (MISDN_IE_DEBG) {
++ int i;
++ char debug[768];
++
++ for (i = 0; i < *user_len; ++i) {
++ sprintf(debug + (i * 3), " %02x", user[i]);
++ }
++ debug[i * 3] = 0;
++ printf(" protocol=%d user-user%s\n", *protocol, debug);
+ }
+- 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-beta3) (revision 202568)
++++ b/channels/chan_gtalk.c (.../trunk) (revision 202568)
+@@ -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;
+@@ -617,13 +613,13 @@
+ /* codec points to the first <payload-type/> tag */
+ 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);
++ 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 */
+@@ -774,7 +770,7 @@
+ struct gtalk_candidate *tmp;
+ struct aji_client *c = client->connection;
+ struct gtalk_candidate *ours1 = NULL, *ours2 = NULL;
+- struct sockaddr_in sin;
++ struct sockaddr_in sin = { 0, };
+ struct sockaddr_in dest;
+ struct in_addr us;
+ iks *iq, *gtalk, *candidate, *transport;
+@@ -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,13 @@
+ 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);
++ if (!(tmp->rtp = ast_rtp_instance_new(NULL, sched, &bindaddr, NULL))) {
++ ast_log(LOG_ERROR, "Failed to create a new RTP instance (possibly an invalid bindaddr?)\n");
++ ast_free(tmp);
++ return 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 +1015,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 +1143,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);
+ }
+@@ -1207,13 +1208,13 @@
+ 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);
++ 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);
+
+@@ -1226,7 +1227,7 @@
+ gtalk_action(client, p, "reject");
+ p->alreadygone = 1;
+ gtalk_hangup(chan);
+- ast_channel_free(chan);
++ ast_channel_release(chan);
+ return -1;
+ }
+
+@@ -1257,8 +1258,8 @@
+ struct gtalk_candidate *tmp;
+ struct hostent *hp;
+ struct ast_hostent ahp;
+- struct sockaddr_in sin;
+- struct sockaddr_in aux;
++ struct sockaddr_in sin = { 0, };
++ struct sockaddr_in aux = { 0, };
+
+ if (time(NULL) == p->laststun)
+ return 0;
+@@ -1277,16 +1278,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);
+@@ -1387,7 +1388,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 +1439,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 +1448,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 +2063,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 +2087,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: channels/iax2-parser.c
+===================================================================
+--- a/channels/iax2-parser.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/channels/iax2-parser.c (.../trunk) (revision 202568)
+@@ -279,7 +279,7 @@
+ { IAX_IE_OSPTOKEN, "OSPTOKEN" },
+ };
+
+-static struct iax2_ie prov_ies[] = {
++static const struct iax2_ie prov_ies[] = {
+ { PROV_IE_USEDHCP, "USEDHCP" },
+ { PROV_IE_IPADDR, "IPADDR", dump_ipaddr },
+ { PROV_IE_SUBNET, "SUBNET", dump_ipaddr },
+@@ -576,6 +576,9 @@
+ "VIDUPDT",
+ "T38 ",
+ "SRCUPDT",
++ "TXFER ",
++ "CNLINE ",
++ "REDIR ",
+ };
+ struct ast_iax2_full_hdr *fh;
+ char retries[20];
+Index: CREDITS
+===================================================================
+--- a/CREDITS (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/CREDITS (.../trunk) (revision 202568)
+@@ -200,6 +200,10 @@
+ Eliel C. Sardanons - XML documentation implementation, and various other contributions
+ eliels(AT)gmail.com
+
++Sean Bright - Snom call pickup, newt interface for menuselect, cdr_tds rewrite,
++ countless other improvements, fixes, and good ideas.
++ sean(AT)malleable.com
++
+ === OTHER CONTRIBUTIONS ===
+ John Todd - Monkey sounds and associated teletorture prompt
+ Michael Jerris - bug marshaling
+Index: BUGS
+===================================================================
+--- a/BUGS (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/BUGS (.../trunk) (revision 202568)
+@@ -4,7 +4,7 @@
+ To learn about and report Asterisk bugs, please visit
+ the official Asterisk Bug Tracker at:
+
+- http://bugs.digium.com
++ https://issues.asterisk.org
+
+ For more information on using the bug tracker, or to
+ learn how you can contribute by acting as a bug marshal
+Index: tests/test_logger.c
+===================================================================
+--- a/tests/test_logger.c (.../tags/1.6.2.0-beta3) (revision 0)
++++ b/tests/test_logger.c (.../trunk) (revision 202568)
+@@ -0,0 +1,209 @@
++/*
++ * Asterisk -- An open source telephony toolkit.
++ *
++ * Copyright (C) 2009, 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.
++ */
++
++/*! \file
++ *
++ * \brief Test module for the logging subsystem
++ *
++ * \author\verbatim Kevin P. Fleming <kpfleming@digium.com> \endverbatim
++ *
++ * \ingroup tests
++ */
++
++/*** MODULEINFO
++ <defaultenabled>no</defaultenabled>
++ ***/
++
++#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/lock.h"
++#include "asterisk/app.h"
++#include "asterisk/cli.h"
++
++struct test {
++ const char *name;
++ unsigned int x_success;
++ unsigned int x_failure;
++ unsigned int u_success;
++ unsigned int u_failure;
++};
++
++static void output_tests(struct test *tests, size_t num_tests, int fd)
++{
++ unsigned int x;
++
++ for (x = 0; x < num_tests; x++) {
++ ast_cli(fd, "Test %d: %s\n", x + 1, tests[x].name);
++ ast_cli(fd, "\tExpected Successes: %d\n", tests[x].x_success);
++ ast_cli(fd, "\tExpected Failures: %d\n", tests[x].x_failure);
++ ast_cli(fd, "\tUnexpected Successes: %d\n", tests[x].u_success);
++ ast_cli(fd, "\tUnexpected Failures: %d\n", tests[x].u_failure);
++ ast_cli(fd, "Test %d Result: %s\n", x + 1, (tests[x].u_success + tests[x].u_failure) ? "FAIL" : "PASS");
++ }
++}
++
++static char *handle_cli_dynamic_level_test(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
++{
++ unsigned int level;
++ unsigned int x;
++ unsigned int test;
++ struct test tests[] = {
++ { .name = "Simple register/message/unregister",
++ },
++ { .name = "Register multiple levels",
++ },
++ };
++
++ switch (cmd) {
++ case CLI_INIT:
++ e->command = "logger test dynamic";
++ e->usage = ""
++ "Usage: logger test dynamic\n"
++ "";
++ return NULL;
++ case CLI_GENERATE:
++ return NULL;
++ }
++
++ for (test = 0; test < ARRAY_LEN(tests); test++) {
++ ast_cli(a->fd, "Test %d: %s.\n", test + 1, tests[test].name);
++ switch (test) {
++ case 0:
++ if ((level = ast_logger_register_level("test")) != -1) {
++ ast_cli(a->fd, "Test: got level %d\n", level);
++ ast_log_dynamic_level(level, "Logger Dynamic Test: Test 1\n");
++ ast_logger_unregister_level("test");
++ tests[test].x_success++;
++ } else {
++ ast_cli(a->fd, "Test: Failed, could not register level 'test'.\n");
++ tests[test].u_failure++;
++ }
++ break;
++ case 1:
++ {
++ char level_name[18][8];
++
++ for (x = 0; x < ARRAY_LEN(level_name); x++) {
++ sprintf(level_name[x], "level%02d", x);
++ if ((level = ast_logger_register_level(level_name[x])) == -1) {
++ if (x < 16) {
++ tests[test].u_failure++;
++ } else {
++ tests[test].x_failure++;
++ }
++ level_name[x][0] = '\0';
++ } else {
++ ast_cli(a->fd, "Test: registered '%s', got level %d\n", level_name[x], level);
++ if (x < 16) {
++ tests[test].x_success++;
++ } else {
++ tests[test].u_success++;
++ }
++ }
++ }
++
++ for (x = 0; x < ARRAY_LEN(level_name); x++) {
++ if (!ast_strlen_zero(level_name[x])) {
++ ast_logger_unregister_level(level_name[x]);
++ }
++ }
++ }
++ }
++ }
++
++ output_tests(tests, ARRAY_LEN(tests), a->fd);
++
++ return CLI_SUCCESS;
++}
++
++static char *handle_cli_performance_test(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
++{
++ unsigned int level;
++ unsigned int test;
++ struct test tests[] = {
++ { .name = "Log 10,000 messages",
++ },
++ };
++
++ switch (cmd) {
++ case CLI_INIT:
++ e->command = "logger test performance";
++ e->usage = ""
++ "Usage: logger test performance\n"
++ "";
++ return NULL;
++ case CLI_GENERATE:
++ return NULL;
++ }
++
++ for (test = 0; test < ARRAY_LEN(tests); test++) {
++ ast_cli(a->fd, "Test %d: %s.\n", test + 1, tests[test].name);
++ switch (test) {
++ case 0:
++ if ((level = ast_logger_register_level("perftest")) != -1) {
++ unsigned int x;
++ struct timeval start, end;
++ int elapsed;
++
++ ast_cli(a->fd, "Test: got level %d\n", level);
++ start = ast_tvnow();
++ for (x = 0; x < 10000; x++) {
++ ast_log_dynamic_level(level, "Performance test log message\n");
++ }
++ end = ast_tvnow();
++ elapsed = ast_tvdiff_ms(end, start);
++ ast_cli(a->fd, "Test: 10,000 messages in %f seconds.\n", (float) elapsed / 1000);
++ ast_logger_unregister_level("perftest");
++ tests[test].x_success++;
++ } else {
++ ast_cli(a->fd, "Test: Failed, could not register level 'perftest'.\n");
++ tests[test].u_failure++;
++ }
++ break;
++ }
++ }
++
++ output_tests(tests, ARRAY_LEN(tests), a->fd);
++
++ return CLI_SUCCESS;
++}
++
++static struct ast_cli_entry cli_logger[] = {
++ AST_CLI_DEFINE(handle_cli_dynamic_level_test, "Test the dynamic logger level implementation"),
++ AST_CLI_DEFINE(handle_cli_performance_test, "Test the logger performance"),
++};
++
++static int unload_module(void)
++{
++ ast_cli_unregister_multiple(cli_logger, ARRAY_LEN(cli_logger));
++ return 0;
++}
++
++static int load_module(void)
++{
++ ast_cli_register_multiple(cli_logger, ARRAY_LEN(cli_logger));
++ return AST_MODULE_LOAD_SUCCESS;
++}
++
++AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Logger Test Module");
+
+Property changes on: tests/test_logger.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+Added: svn:mime-type
+ + text/plain
+Added: svn:keywords
+ + Author Date Id Revision
+
+Index: tests/test_sched.c
+===================================================================
+--- a/tests/test_sched.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/tests/test_sched.c (.../trunk) (revision 202568)
+@@ -168,7 +168,7 @@
+ case CLI_INIT:
+ e->command = "sched benchmark";
+ e->usage = ""
+- "Usage: sched test <num>\n"
++ "Usage: sched benchmark <num>\n"
+ "";
+ return NULL;
+ case CLI_GENERATE:
+Index: tests/test_substitution.c
+===================================================================
+--- a/tests/test_substitution.c (.../tags/1.6.2.0-beta3) (revision 0)
++++ b/tests/test_substitution.c (.../trunk) (revision 202568)
+@@ -0,0 +1,241 @@
++/*
++ * Asterisk -- An open source telephony toolkit.
++ *
++ * Copyright (C) 2009, Digium, Inc.
++ *
++ * Tilghman Lesher <tlesher AT digium DOT 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 Substitution Test
++ *
++ * \author\verbatim Tilghman Lesher <tlesher AT digium DOT com> \endverbatim
++ *
++ * \ingroup tests
++ */
++
++/*** MODULEINFO
++ <defaultenabled>no</defaultenabled>
++ ***/
++
++#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/lock.h"
++#include "asterisk/app.h"
++#include "asterisk/strings.h"
++#include "asterisk/stringfields.h"
++#include "asterisk/threadstorage.h"
++#include "asterisk/cli.h"
++
++AST_THREADSTORAGE(buf_buf);
++AST_THREADSTORAGE(var_buf);
++
++static void test_chan_integer(int fd, struct ast_channel *c, int *ifield, const char *expression)
++{
++ int i, okay = 1, value1 = -1, value2 = -1;
++ char workspace[4096];
++ struct ast_str *str = ast_str_thread_get(&buf_buf, 16);
++
++ for (i = 0; i < 256; i++) {
++ *ifield = i;
++ ast_str_substitute_variables(&str, 0, c, expression);
++ pbx_substitute_variables_helper(c, expression, workspace, sizeof(workspace));
++ if (sscanf(workspace, "%d", &value1) != 1 || value1 != i || sscanf(ast_str_buffer(str), "%d", &value2) != 1 || value2 != i) {
++ ast_cli(fd, "%s != %s and/or %d != %d != %d\n", ast_str_buffer(str), workspace, value1, value2, i);
++ okay = 0;
++ break;
++ }
++ }
++ ast_cli(fd, "Testing '%s' . . . . . %s\n", expression, okay ? "passed" : "FAILED");
++}
++
++static void test_chan_string(int fd, struct ast_channel *c, char *cfield, size_t cfieldsize, const char *expression)
++{
++ const char *values[] = { "one", "three", "reallylongdinosaursoundingthingwithwordsinit" };
++ int i, okay = 1;
++ char workspace[4096];
++ struct ast_str *str = ast_str_thread_get(&buf_buf, 16);
++
++ for (i = 0; i < ARRAY_LEN(values); i++) {
++ ast_copy_string(cfield, values[i], cfieldsize);
++ ast_str_substitute_variables(&str, 0, c, expression);
++ pbx_substitute_variables_helper(c, expression, workspace, sizeof(workspace));
++ if (strcmp(cfield, ast_str_buffer(str)) != 0 || strcmp(cfield, workspace) != 0) {
++ ast_cli(fd, "%s != %s != %s\n", cfield, ast_str_buffer(str), workspace);
++ okay = 0;
++ break;
++ }
++ }
++ ast_cli(fd, "Testing '%s' . . . . . %s\n", expression, okay ? "passed" : "FAILED");
++}
++
++static void test_chan_variable(int fd, struct ast_channel *c, const char *varname)
++{
++ const char *values[] = { "one", "three", "reallylongdinosaursoundingthingwithwordsinit" };
++ int i, okay = 1;
++ char workspace[4096];
++ struct ast_str *str = ast_str_thread_get(&buf_buf, 16);
++ struct ast_str *var = ast_str_thread_get(&var_buf, 16);
++
++ ast_str_set(&var, 0, "${%s}", varname);
++ for (i = 0; i < ARRAY_LEN(values); i++) {
++ pbx_builtin_setvar_helper(c, varname, values[i]);
++ ast_str_substitute_variables(&str, 0, c, ast_str_buffer(var));
++ pbx_substitute_variables_helper(c, ast_str_buffer(var), workspace, sizeof(workspace));
++ if (strcmp(values[i], ast_str_buffer(str)) != 0 || strcmp(values[i], workspace) != 0) {
++ ast_cli(fd, "%s != %s != %s\n", values[i], ast_str_buffer(str), workspace);
++ okay = 0;
++ break;
++ }
++ }
++ ast_cli(fd, "Testing '%s' . . . . . %s\n", ast_str_buffer(var), okay ? "passed" : "FAILED");
++}
++
++static void test_chan_function(int fd, struct ast_channel *c, const char *expression)
++{
++ int okay = 1;
++ char workspace[4096];
++ struct ast_str *str = ast_str_thread_get(&buf_buf, 16);
++
++ ast_str_substitute_variables(&str, 0, c, expression);
++ pbx_substitute_variables_helper(c, expression, workspace, sizeof(workspace));
++ if (strcmp(workspace, ast_str_buffer(str)) != 0) {
++ ast_cli(fd, "%s != %s\n", ast_str_buffer(str), workspace);
++ okay = 0;
++ }
++ ast_cli(fd, "Testing '%s' . . . . . %s\n", expression, okay ? "passed" : "FAILED");
++}
++
++static void test_2way_function(int fd, struct ast_channel *c, const char *encode1, const char *encode2, const char *decode1, const char *decode2)
++{
++ struct ast_str *str = ast_str_thread_get(&buf_buf, 16), *expression = ast_str_alloca(120);
++
++ ast_str_set(&expression, 0, "%s%s%s", encode1, "foobarbaz", encode2);
++ ast_str_substitute_variables(&str, 0, c, ast_str_buffer(expression));
++ ast_str_set(&expression, 0, "%s%s%s", decode1, ast_str_buffer(str), decode2);
++ ast_str_substitute_variables(&str, 0, c, ast_str_buffer(expression));
++ ast_cli(fd, "Testing '%s%s' and '%s%s' . . . . . %s\n", encode1, encode2, decode1, decode2, !strcmp(ast_str_buffer(str), "foobarbaz") ? "passed" : "FAILED");
++ if (strcmp(ast_str_buffer(str), "foobarbaz")) {
++ ast_cli(fd, " '%s' != 'foobarbaz'\n", ast_str_buffer(str));
++ }
++}
++
++static void test_expected_result(int fd, struct ast_channel *c, const char *expression, const char *result)
++{
++ struct ast_str *str = ast_str_thread_get(&buf_buf, 16);
++ ast_str_substitute_variables(&str, 0, c, expression);
++ ast_cli(fd, "Testing '%s' ('%s') == '%s' . . . . . %s\n", ast_str_buffer(str), expression, result, !strcmp(ast_str_buffer(str), result) ? "passed" : "FAILED");
++}
++
++static char *handle_cli_test_substitution(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
++{
++ struct ast_channel *c;
++ int i;
++
++ switch (cmd) {
++ case CLI_INIT:
++ e->command = "test substitution";
++ e->usage = ""
++ "Usage: test substitution\n"
++ " Test variable and function substitution.\n";
++ return NULL;
++ case CLI_GENERATE:
++ return NULL;
++ }
++
++ if (a->argc != e->args) {
++ return CLI_SHOWUSAGE;
++ }
++
++ ast_cli(a->fd, "Testing variable substitution ...\n");
++ c = ast_channel_alloc(0, 0, "", "", "", "", "", 0, "Test/substitution");
++
++ test_chan_integer(a->fd, c, &c->cid.cid_pres, "${CALLINGPRES}");
++ test_chan_integer(a->fd, c, &c->cid.cid_ani2, "${CALLINGANI2}");
++ test_chan_integer(a->fd, c, &c->cid.cid_ton, "${CALLINGTON}");
++ test_chan_integer(a->fd, c, &c->cid.cid_tns, "${CALLINGTNS}");
++ test_chan_integer(a->fd, c, &c->hangupcause, "${HANGUPCAUSE}");
++ test_chan_integer(a->fd, c, &c->priority, "${PRIORITY}");
++ test_chan_string(a->fd, c, c->context, sizeof(c->context), "${CONTEXT}");
++ test_chan_string(a->fd, c, c->exten, sizeof(c->exten), "${EXTEN}");
++ test_chan_variable(a->fd, c, "CHANNEL(language)");
++ test_chan_variable(a->fd, c, "CHANNEL(musicclass)");
++ test_chan_variable(a->fd, c, "CHANNEL(parkinglot)");
++ test_chan_variable(a->fd, c, "CALLERID(name)");
++ test_chan_variable(a->fd, c, "CURLOPT(proxyuserpwd)");
++ test_chan_variable(a->fd, c, "CDR(foo)");
++ test_chan_variable(a->fd, c, "ENV(foo)");
++ test_chan_variable(a->fd, c, "GLOBAL(foo)");
++ test_chan_variable(a->fd, c, "GROUP()");
++ test_2way_function(a->fd, c, "${AES_ENCRYPT(abcdefghijklmnop,", ")}", "${AES_DECRYPT(abcdefghijklmnop,", ")}");
++ test_2way_function(a->fd, c, "${BASE64_ENCODE(", ")}", "${BASE64_DECODE(", ")}");
++ pbx_builtin_setvar_helper(c, "foo", "123");
++ pbx_builtin_setvar_helper(c, "bar", "foo");
++ pbx_builtin_setvar_helper(c, "baz", "fo");
++ test_expected_result(a->fd, c, "${foo}${foo}", "123123");
++ test_expected_result(a->fd, c, "A${foo}A${foo}A", "A123A123A");
++ test_expected_result(a->fd, c, "A${${bar}}A", "A123A");
++ test_expected_result(a->fd, c, "A${${baz}o}A", "A123A");
++ test_expected_result(a->fd, c, "A${${baz}o:1}A", "A23A");
++ test_expected_result(a->fd, c, "A${${baz}o:1:1}A", "A2A");
++ test_expected_result(a->fd, c, "A${${baz}o:1:-1}A", "A2A");
++ test_expected_result(a->fd, c, "A${${baz}o:-1:1}A", "A3A");
++ test_expected_result(a->fd, c, "A${${baz}o:-2:1}A", "A2A");
++ test_expected_result(a->fd, c, "A${${baz}o:-2:-1}A", "A2A");
++
++ /* For testing dialplan functions */
++ for (i = 0; ; i++) {
++ char *cmd = ast_cli_generator("core show function", "", i);
++ if (cmd == NULL) {
++ break;
++ }
++ if (strcmp(cmd, "CHANNEL") && strcmp(cmd, "CALLERID") && strcmp(cmd, "CURLOPT") && strncmp(cmd, "AES", 3) && strncmp(cmd, "BASE64", 6) && strcmp(cmd, "CDR") && strcmp(cmd, "ENV") && strcmp(cmd, "GLOBAL") && strcmp(cmd, "GROUP") && strcmp(cmd, "CUT") && strcmp(cmd, "LISTFILTER") && strcmp(cmd, "PP_EACH_EXTENSION") && strcmp(cmd, "SET")) {
++ struct ast_custom_function *acf = ast_custom_function_find(cmd);
++ if (acf->read && acf->read2) {
++ char expression[80];
++ snprintf(expression, sizeof(expression), "${%s(foo)}", cmd);
++ test_chan_function(a->fd, c, expression);
++ }
++ }
++ ast_free(cmd);
++ }
++
++ ast_hangup(c);
++
++ return CLI_SUCCESS;
++}
++
++static struct ast_cli_entry cli_substitution[] = {
++ AST_CLI_DEFINE(handle_cli_test_substitution, "Test variable substitution"),
++};
++
++static int unload_module(void)
++{
++ ast_cli_unregister_multiple(cli_substitution, ARRAY_LEN(cli_substitution));
++ return 0;
++}
++
++static int load_module(void)
++{
++ ast_cli_register_multiple(cli_substitution, ARRAY_LEN(cli_substitution));
++ return AST_MODULE_LOAD_SUCCESS;
++}
++
++AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Substitution tests");
+
+Property changes on: tests/test_substitution.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+Added: svn:mime-type
+ + text/plain
+Added: svn:keywords
+ + Author Date Id Revision
+
+Index: tests/test_skel.c
+===================================================================
+--- a/tests/test_skel.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/tests/test_skel.c (.../trunk) (revision 202568)
+@@ -40,6 +40,7 @@
+ #include "asterisk/module.h"
+ #include "asterisk/lock.h"
+ #include "asterisk/app.h"
++#include "asterisk/cli.h"
+
+ static int unload_module(void)
+ {
+Index: configure.ac
+===================================================================
+--- a/configure.ac (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/configure.ac (.../trunk) (revision 202568)
+@@ -244,6 +244,7 @@
+ AST_EXT_LIB_SETUP([GTK2], [gtk2 libraries], [gtk2])
+ AST_EXT_LIB_SETUP([GMIME], [GMime library], [gmime])
+ AST_EXT_LIB_SETUP([HOARD], [Hoard Memory Allocator], [hoard])
++AST_EXT_LIB_SETUP([ICAL], [ical libraries], [ical])
+ 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])
+@@ -258,6 +259,7 @@
+ AST_EXT_LIB_SETUP([MISDN], [mISDN User Library], [misdn])
+ AST_EXT_LIB_SETUP([NBS], [Network Broadcast Sound], [nbs])
+ AST_EXT_LIB_SETUP([NCURSES], [ncurses], [ncurses])
++AST_EXT_LIB_SETUP([NEON], [neon], [neon])
+ AST_EXT_LIB_SETUP([NETSNMP], [Net-SNMP], [netsnmp])
+ AST_EXT_LIB_SETUP([NEWT], [newt], [newt])
+ AST_EXT_LIB_SETUP([OGG], [OGG], [ogg])
+@@ -512,9 +514,8 @@
+ AST_GCC_ATTRIBUTE(deprecated)
+ AST_GCC_ATTRIBUTE(sentinel)
+ AST_GCC_ATTRIBUTE(warn_unused_result)
+-AST_GCC_ATTRIBUTE(weak)
++AST_GCC_ATTRIBUTE(weakref, [weakref("foo")], static)
+ AST_GCC_ATTRIBUTE(weak_import)
+-AST_GCC_ATTRIBUTE(alias, [alias("foo")])
+
+ AC_MSG_CHECKING(for -ffunction-sections support)
+ saved_CFLAGS="${CFLAGS}"
+@@ -627,6 +628,10 @@
+ AC_MSG_RESULT(no)
+ )
+
++AST_C_DEFINE_CHECK([GLOB_NOMAGIC], [GLOB_NOMAGIC], [glob.h])
++
++AST_C_DEFINE_CHECK([GLOB_BRACE], [GLOB_BRACE], [glob.h])
++
+ AST_C_DEFINE_CHECK([IP_MTU_DISCOVER], [IP_MTU_DISCOVER], [netinet/in.h])
+
+ AC_CHECK_HEADER([libkern/OSAtomic.h],
+@@ -650,6 +655,8 @@
+
+ AST_C_COMPILE_CHECK([DAHDI_LINEREVERSE_VMWI], [struct dahdi_vmwi_info booger], [dahdi/user.h], , [enhanced dahdi vmwi support])
+
++AST_C_COMPILE_CHECK([DAHDI_ECHOCANCEL_FAX_MODE], [int foo = DAHDI_ECHOCANCEL_FAX_MODE], [dahdi/user.h])
++
+ # BSD might not have exp2, and/or log2
+ AST_EXT_LIB_CHECK([EXP2L], [m], [exp2l])
+ AST_EXT_LIB_CHECK([LOG2L], [m], [log2l])
+@@ -773,6 +780,8 @@
+ PBX_ICONV=1
+ fi
+
++AST_EXT_LIB_CHECK([ICAL], [ical], [icaltimezone_new], [libical/ical.h], [-lpthread])
++
+ AST_EXT_LIB_CHECK([IKSEMEL], [iksemel], [iks_start_sasl], [iksemel.h])
+
+ if test "${USE_IMAP_TK}" != "no"; then
+@@ -1344,6 +1353,8 @@
+
+ AST_EXT_LIB_CHECK([NCURSES], [ncurses], [initscr], [curses.h])
+
++AST_EXT_TOOL_CHECK([NEON], [neon])
++
+ AST_EXT_TOOL_CHECK([NETSNMP], [net-snmp], , [--agent-libs],
+ [#include <net-snmp/net-snmp-config.h>
+ #include <net-snmp/net-snmp-includes.h>
+@@ -1422,6 +1433,8 @@
+
+ AST_EXT_LIB_CHECK([PRI_INBANDDISCONNECT], [pri], [pri_set_inbanddisconnect], [libpri.h])
+
++AST_EXT_LIB_CHECK([PRI_SERVICE_MESSAGES], [pri], [pri_maintenance_service], [libpri.h])
++
+ AST_EXT_LIB_CHECK([RESAMPLE], [resample], [resample_open], [libresample.h], [-lm])
+
+ AST_C_COMPILE_CHECK([SPANDSP], [
+Index: apps/app_dahdiscan.c
+===================================================================
+--- a/apps/app_dahdiscan.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/apps/app_dahdiscan.c (.../trunk) (revision 202568)
+@@ -1,378 +0,0 @@
+-/*
+- * Asterisk -- An open source telephony toolkit.
+- *
+- * Copyright (C) 1999 - 2005, Digium, Inc.
+- *
+- * Mark Spencer <markster@digium.com>
+- *
+- * Modified from app_zapbarge by David Troy <dave@toad.net>
+- *
+- * Special thanks to comphealth.com for sponsoring this
+- * GPL application.
+- *
+- * 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 DAHDI Scanner
+- *
+- * \author Mark Spencer <markster@digium.com>
+- *
+- * \ingroup applications
+- */
+-
+-/*** MODULEINFO
+- <depend>dahdi</depend>
+- ***/
+-
+-#include "asterisk.h"
+-
+-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 153365 $")
+-
+-#include <dahdi/user.h>
+-
+-#include "asterisk/lock.h"
+-#include "asterisk/file.h"
+-#include "asterisk/channel.h"
+-#include "asterisk/pbx.h"
+-#include "asterisk/module.h"
+-#include "asterisk/config.h"
+-#include "asterisk/app.h"
+-#include "asterisk/utils.h"
+-#include "asterisk/cli.h"
+-#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";
+-
+-#define CONF_SIZE 160
+-
+-static struct ast_channel *get_dahdi_channel_locked(int num) {
+- char name[80];
+-
+- snprintf(name, sizeof(name), "DAHDI/%d-1", num);
+- return ast_get_channel_by_name_locked(name);
+-}
+-
+-static int careful_write(int fd, unsigned char *data, int len)
+-{
+- int res;
+- while (len) {
+- res = write(fd, data, len);
+- if (res < 1) {
+- if (errno != EAGAIN) {
+- ast_log(LOG_WARNING, "Failed to write audio data to conference: %s\n", strerror(errno));
+- return -1;
+- } else {
+- return 0;
+- }
+- }
+- len -= res;
+- data += res;
+- }
+- return 0;
+-}
+-
+-static int conf_run(struct ast_channel *chan, int confno, int confflags)
+-{
+- int fd;
+- struct dahdi_confinfo dahdic;
+- struct ast_frame *f;
+- struct ast_channel *c;
+- struct ast_frame fr;
+- int outfd;
+- int ms;
+- int nfds;
+- int res;
+- int flags;
+- int retrydahdi;
+- int origfd;
+- int ret = -1;
+- char input[4];
+- int ic = 0;
+-
+- struct dahdi_bufferinfo bi;
+- char __buf[CONF_SIZE + AST_FRIENDLY_OFFSET];
+- char *buf = __buf + AST_FRIENDLY_OFFSET;
+-
+- /* Set it into U-law mode (write) */
+- if (ast_set_write_format(chan, AST_FORMAT_ULAW) < 0) {
+- ast_log(LOG_WARNING, "Unable to set '%s' to write ulaw mode\n", chan->name);
+- goto outrun;
+- }
+-
+- /* Set it into U-law mode (read) */
+- if (ast_set_read_format(chan, AST_FORMAT_ULAW) < 0) {
+- ast_log(LOG_WARNING, "Unable to set '%s' to read ulaw mode\n", chan->name);
+- goto outrun;
+- }
+- ast_indicate(chan, -1);
+- retrydahdi = strcasecmp(chan->tech->type, "DAHDI");
+- dahdiretry:
+- origfd = chan->fds[0];
+- if (retrydahdi) {
+- fd = open("/dev/dahdi/pseudo", O_RDWR);
+- if (fd < 0) {
+- ast_log(LOG_WARNING, "Unable to open pseudo channel: %s\n", strerror(errno));
+- goto outrun;
+- }
+- /* 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;
+- bi.txbufpolicy = DAHDI_POLICY_IMMEDIATE;
+- bi.rxbufpolicy = DAHDI_POLICY_IMMEDIATE;
+- bi.numbufs = 4;
+- if (ioctl(fd, DAHDI_SET_BUFINFO, &bi)) {
+- ast_log(LOG_WARNING, "Unable to set buffering information: %s\n", strerror(errno));
+- close(fd);
+- goto outrun;
+- }
+- nfds = 1;
+- } else {
+- /* XXX Make sure we're not running on a pseudo channel XXX */
+- fd = chan->fds[0];
+- nfds = 0;
+- }
+- memset(&dahdic, 0, sizeof(dahdic));
+- /* Check to see if we're in a conference... */
+- dahdic.chan = 0;
+- if (ioctl(fd, DAHDI_GETCONF, &dahdic)) {
+- ast_log(LOG_WARNING, "Error getting conference\n");
+- close(fd);
+- goto outrun;
+- }
+- if (dahdic.confmode) {
+- /* Whoa, already in a conference... Retry... */
+- if (!retrydahdi) {
+- ast_debug(1, "DAHDI channel is in a conference already, retrying with pseudo\n");
+- retrydahdi = 1;
+- goto dahdiretry;
+- }
+- }
+- memset(&dahdic, 0, sizeof(dahdic));
+- /* Add us to the conference */
+- dahdic.chan = 0;
+- dahdic.confno = confno;
+- dahdic.confmode = DAHDI_CONF_MONITORBOTH;
+-
+- if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
+- ast_log(LOG_WARNING, "Error setting conference\n");
+- close(fd);
+- goto outrun;
+- }
+- ast_debug(1, "Placed channel %s in DAHDI channel %d monitor\n", chan->name, confno);
+-
+- for (;;) {
+- outfd = -1;
+- ms = -1;
+- c = ast_waitfor_nandfds(&chan, 1, &fd, nfds, NULL, &outfd, &ms);
+- if (c) {
+- if (c->fds[0] != origfd) {
+- if (retrydahdi) {
+- /* Kill old pseudo */
+- close(fd);
+- }
+- ast_debug(1, "Ooh, something swapped out under us, starting over\n");
+- retrydahdi = 0;
+- goto dahdiretry;
+- }
+- f = ast_read(c);
+- if (!f) {
+- break;
+- }
+- if (f->frametype == AST_FRAME_DTMF) {
+- if (f->subclass == '#') {
+- ret = 0;
+- break;
+- } else if (f->subclass == '*') {
+- ret = -1;
+- break;
+- } else {
+- input[ic++] = f->subclass;
+- }
+- if (ic == 3) {
+- input[ic++] = '\0';
+- ic = 0;
+- ret = atoi(input);
+- ast_verb(3, "DAHDIScan: change channel to %d\n", ret);
+- break;
+- }
+- }
+-
+- if (fd != chan->fds[0]) {
+- if (f->frametype == AST_FRAME_VOICE) {
+- if (f->subclass == AST_FORMAT_ULAW) {
+- /* Carefully write */
+- careful_write(fd, f->data.ptr, f->datalen);
+- } else {
+- ast_log(LOG_WARNING, "Huh? Got a non-ulaw (%d) frame in the conference\n", f->subclass);
+- }
+- }
+- }
+- ast_frfree(f);
+- } else if (outfd > -1) {
+- res = read(outfd, buf, CONF_SIZE);
+- if (res > 0) {
+- memset(&fr, 0, sizeof(fr));
+- fr.frametype = AST_FRAME_VOICE;
+- fr.subclass = AST_FORMAT_ULAW;
+- fr.datalen = res;
+- fr.samples = res;
+- fr.data.ptr = buf;
+- fr.offset = AST_FRIENDLY_OFFSET;
+- if (ast_write(chan, &fr) < 0) {
+- ast_log(LOG_WARNING, "Unable to write frame to channel: %s\n", strerror(errno));
+- /* break; */
+- }
+- } else {
+- ast_log(LOG_WARNING, "Failed to read frame: %s\n", strerror(errno));
+- }
+- }
+- }
+- if (f) {
+- ast_frfree(f);
+- }
+- if (fd != chan->fds[0]) {
+- close(fd);
+- } else {
+- /* Take out of conference */
+- /* Add us to the conference */
+- dahdic.chan = 0;
+- dahdic.confno = 0;
+- dahdic.confmode = 0;
+- if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
+- ast_log(LOG_WARNING, "Error setting conference\n");
+- }
+- }
+-
+- outrun:
+-
+- return ret;
+-}
+-
+-static int conf_exec(struct ast_channel *chan, void *data)
+-{
+- int res=-1;
+- int confflags = 0;
+- int confno = 0;
+- char confnostr[80] = "", *tmp = NULL;
+- struct ast_channel *tempchan = NULL, *lastchan = NULL, *ichan = NULL;
+- struct ast_frame *f;
+- char *desired_group;
+- int input = 0, search_group = 0;
+-
+- if (chan->_state != AST_STATE_UP)
+- ast_answer(chan);
+-
+- desired_group = ast_strdupa(data);
+- if (!ast_strlen_zero(desired_group)) {
+- ast_verb(3, "Scanning for group %s\n", desired_group);
+- search_group = 1;
+- }
+-
+- for (;;) {
+- if (ast_waitfor(chan, 100) < 0)
+- break;
+-
+- f = ast_read(chan);
+- if (!f)
+- break;
+- if ((f->frametype == AST_FRAME_DTMF) && (f->subclass == '*')) {
+- ast_frfree(f);
+- break;
+- }
+- ast_frfree(f);
+- ichan = NULL;
+- if(input) {
+- ichan = get_dahdi_channel_locked(input);
+- input = 0;
+- }
+-
+- tempchan = ichan ? ichan : ast_channel_walk_locked(tempchan);
+-
+- if (!tempchan && !lastchan) {
+- break;
+- }
+-
+- if (tempchan && search_group) {
+- const char *mygroup;
+- if ((mygroup = pbx_builtin_getvar_helper(tempchan, "GROUP")) && (!strcmp(mygroup, desired_group))) {
+- ast_verb(3, "Found Matching Channel %s in group %s\n", tempchan->name, desired_group);
+- } else {
+- ast_channel_unlock(tempchan);
+- lastchan = tempchan;
+- continue;
+- }
+- }
+- if (tempchan && (!strcmp(tempchan->tech->type, "DAHDI")) && (tempchan != chan)) {
+- ast_verb(3, "DAHDI channel %s is in-use, monitoring...\n", tempchan->name);
+- ast_copy_string(confnostr, tempchan->name, sizeof(confnostr));
+- ast_channel_unlock(tempchan);
+- if ((tmp = strchr(confnostr, '-'))) {
+- *tmp = '\0';
+- }
+- confno = atoi(strchr(confnostr, '/') + 1);
+- ast_stopstream(chan);
+- ast_say_number(chan, confno, AST_DIGIT_ANY, chan->language, (char *) NULL);
+- res = conf_run(chan, confno, confflags);
+- if (res < 0) {
+- break;
+- }
+- input = res;
+- } else if (tempchan) {
+- ast_channel_unlock(tempchan);
+- }
+- lastchan = tempchan;
+- }
+- return res;
+-}
+-
+-static int unload_module(void)
+-{
+- return ast_unregister_application(app);
+-}
+-
+-static int load_module(void)
+-{
+- 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_stack.c
+===================================================================
+--- a/apps/app_stack.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/apps/app_stack.c (.../trunk) (revision 202568)
+@@ -164,12 +164,27 @@
+ <ref type="application">Return</ref>
+ </see-also>
+ </function>
++ <agi name="gosub" language="en_US">
++ <synopsis>
++ Cause the channel to execute the specified dialplan subroutine.
++ </synopsis>
++ <syntax>
++ <parameter name="context" required="true" />
++ <parameter name="extension" required="true" />
++ <parameter name="priority" required="true" />
++ <parameter name="optional-argument" />
++ </syntax>
++ <description>
++ <para>Cause the channel to execute the specified dialplan subroutine,
++ returning to the dialplan with execution of a Return().</para>
++ </description>
++ </agi>
+ ***/
+
+-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 * const app_gosub = "Gosub";
++static const char * const app_gosubif = "GosubIf";
++static const char * const app_return = "Return";
++static const char * const app_pop = "StackPop";
+
+ static void gosub_free(void *data);
+
+@@ -266,7 +281,7 @@
+ ast_free(oldlist);
+ }
+
+-static int pop_exec(struct ast_channel *chan, void *data)
++static int pop_exec(struct ast_channel *chan, const char *data)
+ {
+ struct ast_datastore *stack_store = ast_channel_datastore_find(chan, &stack_info, NULL);
+ struct gosub_stack_frame *oldframe;
+@@ -290,12 +305,12 @@
+ return 0;
+ }
+
+-static int return_exec(struct ast_channel *chan, void *data)
++static int return_exec(struct ast_channel *chan, const char *data)
+ {
+ struct ast_datastore *stack_store = ast_channel_datastore_find(chan, &stack_info, NULL);
+ struct gosub_stack_frame *oldframe;
+ AST_LIST_HEAD(, gosub_stack_frame) *oldlist;
+- char *retval = data;
++ const char *retval = data;
+
+ if (!stack_store) {
+ ast_log(LOG_ERROR, "Return without Gosub: stack is unallocated\n");
+@@ -320,7 +335,7 @@
+ return 0;
+ }
+
+-static int gosub_exec(struct ast_channel *chan, void *data)
++static int gosub_exec(struct ast_channel *chan, const char *data)
+ {
+ struct ast_datastore *stack_store = ast_channel_datastore_find(chan, &stack_info, NULL);
+ AST_LIST_HEAD(, gosub_stack_frame) *oldlist;
+@@ -410,7 +425,7 @@
+ return 0;
+ }
+
+-static int gosubif_exec(struct ast_channel *chan, void *data)
++static int gosubif_exec(struct ast_channel *chan, const char *data)
+ {
+ char *args;
+ int res=0;
+@@ -537,7 +552,7 @@
+ .read = peek_read,
+ };
+
+-static int handle_gosub(struct ast_channel *chan, AGI *agi, int argc, char **argv)
++static int handle_gosub(struct ast_channel *chan, AGI *agi, int argc, const char * const *argv)
+ {
+ int old_priority, priority;
+ char old_context[AST_MAX_CONTEXT], old_extension[AST_MAX_EXTENSION];
+@@ -627,19 +642,12 @@
+ return RESULT_SUCCESS;
+ }
+
+-static char usage_gosub[] =
+-" Usage: GOSUB <context> <extension> <priority> [<optional-argument>]\n"
+-" Cause the channel to execute the specified dialplan subroutine, returning\n"
+-" to the dialplan with execution of a Return()\n";
++static struct agi_command gosub_agi_command =
++ { { "gosub", NULL }, handle_gosub, NULL, NULL, 0 };
+
+-struct agi_command gosub_agi_command =
+- { { "gosub", NULL }, handle_gosub, "Execute a dialplan subroutine", usage_gosub , 0 };
+-
+ static int unload_module(void)
+ {
+- if (ast_agi_unregister) {
+- ast_agi_unregister(ast_module_info->self, &gosub_agi_command);
+- }
++ ast_agi_unregister(ast_module_info->self, &gosub_agi_command);
+
+ ast_unregister_application(app_return);
+ ast_unregister_application(app_pop);
+@@ -653,9 +661,7 @@
+
+ static int load_module(void)
+ {
+- if (ast_agi_register) {
+- ast_agi_register(ast_module_info->self, &gosub_agi_command);
+- }
++ ast_agi_register(ast_module_info->self, &gosub_agi_command);
+
+ ast_register_application_xml(app_pop, pop_exec);
+ ast_register_application_xml(app_return, return_exec);
+Index: apps/app_chanspy.c
+===================================================================
+--- a/apps/app_chanspy.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/apps/app_chanspy.c (.../trunk) (revision 202568)
+@@ -50,6 +50,7 @@
+ #include "asterisk/module.h"
+ #include "asterisk/lock.h"
+ #include "asterisk/options.h"
++#include "asterisk/autochan.h"
+
+ #define AST_NAME_STRLEN 256
+ #define NUM_SPYGROUPS 128
+@@ -141,6 +142,16 @@
+ name of the last channel that was spied on will be stored
+ in the <variable>SPY_CHANNEL</variable> variable.</para>
+ </option>
++ <option name="x">
++ <argument name="digit" required="true">
++ <para>Specify a DTMF digit that can be used to exit the application.</para>
++ </argument>
++ </option>
++ <option name="c">
++ <argument name="digit" required="true">
++ <para>Specify a DTMF digit that can be used to spy on the next available channel.</para>
++ </argument>
++ </option>
+ <option name="e">
+ <argument name="ext" required="true" />
+ <para>Enable <emphasis>enforced</emphasis> mode, so the spying channel can
+@@ -262,6 +273,16 @@
+ name of the last channel that was spied on will be stored
+ in the <variable>SPY_CHANNEL</variable> variable.</para>
+ </option>
++ <option name="x">
++ <argument name="digit" required="true">
++ <para>Specify a DTMF digit that can be used to exit the application.</para>
++ </argument>
++ </option>
++ <option name="c">
++ <argument name="digit" required="true">
++ <para>Specify a DTMF digit that can be used to spy on the next available channel.</para>
++ </argument>
++ </option>
+ <option name="e">
+ <argument name="ext" required="true" />
+ <para>Enable <emphasis>enforced</emphasis> mode, so the spying channel can
+@@ -287,12 +308,29 @@
+ <ref type="application">ChanSpy</ref>
+ </see-also>
+ </application>
+-
++
++ <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 const char *app_chan = "ChanSpy";
+
+-static const char *app_ext = "ExtenSpy";
++static const char app_chan[] = "ChanSpy";
+
++static const char app_ext[] = "ExtenSpy";
++
++static const char app_dahdiscan[] = "DAHDIScan";
++
+ enum {
+ OPTION_QUIET = (1 << 0), /* Quiet, no announcement */
+ OPTION_BRIDGED = (1 << 1), /* Only look at bridged calls */
+@@ -307,8 +345,11 @@
+ OPTION_NOTECH = (1 << 10), /* Skip technology name playback */
+ OPTION_BARGE = (1 << 11), /* Barge mode (whisper to both channels) */
+ OPTION_NAME = (1 << 12), /* Say the name of the person on whom we will spy */
+- OPTION_DTMF_SWITCH_MODES = (1 << 13), /*Allow numeric DTMF to switch between chanspy modes */
+-} chanspy_opt_flags;
++ OPTION_DTMF_SWITCH_MODES = (1 << 13), /* Allow numeric DTMF to switch between chanspy modes */
++ OPTION_DTMF_EXIT = (1 << 14), /* Set DTMF to exit, added for DAHDIScan integration */
++ OPTION_DTMF_CYCLE = (1 << 15), /* Custom DTMF for cycling next avaliable channel, (default is '*') */
++ OPTION_DAHDI_SCAN = (1 << 16), /* Scan groups in DAHDIScan mode */
++};
+
+ enum {
+ OPT_ARG_VOLUME = 0,
+@@ -316,8 +357,10 @@
+ OPT_ARG_RECORD,
+ OPT_ARG_ENFORCED,
+ OPT_ARG_NAME,
++ OPT_ARG_EXIT,
++ OPT_ARG_CYCLE,
+ OPT_ARG_ARRAY_SIZE,
+-} chanspy_opt_args;
++};
+
+ AST_APP_OPTIONS(spy_opts, {
+ AST_APP_OPTION('q', OPTION_QUIET),
+@@ -334,10 +377,10 @@
+ AST_APP_OPTION('s', OPTION_NOTECH),
+ AST_APP_OPTION_ARG('n', OPTION_NAME, OPT_ARG_NAME),
+ AST_APP_OPTION('d', OPTION_DTMF_SWITCH_MODES),
++ AST_APP_OPTION_ARG('x', OPTION_DTMF_EXIT, OPT_ARG_EXIT),
++ AST_APP_OPTION_ARG('c', OPTION_DTMF_CYCLE, OPT_ARG_CYCLE),
+ });
+
+-static int next_unique_id_to_use = 0;
+-
+ struct chanspy_translation_helper {
+ /* spy data */
+ struct ast_audiohook spy_audiohook;
+@@ -347,6 +390,12 @@
+ int volfactor;
+ };
+
++struct spy_dtmf_options {
++ char exit;
++ char cycle;
++ char volume;
++};
++
+ static void *spy_alloc(struct ast_channel *chan, void *data)
+ {
+ /* just store the data pointer in the channel structure */
+@@ -361,7 +410,7 @@
+ static int spy_generate(struct ast_channel *chan, void *data, int len, int samples)
+ {
+ struct chanspy_translation_helper *csth = data;
+- struct ast_frame *f = NULL;
++ struct ast_frame *f, *cur;
+
+ ast_audiohook_lock(&csth->spy_audiohook);
+ if (csth->spy_audiohook.status != AST_AUDIOHOOK_STATUS_RUNNING) {
+@@ -377,14 +426,16 @@
+ if (!f)
+ return 0;
+
+- if (ast_write(chan, f)) {
+- ast_frfree(f);
+- return -1;
+- }
++ for (cur = f; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
++ if (ast_write(chan, cur)) {
++ ast_frfree(f);
++ return -1;
++ }
+
+- if (csth->fd) {
+- if (write(csth->fd, f->data.ptr, f->datalen) < 0) {
+- ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno));
++ if (csth->fd) {
++ if (write(csth->fd, cur->data.ptr, cur->datalen) < 0) {
++ ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno));
++ }
+ }
+ }
+
+@@ -399,28 +450,22 @@
+ .generate = spy_generate,
+ };
+
+-static int start_spying(struct ast_channel *chan, const char *spychan_name, struct ast_audiohook *audiohook)
++static int start_spying(struct ast_autochan *autochan, const char *spychan_name, struct ast_audiohook *audiohook)
+ {
+ int res = 0;
+ struct ast_channel *peer = NULL;
+
+- ast_log(LOG_NOTICE, "Attaching %s to %s\n", spychan_name, chan->name);
++ ast_log(LOG_NOTICE, "Attaching %s to %s\n", spychan_name, autochan->chan->name);
+
+ ast_set_flag(audiohook, AST_AUDIOHOOK_TRIGGER_SYNC | AST_AUDIOHOOK_SMALL_QUEUE);
+- res = ast_audiohook_attach(chan, audiohook);
++ res = ast_audiohook_attach(autochan->chan, audiohook);
+
+- if (!res && ast_test_flag(chan, AST_FLAG_NBRIDGE) && (peer = ast_bridged_channel(chan))) {
++ if (!res && ast_test_flag(autochan->chan, AST_FLAG_NBRIDGE) && (peer = ast_bridged_channel(autochan->chan))) {
+ ast_softhangup(peer, AST_SOFTHANGUP_UNBRIDGE);
+ }
+ return res;
+ }
+
+-struct chanspy_ds {
+- struct ast_channel *chan;
+- char unique_id[20];
+- ast_mutex_t lock;
+-};
+-
+ static void change_spy_mode(const char digit, struct ast_flags *flags)
+ {
+ if (digit == '4') {
+@@ -435,8 +480,9 @@
+ }
+ }
+
+-static int channel_spy(struct ast_channel *chan, struct chanspy_ds *spyee_chanspy_ds,
+- int *volfactor, int fd, struct ast_flags *flags, char *exitcontext)
++static int channel_spy(struct ast_channel *chan, struct ast_autochan *spyee_autochan,
++ int *volfactor, int fd, struct spy_dtmf_options *user_options, struct ast_flags *flags,
++ char *exitcontext)
+ {
+ struct chanspy_translation_helper csth;
+ int running = 0, res, x = 0;
+@@ -444,32 +490,22 @@
+ char *name;
+ struct ast_frame *f;
+ struct ast_silence_generator *silgen = NULL;
+- struct ast_channel *spyee = NULL, *spyee_bridge = NULL;
++ struct ast_autochan *spyee_bridge_autochan = NULL;
+ const char *spyer_name;
+
+ ast_channel_lock(chan);
+ spyer_name = ast_strdupa(chan->name);
+ ast_channel_unlock(chan);
+
+- ast_mutex_lock(&spyee_chanspy_ds->lock);
+- if (spyee_chanspy_ds->chan) {
+- spyee = spyee_chanspy_ds->chan;
+- ast_channel_lock(spyee);
+- }
+- ast_mutex_unlock(&spyee_chanspy_ds->lock);
+-
+- if (!spyee) {
+- return 0;
+- }
+-
+ /* We now hold the channel lock on spyee */
+
+- if (ast_check_hangup(chan) || ast_check_hangup(spyee)) {
+- ast_channel_unlock(spyee);
++ if (ast_check_hangup(chan) || ast_check_hangup(spyee_autochan->chan)) {
+ return 0;
+ }
+
+- name = ast_strdupa(spyee->name);
++ ast_channel_lock(spyee_autochan->chan);
++ name = ast_strdupa(spyee_autochan->chan->name);
++ ast_channel_unlock(spyee_autochan->chan);
+
+ ast_verb(2, "Spying on channel %s\n", name);
+ manager_event(EVENT_FLAG_CALL, "ChanSpyStart",
+@@ -481,26 +517,23 @@
+
+ ast_audiohook_init(&csth.spy_audiohook, AST_AUDIOHOOK_TYPE_SPY, "ChanSpy");
+
+- if (start_spying(spyee, spyer_name, &csth.spy_audiohook)) {
++ if (start_spying(spyee_autochan, spyer_name, &csth.spy_audiohook)) {
+ ast_audiohook_destroy(&csth.spy_audiohook);
+- ast_channel_unlock(spyee);
+ return 0;
+ }
+
+- ast_audiohook_init(&csth.whisper_audiohook, AST_AUDIOHOOK_TYPE_WHISPER, "ChanSpy");
++ ast_audiohook_init(&csth.whisper_audiohook, AST_AUDIOHOOK_TYPE_WHISPER, "ChanSpy");
+ ast_audiohook_init(&csth.bridge_whisper_audiohook, AST_AUDIOHOOK_TYPE_WHISPER, "Chanspy");
+- if (start_spying(spyee, spyer_name, &csth.whisper_audiohook)) {
+- ast_log(LOG_WARNING, "Unable to attach whisper audiohook to spyee %s. Whisper mode disabled!\n", spyee->name);
++ if (start_spying(spyee_autochan, spyer_name, &csth.whisper_audiohook)) {
++ ast_log(LOG_WARNING, "Unable to attach whisper audiohook to spyee %s. Whisper mode disabled!\n", name);
+ }
+- if ((spyee_bridge = ast_bridged_channel(spyee))) {
+- ast_channel_lock(spyee_bridge);
+- if (start_spying(spyee_bridge, spyer_name, &csth.bridge_whisper_audiohook)) {
+- ast_log(LOG_WARNING, "Unable to attach barge audiohook on spyee %s. Barge mode disabled!\n", spyee->name);
++ if ((spyee_bridge_autochan = ast_autochan_setup(ast_bridged_channel(spyee_autochan->chan)))) {
++ ast_channel_lock(spyee_bridge_autochan->chan);
++ if (start_spying(spyee_bridge_autochan, spyer_name, &csth.bridge_whisper_audiohook)) {
++ ast_log(LOG_WARNING, "Unable to attach barge audiohook on spyee %s. Barge mode disabled!\n", name);
+ }
+- ast_channel_unlock(spyee_bridge);
++ ast_channel_unlock(spyee_bridge_autochan->chan);
+ }
+- ast_channel_unlock(spyee);
+- spyee = NULL;
+
+ ast_channel_lock(chan);
+ ast_set_flag(chan, AST_FLAG_END_DTMF_ONLY);
+@@ -590,10 +623,13 @@
+ }
+ }
+
+- if (res == '*') {
++ if (res == user_options->cycle) {
+ running = 0;
+ break;
+- } else if (res == '#') {
++ } else if (res == user_options->exit) {
++ running = -2;
++ break;
++ } else if (res == user_options->volume) {
+ if (!ast_strlen_zero(inp)) {
+ running = atoi(inp);
+ break;
+@@ -633,128 +669,45 @@
+ ast_audiohook_detach(&csth.spy_audiohook);
+ ast_audiohook_unlock(&csth.spy_audiohook);
+ ast_audiohook_destroy(&csth.spy_audiohook);
+-
++
++ if (spyee_bridge_autochan) {
++ ast_autochan_destroy(spyee_bridge_autochan);
++ }
++
+ ast_verb(2, "Done Spying on channel %s\n", name);
+ manager_event(EVENT_FLAG_CALL, "ChanSpyStop", "SpyeeChannel: %s\r\n", name);
+
+ return running;
+ }
+
+-/*!
+- * \note This relies on the embedded lock to be recursive, as it may be called
+- * due to a call to chanspy_ds_free with the lock held there.
+- */
+-static void chanspy_ds_destroy(void *data)
++static struct ast_autochan *next_channel(struct ast_channel_iterator *iter,
++ struct ast_autochan *autochan, struct ast_channel *chan)
+ {
+- struct chanspy_ds *chanspy_ds = data;
++ struct ast_channel *next;
++ const size_t pseudo_len = strlen("DAHDI/pseudo");
+
+- /* Setting chan to be NULL is an atomic operation, but we don't want this
+- * value to change while this lock is held. The lock is held elsewhere
+- * while it performs non-atomic operations with this channel pointer */
+-
+- ast_mutex_lock(&chanspy_ds->lock);
+- chanspy_ds->chan = NULL;
+- ast_mutex_unlock(&chanspy_ds->lock);
+-}
+-
+-static void chanspy_ds_chan_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan)
+-{
+- struct chanspy_ds *chanspy_ds = data;
+-
+- ast_mutex_lock(&chanspy_ds->lock);
+- chanspy_ds->chan = new_chan;
+- ast_mutex_unlock(&chanspy_ds->lock);
+-}
+-
+-static const struct ast_datastore_info chanspy_ds_info = {
+- .type = "chanspy",
+- .destroy = chanspy_ds_destroy,
+- .chan_fixup = chanspy_ds_chan_fixup,
+-};
+-
+-static struct chanspy_ds *chanspy_ds_free(struct chanspy_ds *chanspy_ds)
+-{
+- if (!chanspy_ds)
++ if (!iter) {
+ return NULL;
+-
+- ast_mutex_lock(&chanspy_ds->lock);
+- if (chanspy_ds->chan) {
+- struct ast_datastore *datastore;
+- struct ast_channel *chan;
+-
+- chan = chanspy_ds->chan;
+-
+- ast_channel_lock(chan);
+- if ((datastore = ast_channel_datastore_find(chan, &chanspy_ds_info, chanspy_ds->unique_id))) {
+- ast_channel_datastore_remove(chan, datastore);
+- /* chanspy_ds->chan is NULL after this call */
+- chanspy_ds_destroy(datastore->data);
+- datastore->data = NULL;
+- ast_datastore_free(datastore);
+- }
+- ast_channel_unlock(chan);
+ }
+- ast_mutex_unlock(&chanspy_ds->lock);
+
+- return NULL;
+-}
+-
+-/*! \note Returns the channel in the chanspy_ds locked as well as the chanspy_ds locked */
+-static struct chanspy_ds *setup_chanspy_ds(struct ast_channel *chan, struct chanspy_ds *chanspy_ds)
+-{
+- struct ast_datastore *datastore = NULL;
+-
+- ast_mutex_lock(&chanspy_ds->lock);
+-
+- if (!(datastore = ast_datastore_alloc(&chanspy_ds_info, chanspy_ds->unique_id))) {
+- ast_mutex_unlock(&chanspy_ds->lock);
+- chanspy_ds = chanspy_ds_free(chanspy_ds);
+- ast_channel_unlock(chan);
++redo:
++ if (!(next = ast_channel_iterator_next(iter))) {
+ return NULL;
+ }
+-
+- chanspy_ds->chan = chan;
+- datastore->data = chanspy_ds;
+- ast_channel_datastore_add(chan, datastore);
+
+- return chanspy_ds;
+-}
+-
+-static struct chanspy_ds *next_channel(struct ast_channel *chan,
+- const struct ast_channel *last, const char *spec,
+- const char *exten, const char *context, struct chanspy_ds *chanspy_ds)
+-{
+- struct ast_channel *next;
+- const size_t pseudo_len = strlen("DAHDI/pseudo");
+-
+-redo:
+- if (!ast_strlen_zero(spec))
+- next = ast_walk_channel_by_name_prefix_locked(last, spec, strlen(spec));
+- else if (!ast_strlen_zero(exten))
+- next = ast_walk_channel_by_exten_locked(last, exten, context);
+- else
+- next = ast_channel_walk_locked(last);
+-
+- if (!next)
+- return NULL;
+-
+ if (!strncmp(next->name, "DAHDI/pseudo", pseudo_len)) {
+- last = next;
+- ast_channel_unlock(next);
+ goto redo;
+ } else if (next == chan) {
+- last = next;
+- ast_channel_unlock(next);
+ goto redo;
+ }
+
+- return setup_chanspy_ds(next, chanspy_ds);
++ return ast_autochan_setup(next);
+ }
+
+ static int common_exec(struct ast_channel *chan, struct ast_flags *flags,
+- int volfactor, const int fd, const char *mygroup, const char *myenforced,
+- const char *spec, const char *exten, const char *context, const char *mailbox,
+- const char *name_context)
++ int volfactor, const int fd, struct spy_dtmf_options *user_options,
++ const char *mygroup, const char *myenforced, const char *spec, const char *exten,
++ const char *context, const char *mailbox, const char *name_context)
+ {
+ char nameprefix[AST_NAME_STRLEN];
+ char peer_name[AST_NAME_STRLEN + 5];
+@@ -765,7 +718,7 @@
+ char *ptr;
+ int num;
+ int num_spyed_upon = 1;
+- struct chanspy_ds chanspy_ds = { 0, };
++ struct ast_channel_iterator *iter = NULL;
+
+ if (ast_test_flag(flags, OPTION_EXIT)) {
+ const char *c;
+@@ -780,10 +733,6 @@
+ ast_channel_unlock(chan);
+ }
+
+- ast_mutex_init(&chanspy_ds.lock);
+-
+- snprintf(chanspy_ds.unique_id, sizeof(chanspy_ds.unique_id), "%d", ast_atomic_fetchadd_int(&next_unique_id_to_use, +1));
+-
+ if (chan->_state != AST_STATE_UP)
+ ast_answer(chan);
+
+@@ -792,8 +741,8 @@
+ waitms = 100;
+
+ for (;;) {
+- struct chanspy_ds *peer_chanspy_ds = NULL, *next_chanspy_ds = NULL;
+- struct ast_channel *prev = NULL, *peer = NULL;
++ struct ast_autochan *autochan = NULL, *next_autochan = NULL;
++ struct ast_channel *prev = NULL;
+
+ if (!ast_test_flag(flags, OPTION_QUIET) && num_spyed_upon) {
+ res = ast_streamfile(chan, "beep", chan->language);
+@@ -814,6 +763,19 @@
+ }
+ }
+
++ /* Set up the iterator we'll be using during this call */
++ if (!ast_strlen_zero(spec)) {
++ iter = ast_channel_iterator_by_name_new(0, spec, strlen(spec));
++ } else if (!ast_strlen_zero(exten)) {
++ iter = ast_channel_iterator_by_exten_new(0, exten, context);
++ } else {
++ iter = ast_channel_iterator_all_new(0);
++ }
++
++ if (!iter) {
++ return -1;
++ }
++
+ res = ast_waitfordigit(chan, waitms);
+ if (res < 0) {
+ ast_clear_flag(chan, AST_FLAG_SPYING);
+@@ -833,38 +795,30 @@
+ waitms = 100;
+ num_spyed_upon = 0;
+
+- for (peer_chanspy_ds = next_channel(chan, prev, spec, exten, context, &chanspy_ds);
+- peer_chanspy_ds;
+- 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) {
++ for (autochan = next_channel(iter, autochan, chan);
++ autochan;
++ prev = autochan->chan, ast_autochan_destroy(autochan),
++ autochan = next_autochan ? next_autochan :
++ next_channel(iter, autochan, chan), next_autochan = NULL) {
+ int igrp = !mygroup;
+ int ienf = !myenforced;
+ char *s;
+
+- peer = peer_chanspy_ds->chan;
+-
+- ast_mutex_unlock(&peer_chanspy_ds->lock);
+-
+- if (peer == prev) {
+- ast_channel_unlock(peer);
+- chanspy_ds_free(peer_chanspy_ds);
++ if (autochan->chan == prev) {
++ ast_autochan_destroy(autochan);
+ break;
+ }
+
+ if (ast_check_hangup(chan)) {
+- ast_channel_unlock(peer);
+- chanspy_ds_free(peer_chanspy_ds);
++ ast_autochan_destroy(autochan);
+ break;
+ }
+
+- if (ast_test_flag(flags, OPTION_BRIDGED) && !ast_bridged_channel(peer)) {
+- ast_channel_unlock(peer);
++ if (ast_test_flag(flags, OPTION_BRIDGED) && !ast_bridged_channel(autochan->chan)) {
+ continue;
+ }
+
+- if (ast_check_hangup(peer) || ast_test_flag(peer, AST_FLAG_SPYING)) {
+- ast_channel_unlock(peer);
++ if (ast_check_hangup(autochan->chan) || ast_test_flag(autochan->chan, AST_FLAG_SPYING)) {
+ continue;
+ }
+
+@@ -875,14 +829,22 @@
+ char dup_mygroup[512];
+ char *groups[NUM_SPYGROUPS];
+ char *mygroups[NUM_SPYGROUPS];
+- const char *group;
++ const char *group = NULL;
+ 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));
+
+- if ((group = pbx_builtin_getvar_helper(peer, "SPYGROUP"))) {
++ /* Before dahdi scan was part of chanspy, it would use the "GROUP" variable
++ * rather than "SPYGROUP", this check is done to preserve expected behavior */
++ if (ast_test_flag(flags, OPTION_DAHDI_SCAN)) {
++ group = pbx_builtin_getvar_helper(autochan->chan, "GROUP");
++ } else {
++ group = pbx_builtin_getvar_helper(autochan->chan, "SPYGROUP");
++ }
++
++ if (!ast_strlen_zero(group)) {
+ ast_copy_string(dup_group, group, sizeof(dup_group));
+ num_groups = ast_app_separate_args(dup_group, ':', groups,
+ ARRAY_LEN(groups));
+@@ -899,10 +861,8 @@
+ }
+
+ if (!igrp) {
+- ast_channel_unlock(peer);
+ continue;
+ }
+-
+ if (myenforced) {
+ char ext[AST_CHANNEL_NAME + 3];
+ char buffer[512];
+@@ -910,7 +870,7 @@
+
+ snprintf(buffer, sizeof(buffer) - 1, ":%s:", myenforced);
+
+- ast_copy_string(ext + 1, peer->name, sizeof(ext) - 1);
++ ast_copy_string(ext + 1, autochan->chan->name, sizeof(ext) - 1);
+ if ((end = strchr(ext, '-'))) {
+ *end++ = ':';
+ *end = '\0';
+@@ -928,18 +888,13 @@
+ }
+
+ strcpy(peer_name, "spy-");
+- strncat(peer_name, peer->name, AST_NAME_STRLEN - 4 - 1);
++ strncat(peer_name, autochan->chan->name, AST_NAME_STRLEN - 4 - 1);
+ ptr = strchr(peer_name, '/');
+ *ptr++ = '\0';
+ ptr = strsep(&ptr, "-");
+
+ for (s = peer_name; s < ptr; s++)
+ *s = tolower(*s);
+- /* We have to unlock the peer channel here to avoid a deadlock.
+- * So, when we need to dereference it again, we have to lock the
+- * datastore and get the pointer from there to see if the channel
+- * is still valid. */
+- ast_channel_unlock(peer);
+
+ if (!ast_test_flag(flags, OPTION_QUIET)) {
+ if (ast_test_flag(flags, OPTION_NAME)) {
+@@ -955,7 +910,7 @@
+ res = ast_waitstream(chan, "");
+ }
+ if (res) {
+- chanspy_ds_free(peer_chanspy_ds);
++ ast_autochan_destroy(autochan);
+ break;
+ }
+ } else {
+@@ -967,42 +922,38 @@
+ }
+ }
+
+- res = channel_spy(chan, peer_chanspy_ds, &volfactor, fd, flags, exitcontext);
+- num_spyed_upon++;
++ res = channel_spy(chan, autochan, &volfactor, fd, user_options, flags, exitcontext);
++ num_spyed_upon++;
+
+ if (res == -1) {
+- chanspy_ds_free(peer_chanspy_ds);
++ ast_autochan_destroy(autochan);
+ goto exit;
+ } else if (res == -2) {
+ res = 0;
+- chanspy_ds_free(peer_chanspy_ds);
++ ast_autochan_destroy(autochan);
+ goto exit;
+ } else if (res > 1 && spec) {
+ struct ast_channel *next;
+
+ snprintf(nameprefix, AST_NAME_STRLEN, "%s/%d", spec, res);
+
+- if ((next = ast_get_channel_by_name_prefix_locked(nameprefix, strlen(nameprefix)))) {
+- peer_chanspy_ds = chanspy_ds_free(peer_chanspy_ds);
+- next_chanspy_ds = setup_chanspy_ds(next, &chanspy_ds);
++ if ((next = ast_channel_get_by_name_prefix(nameprefix, strlen(nameprefix)))) {
++ next_autochan = ast_autochan_setup(next);
++ next = ast_channel_unref(next);
+ } else {
+ /* stay on this channel, if it is still valid */
+-
+- ast_mutex_lock(&peer_chanspy_ds->lock);
+- if (peer_chanspy_ds->chan) {
+- ast_channel_lock(peer_chanspy_ds->chan);
+- next_chanspy_ds = peer_chanspy_ds;
+- peer_chanspy_ds = NULL;
++ if (!ast_check_hangup(autochan->chan)) {
++ next_autochan = ast_autochan_setup(autochan->chan);
+ } else {
+ /* the channel is gone */
+- ast_mutex_unlock(&peer_chanspy_ds->lock);
+- next_chanspy_ds = NULL;
++ next_autochan = NULL;
+ }
+ }
+-
+- peer = NULL;
+ }
+ }
++
++ iter = ast_channel_iterator_destroy(iter);
++
+ if (res == -1 || ast_check_hangup(chan))
+ break;
+ }
+@@ -1012,20 +963,21 @@
+
+ ast_channel_setoption(chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0);
+
+- ast_mutex_lock(&chanspy_ds.lock);
+- ast_mutex_unlock(&chanspy_ds.lock);
+- ast_mutex_destroy(&chanspy_ds.lock);
+-
+ return res;
+ }
+
+-static int chanspy_exec(struct ast_channel *chan, void *data)
++static int chanspy_exec(struct ast_channel *chan, const char *data)
+ {
+ char *myenforced = NULL;
+ char *mygroup = NULL;
+ char *recbase = NULL;
+ int fd = 0;
+ struct ast_flags flags;
++ struct spy_dtmf_options user_options = {
++ .cycle = '*',
++ .volume = '#',
++ .exit = '\0',
++ };
+ int oldwf = 0;
+ int volfactor = 0;
+ int res;
+@@ -1036,14 +988,15 @@
+ AST_APP_ARG(options);
+ );
+ char *opts[OPT_ARG_ARRAY_SIZE];
++ char *parse = ast_strdupa(data);
+
+- data = ast_strdupa(data);
+- AST_STANDARD_APP_ARGS(args, data);
++ AST_STANDARD_APP_ARGS(args, parse);
+
+ if (args.spec && !strcmp(args.spec, "all"))
+ args.spec = NULL;
+
+ if (args.options) {
++ char tmp;
+ ast_app_parse_options(spy_opts, &flags, opts, args.options);
+ if (ast_test_flag(&flags, OPTION_GROUP))
+ mygroup = opts[OPT_ARG_GROUP];
+@@ -1052,6 +1005,24 @@
+ !(recbase = opts[OPT_ARG_RECORD]))
+ recbase = "chanspy";
+
++ if (ast_test_flag(&flags, OPTION_DTMF_EXIT) && opts[OPT_ARG_EXIT]) {
++ tmp = opts[OPT_ARG_EXIT][0];
++ if (strchr("0123456789*#", tmp) && tmp != '\0') {
++ user_options.exit = tmp;
++ } else {
++ ast_log(LOG_NOTICE, "Argument for option 'x' must be a valid DTMF digit.");
++ }
++ }
++
++ if (ast_test_flag(&flags, OPTION_DTMF_CYCLE) && opts[OPT_ARG_CYCLE]) {
++ tmp = opts[OPT_ARG_CYCLE][0];
++ if (strchr("0123456789*#", tmp) && tmp != '\0') {
++ user_options.cycle = tmp;
++ } else {
++ ast_log(LOG_NOTICE, "Argument for option 'c' must be a valid DTMF digit.");
++ }
++ }
++
+ if (ast_test_flag(&flags, OPTION_VOLUME) && opts[OPT_ARG_VOLUME]) {
+ int vol;
+
+@@ -1066,7 +1037,7 @@
+
+ if (ast_test_flag(&flags, OPTION_ENFORCED))
+ myenforced = opts[OPT_ARG_ENFORCED];
+-
++
+ if (ast_test_flag(&flags, OPTION_NAME)) {
+ if (!ast_strlen_zero(opts[OPT_ARG_NAME])) {
+ char *delimiter;
+@@ -1079,10 +1050,9 @@
+ }
+ }
+ }
+-
+-
+- } else
++ } else {
+ ast_clear_flag(&flags, AST_FLAGS_ALL);
++ }
+
+ oldwf = chan->writeformat;
+ if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) {
+@@ -1100,7 +1070,7 @@
+ }
+ }
+
+- res = common_exec(chan, &flags, volfactor, fd, mygroup, myenforced, args.spec, NULL, NULL, mailbox, name_context);
++ res = common_exec(chan, &flags, volfactor, fd, &user_options, mygroup, myenforced, args.spec, NULL, NULL, mailbox, name_context);
+
+ if (fd)
+ close(fd);
+@@ -1111,13 +1081,18 @@
+ return res;
+ }
+
+-static int extenspy_exec(struct ast_channel *chan, void *data)
++static int extenspy_exec(struct ast_channel *chan, const char *data)
+ {
+ char *ptr, *exten = NULL;
+ char *mygroup = NULL;
+ char *recbase = NULL;
+ int fd = 0;
+ struct ast_flags flags;
++ struct spy_dtmf_options user_options = {
++ .cycle = '*',
++ .volume = '#',
++ .exit = '\0',
++ };
+ int oldwf = 0;
+ int volfactor = 0;
+ int res;
+@@ -1127,10 +1102,9 @@
+ AST_APP_ARG(context);
+ AST_APP_ARG(options);
+ );
++ char *parse = ast_strdupa(data);
+
+- data = ast_strdupa(data);
+-
+- AST_STANDARD_APP_ARGS(args, data);
++ AST_STANDARD_APP_ARGS(args, parse);
+ if (!ast_strlen_zero(args.context) && (ptr = strchr(args.context, '@'))) {
+ exten = args.context;
+ *ptr++ = '\0';
+@@ -1142,6 +1116,7 @@
+
+ if (args.options) {
+ char *opts[OPT_ARG_ARRAY_SIZE];
++ char tmp;
+
+ ast_app_parse_options(spy_opts, &flags, opts, args.options);
+ if (ast_test_flag(&flags, OPTION_GROUP))
+@@ -1151,6 +1126,24 @@
+ !(recbase = opts[OPT_ARG_RECORD]))
+ recbase = "chanspy";
+
++ if (ast_test_flag(&flags, OPTION_DTMF_EXIT) && opts[OPT_ARG_EXIT]) {
++ tmp = opts[OPT_ARG_EXIT][0];
++ if (strchr("0123456789*#", tmp) && tmp != '\0') {
++ user_options.exit = tmp;
++ } else {
++ ast_log(LOG_NOTICE, "Argument for option 'x' must be a valid DTMF digit.");
++ }
++ }
++
++ if (ast_test_flag(&flags, OPTION_DTMF_CYCLE) && opts[OPT_ARG_CYCLE]) {
++ tmp = opts[OPT_ARG_CYCLE][0];
++ if (strchr("0123456789*#", tmp) && tmp != '\0') {
++ user_options.cycle = tmp;
++ } else {
++ ast_log(LOG_NOTICE, "Argument for option 'c' must be a valid DTMF digit.");
++ }
++ }
++
+ if (ast_test_flag(&flags, OPTION_VOLUME) && opts[OPT_ARG_VOLUME]) {
+ int vol;
+
+@@ -1163,7 +1156,6 @@
+ if (ast_test_flag(&flags, OPTION_PRIVATE))
+ ast_set_flag(&flags, OPTION_WHISPER);
+
+-
+ if (ast_test_flag(&flags, OPTION_NAME)) {
+ if (!ast_strlen_zero(opts[OPT_ARG_NAME])) {
+ char *delimiter;
+@@ -1177,8 +1169,9 @@
+ }
+ }
+
+- } else
++ } else {
+ ast_clear_flag(&flags, AST_FLAGS_ALL);
++ }
+
+ oldwf = chan->writeformat;
+ if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) {
+@@ -1197,7 +1190,7 @@
+ }
+
+
+- res = common_exec(chan, &flags, volfactor, fd, mygroup, NULL, NULL, exten, args.context, mailbox, name_context);
++ res = common_exec(chan, &flags, volfactor, fd, &user_options, mygroup, NULL, NULL, exten, args.context, mailbox, name_context);
+
+ if (fd)
+ close(fd);
+@@ -1208,12 +1201,49 @@
+ return res;
+ }
+
++static int dahdiscan_exec(struct ast_channel *chan, const char *data)
++{
++ const char *spec = "DAHDI";
++ struct ast_flags flags;
++ struct spy_dtmf_options user_options = {
++ .cycle = '#',
++ .volume = '\0',
++ .exit = '*',
++ };
++ int oldwf = 0;
++ int res;
++ char *mygroup = NULL;
++
++ ast_clear_flag(&flags, AST_FLAGS_ALL);
++
++ if (!ast_strlen_zero(data)) {
++ mygroup = ast_strdupa(data);
++ }
++ ast_set_flag(&flags, OPTION_DTMF_EXIT);
++ ast_set_flag(&flags, OPTION_DTMF_CYCLE);
++ ast_set_flag(&flags, OPTION_DAHDI_SCAN);
++
++ oldwf = chan->writeformat;
++ if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) {
++ ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
++ return -1;
++ }
++
++ res = common_exec(chan, &flags, 0, 0, &user_options, mygroup, NULL, spec, NULL, NULL, NULL, NULL);
++
++ if (oldwf && ast_set_write_format(chan, oldwf) < 0)
++ ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
++
++ return res;
++}
++
+ static int unload_module(void)
+ {
+ int res = 0;
+
+ res |= ast_unregister_application(app_chan);
+ res |= ast_unregister_application(app_ext);
++ res |= ast_unregister_application(app_dahdiscan);
+
+ return res;
+ }
+@@ -1224,6 +1254,7 @@
+
+ res |= ast_register_application_xml(app_chan, chanspy_exec);
+ res |= ast_register_application_xml(app_ext, extenspy_exec);
++ res |= ast_register_application_xml(app_dahdiscan, dahdiscan_exec);
+
+ return res;
+ }
+Index: apps/app_jack.c
+===================================================================
+--- a/apps/app_jack.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/apps/app_jack.c (.../trunk) (revision 202568)
+@@ -26,7 +26,7 @@
+ * and output jack port so that the audio can be processed through
+ * another application, or to play audio from another application.
+ *
+- * \arg http://www.jackaudio.org/
++ * \extref http://www.jackaudio.org/
+ *
+ * \note To install libresample, check it out of the following repository:
+ * <code>$ svn co http://svn.digium.com/svn/thirdparty/libresample/trunk</code>
+@@ -106,14 +106,15 @@
+ </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
++ <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 const char jack_app[] = "JACK";
++
+ struct jack_data {
+ AST_DECLARE_STRING_FIELDS(
+ AST_STRING_FIELD(server_name);
+@@ -181,7 +182,7 @@
+ } else
+ ast_str_append(&str, 0, ", %s", jack_status_to_str((1 << i)));
+ }
+-
++
+ ast_log(LOG_NOTICE, "%s: %s\n", prefix, ast_str_buffer(str));
+ }
+
+@@ -201,10 +202,10 @@
+
+ /* XXX Hard coded 8 kHz */
+
+- to_srate = input ? 8000.0 : jack_srate;
++ to_srate = input ? 8000.0 : jack_srate;
+ from_srate = input ? jack_srate : 8000.0;
+
+- resample_factor = input ? &jack_data->input_resample_factor :
++ resample_factor = input ? &jack_data->input_resample_factor :
+ &jack_data->output_resample_factor;
+
+ if (from_srate == to_srate) {
+@@ -219,9 +220,9 @@
+ resampler = input ? &jack_data->input_resampler :
+ &jack_data->output_resampler;
+
+- if (!(*resampler = resample_open(RESAMPLE_QUALITY,
++ if (!(*resampler = resample_open(RESAMPLE_QUALITY,
+ *resample_factor, *resample_factor))) {
+- ast_log(LOG_ERROR, "Failed to open %s resampler\n",
++ ast_log(LOG_ERROR, "Failed to open %s resampler\n",
+ input ? "input" : "output");
+ return -1;
+ }
+@@ -233,9 +234,9 @@
+ * \brief Handle jack input port
+ *
+ * Read nframes number of samples from the input buffer, resample it
+- * if necessary, and write it into the appropriate ringbuffer.
++ * if necessary, and write it into the appropriate ringbuffer.
+ */
+-static void handle_input(void *buf, jack_nframes_t nframes,
++static void handle_input(void *buf, jack_nframes_t nframes,
+ struct jack_data *jack_data)
+ {
+ short s_buf[nframes];
+@@ -266,7 +267,7 @@
+
+ total_out_buf_used += out_buf_used;
+ total_in_buf_used += in_buf_used;
+-
++
+ if (total_out_buf_used == ARRAY_LEN(f_buf)) {
+ ast_log(LOG_ERROR, "Output buffer filled ... need to increase its size, "
+ "nframes '%d', total_out_buf_used '%d'\n", nframes, total_out_buf_used);
+@@ -276,7 +277,7 @@
+
+ for (i = 0; i < total_out_buf_used; i++)
+ s_buf[i] = f_buf[i] * (SHRT_MAX / 1.0);
+-
++
+ write_len = total_out_buf_used * sizeof(int16_t);
+ } else {
+ /* No resampling needed */
+@@ -298,7 +299,7 @@
+ * Read nframes number of samples from the ringbuffer and write it out to the
+ * output port buffer.
+ */
+-static void handle_output(void *buf, jack_nframes_t nframes,
++static void handle_output(void *buf, jack_nframes_t nframes,
+ struct jack_data *jack_data)
+ {
+ size_t res, len;
+@@ -368,7 +369,7 @@
+ resample_close(jack_data->output_resampler);
+ jack_data->output_resampler = NULL;
+ }
+-
++
+ if (jack_data->input_resampler) {
+ resample_close(jack_data->input_resampler);
+ jack_data->input_resampler = NULL;
+@@ -539,10 +540,10 @@
+ int in_buf_used;
+ int out_buf_used;
+
+- out_buf_used = resample_process(jack_data->output_resampler,
++ out_buf_used = resample_process(jack_data->output_resampler,
+ jack_data->output_resample_factor,
+- &in_buf[total_in_buf_used], ARRAY_LEN(in_buf) - total_in_buf_used,
+- 0, &in_buf_used,
++ &in_buf[total_in_buf_used], ARRAY_LEN(in_buf) - total_in_buf_used,
++ 0, &in_buf_used,
+ &f_buf[total_out_buf_used], ARRAY_LEN(f_buf) - total_out_buf_used);
+
+ if (out_buf_used < 0)
+@@ -599,7 +600,7 @@
+ */
+ static void handle_jack_audio(struct ast_channel *chan, struct jack_data *jack_data,
+ struct ast_frame *out_frame)
+-{
++{
+ short buf[160];
+ struct ast_frame f = {
+ .frametype = AST_FRAME_VOICE,
+@@ -677,7 +678,7 @@
+
+ if (!(jack_data = ast_calloc(1, sizeof(*jack_data))))
+ return NULL;
+-
++
+ if (ast_string_field_init(jack_data, 32)) {
+ ast_free(jack_data);
+ return NULL;
+@@ -740,19 +741,14 @@
+ return 0;
+ }
+
+-static int jack_exec(struct ast_channel *chan, void *data)
++static int jack_exec(struct ast_channel *chan, const char *data)
+ {
+ struct jack_data *jack_data;
+- AST_DECLARE_APP_ARGS(args,
+- AST_APP_ARG(options);
+- );
+
+ if (!(jack_data = jack_data_alloc()))
+ return -1;
+
+- args.options = data;
+-
+- if (!ast_strlen_zero(args.options) && handle_options(jack_data, args.options)) {
++ if (!ast_strlen_zero(data) && handle_options(jack_data, data)) {
+ destroy_jack_data(jack_data);
+ return -1;
+ }
+@@ -816,7 +812,7 @@
+ .destroy = jack_hook_ds_destroy,
+ };
+
+-static int jack_hook_callback(struct ast_audiohook *audiohook, struct ast_channel *chan,
++static int jack_hook_callback(struct ast_audiohook *audiohook, struct ast_channel *chan,
+ struct ast_frame *frame, enum ast_audiohook_direction direction)
+ {
+ struct ast_datastore *datastore;
+@@ -875,7 +871,7 @@
+ }
+
+ if (ast_strlen_zero(args.mode) || strcasecmp(args.mode, "manipulate")) {
+- ast_log(LOG_ERROR, "'%s' is not a supported mode. Only manipulate is supported.\n",
++ ast_log(LOG_ERROR, "'%s' is not a supported mode. Only manipulate is supported.\n",
+ S_OR(args.mode, "<none>"));
+ goto return_error;
+ }
+@@ -945,7 +941,7 @@
+ return 0;
+ }
+
+-static int jack_hook_write(struct ast_channel *chan, const char *cmd, char *data,
++static int jack_hook_write(struct ast_channel *chan, const char *cmd, char *data,
+ const char *value)
+ {
+ int res;
+@@ -955,7 +951,7 @@
+ else if (!strcasecmp(value, "off"))
+ res = disable_jack_hook(chan);
+ else {
+- ast_log(LOG_ERROR, "'%s' is not a valid value for JACK_HOOK()\n", value);
++ ast_log(LOG_ERROR, "'%s' is not a valid value for JACK_HOOK()\n", value);
+ res = -1;
+ }
+
+Index: apps/app_cdr.c
+===================================================================
+--- a/apps/app_cdr.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/apps/app_cdr.c (.../trunk) (revision 202568)
+@@ -44,9 +44,9 @@
+ </application>
+ ***/
+
+-static char *nocdr_app = "NoCDR";
++static const char nocdr_app[] = "NoCDR";
+
+-static int nocdr_exec(struct ast_channel *chan, void *data)
++static int nocdr_exec(struct ast_channel *chan, const char *data)
+ {
+ if (chan->cdr)
+ ast_set_flag(chan->cdr, AST_CDR_FLAG_POST_DISABLED);
+Index: apps/app_adsiprog.c
+===================================================================
+--- a/apps/app_adsiprog.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/apps/app_adsiprog.c (.../trunk) (revision 202568)
+@@ -45,7 +45,7 @@
+ #include "asterisk/utils.h"
+ #include "asterisk/lock.h"
+
+-static char *app = "ADSIProg";
++static const char app[] = "ADSIProg";
+
+ /*** DOCUMENTATION
+ <application name="ADSIProg" language="en_US">
+@@ -71,10 +71,10 @@
+
+ struct adsi_event {
+ int id;
+- char *name;
++ const char *name;
+ };
+
+-static struct adsi_event events[] = {
++static const struct adsi_event events[] = {
+ { 1, "CALLERID" },
+ { 2, "VMWI" },
+ { 3, "NEARANSWER" },
+@@ -101,7 +101,7 @@
+ { 24, "CPEID" },
+ };
+
+-static struct adsi_event justify[] = {
++static const struct adsi_event justify[] = {
+ { 0, "CENTER" },
+ { 1, "RIGHT" },
+ { 2, "LEFT" },
+@@ -232,7 +232,7 @@
+ return 0;
+ }
+
+-static char *get_token(char **buf, char *script, int lineno)
++static char *get_token(char **buf, const char *script, int lineno)
+ {
+ char *tmp = *buf, *keyword;
+ int quoted = 0;
+@@ -264,7 +264,7 @@
+
+ static char *validdtmf = "123456789*0#ABCD";
+
+-static int send_dtmf(char *buf, char *name, int id, char *args, struct adsi_script *state, char *script, int lineno)
++static int send_dtmf(char *buf, char *name, int id, char *args, struct adsi_script *state, const char *script, int lineno)
+ {
+ char dtmfstr[80], *a;
+ int bytes = 0;
+@@ -294,7 +294,7 @@
+ return bytes;
+ }
+
+-static int goto_line(char *buf, char *name, int id, char *args, struct adsi_script *state, char *script, int lineno)
++static int goto_line(char *buf, char *name, int id, char *args, struct adsi_script *state, const char *script, int lineno)
+ {
+ char *page = get_token(&args, script, lineno);
+ char *gline = get_token(&args, script, lineno);
+@@ -327,7 +327,7 @@
+ return 2;
+ }
+
+-static int goto_line_rel(char *buf, char *name, int id, char *args, struct adsi_script *state, char *script, int lineno)
++static int goto_line_rel(char *buf, char *name, int id, char *args, struct adsi_script *state, const char *script, int lineno)
+ {
+ char *dir = get_token(&args, script, lineno);
+ char *gline = get_token(&args, script, lineno);
+@@ -360,7 +360,7 @@
+ return 2;
+ }
+
+-static int send_delay(char *buf, char *name, int id, char *args, struct adsi_script *state, char *script, int lineno)
++static int send_delay(char *buf, char *name, int id, char *args, struct adsi_script *state, const char *script, int lineno)
+ {
+ char *gtime = get_token(&args, script, lineno);
+ int ms;
+@@ -385,7 +385,7 @@
+ return 2;
+ }
+
+-static int set_state(char *buf, char *name, int id, char *args, struct adsi_script *istate, char *script, int lineno)
++static int set_state(char *buf, char *name, int id, char *args, struct adsi_script *istate, const char *script, int lineno)
+ {
+ char *gstate = get_token(&args, script, lineno);
+ int state;
+@@ -406,7 +406,7 @@
+ return 2;
+ }
+
+-static int cleartimer(char *buf, char *name, int id, char *args, struct adsi_script *istate, char *script, int lineno)
++static int cleartimer(char *buf, char *name, int id, char *args, struct adsi_script *istate, const char *script, int lineno)
+ {
+ char *tok = get_token(&args, script, lineno);
+
+@@ -424,7 +424,7 @@
+ return 2;
+ }
+
+-static struct adsi_flag *getflagbyname(struct adsi_script *state, char *name, char *script, int lineno, int create)
++static struct adsi_flag *getflagbyname(struct adsi_script *state, char *name, const char *script, int lineno, int create)
+ {
+ int x;
+
+@@ -449,7 +449,7 @@
+ return &state->flags[state->numflags-1];
+ }
+
+-static int setflag(char *buf, char *name, int id, char *args, struct adsi_script *state, char *script, int lineno)
++static int setflag(char *buf, char *name, int id, char *args, struct adsi_script *state, const char *script, int lineno)
+ {
+ char *tok = get_token(&args, script, lineno);
+ char sname[80];
+@@ -476,7 +476,7 @@
+ return 2;
+ }
+
+-static int clearflag(char *buf, char *name, int id, char *args, struct adsi_script *state, char *script, int lineno)
++static int clearflag(char *buf, char *name, int id, char *args, struct adsi_script *state, const char *script, int lineno)
+ {
+ char *tok = get_token(&args, script, lineno);
+ struct adsi_flag *flag;
+@@ -503,7 +503,7 @@
+ return 2;
+ }
+
+-static int starttimer(char *buf, char *name, int id, char *args, struct adsi_script *istate, char *script, int lineno)
++static int starttimer(char *buf, char *name, int id, char *args, struct adsi_script *istate, const char *script, int lineno)
+ {
+ char *tok = get_token(&args, script, lineno);
+ int secs;
+@@ -549,7 +549,7 @@
+ return -1;
+ }
+
+-static struct adsi_soft_key *getkeybyname(struct adsi_script *state, char *name, char *script, int lineno)
++static struct adsi_soft_key *getkeybyname(struct adsi_script *state, char *name, const char *script, int lineno)
+ {
+ int x;
+
+@@ -570,7 +570,7 @@
+ return &state->keys[state->numkeys-1];
+ }
+
+-static struct adsi_subscript *getsubbyname(struct adsi_script *state, char *name, char *script, int lineno)
++static struct adsi_subscript *getsubbyname(struct adsi_script *state, char *name, const char *script, int lineno)
+ {
+ int x;
+
+@@ -591,7 +591,7 @@
+ return &state->subs[state->numsubs-1];
+ }
+
+-static struct adsi_state *getstatebyname(struct adsi_script *state, char *name, char *script, int lineno, int create)
++static struct adsi_state *getstatebyname(struct adsi_script *state, char *name, const char *script, int lineno, int create)
+ {
+ int x;
+
+@@ -616,7 +616,7 @@
+ return &state->states[state->numstates-1];
+ }
+
+-static struct adsi_display *getdisplaybyname(struct adsi_script *state, char *name, char *script, int lineno, int create)
++static struct adsi_display *getdisplaybyname(struct adsi_script *state, char *name, const char *script, int lineno, int create)
+ {
+ int x;
+
+@@ -641,7 +641,7 @@
+ return &state->displays[state->numdisplays-1];
+ }
+
+-static int showkeys(char *buf, char *name, int id, char *args, struct adsi_script *state, char *script, int lineno)
++static int showkeys(char *buf, char *name, int id, char *args, struct adsi_script *state, const char *script, int lineno)
+ {
+ char *tok, newkey[80];
+ int bytes, x, flagid = 0;
+@@ -688,7 +688,7 @@
+ return 2 + x;
+ }
+
+-static int showdisplay(char *buf, char *name, int id, char *args, struct adsi_script *state, char *script, int lineno)
++static int showdisplay(char *buf, char *name, int id, char *args, struct adsi_script *state, const char *script, int lineno)
+ {
+ char *tok, dispname[80];
+ int line = 0, flag = 0, cmd = 3;
+@@ -739,7 +739,7 @@
+ return 3;
+ }
+
+-static int cleardisplay(char *buf, char *name, int id, char *args, struct adsi_script *istate, char *script, int lineno)
++static int cleardisplay(char *buf, char *name, int id, char *args, struct adsi_script *istate, const char *script, int lineno)
+ {
+ char *tok = get_token(&args, script, lineno);
+
+@@ -751,7 +751,7 @@
+ return 2;
+ }
+
+-static int digitdirect(char *buf, char *name, int id, char *args, struct adsi_script *istate, char *script, int lineno)
++static int digitdirect(char *buf, char *name, int id, char *args, struct adsi_script *istate, const char *script, int lineno)
+ {
+ char *tok = get_token(&args, script, lineno);
+
+@@ -763,7 +763,7 @@
+ return 2;
+ }
+
+-static int clearcbone(char *buf, char *name, int id, char *args, struct adsi_script *istate, char *script, int lineno)
++static int clearcbone(char *buf, char *name, int id, char *args, struct adsi_script *istate, const char *script, int lineno)
+ {
+ char *tok = get_token(&args, script, lineno);
+
+@@ -775,7 +775,7 @@
+ return 2;
+ }
+
+-static int digitcollect(char *buf, char *name, int id, char *args, struct adsi_script *istate, char *script, int lineno)
++static int digitcollect(char *buf, char *name, int id, char *args, struct adsi_script *istate, const char *script, int lineno)
+ {
+ char *tok = get_token(&args, script, lineno);
+
+@@ -787,7 +787,7 @@
+ return 2;
+ }
+
+-static int subscript(char *buf, char *name, int id, char *args, struct adsi_script *state, char *script, int lineno)
++static int subscript(char *buf, char *name, int id, char *args, struct adsi_script *state, const char *script, int lineno)
+ {
+ char *tok = get_token(&args, script, lineno);
+ char subscr[80];
+@@ -812,7 +812,7 @@
+ return 2;
+ }
+
+-static int onevent(char *buf, char *name, int id, char *args, struct adsi_script *state, char *script, int lineno)
++static int onevent(char *buf, char *name, int id, char *args, struct adsi_script *state, const char *script, int lineno)
+ {
+ char *tok = get_token(&args, script, lineno);
+ char subscr[80], sname[80];
+@@ -879,10 +879,10 @@
+ struct adsi_key_cmd {
+ char *name;
+ int id;
+- int (*add_args)(char *buf, char *name, int id, char *args, struct adsi_script *state, char *script, int lineno);
++ int (*add_args)(char *buf, char *name, int id, char *args, struct adsi_script *state, const char *script, int lineno);
+ };
+
+-static struct adsi_key_cmd kcmds[] = {
++static const struct adsi_key_cmd kcmds[] = {
+ { "SENDDTMF", 0, send_dtmf },
+ /* Encoded DTMF would go here */
+ { "ONHOOK", 0x81 },
+@@ -924,7 +924,7 @@
+ { "EXIT", 0xa0 },
+ };
+
+-static struct adsi_key_cmd opcmds[] = {
++static const struct adsi_key_cmd opcmds[] = {
+
+ /* 1 - Branch on event -- handled specially */
+ { "SHOWKEYS", 2, showkeys },
+@@ -944,7 +944,7 @@
+ };
+
+
+-static int process_returncode(struct adsi_soft_key *key, char *code, char *args, struct adsi_script *state, char *script, int lineno)
++static int process_returncode(struct adsi_soft_key *key, char *code, char *args, struct adsi_script *state, const char *script, int lineno)
+ {
+ int x, res;
+ char *unused;
+@@ -973,7 +973,7 @@
+ return -1;
+ }
+
+-static int process_opcode(struct adsi_subscript *sub, char *code, char *args, struct adsi_script *state, char *script, int lineno)
++static int process_opcode(struct adsi_subscript *sub, char *code, char *args, struct adsi_script *state, const char *script, int lineno)
+ {
+ int x, res, max = sub->id ? MAX_SUB_LEN : MAX_MAIN_LEN;
+ char *unused;
+@@ -1010,7 +1010,7 @@
+ return -1;
+ }
+
+-static int adsi_process(struct adsi_script *state, char *buf, char *script, int lineno)
++static int adsi_process(struct adsi_script *state, char *buf, const char *script, int lineno)
+ {
+ char *keyword = get_token(&buf, script, lineno);
+ char *args, vname[256], tmp[80], tmp2[80];
+@@ -1358,7 +1358,7 @@
+ return 0;
+ }
+
+-static struct adsi_script *compile_script(char *script)
++static struct adsi_script *compile_script(const char *script)
+ {
+ FILE *f;
+ char fn[256], buf[256], *c;
+@@ -1451,7 +1451,7 @@
+ }
+ #endif
+
+-static int adsi_prog(struct ast_channel *chan, char *script)
++static int adsi_prog(struct ast_channel *chan, const char *script)
+ {
+ struct adsi_script *scr;
+ int x, bytes;
+@@ -1562,7 +1562,7 @@
+ return 0;
+ }
+
+-static int adsi_exec(struct ast_channel *chan, void *data)
++static int adsi_exec(struct ast_channel *chan, const char *data)
+ {
+ int res = 0;
+
+Index: apps/app_read.c
+===================================================================
+--- a/apps/app_read.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/apps/app_read.c (.../trunk) (revision 202568)
+@@ -108,11 +108,11 @@
+ </application>
+ ***/
+
+-enum {
++enum read_option_flags {
+ OPT_SKIP = (1 << 0),
+ OPT_INDICATION = (1 << 1),
+ OPT_NOANSWER = (1 << 2),
+-} read_option_flags;
++};
+
+ AST_APP_OPTIONS(read_app_options, {
+ AST_APP_OPTION('s', OPT_SKIP),
+@@ -122,9 +122,7 @@
+
+ static char *app = "Read";
+
+-#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)
++static int read_exec(struct ast_channel *chan, const char *data)
+ {
+ int res = 0;
+ char tmp[256] = "";
+Index: apps/app_dictate.c
+===================================================================
+--- a/apps/app_dictate.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/apps/app_dictate.c (.../trunk) (revision 202568)
+@@ -55,7 +55,7 @@
+ </application>
+ ***/
+
+-static char *app = "Dictate";
++static const char app[] = "Dictate";
+
+ typedef enum {
+ DFLAG_RECORD = (1 << 0),
+@@ -81,7 +81,7 @@
+ return res;
+ }
+
+-static int dictate_exec(struct ast_channel *chan, void *data)
++static int dictate_exec(struct ast_channel *chan, const char *data)
+ {
+ char *path = NULL, filein[256], *filename = "";
+ char *parse;
+Index: apps/app_festival.c
+===================================================================
+--- a/apps/app_festival.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/apps/app_festival.c (.../trunk) (revision 202568)
+@@ -264,7 +264,7 @@
+ return res;
+ }
+
+-static int festival_exec(struct ast_channel *chan, void *vdata)
++static int festival_exec(struct ast_channel *chan, const char *vdata)
+ {
+ int usecache;
+ int res = 0;
+Index: apps/app_softhangup.c
+===================================================================
+--- a/apps/app_softhangup.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/apps/app_softhangup.c (.../trunk) (revision 202568)
+@@ -69,7 +69,7 @@
+ AST_APP_OPTION('a', OPTION_ALL),
+ });
+
+-static int softhangup_exec(struct ast_channel *chan, void *data)
++static int softhangup_exec(struct ast_channel *chan, const char *data)
+ {
+ struct ast_channel *c = NULL;
+ char *cut, *opts[0];
+@@ -80,6 +80,7 @@
+ AST_APP_ARG(channel);
+ AST_APP_ARG(options);
+ );
++ struct ast_channel_iterator *iter;
+
+ if (ast_strlen_zero(data)) {
+ ast_log(LOG_WARNING, "SoftHangup requires an argument (Technology/resource)\n");
+@@ -93,9 +94,12 @@
+ ast_app_parse_options(app_opts, &flags, opts, args.options);
+ lenmatch = strlen(args.channel);
+
+- for (c = ast_walk_channel_by_name_prefix_locked(NULL, args.channel, lenmatch);
+- c;
+- c = ast_walk_channel_by_name_prefix_locked(c, args.channel, lenmatch)) {
++ if (!(iter = ast_channel_iterator_by_name_new(0, args.channel, lenmatch))) {
++ return -1;
++ }
++
++ while ((c = ast_channel_iterator_next(iter))) {
++ ast_channel_lock(c);
+ ast_copy_string(name, c->name, sizeof(name));
+ if (ast_test_flag(&flags, OPTION_ALL)) {
+ /* CAPI is set up like CAPI[foo/bar]/clcnt */
+@@ -113,12 +117,16 @@
+ ast_softhangup(c, AST_SOFTHANGUP_EXPLICIT);
+ if (!ast_test_flag(&flags, OPTION_ALL)) {
+ ast_channel_unlock(c);
++ c = ast_channel_unref(c);
+ break;
+ }
+ }
+ ast_channel_unlock(c);
++ c = ast_channel_unref(c);
+ }
+
++ ast_channel_iterator_destroy(iter);
++
+ return 0;
+ }
+
+Index: apps/app_playtones.c
+===================================================================
+--- a/apps/app_playtones.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/apps/app_playtones.c (.../trunk) (revision 202568)
+@@ -72,7 +72,7 @@
+ </application>
+ ***/
+
+-static int handle_playtones(struct ast_channel *chan, void *data)
++static int handle_playtones(struct ast_channel *chan, const char *data)
+ {
+ struct ast_tone_zone_sound *ts;
+ int res;
+@@ -99,7 +99,7 @@
+ return res;
+ }
+
+-static int handle_stopplaytones(struct ast_channel *chan, void *data)
++static int handle_stopplaytones(struct ast_channel *chan, const char *data)
+ {
+ ast_playtones_stop(chan);
+
+Index: apps/app_alarmreceiver.c
+===================================================================
+--- a/apps/app_alarmreceiver.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/apps/app_alarmreceiver.c (.../trunk) (revision 202568)
+@@ -62,7 +62,7 @@
+
+ typedef struct event_node event_node_t;
+
+-static char *app = "AlarmReceiver";
++static const char app[] = "AlarmReceiver";
+ /*** DOCUMENTATION
+ <application name="AlarmReceiver" language="en_US">
+ <synopsis>
+@@ -416,7 +416,7 @@
+ *
+ * The function will return 0 when the caller hangs up, else a -1 if there was a problem.
+ */
+-static int receive_ademco_contact_id( struct ast_channel *chan, void *data, int fdto, int sdto, int tldn, event_node_t **ehead)
++static int receive_ademco_contact_id(struct ast_channel *chan, const void *data, int fdto, int sdto, int tldn, event_node_t **ehead)
+ {
+ int i, j;
+ int res = 0;
+@@ -564,7 +564,7 @@
+ * This is the main function called by Asterisk Core whenever the App is invoked in the extension logic.
+ * This function will always return 0.
+ */
+-static int alarmreceiver_exec(struct ast_channel *chan, void *data)
++static int alarmreceiver_exec(struct ast_channel *chan, const char *data)
+ {
+ int res = 0;
+ event_node_t *elp, *efree;
+Index: apps/app_image.c
+===================================================================
+--- a/apps/app_image.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/apps/app_image.c (.../trunk) (revision 202568)
+@@ -69,7 +69,7 @@
+ </application>
+ ***/
+
+-static int sendimage_exec(struct ast_channel *chan, void *data)
++static int sendimage_exec(struct ast_channel *chan, const char *data)
+ {
+
+ if (ast_strlen_zero(data)) {
+Index: apps/app_getcpeid.c
+===================================================================
+--- a/apps/app_getcpeid.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/apps/app_getcpeid.c (.../trunk) (revision 202568)
+@@ -61,7 +61,7 @@
+ return ast_adsi_print(chan, tmp, justify, voice);
+ }
+
+-static int cpeid_exec(struct ast_channel *chan, void *idata)
++static int cpeid_exec(struct ast_channel *chan, const char *idata)
+ {
+ int res=0;
+ unsigned char cpeid[4];
+Index: apps/app_talkdetect.c
+===================================================================
+--- a/apps/app_talkdetect.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/apps/app_talkdetect.c (.../trunk) (revision 202568)
+@@ -73,7 +73,7 @@
+
+ static char *app = "BackgroundDetect";
+
+-static int background_detect_exec(struct ast_channel *chan, void *data)
++static int background_detect_exec(struct ast_channel *chan, const char *data)
+ {
+ int res = 0;
+ char *tmp;
+Index: apps/app_db.c
+===================================================================
+--- a/apps/app_db.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/apps/app_db.c (.../trunk) (revision 202568)
+@@ -79,11 +79,10 @@
+ </application>
+ ***/
+
+-/*! \todo XXX Remove this application after 1.4 is relased */
+-static char *d_app = "DBdel";
+-static char *dt_app = "DBdeltree";
++static const char d_app[] = "DBdel";
++static const char dt_app[] = "DBdeltree";
+
+-static int deltree_exec(struct ast_channel *chan, void *data)
++static int deltree_exec(struct ast_channel *chan, const char *data)
+ {
+ char *argv, *family, *keytree;
+
+@@ -114,7 +113,7 @@
+ return 0;
+ }
+
+-static int del_exec(struct ast_channel *chan, void *data)
++static int del_exec(struct ast_channel *chan, const char *data)
+ {
+ char *argv, *family, *key;
+ static int deprecation_warning = 0;
+Index: apps/app_controlplayback.c
+===================================================================
+--- a/apps/app_controlplayback.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/apps/app_controlplayback.c (.../trunk) (revision 202568)
+@@ -92,7 +92,7 @@
+ </description>
+ </application>
+ ***/
+-static const char *app = "ControlPlayback";
++static const char app[] = "ControlPlayback";
+
+ enum {
+ OPT_OFFSET = (1 << 1),
+@@ -125,7 +125,7 @@
+ return 0;
+ }
+
+-static int controlplayback_exec(struct ast_channel *chan, void *data)
++static int controlplayback_exec(struct ast_channel *chan, const char *data)
+ {
+ int res = 0;
+ int skipms = 0;
+Index: apps/app_setcallerid.c
+===================================================================
+--- a/apps/app_setcallerid.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/apps/app_setcallerid.c (.../trunk) (revision 202568)
+@@ -84,7 +84,7 @@
+
+ static char *app2 = "SetCallerPres";
+
+-static int setcallerid_pres_exec(struct ast_channel *chan, void *data)
++static int setcallerid_pres_exec(struct ast_channel *chan, const char *data)
+ {
+ int pres = -1;
+ static int deprecated = 0;
+Index: apps/Makefile
+===================================================================
+--- a/apps/Makefile (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/apps/Makefile (.../trunk) (revision 202568)
+@@ -18,11 +18,9 @@
+ MENUSELECT_OPTS_app_directory:=$(MENUSELECT_OPTS_app_voicemail)
+ ifneq ($(findstring ODBC_STORAGE,$(MENUSELECT_OPTS_app_voicemail)),)
+ MENUSELECT_DEPENDS_app_voicemail+=$(MENUSELECT_DEPENDS_ODBC_STORAGE)
+- MENUSELECT_DEPENDS_app_directory+=$(MENUSELECT_DEPENDS_ODBC_STORAGE)
+ endif
+ ifneq ($(findstring IMAP_STORAGE,$(MENUSELECT_OPTS_app_voicemail)),)
+ MENUSELECT_DEPENDS_app_voicemail+=$(MENUSELECT_DEPENDS_IMAP_STORAGE)
+- MENUSELECT_DEPENDS_app_directory+=$(MENUSELECT_DEPENDS_IMAP_STORAGE)
+ endif
+
+ all: _all
+Index: apps/app_mp3.c
+===================================================================
+--- a/apps/app_mp3.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/apps/app_mp3.c (.../trunk) (revision 202568)
+@@ -64,7 +64,7 @@
+ ***/
+ static char *app = "MP3Player";
+
+-static int mp3play(char *filename, int fd)
++static int mp3play(const char *filename, int fd)
+ {
+ int res;
+
+@@ -117,7 +117,7 @@
+
+ }
+
+-static int mp3_exec(struct ast_channel *chan, void *data)
++static int mp3_exec(struct ast_channel *chan, const char *data)
+ {
+ int res=0;
+ int fds[2];
+@@ -152,8 +152,8 @@
+ return -1;
+ }
+
+- res = mp3play((char *)data, fds[1]);
+- if (!strncasecmp((char *)data, "http://", 7)) {
++ res = mp3play(data, fds[1]);
++ if (!strncasecmp(data, "http://", 7)) {
+ timeout = 10000;
+ }
+ /* Wait 1000 ms first */
+Index: apps/app_zapateller.c
+===================================================================
+--- a/apps/app_zapateller.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/apps/app_zapateller.c (.../trunk) (revision 202568)
+@@ -74,7 +74,7 @@
+
+ static char *app = "Zapateller";
+
+-static int zapateller_exec(struct ast_channel *chan, void *data)
++static int zapateller_exec(struct ast_channel *chan, const char *data)
+ {
+ int res = 0;
+ int i, answer = 0, nocallerid = 0;
+Index: apps/app_senddtmf.c
+===================================================================
+--- a/apps/app_senddtmf.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/apps/app_senddtmf.c (.../trunk) (revision 202568)
+@@ -59,10 +59,27 @@
+ <ref type="application">Read</ref>
+ </see-also>
+ </application>
++ <manager name="PlayDTMF" language="en_US">
++ <synopsis>
++ Play DTMF signal on a specific channel.
++ </synopsis>
++ <syntax>
++ <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
++ <parameter name="Channel" required="true">
++ <para>Channel name to send digit to.</para>
++ </parameter>
++ <parameter name="Digit" required="true">
++ <para>The DTMF digit to play.</para>
++ </parameter>
++ </syntax>
++ <description>
++ <para>Plays a dtmf digit on the specified channel.</para>
++ </description>
++ </manager>
+ ***/
+ static char *app = "SendDTMF";
+
+-static int senddtmf_exec(struct ast_channel *chan, void *vdata)
++static int senddtmf_exec(struct ast_channel *chan, const char *vdata)
+ {
+ int res = 0;
+ char *data;
+@@ -90,33 +107,29 @@
+ return res;
+ }
+
+-static char mandescr_playdtmf[] =
+-"Description: Plays a dtmf digit on the specified channel.\n"
+-"Variables: (all are required)\n"
+-" Channel: Channel name to send digit to\n"
+-" Digit: The dtmf digit to play\n";
+-
+ static int manager_play_dtmf(struct mansession *s, const struct message *m)
+ {
+ const char *channel = astman_get_header(m, "Channel");
+ const char *digit = astman_get_header(m, "Digit");
+- struct ast_channel *chan = ast_get_channel_by_name_locked(channel);
+-
+- if (!chan) {
+- astman_send_error(s, m, "Channel not specified");
++ struct ast_channel *chan;
++
++ if (!(chan = ast_channel_get_by_name(channel))) {
++ astman_send_error(s, m, "Channel not found");
+ return 0;
+ }
++
+ if (ast_strlen_zero(digit)) {
+ astman_send_error(s, m, "No digit specified");
+- ast_channel_unlock(chan);
++ chan = ast_channel_unref(chan);
+ return 0;
+ }
+
+ ast_senddigit(chan, *digit, 0);
+
+- ast_channel_unlock(chan);
++ chan = ast_channel_unref(chan);
++
+ astman_send_ack(s, m, "DTMF successfully queued");
+-
++
+ return 0;
+ }
+
+@@ -134,7 +147,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_manager_register_xml("PlayDTMF", EVENT_FLAG_CALL, manager_play_dtmf);
+ res |= ast_register_application_xml(app, senddtmf_exec);
+
+ return res;
+Index: apps/app_rpt.c
+===================================================================
+--- a/apps/app_rpt.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/apps/app_rpt.c (.../trunk) (revision 202568)
+@@ -439,7 +439,7 @@
+ static int debug = 0; /* Set this >0 for extra debug output */
+ static int nrpts = 0;
+
+-static char remdtmfstr[] = "0123456789*#ABCD";
++static const char remdtmfstr[] = "0123456789*#ABCD";
+
+ enum {TOP_TOP,TOP_WON,WON_BEFREAD,BEFREAD_AFTERREAD};
+
+@@ -1957,7 +1957,11 @@
+ if (!myrpt->p.statpost_url) return;
+ str = ast_malloc(strlen(pairs) + strlen(myrpt->p.statpost_url) + 200);
+ astr = ast_strdup(myrpt->p.statpost_program);
+- if ((!str) || (!astr)) return;
++ if ((!str) || (!astr)) {
++ ast_free(str);
++ ast_free(astr);
++ return;
++ }
+ n = finddelim(astr,astrs,100);
+ if (n < 1) return;
+ ast_mutex_lock(&myrpt->statpost_lock);
+@@ -2895,12 +2899,8 @@
+ for(j = 0; j < numoflinks; j++){ /* ast_free() all link names */
+ ast_free(listoflinks[j]);
+ }
+- if(called_number){
+- ast_free(called_number);
+- }
+- if(lastdtmfcommand){
+- ast_free(lastdtmfcommand);
+- }
++ ast_free(called_number);
++ ast_free(lastdtmfcommand);
+ return RESULT_SUCCESS;
+ }
+ }
+@@ -3646,8 +3646,7 @@
+ if(res)
+ break;
+ }
+- if(p)
+- ast_free(p);
++ ast_free(p);
+ if(!res)
+ res = play_tone_pair(chan, 0, 0, 100, 0); /* This is needed to ensure the last tone segment is timed correctly */
+
+@@ -3828,8 +3827,7 @@
+ else{
+ res = -1;
+ }
+- if(telemetry_save)
+- ast_free(telemetry_save);
++ ast_free(telemetry_save);
+ return res;
+ }
+
+@@ -3907,8 +3905,7 @@
+ interval = 0;
+ break;
+ }
+- if(wait_times_save)
+- ast_free(wait_times_save);
++ ast_free(wait_times_save);
+ return interval;
+ }
+
+@@ -3940,7 +3937,7 @@
+ struct rpt *myrpt;
+ struct rpt_link *l,*l1,linkbase;
+ struct ast_channel *mychannel;
+-int id_malloc, vmajor, vminor, m;
++int vmajor, vminor, m;
+ char *p,*ct,*ct_copy,*ident, *nodename,*cp;
+ time_t t;
+ #ifdef NEW_ASTERISK
+@@ -3987,14 +3984,10 @@
+ ast_free(mytele);
+ pthread_exit(NULL);
+ }
+- else{
+- id_malloc = 1;
+- }
+ }
+ else
+ {
+ ident = "";
+- id_malloc = 0;
+ }
+ rpt_mutex_unlock(&myrpt->lock);
+
+@@ -4010,8 +4003,7 @@
+ ast_log(LOG_NOTICE,"Telemetry thread aborted at line %d, mode: %d\n",__LINE__, mytele->mode); /*@@@@@@@@@@@*/
+ rpt_mutex_unlock(&myrpt->lock);
+ ast_free(nodename);
+- if(id_malloc)
+- ast_free(ident);
++ ast_free(ident);
+ ast_free(mytele);
+ pthread_exit(NULL);
+ }
+@@ -4057,8 +4049,7 @@
+ rpt_mutex_unlock(&myrpt->lock);
+ ast_log(LOG_NOTICE,"Telemetry thread aborted at line %d, mode: %d\n",__LINE__, mytele->mode); /*@@@@@@@@@@@*/
+ ast_free(nodename);
+- if(id_malloc)
+- ast_free(ident);
++ ast_free(ident);
+ ast_free(mytele);
+ ast_hangup(mychannel);
+ pthread_exit(NULL);
+@@ -4252,8 +4243,7 @@
+ rpt_mutex_unlock(&myrpt->lock);
+ ast_log(LOG_NOTICE,"Telemetry thread aborted at line %d, mode: %d\n",__LINE__, mytele->mode); /*@@@@@@@@@@@*/
+ ast_free(nodename);
+- if(id_malloc)
+- ast_free(ident);
++ ast_free(ident);
+ ast_free(mytele);
+ ast_hangup(mychannel);
+ pthread_exit(NULL);
+@@ -4293,8 +4283,7 @@
+ rpt_mutex_unlock(&myrpt->lock);
+ ast_log(LOG_NOTICE,"Telemetry thread aborted at line %d, mode: %d\n",__LINE__, mytele->mode); /*@@@@@@@@@@@*/
+ ast_free(nodename);
+- if(id_malloc)
+- ast_free(ident);
++ ast_free(ident);
+ ast_free(mytele);
+ ast_hangup(mychannel);
+ pthread_exit(NULL);
+@@ -4816,8 +4805,7 @@
+ rpt_mutex_unlock(&myrpt->lock);
+ ast_log(LOG_NOTICE,"Telemetry thread aborted at line %d, mode: %d\n",__LINE__, mytele->mode); /*@@@@@@@@@@@*/
+ ast_free(nodename);
+- if(id_malloc)
+- ast_free(ident);
++ ast_free(ident);
+ ast_free(mytele);
+ ast_hangup(mychannel);
+ pthread_exit(NULL);
+@@ -5193,8 +5181,7 @@
+ myrpt->active_telem = NULL;
+ rpt_mutex_unlock(&myrpt->lock);
+ ast_free(nodename);
+- if(id_malloc)
+- ast_free(ident);
++ ast_free(ident);
+ ast_free(mytele);
+ ast_hangup(mychannel);
+ #ifdef APP_RPT_LOCK_DEBUG
+@@ -13114,7 +13101,7 @@
+ pthread_exit(NULL);
+ }
+
+-static int rpt_exec(struct ast_channel *chan, void *data)
++static int rpt_exec(struct ast_channel *chan, const void *data)
+ {
+ int res=-1,i,rem_totx,rem_rx,remkeyed,n,phone_mode = 0;
+ int iskenwood_pci4,authtold,authreq,setting,notremming,reming;
+Index: apps/app_mixmonitor.c
+===================================================================
+--- a/apps/app_mixmonitor.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/apps/app_mixmonitor.c (.../trunk) (revision 202568)
+@@ -45,11 +45,13 @@
+ #include "asterisk/cli.h"
+ #include "asterisk/app.h"
+ #include "asterisk/channel.h"
++#include "asterisk/autochan.h"
+
+ /*** DOCUMENTATION
+ <application name="MixMonitor" language="en_US">
+ <synopsis>
+- Record a call and mix the audio during the recording.
++ Record a call and mix the audio during the recording. Use of StopMixMonitor is required
++ to guarantee the audio file is available for processing during dialplan execution.
+ </synopsis>
+ <syntax>
+ <parameter name="file" required="true" argsep=".">
+@@ -111,7 +113,7 @@
+ </application>
+ <application name="StopMixMonitor" language="en_US">
+ <synopsis>
+- Stop recording a call through MixMonitor.
++ Stop recording a call through MixMonitor, and free the recording's file handle.
+ </synopsis>
+ <syntax />
+ <description>
+@@ -127,37 +129,36 @@
+
+ #define get_volfactor(x) x ? ((x > 0) ? (1 << x) : ((1 << abs(x)) * -1)) : 0
+
+-static const char *app = "MixMonitor";
++static const char * const app = "MixMonitor";
+
+-static const char *stop_app = "StopMixMonitor";
++static const char * const stop_app = "StopMixMonitor";
+
+-struct module_symbols *me;
++static const char * const mixmonitor_spy_type = "MixMonitor";
+
+-static const char *mixmonitor_spy_type = "MixMonitor";
+-
+ struct mixmonitor {
+ struct ast_audiohook audiohook;
+ char *filename;
+ char *post_process;
+ char *name;
+ unsigned int flags;
++ struct ast_autochan *autochan;
+ struct mixmonitor_ds *mixmonitor_ds;
+ };
+
+-enum {
++enum mixmonitor_flags {
+ MUXFLAG_APPEND = (1 << 1),
+ MUXFLAG_BRIDGED = (1 << 2),
+ MUXFLAG_VOLUME = (1 << 3),
+ MUXFLAG_READVOLUME = (1 << 4),
+ MUXFLAG_WRITEVOLUME = (1 << 5),
+-} mixmonitor_flags;
++};
+
+-enum {
++enum mixmonitor_args {
+ OPT_ARG_READVOLUME = 0,
+ OPT_ARG_WRITEVOLUME,
+ OPT_ARG_VOLUME,
+ OPT_ARG_ARRAY_SIZE,
+-} mixmonitor_args;
++};
+
+ AST_APP_OPTIONS(mixmonitor_opts, {
+ AST_APP_OPTION('a', MUXFLAG_APPEND),
+@@ -167,48 +168,43 @@
+ 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;
++
++ /* The filestream is held in the datastore so it can be stopped
++ * immediately during stop_mixmonitor or channel destruction. */
++ int fs_quit;
++ struct ast_filestream *fs;
++
+ };
+
+-static void mixmonitor_ds_destroy(void *data)
++static void mixmonitor_ds_close_fs(struct mixmonitor_ds *mixmonitor_ds)
+ {
+- 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);
++ if (mixmonitor_ds->fs) {
++ ast_closestream(mixmonitor_ds->fs);
++ mixmonitor_ds->fs = NULL;
++ mixmonitor_ds->fs_quit = 1;
++ ast_verb(2, "MixMonitor close filestream\n");
++ }
+ ast_mutex_unlock(&mixmonitor_ds->lock);
+ }
+
+-static void mixmonitor_ds_chan_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan)
++static void mixmonitor_ds_destroy(void *data)
+ {
+ struct mixmonitor_ds *mixmonitor_ds = data;
+
+ ast_mutex_lock(&mixmonitor_ds->lock);
+- mixmonitor_ds->chan = new_chan;
++ mixmonitor_ds->destruction_ok = 1;
++ ast_cond_signal(&mixmonitor_ds->destruction_condition);
+ 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)
+@@ -229,19 +225,32 @@
+
+ #define SAMPLES_PER_FRAME 160
+
++static void mixmonitor_free(struct mixmonitor *mixmonitor)
++{
++ if (mixmonitor) {
++ if (mixmonitor->mixmonitor_ds) {
++ ast_mutex_destroy(&mixmonitor->mixmonitor_ds->lock);
++ ast_cond_destroy(&mixmonitor->mixmonitor_ds->destruction_condition);
++ ast_free(mixmonitor->mixmonitor_ds);
++ }
++ ast_free(mixmonitor);
++ }
++}
+ static void *mixmonitor_thread(void *obj)
+ {
+ struct mixmonitor *mixmonitor = obj;
+- struct ast_filestream *fs = NULL;
++ struct ast_filestream **fs = NULL;
+ unsigned int oflags;
+ char *ext;
+ int errflag = 0;
+
+ ast_verb(2, "Begin MixMonitor Recording %s\n", mixmonitor->name);
+-
++
+ ast_audiohook_lock(&mixmonitor->audiohook);
+
+- while (mixmonitor->audiohook.status == AST_AUDIOHOOK_STATUS_RUNNING) {
++ fs = &mixmonitor->mixmonitor_ds->fs;
++
++ while (mixmonitor->audiohook.status == AST_AUDIOHOOK_STATUS_RUNNING && !mixmonitor->mixmonitor_ds->fs_quit) {
+ struct ast_frame *fr = NULL;
+
+ ast_audiohook_trigger_wait(&mixmonitor->audiohook);
+@@ -252,32 +261,34 @@
+ if (!(fr = ast_audiohook_read_frame(&mixmonitor->audiohook, SAMPLES_PER_FRAME, AST_AUDIOHOOK_DIRECTION_BOTH, AST_FORMAT_SLINEAR)))
+ continue;
+
+- 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);
++ if (!ast_test_flag(mixmonitor, MUXFLAG_BRIDGED) || (mixmonitor->autochan->chan && ast_bridged_channel(mixmonitor->autochan->chan))) {
++ ast_mutex_lock(&mixmonitor->mixmonitor_ds->lock);
+ /* Initialize the file if not already done so */
+- if (!fs && !errflag) {
++ if (!*fs && !errflag && !mixmonitor->mixmonitor_ds->fs_quit) {
+ oflags = O_CREAT | O_WRONLY;
+ oflags |= ast_test_flag(mixmonitor, MUXFLAG_APPEND) ? O_APPEND : O_TRUNC;
+-
++
+ if ((ext = strrchr(mixmonitor->filename, '.')))
+ *(ext++) = '\0';
+ else
+ ext = "raw";
+-
+- if (!(fs = ast_writefile(mixmonitor->filename, ext, NULL, oflags, 0, 0666))) {
++
++ if (!(*fs = ast_writefile(mixmonitor->filename, ext, NULL, oflags, 0, 0666))) {
+ ast_log(LOG_ERROR, "Cannot open %s.%s\n", mixmonitor->filename, ext);
+ errflag = 1;
+ }
+ }
+-
+- /* Write out frame */
+- if (fs)
+- ast_writestream(fs, fr);
+- } else {
++
++ /* Write out the frame(s) */
++ if (*fs) {
++ struct ast_frame *cur;
++
++ for (cur = fr; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
++ ast_writestream(*fs, cur);
++ }
++ }
+ ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock);
+ }
+-
+ /* All done! free it. */
+ ast_frame_free(fr, 0);
+
+@@ -287,26 +298,25 @@
+ ast_audiohook_unlock(&mixmonitor->audiohook);
+ ast_audiohook_destroy(&mixmonitor->audiohook);
+
+- ast_verb(2, "End MixMonitor Recording %s\n", mixmonitor->name);
++ mixmonitor_ds_close_fs(mixmonitor->mixmonitor_ds);
+
+- if (fs)
+- ast_closestream(fs);
+
+ if (mixmonitor->post_process) {
+ ast_verb(2, "Executing [%s]\n", mixmonitor->post_process);
+ ast_safe_system(mixmonitor->post_process);
+ }
+
++ ast_autochan_destroy(mixmonitor->autochan);
++
+ 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);
+
++
++ ast_verb(2, "End MixMonitor Recording %s\n", mixmonitor->name);
++ mixmonitor_free(mixmonitor);
+ return NULL;
+ }
+
+@@ -318,17 +328,17 @@
+ 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_mutex_destroy(&mixmonitor_ds->lock);
++ ast_cond_destroy(&mixmonitor_ds->destruction_condition);
+ 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);
+@@ -372,7 +382,14 @@
+
+ /* Copy over flags and channel name */
+ mixmonitor->flags = flags;
++ if (!(mixmonitor->autochan = ast_autochan_setup(chan))) {
++ mixmonitor_free(mixmonitor);
++ return;
++ }
++
+ if (setup_mixmonitor_ds(mixmonitor, chan)) {
++ ast_autochan_destroy(mixmonitor->autochan);
++ mixmonitor_free(mixmonitor);
+ return;
+ }
+ mixmonitor->name = (char *) mixmonitor + sizeof(*mixmonitor);
+@@ -409,7 +426,7 @@
+ ast_pthread_create_detached_background(&thread, NULL, mixmonitor_thread, mixmonitor);
+ }
+
+-static int mixmonitor_exec(struct ast_channel *chan, void *data)
++static int mixmonitor_exec(struct ast_channel *chan, const char *data)
+ {
+ int x, readvol = 0, writevol = 0;
+ struct ast_flags flags = {0};
+@@ -490,8 +507,16 @@
+ return 0;
+ }
+
+-static int stop_mixmonitor_exec(struct ast_channel *chan, void *data)
++static int stop_mixmonitor_exec(struct ast_channel *chan, const char *data)
+ {
++ struct ast_datastore *datastore = NULL;
++
++ /* closing the filestream here guarantees the file is avaliable to the dialplan
++ * after calling StopMixMonitor */
++ if ((datastore = ast_channel_datastore_find(chan, &mixmonitor_ds_info, NULL))) {
++ mixmonitor_ds_close_fs(datastore->data);
++ }
++
+ ast_audiohook_detach_source(chan, mixmonitor_spy_type);
+ return 0;
+ }
+@@ -515,12 +540,14 @@
+ if (a->argc < 3)
+ return CLI_SHOWUSAGE;
+
+- if (!(chan = ast_get_channel_by_name_prefix_locked(a->argv[2], strlen(a->argv[2])))) {
++ if (!(chan = ast_channel_get_by_name_prefix(a->argv[2], strlen(a->argv[2])))) {
+ ast_cli(a->fd, "No channel matching '%s' found.\n", a->argv[2]);
+ /* Technically this is a failure, but we don't want 2 errors printing out */
+ return CLI_SUCCESS;
+ }
+
++ ast_channel_lock(chan);
++
+ if (!strcasecmp(a->argv[1], "start")) {
+ mixmonitor_exec(chan, a->argv[3]);
+ ast_channel_unlock(chan);
+@@ -529,6 +556,8 @@
+ ast_audiohook_detach_source(chan, mixmonitor_spy_type);
+ }
+
++ chan = ast_channel_unref(chan);
++
+ return CLI_SUCCESS;
+ }
+
+Index: apps/app_ivrdemo.c
+===================================================================
+--- a/apps/app_ivrdemo.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/apps/app_ivrdemo.c (.../trunk) (revision 202568)
+@@ -59,7 +59,7 @@
+
+ static int ivr_demo_func(struct ast_channel *chan, void *data)
+ {
+- ast_verbose("IVR Demo, data is %s!\n", (char *)data);
++ ast_verbose("IVR Demo, data is %s!\n", (char *) data);
+ return 0;
+ }
+
+@@ -93,22 +93,24 @@
+ { NULL },
+ });
+
+-
+-static int skel_exec(struct ast_channel *chan, void *data)
++static int skel_exec(struct ast_channel *chan, const char *data)
+ {
+ int res=0;
++ char *tmp;
+
+ if (ast_strlen_zero(data)) {
+ ast_log(LOG_WARNING, "skel requires an argument (filename)\n");
+ return -1;
+ }
+
++ tmp = ast_strdupa(data);
++
+ /* Do our thing here */
+
+ if (chan->_state != AST_STATE_UP)
+ res = ast_answer(chan);
+ if (!res)
+- res = ast_ivr_menu_run(chan, &ivr_demo, data);
++ res = ast_ivr_menu_run(chan, &ivr_demo, tmp);
+
+ return res;
+ }
+Index: apps/app_milliwatt.c
+===================================================================
+--- a/apps/app_milliwatt.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/apps/app_milliwatt.c (.../trunk) (revision 202568)
+@@ -55,9 +55,9 @@
+ </application>
+ ***/
+
+-static char *app = "Milliwatt";
++static const char app[] = "Milliwatt";
+
+-static char digital_milliwatt[] = {0x1e,0x0b,0x0b,0x1e,0x9e,0x8b,0x8b,0x9e} ;
++static const char digital_milliwatt[] = {0x1e,0x0b,0x0b,0x1e,0x9e,0x8b,0x8b,0x9e} ;
+
+ static void *milliwatt_alloc(struct ast_channel *chan, void *params)
+ {
+@@ -139,7 +139,7 @@
+ return -1;
+ }
+
+-static int milliwatt_exec(struct ast_channel *chan, void *data)
++static int milliwatt_exec(struct ast_channel *chan, const char *data)
+ {
+ const char *options = data;
+ struct ast_app *playtones_app;
+Index: apps/app_parkandannounce.c
+===================================================================
+--- a/apps/app_parkandannounce.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/apps/app_parkandannounce.c (.../trunk) (revision 202568)
+@@ -85,7 +85,7 @@
+
+ static char *app = "ParkAndAnnounce";
+
+-static int parkandannounce_exec(struct ast_channel *chan, void *data)
++static int parkandannounce_exec(struct ast_channel *chan, const char *data)
+ {
+ int res = -1;
+ int lot, timeout = 0, dres;
+Index: apps/app_readfile.c
+===================================================================
+--- a/apps/app_readfile.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/apps/app_readfile.c (.../trunk) (revision 202568)
+@@ -67,7 +67,7 @@
+
+ static char *app_readfile = "ReadFile";
+
+-static int readfile_exec(struct ast_channel *chan, void *data)
++static int readfile_exec(struct ast_channel *chan, const char *data)
+ {
+ int res=0;
+ char *s, *varname=NULL, *file=NULL, *length=NULL, *returnvar=NULL;
+Index: apps/app_meetme.c
+===================================================================
+--- a/apps/app_meetme.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/apps/app_meetme.c (.../trunk) (revision 202568)
+@@ -420,6 +420,80 @@
+ </variablelist>
+ </description>
+ </application>
++ <function name="MEETME_INFO" language="en_US">
++ <synopsis>
++ Query a given conference of various properties.
++ </synopsis>
++ <syntax>
++ <parameter name="keyword" required="true">
++ <para>Options:</para>
++ <enumlist>
++ <enum name="lock">
++ <para>Boolean of whether the corresponding conference is locked.</para>
++ </enum>
++ <enum name="parties">
++ <para>Number of parties in a given conference</para>
++ </enum>
++ <enum name="activity">
++ <para>Duration of conference in seconds.</para>
++ </enum>
++ <enum name="dynamic">
++ <para>Boolean of whether the corresponding conference is dynamic.</para>
++ </enum>
++ </enumlist>
++ </parameter>
++ <parameter name="confno" required="true">
++ <para>Conference number to retrieve information from.</para>
++ </parameter>
++ </syntax>
++ <description />
++ <see-also>
++ <ref type="application">MeetMe</ref>
++ <ref type="application">MeetMeCount</ref>
++ <ref type="application">MeetMeAdmin</ref>
++ <ref type="application">MeetMeChannelAdmin</ref>
++ </see-also>
++ </function>
++ <manager name="MeetmeMute" language="en_US">
++ <synopsis>
++ Mute a Meetme user.
++ </synopsis>
++ <syntax>
++ <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
++ <parameter name="Meetme" required="true" />
++ <parameter name="Usernum" required="true" />
++ </syntax>
++ <description>
++ </description>
++ </manager>
++ <manager name="MeetmeUnmute" language="en_US">
++ <synopsis>
++ Unmute a Meetme user.
++ </synopsis>
++ <syntax>
++ <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
++ <parameter name="Meetme" required="true" />
++ <parameter name="Usernum" required="true" />
++ </syntax>
++ <description>
++ </description>
++ </manager>
++ <manager name="MeetmeList" language="en_US">
++ <synopsis>
++ List participants in a conference.
++ </synopsis>
++ <syntax>
++ <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
++ <parameter name="Conference" required="true">
++ <para>Conference number.</para>
++ </parameter>
++ </syntax>
++ <description>
++ <para>Lists all users in a particular MeetMe conference.
++ MeetmeList will follow as separate events, followed by a final event called
++ MeetmeListComplete.</para>
++ </description>
++ </manager>
+ ***/
+
+ #define CONFIG_FILE_NAME "meetme.conf"
+@@ -565,12 +639,12 @@
+ AST_APP_OPTION_ARG('L', CONFFLAG_DURATION_LIMIT, OPT_ARG_DURATION_LIMIT),
+ END_OPTIONS );
+
+-static const char *app = "MeetMe";
+-static const char *app2 = "MeetMeCount";
+-static const char *app3 = "MeetMeAdmin";
+-static const char *app4 = "MeetMeChannelAdmin";
+-static const char *slastation_app = "SLAStation";
+-static const char *slatrunk_app = "SLATrunk";
++static const char * const app = "MeetMe";
++static const char * const app2 = "MeetMeCount";
++static const char * const app3 = "MeetMeAdmin";
++static const char * const app4 = "MeetMeChannelAdmin";
++static const char * const slastation_app = "SLAStation";
++static const char * const slatrunk_app = "SLATrunk";
+
+ /* Lookup RealTime conferences based on confno and current time */
+ static int rt_schedule;
+@@ -861,7 +935,7 @@
+ * conversion... the numbers have been modified
+ * to give the user a better level of adjustability
+ */
+-static char const gain_map[] = {
++static const char gain_map[] = {
+ -15,
+ -13,
+ -10,
+@@ -876,7 +950,7 @@
+ };
+
+
+-static int admin_exec(struct ast_channel *chan, void *data);
++static int admin_exec(struct ast_channel *chan, const char *data);
+ static void *recordthread(void *args);
+
+ static char *istalking(int x)
+@@ -1144,7 +1218,7 @@
+
+ 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};
++ static const char * const cmds[] = {"concise", "lock", "unlock", "mute", "unmute", "kick", "list", NULL};
+
+ int len = strlen(word);
+ int which = 0;
+@@ -3195,9 +3269,18 @@
+ }
+ }
+ if (conf->transframe[idx]) {
+- if (conf->transframe[idx]->frametype != AST_FRAME_NULL) {
+- 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);
++ if ((conf->transframe[idx]->frametype != AST_FRAME_NULL) &&
++ can_write(chan, confflags)) {
++ struct ast_frame *cur;
++
++ /* the translator may have returned a list of frames, so
++ write each one onto the channel
++ */
++ for (cur = conf->transframe[idx]; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
++ if (ast_write(chan, cur)) {
++ ast_log(LOG_WARNING, "Unable to write frame to channel %s\n", chan->name);
++ break;
++ }
+ }
+ }
+ } else {
+@@ -3600,7 +3683,7 @@
+ }
+
+ /*! \brief The MeetmeCount application */
+-static int count_exec(struct ast_channel *chan, void *data)
++static int count_exec(struct ast_channel *chan, const char *data)
+ {
+ int res = 0;
+ struct ast_conference *conf;
+@@ -3646,7 +3729,7 @@
+ }
+
+ /*! \brief The meetme() application */
+-static int conf_exec(struct ast_channel *chan, void *data)
++static int conf_exec(struct ast_channel *chan, const char *data)
+ {
+ int res = -1;
+ char confno[MAX_CONFNUM] = "";
+@@ -3657,7 +3740,8 @@
+ int dynamic = 0;
+ int empty = 0, empty_no_pin = 0;
+ int always_prompt = 0;
+- char *notdata, *info, the_pin[MAX_PIN] = "";
++ const char *notdata;
++ char *info, the_pin[MAX_PIN] = "";
+ AST_DECLARE_APP_ARGS(args,
+ AST_APP_ARG(confno);
+ AST_APP_ARG(options);
+@@ -3920,7 +4004,7 @@
+
+ /*! \brief The MeetMeadmin application */
+ /* MeetMeAdmin(confno, command, caller) */
+-static int admin_exec(struct ast_channel *chan, void *data) {
++static int admin_exec(struct ast_channel *chan, const char *data) {
+ char *params;
+ struct ast_conference *cnf;
+ struct ast_conf_user *user = NULL;
+@@ -4102,7 +4186,7 @@
+
+ /*--- channel_admin_exec: The MeetMeChannelAdmin application */
+ /* MeetMeChannelAdmin(channel, command) */
+-static int channel_admin_exec(struct ast_channel *chan, void *data) {
++static int channel_admin_exec(struct ast_channel *chan, const char *data) {
+ char *params;
+ struct ast_conference *conf = NULL;
+ struct ast_conf_user *user = NULL;
+@@ -4235,14 +4319,6 @@
+ return meetmemute(s, m, 0);
+ }
+
+-static char mandescr_meetmelist[] =
+-"Description: Lists all users in a particular MeetMe conference.\n"
+-"MeetmeList will follow as separate events, followed by a final event called\n"
+-"MeetmeListComplete.\n"
+-"Variables:\n"
+-" *ActionId: <id>\n"
+-" *Conference: <confno>\n";
+-
+ static int action_meetmelist(struct mansession *s, const struct message *m)
+ {
+ const char *actionid = astman_get_header(m, "ActionID");
+@@ -5552,7 +5628,7 @@
+ return trunk_ref;
+ }
+
+-static int sla_station_exec(struct ast_channel *chan, void *data)
++static int sla_station_exec(struct ast_channel *chan, const char *data)
+ {
+ char *station_name, *trunk_name;
+ struct sla_station *station;
+@@ -5759,7 +5835,7 @@
+ AST_APP_OPTION_ARG('M', SLA_TRUNK_OPT_MOH, SLA_TRUNK_OPT_ARG_MOH_CLASS),
+ END_OPTIONS );
+
+-static int sla_trunk_exec(struct ast_channel *chan, void *data)
++static int sla_trunk_exec(struct ast_channel *chan, const char *data)
+ {
+ char conf_name[MAX_CONFNUM];
+ struct ast_conference *conf;
+@@ -6357,16 +6433,7 @@
+
+ static struct ast_custom_function meetme_info_acf = {
+ .name = "MEETME_INFO",
+- .synopsis = "Query a given conference of various properties.",
+- .syntax = "MEETME_INFO(<keyword>,<confno>)",
+ .read = acf_meetme_info,
+- .desc =
+-"Returns information from a given keyword. (For booleans 1-true, 0-false)\n"
+-" Options:\n"
+-" lock - boolean of whether the corresponding conference is locked\n"
+-" parties - number of parties in a given conference\n"
+-" activity - duration of conference in seconds\n"
+-" dynamic - boolean of whether the corresponding coference is dynamic\n",
+ };
+
+
+@@ -6417,12 +6484,9 @@
+ res |= load_config(0);
+
+ ast_cli_register_multiple(cli_meetme, ARRAY_LEN(cli_meetme));
+- res |= ast_manager_register("MeetmeMute", EVENT_FLAG_CALL,
+- action_meetmemute, "Mute a Meetme user");
+- res |= ast_manager_register("MeetmeUnmute", EVENT_FLAG_CALL,
+- 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_manager_register_xml("MeetmeMute", EVENT_FLAG_CALL, action_meetmemute);
++ res |= ast_manager_register_xml("MeetmeUnmute", EVENT_FLAG_CALL, action_meetmeunmute);
++ res |= ast_manager_register_xml("MeetmeList", EVENT_FLAG_REPORTING, action_meetmelist);
+ 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);
+Index: apps/app_test.c
+===================================================================
+--- a/apps/app_test.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/apps/app_test.c (.../trunk) (revision 202568)
+@@ -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,51 +140,51 @@
+ res = ast_waitfordigit(chan, ms);
+ ast_tonepair_stop(chan);
+ }
+- return res;
++ return res;
+ }
+
+-static int testclient_exec(struct ast_channel *chan, void *data)
++static int testclient_exec(struct ast_channel *chan, const char *data)
+ {
+ int res = 0;
+- char *testid=data;
++ const char *testid=data;
+ 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");
+ }
+@@ -314,7 +318,7 @@
+ return res;
+ }
+
+-static int testserver_exec(struct ast_channel *chan, void *data)
++static int testserver_exec(struct ast_channel *chan, const char *data)
+ {
+ int res = 0;
+ char testid[80]="";
+@@ -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_morsecode.c
+===================================================================
+--- a/apps/app_morsecode.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/apps/app_morsecode.c (.../trunk) (revision 202568)
+@@ -63,9 +63,9 @@
+ </see-also>
+ </application>
+ ***/
+-static char *app_morsecode = "Morsecode";
++static const char app_morsecode[] = "Morsecode";
+
+-static char *morsecode[] = {
++static const char * const morsecode[] = {
+ "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", /* 0-15 */
+ "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", /* 16-31 */
+ " ", /* 32 - <space> */
+@@ -118,10 +118,10 @@
+ ast_playtones_stop(chan);
+ }
+
+-static int morsecode_exec(struct ast_channel *chan, void *data)
++static int morsecode_exec(struct ast_channel *chan, const char *data)
+ {
+ int res=0, ditlen, tone;
+- char *digit;
++ const char *digit;
+ const char *ditlenc, *tonec;
+
+ if (ast_strlen_zero(data)) {
+@@ -147,7 +147,7 @@
+
+ for (digit = data; *digit; digit++) {
+ int digit2 = *digit;
+- char *dahdit;
++ const char *dahdit;
+ if (digit2 < 0) {
+ continue;
+ }
+Index: apps/app_ices.c
+===================================================================
+--- a/apps/app_ices.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/apps/app_ices.c (.../trunk) (revision 202568)
+@@ -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>
+
+@@ -104,7 +104,7 @@
+ _exit(0);
+ }
+
+-static int ices_exec(struct ast_channel *chan, void *data)
++static int ices_exec(struct ast_channel *chan, const char *data)
+ {
+ int res = 0;
+ int fds[2];
+Index: apps/app_exec.c
+===================================================================
+--- a/apps/app_exec.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/apps/app_exec.c (.../trunk) (revision 202568)
+@@ -125,63 +125,68 @@
+ * affecting the dialplan.
+ */
+
+-static char *app_exec = "Exec";
+-static char *app_tryexec = "TryExec";
+-static char *app_execif = "ExecIf";
++static const char app_exec[] = "Exec";
++static const char app_tryexec[] = "TryExec";
++static const char app_execif[] = "ExecIf";
+
+-static int exec_exec(struct ast_channel *chan, void *data)
++static int exec_exec(struct ast_channel *chan, const char *data)
+ {
+ int res = 0;
+- char *s, *appname, *endargs, args[MAXRESULT];
++ char *s, *appname, *endargs;
+ struct ast_app *app;
++ struct ast_str *args = NULL;
+
+ if (ast_strlen_zero(data))
+ return 0;
+
+ s = ast_strdupa(data);
+- args[0] = 0;
+ appname = strsep(&s, "(");
+ if (s) {
+ endargs = strrchr(s, ')');
+ if (endargs)
+ *endargs = '\0';
+- pbx_substitute_variables_helper(chan, s, args, MAXRESULT - 1);
++ if ((args = ast_str_create(16))) {
++ ast_str_substitute_variables(&args, 0, chan, s);
++ }
+ }
+ if (appname) {
+ app = pbx_findapp(appname);
+ if (app) {
+- res = pbx_exec(chan, app, args);
++ res = pbx_exec(chan, app, args ? ast_str_buffer(args) : NULL);
+ } else {
+ ast_log(LOG_WARNING, "Could not find application (%s)\n", appname);
+ res = -1;
+ }
+ }
+
++ ast_free(args);
+ return res;
+ }
+
+-static int tryexec_exec(struct ast_channel *chan, void *data)
++static int tryexec_exec(struct ast_channel *chan, const char *data)
+ {
+ int res = 0;
+- char *s, *appname, *endargs, args[MAXRESULT];
++ char *s, *appname, *endargs;
+ struct ast_app *app;
++ struct ast_str *args = NULL;
+
+ if (ast_strlen_zero(data))
+ return 0;
+
+ s = ast_strdupa(data);
+- args[0] = 0;
+ appname = strsep(&s, "(");
+ if (s) {
+ endargs = strrchr(s, ')');
+ if (endargs)
+ *endargs = '\0';
+- pbx_substitute_variables_helper(chan, s, args, MAXRESULT - 1);
++ if ((args = ast_str_create(16))) {
++ ast_str_substitute_variables(&args, 0, chan, s);
++ }
+ }
+ if (appname) {
+ app = pbx_findapp(appname);
+ if (app) {
+- res = pbx_exec(chan, app, args);
++ res = pbx_exec(chan, app, args ? ast_str_buffer(args) : NULL);
+ pbx_builtin_setvar_helper(chan, "TRYSTATUS", res ? "FAILED" : "SUCCESS");
+ } else {
+ ast_log(LOG_WARNING, "Could not find application (%s)\n", appname);
+@@ -189,10 +194,11 @@
+ }
+ }
+
++ ast_free(args);
+ return 0;
+ }
+
+-static int execif_exec(struct ast_channel *chan, void *data)
++static int execif_exec(struct ast_channel *chan, const char *data)
+ {
+ int res = 0;
+ char *truedata = NULL, *falsedata = NULL, *end, *firstcomma, *firstquestion;
+Index: apps/app_channelredirect.c
+===================================================================
+--- a/apps/app_channelredirect.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/apps/app_channelredirect.c (.../trunk) (revision 202568)
+@@ -60,9 +60,9 @@
+ </description>
+ </application>
+ ***/
+-static char *app = "ChannelRedirect";
++static const char app[] = "ChannelRedirect";
+
+-static int asyncgoto_exec(struct ast_channel *chan, void *data)
++static int asyncgoto_exec(struct ast_channel *chan, const char *data)
+ {
+ int res = -1;
+ char *info;
+@@ -86,8 +86,7 @@
+ return -1;
+ }
+
+- chan2 = ast_get_channel_by_name_locked(args.channel);
+- if (!chan2) {
++ if (!(chan2 = ast_channel_get_by_name(args.channel))) {
+ ast_log(LOG_WARNING, "No such channel: %s\n", args.channel);
+ pbx_builtin_setvar_helper(chan, "CHANNELREDIRECT_STATUS", "NOCHANNEL");
+ return 0;
+@@ -96,9 +95,12 @@
+ if (chan2->pbx) {
+ ast_set_flag(chan2, AST_FLAG_BRIDGE_HANGUP_DONT); /* don't let the after-bridge code run the h-exten */
+ }
++
+ res = ast_async_parseable_goto(chan2, args.label);
++
++ chan2 = ast_channel_unref(chan2);
++
+ pbx_builtin_setvar_helper(chan, "CHANNELREDIRECT_STATUS", "SUCCESS");
+- ast_channel_unlock(chan2);
+
+ return res;
+ }
+Index: apps/app_forkcdr.c
+===================================================================
+--- a/apps/app_forkcdr.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/apps/app_forkcdr.c (.../trunk) (revision 202568)
+@@ -226,7 +226,7 @@
+ ast_set_flag(cdr, AST_CDR_FLAG_CHILD | AST_CDR_FLAG_LOCKED);
+ }
+
+-static int forkcdr_exec(struct ast_channel *chan, void *data)
++static int forkcdr_exec(struct ast_channel *chan, const char *data)
+ {
+ int res = 0;
+ char *argcopy = NULL;
+Index: apps/app_skel.c
+===================================================================
+--- a/apps/app_skel.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/apps/app_skel.c (.../trunk) (revision 202568)
+@@ -74,18 +74,18 @@
+
+ static char *app = "Skel";
+
+-enum {
++enum option_flags {
+ OPTION_A = (1 << 0),
+ OPTION_B = (1 << 1),
+ OPTION_C = (1 << 2),
+-} option_flags;
++};
+
+-enum {
++enum option_args {
+ OPTION_ARG_B = 0,
+ OPTION_ARG_C = 1,
+ /* This *must* be the last value in this enum! */
+ OPTION_ARG_ARRAY_SIZE = 2,
+-} option_args;
++};
+
+ AST_APP_OPTIONS(app_opts,{
+ AST_APP_OPTION('a', OPTION_A),
+@@ -94,7 +94,7 @@
+ });
+
+
+-static int app_exec(struct ast_channel *chan, void *data)
++static int app_exec(struct ast_channel *chan, const char *data)
+ {
+ int res = 0;
+ struct ast_flags flags;
+Index: apps/app_directed_pickup.c
+===================================================================
+--- a/apps/app_directed_pickup.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/apps/app_directed_pickup.c (.../trunk) (revision 202568)
+@@ -40,6 +40,7 @@
+ #include "asterisk/lock.h"
+ #include "asterisk/app.h"
+ #include "asterisk/features.h"
++#include "asterisk/callerid.h"
+
+ #define PICKUPMARK "PICKUPMARK"
+
+@@ -83,17 +84,31 @@
+ </application>
+ ***/
+
+-static const char *app = "Pickup";
+-static const char *app2 = "PickupChan";
++static const char app[] = "Pickup";
++static const char app2[] = "PickupChan";
+ /*! \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;
++ if (ast_channel_connected_line_macro(NULL, chan, &connected_caller, 0, 0)) {
++ 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;
+@@ -121,17 +136,35 @@
+ return 0;
+ }
+
++struct pickup_by_name_args {
++ const char *name;
++ size_t len;
++};
++
++static int pickup_by_name_cb(void *obj, void *arg, void *data, int flags)
++{
++ struct ast_channel *chan = obj;
++ struct pickup_by_name_args *args = data;
++
++ ast_channel_lock(chan);
++ if (!strncasecmp(chan->name, args->name, args->len) && can_pickup(chan)) {
++ /* Return with the channel still locked on purpose */
++ return CMP_MATCH | CMP_STOP;
++ }
++ ast_channel_unlock(chan);
++
++ return 0;
++}
++
+ /*! \brief Helper Function to walk through ALL channels checking NAME and STATE */
+ static struct ast_channel *my_ast_get_channel_by_name_locked(const char *channame)
+ {
+- struct ast_channel *chan;
+ char *chkchan;
+- size_t channame_len, chkchan_len;
++ struct pickup_by_name_args pickup_args;
+
+- channame_len = strlen(channame);
+- chkchan_len = channame_len + 2;
++ pickup_args.len = strlen(channame) + 2;
+
+- chkchan = alloca(chkchan_len);
++ chkchan = alloca(pickup_args.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
+@@ -140,15 +173,9 @@
+ strcpy(chkchan, channame);
+ strcat(chkchan, "-");
+
+- for (chan = ast_walk_channel_by_name_prefix_locked(NULL, channame, channame_len);
+- 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;
++ pickup_args.name = chkchan;
++
++ return ast_channel_callback(pickup_by_name_cb, NULL, &pickup_args, 0);
+ }
+
+ /*! \brief Attempt to pick up specified channel named , does not use context */
+@@ -157,80 +184,86 @@
+ int res = 0;
+ struct ast_channel *target;
+
+- if (!(target = my_ast_get_channel_by_name_locked(pickup)))
++ if (!(target = my_ast_get_channel_by_name_locked(pickup))) {
+ return -1;
++ }
+
+ /* Just check that we are not picking up the SAME as target */
+- if (chan->name != target->name && chan != target) {
++ if (chan != target) {
+ res = pickup_do(chan, target);
+ }
++
+ ast_channel_unlock(target);
++ target = ast_channel_unref(target);
+
+ 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)
+ {
+ struct ast_channel *target = NULL;
+- struct pickup_criteria search = {
+- .exten = exten,
+- .context = context,
+- };
++ struct ast_channel_iterator *iter;
++ int res = -1;
+
+- target = ast_channel_search_locked(find_by_exten, &search);
++ if (!(iter = ast_channel_iterator_by_exten_new(0, exten, context))) {
++ return -1;
++ }
+
++ while ((target = ast_channel_iterator_next(iter))) {
++ ast_channel_lock(target);
++ if (can_pickup(target)) {
++ break;
++ }
++ ast_channel_unlock(target);
++ target = ast_channel_unref(target);
++ }
++
+ if (target) {
+- int res = pickup_do(chan, target);
++ res = pickup_do(chan, target);
+ ast_channel_unlock(target);
+- target = NULL;
+- return res;
++ target = ast_channel_unref(target);
+ }
+
+- return -1;
++ return res;
+ }
+
+-static int find_by_mark(struct ast_channel *c, void *data)
++static int find_by_mark(void *obj, void *arg, void *data, int flags)
+ {
++ struct ast_channel *c = obj;
+ const char *mark = data;
+ const char *tmp;
++ int res;
+
+- return (tmp = pbx_builtin_getvar_helper(c, PICKUPMARK)) &&
++ ast_channel_lock(c);
++
++ res = (tmp = pbx_builtin_getvar_helper(c, PICKUPMARK)) &&
+ !strcasecmp(tmp, mark) &&
+ can_pickup(c);
++
++ ast_channel_unlock(c);
++
++ return res ? CMP_MATCH | CMP_STOP : 0;
+ }
+
+ /* Attempt to pick up specified mark */
+ static int pickup_by_mark(struct ast_channel *chan, const char *mark)
+ {
+- struct ast_channel *target = ast_channel_search_locked(find_by_mark, (char *) mark);
++ struct ast_channel *target;
++ int res = -1;
+
+- if (target) {
+- int res = pickup_do(chan, target);
++ if ((target = ast_channel_callback(find_by_mark, NULL, (char *) mark, 0))) {
++ ast_channel_lock(target);
++ res = pickup_do(chan, target);
+ ast_channel_unlock(target);
+- target = NULL;
+- return res;
++ target = ast_channel_unref(target);
+ }
+
+- return -1;
++ return res;
+ }
+
+ /* application entry point for Pickup() */
+-static int pickup_exec(struct ast_channel *chan, void *data)
++static int pickup_exec(struct ast_channel *chan, const char *data)
+ {
+ int res = 0;
+ char *tmp = ast_strdupa(data);
+@@ -259,7 +292,7 @@
+ }
+
+ /* application entry point for PickupChan() */
+-static int pickupchan_exec(struct ast_channel *chan, void *data)
++static int pickupchan_exec(struct ast_channel *chan, const char *data)
+ {
+ int res = 0;
+ char *tmp = ast_strdupa(data);
+Index: apps/app_minivm.c
+===================================================================
+--- a/apps/app_minivm.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/apps/app_minivm.c (.../trunk) (revision 202568)
+@@ -400,6 +400,99 @@
+ subscribed to the mailbox passed in the first parameter.</para>
+ </description>
+ </application>
++<function name="MINIVMCOUNTER" language="en_US">
++ <synopsis>
++ Reads or sets counters for MiniVoicemail message.
++ </synopsis>
++ <syntax argsep=":">
++ <parameter name="account" required="true">
++ <para>If account is given and it exists, the counter is specific for the account.</para>
++ <para>If account is a domain and the domain directory exists, counters are specific for a domain.</para>
++ </parameter>
++ <parameter name="name" required="true">
++ <para>The name of the counter is a string, up to 10 characters.</para>
++ </parameter>
++ <parameter name="operand">
++ <para>The counters never goes below zero. Valid operands for changing the value of a counter when assigning a value are:</para>
++ <enumlist>
++ <enum name="i"><para>Increment by value.</para></enum>
++ <enum name="d"><para>Decrement by value.</para></enum>
++ <enum name="s"><para>Set to value.</para></enum>
++ </enumlist>
++ </parameter>
++ </syntax>
++ <description>
++ <para>The operation is atomic and the counter is locked while changing the value. The counters are stored as text files in the minivm account directories. It might be better to use realtime functions if you are using a database to operate your Asterisk.</para>
++ </description>
++ <see-also>
++ <ref type="application">MinivmRecord</ref>
++ <ref type="application">MinivmGreet</ref>
++ <ref type="application">MinivmNotify</ref>
++ <ref type="application">MinivmDelete</ref>
++ <ref type="application">MinivmAccMess</ref>
++ <ref type="application">MinivmMWI</ref>
++ <ref type="function">MINIVMACCOUNT</ref>
++ </see-also>
++</function>
++<function name="MINIVMACCOUNT" language="en_US">
++ <synopsis>
++ Gets MiniVoicemail account information.
++ </synopsis>
++ <syntax argsep=":">
++ <parameter name="account" required="true" />
++ <parameter name="item" required="true">
++ <para>Valid items are:</para>
++ <enumlist>
++ <enum name="path">
++ <para>Path to account mailbox (if account exists, otherwise temporary mailbox).</para>
++ </enum>
++ <enum name="hasaccount">
++ <para>1 is static Minivm account exists, 0 otherwise.</para>
++ </enum>
++ <enum name="fullname">
++ <para>Full name of account owner.</para>
++ </enum>
++ <enum name="email">
++ <para>Email address used for account.</para>
++ </enum>
++ <enum name="etemplate">
++ <para>Email template for account (default template if none is configured).</para>
++ </enum>
++ <enum name="ptemplate">
++ <para>Pager template for account (default template if none is configured).</para>
++ </enum>
++ <enum name="accountcode">
++ <para>Account code for the voicemail account.</para>
++ </enum>
++ <enum name="pincode">
++ <para>Pin code for voicemail account.</para>
++ </enum>
++ <enum name="timezone">
++ <para>Time zone for voicemail account.</para>
++ </enum>
++ <enum name="language">
++ <para>Language for voicemail account.</para>
++ </enum>
++ <enum name="&lt;channel variable name&gt;">
++ <para>Channel variable value (set in configuration for account).</para>
++ </enum>
++ </enumlist>
++ </parameter>
++ </syntax>
++ <description>
++ <para />
++ </description>
++ <see-also>
++ <ref type="application">MinivmRecord</ref>
++ <ref type="application">MinivmGreet</ref>
++ <ref type="application">MinivmNotify</ref>
++ <ref type="application">MinivmDelete</ref>
++ <ref type="application">MinivmAccMess</ref>
++ <ref type="application">MinivmMWI</ref>
++ <ref type="function">MINIVMCOUNTER</ref>
++ </see-also>
++</function>
++
+ ***/
+
+ #ifndef TRUE
+@@ -455,19 +548,19 @@
+
+
+
+-enum {
++enum minivm_option_flags {
+ OPT_SILENT = (1 << 0),
+ OPT_BUSY_GREETING = (1 << 1),
+ OPT_UNAVAIL_GREETING = (1 << 2),
+ OPT_TEMP_GREETING = (1 << 3),
+ OPT_NAME_GREETING = (1 << 4),
+ OPT_RECORDGAIN = (1 << 5),
+-} minivm_option_flags;
++};
+
+-enum {
++enum minivm_option_args {
+ OPT_ARG_RECORDGAIN = 0,
+ OPT_ARG_ARRAY_SIZE = 1,
+-} minivm_option_args;
++};
+
+ AST_APP_OPTIONS(minivm_app_options, {
+ AST_APP_OPTION('s', OPT_SILENT),
+@@ -483,11 +576,12 @@
+ AST_APP_OPTION('n', OPT_NAME_GREETING),
+ });
+
+-/*! \brief Structure for linked list of Mini-Voicemail users: \ref minivm_accounts */
++/*!\internal
++ * \brief Structure for linked list of Mini-Voicemail users: \ref minivm_accounts */
+ struct minivm_account {
+ char username[AST_MAX_CONTEXT]; /*!< Mailbox username */
+ char domain[AST_MAX_CONTEXT]; /*!< Voicemail domain */
+-
++
+ char pincode[10]; /*!< Secret pin code, numbers only */
+ char fullname[120]; /*!< Full name, for directory app */
+ char email[80]; /*!< E-mail address - override */
+@@ -502,18 +596,20 @@
+ char attachfmt[80]; /*!< Format for voicemail audio file attachment */
+ char etemplate[80]; /*!< Pager template */
+ char ptemplate[80]; /*!< Voicemail format */
+- unsigned int flags; /*!< MVM_ flags */
++ unsigned int flags; /*!< MVM_ flags */
+ struct ast_variable *chanvars; /*!< Variables for e-mail template */
+ double volgain; /*!< Volume gain for voicemails sent via e-mail */
+- AST_LIST_ENTRY(minivm_account) list;
++ AST_LIST_ENTRY(minivm_account) list;
+ };
+
+-/*! \brief The list of e-mail accounts */
++/*!\internal
++ * \brief The list of e-mail accounts */
+ static AST_LIST_HEAD_STATIC(minivm_accounts, minivm_account);
+
+-/*! \brief Linked list of e-mail templates in various languages
+- These are used as templates for e-mails, pager messages and jabber messages
+- \ref message_templates
++/*!\internal
++ * \brief Linked list of e-mail templates in various languages
++ * These are used as templates for e-mails, pager messages and jabber messages
++ * \ref message_templates
+ */
+ struct minivm_template {
+ char name[80]; /*!< Template name */
+@@ -574,7 +670,7 @@
+ AST_MUTEX_DEFINE_STATIC(minivmlock); /*!< Lock to protect voicemail system */
+ AST_MUTEX_DEFINE_STATIC(minivmloglock); /*!< Lock to protect voicemail system log file */
+
+-FILE *minivmlogfile; /*!< The minivm log file */
++static FILE *minivmlogfile; /*!< The minivm log file */
+
+ static int global_vmminmessage; /*!< Minimum duration of messages */
+ static int global_vmmaxmessage; /*!< Maximum duration of message */
+@@ -588,11 +684,11 @@
+
+ static struct ast_flags globalflags = {0}; /*!< Global voicemail flags */
+ static int global_saydurationminfo;
+-static char global_charset[32]; /*!< Global charset in messages */
+
+ static double global_volgain; /*!< Volume gain for voicmemail via e-mail */
+
+-/*! \brief Default dateformat, can be overridden in configuration file */
++/*!\internal
++ * \brief Default dateformat, can be overridden in configuration file */
+ #define DEFAULT_DATEFORMAT "%A, %B %d, %Y at %r"
+ #define DEFAULT_CHARSET "ISO-8859-1"
+
+@@ -603,7 +699,8 @@
+ static struct minivm_account *find_user_realtime(const char *domain, const char *username);
+ static char *handle_minivm_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
+
+-/*! \brief Create message template */
++/*!\internal
++ * \brief Create message template */
+ static struct minivm_template *message_template_create(const char *name)
+ {
+ struct minivm_template *template;
+@@ -622,7 +719,8 @@
+ return template;
+ }
+
+-/*! \brief Release memory allocated by message template */
++/*!\internal
++ * \brief Release memory allocated by message template */
+ static void message_template_free(struct minivm_template *template)
+ {
+ if (template->body)
+@@ -631,7 +729,8 @@
+ ast_free (template);
+ }
+
+-/*! \brief Build message template from configuration */
++/*!\internal
++ * \brief Build message template from configuration */
+ static int message_template_build(const char *name, struct ast_variable *var)
+ {
+ struct minivm_template *template;
+@@ -693,7 +792,8 @@
+ return error;
+ }
+
+-/*! \brief Find named template */
++/*!\internal
++ * \brief Find named template */
+ static struct minivm_template *message_template_find(const char *name)
+ {
+ struct minivm_template *this, *res = NULL;
+@@ -714,18 +814,21 @@
+ }
+
+
+-/*! \brief Clear list of templates */
++/*!\internal
++ * \brief Clear list of templates */
+ static void message_destroy_list(void)
+ {
+ struct minivm_template *this;
+ AST_LIST_LOCK(&message_templates);
+- while ((this = AST_LIST_REMOVE_HEAD(&message_templates, list)))
++ while ((this = AST_LIST_REMOVE_HEAD(&message_templates, list))) {
+ message_template_free(this);
+-
++ }
++
+ AST_LIST_UNLOCK(&message_templates);
+ }
+
+-/*! \brief read buffer from file (base64 conversion) */
++/*!\internal
++ * \brief read buffer from file (base64 conversion) */
+ static int b64_inbuf(struct b64_baseio *bio, FILE *fi)
+ {
+ int l;
+@@ -747,7 +850,8 @@
+ return 1;
+ }
+
+-/*! \brief read character from file to buffer (base64 conversion) */
++/*!\internal
++ * \brief read character from file to buffer (base64 conversion) */
+ static int b64_inchar(struct b64_baseio *bio, FILE *fi)
+ {
+ if (bio->iocp >= bio->iolen) {
+@@ -758,7 +862,8 @@
+ return bio->iobuf[bio->iocp++];
+ }
+
+-/*! \brief write buffer to file (base64 conversion) */
++/*!\internal
++ * \brief write buffer to file (base64 conversion) */
+ static int b64_ochar(struct b64_baseio *bio, int c, FILE *so)
+ {
+ if (bio->linelength >= B64_BASELINELEN) {
+@@ -776,7 +881,8 @@
+ return 1;
+ }
+
+-/*! \brief Encode file to base64 encoding for email attachment (base64 conversion) */
++/*!\internal
++ * \brief Encode file to base64 encoding for email attachment (base64 conversion) */
+ static int base_encode(char *filename, FILE *so)
+ {
+ unsigned char dtable[B64_BASEMAXINLINE];
+@@ -859,7 +965,8 @@
+ }
+
+
+-/*! \brief Free user structure - if it's allocated */
++/*!\internal
++ * \brief Free user structure - if it's allocated */
+ static void free_user(struct minivm_account *vmu)
+ {
+ if (vmu->chanvars)
+@@ -869,8 +976,9 @@
+
+
+
+-/*! \brief Prepare for voicemail template by adding channel variables
+- to the channel
++/*!\internal
++ * \brief Prepare for voicemail template by adding channel variables
++ * to the channel
+ */
+ static void prep_email_sub_vars(struct ast_channel *channel, const struct minivm_account *vmu, const char *cidnum, const char *cidname, const char *dur, const char *date, const char *counter)
+ {
+@@ -899,7 +1007,8 @@
+ pbx_builtin_setvar_helper(channel, "MVM_COUNTER", counter);
+ }
+
+-/*! \brief Set default values for Mini-Voicemail users */
++/*!\internal
++ * \brief Set default values for Mini-Voicemail users */
+ static void populate_defaults(struct minivm_account *vmu)
+ {
+ ast_copy_flags(vmu, (&globalflags), AST_FLAGS_ALL);
+@@ -907,26 +1016,8 @@
+ vmu->volgain = global_volgain;
+ }
+
+-/*! \brief Fix quote of mail headers for non-ascii characters */
+-static char *mailheader_quote(const char *from, char *to, size_t len)
+-{
+- char *ptr = to;
+- *ptr++ = '"';
+- for (; ptr < to + len - 1; from++) {
+- if (*from == '"')
+- *ptr++ = '\\';
+- else if (*from == '\0')
+- break;
+- *ptr++ = *from;
+- }
+- if (ptr < to + len - 1)
+- *ptr++ = '"';
+- *ptr = '\0';
+- return to;
+-}
+-
+-
+-/*! \brief Allocate new vm user and set default values */
++/*!\internal
++ * \brief Allocate new vm user and set default values */
+ static struct minivm_account *mvm_user_alloc(void)
+ {
+ struct minivm_account *new;
+@@ -940,7 +1031,8 @@
+ }
+
+
+-/*! \brief Clear list of users */
++/*!\internal
++ * \brief Clear list of users */
+ static void vmaccounts_destroy_list(void)
+ {
+ struct minivm_account *this;
+@@ -951,7 +1043,8 @@
+ }
+
+
+-/*! \brief Find user from static memory object list */
++/*!\internal
++ * \brief Find user from static memory object list */
+ static struct minivm_account *find_account(const char *domain, const char *username, int createtemp)
+ {
+ struct minivm_account *vmu = NULL, *cur;
+@@ -992,8 +1085,9 @@
+ return vmu;
+ }
+
+-/*! \brief Find user in realtime storage
+- Returns pointer to minivm_account structure
++/*!\internal
++ * \brief Find user in realtime storage
++ * \return pointer to minivm_account structure
+ */
+ static struct minivm_account *find_user_realtime(const char *domain, const char *username)
+ {
+@@ -1023,7 +1117,102 @@
+ return retval;
+ }
+
+-/*! \brief Send voicemail with audio file as an attachment */
++/*!\internal
++ * \brief Check if the string would need encoding within the MIME standard, to
++ * avoid confusing certain mail software that expects messages to be 7-bit
++ * clean.
++ */
++static int check_mime(const char *str)
++{
++ for (; *str; str++) {
++ if (*str > 126 || *str < 32 || strchr("()<>@,:;/\"[]?.=", *str)) {
++ return 1;
++ }
++ }
++ return 0;
++}
++
++/*!\internal
++ * \brief Encode a string according to the MIME rules for encoding strings
++ * that are not 7-bit clean or contain control characters.
++ *
++ * Additionally, if the encoded string would exceed the MIME limit of 76
++ * characters per line, then the encoding will be broken up into multiple
++ * sections, separated by a space character, in order to facilitate
++ * breaking up the associated header across multiple lines.
++ *
++ * \param end An expandable buffer for holding the result
++ * \param maxlen \see ast_str
++ * \param charset Character set in which the result should be encoded
++ * \param start A string to be encoded
++ * \param preamble The length of the first line already used for this string,
++ * to ensure that each line maintains a maximum length of 76 chars.
++ * \param postamble the length of any additional characters appended to the
++ * line, used to ensure proper field wrapping.
++ * \return The encoded string.
++ */
++static const char *ast_str_encode_mime(struct ast_str **end, ssize_t maxlen, const char *charset, const char *start, size_t preamble, size_t postamble)
++{
++ struct ast_str *tmp = ast_str_alloca(80);
++ int first_section = 1;
++ *end = '\0';
++
++ ast_str_reset(*end);
++ ast_str_set(&tmp, -1, "=?%s?Q?", charset);
++ for (; *start; start++) {
++ int need_encoding = 0;
++ if (*start < 33 || *start > 126 || strchr("()<>@,:;/\"[]?.=_", *start)) {
++ need_encoding = 1;
++ }
++ if ((first_section && need_encoding && preamble + ast_str_strlen(tmp) > 70) ||
++ (first_section && !need_encoding && preamble + ast_str_strlen(tmp) > 72) ||
++ (!first_section && need_encoding && ast_str_strlen(tmp) > 70) ||
++ (!first_section && !need_encoding && ast_str_strlen(tmp) > 72)) {
++ /* Start new line */
++ ast_str_append(end, maxlen, "%s%s?=", first_section ? "" : " ", ast_str_buffer(tmp));
++ ast_str_set(&tmp, -1, "=?%s?Q?", charset);
++ first_section = 0;
++ }
++ if (need_encoding && *start == ' ') {
++ ast_str_append(&tmp, -1, "_");
++ } else if (need_encoding) {
++ ast_str_append(&tmp, -1, "=%hhX", *start);
++ } else {
++ ast_str_append(&tmp, -1, "%c", *start);
++ }
++ }
++ ast_str_append(end, maxlen, "%s%s?=%s", first_section ? "" : " ", ast_str_buffer(tmp), ast_str_strlen(tmp) + postamble > 74 ? " " : "");
++ return ast_str_buffer(*end);
++}
++
++/*!\internal
++ * \brief Wraps a character sequence in double quotes, escaping occurences of quotes within the string.
++ * \param from The string to work with.
++ * \param buf The destination buffer to write the modified quoted string.
++ * \param maxlen Always zero. \see ast_str
++ *
++ * \return The destination string with quotes wrapped on it (the to field).
++ */
++static const char *ast_str_quote(struct ast_str **buf, ssize_t maxlen, const char *from)
++{
++ const char *ptr;
++
++ /* We're only ever passing 0 to maxlen, so short output isn't possible */
++ ast_str_set(buf, maxlen, "\"");
++ for (ptr = from; *ptr; ptr++) {
++ if (*ptr == '"' || *ptr == '\\') {
++ ast_str_append(buf, maxlen, "\\%c", *ptr);
++ } else {
++ ast_str_append(buf, maxlen, "%c", *ptr);
++ }
++ }
++ ast_str_append(buf, maxlen, "\"");
++
++ return ast_str_buffer(*buf);
++}
++
++/*!\internal
++ * \brief Send voicemail with audio file as an attachment */
+ static int sendmail(struct minivm_template *template, struct minivm_account *vmu, char *cidnum, char *cidname, const char *filename, char *format, int duration, int attach_user_voicemail, enum mvm_messagetype type, const char *counter)
+ {
+ FILE *p = NULL;
+@@ -1039,14 +1228,18 @@
+ struct timeval now;
+ struct ast_tm tm;
+ struct minivm_zone *the_zone = NULL;
+- int len_passdata;
+ struct ast_channel *ast;
+ char *finalfilename;
+- char *passdata = NULL;
+- char *passdata2 = NULL;
++ struct ast_str *str1 = ast_str_create(16), *str2 = ast_str_create(16);
+ char *fromaddress;
+ char *fromemail;
+
++ if (!str1 || !str2) {
++ ast_free(str1);
++ ast_free(str2);
++ return -1;
++ }
++
+ if (type == MVM_MESSAGE_EMAIL) {
+ if (vmu && !ast_strlen_zero(vmu->email)) {
+ ast_copy_string(email, vmu->email, sizeof(email));
+@@ -1160,51 +1353,71 @@
+ if (ast_strlen_zero(fromaddress)) {
+ fprintf(p, "From: Asterisk PBX <%s>\n", who);
+ } else {
+- /* Allocate a buffer big enough for variable substitution */
+- int vmlen = strlen(fromaddress) * 3 + 200;
+-
+ ast_debug(4, "Fromaddress template: %s\n", fromaddress);
+- if ((passdata = alloca(vmlen))) {
+- pbx_substitute_variables_helper(ast, fromaddress, passdata, vmlen);
+- len_passdata = strlen(passdata) * 2 + 3;
+- passdata2 = alloca(len_passdata);
+- fprintf(p, "From: %s <%s>\n", mailheader_quote(passdata, passdata2, len_passdata), who);
+- } else {
+- ast_log(LOG_WARNING, "Cannot allocate workspace for variable substitution\n");
+- fclose(p);
+- return -1;
++ ast_str_substitute_variables(&str1, 0, ast, fromaddress);
++ if (check_mime(ast_str_buffer(str1))) {
++ int first_line = 1;
++ char *ptr;
++ ast_str_encode_mime(&str2, 0, template->charset, ast_str_buffer(str1), strlen("From: "), strlen(who) + 3);
++ while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
++ *ptr = '\0';
++ fprintf(p, "%s %s\n", first_line ? "From:" : "", ast_str_buffer(str2));
++ first_line = 0;
++ /* Substring is smaller, so this will never grow */
++ ast_str_set(&str2, 0, "%s", ptr + 1);
++ }
++ fprintf(p, "%s %s <%s>\n", first_line ? "From:" : "", ast_str_buffer(str2), who);
++ } else {
++ fprintf(p, "From: %s <%s>\n", ast_str_quote(&str2, 0, ast_str_buffer(str1)), who);
+ }
+ }
+- 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)ast_random(), vmu->username, (int)getpid(), who);
+- len_passdata = strlen(vmu->fullname) * 2 + 3;
+- passdata2 = alloca(len_passdata);
+- if (!ast_strlen_zero(vmu->email))
+- fprintf(p, "To: %s <%s>\n", mailheader_quote(vmu->fullname, passdata2, len_passdata), vmu->email);
+- else
+- fprintf(p, "To: %s <%s@%s>\n", mailheader_quote(vmu->fullname, passdata2, len_passdata), vmu->username, vmu->domain);
+
++ if (ast_strlen_zero(vmu->email)) {
++ snprintf(email, sizeof(email), "%s@%s", vmu->username, vmu->domain);
++ } else {
++ ast_copy_string(email, vmu->email, sizeof(email));
++ }
++
++ if (check_mime(vmu->fullname)) {
++ int first_line = 1;
++ char *ptr;
++ ast_str_encode_mime(&str2, 0, template->charset, vmu->fullname, strlen("To: "), strlen(email) + 3);
++ while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
++ *ptr = '\0';
++ fprintf(p, "%s %s\n", first_line ? "To:" : "", ast_str_buffer(str2));
++ first_line = 0;
++ /* Substring is smaller, so this will never grow */
++ ast_str_set(&str2, 0, "%s", ptr + 1);
++ }
++ fprintf(p, "%s %s <%s>\n", first_line ? "To:" : "", ast_str_buffer(str2), email);
++ } else {
++ fprintf(p, "To: %s <%s>\n", ast_str_quote(&str2, 0, vmu->fullname), email);
++ }
++
+ if (!ast_strlen_zero(template->subject)) {
+- char *pass_data;
+- int vmlen = strlen(template->subject) * 3 + 200;
+- if ((pass_data = alloca(vmlen))) {
+- pbx_substitute_variables_helper(ast, template->subject, pass_data, vmlen);
+- fprintf(p, "Subject: %s\n", pass_data);
++ ast_str_substitute_variables(&str1, 0, ast, template->subject);
++ if (check_mime(ast_str_buffer(str1))) {
++ int first_line = 1;
++ char *ptr;
++ ast_str_encode_mime(&str2, 0, template->charset, ast_str_buffer(str1), strlen("Subject: "), 0);
++ while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
++ *ptr = '\0';
++ fprintf(p, "%s %s\n", first_line ? "Subject:" : "", ast_str_buffer(str2));
++ first_line = 0;
++ /* Substring is smaller, so this will never grow */
++ ast_str_set(&str2, 0, "%s", ptr + 1);
++ }
++ fprintf(p, "%s %s\n", first_line ? "Subject:" : "", ast_str_buffer(str2));
+ } else {
+- ast_log(LOG_WARNING, "Cannot allocate workspace for variable substitution\n");
+- fclose(p);
+- return -1;
++ fprintf(p, "Subject: %s\n", ast_str_buffer(str1));
+ }
+-
+- ast_debug(4, "Subject now: %s\n", pass_data);
+-
+- } else {
++ } else {
+ fprintf(p, "Subject: New message in mailbox %s@%s\n", vmu->username, vmu->domain);
+ ast_debug(1, "Using default subject for this email \n");
+ }
+
+-
+ if (option_debug > 2)
+ fprintf(p, "X-Asterisk-debug: template %s user account %s@%s\n", template->name, vmu->username, vmu->domain);
+ fprintf(p, "MIME-Version: 1.0\n");
+@@ -1215,19 +1428,13 @@
+ fprintf(p, "Content-Type: multipart/mixed; boundary=\"%s\"\n\n\n", bound);
+
+ fprintf(p, "--%s\n", bound);
+- fprintf(p, "Content-Type: text/plain; charset=%s\nContent-Transfer-Encoding: 8bit\n\n", global_charset);
++ fprintf(p, "Content-Type: text/plain; charset=%s\nContent-Transfer-Encoding: 8bit\n\n", template->charset);
+ if (!ast_strlen_zero(template->body)) {
+- char *pass_data;
+- int vmlen = strlen(template->body)*3 + 200;
+- if ((pass_data = alloca(vmlen))) {
+- pbx_substitute_variables_helper(ast, template->body, pass_data, vmlen);
+- ast_debug(3, "Message now: %s\n-----\n", pass_data);
+- fprintf(p, "%s\n", pass_data);
+- } else
+- ast_log(LOG_WARNING, "Cannot allocate workspace for variable substitution\n");
++ ast_str_substitute_variables(&str1, 0, ast, template->body);
++ ast_debug(3, "Message now: %s\n-----\n", ast_str_buffer(str1));
++ fprintf(p, "%s\n", ast_str_buffer(str1));
+ } else {
+ fprintf(p, "Dear %s:\n\n\tJust wanted to let you know you were just left a %s long message \n"
+-
+ "in mailbox %s from %s, on %s so you might\n"
+ "want to check it when you get a chance. Thanks!\n\n\t\t\t\t--Asterisk\n\n", vmu->fullname,
+ dur, vmu->username, (cidname ? cidname : (cidnum ? cidnum : "an unknown caller")), date);
+@@ -1239,7 +1446,7 @@
+ ast_debug(3, "Attaching file to message: %s\n", fname);
+ if (!strcasecmp(format, "ogg"))
+ ctype = "application/";
+-
++
+ fprintf(p, "--%s\n", bound);
+ fprintf(p, "Content-Type: %s%s; name=\"voicemailmsg.%s\"\n", ctype, format, format);
+ fprintf(p, "Content-Transfer-Encoding: base64\n");
+@@ -1254,18 +1461,23 @@
+ ast_safe_system(tmp2);
+ ast_debug(1, "Sent message to %s with command '%s' - %s\n", vmu->email, global_mailcmd, template->attachment ? "(media attachment)" : "");
+ ast_debug(3, "Actual command used: %s\n", tmp2);
+- if (ast)
+- ast_channel_free(ast);
++ if (ast) {
++ ast = ast_channel_release(ast);
++ }
++ ast_free(str1);
++ ast_free(str2);
+ return 0;
+ }
+
+-/*! \brief Create directory based on components */
++/*!\internal
++ * \brief Create directory based on components */
+ static int make_dir(char *dest, int len, const char *domain, const char *username, const char *folder)
+ {
+ return snprintf(dest, len, "%s%s/%s%s%s", MVM_SPOOL_DIR, domain, username, ast_strlen_zero(folder) ? "" : "/", folder ? folder : "");
+ }
+
+-/*! \brief Checks if directory exists. Does not create directory, but builds string in dest
++/*!\internal
++ * \brief Checks if directory exists. Does not create directory, but builds string in dest
+ * \param dest String. base directory.
+ * \param len Int. Length base directory string.
+ * \param domain String. Ignored if is null or empty string.
+@@ -1283,11 +1495,12 @@
+ return TRUE;
+ }
+
+-/*! \brief basically mkdir -p $dest/$domain/$username/$folder
++/*!\internal
++ * \brief basically mkdir -p $dest/$domain/$username/$folder
+ * \param dest String. base directory.
+ * \param len Length of directory string
+ * \param domain String. Ignored if is null or empty string.
+- * \param folder String. Ignored if is null or empty string.
++ * \param folder String. Ignored if is null or empty string.
+ * \param username String. Ignored if is null or empty string.
+ * \return -1 on failure, 0 on success.
+ */
+@@ -1304,8 +1517,9 @@
+ }
+
+
+-/*! \brief Play intro message before recording voicemail
+-*/
++/*!\internal
++ * \brief Play intro message before recording voicemail
++ */
+ static int invent_message(struct ast_channel *chan, char *domain, char *username, int busy, char *ecodes)
+ {
+ int res;
+@@ -1327,7 +1541,7 @@
+ char *i = username;
+
+ ast_debug(2, "No personal prompts. Using default prompt set for language\n");
+-
++
+ while (*i) {
+ ast_debug(2, "Numeric? Checking %c\n", *i);
+ if (!isdigit(*i)) {
+@@ -1338,16 +1552,16 @@
+ }
+
+ if (numericusername) {
+- if(ast_streamfile(chan, "vm-theperson", chan->language))
++ if (ast_streamfile(chan, "vm-theperson", chan->language))
+ return -1;
+ if ((res = ast_waitstream(chan, ecodes)))
+ return res;
+-
++
+ res = ast_say_digit_str(chan, username, ecodes, chan->language);
+ if (res)
+ return res;
+ } else {
+- if(ast_streamfile(chan, "vm-theextensionis", chan->language))
++ if (ast_streamfile(chan, "vm-theextensionis", chan->language))
+ return -1;
+ if ((res = ast_waitstream(chan, ecodes)))
+ return res;
+@@ -1361,7 +1575,8 @@
+ return res;
+ }
+
+-/*! \brief Delete media files and attribute file */
++/*!\internal
++ * \brief Delete media files and attribute file */
+ static int vm_delete(char *file)
+ {
+ int res;
+@@ -1374,30 +1589,31 @@
+ }
+
+
+-/*! \brief Record voicemail message & let caller review or re-record it, or set options if applicable */
++/*!\internal
++ * \brief Record voicemail message & let caller review or re-record it, or set options if applicable */
+ static int play_record_review(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime, char *fmt,
+ int outsidecaller, struct minivm_account *vmu, int *duration, const char *unlockdir,
+ signed char record_gain)
+ {
+- int cmd = 0;
+- int max_attempts = 3;
+- int attempts = 0;
+- int recorded = 0;
+- int message_exists = 0;
++ int cmd = 0;
++ int max_attempts = 3;
++ int attempts = 0;
++ int recorded = 0;
++ int message_exists = 0;
+ signed char zero_gain = 0;
+ char *acceptdtmf = "#";
+ char *canceldtmf = "";
+
+- /* Note that urgent and private are for flagging messages as such in the future */
+-
++ /* Note that urgent and private are for flagging messages as such in the future */
++
+ /* barf if no pointer passed to store duration in */
+ if (duration == NULL) {
+ ast_log(LOG_WARNING, "Error play_record_review called without duration pointer\n");
+ return -1;
+ }
+
+- cmd = '3'; /* Want to start by recording */
+-
++ cmd = '3'; /* Want to start by recording */
++
+ while ((cmd >= 0) && (cmd != 't')) {
+ switch (cmd) {
+ case '1':
+@@ -1405,23 +1621,23 @@
+ ast_stream_and_wait(chan, "vm-msgsaved", "");
+ cmd = 't';
+ break;
+- case '2':
+- /* Review */
++ case '2':
++ /* Review */
+ ast_verb(3, "Reviewing the message\n");
+- ast_streamfile(chan, recordfile, chan->language);
+- cmd = ast_waitstream(chan, AST_DIGIT_ANY);
+- break;
+- case '3':
+- message_exists = 0;
+- /* Record */
+- if (recorded == 1)
++ ast_streamfile(chan, recordfile, chan->language);
++ cmd = ast_waitstream(chan, AST_DIGIT_ANY);
++ break;
++ case '3':
++ message_exists = 0;
++ /* Record */
++ if (recorded == 1)
+ ast_verb(3, "Re-recording the message\n");
+- else
++ else
+ ast_verb(3, "Recording the message\n");
+ if (recorded && outsidecaller)
+- cmd = ast_play_and_wait(chan, "beep");
+- recorded = 1;
+- /* After an attempt has been made to record message, we have to take care of INTRO and beep for incoming messages, but not for greetings */
++ cmd = ast_play_and_wait(chan, "beep");
++ recorded = 1;
++ /* After an attempt has been made to record message, we have to take care of INTRO and beep for incoming messages, but not for greetings */
+ if (record_gain)
+ ast_channel_setoption(chan, AST_OPTION_RXGAIN, &record_gain, sizeof(record_gain), 0);
+ if (ast_test_flag(vmu, MVM_OPERATOR))
+@@ -1429,10 +1645,10 @@
+ cmd = ast_play_and_record_full(chan, playfile, recordfile, maxtime, fmt, duration, global_silencethreshold, global_maxsilence, unlockdir, acceptdtmf, canceldtmf);
+ if (record_gain)
+ ast_channel_setoption(chan, AST_OPTION_RXGAIN, &zero_gain, sizeof(zero_gain), 0);
+- if (cmd == -1) /* User has hung up, no options to give */
+- return cmd;
+- if (cmd == '0')
+- break;
++ if (cmd == -1) /* User has hung up, no options to give */
++ return cmd;
++ if (cmd == '0')
++ break;
+ else if (cmd == '*')
+ break;
+ else {
+@@ -1483,7 +1699,7 @@
+ if (!cmd)
+ cmd = ast_waitfordigit(chan, 600);
+ }
+-
++
+ if (!cmd && outsidecaller && ast_test_flag(vmu, MVM_OPERATOR)) {
+ cmd = ast_play_and_wait(chan, "vm-reachoper");
+ if (!cmd)
+@@ -1499,7 +1715,7 @@
+ }
+ }
+ }
+- if (outsidecaller)
++ if (outsidecaller)
+ ast_play_and_wait(chan, "vm-goodbye");
+ if (cmd == 't')
+ cmd = 0;
+@@ -1520,10 +1736,11 @@
+ chan->cid.cid_name, chan->cid.cid_num);
+
+ ast_debug(1, "Executing: %s\n", arguments);
+- ast_safe_system(arguments);
++ ast_safe_system(arguments);
+ }
+
+-/*! \brief Send message to voicemail account owner */
++/*!\internal
++ * \brief Send message to voicemail account owner */
+ static int notify_new_message(struct ast_channel *chan, const char *templatename, struct minivm_account *vmu, const char *filename, long duration, const char *format, char *cidnum, char *cidname)
+ {
+ char *stringp;
+@@ -1536,8 +1753,9 @@
+ if (!ast_strlen_zero(vmu->attachfmt)) {
+ if (strstr(format, vmu->attachfmt)) {
+ format = vmu->attachfmt;
+- } else
++ } else {
+ ast_log(LOG_WARNING, "Attachment format '%s' is not one of the recorded formats '%s'. Falling back to default format for '%s@%s'.\n", vmu->attachfmt, format, vmu->username, vmu->domain);
++ }
+ }
+
+ etemplate = message_template_find(vmu->etemplate);
+@@ -1594,13 +1812,15 @@
+
+ run_externnotify(chan, vmu); /* Run external notification */
+
+- if (etemplate->locale)
++ if (etemplate->locale) {
+ setlocale(LC_TIME, oldlocale); /* Rest to old locale */
++ }
+ return res;
+ }
+
+
+-/*! \brief Record voicemail message, store into file prepared for sending e-mail */
++/*!\internal
++ * \brief Record voicemail message, store into file prepared for sending e-mail */
+ static int leave_voicemail(struct ast_channel *chan, char *username, struct leave_vm_options *options)
+ {
+ char tmptxtfile[PATH_MAX];
+@@ -1662,7 +1882,6 @@
+
+
+ snprintf(tmptxtfile, sizeof(tmptxtfile), "%s/XXXXXX", tmpdir);
+-
+
+ /* XXX This file needs to be in temp directory */
+ txtdes = mkstemp(tmptxtfile);
+@@ -1699,7 +1918,7 @@
+ get_date(date, sizeof(date));
+ ast_localtime(&now, &tm, NULL);
+ ast_strftime(timebuf, sizeof(timebuf), "%H:%M:%S", &tm);
+-
++
+ snprintf(logbuf, sizeof(logbuf),
+ /* "Mailbox:domain:macrocontext:exten:priority:callerchan:callerid:origdate:origtime:duration:durationstatus:accountcode" */
+ "%s:%s:%s:%s:%d:%s:%s:%s:%s:%d:%s:%s\n",
+@@ -1750,12 +1969,14 @@
+ }
+ global_stats.lastreceived = ast_tvnow();
+ global_stats.receivedmessages++;
+-// /* Go ahead and delete audio files from system, they're not needed any more */
+-// if (ast_fileexists(tmptxtfile, NULL, NULL) <= 0) {
+-// ast_filedelete(tmptxtfile, NULL);
+-// /* Even not being used at the moment, it's better to convert ast_log to ast_debug anyway */
+-// ast_debug(2, "-_-_- Deleted audio file after notification :: %s \n", tmptxtfile);
+-// }
++#if 0
++ /* Go ahead and delete audio files from system, they're not needed any more */
++ if (ast_fileexists(tmptxtfile, NULL, NULL) <= 0) {
++ ast_filedelete(tmptxtfile, NULL);
++ /* Even not being used at the moment, it's better to convert ast_log to ast_debug anyway */
++ ast_debug(2, "-_-_- Deleted audio file after notification :: %s \n", tmptxtfile);
++ }
++#endif
+
+ if (res > 0)
+ res = 0;
+@@ -1767,7 +1988,8 @@
+ return res;
+ }
+
+-/*! \brief Queue a message waiting event */
++/*!\internal
++ * \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;
+@@ -1791,8 +2013,9 @@
+ ast_event_queue_and_cache(event);
+ }
+
+-/*! \brief Send MWI using interal Asterisk event subsystem */
+-static int minivm_mwi_exec(struct ast_channel *chan, void *data)
++/*!\internal
++ * \brief Send MWI using interal Asterisk event subsystem */
++static int minivm_mwi_exec(struct ast_channel *chan, const char *data)
+ {
+ int argc;
+ char *argv[4];
+@@ -1802,38 +2025,39 @@
+ 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));
++ 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;
+- }
++ 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)
++/*!\internal
++ * \brief Notify voicemail account owners - either generic template or user specific */
++static int minivm_notify_exec(struct ast_channel *chan, const char *data)
+ {
+ int argc;
+ char *argv[2];
+@@ -1847,7 +2071,7 @@
+ const char *filename;
+ const char *format;
+ const char *duration_string;
+-
++
+ if (ast_strlen_zero(data)) {
+ ast_log(LOG_ERROR, "Minivm needs at least an account argument \n");
+ return -1;
+@@ -1911,8 +2135,9 @@
+
+ }
+
+-/*! \brief Dialplan function to record voicemail */
+-static int minivm_record_exec(struct ast_channel *chan, void *data)
++/*!\internal
++ * \brief Dialplan function to record voicemail */
++static int minivm_record_exec(struct ast_channel *chan, const char *data)
+ {
+ int res = 0;
+ char *tmp;
+@@ -1921,7 +2146,7 @@
+ char *argv[2];
+ struct ast_flags flags = { 0 };
+ char *opts[OPT_ARG_ARRAY_SIZE];
+-
++
+ memset(&leave_options, 0, sizeof(leave_options));
+
+ /* Answer channel if it's not already answered */
+@@ -1967,8 +2192,9 @@
+ return res;
+ }
+
+-/*! \brief Play voicemail prompts - either generic or user specific */
+-static int minivm_greet_exec(struct ast_channel *chan, void *data)
++/*!\internal
++ * \brief Play voicemail prompts - either generic or user specific */
++static int minivm_greet_exec(struct ast_channel *chan, const char *data)
+ {
+ struct leave_vm_options leave_options = { 0, '\0'};
+ int argc;
+@@ -2153,12 +2379,13 @@
+
+ }
+
+-/*! \brief Dialplan application to delete voicemail */
+-static int minivm_delete_exec(struct ast_channel *chan, void *data)
++/*!\internal
++ * \brief Dialplan application to delete voicemail */
++static int minivm_delete_exec(struct ast_channel *chan, const char *data)
+ {
+ int res = 0;
+ char filename[BUFSIZ];
+-
++
+ if (!ast_strlen_zero(data)) {
+ ast_copy_string(filename, (char *) data, sizeof(filename));
+ } else {
+@@ -2192,7 +2419,7 @@
+ }
+
+ /*! \brief Record specific messages for voicemail account */
+-static int minivm_accmess_exec(struct ast_channel *chan, void *data)
++static int minivm_accmess_exec(struct ast_channel *chan, const char *data)
+ {
+ int argc = 0;
+ char *argv[2];
+@@ -2608,7 +2835,6 @@
+ ast_copy_string(default_vmformat, "wav", sizeof(default_vmformat));
+ ast_set2_flag((&globalflags), FALSE, MVM_REVIEW);
+ ast_set2_flag((&globalflags), FALSE, MVM_OPERATOR);
+- strcpy(global_charset, "ISO-8859-1");
+ /* Reset statistics */
+ memset(&global_stats, 0, sizeof(global_stats));
+ global_stats.reset = ast_tvnow();
+@@ -3228,41 +3454,13 @@
+
+ static struct ast_custom_function minivm_counter_function = {
+ .name = "MINIVMCOUNTER",
+- .synopsis = "Reads or sets counters for MiniVoicemail message",
+- .syntax = "MINIVMCOUNTER(<account>:name[:operand])",
+ .read = minivm_counter_func_read,
+ .write = minivm_counter_func_write,
+- .desc = "Valid operands for changing the value of a counter when assigning a value are:\n"
+- "- i Increment by value\n"
+- "- d Decrement by value\n"
+- "- s Set to value\n"
+- "\nThe counters never goes below zero.\n"
+- "- The name of the counter is a string, up to 10 characters\n"
+- "- If account is given and it exists, the counter is specific for the account\n"
+- "- If account is a domain and the domain directory exists, counters are specific for a domain\n"
+- "The operation is atomic and the counter is locked while changing the value\n"
+- "\nThe counters are stored as text files in the minivm account directories. It might be better to use\n"
+- "realtime functions if you are using a database to operate your Asterisk\n",
+ };
+
+ static struct ast_custom_function minivm_account_function = {
+ .name = "MINIVMACCOUNT",
+- .synopsis = "Gets MiniVoicemail account information",
+- .syntax = "MINIVMACCOUNT(<account>:item)",
+ .read = minivm_account_func_read,
+- .desc = "Valid items are:\n"
+- "- path Path to account mailbox (if account exists, otherwise temporary mailbox)\n"
+- "- hasaccount 1 if static Minivm account exists, 0 otherwise\n"
+- "- fullname Full name of account owner\n"
+- "- email Email address used for account\n"
+- "- etemplate E-mail template for account (default template if none is configured)\n"
+- "- ptemplate Pager template for account (default template if none is configured)\n"
+- "- accountcode Account code for voicemail account\n"
+- "- pincode Pin code for voicemail account\n"
+- "- timezone Time zone for voicemail account\n"
+- "- language Language for voicemail account\n"
+- "- <channel variable name> Channel variable value (set in configuration for account)\n"
+- "\n",
+ };
+
+ /*! \brief Load mini voicemail module */
+Index: apps/app_dumpchan.c
+===================================================================
+--- a/apps/app_dumpchan.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/apps/app_dumpchan.c (.../trunk) (revision 202568)
+@@ -60,7 +60,7 @@
+ </application>
+ ***/
+
+-static char *app = "DumpChan";
++static const char app[] = "DumpChan";
+
+ static int serialize_showchan(struct ast_channel *c, char *buf, size_t size)
+ {
+@@ -147,7 +147,7 @@
+ return 0;
+ }
+
+-static int dumpchan_exec(struct ast_channel *chan, void *data)
++static int dumpchan_exec(struct ast_channel *chan, const char *data)
+ {
+ struct ast_str *vars = ast_str_thread_get(&ast_str_thread_global_buf, 16);
+ char info[1024];
+Index: apps/app_macro.c
+===================================================================
+--- a/apps/app_macro.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/apps/app_macro.c (.../trunk) (revision 202568)
+@@ -36,6 +36,7 @@
+ #include "asterisk/config.h"
+ #include "asterisk/utils.h"
+ #include "asterisk/lock.h"
++#include "asterisk/app.h"
+
+ /*** DOCUMENTATION
+ <application name="Macro" language="en_US">
+@@ -158,7 +159,7 @@
+
+ static void macro_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan);
+
+-struct ast_datastore_info macro_ds_info = {
++static struct ast_datastore_info macro_ds_info = {
+ .type = "MACRO",
+ .chan_fixup = macro_fixup,
+ };
+@@ -216,7 +217,7 @@
+ return NULL;
+ }
+
+-static int _macro_exec(struct ast_channel *chan, void *data, int exclusive)
++static int _macro_exec(struct ast_channel *chan, const char *data, int exclusive)
+ {
+ const char *s;
+ char *tmp;
+@@ -236,13 +237,14 @@
+ int offset, depth = 0, maxdepth = 7;
+ int setmacrocontext=0;
+ int autoloopflag, inhangup = 0;
++ struct ast_str *tmp_subst = NULL;
+
+ char *save_macro_exten;
+ char *save_macro_context;
+ char *save_macro_priority;
+ char *save_macro_offset;
+ struct ast_datastore *macro_store = ast_channel_datastore_find(chan, &macro_ds_info, NULL);
+-
++
+ if (ast_strlen_zero(data)) {
+ ast_log(LOG_WARNING, "Macro() requires arguments. See \"core show application macro\" for help.\n");
+ return -1;
+@@ -286,7 +288,6 @@
+ return 0;
+ }
+ snprintf(depthc, sizeof(depthc), "%d", depth + 1);
+- pbx_builtin_setvar_helper(chan, "MACRO_DEPTH", depthc);
+
+ tmp = ast_strdupa(data);
+ rest = tmp;
+@@ -316,7 +317,11 @@
+ }
+ ast_autoservice_stop(chan);
+ }
+-
++
++ if (!(tmp_subst = ast_str_create(16))) {
++ return -1;
++ }
++
+ /* Save old info */
+ oldpriority = chan->priority;
+ ast_copy_string(oldexten, chan->exten, sizeof(oldexten));
+@@ -342,6 +347,8 @@
+ save_macro_offset = ast_strdup(pbx_builtin_getvar_helper(chan, "MACRO_OFFSET"));
+ pbx_builtin_setvar_helper(chan, "MACRO_OFFSET", NULL);
+
++ pbx_builtin_setvar_helper(chan, "MACRO_DEPTH", depthc);
++
+ /* Setup environment for new run */
+ chan->exten[0] = 's';
+ chan->exten[1] = '\0';
+@@ -420,8 +427,10 @@
+ gosub_level++;
+ ast_debug(1, "Incrementing gosub_level\n");
+ } else if (!strcasecmp(runningapp, "GOSUBIF")) {
+- char tmp2[1024], *cond, *app_arg, *app2 = tmp2;
+- pbx_substitute_variables_helper(chan, runningdata, tmp2, sizeof(tmp2) - 1);
++ char *cond, *app_arg;
++ char *app2;
++ ast_str_substitute_variables(&tmp_subst, 0, chan, runningdata);
++ app2 = ast_str_buffer(tmp_subst);
+ cond = strsep(&app2, "?");
+ app_arg = strsep(&app2, ":");
+ if (pbx_checkcondition(cond)) {
+@@ -443,19 +452,23 @@
+ ast_debug(1, "Decrementing gosub_level\n");
+ } else if (!strncasecmp(runningapp, "EXEC", 4)) {
+ /* Must evaluate args to find actual app */
+- char tmp2[1024], *tmp3 = NULL;
+- pbx_substitute_variables_helper(chan, runningdata, tmp2, sizeof(tmp2) - 1);
++ char *tmp2, *tmp3 = NULL;
++ ast_str_substitute_variables(&tmp_subst, 0, chan, runningdata);
++ tmp2 = ast_str_buffer(tmp_subst);
+ if (!strcasecmp(runningapp, "EXECIF")) {
+- tmp3 = strchr(tmp2, '|');
+- if (tmp3)
++ if ((tmp3 = strchr(tmp2, '|'))) {
+ *tmp3++ = '\0';
+- if (!pbx_checkcondition(tmp2))
++ }
++ if (!pbx_checkcondition(tmp2)) {
+ tmp3 = NULL;
+- } else
++ }
++ } else {
+ tmp3 = tmp2;
++ }
+
+- if (tmp3)
++ if (tmp3) {
+ ast_debug(1, "Last app: %s\n", tmp3);
++ }
+
+ if (tmp3 && !strncasecmp(tmp3, "GOSUB", 5)) {
+ gosub_level++;
+@@ -552,21 +565,22 @@
+ }
+ }
+ ast_channel_unlock(chan);
++ ast_free(tmp_subst);
+
+ return res;
+ }
+
+-static int macro_exec(struct ast_channel *chan, void *data)
++static int macro_exec(struct ast_channel *chan, const char *data)
+ {
+ return _macro_exec(chan, data, 0);
+ }
+
+-static int macroexclusive_exec(struct ast_channel *chan, void *data)
++static int macroexclusive_exec(struct ast_channel *chan, const char *data)
+ {
+ return _macro_exec(chan, data, 1);
+ }
+
+-static int macroif_exec(struct ast_channel *chan, void *data)
++static int macroif_exec(struct ast_channel *chan, const char *data)
+ {
+ char *expr = NULL, *label_a = NULL, *label_b = NULL;
+ int res = 0;
+@@ -591,7 +605,7 @@
+ return res;
+ }
+
+-static int macro_exit_exec(struct ast_channel *chan, void *data)
++static int macro_exit_exec(struct ast_channel *chan, const char *data)
+ {
+ return MACRO_EXIT_RESULT;
+ }
+Index: apps/app_sms.c
+===================================================================
+--- a/apps/app_sms.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/apps/app_sms.c (.../trunk) (revision 202568)
+@@ -123,7 +123,7 @@
+ * To pick the two carriers (1300Hz for '1' and 2100 Hz for '0') used by
+ * the modulation, we should take one every 13 and 21 samples respectively.
+ */
+-static signed short wave[] = {
++static const signed short wave[] = {
+ 0, 392, 782, 1167, 1545, 1913, 2270, 2612, 2939, 3247, 3536, 3802, 4045, 4263, 4455, 4619, 4755, 4862, 4938, 4985,
+ 5000, 4985, 4938, 4862, 4755, 4619, 4455, 4263, 4045, 3802, 3536, 3247, 2939, 2612, 2270, 1913, 1545, 1167, 782, 392,
+ 0, -392, -782, -1167,
+@@ -815,7 +815,7 @@
+ char line[1000];
+ FILE *s;
+ char dcsset = 0; /* if DSC set */
+- ast_log(LOG_EVENT, "Sending %s\n", fn);
++ ast_log(LOG_NOTICE, "Sending %s\n", fn);
+ h->rx = h->udl = *h->oa = *h->da = h->pid = h->srr = h->udhi = h->rp = h->vp = h->udhl = 0;
+ h->mr = -1;
+ h->dcs = 0xF1; /* normal messages class 1 */
+@@ -1080,7 +1080,7 @@
+ if (rename(fn, fn2)) {
+ unlink(fn);
+ } else {
+- ast_log(LOG_EVENT, "Received to %s\n", fn2);
++ ast_log(LOG_NOTICE, "Received to %s\n", fn2);
+ }
+ }
+
+@@ -1832,19 +1832,19 @@
+ * - AST_APP_OPTIONS() to drive the parsing routine
+ * - in the function, AST_DECLARE_APP_ARGS(...) for the arguments.
+ */
+-enum {
++enum sms_flags {
+ OPTION_BE_SMSC = (1 << 0), /* act as sms center */
+ OPTION_ANSWER = (1 << 1), /* answer on incoming calls */
+ OPTION_TWO = (1 << 2), /* Use Protocol Two */
+ OPTION_PAUSE = (1 << 3), /* pause before sending data, in ms */
+ OPTION_SRR = (1 << 4), /* set srr */
+ OPTION_DCS = (1 << 5), /* set dcs */
+-} sms_flags;
++};
+
+-enum {
++enum sms_opt_args {
+ OPTION_ARG_PAUSE = 0,
+ OPTION_ARG_ARRAY_SIZE
+-} sms_opt_args;
++};
+
+ AST_APP_OPTIONS(sms_options, {
+ AST_APP_OPTION('s', OPTION_BE_SMSC),
+@@ -1855,7 +1855,7 @@
+ AST_APP_OPTION_ARG('p', OPTION_PAUSE, OPTION_ARG_PAUSE),
+ } );
+
+-static int sms_exec(struct ast_channel *chan, void *data)
++static int sms_exec(struct ast_channel *chan, const char *data)
+ {
+ int res = -1;
+ sms_t h = { 0 };
+Index: apps/app_confbridge.c
+===================================================================
+--- a/apps/app_confbridge.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/apps/app_confbridge.c (.../trunk) (revision 202568)
+@@ -111,7 +111,7 @@
+ * bridge lock if it is important.
+ */
+
+-static const char *app = "ConfBridge";
++static const char app[] = "ConfBridge";
+
+ enum {
+ OPTION_ADMIN = (1 << 0), /*!< Set if the caller is an administrator */
+@@ -683,7 +683,7 @@
+ }
+
+ /*! \brief The ConfBridge application */
+-static int confbridge_exec(struct ast_channel *chan, void *data)
++static int confbridge_exec(struct ast_channel *chan, const char *data)
+ {
+ int res = 0, volume_adjustments[2];
+ char *parse;
+Index: apps/app_verbose.c
+===================================================================
+--- a/apps/app_verbose.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/apps/app_verbose.c (.../trunk) (revision 202568)
+@@ -72,7 +72,7 @@
+ ***/
+
+
+-static int verbose_exec(struct ast_channel *chan, void *data)
++static int verbose_exec(struct ast_channel *chan, const char *data)
+ {
+ int vsize;
+ char *parse;
+@@ -118,7 +118,7 @@
+ return 0;
+ }
+
+-static int log_exec(struct ast_channel *chan, void *data)
++static int log_exec(struct ast_channel *chan, const char *data)
+ {
+ char *parse;
+ int lnum = -1;
+@@ -146,8 +146,6 @@
+ lnum = __LOG_VERBOSE;
+ } else if (!strcasecmp(args.level, "DTMF")) {
+ lnum = __LOG_DTMF;
+- } else if (!strcasecmp(args.level, "EVENT")) {
+- lnum = __LOG_EVENT;
+ } else {
+ ast_log(LOG_ERROR, "Unknown log level: '%s'\n", args.level);
+ }
+Index: apps/app_voicemail.c
+===================================================================
+--- a/apps/app_voicemail.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/apps/app_voicemail.c (.../trunk) (revision 202568)
+@@ -46,15 +46,22 @@
+
+ /*** 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="FILE_STORAGE" displayname="Storage of Voicemail using filesystem">
++ <conflict>ODBC_STORAGE</conflict>
++ <conflict>IMAP_STORAGE</conflict>
++ <defaultenabled>yes</defaultenabled>
++ </member>
+ <member name="ODBC_STORAGE" displayname="Storage of Voicemail using ODBC">
+ <depend>generic_odbc</depend>
+ <depend>ltdl</depend>
+ <conflict>IMAP_STORAGE</conflict>
++ <conflict>FILE_STORAGE</conflict>
+ <defaultenabled>no</defaultenabled>
+ </member>
+ <member name="IMAP_STORAGE" displayname="Storage of Voicemail using IMAP4">
+ <depend>imap_tk</depend>
+ <conflict>ODBC_STORAGE</conflict>
++ <conflict>FILE_STORAGE</conflict>
+ <use>openssl</use>
+ <defaultenabled>no</defaultenabled>
+ </member>
+@@ -298,6 +305,16 @@
+ context.</para>
+ </description>
+ </function>
++ <manager name="VoicemailUsersList" language="en_US">
++ <synopsis>
++ List All Voicemail User Information.
++ </synopsis>
++ <syntax>
++ <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
++ </syntax>
++ <description>
++ </description>
++ </manager>
+ ***/
+
+ #ifdef IMAP_STORAGE
+@@ -415,16 +432,16 @@
+ #define ERROR_LOCK_PATH -100
+
+
+-enum {
++enum vm_box {
+ NEW_FOLDER,
+ OLD_FOLDER,
+ WORK_FOLDER,
+ FAMILY_FOLDER,
+ FRIENDS_FOLDER,
+ GREETINGS_FOLDER
+-} vm_box;
++};
+
+-enum {
++enum vm_option_flags {
+ OPT_SILENT = (1 << 0),
+ OPT_BUSY_GREETING = (1 << 1),
+ OPT_UNAVAIL_GREETING = (1 << 2),
+@@ -434,15 +451,15 @@
+ OPT_DTMFEXIT = (1 << 7),
+ OPT_MESSAGE_Urgent = (1 << 8),
+ OPT_MESSAGE_PRIORITY = (1 << 9)
+-} vm_option_flags;
++};
+
+-enum {
++enum vm_option_args {
+ OPT_ARG_RECORDGAIN = 0,
+ OPT_ARG_PLAYFOLDER = 1,
+ OPT_ARG_DTMFEXIT = 2,
+ /* This *must* be the last value in this enum! */
+ OPT_ARG_ARRAY_SIZE = 3,
+-} vm_option_args;
++};
+
+ AST_APP_OPTIONS(vm_app_options, {
+ AST_APP_OPTION('s', OPT_SILENT),
+@@ -1417,7 +1434,7 @@
+
+ static const char *mbox(int id)
+ {
+- static const char *msgs[] = {
++ static const char * const msgs[] = {
+ #ifdef IMAP_STORAGE
+ imapfolder,
+ #else
+@@ -3332,7 +3349,8 @@
+ char *c;
+ struct ast_config *cfg=NULL;
+ struct odbc_obj *obj;
+- struct insert_data idata = { .sql = sql, .msgnums = msgnums, .dir = dir, .mailboxuser = mailboxuser, .mailboxcontext = mailboxcontext };
++ struct insert_data idata = { .sql = sql, .msgnums = msgnums, .dir = dir, .mailboxuser = mailboxuser, .mailboxcontext = mailboxcontext,
++ .context = "", .macrocontext = "", .callerid = "", .origtime = "", .duration = "", .category = "", .flag = "" };
+ struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
+
+ delete_file(dir, msgnum);
+@@ -3846,9 +3864,10 @@
+ return 1;
+ }
+
+-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)
++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, const char *category, const char *flag)
+ {
+ char callerid[256];
++ char num[12];
+ char fromdir[256], fromfile[256];
+ struct ast_config *msg_cfg;
+ const char *origcallerid, *origtime;
+@@ -3859,8 +3878,8 @@
+ /* 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);
+- snprintf(passdata, passdatasize, "%d", msgnum);
+- pbx_builtin_setvar_helper(ast, "VM_MSGNUM", passdata);
++ snprintf(num, sizeof(num), "%d", msgnum);
++ pbx_builtin_setvar_helper(ast, "VM_MSGNUM", num);
+ pbx_builtin_setvar_helper(ast, "VM_CONTEXT", context);
+ pbx_builtin_setvar_helper(ast, "VM_MAILBOX", mailbox);
+ pbx_builtin_setvar_helper(ast, "VM_CALLERID", (!ast_strlen_zero(cidname) || !ast_strlen_zero(cidnum)) ?
+@@ -3904,30 +3923,32 @@
+ /*!
+ * \brief Wraps a character sequence in double quotes, escaping occurences of quotes within the string.
+ * \param from The string to work with.
+- * \param to The string to write the modified quoted string. This buffer should be sufficiently larger than the from string, so as to allow it to be expanded by the surrounding quotes and escaping of internal quotes.
++ * \param buf The buffer into which to write the modified quoted string.
++ * \param maxlen Always zero, but see \see ast_str
+ *
+ * \return The destination string with quotes wrapped on it (the to field).
+ */
+-static char *quote(const char *from, char *to, size_t len)
++static const char *ast_str_quote(struct ast_str **buf, ssize_t maxlen, const char *from)
+ {
+- char *ptr = to;
+- *ptr++ = '"';
+- for (; ptr < to + len - 1; from++) {
+- if (*from == '"')
+- *ptr++ = '\\';
+- else if (*from == '\0')
+- break;
+- *ptr++ = *from;
++ const char *ptr;
++
++ /* We're only ever passing 0 to maxlen, so short output isn't possible */
++ ast_str_set(buf, maxlen, "\"");
++ for (ptr = from; *ptr; ptr++) {
++ if (*ptr == '"' || *ptr == '\\') {
++ ast_str_append(buf, maxlen, "\\%c", *ptr);
++ } else {
++ ast_str_append(buf, maxlen, "%c", *ptr);
++ }
+ }
+- if (ptr < to + len - 1)
+- *ptr++ = '"';
+- *ptr = '\0';
+- return to;
++ ast_str_append(buf, maxlen, "\"");
++
++ return ast_str_buffer(*buf);
+ }
+
+ /*! \brief
+ * fill in *tm for current time according to the proper timezone, if any.
+- * Return tm so it can be used as a function argument.
++ * \return tm so it can be used as a function argument.
+ */
+ static const struct ast_tm *vmu_tm(const struct ast_vm_user *vmu, struct ast_tm *tm)
+ {
+@@ -3970,46 +3991,46 @@
+ * sections, separated by a space character, in order to facilitate
+ * breaking up the associated header across multiple lines.
+ *
++ * \param end An expandable buffer for holding the result
++ * \param maxlen Always zero, but see \see ast_str
+ * \param start A string to be encoded
+- * \param end An expandable buffer for holding the result
+ * \param preamble The length of the first line already used for this string,
+ * to ensure that each line maintains a maximum length of 76 chars.
+ * \param postamble the length of any additional characters appended to the
+ * line, used to ensure proper field wrapping.
+ * \retval The encoded string.
+ */
+-static char *encode_mime_str(const char *start, char *end, size_t endsize, size_t preamble, size_t postamble)
++static const char *ast_str_encode_mime(struct ast_str **end, ssize_t maxlen, const char *start, size_t preamble, size_t postamble)
+ {
+- char tmp[80];
++ struct ast_str *tmp = ast_str_alloca(80);
+ int first_section = 1;
+- size_t endlen = 0, tmplen = 0;
+- *end = '\0';
+
+- tmplen = snprintf(tmp, sizeof(tmp), "=?%s?Q?", charset);
++ ast_str_reset(*end);
++ ast_str_set(&tmp, -1, "=?%s?Q?", charset);
+ for (; *start; start++) {
+ int need_encoding = 0;
+ if (*start < 33 || *start > 126 || strchr("()<>@,:;/\"[]?.=_", *start)) {
+ need_encoding = 1;
+ }
+- if ((first_section && need_encoding && preamble + tmplen > 70) ||
+- (first_section && !need_encoding && preamble + tmplen > 72) ||
+- (!first_section && need_encoding && tmplen > 70) ||
+- (!first_section && !need_encoding && tmplen > 72)) {
++ if ((first_section && need_encoding && preamble + ast_str_strlen(tmp) > 70) ||
++ (first_section && !need_encoding && preamble + ast_str_strlen(tmp) > 72) ||
++ (!first_section && need_encoding && ast_str_strlen(tmp) > 70) ||
++ (!first_section && !need_encoding && ast_str_strlen(tmp) > 72)) {
+ /* Start new line */
+- endlen += snprintf(end + endlen, endsize - endlen, "%s%s?=", first_section ? "" : " ", tmp);
+- tmplen = snprintf(tmp, sizeof(tmp), "=?%s?Q?", charset);
++ ast_str_append(end, maxlen, "%s%s?=", first_section ? "" : " ", ast_str_buffer(tmp));
++ ast_str_set(&tmp, -1, "=?%s?Q?", charset);
+ first_section = 0;
+ }
+ if (need_encoding && *start == ' ') {
+- tmplen += snprintf(tmp + tmplen, sizeof(tmp) - tmplen, "_");
++ ast_str_append(&tmp, -1, "_");
+ } else if (need_encoding) {
+- tmplen += snprintf(tmp + tmplen, sizeof(tmp) - tmplen, "=%hhX", *start);
++ ast_str_append(&tmp, -1, "=%hhX", *start);
+ } else {
+- tmplen += snprintf(tmp + tmplen, sizeof(tmp) - tmplen, "%c", *start);
++ ast_str_append(&tmp, -1, "%c", *start);
+ }
+ }
+- snprintf(end + endlen, endsize - endlen, "%s%s?=%s", first_section ? "" : " ", tmp, endlen + postamble > 74 ? " " : "");
+- return end;
++ ast_str_append(end, maxlen, "%s%s?=%s", first_section ? "" : " ", ast_str_buffer(tmp), ast_str_strlen(tmp) + postamble > 74 ? " " : "");
++ return ast_str_buffer(*end);
+ }
+
+ /*!
+@@ -4041,28 +4062,21 @@
+ char dur[256];
+ struct ast_tm tm;
+ char enc_cidnum[256] = "", enc_cidname[256] = "";
+- char *passdata = NULL, *passdata2;
+- size_t len_passdata = 0, len_passdata2, tmplen;
++ struct ast_str *str1 = ast_str_create(16), *str2 = ast_str_create(16);
+ char *greeting_attachment;
+ char filename[256];
+
++ if (!str1 || !str2) {
++ ast_free(str1);
++ ast_free(str2);
++ return;
++ }
+ #ifdef IMAP_STORAGE
+ #define ENDL "\r\n"
+ #else
+ #define ENDL "\n"
+ #endif
+
+- /* One alloca for multiple fields */
+- len_passdata2 = strlen(vmu->fullname);
+- if (emailsubject && (tmplen = strlen(emailsubject)) > len_passdata2) {
+- len_passdata2 = tmplen;
+- }
+- if ((tmplen = strlen(fromstring)) > len_passdata2) {
+- len_passdata2 = tmplen;
+- }
+- len_passdata2 = len_passdata2 * 3 + 200;
+- passdata2 = alloca(len_passdata2);
+-
+ if (cidnum) {
+ strip_control(cidnum, enc_cidnum, sizeof(enc_cidnum));
+ }
+@@ -4071,14 +4085,16 @@
+ }
+ gethostname(host, sizeof(host) - 1);
+
+- if (strchr(srcemail, '@'))
++ if (strchr(srcemail, '@')) {
+ ast_copy_string(who, srcemail, sizeof(who));
+- else
++ } else {
+ snprintf(who, sizeof(who), "%s@%s", srcemail, host);
++ }
+
+ greeting_attachment = strrchr(ast_strdupa(attach), '/');
+- if (greeting_attachment)
++ if (greeting_attachment) {
+ *greeting_attachment++ = '\0';
++ }
+
+ snprintf(dur, sizeof(dur), "%d:%02d", duration / 60, duration % 60);
+ ast_strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", vmu_tm(vmu, &tm));
+@@ -4091,25 +4107,24 @@
+ struct ast_channel *ast;
+ 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, 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);
+- if (check_mime(passdata2)) {
++ prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, enc_cidnum, enc_cidname, dur, date, category, flag);
++ ast_str_substitute_variables(&str1, 0, ast, fromstring);
++
++ if (check_mime(ast_str_buffer(str1))) {
+ int first_line = 1;
+- encode_mime_str(passdata2, passdata, len_passdata, strlen("From: "), strlen(who) + 3);
+- while ((ptr = strchr(passdata, ' '))) {
++ ast_str_encode_mime(&str2, 0, ast_str_buffer(str1), strlen("From: "), strlen(who) + 3);
++ while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
+ *ptr = '\0';
+- fprintf(p, "%s %s" ENDL, first_line ? "From:" : "", passdata);
++ fprintf(p, "%s %s" ENDL, first_line ? "From:" : "", ast_str_buffer(str2));
+ first_line = 0;
+- passdata = ptr + 1;
++ /* Substring is smaller, so this will never grow */
++ ast_str_set(&str2, 0, "%s", ptr + 1);
+ }
+- fprintf(p, "%s %s <%s>" ENDL, first_line ? "From:" : "", passdata, who);
++ fprintf(p, "%s %s <%s>" ENDL, first_line ? "From:" : "", ast_str_buffer(str2), who);
+ } else {
+- fprintf(p, "From: %s <%s>" ENDL, quote(passdata2, passdata, len_passdata), who);
++ fprintf(p, "From: %s <%s>" ENDL, ast_str_quote(&str2, 0, ast_str_buffer(str1)), who);
+ }
+- ast_channel_free(ast);
++ ast = ast_channel_release(ast);
+ } else {
+ ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
+ }
+@@ -4120,46 +4135,41 @@
+ if (check_mime(vmu->fullname)) {
+ int first_line = 1;
+ char *ptr;
+- encode_mime_str(vmu->fullname, passdata2, len_passdata2, strlen("To: "), strlen(vmu->email) + 3);
+- while ((ptr = strchr(passdata2, ' '))) {
++ ast_str_encode_mime(&str2, 0, vmu->fullname, strlen("To: "), strlen(vmu->email) + 3);
++ while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
+ *ptr = '\0';
+- fprintf(p, "%s %s" ENDL, first_line ? "To:" : "", passdata2);
++ fprintf(p, "%s %s" ENDL, first_line ? "To:" : "", ast_str_buffer(str2));
+ first_line = 0;
+- passdata2 = ptr + 1;
++ /* Substring is smaller, so this will never grow */
++ ast_str_set(&str2, 0, "%s", ptr + 1);
+ }
+- fprintf(p, "%s %s <%s>" ENDL, first_line ? "To:" : "", passdata2, vmu->email);
++ fprintf(p, "%s %s <%s>" ENDL, first_line ? "To:" : "", ast_str_buffer(str2), vmu->email);
+ } else {
+- fprintf(p, "To: %s <%s>" ENDL, quote(vmu->fullname, passdata2, len_passdata2), vmu->email);
++ fprintf(p, "To: %s <%s>" ENDL, ast_str_quote(&str2, 0, vmu->fullname), vmu->email);
+ }
++
+ 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(e_subj) * 3 + 200;
+- /* Only allocate more space if the previous was not large enough */
+- if (vmlen > len_passdata) {
+- passdata = alloca(vmlen);
+- len_passdata = vmlen;
+- }
+-
+- memset(passdata, 0, len_passdata);
+- 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)) {
++ prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
++ ast_str_substitute_variables(&str1, 0, ast, e_subj);
++ if (check_mime(ast_str_buffer(str1))) {
+ int first_line = 1;
+ char *ptr;
+- encode_mime_str(passdata, passdata2, len_passdata2, strlen("Subject: "), 0);
+- while ((ptr = strchr(passdata2, ' '))) {
++ ast_str_encode_mime(&str2, 0, ast_str_buffer(str1), strlen("Subject: "), 0);
++ while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
+ *ptr = '\0';
+- fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", passdata2);
++ fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", ast_str_buffer(str2));
+ first_line = 0;
+- passdata2 = ptr + 1;
++ /* Substring is smaller, so this will never grow */
++ ast_str_set(&str2, 0, "%s", ptr + 1);
+ }
+- fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", passdata2);
++ fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", ast_str_buffer(str2));
+ } else {
+- fprintf(p, "Subject: %s" ENDL, passdata);
++ fprintf(p, "Subject: %s" ENDL, ast_str_buffer(str1));
+ }
+- ast_channel_free(ast);
++ ast = ast_channel_release(ast);
+ } else {
+ ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
+ }
+@@ -4225,16 +4235,13 @@
+ 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(e_body) * 3 + 200;
+- passdata = alloca(vmlen);
+- memset(passdata, 0, vmlen);
+- 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
++ prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
++ ast_str_substitute_variables(&str1, 0, ast, e_body);
++ fprintf(p, "%s" ENDL, ast_str_buffer(str1));
++ ast = ast_channel_release(ast);
++ } else {
+ ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
++ }
+ } else if (msgnum > -1) {
+ if (strcmp(vmu->mailbox, mailbox)) {
+ /* Forwarded type */
+@@ -4299,6 +4306,8 @@
+ add_email_attachment(p, vmu, format, attach, greeting_attachment, mailbox, bound, filename, 1, msgnum);
+ }
+ }
++ ast_free(str1);
++ ast_free(str2);
+ }
+
+ 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)
+@@ -4352,7 +4361,6 @@
+ }
+ return 0;
+ }
+-#undef ENDL
+
+ 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)
+ {
+@@ -4384,6 +4392,7 @@
+
+ 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 enc_cidnum[256], enc_cidname[256];
+ char date[256];
+ char host[MAXHOSTNAMELEN] = "";
+ char who[256];
+@@ -4392,49 +4401,106 @@
+ char tmp2[PATH_MAX];
+ struct ast_tm tm;
+ FILE *p;
++ struct ast_str *str1 = ast_str_create(16), *str2 = ast_str_create(16);
+
++ if (!str1 || !str2) {
++ ast_free(str1);
++ ast_free(str2);
++ return -1;
++ }
++
++ if (cidnum) {
++ strip_control(cidnum, enc_cidnum, sizeof(enc_cidnum));
++ }
++ if (cidname) {
++ strip_control(cidname, enc_cidname, sizeof(enc_cidname));
++ }
++
+ if ((p = vm_mkftemp(tmp)) == NULL) {
+ ast_log(AST_LOG_WARNING, "Unable to launch '%s' (can't create temporary file)\n", mailcmd);
++ ast_free(str1);
++ ast_free(str2);
+ return -1;
+ }
+ gethostname(host, sizeof(host)-1);
+- if (strchr(srcemail, '@'))
++ if (strchr(srcemail, '@')) {
+ ast_copy_string(who, srcemail, sizeof(who));
+- else
++ } else {
+ snprintf(who, sizeof(who), "%s@%s", srcemail, host);
++ }
+ snprintf(dur, sizeof(dur), "%d:%02d", duration / 60, duration % 60);
+ ast_strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", vmu_tm(vmu, &tm));
+ fprintf(p, "Date: %s\n", date);
+
+- if (*pagerfromstring) {
++ if (!ast_strlen_zero(pagerfromstring)) {
+ struct ast_channel *ast;
+ if ((ast = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Substitution/voicemail"))) {
+- char *passdata;
+- int vmlen = strlen(fromstring)*3 + 200;
+- passdata = alloca(vmlen);
+- memset(passdata, 0, vmlen);
+- 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);
+- } else
++ char *ptr;
++ prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, enc_cidnum, enc_cidname, dur, date, category, flag);
++ ast_str_substitute_variables(&str1, 0, ast, pagerfromstring);
++
++ if (check_mime(ast_str_buffer(str1))) {
++ int first_line = 1;
++ ast_str_encode_mime(&str2, 0, ast_str_buffer(str1), strlen("From: "), strlen(who) + 3);
++ while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
++ *ptr = '\0';
++ fprintf(p, "%s %s" ENDL, first_line ? "From:" : "", ast_str_buffer(str2));
++ first_line = 0;
++ /* Substring is smaller, so this will never grow */
++ ast_str_set(&str2, 0, "%s", ptr + 1);
++ }
++ fprintf(p, "%s %s <%s>" ENDL, first_line ? "From:" : "", ast_str_buffer(str2), who);
++ } else {
++ fprintf(p, "From: %s <%s>" ENDL, ast_str_quote(&str2, 0, ast_str_buffer(str1)), who);
++ }
++ ast = ast_channel_release(ast);
++ } else {
+ ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
+- } else
+- fprintf(p, "From: Asterisk PBX <%s>\n", who);
+- fprintf(p, "To: %s\n", pager);
+- if (pagersubject) {
++ }
++ } else {
++ fprintf(p, "From: Asterisk PBX <%s>" ENDL, who);
++ }
++
++ if (check_mime(vmu->fullname)) {
++ int first_line = 1;
++ char *ptr;
++ ast_str_encode_mime(&str2, 0, vmu->fullname, strlen("To: "), strlen(pager) + 3);
++ while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
++ *ptr = '\0';
++ fprintf(p, "%s %s" ENDL, first_line ? "To:" : "", ast_str_buffer(str2));
++ first_line = 0;
++ /* Substring is smaller, so this will never grow */
++ ast_str_set(&str2, 0, "%s", ptr + 1);
++ }
++ fprintf(p, "%s %s <%s>" ENDL, first_line ? "To:" : "", ast_str_buffer(str2), pager);
++ } else {
++ fprintf(p, "To: %s <%s>" ENDL, ast_str_quote(&str2, 0, vmu->fullname), pager);
++ }
++
++ if (!ast_strlen_zero(pagersubject)) {
+ struct ast_channel *ast;
+ if ((ast = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Substitution/voicemail"))) {
+- char *passdata;
+- int vmlen = strlen(pagersubject) * 3 + 200;
+- passdata = alloca(vmlen);
+- memset(passdata, 0, vmlen);
+- 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);
+- } else
++ prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
++ ast_str_substitute_variables(&str1, 0, ast, pagersubject);
++ if (check_mime(ast_str_buffer(str1))) {
++ int first_line = 1;
++ char *ptr;
++ ast_str_encode_mime(&str2, 0, ast_str_buffer(str1), strlen("Subject: "), 0);
++ while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
++ *ptr = '\0';
++ fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", ast_str_buffer(str2));
++ first_line = 0;
++ /* Substring is smaller, so this will never grow */
++ ast_str_set(&str2, 0, "%s", ptr + 1);
++ }
++ fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", ast_str_buffer(str2));
++ } else {
++ fprintf(p, "Subject: %s" ENDL, ast_str_buffer(str1));
++ }
++ ast = ast_channel_release(ast);
++ } else {
+ ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
++ }
+ } else {
+ if (ast_strlen_zero(flag)) {
+ fprintf(p, "Subject: New VM\n\n");
+@@ -4447,26 +4513,27 @@
+ if (pagerbody) {
+ struct ast_channel *ast;
+ if ((ast = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Substitution/voicemail"))) {
+- char *passdata;
+- int vmlen = strlen(pagerbody) * 3 + 200;
+- passdata = alloca(vmlen);
+- memset(passdata, 0, vmlen);
+- 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);
+- } else
++ prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
++ ast_str_substitute_variables(&str1, 0, ast, pagerbody);
++ fprintf(p, "%s" ENDL, ast_str_buffer(str1));
++ ast = ast_channel_release(ast);
++ } else {
+ ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
++ }
+ } else {
+ fprintf(p, "New %s long %s msg in box %s\n"
+ "from %s, on %s", dur, flag, mailbox, (cidname ? cidname : (cidnum ? cidnum : "unknown")), date);
+ }
++
+ fclose(p);
+ snprintf(tmp2, sizeof(tmp2), "( %s < %s ; rm -f %s ) &", mailcmd, tmp, tmp);
+ ast_safe_system(tmp2);
+ ast_debug(1, "Sent page to %s with command '%s'\n", pager, mailcmd);
++ ast_free(str1);
++ ast_free(str2);
+ return 0;
+ }
++#undef ENDL
+
+ /*!
+ * \brief Gets the current date and time, as formatted string.
+@@ -5037,8 +5104,11 @@
+ const char *alldtmf = "0123456789ABCD*#";
+ char flag[80];
+
+- ast_str_set(&tmp, 0, "%s", ext);
+- ext = ast_str_buffer(tmp);
++ if (!tmp) {
++ return -1;
++ }
++
++ ext = ast_strdupa(ext);
+ if ((context = strchr(ext, '@'))) {
+ *context++ = '\0';
+ tmpptr = strchr(context, '&');
+@@ -8894,7 +8964,7 @@
+ return 0;
+ }
+
+-static int vm_execmain(struct ast_channel *chan, void *data)
++static int vm_execmain(struct ast_channel *chan, const char *data)
+ {
+ /* XXX This is, admittedly, some pretty horrendous code. For some
+ reason it just seemed a lot easier to do with GOTO's. I feel
+@@ -9602,7 +9672,7 @@
+ return res;
+ }
+
+-static int vm_exec(struct ast_channel *chan, void *data)
++static int vm_exec(struct ast_channel *chan, const char *data)
+ {
+ int res = 0;
+ char *tmp;
+@@ -9734,7 +9804,7 @@
+ return 0;
+ }
+
+-static int vm_box_exists(struct ast_channel *chan, void *data)
++static int vm_box_exists(struct ast_channel *chan, const char *data)
+ {
+ struct ast_vm_user svm;
+ char *context, *box;
+@@ -9798,16 +9868,16 @@
+ .read = acf_mailbox_exists,
+ };
+
+-static int vmauthenticate(struct ast_channel *chan, void *data)
++static int vmauthenticate(struct ast_channel *chan, const char *data)
+ {
+- char *s = data, *user=NULL, *context=NULL, mailbox[AST_MAX_EXTENSION] = "";
++ char *s, *user=NULL, *context=NULL, mailbox[AST_MAX_EXTENSION] = "";
+ struct ast_vm_user vmus;
+ char *options = NULL;
+ int silent = 0, skipuser = 0;
+ int res = -1;
+
+- if (s) {
+- s = ast_strdupa(s);
++ if (data) {
++ s = ast_strdupa(data);
+ user = strsep(&s, ",");
+ options = strsep(&s, ",");
+ if (user) {
+@@ -10637,10 +10707,10 @@
+ if ((val = ast_variable_retrieve(cfg, "general", "smdienable")) && ast_true(val)) {
+ ast_debug(1, "Enabled SMDI voicemail notification\n");
+ if ((val = ast_variable_retrieve(cfg, "general", "smdiport"))) {
+- smdi_iface = ast_smdi_interface_find ? ast_smdi_interface_find(val) : NULL;
++ smdi_iface = ast_smdi_interface_find(val);
+ } else {
+ ast_debug(1, "No SMDI interface set, trying default (/dev/ttyS0)\n");
+- smdi_iface = ast_smdi_interface_find ? ast_smdi_interface_find("/dev/ttyS0") : NULL;
++ smdi_iface = ast_smdi_interface_find("/dev/ttyS0");
+ }
+ if (!smdi_iface) {
+ ast_log(AST_LOG_ERROR, "No valid SMDI interface specfied, disabling SMDI voicemail notification\n");
+@@ -11098,7 +11168,7 @@
+ 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");
++ res |= ast_manager_register_xml("VoicemailUsersList", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, manager_list_voicemail_users);
+ if (res)
+ return res;
+
+Index: apps/app_dial.c
+===================================================================
+--- a/apps/app_dial.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/apps/app_dial.c (.../trunk) (revision 202568)
+@@ -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>
+@@ -131,6 +133,10 @@
+ <para>When the caller hangs up, transfer the called party
+ to the specified destination and continue execution at that location.</para>
+ </option>
++ <option name="F">
++ <para>Proceed with dialplan execution at the next priority in the current extension if the
++ source channel hangs up.</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>
+@@ -155,6 +161,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>
+@@ -363,6 +373,9 @@
+ <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>
++ <option name="z">
++ <para>On a call forward, cancel any dial timeout which has been set for this call.</para>
++ </option>
+ </optionlist>
+ </parameter>
+ <parameter name="URL">
+@@ -383,7 +396,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
+@@ -453,8 +465,8 @@
+ </application>
+ ***/
+
+-static char *app = "Dial";
+-static char *rapp = "RetryDial";
++static const char app[] = "Dial";
++static const char rapp[] = "RetryDial";
+
+ enum {
+ OPT_ANNOUNCE = (1 << 0),
+@@ -465,12 +477,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),
+@@ -491,9 +504,11 @@
+
+ #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)
++#define OPT_CANCEL_TIMEOUT ((uint64_t)1 << 37)
+
+ enum {
+ OPT_ARG_ANNOUNCE = 0,
+@@ -525,13 +540,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),
+@@ -545,6 +561,7 @@
+ AST_APP_OPTION('W', OPT_CALLER_MONITOR),
+ AST_APP_OPTION('x', OPT_CALLEE_MIXMONITOR),
+ AST_APP_OPTION('X', OPT_CALLER_MIXMONITOR),
++ AST_APP_OPTION('z', OPT_CANCEL_TIMEOUT),
+ END_OPTIONS );
+
+ #define CAN_EARLY_BRIDGE(flags,chan,peer) (!ast_test_flag64(flags, OPT_CALLEE_HANGUP | \
+@@ -559,8 +576,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)
+ {
+@@ -575,6 +594,7 @@
+ /* This is for the channel drivers */
+ outgoing->chan->hangupcause = AST_CAUSE_ANSWERED_ELSEWHERE;
+ }
++ ast_party_connected_line_free(&outgoing->connected);
+ ast_hangup(outgoing->chan);
+ }
+ oo = outgoing;
+@@ -659,12 +679,17 @@
+ return 0;
+ }
+
+-
++/* do not call with chan lock held */
+ 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);
++ const char *context;
++ const char *exten;
+
++ ast_channel_lock(chan);
++ context = ast_strdupa(S_OR(chan->macrocontext, chan->context));
++ exten = ast_strdupa(S_OR(chan->macroexten, chan->exten));
++ ast_channel_unlock(chan);
++
+ return ast_get_hint(NULL, 0, name, namelen, chan, context, exten) ? name : "";
+ }
+
+@@ -699,14 +724,18 @@
+ *
+ * XXX this code is highly suspicious, as it essentially overwrites
+ * the outgoing channel without properly deleting it.
++ *
++ * \todo eventually this function should be intergrated into and replaced by ast_call_forward()
+ */
+ static void do_forward(struct chanlist *o,
+- struct cause_args *num, struct ast_flags64 *peerflags, int single)
++ struct cause_args *num, struct ast_flags64 *peerflags, int single, int *to)
+ {
+ char tmpchan[256];
+ 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;
+@@ -750,28 +779,42 @@
+ 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(in->cid.cid_rdnis, ast_strdup(c->cid.cid_rdnis));
++ ast_channel_update_redirecting(in, apr);
++
++ ast_clear_flag64(peerflags, OPT_IGNORE_CONNECTEDLINE);
++ if (ast_test_flag64(peerflags, OPT_CANCEL_TIMEOUT)) {
++ *to = -1;
+ }
+- S_REPLACE(c->cid.cid_rdnis, ast_strdup(S_OR(in->macroexten, in->exten)));
++
++ ast_channel_unlock(in);
++ ast_channel_unlock(c);
++
+ 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);
+@@ -780,11 +823,21 @@
+ c = o->chan = NULL;
+ num->nochan++;
+ } else {
++ ast_channel_lock(c);
++ while (ast_channel_trylock(in)) {
++ CHANNEL_DEADLOCK_AVOIDANCE(c);
++ }
+ 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);
++ const char *tmpexten;
++ tmpexten = ast_strdupa(S_OR(in->macroexten, in->exten));
++ ast_channel_unlock(in);
++ ast_channel_unlock(c);
++ ast_set_callerid(c, tmpexten, get_cid_name(cidname, sizeof(cidname), in), NULL);
++ } else {
++ ast_channel_unlock(in);
++ ast_channel_unlock(c);
+ }
+ /* Hangup the original channel now, in case we needed it */
+ ast_hangup(original);
+@@ -807,23 +860,37 @@
+ 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);
+
++ ast_party_connected_line_init(&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_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
+@@ -870,6 +937,20 @@
+ 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) {
++ if (ast_channel_connected_line_macro(c, in, &o->connected, 1, 0)) {
++ 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 |
+@@ -887,7 +968,7 @@
+ continue;
+ /* here, o->chan == c == winner */
+ if (!ast_strlen_zero(c->call_forward)) {
+- do_forward(o, &num, peerflags, single);
++ do_forward(o, &num, peerflags, single, to);
+ continue;
+ }
+ f = ast_read(winner);
+@@ -908,6 +989,20 @@
+ /* 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) {
++ if (ast_channel_connected_line_macro(c, in, &o->connected, 1, 0)) {
++ 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();
+@@ -963,6 +1058,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);
+@@ -972,6 +1071,30 @@
+ 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 {
++ if (ast_channel_connected_line_macro(c, in, f, 1, 1)) {
++ 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))
+@@ -1063,8 +1186,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);
+@@ -1082,13 +1205,19 @@
+ if (ast_write(outgoing->chan, f))
+ ast_log(LOG_WARNING, "Unable to forward voice or dtmf\n");
+ }
+- if (single && (f->frametype == AST_FRAME_CONTROL) &&
+- ((f->subclass == AST_CONTROL_HOLD) ||
+- (f->subclass == AST_CONTROL_UNHOLD) ||
+- (f->subclass == AST_CONTROL_VIDUPDATE) ||
+- (f->subclass == AST_CONTROL_SRCUPDATE))) {
+- 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);
++ if (single && (f->frametype == AST_FRAME_CONTROL)) {
++ if ((f->subclass == AST_CONTROL_HOLD) ||
++ (f->subclass == AST_CONTROL_UNHOLD) ||
++ (f->subclass == AST_CONTROL_VIDUPDATE) ||
++ (f->subclass == AST_CONTROL_SRCUPDATE) ||
++ (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);
++ } else if (f->subclass == AST_CONTROL_CONNECTED_LINE) {
++ if (ast_channel_connected_line_macro(in, outgoing->chan, f, 0, 1)) {
++ ast_indicate_data(outgoing->chan, f->subclass, f->data.ptr, f->datalen);
++ }
++ }
+ }
+ ast_frfree(f);
+ }
+@@ -1108,6 +1237,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++)
+@@ -1316,7 +1465,7 @@
+ ast_autoservice_stop(chan);
+ if (ast_test_flag64(opts, OPT_PRIVACY) && (res2 >= '1' && res2 <= '5')) {
+ /* map keypresses to various things, the index is res2 - '1' */
+- static const char *_val[] = { "ALLOW", "DENY", "TORTURE", "KILL", "ALLOW" };
++ static const char * const _val[] = { "ALLOW", "DENY", "TORTURE", "KILL", "ALLOW" };
+ static const int _flag[] = { AST_PRIVACY_ALLOW, AST_PRIVACY_DENY, AST_PRIVACY_TORTURE, AST_PRIVACY_KILL, AST_PRIVACY_ALLOW};
+ int i = res2 - '1';
+ ast_verb(3, "--Set privacy database entry %s/%s to %s\n",
+@@ -1405,11 +1554,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);
+ }
+
+@@ -1499,7 +1648,7 @@
+ bconfig->end_bridge_callback_data = originator;
+ }
+
+-static int dial_exec_full(struct ast_channel *chan, void *data, struct ast_flags64 *peerflags, int *continue_exec)
++static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast_flags64 *peerflags, int *continue_exec)
+ {
+ int res = -1; /* default: error */
+ char *rest, *cur; /* scan the list of destinations */
+@@ -1513,7 +1662,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,
+@@ -1564,12 +1713,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) {
+@@ -1581,8 +1729,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])) {
+@@ -1602,7 +1751,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);
+ }
+
+@@ -1619,7 +1768,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 | OPT_CANCEL_TIMEOUT);
+
+ /* loop through the list of dial destinations */
+ rest = args.peers;
+@@ -1656,6 +1805,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)
+@@ -1728,8 +1885,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);
+@@ -1739,20 +1902,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;
+
+@@ -1775,6 +1949,7 @@
+ else
+ ast_copy_string(tc->exten, chan->exten, sizeof(tc->exten));
+
++ ast_channel_unlock(tc);
+ 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 */
+@@ -1789,15 +1964,19 @@
+ if (tc->hangupcause) {
+ chan->hangupcause = tc->hangupcause;
+ }
++ ast_channel_unlock(chan);
+ ast_hangup(tc);
+ tc = NULL;
+ ast_free(tmp);
+ continue;
+ } else {
++ const char *tmpexten = ast_strdupa(S_OR(chan->macroexten, chan->exten));
+ 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);
++ ast_channel_unlock(chan);
++ if (!ast_test_flag64(peerflags, OPT_ORIGINAL_CLID)) {
++ ast_set_callerid(tc, tmpexten, 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
+@@ -1849,7 +2028,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
+@@ -2206,9 +2385,18 @@
+ }
+ ast_set2_flag(peer, autoloopflag, AST_FLAG_IN_AUTOLOOP); /* set it back the way it was */
+ }
+- if (!ast_check_hangup(peer) && ast_test_flag64(&opts, OPT_CALLEE_GO_ON) && !ast_strlen_zero(opt_args[OPT_ARG_CALLEE_GO_ON])) {
+- replace_macro_delimiter(opt_args[OPT_ARG_CALLEE_GO_ON]);
+- ast_parseable_goto(peer, opt_args[OPT_ARG_CALLEE_GO_ON]);
++ if (!ast_check_hangup(peer) && ast_test_flag64(&opts, OPT_CALLEE_GO_ON)) {
++ if(!ast_strlen_zero(opt_args[OPT_ARG_CALLEE_GO_ON])) {
++ replace_macro_delimiter(opt_args[OPT_ARG_CALLEE_GO_ON]);
++ ast_parseable_goto(peer, opt_args[OPT_ARG_CALLEE_GO_ON]);
++ } else { /* F() */
++ int res;
++ res = ast_goto_if_exists(peer, chan->context, chan->exten, (chan->priority) + 1);
++ if (res == AST_PBX_GOTO_FAILED) {
++ ast_hangup(peer);
++ goto out;
++ }
++ }
+ ast_pbx_start(peer);
+ } else {
+ if (!ast_check_hangup(chan))
+@@ -2249,7 +2437,7 @@
+ return res;
+ }
+
+-static int dial_exec(struct ast_channel *chan, void *data)
++static int dial_exec(struct ast_channel *chan, const char *data)
+ {
+ struct ast_flags64 peerflags;
+
+@@ -2258,7 +2446,7 @@
+ return dial_exec_full(chan, data, &peerflags, NULL);
+ }
+
+-static int retrydial_exec(struct ast_channel *chan, void *data)
++static int retrydial_exec(struct ast_channel *chan, const char *data)
+ {
+ char *parse;
+ const char *context = NULL;
+Index: apps/app_nbscat.c
+===================================================================
+--- a/apps/app_nbscat.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/apps/app_nbscat.c (.../trunk) (revision 202568)
+@@ -105,7 +105,7 @@
+
+ }
+
+-static int NBScat_exec(struct ast_channel *chan, void *data)
++static int NBScat_exec(struct ast_channel *chan, const char *data)
+ {
+ int res=0;
+ int fds[2];
+Index: apps/app_page.c
+===================================================================
+--- a/apps/app_page.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/apps/app_page.c (.../trunk) (revision 202568)
+@@ -99,15 +99,15 @@
+ </see-also>
+ </application>
+ ***/
+-static const char *app_page= "Page";
++static const char * const app_page= "Page";
+
+-enum {
++enum page_opt_flags {
+ 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, {
+ AST_APP_OPTION('d', PAGE_DUPLEX),
+@@ -118,7 +118,7 @@
+ });
+
+
+-static int page_exec(struct ast_channel *chan, void *data)
++static int page_exec(struct ast_channel *chan, const char *data)
+ {
+ char *tech, *resource, *tmp;
+ char meetmeopts[88], originator[AST_CHANNEL_NAME], *opts[0];
+Index: apps/app_echo.c
+===================================================================
+--- a/apps/app_echo.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/apps/app_echo.c (.../trunk) (revision 202568)
+@@ -46,9 +46,9 @@
+ </application>
+ ***/
+
+-static char *app = "Echo";
++static const char app[] = "Echo";
+
+-static int echo_exec(struct ast_channel *chan, void *data)
++static int echo_exec(struct ast_channel *chan, const char *data)
+ {
+ int res = -1;
+ int format;
+Index: apps/app_waitforsilence.c
+===================================================================
+--- a/apps/app_waitforsilence.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/apps/app_waitforsilence.c (.../trunk) (revision 202568)
+@@ -202,7 +202,7 @@
+ return res;
+ }
+
+-static int waitfor_exec(struct ast_channel *chan, void *data, int wait_for_silence)
++static int waitfor_exec(struct ast_channel *chan, const char *data, int wait_for_silence)
+ {
+ int res = 1;
+ int timereqd = 1000;
+@@ -232,12 +232,12 @@
+ return res;
+ }
+
+-static int waitforsilence_exec(struct ast_channel *chan, void *data)
++static int waitforsilence_exec(struct ast_channel *chan, const char *data)
+ {
+ return waitfor_exec(chan, data, 1);
+ }
+
+-static int waitfornoise_exec(struct ast_channel *chan, void *data)
++static int waitfornoise_exec(struct ast_channel *chan, const char *data)
+ {
+ return waitfor_exec(chan, data, 0);
+ }
+Index: apps/app_sayunixtime.c
+===================================================================
+--- a/apps/app_sayunixtime.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/apps/app_sayunixtime.c (.../trunk) (revision 202568)
+@@ -89,7 +89,7 @@
+ static char *app_sayunixtime = "SayUnixTime";
+ static char *app_datetime = "DateTime";
+
+-static int sayunixtime_exec(struct ast_channel *chan, void *data)
++static int sayunixtime_exec(struct ast_channel *chan, const char *data)
+ {
+ AST_DECLARE_APP_ARGS(args,
+ AST_APP_ARG(timeval);
+Index: apps/app_readexten.c
+===================================================================
+--- a/apps/app_readexten.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/apps/app_readexten.c (.../trunk) (revision 202568)
+@@ -111,11 +111,11 @@
+ </function>
+ ***/
+
+-enum {
++enum readexten_option_flags {
+ OPT_SKIP = (1 << 0),
+ OPT_INDICATION = (1 << 1),
+ OPT_NOANSWER = (1 << 2),
+-} readexten_option_flags;
++};
+
+ AST_APP_OPTIONS(readexten_app_options, {
+ AST_APP_OPTION('s', OPT_SKIP),
+@@ -125,7 +125,7 @@
+
+ static char *app = "ReadExten";
+
+-static int readexten_exec(struct ast_channel *chan, void *data)
++static int readexten_exec(struct ast_channel *chan, const char *data)
+ {
+ int res = 0;
+ char exten[256] = "";
+Index: apps/app_dahdiras.c
+===================================================================
+--- a/apps/app_dahdiras.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/apps/app_dahdiras.c (.../trunk) (revision 202568)
+@@ -73,7 +73,7 @@
+
+ ***/
+
+-static char *app = "DAHDIRAS";
++static const char app[] = "DAHDIRAS";
+
+ #define PPP_MAX_ARGS 32
+ #define PPP_EXEC "/usr/sbin/pppd"
+@@ -187,7 +187,7 @@
+ ast_safe_fork_cleanup();
+ }
+
+-static int dahdiras_exec(struct ast_channel *chan, void *data)
++static int dahdiras_exec(struct ast_channel *chan, const char *data)
+ {
+ int res=-1;
+ char *args;
+Index: apps/app_disa.c
+===================================================================
+--- a/apps/app_disa.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/apps/app_disa.c (.../trunk) (revision 202568)
+@@ -110,12 +110,12 @@
+ </see-also>
+ </application>
+ ***/
+-static char *app = "DISA";
++static const char app[] = "DISA";
+
+ enum {
+ NOANSWER_FLAG = (1 << 0),
+ POUND_TO_END_FLAG = (1 << 1),
+-} option_flags;
++};
+
+ AST_APP_OPTIONS(app_opts, {
+ AST_APP_OPTION('n', NOANSWER_FLAG),
+@@ -140,7 +140,7 @@
+ }
+ }
+
+-static int disa_exec(struct ast_channel *chan, void *data)
++static int disa_exec(struct ast_channel *chan, const char *data)
+ {
+ int i = 0, j, k = 0, did_ignore = 0, special_noanswer = 0;
+ int firstdigittimeout = (chan->pbx ? chan->pbx->rtimeoutms : 20000);
+Index: apps/app_userevent.c
+===================================================================
+--- a/apps/app_userevent.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/apps/app_userevent.c (.../trunk) (revision 202568)
+@@ -56,7 +56,7 @@
+
+ static char *app = "UserEvent";
+
+-static int userevent_exec(struct ast_channel *chan, void *data)
++static int userevent_exec(struct ast_channel *chan, const char *data)
+ {
+ char *parse;
+ int x;
+Index: apps/app_chanisavail.c
+===================================================================
+--- a/apps/app_chanisavail.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/apps/app_chanisavail.c (.../trunk) (revision 202568)
+@@ -41,7 +41,7 @@
+ #include "asterisk/app.h"
+ #include "asterisk/devicestate.h"
+
+-static char *app = "ChanIsAvail";
++static const char app[] = "ChanIsAvail";
+
+ /*** DOCUMENTATION
+ <application name="ChanIsAvail" language="en_US">
+@@ -92,7 +92,7 @@
+ </application>
+ ***/
+
+-static int chanavail_exec(struct ast_channel *chan, void *data)
++static int chanavail_exec(struct ast_channel *chan, const char *data)
+ {
+ int inuse=-1, option_state=0, string_compare=0, option_all_avail=0;
+ int status;
+Index: apps/app_system.c
+===================================================================
+--- a/apps/app_system.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/apps/app_system.c (.../trunk) (revision 202568)
+@@ -100,7 +100,7 @@
+
+ static char *chanvar = "SYSTEMSTATUS";
+
+-static int system_exec_helper(struct ast_channel *chan, void *data, int failmode)
++static int system_exec_helper(struct ast_channel *chan, const char *data, int failmode)
+ {
+ int res = 0;
+ struct ast_str *buf = ast_str_thread_get(&buf_buf, 16);
+@@ -140,12 +140,12 @@
+ return res;
+ }
+
+-static int system_exec(struct ast_channel *chan, void *data)
++static int system_exec(struct ast_channel *chan, const char *data)
+ {
+ return system_exec_helper(chan, data, -1);
+ }
+
+-static int trysystem_exec(struct ast_channel *chan, void *data)
++static int trysystem_exec(struct ast_channel *chan, const char *data)
+ {
+ return system_exec_helper(chan, data, 0);
+ }
+Index: apps/app_transfer.c
+===================================================================
+--- a/apps/app_transfer.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/apps/app_transfer.c (.../trunk) (revision 202568)
+@@ -72,9 +72,9 @@
+ </application>
+ ***/
+
+-static const char *app = "Transfer";
++static const char * const app = "Transfer";
+
+-static int transfer_exec(struct ast_channel *chan, void *data)
++static int transfer_exec(struct ast_channel *chan, const char *data)
+ {
+ int res;
+ int len;
+Index: apps/app_playback.c
+===================================================================
+--- a/apps/app_playback.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/apps/app_playback.c (.../trunk) (revision 202568)
+@@ -90,8 +90,8 @@
+ * 'say load [new|old]' will enable the new or old method, or report status
+ */
+ static const void *say_api_buf[40];
+-static const char *say_old = "old";
+-static const char *say_new = "new";
++static const char * const say_old = "old";
++static const char * const say_new = "new";
+
+ static void save_say_mode(const void *arg)
+ {
+@@ -380,7 +380,7 @@
+ static char *__say_cli_init(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+ {
+ const char *old_mode = say_api_buf[0] ? say_new : say_old;
+- char *mode;
++ const char *mode;
+ switch (cmd) {
+ case CLI_INIT:
+ e->command = "say load [new|old]";
+@@ -415,7 +415,7 @@
+ AST_CLI_DEFINE(__say_cli_init, "Set or show the say mode"),
+ };
+
+-static int playback_exec(struct ast_channel *chan, void *data)
++static int playback_exec(struct ast_channel *chan, const char *data)
+ {
+ int res = 0;
+ int mres = 0;
+Index: apps/app_speech_utils.c
+===================================================================
+--- a/apps/app_speech_utils.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/apps/app_speech_utils.c (.../trunk) (revision 202568)
+@@ -481,7 +481,7 @@
+
+
+ /*! \brief SpeechCreate() Dialplan Application */
+-static int speech_create(struct ast_channel *chan, void *data)
++static int speech_create(struct ast_channel *chan, const char *data)
+ {
+ struct ast_speech *speech = NULL;
+ struct ast_datastore *datastore = NULL;
+@@ -508,7 +508,7 @@
+ }
+
+ /*! \brief SpeechLoadGrammar(Grammar Name,Path) Dialplan Application */
+-static int speech_load(struct ast_channel *chan, void *vdata)
++static int speech_load(struct ast_channel *chan, const char *vdata)
+ {
+ int res = 0;
+ struct ast_speech *speech = find_speech(chan);
+@@ -534,7 +534,7 @@
+ }
+
+ /*! \brief SpeechUnloadGrammar(Grammar Name) Dialplan Application */
+-static int speech_unload(struct ast_channel *chan, void *data)
++static int speech_unload(struct ast_channel *chan, const char *data)
+ {
+ int res = 0;
+ struct ast_speech *speech = find_speech(chan);
+@@ -549,7 +549,7 @@
+ }
+
+ /*! \brief SpeechDeactivateGrammar(Grammar Name) Dialplan Application */
+-static int speech_deactivate(struct ast_channel *chan, void *data)
++static int speech_deactivate(struct ast_channel *chan, const char *data)
+ {
+ int res = 0;
+ struct ast_speech *speech = find_speech(chan);
+@@ -564,7 +564,7 @@
+ }
+
+ /*! \brief SpeechActivateGrammar(Grammar Name) Dialplan Application */
+-static int speech_activate(struct ast_channel *chan, void *data)
++static int speech_activate(struct ast_channel *chan, const char *data)
+ {
+ int res = 0;
+ struct ast_speech *speech = find_speech(chan);
+@@ -579,7 +579,7 @@
+ }
+
+ /*! \brief SpeechStart() Dialplan Application */
+-static int speech_start(struct ast_channel *chan, void *data)
++static int speech_start(struct ast_channel *chan, const char *data)
+ {
+ int res = 0;
+ struct ast_speech *speech = find_speech(chan);
+@@ -593,7 +593,7 @@
+ }
+
+ /*! \brief SpeechProcessingSound(Sound File) Dialplan Application */
+-static int speech_processing_sound(struct ast_channel *chan, void *data)
++static int speech_processing_sound(struct ast_channel *chan, const char *data)
+ {
+ int res = 0;
+ struct ast_speech *speech = find_speech(chan);
+@@ -636,7 +636,7 @@
+ END_OPTIONS );
+
+ /*! \brief SpeechBackground(Sound File,Timeout) Dialplan Application */
+-static int speech_background(struct ast_channel *chan, void *data)
++static int speech_background(struct ast_channel *chan, const char *data)
+ {
+ unsigned int timeout = 0;
+ int res = 0, done = 0, started = 0, quieted = 0, max_dtmf_len = 0;
+@@ -888,7 +888,7 @@
+
+
+ /*! \brief SpeechDestroy() Dialplan Application */
+-static int speech_destroy(struct ast_channel *chan, void *data)
++static int speech_destroy(struct ast_channel *chan, const char *data)
+ {
+ int res = 0;
+ struct ast_speech *speech = find_speech(chan);
+Index: apps/app_osplookup.c
+===================================================================
+--- a/apps/app_osplookup.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/apps/app_osplookup.c (.../trunk) (revision 202568)
+@@ -39,6 +39,7 @@
+
+ #include <osp/osp.h>
+ #include <osp/osputils.h>
++#include <osp/ospb64.h>
+
+ #include "asterisk/paths.h"
+ #include "asterisk/lock.h"
+@@ -52,9 +53,162 @@
+ #include "asterisk/cli.h"
+ #include "asterisk/astosp.h"
+
++/*** DOCUMENTATION
++ <application name="OSPAuth" language="en_US">
++ <synopsis>
++ OSP Authentication.
++ </synopsis>
++ <syntax>
++ <parameter name="provider" />
++ <parameter name="options" />
++ </syntax>
++ <description>
++ <para>Authenticate a SIP INVITE by OSP and sets the variables:</para>
++ <variablelist>
++ <variable name="OSPINHANDLE">
++ <para>The inbound call transaction handle.</para>
++ </variable>
++ <variable name="OSPINTIMELIMIT">
++ <para>The inbound call duration limit in seconds.</para>
++ </variable>
++ </variablelist>
++ <para>This application sets the following channel variable upon completion:</para>
++ <variablelist>
++ <variable name="OSPAUTHSTATUS">
++ <para>The status of the OSP Auth attempt as a text string, one of</para>
++ <value name="SUCCESS" />
++ <value name="FAILED" />
++ <value name="ERROR" />
++ </variable>
++ </variablelist>
++ </description>
++ </application>
++ <application name="OSPLookup" language="en_US">
++ <synopsis>
++ Lookup destination by OSP.
++ </synopsis>
++ <syntax>
++ <parameter name="exten" required="true" />
++ <parameter name="provider" />
++ <parameter name="options">
++ <enumlist>
++ <enum name="h">
++ <para>generate H323 call id for the outbound call</para>
++ </enum>
++ <enum name="s">
++ <para>generate SIP call id for the outbound call.
++ Have not been implemented</para>
++ </enum>
++ <enum name="i">
++ <para>generate IAX call id for the outbound call.
++ Have not been implemented</para>
++ </enum>
++ </enumlist>
++ </parameter>
++ </syntax>
++ <description>
++ <para>Looks up an extension via OSP and sets the variables, where <literal>n</literal> is the
++ number of the result beginning with <literal>1</literal>:</para>
++ <variablelist>
++ <variable name="OSPOUTHANDLE">
++ <para>The OSP Handle for anything remaining.</para>
++ </variable>
++ <variable name="OSPTECH">
++ <para>The technology to use for the call.</para>
++ </variable>
++ <variable name="OSPDEST">
++ <para>The destination to use for the call.</para>
++ </variable>
++ <variable name="OSPCALLED">
++ <para>The called number to use for the call.</para>
++ </variable>
++ <variable name="OSPCALLING">
++ <para>The calling number to use for the call.</para>
++ </variable>
++ <variable name="OSPDIALSTR">
++ <para>The dial command string.</para>
++ </variable>
++ <variable name="OSPOUTTOKEN">
++ <para>The actual OSP token as a string.</para>
++ </variable>
++ <variable name="OSPOUTTIMELIMIT">
++ <para>The outbound call duraction limit in seconds.</para>
++ </variable>
++ <variable name="OSPOUTCALLIDTYPES">
++ <para>The outbound call id types.</para>
++ </variable>
++ <variable name="OSPOUTCALLID">
++ <para>The outbound call id.</para>
++ </variable>
++ <variable name="OSPRESULTS">
++ <para>The number of OSP results total remaining.</para>
++ </variable>
++ </variablelist>
++ <variablelist>
++ <variable name="OSPLOOKUPSTATUS">
++ <para>This application sets the following channel variable upon completion:</para>
++ <value name="SUCCESS" />
++ <value name="FAILED" />
++ <value name="ERROR" />
++ </variable>
++ </variablelist>
++ </description>
++ </application>
++ <application name="OSPNext" language="en_US">
++ <synopsis>
++ Lookup next destination by OSP.
++ </synopsis>
++ <syntax>
++ <parameter name="cause" required="true" />
++ <parameter name="provider" />
++ <parameter name="options" />
++ </syntax>
++ <description>
++ <para>Looks up the next OSP Destination for <variable>OSPOUTHANDLE</variable>.</para>
++ <para>This application sets the following channel variable upon completion:</para>
++ <variablelist>
++ <variable name="OSPNEXTSTATUS">
++ <para>The status of the OSP Next attempt as a text string, one of</para>
++ <value name="SUCCESS" />
++ <value name="FAILED" />
++ <value name="ERROR" />
++ </variable>
++ </variablelist>
++ </description>
++ <see-also>
++ <ref type="application">OSPLookup</ref>
++ </see-also>
++ </application>
++ <application name="OSPFinish" language="en_US">
++ <synopsis>
++ Record OSP entry.
++ </synopsis>
++ <syntax>
++ <parameter name="status" />
++ <parameter name="options" />
++ </syntax>
++ <description>
++ <para>Records call state for <variable>OSPINHANDLE</variable>, according to status, which should
++ be one of <literal>BUSY</literal>, <literal>CONGESTION</literal>, <literal>ANSWER</literal>,
++ <literal>NOANSWER</literal>, or <literal>CHANUNAVAIL</literal> or coincidentally, just what the
++ Dial application stores in its <variable>DIALSTATUS</variable>.</para>
++ <para>This application sets the following channel variable upon completion:</para>
++ <variablelist>
++ <variable name="OSPFINISHSTATUS">
++ <para>The status of the OSP Finish attempt as a text string, one of</para>
++ <value name="SUCCESS" />
++ <value name="FAILED" />
++ <value name="ERROR" />
++ </variable>
++ </variablelist>
++ </description>
++ </application>
++ ***/
++
+ /* OSP Buffer Sizes */
+ #define OSP_INTSTR_SIZE ((unsigned int)16) /* OSP signed/unsigned int string buffer size */
+ #define OSP_NORSTR_SIZE ((unsigned int)256) /* OSP normal string buffer size */
++#define OSP_KEYSTR_SIZE ((unsigned int)1024) /* OSP certificate string buffer size */
+ #define OSP_TOKSTR_SIZE ((unsigned int)4096) /* OSP token string buffer size */
+ #define OSP_TECHSTR_SIZE ((unsigned int)32) /* OSP signed/unsigned int string buffer size */
+ #define OSP_UUID_SIZE ((unsigned int)16) /* UUID size */
+@@ -127,7 +281,7 @@
+ char privatekey[OSP_NORSTR_SIZE]; /* OSP private key file name */
+ char localcert[OSP_NORSTR_SIZE]; /* OSP local cert file name */
+ unsigned int cacount; /* Number of cacerts */
+- char cacerts[OSP_MAX_CERTS][OSP_NORSTR_SIZE]; /* Cacert file names */
++ char cacerts[OSP_MAX_CERTS][OSP_NORSTR_SIZE]; /* Cacert file names */
+ unsigned int spcount; /* Number of service points */
+ char srvpoints[OSP_MAX_SRVS][OSP_NORSTR_SIZE]; /* Service point URLs */
+ int maxconnections; /* Max number of connections */
+@@ -167,9 +321,15 @@
+ AST_MUTEX_DEFINE_STATIC(osplock); /* Lock of OSP provider list */
+ static int osp_initialized = 0; /* Init flag */
+ static int osp_hardware = 0; /* Hardware accelleration flag */
++static int osp_security = 0; /* Using security features flag */
+ static struct osp_provider* ospproviders = NULL; /* OSP provider list */
+ static unsigned int osp_tokenformat = TOKEN_ALGO_SIGNED; /* Token format supported */
+
++/* OSP default certificates */
++const char* B64PKey = "MIIBOgIBAAJBAK8t5l+PUbTC4lvwlNxV5lpl+2dwSZGW46dowTe6y133XyVEwNiiRma2YNk3xKs/TJ3Wl9Wpns2SYEAJsFfSTukCAwEAAQJAPz13vCm2GmZ8Zyp74usTxLCqSJZNyMRLHQWBM0g44Iuy4wE3vpi7Wq+xYuSOH2mu4OddnxswCP4QhaXVQavTAQIhAOBVCKXtppEw9UaOBL4vW0Ed/6EA/1D8hDW6St0h7EXJAiEAx+iRmZKhJD6VT84dtX5ZYNVk3j3dAcIOovpzUj9a0CECIEduTCapmZQ5xqAEsLXuVlxRtQgLTUD4ZxDElPn8x0MhAiBE2HlcND0+qDbvtwJQQOUzDgqg5xk3w8capboVdzAlQQIhAMC+lDL7+gDYkNAft5Mu+NObJmQs4Cr+DkDFsKqoxqrm";
++const char* B64LCert = "MIIBeTCCASMCEHqkOHVRRWr+1COq3CR/xsowDQYJKoZIhvcNAQEEBQAwOzElMCMGA1UEAxMcb3NwdGVzdHNlcnZlci50cmFuc25leHVzLmNvbTESMBAGA1UEChMJT1NQU2VydmVyMB4XDTA1MDYyMzAwMjkxOFoXDTA2MDYyNDAwMjkxOFowRTELMAkGA1UEBhMCQVUxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNVBAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDBcMA0GCSqGSIb3DQEBAQUAA0sAMEgCQQCvLeZfj1G0wuJb8JTcVeZaZftncEmRluOnaME3ustd918lRMDYokZmtmDZN8SrP0yd1pfVqZ7NkmBACbBX0k7pAgMBAAEwDQYJKoZIhvcNAQEEBQADQQDnV8QNFVVJx/+7IselU0wsepqMurivXZzuxOmTEmTVDzCJx1xhA8jd3vGAj7XDIYiPub1PV23eY5a2ARJuw5w9";
++const char* B64CACert = "MIIBYDCCAQoCAQEwDQYJKoZIhvcNAQEEBQAwOzElMCMGA1UEAxMcb3NwdGVzdHNlcnZlci50cmFuc25leHVzLmNvbTESMBAGA1UEChMJT1NQU2VydmVyMB4XDTAyMDIwNDE4MjU1MloXDTEyMDIwMzE4MjU1MlowOzElMCMGA1UEAxMcb3NwdGVzdHNlcnZlci50cmFuc25leHVzLmNvbTESMBAGA1UEChMJT1NQU2VydmVyMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAPGeGwV41EIhX0jEDFLRXQhDEr50OUQPq+f55VwQd0TQNts06BP29+UiNdRW3c3IRHdZcJdC1Cg68ME9cgeq0h8CAwEAATANBgkqhkiG9w0BAQQFAANBAGkzBSj1EnnmUxbaiG1N4xjIuLAWydun7o3bFk2tV8dBIhnuh445obYyk1EnQ27kI7eACCILBZqi2MHDOIMnoN0=";
++
+ /* OSP Client Wrapper APIs */
+
+ /*!
+@@ -190,7 +350,10 @@
+ OSPT_CERT cacerts[OSP_MAX_CERTS];
+ const OSPT_CERT* pcacerts[OSP_MAX_CERTS];
+ const char* psrvpoints[OSP_MAX_SRVS];
+- int t, i, j, error = OSPC_ERR_NO_ERROR;
++ unsigned char privatekeydata[OSP_KEYSTR_SIZE];
++ unsigned char localcertdata[OSP_KEYSTR_SIZE];
++ unsigned char cacertdata[OSP_KEYSTR_SIZE];
++ int i, t, error = OSPC_ERR_NO_ERROR;
+
+ if (!(p = ast_calloc(1, sizeof(*p)))) {
+ ast_log(LOG_ERROR, "Out of memory\n");
+@@ -213,30 +376,36 @@
+ v = ast_variable_browse(cfg, provider);
+ while(v) {
+ if (!strcasecmp(v->name, "privatekey")) {
+- if (v->value[0] == '/') {
+- ast_copy_string(p->privatekey, v->value, sizeof(p->privatekey));
+- } else {
+- snprintf(p->privatekey, sizeof(p->privatekey), "%s/%s", ast_config_AST_KEY_DIR, v->value);
++ if (osp_security) {
++ if (v->value[0] == '/') {
++ ast_copy_string(p->privatekey, v->value, sizeof(p->privatekey));
++ } else {
++ snprintf(p->privatekey, sizeof(p->privatekey), "%s/%s", ast_config_AST_KEY_DIR, v->value);
++ }
++ ast_debug(1, "OSP: privatekey '%s'\n", p->privatekey);
+ }
+- ast_debug(1, "OSP: privatekey '%s'\n", p->privatekey);
+ } else if (!strcasecmp(v->name, "localcert")) {
+- if (v->value[0] == '/') {
+- ast_copy_string(p->localcert, v->value, sizeof(p->localcert));
+- } else {
+- snprintf(p->localcert, sizeof(p->localcert), "%s/%s", ast_config_AST_KEY_DIR, v->value);
++ if (osp_security) {
++ if (v->value[0] == '/') {
++ ast_copy_string(p->localcert, v->value, sizeof(p->localcert));
++ } else {
++ snprintf(p->localcert, sizeof(p->localcert), "%s/%s", ast_config_AST_KEY_DIR, v->value);
++ }
++ ast_debug(1, "OSP: localcert '%s'\n", p->localcert);
+ }
+- ast_debug(1, "OSP: localcert '%s'\n", p->localcert);
+ } else if (!strcasecmp(v->name, "cacert")) {
+- if (p->cacount < OSP_MAX_CERTS) {
+- if (v->value[0] == '/') {
+- ast_copy_string(p->cacerts[p->cacount], v->value, sizeof(p->cacerts[0]));
++ if (osp_security) {
++ if (p->cacount < OSP_MAX_CERTS) {
++ if (v->value[0] == '/') {
++ ast_copy_string(p->cacerts[p->cacount], v->value, sizeof(p->cacerts[0]));
++ } else {
++ snprintf(p->cacerts[p->cacount], sizeof(p->cacerts[0]), "%s/%s", ast_config_AST_KEY_DIR, v->value);
++ }
++ ast_debug(1, "OSP: cacerts[%d]: '%s'\n", p->cacount, p->cacerts[p->cacount]);
++ p->cacount++;
+ } else {
+- snprintf(p->cacerts[p->cacount], sizeof(p->cacerts[0]), "%s/%s", ast_config_AST_KEY_DIR, v->value);
++ ast_log(LOG_WARNING, "OSP: Too many CA Certificates at line %d\n", v->lineno);
+ }
+- ast_debug(1, "OSP: cacert[%d]: '%s'\n", p->cacount, p->cacerts[p->cacount]);
+- p->cacount++;
+- } else {
+- ast_log(LOG_WARNING, "OSP: Too many CA Certificates at line %d\n", v->lineno);
+ }
+ } else if (!strcasecmp(v->name, "servicepoint")) {
+ if (p->spcount < OSP_MAX_SRVS) {
+@@ -307,96 +476,110 @@
+ v = v->next;
+ }
+
+- error = OSPPUtilLoadPEMPrivateKey((unsigned char*)p->privatekey, &privatekey);
+- if (error != OSPC_ERR_NO_ERROR) {
+- ast_log(LOG_WARNING, "OSP: Unable to load privatekey '%s', error '%d'\n", p->privatekey, error);
+- ast_free(p);
+- return 0;
++ if (p->cacount == 0) {
++ p->cacount = 1;
+ }
+
+- error = OSPPUtilLoadPEMCert((unsigned char*)p->localcert, &localcert);
+- if (error != OSPC_ERR_NO_ERROR) {
+- ast_log(LOG_WARNING, "OSP: Unable to load localcert '%s', error '%d'\n", p->localcert, error);
+- if (privatekey.PrivateKeyData) {
+- ast_free(privatekey.PrivateKeyData);
+- }
+- ast_free(p);
+- return 0;
++ for (i = 0; i < p->spcount; i++) {
++ psrvpoints[i] = p->srvpoints[i];
+ }
+
+- if (p->cacount < 1) {
+- snprintf(p->cacerts[p->cacount], sizeof(p->cacerts[0]), "%s/%s-cacert.pem", ast_config_AST_KEY_DIR, provider);
+- ast_debug(1, "OSP: cacert[%d]: '%s'\n", p->cacount, p->cacerts[p->cacount]);
+- p->cacount++;
+- }
+- for (i = 0; i < p->cacount; i++) {
+- error = OSPPUtilLoadPEMCert((unsigned char*)p->cacerts[i], &cacerts[i]);
+- if (error != OSPC_ERR_NO_ERROR) {
+- ast_log(LOG_WARNING, "OSP: Unable to load cacert '%s', error '%d'\n", p->cacerts[i], error);
+- for (j = 0; j < i; j++) {
+- if (cacerts[j].CertData) {
+- ast_free(cacerts[j].CertData);
++ if (osp_security) {
++ privatekey.PrivateKeyData = NULL;
++ privatekey.PrivateKeyLength = 0;
++
++ localcert.CertData = NULL;
++ localcert.CertDataLength = 0;
++
++ for (i = 0; i < p->cacount; i++) {
++ cacerts[i].CertData = NULL;
++ cacerts[i].CertDataLength = 0;
++ }
++
++ if ((error = OSPPUtilLoadPEMPrivateKey((unsigned char*)p->privatekey, &privatekey)) != OSPC_ERR_NO_ERROR) {
++ ast_log(LOG_WARNING, "OSP: Unable to load privatekey '%s', error '%d'\n", p->privatekey, error);
++ } else if ((error = OSPPUtilLoadPEMCert((unsigned char*)p->localcert, &localcert)) != OSPC_ERR_NO_ERROR) {
++ ast_log(LOG_WARNING, "OSP: Unable to load localcert '%s', error '%d'\n", p->localcert, error);
++ } else {
++ for (i = 0; i < p->cacount; i++) {
++ if ((error = OSPPUtilLoadPEMCert((unsigned char*)p->cacerts[i], &cacerts[i])) != OSPC_ERR_NO_ERROR) {
++ ast_log(LOG_WARNING, "OSP: Unable to load cacert '%s', error '%d'\n", p->cacerts[i], error);
++ break;
++ } else {
++ pcacerts[i] = &cacerts[i];
+ }
+ }
+- if (localcert.CertData) {
+- ast_free(localcert.CertData);
+- }
+- if (privatekey.PrivateKeyData) {
+- ast_free(privatekey.PrivateKeyData);
+- }
+- ast_free(p);
+- return 0;
+ }
+- pcacerts[i] = &cacerts[i];
+- }
++ } else {
++ privatekey.PrivateKeyData = privatekeydata;
++ privatekey.PrivateKeyLength = sizeof(privatekeydata);
+
+- for (i = 0; i < p->spcount; i++) {
+- psrvpoints[i] = p->srvpoints[i];
++ localcert.CertData = localcertdata;
++ localcert.CertDataLength = sizeof(localcertdata);
++
++ cacerts[0].CertData = cacertdata;
++ cacerts[0].CertDataLength = sizeof(cacertdata);
++ pcacerts[0] = &cacerts[0];
++
++ if ((error = OSPPBase64Decode(B64PKey, strlen(B64PKey), privatekey.PrivateKeyData, &privatekey.PrivateKeyLength)) != OSPC_ERR_NO_ERROR) {
++ ast_log(LOG_WARNING, "OSP: Unable to decode private key, error '%d'\n", error);
++ } else if ((error = OSPPBase64Decode(B64LCert, strlen(B64LCert), localcert.CertData, &localcert.CertDataLength)) != OSPC_ERR_NO_ERROR) {
++ ast_log(LOG_WARNING, "OSP: Unable to decode local cert, error '%d'\n", error);
++ } else if ((error = OSPPBase64Decode(B64CACert, strlen(B64CACert), cacerts[0].CertData, &cacerts[0].CertDataLength)) != OSPC_ERR_NO_ERROR) {
++ ast_log(LOG_WARNING, "OSP: Unable to decode cacert, error '%d'\n", error);
++ }
+ }
+
+- error = OSPPProviderNew(
+- p->spcount,
+- psrvpoints,
+- NULL,
+- OSP_AUDIT_URL,
+- &privatekey,
+- &localcert,
+- p->cacount,
+- pcacerts,
+- OSP_LOCAL_VALIDATION,
+- OSP_SSL_LIFETIME,
+- p->maxconnections,
+- OSP_HTTP_PERSISTENCE,
+- p->retrydelay,
+- p->retrylimit,
+- p->timeout,
+- OSP_CUSTOMER_ID,
+- OSP_DEVICE_ID,
+- &p->handle);
+- if (error != OSPC_ERR_NO_ERROR) {
+- ast_log(LOG_WARNING, "OSP: Unable to create provider '%s', error '%d'\n", provider, error);
+- ast_free(p);
+- res = -1;
+- } else {
+- ast_debug(1, "OSP: provider '%s'\n", provider);
+- ast_mutex_lock(&osplock);
+- p->next = ospproviders;
+- ospproviders = p;
+- ast_mutex_unlock(&osplock);
+- res = 1;
++ if (error == OSPC_ERR_NO_ERROR) {
++ error = OSPPProviderNew(
++ p->spcount,
++ psrvpoints,
++ NULL,
++ OSP_AUDIT_URL,
++ &privatekey,
++ &localcert,
++ p->cacount,
++ pcacerts,
++ OSP_LOCAL_VALIDATION,
++ OSP_SSL_LIFETIME,
++ p->maxconnections,
++ OSP_HTTP_PERSISTENCE,
++ p->retrydelay,
++ p->retrylimit,
++ p->timeout,
++ OSP_CUSTOMER_ID,
++ OSP_DEVICE_ID,
++ &p->handle);
++ if (error != OSPC_ERR_NO_ERROR) {
++ ast_log(LOG_WARNING, "OSP: Unable to create provider '%s', error '%d'\n", provider, error);
++ res = -1;
++ } else {
++ ast_debug(1, "OSP: provider '%s'\n", provider);
++ ast_mutex_lock(&osplock);
++ p->next = ospproviders;
++ ospproviders = p;
++ ast_mutex_unlock(&osplock);
++ res = 1;
++ }
+ }
+
+- for (i = 0; i < p->cacount; i++) {
+- if (cacerts[i].CertData) {
+- ast_free(cacerts[i].CertData);
++ if (osp_security) {
++ for (i = 0; i < p->cacount; i++) {
++ if (cacerts[i].CertData) {
++ ast_free(cacerts[i].CertData);
++ }
+ }
++ if (localcert.CertData) {
++ ast_free(localcert.CertData);
++ }
++ if (privatekey.PrivateKeyData) {
++ ast_free(privatekey.PrivateKeyData);
++ }
+ }
+- if (localcert.CertData) {
+- ast_free(localcert.CertData);
++
++ if (res != 1) {
++ ast_free(p);
+ }
+- if (privatekey.PrivateKeyData) {
+- ast_free(privatekey.PrivateKeyData);
+- }
+
+ return res;
+ }
+@@ -849,6 +1032,8 @@
+ * \param srcdev Source device of outbound call
+ * \param calling Calling number
+ * \param called Called number
++ * \param snetid Source network ID
++ * \param rnumber Routing number
+ * \param callidtypes Call ID types
+ * \param result Lookup results
+ * \return 1 Found , 0 No route, -1 Error
+@@ -858,6 +1043,8 @@
+ const char* srcdev,
+ const char* calling,
+ const char* called,
++ const char* snetid,
++ const char* rnumber,
+ unsigned int callidtypes,
+ struct osp_result* result)
+ {
+@@ -903,6 +1090,14 @@
+ return -1;
+ }
+
++ if (!ast_strlen_zero(snetid)) {
++ OSPPTransactionSetNetworkIds(result->outhandle, snetid, "");
++ }
++
++ if (!ast_strlen_zero(rnumber)) {
++ OSPPTransactionSetRoutingNumber(result->outhandle, rnumber);
++ }
++
+ callidnum = 0;
+ callids[0] = NULL;
+ for (i = 0; i < OSP_CALLID_MAXNUM; i++) {
+@@ -1253,8 +1448,8 @@
+ * \return 0 Success, -1 Failed
+ */
+ static int ospauth_exec(
+- struct ast_channel* chan,
+- void* data)
++ struct ast_channel *chan,
++ const char *data)
+ {
+ int res;
+ const char* provider = OSP_DEF_PROVIDER;
+@@ -1334,7 +1529,7 @@
+ */
+ static int osplookup_exec(
+ struct ast_channel* chan,
+- void* data)
++ const char * data)
+ {
+ int res, cres;
+ const char* provider = OSP_DEF_PROVIDER;
+@@ -1342,6 +1537,7 @@
+ struct ast_var_t* current;
+ const char* srcdev = "";
+ const char* snetid = "";
++ const char* rnumber = "";
+ char buffer[OSP_TOKSTR_SIZE];
+ unsigned int callidtypes = OSP_CALLID_UNDEFINED;
+ struct osp_result result;
+@@ -1401,6 +1597,8 @@
+ }
+ } else if (!strcasecmp(ast_var_name(current), "OSPINNETWORKID")) {
+ snetid = ast_var_value(current);
++ } else if (!strcasecmp(ast_var_name(current), "OSPROUTINGNUMBER")) {
++ rnumber = ast_var_value(current);
+ } else if (!strcasecmp(ast_var_name(current), "OSPPEERIP")) {
+ srcdev = ast_var_value(current);
+ }
+@@ -1408,13 +1606,14 @@
+ ast_debug(1, "OSPLookup: OSPINHANDLE '%d'\n", result.inhandle);
+ ast_debug(1, "OSPLookup: OSPINTIMELIMIT '%d'\n", result.intimelimit);
+ ast_debug(1, "OSPLookup: OSPINNETWORKID '%s'\n", snetid);
++ ast_debug(1, "OSPLookup: OSPROUTINGNUMBER '%s'\n", rnumber);
+ ast_debug(1, "OSPLookup: source device '%s'\n", srcdev);
+
+ if ((cres = ast_autoservice_start(chan)) < 0) {
+ return -1;
+ }
+
+- if ((res = osp_lookup(provider, srcdev, chan->cid.cid_num, args.exten, callidtypes, &result)) > 0) {
++ if ((res = osp_lookup(provider, srcdev, chan->cid.cid_num, args.exten, snetid, rnumber, callidtypes, &result)) > 0) {
+ status = AST_OSP_SUCCESS;
+ } else {
+ result.tech[0] = '\0';
+@@ -1445,6 +1644,8 @@
+ ast_debug(1, "OSPLookup: OSPCALLED '%s'\n", result.called);
+ pbx_builtin_setvar_helper(chan, "OSPCALLING", result.calling);
+ ast_debug(1, "OSPLookup: OSPCALLING '%s'\n", result.calling);
++ pbx_builtin_setvar_helper(chan, "OSPOUTNETWORKID", result.networkid);
++ ast_debug(1, "OSPLookup: OSPOUTNETWORKID '%s'\n", result.networkid);
+ pbx_builtin_setvar_helper(chan, "OSPOUTTOKEN", result.token);
+ ast_debug(1, "OSPLookup: OSPOUTTOKEN size '%zd'\n", strlen(result.token));
+ snprintf(buffer, sizeof(buffer), "%d", result.numresults);
+@@ -1502,7 +1703,7 @@
+ */
+ static int ospnext_exec(
+ struct ast_channel* chan,
+- void* data)
++ const char * data)
+ {
+ int res;
+ const char* provider = OSP_DEF_PROVIDER;
+@@ -1606,6 +1807,8 @@
+ ast_debug(1, "OSPNext: OSPCALLED'%s'\n", result.called);
+ pbx_builtin_setvar_helper(chan, "OSPCALLING", result.calling);
+ ast_debug(1, "OSPNext: OSPCALLING '%s'\n", result.calling);
++ pbx_builtin_setvar_helper(chan, "OSPOUTNETWORKID", result.networkid);
++ ast_debug(1, "OSPLookup: OSPOUTNETWORKID '%s'\n", result.networkid);
+ pbx_builtin_setvar_helper(chan, "OSPOUTTOKEN", result.token);
+ ast_debug(1, "OSPNext: OSPOUTTOKEN size '%zd'\n", strlen(result.token));
+ snprintf(buffer, sizeof(buffer), "%d", result.numresults);
+@@ -1656,7 +1859,7 @@
+ */
+ static int ospfinished_exec(
+ struct ast_channel* chan,
+- void* data)
++ const char * data)
+ {
+ int res = 1;
+ int cause = 0;
+@@ -1801,6 +2004,12 @@
+ }
+ ast_debug(1, "OSP: osp_hardware '%d'\n", osp_hardware);
+
++ t = ast_variable_retrieve(cfg, OSP_GENERAL_CAT, "securityfeatures");
++ if (t && ast_true(t)) {
++ osp_security = 1;
++ }
++ ast_debug(1, "OSP: osp_security '%d'\n", osp_security);
++
+ t = ast_variable_retrieve(cfg, OSP_GENERAL_CAT, "tokenformat");
+ if (t) {
+ if ((sscanf(t, "%d", &v) == 1) &&
+@@ -1854,6 +2063,7 @@
+ OSPPCleanup();
+
+ osp_tokenformat = TOKEN_ALGO_SIGNED;
++ osp_security = 0;
+ osp_hardware = 0;
+ osp_initialized = 0;
+ }
+@@ -1896,8 +2106,11 @@
+ tokenalgo = "Signed";
+ break;
+ }
+- ast_cli(a->fd, "OSP: %s %s %s\n",
+- osp_initialized ? "Initialized" : "Uninitialized", osp_hardware ? "Accelerated" : "Normal", tokenalgo);
++ ast_cli(a->fd, "OSP: %s/%s/%s/%s\n",
++ osp_initialized ? "Initialized" : "Uninitialized",
++ osp_hardware ? "Accelerated" : "Normal",
++ osp_security ? "Enabled" : "Disabled",
++ tokenalgo);
+ }
+
+ ast_mutex_lock(&osplock);
+@@ -1908,10 +2121,12 @@
+ ast_cli(a->fd, "\n");
+ }
+ ast_cli(a->fd, " == OSP Provider '%s' == \n", p->name);
+- ast_cli(a->fd, "Local Private Key: %s\n", p->privatekey);
+- ast_cli(a->fd, "Local Certificate: %s\n", p->localcert);
+- for (i = 0; i < p->cacount; i++) {
+- ast_cli(a->fd, "CA Certificate %d: %s\n", i + 1, p->cacerts[i]);
++ if (osp_security) {
++ ast_cli(a->fd, "Local Private Key: %s\n", p->privatekey);
++ ast_cli(a->fd, "Local Certificate: %s\n", p->localcert);
++ for (i = 0; i < p->cacount; i++) {
++ ast_cli(a->fd, "CA Certificate %d: %s\n", i + 1, p->cacerts[i]);
++ }
+ }
+ for (i = 0; i < p->spcount; i++) {
+ ast_cli(a->fd, "Service Point %d: %s\n", i + 1, p->srvpoints[i]);
+@@ -1940,63 +2155,17 @@
+ return CLI_SUCCESS;
+ }
+
+-static const char* app1= "OSPAuth";
+-static const char* synopsis1 = "OSP authentication";
+-static const char* descrip1 =
+-" OSPAuth([provider[,options]]): Authenticate a SIP INVITE by OSP and sets\n"
+-"the variables:\n"
+-" ${OSPINHANDLE}: The inbound call transaction handle\n"
+-" ${OSPINTIMELIMIT}: The inbound call duration limit in seconds\n"
+-"\n"
+-"This application sets the following channel variable upon completion:\n"
+-" OSPAUTHSTATUS The status of the OSP Auth attempt as a text string, one of\n"
+-" SUCCESS | FAILED | ERROR\n";
++/* OSPAuth() dialplan application */
++static const char app1[] = "OSPAuth";
+
+-static const char* app2= "OSPLookup";
+-static const char* synopsis2 = "Lookup destination by OSP";
+-static const char* descrip2 =
+-" OSPLookup(exten[,provider[,options]]): Looks up an extension via OSP and sets\n"
+-"the variables, where 'n' is the number of the result beginning with 1:\n"
+-" ${OSPOUTHANDLE}: The OSP Handle for anything remaining\n"
+-" ${OSPTECH}: The technology to use for the call\n"
+-" ${OSPDEST}: The destination to use for the call\n"
+-" ${OSPCALLED}: The called number to use for the call\n"
+-" ${OSPCALLING}: The calling number to use for the call\n"
+-" ${OSPDIALSTR}: The dial command string\n"
+-" ${OSPOUTTOKEN}: The actual OSP token as a string\n"
+-" ${OSPOUTTIMELIMIT}: The outbound call duration limit in seconds\n"
+-" ${OSPOUTCALLIDTYPES}: The outbound call id types\n"
+-" ${OSPOUTCALLID}: The outbound call id\n"
+-" ${OSPRESULTS}: The number of OSP results total remaining\n"
+-"\n"
+-"The option string may contain the following character:\n"
+-" 'h' -- generate H323 call id for the outbound call\n"
+-" 's' -- generate SIP call id for the outbound call. Have not been implemented\n"
+-" 'i' -- generate IAX call id for the outbound call. Have not been implemented\n"
+-"This application sets the following channel variable upon completion:\n"
+-" OSPLOOKUPSTATUS The status of the OSP Lookup attempt as a text string, one of\n"
+-" SUCCESS | FAILED | ERROR\n";
++/* OSPLookup() dialplan application */
++static const char app2[] = "OSPLookup";
+
+-static const char* app3 = "OSPNext";
+-static const char* synopsis3 = "Lookup next destination by OSP";
+-static const char* descrip3 =
+-" OSPNext(cause[,provider[,options]]): Looks up the next OSP Destination for ${OSPOUTHANDLE}\n"
+-"See OSPLookup for more information\n"
+-"\n"
+-"This application sets the following channel variable upon completion:\n"
+-" OSPNEXTSTATUS The status of the OSP Next attempt as a text string, one of\n"
+-" SUCCESS | FAILED | ERROR\n";
++/* OSPNext() dialplan application */
++static const char app3[] = "OSPNext";
+
+-static const char* app4 = "OSPFinish";
+-static const char* synopsis4 = "Record OSP entry";
+-static const char* descrip4 =
+-" OSPFinish([status[,options]]): Records call state for ${OSPINHANDLE}, according to\n"
+-"status, which should be one of BUSY, CONGESTION, ANSWER, NOANSWER, or CHANUNAVAIL\n"
+-"or coincidentally, just what the Dial application stores in its ${DIALSTATUS}.\n"
+-"\n"
+-"This application sets the following channel variable upon completion:\n"
+-" OSPFINISHSTATUS The status of the OSP Finish attempt as a text string, one of\n"
+-" SUCCESS | FAILED | ERROR \n";
++/* OSPFinish() dialplan application */
++static const char app4[] = "OSPFinish";
+
+ static struct ast_cli_entry cli_osp[] = {
+ AST_CLI_DEFINE(handle_cli_osp_show, "Displays OSF information")
+@@ -2010,10 +2179,10 @@
+ return AST_MODULE_LOAD_DECLINE;
+
+ ast_cli_register_multiple(cli_osp, sizeof(cli_osp) / sizeof(struct ast_cli_entry));
+- res = ast_register_application(app1, ospauth_exec, synopsis1, descrip1);
+- res |= ast_register_application(app2, osplookup_exec, synopsis2, descrip2);
+- res |= ast_register_application(app3, ospnext_exec, synopsis3, descrip3);
+- res |= ast_register_application(app4, ospfinished_exec, synopsis4, descrip4);
++ res = ast_register_application_xml(app1, ospauth_exec);
++ res |= ast_register_application_xml(app2, osplookup_exec);
++ res |= ast_register_application_xml(app3, ospnext_exec);
++ res |= ast_register_application_xml(app4, ospfinished_exec);
+
+ return res;
+ }
+Index: apps/app_sendtext.c
+===================================================================
+--- a/apps/app_sendtext.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/apps/app_sendtext.c (.../trunk) (revision 202568)
+@@ -70,9 +70,9 @@
+ </application>
+ ***/
+
+-static const char *app = "SendText";
++static const char * const app = "SendText";
+
+-static int sendtext_exec(struct ast_channel *chan, void *data)
++static int sendtext_exec(struct ast_channel *chan, const char *data)
+ {
+ int res = 0;
+ char *status = "UNSUPPORTED";
+Index: apps/app_amd.c
+===================================================================
+--- a/apps/app_amd.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/apps/app_amd.c (.../trunk) (revision 202568)
+@@ -124,7 +124,7 @@
+
+ ***/
+
+-static char *app = "AMD";
++static const char app[] = "AMD";
+
+ #define STATE_IN_WORD 1
+ #define STATE_IN_SILENCE 2
+@@ -143,7 +143,7 @@
+ /* Set to the lowest ms value provided in amd.conf or application parameters */
+ static int dfltMaxWaitTimeForFrame = 50;
+
+-static void isAnsweringMachine(struct ast_channel *chan, void *data)
++static void isAnsweringMachine(struct ast_channel *chan, const char *data)
+ {
+ int res = 0;
+ struct ast_frame *f = NULL;
+@@ -404,7 +404,7 @@
+ }
+
+
+-static int amd_exec(struct ast_channel *chan, void *data)
++static int amd_exec(struct ast_channel *chan, const char *data)
+ {
+ isAnsweringMachine(chan, data);
+
+Index: apps/app_url.c
+===================================================================
+--- a/apps/app_url.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/apps/app_url.c (.../trunk) (revision 202568)
+@@ -82,15 +82,15 @@
+
+ static char *app = "SendURL";
+
+-enum {
++enum option_flags {
+ OPTION_WAIT = (1 << 0),
+-} option_flags;
++};
+
+ AST_APP_OPTIONS(app_opts,{
+ AST_APP_OPTION('w', OPTION_WAIT),
+ });
+
+-static int sendurl_exec(struct ast_channel *chan, void *data)
++static int sendurl_exec(struct ast_channel *chan, const char *data)
+ {
+ int res = 0;
+ char *tmp;
+Index: apps/app_externalivr.c
+===================================================================
+--- a/apps/app_externalivr.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/apps/app_externalivr.c (.../trunk) (revision 202568)
+@@ -48,34 +48,58 @@
+ #include "asterisk/tcptls.h"
+ #include "asterisk/astobj2.h"
+
+-static const char *app = "ExternalIVR";
++/*** DOCUMENTATION
++ <application name="ExternalIVR" language="en_US">
++ <synopsis>
++ Interfaces with an external IVR application.
++ </synopsis>
++ <syntax>
++ <parameter name="command|ivr://host" required="true" hasparams="true">
++ <argument name="arg1" />
++ <argument name="arg2" multiple="yes" />
++ </parameter>
++ <parameter name="options">
++ <optionlist>
++ <option name="n">
++ <para>Tells ExternalIVR() not to answer the channel.</para>
++ </option>
++ <option name="i">
++ <para>Tells ExternalIVR() not to send a hangup and exit when the
++ channel receives a hangup, instead it sends an <literal>I</literal>
++ informative message meaning that the external application MUST hang
++ up the call with an <literal>H</literal> command.</para>
++ </option>
++ <option name="d">
++ <para>Tells ExternalIVR() to run on a channel that has been hung up
++ and will not look for hangups. The external application must exit with
++ an <literal>E</literal> command.</para>
++ </option>
++ </optionlist>
++ </parameter>
++ </syntax>
++ <description>
++ <para>Either forks a process to run given command or makes a socket to connect
++ to given host and starts a generator on the channel. The generator's play list
++ is controlled by the external application, which can add and clear entries via
++ simple commands issued over its stdout. The external application will receive
++ all DTMF events received on the channel, and notification if the channel is
++ hung up. The received on the channel, and notification if the channel is hung
++ up. The application will not be forcibly terminated when the channel is hung up.
++ See <filename>doc/externalivr.txt</filename> for a protocol specification.</para>
++ </description>
++ </application>
++ ***/
+
+-static const char *synopsis = "Interfaces with an external IVR application";
+-static const char *descrip =
+-" ExternalIVR(command|ivr://ivrhosti([,arg[,arg...]])[,options]): Either forks a process\n"
+-"to run given command or makes a socket to connect to given host and starts\n"
+-"a generator on the channel. The generator's play list is controlled by the\n"
+-"external application, which can add and clear entries via simple commands\n"
+-"issued over its stdout. The external application will receive all DTMF events\n"
+-"received on the channel, and notification if the channel is hung up. The\n"
+-"application will not be forcibly terminated when the channel is hung up.\n"
+-"See doc/externalivr.txt for a protocol specification.\n"
+-"The 'n' option tells ExternalIVR() not to answer the channel. \n"
+-"The 'i' option tells ExternalIVR() not to send a hangup and exit when the\n"
+-" channel receives a hangup, instead it sends an 'I' informative message\n"
+-" meaning that the external application MUST hang up the call with an H command\n"
+-"The 'd' option tells ExternalIVR() to run on a channel that has been hung up\n"
+-" and will not look for hangups. The external application must exit with\n"
+-" an 'E' command.\n";
++static const char app[] = "ExternalIVR";
+
+ /* XXX the parser in gcc 2.95 gets confused if you don't put a space between 'name' and the comma */
+ #define ast_chan_log(level, channel, format, ...) ast_log(level, "%s: " format, channel->name , ## __VA_ARGS__)
+
+-enum {
++enum options_flags {
+ noanswer = (1 << 0),
+ ignore_hangup = (1 << 1),
+ run_dead = (1 << 2),
+-} options_flags;
++};
+
+ AST_APP_OPTIONS(app_opts, {
+ AST_APP_OPTION('n', noanswer),
+@@ -311,7 +335,7 @@
+ return entry;
+ }
+
+-static int app_exec(struct ast_channel *chan, void *data)
++static int app_exec(struct ast_channel *chan, const char *data)
+ {
+ struct ast_flags flags = { 0, };
+ char *opts[0];
+@@ -800,7 +824,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_INFO_STANDARD(ASTERISK_GPL_KEY, "External IVR Interface Application");
+Index: apps/app_directory.c
+===================================================================
+--- a/apps/app_directory.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/apps/app_directory.c (.../trunk) (revision 202568)
+@@ -113,7 +113,7 @@
+ </application>
+
+ ***/
+-static char *app = "Directory";
++static const char app[] = "Directory";
+
+ /* For simplicity, I'm keeping the format compatible with the voicemail config,
+ but i'm open to suggestions for isolating it */
+@@ -128,7 +128,7 @@
+ OPT_LISTBYLASTNAME = (1 << 4),
+ OPT_LISTBYEITHER = OPT_LISTBYFIRSTNAME | OPT_LISTBYLASTNAME,
+ OPT_PAUSE = (1 << 5),
+-} directory_option_flags;
++};
+
+ enum {
+ OPT_ARG_FIRSTNAME = 0,
+@@ -714,7 +714,7 @@
+ return res;
+ }
+
+-static int directory_exec(struct ast_channel *chan, void *data)
++static int directory_exec(struct ast_channel *chan, const char *data)
+ {
+ int res = 0, digit = 3;
+ struct ast_config *cfg, *ucfg;
+Index: apps/app_while.c
+===================================================================
+--- a/apps/app_while.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/apps/app_while.c (.../trunk) (revision 202568)
+@@ -186,7 +186,7 @@
+ return res;
+ }
+
+-static int _while_exec(struct ast_channel *chan, void *data, int end)
++static int _while_exec(struct ast_channel *chan, const char *data, int end)
+ {
+ int res=0;
+ const char *while_pri = NULL;
+@@ -296,19 +296,19 @@
+ return res;
+ }
+
+-static int while_start_exec(struct ast_channel *chan, void *data) {
++static int while_start_exec(struct ast_channel *chan, const char *data) {
+ return _while_exec(chan, data, 0);
+ }
+
+-static int while_end_exec(struct ast_channel *chan, void *data) {
++static int while_end_exec(struct ast_channel *chan, const char *data) {
+ return _while_exec(chan, data, 1);
+ }
+
+-static int while_exit_exec(struct ast_channel *chan, void *data) {
++static int while_exit_exec(struct ast_channel *chan, const char *data) {
+ return _while_exec(chan, data, 2);
+ }
+
+-static int while_continue_exec(struct ast_channel *chan, void *data)
++static int while_continue_exec(struct ast_channel *chan, const char *data)
+ {
+ int x;
+ const char *prefix = "WHILE", *while_pri=NULL;
+Index: apps/app_dahdibarge.c
+===================================================================
+--- a/apps/app_dahdibarge.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/apps/app_dahdibarge.c (.../trunk) (revision 202568)
+@@ -70,7 +70,7 @@
+ </description>
+ </application>
+ ***/
+-static char *app = "DAHDIBarge";
++static const char app[] = "DAHDIBarge";
+
+ #define CONF_SIZE 160
+
+@@ -258,7 +258,7 @@
+ return ret;
+ }
+
+-static int conf_exec(struct ast_channel *chan, void *data)
++static int conf_exec(struct ast_channel *chan, const char *data)
+ {
+ int res = -1;
+ int retrycnt = 0;
+Index: apps/app_privacy.c
+===================================================================
+--- a/apps/app_privacy.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/apps/app_privacy.c (.../trunk) (revision 202568)
+@@ -80,7 +80,7 @@
+
+ static char *app = "PrivacyManager";
+
+-static int privacy_exec (struct ast_channel *chan, void *data)
++static int privacy_exec(struct ast_channel *chan, const char *data)
+ {
+ int res=0;
+ int retries;
+Index: apps/app_record.c
+===================================================================
+--- a/apps/app_record.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/apps/app_record.c (.../trunk) (revision 202568)
+@@ -129,7 +129,7 @@
+ AST_APP_OPTION('x', OPTION_IGNORE_TERMINATE),
+ });
+
+-static int record_exec(struct ast_channel *chan, void *data)
++static int record_exec(struct ast_channel *chan, const char *data)
+ {
+ int res = 0;
+ int count = 0;
+Index: apps/app_authenticate.c
+===================================================================
+--- a/apps/app_authenticate.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/apps/app_authenticate.c (.../trunk) (revision 202568)
+@@ -43,7 +43,7 @@
+ OPT_DATABASE = (1 << 1),
+ OPT_MULTIPLE = (1 << 3),
+ OPT_REMOVE = (1 << 4),
+-} auth_option_flags;
++};
+
+ AST_APP_OPTIONS(auth_app_options, {
+ AST_APP_OPTION('a', OPT_ACCOUNT),
+@@ -53,7 +53,7 @@
+ });
+
+
+-static char *app = "Authenticate";
++static const char app[] = "Authenticate";
+ /*** DOCUMENTATION
+ <application name="Authenticate" language="en_US">
+ <synopsis>
+@@ -105,7 +105,7 @@
+ </application>
+ ***/
+
+-static int auth_exec(struct ast_channel *chan, void *data)
++static int auth_exec(struct ast_channel *chan, const char *data)
+ {
+ int res = 0, retries, maxdigits;
+ char passwd[256], *prompt = "agent-pass", *argcopy = NULL;
+Index: apps/app_fax.c
+===================================================================
+--- a/apps/app_fax.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/apps/app_fax.c (.../trunk) (revision 202568)
+@@ -141,8 +141,8 @@
+
+ ***/
+
+-static char *app_sndfax_name = "SendFAX";
+-static char *app_rcvfax_name = "ReceiveFAX";
++static const char app_sndfax_name[] = "SendFAX";
++static const char app_rcvfax_name[] = "ReceiveFAX";
+
+ #define MAX_SAMPLES 240
+
+@@ -351,7 +351,7 @@
+ return 0;
+ }
+
+-struct ast_generator generator = {
++static struct ast_generator generator = {
+ alloc: fax_generator_alloc,
+ generate: fax_generator_generate,
+ };
+@@ -374,7 +374,7 @@
+ struct timeval now, start, state_change;
+ enum ast_control_t38 t38control;
+
+-#if SPANDSP_RELEASE_DATE >= 20081012
++#if SPANDSP_RELEASE_DATE >= 20080725
+ /* for spandsp shaphots 0.0.6 and higher */
+ t30state = &fax.t30;
+ #else
+@@ -553,7 +553,7 @@
+ t30_state_t *t30state;
+ t38_core_state_t *t38state;
+
+-#if SPANDSP_RELEASE_DATE >= 20081012
++#if SPANDSP_RELEASE_DATE >= 20080725
+ /* for spandsp shaphots 0.0.6 and higher */
+ t30state = &t38.t30;
+ t38state = &t38.t38_fe.t38;
+@@ -705,11 +705,12 @@
+
+ /* === Application functions === */
+
+-static int sndfax_exec(struct ast_channel *chan, void *data)
++static int sndfax_exec(struct ast_channel *chan, const char *data)
+ {
+ int res = 0;
+ char *parse;
+ fax_session session;
++ char restore_digit_detect = 0;
+
+ AST_DECLARE_APP_ARGS(args,
+ AST_APP_ARG(file_name);
+@@ -744,16 +745,41 @@
+ session.chan = chan;
+ session.finished = 0;
+
++ /* get current digit detection mode, then disable digit detection if enabled */
++ {
++ int dummy = sizeof(restore_digit_detect);
++
++ ast_channel_queryoption(chan, AST_OPTION_DIGIT_DETECT, &restore_digit_detect, &dummy, 0);
++ }
++
++ if (restore_digit_detect) {
++ char new_digit_detect = 0;
++
++ ast_channel_setoption(chan, AST_OPTION_DIGIT_DETECT, &new_digit_detect, sizeof(new_digit_detect), 0);
++ }
++
++ /* disable FAX tone detection if enabled */
++ {
++ char new_fax_detect = 0;
++
++ ast_channel_setoption(chan, AST_OPTION_FAX_DETECT, &new_fax_detect, sizeof(new_fax_detect), 0);
++ }
++
+ res = transmit(&session);
+
++ if (restore_digit_detect) {
++ ast_channel_setoption(chan, AST_OPTION_DIGIT_DETECT, &restore_digit_detect, sizeof(restore_digit_detect), 0);
++ }
++
+ return res;
+ }
+
+-static int rcvfax_exec(struct ast_channel *chan, void *data)
++static int rcvfax_exec(struct ast_channel *chan, const char *data)
+ {
+ int res = 0;
+ char *parse;
+ fax_session session;
++ char restore_digit_detect = 0;
+
+ AST_DECLARE_APP_ARGS(args,
+ AST_APP_ARG(file_name);
+@@ -788,8 +814,32 @@
+ session.chan = chan;
+ session.finished = 0;
+
++ /* get current digit detection mode, then disable digit detection if enabled */
++ {
++ int dummy = sizeof(restore_digit_detect);
++
++ ast_channel_queryoption(chan, AST_OPTION_DIGIT_DETECT, &restore_digit_detect, &dummy, 0);
++ }
++
++ if (restore_digit_detect) {
++ char new_digit_detect = 0;
++
++ ast_channel_setoption(chan, AST_OPTION_DIGIT_DETECT, &new_digit_detect, sizeof(new_digit_detect), 0);
++ }
++
++ /* disable FAX tone detection if enabled */
++ {
++ char new_fax_detect = 0;
++
++ ast_channel_setoption(chan, AST_OPTION_FAX_DETECT, &new_fax_detect, sizeof(new_fax_detect), 0);
++ }
++
+ res = transmit(&session);
+
++ if (restore_digit_detect) {
++ ast_channel_setoption(chan, AST_OPTION_DIGIT_DETECT, &restore_digit_detect, sizeof(restore_digit_detect), 0);
++ }
++
+ return res;
+ }
+
+Index: apps/app_waituntil.c
+===================================================================
+--- a/apps/app_waituntil.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/apps/app_waituntil.c (.../trunk) (revision 202568)
+@@ -67,7 +67,7 @@
+
+ static char *app = "WaitUntil";
+
+-static int waituntil_exec(struct ast_channel *chan, void *data)
++static int waituntil_exec(struct ast_channel *chan, const char *data)
+ {
+ int res;
+ double fraction;
+Index: apps/app_originate.c
+===================================================================
+--- a/apps/app_originate.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/apps/app_originate.c (.../trunk) (revision 202568)
+@@ -89,7 +89,7 @@
+ </application>
+ ***/
+
+-static int originate_exec(struct ast_channel *chan, void *data)
++static int originate_exec(struct ast_channel *chan, const char *data)
+ {
+ AST_DECLARE_APP_ARGS(args,
+ AST_APP_ARG(tech_data);
+Index: apps/app_queue.c
+===================================================================
+--- a/apps/app_queue.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/apps/app_queue.c (.../trunk) (revision 202568)
+@@ -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>
+@@ -198,6 +203,11 @@
+ <parameter name="rule">
+ <para>Will cause the queue's defaultrule to be overridden by the rule specified.</para>
+ </parameter>
++ <parameter name="position">
++ <para>Attempt to enter the caller into the queue at the numerical position specified. <literal>1</literal>
++ would attempt to enter the caller at the head of the queue, and <literal>3</literal> would attempt to place
++ the caller third in the queue.</para>
++ </parameter>
+ </syntax>
+ <description>
+ <para>In addition to transferring the call, a call may be parked and then picked
+@@ -484,7 +494,160 @@
+ <para>Gets or sets queue members penalty.</para>
+ </description>
+ </function>
+-
++ <manager name="Queues" language="en_US">
++ <synopsis>
++ Queues.
++ </synopsis>
++ <syntax>
++ <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
++ </syntax>
++ <description>
++ </description>
++ </manager>
++ <manager name="QueueStatus" language="en_US">
++ <synopsis>
++ Show queue status.
++ </synopsis>
++ <syntax>
++ <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
++ <parameter name="Queue" />
++ <parameter name="Member" />
++ </syntax>
++ <description>
++ </description>
++ </manager>
++ <manager name="QueueSummary" language="en_US">
++ <synopsis>
++ Show queue summary.
++ </synopsis>
++ <syntax>
++ <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
++ <parameter name="Queue" />
++ </syntax>
++ <description>
++ </description>
++ </manager>
++ <manager name="QueueAdd" language="en_US">
++ <synopsis>
++ Add interface to queue.
++ </synopsis>
++ <syntax>
++ <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
++ <parameter name="Queue" required="true" />
++ <parameter name="Interface" required="true" />
++ <parameter name="Penalty" />
++ <parameter name="Paused" />
++ <parameter name="MemberName" />
++ <parameter name="StateInterface" />
++ </syntax>
++ <description>
++ </description>
++ </manager>
++ <manager name="QueueRemove" language="en_US">
++ <synopsis>
++ Remove interface from queue.
++ </synopsis>
++ <syntax>
++ <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
++ <parameter name="Queue" required="true" />
++ <parameter name="Interface" required="true" />
++ </syntax>
++ <description>
++ </description>
++ </manager>
++ <manager name="QueuePause" language="en_US">
++ <synopsis>
++ Makes a queue member temporarily unavailable.
++ </synopsis>
++ <syntax>
++ <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
++ <parameter name="Interface" required="true" />
++ <parameter name="Paused" required="true" />
++ <parameter name="Queue" />
++ <parameter name="Reason" />
++ </syntax>
++ <description>
++ </description>
++ </manager>
++ <manager name="QueueLog" language="en_US">
++ <synopsis>
++ Adds custom entry in queue_log.
++ </synopsis>
++ <syntax>
++ <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
++ <parameter name="Queue" required="true" />
++ <parameter name="Event" required="true" />
++ <parameter name="Uniqueid" />
++ <parameter name="Interface" />
++ <parameter name="Message" />
++ </syntax>
++ <description>
++ </description>
++ </manager>
++ <manager name="QueuePenalty" language="en_US">
++ <synopsis>
++ Set the penalty for a queue member.
++ </synopsis>
++ <syntax>
++ <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
++ <parameter name="Interface" required="true" />
++ <parameter name="Penalty" required="true" />
++ <parameter name="Queue" />
++ </syntax>
++ <description>
++ </description>
++ </manager>
++ <manager name="QueueRule" language="en_US">
++ <synopsis>
++ Queue Rules.
++ </synopsis>
++ <syntax>
++ <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
++ <parameter name="Rule" />
++ </syntax>
++ <description>
++ </description>
++ </manager>
++ <manager name="QueueReload" language="en_US">
++ <synopsis>
++ Reload a queue, queues, or any sub-section of a queue or queues.
++ </synopsis>
++ <syntax>
++ <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
++ <parameter name="Queue" />
++ <parameter name="Members">
++ <enumlist>
++ <enum name="yes" />
++ <enum name="no" />
++ </enumlist>
++ </parameter>
++ <parameter name="Rules">
++ <enumlist>
++ <enum name="yes" />
++ <enum name="no" />
++ </enumlist>
++ </parameter>
++ <parameter name="Parameters">
++ <enumlist>
++ <enum name="yes" />
++ <enum name="no" />
++ </enumlist>
++ </parameter>
++ </syntax>
++ <description>
++ </description>
++ </manager>
++ <manager name="QueueReset" language="en_US">
++ <synopsis>
++ Reset queue statistics.
++ </synopsis>
++ <syntax>
++ <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
++ <parameter name="Queue" />
++ </syntax>
++ <description>
++ </description>
++ </manager>
+ ***/
+
+ enum {
+@@ -547,7 +710,7 @@
+ static char *app_ql = "QueueLog" ;
+
+ /*! \brief Persistent Members astdb family */
+-static const char *pm_family = "Queue/PersistentMembers";
++static const char * const pm_family = "Queue/PersistentMembers";
+ /* The maximum length of each persistent member queue database entry */
+ #define PM_MAX_LEN 8192
+
+@@ -583,7 +746,7 @@
+ QUEUE_CONTINUE = 7,
+ };
+
+-const struct {
++static const struct {
+ enum queue_result id;
+ char *text;
+ } queue_results[] = {
+@@ -625,6 +788,8 @@
+ time_t lastcall;
+ struct call_queue *lastqueue;
+ struct member *member;
++ unsigned int update_connectedline:1;
++ struct ast_party_connected_line connected;
+ };
+
+
+@@ -812,7 +977,7 @@
+ AST_LIST_ENTRY(rule_list) list;
+ };
+
+-AST_LIST_HEAD_STATIC(rule_lists, rule_list);
++static AST_LIST_HEAD_STATIC(rule_lists, rule_list);
+
+ static struct ao2_container *queues;
+
+@@ -1918,7 +2083,7 @@
+ ast_config_destroy(member_config);
+ }
+
+-static int join_queue(char *queuename, struct queue_ent *qe, enum queue_result *reason)
++static int join_queue(char *queuename, struct queue_ent *qe, enum queue_result *reason, int position)
+ {
+ struct call_queue *q;
+ struct queue_ent *cur, *prev = NULL;
+@@ -1959,6 +2124,17 @@
+ insert_entry(q, prev, qe, &pos);
+ inserted = 1;
+ }
++ /* <= is necessary for the position comparison because it may not be possible to enter
++ * at our desired position since higher-priority callers may have taken the position we want
++ */
++ if (!inserted && (qe->prio <= cur->prio) && position && (position <= pos + 1)) {
++ insert_entry(q, prev, qe, &pos);
++ /*pos is incremented inside insert_entry, so don't need to add 1 here*/
++ if (position < pos) {
++ ast_log(LOG_NOTICE, "Asked to be inserted at position %d but forced into position %d due to higher priority callers\n", position, pos);
++ }
++ inserted = 1;
++ }
+ cur->pos = ++pos;
+ prev = cur;
+ cur = cur->next;
+@@ -2219,12 +2395,13 @@
+ prev = NULL;
+ for (current = q->head; current; current = current->next) {
+ if (current == qe) {
++ char posstr[20];
+ q->count--;
+
+ /* Take us out of the queue */
+ manager_event(EVENT_FLAG_CALL, "Leave",
+- "Channel: %s\r\nQueue: %s\r\nCount: %d\r\nUniqueid: %s\r\n",
+- qe->chan->name, q->name, q->count, qe->chan->uniqueid);
++ "Channel: %s\r\nQueue: %s\r\nCount: %d\r\nPosition: %d\r\nUniqueid: %s\r\n",
++ qe->chan->name, q->name, q->count, qe->pos, qe->chan->uniqueid);
+ ast_debug(1, "Queue '%s' Leave, Channel '%s'\n", q->name, qe->chan->name );
+ /* Take us out of the queue */
+ if (prev)
+@@ -2234,6 +2411,8 @@
+ /* Free penalty rules */
+ while ((pr_iter = AST_LIST_REMOVE_HEAD(&qe->qe_rules, list)))
+ ast_free(pr_iter);
++ snprintf(posstr, sizeof(posstr), "%d", qe->pos);
++ pbx_builtin_setvar_helper(qe->chan, "QUEUEPOSITION", posstr);
+ } else {
+ /* Renumber the people after us in the queue based on a new count */
+ current->pos = ++pos;
+@@ -2378,7 +2557,7 @@
+ static char *vars2manager(struct ast_channel *chan, char *vars, size_t len)
+ {
+ struct ast_str *buf = ast_str_thread_get(&ast_str_thread_global_buf, len + 1);
+- char *tmp;
++ const char *tmp;
+
+ if (pbx_builtin_serialize_variables(chan, &buf)) {
+ int i, j;
+@@ -2492,23 +2671,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);
+
+@@ -2516,7 +2713,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");
+@@ -2539,13 +2735,14 @@
+ strcpy(tmp->chan->cdr->accountcode, qe->chan->cdr->accountcode);
+ strcpy(tmp->chan->cdr->userfield, qe->chan->cdr->userfield);
+ }
+- 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));
+@@ -2573,6 +2770,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;
+@@ -2802,8 +3001,10 @@
+ * \param[in] prebusies number of busy members calculated prior to calling wait_for_answer
+ * \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()
++ *
++ * \todo eventually all call forward logic should be intergerated into and replaced by ast_call_forward()
+ */
+-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;
+@@ -2823,7 +3024,15 @@
+ #ifdef HAVE_EPOLL
+ struct callattempt *epollo;
+ #endif
++ struct ast_party_connected_line connected_caller;
++ char *inchan_name;
+
++ ast_party_connected_line_init(&connected_caller);
++
++ 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) {
+@@ -2873,9 +3082,32 @@
+ }
+ 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];
++ if (o->chan) {
++ 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) {
++ if (ast_channel_connected_line_macro(o->chan, in, &o->connected, 1, 0)) {
++ 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)) {
+@@ -2884,12 +3116,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;
+@@ -2904,7 +3139,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) {
+@@ -2912,32 +3147,44 @@
+ 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);
++ ast_channel_unlock(o->chan);
+ do_hang(o);
+ numnochan++;
++ } else {
++ ast_channel_unlock(o->chan);
+ }
++ ast_channel_unlock(in);
+ }
+ /* Hangup the original channel now, in case we needed it */
+ ast_hangup(winner);
+@@ -2950,12 +3197,26 @@
+ 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) {
++ if (ast_channel_connected_line_macro(o->chan, in, &o->connected, 1, 0)) {
++ 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);
+@@ -2970,7 +3231,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);
+@@ -2985,13 +3246,38 @@
+ 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 {
++ if (ast_channel_connected_line_macro(o->chan, in, f, 1, 1)) {
++ 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);
+@@ -3545,6 +3831,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;
+@@ -3610,6 +3897,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;
+@@ -3619,7 +3909,6 @@
+ case 'C':
+ qe->cancel_answered_elsewhere = 1;
+ break;
+-
+ }
+
+ /* if the calling channel has the ANSWERED_ELSEWHERE flag set, make sure this is inherited.
+@@ -3689,6 +3978,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);
+@@ -3720,6 +4020,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 */
+@@ -3760,7 +4061,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
+@@ -3955,18 +4256,16 @@
+ else
+ which = peer;
+ ast_channel_unlock(qe->chan);
+- if (ast_monitor_start) {
+- if (monitorfilename) {
+- ast_monitor_start(which, qe->parent->monfmt, monitorfilename, 1, X_REC_IN | X_REC_OUT);
+- } else if (qe->chan->cdr && ast_monitor_start) {
+- ast_monitor_start(which, qe->parent->monfmt, qe->chan->cdr->uniqueid, 1, X_REC_IN | X_REC_OUT);
+- } else if (ast_monitor_start) {
+- /* Last ditch effort -- no CDR, make up something */
+- snprintf(tmpid, sizeof(tmpid), "chan-%lx", ast_random());
+- ast_monitor_start(which, qe->parent->monfmt, tmpid, 1, X_REC_IN | X_REC_OUT);
+- }
++ if (monitorfilename) {
++ ast_monitor_start(which, qe->parent->monfmt, monitorfilename, 1, X_REC_IN | X_REC_OUT);
++ } else if (qe->chan->cdr) {
++ ast_monitor_start(which, qe->parent->monfmt, qe->chan->cdr->uniqueid, 1, X_REC_IN | X_REC_OUT);
++ } else {
++ /* Last ditch effort -- no CDR, make up something */
++ snprintf(tmpid, sizeof(tmpid), "chan-%lx", ast_random());
++ ast_monitor_start(which, qe->parent->monfmt, tmpid, 1, X_REC_IN | X_REC_OUT);
+ }
+- if (!ast_strlen_zero(monexec) && ast_monitor_setjoinfiles) {
++ if (!ast_strlen_zero(monexec)) {
+ ast_monitor_setjoinfiles(which, 1);
+ }
+ } else {
+@@ -4514,7 +4813,7 @@
+ }
+
+ /* \brief Sets members penalty, if queuename=NULL we set member penalty in all the queues. */
+-static int set_member_penalty(char *queuename, char *interface, int penalty)
++static int set_member_penalty(const char *queuename, const char *interface, int penalty)
+ {
+ int foundinterface = 0, foundqueue = 0;
+ struct call_queue *q;
+@@ -4691,7 +4990,7 @@
+ }
+
+ /*! \brief PauseQueueMember application */
+-static int pqm_exec(struct ast_channel *chan, void *data)
++static int pqm_exec(struct ast_channel *chan, const char *data)
+ {
+ char *parse;
+ AST_DECLARE_APP_ARGS(args,
+@@ -4727,7 +5026,7 @@
+ }
+
+ /*! \brief UnPauseQueueMember application */
+-static int upqm_exec(struct ast_channel *chan, void *data)
++static int upqm_exec(struct ast_channel *chan, const char *data)
+ {
+ char *parse;
+ AST_DECLARE_APP_ARGS(args,
+@@ -4763,7 +5062,7 @@
+ }
+
+ /*! \brief RemoveQueueMember application */
+-static int rqm_exec(struct ast_channel *chan, void *data)
++static int rqm_exec(struct ast_channel *chan, const char *data)
+ {
+ int res=-1;
+ char *parse, *temppos = NULL;
+@@ -4820,7 +5119,7 @@
+ }
+
+ /*! \brief AddQueueMember application */
+-static int aqm_exec(struct ast_channel *chan, void *data)
++static int aqm_exec(struct ast_channel *chan, const char *data)
+ {
+ int res=-1;
+ char *parse, *temppos = NULL;
+@@ -4883,7 +5182,7 @@
+ }
+
+ /*! \brief QueueLog application */
+-static int ql_exec(struct ast_channel *chan, void *data)
++static int ql_exec(struct ast_channel *chan, const char *data)
+ {
+ char *parse;
+
+@@ -4958,7 +5257,7 @@
+ * 6. Try 4 again unless some condition (such as an expiration time) causes us to
+ * exit the queue.
+ */
+-static int queue_exec(struct ast_channel *chan, void *data)
++static int queue_exec(struct ast_channel *chan, const char *data)
+ {
+ int res=-1;
+ int ringing=0;
+@@ -4974,6 +5273,7 @@
+ int noption = 0;
+ char *parse;
+ int makeannouncement = 0;
++ int position = 0;
+ AST_DECLARE_APP_ARGS(args,
+ AST_APP_ARG(queuename);
+ AST_APP_ARG(options);
+@@ -4984,12 +5284,13 @@
+ AST_APP_ARG(macro);
+ AST_APP_ARG(gosub);
+ AST_APP_ARG(rule);
++ AST_APP_ARG(position);
+ );
+ /* Our queue entry */
+ struct queue_ent qe;
+
+ if (ast_strlen_zero(data)) {
+- ast_log(LOG_WARNING, "Queue requires an argument: queuename[,options[,URL[,announceoverride[,timeout[,agi[,macro[,gosub[,rule]]]]]]]]\n");
++ ast_log(LOG_WARNING, "Queue requires an argument: queuename[,options[,URL[,announceoverride[,timeout[,agi[,macro[,gosub[,rule[,position]]]]]]]]]\n");
+ return -1;
+ }
+
+@@ -5055,6 +5356,14 @@
+ if (args.options && (strchr(args.options, 'c')))
+ qcontinue = 1;
+
++ if (args.position) {
++ position = atoi(args.position);
++ if (position < 0) {
++ ast_log(LOG_WARNING, "Invalid position '%s' given for call to queue '%s'. Assuming no preference for position\n", args.position, args.queuename);
++ position = 0;
++ }
++ }
++
+ ast_debug(1, "queue: %s, options: %s, url: %s, announce: %s, expires: %ld, priority: %d\n",
+ args.queuename, args.options, args.url, args.announceoverride, (long)qe.expire, prio);
+
+@@ -5067,7 +5376,7 @@
+ qe.last_periodic_announce_time = time(NULL);
+ qe.last_periodic_announce_sound = 0;
+ qe.valid_digits = 0;
+- if (join_queue(args.queuename, &qe, &reason)) {
++ if (join_queue(args.queuename, &qe, &reason, position)) {
+ ast_log(LOG_WARNING, "Unable to join queue '%s'\n", args.queuename);
+ set_queue_result(chan, reason);
+ return 0;
+@@ -5998,7 +6307,7 @@
+ * List the queues strategy, calls processed, members logged in,
+ * other queue statistics such as avg hold time.
+ */
+-static char *__queues_show(struct mansession *s, int fd, int argc, char **argv)
++static char *__queues_show(struct mansession *s, int fd, int argc, const char * const *argv)
+ {
+ struct call_queue *q;
+ struct ast_str *out = ast_str_alloca(240);
+@@ -6173,7 +6482,7 @@
+ */
+ static int manager_queues_show(struct mansession *s, const struct message *m)
+ {
+- char *a[] = { "queue", "show" };
++ static const char * const a[] = { "queue", "show" };
+
+ __queues_show(s, -1, 2, a);
+ astman_append(s, "\r\n\r\n"); /* Properly terminate Manager output */
+@@ -6609,7 +6918,7 @@
+
+ static char *handle_queue_add_member(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+ {
+- char *queuename, *interface, *membername = NULL, *state_interface = NULL;
++ const char *queuename, *interface, *membername = NULL, *state_interface = NULL;
+ int penalty;
+
+ switch ( cmd ) {
+@@ -6724,7 +7033,7 @@
+
+ static char *handle_queue_remove_member(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+ {
+- char *queuename, *interface;
++ const char *queuename, *interface;
+
+ switch (cmd) {
+ case CLI_INIT:
+@@ -6789,7 +7098,7 @@
+
+ static char *handle_queue_pause_member(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+ {
+- char *queuename, *interface, *reason;
++ const char *queuename, *interface, *reason;
+ int paused;
+
+ switch (cmd) {
+@@ -6863,7 +7172,7 @@
+
+ static char *handle_queue_set_member_penalty(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+ {
+- char *queuename = NULL, *interface;
++ const char *queuename = NULL, *interface;
+ int penalty = 0;
+
+ switch (cmd) {
+@@ -6925,7 +7234,7 @@
+
+ static char *handle_queue_rule_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+ {
+- char *rule;
++ const char *rule;
+ struct rule_list *rl_iter;
+ struct penalty_rule *pr_iter;
+ switch (cmd) {
+@@ -7152,17 +7461,17 @@
+ 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");
+- res |= ast_manager_register("QueueAdd", EVENT_FLAG_AGENT, manager_add_queue_member, "Add interface to queue.");
+- res |= ast_manager_register("QueueRemove", EVENT_FLAG_AGENT, manager_remove_queue_member, "Remove interface from queue.");
+- res |= ast_manager_register("QueuePause", EVENT_FLAG_AGENT, manager_pause_queue_member, "Makes a queue member temporarily unavailable");
+- 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_manager_register_xml("Queues", 0, manager_queues_show);
++ res |= ast_manager_register_xml("QueueStatus", 0, manager_queues_status);
++ res |= ast_manager_register_xml("QueueSummary", 0, manager_queues_summary);
++ res |= ast_manager_register_xml("QueueAdd", EVENT_FLAG_AGENT, manager_add_queue_member);
++ res |= ast_manager_register_xml("QueueRemove", EVENT_FLAG_AGENT, manager_remove_queue_member);
++ res |= ast_manager_register_xml("QueuePause", EVENT_FLAG_AGENT, manager_pause_queue_member);
++ res |= ast_manager_register_xml("QueueLog", EVENT_FLAG_AGENT, manager_queue_log_custom);
++ res |= ast_manager_register_xml("QueuePenalty", EVENT_FLAG_AGENT, manager_queue_member_penalty);
++ res |= ast_manager_register_xml("QueueRule", 0, manager_queue_rule_show);
++ res |= ast_manager_register_xml("QueueReload", 0, manager_queue_reload);
++ res |= ast_manager_register_xml("QueueReset", 0, manager_queue_reset);
+ res |= ast_custom_function_register(&queuevar_function);
+ res |= ast_custom_function_register(&queuemembercount_function);
+ res |= ast_custom_function_register(&queuemembercount_dep);
+Index: apps/app_followme.c
+===================================================================
+--- a/apps/app_followme.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/apps/app_followme.c (.../trunk) (revision 202568)
+@@ -275,18 +275,19 @@
+ }
+
+ /*! \brief Add a new number */
+-static struct number *create_followme_number(char *number, int timeout, int numorder)
++static struct number *create_followme_number(const char *number, int timeout, int numorder)
+ {
+ struct number *cur;
++ char *buf = ast_strdupa(number);
+ char *tmp;
+
+ if (!(cur = ast_calloc(1, sizeof(*cur))))
+ return NULL;
+
+ cur->timeout = timeout;
+- if ((tmp = strchr(number, ',')))
++ if ((tmp = strchr(buf, ',')))
+ *tmp = '\0';
+- ast_copy_string(cur->number, number, sizeof(cur->number));
++ ast_copy_string(cur->number, buf, sizeof(cur->number));
+ cur->order = numorder;
+ ast_debug(1, "Created a number, %s, order of , %d, with a timeout of %ld.\n", cur->number, cur->order, cur->timeout);
+
+@@ -996,7 +997,7 @@
+ bconfig->end_bridge_callback_data = originator;
+ }
+
+-static int app_exec(struct ast_channel *chan, void *data)
++static int app_exec(struct ast_channel *chan, const char *data)
+ {
+ struct fm_args targs = { 0, };
+ struct ast_bridge_config config;
+Index: apps/app_waitforring.c
+===================================================================
+--- a/apps/app_waitforring.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/apps/app_waitforring.c (.../trunk) (revision 202568)
+@@ -53,7 +53,7 @@
+
+ static char *app = "WaitForRing";
+
+-static int waitforring_exec(struct ast_channel *chan, void *data)
++static int waitforring_exec(struct ast_channel *chan, const char *data)
+ {
+ struct ast_frame *f;
+ int res = 0;
+Index: apps/app_flash.c
+===================================================================
+--- a/apps/app_flash.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/apps/app_flash.c (.../trunk) (revision 202568)
+@@ -72,7 +72,7 @@
+ return j;
+ }
+
+-static int flash_exec(struct ast_channel *chan, void *data)
++static int flash_exec(struct ast_channel *chan, const char *data)
+ {
+ int res = -1;
+ int x;
+Index: doc/asterisk.sgml
+===================================================================
+--- a/doc/asterisk.sgml (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/doc/asterisk.sgml (.../trunk) (revision 202568)
+@@ -327,7 +327,7 @@
+ <refsect1>
+ <title>BUGS</title>
+ <para>
+- Bug reports and feature requests may be filed at http://bugs.digium.com
++ Bug reports and feature requests may be filed at https://issues.asterisk.org
+ </para>
+ </refsect1>
+ <refsect1>
+Index: doc/CODING-GUIDELINES
+===================================================================
+--- a/doc/CODING-GUIDELINES (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/doc/CODING-GUIDELINES (.../trunk) (revision 202568)
+@@ -22,7 +22,7 @@
+ Asterisk is published under a dual-licensing scheme by Digium.
+ To be accepted into the codebase, all non-trivial changes must be
+ licensed to Digium. For more information, see the electronic license
+-agreement on http://bugs.digium.com/.
++agreement on https://issues.asterisk.org/.
+
+ Patches should be in the form of a unified (-u) diff, made from a checkout
+ from subversion.
+@@ -114,7 +114,6 @@
+ is almost always necessary) write a short comment next to each #include to
+ explain why you need it.
+
+-
+ * Declaration of functions and variables
+ ----------------------------------------
+
+@@ -122,15 +121,47 @@
+ since it is harder to read and not portable to GCC 2.95 and others.
+
+ - Functions and variables that are not intended to be used outside the module
+- must be declared static.
++ must be declared static. If you are compiling on a Linux platform that has the
++ 'dwarves' package available, you can use the 'pglobal' tool from that package
++ to check for unintended global variables or functions being exposed in your
++ object files. Usage is very simple:
+
++ $ pglobal -vf <path to .o file>
++
+ - When reading integer numeric input with scanf (or variants), do _NOT_ use '%i'
+ unless you specifically want to allow non-base-10 input; '%d' is always a better
+ choice, since it will not silently turn numbers with leading zeros into base-8.
+
+-- Strings that are coming from input should not be used as a first argument to
+- a formatted *printf function.
++- Strings that are coming from input should not be used as the format argument to
++ any printf-style function.
+
++* Structure alignment and padding
++---------------------------------
++
++On many platforms, structure fields (in structures that are not marked 'packed')
++will be laid out by the compiler with gaps (padding) between them, in order to
++satisfy alignment requirements. As a simple example:
++
++struct foo {
++ int bar;
++ void *xyz;
++}
++
++On nearly every 64-bit platform, this will result in 4 bytes of dead space between
++'bar' and 'xyz', because pointers on 64-bit platforms must be aligned on 8-byte
++boundaries. Once you have your code written and tested, it may be worthwhile to review
++your structure definitions to look for problems of this nature. If you are on a Linux
++platform with the 'dwarves' package available, the 'pahole' tool from that package
++can be used to both check for padding issues of this type and also propose reorganized
++structure definitions to eliminate it. Usage is quite simple; for a structure named 'foo',
++the command would look something like this:
++
++$ pahole --reorganize --show_reorg_steps -C foo <path to module>
++
++The 'pahole' tool has many other modes available, including some that will list all the
++structures declared in the module and the amount of padding in each one that could possibly
++be recovered.
++
+ * Use the internal API
+ ----------------------
+
+Index: doc/asterisk.8
+===================================================================
+--- a/doc/asterisk.8 (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/doc/asterisk.8 (.../trunk) (revision 202568)
+@@ -176,7 +176,7 @@
+ \fBasterisk -rx "core show channels"\fR - Display channels on running server
+ .SH "BUGS"
+ .PP
+-Bug reports and feature requests may be filed at http://bugs.digium.com
++Bug reports and feature requests may be filed at https://issues.asterisk.org
+ .SH "SEE ALSO"
+ .PP
+ *CLI> \fBhelp\fR - Help on Asterisk CLI
+Index: doc/backtrace.txt
+===================================================================
+--- a/doc/backtrace.txt (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/doc/backtrace.txt (.../trunk) (revision 202568)
+@@ -1,6 +1,6 @@
+ This document is intended to provide information on how to obtain the
+ backtraces required on the asterisk bug tracker, available at
+-http://bugs.digium.com. The information is required by developers to
++https://issues.asterisk.org. The information is required by developers to
+ help fix problem with bugs of any kind. Backtraces provide information
+ about what was wrong when a program crashed; in our case,
+ Asterisk. There are two kind of backtraces (aka 'bt') which are
+Index: doc/janitor-projects.txt
+===================================================================
+--- a/doc/janitor-projects.txt (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/doc/janitor-projects.txt (.../trunk) (revision 202568)
+@@ -32,3 +32,5 @@
+ -- 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).
++
++ -- Convert all usage of the signal(2) system API to the more portable sigaction(2) system API.
+Index: doc/lang/urdu.ods
+===================================================================
+Cannot display: file marked as a binary type.
+svn:mime-type = application/x-open-document-spreadsheet
+
+Property changes on: doc/lang/urdu.ods
+___________________________________________________________________
+Added: svn:mime-type
+ + application/x-open-document-spreadsheet
+
+Index: doc/appdocsxml.dtd
+===================================================================
+--- a/doc/appdocsxml.dtd (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/doc/appdocsxml.dtd (.../trunk) (revision 202568)
+@@ -1,4 +1,4 @@
+- <!ELEMENT docs (application|function|agi)*>
++ <!ELEMENT docs (application|function|agi|manager)*>
+ <!ATTLIST docs xmlns:xi CDATA #FIXED "http://www.w3.org/2001/XInclude">
+
+ <!ELEMENT xi:include (xi:fallback?) >
+@@ -23,6 +23,10 @@
+ <!ATTLIST agi name CDATA #REQUIRED>
+ <!ATTLIST agi language CDATA #REQUIRED>
+
++ <!ELEMENT manager (synopsis?,syntax?,description?,see-also?)>
++ <!ATTLIST manager name CDATA #REQUIRED>
++ <!ATTLIST manager language CDATA #REQUIRED>
++
+ <!ELEMENT see-also (ref|xi:include)*>
+
+ <!ELEMENT ref (#PCDATA)>
+Index: doc/datastores.txt
+===================================================================
+--- a/doc/datastores.txt (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/doc/datastores.txt (.../trunk) (revision 202568)
+@@ -19,8 +19,8 @@
+
+ * How do you create a data store?
+
+-1. Use ast_channel_datastore_alloc function to return a pre-allocated structure
+- Ex: datastore = ast_channel_datastore_alloc(&example_datastore, "uid");
++1. Use ast_datastore_alloc function to return a pre-allocated structure
++ Ex: datastore = ast_datastore_alloc(&example_datastore, "uid");
+ This function takes two arguments: (datastore info structure, uid)
+ 2. Attach data to pre-allocated structure.
+ Ex: datastore->data = mysillydata;
+@@ -36,7 +36,7 @@
+ }
+
+ struct ast_datastore *datastore = NULL;
+-datastore = ast_channel_datastore_alloc(&example_datastore, NULL);
++datastore = ast_datastore_alloc(&example_datastore, NULL);
+ datastore->data = mysillydata;
+ ast_channel_datastore_add(chan, datastore);
+
+Index: doc/manager_1_1.txt
+===================================================================
+--- a/doc/manager_1_1.txt (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/doc/manager_1_1.txt (.../trunk) (revision 202568)
+@@ -252,6 +252,35 @@
+ To list the information about a specific SKINNY line.
+ Variables:
+ Line: <line> Line to show information about.
++
++- Action: CoreSettings
++ Modules: manager.c
++ Purpose: To report core settings, like AMI and Asterisk version,
++ maxcalls and maxload settings.
++ * Integrated in SVN trunk as of May 4th, 2007
++ Example:
++ Response: Success
++ ActionID: 1681692777
++ AMIversion: 1.1
++ AsteriskVersion: SVN-oej-moremanager-r61756M
++ SystemName: EDVINA-node-a
++ CoreMaxCalls: 120
++ CoreMaxLoadAvg: 0.000000
++ CoreRunUser: edvina
++ CoreRunGroup: edvina
++
++- Action: CoreStatus
++ Modules: manager.c
++ Purpose: To report current PBX core status flags, like
++ number of concurrent calls, startup and reload time.
++ * Integrated in SVN trunk as of May 4th, 2007
++ Example:
++ Response: Success
++ ActionID: 1649760492
++ CoreStartupTime: 22:35:17
++ CoreReloadTime: 22:35:17
++ CoreCurrentCalls: 20
++
+
+ * NEW EVENTS
+ ------------
+@@ -294,34 +323,6 @@
+ SIPcallid: NTQzYWFiOWM4NmE0MWRkZjExMzU2YzQ3OWQwNzg3ZmI.
+ SIPfullcontact: sip:olle@127.0.0.1:49054
+
+-- Action: CoreSettings
+- Modules: manager.c
+- Purpose: To report core settings, like AMI and Asterisk version,
+- maxcalls and maxload settings.
+- * Integrated in SVN trunk as of May 4th, 2007
+- Example:
+- Response: Success
+- ActionID: 1681692777
+- AMIversion: 1.1
+- AsteriskVersion: SVN-oej-moremanager-r61756M
+- SystemName: EDVINA-node-a
+- CoreMaxCalls: 120
+- CoreMaxLoadAvg: 0.000000
+- CoreRunUser: edvina
+- CoreRunGroup: edvina
+-
+-- Action: CoreStatus
+- Modules: manager.c
+- Purpose: To report current PBX core status flags, like
+- number of concurrent calls, startup and reload time.
+- * Integrated in SVN trunk as of May 4th, 2007
+- Example:
+- Response: Success
+- ActionID: 1649760492
+- CoreStartupTime: 22:35:17
+- CoreReloadTime: 22:35:17
+- CoreCurrentCalls: 20
+-
+ - Event: NewAccountCode
+ Modules: cdr.c
+ Purpose: To report a change in account code for a live channel
+Index: doc/tex/asterisk.tex
+===================================================================
+--- a/doc/tex/asterisk.tex (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/doc/tex/asterisk.tex (.../trunk) (revision 202568)
+@@ -135,6 +135,9 @@
+ \chapter{Phone Provisioning}
+ \input{phoneprov.tex}
+
++\chapter{Calendaring}
++ \input{calendaring.tex}
++
+ \chapter{Development}
+ \section{Backtrace}
+ \input{backtrace.tex}
+Index: doc/tex/channelvariables.tex
+===================================================================
+--- a/doc/tex/channelvariables.tex (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/doc/tex/channelvariables.tex (.../trunk) (revision 202568)
+@@ -853,6 +853,10 @@
+ ${QUEUE_MIN_PENALTY} Minimum member penalty allowed to answer caller
+ ${QUEUESTATUS} Status of the call, one of:
+ (TIMEOUT | FULL | JOINEMPTY | LEAVEEMPTY | JOINUNAVAIL | LEAVEUNAVAIL)
++${QUEUEPOSITION} * When a caller is removed from a queue, his current position is logged
++ in this variable. If the value is 0, then this means that the caller was
++ serviced by a queue member. If non-zero, then this was the position in the
++ queue the caller was in when he left.
+ ${RECORDED_FILE} * Recorded file in record()
+ ${TALK_DETECTED} * Result from talkdetect()
+ ${TOUCH_MONITOR} The filename base to use with Touch Monitor (auto record)
+@@ -925,7 +929,9 @@
+ ${SIPFROMDOMAIN} Set SIP domain on outbound calls
+ ${SIPUSERAGENT} * SIP user agent (deprecated)
+ ${SIPURI} * SIP uri
+-${SIP_CODEC} Set the SIP codec for a call
++${SIP_CODEC} Set the SIP codec for an inbound call
++${SIP_CODEC_INBOUND} Set the SIP codec for an inbound call
++${SIP_CODEC_OUTBOUND} Set the SIP codec for an outbound call
+ ${SIP_URI_OPTIONS} * additional options to add to the URI for an outgoing call
+ ${RTPAUDIOQOS} RTCP QoS report for the audio of this call
+ ${RTPVIDEOQOS} RTCP QoS report for the video of this call
+@@ -999,3 +1005,11 @@
+ ${OSPOUTTIMELIMIT} Duration limit for out_bound call
+ ${OSPRESULTS} Number of remained destinations
+ \end{verbatim}
++
++\subsection{Connected line digit manipulation}
++\begin{verbatim}
++${CONNECTED_LINE_SEND_CALLEE_MACRO} Macro to call before sending a connected line update to the callee
++${CONNECTED_LINE_SEND_CALLEE_MACRO_ARGS} Arguments to pass to ${CONNECTED_LINE_SEND_CALLEE_MACRO}
++${CONNECTED_LINE_SEND_CALLER_MACRO} Macro to call before sending a connected line update to the caller
++${CONNECTED_LINE_SEND_CALLER_MACRO_ARGS} Arguments to pass to ${CONNECTED_LINE_SEND_CALLER_MACRO}
++\end{verbatim}
+Index: doc/tex/calendaring.tex
+===================================================================
+--- a/doc/tex/calendaring.tex (.../tags/1.6.2.0-beta3) (revision 0)
++++ b/doc/tex/calendaring.tex (.../trunk) (revision 202568)
+@@ -0,0 +1,206 @@
++\section{Introduction}
++
++The Asterisk Calendaring API aims to be a generic interface for integrating
++Asterisk with various calendaring technologies. The goal is to be able to
++support reading and writing of calendar events as well as allowing notification
++of pending events through the Asterisk dialplan.
++
++There are three calendaring modules that ship with Asterisk that provide support
++for iCalendar, CalDAV, and Microsoft Exchange Server calendars. All three
++modules support event notification. Both CalDAV and Exchange support reading
++and writing calendars, while iCalendar is a read-only format.
++
++\section{Configuring Asterisk Calendaring}
++
++All asterisk calendaring modules are configured through calender.conf. Each
++calendar module can define its own set of required parameters in addition to the
++parameters available to all calendar types. An effort has been made to keep all
++options the same in all calendaring modules, but some options will diverge over
++time as features are added to each module.
++
++An example calendar.conf might look like:
++\begin{astlisting}
++\begin{verbatim}
++[calendar_joe]
++type = ical
++url = https://example.com/home/jdoe/Calendar
++user = jdoe
++secret = mysecret
++refresh = 15
++timeframe = 600
++autoreminder = 10
++channel = SIP/joe
++context = calendar_event_notify
++extension = s
++waittime = 30
++\end{verbatim}
++\end{astlisting}
++
++\subsection{Module-independent settings}
++
++The settings related to calendar event notification are handled by the core
++calendaring API. These settings are:
++\begin{description}
++\item[autoreminder] This allows the overriding of any alarms that may or may not
++be set for a calendar event. It is specified in minutes.
++\item[refresh] How often to refresh the calendar data; specified in minutes.
++\item[timeframe] How far into the future each calendar refresh should look. This
++is the amount of data that will be visible to queries from the dialplan. This
++setting should always be greater than or equal to the refresh setting or events
++may be missed. It is specified in minutes.
++\item[channel] The channel that should be used for making the notification
++attempt.
++\item[waittime] How long to wait, in seconds, for the channel to answer a notification
++attempt.
++\end{description}
++
++There are two ways to specify how to handle a notification. One option is
++providing a context and extension, while the other is providing an application
++and the arguments to that application. One (and only one) of these options
++should be provided.
++
++\begin{description}
++\item[context] The context of the extension to connect to the notification
++channel
++\item[extension] The extension to connect to the notification. Note that the
++priority will always be 1.
++\end{description}
++
++or
++
++\begin{description}
++\item[app] The dialplan application to execute upon the answer of a notification
++\item[appdata] The data to pass to the notification dialplan application
++\end{description}
++
++\subsection{Module-dependent settings}
++
++Connection-related options are specific to each module. Currently, all modules
++take a url, user, and secret for configuration and no other module-specific
++settings have been implemented. At this time, no support for HTTP redirects has
++been implemented, so it is important to specify the correct URL--paying attention
++to any trailing slashes that may be necessary.
++
++\section{Dialplan functions}
++\subsection{Read functions}
++
++The simplest dialplan query is the CALENDAR\_BUSY query. It takes a single
++option, the name of the calendar defined, and returns "1" for busy (including
++tentatively busy) and "0" for not busy.
++
++For more information about a calendar event, a combination of CALENDAR\_QUERY
++and CALENDAR\_QUERY\_RESULT is used. CALENDAR\_QUERY takes the calendar name
++and optionally a start and end time in "unix time" (seconds from unix epoch). It
++returns an id that can be passed to CALENDAR\_QUERY\_RESULT along with a field
++name to return the data in that field. If multiple events are returned in the
++query, the number of the event in the list can be specified as well. The available
++fields to return are:
++\begin{description}
++\item[summary] A short summary of the event
++\item[description] The full description of the event
++\item[organizer] Who organized the event
++\item[location] Where the event is located
++\item[calendar] The name of the calendar from calendar.conf
++\item[uid] The unique identifier associated with the event
++\item[start] The start of the event in seconds since Unix epoch
++\item[end] The end of the event in seconds since Unix epoch
++\item[busystate] The busy state 0=Free, 1=Tentative, 2=Busy
++\item[attendees] A comma separated list of attendees as stored in the event and
++may include prefixes such as "mailto:".
++\end{description}
++
++When an event notification is sent to the dial plan, the CALENDAR\_EVENT
++function may be used to return the information about the event that is causing
++the notification. The fields that can be returned are the same as those from
++CALENDAR\_QUERY\_RESULT.
++\subsection{Write functions}
++
++To write an event to a calendar, the CALENDAR\_WRITE function is used. This
++function takes a calendar name and also uses the same fields as
++CALENDAR\_QUERY\_RESULT. As a write function, it takes a set of comma-separated
++values that are in the same order as the specified fields. For example:
++\begin{astlisting}
++\begin{verbatim}
++CALENDAR_WRITE(mycalendar,summary,organizer,start,end,busystate)=
++ "My event","mailto:jdoe@example.com",228383580,228383640,1)
++\end{verbatim}
++\end{astlisting}
++
++\section{Dialplan Examples}
++\subsection{Office hours}
++A common business PBX scenario is would be executing dialplan logic based on
++when the business is open and the phones staffed. If the business is closed for
++holidays, it is sometimes desirable to play a message to the caller stating why
++the business is closed.
++
++The standard way to do this in asterisk has been doing a series of GotoIfTime
++statements or time-based include statements. Either way can be tedious and
++requires someone with access to edit asterisk config files.
++
++With calendaring, the adminstrator only needs to set up a calendar that contains
++the various holidays or even recurring events specifying the office hours. A
++custom greeting filename could even be contained in the description field for
++playback. For example:
++\begin{astlisting}
++\begin{verbatim}
++[incoming]
++exten => 5555551212,1,Answer
++exten => 5555551212,n,GotoIf(${CALENDAR_BUSY(officehours)}?closed:attendant,s,1)
++exten => 5555551212,n(closed),Set(id=${CALENDAR_QUERY(office,${EPOCH},${EPOCH})})
++exten => 5555551212,n,Set(soundfile=${CALENDAR_QUERY_RESULT(${id},description)})
++exten => 5555551212,n,Playback($[${ISNULL(soundfile)} ? generic-closed :: ${soundfile}])
++exten => 5555551212,n,Hangup
++\end{verbatim}
++\end{astlisting}
++
++\subsection{Meeting reminders}
++One useful application of Asterisk Calendaring is the ability to execute
++dialplan logic based on an event notification. Most calendaring technologies
++allow a user to set an alarm for an event. If these alarms are set on a calendar
++that Asterisk is monitoring and the calendar is set up for event notification
++via calendar.conf, then Asterisk will execute notify the specified channel at
++the time of the alarm. If an overrided notification time is set with the
++autoreminder setting, then the notification would happen at that time instead.
++
++The following example demonstrates the set up for a simple event notification
++that plays back a generic message followed by the time of the upcoming meeting.
++calendar.conf.
++\begin{astlisting}
++\begin{verbatim}
++[calendar_joe]
++type = ical
++url = https://example.com/home/jdoe/Calendar
++user = jdoe
++secret = mysecret
++refresh = 15
++timeframe = 600
++autoreminder = 10
++channel = SIP/joe
++context = calendar_event_notify
++extension = s
++waittime = 30
++\end{verbatim}
++\end{astlisting}
++
++\begin{astlisting}
++\begin{verbatim}
++[calendar_event_notify]
++exten => s,1,Answer
++exten => s,n,Playback(you-have-a-meeting-at)
++exten => s,n,SayUnixTime(${CALENDAR_EVENT(start)})
++exten => s,n,Hangup
++\end{verbatim}
++\end{astlisting}
++
++\subsection{Writing an event}
++Both CalDAV and Exchange calendar servers support creating new events. The
++following example demonstrates writing a log of a call to a calendar.
++\begin{astlisting}
++\begin{verbatim}
++[incoming]
++exten => 6000,1,Set(start=${EPOCH})
++exten => 6000,n,Dial(SIP/joe)
++exten => h,1,Set(end=${EPOCH})
++exten => h,n,Set(CALENDAR_WRITE(calendar_joe,summary,start,end)=Call from ${CALLERID(all)},${start},${end})
++\end{verbatim}
++\end{astlisting}
+
+Property changes on: doc/tex/calendaring.tex
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+Added: svn:mime-type
+ + text/plain
+Added: svn:keywords
+ + Author Date Id Revision
+
+Index: doc/tex/misdn.tex
+===================================================================
+--- a/doc/tex/misdn.tex (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/doc/tex/misdn.tex (.../trunk) (revision 202568)
+@@ -247,7 +247,7 @@
+ an '*', the rest is clear I think.
+
+ Please take a trace of the problem and open a report in the Asterisk issue
+-tracker at \url{http://bugs.digium.com} in the "channel drivers" project,
++tracker at \url{https://issues.asterisk.org} in the "channel drivers" project,
+ "chan\_misdn" category. Read the bug guidelines to make sure you
+ provide all the information needed.
+
+Index: doc/tex/backtrace.tex
+===================================================================
+--- a/doc/tex/backtrace.tex (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/doc/tex/backtrace.tex (.../trunk) (revision 202568)
+@@ -1,6 +1,6 @@
+ This document is intended to provide information on how to obtain the
+ backtraces required on the asterisk bug tracker, available at
+-\url{http://bugs.digium.com}. The information is required by developers to
++\url{https://issues.asterisk.org}. The information is required by developers to
+ help fix problem with bugs of any kind. Backtraces provide information
+ about what was wrong when a program crashed; in our case,
+ Asterisk. There are two kind of backtraces (aka 'bt') which are
+Index: doc/tex/mp3.tex
+===================================================================
+--- a/doc/tex/mp3.tex (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/doc/tex/mp3.tex (.../trunk) (revision 202568)
+@@ -7,5 +7,5 @@
+ However, if you still need to use mp3 as your music on hold format, a format
+ driver for reading MP3 audio files is available in the asterisk-addons SVN
+ repository on svn.digium.com or in the asterisk-addons release at
+-\url{http://downloads.digium.com/pub/telephony/asterisk/}.
++\url{http://downloads.asterisk.org/pub/telephony/asterisk/}.
+
+Index: UPGRADE.txt
+===================================================================
+--- a/UPGRADE.txt (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/UPGRADE.txt (.../trunk) (revision 202568)
+@@ -18,6 +18,17 @@
+ ===
+ ===========================================================
+
++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.
++* The app_dahdiscan.c file has been removed, but the dialplan app DAHDIScan still
++ remains. It now exists within app_chanspy.c and retains the exact same
++ functionality as before.
++
+ 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-beta3) (revision 202568)
++++ b/CHANGES (.../trunk) (revision 202568)
+@@ -7,7 +7,170 @@
+ === 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.
++ * Added SIP_CODEC_OUTBOUND dialplan variable which can be used to set the codec
++ to be used for the outgoing call. It must be one of the codecs configured
++ for the device.
++ * Added tlsprivatekey option to sip.conf. This allows a separate .pem file
++ to be used for holding a private key. If tlsprivatekey is not specified,
++ tlscertfile is searched for both public and private key.
++ * Added tlsclientmethod option to sip.conf. This allows the protocol for
++ outbound client connections to be specified.
++ * 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.
++ * The 'ignoresdpversion' behavior has been made automatic when the SDP received
++ is in response to a T.38 re-INVITE that Asterisk initiated. In this situation,
++ since the call will fail if Asterisk does not process the incoming SDP, Asterisk
++ will accept the SDP even if the SDP version number is not properly incremented,
++ but will generate a warning in the log indicating that the SIP peer that sent
++ the SDP should have the 'ignoresdpversion' option set.
++
++IAX2 Changes
++-----------
++ * Added rtsavesysname option into iax.conf to allow the systname to be saved
++ on realtime updates.
++
++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.
++ * Added functionality to the app_dial F() option to continue with execution
++ at the current location when no parameters are provided.
++ * Added c() option to app_chanspy. This option allows custom DTMF to be set
++ to cycle through the next avaliable channel. By default this is still '*'.
++ * Added x() option to app_chanspy. This option allows DTMF to be set to
++ exit the application.
++
++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.
++ * For DAHDI channels, the CHANNEL() dialplan function now
++ supports changing the channel's buffer policy (for the current
++ call only), using this syntax:
++
++ exten => s,n,Set(CHANNEL(buffers)=6,full)
++
++ This would change the channel to the 'full' buffer policy and
++ 6 (six) buffers. Possible options for this setting are the same
++ as those in chan_dahdi.conf.
++ * For DAHDI channels, the CHANNEL() dialplan function now allows
++ the dialplan to request changes in the configuration of the active
++ echo canceller on the channel (if any), for the current call only.
++ The syntax is:
++
++ exten => s,n,Set(CHANNEL(echocan_mode)=off)
++
++ The possible values are:
++
++ on - normal mode (the echo canceller is actually reinitalized)
++ off - disabled
++ fax - FAX/data mode (NLP disabled if possible, otherwise completely
++ disabled)
++ voice - voice mode (returns from FAX mode, reverting the changes that
++ were made when FAX mode was requested)
++
++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.
++ * Added new dialplan application misdn_command which permits controlling
++ the CCBS/CCNR functionality.
++ * Added new dialplan function mISDN_CC which permits retrieval of various
++ values from an active call completion record.
++ * For PTP, you should manually send the COLR of the redirected-to party
++ for an incomming redirected call if the incoming call could experience
++ further redirects. Just set the REDIRECTING(to-num,i) = ${EXTEN} and
++ set the REDIRECTING(to-pres) to the COLR. A call has been redirected
++ if the REDIRECTING(from-num) is not empty.
++ * For outgoing PTP redirected calls, you now need to use the inhibit(i)
++ option on all of the REDIRECTING statements before dialing the
++ redirected-to party. You still have to set the REDIRECTING(to-xxx,i)
++ and the REDIRECTING(from-xxx,i) values. The PTP call will update the
++ redirecting-to presentation (COLR) when it becomes available.
++ * Added outgoing_colp parameter to misdn.conf to filter outgoing COLP
++ information.
++
++thirdparty mISDN enhancements
++-----------------------------
++mISDN has been modified by Digium, Inc. to greatly expand facility message
++support to allow:
++ * Enhanced COLP support for call diversion and transfer.
++ * CCBS/CCNR support.
++
++The latest modified mISDN v1.1.x based version is available at:
++http://svn.digium.com/svn/thirdparty/mISDN/trunk
++http://svn.digium.com/svn/thirdparty/mISDNuser/trunk
++
++Tagged versions of the modified mISDN code are available under:
++http://svn.digium.com/svn/thirdparty/mISDN/tags
++http://svn.digium.com/svn/thirdparty/mISDNuser/tags
++
++Asterisk Manager Interface
++--------------------------
++ * The Hangup action now accepts a Cause header which may be used to
++ set the channel's hangup cause.
++ * sslprivatekey option added to manager.conf and http.conf. Adds the ability
++ to specify a separate .pem file to hold a private key. By default sslcert
++ is used to hold both the public and private key.
++ * Options in manager.conf and http.conf with the 'ssl' prefix have been replaced
++ for options containing the 'tls' prefix. For example, 'sslenable' is now
++ 'tlsenable'. This has been done in effort to keep ssl and tls options consistent
++ across all .conf files. All affected sample.conf files have been modified to
++ reflect this change. Previous options such as 'sslenable' still work,
++ but options with the 'tls' prefix are preferred.
++
++Logger
++------
++ * The rarely used 'event_log' and LOG_EVENT channel have been removed; the few
++ users of this channel in the tree have been converted to LOG_NOTICE or removed
++ (in cases where the same message was already generated to another channel).
++
++CDR
++---
++ * Multiple files and formats can now be specified in cdr_custom.conf.
++
++Calendaring for Asterisk
++------------------------
++ * A new set of modules were added supporing calendar integration with Asterisk.
++ Dialplan functions for reading from and writing to calendars are included,
++ as well as the ability to execute dialplan logic upon calendar event notifications.
++ iCalendar, CalDAV, and Exchange Server calendars are supported (Exchange support
++ only tested on Exchange Server 2003 with no support for forms-based authentication).
++
+ ------------------------------------------------------------------------------
+ --- Functionality changes from Asterisk 1.6.1 to Asterisk 1.6.2 -------------
+ ------------------------------------------------------------------------------
+@@ -77,6 +240,7 @@
+ 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.
++ * Added service message support for 4ESS/5ESS switches.
+
+ Dialplan Functions
+ ------------------
+Index: sounds/Makefile
+===================================================================
+--- a/sounds/Makefile (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/sounds/Makefile (.../trunk) (revision 202568)
+@@ -19,7 +19,7 @@
+ MOH_DIR:=$(DESTDIR)$(ASTDATADIR)/moh
+ CORE_SOUNDS_VERSION:=1.4.15
+ EXTRA_SOUNDS_VERSION:=1.4.9
+-SOUNDS_URL:=http://downloads.digium.com/pub/telephony/sounds/releases
++SOUNDS_URL:=http://downloads.asterisk.org/pub/telephony/sounds/releases
+ MCS:=$(subst -EN-,-en-,$(MENUSELECT_CORE_SOUNDS))
+ MCS:=$(subst -FR-,-fr-,$(MCS))
+ MCS:=$(subst -ES-,-es-,$(MCS))
+Index: Makefile
+===================================================================
+--- a/Makefile (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/Makefile (.../trunk) (revision 202568)
+@@ -307,7 +307,7 @@
+
+ ifneq ($(findstring darwin,$(OSARCH)),)
+ ASTCFLAGS+=-D__Darwin__
+- SOLINK=-dynamic -bundle -undefined suppress -force_flat_namespace
++ SOLINK=-bundle -undefined suppress -force_flat_namespace
+ else
+ # These are used for all but Darwin
+ SOLINK=-shared
+@@ -327,6 +327,10 @@
+ # comment to print directories during submakes
+ #PRINT_DIR=yes
+
++ifneq ($(INSIDE_EMACS),)
++PRINT_DIR=yes
++endif
++
+ SILENTMAKE:=$(MAKE) --quiet --no-print-directory
+ ifneq ($(PRINT_DIR)$(NOISY_BUILD),)
+ SUBMAKE:=$(MAKE)
+@@ -371,24 +375,24 @@
+ menuselect/menuselect --check-deps menuselect.makeopts $(GLOBAL_MAKEOPTS) $(USER_MAKEOPTS)
+
+ $(MOD_SUBDIRS_EMBED_LDSCRIPT):
+- @echo "EMBED_LDSCRIPTS+="`$(SILENTMAKE) -C $(@:-embed-ldscript=) SUBDIR=$(@:-embed-ldscript=) __embed_ldscript` >> makeopts.embed_rules
++ +@echo "EMBED_LDSCRIPTS+="`$(SILENTMAKE) -C $(@:-embed-ldscript=) SUBDIR=$(@:-embed-ldscript=) __embed_ldscript` >> makeopts.embed_rules
+
+ $(MOD_SUBDIRS_EMBED_LDFLAGS):
+- @echo "EMBED_LDFLAGS+="`$(SILENTMAKE) -C $(@:-embed-ldflags=) SUBDIR=$(@:-embed-ldflags=) __embed_ldflags` >> makeopts.embed_rules
++ +@echo "EMBED_LDFLAGS+="`$(SILENTMAKE) -C $(@:-embed-ldflags=) SUBDIR=$(@:-embed-ldflags=) __embed_ldflags` >> makeopts.embed_rules
+
+ $(MOD_SUBDIRS_EMBED_LIBS):
+- @echo "EMBED_LIBS+="`$(SILENTMAKE) -C $(@:-embed-libs=) SUBDIR=$(@:-embed-libs=) __embed_libs` >> makeopts.embed_rules
++ +@echo "EMBED_LIBS+="`$(SILENTMAKE) -C $(@:-embed-libs=) SUBDIR=$(@:-embed-libs=) __embed_libs` >> makeopts.embed_rules
+
+ $(MOD_SUBDIRS_MENUSELECT_TREE):
+- @$(SUBMAKE) -C $(@:-menuselect-tree=) SUBDIR=$(@:-menuselect-tree=) moduleinfo
+- @$(SUBMAKE) -C $(@:-menuselect-tree=) SUBDIR=$(@:-menuselect-tree=) makeopts
++ +@$(SUBMAKE) -C $(@:-menuselect-tree=) SUBDIR=$(@:-menuselect-tree=) moduleinfo
++ +@$(SUBMAKE) -C $(@:-menuselect-tree=) SUBDIR=$(@:-menuselect-tree=) makeopts
+
+ makeopts.embed_rules: menuselect.makeopts
+ @echo "Generating embedded module rules ..."
+ @rm -f $@
+- @$(SUBMAKE) $(MOD_SUBDIRS_EMBED_LDSCRIPT)
+- @$(SUBMAKE) $(MOD_SUBDIRS_EMBED_LDFLAGS)
+- @$(SUBMAKE) $(MOD_SUBDIRS_EMBED_LIBS)
++ +@$(SUBMAKE) $(MOD_SUBDIRS_EMBED_LDSCRIPT)
++ +@$(SUBMAKE) $(MOD_SUBDIRS_EMBED_LDFLAGS)
++ +@$(SUBMAKE) $(MOD_SUBDIRS_EMBED_LIBS)
+
+ $(SUBDIRS): main/version.c include/asterisk/version.h include/asterisk/build.h include/asterisk/buildopts.h defaults.h makeopts.embed_rules
+
+@@ -411,10 +415,10 @@
+ endif
+
+ $(MOD_SUBDIRS):
+- @ASTCFLAGS="$(MOD_SUBDIR_CFLAGS) $(ASTCFLAGS)" ASTLDFLAGS="$(ASTLDFLAGS)" $(SUBMAKE) --no-builtin-rules -C $@ SUBDIR=$@ all
++ +@ASTCFLAGS="$(MOD_SUBDIR_CFLAGS) $(ASTCFLAGS)" ASTLDFLAGS="$(ASTLDFLAGS)" $(SUBMAKE) --no-builtin-rules -C $@ SUBDIR=$@ all
+
+ $(OTHER_SUBDIRS):
+- @ASTCFLAGS="$(OTHER_SUBDIR_CFLAGS) $(ASTCFLAGS)" ASTLDFLAGS="$(ASTLDFLAGS)" $(SUBMAKE) --no-builtin-rules -C $@ SUBDIR=$@ all
++ +@ASTCFLAGS="$(OTHER_SUBDIR_CFLAGS) $(ASTCFLAGS)" ASTLDFLAGS="$(ASTLDFLAGS)" $(SUBMAKE) --no-builtin-rules -C $@ SUBDIR=$@ all
+
+ defaults.h: makeopts
+ @build_tools/make_defaults_h > $@.tmp
+@@ -442,10 +446,10 @@
+ @rm -f $@.tmp
+
+ $(SUBDIRS_CLEAN):
+- @$(SUBMAKE) -C $(@:-clean=) clean
++ +@$(SUBMAKE) -C $(@:-clean=) clean
+
+ $(SUBDIRS_DIST_CLEAN):
+- @$(SUBMAKE) -C $(@:-dist-clean=) dist-clean
++ +@$(SUBMAKE) -C $(@:-dist-clean=) dist-clean
+
+ clean: $(SUBDIRS_CLEAN) _clean
+
+@@ -559,8 +563,10 @@
+ chmod 755 $(DESTDIR)$(ASTSBINDIR)/safe_asterisk;\
+ fi
+ $(INSTALL) -d $(DESTDIR)$(ASTHEADERDIR)
++ $(INSTALL) -d $(DESTDIR)$(ASTHEADERDIR)/doxygen
+ $(INSTALL) -m 644 include/asterisk.h $(DESTDIR)$(includedir)
+ $(INSTALL) -m 644 include/asterisk/*.h $(DESTDIR)$(ASTHEADERDIR)
++ $(INSTALL) -m 644 include/asterisk/doxygen/*.h $(DESTDIR)$(ASTHEADERDIR)/doxygen
+ if [ -n "$(OLDHEADERS)" ]; then \
+ rm -f $(addprefix $(DESTDIR)$(ASTHEADERDIR)/,$(OLDHEADERS)) ;\
+ fi
+@@ -918,28 +924,28 @@
+ MAKE_MENUSELECT=CC="$(HOST_CC)" CXX="$(CXX)" LD="" AR="" RANLIB="" CFLAGS="" $(MAKE) -C menuselect CONFIGURE_SILENT="--silent"
+
+ menuselect/menuselect: menuselect/makeopts
+- $(MAKE_MENUSELECT) menuselect
++ +$(MAKE_MENUSELECT) menuselect
+
+ menuselect/cmenuselect: menuselect/makeopts
+- $(MAKE_MENUSELECT) cmenuselect
++ +$(MAKE_MENUSELECT) cmenuselect
+
+ menuselect/gmenuselect: menuselect/makeopts
+- $(MAKE_MENUSELECT) gmenuselect
++ +$(MAKE_MENUSELECT) gmenuselect
+
+ menuselect/nmenuselect: menuselect/makeopts
+- $(MAKE_MENUSELECT) nmenuselect
++ +$(MAKE_MENUSELECT) nmenuselect
+
+ menuselect/makeopts: makeopts
+- $(MAKE_MENUSELECT) makeopts
++ +$(MAKE_MENUSELECT) makeopts
+
+ menuselect-tree: $(foreach dir,$(filter-out main,$(MOD_SUBDIRS)),$(wildcard $(dir)/*.c) $(wildcard $(dir)/*.cc)) build_tools/cflags.xml build_tools/cflags-devmode.xml sounds/sounds.xml build_tools/embed_modules.xml configure
+ @echo "Generating input for menuselect ..."
+ @echo "<?xml version=\"1.0\"?>" > $@
+ @echo >> $@
+ @echo "<menu name=\"Asterisk Module and Build Option Selection\">" >> $@
+- @for dir in $(sort $(filter-out main,$(MOD_SUBDIRS))); do $(SILENTMAKE) -C $${dir} SUBDIR=$${dir} moduleinfo >> $@; done
++ +@for dir in $(sort $(filter-out main,$(MOD_SUBDIRS))); do $(SILENTMAKE) -C $${dir} SUBDIR=$${dir} moduleinfo >> $@; done
+ @cat build_tools/cflags.xml >> $@
+- @for dir in $(sort $(filter-out main,$(MOD_SUBDIRS))); do $(SILENTMAKE) -C $${dir} SUBDIR=$${dir} makeopts >> $@; done
++ +@for dir in $(sort $(filter-out main,$(MOD_SUBDIRS))); do $(SILENTMAKE) -C $${dir} SUBDIR=$${dir} makeopts >> $@; done
+ @if [ "${AST_DEVMODE}" = "yes" ]; then \
+ cat build_tools/cflags-devmode.xml >> $@; \
+ fi
+Index: autoconf/ast_gcc_attribute.m4
+===================================================================
+--- a/autoconf/ast_gcc_attribute.m4 (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/autoconf/ast_gcc_attribute.m4 (.../trunk) (revision 202568)
+@@ -1,16 +1,16 @@
+ # Helper function to check for gcc attributes.
+-# AST_GCC_ATTRIBUTE([attribute name], [attribute syntax])
++# AST_GCC_ATTRIBUTE([attribute name], [attribute syntax], [attribute scope])
+
+ AC_DEFUN([AST_GCC_ATTRIBUTE],
+ [
+ AC_MSG_CHECKING(for compiler 'attribute $1' support)
+ saved_CFLAGS="$CFLAGS"
+-CFLAGS="$CFLAGS -Werror"
++CFLAGS="$CFLAGS -Wall -Wno-unused -Werror"
+
+ if test "x$2" = "x"
+ then
+ AC_COMPILE_IFELSE(
+- AC_LANG_PROGRAM([void __attribute__(($1)) *test(void *muffin, ...) {}],
++ AC_LANG_PROGRAM([$3 void __attribute__(($1)) *test(void *muffin, ...) {return (void *) 0;}],
+ []),
+ AC_MSG_RESULT(yes)
+ AC_DEFINE_UNQUOTED([HAVE_ATTRIBUTE_$1], 1, [Define to 1 if your GCC C compiler supports the '$1' attribute.]),
+@@ -18,7 +18,7 @@
+ )
+ else
+ AC_COMPILE_IFELSE(
+- AC_LANG_PROGRAM([void __attribute__(($2)) *test(void *muffin, ...) {}],
++ AC_LANG_PROGRAM([$3 void __attribute__(($2)) *test(void *muffin, ...) {return (void *) 0;}],
+ []),
+ AC_MSG_RESULT(yes)
+ AC_DEFINE_UNQUOTED([HAVE_ATTRIBUTE_$1], 1, [Define to 1 if your GCC C compiler supports the '$1' attribute.]),
+Index: autoconf/ast_ext_lib.m4
+===================================================================
+--- a/autoconf/ast_ext_lib.m4 (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/autoconf/ast_ext_lib.m4 (.../trunk) (revision 202568)
+@@ -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_rand.c
+===================================================================
+--- a/funcs/func_rand.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/funcs/func_rand.c (.../trunk) (revision 202568)
+@@ -87,6 +87,7 @@
+ static struct ast_custom_function acf_rand = {
+ .name = "RAND",
+ .read = acf_rand_exec,
++ .read_max = 12,
+ };
+
+ static int unload_module(void)
+Index: funcs/func_base64.c
+===================================================================
+--- a/funcs/func_base64.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/funcs/func_base64.c (.../trunk) (revision 202568)
+@@ -29,6 +29,7 @@
+ #include "asterisk/module.h"
+ #include "asterisk/pbx.h" /* function register/unregister */
+ #include "asterisk/utils.h"
++#include "asterisk/strings.h"
+
+ /*** DOCUMENTATION
+ <function name="BASE64_ENCODE" language="en_US">
+@@ -59,40 +60,61 @@
+ </function>
+ ***/
+
+-static int base64_encode(struct ast_channel *chan, const char *cmd, char *data,
+- char *buf, size_t len)
++static int base64_helper(struct ast_channel *chan, const char *cmd, char *data,
++ char *buf, struct ast_str **str, ssize_t len)
+ {
+ if (ast_strlen_zero(data)) {
+- ast_log(LOG_WARNING, "Syntax: BASE64_ENCODE(<data>) - missing argument!\n");
++ ast_log(LOG_WARNING, "Syntax: %s(<data>) - missing argument!\n", cmd);
+ return -1;
+ }
+
+- ast_base64encode(buf, (unsigned char *) data, strlen(data), len);
++ if (cmd[7] == 'E') {
++ if (buf) {
++ ast_base64encode(buf, (unsigned char *) data, strlen(data), len);
++ } else {
++ if (len >= 0) {
++ ast_str_make_space(str, len ? len : ast_str_strlen(*str) + strlen(data) * 4 / 3 + 2);
++ }
++ ast_base64encode(ast_str_buffer(*str) + ast_str_strlen(*str), (unsigned char *) data, strlen(data), ast_str_size(*str) - ast_str_strlen(*str));
++ ast_str_update(*str);
++ }
++ } else {
++ if (buf) {
++ ast_base64decode((unsigned char *) buf, data, len);
++ } else {
++ if (len >= 0) {
++ ast_str_make_space(str, len ? len : ast_str_strlen(*str) + strlen(data) * 3 / 4 + 2);
++ }
++ ast_base64decode((unsigned char *) ast_str_buffer(*str) + ast_str_strlen(*str), data, ast_str_size(*str) - ast_str_strlen(*str));
++ ast_str_update(*str);
++ }
++ }
+
+ return 0;
+ }
+
+-static int base64_decode(struct ast_channel *chan, const char *cmd, char *data,
++static int base64_buf_helper(struct ast_channel *chan, const char *cmd, char *data,
+ char *buf, size_t len)
+ {
+- if (ast_strlen_zero(data)) {
+- ast_log(LOG_WARNING, "Syntax: BASE64_DECODE(<base_64 string>) - missing argument!\n");
+- return -1;
+- }
++ return base64_helper(chan, cmd, data, buf, NULL, len);
++}
+
+- ast_base64decode((unsigned char *) buf, data, len);
+-
+- return 0;
++static int base64_str_helper(struct ast_channel *chan, const char *cmd, char *data,
++ struct ast_str **buf, ssize_t len)
++{
++ return base64_helper(chan, cmd, data, NULL, buf, len);
+ }
+
+ static struct ast_custom_function base64_encode_function = {
+ .name = "BASE64_ENCODE",
+- .read = base64_encode,
++ .read = base64_buf_helper,
++ .read2 = base64_str_helper,
+ };
+
+ static struct ast_custom_function base64_decode_function = {
+ .name = "BASE64_DECODE",
+- .read = base64_decode,
++ .read = base64_buf_helper,
++ .read2 = base64_str_helper,
+ };
+
+ static int unload_module(void)
+Index: funcs/func_speex.c
+===================================================================
+--- a/funcs/func_speex.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/funcs/func_speex.c (.../trunk) (revision 202568)
+@@ -337,13 +337,15 @@
+ static struct ast_custom_function agc_function = {
+ .name = "AGC",
+ .write = speex_write,
+- .read = speex_read
++ .read = speex_read,
++ .read_max = 22,
+ };
+
+ static struct ast_custom_function denoise_function = {
+ .name = "DENOISE",
+ .write = speex_write,
+- .read = speex_read
++ .read = speex_read,
++ .read_max = 22,
+ };
+
+ static int unload_module(void)
+Index: funcs/func_module.c
+===================================================================
+--- a/funcs/func_module.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/funcs/func_module.c (.../trunk) (revision 202568)
+@@ -65,6 +65,7 @@
+ static struct ast_custom_function ifmodule_function = {
+ .name = "IFMODULE",
+ .read = ifmodule_read,
++ .read_max = 2,
+ };
+
+
+Index: funcs/func_md5.c
+===================================================================
+--- a/funcs/func_md5.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/funcs/func_md5.c (.../trunk) (revision 202568)
+@@ -64,6 +64,7 @@
+ static struct ast_custom_function md5_function = {
+ .name = "MD5",
+ .read = md5,
++ .read_max = 33,
+ };
+
+ static int unload_module(void)
+Index: funcs/func_env.c
+===================================================================
+--- a/funcs/func_env.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/funcs/func_env.c (.../trunk) (revision 202568)
+@@ -230,7 +230,8 @@
+
+ static struct ast_custom_function stat_function = {
+ .name = "STAT",
+- .read = stat_read
++ .read = stat_read,
++ .read_max = 12,
+ };
+
+ static struct ast_custom_function file_function = {
+Index: funcs/func_strings.c
+===================================================================
+--- a/funcs/func_strings.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/funcs/func_strings.c (.../trunk) (revision 202568)
+@@ -276,12 +276,83 @@
+ <para>Example: ${QUOTE(ab"c"de)} will return "abcde"</para>
+ </description>
+ </function>
++ <function name="SHIFT" language="en_US">
++ <synopsis>
++ Removes and returns the first item off of a variable containing delimited text
++ </synopsis>
++ <syntax>
++ <parameter name="varname" required="true" />
++ <parameter name="delimiter" required="false" default="," />
++ </syntax>
++ <description>
++ <para>Example:</para>
++ <para>exten => s,1,Set(array=one,two,three)</para>
++ <para>exten => s,n,While($["${SET(var=${SHIFT(array)})}" != ""])</para>
++ <para>exten => s,n,NoOp(var is ${var})</para>
++ <para>exten => s,n,EndWhile</para>
++ <para>This would iterate over each value in array, left to right, and
++ would result in NoOp(var is one), NoOp(var is two), and
++ NoOp(var is three) being executed.
++ </para>
++ </description>
++ </function>
++ <function name="POP" language="en_US">
++ <synopsis>
++ Removes and returns the last item off of a variable containing delimited text
++ </synopsis>
++ <syntax>
++ <parameter name="varname" required="true" />
++ <parameter name="delimiter" required="false" default="," />
++ </syntax>
++ <description>
++ <para>Example:</para>
++ <para>exten => s,1,Set(array=one,two,three)</para>
++ <para>exten => s,n,While($["${SET(var=${POP(array)})}" != ""])</para>
++ <para>exten => s,n,NoOp(var is ${var})</para>
++ <para>exten => s,n,EndWhile</para>
++ <para>This would iterate over each value in array, right to left, and
++ would result in NoOp(var is three), NoOp(var is two), and
++ NoOp(var is one) being executed.
++ </para>
++ </description>
++ </function>
++ <function name="PUSH" language="en_US">
++ <synopsis>
++ Appends one or more values to the end of a variable containing delimited text
++ </synopsis>
++ <syntax>
++ <parameter name="varname" required="true" />
++ <parameter name="delimiter" required="false" default="," />
++ </syntax>
++ <description>
++ <para>Example: Set(PUSH(array)=one,two,three) would append one,
++ two, and three to the end of the values stored in the variable
++ "array".
++ </para>
++ </description>
++ </function>
++ <function name="UNSHIFT" language="en_US">
++ <synopsis>
++ Inserts one or more values to the beginning of a variable containing delimited text
++ </synopsis>
++ <syntax>
++ <parameter name="varname" required="true" />
++ <parameter name="delimiter" required="false" default="," />
++ </syntax>
++ <description>
++ <para>Example: Set(UNSHIFT(array)=one,two,three) would insert one,
++ two, and three before the values stored in the variable
++ "array".
++ </para>
++ </description>
++ </function>
+ ***/
+
+-static int function_fieldqty(struct ast_channel *chan, const char *cmd,
+- char *parse, char *buf, size_t len)
++static int function_fieldqty_helper(struct ast_channel *chan, const char *cmd,
++ char *parse, char *buf, struct ast_str **sbuf, ssize_t len)
+ {
+- char *varsubst, varval[8192], *varval2 = varval;
++ char *varsubst;
++ struct ast_str *str = ast_str_create(16);
+ int fieldcount = 0;
+ AST_DECLARE_APP_ARGS(args,
+ AST_APP_ARG(varname);
+@@ -290,6 +361,10 @@
+ char delim[2] = "";
+ size_t delim_used;
+
++ if (!str) {
++ return -1;
++ }
++
+ AST_STANDARD_APP_ARGS(args, parse);
+ if (args.delim) {
+ ast_get_encoded_char(args.delim, delim, &delim_used);
+@@ -297,27 +372,47 @@
+ varsubst = alloca(strlen(args.varname) + 4);
+
+ sprintf(varsubst, "${%s}", args.varname);
+- pbx_substitute_variables_helper(chan, varsubst, varval, sizeof(varval) - 1);
+- if (ast_strlen_zero(varval2))
++ ast_str_substitute_variables(&str, 0, chan, varsubst);
++ if (ast_str_strlen(str) == 0) {
+ fieldcount = 0;
+- else {
+- while (strsep(&varval2, delim))
++ } else {
++ char *varval = ast_str_buffer(str);
++ while (strsep(&varval, delim)) {
+ fieldcount++;
++ }
+ }
+ } else {
+ fieldcount = 1;
+ }
+- snprintf(buf, len, "%d", fieldcount);
++ if (sbuf) {
++ ast_str_set(sbuf, len, "%d", fieldcount);
++ } else {
++ snprintf(buf, len, "%d", fieldcount);
++ }
+
++ ast_free(str);
+ return 0;
+ }
+
++static int function_fieldqty(struct ast_channel *chan, const char *cmd,
++ char *parse, char *buf, size_t len)
++{
++ return function_fieldqty_helper(chan, cmd, parse, buf, NULL, len);
++}
++
++static int function_fieldqty_str(struct ast_channel *chan, const char *cmd,
++ char *parse, struct ast_str **buf, ssize_t len)
++{
++ return function_fieldqty_helper(chan, cmd, parse, NULL, buf, len);
++}
++
+ static struct ast_custom_function fieldqty_function = {
+ .name = "FIELDQTY",
+ .read = function_fieldqty,
++ .read2 = function_fieldqty_str,
+ };
+
+-static int listfilter(struct ast_channel *chan, const char *cmd, char *parse, char *buf, size_t len)
++static int listfilter(struct ast_channel *chan, const char *cmd, char *parse, char *buf, struct ast_str **bufstr, ssize_t len)
+ {
+ AST_DECLARE_APP_ARGS(args,
+ AST_APP_ARG(listname);
+@@ -327,11 +422,18 @@
+ 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);
++ struct ast_str *result, **result_ptr = &result;
+ char *delim;
+
+ AST_STANDARD_APP_ARGS(args, parse);
+
++ if (buf) {
++ result = ast_str_thread_get(&result_buf, 16);
++ } else {
++ /* Place the result directly into the output buffer */
++ result_ptr = bufstr;
++ }
++
+ if (args.argc < 3) {
+ ast_log(LOG_ERROR, "Usage: LISTFILTER(<listname>,<delimiter>,<fieldvalue>)\n");
+ return -1;
+@@ -351,7 +453,11 @@
+
+ /* 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 (buf) {
++ ast_copy_string(buf, orig_list, len);
++ } else {
++ ast_str_set(result_ptr, len, "%s", orig_list);
++ }
+ if (chan) {
+ ast_channel_unlock(chan);
+ }
+@@ -371,7 +477,9 @@
+
+ ast_str_reset(result);
+ /* Enough space for any result */
+- ast_str_make_space(&result, strlen(orig_list) + 1);
++ if (len > -1) {
++ ast_str_make_space(result_ptr, len ? len : strlen(orig_list) + 1);
++ }
+
+ begin = orig_list;
+ next = strstr(begin, delim);
+@@ -391,10 +499,10 @@
+ } else {
+ /* Copy field to output */
+ if (!first) {
+- ast_str_append(&result, 0, "%s", delim);
++ ast_str_append(result_ptr, len, "%s", delim);
+ }
+
+- ast_str_append_substr(&result, 0, begin, cur - begin + 1);
++ ast_str_append_substr(result_ptr, len, begin, cur - begin + 1);
+ first = 0;
+ begin = cur + dlen;
+ }
+@@ -403,14 +511,27 @@
+ ast_channel_unlock(chan);
+ }
+
+- ast_copy_string(buf, ast_str_buffer(result), len);
++ if (buf) {
++ ast_copy_string(buf, ast_str_buffer(result), len);
++ }
+
+ return 0;
+ }
+
++static int listfilter_read(struct ast_channel *chan, const char *cmd, char *parse, char *buf, size_t len)
++{
++ return listfilter(chan, cmd, parse, buf, NULL, len);
++}
++
++static int listfilter_read2(struct ast_channel *chan, const char *cmd, char *parse, struct ast_str **buf, ssize_t len)
++{
++ return listfilter(chan, cmd, parse, NULL, buf, len);
++}
++
+ static struct ast_custom_function listfilter_function = {
+ .name = "LISTFILTER",
+- .read = listfilter,
++ .read = listfilter_read,
++ .read2 = listfilter_read2,
+ };
+
+ static int filter(struct ast_channel *chan, const char *cmd, char *parse, char *buf,
+@@ -538,7 +659,7 @@
+ AST_LIST_TRAVERSE_SAFE_END
+ }
+
+-static int exec_clearhash(struct ast_channel *chan, void *data)
++static int exec_clearhash(struct ast_channel *chan, const char *data)
+ {
+ char prefix[80];
+ snprintf(prefix, sizeof(prefix), HASH_PREFIX, data ? (char *)data : "null");
+@@ -614,16 +735,15 @@
+ static int hashkeys_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
+ {
+ struct ast_var_t *newvar;
+- int plen;
+- char prefix[80];
+- snprintf(prefix, sizeof(prefix), HASH_PREFIX, data);
+- plen = strlen(prefix);
++ struct ast_str *prefix = ast_str_alloca(80);
+
++ ast_str_set(&prefix, -1, HASH_PREFIX, data);
+ memset(buf, 0, len);
++
+ AST_LIST_TRAVERSE(&chan->varshead, newvar, entries) {
+- if (strncasecmp(prefix, ast_var_name(newvar), plen) == 0) {
++ if (strncasecmp(ast_str_buffer(prefix), ast_var_name(newvar), ast_str_strlen(prefix)) == 0) {
+ /* Copy everything after the prefix */
+- strncat(buf, ast_var_name(newvar) + plen, len - strlen(buf) - 1);
++ strncat(buf, ast_var_name(newvar) + ast_str_strlen(prefix), len - strlen(buf) - 1);
+ /* Trim the trailing ~ */
+ buf[strlen(buf) - 1] = ',';
+ }
+@@ -633,6 +753,29 @@
+ return 0;
+ }
+
++static int hashkeys_read2(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t len)
++{
++ struct ast_var_t *newvar;
++ struct ast_str *prefix = ast_str_alloca(80);
++ char *tmp;
++
++ ast_str_set(&prefix, -1, HASH_PREFIX, data);
++
++ AST_LIST_TRAVERSE(&chan->varshead, newvar, entries) {
++ if (strncasecmp(ast_str_buffer(prefix), ast_var_name(newvar), ast_str_strlen(prefix)) == 0) {
++ /* Copy everything after the prefix */
++ ast_str_append(buf, len, "%s", ast_var_name(newvar) + ast_str_strlen(prefix));
++ /* Trim the trailing ~ */
++ tmp = ast_str_buffer(*buf);
++ tmp[ast_str_strlen(*buf) - 1] = ',';
++ }
++ }
++ /* Trim the trailing comma */
++ tmp = ast_str_buffer(*buf);
++ tmp[ast_str_strlen(*buf) - 1] = '\0';
++ return 0;
++}
++
+ static int hash_write(struct ast_channel *chan, const char *cmd, char *var, const char *value)
+ {
+ char varname[256];
+@@ -708,6 +851,7 @@
+ static struct ast_custom_function hashkeys_function = {
+ .name = "HASHKEYS",
+ .read = hashkeys_read,
++ .read2 = hashkeys_read2,
+ };
+
+ static struct ast_custom_function array_function = {
+@@ -759,6 +903,7 @@
+ static struct ast_custom_function len_function = {
+ .name = "LEN",
+ .read = len,
++ .read_max = 12,
+ };
+
+ static int acf_strftime(struct ast_channel *chan, const char *cmd, char *parse,
+@@ -850,9 +995,23 @@
+ return 0;
+ }
+
++static int function_eval2(struct ast_channel *chan, const char *cmd, char *data,
++ struct ast_str **buf, ssize_t buflen)
++{
++ if (ast_strlen_zero(data)) {
++ ast_log(LOG_WARNING, "EVAL requires an argument: EVAL(<string>)\n");
++ return -1;
++ }
++
++ ast_str_substitute_variables(buf, buflen, chan, data);
++
++ return 0;
++}
++
+ static struct ast_custom_function eval_function = {
+ .name = "EVAL",
+ .read = function_eval,
++ .read2 = function_eval2,
+ };
+
+ static int keypadhash(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
+@@ -904,9 +1063,24 @@
+ return 0;
+ }
+
++static int string_toupper2(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t buflen)
++{
++ char *bufptr, *dataptr = data;
++
++ if (buflen > -1) {
++ ast_str_make_space(buf, buflen > 0 ? buflen : strlen(data) + 1);
++ }
++ bufptr = ast_str_buffer(*buf);
++ while ((bufptr < ast_str_buffer(*buf) + ast_str_size(*buf) - 1) && (*bufptr++ = toupper(*dataptr++)));
++ ast_str_update(*buf);
++
++ return 0;
++}
++
+ static struct ast_custom_function toupper_function = {
+ .name = "TOUPPER",
+ .read = string_toupper,
++ .read2 = string_toupper2,
+ };
+
+ static int string_tolower(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
+@@ -918,11 +1092,160 @@
+ return 0;
+ }
+
++static int string_tolower2(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t buflen)
++{
++ char *bufptr, *dataptr = data;
++
++ if (buflen > -1) {
++ ast_str_make_space(buf, buflen > 0 ? buflen : strlen(data) + 1);
++ }
++ bufptr = ast_str_buffer(*buf);
++ while ((bufptr < ast_str_buffer(*buf) + ast_str_size(*buf) - 1) && (*bufptr++ = tolower(*dataptr++)));
++ ast_str_update(*buf);
++
++ return 0;
++}
++
+ static struct ast_custom_function tolower_function = {
+ .name = "TOLOWER",
+ .read = string_tolower,
++ .read2 = string_tolower2,
+ };
+
++static int array_remove(struct ast_channel *chan, const char *cmd, char *var, char *buf, size_t len, int beginning)
++{
++ const char *tmp;
++ char *after, *before;
++ char *(*search_func)(const char *s, int c) = beginning ? strchr : strrchr;
++ AST_DECLARE_APP_ARGS(args,
++ AST_APP_ARG(var);
++ AST_APP_ARG(delimiter);
++ );
++
++ if (!chan) {
++ ast_log(LOG_WARNING, "%s requires a channel\n", cmd);
++ return -1;
++ }
++
++ AST_STANDARD_APP_ARGS(args, var);
++
++ if (ast_strlen_zero(args.var)) {
++ ast_log(LOG_WARNING, "%s requires a channel variable name\n", cmd);
++ return -1;
++ }
++
++ if (args.delimiter && strlen(args.delimiter) != 1) {
++ ast_log(LOG_WARNING, "%s delimeters should be a single character\n", cmd);
++ return -1;
++ }
++
++ ast_channel_lock(chan);
++ if (ast_strlen_zero(tmp = pbx_builtin_getvar_helper(chan, args.var))) {
++ ast_channel_unlock(chan);
++ return 0;
++ }
++
++ before = ast_strdupa(tmp);
++ ast_channel_unlock(chan);
++
++ /* Only one entry in array */
++ if (!(after = search_func(before, S_OR(args.delimiter, ",")[0]))) {
++ ast_copy_string(buf, before, len);
++ pbx_builtin_setvar_helper(chan, args.var, "");
++ } else {
++ *after++ = '\0';
++ ast_copy_string(buf, beginning ? before : after, len);
++ pbx_builtin_setvar_helper(chan, args.var, beginning ? after : before);
++ }
++
++ return 0;
++
++}
++
++static int shift(struct ast_channel *chan, const char *cmd, char *var, char *buf, size_t len)
++{
++ return array_remove(chan, cmd, var, buf, len, 1);
++}
++static struct ast_custom_function shift_function = {
++ .name = "SHIFT",
++ .read = shift,
++};
++
++static int pop(struct ast_channel *chan, const char *cmd, char *var, char *buf, size_t len)
++{
++ return array_remove(chan, cmd, var, buf, len, 0);
++}
++
++static struct ast_custom_function pop_function = {
++ .name = "POP",
++ .read = pop,
++};
++
++static int array_insert(struct ast_channel *chan, const char *cmd, char *var, const char *val, int beginning)
++{
++ const char *tmp;
++ struct ast_str *buf;
++ AST_DECLARE_APP_ARGS(args,
++ AST_APP_ARG(var);
++ AST_APP_ARG(delimiter);
++ );
++
++ if (!chan) {
++ ast_log(LOG_WARNING, "%s requires a channel\n", cmd);
++ return -1;
++ }
++
++ AST_STANDARD_APP_ARGS(args, var);
++
++ if (ast_strlen_zero(args.var) || ast_strlen_zero(val)) {
++ ast_log(LOG_WARNING, "%s requires a variable, and at least one value\n", cmd);
++ return -1;
++ }
++
++ if (args.delimiter && strlen(args.delimiter) != 1) {
++ ast_log(LOG_WARNING, "%s delimeters should be a single character\n", cmd);
++ return -1;
++ }
++
++ if (!(buf = ast_str_create(32))) {
++ ast_log(LOG_ERROR, "Unable to allocate memory for buffer!\n");
++ return -1;
++ }
++
++ ast_channel_lock(chan);
++ if (!(tmp = pbx_builtin_getvar_helper(chan, args.var))) {
++ ast_str_set(&buf, 0, "%s", val);
++ } else {
++ ast_str_append(&buf, 0, "%s%s%s", beginning ? val : tmp, S_OR(args.delimiter, ","), beginning ? tmp : val);
++ }
++ ast_channel_unlock(chan);
++
++ pbx_builtin_setvar_helper(chan, args.var, ast_str_buffer(buf));
++ ast_free(buf);
++
++ return 0;
++}
++
++static int push(struct ast_channel *chan, const char *cmd, char *var, const char *val)
++{
++ return array_insert(chan, cmd, var, val, 0);
++}
++
++static struct ast_custom_function push_function = {
++ .name = "PUSH",
++ .write = push,
++};
++
++static int unshift(struct ast_channel *chan, const char *cmd, char *var, const char *val)
++{
++ return array_insert(chan, cmd, var, val, 1);
++}
++
++static struct ast_custom_function unshift_function = {
++ .name = "UNSHIFT",
++ .write = unshift,
++};
++
+ static int unload_module(void)
+ {
+ int res = 0;
+@@ -943,6 +1266,10 @@
+ res |= ast_unregister_application(app_clearhash);
+ res |= ast_custom_function_unregister(&toupper_function);
+ res |= ast_custom_function_unregister(&tolower_function);
++ res |= ast_custom_function_unregister(&shift_function);
++ res |= ast_custom_function_unregister(&pop_function);
++ res |= ast_custom_function_unregister(&push_function);
++ res |= ast_custom_function_unregister(&unshift_function);
+
+ return res;
+ }
+@@ -967,6 +1294,10 @@
+ res |= ast_register_application_xml(app_clearhash, exec_clearhash);
+ res |= ast_custom_function_register(&toupper_function);
+ res |= ast_custom_function_register(&tolower_function);
++ res |= ast_custom_function_register(&shift_function);
++ res |= ast_custom_function_register(&pop_function);
++ res |= ast_custom_function_register(&push_function);
++ res |= ast_custom_function_register(&unshift_function);
+
+ return res;
+ }
+Index: funcs/func_sysinfo.c
+===================================================================
+--- a/funcs/func_sysinfo.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/funcs/func_sysinfo.c (.../trunk) (revision 202568)
+@@ -36,6 +36,57 @@
+ #include "asterisk/module.h"
+ #include "asterisk/pbx.h"
+
++/*** DOCUMENTATION
++ <function name="SYSINFO" language="en_US">
++ <synopsis>
++ Returns system information specified by parameter.
++ </synopsis>
++ <syntax>
++ <parameter name="parameter" required="true">
++ <enumlist>
++ <enum name="loadavg">
++ <para>System load average from past minute.</para>
++ </enum>
++ <enum name="numcalls">
++ <para>Number of active calls currently in progress.</para>
++ </enum>
++ <enum name="uptime">
++ <para>System uptime in hours.</para>
++ <note><para>This parameter is dependant upon operating system.</para></note>
++ </enum>
++ <enum name="totalram">
++ <para>Total usable main memory size in KiB.</para>
++ <note><para>This parameter is dependant upon operating system.</para></note>
++ </enum>
++ <enum name="freeram">
++ <para>Available memory size in KiB.</para>
++ <note><para>This parameter is dependant upon operating system.</para></note>
++ </enum>
++ <enum name="bufferram">
++ <para>Memory used by buffers in KiB.</para>
++ <note><para>This parameter is dependant upon operating system.</para></note>
++ </enum>
++ <enum name="totalswap">
++ <para>Total swap space still available in KiB.</para>
++ <note><para>This parameter is dependant upon operating system.</para></note>
++ </enum>
++ <enum name="freeswap">
++ <para>Free swap space still available in KiB.</para>
++ <note><para>This parameter is dependant upon operating system.</para></note>
++ </enum>
++ <enum name="numprocs">
++ <para>Number of current processes.</para>
++ <note><para>This parameter is dependant upon operating system.</para></note>
++ </enum>
++ </enumlist>
++ </parameter>
++ </syntax>
++ <description>
++ <para>Returns information from a given parameter.</para>
++ </description>
++ </function>
++ ***/
++
+ static int sysinfo_helper(struct ast_channel *chan, const char *cmd, char *data,
+ char *buf, size_t len)
+ {
+@@ -83,23 +134,8 @@
+
+ static struct ast_custom_function sysinfo_function = {
+ .name = "SYSINFO",
+- .synopsis = "Returns system information specified by parameter.",
+- .syntax = "SYSINFO(<parameter>)",
+ .read = sysinfo_helper,
+- .desc =
+-"Returns information from a given parameter\n"
+-" Options:\n"
+-" loadavg - system load average from past minute\n"
+-" numcalls - number of active calls currently in progress\n"
+-#if defined(HAVE_SYSINFO)
+-" uptime - system uptime in hours\n"
+-" totalram - total usable main memory size in KiB\n"
+-" freeram - available memory size in KiB\n"
+-" bufferram - memory used by buffers in KiB\n"
+-" totalswap - total swap space size in KiB\n"
+-" freeswap - free swap space still available in KiB\n"
+-" numprocs - number of current processes\n",
+-#endif /* HAVE_SYSINFO */
++ .read_max = 22,
+ };
+
+ static int unload_module(void)
+Index: funcs/func_vmcount.c
+===================================================================
+--- a/funcs/func_vmcount.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/funcs/func_vmcount.c (.../trunk) (revision 202568)
+@@ -94,9 +94,10 @@
+ return 0;
+ }
+
+-struct ast_custom_function acf_vmcount = {
++static struct ast_custom_function acf_vmcount = {
+ .name = "VMCOUNT",
+ .read = acf_vmcount_exec,
++ .read_max = 12,
+ };
+
+ static int unload_module(void)
+Index: funcs/func_sha1.c
+===================================================================
+--- a/funcs/func_sha1.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/funcs/func_sha1.c (.../trunk) (revision 202568)
+@@ -74,6 +74,7 @@
+ static struct ast_custom_function sha1_function = {
+ .name = "SHA1",
+ .read = sha1,
++ .read_max = 42,
+ };
+
+ static int unload_module(void)
+Index: funcs/func_logic.c
+===================================================================
+--- a/funcs/func_logic.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/funcs/func_logic.c (.../trunk) (revision 202568)
+@@ -223,41 +223,73 @@
+ return 0;
+ }
+
+-static int acf_import(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
++static int set2(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **str, ssize_t len)
+ {
++ if (len > -1) {
++ ast_str_make_space(str, len == 0 ? strlen(data) : len);
++ }
++ return set(chan, cmd, data, ast_str_buffer(*str), ast_str_size(*str));
++}
++
++static int import_helper(struct ast_channel *chan, const char *cmd, char *data, char *buf, struct ast_str **str, ssize_t len)
++{
+ AST_DECLARE_APP_ARGS(args,
+ AST_APP_ARG(channel);
+ AST_APP_ARG(varname);
+ );
+ AST_STANDARD_APP_ARGS(args, data);
+- buf[0] = 0;
++ if (buf) {
++ *buf = '\0';
++ }
++
+ if (!ast_strlen_zero(args.varname)) {
+- struct ast_channel *chan2 = ast_get_channel_by_name_locked(args.channel);
+- if (chan2) {
++ struct ast_channel *chan2;
++
++ if ((chan2 = ast_channel_get_by_name(args.channel))) {
+ char *s = alloca(strlen(args.varname) + 4);
+ if (s) {
+ sprintf(s, "${%s}", args.varname);
+- pbx_substitute_variables_helper(chan2, s, buf, len);
++ ast_channel_lock(chan2);
++ if (buf) {
++ pbx_substitute_variables_helper(chan2, s, buf, len);
++ } else {
++ ast_str_substitute_variables(str, len, chan2, s);
++ }
++ ast_channel_unlock(chan2);
+ }
+- ast_channel_unlock(chan2);
++ chan2 = ast_channel_unref(chan2);
+ }
+ }
++
+ return 0;
+ }
+
++static int import_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
++{
++ return import_helper(chan, cmd, data, buf, NULL, len);
++}
++
++static int import_read2(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **str, ssize_t len)
++{
++ return import_helper(chan, cmd, data, NULL, str, len);
++}
++
+ static struct ast_custom_function isnull_function = {
+ .name = "ISNULL",
+ .read = isnull,
++ .read_max = 2,
+ };
+
+ static struct ast_custom_function set_function = {
+ .name = "SET",
+ .read = set,
++ .read2 = set2,
+ };
+
+ static struct ast_custom_function exists_function = {
+ .name = "EXISTS",
+ .read = exists,
++ .read_max = 2,
+ };
+
+ static struct ast_custom_function if_function = {
+@@ -272,7 +304,8 @@
+
+ static struct ast_custom_function import_function = {
+ .name = "IMPORT",
+- .read = acf_import,
++ .read = import_read,
++ .read2 = import_read2,
+ };
+
+ static int unload_module(void)
+Index: funcs/func_enum.c
+===================================================================
+--- a/funcs/func_enum.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/funcs/func_enum.c (.../trunk) (revision 202568)
+@@ -216,7 +216,7 @@
+ return 0;
+ }
+
+-unsigned int enum_datastore_id;
++static unsigned int enum_datastore_id;
+
+ struct enum_result_datastore {
+ struct enum_context *context;
+@@ -243,7 +243,7 @@
+ erds_destroy(erds);
+ }
+
+-const struct ast_datastore_info enum_result_datastore_info = {
++static const struct ast_datastore_info enum_result_datastore_info = {
+ .type = "ENUMQUERY",
+ .destroy = erds_destroy_cb,
+ };
+Index: funcs/func_groupcount.c
+===================================================================
+--- a/funcs/func_groupcount.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/funcs/func_groupcount.c (.../trunk) (revision 202568)
+@@ -134,6 +134,7 @@
+ static struct ast_custom_function group_count_function = {
+ .name = "GROUP_COUNT",
+ .read = group_count_function_read,
++ .read_max = 12,
+ };
+
+ static int group_match_count_function_read(struct ast_channel *chan,
+@@ -159,6 +160,7 @@
+ static struct ast_custom_function group_match_count_function = {
+ .name = "GROUP_MATCH_COUNT",
+ .read = group_match_count_function_read,
++ .read_max = 12,
+ .write = NULL,
+ };
+
+Index: funcs/func_odbc.c
+===================================================================
+--- a/funcs/func_odbc.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/funcs/func_odbc.c (.../trunk) (revision 202568)
+@@ -99,10 +99,10 @@
+
+ static char *config = "func_odbc.conf";
+
+-enum {
++enum odbc_option_flags {
+ OPT_ESCAPECOMMAS = (1 << 0),
+ OPT_MULTIROW = (1 << 1),
+-} odbc_option_flags;
++};
+
+ struct acf_odbc_query {
+ AST_RWLIST_ENTRY(acf_odbc_query) list;
+@@ -118,7 +118,7 @@
+
+ static void odbc_datastore_free(void *data);
+
+-struct ast_datastore_info odbc_info = {
++static struct ast_datastore_info odbc_info = {
+ .type = "FUNC_ODBC",
+ .destroy = odbc_datastore_free,
+ };
+@@ -135,7 +135,7 @@
+ char names[0];
+ };
+
+-AST_RWLIST_HEAD_STATIC(queries, acf_odbc_query);
++static AST_RWLIST_HEAD_STATIC(queries, acf_odbc_query);
+
+ static int resultcount = 0;
+
+@@ -257,7 +257,7 @@
+ if (chan)
+ ast_autoservice_stop(chan);
+ if (bogus_chan) {
+- ast_channel_free(chan);
++ ast_channel_release(chan);
+ } else {
+ pbx_builtin_setvar_helper(chan, "ODBCSTATUS", status);
+ }
+@@ -367,7 +367,7 @@
+ if (chan)
+ ast_autoservice_stop(chan);
+ if (bogus_chan)
+- ast_channel_free(chan);
++ ast_channel_release(chan);
+
+ return 0;
+ }
+@@ -473,7 +473,7 @@
+ ast_autoservice_stop(chan);
+ }
+ if (bogus_chan) {
+- ast_channel_free(chan);
++ ast_channel_release(chan);
+ }
+ return -1;
+ }
+@@ -490,7 +490,7 @@
+ ast_autoservice_stop(chan);
+ }
+ if (bogus_chan) {
+- ast_channel_free(chan);
++ ast_channel_release(chan);
+ }
+ return -1;
+ }
+@@ -517,7 +517,7 @@
+ if (chan)
+ ast_autoservice_stop(chan);
+ if (bogus_chan)
+- ast_channel_free(chan);
++ ast_channel_release(chan);
+ return res1;
+ }
+
+@@ -561,7 +561,7 @@
+ if (chan)
+ ast_autoservice_stop(chan);
+ if (bogus_chan)
+- ast_channel_free(chan);
++ ast_channel_release(chan);
+ return -1;
+ }
+ resultset = tmp;
+@@ -657,7 +657,7 @@
+ if (chan)
+ ast_autoservice_stop(chan);
+ if (bogus_chan)
+- ast_channel_free(chan);
++ ast_channel_release(chan);
+ return -1;
+ }
+ odbc_store->data = resultset;
+@@ -670,7 +670,7 @@
+ if (chan)
+ ast_autoservice_stop(chan);
+ if (bogus_chan)
+- ast_channel_free(chan);
++ ast_channel_release(chan);
+ return 0;
+ }
+
+@@ -732,7 +732,7 @@
+
+ static char *app_odbcfinish = "ODBCFinish";
+
+-static int exec_odbcfinish(struct ast_channel *chan, void *data)
++static int exec_odbcfinish(struct ast_channel *chan, const char *data)
+ {
+ struct ast_datastore *store = ast_channel_datastore_find(chan, &odbc_info, data);
+ if (!store) /* Already freed; no big deal. */
+@@ -1060,7 +1060,7 @@
+ }
+
+ ast_str_substitute_variables(&sql, 0, chan, query->sql_read);
+- ast_channel_free(chan);
++ chan = ast_channel_release(chan);
+
+ if (a->argc == 5 && !strcmp(a->argv[4], "exec")) {
+ /* Execute the query */
+@@ -1273,7 +1273,7 @@
+ 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);
++ chan = ast_channel_release(chan);
+
+ if (a->argc == 6 && !strcmp(a->argv[5], "exec")) {
+ /* Execute the query */
+Index: funcs/func_aes.c
+===================================================================
+--- a/funcs/func_aes.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/funcs/func_aes.c (.../trunk) (revision 202568)
+@@ -31,6 +31,7 @@
+ #include "asterisk/pbx.h"
+ #include "asterisk/app.h"
+ #include "asterisk/aes.h"
++#include "asterisk/strings.h"
+
+ #define AES_BLOCK_SIZE 16
+
+@@ -71,15 +72,15 @@
+
+
+ static int aes_helper(struct ast_channel *chan, const char *cmd, char *data,
+- char *buf, size_t len)
++ char *buf, struct ast_str **str, ssize_t maxlen)
+ {
+ unsigned char curblock[AES_BLOCK_SIZE] = { 0, };
+- char *tmp;
++ char *tmp = NULL;
+ char *tmpP;
+ int data_len, encrypt;
++ int keylen, len, tmplen, elen = 0;
+ 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);
+@@ -92,22 +93,37 @@
+ 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);
++ if ((keylen = 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%s!\n", cmd, keylen < 16 ? " - padding" : "");
+ 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 */
++ if (buf) {
++ len = maxlen;
++ } else if (maxlen == -1) {
++ len = ast_str_size(*str);
++ } else if (maxlen > 0) {
++ len = maxlen;
++ } else {
++ len = INT_MAX;
++ }
++ ast_debug(3, "len=%d\n", len);
++
++ encrypt = strcmp("AES_DECRYPT", cmd); /* -1 if encrypting, 0 if decrypting */
++ /* Round up the buffer to an even multiple of 16, plus 1 */
++ tmplen = (strlen(args.data) / 16 + 1) * 16 + 1;
++ tmp = ast_calloc(1, tmplen);
+ 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);
++ /* encryption: plaintext -> encryptedtext -> base64 */
++ ast_aes_encrypt_key((unsigned char *) args.key, &ecx);
++ strcpy(tmp, args.data);
+ data_len = strlen(tmp);
+ } else {
+- data_len = ast_base64decode((unsigned char *) tmp, args.data, len);
++ /* decryption: base64 -> encryptedtext -> plaintext */
++ ast_aes_decrypt_key((unsigned char *) args.key, &dcx);
++ data_len = ast_base64decode((unsigned char *) tmp, args.data, tmplen);
+ }
+
+ if (data_len >= len) { /* make sure to not go over buffer len */
+@@ -116,8 +132,11 @@
+ }
+
+ while (data_len > 0) {
++ /* Tricky operation. We first copy the data into curblock, then
++ * the data is encrypted or decrypted and put back into the original
++ * buffer. */
+ memset(curblock, 0, AES_BLOCK_SIZE);
+- memcpy(curblock, tmpP, (data_len < AES_BLOCK_SIZE) ? data_len : AES_BLOCK_SIZE);
++ memcpy(curblock, tmpP, AES_BLOCK_SIZE);
+ if (encrypt) {
+ ast_aes_encrypt(curblock, (unsigned char *) tmpP, &ecx);
+ } else {
+@@ -125,26 +144,53 @@
+ }
+ tmpP += AES_BLOCK_SIZE;
+ data_len -= AES_BLOCK_SIZE;
++ elen += AES_BLOCK_SIZE;
+ }
+
+ if (encrypt) { /* if encrypting encode result to base64 */
+- ast_base64encode(buf, (unsigned char *) tmp, strlen(tmp), len);
++ if (buf) {
++ ast_base64encode(buf, (unsigned char *) tmp, elen, len);
++ } else {
++ if (maxlen >= 0) {
++ ast_str_make_space(str, maxlen ? maxlen : elen * 4 / 3 + 2);
++ }
++ ast_base64encode(ast_str_buffer(*str), (unsigned char *) tmp, elen, ast_str_size(*str));
++ ast_str_update(*str);
++ }
+ } else {
+- memcpy(buf, tmp, len);
++ if (buf) {
++ memcpy(buf, tmp, len);
++ } else {
++ ast_str_set(str, maxlen, "%s", tmp);
++ }
+ }
+ ast_free(tmp);
+
+ return 0;
+ }
+
++static int aes_buf_helper(struct ast_channel *chan, const char *cmd, char *data,
++ char *buf, size_t maxlen)
++{
++ return aes_helper(chan, cmd, data, buf, NULL, maxlen);
++}
++
++static int aes_str_helper(struct ast_channel *chan, const char *cmd, char *data,
++ struct ast_str **buf, ssize_t maxlen)
++{
++ return aes_helper(chan, cmd, data, NULL, buf, maxlen);
++}
++
+ static struct ast_custom_function aes_encrypt_function = {
+ .name = "AES_ENCRYPT",
+- .read = aes_helper,
++ .read = aes_buf_helper,
++ .read2 = aes_str_helper,
+ };
+
+ static struct ast_custom_function aes_decrypt_function = {
+ .name = "AES_DECRYPT",
+- .read = aes_helper,
++ .read = aes_buf_helper,
++ .read2 = aes_str_helper,
+ };
+
+ static int unload_module(void)
+Index: funcs/func_dialplan.c
+===================================================================
+--- a/funcs/func_dialplan.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/funcs/func_dialplan.c (.../trunk) (revision 202568)
+@@ -105,6 +105,7 @@
+ static struct ast_custom_function isexten_function = {
+ .name = "DIALPLAN_EXISTS",
+ .read = isexten_function_read,
++ .read_max = 2,
+ };
+
+ static int unload_module(void)
+Index: funcs/func_db.c
+===================================================================
+--- a/funcs/func_db.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/funcs/func_db.c (.../trunk) (revision 202568)
+@@ -201,6 +201,7 @@
+ static struct ast_custom_function db_exists_function = {
+ .name = "DB_EXISTS",
+ .read = function_db_exists,
++ .read_max = 2,
+ };
+
+ static int function_db_delete(struct ast_channel *chan, const char *cmd,
+Index: funcs/func_timeout.c
+===================================================================
+--- a/funcs/func_timeout.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/funcs/func_timeout.c (.../trunk) (revision 202568)
+@@ -191,6 +191,7 @@
+ static struct ast_custom_function timeout_function = {
+ .name = "TIMEOUT",
+ .read = timeout_read,
++ .read_max = 22,
+ .write = timeout_write,
+ };
+
+Index: funcs/func_lock.c
+===================================================================
+--- a/funcs/func_lock.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/funcs/func_lock.c (.../trunk) (revision 202568)
+@@ -84,7 +84,7 @@
+
+
+
+-AST_LIST_HEAD_STATIC(locklist, lock_frame);
++static AST_LIST_HEAD_STATIC(locklist, lock_frame);
+
+ static void lock_free(void *data);
+ static int unloading = 0;
+@@ -324,16 +324,19 @@
+ static struct ast_custom_function lock_function = {
+ .name = "LOCK",
+ .read = lock_read,
++ .read_max = 2,
+ };
+
+ static struct ast_custom_function trylock_function = {
+ .name = "TRYLOCK",
+ .read = trylock_read,
++ .read_max = 2,
+ };
+
+ static struct ast_custom_function unlock_function = {
+ .name = "UNLOCK",
+ .read = unlock_read,
++ .read_max = 2,
+ };
+
+ static int unload_module(void)
+Index: funcs/func_math.c
+===================================================================
+--- a/funcs/func_math.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/funcs/func_math.c (.../trunk) (revision 202568)
+@@ -1,9 +1,10 @@
+ /*
+ * Asterisk -- An open source telephony toolkit.
+ *
+- * Copyright (C) 2004 - 2006, Andy Powell
++ * Copyright (C) 2004 - 2006, Andy Powell
+ *
+ * Updated by Mark Spencer <markster@digium.com>
++ * Updated by Nir Simionovich <nirs@greenfieldtech.net>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+@@ -22,6 +23,7 @@
+ *
+ * \author Andy Powell
+ * \author Mark Spencer <markster@digium.com>
++ * \author Nir Simionovich <nirs@greenfieldtech.net>
+ *
+ * \ingroup functions
+ */
+@@ -66,6 +68,40 @@
+ <para>Example: Set(i=${MATH(123%16,int)}) - sets var i=11</para>
+ </description>
+ </function>
++ <function name="INC" language="en_US">
++ <synopsis>
++ Increments the value of a variable, while returning the updated value to the dialplan
++ </synopsis>
++ <syntax>
++ <parameter name="variable" required="true">
++ <para>
++ The variable name to be manipulated, without the braces.
++ </para>
++ </parameter>
++ </syntax>
++ <description>
++ <para>Increments the value of a variable, while returning the updated value to the dialplan</para>
++ <para>Example: INC(MyVAR) - Increments MyVar</para>
++ <para>Note: INC(${MyVAR}) - Is wrong, as INC expects the variable name, not its value</para>
++ </description>
++ </function>
++ <function name="DEC" language="en_US">
++ <synopsis>
++ Decrements the value of a variable, while returning the updated value to the dialplan
++ </synopsis>
++ <syntax>
++ <parameter name="variable" required="true">
++ <para>
++ The variable name to be manipulated, without the braces.
++ </para>
++ </parameter>
++ </syntax>
++ <description>
++ <para>Decrements the value of a variable, while returning the updated value to the dialplan</para>
++ <para>Example: DEC(MyVAR) - Increments MyVar</para>
++ <para>Note: DEC(${MyVAR}) - Is wrong, as INC expects the variable name, not its value</para>
++ </description>
++ </function>
+ ***/
+
+ enum TypeOfFunctions {
+@@ -333,19 +369,107 @@
+ return 0;
+ }
+
++static int crement_function_read(struct ast_channel *chan, const char *cmd,
++ char *data, char *buf, size_t len)
++{
++ int ret = -1;
++ int int_value = 0;
++ int modify_orig = 0;
++ const char *var;
++ char endchar = 0, returnvar[12]; /* If you need a variable longer than 11 digits - something is way wrong */
++
++ if (ast_strlen_zero(data)) {
++ ast_log(LOG_WARNING, "Syntax: %s(<data>) - missing argument!\n", cmd);
++ return -1;
++ }
++
++ ast_channel_lock(chan);
++
++ if (!(var = pbx_builtin_getvar_helper(chan, data))) {
++ ast_log(LOG_NOTICE, "Failed to obtain variable %s, bailing out\n", data);
++ ast_channel_unlock(chan);
++ return -1;
++ }
++
++ if (ast_strlen_zero(var)) {
++ ast_log(LOG_NOTICE, "Variable %s doesn't exist - are you sure you wrote it corrrectly?\n", data);
++ ast_channel_unlock(chan);
++ return -1;
++ }
++
++ if (sscanf(var, "%d%c", &int_value, &endchar) == 0 || endchar != 0) {
++ ast_log(LOG_NOTICE, "The content of ${%s} is not a numeric value - bailing out!\n", data);
++ ast_channel_unlock(chan);
++ return -1;
++ }
++
++ /* now we'll actually do something useful */
++ if (!strcasecmp(cmd, "INC")) { /* Increment variable */
++ int_value++;
++ modify_orig = 1;
++ } else if (!strcasecmp(cmd, "DEC")) { /* Decrement variable */
++ int_value--;
++ modify_orig = 1;
++ }
++
++ ast_log(LOG_NOTICE, "The value is now: %d\n", int_value);
++
++ if (snprintf(returnvar, sizeof(returnvar), "%d", int_value) > 0) {
++ pbx_builtin_setvar_helper(chan, data, returnvar);
++ if (modify_orig) {
++ ast_copy_string(buf, returnvar, len);
++ }
++ ret = 0;
++ } else {
++ pbx_builtin_setvar_helper(chan, data, "0");
++ if (modify_orig) {
++ ast_copy_string(buf, "0", len);
++ }
++ ast_log(LOG_NOTICE, "Variable %s refused to be %sREMENTED, setting value to 0", data, cmd);
++ ret = 0;
++ }
++
++ ast_channel_unlock(chan);
++
++ return ret;
++}
++
++
+ static struct ast_custom_function math_function = {
+ .name = "MATH",
+ .read = math
+ };
+
++static struct ast_custom_function increment_function = {
++ .name = "INC",
++ .read = crement_function_read,
++};
++
++static struct ast_custom_function decrement_function = {
++ .name = "DEC",
++ .read = crement_function_read,
++};
++
+ static int unload_module(void)
+ {
+- return ast_custom_function_unregister(&math_function);
++ int res = 0;
++
++ res |= ast_custom_function_unregister(&math_function);
++ res |= ast_custom_function_unregister(&increment_function);
++ res |= ast_custom_function_unregister(&decrement_function);
++
++ return res;
+ }
+
+ static int load_module(void)
+ {
+- return ast_custom_function_register(&math_function);
++ int res = 0;
++
++ res |= ast_custom_function_register(&math_function);
++ res |= ast_custom_function_register(&increment_function);
++ res |= ast_custom_function_register(&decrement_function);
++
++ return res;
+ }
+
+ AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Mathematical dialplan function");
+Index: funcs/func_cut.c
+===================================================================
+--- a/funcs/func_cut.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/funcs/func_cut.c (.../trunk) (revision 202568)
+@@ -77,9 +77,6 @@
+ </function>
+ ***/
+
+-/* Maximum length of any variable */
+-#define MAXRESULT 1024
+-
+ struct sortable_keys {
+ char *key;
+ float value;
+@@ -151,99 +148,86 @@
+ return 0;
+ }
+
+-static int cut_internal(struct ast_channel *chan, char *data, char *buffer, size_t buflen)
++static int cut_internal(struct ast_channel *chan, char *data, struct ast_str **buf, ssize_t buflen)
+ {
+- char *parse;
++ char *parse, ds[2], *var_expr;
+ size_t delim_consumed;
++ struct ast_str *var_value;
+ AST_DECLARE_APP_ARGS(args,
+ AST_APP_ARG(varname);
+ AST_APP_ARG(delimiter);
+ AST_APP_ARG(field);
+ );
+
+- *buffer = '\0';
+-
+ parse = ast_strdupa(data);
+
+ AST_STANDARD_APP_ARGS(args, parse);
+
+- /* Check and parse arguments */
++ /* Check arguments */
+ if (args.argc < 3) {
+ return ERROR_NOARG;
+- } else {
+- char d, ds[2] = "";
+- char *tmp = alloca(strlen(args.varname) + 4);
+- char varvalue[MAXRESULT], *tmp2=varvalue;
++ } else if (!(var_expr = alloca(strlen(args.varname) + 4))) {
++ return ERROR_NOMEM;
++ }
+
+- if (tmp) {
+- snprintf(tmp, strlen(args.varname) + 4, "${%s}", args.varname);
+- } else {
+- return ERROR_NOMEM;
+- }
++ /* Get the value of the variable named in the 1st argument */
++ snprintf(var_expr, strlen(args.varname) + 4, "${%s}", args.varname);
++ var_value = ast_str_create(16);
++ ast_str_substitute_variables(&var_value, 0, chan, var_expr);
+
+- if (ast_get_encoded_char(args.delimiter, ds, &delim_consumed))
+- ast_copy_string(ds, "-", sizeof(ds));
++ /* Copy delimiter from 2nd argument to ds[] possibly decoding backslash escapes */
++ if (ast_get_encoded_char(args.delimiter, ds, &delim_consumed)) {
++ ast_copy_string(ds, "-", sizeof(ds));
++ }
++ ds[1] = '\0';
+
+- /* String form of the delimiter, for use with strsep(3) */
+- d = *ds;
++ if (ast_str_strlen(var_value)) {
++ int curfieldnum = 1;
++ char *curfieldptr = ast_str_buffer(var_value);
++ int out_field_count = 0;
+
+- pbx_substitute_variables_helper(chan, tmp, tmp2, MAXRESULT - 1);
++ while (curfieldptr != NULL && args.field != NULL) {
++ char *next_range = strsep(&(args.field), "&");
++ int start_field, stop_field;
++ char trashchar;
+
+- if (tmp2) {
+- int curfieldnum = 1, firstfield = 1;
+- while (tmp2 != NULL && args.field != NULL) {
+- char *nextgroup = strsep(&(args.field), "&");
+- int num1 = 0, num2 = MAXRESULT;
+- char trashchar;
++ if (sscanf(next_range, "%d-%d", &start_field, &stop_field) == 2) {
++ /* range with both start and end */
++ } else if (sscanf(next_range, "-%d", &stop_field) == 1) {
++ /* range with end only */
++ start_field = 1;
++ } else if ((sscanf(next_range, "%d%c", &start_field, &trashchar) == 2) && (trashchar == '-')) {
++ /* range with start only */
++ stop_field = INT_MAX;
++ } else if (sscanf(next_range, "%d", &start_field) == 1) {
++ /* single number */
++ stop_field = start_field;
++ } else {
++ /* invalid field spec */
++ ast_free(var_value);
++ return ERROR_USAGE;
++ }
+
+- if (sscanf(nextgroup, "%d-%d", &num1, &num2) == 2) {
+- /* range with both start and end */
+- } else if (sscanf(nextgroup, "-%d", &num2) == 1) {
+- /* range with end */
+- num1 = 0;
+- } else if ((sscanf(nextgroup, "%d%c", &num1, &trashchar) == 2) && (trashchar == '-')) {
+- /* range with start */
+- num2 = MAXRESULT;
+- } else if (sscanf(nextgroup, "%d", &num1) == 1) {
+- /* single number */
+- num2 = num1;
+- } else {
+- return ERROR_USAGE;
+- }
++ /* Get to start, if not there already */
++ while (curfieldptr != NULL && curfieldnum < start_field) {
++ strsep(&curfieldptr, ds);
++ curfieldnum++;
++ }
+
+- /* Get to start, if any */
+- if (num1 > 0) {
+- while (tmp2 != (char *)NULL + 1 && curfieldnum < num1) {
+- tmp2 = strchr(tmp2, d) + 1;
+- curfieldnum++;
+- }
+- }
++ /* Most frequent problem is the expectation of reordering fields */
++ if (curfieldnum > start_field) {
++ ast_log(LOG_WARNING, "We're already past the field you wanted?\n");
++ }
+
+- /* Most frequent problem is the expectation of reordering fields */
+- if ((num1 > 0) && (curfieldnum > num1))
+- ast_log(LOG_WARNING, "We're already past the field you wanted?\n");
+-
+- /* Re-null tmp2 if we added 1 to NULL */
+- if (tmp2 == (char *)NULL + 1)
+- tmp2 = NULL;
+-
+- /* Output fields until we either run out of fields or num2 is reached */
+- while (tmp2 != NULL && curfieldnum <= num2) {
+- char *tmp3 = strsep(&tmp2, ds);
+- int curlen = strlen(buffer);
+-
+- if (firstfield) {
+- snprintf(buffer, buflen, "%s", tmp3);
+- firstfield = 0;
+- } else {
+- snprintf(buffer + curlen, buflen - curlen, "%c%s", d, tmp3);
+- }
+-
+- curfieldnum++;
+- }
++ /* Output fields until we either run out of fields or stop_field is reached */
++ while (curfieldptr != NULL && curfieldnum <= stop_field) {
++ char *field_value = strsep(&curfieldptr, ds);
++ ast_str_append(buf, buflen, "%s%s", out_field_count++ ? ds : "", field_value);
++ curfieldnum++;
+ }
+ }
+ }
++ ast_free(var_value);
+ return 0;
+ }
+
+@@ -271,7 +255,33 @@
+ static int acf_cut_exec(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
+ {
+ int ret = -1;
++ struct ast_str *str = ast_str_create(16);
+
++ switch (cut_internal(chan, data, &str, len)) {
++ case ERROR_NOARG:
++ ast_log(LOG_ERROR, "Syntax: CUT(<varname>,<char-delim>,<range-spec>) - missing argument!\n");
++ break;
++ case ERROR_NOMEM:
++ ast_log(LOG_ERROR, "Out of memory\n");
++ break;
++ case ERROR_USAGE:
++ ast_log(LOG_ERROR, "Usage: CUT(<varname>,<char-delim>,<range-spec>)\n");
++ break;
++ case 0:
++ ret = 0;
++ ast_copy_string(buf, ast_str_buffer(str), len);
++ break;
++ default:
++ ast_log(LOG_ERROR, "Unknown internal error\n");
++ }
++ ast_free(str);
++ return ret;
++}
++
++static int acf_cut_exec2(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t len)
++{
++ int ret = -1;
++
+ switch (cut_internal(chan, data, buf, len)) {
+ case ERROR_NOARG:
+ ast_log(LOG_ERROR, "Syntax: CUT(<varname>,<char-delim>,<range-spec>) - missing argument!\n");
+@@ -292,14 +302,15 @@
+ return ret;
+ }
+
+-struct ast_custom_function acf_sort = {
++static struct ast_custom_function acf_sort = {
+ .name = "SORT",
+ .read = acf_sort_exec,
+ };
+
+-struct ast_custom_function acf_cut = {
++static struct ast_custom_function acf_cut = {
+ .name = "CUT",
+ .read = acf_cut_exec,
++ .read2 = acf_cut_exec2,
+ };
+
+ static int unload_module(void)
+Index: funcs/func_redirecting.c
+===================================================================
+--- a/funcs/func_redirecting.c (.../tags/1.6.2.0-beta3) (revision 0)
++++ b/funcs/func_redirecting.c (.../trunk) (revision 202568)
+@@ -0,0 +1,482 @@
++/*
++ * 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"
++
++/*
++ * Do not document the REDIRECTING(pres) datatype.
++ * It has turned out that the from-pres and to-pres values must be kept
++ * separate. They represent two different parties and there is a case when
++ * they are active at the same time. The plain pres option will simply
++ * live on as a historical relic.
++ */
++/*** 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 = "from-pres" />
++ <enum name = "to-all" />
++ <enum name = "to-num" />
++ <enum name = "to-name" />
++ <enum name = "to-ton" />
++ <enum name = "to-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_global.c
+===================================================================
+--- a/funcs/func_global.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/funcs/func_global.c (.../trunk) (revision 202568)
+@@ -134,6 +134,7 @@
+ AST_APP_ARG(var);
+ AST_APP_ARG(chan);
+ );
++ struct ast_channel *c_ref = NULL;
+
+ if (ast_strlen_zero(data)) {
+ ast_log(LOG_WARNING, "SHARED() requires an argument: SHARED(<var>[,<chan>])\n");
+@@ -145,15 +146,20 @@
+ if (!ast_strlen_zero(args.chan)) {
+ char *prefix = alloca(strlen(args.chan) + 2);
+ sprintf(prefix, "%s-", args.chan);
+- if (!(chan = ast_get_channel_by_name_locked(args.chan)) && !(chan = ast_get_channel_by_name_prefix_locked(prefix, strlen(prefix)))) {
++ if (!(c_ref = ast_channel_get_by_name(args.chan)) && !(c_ref = ast_channel_get_by_name_prefix(prefix, strlen(prefix)))) {
+ ast_log(LOG_ERROR, "Channel '%s' not found! Variable '%s' will be blank.\n", args.chan, args.var);
+ return -1;
+ }
+- } else
+- ast_channel_lock(chan);
++ chan = c_ref;
++ }
+
++ ast_channel_lock(chan);
++
+ if (!(varstore = ast_channel_datastore_find(chan, &shared_variable_info, NULL))) {
+ ast_channel_unlock(chan);
++ if (c_ref) {
++ c_ref = ast_channel_unref(c_ref);
++ }
+ return -1;
+ }
+
+@@ -170,6 +176,10 @@
+
+ ast_channel_unlock(chan);
+
++ if (c_ref) {
++ c_ref = ast_channel_unref(c_ref);
++ }
++
+ return 0;
+ }
+
+@@ -182,6 +192,7 @@
+ AST_APP_ARG(var);
+ AST_APP_ARG(chan);
+ );
++ struct ast_channel *c_ref = NULL;
+
+ if (ast_strlen_zero(data)) {
+ ast_log(LOG_WARNING, "SHARED() requires an argument: SHARED(<var>[,<chan>])\n");
+@@ -193,17 +204,22 @@
+ if (!ast_strlen_zero(args.chan)) {
+ char *prefix = alloca(strlen(args.chan) + 2);
+ sprintf(prefix, "%s-", args.chan);
+- if (!(chan = ast_get_channel_by_name_locked(args.chan)) && !(chan = ast_get_channel_by_name_prefix_locked(prefix, strlen(prefix)))) {
++ if (!(c_ref = ast_channel_get_by_name(args.chan)) && !(c_ref = ast_channel_get_by_name_prefix(prefix, strlen(prefix)))) {
+ ast_log(LOG_ERROR, "Channel '%s' not found! Variable '%s' not set to '%s'.\n", args.chan, args.var, value);
+ return -1;
+ }
+- } else
+- ast_channel_lock(chan);
++ chan = c_ref;
++ }
+
++ ast_channel_lock(chan);
++
+ if (!(varstore = ast_channel_datastore_find(chan, &shared_variable_info, NULL))) {
+ if (!(varstore = ast_datastore_alloc(&shared_variable_info, NULL))) {
+ ast_log(LOG_ERROR, "Unable to allocate new datastore. Shared variable not set.\n");
+ ast_channel_unlock(chan);
++ if (c_ref) {
++ c_ref = ast_channel_unref(c_ref);
++ }
+ return -1;
+ }
+
+@@ -211,6 +227,9 @@
+ ast_log(LOG_ERROR, "Unable to allocate variable structure. Shared variable not set.\n");
+ ast_datastore_free(varstore);
+ ast_channel_unlock(chan);
++ if (c_ref) {
++ c_ref = ast_channel_unref(c_ref);
++ }
+ return -1;
+ }
+
+@@ -241,6 +260,10 @@
+
+ ast_channel_unlock(chan);
+
++ if (c_ref) {
++ c_ref = ast_channel_unref(c_ref);
++ }
++
+ return 0;
+ }
+
+Index: funcs/func_extstate.c
+===================================================================
+--- a/funcs/func_extstate.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/funcs/func_extstate.c (.../trunk) (revision 202568)
+@@ -122,6 +122,7 @@
+ static struct ast_custom_function extstate_function = {
+ .name = "EXTENSION_STATE",
+ .read = extstate_read,
++ .read_max = 12,
+ };
+
+ static int unload_module(void)
+Index: funcs/func_realtime.c
+===================================================================
+--- a/funcs/func_realtime.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/funcs/func_realtime.c (.../trunk) (revision 202568)
+@@ -410,29 +410,29 @@
+ return 0;
+ }
+
+-struct ast_custom_function realtime_function = {
++static struct ast_custom_function realtime_function = {
+ .name = "REALTIME",
+ .read = function_realtime_read,
+ .write = function_realtime_write,
+ };
+
+-struct ast_custom_function realtimefield_function = {
++static struct ast_custom_function realtimefield_function = {
+ .name = "REALTIME_FIELD",
+ .read = realtimefield_read,
+ .write = function_realtime_write,
+ };
+
+-struct ast_custom_function realtimehash_function = {
++static struct ast_custom_function realtimehash_function = {
+ .name = "REALTIME_HASH",
+ .read = realtimefield_read,
+ };
+
+-struct ast_custom_function realtime_store_function = {
++static struct ast_custom_function realtime_store_function = {
+ .name = "REALTIME_STORE",
+ .write = function_realtime_store,
+ };
+
+-struct ast_custom_function realtime_destroy_function = {
++static struct ast_custom_function realtime_destroy_function = {
+ .name = "REALTIME_DESTROY",
+ .read = function_realtime_readdestroy,
+ };
+Index: funcs/func_curl.c
+===================================================================
+--- a/funcs/func_curl.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/funcs/func_curl.c (.../trunk) (revision 202568)
+@@ -276,7 +276,7 @@
+ return 0;
+ }
+
+-static int acf_curlopt_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
++static int acf_curlopt_helper(struct ast_channel *chan, const char *cmd, char *data, char *buf, struct ast_str **bufstr, ssize_t len)
+ {
+ struct ast_datastore *store;
+ struct global_curl_info *list[2] = { &global_curl_info, NULL };
+@@ -303,38 +303,78 @@
+ 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);
++ if (buf) {
++ snprintf(buf, len, "%ld", (long) cur->value);
++ } else {
++ ast_str_set(bufstr, 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);
++ if ((long) cur->value % 1000 == 0) {
++ if (buf) {
++ snprintf(buf, len, "%ld", (long)cur->value / 1000);
++ } else {
++ ast_str_set(bufstr, len, "%ld", (long) cur->value / 1000);
++ }
+ } else {
+- snprintf(buf, len, "%.3f", (double)((long)cur->value) / 1000.0);
++ if (buf) {
++ snprintf(buf, len, "%.3f", (double) ((long) cur->value) / 1000.0);
++ } else {
++ ast_str_set(bufstr, 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);
++ if (buf) {
++ ast_copy_string(buf, cur->value, len);
++ } else {
++ ast_str_set(bufstr, 0, "%s", (char *) cur->value);
++ }
+ } 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);
++ if (buf) {
++ ast_copy_string(buf, "socks4", len);
++ } else {
++ ast_str_set(bufstr, 0, "socks4");
++ }
+ #endif
+ #if CURLVERSION_ATLEAST(7,18,0)
+ } else if ((long)cur->value == CURLPROXY_SOCKS4A) {
+- ast_copy_string(buf, "socks4a", len);
++ if (buf) {
++ ast_copy_string(buf, "socks4a", len);
++ } else {
++ ast_str_set(bufstr, 0, "socks4a");
++ }
+ #endif
+ } else if ((long)cur->value == CURLPROXY_SOCKS5) {
+- ast_copy_string(buf, "socks5", len);
++ if (buf) {
++ ast_copy_string(buf, "socks5", len);
++ } else {
++ ast_str_set(bufstr, 0, "socks5");
++ }
+ #if CURLVERSION_ATLEAST(7,18,0)
+ } else if ((long)cur->value == CURLPROXY_SOCKS5_HOSTNAME) {
+- ast_copy_string(buf, "socks5hostname", len);
++ if (buf) {
++ ast_copy_string(buf, "socks5hostname", len);
++ } else {
++ ast_str_set(bufstr, 0, "socks5hostname");
++ }
+ #endif
+ #if CURLVERSION_ATLEAST(7,10,0)
+ } else if ((long)cur->value == CURLPROXY_HTTP) {
+- ast_copy_string(buf, "http", len);
++ if (buf) {
++ ast_copy_string(buf, "http", len);
++ } else {
++ ast_str_set(bufstr, 0, "http");
++ }
+ #endif
+ } else {
+- ast_copy_string(buf, "unknown", len);
++ if (buf) {
++ ast_copy_string(buf, "unknown", len);
++ } else {
++ ast_str_set(bufstr, 0, "unknown");
++ }
+ }
+ }
+ break;
+@@ -349,6 +389,16 @@
+ return cur ? 0 : -1;
+ }
+
++static int acf_curlopt_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
++{
++ return acf_curlopt_helper(chan, cmd, data, buf, NULL, len);
++}
++
++static int acf_curlopt_read2(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t len)
++{
++ return acf_curlopt_helper(chan, cmd, data, NULL, buf, len);
++}
++
+ static size_t WriteMemoryCallback(void *ptr, size_t size, size_t nmemb, void *data)
+ {
+ register int realsize = size * nmemb;
+@@ -363,7 +413,7 @@
+ return realsize;
+ }
+
+-static const char *global_useragent = "asterisk-libcurl-agent/1.0";
++static const char * const global_useragent = "asterisk-libcurl-agent/1.0";
+
+ static int curl_instance_init(void *data)
+ {
+@@ -391,7 +441,7 @@
+
+ AST_THREADSTORAGE_CUSTOM(curl_instance, curl_instance_init, curl_instance_cleanup);
+
+-static int acf_curl_exec(struct ast_channel *chan, const char *cmd, char *info, char *buf, size_t len)
++static int acf_curl_helper(struct ast_channel *chan, const char *cmd, char *info, char *buf, struct ast_str **input_str, ssize_t len)
+ {
+ struct ast_str *str = ast_str_create(16);
+ int ret = -1;
+@@ -405,15 +455,17 @@
+ int hashcompat = 0;
+ AST_LIST_HEAD(global_curl_info, curl_settings) *list = NULL;
+
+- *buf = '\0';
+-
++ if (buf) {
++ *buf = '\0';
++ }
++
+ if (ast_strlen_zero(info)) {
+ ast_log(LOG_WARNING, "CURL requires an argument (URL)\n");
+ ast_free(str);
+ return -1;
+ }
+
+- AST_STANDARD_APP_ARGS(args, info);
++ AST_STANDARD_APP_ARGS(args, info);
+
+ if (chan) {
+ ast_autoservice_start(chan);
+@@ -483,11 +535,19 @@
+ rowcount++;
+ }
+ pbx_builtin_setvar_helper(chan, "~ODBCFIELDS~", ast_str_buffer(fields));
+- ast_copy_string(buf, ast_str_buffer(values), len);
++ if (buf) {
++ ast_copy_string(buf, ast_str_buffer(values), len);
++ } else {
++ ast_str_set(input_str, len, "%s", ast_str_buffer(values));
++ }
+ ast_free(fields);
+ ast_free(values);
+ } else {
+- ast_copy_string(buf, ast_str_buffer(str), len);
++ if (buf) {
++ ast_copy_string(buf, ast_str_buffer(str), len);
++ } else {
++ ast_str_set(input_str, len, "%s", ast_str_buffer(str));
++ }
+ }
+ ret = 0;
+ }
+@@ -495,11 +555,21 @@
+
+ if (chan)
+ ast_autoservice_stop(chan);
+-
++
+ return ret;
+ }
+
+-struct ast_custom_function acf_curl = {
++static int acf_curl_exec(struct ast_channel *chan, const char *cmd, char *info, char *buf, size_t len)
++{
++ return acf_curl_helper(chan, cmd, info, buf, NULL, len);
++}
++
++static int acf_curl2_exec(struct ast_channel *chan, const char *cmd, char *info, struct ast_str **buf, ssize_t len)
++{
++ return acf_curl_helper(chan, cmd, info, NULL, buf, len);
++}
++
++static struct ast_custom_function acf_curl = {
+ .name = "CURL",
+ .synopsis = "Retrieves the contents of a URL",
+ .syntax = "CURL(url[,post-data])",
+@@ -507,9 +577,10 @@
+ " url - URL to retrieve\n"
+ " post-data - Optional data to send as a POST (GET is default action)\n",
+ .read = acf_curl_exec,
++ .read2 = acf_curl2_exec,
+ };
+
+-struct ast_custom_function acf_curlopt = {
++static struct ast_custom_function acf_curlopt = {
+ .name = "CURLOPT",
+ .synopsis = "Set options for use with the CURL() function",
+ .syntax = "CURLOPT(<option>)",
+@@ -532,6 +603,7 @@
+ " hashcompat - Result data will be compatible for use with HASH()\n"
+ "",
+ .read = acf_curlopt_read,
++ .read2 = acf_curlopt_read2,
+ .write = acf_curlopt_write,
+ };
+
+Index: funcs/func_blacklist.c
+===================================================================
+--- a/funcs/func_blacklist.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/funcs/func_blacklist.c (.../trunk) (revision 202568)
+@@ -70,9 +70,26 @@
+ return 0;
+ }
+
++static int blacklist_read2(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **str, ssize_t len)
++{
++ /* 2 bytes is a single integer, plus terminating null */
++ if (ast_str_size(*str) - ast_str_strlen(*str) < 2) {
++ if (len > ast_str_size(*str) || len == 0) {
++ ast_str_make_space(str, len ? len : ast_str_strlen(*str) + 2);
++ }
++ }
++ if (ast_str_size(*str) - ast_str_strlen(*str) >= 2) {
++ int res = blacklist_read(chan, cmd, data, ast_str_buffer(*str) + ast_str_strlen(*str), 2);
++ ast_str_update(*str);
++ return res;
++ }
++ return -1;
++}
++
+ static struct ast_custom_function blacklist_function = {
+ .name = "BLACKLIST",
+ .read = blacklist_read,
++ .read2 = blacklist_read2,
+ };
+
+ static int unload_module(void)
+Index: funcs/func_cdr.c
+===================================================================
+--- a/funcs/func_cdr.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/funcs/func_cdr.c (.../trunk) (revision 202568)
+@@ -163,12 +163,12 @@
+ </function>
+ ***/
+
+-enum {
++enum cdr_option_flags {
+ OPT_RECURSIVE = (1 << 0),
+ OPT_UNPARSED = (1 << 1),
+ OPT_LAST = (1 << 2),
+ OPT_SKIPLOCKED = (1 << 3),
+-} cdr_option_flags;
++};
+
+ AST_APP_OPTIONS(cdr_func_options, {
+ AST_APP_OPTION('l', OPT_LAST),
+Index: funcs/func_channel.c
+===================================================================
+--- a/funcs/func_channel.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/funcs/func_channel.c (.../trunk) (revision 202568)
+@@ -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>
+@@ -224,7 +227,7 @@
+ ast_channel_unlock(chan); \
+ } while (0)
+
+-char *transfercapability_table[0x20] = {
++static const char * const transfercapability_table[0x20] = {
+ "SPEECH", "UNK", "UNK", "UNK", "UNK", "UNK", "UNK", "UNK",
+ "DIGITAL", "RESTRICTED_DIGITAL", "UNK", "UNK", "UNK", "UNK", "UNK", "UNK",
+ "3K1AUDIO", "DIGITAL_W_TONES", "UNK", "UNK", "UNK", "UNK", "UNK", "UNK",
+@@ -260,7 +263,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);
+@@ -358,7 +363,8 @@
+ regex_t re;
+ int res;
+ size_t buflen = 0;
+-
++ struct ast_channel_iterator *iter;
++
+ buf[0] = '\0';
+
+ if (!ast_strlen_zero(data)) {
+@@ -369,7 +375,15 @@
+ }
+ }
+
+- for (c = ast_channel_walk_locked(NULL); c; ast_channel_unlock(c), c = ast_channel_walk_locked(c)) {
++ if (!(iter = ast_channel_iterator_all_new(0))) {
++ if (!ast_strlen_zero(data)) {
++ regfree(&re);
++ }
++ return -1;
++ }
++
++ while ((c = ast_channel_iterator_next(iter))) {
++ ast_channel_lock(c);
+ if (ast_strlen_zero(data) || regexec(&re, c->name, 0, NULL, 0) == 0) {
+ size_t namelen = strlen(c->name);
+ if (buflen + namelen + (ast_strlen_zero(buf) ? 0 : 1) + 1 < maxlen) {
+@@ -383,8 +397,12 @@
+ ast_log(LOG_WARNING, "Number of channels exceeds the available buffer space. Output will be truncated!\n");
+ }
+ }
++ ast_channel_unlock(c);
++ c = ast_channel_unref(c);
+ }
+
++ ast_channel_iterator_destroy(iter);
++
+ if (!ast_strlen_zero(data)) {
+ regfree(&re);
+ }
+Index: funcs/func_connectedline.c
+===================================================================
+--- a/funcs/func_connectedline.c (.../tags/1.6.2.0-beta3) (revision 0)
++++ b/funcs/func_connectedline.c (.../trunk) (revision 202568)
+@@ -0,0 +1,237 @@
++/*
++ * 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"
++
++/*
++ * Do not document the CONNECTEDLINE(source) datatype.
++ * It has turned out to not be needed. The source value is really .
++ * only useful as a possible tracing aid.
++ */
++/*** 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" />
++ </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.</para>
++ </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
+
+Index: funcs/func_callerid.c
+===================================================================
+--- a/funcs/func_callerid.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/funcs/func_callerid.c (.../trunk) (revision 202568)
+@@ -274,12 +274,14 @@
+ static struct ast_custom_function callerid_function = {
+ .name = "CALLERID",
+ .read = callerid_read,
++ .read_max = 256,
+ .write = callerid_write,
+ };
+
+ static struct ast_custom_function callerpres_function = {
+ .name = "CALLERPRES",
+ .read = callerpres_read,
++ .read_max = 50,
+ .write = callerpres_write,
+ };
+
+Index: funcs/func_devstate.c
+===================================================================
+--- a/funcs/func_devstate.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/funcs/func_devstate.c (.../trunk) (revision 202568)
+@@ -255,8 +255,8 @@
+ return NULL;
+ case CLI_GENERATE:
+ {
+- static char * const cmds[] = { "UNKNOWN", "NOT_INUSE", "INUSE", "BUSY",
+- "UNAVAILABLE", "RINGING", "RINGINUSE", "ONHOLD", NULL };
++ static const char * const cmds[] = { "UNKNOWN", "NOT_INUSE", "INUSE", "BUSY",
++ "UNAVAILABLE", "RINGING", "RINGINUSE", "ONHOLD", NULL };
+
+ if (a->pos == e->args + 1)
+ return ast_cli_complete(a->word, cmds, a->n);
+Index: include/asterisk/rtp.h
+===================================================================
+--- a/include/asterisk/rtp.h (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/include/asterisk/rtp.h (.../trunk) (revision 202568)
+@@ -1,433 +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);
+-
+-/*!
+- * \since 1.4.26
+- * \brief set potential alternate source for RTP media
+- *
+- * This function may be used to give the RTP stack a hint that there is a potential
+- * second source of media. One case where this is used is when the SIP stack receives
+- * a REINVITE to which it will be replying with a 491. In such a scenario, the IP and
+- * port information in the SDP of that REINVITE lets us know that we may receive media
+- * from that source/those sources even though the SIP transaction was unable to be completed
+- * successfully
+- *
+- * \param rtp The RTP structure we wish to set up an alternate host/port on
+- * \param alt The address information for the alternate media source
+- * \retval void
+- */
+-void ast_rtp_set_alt_peer(struct ast_rtp *rtp, struct sockaddr_in *alt);
+-
+-/* 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-beta3) (revision 0)
++++ b/include/asterisk/rtp_engine.h (.../trunk) (revision 202568)
+@@ -0,0 +1,1640 @@
++/*
++ * 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 setting an alternate remote address */
++ void (*alt_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);
++ /*! Callback to get the transcodeable formats supported */
++ int (*available_formats)(struct ast_rtp_instance *instance, int to_endpoint, int to_asterisk);
++ /*! 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 of an an alternate RTP address to receive from
++ *
++ * \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_alt_remote_address(instance, &sin);
++ * \endcode
++ *
++ * This changes the alternate 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_alt_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 Request the formats that can be transcoded
++ *
++ * \param instance The RTP instance
++ * \param to_endpoint Formats being sent/received towards the endpoint
++ * \param to_asterisk Formats being sent/received towards Asterisk
++ *
++ * \retval supported formats
++ *
++ * Example usage:
++ *
++ * \code
++ * ast_rtp_instance_available_formats(instance, AST_FORMAT_ULAW, AST_FORMAT_SLINEAR);
++ * \endcode
++ *
++ * This sees if it is possible to have ulaw communicated to the endpoint but signed linear received into Asterisk.
++ *
++ * \since 1.6.3
++ */
++int ast_rtp_instance_available_formats(struct ast_rtp_instance *instance, int to_endpoint, int to_asterisk);
++
++/*!
++ * \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-beta3) (revision 202568)
++++ b/include/asterisk/utils.h (.../trunk) (revision 202568)
+@@ -32,8 +32,9 @@
+ #include "asterisk/time.h"
+ #include "asterisk/logger.h"
+ #include "asterisk/localtime.h"
++#include "asterisk/stringfields.h"
+
+-/*!
++/*!
+ \note \verbatim
+ Note:
+ It is very important to use only unsigned variables to hold
+@@ -214,9 +215,9 @@
+ struct hostent *ast_gethostbyname(const char *host, struct ast_hostent *hp);
+
+ /*! \brief Produces MD5 hash based on input string */
+-void ast_md5_hash(char *output, char *input);
++void ast_md5_hash(char *output, const char *input);
+ /*! \brief Produces SHA1 hash based on input string */
+-void ast_sha1_hash(char *output, char *input);
++void ast_sha1_hash(char *output, const char *input);
+
+ int ast_base64encode_full(char *dst, const unsigned char *src, int srclen, int max, int linebreaks);
+
+@@ -646,6 +647,33 @@
+
+ #define ARRAY_LEN(a) (sizeof(a) / sizeof(0[a]))
+
++
++/* Definition for Digest authorization */
++struct ast_http_digest {
++ AST_DECLARE_STRING_FIELDS(
++ AST_STRING_FIELD(username);
++ AST_STRING_FIELD(nonce);
++ AST_STRING_FIELD(uri);
++ AST_STRING_FIELD(realm);
++ AST_STRING_FIELD(domain);
++ AST_STRING_FIELD(response);
++ AST_STRING_FIELD(cnonce);
++ AST_STRING_FIELD(opaque);
++ AST_STRING_FIELD(nc);
++ );
++ int qop; /* Flag set to 1, if we send/recv qop="quth" */
++};
++
++/*!
++ *\brief Parse digest authorization header.
++ *\return Returns -1 if we have no auth or something wrong with digest.
++ *\note This function may be used for Digest request and responce header.
++ * request arg is set to nonzero, if we parse Digest Request.
++ * pedantic arg can be set to nonzero if we need to do addition Digest check.
++ */
++int ast_parse_digest(const char *digest, struct ast_http_digest *d, int request, int pedantic);
++
++
+ #ifdef AST_DEVMODE
+ #define ast_assert(a) _ast_assert(a, # a, __FILE__, __LINE__, __PRETTY_FUNCTION__)
+ static void force_inline _ast_assert(int condition, const char *condition_str,
+Index: include/asterisk/channel.h
+===================================================================
+--- a/include/asterisk/channel.h (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/include/asterisk/channel.h (.../trunk) (revision 202568)
+@@ -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.
+
+@@ -124,6 +124,7 @@
+ #define _ASTERISK_CHANNEL_H
+
+ #include "asterisk/abstract_jb.h"
++#include "asterisk/astobj2.h"
+
+ #include "asterisk/poll-compat.h"
+
+@@ -183,45 +184,174 @@
+ 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.
++ * \note enum AST_CONNECTED_LINE_UPDATE_SOURCE values
++ * for Normal-Answer and Call-transfer.
++ */
++ 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 +380,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,9 +511,60 @@
+ T38_STATE_NEGOTIATED, /*!< T38 established */
+ };
+
+-/*! \brief Main Channel structure associated with a channel.
+- * This is the side of it mostly used by the pbx and call management.
++/*!
++ * \page AstChannel ast_channel locking and reference tracking
+ *
++ * \par Creating Channels
++ * A channel is allocated using the ast_channel_alloc() function. When created, it is
++ * automatically inserted into the main channels hash table that keeps track of all
++ * active channels in the system. The hash key is based on the channel name. Because
++ * of this, if you want to change the name, you _must_ use ast_change_name(), not change
++ * the name field directly. When ast_channel_alloc() returns a channel pointer, you now
++ * hold a reference to that channel. In most cases this reference is given to ast_pbx_run().
++ *
++ * \par Channel Locking
++ * There is a lock associated with every ast_channel. It is allocated internally via astobj2.
++ * To lock or unlock a channel, you must use the ast_channel_lock() wrappers.
++ *
++ * Previously, before ast_channel was converted to astobj2, the channel lock was used in some
++ * additional ways that are no longer necessary. Before, the only way to ensure that a channel
++ * did not disappear out from under you if you were working with a channel outside of the channel
++ * thread that owns it, was to hold the channel lock. Now, that is no longer necessary.
++ * You simply must hold a reference to the channel to ensure it does not go away.
++ *
++ * The channel must be locked if you need to ensure that data that you reading from the channel
++ * does not change while you access it. Further, you must hold the channel lock if you are
++ * making a non-atomic change to channel data.
++ *
++ * \par Channel References
++ * There are multiple ways to get a reference to a channel. The first is that you hold a reference
++ * to a channel after creating it. The other ways involve using the channel search or the channel
++ * traversal APIs. These functions are the ast_channel_get_*() functions or ast_channel_iterator_*()
++ * functions. Once a reference is retrieved by one of these methods, you know that the channel will
++ * not go away. So, the channel should only get locked as needed for data access or modification.
++ * But, make sure that the reference gets released when you are done with it!
++ *
++ * There are different things you can do when you are done with a reference to a channel. The first
++ * is to simply release the reference using ast_channel_unref(). The other option is to call
++ * ast_channel_release(). This function is generally used where ast_channel_free() was used in
++ * the past. The release function releases a reference as well as ensures that the channel is no
++ * longer in the global channels container. That way, the channel will get destroyed as soon as any
++ * other pending references get released.
++ *
++ * \par Exceptions to the rules
++ * Even though ast_channel is reference counted, there are some places where pointers to an ast_channel
++ * get stored, but the reference count does not reflect it. The reason is mostly historical.
++ * The only places where this happens should be places where because of how the code works, we
++ * _know_ that the pointer to the channel will get removed before the channel goes away. The main
++ * example of this is in channel drivers. Channel drivers generally store a pointer to their owner
++ * ast_channel in their technology specific pvt struct. In this case, the channel drivers _know_
++ * that this pointer to the channel will be removed in time, because the channel's hangup callback
++ * gets called before the channel goes away.
++ */
++
++/*!
++ * \brief Main Channel structure associated with a channel.
++ *
+ * \note XXX It is important to remember to increment .cleancount each time
+ * this structure is changed. XXX
+ *
+@@ -395,7 +576,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 +583,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 +601,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];
+@@ -440,8 +620,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 */
+@@ -451,16 +652,17 @@
+ struct ast_jb jb; /*!< The jitterbuffer state */
+ struct timeval dtmf_tv; /*!< The time that an in process digit began, or the last digit ended */
+ AST_LIST_HEAD_NOLOCK(datastores, ast_datastore) datastores; /*!< Data stores on the channel */
++ AST_LIST_HEAD_NOLOCK(autochans, ast_autochan) autochans; /*!< Autochans on the channel */
+
+ unsigned long insmpl; /*!< Track the read/written samples for monitor use */
+ 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 +675,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,15 +692,10 @@
+ #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 */
+- };
+- };
++ struct ast_bridge *bridge; /*!< Bridge this channel is participating in */
++ struct ast_timer *timer; /*!< timer object that provided timingfd */
+
+ char context[AST_MAX_CONTEXT]; /*!< Dialplan: Current extension context */
+ char exten[AST_MAX_EXTENSION]; /*!< Dialplan: Current extension number */
+@@ -509,17 +706,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),
+@@ -550,7 +751,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 */
+@@ -584,7 +785,7 @@
+ struct ast_flags features_callee;
+ struct timeval start_time;
+ struct timeval nexteventts;
+- struct timeval partialfeature_timer;
++ struct timeval feature_start_time;
+ long feature_timer;
+ long timelimit;
+ long play_warning;
+@@ -592,7 +793,6 @@
+ const char *warning_sound;
+ const char *end_sound;
+ const char *start_sound;
+- int firstpass;
+ unsigned int flags;
+ void (* end_bridge_callback)(void *); /*!< A callback that is called after a bridge attempt */
+ void *end_bridge_callback_data; /*!< Data passed to the callback */
+@@ -676,7 +876,6 @@
+ * \retval 0 success
+ * \retval non-zero failure
+ */
+-
+ int ast_channel_datastore_add(struct ast_channel *chan, struct ast_datastore *datastore);
+
+ /*!
+@@ -726,19 +925,26 @@
+ __FILE__, __LINE__, __FUNCTION__, __VA_ARGS__)
+
+ /*!
+- * \brief Queue an outgoing frame
++ * \brief Queue one or more frames to a channel's frame queue
+ *
+- * \note The channel does not need to be locked before calling this function.
++ * \param chan the channel to queue the frame(s) on
++ * \param f the frame(s) to queue. Note that the frame(s) will be duplicated
++ * by this function. It is the responsibility of the caller to handle
++ * freeing the memory associated with the frame(s) being passed if
++ * necessary.
++ *
++ * \retval 0 success
++ * \retval non-zero failure
+ */
+ int ast_queue_frame(struct ast_channel *chan, struct ast_frame *f);
+
+ /*!
+- * \brief Queue an outgoing frame to the head of the frame queue
++ * \brief Queue one or more frames to the head of a channel's frame queue
+ *
+- * \param chan the channel to queue the frame on
+- * \param f the frame to queue. Note that this frame will be duplicated by
+- * this function. It is the responsibility of the caller to handle
+- * freeing the memory associated with the frame being passed if
++ * \param chan the channel to queue the frame(s) on
++ * \param f the frame(s) to queue. Note that the frame(s) will be duplicated
++ * by this function. It is the responsibility of the caller to handle
++ * freeing the memory associated with the frame(s) being passed if
+ * necessary.
+ *
+ * \retval 0 success
+@@ -788,6 +994,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.
+@@ -807,12 +1014,26 @@
+ /*!
+ * \brief Change channel name
+ *
+- * \note The channel must be locked before calling this function.
++ * \pre The channel must be locked before calling this function.
++ *
++ * \param chan the channel to change the name of
++ * \param newname the name to change to
++ *
++ * \return nothing
+ */
+-void ast_change_name(struct ast_channel *chan, char *newname);
++void ast_change_name(struct ast_channel *chan, const char *newname);
+
+-/*! \brief Free a channel structure */
+-void ast_channel_free(struct ast_channel *);
++/*!
++ * \brief Unlink and release reference to a channel
++ *
++ * This function will unlink the channel from the global channels container
++ * if it is still there and also release the current reference to the channel.
++ *
++ * \return NULL, convenient for clearing invalid pointers
++ *
++ * \since 1.6.3
++ */
++struct ast_channel *ast_channel_release(struct ast_channel *chan);
+
+ /*!
+ * \brief Requests a channel
+@@ -822,6 +1043,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
+ *
+@@ -864,66 +1086,76 @@
+ */
+ 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 Forwards a call to a new channel specified by the original channel's call_forward str. If possible, the new forwarded channel is created and returned while the original one is terminated.
+-* \param caller in channel that requested orig
+-* \param orig channel being replaced by the call forward channel
+-* \param timeout maximum amount of time to wait for setup of new forward channel
+-* \param format requested channel format
+-* \param oh outgoing helper used with original channel
+-* \param outstate reason why unsuccessful (if uncuccessful)
+-* \return Returns the forwarded call's ast_channel on success or NULL on failure
+-*/
++ * \brief Forwards a call to a new channel specified by the original channel's call_forward str. If possible, the new forwarded channel is created and returned while the original one is terminated.
++ * \param caller in channel that requested orig
++ * \param orig channel being replaced by the call forward channel
++ * \param timeout maximum amount of time to wait for setup of new forward channel
++ * \param format requested channel format
++ * \param oh outgoing helper used with original channel
++ * \param outstate reason why unsuccessful (if uncuccessful)
++ * \return Returns the forwarded call's ast_channel on success or NULL on failure
++ */
+ struct ast_channel *ast_call_forward(struct ast_channel *caller, struct ast_channel *orig, int *timeout, int format, struct outgoing_helper *oh, int *outstate);
+
+-/*!\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.
+@@ -938,6 +1170,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.
+@@ -948,9 +1181,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
+@@ -960,11 +1195,14 @@
+ */
+ int ast_check_hangup(struct ast_channel *chan);
+
++int ast_check_hangup_locked(struct ast_channel *chan);
++
+ /*!
+ * \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 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
+@@ -987,11 +1225,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
+@@ -1003,7 +1243,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
+@@ -1023,6 +1264,7 @@
+ *
+ * \param chan channel to answer
+ *
++ * \details
+ * This function answers a channel and handles all necessary call
+ * setup functions.
+ *
+@@ -1083,18 +1325,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
+@@ -1102,7 +1347,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
+@@ -1114,33 +1360,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
+@@ -1148,44 +1404,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
+@@ -1193,7 +1460,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
+@@ -1201,7 +1469,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
+@@ -1212,7 +1481,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
+@@ -1220,7 +1490,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
+@@ -1234,6 +1505,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.
+@@ -1243,34 +1515,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
+@@ -1278,7 +1551,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)
+@@ -1286,69 +1560,41 @@
+ */
+ char *ast_recvtext(struct ast_channel *chan, int timeout);
+
+-/*! \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*!
+- */
+-struct ast_channel *ast_channel_walk_locked(const struct ast_channel *prev);
+-
+-/*! \brief Get channel by name or uniqueid (locks channel) */
+-struct ast_channel *ast_get_channel_by_name_locked(const char *chan);
+-
+-/*! \brief Get channel by name or uniqueid prefix (locks channel) */
+-struct ast_channel *ast_get_channel_by_name_prefix_locked(const char *name, const int namelen);
+-
+-/*! \brief Get channel by name or uniqueid prefix (locks channel) */
+-struct ast_channel *ast_walk_channel_by_name_prefix_locked(const struct ast_channel *chan, const char *name, const int namelen);
+-
+-/*! \brief Get channel by exten (and optionally context) and lock it */
+-struct ast_channel *ast_get_channel_by_exten_locked(const char *exten, const char *context);
+-
+-/*! \brief Get next channel by exten (and optionally context) and lock it */
+-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
+- * 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
++/*!
++ * \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);
+
+@@ -1364,28 +1610,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);
+@@ -1396,6 +1651,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
+@@ -1407,100 +1663,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 */
+@@ -1558,105 +1828,133 @@
+ *
+ * \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
++ *
++ * \note This function does _not_ return a reference to the bridged channel.
++ * The reason for this is mostly historical. It _should_ return a reference,
++ * but it will take a lot of work to make the code base account for that.
++ * So, for now, the old rules still apply for how to handle this function.
++ * If this function is being used from the channel thread that owns the channel,
++ * then a reference is already held, and channel locking is not required to
++ * guarantee that the channel will stay around. If this function is used
++ * outside of the associated channel thread, the channel parameter 'chan'
++ * MUST be locked before calling this function. Also, 'chan' must remain locked
++ * for the entire time that the result of this function is being used.
++ *
++ * \param chan Current channel
++ *
++ * \return A pointer to the bridged 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)
+ */
+@@ -1699,12 +1997,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
+@@ -1761,23 +2061,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;
+@@ -1785,7 +2085,518 @@
+ AST_LIST_ENTRY(ast_group_info) group_list;
+ };
+
++#define ast_channel_lock(chan) ao2_lock(chan)
++#define ast_channel_unlock(chan) ao2_unlock(chan)
++#define ast_channel_trylock(chan) ao2_trylock(chan)
+
++/*!
++ * \brief Lock two channels.
++ */
++#define ast_channel_lock_both(chan1, chan2) do { \
++ ast_channel_lock(chan1); \
++ while (ast_channel_trylock(chan2)) { \
++ ast_channel_unlock(chan1); \
++ sched_yield(); \
++ ast_channel_lock(chan1); \
++ } \
++ } while (0)
++
++/*!
++ * \brief Increase channel reference count
++ *
++ * \param c the channel
++ *
++ * \retval c always
++ *
++ * \since 1.6.3
++ */
++#define ast_channel_ref(c) ({ ao2_ref(c, +1); (c); })
++
++/*!
++ * \brief Decrease channel reference count
++ *
++ * \param c the channel
++ *
++ * \retval NULL always
++ *
++ * \since 1.6.3
++ */
++#define ast_channel_unref(c) ({ ao2_ref(c, -1); (struct ast_channel *) (NULL); })
++
++/*! Channel Iterating @{ */
++
++/*!
++ * \brief A channel iterator
++ *
++ * This is an opaque type.
++ */
++struct ast_channel_iterator;
++
++/*!
++ * \brief Destroy a channel iterator
++ *
++ * \arg i the itereator to destroy
++ *
++ * This function is used to destroy a channel iterator that was retrieved by
++ * using one of the channel_iterator_new() functions.
++ *
++ * \return NULL, for convenience to clear out the pointer to the iterator that
++ * was just destroyed.
++ *
++ * \since 1.6.3
++ */
++struct ast_channel_iterator *ast_channel_iterator_destroy(struct ast_channel_iterator *i);
++
++/*!
++ * \brief Create a new channel iterator based on extension
++ *
++ * \arg ao2_flags astobj2 iterator flags
++ * \arg exten The extension that channels must be in
++ * \arg context The context that channels must be in (optional)
++ *
++ * After creating an iterator using this function, the ast_channel_iterator_next()
++ * function can be used to iterate through all channels that are currently
++ * in the specified context and extension.
++ *
++ * \retval NULL on failure
++ * \retval a new channel iterator based on the specified parameters
++ *
++ * \since 1.6.3
++ */
++struct ast_channel_iterator *ast_channel_iterator_by_exten_new(int ao2_flags, const char *exten,
++ const char *context);
++
++/*!
++ * \brief Create a new channel iterator based on name
++ *
++ * \arg ao2_flags astobj2 iterator flags
++ * \arg name channel name or channel uniqueid to match
++ * \arg name_len number of characters in the channel name to match on. This
++ * would be used to match based on name prefix. If matching on the full
++ * channel name is desired, then this parameter should be 0.
++ *
++ * After creating an iterator using this function, the ast_channel_iterator_next()
++ * function can be used to iterate through all channels that exist that have
++ * the specified name or name prefix.
++ *
++ * \retval NULL on failure
++ * \retval a new channel iterator based on the specified parameters
++ *
++ * \since 1.6.3
++ */
++struct ast_channel_iterator *ast_channel_iterator_by_name_new(int ao2_flags, const char *name,
++ size_t name_len);
++
++/*!
++ * \brief Create a new channel iterator
++ *
++ * \arg ao2_flags astobj2 iterator flags
++ *
++ * After creating an iterator using this function, the ast_channel_iterator_next()
++ * function can be used to iterate through all channels that exist.
++ *
++ * \retval NULL on failure
++ * \retval a new channel iterator
++ *
++ * \since 1.6.3
++ */
++struct ast_channel_iterator *ast_channel_iterator_all_new(int ao2_flags);
++
++/*!
++ * \brief Get the next channel for a channel iterator
++ *
++ * \arg i the channel iterator that was created using one of the
++ * channel_iterator_new() functions.
++ *
++ * This function should be used to iterate through all channels that match a
++ * specified set of parameters that were provided when the iterator was created.
++ *
++ * \retval the next channel that matches the parameters used when the iterator
++ * was created.
++ * \retval NULL, if no more channels match the iterator parameters.
++ *
++ * \since 1.6.3
++ */
++struct ast_channel *ast_channel_iterator_next(struct ast_channel_iterator *i);
++
++/*! @} End channel iterator definitions. */
++
++/*!
++ * \brief Call a function with every active channel
++ *
++ * This function executes a callback one time for each active channel on the
++ * system. The channel is provided as an argument to the function.
++ *
++ * \since 1.6.3
++ */
++struct ast_channel *ast_channel_callback(ao2_callback_data_fn *cb_fn, void *arg,
++ void *data, int ao2_flags);
++
++/*! @{ Channel search functions */
++
++/*!
++ * \brief Find a channel by name
++ *
++ * \arg name the name or uniqueid of the channel to search for
++ *
++ * Find a channel that has the same name as the provided argument.
++ *
++ * \retval a channel with the name specified by the argument
++ * \retval NULL if no channel was found
++ *
++ * \since 1.6.3
++ */
++struct ast_channel *ast_channel_get_by_name(const char *name);
++
++/*!
++ * \brief Find a channel by a name prefix
++ *
++ * \arg name The channel name or uniqueid prefix to search for
++ * \arg name_len Only search for up to this many characters from the name
++ *
++ * Find a channel that has the same name prefix as specified by the arguments.
++ *
++ * \retval a channel with the name prefix specified by the arguments
++ * \retval NULL if no channel was found
++ *
++ * \since 1.6.3
++ */
++struct ast_channel *ast_channel_get_by_name_prefix(const char *name, size_t name_len);
++
++/*!
++ * \brief Find a channel by extension and context
++ *
++ * \arg exten the extension to search for
++ * \arg context the context to search for (optional)
++ *
++ * Return a channel that is currently at the specified extension and context.
++ *
++ * \retval a channel that is at the specified extension and context
++ * \retval NULL if no channel was found
++ *
++ * \since 1.6.3
++ */
++struct ast_channel *ast_channel_get_by_exten(const char *exten, const char *context);
++
++/*! @} End channel search functions. */
++
++/*!
++ * \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);
++
++/*!
++ * \since 1.6.3
++ * \brief Run a connected line interception macro and update a channel's connected line
++ * information
++ *
++ * Whenever we want to update a channel's connected line information, we may need to run
++ * a macro so that an administrator can manipulate the information before sending it
++ * out. This function both runs the macro and sends the update to the channel.
++ *
++ * \param autoservice_chan Channel to place into autoservice while the macro is running.
++ * It is perfectly safe for this to be NULL
++ * \param macro_chan The channel to run the macro on. Also the channel from which we
++ * determine which macro we need to run.
++ * \param connected_info Either an ast_party_connected_line or ast_frame pointer of type
++ * AST_CONTROL_CONNECTED_LINE
++ * \param caller If true, then run CONNECTED_LINE_CALLER_SEND_MACRO, otherwise run
++ * CONNECTED_LINE_CALLEE_SEND_MACRO
++ * \param frame If true, then connected_info is an ast_frame pointer, otherwise it is an
++ * ast_party_connected_line pointer.
++ * \retval 0 Success
++ * \retval -1 Either the macro does not exist, or there was an error while attempting to
++ * run the macro
++ *
++ * \todo Have multiple return codes based on the MACRO_RESULT
++ * \todo Make constants so that caller and frame can be more expressive than just '1' and
++ * '0'
++ */
++int ast_channel_connected_line_macro(struct ast_channel *autoservice_chan, struct ast_channel *macro_chan, const void *connected_info, int caller, int frame);
+ #if defined(__cplusplus) || defined(c_plusplus)
+ }
+ #endif
+Index: include/asterisk/_private.h
+===================================================================
+--- a/include/asterisk/_private.h (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/include/asterisk/_private.h (.../trunk) (revision 202568)
+@@ -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/manager.h
+===================================================================
+--- a/include/asterisk/manager.h (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/include/asterisk/manager.h (.../trunk) (revision 202568)
+@@ -22,6 +22,7 @@
+ #include "asterisk/network.h"
+ #include "asterisk/lock.h"
+ #include "asterisk/datastore.h"
++#include "asterisk/xmldoc.h"
+
+ /*!
+ \file
+@@ -116,14 +117,19 @@
+ struct manager_action {
+ /*! Name of the action */
+ const char *action;
+- /*! Short description of the action */
+- const char *synopsis;
+- /*! Detailed description of the action */
+- const char *description;
++ AST_DECLARE_STRING_FIELDS(
++ AST_STRING_FIELD(synopsis); /*!< Synopsis text (short description). */
++ AST_STRING_FIELD(description); /*!< Description (help text) */
++ AST_STRING_FIELD(syntax); /*!< Syntax text */
++ AST_STRING_FIELD(arguments); /*!< Description of each argument. */
++ AST_STRING_FIELD(seealso); /*!< See also */
++ );
+ /*! Permission required for action. EVENT_FLAG_* */
+ int authority;
+ /*! Function to be called */
+ int (*func)(struct mansession *s, const struct message *m);
++ /*! Where the documentation come from. */
++ enum ast_doc_src docsrc;
+ /*! For easy linking */
+ AST_RWLIST_ENTRY(manager_action) list;
+ };
+@@ -132,6 +138,8 @@
+ * \note Use ast_manager_register2() to register with help text for new manager commands */
+ #define ast_manager_register(a, b, c, d) ast_manager_register2(a, b, c, d, NULL)
+
++/*! \brief Register a manager callback using XML documentation to describe the manager. */
++#define ast_manager_register_xml(a, b, c) ast_manager_register2(a, b, c, NULL, NULL)
+
+ /*! \brief Register a manager command with the manager interface
+ \param action Name of the requested Action:
+Index: include/asterisk/features.h
+===================================================================
+--- a/include/asterisk/features.h (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/include/asterisk/features.h (.../trunk) (revision 202568)
+@@ -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, const 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, const 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/http.h
+===================================================================
+--- a/include/asterisk/http.h (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/include/asterisk/http.h (.../trunk) (revision 202568)
+@@ -52,27 +52,40 @@
+ * be run earlier in the startup process so modules have it available.
+ */
+
+-
+-/*! \brief HTTP Callbacks take the socket
+-
+- \note The method and the path as arguments and should
+- return the content, allocated with malloc(). Status should be changed to reflect
+- the status of the request if it isn't 200 and title may be set to a malloc()'d string
+- to an appropriate title for non-200 responses. Content length may also be specified.
+-\verbatim
+- The return value may include additional headers at the front and MUST include a blank
+- line with \r\n to provide separation between user headers and content (even if no
+- content is specified)
+-\endverbatim
+-*/
+-
++/*! \brief HTTP Request methods known by Asterisk */
+ enum ast_http_method {
++ AST_HTTP_UNKNOWN = -1, /*!< Unknown response */
+ AST_HTTP_GET = 0,
+ AST_HTTP_POST,
++ AST_HTTP_HEAD,
++ AST_HTTP_PUT, /*!< Not supported in Asterisk */
+ };
++
+ struct ast_http_uri;
+
+-typedef struct ast_str *(*ast_http_callback)(struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *params, struct ast_variable *headers, int *status, char **title, int *contentlength);
++/*! \brief HTTP Callbacks
++ *
++ * \note The callback function receives server instance, uri, http method,
++ * get method (if present in URI), and http headers as arguments and should
++ * use the ast_http_send() function for sending content allocated with ast_str
++ * and/or content from an opened file descriptor.
++ *
++ * Status and status text should be sent as arguments to the ast_http_send()
++ * function to reflect the status of the request (200 or 304, for example).
++ * Content length is calculated by ast_http_send() automatically.
++ *
++ * Static content may be indicated to the ast_http_send() function, to indicate
++ * that it may be cached.
++ *
++ * \verbatim
++ * The return value may include additional headers at the front and MUST
++ * include a blank line with \r\n to provide separation between user headers
++ * and content (even if no content is specified)
++ * \endverbatim
++ *
++ * For an error response, the ast_http_error() function may be used.
++*/
++typedef int (*ast_http_callback)(struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_params, struct ast_variable *headers);
+
+ /*! \brief Definition of a URI handler */
+ struct ast_http_uri {
+@@ -81,12 +94,6 @@
+ const char *uri;
+ ast_http_callback callback;
+ unsigned int has_subtree:1;
+- /*! This handler serves static content */
+- unsigned int static_content:1;
+- /*! This handler accepts GET requests */
+- unsigned int supports_get:1;
+- /*! This handler accepts POST requests */
+- unsigned int supports_post:1;
+ /*! Structure is malloc'd */
+ unsigned int mallocd:1;
+ /*! Data structure is malloc'd */
+@@ -97,6 +104,9 @@
+ const char *key;
+ };
+
++/*! \brief Get cookie from Request headers */
++struct ast_variable *ast_http_get_cookies(struct ast_variable *headers);
++
+ /*! \brief Register a URI handler */
+ int ast_http_uri_link(struct ast_http_uri *urihandler);
+
+@@ -106,9 +116,59 @@
+ /*! \brief Unregister all handlers with matching key */
+ void ast_http_uri_unlink_all_with_key(const char *key);
+
+-/*! \brief Return an ast_str malloc()'d string containing an HTTP error message */
+-struct ast_str *ast_http_error(int status, const char *title, const char *extra_header, const char *text);
++/*!\brief Return http method name string
++ * \since 1.6.3
++ */
++const char *ast_get_http_method(enum ast_http_method method) attribute_pure;
+
++/*!\brief Return mime type based on extension
++ * \param ftype filename extension
++ * \return String containing associated MIME type
++ * \since 1.6.3
++ */
++const char *ast_http_ftype2mtype(const char *ftype) attribute_pure;
++
++/*!\brief Return manager id, if exist, from request headers
++ * \param headers List of HTTP headers
++ * \return 32-bit associated manager session identifier
++ * \since 1.6.3
++ */
++uint32_t ast_http_manid_from_vars(struct ast_variable *headers) attribute_pure;
++
++/*! \brief Generic function for sending http/1.1 response.
++ * \param ser TCP/TLS session object
++ * \param method GET/POST/HEAD
++ * \param status_code HTTP response code (200/401/403/404/500)
++ * \param status_title English equivalent to the status_code parameter
++ * \param http_header An ast_str object containing all headers
++ * \param out An ast_str object containing the body of the response
++ * \param fd If out is NULL, a file descriptor where the body of the response is held (otherwise -1)
++ * \param static_content Zero if the content is dynamically generated and should not be cached; nonzero otherwise
++ *
++ * \note Function determines the HTTP response header from status_code,
++ * status_header, and http_header.
++ *
++ * Extra HTTP headers MUST be present only in the http_header argument. The
++ * argument "out" should contain only content of the response (no headers!).
++ *
++ * HTTP content can be constructed from the argument "out", if it is not NULL;
++ * otherwise, the function will read content from FD.
++ *
++ * This function calculates the content-length http header itself.
++ *
++ * Both the http_header and out arguments will be freed by this function;
++ * however, if FD is open, it will remain open.
++ *
++ * \since 1.6.3
++ */
++void ast_http_send(struct ast_tcptls_session_instance *ser, enum ast_http_method method, int status_code, const char *status_title, struct ast_str *http_header, struct ast_str *out, const int fd, unsigned int static_content);
++
++/*!\brief Send http "401 Unauthorized" response and close socket */
++void ast_http_auth(struct ast_tcptls_session_instance *ser, const char *realm, const unsigned long nonce, const unsigned long opaque, int stale, const char *text);
++
++/*!\brief Send HTTP error message and close socket */
++void ast_http_error(struct ast_tcptls_session_instance *ser, int status, const char *title, const char *text);
++
+ /*!
+ * \brief Return the current prefix
+ * \param buf[out] destination buffer for previous
+@@ -117,4 +177,15 @@
+ */
+ void ast_http_prefix(char *buf, int len);
+
++
++/*!\brief Get post variables from client Request Entity-Body, if content type is application/x-www-form-urlencoded.
++ * \param ser TCP/TLS session object
++ * \param headers List of HTTP headers
++ * \return List of variables within the POST body
++ * \note Since returned list is malloc'd, list should be free'd by the calling function
++ * \since 1.6.3
++ */
++struct ast_variable *ast_http_get_post_vars(struct ast_tcptls_session_instance *ser, struct ast_variable *headers);
++
++
+ #endif /* _ASTERISK_SRV_H */
+Index: include/asterisk/app.h
+===================================================================
+--- a/include/asterisk/app.h (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/include/asterisk/app.h (.../trunk) (revision 202568)
+@@ -106,9 +106,29 @@
+ int ast_app_getdata(struct ast_channel *c, const char *prompt, char *s, int maxlen, int timeout);
+
+ /*! \brief Full version with audiofd and controlfd. NOTE: returns '2' on ctrlfd available, not '1' like other full functions */
+-int ast_app_getdata_full(struct ast_channel *c, char *prompt, char *s, int maxlen, int timeout, int audiofd, int ctrlfd);
++int ast_app_getdata_full(struct ast_channel *c, const char *prompt, char *s, int maxlen, int timeout, int audiofd, int ctrlfd);
+
+ /*!
++ * \since 1.6.3
++ * \brief Run a macro on a channel, placing a second channel into autoservice.
++ *
++ * This is a shorthand method that makes it very easy to run a macro on any given
++ * channel. It is perfectly reasonable to supply a NULL autoservice_chan here in case
++ * there is no channel to place into autoservice. It is very important that the
++ * autoservice_chan parameter is not locked prior to calling ast_app_run_macro. A
++ * deadlock could result, otherwise.
++ *
++ * \param autoservice_chan A channel to place into autoservice while the macro is run
++ * \param macro_chan The channel to run the macro on
++ * \param macro_name The name of the macro to run
++ * \param macro_args The arguments to pass to the macro
++ * \retval 0 success
++ * \retval -1 failure
++ */
++int ast_app_run_macro(struct ast_channel *autoservice_chan, struct ast_channel
++ *macro_chan, const char * const macro_name, const char * const macro_args);
++
++/*!
+ * \brief Set voicemail function callbacks
+ * \param[in] inboxcount2_func set function pointer
+ * \param[in] sayname_func set function pointer
+@@ -427,19 +447,19 @@
+
+ Example usage:
+ \code
+- enum {
++ enum my_app_option_flags {
+ OPT_JUMP = (1 << 0),
+ OPT_BLAH = (1 << 1),
+ OPT_BLORT = (1 << 2),
+- } my_app_option_flags;
++ };
+
+- enum {
++ enum my_app_option_args {
+ OPT_ARG_BLAH = 0,
+ OPT_ARG_BLORT,
+ !! this entry tells how many possible arguments there are,
+ and must be the last entry in the list
+ OPT_ARG_ARRAY_SIZE,
+- } my_app_option_args;
++ };
+
+ AST_APP_OPTIONS(my_app_options, {
+ AST_APP_OPTION('j', OPT_JUMP),
+Index: include/asterisk/image.h
+===================================================================
+--- a/include/asterisk/image.h (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/include/asterisk/image.h (.../trunk) (revision 202568)
+@@ -51,7 +51,7 @@
+ * \retval 0 on success
+ * \retval -1 on error
+ */
+-int ast_send_image(struct ast_channel *chan, char *filename);
++int ast_send_image(struct ast_channel *chan, const char *filename);
+
+ /*!
+ * \brief Make an image
+@@ -62,7 +62,7 @@
+ * \retval an ast_frame on success
+ * \retval NULL on failure
+ */
+-struct ast_frame *ast_read_image(char *filename, const char *preflang, int format);
++struct ast_frame *ast_read_image(const char *filename, const char *preflang, int format);
+
+ /*!
+ * \brief Register image format
+Index: include/asterisk/linkedlists.h
+===================================================================
+--- a/include/asterisk/linkedlists.h (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/include/asterisk/linkedlists.h (.../trunk) (revision 202568)
+@@ -765,20 +765,47 @@
+ * calling this macro (the list entries are \b moved to the target list).
+ */
+ #define AST_LIST_APPEND_LIST(head, list, field) do { \
+- if (!(head)->first) { \
++ if (!(list)->first) { \
++ break; \
++ } \
++ if (!(head)->first) { \
+ (head)->first = (list)->first; \
+ (head)->last = (list)->last; \
+- } else { \
++ } else { \
+ (head)->last->field.next = (list)->first; \
+ (head)->last = (list)->last; \
+- } \
+- (list)->first = NULL; \
+- (list)->last = NULL; \
++ } \
++ (list)->first = NULL; \
++ (list)->last = NULL; \
+ } while (0)
+
+ #define AST_RWLIST_APPEND_LIST AST_LIST_APPEND_LIST
+
+ /*!
++ \brief Inserts a whole list after a specific entry in a list
++ \param head This is a pointer to the list head structure
++ \param list This is a pointer to the list to be inserted.
++ \param elm This is a pointer to the entry after which the new list should
++ be inserted.
++ \param field This is the name of the field (declared using AST_LIST_ENTRY())
++ used to link entries of the lists together.
++
++ Note: The source list (the \a list parameter) will be empty after
++ calling this macro (the list entries are \b moved to the target list).
++ */
++#define AST_LIST_INSERT_LIST_AFTER(head, list, elm, field) do { \
++ (list)->last->field.next = (elm)->field.next; \
++ (elm)->field.next = (list)->first; \
++ if ((head)->last == elm) { \
++ (head)->last = (list)->last; \
++ } \
++ (list)->first = NULL; \
++ (list)->last = NULL; \
++} while(0)
++
++#define AST_RWLIST_INSERT_LIST_AFTER AST_LIST_INSERT_LIST_AFTER
++
++/*!
+ * \brief Removes and returns the head entry from a list.
+ * \param head This is a pointer to the list head structure
+ * \param field This is the name of the field (declared using AST_LIST_ENTRY())
+Index: include/asterisk/doxygen/reviewboard.h
+===================================================================
+--- a/include/asterisk/doxygen/reviewboard.h (.../tags/1.6.2.0-beta3) (revision 0)
++++ b/include/asterisk/doxygen/reviewboard.h (.../trunk) (revision 202568)
+@@ -0,0 +1,127 @@
++/*
++* Asterisk -- An open source telephony toolkit.
++*
++* Copyright (C) 1999 - 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
++*/
++
++/*!
++ * \page Reviewboard Reviewboard Usage and Guidelines
++ *
++ * \AsteriskTrunkWarning
++ *
++ * <hr/>
++ *
++ * \section ReviewboardGuidelines Usage Guidelines
++ *
++ * Mantis (https://issues.asterisk.org) and Reviewboard (https://reviewboard.asterisk.org)
++ * are both utilities that the Asterisk development community uses to help
++ * track and review code being written for Asterisk. Since both systems
++ * are used for posting patches, it is worth discussing when it is appropriate
++ * to use reviewboard and when not.
++ *
++ * Here are the situations in which it is appropriate to post code to reviewboard:
++ * - A committer has a patch that they would like to get some feedback on before
++ * merging into one of the main branches.
++ * - A committer or bug marshal has requested a contributor to post their patch
++ * from Mantis on reviewboard to aid in the review process. This typically
++ * happens with complex code contributions where reviewboard can help aid in
++ * providing feedback.
++ *
++ * We do encourage all interested parties to participate in the review process.
++ * However, aside from the cases mentioned above, we prefer that all code
++ * submissions first go through Mantis.
++ *
++ * \note It is acceptable for a committer to post patches to reviewboard before
++ * they are complete to get some feedback on the approach being taken. However,
++ * if the code is not yet ready to be merged, it \b must be documented as such.
++ * A review request with a patch proposed for merging should have documented
++ * testing and should not have blatant coding guidelines violations. Lack of
++ * these things is careless and shows disrespect for those reviewing your code.
++ *
++ * <hr/>
++ *
++ * \section ReviewboardPosting Posting Code to Reviewboard
++ *
++ * \subsection postreview Using post-review
++ *
++ * The easiest way to post a patch to reviewboard is by using the
++ * post-review tool. We have post-review in our repotools svn repository.
++ *
++ \verbatim
++ $ svn co http://svn.digium.com/svn/repotools
++ \endverbatim
++ *
++ * Essentially, post-review is a script that will take the output of "svn
++ * diff" and create a review request out of it for you. So, once you have
++ * a working copy with the changes you expect in the output of "svn diff",
++ * you just run the following command:
++ *
++ \verbatim
++ $ post-review
++ \endverbatim
++ *
++ * If it complains about not knowing which reviewboard server to use, add
++ * the server option:
++ *
++ \verbatim
++ $ post-review --server=https://reviewboard.asterisk.org
++ \endverbatim
++ *
++ * \subsection postreviewnewfiles Dealing with New Files
++ *
++ * I have one final note about an oddity with using post-review. If you
++ * maintain your code in a team branch, and the new code includes new
++ * files, there are some additional steps you must take to get post-review
++ * to behave properly.
++ *
++ * You would start by getting your changes applied to a trunk working copy:
++ *
++ \verbatim
++ $ cd .../trunk
++ \endverbatim
++ *
++ * Then, apply the changes from your branch:
++ *
++ \verbatim
++ $ svn merge .../trunk .../team/group/my_new_code
++ \endverbatim
++ *
++ * Now, the code is merged into your working copy. However, for a new
++ * file, subversion treats it as a copy of existing content and not new
++ * content, so new files don't show up in "svn diff" at this point. To get
++ * it to show up in the diff, use the following commands so svn treats it
++ * as new content and publishes it in the diff:
++ *
++ \verbatim
++ $ svn revert my_new_file.c
++ $ svn add my_new_file.c
++ \endverbatim
++ *
++ * Now, it should work, and you can run "post-review" as usual.
++ *
++ * \subsection postreviewupdate Updating Patch on Existing Review Request
++ *
++ * Most of the time, a patch on reviewboard will require multiple iterations
++ * before other sign off on it being ready to be merged. To update the diff
++ * for an existing review request, you can use post-review and the -r option.
++ * Apply the current version of the diff to a working copy as described above,
++ * and then run the following command:
++ *
++ \verbatim
++ $ post-review -r <review request number>
++ \endverbatim
++ */
+
+Property changes on: include/asterisk/doxygen/reviewboard.h
+___________________________________________________________________
+Added: svn:mime-type
+ + text/plain
+Added: svn:keywords
+ + Author Date Id Revision
+Added: svn:eol-style
+ + native
+
+Index: include/asterisk/doxygen/commits.h
+===================================================================
+--- a/include/asterisk/doxygen/commits.h (.../tags/1.6.2.0-beta3) (revision 0)
++++ b/include/asterisk/doxygen/commits.h (.../trunk) (revision 202568)
+@@ -0,0 +1,114 @@
++/*
++ * Asterisk -- An open source telephony toolkit.
++ *
++ * Copyright (C) 1999 - 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
++ */
++
++/*!
++ * \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. Always end the first sentence (and any
++ * subsequent sentences) with punctuation.
++ *
++ * 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 (https://issues.asterisk.org/)
++ *
++ * 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 (https://reviewboard.asterisk.org/)
++ *
++ * To have a commit set a review request as submitted, include the full URL
++ * to the review request. For example:
++ * \arg Review: %https://reviewboard.asterisk.org/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
++ */
++
++
+
+Property changes on: include/asterisk/doxygen/commits.h
+___________________________________________________________________
+Added: svn:mime-type
+ + text/plain
+Added: svn:keywords
+ + Author Date Id Revision
+Added: svn:eol-style
+ + native
+
+Index: include/asterisk/doxygen/licensing.h
+===================================================================
+--- a/include/asterisk/doxygen/licensing.h (.../tags/1.6.2.0-beta3) (revision 0)
++++ b/include/asterisk/doxygen/licensing.h (.../trunk) (revision 202568)
+@@ -0,0 +1,153 @@
++/*
++ * Asterisk -- An open source telephony toolkit.
++ *
++ * Copyright (C) 1999 - 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
++ */
++
++/*!
++ * \page Licensing Asterisk Licensing Information
++ *
++ * \section license Asterisk License
++ * \verbinclude LICENSE
++ *
++ * \section otherlicenses Licensing of 3rd Party Code
++ *
++ * This section contains a (not yet complete) list of libraries that are used
++ * by various parts of Asterisk, including related licensing information.
++ *
++ * \subsection alsa_lib ALSA Library
++ * \arg <b>Library</b>: libasound
++ * \arg <b>Website</b>: http://www.alsa-project.org
++ * \arg <b>Used by</b>: chan_alsa
++ * \arg <b>License</b>: LGPL
++ *
++ * \subsection openssl_lib OpenSSL
++ * \arg <b>Library</b>: libcrypto, libssl
++ * \arg <b>Website</b>: http://www.openssl.org
++ * \arg <b>Used by</b>: Asterisk core (TLS for manager and HTTP), res_crypto
++ * \arg <b>License</b>: Apache 2.0
++ * \arg <b>Note</b>: An exception has been granted to allow linking of
++ * OpenSSL with Asterisk.
++ *
++ * \subsection curl_lib Curl
++ * \arg <b>Library</b>: libcurl
++ * \arg <b>Website</b>: http://curl.haxx.se
++ * \arg <b>Used by</b>: func_curl, res_config_curl, res_curl
++ * \arg <b>License</b>: BSD
++ *
++ * \subsection portaudio_lib PortAudio
++ * \arg <b>Library</b>: libportaudio
++ * \arg <b>Website</b>: http://www.portaudio.com
++ * \arg <b>Used by</b>: chan_console
++ * \arg <b>License</b>: BSD
++ * \arg <b>Note</b>: Even though PortAudio is licensed under a BSD style
++ * license, PortAudio will make use of some audio interface,
++ * depending on how it was built. That audio interface may
++ * introduce additional licensing restrictions. On Linux,
++ * this would most commonly be ALSA: \ref alsa_lib.
++ *
++ * \subsection rawlist Raw list of libraries that used by any part of Asterisk
++ * \li c-client.a (app_voicemail with IMAP support)
++ * \li libSDL-1.2.so.0
++ * \li libSaClm.so.2
++ * \li libSaEvt.so.2
++ * \li libX11.so.6
++ * \li libXau.so.6
++ * \li libXdmcp.so.6
++ * \li libasound.so.2
++ * \li libc.so.6
++ * \li libcom_err.so.2
++ * \li libcrypt.so.1
++ * \li libcrypto.so.0.9.8 (chan_h323)
++ * \li libcurl.so.4
++ * \li libdirect-1.0.so.0
++ * \li libdirectfb-1.0.so.0
++ * \li libdl.so.2
++ * \li libexpat.so (chan_h323)
++ * \li libfusion-1.0.so.0
++ * \li libgcc_s.so (chan_h323)
++ * \li libgcrypt.so.11 (chan_h323)
++ * \li libglib-2.0.so.0
++ * \li libgmime-2.0.so.2
++ * \li libgmodule-2.0.so.0
++ * \li libgnutls.so.13 (chan_h323)
++ * \li libgobject-2.0.so.0
++ * \li libgpg-error.so.0 (chan_h323)
++ * \li libgssapi_krb5.so.2
++ * \li libgthread-2.0.so.0
++ * \li libidn.so.11
++ * \li libiksemel.so.3
++ * \li libisdnnet.so
++ * \li libjack.so.0
++ * \li libjpeg.so.62
++ * \li libk5crypto.so.3
++ * \li libkeyutils.so.1
++ * \li libkrb5.so.3
++ * \li libkrb5support.so.0
++ * \li liblber-2.4.so.2 (chan_h323)
++ * \li libldap_r-2.4.so.2 (chan_h323)
++ * \li libltdl.so.3
++ * \li liblua5.1.so.0
++ * \li libm.so.6
++ * \li libmISDN.so
++ * \li libnbs.so.1
++ * \li libncurses.so.5
++ * \li libnetsnmp.so.15
++ * \li libnetsnmpagent.so.15
++ * \li libnetsnmphelpers.so.15
++ * \li libnetsnmpmibs.so.15
++ * \li libnsl.so.1
++ * \li libodbc.so.1
++ * \li libogg.so.0
++ * \li libopenh323.so (chan_h323)
++ * \li libpcre.so.3
++ * \li libperl.so.5.8
++ * \li libportaudio.so.2
++ * \li libpq.so.5
++ * \li libpri.so.1.4
++ * \li libpt.so (chan_h323)
++ * \li libpthread.so.0
++ * \li libradiusclient-ng.so.2
++ * \li libresample.so.1.0
++ * \li libresolv.so.2 (chan_h323)
++ * \li librt.so.1
++ * \li libsasl2.so.2 (chan_h323)
++ * \li libselinux.so.1
++ * \li libsensors.so.3
++ * \li libspandsp.so.1
++ * \li libspeex.so.1
++ * \li libsqlite.so.0
++ * \li libsqlite3.so.0
++ * \li libss7.so.1
++ * \li libssl.so.0.9.8 (chan_h323)
++ * \li libstdc++.so (chan_h323, chan_vpb)
++ * \li libsuppserv.so
++ * \li libsybdb.so.5
++ * \li libsysfs.so.2
++ * \li libtasn1.so.3 (chan_h323)
++ * \li libtds.so.4
++ * \li libtiff.so.4
++ * \li libtonezone.so.1.0
++ * \li libvorbis.so.0
++ * \li libvorbisenc.so.2
++ * \li libvpb.a (chan_vpb)
++ * \li libwrap.so.0
++ * \li libxcb-xlib.so.0
++ * \li libxcb.so.1
++ * \li libz.so.1 (chan_h323)
++ * \li linux-vdso.so.1
++*/
+
+Property changes on: include/asterisk/doxygen/licensing.h
+___________________________________________________________________
+Added: svn:mime-type
+ + text/plain
+Added: svn:keywords
+ + Author Date Id Revision
+Added: svn:eol-style
+ + native
+
+Index: include/asterisk/doxygen/releases.h
+===================================================================
+--- a/include/asterisk/doxygen/releases.h (.../tags/1.6.2.0-beta3) (revision 0)
++++ b/include/asterisk/doxygen/releases.h (.../trunk) (revision 202568)
+@@ -0,0 +1,298 @@
++/*
++ * Asterisk -- An open source telephony toolkit.
++ *
++ * Copyright (C) 1999 - 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
++ */
++
++/*!
++ * \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 ReleasePolicies Asterisk Release and Commit Policies
++ *
++ * \AsteriskTrunkWarning
++ *
++ * \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.asterisk.org/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.
++ *
++ * \subsection ast12releasenumbers Release Numbering
++ *
++ * - 1.2.X - a release that contains new security fixes
++ * - 1.2.X.Y - a release that contains fixes to the security patches released in
++ * version 1.2.X
++ *
++ * <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.
++ *
++ * \subsection ast14releasenumbers Release Numbering
++ *
++ * - 1.4.X - a release that contains new bug fixes to the 1.4 release series
++ * - 1.4.X.Y - a release that contains very few changes on top of 1.4.X. This
++ * may be for a security patch, or for a regression introduced in 1.4.X.
++ *
++ * <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>.
++ *
++ * \subsection ast16releasenumbers Release Numbering
++ *
++ * - 1.6.X - a release that includes new functionality
++ * - 1.6.X.Y - a release that contains fixes for bugs or security issues identified
++ * in the 1.6.X release series.
++ *
++ * <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.
++ */
+
+Property changes on: include/asterisk/doxygen/releases.h
+___________________________________________________________________
+Added: svn:mime-type
+ + text/plain
+Added: svn:keywords
+ + Author Date Id Revision
+Added: svn:eol-style
+ + native
+
+Index: include/asterisk/smdi.h
+===================================================================
+--- a/include/asterisk/smdi.h (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/include/asterisk/smdi.h (.../trunk) (revision 202568)
+@@ -85,8 +85,9 @@
+ */
+ struct ast_smdi_interface;
+
+-AST_OPTIONAL_API(void, ast_smdi_interface_unref, (struct ast_smdi_interface
+- *iface), { return; });
++AST_OPTIONAL_API(void, ast_smdi_interface_unref,
++ (struct ast_smdi_interface *iface),
++ { return; });
+
+ /*!
+ * \brief Get the next SMDI message from the queue.
+@@ -98,8 +99,9 @@
+ *
+ * \return the next SMDI message, or NULL if there were no pending messages.
+ */
+-AST_OPTIONAL_API(struct ast_smdi_md_message *, ast_smdi_md_message_pop, (struct
+- ast_smdi_interface *iface), { return NULL; });
++AST_OPTIONAL_API(struct ast_smdi_md_message *, ast_smdi_md_message_pop,
++ (struct ast_smdi_interface *iface),
++ { return NULL; });
+
+ /*!
+ * \brief Get the next SMDI message from the queue.
+@@ -114,7 +116,8 @@
+ * the timeout has expired.
+ */
+ AST_OPTIONAL_API(struct ast_smdi_md_message *, ast_smdi_md_message_wait,
+- (struct ast_smdi_interface *iface, int timeout), { return NULL; });
++ (struct ast_smdi_interface *iface, int timeout),
++ { return NULL; });
+
+ /*!
+ * \brief Put an SMDI message back in the front of the queue.
+@@ -125,8 +128,9 @@
+ * should be used if a message was popped but is not going to be processed for
+ * some reason, and the message needs to be returned to the queue.
+ */
+-AST_OPTIONAL_API(void, ast_smdi_md_message_putback, (struct ast_smdi_interface
+- *iface, struct ast_smdi_md_message *msg), { return; });
++AST_OPTIONAL_API(void, ast_smdi_md_message_putback,
++ (struct ast_smdi_interface *iface, struct ast_smdi_md_message *msg),
++ { return; });
+
+ /*!
+ * \brief Get the next SMDI message from the queue.
+@@ -139,7 +143,8 @@
+ * \return the next SMDI message, or NULL if there were no pending messages.
+ */
+ AST_OPTIONAL_API(struct ast_smdi_mwi_message *, ast_smdi_mwi_message_pop,
+- (struct ast_smdi_interface *iface), { return NULL; });
++ (struct ast_smdi_interface *iface),
++ { return NULL; });
+
+ /*!
+ * \brief Get the next SMDI message from the queue.
+@@ -154,11 +159,13 @@
+ * the timeout has expired.
+ */
+ AST_OPTIONAL_API(struct ast_smdi_mwi_message *, ast_smdi_mwi_message_wait,
+- (struct ast_smdi_interface *iface, int timeout), { return NULL; });
+-AST_OPTIONAL_API(struct ast_smdi_mwi_message *,
+- ast_smdi_mwi_message_wait_station, (struct ast_smdi_interface *iface, int
+- timeout, const char *station), { return NULL; });
++ (struct ast_smdi_interface *iface, int timeout),
++ { return NULL; });
+
++AST_OPTIONAL_API(struct ast_smdi_mwi_message *, ast_smdi_mwi_message_wait_station,
++ (struct ast_smdi_interface *iface, int timeout, const char *station),
++ { return NULL; });
++
+ /*!
+ * \brief Put an SMDI message back in the front of the queue.
+ * \param iface a pointer to the interface to use.
+@@ -168,8 +175,9 @@
+ * should be used if a message was popped but is not going to be processed for
+ * some reason, and the message needs to be returned to the queue.
+ */
+-AST_OPTIONAL_API(void, ast_smdi_mwi_message_putback, (struct ast_smdi_interface
+- *iface, struct ast_smdi_mwi_message *msg), { return; });
++AST_OPTIONAL_API(void, ast_smdi_mwi_message_putback,
++ (struct ast_smdi_interface *iface, struct ast_smdi_mwi_message *msg),
++ { return; });
+
+ /*!
+ * \brief Find an SMDI interface with the specified name.
+@@ -180,30 +188,35 @@
+ * #ASTOBJ_UNREF(iface, ast_smdi_interface_destroy).
+ */
+ AST_OPTIONAL_API(struct ast_smdi_interface *, ast_smdi_interface_find,
+- (const char *iface_name), { return NULL; });
++ (const char *iface_name),
++ { return NULL; });
+
+ /*!
+ * \brief Set the MWI indicator for a mailbox.
+ * \param iface the interface to use.
+ * \param mailbox the mailbox to use.
+ */
+-AST_OPTIONAL_API(int, ast_smdi_mwi_set, (struct ast_smdi_interface *iface,
+- const char *mailbox), { return -1; });
++AST_OPTIONAL_API(int, ast_smdi_mwi_set,
++ (struct ast_smdi_interface *iface, const char *mailbox),
++ { return -1; });
+
+ /*!
+ * \brief Unset the MWI indicator for a mailbox.
+ * \param iface the interface to use.
+ * \param mailbox the mailbox to use.
+ */
+-AST_OPTIONAL_API(int, ast_smdi_mwi_unset, (struct ast_smdi_interface *iface,
+- const char *mailbox), { return -1; });
++AST_OPTIONAL_API(int, ast_smdi_mwi_unset,
++ (struct ast_smdi_interface *iface, const char *mailbox),
++ { return -1; });
+
+ /*! \brief ast_smdi_md_message destructor. */
+ AST_OPTIONAL_API(void, ast_smdi_md_message_destroy,
+- (struct ast_smdi_md_message *msg), { return; });
++ (struct ast_smdi_md_message *msg),
++ { return; });
+
+ /*! \brief ast_smdi_mwi_message destructor. */
+-AST_OPTIONAL_API(void, ast_smdi_mwi_message_destroy, (struct
+- ast_smdi_mwi_message *msg), { return; });
++AST_OPTIONAL_API(void, ast_smdi_mwi_message_destroy,
++ (struct ast_smdi_mwi_message *msg),
++ { return; });
+
+ #endif /* !ASTERISK_SMDI_H */
+Index: include/asterisk/speech.h
+===================================================================
+--- a/include/asterisk/speech.h (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/include/asterisk/speech.h (.../trunk) (revision 202568)
+@@ -78,13 +78,13 @@
+ /*! Destroy any data set on the speech structure by the engine */
+ int (*destroy)(struct ast_speech *speech);
+ /*! Load a local grammar on the speech structure */
+- int (*load)(struct ast_speech *speech, char *grammar_name, char *grammar);
++ int (*load)(struct ast_speech *speech, const char *grammar_name, const char *grammar);
+ /*! Unload a local grammar */
+- int (*unload)(struct ast_speech *speech, char *grammar_name);
++ int (*unload)(struct ast_speech *speech, const char *grammar_name);
+ /*! Activate a loaded grammar */
+- int (*activate)(struct ast_speech *speech, char *grammar_name);
++ int (*activate)(struct ast_speech *speech, const char *grammar_name);
+ /*! Deactivate a loaded grammar */
+- int (*deactivate)(struct ast_speech *speech, char *grammar_name);
++ int (*deactivate)(struct ast_speech *speech, const char *grammar_name);
+ /*! Write audio to the speech engine */
+ int (*write)(struct ast_speech *speech, void *data, int len);
+ /*! Signal DTMF was received */
+@@ -92,7 +92,7 @@
+ /*! Prepare engine to accept audio */
+ int (*start)(struct ast_speech *speech);
+ /*! Change an engine specific setting */
+- int (*change)(struct ast_speech *speech, char *name, const char *value);
++ int (*change)(struct ast_speech *speech, const char *name, const char *value);
+ /*! Change the type of results we want back */
+ int (*change_results_type)(struct ast_speech *speech, enum ast_speech_results_type results_type);
+ /*! Try to get results */
+@@ -117,13 +117,13 @@
+ };
+
+ /*! \brief Activate a grammar on a speech structure */
+-int ast_speech_grammar_activate(struct ast_speech *speech, char *grammar_name);
++int ast_speech_grammar_activate(struct ast_speech *speech, const char *grammar_name);
+ /*! \brief Deactivate a grammar on a speech structure */
+-int ast_speech_grammar_deactivate(struct ast_speech *speech, char *grammar_name);
++int ast_speech_grammar_deactivate(struct ast_speech *speech, const char *grammar_name);
+ /*! \brief Load a grammar on a speech structure (not globally) */
+-int ast_speech_grammar_load(struct ast_speech *speech, char *grammar_name, char *grammar);
++int ast_speech_grammar_load(struct ast_speech *speech, const char *grammar_name, const char *grammar);
+ /*! \brief Unload a grammar */
+-int ast_speech_grammar_unload(struct ast_speech *speech, char *grammar_name);
++int ast_speech_grammar_unload(struct ast_speech *speech, const char *grammar_name);
+ /*! \brief Get speech recognition results */
+ struct ast_speech_result *ast_speech_results_get(struct ast_speech *speech);
+ /*! \brief Free a set of results */
+@@ -131,7 +131,7 @@
+ /*! \brief Indicate to the speech engine that audio is now going to start being written */
+ void ast_speech_start(struct ast_speech *speech);
+ /*! \brief Create a new speech structure */
+-struct ast_speech *ast_speech_new(char *engine_name, int formats);
++struct ast_speech *ast_speech_new(const char *engine_name, int formats);
+ /*! \brief Destroy a speech structure */
+ int ast_speech_destroy(struct ast_speech *speech);
+ /*! \brief Write audio to the speech engine */
+@@ -139,7 +139,7 @@
+ /*! \brief Signal to the engine that DTMF was received */
+ int ast_speech_dtmf(struct ast_speech *speech, const char *dtmf);
+ /*! \brief Change an engine specific attribute */
+-int ast_speech_change(struct ast_speech *speech, char *name, const char *value);
++int ast_speech_change(struct ast_speech *speech, const char *name, const char *value);
+ /*! \brief Change the type of results we want */
+ int ast_speech_change_results_type(struct ast_speech *speech, enum ast_speech_results_type results_type);
+ /*! \brief Change state of a speech structure */
+@@ -147,7 +147,7 @@
+ /*! \brief Register a speech recognition engine */
+ int ast_speech_register(struct ast_speech_engine *engine);
+ /*! \brief Unregister a speech recognition engine */
+-int ast_speech_unregister(char *engine_name);
++int ast_speech_unregister(const char *engine_name);
+
+ #if defined(__cplusplus) || defined(c_plusplus)
+ }
+Index: include/asterisk/abstract_jb.h
+===================================================================
+--- a/include/asterisk/abstract_jb.h (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/include/asterisk/abstract_jb.h (.../trunk) (revision 202568)
+@@ -84,7 +84,7 @@
+ /*! \brief Jitterbuffer configuration. */
+ struct ast_jb_conf conf;
+ /*! \brief Jitterbuffer implementation to be used. */
+- struct ast_jb_impl *impl;
++ const struct ast_jb_impl *impl;
+ /*! \brief Jitterbuffer object, passed to the implementation. */
+ void *jbobj;
+ /*! \brief The time the jitterbuffer was created. */
+Index: include/asterisk/event.h
+===================================================================
+--- a/include/asterisk/event.h (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/include/asterisk/event.h (.../trunk) (revision 202568)
+@@ -157,6 +157,20 @@
+ enum ast_event_ie_type ie_type, uint32_t uint);
+
+ /*!
++ * \brief Append a bitflags parameter to a subscription
++ *
++ * \param sub the dynamic subscription allocated with ast_event_subscribe_new()
++ * \param ie_type the information element type for the parameter
++ * \param flags the flags that must be present in the event to match this subscription
++ *
++ * \retval 0 success
++ * \retval non-zero failure
++ * \since 1.6.3
++ */
++int ast_event_sub_append_ie_bitflags(struct ast_event_sub *sub,
++ enum ast_event_ie_type ie_type, uint32_t flags);
++
++/*!
+ * \brief Append a string parameter to a subscription
+ *
+ * \param sub the dynamic subscription allocated with ast_event_subscribe_new()
+@@ -447,6 +461,24 @@
+ uint32_t data);
+
+ /*!
++ * \brief Append an information element that has a bitflags payload
++ *
++ * \param event the event that the IE will be appended to
++ * \param ie_type the type of IE to append
++ * \param flags the flags that are the payload of the IE
++ *
++ * \retval 0 success
++ * \retval -1 failure
++ * \since 1.6.3
++ *
++ * The pointer to the event will get updated with the new location for the event
++ * that now contains the appended information element. If the re-allocation of
++ * the memory for this event fails, it will be set to NULL.
++ */
++int ast_event_append_ie_bitflags(struct ast_event **event, enum ast_event_ie_type ie_type,
++ uint32_t bitflags);
++
++/*!
+ * \brief Append an information element that has a raw payload
+ *
+ * \param event the event that the IE will be appended to
+@@ -477,6 +509,18 @@
+ uint32_t ast_event_get_ie_uint(const struct ast_event *event, enum ast_event_ie_type ie_type);
+
+ /*!
++ * \brief Get the value of an information element that has a bitflags payload
++ *
++ * \param event The event to get the IE from
++ * \param ie_type the type of information element to retrieve
++ *
++ * \return This returns the payload of the information element with the given type.
++ * However, an IE with a payload of 0, and the case where no IE is found
++ * yield the same return value.
++ */
++uint32_t ast_event_get_ie_bitflags(const struct ast_event *event, enum ast_event_ie_type ie_type);
++
++/*!
+ * \brief Get the value of an information element that has a string payload
+ *
+ * \param event The event to get the IE from
+@@ -615,7 +659,7 @@
+ enum ast_event_ie_type ast_event_iterator_get_ie_type(struct ast_event_iterator *iterator);
+
+ /*!
+- * \brief Get the value of the current IE in the ierator as an integer payload
++ * \brief Get the value of the current IE in the iterator as an integer payload
+ *
+ * \param iterator The iterator instance
+ *
+@@ -624,6 +668,15 @@
+ uint32_t ast_event_iterator_get_ie_uint(struct ast_event_iterator *iterator);
+
+ /*!
++ * \brief Get the value of the current IE in the iterator as a bitflags payload
++ *
++ * \param iterator The iterator instance
++ *
++ * \return This returns the payload of the information element as bitflags.
++ */
++uint32_t ast_event_iterator_get_ie_bitflags(struct ast_event_iterator *iterator);
++
++/*!
+ * \brief Get the value of the current IE in the iterator as a string payload
+ *
+ * \param iterator The iterator instance
+Index: include/asterisk/event_defs.h
+===================================================================
+--- a/include/asterisk/event_defs.h (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/include/asterisk/event_defs.h (.../trunk) (revision 202568)
+@@ -137,6 +137,8 @@
+ AST_EVENT_IE_PLTYPE_STR,
+ /*! Raw data, compared with memcmp */
+ AST_EVENT_IE_PLTYPE_RAW,
++ /*! Bit flags (unsigned integer, compared using boolean logic) */
++ AST_EVENT_IE_PLTYPE_BITFLAGS,
+ };
+
+ /*!
+Index: include/asterisk/compat.h
+===================================================================
+--- a/include/asterisk/compat.h (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/include/asterisk/compat.h (.../trunk) (revision 202568)
+@@ -187,10 +187,10 @@
+ #define GLOB_ABORTED GLOB_ABEND
+ #endif
+ #include <glob.h>
+-#ifdef SOLARIS
++#if !defined(HAVE_GLOB_NOMAGIC) || !defined(HAVE_GLOB_BRACE)
+ #define MY_GLOB_FLAGS GLOB_NOCHECK
+ #else
+-#define MY_GLOB_FLAGS (GLOB_NOMAGIC|GLOB_BRACE)
++#define MY_GLOB_FLAGS (GLOB_NOMAGIC | GLOB_BRACE)
+ #endif
+
+ #endif
+Index: include/asterisk/ast_expr.h
+===================================================================
+--- a/include/asterisk/ast_expr.h (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/include/asterisk/ast_expr.h (.../trunk) (revision 202568)
+@@ -31,8 +31,24 @@
+ extern "C" {
+ #endif
+
++/*!\brief Evaluate the given expression
++ * \param expr An expression
++ * \param buf Result buffer
++ * \param length Size of the result buffer, in bytes
++ * \param chan Channel to use for evaluating included dialplan functions, if any
++ * \return Length of the result string, in bytes
++ */
+ int ast_expr(char *expr, char *buf, int length, struct ast_channel *chan);
+
++/*!\brief Evaluate the given expression
++ * \param str Dynamic result buffer
++ * \param maxlen <0 if the size of the buffer should remain constant, >0 if the size of the buffer should expand to that many bytes, maximum, or 0 for unlimited expansion of the result buffer
++ * \param chan Channel to use for evaluating included dialplan functions, if any
++ * \param expr An expression
++ * \return Length of the result string, in bytes
++ */
++int ast_str_expr(struct ast_str **str, ssize_t maxlen, struct ast_channel *chan, char *expr);
++
+ #if defined(__cplusplus) || defined(c_plusplus)
+ }
+ #endif
+Index: include/asterisk/module.h
+===================================================================
+--- a/include/asterisk/module.h (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/include/asterisk/module.h (.../trunk) (revision 202568)
+@@ -58,10 +58,11 @@
+ };
+
+ enum ast_module_load_result {
+- AST_MODULE_LOAD_SUCCESS = 0, /*!< Module loaded and configured */
+- AST_MODULE_LOAD_DECLINE = 1, /*!< Module is not configured */
+- AST_MODULE_LOAD_SKIP = 2, /*!< Module was skipped for some reason */
+- AST_MODULE_LOAD_FAILURE = -1, /*!< Module could not be loaded properly */
++ AST_MODULE_LOAD_SUCCESS = 0, /*!< Module loaded and configured */
++ AST_MODULE_LOAD_DECLINE = 1, /*!< Module is not configured */
++ AST_MODULE_LOAD_SKIP = 2, /*!< Module was skipped for some reason */
++ AST_MODULE_LOAD_PRIORITY = 3, /*!< Module is not loaded yet, but is added to prioity heap */
++ AST_MODULE_LOAD_FAILURE = -1, /*!< Module could not be loaded properly */
+ };
+
+ /*!
+@@ -423,7 +424,7 @@
+ * \retval 0 success
+ * \retval -1 failure.
+ */
+-int ast_register_application2(const char *app, int (*execute)(struct ast_channel *, void *),
++int ast_register_application2(const char *app, int (*execute)(struct ast_channel *, const char *),
+ const char *synopsis, const char *description, void *mod);
+
+ /*!
+Index: include/asterisk/monitor.h
+===================================================================
+--- a/include/asterisk/monitor.h (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/include/asterisk/monitor.h (.../trunk) (revision 202568)
+@@ -51,27 +51,34 @@
+ };
+
+ /* Start monitoring a channel */
+-AST_OPTIONAL_API(int, ast_monitor_start, (struct ast_channel *chan, const char
+- *format_spec, const char *fname_base, int need_lock, int stream_action),
+- { return -1; });
++AST_OPTIONAL_API(int, ast_monitor_start,
++ (struct ast_channel *chan, const char *format_spec,
++ const char *fname_base, int need_lock, int stream_action),
++ { return -1; });
+
+ /* Stop monitoring a channel */
+-AST_OPTIONAL_API(int, ast_monitor_stop, (struct ast_channel *chan, int
+- need_lock), { return -1; });
++AST_OPTIONAL_API(int, ast_monitor_stop,
++ (struct ast_channel *chan, int need_lock),
++ { return -1; });
+
+ /* Change monitoring filename of a channel */
+-AST_OPTIONAL_API(int, ast_monitor_change_fname, (struct ast_channel *chan,
+- const char *fname_base, int need_lock), { return -1; });
++AST_OPTIONAL_API(int, ast_monitor_change_fname,
++ (struct ast_channel *chan, const char *fname_base,
++ int need_lock),
++ { return -1; });
+
+-AST_OPTIONAL_API(void, ast_monitor_setjoinfiles, (struct ast_channel *chan,
+- int turnon), { return; });
++AST_OPTIONAL_API(void, ast_monitor_setjoinfiles,
++ (struct ast_channel *chan, int turnon),
++ { return; });
+
+ /* Pause monitoring of a channel */
+-AST_OPTIONAL_API(int, ast_monitor_pause, (struct ast_channel *chan),
+- { return -1; });
++AST_OPTIONAL_API(int, ast_monitor_pause,
++ (struct ast_channel *chan),
++ { return -1; });
+
+ /* Unpause monitoring of a channel */
+-AST_OPTIONAL_API(int, ast_monitor_unpause, (struct ast_channel *chan),
+- { return -1; });
++AST_OPTIONAL_API(int, ast_monitor_unpause,
++ (struct ast_channel *chan),
++ { return -1; });
+
+ #endif /* _ASTERISK_MONITOR_H */
+Index: include/asterisk/frame.h
+===================================================================
+--- a/include/asterisk/frame.h (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/include/asterisk/frame.h (.../trunk) (revision 202568)
+@@ -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)
+
+@@ -381,6 +391,21 @@
+ */
+ #define AST_OPTION_T38_STATE 10
+
++/*! Request that the channel driver deliver frames in a specific format */
++#define AST_OPTION_FORMAT_READ 11
++
++/*! Request that the channel driver be prepared to accept frames in a specific format */
++#define AST_OPTION_FORMAT_WRITE 12
++
++/*! Request that the channel driver make two channels of the same tech type compatible if possible */
++#define AST_OPTION_MAKE_COMPATIBLE 13
++
++/*! Get or set the digit detection state of the channel */
++#define AST_OPTION_DIGIT_DETECT 14
++
++/*! Get or set the fax tone detection state of the channel */
++#define AST_OPTION_FAX_DETECT 15
++
+ struct oprmode {
+ struct ast_channel *peer;
+ int mode;
+@@ -430,9 +455,9 @@
+ #endif
+
+ /*!
+- * \brief Frees a frame
++ * \brief Frees a frame or list of frames
+ *
+- * \param fr Frame to free
++ * \param fr Frame to free, or head of list to free
+ * \param cache Whether to consider this frame for frame caching
+ */
+ void ast_frame_free(struct ast_frame *fr, int cache);
+@@ -446,6 +471,11 @@
+ * data malloc'd. If you need to store frames, say for queueing, then
+ * you should call this function.
+ * \return Returns a frame on success, NULL on error
++ * \note This function may modify the frame passed to it, so you must
++ * not assume the frame will be intact after the isolated frame has
++ * been produced. In other words, calling this function on a frame
++ * should be the last operation you do with that frame before freeing
++ * it (or exiting the block, if the frame is on the stack.)
+ */
+ struct ast_frame *ast_frisolate(struct ast_frame *fr);
+
+Index: include/asterisk/autochan.h
+===================================================================
+--- a/include/asterisk/autochan.h (.../tags/1.6.2.0-beta3) (revision 0)
++++ b/include/asterisk/autochan.h (.../trunk) (revision 202568)
+@@ -0,0 +1,112 @@
++/*
++ * Asterisk -- An open source telephony toolkit.
++ *
++ * Copyright (C) 2009, 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
++ * \brief "smart" channels that update automatically if a channel is masqueraded
++ *
++ * \author Mark Michelson <mmichelson@digium.com>
++ */
++
++#include "asterisk.h"
++#include "asterisk/linkedlists.h"
++
++#ifndef _ASTERISK_AUTOCHAN_H
++#define _ASTERISK_AUTOCHAN_H
++
++struct ast_autochan {
++ struct ast_channel *chan;
++ AST_LIST_ENTRY(ast_autochan) list;
++};
++
++/*!
++ * \par Just what the $!@# is an autochan?
++ *
++ * An ast_autochan is a structure which contains an ast_channel. The pointer
++ * inside an autochan has the ability to update itself if the channel it points
++ * to is masqueraded into a different channel.
++ *
++ * This has a great benefit for any application or service which creates a thread
++ * outside of the channel's main operating thread which keeps a pointer to said
++ * channel. when a masquerade occurs on the channel, the autochan's chan pointer
++ * will automatically update to point to the new channel.
++ *
++ * Some rules for autochans
++ *
++ * 1. If you are going to use an autochan, then be sure to always refer to the
++ * channel using the chan pointer inside the autochan if possible, since this is
++ * the pointer that will be updated during a masquerade.
++ *
++ * 2. If you are going to save off a pointer to the autochan's chan, then be sure
++ * to save off the pointer using ast_channel_ref and to unref the channel when you
++ * are finished with the pointer. If you do not do this and a masquerade occurs on
++ * the channel, then it is possible that your saved pointer will become invalid.
++ */
++
++/*!
++ * \brief set up a new ast_autochan structure
++ *
++ * \details
++ * Allocates and initializes an ast_autochan, sets the
++ * autochan's chan pointer to point to the chan parameter, and
++ * adds the autochan to the global list of autochans. The newly-
++ * created autochan is returned to the caller. This function will
++ * cause the refcount of chan to increase by 1.
++ *
++ * \param chan The channel our new autochan will point to
++ *
++ * \note autochans must be freed using ast_autochan_destroy
++ *
++ * \retval NULL Failure
++ * \retval non-NULL success
++ */
++struct ast_autochan *ast_autochan_setup(struct ast_channel *chan);
++
++/*!
++ * \brief destroy an ast_autochan structure
++ *
++ * \details
++ * Removes the passed-in autochan from the list of autochans and
++ * unrefs the channel that is pointed to. Also frees the autochan
++ * struct itself. This function will unref the channel reference
++ * which was made in ast_autochan_setup
++ *
++ * \param autochan The autochan that you wish to destroy
++ *
++ * \retval void
++ */
++void ast_autochan_destroy(struct ast_autochan *autochan);
++
++/*!
++ * \brief Switch what channel autochans point to
++ *
++ * \details
++ * Traverses the list of autochans. All autochans which point to
++ * old_chan will be updated to point to new_chan instead. Currently
++ * this is only called from ast_do_masquerade in channel.c.
++ *
++ * \pre Both channels must be locked before calling this function.
++ *
++ * \param old_chan The channel that autochans may currently point to
++ * \param new_chan The channel that we want to point those autochans to now
++ *
++ * \retval void
++ */
++void ast_autochan_new_channel(struct ast_channel *old_chan, struct ast_channel *new_chan);
++
++#endif /* _ASTERISK_AUTOCHAN_H */
+
+Property changes on: include/asterisk/autochan.h
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+Added: svn:mime-type
+ + text/plain
+Added: svn:keywords
+ + Author Date Id Revision
+
+Index: include/asterisk/taskprocessor.h
+===================================================================
+--- a/include/asterisk/taskprocessor.h (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/include/asterisk/taskprocessor.h (.../trunk) (revision 202568)
+@@ -73,7 +73,7 @@
+ * TPS_REF_IF_EXISTS reference type is specified and the taskprocessor does not exist
+ * \since 1.6.1
+ */
+-struct ast_taskprocessor *ast_taskprocessor_get(char *name, enum ast_tps_options create);
++struct ast_taskprocessor *ast_taskprocessor_get(const char *name, enum ast_tps_options create);
+
+ /*! \brief Unreference the specified taskprocessor and its reference count will decrement.
+ *
+Index: include/asterisk/astobj2.h
+===================================================================
+--- a/include/asterisk/astobj2.h (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/include/asterisk/astobj2.h (.../trunk) (revision 202568)
+@@ -404,24 +404,24 @@
+
+ #if defined(REF_DEBUG)
+
+-#define ao2_t_alloc(data_size, destructor_fn, debug_msg) _ao2_alloc_debug((data_size), (destructor_fn), (debug_msg), __FILE__, __LINE__, __PRETTY_FUNCTION__, 1)
+-#define ao2_alloc(data_size, destructor_fn) _ao2_alloc_debug((data_size), (destructor_fn), "", __FILE__, __LINE__, __PRETTY_FUNCTION__, 1)
++#define ao2_t_alloc(data_size, destructor_fn, debug_msg) __ao2_alloc_debug((data_size), (destructor_fn), (debug_msg), __FILE__, __LINE__, __PRETTY_FUNCTION__, 1)
++#define ao2_alloc(data_size, destructor_fn) __ao2_alloc_debug((data_size), (destructor_fn), "", __FILE__, __LINE__, __PRETTY_FUNCTION__, 1)
+
+ #elif defined(__AST_DEBUG_MALLOC)
+
+-#define ao2_t_alloc(data_size, destructor_fn, debug_msg) _ao2_alloc_debug((data_size), (destructor_fn), (debug_msg), __FILE__, __LINE__, __PRETTY_FUNCTION__, 0)
+-#define ao2_alloc(data_size, destructor_fn) _ao2_alloc_debug((data_size), (destructor_fn), "", __FILE__, __LINE__, __PRETTY_FUNCTION__, 0)
++#define ao2_t_alloc(data_size, destructor_fn, debug_msg) __ao2_alloc_debug((data_size), (destructor_fn), (debug_msg), __FILE__, __LINE__, __PRETTY_FUNCTION__, 0)
++#define ao2_alloc(data_size, destructor_fn) __ao2_alloc_debug((data_size), (destructor_fn), "", __FILE__, __LINE__, __PRETTY_FUNCTION__, 0)
+
+ #else
+
+-#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))
++#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,
++void *__ao2_alloc_debug(const size_t data_size, ao2_destructor_fn destructor_fn, char *tag,
+ const char *file, int line, const char *funcname, int ref_debug);
+-void *_ao2_alloc(const size_t data_size, ao2_destructor_fn destructor_fn);
++void *__ao2_alloc(const size_t data_size, ao2_destructor_fn destructor_fn);
+
+ /*! @} */
+
+@@ -450,19 +450,18 @@
+
+ #ifdef REF_DEBUG
+
+-#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__)
++#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(o,delta,tag) _ao2_ref((o), (delta))
+-#define ao2_ref(o,delta) _ao2_ref((o), (delta))
++#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);
+
+ /*! @} */
+
+@@ -475,8 +474,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
+@@ -488,8 +487,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
+@@ -501,8 +500,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
+
+ /*!
+@@ -707,27 +706,27 @@
+
+ #if defined(REF_DEBUG)
+
+-#define ao2_t_container_alloc(arg1,arg2,arg3,arg4) _ao2_container_alloc_debug((arg1), (arg2), (arg3), (arg4), __FILE__, __LINE__, __PRETTY_FUNCTION__, 1)
+-#define ao2_container_alloc(arg1,arg2,arg3) _ao2_container_alloc_debug((arg1), (arg2), (arg3), "", __FILE__, __LINE__, __PRETTY_FUNCTION__, 1)
++#define ao2_t_container_alloc(arg1,arg2,arg3,arg4) __ao2_container_alloc_debug((arg1), (arg2), (arg3), (arg4), __FILE__, __LINE__, __PRETTY_FUNCTION__, 1)
++#define ao2_container_alloc(arg1,arg2,arg3) __ao2_container_alloc_debug((arg1), (arg2), (arg3), "", __FILE__, __LINE__, __PRETTY_FUNCTION__, 1)
+
+ #elif defined(__AST_DEBUG_MALLOC)
+
+-#define ao2_t_container_alloc(arg1,arg2,arg3,arg4) _ao2_container_alloc_debug((arg1), (arg2), (arg3), (arg4), __FILE__, __LINE__, __PRETTY_FUNCTION__, 0)
+-#define ao2_container_alloc(arg1,arg2,arg3) _ao2_container_alloc_debug((arg1), (arg2), (arg3), "", __FILE__, __LINE__, __PRETTY_FUNCTION__, 0)
++#define ao2_t_container_alloc(arg1,arg2,arg3,arg4) __ao2_container_alloc_debug((arg1), (arg2), (arg3), (arg4), __FILE__, __LINE__, __PRETTY_FUNCTION__, 0)
++#define ao2_container_alloc(arg1,arg2,arg3) __ao2_container_alloc_debug((arg1), (arg2), (arg3), "", __FILE__, __LINE__, __PRETTY_FUNCTION__, 0)
+
+ #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,
+- ao2_hash_fn *hash_fn, ao2_callback_fn *cmp_fn);
+-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,
+- int ref_debug);
++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,
++ ao2_hash_fn *hash_fn, ao2_callback_fn *cmp_fn,
++ char *tag, char *file, int line, const char *funcname,
++ int ref_debug);
+
+ /*! \brief
+ * Returns the number of elements in a container.
+@@ -762,18 +761,18 @@
+ */
+ #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 a container
+@@ -793,18 +792,18 @@
+ */
+ #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 */
+@@ -896,22 +895,20 @@
+ */
+ #ifdef REF_DEBUG
+
+-#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__)
++#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(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))
++#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,
+- 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);
++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, enum search_flags flags, ao2_callback_fn *cb_fn, void *arg);
++
+ /*! @} */
+
+ /*! \brief
+@@ -930,36 +927,41 @@
+ * \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,
+- 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);
+
++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))
++#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
+ *
+@@ -1060,18 +1062,18 @@
+
+ #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/cli.h
+===================================================================
+--- a/include/asterisk/cli.h (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/include/asterisk/cli.h (.../trunk) (revision 202568)
+@@ -97,7 +97,7 @@
+ \code
+ static char *test_new_cli(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+ {
+- static char *choices = { "one", "two", "three", NULL };
++ static const char * const choices[] = { "one", "two", "three", NULL };
+
+ switch (cmd) {
+ case CLI_INIT:
+@@ -128,7 +128,7 @@
+ /*! \brief calling arguments for new-style handlers.
+ * \arg \ref CLI_command_API
+ */
+-enum ast_cli_fn {
++enum ast_cli_command {
+ CLI_INIT = -2, /* return the usage string */
+ CLI_GENERATE = -3, /* behave as 'generator', remap argv to struct ast_cli_args */
+ CLI_HANDLER = -4, /* run the normal handler */
+@@ -136,27 +136,25 @@
+
+ /* argument for new-style CLI handler */
+ struct ast_cli_args {
+- int fd;
+- int argc;
+- char **argv;
++ const int fd;
++ const int argc;
++ const char * const *argv;
+ const char *line; /* the current input line */
+ const char *word; /* the word we want to complete */
+- int pos; /* position of the word to complete */
+- int n; /* the iteration count (n-th entry we generate) */
++ const int pos; /* position of the word to complete */
++ const int n; /* the iteration count (n-th entry we generate) */
+ };
+
+-struct ast_cli_entry;
+-typedef char *(*cli_fn)(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
+-
+ /*! \brief descriptor for a cli entry.
+ * \arg \ref CLI_command_API
+ */
+ struct ast_cli_entry {
+- char * const cmda[AST_MAX_CMD_LEN]; /*!< words making up the command.
+- * set the first entry to NULL for a new-style entry. */
++ const char * const cmda[AST_MAX_CMD_LEN]; /*!< words making up the command.
++ * set the first entry to NULL for a new-style entry.
++ */
+
+- const char *summary; /*!< Summary of the command (< 60 characters) */
+- const char *usage; /*!< Detailed usage information */
++ const char * const summary; /*!< Summary of the command (< 60 characters) */
++ const char * usage; /*!< Detailed usage information */
+
+ int inuse; /*!< For keeping track of usage */
+ struct module *module; /*!< module this belongs to */
+@@ -166,7 +164,7 @@
+ */
+ int args; /*!< number of non-null entries in cmda */
+ char *command; /*!< command, non-null for new-style entries */
+- cli_fn handler;
++ char *(*handler)(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
+ /*! For linking */
+ AST_LIST_ENTRY(ast_cli_entry) list;
+ };
+@@ -183,7 +181,7 @@
+ \code
+ char *my_generate(const char *line, const char *word, int pos, int n)
+ {
+- static char *choices = { "one", "two", "three", NULL };
++ static const char * const choices[] = { "one", "two", "three", NULL };
+ if (pos == 2)
+ return ast_cli_complete(word, choices, n);
+ else
+@@ -191,7 +189,7 @@
+ }
+ \endcode
+ */
+-char *ast_cli_complete(const char *word, char *const choices[], int pos);
++char *ast_cli_complete(const char *word, const char * const choices[], int pos);
+
+ /*!
+ * \brief Interprets a command
+Index: include/asterisk/calendar.h
+===================================================================
+--- a/include/asterisk/calendar.h (.../tags/1.6.2.0-beta3) (revision 0)
++++ b/include/asterisk/calendar.h (.../trunk) (revision 202568)
+@@ -0,0 +1,187 @@
++/*
++ * Asterisk -- An open source telephony toolkit.
++ *
++ * Copyright (C) 2008 - 2009, Digium, Inc.
++ *
++ * Terry Wilson <twilson@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_CALENDAR_H
++#define _ASTERISK_CALENDAR_H
++
++#include "asterisk.h"
++#include "asterisk/stringfields.h"
++#include "asterisk/config.h"
++#include "asterisk/linkedlists.h"
++#include "asterisk/lock.h"
++
++/*! \file calendar.h
++ * \brief A general API for managing calendar events with Asterisk
++ *
++ * \author Terry Wilson <twilson@digium.com>
++ *
++ * \note This API implements an abstraction for handling different calendaring
++ * technologies in Asterisk. The services provided by the API are a dialplan
++ * function to query whether or not a calendar is busy at the present time, a
++ * adialplan function to query specific information about events in a time range,
++ * a devicestate provider, and notification of calendar events through execution
++ * of dialplan apps or dialplan logic at a specific context and extension. The
++ * information available through the CALENDAR_EVENT() dialplan function are:
++ *
++ * SUMMARY, DESCRIPTION, ORGANIZER, LOCATION
++ * CALENDAR, UID, START, END, and BUSYSTATE
++ *
++ * BUSYSTATE can have the values 0 (free), 1 (tentatively busy), or 2 (busy)
++ *
++ * Usage
++ * All calendaring configuration data is located in calendar.conf and is only read
++ * directly by the Calendaring API. Each calendar technology resource must register
++ * a load_calendar callback which will be passed an ast_calendar_load_data structure.
++ * The load_calendar callback function should then set the values it needs from this
++ * cfg, load the calendar data, and then loop updating the calendar data and events
++ * baesd on the refresh interval in the ast_calendar object. Each call to
++ * the load_calendar callback will be will run in its own thread.
++ *
++ * Updating events involves creating an astobj2 container of new events and passing
++ * it to the API through ast_calendar_merge_events.
++ *
++ * Calendar technology resource modules must also register an unref_calendar callback
++ * which will only be called when the resource module calls ast_calendar_unregister()
++ * to unregister that module's calendar type (usually done in module_unload())
++ */
++
++extern struct ast_config *ast_calendar_config;
++
++struct ast_calendar;
++struct ast_calendar_event;
++
++/*! \brief Individual calendaring technology data */
++struct ast_calendar_tech {
++ const char *type;
++ const char *description;
++ const char *module;
++ int (* is_busy)(struct ast_calendar *calendar); /*!< Override default busy determination */
++ void *(* load_calendar)(void *data); /*!< Create private structure, add calendar events, etc. */
++ void *(* unref_calendar)(void *obj); /*!< Function to be called to free the private structure */
++ int (* write_event)(struct ast_calendar_event *event); /*!< Function for writing an event to the calendar */
++ AST_LIST_ENTRY(ast_calendar_tech) list;
++};
++
++enum ast_calendar_busy_state {
++ AST_CALENDAR_BS_FREE = 0,
++ AST_CALENDAR_BS_BUSY_TENTATIVE,
++ AST_CALENDAR_BS_BUSY,
++};
++
++struct ast_calendar_attendee {
++ char *data;
++ AST_LIST_ENTRY(ast_calendar_attendee) next;
++};
++
++/* \brief Calendar events */
++struct ast_calendar_event {
++ AST_DECLARE_STRING_FIELDS(
++ AST_STRING_FIELD(summary);
++ AST_STRING_FIELD(description);
++ AST_STRING_FIELD(organizer);
++ AST_STRING_FIELD(location);
++ AST_STRING_FIELD(uid);
++ );
++ struct ast_calendar *owner; /*!< The calendar that owns this event */
++ time_t start; /*!< Start of event (UTC) */
++ time_t end; /*!< End of event (UTC) */
++ time_t alarm; /*!< Time for event notification */
++ enum ast_calendar_busy_state busy_state; /*!< The busy status of the event */
++ int notify_sched; /*!< The sched for event notification */
++ int bs_start_sched; /*!< The sched for changing the device state at the start of an event */
++ int bs_end_sched; /*!< The sched for changing the device state at the end of an event */
++ AST_LIST_HEAD_NOLOCK(attendees, ast_calendar_attendee) attendees;
++};
++
++/*! \brief Asterisk calendar structure */
++struct ast_calendar {
++ const struct ast_calendar_tech *tech;
++ void *tech_pvt;
++ AST_DECLARE_STRING_FIELDS(
++ AST_STRING_FIELD(name); /*!< Name from config file [name] */
++ AST_STRING_FIELD(notify_channel); /*!< Channel to use for notification */
++ AST_STRING_FIELD(notify_context); /*!< Optional context to execute from for notification */
++ AST_STRING_FIELD(notify_extension); /*!< Optional extension to execute from for notification */
++ AST_STRING_FIELD(notify_app); /*!< Optional dialplan app to execute for notification */
++ AST_STRING_FIELD(notify_appdata); /*!< Optional arguments for dialplan app */
++ );
++ int autoreminder; /*!< If set, override any calendar_tech specific notification times and use this time (in mins) */
++ int notify_waittime; /*!< Maxiumum time to allow for a notification attempt */
++ int refresh; /*!< When to refresh the calendar events */
++ int timeframe; /*!< Span (in mins) of calendar data to pull with each request */
++ pthread_t thread; /*!< The thread that the calendar is loaded/updated in */
++ ast_cond_t unload;
++ int unloading:1;
++ int pending_deletion:1;
++ struct ao2_container *events; /*!< The events that are known at this time */
++};
++
++/*! \brief Register a new calendar technology
++ *
++ * \param tech calendar technology to register
++ *
++ * \retval 0 success
++ * \retval -1 failure
++ */
++int ast_calendar_register(struct ast_calendar_tech *tech);
++
++/*! \brief Unregister a new calendar technology
++ *
++ * \param tech calendar technology to unregister
++ *
++ * \retval 0 success
++ * \retva -1 failure
++ */
++void ast_calendar_unregister(struct ast_calendar_tech *tech);
++
++/*! \brief Allocate an astobj2 ast_calendar_event object
++ *
++ * \param cal calendar to allocate an event for
++ *
++ * \return a new, initialized calendar event
++ */
++struct ast_calendar_event *ast_calendar_event_alloc(struct ast_calendar *cal);
++
++/*! \brief Allocate an astobj2 container for ast_calendar_event objects
++ *
++ * \return a new event container
++ */
++struct ao2_container *ast_calendar_event_container_alloc(void);
++
++/*! \brief Add an event to the list of events for a calendar
++ *
++ * \param cal calendar containing the events to be merged
++ * \param new_events an oa2 container of events to be merged into cal->events
++ */
++void ast_calendar_merge_events(struct ast_calendar *cal, struct ao2_container *new_events);
++
++/*! \brief Unreference an ast_calendar_event
++ *
++ * \param event event to unref
++ *
++ * \return NULL
++ */
++struct ast_calendar_event *ast_calendar_unref_event(struct ast_calendar_event *event);
++
++/*! \brief Remove all events from calendar
++ *
++ * \param cal calendar whose events need to be cleared
++ */
++void ast_calendar_clear_events(struct ast_calendar *cal);
++
++#endif /* _ASTERISK_CALENDAR_H */
+
+Property changes on: include/asterisk/calendar.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.2.0-beta3) (revision 202568)
++++ b/include/asterisk/optional_api.h (.../trunk) (revision 202568)
+@@ -32,14 +32,14 @@
+ *
+ * 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
++ * platform that supports special compiler and dynamic linker attributes.
++ * If so the API function will actually be 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
++ * various methods 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.
+ *
+@@ -57,13 +57,25 @@
+ * safely know that the API is not available, and to avoid using any
+ * other APIs from the not-present provider.
+ *
++ * In addition to this declaration in the header file, the actual definition of
++ * the API function must use the AST_OPTIONAL_API_NAME macro to (possibly)
++ * modify the real name of the API function, depending on the specific
++ * implementation requirements. The corresponding example from res_agi.c:
++ *
++ * \code
++ * int AST_OPTIONAL_API_NAME(ast_agi_register)(struct ast_module *mod, agi_command *cmd)
++ * {
++ * ...
++ * }
++ * \endcode
++ *
+ * 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,
++ * \note If the platform does not provide adequate resources,
+ * 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
+@@ -83,17 +95,115 @@
+ */
+ #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;
++
++#if defined(HAVE_ATTRIBUTE_weak_import)
++
++/*
++ * This is the Darwin (Mac OS/X) implementation, that only provides the
++ * 'weak_import' compiler attribute for weak symbols. On this platform,
++ *
++ * - The module providing the API will only provide a '__' prefixed version
++ * of the API function to other modules (this will be hidden from the other
++ * modules by the macros), so any modules compiled against older versions
++ * of the module that provided a non-prefixed version of the API function
++ * will fail to link at runtime.
++ * - In the API module itself, access to the API function without using a
++ * prefixed name is provided by a static pointer variable that holds the
++ * function address.
++ * - 'Consumer' modules of the API will use a combination of a weak_import
++ * symbol, a local stub function, a pointer variable and a constructor function
++ * (which initializes that pointer variable as the module is being loaded)
++ * to provide safe, optional access to the API function without any special
++ * code being required.
++ */
++
++#define AST_OPTIONAL_API_NAME(name) __##name
++
++#if defined(AST_API_MODULE)
++
++#define AST_OPTIONAL_API(result, name, proto, stub) \
++ result AST_OPTIONAL_API_NAME(name) proto; \
++ static attribute_unused typeof(AST_OPTIONAL_API_NAME(name)) * const name = AST_OPTIONAL_API_NAME(name);
++
++#define AST_OPTIONAL_API_ATTR(result, attr, name, proto, stub) \
++ result __attribute__((attr)) AST_OPTIONAL_API_NAME(name) proto; \
++ static attribute_unused typeof(AST_OPTIONAL_API_NAME(name)) * const name = AST_OPTIONAL_API_NAME(name);
++
+ #else
++
++#define AST_OPTIONAL_API(result, name, proto, stub) \
++ static result __stub__##name proto stub; \
++ __attribute__((weak_import)) typeof(__stub__##name) AST_OPTIONAL_API_NAME(name); \
++ static attribute_unused typeof(__stub__##name) * name; \
++ static void __attribute__((constructor)) __init__##name(void) { name = AST_OPTIONAL_API_NAME(name) ? : __stub__##name; }
++
++#define AST_OPTIONAL_API_ATTR(result, attr, name, proto, stub) \
++ static __attribute__((attr)) result __stub__##name proto stub; \
++ __attribute__((attr, weak_import)) typeof(__stub__##name) AST_OPTIONAL_API_NAME(name); \
++ static attribute_unused __attribute__((attr)) typeof(__stub__##name) * name; \
++ static void __attribute__((constructor)) __init__##name(void) { name = AST_OPTIONAL_API_NAME(name) ? : __stub__##name; }
++
++
++#endif
++
++/* End of Darwin (Mac OS/X) implementation */
++
++#elif defined(HAVE_ATTRIBUTE_weakref)
++
++/*
++ * This is the generic GCC implementation, used when the 'weakref'
++ * compiler attribute is available. On these platforms:
++ *
++ * - The module providing the API will provide a '__' prefixed version
++ * of the API function to other modules (this will be hidden from the other
++ * modules by the macros), and also a non-prefixed alias so that modules
++ * compiled against older versions of the module that provided a non-prefixed
++ * version of the API function will continue to link properly.
++ * - In the API module itself, access to the API function without using a
++ * prefixed name is provided by the non-prefixed alias described above.
++ * - 'Consumer' modules of the API will use a combination of a weakref
++ * symbol, a local stub function, a pointer variable and a constructor function
++ * (which initializes that pointer variable as the module is being loaded)
++ * to provide safe, optional access to the API function without any special
++ * code being required.
++ */
++
++#define AST_OPTIONAL_API_NAME(name) __##name
++
++#if defined(AST_API_MODULE)
++
++#define AST_OPTIONAL_API(result, name, proto, stub) \
++ result AST_OPTIONAL_API_NAME(name) proto; \
++ __attribute__((alias(__stringify(AST_OPTIONAL_API_NAME(name))))) typeof(AST_OPTIONAL_API_NAME(name)) name;
++
++#define AST_OPTIONAL_API_ATTR(result, attr, name, proto, stub) \
++ result __attribute__((attr)) AST_OPTIONAL_API_NAME(name) proto; \
++ __attribute__((alias(__stringify(AST_OPTIONAL_API_NAME(name))))) typeof(AST_OPTIONAL_API_NAME(name)) name;
++
++#else
++
++#define AST_OPTIONAL_API(result, name, proto, stub) \
++ static result __stub__##name proto stub; \
++ static __attribute__((weakref(__stringify(AST_OPTIONAL_API_NAME(name))))) typeof(__stub__##name) __ref__##name; \
++ static attribute_unused typeof(__stub__##name) * name; \
++ static void __attribute__((constructor)) __init__##name(void) { name = __ref__##name ? : __stub__##name; }
++
++#define AST_OPTIONAL_API_ATTR(result, attr, name, proto, stub) \
++ static __attribute__((attr)) result __stub__##name proto stub; \
++ static __attribute__((attr, weakref(__stringify(AST_OPTIONAL_API_NAME(name))))) typeof(__stub__##name) __ref__##name; \
++ static attribute_unused __attribute__((attr)) typeof(__stub__##name) * name; \
++ static void __attribute__((constructor)) __init__##name(void) { name = __ref__##name ? : __stub__##name; }
++
++#endif
++
++/* End of GCC implementation */
++
++#else
++
++/* This is the non-optional implementation. */
++
++#define AST_OPTIONAL_API_NAME(name) name
++
+ /*!
+ * \brief Define an optional API function
+ *
+@@ -108,7 +218,8 @@
+ * { return AST_OPTIONAL_API_UNAVAILABLE; });
+ * \endcode
+ */
+-#define AST_OPTIONAL_API(result, name, proto, stub) result name proto;
++#define AST_OPTIONAL_API(result, name, proto, stub) result AST_OPTIONAL_API_NAME(name) proto
++
+ /*!
+ * \brief Define an optional API function with compiler attributes
+ *
+@@ -118,7 +229,10 @@
+ * \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;
++#define AST_OPTIONAL_API_ATTR(result, attr, name, proto, stub) result __attribute__((attr)) AST_OPTIONAL_API_NAME(name) proto
++
++/* End of non-optional implementation */
++
+ #endif
+
+ #undef AST_API_MODULE
+Index: include/asterisk/logger.h
+===================================================================
+--- a/include/asterisk/logger.h (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/include/asterisk/logger.h (.../trunk) (revision 202568)
+@@ -123,17 +123,6 @@
+ #endif
+ #define AST_LOG_DEBUG __LOG_DEBUG, _A_
+
+-#ifdef LOG_EVENT
+-#undef LOG_EVENT
+-#endif
+-#define __LOG_EVENT 1
+-#define LOG_EVENT __LOG_EVENT, _A_
+-
+-#ifdef AST_LOG_EVENT
+-#undef AST_LOG_EVENT
+-#endif
+-#define AST_LOG_EVENT __LOG_EVENT, _A_
+-
+ #ifdef LOG_NOTICE
+ #undef LOG_NOTICE
+ #endif
+@@ -206,6 +195,37 @@
+ unsigned int ast_verbose_get_by_file(const char *file);
+
+ /*!
++ * \brief Register a new logger level
++ * \param name The name of the level to be registered
++ * \retval -1 if an error occurs
++ * \retval non-zero level to be used with ast_log for sending messages to this level
++ * \since 1.6.3
++ */
++int ast_logger_register_level(const char *name);
++
++/*!
++ * \brief Unregister a previously registered logger level
++ * \param name The name of the level to be unregistered
++ * \return nothing
++ * \since 1.6.3
++ */
++void ast_logger_unregister_level(const char *name);
++
++/*!
++ * \brief Send a log message to a dynamically registered log level
++ * \param level The log level to send the message to
++ *
++ * Like ast_log, the log message may include printf-style formats, and
++ * the data for these must be provided as additional parameters after
++ * the log message.
++ *
++ * \return nothing
++ * \since 1.6.3
++ */
++
++#define ast_log_dynamic_level(level, ...) ast_log(level, __FILE__, __LINE__, __PRETTY_FUNCTION__, __VA_ARGS__)
++
++/*!
+ * \brief Log a DEBUG message
+ * \param level The minimum value of option_debug for this message
+ * to get logged
+Index: include/asterisk/lock.h
+===================================================================
+--- a/include/asterisk/lock.h (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/include/asterisk/lock.h (.../trunk) (revision 202568)
+@@ -58,7 +58,9 @@
+ #ifndef HAVE_PTHREAD_RWLOCK_TIMEDWRLOCK
+ #include "asterisk/time.h"
+ #endif
++
+ #include "asterisk/logger.h"
++#include "asterisk/astobj2.h"
+
+ /* internal macro to profile mutexes. Only computes the delay on
+ * non-blocking calls.
+@@ -272,13 +274,13 @@
+ do { \
+ char __filename[80], __func[80], __mutex_name[80]; \
+ int __lineno; \
+- int __res = ast_find_lock_info(&chan->lock_dont_use, __filename, sizeof(__filename), &__lineno, __func, sizeof(__func), __mutex_name, sizeof(__mutex_name)); \
++ int __res = ast_find_lock_info(ao2_object_get_lockaddr(chan), __filename, sizeof(__filename), &__lineno, __func, sizeof(__func), __mutex_name, sizeof(__mutex_name)); \
+ ast_channel_unlock(chan); \
+ usleep(1); \
+ if (__res < 0) { /* Shouldn't ever happen, but just in case... */ \
+ ast_channel_lock(chan); \
+ } else { \
+- __ast_pthread_mutex_lock(__filename, __lineno, __func, __mutex_name, &chan->lock_dont_use); \
++ __ao2_lock(chan, __filename, __func, __lineno, __mutex_name); \
+ } \
+ } while (0)
+
+@@ -2024,33 +2026,4 @@
+ })
+ #endif
+
+-#ifndef DEBUG_CHANNEL_LOCKS
+-/*! \brief Lock a channel. If DEBUG_CHANNEL_LOCKS is defined
+- in the Makefile, print relevant output for debugging */
+-#define ast_channel_lock(x) ast_mutex_lock(&x->lock_dont_use)
+-/*! \brief Unlock a channel. If DEBUG_CHANNEL_LOCKS is defined
+- in the Makefile, print relevant output for debugging */
+-#define ast_channel_unlock(x) ast_mutex_unlock(&x->lock_dont_use)
+-/*! \brief Try locking a channel. If DEBUG_CHANNEL_LOCKS is defined
+- in the Makefile, print relevant output for debugging */
+-#define ast_channel_trylock(x) ast_mutex_trylock(&x->lock_dont_use)
+-#else
+-
+-#define ast_channel_lock(a) __ast_channel_lock(a, __FILE__, __LINE__, __PRETTY_FUNCTION__)
+-/*! \brief Lock AST channel (and print debugging output)
+-\note You need to enable DEBUG_CHANNEL_LOCKS for this function */
+-int __ast_channel_lock(struct ast_channel *chan, const char *file, int lineno, const char *func);
+-
+-#define ast_channel_unlock(a) __ast_channel_unlock(a, __FILE__, __LINE__, __PRETTY_FUNCTION__)
+-/*! \brief Unlock AST channel (and print debugging output)
+-\note You need to enable DEBUG_CHANNEL_LOCKS for this function
+-*/
+-int __ast_channel_unlock(struct ast_channel *chan, const char *file, int lineno, const char *func);
+-
+-#define ast_channel_trylock(a) __ast_channel_trylock(a, __FILE__, __LINE__, __PRETTY_FUNCTION__)
+-/*! \brief Lock AST channel (and print debugging output)
+-\note You need to enable DEBUG_CHANNEL_LOCKS for this function */
+-int __ast_channel_trylock(struct ast_channel *chan, const char *file, int lineno, const char *func);
+-#endif
+-
+ #endif /* _ASTERISK_LOCK_H */
+Index: include/asterisk/pbx.h
+===================================================================
+--- a/include/asterisk/pbx.h (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/include/asterisk/pbx.h (.../trunk) (revision 202568)
+@@ -27,6 +27,7 @@
+ #include "asterisk/chanvars.h"
+ #include "asterisk/hashtab.h"
+ #include "asterisk/stringfields.h"
++#include "asterisk/xmldoc.h"
+
+ #if defined(__cplusplus) || defined(c_plusplus)
+ extern "C" {
+@@ -34,6 +35,7 @@
+
+ #define AST_MAX_APP 32 /*!< Max length of an application */
+
++#define AST_PBX_GOTO_FAILED -3
+ #define AST_PBX_KEEP 0
+ #define AST_PBX_REPLACE 1
+
+@@ -72,12 +74,6 @@
+ /*! \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 */
+@@ -89,8 +85,20 @@
+ 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 */
++ /*! Read function, if read is supported */
++ int (*read)(struct ast_channel *, const char *, char *, char *, size_t);
++ /*! Read function, if read is supported. Note: only one of read or read2
++ * needs to be implemented. In new code, read2 should be implemented as
++ * the way forward, but they should return identical results, within the
++ * constraints of buffer size, if both are implemented. That is, if the
++ * read function is handed a 16-byte buffer, and the result is 17 bytes
++ * long, then the first 15 bytes (remember NULL terminator) should be
++ * the same for both the read and the read2 methods. */
++ int (*read2)(struct ast_channel *, const char *, char *, struct ast_str **, ssize_t);
++ /*! If no read2 function is provided, what maximum size? */
++ size_t read_max;
++ /*! Write function, if write is supported */
++ int (*write)(struct ast_channel *, const char *, char *, const char *);
+ struct ast_module *mod; /*!< Module this custom function belongs to */
+ AST_RWLIST_ENTRY(ast_custom_function) acflist;
+ };
+@@ -197,7 +205,7 @@
+ * \retval 0 success
+ * \retval -1 failure
+ */
+-int pbx_exec(struct ast_channel *c, struct ast_app *app, void *data);
++int pbx_exec(struct ast_channel *c, struct ast_app *app, const char *data);
+
+ /*!
+ * \brief Register a new context or find an existing one
+@@ -421,6 +429,24 @@
+ int ast_get_hint(char *hint, int hintsize, char *name, int namesize,
+ struct ast_channel *c, const char *context, const char *exten);
+
++/*!
++ * \brief If an extension hint exists, return non-zero
++ *
++ * \param hint buffer for hint
++ * \param hintsize Maximum size of hint buffer (<0 to prevent growth, >0 to limit growth to that number of bytes, or 0 for unlimited growth)
++ * \param name buffer for name portion of hint
++ * \param namesize Maximum size of name buffer (<0 to prevent growth, >0 to limit growth to that number of bytes, or 0 for unlimited growth)
++ * \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.
++ * Otherwise, 0 is returned.
++ */
++int ast_str_get_hint(struct ast_str **hint, ssize_t hintsize, struct ast_str **name, ssize_t namesize,
++ struct ast_channel *c, const char *context, const char *exten);
++
+ /*!
+ * \brief Determine whether an extension exists
+ *
+@@ -945,23 +971,61 @@
+ /*!\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);
++int pbx_builtin_setvar(struct ast_channel *chan, const char *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_setvar_multiple(struct ast_channel *chan, const char *data);
+
+-int pbx_builtin_raise_exception(struct ast_channel *chan, void *data);
++int pbx_builtin_raise_exception(struct ast_channel *chan, const char *data);
+
+ /*! @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);
+ /*! @} */
++/*! @} */
+
++/*! @name Substitution routines, using dynamic string buffers */
++
++/*!
++ * \param buf Result will be placed in this buffer.
++ * \param maxlen -1 if the buffer should not grow, 0 if the buffer may grow to any size, and >0 if the buffer should grow only to that number of bytes.
++ * \param chan Channel variables from which to extract values, and channel to pass to any dialplan functions.
++ * \param headp If no channel is specified, a channel list from which to extract variable values
++ * \param var Variable name to retrieve.
++ */
++const char *ast_str_retrieve_variable(struct ast_str **buf, ssize_t maxlen, struct ast_channel *chan, struct varshead *headp, const char *var);
++
++/*!
++ * \param buf Result will be placed in this buffer.
++ * \param maxlen -1 if the buffer should not grow, 0 if the buffer may grow to any size, and >0 if the buffer should grow only to that number of bytes.
++ * \param chan Channel variables from which to extract values, and channel to pass to any dialplan functions.
++ * \param templ Variable template to expand.
++ */
++void ast_str_substitute_variables(struct ast_str **buf, ssize_t maxlen, struct ast_channel *chan, const char *templ);
++
++/*!
++ * \param buf Result will be placed in this buffer.
++ * \param maxlen -1 if the buffer should not grow, 0 if the buffer may grow to any size, and >0 if the buffer should grow only to that number of bytes.
++ * \param headp If no channel is specified, a channel list from which to extract variable values
++ * \param templ Variable template to expand.
++ */
++void ast_str_substitute_variables_varshead(struct ast_str **buf, ssize_t maxlen, struct varshead *headp, const char *templ);
++
++/*!
++ * \param buf Result will be placed in this buffer.
++ * \param maxlen -1 if the buffer should not grow, 0 if the buffer may grow to any size, and >0 if the buffer should grow only to that number of bytes.
++ * \param c Channel variables from which to extract values, and channel to pass to any dialplan functions.
++ * \param headp If no channel is specified, a channel list from which to extract variable values
++ * \param templ Variable template to expand.
++ * \param used Number of bytes read from the template.
++ */
++void ast_str_substitute_variables_full(struct ast_str **buf, ssize_t maxlen, struct ast_channel *c, struct varshead *headp, const char *templ, size_t *used);
++/*! @} */
++
+ int ast_extension_patmatch(const char *pattern, const char *data);
+
+ /*! Set "autofallthrough" flag, if newval is <0, does not actually set. If
+@@ -1049,6 +1113,21 @@
+ int ast_func_read(struct ast_channel *chan, const char *function, char *workspace, size_t len);
+
+ /*!
++ * \brief executes a read operation on a function
++ *
++ * \param chan Channel to execute on
++ * \param function Data containing the function call string (will be modified)
++ * \param str A dynamic string buffer into which to place the result.
++ * \param maxlen <0 if the dynamic buffer should not grow; >0 if the dynamic buffer should be limited to that number of bytes; 0 if the dynamic buffer has no upper limit
++ *
++ * This application executes a function in read mode on a given channel.
++ *
++ * \retval 0 success
++ * \retval non-zero failure
++ */
++int ast_func_read2(struct ast_channel *chan, const char *function, struct ast_str **str, ssize_t maxlen);
++
++/*!
+ * \brief executes a write operation on a function
+ *
+ * \param chan Channel to execute on
+@@ -1120,6 +1199,14 @@
+ unsigned int ast_hashtab_hash_contexts(const void *obj);
+ /*! @} */
+
++/*!
++ * \brief Command completion for the list of installed applications.
++ *
++ * This can be called from a CLI command completion function that wants to
++ * complete from the list of available applications.
++ */
++char *ast_complete_applications(const char *line, const char *word, int state);
++
+ #if defined(__cplusplus) || defined(c_plusplus)
+ }
+ #endif
+Index: include/asterisk/strings.h
+===================================================================
+--- a/include/asterisk/strings.h (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/include/asterisk/strings.h (.../trunk) (revision 202568)
+@@ -281,7 +281,7 @@
+ * string. It will also place a space in the result buffer in between each
+ * string from 'w'.
+ */
+-void ast_join(char *s, size_t len, char * const w[]);
++void ast_join(char *s, size_t len, const char * const w[]);
+
+ /*
+ \brief Parse a time (integer) string.
+@@ -454,7 +454,7 @@
+ * \param buf A pointer to the ast_str structure.
+ */
+ AST_INLINE_API(
+-size_t attribute_pure ast_str_strlen(struct ast_str *buf),
++size_t attribute_pure ast_str_strlen(const struct ast_str *buf),
+ {
+ return buf->__AST_STR_USED;
+ }
+@@ -465,7 +465,7 @@
+ * \retval Current maximum length of the buffer.
+ */
+ AST_INLINE_API(
+-size_t attribute_pure ast_str_size(struct ast_str *buf),
++size_t attribute_pure ast_str_size(const struct ast_str *buf),
+ {
+ return buf->__AST_STR_LEN;
+ }
+@@ -476,9 +476,13 @@
+ * \retval A pointer to the enclosed string.
+ */
+ AST_INLINE_API(
+-char * attribute_pure ast_str_buffer(struct ast_str *buf),
++char * attribute_pure ast_str_buffer(const struct ast_str *buf),
+ {
+- return buf->__AST_STR_STR;
++ /* for now, cast away the const qualifier on the pointer
++ * being returned; eventually, it should become truly const
++ * and only be modified via accessor functions
++ */
++ return (char *) buf->__AST_STR_STR;
+ }
+ )
+
+Index: include/asterisk/stun.h
+===================================================================
+--- a/include/asterisk/stun.h (.../tags/1.6.2.0-beta3) (revision 0)
++++ b/include/asterisk/stun.h (.../trunk) (revision 202568)
+@@ -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-beta3) (revision 202568)
++++ b/include/asterisk/stringfields.h (.../trunk) (revision 202568)
+@@ -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,19 +126,19 @@
+ */
+ 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 */
++ ast_string_field last_alloc; /*!< the last field allocated */
++ struct ast_string_field_pool *embedded_pool; /*!< pointer to the embedded pool, if any */
+ #if defined(__AST_DEBUG_MALLOC)
+ const char *owner_file; /*!< filename of owner */
+ const char *owner_func; /*!< function name of owner */
+@@ -159,7 +160,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);
+
+ /*!
+@@ -181,7 +183,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
+@@ -194,7 +196,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
+@@ -253,26 +255,76 @@
+ int needed, const char *file, int lineno, const char *func);
+
+ /*!
++ * \brief Allocate a structure with embedded stringfields in a single allocation
++ * \param n Number of structures to allocate (see ast_calloc)
++ * \param type The type of structure to allocate
++ * \param size The number of bytes of space (minimum) to allocate for stringfields to use
++ *
++ * This function will allocate memory for one or more structures that use stringfields, and
++ * also allocate space for the stringfields and initialize the stringfield management
++ * structure embedded in the outer structure.
++ *
++ * \since 1.6.3
++ */
++#define ast_calloc_with_stringfields(n, type, size) \
++ __ast_calloc_with_stringfields(n, sizeof(type), offsetof(type, __field_mgr), offsetof(type, __field_mgr_pool), \
++ size, __FILE__, __LINE__, __PRETTY_FUNCTION__)
++
++/*!
++ * \internal
++ * \brief internal version of ast_calloc_with_stringfields
++ */
++void * attribute_malloc __ast_calloc_with_stringfields(unsigned int num_structs, size_t struct_size, size_t field_mgr_offset,
++ size_t field_mgr_pool_offset, size_t pool_size, const char *file,
++ int lineno, const char *func);
++
++/*!
++ \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/agi.h
+===================================================================
+--- a/include/asterisk/agi.h (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/include/asterisk/agi.h (.../trunk) (revision 202568)
+@@ -40,22 +40,22 @@
+ } AGI;
+
+ typedef struct agi_command {
+- char *cmda[AST_MAX_CMD_LEN]; /*!< Null terminated list of the words of the command */
++ const char * const 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[]);
++ int (* const handler)(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[]);
+ /*! Summary of the command (< 60 characters) */
+- char *summary;
++ const char * const summary;
+ /*! Detailed usage information */
+- char *usage;
++ const char * const usage;
+ /*! Does this application run dead */
+- int dead;
++ const int dead;
+ /*! AGI command syntax description */
+- char *syntax;
++ const char * const syntax;
+ /*! See also content */
+- char *seealso;
++ const char * const seealso;
+ /*! Where the documentation come from. */
+- enum ast_doc_src docsrc;
++ const enum ast_doc_src docsrc;
+ /*! Pointer to module that registered the agi command */
+ struct ast_module *mod;
+ /*! Linked list pointer */
+@@ -72,7 +72,8 @@
+ * \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),
++AST_OPTIONAL_API(int, ast_agi_register,
++ (struct ast_module *mod, agi_command *cmd),
+ { return AST_OPTIONAL_API_UNAVAILABLE; });
+
+ /*!
+@@ -85,7 +86,8 @@
+ * \return 1 on success, 0 if the command was not already registered
+ *
+ */
+-AST_OPTIONAL_API(int, 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; });
+
+ /*!
+@@ -103,7 +105,8 @@
+ * will be unregistered. In other words, this function registers all the provided commands, or none
+ * of them.
+ */
+-AST_OPTIONAL_API(int, 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; });
+
+ /*!
+@@ -120,7 +123,8 @@
+ * \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.
+ */
+-AST_OPTIONAL_API(int, 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; });
+
+ /*!
+@@ -134,7 +138,8 @@
+ * \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, ...),
++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)
+Index: include/asterisk/autoconfig.h.in
+===================================================================
+--- a/include/asterisk/autoconfig.h.in (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/include/asterisk/autoconfig.h.in (.../trunk) (revision 202568)
+@@ -94,9 +94,6 @@
+ /* 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
+@@ -123,12 +120,12 @@
+ attribute. */
+ #undef HAVE_ATTRIBUTE_warn_unused_result
+
+-/* 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 to 1 if your GCC C compiler supports the 'weakref' attribute. */
++#undef HAVE_ATTRIBUTE_weakref
++
+ /* Define this to indicate the ${BKTR_DESCRIP} library */
+ #undef HAVE_BKTR
+
+@@ -192,6 +189,12 @@
+ /* Define if your system has the DAHDI headers. */
+ #undef HAVE_DAHDI
+
++/* Define if your system has the DAHDI_ECHOCANCEL_FAX_MODE headers. */
++#undef HAVE_DAHDI_ECHOCANCEL_FAX_MODE
++
++/* Define DAHDI_ECHOCANCEL_FAX_MODE headers version */
++#undef HAVE_DAHDI_ECHOCANCEL_FAX_MODE_VERSION
++
+ /* Define if your system has the DAHDI_HALF_FULL headers. */
+ #undef HAVE_DAHDI_HALF_FULL
+
+@@ -358,6 +361,18 @@
+ /* Define to 1 if you have the `glob' function. */
+ #undef HAVE_GLOB
+
++/* Define if your system has the GLOB_BRACE headers. */
++#undef HAVE_GLOB_BRACE
++
++/* Define GLOB_BRACE headers version */
++#undef HAVE_GLOB_BRACE_VERSION
++
++/* Define if your system has the GLOB_NOMAGIC headers. */
++#undef HAVE_GLOB_NOMAGIC
++
++/* Define GLOB_NOMAGIC headers version */
++#undef HAVE_GLOB_NOMAGIC_VERSION
++
+ /* Define if your system has the GMIME libraries. */
+ #undef HAVE_GMIME
+
+@@ -382,6 +397,12 @@
+ /* Define to indicate the ${HOARD_DESCRIP} library version */
+ #undef HAVE_HOARD_VERSION
+
++/* Define this to indicate the ${ICAL_DESCRIP} library */
++#undef HAVE_ICAL
++
++/* Define to indicate the ${ICAL_DESCRIP} library version */
++#undef HAVE_ICAL_VERSION
++
+ /* Define this to indicate the ${ICONV_DESCRIP} library */
+ #undef HAVE_ICONV
+
+@@ -575,6 +596,9 @@
+ /* Define to 1 if you have the <ndir.h> header file, and it defines `DIR'. */
+ #undef HAVE_NDIR_H
+
++/* Define if your system has the NEON libraries. */
++#undef HAVE_NEON
++
+ /* Define to 1 if you have the <netdb.h> header file. */
+ #undef HAVE_NETDB_H
+
+@@ -674,6 +698,12 @@
+ /* Define to indicate the ${PRI_PROG_W_CAUSE_DESCRIP} library version */
+ #undef HAVE_PRI_PROG_W_CAUSE_VERSION
+
++/* Define this to indicate the ${PRI_SERVICE_MESSAGES_DESCRIP} library */
++#undef HAVE_PRI_SERVICE_MESSAGES
++
++/* Define to indicate the ${PRI_SERVICE_MESSAGES_DESCRIP} library version */
++#undef HAVE_PRI_SERVICE_MESSAGES_VERSION
++
+ /* Define to indicate the ${PRI_DESCRIP} library version */
+ #undef HAVE_PRI_VERSION
+
+@@ -1181,9 +1211,6 @@
+ /* Define to the version of this package. */
+ #undef PACKAGE_VERSION
+
+-/* Define to 1 if the C compiler supports function prototypes. */
+-#undef PROTOTYPES
+-
+ /* Define to necessary symbol if this constant uses a non-standard name on
+ your system. */
+ #undef PTHREAD_CREATE_JOINABLE
+@@ -1200,11 +1227,6 @@
+ /* Define to the type of arg 5 for `select'. */
+ #undef SELECT_TYPE_ARG5
+
+-/* Define to 1 if the `setvbuf' function takes the buffering type as its
+- second argument and the buffer pointer as the third, as on System V before
+- release 3. */
+-#undef SETVBUF_REVERSED
+-
+ /* The size of `int', as computed by sizeof. */
+ #undef SIZEOF_INT
+
+@@ -1225,21 +1247,31 @@
+ /* Define to 1 if your <sys/time.h> declares `struct tm'. */
+ #undef TM_IN_SYS_TIME
+
+-/* Define to 1 if on AIX 3.
+- System headers sometimes define this.
+- We just want to avoid a redefinition error message. */
++/* Enable extensions on AIX 3, Interix. */
+ #ifndef _ALL_SOURCE
+ # undef _ALL_SOURCE
+ #endif
+-
+-/* Number of bits in a file offset, on hosts where this is settable. */
+-#undef _FILE_OFFSET_BITS
+-
+ /* Enable GNU extensions on systems that have them. */
+ #ifndef _GNU_SOURCE
+ # undef _GNU_SOURCE
+ #endif
++/* Enable threading extensions on Solaris. */
++#ifndef _POSIX_PTHREAD_SEMANTICS
++# undef _POSIX_PTHREAD_SEMANTICS
++#endif
++/* Enable extensions on HP NonStop. */
++#ifndef _TANDEM_SOURCE
++# undef _TANDEM_SOURCE
++#endif
++/* Enable general extensions on Solaris. */
++#ifndef __EXTENSIONS__
++# undef __EXTENSIONS__
++#endif
+
++
++/* Number of bits in a file offset, on hosts where this is settable. */
++#undef _FILE_OFFSET_BITS
++
+ /* Define to 1 to make fseeko visible on some hosts (e.g. glibc 2.2). */
+ #undef _LARGEFILE_SOURCE
+
+@@ -1256,20 +1288,6 @@
+ /* Define to 1 if you need to in order for `stat' and other things to work. */
+ #undef _POSIX_SOURCE
+
+-/* Enable extensions on Solaris. */
+-#ifndef __EXTENSIONS__
+-# undef __EXTENSIONS__
+-#endif
+-#ifndef _POSIX_PTHREAD_SEMANTICS
+-# undef _POSIX_PTHREAD_SEMANTICS
+-#endif
+-#ifndef _TANDEM_SOURCE
+-# undef _TANDEM_SOURCE
+-#endif
+-
+-/* Define like PROTOTYPES; this can be used by system headers. */
+-#undef __PROTOTYPES
+-
+ /* Define to empty if `const' does not conform to ANSI C. */
+ #undef const
+
+Index: include/asterisk/extconf.h
+===================================================================
+--- a/include/asterisk/extconf.h (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/include/asterisk/extconf.h (.../trunk) (revision 202568)
+@@ -185,7 +185,7 @@
+ * \version 1.6.1 renamed function from localized_context_create to localized_context_find_or_create
+ */
+ struct ast_context *localized_context_find_or_create(struct ast_context **extcontexts, void *tab, const char *name, const char *registrar);
+-int localized_pbx_builtin_setvar(struct ast_channel *chan, void *data);
++int localized_pbx_builtin_setvar(struct ast_channel *chan, const void *data);
+ int localized_context_add_ignorepat2(struct ast_context *con, const char *value, const char *registrar);
+ int localized_context_add_switch2(struct ast_context *con, const char *value,
+ const char *data, int eval, const char *registrar);
+Index: include/asterisk/tcptls.h
+===================================================================
+--- a/include/asterisk/tcptls.h (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/include/asterisk/tcptls.h (.../trunk) (revision 202568)
+@@ -72,12 +72,19 @@
+ /*! Don't verify certificate when connecting to a server */
+ AST_SSL_DONT_VERIFY_SERVER = (1 << 1),
+ /*! Don't compare "Common Name" against IP or hostname */
+- AST_SSL_IGNORE_COMMON_NAME = (1 << 2)
++ AST_SSL_IGNORE_COMMON_NAME = (1 << 2),
++ /*! Use SSLv2 for outgoing client connections */
++ AST_SSL_SSLV2_CLIENT = (1 << 3),
++ /*! Use SSLv3 for outgoing client connections */
++ AST_SSL_SSLV3_CLIENT = (1 << 4),
++ /*! Use TLSv1 for outgoing client connections */
++ AST_SSL_TLSV1_CLIENT = (1 << 5)
+ };
+
+ struct ast_tls_config {
+ int enabled;
+ char *certfile;
++ char *pvtfile;
+ char *cipher;
+ char *cafile;
+ char *capath;
+@@ -173,6 +180,11 @@
+ void ast_tcptls_server_stop(struct ast_tcptls_session_args *desc);
+ int ast_ssl_setup(struct ast_tls_config *cfg);
+
++/*!
++ * \brief Used to parse conf files containing tls/ssl options.
++ */
++int ast_tls_read_conf(struct ast_tls_config *tls_cfg, struct ast_tcptls_session_args *tls_desc, const char *varname, const char *value);
++
+ 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, const void *buf, size_t count);
+
+Index: include/asterisk/compiler.h
+===================================================================
+--- a/include/asterisk/compiler.h (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/include/asterisk/compiler.h (.../trunk) (revision 202568)
+@@ -68,16 +68,4 @@
+ /* Some older version of GNU gcc (3.3.5 on OpenBSD 4.3 for example) dont like 'NULL' as sentinel */
+ #define SENTINEL ((char *)NULL)
+
+-#ifdef HAVE_ATTRIBUTE_weak
+-#define attribute_weak __attribute__((weak))
+-#else
+-#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.2.0-beta3) (revision 202568)
++++ b/include/asterisk/callerid.h (.../trunk) (revision 202568)
+@@ -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-beta3) (revision 202568)
++++ b/include/asterisk/doxyref.h (.../trunk) (revision 202568)
+@@ -1,7 +1,7 @@
+ /*
+ * Asterisk -- An open source telephony toolkit.
+ *
+- * Copyright (C) 1999 - 2008, Digium, Inc.
++ * Copyright (C) 1999 - 2009, Digium, Inc.
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+@@ -15,9 +15,11 @@
+ */
+
+ /*!
+- * \file
+- * \brief This file generates Doxygen pages from files in the /doc
+- * directory of the Asterisk source code tree
++ * \file
++ *
++ * This is the main header file used for generating miscellaneous developer
++ * documentation using doxygen. This also pulls in all of the documentation
++ * that is in include/asterisk/doxygen/.
+ */
+
+ /*
+@@ -34,6 +36,7 @@
+ * \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 Reviewboard : Reviewboard Usage and Guidelines
+ * \arg \ref AstCREDITS : A Thank You to contributors (unfortunately out of date)
+ *
+ * \section apisandinterfaces Asterisk APIs and Interfaces
+@@ -61,274 +64,13 @@
+ *
+ * \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 Bugs: The Issue Tracker https://issues.asterisk.org
+ * \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
+ */
+
+-/*!
+- * \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 ReleasePolicies Asterisk Release and Commit Policies
+- *
+- * \AsteriskTrunkWarning
+- *
+- * \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 CodeGuide Coding Guidelines
+ * \AsteriskTrunkWarning
+@@ -338,98 +80,6 @@
+ * \verbinclude CODING-GUIDELINES
+ */
+
+-/*!
+- * \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 AstAPI Asterisk API
+ * \section Asteriskapi Asterisk API
+@@ -1018,136 +668,4 @@
+ * http://www.sqlite.org
+ */
+
+-/*!
+- * \page Licensing Asterisk Licensing Information
+- *
+- * \section license Asterisk License
+- * \verbinclude LICENSE
+- *
+- * \section otherlicenses Licensing of 3rd Party Code
+- *
+- * This section contains a (not yet complete) list of libraries that are used
+- * by various parts of Asterisk, including related licensing information.
+- *
+- * \subsection alsa_lib ALSA Library
+- * \arg <b>Library</b>: libasound
+- * \arg <b>Website</b>: http://www.alsa-project.org
+- * \arg <b>Used by</b>: chan_alsa
+- * \arg <b>License</b>: LGPL
+- *
+- * \subsection openssl_lib OpenSSL
+- * \arg <b>Library</b>: libcrypto, libssl
+- * \arg <b>Website</b>: http://www.openssl.org
+- * \arg <b>Used by</b>: Asterisk core (TLS for manager and HTTP), res_crypto
+- * \arg <b>License</b>: Apache 2.0
+- * \arg <b>Note</b>: An exception has been granted to allow linking of
+- * OpenSSL with Asterisk.
+- *
+- * \subsection curl_lib Curl
+- * \arg <b>Library</b>: libcurl
+- * \arg <b>Website</b>: http://curl.haxx.se
+- * \arg <b>Used by</b>: func_curl, res_config_curl, res_curl
+- * \arg <b>License</b>: BSD
+- *
+- * \subsection portaudio_lib PortAudio
+- * \arg <b>Library</b>: libportaudio
+- * \arg <b>Website</b>: http://www.portaudio.com
+- * \arg <b>Used by</b>: chan_console
+- * \arg <b>License</b>: BSD
+- * \arg <b>Note</b>: Even though PortAudio is licensed under a BSD style
+- * license, PortAudio will make use of some audio interface,
+- * depending on how it was built. That audio interface may
+- * introduce additional licensing restrictions. On Linux,
+- * this would most commonly be ALSA: \ref alsa_lib.
+- *
+- * \subsection rawlist Raw list of libraries that used by any part of Asterisk
+- * \li c-client.a (app_voicemail with IMAP support)
+- * \li libSDL-1.2.so.0
+- * \li libSaClm.so.2
+- * \li libSaEvt.so.2
+- * \li libX11.so.6
+- * \li libXau.so.6
+- * \li libXdmcp.so.6
+- * \li libasound.so.2
+- * \li libc.so.6
+- * \li libcom_err.so.2
+- * \li libcrypt.so.1
+- * \li libcrypto.so.0.9.8 (chan_h323)
+- * \li libcurl.so.4
+- * \li libdirect-1.0.so.0
+- * \li libdirectfb-1.0.so.0
+- * \li libdl.so.2
+- * \li libexpat.so (chan_h323)
+- * \li libfusion-1.0.so.0
+- * \li libgcc_s.so (chan_h323)
+- * \li libgcrypt.so.11 (chan_h323)
+- * \li libglib-2.0.so.0
+- * \li libgmime-2.0.so.2
+- * \li libgmodule-2.0.so.0
+- * \li libgnutls.so.13 (chan_h323)
+- * \li libgobject-2.0.so.0
+- * \li libgpg-error.so.0 (chan_h323)
+- * \li libgssapi_krb5.so.2
+- * \li libgthread-2.0.so.0
+- * \li libidn.so.11
+- * \li libiksemel.so.3
+- * \li libisdnnet.so
+- * \li libjack.so.0
+- * \li libjpeg.so.62
+- * \li libk5crypto.so.3
+- * \li libkeyutils.so.1
+- * \li libkrb5.so.3
+- * \li libkrb5support.so.0
+- * \li liblber-2.4.so.2 (chan_h323)
+- * \li libldap_r-2.4.so.2 (chan_h323)
+- * \li libltdl.so.3
+- * \li liblua5.1.so.0
+- * \li libm.so.6
+- * \li libmISDN.so
+- * \li libnbs.so.1
+- * \li libncurses.so.5
+- * \li libnetsnmp.so.15
+- * \li libnetsnmpagent.so.15
+- * \li libnetsnmphelpers.so.15
+- * \li libnetsnmpmibs.so.15
+- * \li libnsl.so.1
+- * \li libodbc.so.1
+- * \li libogg.so.0
+- * \li libopenh323.so (chan_h323)
+- * \li libpcre.so.3
+- * \li libperl.so.5.8
+- * \li libportaudio.so.2
+- * \li libpq.so.5
+- * \li libpri.so.1.4
+- * \li libpt.so (chan_h323)
+- * \li libpthread.so.0
+- * \li libradiusclient-ng.so.2
+- * \li libresample.so.1.0
+- * \li libresolv.so.2 (chan_h323)
+- * \li librt.so.1
+- * \li libsasl2.so.2 (chan_h323)
+- * \li libselinux.so.1
+- * \li libsensors.so.3
+- * \li libspandsp.so.1
+- * \li libspeex.so.1
+- * \li libsqlite.so.0
+- * \li libsqlite3.so.0
+- * \li libss7.so.1
+- * \li libssl.so.0.9.8 (chan_h323)
+- * \li libstdc++.so (chan_h323, chan_vpb)
+- * \li libsuppserv.so
+- * \li libsybdb.so.5
+- * \li libsysfs.so.2
+- * \li libtasn1.so.3 (chan_h323)
+- * \li libtds.so.4
+- * \li libtiff.so.4
+- * \li libtonezone.so.1.0
+- * \li libvorbis.so.0
+- * \li libvorbisenc.so.2
+- * \li libvpb.a (chan_vpb)
+- * \li libwrap.so.0
+- * \li libxcb-xlib.so.0
+- * \li libxcb.so.1
+- * \li libz.so.1 (chan_h323)
+- * \li linux-vdso.so.1
+-*/
++
+Index: include/asterisk/xmldoc.h
+===================================================================
+--- a/include/asterisk/xmldoc.h (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/include/asterisk/xmldoc.h (.../trunk) (revision 202568)
+@@ -23,6 +23,13 @@
+
+ #include "asterisk/xml.h"
+
++/*! \brief From where the documentation come from, this structure is useful for
++ * use it inside application/functions/manager actions structure. */
++enum ast_doc_src {
++ AST_XML_DOC, /*!< From XML documentation */
++ AST_STATIC_DOC /*!< From application/function registration */
++};
++
+ #ifdef AST_XML_DOCS
+
+ /*!
+Index: main/rtp.c
+===================================================================
+--- a/main/rtp.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/main/rtp.c (.../trunk) (revision 202568)
+@@ -1,4917 +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
+- *
+- * \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: 197619 $")
+-
+-#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 (150 * (8000 / 1000)) /*!< 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;
+- unsigned int dtmf_duration; /*!< Total duration in samples since the digit start event */
+- unsigned int dtmf_timeout; /*!< When this timestamp is reached we consider END frame lost and forcibly abort digit */
+- 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 sockaddr_in altthem; /*!< Alternate source of remote media */
+- 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. */
+- struct sockaddr_in altthem; /*!< Alternate source for RTCP */
+- 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->dtmf_timeout = 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->dtmf_timeout = 0;
+- f = send_dtmf(rtp, AST_FRAME_DTMF_END);
+- f->len = 0;
+- rtp->lastevent = timestamp;
+- }
+- } else {
+- /* The duration parameter measures the complete
+- duration of the event (from the beginning) - RFC2833.
+- Account for the fact that duration is only 16 bits long
+- (about 8 seconds at 8000 Hz) and can wrap is digit
+- is hold for too long. */
+- unsigned int new_duration = rtp->dtmf_duration;
+- unsigned int last_duration = new_duration & 0xFFFF;
+-
+- if (last_duration > 64000 && samples < last_duration)
+- new_duration += 0xFFFF + 1;
+- new_duration = (new_duration & ~0xFFFF) | samples;
+-
+- if (event_end & 0x80) {
+- /* End event */
+- if ((rtp->lastevent != seqno) && rtp->resp) {
+- rtp->dtmf_duration = new_duration;
+- f = send_dtmf(rtp, AST_FRAME_DTMF_END);
+- f->len = ast_tvdiff_ms(ast_samp2tv(rtp->dtmf_duration, 8000), ast_tv(0, 0));
+- rtp->resp = 0;
+- rtp->dtmf_duration = rtp->dtmf_timeout = 0;
+- }
+- } else {
+- /* Begin/continuation */
+-
+- if (rtp->resp && rtp->resp != resp) {
+- /* Another digit already began. End it */
+- f = send_dtmf(rtp, AST_FRAME_DTMF_END);
+- f->len = ast_tvdiff_ms(ast_samp2tv(rtp->dtmf_duration, 8000), ast_tv(0, 0));
+- rtp->resp = 0;
+- rtp->dtmf_duration = rtp->dtmf_timeout = 0;
+- }
+-
+-
+- if (rtp->resp) {
+- /* Digit continues */
+- rtp->dtmf_duration = new_duration;
+- } else {
+- /* New digit began */
+- rtp->resp = resp;
+- f = send_dtmf(rtp, AST_FRAME_DTMF_BEGIN);
+- rtp->dtmf_duration = samples;
+- }
+-
+- rtp->dtmf_timeout = timestamp + rtp->dtmf_duration + dtmftimeout;
+- }
+-
+- 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)) &&
+- ((rtp->rtcp->altthem.sin_addr.s_addr != sock_in.sin_addr.s_addr) ||
+- (rtp->rtcp->altthem.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->altthem.sin_addr.s_addr != sock_in.sin_addr.s_addr) ||
+- (rtp->altthem.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->dtmf_timeout && rtp->dtmf_timeout < timestamp) {
+- rtp->dtmf_timeout = 0;
+-
+- if (rtp->resp) {
+- struct ast_frame *f;
+- f = send_dtmf(rtp, AST_FRAME_DTMF_END);
+- f->len = ast_tvdiff_ms(ast_samp2tv(rtp->dtmf_duration, 8000), ast_tv(0, 0));
+- rtp->resp = 0;
+- rtp->dtmf_timeout = rtp->dtmf_duration = 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;
+-}
+-
+-void ast_rtp_set_alt_peer(struct ast_rtp *rtp, struct sockaddr_in *alt)
+-{
+- rtp->altthem.sin_port = alt->sin_port;
+- rtp->altthem.sin_addr = alt->sin_addr;
+- if (rtp->rtcp) {
+- rtp->rtcp->altthem.sin_port = htons(ntohs(alt->sin_port) + 1);
+- rtp->rtcp->altthem.sin_addr = alt->sin_addr;
+- }
+-}
+-
+-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->dtmf_timeout = 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;
+- /* 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, pred/ts/samples %d/%d/%d\n", abs(rtp->lastts - pred), ms, 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)) ||
+- (codec0 != oldcodec0)) {
+- 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 > 64000)) {
+- 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-beta3) (revision 202568)
++++ b/main/utils.c (.../trunk) (revision 202568)
+@@ -227,7 +227,7 @@
+ }
+
+ /*! \brief Produce 32 char MD5 hash of value. */
+-void ast_md5_hash(char *output, char *input)
++void ast_md5_hash(char *output, const char *input)
+ {
+ struct MD5Context md5;
+ unsigned char digest[16];
+@@ -235,7 +235,7 @@
+ int x;
+
+ MD5Init(&md5);
+- MD5Update(&md5, (unsigned char *)input, strlen(input));
++ MD5Update(&md5, (const unsigned char *) input, strlen(input));
+ MD5Final(digest, &md5);
+ ptr = output;
+ for (x = 0; x < 16; x++)
+@@ -243,7 +243,7 @@
+ }
+
+ /*! \brief Produce 40 char SHA1 hash of value. */
+-void ast_sha1_hash(char *output, char *input)
++void ast_sha1_hash(char *output, const char *input)
+ {
+ struct SHA1Context sha;
+ char *ptr;
+@@ -1446,7 +1446,7 @@
+ return dataPut;
+ }
+
+-void ast_join(char *s, size_t len, char * const w[])
++void ast_join(char *s, size_t len, const char * const w[])
+ {
+ int x, ofs = 0;
+ const char *src;
+@@ -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.
+@@ -1479,21 +1504,21 @@
+ size_t size, const char *file, int lineno, const char *func)
+ {
+ struct ast_string_field_pool *pool;
++ size_t alloc_size = optimal_alloc_size(sizeof(*pool) + size);
+
+ #if defined(__AST_DEBUG_MALLOC)
+- if (!(pool = __ast_calloc(1, sizeof(*pool) + size, file, lineno, func))) {
++ if (!(pool = __ast_calloc(1, alloc_size, file, lineno, func))) {
+ return -1;
+ }
+ #else
+- if (!(pool = ast_calloc(1, sizeof(*pool) + size))) {
++ if (!(pool = ast_calloc(1, alloc_size))) {
+ return -1;
+ }
+ #endif
+
+ 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;
+@@ -1505,6 +1530,8 @@
+ * size > 0 means initialize the pool list with a pool of given size.
+ * This must be called right after allocating the object.
+ * size = 0 means release all pools except the most recent one.
++ * If the first pool was allocated via embedding in another
++ * object, that pool will be preserved instead.
+ * This is useful to e.g. reset an object to the initial value.
+ * size < 0 means release all pools.
+ * This must be done before destroying the object.
+@@ -1517,8 +1544,10 @@
+ struct ast_string_field_pool *preserve = NULL;
+
+ /* 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 defined(__AST_DEBUG_MALLOC)
+ mgr->owner_file = file;
+@@ -1529,24 +1558,34 @@
+ *pool_head = NULL;
+ return add_string_pool(mgr, pool_head, needed, file, lineno, func);
+ }
++
++ /* if there is an embedded pool, we can't actually release *all*
++ * pools, we must keep the embedded one. if the caller is about
++ * to free the structure that contains the stringfield manager
++ * and embedded pool anyway, it will be freed as part of that
++ * operation.
++ */
++ if ((needed < 0) && mgr->embedded_pool) {
++ needed = 0;
++ }
++
+ if (needed < 0) { /* reset all pools */
+- if (*pool_head == NULL) {
+- ast_log(LOG_WARNING, "trying to reset empty pool\n");
+- return -1;
+- }
+ cur = *pool_head;
++ } else if (mgr->embedded_pool) { /* preserve the embedded pool */
++ preserve = mgr->embedded_pool;
++ cur = *pool_head;
+ } else { /* preserve the last pool */
+ if (*pool_head == NULL) {
+ ast_log(LOG_WARNING, "trying to reset empty pool\n");
+ return -1;
+ }
+- mgr->used = 0;
+ preserve = *pool_head;
+ cur = preserve->prev;
+ }
+
+ if (preserve) {
+ preserve->prev = NULL;
++ preserve->used = preserve->active = 0;
+ }
+
+ while (cur) {
+@@ -1567,13 +1606,15 @@
+ 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 defined(__AST_DEBUG_MALLOC)
+ if (add_string_pool(mgr, pool_head, new_size, mgr->owner_file, mgr->owner_line, mgr->owner_func))
+@@ -1584,22 +1625,23 @@
+ #endif
+ }
+
+- 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;
+ }
+@@ -1608,30 +1650,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;
+@@ -1639,33 +1708,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 defined(__AST_DEBUG_MALLOC)
+- if (add_string_pool(mgr, pool_head, new_size, mgr->owner_file, mgr->owner_line, mgr->owner_func))
+- return;
+-#else
+- if (add_string_pool(mgr, pool_head, new_size, NULL, 0, NULL))
+- return;
+-#endif
++ 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;
+ }
+ }
+
+@@ -1683,6 +1751,50 @@
+ va_end(ap1);
+ va_end(ap2);
+ }
++
++void *__ast_calloc_with_stringfields(unsigned int num_structs, size_t struct_size, size_t field_mgr_offset,
++ size_t field_mgr_pool_offset, size_t pool_size, const char *file,
++ int lineno, const char *func)
++{
++ struct ast_string_field_mgr *mgr;
++ struct ast_string_field_pool *pool;
++ struct ast_string_field_pool **pool_head;
++ size_t pool_size_needed = sizeof(*pool) + pool_size;
++ size_t size_to_alloc = optimal_alloc_size(struct_size + pool_size_needed);
++ void *allocation;
++ unsigned int x;
++
++#if defined(__AST_DEBUG_MALLOC)
++ if (!(allocation = __ast_calloc(num_structs, size_to_alloc, file, lineno, func))) {
++ return NULL;
++ }
++#else
++ if (!(allocation = ast_calloc(num_structs, size_to_alloc))) {
++ return NULL;
++ }
++#endif
++
++ for (x = 0; x < num_structs; x++) {
++ void *base = allocation + (size_to_alloc * x);
++ const char **p;
++
++ mgr = base + field_mgr_offset;
++ pool_head = base + field_mgr_pool_offset;
++ pool = base + struct_size;
++
++ p = (const char **) pool_head + 1;
++ while ((struct ast_string_field_mgr *) p != mgr) {
++ *p++ = __ast_string_field_empty;
++ }
++
++ mgr->embedded_pool = pool;
++ *pool_head = pool;
++ pool->size = size_to_alloc - struct_size - sizeof(*pool);
++ }
++
++ return allocation;
++}
++
+ /* end of stringfields support */
+
+ AST_MUTEX_DEFINE_STATIC(fetchadd_m); /* used for all fetc&add ops */
+@@ -1809,6 +1921,126 @@
+ return 0;
+ }
+
++
++/*!
++ *\brief Parse digest authorization header.
++ *\return Returns -1 if we have no auth or something wrong with digest.
++ *\note This function may be used for Digest request and responce header.
++ * request arg is set to nonzero, if we parse Digest Request.
++ * pedantic arg can be set to nonzero if we need to do addition Digest check.
++ */
++int ast_parse_digest(const char *digest, struct ast_http_digest *d, int request, int pedantic) {
++ int i;
++ char *c, key[512], val[512], tmp[512];
++ struct ast_str *str = ast_str_create(16);
++
++ if (ast_strlen_zero(digest) || !d || !str) {
++ ast_free(str);
++ return -1;
++ }
++
++ ast_str_set(&str, 0, "%s", digest);
++
++ c = ast_skip_blanks(ast_str_buffer(str));
++
++ if (strncasecmp(tmp, "Digest ", strlen("Digest "))) {
++ ast_log(LOG_WARNING, "Missing Digest.\n");
++ ast_free(str);
++ return -1;
++ }
++ c += strlen("Digest ");
++
++ /* lookup for keys/value pair */
++ while (*c && *(c = ast_skip_blanks(c))) {
++ /* find key */
++ i = 0;
++ while (*c && *c != '=' && *c != ',' && !isspace(*c)) {
++ key[i++] = *c++;
++ }
++ key[i] = '\0';
++ c = ast_skip_blanks(c);
++ if (*c == '=') {
++ c = ast_skip_blanks(++c);
++ i = 0;
++ if (*c == '\"') {
++ /* in quotes. Skip first and look for last */
++ c++;
++ while (*c && *c != '\"') {
++ if (*c == '\\' && c[1] != '\0') { /* unescape chars */
++ c++;
++ }
++ val[i++] = *c++;
++ }
++ } else {
++ /* token */
++ while (*c && *c != ',' && !isspace(*c)) {
++ val[i++] = *c++;
++ }
++ }
++ val[i] = '\0';
++ }
++
++ while (*c && *c != ',') {
++ c++;
++ }
++ if (*c) {
++ c++;
++ }
++
++ if (!strcasecmp(key, "username")) {
++ ast_string_field_set(d, username, val);
++ } else if (!strcasecmp(key, "realm")) {
++ ast_string_field_set(d, realm, val);
++ } else if (!strcasecmp(key, "nonce")) {
++ ast_string_field_set(d, nonce, val);
++ } else if (!strcasecmp(key, "uri")) {
++ ast_string_field_set(d, uri, val);
++ } else if (!strcasecmp(key, "domain")) {
++ ast_string_field_set(d, domain, val);
++ } else if (!strcasecmp(key, "response")) {
++ ast_string_field_set(d, response, val);
++ } else if (!strcasecmp(key, "algorithm")) {
++ if (strcasecmp(val, "MD5")) {
++ ast_log(LOG_WARNING, "Digest algorithm: \"%s\" not supported.\n", val);
++ return -1;
++ }
++ } else if (!strcasecmp(key, "cnonce")) {
++ ast_string_field_set(d, cnonce, val);
++ } else if (!strcasecmp(key, "opaque")) {
++ ast_string_field_set(d, opaque, val);
++ } else if (!strcasecmp(key, "qop") && !strcasecmp(val, "auth")) {
++ d->qop = 1;
++ } else if (!strcasecmp(key, "nc")) {
++ unsigned long u;
++ if (sscanf(val, "%lx", &u) != 1) {
++ ast_log(LOG_WARNING, "Incorrect Digest nc value: \"%s\".\n", val);
++ return -1;
++ }
++ ast_string_field_set(d, nc, val);
++ }
++ }
++ ast_free(str);
++
++ /* Digest checkout */
++ if (ast_strlen_zero(d->realm) || ast_strlen_zero(d->nonce)) {
++ /* "realm" and "nonce" MUST be always exist */
++ return -1;
++ }
++
++ if (!request) {
++ /* Additional check for Digest response */
++ if (ast_strlen_zero(d->username) || ast_strlen_zero(d->uri) || ast_strlen_zero(d->response)) {
++ return -1;
++ }
++
++ if (pedantic && d->qop && (ast_strlen_zero(d->cnonce) || ast_strlen_zero(d->nc))) {
++ return -1;
++ }
++ }
++
++ return 0;
++}
++
+ #ifndef __AST_DEBUG_MALLOC
+ int _ast_asprintf(char **ret, const char *file, int lineno, const char *func, const char *fmt, ...)
+ {
+Index: main/loader.c
+===================================================================
+--- a/main/loader.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/main/loader.c (.../trunk) (revision 202568)
+@@ -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"
+@@ -71,7 +70,7 @@
+
+ AST_LIST_HEAD(module_user_list, ast_module_user);
+
+-static unsigned char expected_key[] =
++static const unsigned char expected_key[] =
+ { 0x87, 0x76, 0x79, 0x35, 0x23, 0xea, 0x3a, 0xd3,
+ 0x25, 0x2a, 0xbb, 0x35, 0x87, 0xe4, 0x22, 0x24 };
+
+@@ -126,7 +125,7 @@
+ need to know what filename the module was loaded from while it
+ is being registered
+ */
+-struct ast_module *resource_being_loaded;
++static struct ast_module *resource_being_loaded;
+
+ /* XXX: should we check for duplicate resource names here? */
+
+@@ -253,7 +252,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 },
+@@ -744,10 +742,9 @@
+ mod->flags.declined = 1;
+ break;
+ case AST_MODULE_LOAD_FAILURE:
++ case AST_MODULE_LOAD_SKIP: /* modules should never return this value */
++ case AST_MODULE_LOAD_PRIORITY:
+ break;
+- case AST_MODULE_LOAD_SKIP:
+- /* modules should never return this value */
+- break;
+ }
+
+ return res;
+@@ -808,7 +805,7 @@
+
+ if (resource_heap) {
+ ast_heap_push(resource_heap, mod);
+- res = AST_MODULE_LOAD_SKIP;
++ res = AST_MODULE_LOAD_PRIORITY;
+ } else {
+ res = start_resource(mod);
+ }
+@@ -894,6 +891,9 @@
+ goto done;
+ case AST_MODULE_LOAD_SKIP:
+ break;
++ case AST_MODULE_LOAD_PRIORITY:
++ AST_LIST_REMOVE_CURRENT(entry);
++ break;
+ }
+ }
+ AST_LIST_TRAVERSE_SAFE_END;
+@@ -909,6 +909,7 @@
+ res = -1;
+ goto done;
+ case AST_MODULE_LOAD_SKIP:
++ case AST_MODULE_LOAD_PRIORITY:
+ break;
+ }
+ }
+Index: main/term.c
+===================================================================
+--- a/main/term.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/main/term.c (.../trunk) (revision 202568)
+@@ -43,7 +43,7 @@
+ static char enddata[80] = "";
+ static char quitdata[80] = "";
+
+-static const char *termpath[] = {
++static const char * const termpath[] = {
+ "/usr/share/terminfo",
+ "/usr/local/share/misc/terminfo",
+ "/usr/lib/terminfo",
+Index: main/cdr.c
+===================================================================
+--- a/main/cdr.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/main/cdr.c (.../trunk) (revision 202568)
+@@ -148,13 +148,16 @@
+ AST_RWLIST_TRAVERSE_SAFE_BEGIN(&be_list, i, list) {
+ if (!strcasecmp(name, i->name)) {
+ AST_RWLIST_REMOVE_CURRENT(list);
+- ast_verb(2, "Unregistered '%s' CDR backend\n", name);
+- ast_free(i);
+ break;
+ }
+ }
+ AST_RWLIST_TRAVERSE_SAFE_END;
+ AST_RWLIST_UNLOCK(&be_list);
++
++ if (i) {
++ ast_verb(2, "Unregistered '%s' CDR backend\n", name);
++ ast_free(i);
++ }
+ }
+
+ int ast_cdr_isset_unanswered(void)
+@@ -282,10 +285,10 @@
+ }
+
+ /* readonly cdr variables */
+-static const char *cdr_readonly_vars[] = { "clid", "src", "dst", "dcontext", "channel", "dstchannel",
+- "lastapp", "lastdata", "start", "answer", "end", "duration",
+- "billsec", "disposition", "amaflags", "accountcode", "uniqueid",
+- "userfield", NULL };
++static const char * const cdr_readonly_vars[] = { "clid", "src", "dst", "dcontext", "channel", "dstchannel",
++ "lastapp", "lastdata", "start", "answer", "end", "duration",
++ "billsec", "disposition", "amaflags", "accountcode", "uniqueid",
++ "userfield", NULL };
+ /*! Set a CDR channel variable
+ \note You can't set the CDR variables that belong to the actual CDR record, like "billsec".
+ */
+Index: main/channel.c
+===================================================================
+--- a/main/channel.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/main/channel.c (.../trunk) (revision 202568)
+@@ -61,6 +61,7 @@
+ #include "asterisk/slinfactory.h"
+ #include "asterisk/audiohook.h"
+ #include "asterisk/timing.h"
++#include "asterisk/autochan.h"
+
+ #ifdef HAVE_EPOLL
+ #include <sys/epoll.h>
+@@ -121,12 +122,17 @@
+ #endif
+
+ /*! \brief the list of registered channel types */
+-static AST_LIST_HEAD_NOLOCK_STATIC(backends, chanlist);
++static AST_RWLIST_HEAD_STATIC(backends, chanlist);
+
+-/*! \brief the list of channels we have. Note that the lock for this list is used for
+- both the channels list and the backends list. */
+-static AST_RWLIST_HEAD_STATIC(channels, ast_channel);
++#ifdef LOW_MEMORY
++#define NUM_CHANNEL_BUCKETS 61
++#else
++#define NUM_CHANNEL_BUCKETS 1567
++#endif
+
++/*! \brief All active channels on the system */
++static struct ao2_container *channels;
++
+ /*! \brief map AST_CAUSE's to readable string representations
+ *
+ * \ref causes.h
+@@ -185,8 +191,10 @@
+ struct ast_variable *ast_channeltype_list(void)
+ {
+ struct chanlist *cl;
+- struct ast_variable *var=NULL, *prev = NULL;
+- AST_LIST_TRAVERSE(&backends, cl, list) {
++ struct ast_variable *var = NULL, *prev = NULL;
++
++ AST_RWLIST_RDLOCK(&backends);
++ AST_RWLIST_TRAVERSE(&backends, cl, list) {
+ if (prev) {
+ if ((prev->next = ast_variable_new(cl->tech->type, cl->tech->description, "")))
+ prev = prev->next;
+@@ -195,6 +203,8 @@
+ prev = var;
+ }
+ }
++ AST_RWLIST_UNLOCK(&backends);
++
+ return var;
+ }
+
+@@ -223,18 +233,16 @@
+ ast_cli(a->fd, FORMAT, "Type", "Description", "Devicestate", "Indications", "Transfer");
+ ast_cli(a->fd, FORMAT, "----------", "-----------", "-----------", "-----------", "--------");
+
+- AST_RWLIST_RDLOCK(&channels);
+-
+- AST_LIST_TRAVERSE(&backends, cl, list) {
++ AST_RWLIST_RDLOCK(&backends);
++ AST_RWLIST_TRAVERSE(&backends, cl, list) {
+ ast_cli(a->fd, FORMAT, cl->tech->type, cl->tech->description,
+ (cl->tech->devicestate) ? "yes" : "no",
+ (cl->tech->indicate) ? "yes" : "no",
+ (cl->tech->transfer) ? "yes" : "no");
+ count_chan++;
+ }
++ AST_RWLIST_UNLOCK(&backends);
+
+- AST_RWLIST_UNLOCK(&channels);
+-
+ ast_cli(a->fd, "----------\n%d channel drivers registered.\n", count_chan);
+
+ return CLI_SUCCESS;
+@@ -254,12 +262,14 @@
+
+ wordlen = strlen(a->word);
+
+- AST_LIST_TRAVERSE(&backends, cl, list) {
++ AST_RWLIST_RDLOCK(&backends);
++ AST_RWLIST_TRAVERSE(&backends, cl, list) {
+ if (!strncasecmp(a->word, cl->tech->type, wordlen) && ++which > a->n) {
+ ret = ast_strdup(cl->tech->type);
+ break;
+ }
+ }
++ AST_RWLIST_UNLOCK(&backends);
+
+ return ret;
+ }
+@@ -283,9 +293,9 @@
+ if (a->argc != 4)
+ return CLI_SHOWUSAGE;
+
+- AST_RWLIST_RDLOCK(&channels);
++ AST_RWLIST_RDLOCK(&backends);
+
+- AST_LIST_TRAVERSE(&backends, cl, list) {
++ AST_RWLIST_TRAVERSE(&backends, cl, list) {
+ if (!strncasecmp(cl->tech->type, a->argv[3], strlen(cl->tech->type)))
+ break;
+ }
+@@ -293,7 +303,7 @@
+
+ if (!cl) {
+ ast_cli(a->fd, "\n%s is not a registered channel driver.\n", a->argv[3]);
+- AST_RWLIST_UNLOCK(&channels);
++ AST_RWLIST_UNLOCK(&backends);
+ return CLI_FAILURE;
+ }
+
+@@ -321,7 +331,8 @@
+
+ );
+
+- AST_RWLIST_UNLOCK(&channels);
++ AST_RWLIST_UNLOCK(&backends);
++
+ return CLI_SUCCESS;
+ }
+
+@@ -343,7 +354,7 @@
+ }
+
+ /*! \brief Datastore to put the linked list of ast_chan_trace and trace status */
+-const struct ast_datastore_info ast_chan_trace_datastore_info = {
++static const struct ast_datastore_info ast_chan_trace_datastore_info = {
+ .type = "ChanTrace",
+ .destroy = ast_chan_trace_destroy_cb
+ };
+@@ -469,7 +480,7 @@
+ return 1;
+ }
+
+-static int ast_check_hangup_locked(struct ast_channel *chan)
++int ast_check_hangup_locked(struct ast_channel *chan)
+ {
+ int res;
+ ast_channel_lock(chan);
+@@ -478,30 +489,28 @@
+ return res;
+ }
+
+-/*! \brief Initiate system shutdown */
++static int ast_channel_softhangup_cb(void *obj, void *arg, int flags)
++{
++ struct ast_channel *chan = obj;
++
++ ast_softhangup(chan, AST_SOFTHANGUP_SHUTDOWN);
++
++ return 0;
++}
++
+ void ast_begin_shutdown(int hangup)
+ {
+- struct ast_channel *c;
+ shutting_down = 1;
++
+ if (hangup) {
+- AST_RWLIST_RDLOCK(&channels);
+- AST_RWLIST_TRAVERSE(&channels, c, chan_list) {
+- ast_softhangup(c, AST_SOFTHANGUP_SHUTDOWN);
+- }
+- AST_RWLIST_UNLOCK(&channels);
++ ao2_callback(channels, OBJ_NODATA | OBJ_MULTIPLE, ast_channel_softhangup_cb, NULL);
+ }
+ }
+
+ /*! \brief returns number of active/allocated channels */
+ int ast_active_channels(void)
+ {
+- struct ast_channel *c;
+- int cnt = 0;
+- AST_RWLIST_RDLOCK(&channels);
+- AST_RWLIST_TRAVERSE(&channels, c, chan_list)
+- cnt++;
+- AST_RWLIST_UNLOCK(&channels);
+- return cnt;
++ return channels ? ao2_container_count(channels) : 0;
+ }
+
+ /*! \brief Cancel a shutdown in progress */
+@@ -557,28 +566,29 @@
+ {
+ struct chanlist *chan;
+
+- AST_RWLIST_WRLOCK(&channels);
++ AST_RWLIST_WRLOCK(&backends);
+
+- AST_LIST_TRAVERSE(&backends, chan, list) {
++ AST_RWLIST_TRAVERSE(&backends, chan, list) {
+ if (!strcasecmp(tech->type, chan->tech->type)) {
+ ast_log(LOG_WARNING, "Already have a handler for type '%s'\n", tech->type);
+- AST_RWLIST_UNLOCK(&channels);
++ AST_RWLIST_UNLOCK(&backends);
+ return -1;
+ }
+ }
+
+ if (!(chan = ast_calloc(1, sizeof(*chan)))) {
+- AST_RWLIST_UNLOCK(&channels);
++ AST_RWLIST_UNLOCK(&backends);
+ return -1;
+ }
+ chan->tech = tech;
+- AST_LIST_INSERT_HEAD(&backends, chan, list);
++ AST_RWLIST_INSERT_HEAD(&backends, chan, list);
+
+ ast_debug(1, "Registered handler for '%s' (%s)\n", chan->tech->type, chan->tech->description);
+
+ ast_verb(2, "Registered channel type '%s' (%s)\n", chan->tech->type, chan->tech->description);
+
+- AST_RWLIST_UNLOCK(&channels);
++ AST_RWLIST_UNLOCK(&backends);
++
+ return 0;
+ }
+
+@@ -589,9 +599,9 @@
+
+ ast_debug(1, "Unregistering channel type '%s'\n", tech->type);
+
+- AST_RWLIST_WRLOCK(&channels);
++ AST_RWLIST_WRLOCK(&backends);
+
+- AST_LIST_TRAVERSE_SAFE_BEGIN(&backends, chan, list) {
++ AST_RWLIST_TRAVERSE_SAFE_BEGIN(&backends, chan, list) {
+ if (chan->tech == tech) {
+ AST_LIST_REMOVE_CURRENT(list);
+ ast_free(chan);
+@@ -601,7 +611,7 @@
+ }
+ AST_LIST_TRAVERSE_SAFE_END;
+
+- AST_RWLIST_UNLOCK(&channels);
++ AST_RWLIST_UNLOCK(&backends);
+ }
+
+ /*! \brief Get handle to channel driver based on name */
+@@ -610,16 +620,16 @@
+ struct chanlist *chanls;
+ const struct ast_channel_tech *ret = NULL;
+
+- AST_RWLIST_RDLOCK(&channels);
++ AST_RWLIST_RDLOCK(&backends);
+
+- AST_LIST_TRAVERSE(&backends, chanls, list) {
++ AST_RWLIST_TRAVERSE(&backends, chanls, list) {
+ if (!strcasecmp(name, chanls->tech->type)) {
+ ret = chanls->tech;
+ break;
+ }
+ }
+
+- AST_RWLIST_UNLOCK(&channels);
++ AST_RWLIST_UNLOCK(&backends);
+
+ return ret;
+ }
+@@ -766,6 +776,8 @@
+ .description = "Null channel (should not see this)",
+ };
+
++static void ast_channel_destructor(void *obj);
++
+ /*! \brief Create a new channel structure */
+ static struct ast_channel * attribute_malloc __attribute__((format(printf, 12, 0)))
+ __ast_channel_alloc_ap(int needqueue, int state, const char *cid_num, const char *cid_name,
+@@ -784,28 +796,40 @@
+ return NULL;
+ }
+
+-#if defined(__AST_DEBUG_MALLOC)
+- if (!(tmp = __ast_calloc(1, sizeof(*tmp), file, line, function))) {
++#if defined(REF_DEBUG)
++ if (!(tmp = __ao2_alloc_debug(sizeof(*tmp), ast_channel_destructor, "", file, line, function, 1))) {
+ return NULL;
+ }
++#elif defined(__AST_DEBUG_MALLOC)
++ if (!(tmp = __ao2_alloc_debug(sizeof(*tmp), ast_channel_destructor, "", file, line, function, 0))) {
++ return NULL;
++ }
+ #else
+- if (!(tmp = ast_calloc(1, sizeof(*tmp)))) {
++ if (!(tmp = ao2_alloc(sizeof(*tmp), ast_channel_destructor))) {
+ return NULL;
+ }
+ #endif
+
+ if (!(tmp->sched = sched_context_create())) {
+ ast_log(LOG_WARNING, "Channel allocation failed: Unable to create schedule context\n");
+- ast_free(tmp);
+- return NULL;
++ return ast_channel_unref(tmp);
+ }
+
+ if ((ast_string_field_init(tmp, 128))) {
+- sched_context_destroy(tmp->sched);
+- ast_free(tmp);
+- return NULL;
++ return ast_channel_unref(tmp);
+ }
+
++ if (cid_name) {
++ if (!(tmp->cid.cid_name = ast_strdup(cid_name))) {
++ return ast_channel_unref(tmp);
++ }
++ }
++ if (cid_num) {
++ if (!(tmp->cid.cid_num = ast_strdup(cid_num))) {
++ return ast_channel_unref(tmp);
++ }
++ }
++
+ #ifdef HAVE_EPOLL
+ tmp->epfd = epoll_create(25);
+ #endif
+@@ -834,6 +858,8 @@
+
+ sched_context_destroy(tmp->sched);
+ ast_string_field_free_memory(tmp);
++ ast_free(tmp->cid.cid_name);
++ ast_free(tmp->cid.cid_num);
+ ast_free(tmp);
+ return NULL;
+ } else {
+@@ -876,9 +902,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.
+@@ -923,17 +946,15 @@
+ headp = &tmp->varshead;
+ AST_LIST_HEAD_INIT_NOLOCK(headp);
+
+- ast_mutex_init(&tmp->lock_dont_use);
+-
+ AST_LIST_HEAD_INIT_NOLOCK(&tmp->datastores);
++
++ AST_LIST_HEAD_INIT_NOLOCK(&tmp->autochans);
+
+ ast_string_field_set(tmp, language, defaultlanguage);
+
+ tmp->tech = &null_tech;
+
+- AST_RWLIST_WRLOCK(&channels);
+- AST_RWLIST_INSERT_HEAD(&channels, tmp, chan_list);
+- AST_RWLIST_UNLOCK(&channels);
++ ao2_link(channels, tmp);
+
+ /*\!note
+ * and now, since the channel structure is built, and has its name, let's
+@@ -985,56 +1006,82 @@
+ return result;
+ }
+
+-/*! \brief Queue an outgoing media frame */
+-static int __ast_queue_frame(struct ast_channel *chan, struct ast_frame *fin, int head)
++static int __ast_queue_frame(struct ast_channel *chan, struct ast_frame *fin, int head, struct ast_frame *after)
+ {
+ struct ast_frame *f;
+ struct ast_frame *cur;
+ int blah = 1;
+- int qlen = 0;
++ unsigned int new_frames = 0;
++ unsigned int new_voice_frames = 0;
++ unsigned int queued_frames = 0;
++ unsigned int queued_voice_frames = 0;
++ AST_LIST_HEAD_NOLOCK(, ast_frame) frames;
+
+- /* Build us a copy and free the original one */
+- if (!(f = ast_frdup(fin))) {
+- return -1;
+- }
+-
+ ast_channel_lock(chan);
+
+ /* See if the last frame on the queue is a hangup, if so don't queue anything */
+- if ((cur = AST_LIST_LAST(&chan->readq)) && (cur->frametype == AST_FRAME_CONTROL) && (cur->subclass == AST_CONTROL_HANGUP)) {
+- ast_frfree(f);
++ if ((cur = AST_LIST_LAST(&chan->readq)) &&
++ (cur->frametype == AST_FRAME_CONTROL) &&
++ (cur->subclass == AST_CONTROL_HANGUP)) {
+ ast_channel_unlock(chan);
+ return 0;
+ }
+
++ /* Build copies of all the frames and count them */
++ AST_LIST_HEAD_INIT_NOLOCK(&frames);
++ for (cur = fin; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
++ if (!(f = ast_frdup(cur))) {
++ ast_frfree(AST_LIST_FIRST(&frames));
++ return -1;
++ }
++
++ AST_LIST_INSERT_TAIL(&frames, f, frame_list);
++ new_frames++;
++ if (f->frametype == AST_FRAME_VOICE) {
++ new_voice_frames++;
++ }
++ }
++
+ /* Count how many frames exist on the queue */
+ AST_LIST_TRAVERSE(&chan->readq, cur, frame_list) {
+- qlen++;
++ queued_frames++;
++ if (cur->frametype == AST_FRAME_VOICE) {
++ queued_voice_frames++;
++ }
+ }
+
+- /* Allow up to 96 voice frames outstanding, and up to 128 total frames */
+- if (((fin->frametype == AST_FRAME_VOICE) && (qlen > 96)) || (qlen > 128)) {
+- if (fin->frametype != AST_FRAME_VOICE) {
+- ast_log(LOG_WARNING, "Exceptionally long queue length queuing to %s\n", chan->name);
+- ast_assert(fin->frametype == AST_FRAME_VOICE);
+- } else {
+- ast_debug(1, "Dropping voice to exceptionally long queue on %s\n", chan->name);
++ if ((queued_frames + new_frames) > 128) {
++ ast_log(LOG_WARNING, "Exceptionally long queue length queuing to %s\n", chan->name);
++ while ((f = AST_LIST_REMOVE_HEAD(&frames, frame_list))) {
+ ast_frfree(f);
+- ast_channel_unlock(chan);
+- return 0;
+ }
++ ast_channel_unlock(chan);
++ return 0;
+ }
+
+- if (head) {
+- AST_LIST_INSERT_HEAD(&chan->readq, f, frame_list);
++ if ((queued_voice_frames + new_voice_frames) > 96) {
++ ast_log(LOG_WARNING, "Exceptionally long voice queue length queuing to %s\n", chan->name);
++ while ((f = AST_LIST_REMOVE_HEAD(&frames, frame_list))) {
++ ast_frfree(f);
++ }
++ ast_channel_unlock(chan);
++ return 0;
++ }
++
++ if (after) {
++ AST_LIST_INSERT_LIST_AFTER(&chan->readq, &frames, after, frame_list);
+ } else {
+- AST_LIST_INSERT_TAIL(&chan->readq, f, frame_list);
++ if (head) {
++ AST_LIST_APPEND_LIST(&frames, &chan->readq, frame_list);
++ AST_LIST_HEAD_INIT_NOLOCK(&chan->readq);
++ }
++ AST_LIST_APPEND_LIST(&chan->readq, &frames, frame_list);
+ }
+
+ if (chan->alertpipe[1] > -1) {
+- if (write(chan->alertpipe[1], &blah, sizeof(blah)) != sizeof(blah)) {
+- ast_log(LOG_WARNING, "Unable to write to alert pipe on %s, frametype/subclass %d/%d (qlen = %d): %s!\n",
+- chan->name, f->frametype, f->subclass, qlen, strerror(errno));
++ if (write(chan->alertpipe[1], &blah, new_frames * sizeof(blah)) != (new_frames * sizeof(blah))) {
++ ast_log(LOG_WARNING, "Unable to write to alert pipe on %s (qlen = %d): %s!\n",
++ chan->name, queued_frames, strerror(errno));
+ }
+ } else if (chan->timingfd > -1) {
+ ast_timer_enable_continuous(chan->timer);
+@@ -1049,12 +1096,12 @@
+
+ int ast_queue_frame(struct ast_channel *chan, struct ast_frame *fin)
+ {
+- return __ast_queue_frame(chan, fin, 0);
++ return __ast_queue_frame(chan, fin, 0, NULL);
+ }
+
+ int ast_queue_frame_head(struct ast_channel *chan, struct ast_frame *fin)
+ {
+- return __ast_queue_frame(chan, fin, 1);
++ return __ast_queue_frame(chan, fin, 1, NULL);
+ }
+
+ /*! \brief Queue a hangup frame for channel */
+@@ -1131,167 +1178,181 @@
+ ast_clear_flag(chan, AST_FLAG_DEFER_DTMF);
+ }
+
+-/*!
+- * \brief Helper function to find channels.
+- *
+- * It supports these modes:
+- *
+- * prev != NULL : get channel next in list after prev
+- * name != NULL : get channel with matching name
+- * name != NULL && namelen != 0 : get channel whose name starts with prefix
+- * exten != NULL : get channel whose exten or macroexten matches
+- * context != NULL && exten != NULL : get channel whose context or macrocontext
+- *
+- * It returns with the channel's lock held. If getting the individual lock fails,
+- * unlock and retry quickly up to 10 times, then give up.
+- *
+- * \note XXX Note that this code has cost O(N) because of the need to verify
+- * that the object is still on the global list.
+- *
+- * \note XXX also note that accessing fields (e.g. c->name in ast_log())
+- * can only be done with the lock held or someone could delete the
+- * object while we work on it. This causes some ugliness in the code.
+- * Note that removing the first ast_log() may be harmful, as it would
+- * shorten the retry period and possibly cause failures.
+- * We should definitely go for a better scheme that is deadlock-free.
+- */
+-static struct ast_channel *channel_find_locked(const struct ast_channel *prev,
+- const char *name, const int namelen,
+- const char *context, const char *exten)
++struct ast_channel *ast_channel_callback(ao2_callback_data_fn *cb_fn, void *arg,
++ void *data, int ao2_flags)
+ {
+- const char *msg = prev ? "deadlock" : "initial deadlock";
+- int retries;
+- struct ast_channel *c;
+- const struct ast_channel *_prev = prev;
++ return ao2_callback_data(channels, ao2_flags, cb_fn, arg, data);
++}
+
+- for (retries = 0; retries < 200; retries++) {
+- int done;
+- /* Reset prev on each retry. See note below for the reason. */
+- prev = _prev;
+- AST_RWLIST_RDLOCK(&channels);
+- AST_RWLIST_TRAVERSE(&channels, c, chan_list) {
+- if (prev) { /* look for last item, first, before any evaluation */
+- if (c != prev) /* not this one */
+- continue;
+- /* found, prepare to return c->next */
+- if ((c = AST_RWLIST_NEXT(c, chan_list)) == NULL) break;
+- /*!\note
+- * We're done searching through the list for the previous item.
+- * Any item after this point, we want to evaluate for a match.
+- * If we didn't set prev to NULL here, then we would only
+- * return matches for the first matching item (since the above
+- * "if (c != prev)" would not permit any other potential
+- * matches to reach the additional matching logic, below).
+- * Instead, it would just iterate until it once again found the
+- * original match, then iterate down to the end of the list and
+- * quit.
+- */
+- prev = NULL;
+- }
+- if (name) { /* want match by name */
+- if ((!namelen && strcasecmp(c->name, name) && strcmp(c->uniqueid, name)) ||
+- (namelen && strncasecmp(c->name, name, namelen)))
+- continue; /* name match failed */
+- } else if (exten) {
+- if (context && strcasecmp(c->context, context) &&
+- strcasecmp(c->macrocontext, context))
+- continue; /* context match failed */
+- if (strcasecmp(c->exten, exten) &&
+- strcasecmp(c->macroexten, exten))
+- continue; /* exten match failed */
+- }
+- /* if we get here, c points to the desired record */
+- break;
+- }
+- /* exit if chan not found or mutex acquired successfully */
+- /* this is slightly unsafe, as we _should_ hold the lock to access c->name */
+- done = c == NULL || ast_channel_trylock(c) == 0;
+- if (!done) {
+- ast_debug(1, "Avoiding %s for channel '%p'\n", msg, c);
+- if (retries == 199) {
+- /* We are about to fail due to a deadlock, so report this
+- * while we still have the list lock.
+- */
+- ast_debug(1, "Failure, could not lock '%p' after %d retries!\n", c, retries);
+- /* As we have deadlocked, we will skip this channel and
+- * see if there is another match.
+- * NOTE: No point doing this for a full-name match,
+- * as there can be no more matches.
+- */
+- if (!(name && !namelen)) {
+- prev = c;
+- retries = -1;
+- }
+- }
+- }
+- AST_RWLIST_UNLOCK(&channels);
+- if (done)
+- return c;
+- /* If we reach this point we basically tried to lock a channel and failed. Instead of
+- * starting from the beginning of the list we can restore our saved pointer to the previous
+- * channel and start from there.
+- */
+- prev = _prev;
+- usleep(1); /* give other threads a chance before retrying */
++struct ast_channel_iterator {
++ struct ao2_iterator i;
++ const char *name;
++ size_t name_len;
++ const char *exten;
++ const char *context;
++};
++
++struct ast_channel_iterator *ast_channel_iterator_destroy(struct ast_channel_iterator *i)
++{
++ if (i->name) {
++ ast_free((void *) i->name);
++ i->name = NULL;
+ }
+
++ if (i->exten) {
++ ast_free((void *) i->exten);
++ i->exten = NULL;
++ }
++
++ if (i->context) {
++ ast_free((void *) i->context);
++ i->context = NULL;
++ }
++
++ ast_free(i);
++
+ return NULL;
+ }
+
+-/*! \brief Browse channels in use */
+-struct ast_channel *ast_channel_walk_locked(const struct ast_channel *prev)
++static struct ast_channel_iterator *ast_channel_iterator_new(int ao2_flags, const char *name,
++ size_t name_len, const char *exten, const char *context)
+ {
+- return channel_find_locked(prev, NULL, 0, NULL, NULL);
++ struct ast_channel_iterator *i;
++
++ if (!(i = ast_calloc(1, sizeof(*i)))) {
++ return NULL;
++ }
++
++ if (!ast_strlen_zero(exten) && !(i->exten = ast_strdup(exten))) {
++ goto return_error;
++ }
++
++ if (!ast_strlen_zero(context) && !(i->context = ast_strdup(context))) {
++ goto return_error;
++ }
++
++ if (!ast_strlen_zero(name) && !(i->name = ast_strdup(name))) {
++ goto return_error;
++ }
++
++ i->name_len = name_len;
++
++ i->i = ao2_iterator_init(channels, ao2_flags);
++
++ return i;
++
++return_error:
++ if (i->exten) {
++ ast_free((void *) i->exten);
++ i->exten = NULL;
++ }
++
++ if (i->context) {
++ ast_free((void *) i->context);
++ i->context = NULL;
++ }
++
++ ast_free(i);
++
++ return NULL;
+ }
+
+-/*! \brief Get channel by name and lock it */
+-struct ast_channel *ast_get_channel_by_name_locked(const char *name)
++struct ast_channel_iterator *ast_channel_iterator_by_exten_new(int ao2_flags, const char *exten,
++ const char *context)
+ {
+- return channel_find_locked(NULL, name, 0, NULL, NULL);
++ return ast_channel_iterator_new(ao2_flags, NULL, 0, exten, context);
+ }
+
+-/*! \brief Get channel by name prefix and lock it */
+-struct ast_channel *ast_get_channel_by_name_prefix_locked(const char *name, const int namelen)
++struct ast_channel_iterator *ast_channel_iterator_by_name_new(int ao2_flags, const char *name,
++ size_t name_len)
+ {
+- return channel_find_locked(NULL, name, namelen, NULL, NULL);
++ return ast_channel_iterator_new(ao2_flags, name, name_len, NULL, NULL);
+ }
+
+-/*! \brief Get next channel by name prefix and lock it */
+-struct ast_channel *ast_walk_channel_by_name_prefix_locked(const struct ast_channel *chan, const char *name,
+- const int namelen)
++struct ast_channel_iterator *ast_channel_iterator_all_new(int ao2_flags)
+ {
+- return channel_find_locked(chan, name, namelen, NULL, NULL);
++ return ast_channel_iterator_new(ao2_flags, NULL, 0, NULL, NULL);
+ }
+
+-/*! \brief Get channel by exten (and optionally context) and lock it */
+-struct ast_channel *ast_get_channel_by_exten_locked(const char *exten, const char *context)
++/*!
++ * \note This function will be reduced to 1 line of code once ao2 supports
++ * returning multiple objects from an ao2_callback() using OBJ_MULTIPLE.
++ */
++struct ast_channel *ast_channel_iterator_next(struct ast_channel_iterator *i)
+ {
+- return channel_find_locked(NULL, NULL, 0, context, exten);
++ struct ast_channel *chan = NULL;
++
++ for (; (chan = ao2_iterator_next(&i->i));
++ ast_channel_unlock(chan), ast_channel_unref(chan)) {
++
++ ast_channel_lock(chan);
++
++ if (i->name) { /* match by name */
++ if (!i->name_len) {
++ if (strcasecmp(chan->name, i->name) && strcasecmp(chan->uniqueid, i->name)) {
++ continue; /* name match failed */
++ }
++ } else {
++ if (strncasecmp(chan->name, i->name, i->name_len) &&
++ strncasecmp(chan->uniqueid, i->name, i->name_len)) {
++ continue; /* name match failed */
++ }
++ }
++ } else if (i->exten) {
++ if (i->context && strcasecmp(chan->context, i->context) &&
++ strcasecmp(chan->macrocontext, i->context)) {
++ continue; /* context match failed */
++ }
++
++ if (strcasecmp(chan->exten, i->exten) &&
++ strcasecmp(chan->macroexten, i->exten)) {
++ continue; /* exten match failed */
++ }
++ }
++
++ ast_channel_unlock(chan);
++
++ break; /* chan points to the next chan desired. */
++ }
++
++ return chan;
+ }
+
+-/*! \brief Get next channel by exten (and optionally context) and lock it */
+-struct ast_channel *ast_walk_channel_by_exten_locked(const struct ast_channel *chan, const char *exten,
+- const char *context)
++static struct ast_channel *ast_channel_get_full(const char *name, size_t name_len,
++ const char *exten, const char *context)
+ {
+- return channel_find_locked(chan, NULL, 0, context, exten);
++ struct ast_channel tmp_chan = {
++ .name = name,
++ /* This is sort of a hack. Basically, we're using an arbitrary field
++ * in ast_channel to pass the name_len for a prefix match. If this
++ * gets changed, then the compare callback must be changed, too. */
++ .rings = name_len,
++ };
++
++ if (exten) {
++ ast_copy_string(tmp_chan.exten, exten, sizeof(tmp_chan.exten));
++ }
++
++ if (context) {
++ ast_copy_string(tmp_chan.context, context, sizeof(tmp_chan.context));
++ }
++
++ return ao2_find(channels, &tmp_chan, OBJ_POINTER);
+ }
+
+-/*! \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 *ast_channel_get_by_name(const char *name)
+ {
+- struct ast_channel *c = NULL;
++ return ast_channel_get_full(name, 0, NULL, 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);
++struct ast_channel *ast_channel_get_by_name_prefix(const char *name, size_t name_len)
++{
++ return ast_channel_get_full(name, name_len, NULL, NULL);
++}
+
+- return c;
++struct ast_channel *ast_channel_get_by_exten(const char *exten, const char *context)
++{
++ return ast_channel_get_full(NULL, 0, exten, context);
+ }
+
+ /*! \brief Wait, look for hangups and condition arg */
+@@ -1336,9 +1397,290 @@
+ cid->cid_dnid = cid->cid_num = cid->cid_name = cid->cid_ani = cid->cid_rdnis = NULL;
+ }
+
++struct ast_channel *ast_channel_release(struct ast_channel *chan)
++{
++ /* Safe, even if already unlinked. */
++ ao2_unlink(channels, chan);
++ return ast_channel_unref(chan);
++}
++
++/*!
++ * \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)
++static void ast_channel_destructor(void *obj)
+ {
++ struct ast_channel *chan = obj;
+ int fd;
+ #ifdef HAVE_EPOLL
+ int i;
+@@ -1348,18 +1690,9 @@
+ struct varshead *headp;
+ struct ast_datastore *datastore = NULL;
+ char name[AST_CHANNEL_NAME], *dashptr;
+-
+- headp=&chan->varshead;
+-
+- AST_RWLIST_WRLOCK(&channels);
+- if (!AST_RWLIST_REMOVE(&channels, chan, chan_list)) {
+- ast_log(LOG_ERROR, "Unable to find channel in list to free. Assuming it has already been done.\n");
+- }
+- /* Lock and unlock the channel just to be sure nobody has it locked still
+- due to a reference retrieved from the channel list. */
+- ast_channel_lock(chan);
+- ast_channel_unlock(chan);
+
++ headp = &chan->varshead;
++
+ /* Get rid of each of the data stores on the channel */
+ while ((datastore = AST_LIST_REMOVE_HEAD(&chan->datastores, entry)))
+ /* Free the data store */
+@@ -1398,7 +1731,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);
+@@ -1437,11 +1774,7 @@
+ 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);
+
+ /* Queue an unknown state, because, while we know that this particular
+ * instance is dead, we don't know the state of all other possible
+@@ -1723,9 +2056,9 @@
+ ast_cdr_detach(chan->cdr);
+ chan->cdr = NULL;
+ }
+-
+- ast_channel_free(chan);
+
++ chan = ast_channel_release(chan);
++
+ return res;
+ }
+
+@@ -2420,6 +2753,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:
+@@ -2720,13 +3055,14 @@
+ chan->fdno = -1;
+
+ if (f) {
++ struct ast_frame *readq_tail = AST_LIST_LAST(&chan->readq);
++
+ /* if the channel driver returned more than one frame, stuff the excess
+- into the readq for the next ast_read call (note that we can safely assume
+- that the readq is empty, because otherwise we would not have called into
+- the channel driver and f would be only a single frame)
++ into the readq for the next ast_read call
+ */
+ if (AST_LIST_NEXT(f, frame_list)) {
+- AST_LIST_HEAD_SET_NOLOCK(&chan->readq, AST_LIST_NEXT(f, frame_list));
++ ast_queue_frame(chan, AST_LIST_NEXT(f, frame_list));
++ ast_frfree(AST_LIST_NEXT(f, frame_list));
+ AST_LIST_NEXT(f, frame_list) = NULL;
+ }
+
+@@ -2946,12 +3282,30 @@
+ }
+ }
+
+- if (chan->readtrans && (f = ast_translate(chan->readtrans, f, 1)) == NULL)
++ if (chan->readtrans && (f = ast_translate(chan->readtrans, f, 1)) == NULL) {
+ f = &ast_null_frame;
+- else
+- /* Run generator sitting on the line if timing device not available
+- * and synchronous generation of outgoing frames is necessary */
+- ast_read_generator_actions(chan, f);
++ }
++
++ /* it is possible for the translation process on chan->readtrans to have
++ produced multiple frames from the single input frame we passed it; if
++ this happens, queue the additional frames *before* the frames we may
++ have queued earlier. if the readq was empty, put them at the head of
++ the queue, and if it was not, put them just after the frame that was
++ at the end of the queue.
++ */
++ if (AST_LIST_NEXT(f, frame_list)) {
++ if (!readq_tail) {
++ ast_queue_frame_head(chan, AST_LIST_NEXT(f, frame_list));
++ } else {
++ __ast_queue_frame(chan, AST_LIST_NEXT(f, frame_list), 0, readq_tail);
++ }
++ ast_frfree(AST_LIST_NEXT(f, frame_list));
++ AST_LIST_NEXT(f, frame_list) = NULL;
++ }
++
++ /* Run generator sitting on the line if timing device not available
++ * and synchronous generation of outgoing frames is necessary */
++ ast_read_generator_actions(chan, f);
+ }
+ default:
+ /* Just pass it on! */
+@@ -3022,7 +3376,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:
+@@ -3043,7 +3400,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);
+
+@@ -3052,10 +3409,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);
+@@ -3084,6 +3472,16 @@
+ switch (condition) {
+ case AST_CONTROL_RINGING:
+ ts = ast_get_indication_tone(chan->zone, "ring");
++ /* It is common practice for channel drivers to return -1 if trying
++ * to indicate ringing on a channel which is up. The idea is to let the
++ * core generate the ringing inband. However, we don't want the
++ * warning message about not being able to handle the specific indication
++ * to print nor do we want ast_indicate_data to return an "error" for this
++ * condition
++ */
++ if (chan->_state == AST_STATE_UP) {
++ res = 0;
++ }
+ break;
+ case AST_CONTROL_BUSY:
+ ts = ast_get_indication_tone(chan->zone, "busy");
+@@ -3108,6 +3506,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;
+@@ -3185,7 +3586,7 @@
+ {
+ /* Device does not support DTMF tones, lets fake
+ * it by doing our own generation. */
+- static const char* dtmf_tones[] = {
++ static const char * const dtmf_tones[] = {
+ "941+1336", /* 0 */
+ "697+1209", /* 1 */
+ "697+1336", /* 2 */
+@@ -3280,7 +3681,7 @@
+ int ast_write(struct ast_channel *chan, struct ast_frame *fr)
+ {
+ int res = -1;
+- struct ast_frame *f = NULL, *f2 = NULL;
++ struct ast_frame *f = NULL;
+ int count = 0;
+
+ /*Deadlock avoidance*/
+@@ -3352,10 +3753,12 @@
+ break;
+ case AST_FRAME_DTMF_END:
+ if (chan->audiohooks) {
+- struct ast_frame *old_frame = fr;
+- fr = ast_audiohook_write_list(chan, chan->audiohooks, AST_AUDIOHOOK_DIRECTION_WRITE, fr);
+- if (old_frame != fr)
+- f = fr;
++ struct ast_frame *new_frame = fr;
++
++ new_frame = ast_audiohook_write_list(chan, chan->audiohooks, AST_AUDIOHOOK_DIRECTION_WRITE, fr);
++ if (new_frame != fr) {
++ ast_frfree(new_frame);
++ }
+ }
+ send_dtmf_event(chan, "Sent", fr->subclass, "No", "Yes");
+ ast_clear_flag(chan, AST_FLAG_BLOCKING);
+@@ -3390,14 +3793,6 @@
+ if (chan->tech->write == NULL)
+ break; /*! \todo XXX should return 0 maybe ? */
+
+- /* If audiohooks are present, write the frame out */
+- if (chan->audiohooks) {
+- struct ast_frame *old_frame = fr;
+- fr = ast_audiohook_write_list(chan, chan->audiohooks, AST_AUDIOHOOK_DIRECTION_WRITE, fr);
+- if (old_frame != fr)
+- f2 = fr;
+- }
+-
+ /* If the frame is in the raw write format, then it's easy... just use the frame - otherwise we will have to translate */
+ if (fr->subclass == chan->rawwriteformat)
+ f = fr;
+@@ -3409,37 +3804,82 @@
+ break;
+ }
+
++ if (chan->audiohooks) {
++ struct ast_frame *new_frame, *cur;
++
++ for (cur = f; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
++ new_frame = ast_audiohook_write_list(chan, chan->audiohooks, AST_AUDIOHOOK_DIRECTION_WRITE, cur);
++ if (new_frame != cur) {
++ ast_frfree(new_frame);
++ }
++ }
++ }
++
+ /* If Monitor is running on this channel, then we have to write frames out there too */
++ /* the translator on chan->writetrans may have returned multiple frames
++ from the single frame we passed in; if so, feed each one of them to the
++ monitor */
+ if (chan->monitor && chan->monitor->write_stream) {
++ struct ast_frame *cur;
++
++ for (cur = f; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
+ /* XXX must explain this code */
+ #ifndef MONITOR_CONSTANT_DELAY
+- int jump = chan->insmpl - chan->outsmpl - 4 * f->samples;
+- if (jump >= 0) {
+- jump = chan->insmpl - chan->outsmpl;
+- if (ast_seekstream(chan->monitor->write_stream, jump, SEEK_FORCECUR) == -1)
+- ast_log(LOG_WARNING, "Failed to perform seek in monitoring write stream, synchronization between the files may be broken\n");
+- chan->outsmpl += jump + f->samples;
+- } else
+- chan->outsmpl += f->samples;
++ int jump = chan->insmpl - chan->outsmpl - 4 * cur->samples;
++ if (jump >= 0) {
++ jump = chan->insmpl - chan->outsmpl;
++ if (ast_seekstream(chan->monitor->write_stream, jump, SEEK_FORCECUR) == -1)
++ ast_log(LOG_WARNING, "Failed to perform seek in monitoring write stream, synchronization between the files may be broken\n");
++ chan->outsmpl += jump + cur->samples;
++ } else {
++ chan->outsmpl += cur->samples;
++ }
+ #else
+- int jump = chan->insmpl - chan->outsmpl;
+- if (jump - MONITOR_DELAY >= 0) {
+- if (ast_seekstream(chan->monitor->write_stream, jump - f->samples, SEEK_FORCECUR) == -1)
+- ast_log(LOG_WARNING, "Failed to perform seek in monitoring write stream, synchronization between the files may be broken\n");
+- chan->outsmpl += jump;
+- } else
+- chan->outsmpl += f->samples;
++ int jump = chan->insmpl - chan->outsmpl;
++ if (jump - MONITOR_DELAY >= 0) {
++ if (ast_seekstream(chan->monitor->write_stream, jump - cur->samples, SEEK_FORCECUR) == -1)
++ ast_log(LOG_WARNING, "Failed to perform seek in monitoring write stream, synchronization between the files may be broken\n");
++ chan->outsmpl += jump;
++ } else {
++ chan->outsmpl += cur->samples;
++ }
+ #endif
+- if (chan->monitor->state == AST_MONITOR_RUNNING) {
+- if (ast_writestream(chan->monitor->write_stream, f) < 0)
+- ast_log(LOG_WARNING, "Failed to write data to channel monitor write stream\n");
++ if (chan->monitor->state == AST_MONITOR_RUNNING) {
++ if (ast_writestream(chan->monitor->write_stream, cur) < 0)
++ ast_log(LOG_WARNING, "Failed to write data to channel monitor write stream\n");
++ }
+ }
+ }
+
+- if (f)
+- res = chan->tech->write(chan,f);
+- else
+- res = 0;
++ /* the translator on chan->writetrans may have returned multiple frames
++ from the single frame we passed in; if so, feed each one of them to the
++ channel, freeing each one after it has been written */
++ if ((f != fr) && AST_LIST_NEXT(f, frame_list)) {
++ struct ast_frame *cur, *next;
++ unsigned int skip = 0;
++
++ for (cur = f, next = AST_LIST_NEXT(cur, frame_list);
++ cur;
++ cur = next, next = cur ? AST_LIST_NEXT(cur, frame_list) : NULL) {
++ if (!skip) {
++ if ((res = chan->tech->write(chan, cur)) < 0) {
++ chan->_softhangup |= AST_SOFTHANGUP_DEV;
++ skip = 1;
++ } else if (next) {
++ /* don't do this for the last frame in the list,
++ as the code outside the loop will do it once
++ */
++ chan->fout = FRAMECOUNT_INC(chan->fout);
++ }
++ }
++ ast_frfree(cur);
++ }
++
++ /* reset f so the code below doesn't attempt to free it */
++ f = NULL;
++ } else {
++ res = chan->tech->write(chan, f);
++ }
+ break;
+ case AST_FRAME_NULL:
+ case AST_FRAME_IAX:
+@@ -3456,13 +3896,12 @@
+
+ if (f && f != fr)
+ ast_frfree(f);
+- if (f2)
+- ast_frfree(f2);
+ ast_clear_flag(chan, AST_FLAG_BLOCKING);
++
+ /* Consider a write failure to force a soft hangup */
+- if (res < 0)
++ if (res < 0) {
+ chan->_softhangup |= AST_SOFTHANGUP_DEV;
+- else {
++ } else {
+ chan->fout = FRAMECOUNT_INC(chan->fout);
+ }
+ done:
+@@ -3473,7 +3912,7 @@
+ static int set_format(struct ast_channel *chan, int fmt, int *rawformat, int *format,
+ struct ast_trans_pvt **trans, const int direction)
+ {
+- int native;
++ int native, native_fmt = ast_best_codec(fmt);
+ int res;
+ char from[200], to[200];
+
+@@ -3484,7 +3923,19 @@
+
+ if (!fmt || !native) /* No audio requested */
+ return 0; /* Let's try a call without any sounds (video, text) */
+-
++
++ /* See if the underlying channel driver is capable of performing transcoding for us */
++ if (!ast_channel_setoption(chan, direction ? AST_OPTION_FORMAT_WRITE : AST_OPTION_FORMAT_READ, &native_fmt, sizeof(int*), 0)) {
++ ast_debug(1, "Channel driver natively set channel %s to %s format %s (%d)\n", chan->name,
++ direction ? "write" : "read", ast_getformatname(native_fmt), native_fmt);
++ chan->nativeformats = *rawformat = *format = native_fmt;
++ if (*trans) {
++ ast_translator_free_path(*trans);
++ }
++ *trans = NULL;
++ return 0;
++ }
++
+ /* Find a translation path from the native format to one of the desired formats */
+ if (!direction)
+ /* reading */
+@@ -3580,6 +4031,7 @@
+ {
+ char tmpchan[256];
+ struct ast_channel *new = NULL;
++ struct ast_party_redirecting *apr = &orig->redirecting;
+ char *data, *type;
+ int cause = 0;
+
+@@ -3604,6 +4056,8 @@
+ return NULL;
+ }
+
++ ast_channel_set_redirecting(new, apr);
++
+ /* Copy/inherit important information into new channel */
+ if (oh) {
+ if (oh->vars) {
+@@ -3613,6 +4067,7 @@
+ ast_set_callerid(new, oh->cid_num, oh->cid_name, oh->cid_num);
+ }
+ if (oh->parent_channel) {
++ ast_channel_update_redirecting(oh->parent_channel, apr);
+ ast_channel_inherit_variables(oh->parent_channel, new);
+ ast_channel_datastore_inherit(oh->parent_channel, new);
+ }
+@@ -3620,6 +4075,7 @@
+ ast_cdr_setaccount(new, oh->account);
+ }
+ } else if (caller) { /* no outgoing helper so use caller if avaliable */
++ ast_channel_update_redirecting(caller, apr);
+ ast_channel_inherit_variables(caller, new);
+ ast_channel_datastore_inherit(caller, new);
+ }
+@@ -3630,9 +4086,8 @@
+ }
+ ast_copy_flags(new->cdr, orig->cdr, AST_CDR_FLAG_ORIGINATED);
+ ast_string_field_set(new, accountcode, orig->accountcode);
+- if (!ast_strlen_zero(orig->cid.cid_num) && !ast_strlen_zero(new->cid.cid_name)) {
+- ast_set_callerid(new, orig->cid.cid_num, orig->cid.cid_name, orig->cid.cid_num);
+- }
++ ast_party_caller_copy(&new->cid, &orig->cid);
++ ast_party_connected_line_copy(&new->connected, &orig->connected);
+ ast_channel_unlock(new);
+ ast_channel_unlock(orig);
+
+@@ -3655,6 +4110,7 @@
+ struct ast_channel *chan;
+ int res = 0;
+ int last_subclass = 0;
++ struct ast_party_connected_line connected;
+
+ if (outstate)
+ *outstate = 0;
+@@ -3681,8 +4137,14 @@
+ if (oh->account)
+ ast_cdr_setaccount(chan, oh->account);
+ }
++
+ ast_set_callerid(chan, cid_num, cid_name, cid_num);
+ ast_set_flag(chan->cdr, AST_CDR_FLAG_ORIGINATED);
++ 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);
+@@ -3728,6 +4190,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;
+
+@@ -3794,12 +4258,12 @@
+ cause = &foo;
+ *cause = AST_CAUSE_NOTDEFINED;
+
+- if (AST_RWLIST_RDLOCK(&channels)) {
+- ast_log(LOG_WARNING, "Unable to lock channel list\n");
++ if (AST_RWLIST_RDLOCK(&backends)) {
++ ast_log(LOG_WARNING, "Unable to lock technology backend list\n");
+ return NULL;
+ }
+
+- AST_LIST_TRAVERSE(&backends, chan, list) {
++ AST_RWLIST_TRAVERSE(&backends, chan, list) {
+ if (strcasecmp(type, chan->tech->type))
+ continue;
+
+@@ -3813,11 +4277,11 @@
+ if (res < 0) {
+ ast_log(LOG_WARNING, "No translator path exists for channel type %s (native 0x%x) to 0x%x\n", type, chan->tech->capabilities, format);
+ *cause = AST_CAUSE_BEARERCAPABILITY_NOTAVAIL;
+- AST_RWLIST_UNLOCK(&channels);
++ AST_RWLIST_UNLOCK(&backends);
+ return NULL;
+ }
+ }
+- AST_RWLIST_UNLOCK(&channels);
++ AST_RWLIST_UNLOCK(&backends);
+ if (!chan->tech->requester)
+ return NULL;
+
+@@ -3830,7 +4294,7 @@
+
+ ast_log(LOG_WARNING, "No channel type registered for '%s'\n", type);
+ *cause = AST_CAUSE_NOSUCHDRIVER;
+- AST_RWLIST_UNLOCK(&channels);
++ AST_RWLIST_UNLOCK(&backends);
+
+ return NULL;
+ }
+@@ -3876,6 +4340,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;
+ }
+
+@@ -3955,6 +4450,12 @@
+ int src;
+ int dst;
+
++ /* See if the channel driver can natively make these two channels compatible */
++ if (from->tech->bridge && from->tech->bridge == to->tech->bridge &&
++ !ast_channel_setoption(from, AST_OPTION_MAKE_COMPATIBLE, to, sizeof(struct ast_channel *), 0)) {
++ return 0;
++ }
++
+ if (from->readformat == to->writeformat && from->writeformat == to->readformat) {
+ /* Already compatible! Moving on ... */
+ return 0;
+@@ -4087,10 +4588,16 @@
+ return res;
+ }
+
+-void ast_change_name(struct ast_channel *chan, char *newname)
++void ast_change_name(struct ast_channel *chan, const char *newname)
+ {
++ /* We must re-link, as the hash value will change here. */
++ ao2_unlink(channels, chan);
++
+ manager_event(EVENT_FLAG_CALL, "Rename", "Channel: %s\r\nNewname: %s\r\nUniqueid: %s\r\n", chan->name, newname, chan->uniqueid);
++
+ ast_string_field_set(chan, name, newname);
++
++ ao2_link(channels, chan);
+ }
+
+ void ast_channel_inherit_variables(const struct ast_channel *parent, struct ast_channel *child)
+@@ -4160,6 +4667,26 @@
+ }
+
+ /*!
++ * \pre chan is locked
++ */
++static void report_new_callerid(const struct ast_channel *chan)
++{
++ manager_event(EVENT_FLAG_CALL, "NewCallerid",
++ "Channel: %s\r\n"
++ "CallerIDNum: %s\r\n"
++ "CallerIDName: %s\r\n"
++ "Uniqueid: %s\r\n"
++ "CID-CallingPres: %d (%s)\r\n",
++ chan->name,
++ S_OR(chan->cid.cid_num, ""),
++ S_OR(chan->cid.cid_name, ""),
++ chan->uniqueid,
++ chan->cid.cid_pres,
++ ast_describe_caller_presentation(chan->cid.cid_pres)
++ );
++}
++
++/*!
+ \brief Masquerade a channel
+
+ \note Assumes channel will be locked when called
+@@ -4172,7 +4699,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;
+@@ -4182,12 +4713,6 @@
+ char masqn[AST_CHANNEL_NAME];
+ char zombn[AST_CHANNEL_NAME];
+
+- ast_debug(4, "Actually Masquerading %s(%d) into the structure of %s(%d)\n",
+- clonechan->name, clonechan->_state, original->name, original->_state);
+-
+- manager_event(EVENT_FLAG_CALL, "Masquerade", "Clone: %s\r\nCloneState: %s\r\nOriginal: %s\r\nOriginalState: %s\r\n",
+- clonechan->name, ast_state2str(clonechan->_state), original->name, ast_state2str(original->_state));
+-
+ /* XXX This is a seriously wacked 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
+@@ -4196,34 +4721,33 @@
+ /* We need the clone's lock, too */
+ ast_channel_lock(clonechan);
+
+- ast_debug(2, "Got clone lock for masquerade on '%s' at %p\n", clonechan->name, &clonechan->lock_dont_use);
++ ast_debug(4, "Actually Masquerading %s(%d) into the structure of %s(%d)\n",
++ clonechan->name, clonechan->_state, original->name, original->_state);
+
++ manager_event(EVENT_FLAG_CALL, "Masquerade", "Clone: %s\r\nCloneState: %s\r\nOriginal: %s\r\nOriginalState: %s\r\n",
++ clonechan->name, ast_state2str(clonechan->_state), original->name, ast_state2str(original->_state));
++
+ /* Having remembered the original read/write formats, we turn off any translation on either
+ one */
+ free_translation(clonechan);
+ free_translation(original);
+
+-
+ /* Unlink the masquerade */
+ original->masq = NULL;
+ clonechan->masqr = NULL;
+-
++
+ /* Save the original name */
+ ast_copy_string(orig, original->name, sizeof(orig));
+ /* Save the new name */
+ ast_copy_string(newn, clonechan->name, sizeof(newn));
+ /* Create the masq name */
+ snprintf(masqn, sizeof(masqn), "%s<MASQ>", newn);
+-
++
+ /* Copy the name from the clone channel */
+- ast_string_field_set(original, name, newn);
++ ast_change_name(original, newn);
+
+ /* Mangle the name of the clone channel */
+- ast_string_field_set(clonechan, name, masqn);
+-
+- /* Notify any managers of the change, first the masq then the other */
+- manager_event(EVENT_FLAG_CALL, "Rename", "Channel: %s\r\nNewname: %s\r\nUniqueid: %s\r\n", newn, masqn, clonechan->uniqueid);
+- manager_event(EVENT_FLAG_CALL, "Rename", "Channel: %s\r\nNewname: %s\r\nUniqueid: %s\r\n", orig, newn, original->uniqueid);
++ ast_change_name(clonechan, masqn);
+
+ /* Swap the technologies */
+ t = original->tech;
+@@ -4309,10 +4833,9 @@
+ return -1;
+ }
+
++ /* Mangle the name of the clone channel */
+ snprintf(zombn, sizeof(zombn), "%s<ZOMBIE>", orig);
+- /* Mangle the name of the clone channel */
+- ast_string_field_set(clonechan, name, zombn);
+- manager_event(EVENT_FLAG_CALL, "Rename", "Channel: %s\r\nNewname: %s\r\nUniqueid: %s\r\n", masqn, zombn, clonechan->uniqueid);
++ ast_change_name(clonechan, zombn);
+
+ /* Update the type. */
+ t_pvt = original->monitor;
+@@ -4332,13 +4855,19 @@
+ /* Move data stores over */
+ if (AST_LIST_FIRST(&clonechan->datastores)) {
+ struct ast_datastore *ds;
+- AST_LIST_TRAVERSE(&clonechan->datastores, ds, entry) {
++ /* We use a safe traversal here because some fixup routines actually
++ * remove the datastore from the list and free them.
++ */
++ AST_LIST_TRAVERSE_SAFE_BEGIN(&clonechan->datastores, ds, entry) {
+ if (ds->info->chan_fixup)
+ ds->info->chan_fixup(ds->data, clonechan, original);
+ }
++ AST_LIST_TRAVERSE_SAFE_END;
+ AST_LIST_APPEND_LIST(&original->datastores, &clonechan->datastores, entry);
+ }
+
++ ast_autochan_new_channel(clonechan, original);
++
+ clone_variables(original, clonechan);
+ /* Presense of ADSI capable CPE follows clone */
+ original->adsicpe = clonechan->adsicpe;
+@@ -4353,12 +4882,22 @@
+ /* 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;
++ report_new_callerid(original);
+
++ 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);
+
+@@ -4404,7 +4943,7 @@
+ if (original->visible_indication) {
+ ast_indicate(original, original->visible_indication);
+ }
+-
++
+ /* Now, at this point, the "clone" channel is totally F'd up. We mark it as
+ a zombie so nothing tries to touch it. If it's already been marked as a
+ zombie, then free it now (since it already is considered invalid). */
+@@ -4421,7 +4960,7 @@
+ clonechan->hangupcause,
+ ast_cause2str(clonechan->hangupcause)
+ );
+- ast_channel_free(clonechan);
++ clonechan = ast_channel_release(clonechan);
+ } else {
+ ast_debug(1, "Released clone lock on '%s'\n", clonechan->name);
+ ast_set_flag(clonechan, AST_FLAG_ZOMBIE);
+@@ -4455,20 +4994,9 @@
+ ast_free(chan->cid.cid_ani);
+ chan->cid.cid_ani = ast_strdup(cid_ani);
+ }
+- manager_event(EVENT_FLAG_CALL, "NewCallerid",
+- "Channel: %s\r\n"
+- "CallerIDNum: %s\r\n"
+- "CallerIDName: %s\r\n"
+- "Uniqueid: %s\r\n"
+- "CID-CallingPres: %d (%s)\r\n",
+- chan->name,
+- S_OR(chan->cid.cid_num, ""),
+- S_OR(chan->cid.cid_name, ""),
+- chan->uniqueid,
+- chan->cid.cid_pres,
+- ast_describe_caller_presentation(chan->cid.cid_pres)
+- );
+-
++
++ report_new_callerid(chan);
++
+ ast_channel_unlock(chan);
+ }
+
+@@ -4555,7 +5083,7 @@
+
+ static enum ast_bridge_result ast_generic_bridge(struct ast_channel *c0, struct ast_channel *c1,
+ struct ast_bridge_config *config, struct ast_frame **fo,
+- struct ast_channel **rc, struct timeval bridge_end)
++ struct ast_channel **rc)
+ {
+ /* Copy voice back and forth between the two channels. */
+ struct ast_channel *cs[3];
+@@ -4588,11 +5116,10 @@
+ ast_poll_channel_add(c0, c1);
+
+ if (config->feature_timer > 0 && ast_tvzero(config->nexteventts)) {
+- /* calculate when the bridge should possibly break
++ /* nexteventts is not set when the bridge is not scheduled to
++ * break, so calculate when the bridge should possibly break
+ * if a partial feature match timed out */
+- config->partialfeature_timer = ast_tvadd(ast_tvnow(), ast_samp2tv(config->feature_timer, 1000));
+- } else {
+- memset(&config->partialfeature_timer, 0, sizeof(config->partialfeature_timer));
++ config->nexteventts = ast_tvadd(ast_tvnow(), ast_samp2tv(config->feature_timer, 1000));
+ }
+
+ for (;;) {
+@@ -4605,13 +5132,17 @@
+ res = AST_BRIDGE_RETRY;
+ break;
+ }
+- if (bridge_end.tv_sec) {
+- to = ast_tvdiff_ms(bridge_end, ast_tvnow());
++ if (config->nexteventts.tv_sec) {
++ to = ast_tvdiff_ms(config->nexteventts, ast_tvnow());
+ if (to <= 0) {
+- if (config->timelimit) {
++ if (config->timelimit && !config->feature_timer && !ast_test_flag(config, AST_FEATURE_WARNING_ACTIVE)) {
+ res = AST_BRIDGE_RETRY;
+ /* generic bridge ending to play warning */
+ ast_set_flag(config, AST_FEATURE_WARNING_ACTIVE);
++ } else if (config->feature_timer) {
++ /* feature timer expired - make sure we do not play warning */
++ ast_clear_flag(config, AST_FEATURE_WARNING_ACTIVE);
++ res = AST_BRIDGE_RETRY;
+ } else {
+ res = AST_BRIDGE_COMPLETE;
+ }
+@@ -4622,8 +5153,8 @@
+ * to not break, leave the channel bridge when the feature timer
+ * time has elapsed so the DTMF will be sent to the other side.
+ */
+- if (!ast_tvzero(config->partialfeature_timer)) {
+- int diff = ast_tvdiff_ms(config->partialfeature_timer, ast_tvnow());
++ if (!ast_tvzero(config->nexteventts)) {
++ int diff = ast_tvdiff_ms(config->nexteventts, ast_tvnow());
+ if (diff <= 0) {
+ res = AST_BRIDGE_RETRY;
+ break;
+@@ -4667,11 +5198,19 @@
+ int bridge_exit = 0;
+
+ switch (f->subclass) {
++ case AST_CONTROL_REDIRECTING:
++ ast_indicate_data(other, f->subclass, f->data.ptr, f->datalen);
++ break;
++ case AST_CONTROL_CONNECTED_LINE:
++ if (ast_channel_connected_line_macro(who, other, f, other == c0, 1)) {
++ ast_indicate_data(other, f->subclass, f->data.ptr, f->datalen);
++ }
++ break;
+ case AST_CONTROL_HOLD:
+ case AST_CONTROL_UNHOLD:
+ case AST_CONTROL_VIDUPDATE:
++ case AST_CONTROL_T38:
+ case AST_CONTROL_SRCUPDATE:
+- case AST_CONTROL_T38:
+ ast_indicate_data(other, f->subclass, f->data.ptr, f->datalen);
+ if (jb_in_use) {
+ ast_jb_empty_and_reset(c0, c1);
+@@ -4698,8 +5237,8 @@
+ /* monitored dtmf causes exit from bridge */
+ int monitored_source = (who == c0) ? watch_c0_dtmf : watch_c1_dtmf;
+
+- if (monitored_source &&
+- (f->frametype == AST_FRAME_DTMF_END ||
++ if (monitored_source &&
++ (f->frametype == AST_FRAME_DTMF_END ||
+ f->frametype == AST_FRAME_DTMF_BEGIN)) {
+ *fo = f;
+ *rc = who;
+@@ -4753,13 +5292,13 @@
+ {
+ manager_event(EVENT_FLAG_CALL, "Bridge",
+ "Bridgestate: %s\r\n"
+- "Bridgetype: %s\r\n"
+- "Channel1: %s\r\n"
+- "Channel2: %s\r\n"
+- "Uniqueid1: %s\r\n"
+- "Uniqueid2: %s\r\n"
+- "CallerID1: %s\r\n"
+- "CallerID2: %s\r\n",
++ "Bridgetype: %s\r\n"
++ "Channel1: %s\r\n"
++ "Channel2: %s\r\n"
++ "Uniqueid1: %s\r\n"
++ "Uniqueid2: %s\r\n"
++ "CallerID1: %s\r\n"
++ "CallerID2: %s\r\n",
+ onoff ? "Link" : "Unlink",
+ type == 1 ? "core" : "native",
+ c0->name, c1->name, c0->uniqueid, c1->uniqueid,
+@@ -4838,7 +5377,6 @@
+ struct ast_channel *who = NULL;
+ enum ast_bridge_result res = AST_BRIDGE_COMPLETE;
+ int nativefailed=0;
+- int firstpass;
+ int o0nativeformats;
+ int o1nativeformats;
+ long time_left_ms=0;
+@@ -4862,21 +5400,17 @@
+ return -1;
+
+ *fo = NULL;
+- firstpass = config->firstpass;
+- config->firstpass = 0;
+
+- if (ast_tvzero(config->start_time))
++ if (ast_tvzero(config->start_time)) {
+ config->start_time = ast_tvnow();
+- time_left_ms = config->timelimit;
+-
+- caller_warning = ast_test_flag(&config->features_caller, AST_FEATURE_PLAY_WARNING);
+- callee_warning = ast_test_flag(&config->features_callee, AST_FEATURE_PLAY_WARNING);
+-
+- if (config->start_sound && firstpass) {
+- if (caller_warning)
+- bridge_playfile(c0, c1, config->start_sound, time_left_ms / 1000);
+- if (callee_warning)
+- bridge_playfile(c1, c0, config->start_sound, time_left_ms / 1000);
++ if (config->start_sound) {
++ if (caller_warning) {
++ bridge_playfile(c0, c1, config->start_sound, config->timelimit / 1000);
++ }
++ if (callee_warning) {
++ bridge_playfile(c1, c0, config->start_sound, config->timelimit / 1000);
++ }
++ }
+ }
+
+ /* Keep track of bridge */
+@@ -4888,11 +5422,26 @@
+ o1nativeformats = c1->nativeformats;
+
+ if (config->feature_timer && !ast_tvzero(config->nexteventts)) {
+- config->nexteventts = ast_tvadd(config->start_time, ast_samp2tv(config->feature_timer, 1000));
+- } else if (config->timelimit && firstpass) {
++ config->nexteventts = ast_tvadd(config->feature_start_time, ast_samp2tv(config->feature_timer, 1000));
++ } else if (config->timelimit) {
++ time_left_ms = config->timelimit - ast_tvdiff_ms(ast_tvnow(), config->start_time);
++ caller_warning = ast_test_flag(&config->features_caller, AST_FEATURE_PLAY_WARNING);
++ callee_warning = ast_test_flag(&config->features_callee, AST_FEATURE_PLAY_WARNING);
+ config->nexteventts = ast_tvadd(config->start_time, ast_samp2tv(config->timelimit, 1000));
+- if (caller_warning || callee_warning)
+- config->nexteventts = ast_tvsub(config->nexteventts, ast_samp2tv(config->play_warning, 1000));
++ if ((caller_warning || callee_warning) && config->play_warning) {
++ long next_warn = config->play_warning;
++ if (time_left_ms < config->play_warning) {
++ /* At least one warning was played, which means we are returning after feature */
++ long warns_passed = (config->play_warning - time_left_ms) / config->warning_freq;
++ /* It is 'warns_passed * warning_freq' NOT '(warns_passed + 1) * warning_freq',
++ because nexteventts will be updated once again in the 'if (!to)' block */
++ next_warn = config->play_warning - warns_passed * config->warning_freq;
++ }
++ config->nexteventts = ast_tvsub(config->nexteventts, ast_samp2tv(next_warn, 1000));
++ }
++ } else {
++ config->nexteventts.tv_sec = 0;
++ config->nexteventts.tv_usec = 0;
+ }
+
+ if (!c0->tech->send_digit_begin)
+@@ -4948,10 +5497,12 @@
+ if (callee_warning)
+ bridge_playfile(c1, c0, config->warning_sound, t);
+ }
+- if (config->warning_freq && (time_left_ms > (config->warning_freq + 5000)))
++
++ if (config->warning_freq && (time_left_ms > (config->warning_freq + 5000))) {
+ config->nexteventts = ast_tvadd(config->nexteventts, ast_samp2tv(config->warning_freq, 1000));
+- else
++ } else {
+ config->nexteventts = ast_tvadd(config->start_time, ast_samp2tv(config->timelimit, 1000));
++ }
+ }
+ ast_clear_flag(config, AST_FEATURE_WARNING_ACTIVE);
+ }
+@@ -4996,7 +5547,6 @@
+ ast_set_flag(c0, AST_FLAG_NBRIDGE);
+ ast_set_flag(c1, AST_FLAG_NBRIDGE);
+ if ((res = c0->tech->bridge(c0, c1, config->flags, fo, rc, to)) == AST_BRIDGE_COMPLETE) {
+- /* \todo XXX here should check that cid_num is not NULL */
+ manager_event(EVENT_FLAG_CALL, "Unlink",
+ "Channel1: %s\r\n"
+ "Channel2: %s\r\n"
+@@ -5004,7 +5554,7 @@
+ "Uniqueid2: %s\r\n"
+ "CallerID1: %s\r\n"
+ "CallerID2: %s\r\n",
+- c0->name, c1->name, c0->uniqueid, c1->uniqueid, c0->cid.cid_num, c1->cid.cid_num);
++ c0->name, c1->name, c0->uniqueid, c1->uniqueid, S_OR(c0->cid.cid_num, "<unknown>"), S_OR(c1->cid.cid_num, "<unknown>"));
+ ast_debug(1, "Returning from native bridge, channels: %s, %s\n", c0->name, c1->name);
+
+ ast_clear_flag(c0, AST_FLAG_NBRIDGE);
+@@ -5050,7 +5600,7 @@
+
+ update_bridge_vars(c0, c1);
+
+- res = ast_generic_bridge(c0, c1, config, fo, rc, config->nexteventts);
++ res = ast_generic_bridge(c0, c1, config, fo, rc);
+ if (res != AST_BRIDGE_RETRY) {
+ break;
+ } else if (config->feature_timer) {
+@@ -5069,7 +5619,6 @@
+ c0->_bridge = NULL;
+ c1->_bridge = NULL;
+
+- /* \todo XXX here should check that cid_num is not NULL */
+ manager_event(EVENT_FLAG_CALL, "Unlink",
+ "Channel1: %s\r\n"
+ "Channel2: %s\r\n"
+@@ -5077,7 +5626,7 @@
+ "Uniqueid2: %s\r\n"
+ "CallerID1: %s\r\n"
+ "CallerID2: %s\r\n",
+- c0->name, c1->name, c0->uniqueid, c1->uniqueid, c0->cid.cid_num, c1->cid.cid_num);
++ c0->name, c1->name, c0->uniqueid, c1->uniqueid, S_OR(c0->cid.cid_num, "<unknown>"), S_OR(c1->cid.cid_num, "<unknown>"));
+ ast_debug(1, "Bridge stops bridging channels %s and %s\n", c0->name, c1->name);
+
+ return res;
+@@ -5338,8 +5887,58 @@
+ ast_moh_cleanup_ptr(chan);
+ }
+
++static int ast_channel_hash_cb(const void *obj, const int flags)
++{
++ const struct ast_channel *chan = obj;
++
++ /* If the name isn't set, return 0 so that the ao2_find() search will
++ * start in the first bucket. */
++ if (ast_strlen_zero(chan->name)) {
++ return 0;
++ }
++
++ return ast_str_case_hash(chan->name);
++}
++
++static int ast_channel_cmp_cb(void *obj, void *arg, int flags)
++{
++ struct ast_channel *chan = obj, *cmp_args = arg;
++ size_t name_len;
++ int ret = CMP_MATCH;
++
++ /* This is sort of a hack. Basically, we're using an arbitrary field
++ * in ast_channel to pass the name_len for a prefix match. If this
++ * gets changed, then the uses of ao2_find() must be changed, too. */
++ name_len = cmp_args->rings;
++
++ ast_channel_lock(chan);
++
++ if (cmp_args->name) { /* match by name */
++ if ((!name_len && strcasecmp(chan->name, cmp_args->name)) ||
++ (name_len && strncasecmp(chan->name, cmp_args->name, name_len))) {
++ ret = 0; /* name match failed */
++ }
++ } else if (cmp_args->exten) {
++ if (cmp_args->context && strcasecmp(chan->context, cmp_args->context) &&
++ strcasecmp(chan->macrocontext, cmp_args->context)) {
++ ret = 0; /* context match failed */
++ }
++ if (ret && strcasecmp(chan->exten, cmp_args->exten) &&
++ strcasecmp(chan->macroexten, cmp_args->exten)) {
++ ret = 0; /* exten match failed */
++ }
++ }
++
++ ast_channel_unlock(chan);
++
++ return ret;
++}
++
+ void ast_channels_init(void)
+ {
++ channels = ao2_container_alloc(NUM_CHANNEL_BUCKETS,
++ ast_channel_hash_cb, ast_channel_cmp_cb);
++
+ ast_cli_register_multiple(cli_channel, ARRAY_LEN(cli_channel));
+ }
+
+@@ -5474,116 +6073,6 @@
+ }
+ };
+
+-#ifdef DEBUG_CHANNEL_LOCKS
+-
+-/*! \brief Unlock AST channel (and print debugging output)
+-\note You need to enable DEBUG_CHANNEL_LOCKS for this function
+-*/
+-int __ast_channel_unlock(struct ast_channel *chan, const char *filename, int lineno, const char *func)
+-{
+- int res = 0;
+- ast_debug(3, "::::==== Unlocking AST channel %s\n", chan->name);
+-
+- if (!chan) {
+- ast_debug(1, "::::==== Unlocking non-existing channel \n");
+- return 0;
+- }
+-#ifdef DEBUG_THREADS
+- res = __ast_pthread_mutex_unlock(filename, lineno, func, "(channel lock)", &chan->lock_dont_use);
+-#else
+- res = ast_mutex_unlock(&chan->lock_dont_use);
+-#endif
+-
+- if (option_debug > 2) {
+-#ifdef DEBUG_THREADS
+- int count = 0;
+- if ((count = chan->lock_dont_use.track.reentrancy))
+- ast_debug(3, ":::=== Still have %d locks (recursive)\n", count);
+-#endif
+- if (!res)
+- ast_debug(3, "::::==== Channel %s was unlocked\n", chan->name);
+- if (res == EINVAL) {
+- ast_debug(3, "::::==== Channel %s had no lock by this thread. Failed unlocking\n", chan->name);
+- }
+- }
+- if (res == EPERM) {
+- /* We had no lock, so okay any way*/
+- ast_debug(4, "::::==== Channel %s was not locked at all \n", chan->name);
+- res = 0;
+- }
+- return res;
+-}
+-
+-/*! \brief Lock AST channel (and print debugging output)
+-\note You need to enable DEBUG_CHANNEL_LOCKS for this function */
+-int __ast_channel_lock(struct ast_channel *chan, const char *filename, int lineno, const char *func)
+-{
+- int res;
+-
+- ast_debug(4, "====:::: Locking AST channel %s\n", chan->name);
+-
+-#ifdef DEBUG_THREADS
+- res = __ast_pthread_mutex_lock(filename, lineno, func, "(channel lock)", &chan->lock_dont_use);
+-#else
+- res = ast_mutex_lock(&chan->lock_dont_use);
+-#endif
+-
+- if (option_debug > 3) {
+-#ifdef DEBUG_THREADS
+- int count = 0;
+- if ((count = chan->lock_dont_use.track.reentrancy))
+- ast_debug(4, ":::=== Now have %d locks (recursive)\n", count);
+-#endif
+- if (!res)
+- ast_debug(4, "::::==== Channel %s was locked\n", chan->name);
+- if (res == EDEADLK) {
+- /* We had no lock, so okey any way */
+- ast_debug(4, "::::==== Channel %s was not locked by us. Lock would cause deadlock.\n", chan->name);
+- }
+- if (res == EINVAL) {
+- ast_debug(4, "::::==== Channel %s lock failed. No mutex.\n", chan->name);
+- }
+- }
+- return res;
+-}
+-
+-/*! \brief Lock AST channel (and print debugging output)
+-\note You need to enable DEBUG_CHANNEL_LOCKS for this function */
+-int __ast_channel_trylock(struct ast_channel *chan, const char *filename, int lineno, const char *func)
+-{
+- int res;
+-
+- ast_debug(3, "====:::: Trying to lock AST channel %s\n", chan->name);
+-#ifdef DEBUG_THREADS
+- res = __ast_pthread_mutex_trylock(filename, lineno, func, "(channel lock)", &chan->lock_dont_use);
+-#else
+- res = ast_mutex_trylock(&chan->lock_dont_use);
+-#endif
+-
+- if (option_debug > 2) {
+-#ifdef DEBUG_THREADS
+- int count = 0;
+- if ((count = chan->lock_dont_use.track.reentrancy))
+- ast_debug(3, ":::=== Now have %d locks (recursive)\n", count);
+-#endif
+- if (!res)
+- ast_debug(3, "::::==== Channel %s was locked\n", chan->name);
+- if (res == EBUSY) {
+- /* We failed to lock */
+- ast_debug(3, "::::==== Channel %s failed to lock. Not waiting around...\n", chan->name);
+- }
+- if (res == EDEADLK) {
+- /* We had no lock, so okey any way*/
+- ast_debug(3, "::::==== Channel %s was not locked. Lock would cause deadlock.\n", chan->name);
+- }
+- if (res == EINVAL)
+- ast_debug(3, "::::==== Channel %s lock failed. No mutex.\n", chan->name);
+- }
+- return res;
+-}
+-
+-#endif
+-
+ /*
+ * Wrappers for various ast_say_*() functions that call the full version
+ * of the same functions.
+@@ -5638,6 +6127,616 @@
+ 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);
++}
++
++int ast_channel_connected_line_macro(struct ast_channel *autoservice_chan, struct ast_channel *macro_chan, const void *connected_info, int caller, int frame)
++{
++ const char *macro;
++ const char *macro_args;
++ union {
++ const struct ast_frame *frame;
++ const struct ast_party_connected_line *connected;
++ } pointer;
++ int retval;
++
++ if (frame) {
++ pointer.frame = connected_info;
++ } else {
++ pointer.connected = connected_info;
++ }
++
++ ast_channel_lock(macro_chan);
++ macro = ast_strdupa(S_OR(pbx_builtin_getvar_helper(macro_chan, caller ? "CONNECTED_LINE_CALLER_SEND_MACRO" : "CONNECTED_LINE_CALLEE_SEND_MACRO"), ""));
++ macro_args = ast_strdupa(S_OR(pbx_builtin_getvar_helper(macro_chan, caller ? "CONNECTED_LINE_CALLER_SEND_MACRO_ARGS" : "CONNECTED_LINE_CALLEE_SEND_MACRO_ARGS"), ""));
++ ast_channel_unlock(macro_chan);
++
++ if (ast_strlen_zero(macro)) {
++ return -1;
++ }
++
++ if (frame) {
++ ast_connected_line_parse_data(pointer.frame->data.ptr, pointer.frame->datalen, &macro_chan->connected);
++ } else {
++ ast_party_connected_line_copy(&macro_chan->connected, pointer.connected);
++ }
++
++ if (!(retval = ast_app_run_macro(autoservice_chan, macro_chan, macro, macro_args))) {
++ ast_channel_update_connected_line(macro_chan, &macro_chan->connected);
++ }
++
++ return retval;
++}
++
+ /* DO NOT PUT ADDITIONAL FUNCTIONS BELOW THIS BOUNDARY
+ *
+ * ONLY FUNCTIONS FOR PROVIDING BACKWARDS ABI COMPATIBILITY BELONG HERE
+Index: main/manager.c
+===================================================================
+--- a/main/manager.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/main/manager.c (.../trunk) (revision 202568)
+@@ -22,7 +22,7 @@
+ *
+ * \author Mark Spencer <markster@digium.com>
+ *
+- * \extref OpenSSL http://www.openssl.org - for AMI/SSL
++ * \extref OpenSSL http://www.openssl.org - for AMI/SSL
+ *
+ * At the moment this file contains a number of functions, namely:
+ *
+@@ -75,6 +75,618 @@
+ #include "asterisk/astobj2.h"
+ #include "asterisk/features.h"
+
++/*** DOCUMENTATION
++ <manager name="Ping" language="en_US">
++ <synopsis>
++ Keepalive command.
++ </synopsis>
++ <syntax>
++ <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
++ </syntax>
++ <description>
++ <para>A 'Ping' action will ellicit a 'Pong' response. Used to keep the
++ manager connection open.</para>
++ </description>
++ </manager>
++ <manager name="Events" language="en_US">
++ <synopsis>
++ Control Event Flow.
++ </synopsis>
++ <syntax>
++ <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
++ <parameter name="EventMask" required="true">
++ <enumlist>
++ <enum name="on">
++ <para>If all events should be sent.</para>
++ </enum>
++ <enum name="off">
++ <para>If no events should be sent.</para>
++ </enum>
++ <enum name="system,call,log,...">
++ <para>To select which flags events should have to be sent.</para>
++ </enum>
++ </enumlist>
++ </parameter>
++ </syntax>
++ <description>
++ <para>Enable/Disable sending of events to this manager client.</para>
++ </description>
++ </manager>
++ <manager name="Logoff" language="en_US">
++ <synopsis>
++ Logoff Manager.
++ </synopsis>
++ <syntax>
++ <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
++ </syntax>
++ <description>
++ <para>Logoff the current manager session.</para>
++ </description>
++ </manager>
++ <manager name="Login" language="en_US">
++ <synopsis>
++ Login Manager.
++ </synopsis>
++ <syntax>
++ <parameter name="ActionID">
++ <para>ActionID for this transaction. Will be returned.</para>
++ </parameter>
++ </syntax>
++ <description>
++ <para>Login Manager.</para>
++ </description>
++ </manager>
++ <manager name="Challenge" language="en_US">
++ <synopsis>
++ Generate Challenge for MD5 Auth.
++ </synopsis>
++ <syntax>
++ <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
++ </syntax>
++ <description>
++ <para>Generate a challenge for MD5 authentication.</para>
++ </description>
++ </manager>
++ <manager name="Hangup" language="en_US">
++ <synopsis>
++ Hangup channel.
++ </synopsis>
++ <syntax>
++ <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
++ <parameter name="Channel" required="true">
++ <para>The channel name to be hangup.</para>
++ </parameter>
++ <parameter name="Cause">
++ <para>Numeric hangup cause.</para>
++ </parameter>
++ </syntax>
++ <description>
++ <para>Hangup a channel.</para>
++ </description>
++ </manager>
++ <manager name="Status" language="en_US">
++ <synopsis>
++ List channel status.
++ </synopsis>
++ <syntax>
++ <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
++ <parameter name="Channel" required="true">
++ <para>The name of the channel to query for status.</para>
++ </parameter>
++ <parameter name="Variables">
++ <para>Comma <literal>,</literal> separated list of variable to include.</para>
++ </parameter>
++ </syntax>
++ <description>
++ <para>Will return the status information of each channel along with the
++ value for the specified channel variables.</para>
++ </description>
++ </manager>
++ <manager name="Setvar" language="en_US">
++ <synopsis>
++ Set a channel variable.
++ </synopsis>
++ <syntax>
++ <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
++ <parameter name="Channel">
++ <para>Channel to set variable for.</para>
++ </parameter>
++ <parameter name="Variable" required="true">
++ <para>Variable name.</para>
++ </parameter>
++ <parameter name="Value" required="true">
++ <para>Variable value.</para>
++ </parameter>
++ </syntax>
++ <description>
++ <para>Set a global or local channel variable.</para>
++ </description>
++ </manager>
++ <manager name="Getvar" language="en_US">
++ <synopsis>
++ Gets a channel variable.
++ </synopsis>
++ <syntax>
++ <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
++ <parameter name="Channel">
++ <para>Channel to read variable from.</para>
++ </parameter>
++ <parameter name="Variable" required="true">
++ <para>Variable name.</para>
++ </parameter>
++ </syntax>
++ <description>
++ <para>Get the value of a global or local channel variable.</para>
++ </description>
++ </manager>
++ <manager name="GetConfig" language="en_US">
++ <synopsis>
++ Retrieve configuration.
++ </synopsis>
++ <syntax>
++ <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
++ <parameter name="Filename" required="true">
++ <para>Configuration filename (e.g. <filename>foo.conf</filename>).</para>
++ </parameter>
++ <parameter name="Category">
++ <para>Category in configuration file.</para>
++ </parameter>
++ </syntax>
++ <description>
++ <para>This action will dump the contents of a configuration
++ file by category and contents or optionally by specified category only.</para>
++ </description>
++ </manager>
++ <manager name="GetConfigJSON" language="en_US">
++ <synopsis>
++ Retrieve configuration (JSON format).
++ </synopsis>
++ <syntax>
++ <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
++ <parameter name="Filename" required="true">
++ <para>Configuration filename (e.g. <filename>foo.conf</filename>).</para>
++ </parameter>
++ </syntax>
++ <description>
++ <para>This action will dump the contents of a configuration file by category
++ and contents in JSON format. This only makes sense to be used using rawman over
++ the HTTP interface.</para>
++ </description>
++ </manager>
++ <manager name="UpdateConfig" language="en_US">
++ <synopsis>
++ Update basic configuration.
++ </synopsis>
++ <syntax>
++ <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
++ <parameter name="SrcFilename" required="true">
++ <para>Configuration filename to read (e.g. <filename>foo.conf</filename>).</para>
++ </parameter>
++ <parameter name="DstFilename" required="true">
++ <para>Configuration filename to write (e.g. <filename>foo.conf</filename>)</para>
++ </parameter>
++ <parameter name="Reload">
++ <para>Whether or not a reload should take place (or name of specific module).</para>
++ </parameter>
++ <parameter name="Action-XXXXXX">
++ <para>Action to take.</para>
++ <para>X's represent 6 digit number beginning with 000000.</para>
++ <enumlist>
++ <enum name="NewCat" />
++ <enum name="RenameCat" />
++ <enum name="DelCat" />
++ <enum name="EmptyCat" />
++ <enum name="Update" />
++ <enum name="Delete" />
++ <enum name="Append" />
++ <enum name="Insert" />
++ </enumlist>
++ </parameter>
++ <parameter name="Cat-XXXXXX">
++ <para>Category to operate on.</para>
++ <xi:include xpointer="xpointer(/docs/manager[@name='UpdateConfig']/syntax/parameter[@name='Action-XXXXXX']/para[2])" />
++ </parameter>
++ <parameter name="Var-XXXXXX">
++ <para>Variable to work on.</para>
++ <xi:include xpointer="xpointer(/docs/manager[@name='UpdateConfig']/syntax/parameter[@name='Action-XXXXXX']/para[2])" />
++ </parameter>
++ <parameter name="Value-XXXXXX">
++ <para>Value to work on.</para>
++ <xi:include xpointer="xpointer(/docs/manager[@name='UpdateConfig']/syntax/parameter[@name='Action-XXXXXX']/para[2])" />
++ </parameter>
++ <parameter name="Match-XXXXXX">
++ <para>Extra match required to match line.</para>
++ <xi:include xpointer="xpointer(/docs/manager[@name='UpdateConfig']/syntax/parameter[@name='Action-XXXXXX']/para[2])" />
++ </parameter>
++ <parameter name="Line-XXXXXX">
++ <para>Line in category to operate on (used with delete and insert actions).</para>
++ <xi:include xpointer="xpointer(/docs/manager[@name='UpdateConfig']/syntax/parameter[@name='Action-XXXXXX']/para[2])" />
++ </parameter>
++ </syntax>
++ <description>
++ <para>This action will modify, create, or delete configuration elements
++ in Asterisk configuration files.</para>
++ </description>
++ </manager>
++ <manager name="CreateConfig" language="en_US">
++ <synopsis>
++ Creates an empty file in the configuration directory.
++ </synopsis>
++ <syntax>
++ <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
++ <parameter name="Filename" required="true">
++ <para>The configuration filename to create (e.g. <filename>foo.conf</filename>).</para>
++ </parameter>
++ </syntax>
++ <description>
++ <para>This action will create an empty file in the configuration
++ directory. This action is intended to be used before an UpdateConfig
++ action.</para>
++ </description>
++ </manager>
++ <manager name="ListCategories" language="en_US">
++ <synopsis>
++ List categories in configuration file.
++ </synopsis>
++ <syntax>
++ <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
++ <parameter name="Filename" required="true">
++ <para>Configuration filename (e.g. <filename>foo.conf</filename>).</para>
++ </parameter>
++ </syntax>
++ <description>
++ <para>This action will dump the categories in a given file.</para>
++ </description>
++ </manager>
++ <manager name="Redirect" language="en_US">
++ <synopsis>
++ Redirect (transfer) a call.
++ </synopsis>
++ <syntax>
++ <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
++ <parameter name="Channel" required="true">
++ <para>Channel to redirect.</para>
++ </parameter>
++ <parameter name="ExtraChannel">
++ <para>Second call leg to transfer (optional).</para>
++ </parameter>
++ <parameter name="Exten" required="true">
++ <para>Extension to transfer to.</para>
++ </parameter>
++ <parameter name="Context" required="true">
++ <para>Context to transfer to.</para>
++ </parameter>
++ <parameter name="Priority" required="true">
++ <para>Priority to transfer to.</para>
++ </parameter>
++ </syntax>
++ <description>
++ <para>Redirect (transfer) a call.</para>
++ </description>
++ </manager>
++ <manager name="Atxfer" language="en_US">
++ <synopsis>
++ Attended transfer.
++ </synopsis>
++ <syntax>
++ <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
++ <parameter name="Channel" required="true">
++ <para>Transferer's channel.</para>
++ </parameter>
++ <parameter name="Exten" required="true">
++ <para>Extension to transfer to.</para>
++ </parameter>
++ <parameter name="Context" required="true">
++ <para>Context to transfer to.</para>
++ </parameter>
++ <parameter name="Priority" required="true">
++ <para>Priority to transfer to.</para>
++ </parameter>
++ </syntax>
++ <description>
++ <para>Attended transfer.</para>
++ </description>
++ </manager>
++ <manager name="Originate" language="en_US">
++ <synopsis>
++ Originate a call.
++ </synopsis>
++ <syntax>
++ <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
++ <parameter name="Channel" required="true">
++ <para>Channel name to call.</para>
++ </parameter>
++ <parameter name="Exten">
++ <para>Extension to use (requires <literal>Context</literal> and
++ <literal>Priority</literal>)</para>
++ </parameter>
++ <parameter name="Context">
++ <para>Context to use (requires <literal>Exten</literal> and
++ <literal>Priority</literal>)</para>
++ </parameter>
++ <parameter name="Priority">
++ <para>Priority to use (requires <literal>Exten</literal> and
++ <literal>Context</literal>)</para>
++ </parameter>
++ <parameter name="Application">
++ <para>Application to execute.</para>
++ </parameter>
++ <parameter name="Data">
++ <para>Data to use (requires <literal>Application</literal>).</para>
++ </parameter>
++ <parameter name="Timeout">
++ <para>How long to wait for call to be answered (in ms).</para>
++ </parameter>
++ <parameter name="CallerID">
++ <para>Caller ID to be set on the outgoing channel.</para>
++ </parameter>
++ <parameter name="Variable">
++ <para>Channel variable to set, multiple Variable: headers are allowed.</para>
++ </parameter>
++ <parameter name="Account">
++ <para>Account code.</para>
++ </parameter>
++ <parameter name="Async">
++ <para>Set to <literal>true</literal> for fast origination.</para>
++ </parameter>
++ </syntax>
++ <description>
++ <para>Generates an outgoing call to a
++ <replaceable>Extension</replaceable>/<replaceable>Context</replaceable>/<replaceable>Priority</replaceable>
++ or <replaceable>Application</replaceable>/<replaceable>Data</replaceable></para>
++ </description>
++ </manager>
++ <manager name="Command" language="en_US">
++ <synopsis>
++ Execute Asterisk CLI Command.
++ </synopsis>
++ <syntax>
++ <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
++ <parameter name="Command" required="true">
++ <para>Asterisk CLI command to run.</para>
++ </parameter>
++ </syntax>
++ <description>
++ <para>Run a CLI command.</para>
++ </description>
++ </manager>
++ <manager name="ExtensionState" language="en_US">
++ <synopsis>
++ Check Extension Status.
++ </synopsis>
++ <syntax>
++ <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
++ <parameter name="Exten" required="true">
++ <para>Extension to check state on.</para>
++ </parameter>
++ <parameter name="Context" required="true">
++ <para>Context for extension.</para>
++ </parameter>
++ </syntax>
++ <description>
++ <para>Report the extension state for given extension. If the extension has a hint,
++ will use devicestate to check the status of the device connected to the extension.</para>
++ <para>Will return an <literal>Extension Status</literal> message. The response will include
++ the hint for the extension and the status.</para>
++ </description>
++ </manager>
++ <manager name="AbsoluteTimeout" language="en_US">
++ <synopsis>
++ Set absolute timeout.
++ </synopsis>
++ <syntax>
++ <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
++ <parameter name="Channel" required="true">
++ <para>Channel name to hangup.</para>
++ </parameter>
++ <parameter name="Timeout" required="true">
++ <para>Maximum duration of the call (sec).</para>
++ </parameter>
++ </syntax>
++ <description>
++ <para>Hangup a channel after a certain time. Acknowledges set time with
++ <literal>Timeout Set</literal> message.</para>
++ </description>
++ </manager>
++ <manager name="MailboxStatus" language="en_US">
++ <synopsis>
++ Check mailbox.
++ </synopsis>
++ <syntax>
++ <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
++ <parameter name="Mailbox" required="true">
++ <para>Full mailbox ID <replaceable>mailbox</replaceable>@<replaceable>vm-context</replaceable>.</para>
++ </parameter>
++ </syntax>
++ <description>
++ <para>Checks a voicemail account for status.</para>
++ <para>Returns number of messages.</para>
++ <para>Message: Mailbox Status.</para>
++ <para>Mailbox: <replaceable>mailboxid</replaceable>.</para>
++ <para>Waiting: <replaceable>count</replaceable>.</para>
++ </description>
++ </manager>
++ <manager name="MailboxCount" language="en_US">
++ <synopsis>
++ Check Mailbox Message Count.
++ </synopsis>
++ <syntax>
++ <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
++ <parameter name="Mailbox" required="true">
++ <para>Full mailbox ID <replaceable>mailbox</replaceable>@<replaceable>vm-context</replaceable>.</para>
++ </parameter>
++ </syntax>
++ <description>
++ <para>Checks a voicemail account for new messages.</para>
++ <para>Returns number of urgent, new and old messages.</para>
++ <para>Message: Mailbox Message Count</para>
++ <para>Mailbox: <replaceable>mailboxid</replaceable></para>
++ <para>UrgentMessages: <replaceable>count</replaceable></para>
++ <para>NewMessages: <replaceable>count</replaceable></para>
++ <para>OldMessages: <replaceable>count</replaceable></para>
++ </description>
++ </manager>
++ <manager name="ListCommands" language="en_US">
++ <synopsis>
++ List available manager commands.
++ </synopsis>
++ <syntax>
++ <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
++ </syntax>
++ <description>
++ <para>Returns the action name and synopsis for every action that
++ is available to the user.</para>
++ </description>
++ </manager>
++ <manager name="SendText" language="en_US">
++ <synopsis>
++ Send text message to channel.
++ </synopsis>
++ <syntax>
++ <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
++ <parameter name="Channel" required="true">
++ <para>Channel to send message to.</para>
++ </parameter>
++ <parameter name="Message" required="true">
++ <para>Message to send.</para>
++ </parameter>
++ </syntax>
++ <description>
++ <para>Sends A Text Message to a channel while in a call.</para>
++ </description>
++ </manager>
++ <manager name="UserEvent" language="en_US">
++ <synopsis>
++ Send an arbitrary event.
++ </synopsis>
++ <syntax>
++ <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
++ <parameter name="UserEvent" required="true">
++ <para>Event string to send.</para>
++ </parameter>
++ <parameter name="Header1">
++ <para>Content1.</para>
++ </parameter>
++ <parameter name="HeaderN">
++ <para>ContentN.</para>
++ </parameter>
++ </syntax>
++ <description>
++ <para>Send an event to manager sessions.</para>
++ </description>
++ </manager>
++ <manager name="WaitEvent" language="en_US">
++ <synopsis>
++ Wait for an event to occur.
++ </synopsis>
++ <syntax>
++ <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
++ <parameter name="Timeout" required="true">
++ <para>Maximum time (in seconds) to wait for events, <literal>-1</literal> means forever.</para>
++ </parameter>
++ </syntax>
++ <description>
++ <para>This action will ellicit a <literal>Success</literal> response. Whenever
++ a manager event is queued. Once WaitEvent has been called on an HTTP manager
++ session, events will be generated and queued.</para>
++ </description>
++ </manager>
++ <manager name="CoreSettings" language="en_US">
++ <synopsis>
++ Show PBX core settings (version etc).
++ </synopsis>
++ <syntax>
++ <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
++ </syntax>
++ <description>
++ <para>Query for Core PBX settings.</para>
++ </description>
++ </manager>
++ <manager name="CoreStatus" language="en_US">
++ <synopsis>
++ Show PBX core status variables.
++ </synopsis>
++ <syntax>
++ <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
++ </syntax>
++ <description>
++ <para>Query for Core PBX status.</para>
++ </description>
++ </manager>
++ <manager name="Reload" language="en_US">
++ <synopsis>
++ Send a reload event.
++ </synopsis>
++ <syntax>
++ <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
++ <parameter name="Module">
++ <para>Name of the module to reload.</para>
++ </parameter>
++ </syntax>
++ <description>
++ <para>Send a reload event.</para>
++ </description>
++ </manager>
++ <manager name="CoreShowChannels" language="en_US">
++ <synopsis>
++ List currently active channels.
++ </synopsis>
++ <syntax>
++ <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
++ </syntax>
++ <description>
++ <para>List currently defined channels and some information about them.</para>
++ </description>
++ </manager>
++ <manager name="ModuleLoad" language="en_US">
++ <synopsis>
++ Module management.
++ </synopsis>
++ <syntax>
++ <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
++ <parameter name="Module">
++ <para>Asterisk module name (including .so extension) or subsystem identifier:</para>
++ <enumlist>
++ <enum name="cdr" />
++ <enum name="enum" />
++ <enum name="dnsmgr" />
++ <enum name="extconfig" />
++ <enum name="manager" />
++ <enum name="rtp" />
++ <enum name="http" />
++ </enumlist>
++ </parameter>
++ <parameter name="LoadType" required="true">
++ <para>The operation to be done on module.</para>
++ <enumlist>
++ <enum name="load" />
++ <enum name="unload" />
++ <enum name="reload" />
++ </enumlist>
++ <para>If no module is specified for a <literal>reload</literal> loadtype,
++ all modules are reloaded.</para>
++ </parameter>
++ </syntax>
++ <description>
++ <para>Loads, unloads or reloads an Asterisk module in a running system.</para>
++ </description>
++ </manager>
++ <manager name="ModuleCheck" language="en_US">
++ <synopsis>
++ Check if module is loaded.
++ </synopsis>
++ <syntax>
++ <parameter name="Module" required="true">
++ <para>Asterisk module name (not including extension).</para>
++ </parameter>
++ </syntax>
++ <description>
++ <para>Checks if Asterisk module is loaded. Will return Success/Failure.
++ For success returns, the module revision number is included.</para>
++ </description>
++ </manager>
++ ***/
++
+ enum error_type {
+ UNKNOWN_ACTION = 1,
+ UNKNOWN_CATEGORY,
+@@ -126,8 +738,10 @@
+ static int manager_enabled = 0;
+ static int webmanager_enabled = 0;
+
++#define DEFAULT_REALM "asterisk"
++static char global_realm[MAXHOSTNAMELEN]; /*!< Default realm */
++
+ static int block_sockets;
+-static int num_sessions;
+
+ static int manager_debug; /*!< enable some debugging code in the manager */
+
+@@ -138,11 +752,12 @@
+ * AMI session have managerid == 0; the entry is created upon a connect,
+ * and destroyed with the socket.
+ * HTTP sessions have managerid != 0, the value is used as a search key
+- * to lookup sessions (using the mansession_id cookie).
++ * to lookup sessions (using the mansession_id cookie, or nonce key from
++ * Digest Authentication http header).
+ */
+ #define MAX_BLACKLIST_CMD_LEN 2
+-static struct {
+- char *words[AST_MAX_CMD_LEN];
++static const struct {
++ const char *words[AST_MAX_CMD_LEN];
+ } command_blacklist[] = {
+ {{ "module", "load", NULL }},
+ {{ "module", "unload", NULL }},
+@@ -183,7 +798,6 @@
+ */
+ 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 */
+ struct sockaddr_in sin; /*!< address we are connecting from */
+ FILE *f; /*!< fdopen() on the underlying fd */
+@@ -206,6 +820,9 @@
+ struct eventqent *last_ev; /*!< last event processed. */
+ int writetimeout; /*!< Timeout for ast_carefulwrite() */
+ int pending_event; /*!< Pending events indicator in case when waiting_thread is NULL */
++ time_t noncetime; /*!< Timer for nonce value expiration */
++ unsigned long oldnonce; /*!< Stale nonce value */
++ unsigned long nc; /*!< incremental nonce counter */
+ AST_LIST_HEAD_NOLOCK(mansession_datastores, ast_datastore) datastores; /*!< Data stores on the session */
+ AST_LIST_ENTRY(mansession_session) list;
+ };
+@@ -219,12 +836,13 @@
+ struct mansession_session *session;
+ FILE *f;
+ int fd;
++ ast_mutex_t lock;
+ };
+
++static struct ao2_container *sessions = NULL;
++
+ #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
+@@ -238,8 +856,9 @@
+ int readperm; /*! Authorization for reading */
+ int writeperm; /*! Authorization for writing */
+ int writetimeout; /*! Per user Timeout for ast_carefulwrite() */
+- int displayconnects; /*!< XXX unused */
+- int keep; /*!< mark entries created on a reload */
++ int displayconnects; /*!< XXX unused */
++ int keep; /*!< mark entries created on a reload */
++ char *a1_hash; /*!< precalculated A1 for Digest auth */
+ AST_RWLIST_ENTRY(ast_manager_user) list;
+ };
+
+@@ -252,13 +871,15 @@
+ /*! \brief list of hooks registered */
+ static AST_RWLIST_HEAD_STATIC(manager_hooks, manager_custom_hook);
+
++static struct eventqent *unref_event(struct eventqent *e);
++static void ref_event(struct eventqent *e);
++
+ /*! \brief Add a custom hook to be called when an event is fired */
+ void ast_manager_register_hook(struct manager_custom_hook *hook)
+ {
+ AST_RWLIST_WRLOCK(&manager_hooks);
+ AST_RWLIST_INSERT_TAIL(&manager_hooks, hook, list);
+ AST_RWLIST_UNLOCK(&manager_hooks);
+- return;
+ }
+
+ /*! \brief Delete a custom hook to be called when an event is fired */
+@@ -267,52 +888,8 @@
+ AST_RWLIST_WRLOCK(&manager_hooks);
+ AST_RWLIST_REMOVE(&manager_hooks, hook, list);
+ AST_RWLIST_UNLOCK(&manager_hooks);
+- return;
+ }
+
+-/*! \brief
+- * Event list management functions.
+- * We assume that the event list always has at least one element,
+- * and the delete code will not remove the last entry even if the
+- *
+- */
+-#if 0
+-static time_t __deb(time_t start, const char *msg)
+-{
+- time_t now = time(NULL);
+- ast_verbose("%4d th %p %s\n", (int)(now % 3600), pthread_self(), msg);
+- if (start != 0 && now - start > 5)
+- ast_verbose("+++ WOW, %s took %d seconds\n", msg, (int)(now - start));
+- return now;
+-}
+-
+-static void LOCK_EVENTS(void)
+-{
+- time_t start = __deb(0, "about to lock events");
+- AST_LIST_LOCK(&all_events);
+- __deb(start, "done lock events");
+-}
+-
+-static void UNLOCK_EVENTS(void)
+-{
+- __deb(0, "about to unlock events");
+- AST_LIST_UNLOCK(&all_events);
+-}
+-
+-static void LOCK_SESS(void)
+-{
+- time_t start = __deb(0, "about to lock sessions");
+- AST_LIST_LOCK(&sessions);
+- __deb(start, "done lock sessions");
+-}
+-
+-static void UNLOCK_SESS(void)
+-{
+- __deb(0, "about to unlock sessions");
+- AST_LIST_UNLOCK(&sessions);
+-}
+-#endif
+-
+ int check_manager_enabled()
+ {
+ return manager_enabled;
+@@ -336,8 +913,9 @@
+ /* the list is never empty now, but may become so when
+ * we optimize it in the future, so be prepared.
+ */
+- if (ret)
++ if (ret) {
+ ast_atomic_fetchadd_int(&ret->usecount, 1);
++ }
+ AST_LIST_UNLOCK(&all_events);
+ return ret;
+ }
+@@ -363,9 +941,9 @@
+ * helper functions to convert back and forth between
+ * string and numeric representation of set of flags
+ */
+-static struct permalias {
++static const struct permalias {
+ int num;
+- char *label;
++ const char *label;
+ } perms[] = {
+ { EVENT_FLAG_SYSTEM, "system" },
+ { EVENT_FLAG_CALL, "call" },
+@@ -386,7 +964,7 @@
+ };
+
+ /*! \brief Convert authority code to a list of options */
+-static char *authority_to_str(int authority, struct ast_str **res)
++static const char *authority_to_str(int authority, struct ast_str **res)
+ {
+ int i;
+ char *sep = "";
+@@ -416,12 +994,14 @@
+
+ do {
+ if ((next = strchr(val, delim))) {
+- if (!strncmp(val, smallstr, (next - val)))
++ if (!strncmp(val, smallstr, (next - val))) {
+ return 1;
+- else
++ } else {
+ continue;
+- } else
++ }
++ } else {
+ return !strcmp(smallstr, val);
++ }
+ } while (*(val = (next + 1)));
+
+ return 0;
+@@ -431,12 +1011,14 @@
+ {
+ int x = 0, ret = 0;
+
+- if (!instr)
++ if (!instr) {
+ return 0;
++ }
+
+ for (x = 0; x < ARRAY_LEN(perms); x++) {
+- if (ast_instring(instr, perms[x].label, ','))
++ if (ast_instring(instr, perms[x].label, ',')) {
+ ret |= perms[x].num;
++ }
+ }
+
+ return ret;
+@@ -450,40 +1032,106 @@
+ {
+ const char *p;
+
+- if (ast_strlen_zero(string))
++ if (ast_strlen_zero(string)) {
+ return -1;
++ }
+
+- for (p = string; *p; p++)
+- if (*p < '0' || *p > '9')
++ for (p = string; *p; p++) {
++ if (*p < '0' || *p > '9') {
+ break;
+- if (!p) /* all digits */
++ }
++ }
++ if (!p) { /* all digits */
+ return atoi(string);
+- if (ast_false(string))
++ }
++ if (ast_false(string)) {
+ return 0;
++ }
+ if (ast_true(string)) { /* all permissions */
+ int x, ret = 0;
+- for (x = 0; x < ARRAY_LEN(perms); x++)
++ for (x = 0; x < ARRAY_LEN(perms); x++) {
+ ret |= perms[x].num;
++ }
+ return ret;
+ }
+ return get_perm(string);
+ }
+
+-static int check_manager_session_inuse(const char *name)
++/*! \brief Unreference manager session object.
++ If no more references, then go ahead and delete it */
++static struct mansession_session *unref_mansession(struct mansession_session *s)
+ {
+- struct mansession_session *session = NULL;
++ int refcount = ao2_ref(s, -1);
++ if (manager_debug) {
++ ast_log(LOG_DEBUG, "Mansession: %p refcount now %d\n", s, refcount - 1);
++ }
++ return s;
++}
+
+- AST_LIST_LOCK(&sessions);
+- AST_LIST_TRAVERSE(&sessions, session, list) {
+- if (!strcasecmp(session->username, name))
+- break;
++static void session_destructor(void *obj)
++{
++ struct mansession_session *session = obj;
++ 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(&session->datastores, entry))) {
++ /* Free the data store */
++ ast_datastore_free(datastore);
+ }
+- AST_LIST_UNLOCK(&sessions);
+
+- return session ? 1 : 0;
++ if (session->f != NULL) {
++ fclose(session->f);
++ }
++ unref_event(eqe);
+ }
+
++/*! \brief Allocate manager session structure and add it to the list of sessions */
++static struct mansession_session *build_mansession(struct sockaddr_in sin)
++{
++ struct mansession_session *newsession;
+
++ if (!(newsession = ao2_alloc(sizeof(*newsession), session_destructor))) {
++ return NULL;
++ }
++ newsession->fd = -1;
++ newsession->waiting_thread = AST_PTHREADT_NULL;
++ newsession->writetimeout = 100;
++ newsession->send_events = -1;
++ newsession->sin = sin;
++
++ ao2_link(sessions, newsession);
++
++ return newsession;
++}
++
++static int mansession_cmp_fn(void *obj, void *arg, int flags)
++{
++ struct mansession_session *s = obj;
++ char *str = arg;
++ return !strcasecmp(s->username, str) ? CMP_MATCH : 0;
++}
++
++static void session_destroy(struct mansession_session *s)
++{
++ unref_mansession(s);
++ ao2_unlink(sessions, s);
++}
++
++
++static int check_manager_session_inuse(const char *name)
++{
++ struct mansession_session *session = ao2_find(sessions, (char *) name, 0);
++ int inuse = 0;
++
++ if (session) {
++ inuse = 1;
++ unref_mansession(session);
++ }
++ return inuse;
++}
++
++
+ /*!
+ * lookup an entry in the list of registered users.
+ * must be called with the list lock held.
+@@ -493,8 +1141,9 @@
+ struct ast_manager_user *user = NULL;
+
+ AST_RWLIST_TRAVERSE(&users, user, list)
+- if (!strcasecmp(user->username, name))
++ if (!strcasecmp(user->username, name)) {
+ break;
++ }
+ return user;
+ }
+
+@@ -508,10 +1157,11 @@
+ int ret = 0;
+
+ AST_RWLIST_RDLOCK(&users);
+- if ((user = get_manager_by_name_locked (session->username)))
++ if ((user = get_manager_by_name_locked (session->username))) {
+ ret = user->displayconnects;
++ }
+ AST_RWLIST_UNLOCK(&users);
+-
++
+ return ret;
+ }
+
+@@ -521,10 +1171,14 @@
+ struct ast_str *authority;
+ int num, l, which;
+ char *ret = NULL;
++#ifdef AST_XML_DOCS
++ char syntax_title[64], description_title[64], synopsis_title[64], seealso_title[64], arguments_title[64];
++#endif
++
+ switch (cmd) {
+ case CLI_INIT:
+ e->command = "manager show command";
+- e->usage =
++ e->usage =
+ "Usage: manager show command <actionname> [<actionname> [<actionname> [...]]]\n"
+ " Shows the detailed description for a specific Asterisk manager interface command.\n";
+ return NULL;
+@@ -546,14 +1200,41 @@
+ return CLI_SHOWUSAGE;
+ }
+
++#ifdef AST_XML_DOCS
++ /* setup the titles */
++ term_color(synopsis_title, "[Synopsis]\n", COLOR_MAGENTA, 0, 40);
++ term_color(description_title, "[Description]\n", COLOR_MAGENTA, 0, 40);
++ term_color(syntax_title, "[Syntax]\n", COLOR_MAGENTA, 0, 40);
++ term_color(seealso_title, "[See Also]\n", COLOR_MAGENTA, 0, 40);
++ term_color(arguments_title, "[Arguments]\n", COLOR_MAGENTA, 0, 40);
++#endif
++
+ AST_RWLIST_RDLOCK(&actions);
+ AST_RWLIST_TRAVERSE(&actions, cur, list) {
+ for (num = 3; num < a->argc; num++) {
+ if (!strcasecmp(cur->action, a->argv[num])) {
+- ast_cli(a->fd, "Action: %s\nSynopsis: %s\nPrivilege: %s\n%s\n",
+- cur->action, cur->synopsis,
+- authority_to_str(cur->authority, &authority),
+- S_OR(cur->description, ""));
++#ifdef AST_XML_DOCS
++ if (cur->docsrc == AST_XML_DOC) {
++ ast_cli(a->fd, "%s%s\n\n%s%s\n\n%s%s\n\n%s%s\n\n%s%s\n\n",
++ syntax_title,
++ ast_xmldoc_printable(S_OR(cur->syntax, "Not available"), 1),
++ synopsis_title,
++ ast_xmldoc_printable(S_OR(cur->synopsis, "Not available"), 1),
++ description_title,
++ ast_xmldoc_printable(S_OR(cur->description, "Not available"), 1),
++ arguments_title,
++ ast_xmldoc_printable(S_OR(cur->arguments, "Not available"), 1),
++ seealso_title,
++ ast_xmldoc_printable(S_OR(cur->seealso, "Not available"), 1));
++ } else {
++#endif
++ ast_cli(a->fd, "Action: %s\nSynopsis: %s\nPrivilege: %s\n%s\n",
++ cur->action, cur->synopsis,
++ authority_to_str(cur->authority, &authority),
++ S_OR(cur->description, ""));
++#ifdef AST_XML_DOCS
++ }
++#endif
+ }
+ }
+ }
+@@ -570,17 +1251,19 @@
+ 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;
++ return NULL;
+ }
+- if (a->argc == 3)
++
++ if (a->argc == 3) {
+ ast_cli(a->fd, "manager debug is %s\n", manager_debug? "on" : "off");
+- else if (a->argc == 4) {
+- if (!strcasecmp(a->argv[3], "on"))
++ } else if (a->argc == 4) {
++ if (!strcasecmp(a->argv[3], "on")) {
+ manager_debug = 1;
+- else if (!strcasecmp(a->argv[3], "off"))
++ } else if (!strcasecmp(a->argv[3], "off")) {
+ manager_debug = 0;
+- else
++ } else {
+ return CLI_SHOWUSAGE;
++ }
+ }
+ return CLI_SUCCESS;
+ }
+@@ -596,15 +1279,16 @@
+ switch (cmd) {
+ case CLI_INIT:
+ e->command = "manager show user";
+- e->usage =
++ e->usage =
+ " Usage: manager show user <user>\n"
+ " Display all information related to the manager user specified.\n";
+ return NULL;
+ case CLI_GENERATE:
+ l = strlen(a->word);
+ which = 0;
+- if (a->pos != 3)
++ if (a->pos != 3) {
+ return NULL;
++ }
+ AST_RWLIST_RDLOCK(&users);
+ AST_RWLIST_TRAVERSE(&users, user, list) {
+ if ( !strncasecmp(a->word, user->username, l) && ++which > a->n ) {
+@@ -616,8 +1300,9 @@
+ return ret;
+ }
+
+- if (a->argc != 4)
++ if (a->argc != 4) {
+ return CLI_SHOWUSAGE;
++ }
+
+ AST_RWLIST_RDLOCK(&users);
+
+@@ -655,7 +1340,7 @@
+ switch (cmd) {
+ case CLI_INIT:
+ e->command = "manager show users";
+- e->usage =
++ e->usage =
+ "Usage: manager show users\n"
+ " Prints a listing of all managers that are currently configured on that\n"
+ " system.\n";
+@@ -663,8 +1348,9 @@
+ case CLI_GENERATE:
+ return NULL;
+ }
+- if (a->argc != 3)
++ if (a->argc != 3) {
+ return CLI_SHOWUSAGE;
++ }
+
+ AST_RWLIST_RDLOCK(&users);
+
+@@ -684,9 +1370,8 @@
+
+ AST_RWLIST_UNLOCK(&users);
+
+- ast_cli(a->fd, "-------------------\n");
+- ast_cli(a->fd, "%d manager users configured.\n", count_amu);
+-
++ ast_cli(a->fd,"-------------------\n"
++ "%d manager users configured.\n", count_amu);
+ return CLI_SUCCESS;
+ }
+
+@@ -700,13 +1385,13 @@
+ switch (cmd) {
+ case CLI_INIT:
+ e->command = "manager show commands";
+- e->usage =
++ e->usage =
+ "Usage: manager show commands\n"
+ " Prints a listing of all the available Asterisk manager interface commands.\n";
+ return NULL;
+ case CLI_GENERATE:
+- return NULL;
+- }
++ return NULL;
++ }
+ authority = ast_str_alloca(80);
+ ast_cli(a->fd, HSMC_FORMAT, "Action", "Privilege", "Synopsis");
+ ast_cli(a->fd, HSMC_FORMAT, "------", "---------", "--------");
+@@ -727,26 +1412,30 @@
+ #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"
+ int count = 0;
++ struct ao2_iterator i;
++
+ switch (cmd) {
+ case CLI_INIT:
+ e->command = "manager show connected";
+- e->usage =
++ e->usage =
+ "Usage: manager show connected\n"
+ " Prints a listing of the users that are currently connected to the\n"
+ "Asterisk manager interface.\n";
+ return NULL;
+ case CLI_GENERATE:
+- return NULL;
++ return NULL;
+ }
+
+ ast_cli(a->fd, HSMCONN_FORMAT1, "Username", "IP Address", "Start", "Elapsed", "FileDes", "HttpCnt", "Read", "Write");
+
+- AST_LIST_LOCK(&sessions);
+- AST_LIST_TRAVERSE(&sessions, session, list) {
++ i = ao2_iterator_init(sessions, 0);
++ while ((session = ao2_iterator_next(&i))) {
++ ao2_lock(session);
+ 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++;
++ ao2_unlock(session);
++ unref_mansession(session);
+ }
+- AST_LIST_UNLOCK(&sessions);
+
+ ast_cli(a->fd, "%d users connected.\n", count);
+
+@@ -761,7 +1450,7 @@
+ switch (cmd) {
+ case CLI_INIT:
+ e->command = "manager show eventq";
+- e->usage =
++ e->usage =
+ "Usage: manager show eventq\n"
+ " Prints a listing of all events pending in the Asterisk manger\n"
+ "event queue.\n";
+@@ -793,8 +1482,9 @@
+ case CLI_GENERATE:
+ return NULL;
+ }
+- if (a->argc > 2)
++ if (a->argc > 2) {
+ return CLI_SHOWUSAGE;
++ }
+ reload_manager();
+ return CLI_SUCCESS;
+ }
+@@ -811,12 +1501,6 @@
+ AST_CLI_DEFINE(handle_manager_reload, "Reload manager configurations"),
+ };
+
+-/*
+- * Decrement the usecount for the event; if it goes to zero,
+- * (why check for e->next ?) wakeup the
+- * main thread, which is in charge of freeing the record.
+- * Returns the next record.
+- */
+ static struct eventqent *unref_event(struct eventqent *e)
+ {
+ ast_atomic_fetchadd_int(&e->usecount, -1);
+@@ -829,36 +1513,6 @@
+ }
+
+ /*
+- * destroy a session, leaving the usecount
+- */
+-static void free_session(struct mansession_session *session)
+-{
+- 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(&session->datastores, entry))) {
+- /* Free the data store */
+- ast_datastore_free(datastore);
+- }
+-
+- if (session->f != NULL)
+- fclose(session->f);
+- ast_mutex_destroy(&session->__lock);
+- ast_free(session);
+- unref_event(eqe);
+-}
+-
+-static void destroy_session(struct mansession_session *session)
+-{
+- AST_LIST_LOCK(&sessions);
+- AST_LIST_REMOVE(&sessions, session, list);
+- ast_atomic_fetchadd_int(&num_sessions, -1);
+- free_session(session);
+- AST_LIST_UNLOCK(&sessions);
+-}
+-
+-/*
+ * Generic function to return either the first or the last matching header
+ * from a list of variables, possibly skipping empty strings.
+ * At the moment there is only one use of this function in this file,
+@@ -914,20 +1568,24 @@
+ for (x = 0; x < m->hdrcount; x++) {
+ char *parse, *var, *val;
+
+- if (strncasecmp("Variable: ", m->headers[x], varlen))
++ if (strncasecmp("Variable: ", m->headers[x], varlen)) {
+ continue;
++ }
+ parse = ast_strdupa(m->headers[x] + varlen);
+
+ AST_STANDARD_APP_ARGS(args, parse);
+- if (!args.argc)
++ if (!args.argc) {
+ continue;
++ }
+ for (y = 0; y < args.argc; y++) {
+- if (!args.vars[y])
++ if (!args.vars[y]) {
+ continue;
++ }
+ var = val = ast_strdupa(args.vars[y]);
+ strsep(&val, "=");
+- if (!val || ast_strlen_zero(var))
++ if (!val || ast_strlen_zero(var)) {
+ continue;
++ }
+ cur = ast_variable_new(var, val, "");
+ cur->next = head;
+ head = cur;
+@@ -971,8 +1629,9 @@
+ va_list ap;
+ struct ast_str *buf;
+
+- if (!(buf = ast_str_thread_get(&astman_append_buf, ASTMAN_APPEND_BUF_INITSIZE)))
++ if (!(buf = ast_str_thread_get(&astman_append_buf, ASTMAN_APPEND_BUF_INITSIZE))) {
+ return;
++ }
+
+ va_start(ap, fmt);
+ ast_str_set_va(&buf, 0, fmt, ap);
+@@ -1007,16 +1666,19 @@
+ const char *id = astman_get_header(m, "ActionID");
+
+ astman_append(s, "Response: %s\r\n", resp);
+- if (!ast_strlen_zero(id))
++ if (!ast_strlen_zero(id)) {
+ astman_append(s, "ActionID: %s\r\n", id);
+- if (listflag)
++ }
++ if (listflag) {
+ astman_append(s, "Eventlist: %s\r\n", listflag); /* Start, complete, cancelled */
+- if (msg == MSG_MOREDATA)
++ }
++ if (msg == MSG_MOREDATA) {
+ return;
+- else if (msg)
++ } else if (msg) {
+ astman_append(s, "Message: %s\r\n\r\n", msg);
+- else
++ } else {
+ astman_append(s, "\r\n");
++ }
+ }
+
+ void astman_send_response(struct mansession *s, const struct message *m, char *resp, char *msg)
+@@ -1044,7 +1706,18 @@
+ astman_send_response_full(s, m, "Success", msg, listflag);
+ }
+
++/*! \brief Lock the 'mansession' structure. */
++static void mansession_lock(struct mansession *s)
++{
++ ast_mutex_lock(&s->lock);
++}
+
++/*! \brief Unlock the 'mansession' structure. */
++static void mansession_unlock(struct mansession *s)
++{
++ ast_mutex_unlock(&s->lock);
++}
++
+ /*! \brief
+ Rather than braindead on,off this now can also accept a specific int mask value
+ or a ',' delim list of mask strings (the same as manager.conf) -anthm
+@@ -1053,10 +1726,11 @@
+ {
+ int maskint = strings_to_mask(eventmask);
+
+- ast_mutex_lock(&s->session->__lock);
+- if (maskint >= 0)
++ mansession_lock(s);
++ if (maskint >= 0) {
+ s->session->send_events = maskint;
+- ast_mutex_unlock(&s->session->__lock);
++ }
++ mansession_unlock(s);
+
+ return maskint;
+ }
+@@ -1075,8 +1749,9 @@
+ int error = -1;
+ struct ast_manager_user *user = NULL;
+
+- if (ast_strlen_zero(username)) /* missing username */
++ if (ast_strlen_zero(username)) { /* missing username */
+ return -1;
++ }
+
+ /* locate user in locked state */
+ AST_RWLIST_WRLOCK(&users);
+@@ -1100,14 +1775,16 @@
+ MD5Final(digest, &md5);
+ for (x = 0; x < 16; x++)
+ len += sprintf(md5key + len, "%2.2x", digest[x]);
+- if (!strcmp(md5key, key))
++ if (!strcmp(md5key, key)) {
+ error = 0;
++ }
+ } else {
+- ast_debug(1, "MD5 authentication is not possible. challenge: '%s'\n",
++ ast_debug(1, "MD5 authentication is not possible. challenge: '%s'\n",
+ S_OR(s->session->challenge, ""));
+ }
+- } else if (password && user->secret && !strcmp(password, user->secret))
++ } 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->session->sin.sin_addr), username);
+@@ -1116,24 +1793,18 @@
+ }
+
+ /* auth complete */
+-
++
+ 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);
+ return 0;
+ }
+
+-/*! \brief Manager PING */
+-static char mandescr_ping[] =
+-"Description: A 'Ping' action will ellicit a 'Pong' response. Used to keep the\n"
+-" manager connection open.\n"
+-"Variables: NONE\n";
+-
+ static int action_ping(struct mansession *s, const struct message *m)
+ {
+ const char *actionid = astman_get_header(m, "ActionID");
+@@ -1146,13 +1817,6 @@
+ return 0;
+ }
+
+-static char mandescr_getconfig[] =
+-"Description: A 'GetConfig' action will dump the contents of a configuration\n"
+-"file by category and contents or optionally by specified category only.\n"
+-"Variables: (Names marked with * are required)\n"
+-" *Filename: Configuration filename (e.g. foo.conf)\n"
+-" Category: Category in configuration file\n";
+-
+ static int action_getconfig(struct mansession *s, const struct message *m)
+ {
+ struct ast_config *cfg;
+@@ -1179,25 +1843,21 @@
+ if (ast_strlen_zero(category) || (!ast_strlen_zero(category) && !strcmp(category, cur_category))) {
+ lineno = 0;
+ astman_append(s, "Category-%06d: %s\r\n", catcount, cur_category);
+- for (v = ast_variable_browse(cfg, cur_category); v; v = v->next)
++ for (v = ast_variable_browse(cfg, cur_category); v; v = v->next) {
+ astman_append(s, "Line-%06d-%06d: %s=%s\r\n", catcount, lineno++, v->name, v->value);
++ }
+ catcount++;
+ }
+ }
+- if (!ast_strlen_zero(category) && catcount == 0) /* TODO: actually, a config with no categories doesn't even get loaded */
++ if (!ast_strlen_zero(category) && catcount == 0) { /* TODO: actually, a config with no categories doesn't even get loaded */
+ astman_append(s, "No categories found\r\n");
++ }
+ ast_config_destroy(cfg);
+ astman_append(s, "\r\n");
+
+ return 0;
+ }
+
+-static char mandescr_listcategories[] =
+-"Description: A 'ListCategories' action will dump the categories in\n"
+-"a given file.\n"
+-"Variables:\n"
+-" Filename: Configuration filename (e.g. foo.conf)\n";
+-
+ static int action_listcategories(struct mansession *s, const struct message *m)
+ {
+ struct ast_config *cfg;
+@@ -1219,8 +1879,9 @@
+ astman_append(s, "Category-%06d: %s\r\n", catcount, category);
+ catcount++;
+ }
+- if (catcount == 0) /* TODO: actually, a config with no categories doesn't even get loaded */
++ if (catcount == 0) { /* TODO: actually, a config with no categories doesn't even get loaded */
+ astman_append(s, "Error: no categories found\r\n");
++ }
+ ast_config_destroy(cfg);
+ astman_append(s, "\r\n");
+
+@@ -1228,26 +1889,20 @@
+ }
+
+
+-
+
++
+ /*! The amount of space in out must be at least ( 2 * strlen(in) + 1 ) */
+ static void json_escape(char *out, const char *in)
+ {
+ for (; *in; in++) {
+- if (*in == '\\' || *in == '\"')
++ if (*in == '\\' || *in == '\"') {
+ *out++ = '\\';
++ }
+ *out++ = *in;
+ }
+ *out = '\0';
+ }
+
+-static char mandescr_getconfigjson[] =
+-"Description: A 'GetConfigJSON' action will dump the contents of a configuration\n"
+-"file by category and contents in JSON format. This only makes sense to be used\n"
+-"using rawman over the HTTP interface.\n"
+-"Variables:\n"
+-" Filename: Configuration filename (e.g. foo.conf)\n";
+-
+ static int action_getconfigjson(struct mansession *s, const struct message *m)
+ {
+ struct ast_config *cfg;
+@@ -1282,11 +1937,13 @@
+ }
+ json_escape(buf, category);
+ astman_append(s, "%s\"%s\":[", comma1 ? "," : "", buf);
+- if (!comma1)
++ if (!comma1) {
+ comma1 = 1;
++ }
+ for (v = ast_variable_browse(cfg, category); v; v = v->next) {
+- if (comma2)
++ if (comma2) {
+ astman_append(s, ",");
++ }
+ if (buf_len < 2 * strlen(v->name) + 1) {
+ buf_len *= 2;
+ buf = alloca(buf_len);
+@@ -1299,8 +1956,9 @@
+ }
+ json_escape(buf, v->value);
+ astman_append(s, "%s\"", buf);
+- if (!comma2)
++ if (!comma2) {
+ comma2 = 1;
++ }
+ }
+ astman_append(s, "]");
+ }
+@@ -1347,7 +2005,7 @@
+ object = 1;
+ value++;
+ }
+-
++
+ snprintf(hdr, sizeof(hdr), "Match-%06d", x);
+ match = astman_get_header(m, hdr);
+
+@@ -1365,8 +2023,9 @@
+ }
+ if (ast_strlen_zero(match)) {
+ ast_category_append(cfg, category);
+- } else
++ } else {
+ ast_category_insert(cfg, category, match);
++ }
+ } else if (!strcasecmp(action, "renamecat")) {
+ if (ast_strlen_zero(value)) {
+ result = UNSPECIFIED_ARGUMENT;
+@@ -1419,15 +2078,16 @@
+ break;
+ }
+ if (!(category = ast_category_get(cfg, cat))) {
+- result = UNKNOWN_CATEGORY;
++ result = UNKNOWN_CATEGORY;
+ break;
+ }
+ if (!(v = ast_variable_new(var, value, dfn))) {
+ result = FAILURE_ALLOCATION;
+ break;
+ }
+- if (object || (match && !strcasecmp(match, "object")))
++ if (object || (match && !strcasecmp(match, "object"))) {
+ v->object = 1;
++ }
+ ast_variable_append(category, v);
+ } else if (!strcasecmp(action, "insert")) {
+ if (ast_strlen_zero(var) || ast_strlen_zero(line)) {
+@@ -1455,20 +2115,6 @@
+ return result;
+ }
+
+-static char mandescr_updateconfig[] =
+-"Description: A 'UpdateConfig' action will modify, create, or delete\n"
+-"configuration elements in Asterisk configuration files.\n"
+-"Variables (X's represent 6 digit number beginning with 000000):\n"
+-" SrcFilename: Configuration filename to read(e.g. foo.conf)\n"
+-" DstFilename: Configuration filename to write(e.g. foo.conf)\n"
+-" Reload: Whether or not a reload should take place (or name of specific module)\n"
+-" Action-XXXXXX: Action to Take (NewCat,RenameCat,DelCat,EmptyCat,Update,Delete,Append,Insert)\n"
+-" Cat-XXXXXX: Category to operate on\n"
+-" Var-XXXXXX: Variable to work on\n"
+-" Value-XXXXXX: Value to work on\n"
+-" Match-XXXXXX: Extra match required to match line\n"
+-" Line-XXXXXX: Line in category to operate on (used with delete and insert actions)\n";
+-
+ static int action_updateconfig(struct mansession *s, const struct message *m)
+ {
+ struct ast_config *cfg;
+@@ -1498,8 +2144,9 @@
+ }
+ astman_send_ack(s, m, NULL);
+ if (!ast_strlen_zero(rld)) {
+- if (ast_true(rld))
++ if (ast_true(rld)) {
+ rld = NULL;
++ }
+ ast_module_reload(rld);
+ }
+ } else {
+@@ -1543,13 +2190,6 @@
+ return 0;
+ }
+
+-static char mandescr_createconfig[] =
+-"Description: A 'CreateConfig' action will create an empty file in the\n"
+-"configuration directory. This action is intended to be used before an\n"
+-"UpdateConfig action.\n"
+-"Variables\n"
+-" Filename: The configuration filename to create (e.g. foo.conf)\n";
+-
+ static int action_createconfig(struct mansession *s, const struct message *m)
+ {
+ int fd;
+@@ -1568,14 +2208,6 @@
+ return 0;
+ }
+
+-/*! \brief Manager WAITEVENT */
+-static char mandescr_waitevent[] =
+-"Description: A 'WaitEvent' action will ellicit a 'Success' response. Whenever\n"
+-"a manager event is queued. Once WaitEvent has been called on an HTTP manager\n"
+-"session, events will be generated and queued.\n"
+-"Variables: \n"
+-" Timeout: Maximum time (in seconds) to wait for events, -1 means forever.\n";
+-
+ static int action_waitevent(struct mansession *s, const struct message *m)
+ {
+ const char *timeouts = astman_get_header(m, "Timeout");
+@@ -1585,21 +2217,24 @@
+ const char *id = astman_get_header(m, "ActionID");
+ char idText[256];
+
+- if (!ast_strlen_zero(id))
++ if (!ast_strlen_zero(id)) {
+ snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
+- else
++ } else {
+ idText[0] = '\0';
++ }
+
+ if (!ast_strlen_zero(timeouts)) {
+ sscanf(timeouts, "%i", &timeout);
+- if (timeout < -1)
++ if (timeout < -1) {
+ timeout = -1;
++ }
+ /* XXX maybe put an upper bound, or prevent the use of 0 ? */
+ }
+
+- ast_mutex_lock(&s->session->__lock);
+- if (s->session->waiting_thread != AST_PTHREADT_NULL)
++ mansession_lock(s);
++ if (s->session->waiting_thread != AST_PTHREADT_NULL) {
+ pthread_kill(s->session->waiting_thread, SIGURG);
++ }
+
+ if (s->session->managerid) { /* AMI-over-HTTP session */
+ /*
+@@ -1610,43 +2245,52 @@
+ time_t now = time(NULL);
+ int max = s->session->sessiontimeout - now - 10;
+
+- if (max < 0) /* We are already late. Strange but possible. */
++ if (max < 0) { /* We are already late. Strange but possible. */
+ max = 0;
+- if (timeout < 0 || timeout > max)
++ }
++ if (timeout < 0 || timeout > max) {
+ timeout = max;
+- if (!s->session->send_events) /* make sure we record events */
++ }
++ if (!s->session->send_events) { /* make sure we record events */
+ s->session->send_events = -1;
++ }
+ }
+- ast_mutex_unlock(&s->session->__lock);
++ mansession_unlock(s);
+
+ /* XXX should this go inside the lock ? */
+ 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->session->__lock);
+- if (NEW_EVENT(s))
++ mansession_lock(s);
++ 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->session->waiting_thread != pthread_self())
++ if (s->session->waiting_thread != pthread_self()) {
+ needexit = 1;
+- if (s->session->needdestroy)
++ }
++ if (s->session->needdestroy) {
+ needexit = 1;
+- ast_mutex_unlock(&s->session->__lock);
+- if (needexit)
++ }
++ mansession_unlock(s);
++ if (needexit) {
+ break;
++ }
+ if (s->session->managerid == 0) { /* AMI session */
+- if (ast_wait_for_input(s->session->fd, 1000))
++ 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->session->__lock);
++
++ mansession_lock(s);
+ if (s->session->waiting_thread == pthread_self()) {
+ struct eventqent *eqe;
+ astman_send_response(s, m, "Success", "Waiting for Event completed.");
+@@ -1666,15 +2310,10 @@
+ } else {
+ ast_debug(1, "Abandoning event request!\n");
+ }
+- ast_mutex_unlock(&s->session->__lock);
++ mansession_unlock(s);
+ return 0;
+ }
+
+-static char mandescr_listcommands[] =
+-"Description: Returns the action name and synopsis for every\n"
+-" action that is available to the user\n"
+-"Variables: NONE\n";
+-
+ /*! \note The actionlock is read-locked by the caller of this function */
+ static int action_listcommands(struct mansession *s, const struct message *m)
+ {
+@@ -1683,23 +2322,16 @@
+
+ astman_start_ack(s, m);
+ AST_RWLIST_TRAVERSE(&actions, cur, list) {
+- if (s->session->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));
++ }
+ }
+ astman_append(s, "\r\n");
+
+ return 0;
+ }
+
+-static char mandescr_events[] =
+-"Description: Enable/Disable sending of events to this manager\n"
+-" client.\n"
+-"Variables:\n"
+-" EventMask: 'on' if all events should be sent,\n"
+-" 'off' if no events should be sent,\n"
+-" 'system,call,log' to select which flags events should have to be sent.\n";
+-
+ static int action_events(struct mansession *s, const struct message *m)
+ {
+ const char *mask = astman_get_header(m, "EventMask");
+@@ -1715,10 +2347,6 @@
+ return 0;
+ }
+
+-static char mandescr_logoff[] =
+-"Description: Logoff this manager session\n"
+-"Variables: NONE\n";
+-
+ static int action_logoff(struct mansession *s, const struct message *m)
+ {
+ astman_send_response(s, m, "Goodbye", "Thanks for all the fish.");
+@@ -1727,15 +2355,22 @@
+
+ static int action_login(struct mansession *s, const struct message *m)
+ {
++
++ /* still authenticated - don't process again */
++ if (s->session->authenticated) {
++ astman_send_ack(s, m, "Already authenticated");
++ return 0;
++ }
++
+ if (authenticate(s, m)) {
+ sleep(1);
+ astman_send_error(s, m, "Authentication failed");
+ return -1;
+ }
+ s->session->authenticated = 1;
+- if (manager_displayconnects(s->session))
++ 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;
+ }
+@@ -1745,49 +2380,62 @@
+ const char *authtype = astman_get_header(m, "AuthType");
+
+ if (!strcasecmp(authtype, "MD5")) {
+- if (ast_strlen_zero(s->session->challenge))
++ if (ast_strlen_zero(s->session->challenge)) {
+ snprintf(s->session->challenge, sizeof(s->session->challenge), "%ld", ast_random());
+- ast_mutex_lock(&s->session->__lock);
++ }
++ mansession_lock(s);
+ astman_start_ack(s, m);
+ astman_append(s, "Challenge: %s\r\n\r\n", s->session->challenge);
+- ast_mutex_unlock(&s->session->__lock);
++ mansession_unlock(s);
+ } else {
+ astman_send_error(s, m, "Must specify AuthType");
+ }
+ return 0;
+ }
+
+-static char mandescr_hangup[] =
+-"Description: Hangup a channel\n"
+-"Variables: \n"
+-" Channel: The channel name to be hungup\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;
+ }
+- c = ast_get_channel_by_name_locked(name);
+- if (!c) {
++
++ 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 */
++ }
++ }
++
++ if (!(c = ast_channel_get_by_name(name))) {
+ astman_send_error(s, m, "No such channel");
+ return 0;
+ }
+- ast_softhangup(c, AST_SOFTHANGUP_EXPLICIT);
++
++ ast_channel_lock(c);
++ 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);
++
++ c = ast_channel_unref(c);
++
+ astman_send_ack(s, m, "Channel Hungup");
++
+ return 0;
+ }
+
+-static char mandescr_setvar[] =
+-"Description: Set a global or local channel variable.\n"
+-"Variables: (Names marked with * are required)\n"
+-" Channel: Channel to set variable for\n"
+-" *Variable: Variable name\n"
+-" *Value: Value\n";
+-
+ static int action_setvar(struct mansession *s, const struct message *m)
+ {
+ struct ast_channel *c = NULL;
+@@ -1801,8 +2449,7 @@
+ }
+
+ if (!ast_strlen_zero(name)) {
+- c = ast_get_channel_by_name_locked(name);
+- if (!c) {
++ if (!(c = ast_channel_get_by_name(name))) {
+ astman_send_error(s, m, "No such channel");
+ return 0;
+ }
+@@ -1810,21 +2457,15 @@
+
+ pbx_builtin_setvar_helper(c, varname, S_OR(varval, ""));
+
+- if (c)
+- ast_channel_unlock(c);
++ if (c) {
++ c = ast_channel_unref(c);
++ }
+
+ astman_send_ack(s, m, "Variable Set");
+
+ return 0;
+ }
+
+-static char mandescr_getvar[] =
+-"Description: Get the value of a global or local channel variable.\n"
+-"Variables: (Names marked with * are required)\n"
+-" Channel: Channel to read variable from\n"
+-" *Variable: Variable name\n"
+-" ActionID: Optional Action id for message matching.\n";
+-
+ static int action_getvar(struct mansession *s, const struct message *m)
+ {
+ struct ast_channel *c = NULL;
+@@ -1839,8 +2480,7 @@
+ }
+
+ if (!ast_strlen_zero(name)) {
+- c = ast_get_channel_by_name_locked(name);
+- if (!c) {
++ if (!(c = ast_channel_get_by_name(name))) {
+ astman_send_error(s, m, "No such channel");
+ return 0;
+ }
+@@ -1851,35 +2491,27 @@
+ c = ast_channel_alloc(0, 0, "", "", "", "", "", 0, "Bogus/manager");
+ if (c) {
+ ast_func_read(c, (char *) varname, workspace, sizeof(workspace));
+- ast_channel_free(c);
+- c = NULL;
++ c = ast_channel_release(c);
+ } else
+ ast_log(LOG_ERROR, "Unable to allocate bogus channel for variable substitution. Function results may be blank.\n");
+- } else
++ } else {
+ ast_func_read(c, (char *) varname, workspace, sizeof(workspace));
++ }
+ varval = workspace;
+ } else {
+ pbx_retrieve_variable(c, varname, &varval, workspace, sizeof(workspace), NULL);
+ }
+
+- if (c)
+- ast_channel_unlock(c);
++ if (c) {
++ c = ast_channel_unref(c);
++ }
++
+ astman_start_ack(s, m);
+ astman_append(s, "Variable: %s\r\nValue: %s\r\n\r\n", varname, varval);
+
+ return 0;
+ }
+
+-static char mandescr_status[] =
+-"Description: Lists channel status along with requested channel vars.\n"
+-"Variables: (Names marked with * are required)\n"
+-" *Channel: Name of the channel to query for status\n"
+-" Variables: Comma ',' separated list of variables to include\n"
+-" ActionID: Optional ID for this transaction\n"
+-"Will return the status information of each channel along with the\n"
+-"value for the specified channel variables.\n";
+-
+-
+ /*! \brief Manager "status" command to show channels */
+ /* Needs documentation... */
+ static int action_status(struct mansession *s, const struct message *m)
+@@ -1899,22 +2531,29 @@
+ AST_APP_ARG(name)[100];
+ );
+ struct ast_str *str = ast_str_create(1000);
++ struct ast_channel_iterator *iter = NULL;
+
+- if (!ast_strlen_zero(id))
++ if (!ast_strlen_zero(id)) {
+ snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
+- else
++ } else {
+ idText[0] = '\0';
++ }
+
+- if (all)
+- c = ast_channel_walk_locked(NULL);
+- else {
+- c = ast_get_channel_by_name_locked(name);
+- if (!c) {
++ if (all) {
++ if (!(iter = ast_channel_iterator_all_new(0))) {
++ ast_free(str);
++ astman_send_error(s, m, "Memory Allocation Failure");
++ return 1;
++ }
++ c = ast_channel_iterator_next(iter);
++ } else {
++ if (!(c = ast_channel_get_by_name(name))) {
+ astman_send_error(s, m, "No such channel");
+ ast_free(str);
+ return 0;
+ }
+ }
++
+ astman_send_ack(s, m, "Channel status will follow");
+
+ if (!ast_strlen_zero(cvariables)) {
+@@ -1922,7 +2561,9 @@
+ }
+
+ /* if we look by name, we break after the first iteration */
+- while (c) {
++ for (; c; c = ast_channel_iterator_next(iter)) {
++ ast_channel_lock(c);
++
+ if (!ast_strlen_zero(cvariables)) {
+ int i;
+ ast_str_reset(str);
+@@ -1943,10 +2584,11 @@
+ }
+
+ channels++;
+- if (c->_bridge)
++ if (c->_bridge) {
+ snprintf(bridge, sizeof(bridge), "BridgedChannel: %s\r\nBridgedUniqueid: %s\r\n", c->_bridge->name, c->_bridge->uniqueid);
+- else
++ } else {
+ bridge[0] = '\0';
++ }
+ if (c->pbx) {
+ if (c->cdr) {
+ elapsed_seconds = now.tv_sec - c->cdr->start.tv_sec;
+@@ -1978,45 +2620,45 @@
+ c->exten, c->priority, (long)elapsed_seconds, bridge, c->uniqueid, ast_str_buffer(str), idText);
+ } else {
+ astman_append(s,
+- "Event: Status\r\n"
+- "Privilege: Call\r\n"
+- "Channel: %s\r\n"
+- "CallerIDNum: %s\r\n"
+- "CallerIDName: %s\r\n"
+- "Account: %s\r\n"
+- "State: %s\r\n"
+- "%s"
+- "Uniqueid: %s\r\n"
+- "%s"
+- "%s"
+- "\r\n",
+- c->name,
+- S_OR(c->cid.cid_num, "<unknown>"),
+- S_OR(c->cid.cid_name, "<unknown>"),
+- c->accountcode,
+- ast_state2str(c->_state), bridge, c->uniqueid, ast_str_buffer(str), idText);
++ "Event: Status\r\n"
++ "Privilege: Call\r\n"
++ "Channel: %s\r\n"
++ "CallerIDNum: %s\r\n"
++ "CallerIDName: %s\r\n"
++ "Account: %s\r\n"
++ "State: %s\r\n"
++ "%s"
++ "Uniqueid: %s\r\n"
++ "%s"
++ "%s"
++ "\r\n",
++ c->name,
++ S_OR(c->cid.cid_num, "<unknown>"),
++ S_OR(c->cid.cid_name, "<unknown>"),
++ c->accountcode,
++ ast_state2str(c->_state), bridge, c->uniqueid,
++ ast_str_buffer(str), idText);
+ }
++
+ ast_channel_unlock(c);
+- if (!all)
++ c = ast_channel_unref(c);
++
++ if (!all) {
+ break;
+- c = ast_channel_walk_locked(c);
++ }
+ }
++
+ astman_append(s,
+- "Event: StatusComplete\r\n"
+- "%s"
+- "Items: %d\r\n"
+- "\r\n", idText, channels);
++ "Event: StatusComplete\r\n"
++ "%s"
++ "Items: %d\r\n"
++ "\r\n", idText, channels);
++
+ ast_free(str);
++
+ return 0;
+ }
+
+-static char mandescr_sendtext[] =
+-"Description: Sends A Text Message while in a call.\n"
+-"Variables: (Names marked with * are required)\n"
+-" *Channel: Channel to send message to\n"
+-" *Message: Message to send\n"
+-" ActionID: Optional Action id for message matching.\n";
+-
+ static int action_sendtext(struct mansession *s, const struct message *m)
+ {
+ struct ast_channel *c = NULL;
+@@ -2034,33 +2676,25 @@
+ return 0;
+ }
+
+- c = ast_get_channel_by_name_locked(name);
+- if (!c) {
++ if (!(c = ast_channel_get_by_name(name))) {
+ astman_send_error(s, m, "No such channel");
+ return 0;
+ }
+
++ ast_channel_lock(c);
+ res = ast_sendtext(c, textmsg);
+ ast_channel_unlock(c);
+-
+- if (res > 0)
++ c = ast_channel_unref(c);
++
++ if (res > 0) {
+ astman_send_ack(s, m, "Success");
+- else
++ } else {
+ astman_send_error(s, m, "Failure");
+-
++ }
++
+ return res;
+ }
+
+-static char mandescr_redirect[] =
+-"Description: Redirect (transfer) a call.\n"
+-"Variables: (Names marked with * are required)\n"
+-" *Channel: Channel to redirect\n"
+-" ExtraChannel: Second call leg to transfer (optional)\n"
+-" *Exten: Extension to transfer to\n"
+-" *Context: Context to transfer to\n"
+-" *Priority: Priority to transfer to\n"
+-" ActionID: Optional Action id for message matching.\n";
+-
+ /*! \brief action_redirect: The redirect manager command */
+ static int action_redirect(struct mansession *s, const struct message *m)
+ {
+@@ -2077,38 +2711,44 @@
+ astman_send_error(s, m, "Channel not specified");
+ return 0;
+ }
++
+ if (!ast_strlen_zero(priority) && (sscanf(priority, "%d", &pi) != 1)) {
+ if ((pi = ast_findlabel_extension(NULL, context, exten, priority, NULL)) < 1) {
+ astman_send_error(s, m, "Invalid priority");
+ return 0;
+ }
+ }
+- /* XXX watch out, possible deadlock - we are trying to get two channels!!! */
+- chan = ast_get_channel_by_name_locked(name);
+- if (!chan) {
++
++ if (!(chan = ast_channel_get_by_name(name))) {
+ char buf[256];
+ snprintf(buf, sizeof(buf), "Channel does not exist: %s", name);
+ astman_send_error(s, m, buf);
+ return 0;
+ }
+- if (ast_check_hangup(chan)) {
++
++ if (ast_check_hangup_locked(chan)) {
+ astman_send_error(s, m, "Redirect failed, channel not up.");
+- ast_channel_unlock(chan);
++ chan = ast_channel_unref(chan);
+ return 0;
+ }
+- if (!ast_strlen_zero(name2))
+- chan2 = ast_get_channel_by_name_locked(name2);
+- if (chan2 && ast_check_hangup(chan2)) {
++
++ if (!ast_strlen_zero(name2)) {
++ chan2 = ast_channel_get_by_name(name2);
++ }
++
++ if (chan2 && ast_check_hangup_locked(chan2)) {
+ astman_send_error(s, m, "Redirect failed, extra channel not up.");
+- ast_channel_unlock(chan);
+- ast_channel_unlock(chan2);
++ chan = ast_channel_unref(chan);
++ chan2 = ast_channel_unref(chan2);
+ return 0;
+ }
++
+ if (chan->pbx) {
+ ast_channel_lock(chan);
+ ast_set_flag(chan, AST_FLAG_BRIDGE_HANGUP_DONT); /* don't let the after-bridge code run the h-exten */
+ ast_channel_unlock(chan);
+ }
++
+ res = ast_async_goto(chan, context, exten, pi);
+ if (!res) {
+ if (!ast_strlen_zero(name2)) {
+@@ -2122,30 +2762,29 @@
+ } else {
+ res = -1;
+ }
+- if (!res)
++ if (!res) {
+ astman_send_ack(s, m, "Dual Redirect successful");
+- else
++ } else {
+ astman_send_error(s, m, "Secondary redirect failed");
+- } else
++ }
++ } else {
+ astman_send_ack(s, m, "Redirect successful");
+- } else
++ }
++ } else {
+ astman_send_error(s, m, "Redirect failed");
+- if (chan)
+- ast_channel_unlock(chan);
+- if (chan2)
+- ast_channel_unlock(chan2);
++ }
++
++ if (chan) {
++ chan = ast_channel_unref(chan);
++ }
++
++ if (chan2) {
++ chan2 = ast_channel_unref(chan2);
++ }
++
+ return 0;
+ }
+
+-static char mandescr_atxfer[] =
+-"Description: Attended transfer.\n"
+-"Variables: (Names marked with * are required)\n"
+-" *Channel: Transferer's channel\n"
+-" *Exten: Extension to transfer to\n"
+-" *Context: Context to transfer to\n"
+-" *Priority: Priority to transfer to\n"
+-" ActionID: Optional Action id for message matching.\n";
+-
+ static int action_atxfer(struct mansession *s, const struct message *m)
+ {
+ const char *name = astman_get_header(m, "Channel");
+@@ -2155,7 +2794,7 @@
+ struct ast_call_feature *atxfer_feature = NULL;
+ char *feature_code = NULL;
+
+- if (ast_strlen_zero(name)) {
++ if (ast_strlen_zero(name)) {
+ astman_send_error(s, m, "No channel specified");
+ return 0;
+ }
+@@ -2169,7 +2808,7 @@
+ return 0;
+ }
+
+- if (!(chan = ast_get_channel_by_name_locked(name))) {
++ if (!(chan = ast_channel_get_by_name(name))) {
+ astman_send_error(s, m, "Channel specified does not exist");
+ return 0;
+ }
+@@ -2179,17 +2818,18 @@
+ }
+
+ for (feature_code = atxfer_feature->exten; feature_code && *feature_code; ++feature_code) {
+- struct ast_frame f = {AST_FRAME_DTMF, *feature_code};
++ struct ast_frame f = { AST_FRAME_DTMF, *feature_code };
+ ast_queue_frame(chan, &f);
+ }
+
+ for (feature_code = (char *)exten; feature_code && *feature_code; ++feature_code) {
+- struct ast_frame f = {AST_FRAME_DTMF, *feature_code};
++ struct ast_frame f = { AST_FRAME_DTMF, *feature_code };
+ ast_queue_frame(chan, &f);
+ }
+
++ chan = ast_channel_unref(chan);
++
+ astman_send_ack(s, m, "Atxfer successfully queued");
+- ast_channel_unlock(chan);
+
+ return 0;
+ }
+@@ -2229,12 +2869,6 @@
+ return 0;
+ }
+
+-static char mandescr_command[] =
+-"Description: Run a CLI command.\n"
+-"Variables: (Names marked with * are required)\n"
+-" *Command: Asterisk CLI command to run\n"
+-" ActionID: Optional Action id for message matching.\n";
+-
+ /*! \brief Manager command "command" - execute CLI command */
+ static int action_command(struct mansession *s, const struct message *m)
+ {
+@@ -2256,8 +2890,9 @@
+ }
+
+ astman_append(s, "Response: Follows\r\nPrivilege: Command\r\n");
+- if (!ast_strlen_zero(id))
++ if (!ast_strlen_zero(id)) {
+ astman_append(s, "ActionID: %s\r\n", id);
++ }
+ /* FIXME: Wedge a ActionID response in here, waiting for later changes */
+ ast_cli_command(fd, cmd); /* XXX need to change this to use a FILE * */
+ l = lseek(fd, 0, SEEK_END); /* how many chars available */
+@@ -2281,8 +2916,9 @@
+ close(fd);
+ unlink(template);
+ astman_append(s, "--END COMMAND--\r\n\r\n");
+- if (final_buf)
++ if (final_buf) {
+ ast_free(final_buf);
++ }
+ return 0;
+ }
+
+@@ -2325,8 +2961,9 @@
+ in->vars, in->account, &chan);
+ }
+
+- if (!chan)
+- snprintf(requested_channel, AST_CHANNEL_NAME, "%s/%s", in->tech, in->data);
++ if (!chan) {
++ snprintf(requested_channel, AST_CHANNEL_NAME, "%s/%s", in->tech, in->data);
++ }
+ /* Tell the manager what happened with the channel */
+ manager_event(EVENT_FLAG_CALL, "OriginateResponse",
+ "%s%s"
+@@ -2338,36 +2975,21 @@
+ "Uniqueid: %s\r\n"
+ "CallerIDNum: %s\r\n"
+ "CallerIDName: %s\r\n",
+- in->idtext, ast_strlen_zero(in->idtext) ? "" : "\r\n", res ? "Failure" : "Success",
+- chan ? chan->name : requested_channel, in->context, in->exten, reason,
++ in->idtext, ast_strlen_zero(in->idtext) ? "" : "\r\n", res ? "Failure" : "Success",
++ chan ? chan->name : requested_channel, in->context, in->exten, reason,
+ chan ? chan->uniqueid : "<null>",
+ S_OR(in->cid_num, "<unknown>"),
+ S_OR(in->cid_name, "<unknown>")
+ );
+
+ /* Locked by ast_pbx_outgoing_exten or ast_pbx_outgoing_app */
+- if (chan)
++ if (chan) {
+ ast_channel_unlock(chan);
++ }
+ ast_free(in);
+ return NULL;
+ }
+
+-static char mandescr_originate[] =
+-"Description: Generates an outgoing call to a Extension/Context/Priority or\n"
+-" Application/Data\n"
+-"Variables: (Names marked with * are required)\n"
+-" *Channel: Channel name to call\n"
+-" Exten: Extension to use (requires 'Context' and 'Priority')\n"
+-" Context: Context to use (requires 'Exten' and 'Priority')\n"
+-" Priority: Priority to use (requires 'Exten' and 'Context')\n"
+-" Application: Application to use\n"
+-" Data: Data to use (requires 'Application')\n"
+-" Timeout: How long to wait for call to be answered (in ms)\n"
+-" CallerID: Caller ID to be set on the outgoing channel\n"
+-" Variable: Channel variable to set, multiple Variable: headers are allowed\n"
+-" Account: Account code\n"
+-" Async: Set to 'true' for fast origination\n";
+-
+ static int action_originate(struct mansession *s, const struct message *m)
+ {
+ const char *name = astman_get_header(m, "Channel");
+@@ -2419,13 +3041,15 @@
+ ast_copy_string(tmp2, callerid, sizeof(tmp2));
+ ast_callerid_parse(tmp2, &n, &l);
+ if (n) {
+- if (ast_strlen_zero(n))
++ if (ast_strlen_zero(n)) {
+ n = NULL;
++ }
+ }
+ if (l) {
+ ast_shrink_phone_number(l);
+- if (ast_strlen_zero(l))
++ if (ast_strlen_zero(l)) {
+ l = NULL;
++ }
+ }
+ if (!ast_strlen_zero(codecs)) {
+ format = 0;
+@@ -2439,13 +3063,15 @@
+ if (!ast_strlen_zero(id))
+ snprintf(fast->idtext, sizeof(fast->idtext), "ActionID: %s", id);
+ ast_copy_string(fast->tech, tech, sizeof(fast->tech));
+- ast_copy_string(fast->data, data, sizeof(fast->data));
++ ast_copy_string(fast->data, data, sizeof(fast->data));
+ ast_copy_string(fast->app, app, sizeof(fast->app));
+ ast_copy_string(fast->appdata, appdata, sizeof(fast->appdata));
+- if (l)
++ if (l) {
+ ast_copy_string(fast->cid_num, l, sizeof(fast->cid_num));
+- if (n)
++ }
++ if (n) {
+ ast_copy_string(fast->cid_name, n, sizeof(fast->cid_name));
++ }
+ fast->vars = vars;
+ ast_copy_string(fast->context, context, sizeof(fast->context));
+ ast_copy_string(fast->exten, exten, sizeof(fast->exten));
+@@ -2478,33 +3104,21 @@
+ }
+ res = ast_pbx_outgoing_app(tech, format, data, to, app, appdata, &reason, 1, l, n, vars, account, NULL);
+ } else {
+- if (exten && context && pi)
++ if (exten && context && pi) {
+ res = ast_pbx_outgoing_exten(tech, format, data, to, context, exten, pi, &reason, 1, l, n, vars, account, NULL);
+- else {
++ } else {
+ astman_send_error(s, m, "Originate with 'Exten' requires 'Context' and 'Priority'");
+ return 0;
+ }
+ }
+- if (!res)
++ if (!res) {
+ astman_send_ack(s, m, "Originate successfully queued");
+- else
++ } else {
+ astman_send_error(s, m, "Originate failed");
++ }
+ return 0;
+ }
+
+-/*! \brief Help text for manager command mailboxstatus
+- */
+-static char mandescr_mailboxstatus[] =
+-"Description: Checks a voicemail account for status.\n"
+-"Variables: (Names marked with * are required)\n"
+-" *Mailbox: Full mailbox ID <mailbox>@<vm-context>\n"
+-" ActionID: Optional ActionID for message matching.\n"
+-"Returns number of messages.\n"
+-" Message: Mailbox Status\n"
+-" Mailbox: <mailboxid>\n"
+-" Waiting: <count>\n"
+-"\n";
+-
+ static int action_mailboxstatus(struct mansession *s, const struct message *m)
+ {
+ const char *mailbox = astman_get_header(m, "Mailbox");
+@@ -2522,18 +3136,6 @@
+ return 0;
+ }
+
+-static char mandescr_mailboxcount[] =
+-"Description: Checks a voicemail account for new messages.\n"
+-"Variables: (Names marked with * are required)\n"
+-" *Mailbox: Full mailbox ID <mailbox>@<vm-context>\n"
+-" ActionID: Optional ActionID for message matching.\n"
+-"Returns number of urgent, new and old messages.\n"
+-" Message: Mailbox Message Count\n"
+-" Mailbox: <mailboxid>\n"
+-" UrgentMessages: <count>\n"
+-" NewMessages: <count>\n"
+-" OldMessages: <count>\n"
+-"\n";
+ static int action_mailboxcount(struct mansession *s, const struct message *m)
+ {
+ const char *mailbox = astman_get_header(m, "Mailbox");
+@@ -2555,17 +3157,6 @@
+ return 0;
+ }
+
+-static char mandescr_extensionstate[] =
+-"Description: Report the extension state for given extension.\n"
+-" If the extension has a hint, will use devicestate to check\n"
+-" the status of the device connected to the extension.\n"
+-"Variables: (Names marked with * are required)\n"
+-" *Exten: Extension to check state on\n"
+-" *Context: Context for extension\n"
+-" ActionId: Optional ID for this transaction\n"
+-"Will return an \"Extension Status\" message.\n"
+-"The response will include the hint for the extension and the status.\n";
+-
+ static int action_extensionstate(struct mansession *s, const struct message *m)
+ {
+ const char *exten = astman_get_header(m, "Exten");
+@@ -2576,8 +3167,9 @@
+ astman_send_error(s, m, "Extension not specified");
+ return 0;
+ }
+- if (ast_strlen_zero(context))
++ if (ast_strlen_zero(context)) {
+ context = "default";
++ }
+ status = ast_extension_state(NULL, context, exten);
+ ast_get_hint(hint, sizeof(hint) - 1, NULL, 0, NULL, context, exten);
+ astman_start_ack(s, m);
+@@ -2590,13 +3182,6 @@
+ return 0;
+ }
+
+-static char mandescr_timeout[] =
+-"Description: Hangup a channel after a certain time.\n"
+-"Variables: (Names marked with * are required)\n"
+-" *Channel: Channel name to hangup\n"
+-" *Timeout: Maximum duration of the call (sec)\n"
+-"Acknowledges set time with 'Timeout Set' message\n";
+-
+ static int action_timeout(struct mansession *s, const struct message *m)
+ {
+ struct ast_channel *c;
+@@ -2608,20 +3193,26 @@
+ astman_send_error(s, m, "No channel specified");
+ return 0;
+ }
++
+ if (!timeout || timeout < 0) {
+ astman_send_error(s, m, "No timeout specified");
+ return 0;
+ }
+- c = ast_get_channel_by_name_locked(name);
+- if (!c) {
++
++ if (!(c = ast_channel_get_by_name(name))) {
+ astman_send_error(s, m, "No such channel");
+ return 0;
+ }
+
+ when.tv_usec = (timeout - when.tv_sec) * 1000000.0;
++
++ ast_channel_lock(c);
+ ast_channel_setwhentohangup_tv(c, when);
+ ast_channel_unlock(c);
++ c = ast_channel_unref(c);
++
+ astman_send_ack(s, m, "Timeout Set");
++
+ return 0;
+ }
+
+@@ -2634,7 +3225,7 @@
+ {
+ int ret = 0;
+
+- ast_mutex_lock(&s->session->__lock);
++ ao2_lock(s->session);
+ if (s->session->f != NULL) {
+ struct eventqent *eqe;
+
+@@ -2649,17 +3240,10 @@
+ s->session->last_ev = unref_event(s->session->last_ev);
+ }
+ }
+- ast_mutex_unlock(&s->session->__lock);
++ ao2_unlock(s->session);
+ return ret;
+ }
+
+-static char mandescr_userevent[] =
+-"Description: Send an event to manager sessions.\n"
+-"Variables: (Names marked with * are required)\n"
+-" *UserEvent: EventStringToSend\n"
+-" Header1: Content1\n"
+-" HeaderN: ContentN\n";
+-
+ static int action_userevent(struct mansession *s, const struct message *m)
+ {
+ const char *event = astman_get_header(m, "UserEvent");
+@@ -2678,21 +3262,17 @@
+ return 0;
+ }
+
+-static char mandescr_coresettings[] =
+-"Description: Query for Core PBX settings.\n"
+-"Variables: (Names marked with * are optional)\n"
+-" *ActionID: ActionID of this transaction\n";
+-
+ /*! \brief Show PBX core settings information */
+ static int action_coresettings(struct mansession *s, const struct message *m)
+ {
+ const char *actionid = astman_get_header(m, "ActionID");
+ char idText[150];
+
+- if (!ast_strlen_zero(actionid))
++ if (!ast_strlen_zero(actionid)) {
+ snprintf(idText, sizeof(idText), "ActionID: %s\r\n", actionid);
+- else
++ } else {
+ idText[0] = '\0';
++ }
+
+ astman_append(s, "Response: Success\r\n"
+ "%s"
+@@ -2703,14 +3283,14 @@
+ "CoreMaxLoadAvg: %f\r\n"
+ "CoreRunUser: %s\r\n"
+ "CoreRunGroup: %s\r\n"
+- "CoreMaxFilehandles: %d\r\n"
++ "CoreMaxFilehandles: %d\r\n"
+ "CoreRealTimeEnabled: %s\r\n"
+ "CoreCDRenabled: %s\r\n"
+ "CoreHTTPenabled: %s\r\n"
+ "\r\n",
+ idText,
+ AMI_VERSION,
+- ast_get_version(),
++ ast_get_version(),
+ ast_config_AST_SYSTEM_NAME,
+ option_maxcalls,
+ option_maxload,
+@@ -2724,70 +3304,61 @@
+ return 0;
+ }
+
+-static char mandescr_corestatus[] =
+-"Description: Query for Core PBX status.\n"
+-"Variables: (Names marked with * are optional)\n"
+-" *ActionID: ActionID of this transaction\n";
+-
+ /*! \brief Show PBX core status information */
+ static int action_corestatus(struct mansession *s, const struct message *m)
+ {
+ const char *actionid = astman_get_header(m, "ActionID");
+ char idText[150];
+- char startuptime[150];
+- char reloadtime[150];
++ char startuptime[150], startupdate[150];
++ char reloadtime[150], reloaddate[150];
+ struct ast_tm tm;
+
+- if (!ast_strlen_zero(actionid))
++ if (!ast_strlen_zero(actionid)) {
+ snprintf(idText, sizeof(idText), "ActionID: %s\r\n", actionid);
+- else
++ } else {
+ idText[0] = '\0';
++ }
+
+ ast_localtime(&ast_startuptime, &tm, NULL);
+ ast_strftime(startuptime, sizeof(startuptime), "%H:%M:%S", &tm);
++ ast_strftime(startupdate, sizeof(startupdate), "%Y-%m-%d", &tm);
+ ast_localtime(&ast_lastreloadtime, &tm, NULL);
+ ast_strftime(reloadtime, sizeof(reloadtime), "%H:%M:%S", &tm);
++ ast_strftime(reloaddate, sizeof(reloaddate), "%Y-%m-%d", &tm);
+
+ astman_append(s, "Response: Success\r\n"
+ "%s"
++ "CoreStartupDate: %s\r\n"
+ "CoreStartupTime: %s\r\n"
++ "CoreReloadDate: %s\r\n"
+ "CoreReloadTime: %s\r\n"
+ "CoreCurrentCalls: %d\r\n"
+ "\r\n",
+ idText,
++ startupdate,
+ startuptime,
++ reloaddate,
+ reloadtime,
+ ast_active_channels()
+ );
+ return 0;
+ }
+
+-static char mandescr_reload[] =
+-"Description: Send a reload event.\n"
+-"Variables: (Names marked with * are optional)\n"
+-" *ActionID: ActionID of this transaction\n"
+-" *Module: Name of the module to reload\n";
+-
+ /*! \brief Send a reload event */
+ static int action_reload(struct mansession *s, const struct message *m)
+ {
+ const char *module = astman_get_header(m, "Module");
+ int res = ast_module_reload(S_OR(module, NULL));
+
+- if (res == 2)
++ if (res == 2) {
+ astman_send_ack(s, m, "Module Reloaded");
+- else
++ } else {
+ astman_send_error(s, m, s == 0 ? "No such module" : "Module does not support reload");
++ }
+ return 0;
+ }
+
+-static char mandescr_coreshowchannels[] =
+-"Description: List currently defined channels and some information\n"
+-" about them.\n"
+-"Variables:\n"
+-" ActionID: Optional Action id for message matching.\n";
+-
+-/*! \brief Manager command "CoreShowChannels" - List currently defined channels
++/*! \brief Manager command "CoreShowChannels" - List currently defined channels
+ * and some information about them. */
+ static int action_coreshowchannels(struct mansession *s, const struct message *m)
+ {
+@@ -2796,18 +3367,28 @@
+ struct ast_channel *c = NULL;
+ int numchans = 0;
+ int duration, durh, durm, durs;
++ struct ast_channel_iterator *iter;
+
+- if (!ast_strlen_zero(actionid))
++ if (!ast_strlen_zero(actionid)) {
+ snprintf(idText, sizeof(idText), "ActionID: %s\r\n", actionid);
+- else
++ } else {
+ idText[0] = '\0';
++ }
+
+- astman_send_listack(s, m, "Channels will follow", "start");
++ if (!(iter = ast_channel_iterator_all_new(0))) {
++ astman_send_error(s, m, "Memory Allocation Failure");
++ return 1;
++ }
+
+- while ((c = ast_channel_walk_locked(c)) != NULL) {
+- struct ast_channel *bc = ast_bridged_channel(c);
++ astman_send_listack(s, m, "Channels will follow", "start");
++
++ for (; (c = ast_channel_iterator_next(iter)); ast_channel_unref(c)) {
++ struct ast_channel *bc;
+ char durbuf[10] = "";
+
++ ast_channel_lock(c);
++
++ bc = ast_bridged_channel(c);
+ if (c->cdr && !ast_tvzero(c->cdr->start)) {
+ duration = (int)(ast_tvdiff_ms(ast_tvnow(), c->cdr->start) / 1000);
+ durh = duration / 3600;
+@@ -2836,7 +3417,9 @@
+ "\r\n", idText, c->name, c->uniqueid, c->context, c->exten, c->priority, c->_state,
+ ast_state2str(c->_state), c->appl ? c->appl : "", c->data ? S_OR(c->data, "") : "",
+ S_OR(c->cid.cid_num, ""), durbuf, S_OR(c->accountcode, ""), bc ? bc->name : "", bc ? bc->uniqueid : "");
++
+ ast_channel_unlock(c);
++
+ numchans++;
+ }
+
+@@ -2847,18 +3430,11 @@
+ "%s"
+ "\r\n", numchans, idText);
+
++ ast_channel_iterator_destroy(iter);
++
+ return 0;
+ }
+
+-static char mandescr_modulecheck[] =
+-"Description: Checks if Asterisk module is loaded\n"
+-"Variables: \n"
+-" ActionID: <id> Action ID for this transaction. Will be returned.\n"
+-" Module: <name> Asterisk module name (not including extension)\n"
+-"\n"
+-"Will return Success/Failure\n"
+-"For success returns, the module revision number is included.\n";
+-
+ /* Manager function to check if module is loaded */
+ static int manager_modulecheck(struct mansession *s, const struct message *m)
+ {
+@@ -2891,10 +3467,11 @@
+ version = ast_file_version_find(filename);
+ #endif
+
+- if (!ast_strlen_zero(id))
++ if (!ast_strlen_zero(id)) {
+ snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
+- else
++ } else {
+ idText[0] = '\0';
++ }
+ astman_append(s, "Response: Success\r\n%s", idText);
+ #if !defined(LOW_MEMORY)
+ astman_append(s, "Version: %s\r\n\r\n", version ? version : "");
+@@ -2902,54 +3479,48 @@
+ return 0;
+ }
+
+-static char mandescr_moduleload[] =
+-"Description: Loads, unloads or reloads an Asterisk module in a running system.\n"
+-"Variables: \n"
+-" ActionID: <id> Action ID for this transaction. Will be returned.\n"
+-" Module: <name> Asterisk module name (including .so extension)\n"
+-" or subsystem identifier:\n"
+-" cdr, enum, dnsmgr, extconfig, manager, rtp, http\n"
+-" LoadType: load | unload | reload\n"
+-" The operation to be done on module\n"
+-" If no module is specified for a reload loadtype, all modules are reloaded";
+-
+ static int manager_moduleload(struct mansession *s, const struct message *m)
+ {
+ int res;
+ const char *module = astman_get_header(m, "Module");
+ const char *loadtype = astman_get_header(m, "LoadType");
+
+- if (!loadtype || strlen(loadtype) == 0)
++ if (!loadtype || strlen(loadtype) == 0) {
+ astman_send_error(s, m, "Incomplete ModuleLoad action.");
+- if ((!module || strlen(module) == 0) && strcasecmp(loadtype, "reload") != 0)
++ }
++ if ((!module || strlen(module) == 0) && strcasecmp(loadtype, "reload") != 0) {
+ astman_send_error(s, m, "Need module name");
++ }
+
+ if (!strcasecmp(loadtype, "load")) {
+ res = ast_load_resource(module);
+- if (res)
++ if (res) {
+ astman_send_error(s, m, "Could not load module.");
+- else
++ } else {
+ astman_send_ack(s, m, "Module loaded.");
++ }
+ } else if (!strcasecmp(loadtype, "unload")) {
+ res = ast_unload_resource(module, AST_FORCE_SOFT);
+- if (res)
++ if (res) {
+ astman_send_error(s, m, "Could not unload module.");
+- else
++ } else {
+ astman_send_ack(s, m, "Module unloaded.");
++ }
+ } else if (!strcasecmp(loadtype, "reload")) {
+ if (module != NULL) {
+ res = ast_module_reload(module);
+- if (res == 0)
++ if (res == 0) {
+ astman_send_error(s, m, "No such module.");
+- else if (res == 1)
++ } else if (res == 1) {
+ astman_send_error(s, m, "Module does not support reload action.");
+- else
++ } else {
+ astman_send_ack(s, m, "Module reloaded.");
++ }
+ } else {
+ ast_module_reload(NULL); /* Reload all modules */
+ astman_send_ack(s, m, "All modules reloaded");
+ }
+- } else
++ } else
+ astman_send_error(s, m, "Incomplete ModuleLoad action.");
+ return 0;
+ }
+@@ -2973,21 +3544,21 @@
+ int ret = 0;
+ struct manager_action *tmp;
+ const char *user = astman_get_header(m, "Username");
++ int (*call_func)(struct mansession *s, const struct message *m) = NULL;
+
+ ast_copy_string(action, __astman_get_header(m, "Action", GET_HEADER_SKIP_EMPTY), sizeof(action));
+- ast_debug(1, "Manager received command '%s'\n", action);
+
+ if (ast_strlen_zero(action)) {
+- ast_mutex_lock(&s->session->__lock);
++ mansession_lock(s);
+ astman_send_error(s, m, "Missing action in request");
+- ast_mutex_unlock(&s->session->__lock);
++ mansession_unlock(s);
+ return 0;
+ }
+
+ if (!s->session->authenticated && strcasecmp(action, "Login") && strcasecmp(action, "Logoff") && strcasecmp(action, "Challenge")) {
+- ast_mutex_lock(&s->session->__lock);
++ mansession_lock(s);
+ astman_send_error(s, m, "Permission denied");
+- ast_mutex_unlock(&s->session->__lock);
++ mansession_unlock(s);
+ return 0;
+ }
+
+@@ -2995,34 +3566,42 @@
+ (!strcasecmp(action, "Login") || !strcasecmp(action, "Challenge"))) {
+ if (check_manager_session_inuse(user)) {
+ sleep(1);
+- ast_mutex_lock(&s->session->__lock);
++ mansession_lock(s);
+ astman_send_error(s, m, "Login Already In Use");
+- ast_mutex_unlock(&s->session->__lock);
++ mansession_unlock(s);
+ return -1;
+ }
+ }
+
+ AST_RWLIST_RDLOCK(&actions);
+ AST_RWLIST_TRAVERSE(&actions, tmp, list) {
+- if (strcasecmp(action, tmp->action))
++ if (strcasecmp(action, tmp->action)) {
+ continue;
+- if (s->session->writeperm & tmp->authority || tmp->authority == 0)
+- ret = tmp->func(s, m);
+- else
++ }
++ if (s->session->writeperm & tmp->authority || tmp->authority == 0) {
++ call_func = tmp->func;
++ } else {
+ astman_send_error(s, m, "Permission denied");
++ tmp = NULL;
++ }
+ break;
+ }
+ AST_RWLIST_UNLOCK(&actions);
+
+- if (!tmp) {
++ if (tmp && call_func) {
++ /* call AMI function after actions list are unlocked */
++ ast_debug(1, "Running action '%s'\n", tmp->action);
++ ret = call_func(s, m);
++ } else {
+ char buf[512];
+ snprintf(buf, sizeof(buf), "Invalid/unknown command: %s. Use Action: ListCommands to show available commands.", action);
+- ast_mutex_lock(&s->session->__lock);
++ mansession_lock(s);
+ astman_send_error(s, m, buf);
+- ast_mutex_unlock(&s->session->__lock);
++ mansession_unlock(s);
+ }
+- if (ret)
++ if (ret) {
+ return ret;
++ }
+ /* Once done with our message, deliver any pending events unless the
+ requester doesn't want them as part of this response.
+ */
+@@ -3054,12 +3633,13 @@
+ */
+ for (x = 0; x < s->session->inlen; x++) {
+ int cr; /* set if we have \r */
+- if (src[x] == '\r' && x+1 < s->session->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')
++ } else if (src[x] == '\n') {
+ cr = 1; /* also accept \n only */
+- else
++ } else {
+ continue;
++ }
+ memmove(output, src, x); /*... but trim \r\n */
+ output[x] = '\0'; /* terminate the string */
+ x += cr; /* number of bytes used */
+@@ -3075,40 +3655,42 @@
+ res = 0;
+ while (res == 0) {
+ /* XXX do we really need this locking ? */
+- ast_mutex_lock(&s->session->__lock);
++ mansession_lock(s);
+ if (s->session->pending_event) {
+ s->session->pending_event = 0;
+- ast_mutex_unlock(&s->session->__lock);
++ mansession_unlock(s);
+ return 0;
+ }
+ s->session->waiting_thread = pthread_self();
+- ast_mutex_unlock(&s->session->__lock);
++ mansession_unlock(s);
+
+ res = ast_wait_for_input(s->session->fd, -1); /* return 0 on timeout ? */
+
+- ast_mutex_lock(&s->session->__lock);
++ mansession_lock(s);
+ s->session->waiting_thread = AST_PTHREADT_NULL;
+- ast_mutex_unlock(&s->session->__lock);
++ mansession_unlock(s);
+ }
+ if (res < 0) {
+ /* If we get a signal from some other thread (typically because
+ * there are new events queued), return 0 to notify the caller.
+ */
+- if (errno == EINTR || errno == EAGAIN)
++ if (errno == EINTR || errno == EAGAIN) {
+ return 0;
++ }
+ ast_log(LOG_WARNING, "poll() returned error: %s\n", strerror(errno));
+ return -1;
+ }
+- ast_mutex_lock(&s->session->__lock);
++
++ mansession_lock(s);
+ res = fread(src + s->session->inlen, 1, maxlen - s->session->inlen, s->session->f);
+- if (res < 1)
++ if (res < 1) {
+ res = -1; /* error return */
+- else {
++ } else {
+ s->session->inlen += res;
+ src[s->session->inlen] = '\0';
+ res = 0;
+ }
+- ast_mutex_unlock(&s->session->__lock);
++ mansession_unlock(s);
+ return res;
+ }
+
+@@ -3120,16 +3702,18 @@
+
+ for (;;) {
+ /* Check if any events are pending and do them if needed */
+- if (process_events(s))
++ if (process_events(s)) {
+ return -1;
++ }
+ res = get_input(s, header_buf);
+ if (res == 0) {
+ continue;
+ } else if (res > 0) {
+- if (ast_strlen_zero(header_buf))
++ if (ast_strlen_zero(header_buf)) {
+ return process_message(s, &m) ? -1 : 0;
+- else if (m.hdrcount < (AST_MAX_MANHEADERS - 1))
++ } else if (m.hdrcount < (AST_MAX_MANHEADERS - 1)) {
+ m.headers[m.hdrcount++] = ast_strdupa(header_buf);
++ }
+ } else {
+ return res;
+ }
+@@ -3147,56 +3731,53 @@
+ static void *session_do(void *data)
+ {
+ struct ast_tcptls_session_instance *ser = data;
+- struct mansession_session *session = ast_calloc(1, sizeof(*session));
+- struct mansession s = {.session = NULL, };
++ struct mansession_session *session = build_mansession(ser->remote_address);
++ struct mansession s = { NULL, };
+ int flags;
+ int res;
+
+- if (session == NULL)
++ if (session == NULL) {
+ goto done;
++ }
+
+- session->writetimeout = 100;
+- session->waiting_thread = AST_PTHREADT_NULL;
+-
+ flags = fcntl(ser->fd, F_GETFL);
+- if (!block_sockets) /* make sure socket is non-blocking */
++ if (!block_sockets) { /* make sure socket is non-blocking */
+ flags |= O_NONBLOCK;
+- else
++ } else {
+ flags &= ~O_NONBLOCK;
++ }
+ fcntl(ser->fd, F_SETFL, flags);
+
+- ast_mutex_init(&session->__lock);
+- session->send_events = -1;
++ ao2_lock(session);
+ /* Hook to the tail of the event queue */
+ session->last_ev = grab_last();
+
++ ast_mutex_init(&s.lock);
++
+ /* these fields duplicate those in the 'ser' structure */
+- session->fd = ser->fd;
+- session->f = ser->f;
++ session->fd = s.fd = ser->fd;
++ session->f = s.f = ser->f;
+ session->sin = ser->remote_address;
+ s.session = session;
+
+ AST_LIST_HEAD_INIT_NOLOCK(&session->datastores);
+
+- AST_LIST_LOCK(&sessions);
+- AST_LIST_INSERT_HEAD(&sessions, session, list);
+- ast_atomic_fetchadd_int(&num_sessions, 1);
+- AST_LIST_UNLOCK(&sessions);
+-
++ ao2_unlock(session);
+ 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 (session->authenticated) {
+- if (manager_displayconnects(session))
++ 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)
++ if (displayconnects) {
+ 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
+@@ -3212,8 +3793,9 @@
+ */
+ usleep(1);
+
+- destroy_session(session);
++ session_destroy(session);
+
++ ast_mutex_destroy(&s.lock);
+ done:
+ ao2_ref(ser, -1);
+ ser = NULL;
+@@ -3225,23 +3807,24 @@
+ {
+ struct mansession_session *session;
+ time_t now = time(NULL);
++ struct ao2_iterator i;
+
+- AST_LIST_LOCK(&sessions);
+- AST_LIST_TRAVERSE_SAFE_BEGIN(&sessions, session, list) {
++ i = ao2_iterator_init(sessions, 0);
++ while ((session = ao2_iterator_next(&i)) && n_max > 0) {
++ ao2_lock(session);
+ if (session->sessiontimeout && (now > session->sessiontimeout) && !session->inuse) {
+- AST_LIST_REMOVE_CURRENT(list);
+- ast_atomic_fetchadd_int(&num_sessions, -1);
+ if (session->authenticated && (VERBOSITY_ATLEAST(2)) && manager_displayconnects(session)) {
+ ast_verb(2, "HTTP Manager '%s' timed out from %s\n",
+ session->username, ast_inet_ntoa(session->sin.sin_addr));
+ }
+- free_session(session); /* XXX outside ? */
+- if (--n_max <= 0)
+- break;
++ ao2_unlock(session);
++ session_destroy(session);
++ n_max--;
++ } else {
++ ao2_unlock(session);
++ unref_mansession(session);
+ }
+ }
+- AST_LIST_TRAVERSE_SAFE_END;
+- AST_LIST_UNLOCK(&sessions);
+ }
+
+ /*
+@@ -3253,8 +3836,9 @@
+ struct eventqent *tmp = ast_malloc(sizeof(*tmp) + strlen(str));
+ static int seq; /* sequence number */
+
+- if (!tmp)
++ if (!tmp) {
+ return -1;
++ }
+
+ /* need to init all fields, because ast_malloc() does not */
+ tmp->usecount = 0;
+@@ -3286,12 +3870,9 @@
+ struct timeval now;
+ struct ast_str *buf;
+
+- /* Abort if there aren't any manager sessions */
+- if (!num_sessions)
+- return 0;
+-
+- if (!(buf = ast_str_thread_get(&manager_event_buf, MANAGER_EVENT_BUF_INITSIZE)))
++ if (!(buf = ast_str_thread_get(&manager_event_buf, MANAGER_EVENT_BUF_INITSIZE))) {
+ return -1;
++ }
+
+ cat_str = authority_to_str(category, &auth);
+ ast_str_set(&buf, 0,
+@@ -3322,21 +3903,25 @@
+ append_event(ast_str_buffer(buf), category);
+
+ /* Wake up any sleeping sessions */
+- AST_LIST_LOCK(&sessions);
+- 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.
+- */
+- session->pending_event = 1;
+- ast_mutex_unlock(&session->__lock);
++ if (sessions) {
++ struct ao2_iterator i;
++ i = ao2_iterator_init(sessions, 0);
++ while ((session = ao2_iterator_next(&i))) {
++ ao2_lock(session);
++ 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.
++ */
++ session->pending_event = 1;
++ }
++ ao2_unlock(session);
++ unref_mansession(session);
++ }
+ }
+- AST_LIST_UNLOCK(&sessions);
+
+ AST_RWLIST_RDLOCK(&manager_hooks);
+ AST_RWLIST_TRAVERSE(&manager_hooks, hook, list) {
+@@ -3362,6 +3947,7 @@
+ AST_RWLIST_TRAVERSE_SAFE_BEGIN(&actions, cur, list) {
+ if (!strcasecmp(action, cur->action)) {
+ AST_RWLIST_REMOVE_CURRENT(list);
++ ast_string_field_free_memory(cur);
+ ast_free(cur);
+ ast_verb(2, "Manager unregistered action %s\n", action);
+ break;
+@@ -3405,10 +3991,11 @@
+ }
+ }
+
+- if (prev)
++ if (prev) {
+ AST_RWLIST_INSERT_AFTER(&actions, prev, act, list);
+- else
++ } else {
+ AST_RWLIST_INSERT_HEAD(&actions, act, list);
++ }
+
+ ast_verb(2, "Manager registered action %s\n", act->action);
+
+@@ -3422,16 +4009,53 @@
+ int ast_manager_register2(const char *action, int auth, int (*func)(struct mansession *s, const struct message *m), const char *synopsis, const char *description)
+ {
+ struct manager_action *cur = NULL;
++#ifdef AST_XML_DOCS
++ char *tmpxml;
++#endif
+
+- if (!(cur = ast_calloc(1, sizeof(*cur))))
++ if (!(cur = ast_calloc(1, sizeof(*cur)))) {
+ return -1;
++ }
+
++ if (ast_string_field_init(cur, 128)) {
++ ast_free(cur);
++ return -1;
++ }
++
+ cur->action = action;
+ cur->authority = auth;
+ cur->func = func;
+- cur->synopsis = synopsis;
+- cur->description = description;
++#ifdef AST_XML_DOCS
++ if (ast_strlen_zero(synopsis) && ast_strlen_zero(description)) {
++ tmpxml = ast_xmldoc_build_synopsis("manager", action);
++ ast_string_field_set(cur, synopsis, tmpxml);
++ ast_free(tmpxml);
+
++ tmpxml = ast_xmldoc_build_syntax("manager", action);
++ ast_string_field_set(cur, syntax, tmpxml);
++ ast_free(tmpxml);
++
++ tmpxml = ast_xmldoc_build_description("manager", action);
++ ast_string_field_set(cur, description, tmpxml);
++ ast_free(tmpxml);
++
++ tmpxml = ast_xmldoc_build_seealso("manager", action);
++ ast_string_field_set(cur, seealso, tmpxml);
++ ast_free(tmpxml);
++
++ tmpxml = ast_xmldoc_build_arguments("manager", action);
++ ast_string_field_set(cur, arguments, tmpxml);
++ ast_free(tmpxml);
++
++ cur->docsrc = AST_XML_DOC;
++ } else {
++#endif
++ ast_string_field_set(cur, synopsis, synopsis);
++ ast_string_field_set(cur, description, description);
++#ifdef AST_XML_DOCS
++ cur->docsrc = AST_STATIC_DOC;
++ }
++#endif
+ if (ast_manager_register_struct(cur)) {
+ ast_free(cur);
+ return -1;
+@@ -3460,7 +4084,7 @@
+ FORMAT_XML,
+ };
+
+-static char *contenttype[] = {
++static const char * const contenttype[] = {
+ [FORMAT_RAW] = "plain",
+ [FORMAT_HTML] = "html",
+ [FORMAT_XML] = "xml",
+@@ -3474,26 +4098,62 @@
+ static struct mansession_session *find_session(uint32_t ident, int incinuse)
+ {
+ struct mansession_session *session;
++ struct ao2_iterator i;
+
+- if (ident == 0)
++ if (ident == 0) {
+ return NULL;
++ }
+
+- AST_LIST_LOCK(&sessions);
+- AST_LIST_TRAVERSE(&sessions, session, list) {
+- ast_mutex_lock(&session->__lock);
++ i = ao2_iterator_init(sessions, 0);
++ while ((session = ao2_iterator_next(&i))) {
++ ao2_lock(session);
+ if (session->managerid == ident && !session->needdestroy) {
+ ast_atomic_fetchadd_int(&session->inuse, incinuse ? 1 : 0);
+ break;
+ }
+- ast_mutex_unlock(&session->__lock);
++ ao2_unlock(session);
++ unref_mansession(session);
+ }
+- AST_LIST_UNLOCK(&sessions);
+
+ return session;
+ }
+
+-int astman_is_authed(uint32_t ident)
++/*!
++ * locate an http session in the list.
++ * The search keys (nonce) and (username) is value from received
++ * "Authorization" http header.
++ * As well as in find_session() function, the value of the nonce can't be zero.
++ * (0 meansi, that the session used for AMI socket connection).
++ * Flag (stale) is set, if client used valid, but old, nonce value.
++ *
++ */
++static struct mansession_session *find_session_by_nonce(const char *username, unsigned long nonce, int *stale)
+ {
++ struct mansession_session *session;
++ struct ao2_iterator i;
++
++ if (nonce == 0 || username == NULL || stale == NULL) {
++ return NULL;
++ }
++
++ i = ao2_iterator_init(sessions, 0);
++ while ((session = ao2_iterator_next(&i))) {
++ ao2_lock(session);
++ if (!strcasecmp(session->username, username) && session->managerid == nonce) {
++ *stale = 0;
++ break;
++ } else if (!strcasecmp(session->username, username) && session->oldnonce == nonce) {
++ *stale = 1;
++ break;
++ }
++ ao2_unlock(session);
++ unref_mansession(session);
++ }
++ return session;
++}
++
++int astman_is_authed(uint32_t ident)
++{
+ int authed;
+ struct mansession_session *session;
+
+@@ -3502,7 +4162,8 @@
+
+ authed = (session->authenticated != 0);
+
+- ast_mutex_unlock(&session->__lock);
++ ao2_unlock(session);
++ unref_mansession(session);
+
+ return authed;
+ }
+@@ -3511,18 +4172,24 @@
+ {
+ int result = 0;
+ struct mansession_session *session;
++ struct ao2_iterator i;
+
+- AST_LIST_LOCK(&sessions);
+- AST_LIST_TRAVERSE(&sessions, session, list) {
+- ast_mutex_lock(&session->__lock);
++ if (ident == 0) {
++ return 0;
++ }
++
++ i = ao2_iterator_init(sessions, 0);
++ while ((session = ao2_iterator_next(&i))) {
++ ao2_lock(session);
+ if ((session->managerid == ident) && (session->readperm & perm)) {
+ result = 1;
+- ast_mutex_unlock(&session->__lock);
++ ao2_unlock(session);
++ unref_mansession(session);
+ break;
+ }
+- ast_mutex_unlock(&session->__lock);
++ ao2_unlock(session);
++ unref_mansession(session);
+ }
+- AST_LIST_UNLOCK(&sessions);
+ return result;
+ }
+
+@@ -3530,18 +4197,24 @@
+ {
+ int result = 0;
+ struct mansession_session *session;
++ struct ao2_iterator i;
+
+- AST_LIST_LOCK(&sessions);
+- AST_LIST_TRAVERSE(&sessions, session, list) {
+- ast_mutex_lock(&session->__lock);
++ if (ident == 0) {
++ return 0;
++ }
++
++ i = ao2_iterator_init(sessions, 0);
++ while ((session = ao2_iterator_next(&i))) {
++ ao2_lock(session);
+ if ((session->managerid == ident) && (session->writeperm & perm)) {
+ result = 1;
+- ast_mutex_unlock(&session->__lock);
++ ao2_unlock(session);
++ unref_mansession(session);
+ break;
+ }
+- ast_mutex_unlock(&session->__lock);
++ ao2_unlock(session);
++ unref_mansession(session);
+ }
+- AST_LIST_UNLOCK(&sessions);
+ return result;
+ }
+
+@@ -3563,10 +4236,11 @@
+ ast_str_append(out, 0, "%s", buf);
+ dst = buf;
+ space = sizeof(buf);
+- if (*src == '\0')
++ if (*src == '\0') {
+ break;
++ }
+ }
+-
++
+ if ( (mode & 2) && !isalnum(*src)) {
+ *dst++ = '_';
+ space--;
+@@ -3611,29 +4285,11 @@
+ int count;
+ };
+
+-static int compress_char(char c)
+-{
+- c &= 0x7f;
+- if (c < 32)
+- return 0;
+- else if (c >= 'a' && c <= 'z')
+- return c - 64;
+- else if (c > 'z')
+- return '_';
+- else
+- return c - 32;
+-}
+-
+ static int variable_count_hash_fn(const void *vvc, const int flags)
+ {
+ const struct variable_count *vc = vvc;
+- int res = 0, i;
+- for (i = 0; i < 5; i++) {
+- if (vc->varname[i] == '\0')
+- break;
+- res += compress_char(vc->varname[i]) << (i * 6);
+- }
+- return res;
++
++ return ast_str_hash(vc->varname);
+ }
+
+ static int variable_count_cmp_fn(void *obj, void *vstr, int flags)
+@@ -3662,7 +4318,7 @@
+ *
+ * General: the unformatted text is used as a value of
+ * XML output: to be completed
+- *
++ *
+ * \verbatim
+ * Each section is within <response type="object" id="xxx">
+ * where xxx is taken from ajaxdest variable or defaults to unknown
+@@ -3675,7 +4331,7 @@
+ * Sections (blank lines in the input) are separated by a <HR>
+ *
+ */
+-static void xml_translate(struct ast_str **out, char *in, struct ast_variable *vars, enum output_format format)
++static void xml_translate(struct ast_str **out, char *in, struct ast_variable *get_vars, enum output_format format)
+ {
+ struct ast_variable *v;
+ const char *dest = NULL;
+@@ -3687,30 +4343,41 @@
+ struct variable_count *vc = NULL;
+ struct ao2_container *vco = NULL;
+
+- for (v = vars; v; v = v->next) {
+- if (!dest && !strcasecmp(v->name, "ajaxdest"))
+- dest = v->value;
+- else if (!objtype && !strcasecmp(v->name, "ajaxobjtype"))
+- objtype = v->value;
++ if (xml) {
++ /* dest and objtype need only for XML format */
++ for (v = get_vars; v; v = v->next) {
++ if (!strcasecmp(v->name, "ajaxdest")) {
++ dest = v->value;
++ } else if (!strcasecmp(v->name, "ajaxobjtype")) {
++ objtype = v->value;
++ }
++ }
++ if (ast_strlen_zero(dest)) {
++ dest = "unknown";
++ }
++ if (ast_strlen_zero(objtype)) {
++ objtype = "generic";
++ }
+ }
+- if (!dest)
+- dest = "unknown";
+- if (!objtype)
+- objtype = "generic";
+
+ /* we want to stop when we find an empty line */
+ while (in && *in) {
+ val = strsep(&in, "\r\n"); /* mark start and end of line */
+- if (in && *in == '\n') /* remove trailing \n if any */
++ if (in && *in == '\n') { /* remove trailing \n if any */
+ in++;
++ }
+ ast_trim_blanks(val);
+ ast_debug(5, "inobj %d in_data %d line <%s>\n", inobj, in_data, val);
+ if (ast_strlen_zero(val)) {
+- if (in_data) { /* close data */
++ /* empty line */
++ if (in_data) {
++ /* close data in Opaque mode */
+ ast_str_append(out, 0, xml ? "'" : "</td></tr>\n");
+ in_data = 0;
+ }
++
+ if (inobj) {
++ /* close block */
+ ast_str_append(out, 0, xml ? " /></response>\n" :
+ "<tr><td colspan=\"2\"><hr></td></tr>\r\n");
+ inobj = 0;
+@@ -3720,54 +4387,57 @@
+ continue;
+ }
+
+- /* we expect Name: value lines */
+- if (in_data) {
+- var = NULL;
+- } else {
+- var = strsep(&val, ":");
+- if (val) { /* found the field name */
+- val = ast_skip_blanks(val);
+- ast_trim_blanks(var);
+- } else { /* field name not found, move to opaque mode */
+- val = var;
+- var = "Opaque-data";
+- }
+- }
+-
+ if (!inobj) {
+- if (xml)
++ /* start new block */
++ if (xml) {
+ ast_str_append(out, 0, "<response type='object' id='%s'><%s", dest, objtype);
+- else
+- ast_str_append(out, 0, "<body>\n");
++ }
+ vco = ao2_container_alloc(37, variable_count_hash_fn, variable_count_cmp_fn);
+ inobj = 1;
+ }
+
+- if (!in_data) { /* build appropriate line start */
+- ast_str_append(out, 0, xml ? " " : "<tr><td>");
+- if ((vc = ao2_find(vco, var, 0)))
+- vc->count++;
+- else {
+- /* Create a new entry for this one */
+- vc = ao2_alloc(sizeof(*vc), NULL);
+- vc->varname = var;
+- vc->count = 1;
+- ao2_link(vco, vc);
+- }
+- xml_copy_escape(out, var, xml ? 1 | 2 : 0);
+- if (vc->count > 1)
+- ast_str_append(out, 0, "-%d", vc->count);
+- ao2_ref(vc, -1);
+- ast_str_append(out, 0, xml ? "='" : "</td><td>");
+- if (!strcmp(var, "Opaque-data"))
+- in_data = 1;
++ if (in_data) {
++ /* Process data field in Opaque mode */
++ xml_copy_escape(out, val, 0); /* data field */
++ ast_str_append(out, 0, xml ? "\n" : "<br>\n");
++ continue;
+ }
++
++ /* We expect "Name: value" line here */
++ var = strsep(&val, ":");
++ if (val) {
++ /* found the field name */
++ val = ast_skip_blanks(val);
++ ast_trim_blanks(var);
++ } else {
++ /* field name not found, switch to opaque mode */
++ val = var;
++ var = "Opaque-data";
++ in_data = 1;
++ }
++
++
++ ast_str_append(out, 0, xml ? " " : "<tr><td>");
++ if ((vc = ao2_find(vco, var, 0))) {
++ vc->count++;
++ } else {
++ /* Create a new entry for this one */
++ vc = ao2_alloc(sizeof(*vc), NULL);
++ vc->varname = var;
++ vc->count = 1;
++ ao2_link(vco, vc);
++ }
++
++ xml_copy_escape(out, var, xml ? 1 | 2 : 0); /* data name */
++ if (vc->count > 1) {
++ ast_str_append(out, 0, "-%d", vc->count);
++ }
++ ao2_ref(vc, -1);
++ ast_str_append(out, 0, xml ? "='" : "</td><td>");
+ xml_copy_escape(out, val, 0); /* data field */
+- if (!in_data)
+- ast_str_append(out, 0, xml ? "'" : "</td></tr>\n");
+- else
+- ast_str_append(out, 0, xml ? "\n" : "<br>\n");
++ ast_str_append(out, 0, xml ? "'" : "</td></tr>\n");
+ }
++
+ if (inobj) {
+ ast_str_append(out, 0, xml ? " /></response>\n" :
+ "<tr><td colspan=\"2\"><hr></td></tr>\r\n");
+@@ -3775,43 +4445,55 @@
+ }
+ }
+
+-static struct ast_str *generic_http_callback(enum output_format format,
+- struct sockaddr_in *remote_address, const char *uri, enum ast_http_method method,
+- struct ast_variable *params, int *status,
+- char **title, int *contentlength)
++static int generic_http_callback(struct ast_tcptls_session_instance *ser,
++ enum ast_http_method method,
++ enum output_format format,
++ struct sockaddr_in *remote_address, const char *uri,
++ struct ast_variable *get_params,
++ struct ast_variable *headers)
+ {
+ struct mansession s = {.session = NULL, };
+ struct mansession_session *session = NULL;
+ uint32_t ident = 0;
+ int blastaway = 0;
+- struct ast_variable *v;
++ struct ast_variable *v, *cookies, *params = get_params;
+ char template[] = "/tmp/ast-http-XXXXXX"; /* template for temporary file */
+- struct ast_str *out = NULL;
++ struct ast_str *http_header = NULL, *out = NULL;
+ struct message m = { 0 };
+ unsigned int x;
+ size_t hdrlen;
+
+- for (v = params; v; v = v->next) {
++ if (method != AST_HTTP_GET && method != AST_HTTP_HEAD && method != AST_HTTP_POST) {
++ ast_http_error(ser, 501, "Not Implemented", "Attempt to use unimplemented / unsupported method");
++ return -1;
++ }
++
++ cookies = ast_http_get_cookies(headers);
++ for (v = cookies; v; v = v->next) {
+ if (!strcasecmp(v->name, "mansession_id")) {
+ sscanf(v->value, "%x", &ident);
+ break;
+ }
+ }
++ if (cookies) {
++ ast_variables_destroy(cookies);
++ }
+
+ if (!(session = find_session(ident, 1))) {
++
++ /**/
+ /* Create new session.
+ * While it is not in the list we don't need any locking
+ */
+- if (!(session = ast_calloc(1, sizeof(*session)))) {
+- *status = 500;
+- goto generic_callback_out;
++ if (!(session = build_mansession(*remote_address))) {
++ ast_http_error(ser, 500, "Server Error", "Internal Server Error (out of memory)\n");
++ return -1;
+ }
++ ao2_lock(session);
+ 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
+@@ -3821,25 +4503,38 @@
+ 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);
+- AST_LIST_INSERT_HEAD(&sessions, session, list);
+- ast_atomic_fetchadd_int(&num_sessions, 1);
+- AST_LIST_UNLOCK(&sessions);
+ }
++ ao2_unlock(session);
+
+- s.session = session;
++ http_header = ast_str_create(128);
++ out = ast_str_create(2048);
+
+- ast_mutex_unlock(&session->__lock);
++ ast_mutex_init(&s.lock);
+
+- if (!(out = ast_str_create(1024))) {
+- *status = 500;
++ if (http_header == NULL || out == NULL) {
++ ast_http_error(ser, 500, "Server Error", "Internal Server Error (ast_str_create() out of memory)\n");
+ goto generic_callback_out;
+ }
+
++ s.session = session;
+ s.fd = mkstemp(template); /* create a temporary file for command output */
+ unlink(template);
++ if (s.fd <= -1) {
++ ast_http_error(ser, 500, "Server Error", "Internal Server Error (mkstemp failed)\n");
++ goto generic_callback_out;
++ }
+ s.f = fdopen(s.fd, "w+");
++ if (!s.f) {
++ ast_log(LOG_WARNING, "HTTP Manager, fdopen failed: %s!\n", strerror(errno));
++ ast_http_error(ser, 500, "Server Error", "Internal Server Error (fdopen failed)\n");
++ close(s.fd);
++ goto generic_callback_out;
++ }
+
++ if (method == AST_HTTP_POST) {
++ params = ast_http_get_post_vars(ser, headers);
++ }
++
+ for (x = 0, v = params; v && (x < AST_MAX_MANHEADERS); x++, v = v->next) {
+ hdrlen = strlen(v->name) + strlen(v->value) + 3;
+ m.headers[m.hdrcount] = alloca(hdrlen);
+@@ -3853,24 +4548,21 @@
+ 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", 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(session->sin.sin_addr));
+ }
+- ast_log(LOG_EVENT, "HTTP Failed attempt from %s\n", ast_inet_ntoa(session->sin.sin_addr));
+ }
+ 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],
+- session->managerid, httptimeout);
++ ast_str_append(&http_header, 0,
++ "Content-type: text/%s\r\n"
++ "Cache-Control: no-cache;\r\n"
++ "Set-Cookie: mansession_id=\"%08x\"; Version=\"1\"; Max-Age=%d"
++ "Pragma: SuppressEvents\r\n",
++ contenttype[format],
++ session->managerid, httptimeout);
+
+ if (format == FORMAT_XML) {
+ ast_str_append(&out, 0, "<ajax-response>\n");
+@@ -3883,7 +4575,7 @@
+
+ #define ROW_FMT "<tr><td colspan=\"2\" bgcolor=\"#f1f1ff\">%s</td></tr>\r\n"
+ #define TEST_STRING \
+- "<form action=\"manager\">\n\
++ "<form action=\"manager\" method=\"post\">\n\
+ Action: <select name=\"action\">\n\
+ <option value=\"\">-----&gt;</option>\n\
+ <option value=\"login\">login</option>\n\
+@@ -3905,13 +4597,16 @@
+ if (s.f != NULL) { /* have temporary output */
+ char *buf;
+ size_t l = ftell(s.f);
+-
++
+ if (l) {
+- if ((buf = mmap(NULL, l, PROT_READ | PROT_WRITE, MAP_SHARED, s.fd, 0))) {
+- if (format == FORMAT_XML || format == FORMAT_HTML)
++ if (MAP_FAILED == (buf = mmap(NULL, l, PROT_READ | PROT_WRITE, MAP_PRIVATE, s.fd, 0))) {
++ ast_log(LOG_WARNING, "mmap failed. Manager output was not processed\n");
++ } else {
++ if (format == FORMAT_XML || format == FORMAT_HTML) {
+ xml_translate(&out, buf, params, format);
+- else
++ } else {
+ ast_str_append(&out, 0, "%s", buf);
++ }
+ munmap(buf, l);
+ }
+ } else if (format == FORMAT_XML || format == FORMAT_HTML) {
+@@ -3924,10 +4619,11 @@
+
+ if (format == FORMAT_XML) {
+ ast_str_append(&out, 0, "</ajax-response>\n");
+- } else if (format == FORMAT_HTML)
++ } else if (format == FORMAT_HTML) {
+ ast_str_append(&out, 0, "</table></body>\r\n");
++ }
+
+- ast_mutex_lock(&session->__lock);
++ ao2_lock(session);
+ /* Reset HTTP timeout. If we're not authenticated, keep it extremely short */
+ session->sessiontimeout = time(NULL) + ((session->authenticated || httptimeout < 5) ? httptimeout : 5);
+
+@@ -3937,64 +4633,447 @@
+ blastaway = 1;
+ } else {
+ ast_debug(1, "Need destroy, but can't do it yet!\n");
+- if (session->waiting_thread != AST_PTHREADT_NULL)
++ if (session->waiting_thread != AST_PTHREADT_NULL) {
+ pthread_kill(session->waiting_thread, SIGURG);
++ }
+ session->inuse--;
+ }
+- } else
++ } else {
+ session->inuse--;
+- ast_mutex_unlock(&session->__lock);
++ }
++ ao2_unlock(session);
+
+- if (blastaway)
+- destroy_session(session);
++ ast_http_send(ser, method, 200, NULL, http_header, out, 0, 0);
++ http_header = out = NULL;
++
+ generic_callback_out:
+- if (*status != 200)
+- return ast_http_error(500, "Server Error", NULL, "Internal Server Error (out of memory)\n");
+- return out;
++ ast_mutex_destroy(&s.lock);
++
++ /* Clear resource */
++
++ if (method == AST_HTTP_POST && params) {
++ ast_variables_destroy(params);
++ }
++ if (http_header) {
++ ast_free(http_header);
++ }
++ if (out) {
++ ast_free(out);
++ }
++
++ if (session && blastaway) {
++ session_destroy(session);
++ } else if (session && session->f) {
++ fclose(session->f);
++ session->f = NULL;
++ }
++
++ return 0;
+ }
+
+-static struct ast_str *manager_http_callback(struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *params, struct ast_variable *headers, int *status, char **title, int *contentlength)
++static int auth_http_callback(struct ast_tcptls_session_instance *ser,
++ enum ast_http_method method,
++ enum output_format format,
++ struct sockaddr_in *remote_address, const char *uri,
++ struct ast_variable *get_params,
++ struct ast_variable *headers)
+ {
+- return generic_http_callback(FORMAT_HTML, &ser->remote_address, uri, method, params, status, title, contentlength);
++ struct mansession_session *session = NULL;
++ struct mansession s = { NULL, };
++ struct ast_variable *v, *params = get_params;
++ char template[] = "/tmp/ast-http-XXXXXX"; /* template for temporary file */
++ struct ast_str *http_header = NULL, *out = NULL;
++ size_t result_size = 512;
++ struct message m = { 0 };
++ unsigned int x;
++ size_t hdrlen;
++
++ time_t time_now = time(NULL);
++ unsigned long nonce = 0, nc;
++ struct ast_http_digest d = { NULL, };
++ struct ast_manager_user *user = NULL;
++ int stale = 0;
++ char resp_hash[256]="";
++ /* Cache for user data */
++ char u_username[80];
++ int u_readperm;
++ int u_writeperm;
++ int u_writetimeout;
++ int u_displayconnects;
++
++ if (method != AST_HTTP_GET && method != AST_HTTP_HEAD && method != AST_HTTP_POST) {
++ ast_http_error(ser, 501, "Not Implemented", "Attempt to use unimplemented / unsupported method");
++ return -1;
++ }
++
++ /* Find "Authorization: " header */
++ for (v = headers; v; v = v->next) {
++ if (!strcasecmp(v->name, "Authorization")) {
++ break;
++ }
++ }
++
++ if (!v || ast_strlen_zero(v->value)) {
++ goto out_401; /* Authorization Header not present - send auth request */
++ }
++
++ /* Digest found - parse */
++ if (ast_string_field_init(&d, 128)) {
++ ast_http_error(ser, 500, "Server Error", "Internal Server Error (out of memory)\n");
++ return -1;
++ }
++
++ if (ast_parse_digest(v->value, &d, 0, 1)) {
++ /* Error in Digest - send new one */
++ nonce = 0;
++ goto out_401;
++ }
++ if (sscanf(d.nonce, "%lx", &nonce) != 1) {
++ ast_log(LOG_WARNING, "Received incorrect nonce in Digest <%s>\n", d.nonce);
++ nonce = 0;
++ goto out_401;
++ }
++
++ AST_RWLIST_WRLOCK(&users);
++ user = get_manager_by_name_locked(d.username);
++ if(!user) {
++ AST_RWLIST_UNLOCK(&users);
++ ast_log(LOG_NOTICE, "%s tried to authenticate with nonexistent user '%s'\n", ast_inet_ntoa(remote_address->sin_addr), d.username);
++ nonce = 0;
++ goto out_401;
++ }
++
++ /* --- We have User for this auth, now check ACL */
++ if (user->ha && !ast_apply_ha(user->ha, remote_address)) {
++ AST_RWLIST_UNLOCK(&users);
++ ast_log(LOG_NOTICE, "%s failed to pass IP ACL as '%s'\n", ast_inet_ntoa(remote_address->sin_addr), d.username);
++ ast_http_error(ser, 403, "Permission denied", "Permission denied\n");
++ return -1;
++ }
++
++ /* --- We have auth, so check it */
++
++ /* compute the expected response to compare with what we received */
++ {
++ char a2[256];
++ char a2_hash[256];
++ char resp[256];
++
++ /* XXX Now request method are hardcoded in A2 */
++ snprintf(a2, sizeof(a2), "%s:%s", ast_get_http_method(method), d.uri);
++ ast_md5_hash(a2_hash, a2);
++
++ if (d.qop) {
++ /* RFC 2617 */
++ snprintf(resp, sizeof(resp), "%s:%08lx:%s:%s:auth:%s", user->a1_hash, nonce, d.nc, d.cnonce, a2_hash);
++ } else {
++ /* RFC 2069 */
++ snprintf(resp, sizeof(resp), "%s:%08lx:%s", user->a1_hash, nonce, a2_hash);
++ }
++ ast_md5_hash(resp_hash, resp);
++ }
++
++ if (!d.nonce || strncasecmp(d.response, resp_hash, strlen(resp_hash))) {
++ /* Something was wrong, so give the client to try with a new challenge */
++ AST_RWLIST_UNLOCK(&users);
++ nonce = 0;
++ goto out_401;
++ }
++
++ /*
++ * User are pass Digest authentication.
++ * Now, cache the user data and unlock user list.
++ */
++ ast_copy_string(u_username, user->username, sizeof(u_username));
++ u_readperm = user->readperm;
++ u_writeperm = user->writeperm;
++ u_displayconnects = user->displayconnects;
++ u_writetimeout = user->writetimeout;
++ AST_RWLIST_UNLOCK(&users);
++
++ if (!(session = find_session_by_nonce(d.username, nonce, &stale))) {
++ /*
++ * Create new session.
++ * While it is not in the list we don't need any locking
++ */
++ if (!(session = build_mansession(*remote_address))) {
++ ast_http_error(ser, 500, "Server Error", "Internal Server Error (out of memory)\n");
++ return -1;
++ }
++ ao2_lock(session);
++
++ ast_copy_string(session->username, u_username, sizeof(session->username));
++ session->managerid = nonce;
++ session->last_ev = grab_last();
++ AST_LIST_HEAD_INIT_NOLOCK(&session->datastores);
++
++ session->readperm = u_readperm;
++ session->writeperm = u_writeperm;
++ session->writetimeout = u_writetimeout;
++
++ if (u_displayconnects) {
++ ast_verb(2, "HTTP Manager '%s' logged in from %s\n", session->username, ast_inet_ntoa(session->sin.sin_addr));
++ }
++ session->noncetime = session->sessionstart = time_now;
++ session->authenticated = 1;
++ } else if (stale) {
++ /*
++ * Session found, but nonce is stale.
++ *
++ * This could be because an old request (w/old nonce) arrived.
++ *
++ * This may be as the result of http proxy usage (separate delay or
++ * multipath) or in a situation where a page was refreshed too quickly
++ * (seen in Firefox).
++ *
++ * In this situation, we repeat the 401 auth with the current nonce
++ * value.
++ */
++ nonce = session->managerid;
++ ao2_unlock(session);
++ stale = 1;
++ goto out_401;
++ } else {
++ sscanf(d.nc, "%lx", &nc);
++ if (session->nc >= nc || ((time_now - session->noncetime) > 62) ) {
++ /*
++ * Nonce time expired (> 2 minutes) or something wrong with nonce
++ * counter.
++ *
++ * Create new nonce key and resend Digest auth request. Old nonce
++ * is saved for stale checking...
++ */
++ session->nc = 0; /* Reset nonce counter */
++ session->oldnonce = session->managerid;
++ nonce = session->managerid = ast_random();
++ session->noncetime = time_now;
++ ao2_unlock(session);
++ stale = 1;
++ goto out_401;
++ } else {
++ session->nc = nc; /* All OK, save nonce counter */
++ }
++ }
++
++
++ /* Reset session timeout. */
++ session->sessiontimeout = time(NULL) + (httptimeout > 5 ? httptimeout : 5);
++ ao2_unlock(session);
++
++ ast_mutex_init(&s.lock);
++ s.session = session;
++ s.fd = mkstemp(template); /* create a temporary file for command output */
++ unlink(template);
++ if (s.fd <= -1) {
++ ast_http_error(ser, 500, "Server Error", "Internal Server Error (mkstemp failed)\n");
++ goto auth_callback_out;
++ }
++ s.f = fdopen(s.fd, "w+");
++ if (!s.f) {
++ ast_log(LOG_WARNING, "HTTP Manager, fdopen failed: %s!\n", strerror(errno));
++ ast_http_error(ser, 500, "Server Error", "Internal Server Error (fdopen failed)\n");
++ close(s.fd);
++ goto auth_callback_out;
++ }
++
++ if (method == AST_HTTP_POST) {
++ params = ast_http_get_post_vars(ser, headers);
++ }
++
++ for (x = 0, v = params; v && (x < AST_MAX_MANHEADERS); x++, v = v->next) {
++ hdrlen = strlen(v->name) + strlen(v->value) + 3;
++ m.headers[m.hdrcount] = alloca(hdrlen);
++ snprintf((char *) m.headers[m.hdrcount], hdrlen, "%s: %s", v->name, v->value);
++ ast_verb(4, "HTTP Manager add header %s\n", m.headers[m.hdrcount]);
++ m.hdrcount = x + 1;
++ }
++
++ if (process_message(&s, &m)) {
++ if (u_displayconnects) {
++ ast_verb(2, "HTTP Manager '%s' logged off from %s\n", session->username, ast_inet_ntoa(session->sin.sin_addr));
++ }
++
++ session->needdestroy = 1;
++ }
++
++ if (s.f) {
++ result_size = ftell(s.f); /* Calculate approx. size of result */
++ }
++
++ http_header = ast_str_create(80);
++ out = ast_str_create(result_size * 2 + 512);
++
++ if (http_header == NULL || out == NULL) {
++ ast_http_error(ser, 500, "Server Error", "Internal Server Error (ast_str_create() out of memory)\n");
++ goto auth_callback_out;
++ }
++
++ ast_str_append(&http_header, 0, "Content-type: text/%s", contenttype[format]);
++
++ if (format == FORMAT_XML) {
++ ast_str_append(&out, 0, "<ajax-response>\n");
++ } else if (format == FORMAT_HTML) {
++ ast_str_append(&out, 0,
++ "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\r\n"
++ "<html><head>\r\n"
++ "<title>Asterisk&trade; Manager Interface</title>\r\n"
++ "</head><body style=\"background-color: #ffffff;\">\r\n"
++ "<form method=\"POST\">\r\n"
++ "<table align=\"center\" style=\"background-color: #f1f1f1;\" width=\"500\">\r\n"
++ "<tr><th colspan=\"2\" style=\"background-color: #f1f1ff;\"><h1>Manager Tester</h1></th></tr>\r\n"
++ "<tr><th colspan=\"2\" style=\"background-color: #f1f1ff;\">Action: <input name=\"action\" /> Cmd: <input name=\"command\" /><br>"
++ "<input type=\"submit\" value=\"Send request\" /></th></tr>\r\n");
++ }
++
++ if (s.f != NULL) { /* have temporary output */
++ char *buf;
++ size_t l = ftell(s.f);
++
++ if (l) {
++ 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 {
++ ast_str_append(&out, 0, "%s", buf);
++ }
++ munmap(buf, l);
++ }
++ } else if (format == FORMAT_XML || format == FORMAT_HTML) {
++ xml_translate(&out, "", params, format);
++ }
++ fclose(s.f);
++ s.f = NULL;
++ s.fd = -1;
++ }
++
++ if (format == FORMAT_XML) {
++ ast_str_append(&out, 0, "</ajax-response>\n");
++ } else if (format == FORMAT_HTML) {
++ ast_str_append(&out, 0, "</table></form></body></html>\r\n");
++ }
++
++ ast_http_send(ser, method, 200, NULL, http_header, out, 0, 0);
++ http_header = out = NULL;
++
++auth_callback_out:
++ ast_mutex_destroy(&s.lock);
++
++ /* Clear resources and unlock manager session */
++ if (method == AST_HTTP_POST && params) {
++ ast_variables_destroy(params);
++ }
++
++ ast_free(http_header);
++ ast_free(out);
++
++ ao2_lock(session);
++ if (session->f) {
++ fclose(session->f);
++ }
++ session->f = NULL;
++ session->fd = -1;
++ ao2_unlock(session);
++
++ if (session->needdestroy) {
++ ast_debug(1, "Need destroy, doing it now!\n");
++ session_destroy(session);
++ }
++ ast_string_field_free_memory(&d);
++ return 0;
++
++out_401:
++ if (!nonce) {
++ nonce = ast_random();
++ }
++
++ ast_http_auth(ser, global_realm, nonce, nonce, stale, NULL);
++ ast_string_field_free_memory(&d);
++ return 0;
+ }
+
+-static struct ast_str *mxml_http_callback(struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *params, struct ast_variable *headers, int *status, char **title, int *contentlength)
++static int manager_http_callback(struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_params, struct ast_variable *headers)
+ {
+- return generic_http_callback(FORMAT_XML, &ser->remote_address, uri, method, params, status, title, contentlength);
++ return generic_http_callback(ser, method, FORMAT_HTML, &ser->remote_address, uri, get_params, headers);
+ }
+
+-static struct ast_str *rawman_http_callback(struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *params, struct ast_variable *headers, int *status, char **title, int *contentlength)
++static int mxml_http_callback(struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_params, struct ast_variable *headers)
+ {
+- return generic_http_callback(FORMAT_RAW, &ser->remote_address, uri, method, params, status, title, contentlength);
++ return generic_http_callback(ser, method, FORMAT_XML, &ser->remote_address, uri, get_params, headers);
+ }
+
+-struct ast_http_uri rawmanuri = {
++static int rawman_http_callback(struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_params, struct ast_variable *headers)
++{
++ return generic_http_callback(ser, method, FORMAT_RAW, &ser->remote_address, uri, get_params, headers);
++}
++
++static struct ast_http_uri rawmanuri = {
+ .description = "Raw HTTP Manager Event Interface",
+ .uri = "rawman",
+ .callback = rawman_http_callback,
+- .supports_get = 1,
+ .data = NULL,
+ .key = __FILE__,
+ };
+
+-struct ast_http_uri manageruri = {
++static struct ast_http_uri manageruri = {
+ .description = "HTML Manager Event Interface",
+ .uri = "manager",
+ .callback = manager_http_callback,
+- .supports_get = 1,
+ .data = NULL,
+ .key = __FILE__,
+ };
+
+-struct ast_http_uri managerxmluri = {
++static struct ast_http_uri managerxmluri = {
+ .description = "XML Manager Event Interface",
+ .uri = "mxml",
+ .callback = mxml_http_callback,
+- .supports_get = 1,
+ .data = NULL,
+ .key = __FILE__,
+ };
+
++
++/* Callback with Digest authentication */
++static int auth_manager_http_callback(struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_params, struct ast_variable *headers)
++{
++ return auth_http_callback(ser, method, FORMAT_HTML, &ser->remote_address, uri, get_params, headers);
++}
++
++static int auth_mxml_http_callback(struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_params, struct ast_variable *headers)
++{
++ return auth_http_callback(ser, method, FORMAT_XML, &ser->remote_address, uri, get_params, headers);
++}
++
++static int auth_rawman_http_callback(struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_params, struct ast_variable *headers)
++{
++ return auth_http_callback(ser, method, FORMAT_RAW, &ser->remote_address, uri, get_params, headers);
++}
++
++static struct ast_http_uri arawmanuri = {
++ .description = "Raw HTTP Manager Event Interface w/Digest authentication",
++ .uri = "arawman",
++ .has_subtree = 0,
++ .callback = auth_rawman_http_callback,
++ .data = NULL,
++ .key = __FILE__,
++};
++
++static struct ast_http_uri amanageruri = {
++ .description = "HTML Manager Event Interface w/Digest authentication",
++ .uri = "amanager",
++ .has_subtree = 0,
++ .callback = auth_manager_http_callback,
++ .data = NULL,
++ .key = __FILE__,
++};
++
++static struct ast_http_uri amanagerxmluri = {
++ .description = "XML Manager Event Interface w/Digest authentication",
++ .uri = "amxml",
++ .has_subtree = 0,
++ .callback = auth_mxml_http_callback,
++ .data = NULL,
++ .key = __FILE__,
++};
++
+ static int registered = 0;
+ static int webregged = 0;
+
+@@ -4007,11 +5086,11 @@
+ purge_events();
+ }
+
+-struct ast_tls_config ami_tls_cfg;
++static struct ast_tls_config ami_tls_cfg;
+ static struct ast_tcptls_session_args ami_desc = {
+ .accept_fd = -1,
+ .master = AST_PTHREADT_NULL,
+- .tls_cfg = NULL,
++ .tls_cfg = NULL,
+ .poll_timeout = 5000, /* wake up every 5 seconds */
+ .periodic_fn = purge_old_stuff,
+ .name = "AMI server",
+@@ -4022,7 +5101,7 @@
+ static struct ast_tcptls_session_args amis_desc = {
+ .accept_fd = -1,
+ .master = AST_PTHREADT_NULL,
+- .tls_cfg = &ami_tls_cfg,
++ .tls_cfg = &ami_tls_cfg,
+ .poll_timeout = -1, /* the other does the periodic cleanup */
+ .name = "AMI TLS server",
+ .accept_fn = ast_tcptls_server_root, /* thread doing the accept() */
+@@ -4035,49 +5114,48 @@
+ const char *val;
+ char *cat = NULL;
+ int newhttptimeout = 60;
+- int have_sslbindaddr = 0;
+- struct hostent *hp;
+- struct ast_hostent ahp;
+ struct ast_manager_user *user = NULL;
+ struct ast_variable *var;
+ struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
++ char a1[256];
++ char a1_hash[256];
+
+ manager_enabled = 0;
+
+ if (!registered) {
+ /* Register default actions */
+- ast_manager_register2("Ping", 0, action_ping, "Keepalive command", mandescr_ping);
+- ast_manager_register2("Events", 0, action_events, "Control Event Flow", mandescr_events);
+- ast_manager_register2("Logoff", 0, action_logoff, "Logoff Manager", mandescr_logoff);
+- ast_manager_register2("Login", 0, action_login, "Login Manager", NULL);
+- ast_manager_register2("Challenge", 0, action_challenge, "Generate Challenge for MD5 Auth", NULL);
+- ast_manager_register2("Hangup", EVENT_FLAG_SYSTEM | EVENT_FLAG_CALL, action_hangup, "Hangup Channel", mandescr_hangup);
+- ast_manager_register2("Status", EVENT_FLAG_SYSTEM | EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, action_status, "Lists channel status", mandescr_status);
+- ast_manager_register2("Setvar", EVENT_FLAG_CALL, action_setvar, "Set Channel Variable", mandescr_setvar);
+- ast_manager_register2("Getvar", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, action_getvar, "Gets a Channel Variable", mandescr_getvar);
+- ast_manager_register2("GetConfig", EVENT_FLAG_SYSTEM | EVENT_FLAG_CONFIG, action_getconfig, "Retrieve configuration", mandescr_getconfig);
+- ast_manager_register2("GetConfigJSON", EVENT_FLAG_SYSTEM | EVENT_FLAG_CONFIG, action_getconfigjson, "Retrieve configuration (JSON format)", mandescr_getconfigjson);
+- ast_manager_register2("UpdateConfig", EVENT_FLAG_CONFIG, action_updateconfig, "Update basic configuration", mandescr_updateconfig);
+- ast_manager_register2("CreateConfig", EVENT_FLAG_CONFIG, action_createconfig, "Creates an empty file in the configuration directory", mandescr_createconfig);
+- ast_manager_register2("ListCategories", EVENT_FLAG_CONFIG, action_listcategories, "List categories in configuration file", mandescr_listcategories);
+- ast_manager_register2("Redirect", EVENT_FLAG_CALL, action_redirect, "Redirect (transfer) a call", mandescr_redirect );
+- ast_manager_register2("Atxfer", EVENT_FLAG_CALL, action_atxfer, "Attended transfer", mandescr_atxfer);
+- ast_manager_register2("Originate", EVENT_FLAG_ORIGINATE, action_originate, "Originate Call", mandescr_originate);
+- ast_manager_register2("Command", EVENT_FLAG_COMMAND, action_command, "Execute Asterisk CLI Command", mandescr_command );
+- ast_manager_register2("ExtensionState", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, action_extensionstate, "Check Extension Status", mandescr_extensionstate );
+- ast_manager_register2("AbsoluteTimeout", EVENT_FLAG_SYSTEM | EVENT_FLAG_CALL, action_timeout, "Set Absolute Timeout", mandescr_timeout );
+- ast_manager_register2("MailboxStatus", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, action_mailboxstatus, "Check Mailbox", mandescr_mailboxstatus );
+- ast_manager_register2("MailboxCount", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, action_mailboxcount, "Check Mailbox Message Count", mandescr_mailboxcount );
+- ast_manager_register2("ListCommands", 0, action_listcommands, "List available manager commands", mandescr_listcommands);
+- ast_manager_register2("SendText", EVENT_FLAG_CALL, action_sendtext, "Send text message to channel", mandescr_sendtext);
+- ast_manager_register2("UserEvent", EVENT_FLAG_USER, action_userevent, "Send an arbitrary event", mandescr_userevent);
+- ast_manager_register2("WaitEvent", 0, action_waitevent, "Wait for an event to occur", mandescr_waitevent);
+- ast_manager_register2("CoreSettings", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, action_coresettings, "Show PBX core settings (version etc)", mandescr_coresettings);
+- ast_manager_register2("CoreStatus", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, action_corestatus, "Show PBX core status variables", mandescr_corestatus);
+- ast_manager_register2("Reload", EVENT_FLAG_CONFIG | EVENT_FLAG_SYSTEM, action_reload, "Send a reload event", mandescr_reload);
+- ast_manager_register2("CoreShowChannels", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, action_coreshowchannels, "List currently active channels", mandescr_coreshowchannels);
+- 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_manager_register_xml("Ping", 0, action_ping);
++ ast_manager_register_xml("Events", 0, action_events);
++ ast_manager_register_xml("Logoff", 0, action_logoff);
++ ast_manager_register_xml("Login", 0, action_login);
++ ast_manager_register_xml("Challenge", 0, action_challenge);
++ ast_manager_register_xml("Hangup", EVENT_FLAG_SYSTEM | EVENT_FLAG_CALL, action_hangup);
++ ast_manager_register_xml("Status", EVENT_FLAG_SYSTEM | EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, action_status);
++ ast_manager_register_xml("Setvar", EVENT_FLAG_CALL, action_setvar);
++ ast_manager_register_xml("Getvar", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, action_getvar);
++ ast_manager_register_xml("GetConfig", EVENT_FLAG_SYSTEM | EVENT_FLAG_CONFIG, action_getconfig);
++ ast_manager_register_xml("GetConfigJSON", EVENT_FLAG_SYSTEM | EVENT_FLAG_CONFIG, action_getconfigjson);
++ ast_manager_register_xml("UpdateConfig", EVENT_FLAG_CONFIG, action_updateconfig);
++ ast_manager_register_xml("CreateConfig", EVENT_FLAG_CONFIG, action_createconfig);
++ ast_manager_register_xml("ListCategories", EVENT_FLAG_CONFIG, action_listcategories);
++ ast_manager_register_xml("Redirect", EVENT_FLAG_CALL, action_redirect);
++ ast_manager_register_xml("Atxfer", EVENT_FLAG_CALL, action_atxfer);
++ ast_manager_register_xml("Originate", EVENT_FLAG_ORIGINATE, action_originate);
++ ast_manager_register_xml("Command", EVENT_FLAG_COMMAND, action_command);
++ ast_manager_register_xml("ExtensionState", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, action_extensionstate);
++ ast_manager_register_xml("AbsoluteTimeout", EVENT_FLAG_SYSTEM | EVENT_FLAG_CALL, action_timeout);
++ ast_manager_register_xml("MailboxStatus", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, action_mailboxstatus);
++ ast_manager_register_xml("MailboxCount", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, action_mailboxcount);
++ ast_manager_register_xml("ListCommands", 0, action_listcommands);
++ ast_manager_register_xml("SendText", EVENT_FLAG_CALL, action_sendtext);
++ ast_manager_register_xml("UserEvent", EVENT_FLAG_USER, action_userevent);
++ ast_manager_register_xml("WaitEvent", 0, action_waitevent);
++ ast_manager_register_xml("CoreSettings", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, action_coresettings);
++ ast_manager_register_xml("CoreStatus", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, action_corestatus);
++ ast_manager_register_xml("Reload", EVENT_FLAG_CONFIG | EVENT_FLAG_SYSTEM, action_reload);
++ ast_manager_register_xml("CoreShowChannels", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, action_coreshowchannels);
++ ast_manager_register_xml("ModuleLoad", EVENT_FLAG_SYSTEM, manager_moduleload);
++ ast_manager_register_xml("ModuleCheck", EVENT_FLAG_SYSTEM, manager_modulecheck);
+
+ ast_cli_register_multiple(cli_manager, ARRAY_LEN(cli_manager));
+ ast_extension_state_add(NULL, NULL, manager_state_cb, NULL);
+@@ -4085,8 +5163,9 @@
+ /* Append placeholder event so master_eventq never runs dry */
+ append_event("Event: Placeholder\r\n\r\n", 0);
+ }
+- if ((cfg = ast_config_load2("manager.conf", "manager", config_flags)) == CONFIG_STATUS_FILEUNCHANGED)
++ if ((cfg = ast_config_load2("manager.conf", "manager", config_flags)) == CONFIG_STATUS_FILEUNCHANGED) {
+ return 0;
++ }
+
+ displayconnects = 1;
+ if (!cfg) {
+@@ -4095,39 +5174,34 @@
+ }
+
+ /* default values */
++ ast_copy_string(global_realm, S_OR(ast_config_AST_SYSTEM_NAME, DEFAULT_REALM), sizeof(global_realm));
+ memset(&ami_desc.local_address, 0, sizeof(struct sockaddr_in));
+ memset(&amis_desc.local_address, 0, sizeof(amis_desc.local_address));
+ amis_desc.local_address.sin_port = htons(5039);
+ ami_desc.local_address.sin_port = htons(DEFAULT_MANAGER_PORT);
+
+ ami_tls_cfg.enabled = 0;
+- if (ami_tls_cfg.certfile)
++ if (ami_tls_cfg.certfile) {
+ ast_free(ami_tls_cfg.certfile);
++ }
+ ami_tls_cfg.certfile = ast_strdup(AST_CERTFILE);
+- if (ami_tls_cfg.cipher)
++ if (ami_tls_cfg.pvtfile) {
++ ast_free(ami_tls_cfg.pvtfile);
++ }
++ ami_tls_cfg.pvtfile = ast_strdup("");
++ if (ami_tls_cfg.cipher) {
+ ast_free(ami_tls_cfg.cipher);
++ }
+ ami_tls_cfg.cipher = ast_strdup("");
+
+ for (var = ast_variable_browse(cfg, "general"); var; var = var->next) {
+ val = var->value;
+- if (!strcasecmp(var->name, "sslenable"))
+- ami_tls_cfg.enabled = ast_true(val);
+- else if (!strcasecmp(var->name, "sslbindport"))
+- amis_desc.local_address.sin_port = htons(atoi(val));
+- else if (!strcasecmp(var->name, "sslbindaddr")) {
+- if ((hp = ast_gethostbyname(val, &ahp))) {
+- memcpy(&amis_desc.local_address.sin_addr, hp->h_addr, sizeof(amis_desc.local_address.sin_addr));
+- have_sslbindaddr = 1;
+- } else {
+- ast_log(LOG_WARNING, "Invalid bind address '%s'\n", val);
+- }
+- } else if (!strcasecmp(var->name, "sslcert")) {
+- ast_free(ami_tls_cfg.certfile);
+- ami_tls_cfg.certfile = ast_strdup(val);
+- } else if (!strcasecmp(var->name, "sslcipher")) {
+- ast_free(ami_tls_cfg.cipher);
+- ami_tls_cfg.cipher = ast_strdup(val);
+- } else if (!strcasecmp(var->name, "enabled")) {
++
++ if (!ast_tls_read_conf(&ami_tls_cfg, &amis_desc, var->name, val)) {
++ continue;
++ }
++
++ if (!strcasecmp(var->name, "enabled")) {
+ manager_enabled = ast_true(val);
+ } else if (!strcasecmp(var->name, "block-sockets")) {
+ block_sockets = ast_true(val);
+@@ -4140,7 +5214,7 @@
+ ast_log(LOG_WARNING, "Invalid address '%s' specified, using 0.0.0.0\n", val);
+ memset(&ami_desc.local_address.sin_addr, 0, sizeof(ami_desc.local_address.sin_addr));
+ }
+- } else if (!strcasecmp(var->name, "allowmultiplelogin")) {
++ } else if (!strcasecmp(var->name, "allowmultiplelogin")) {
+ allowmultiplelogin = ast_true(val);
+ } else if (!strcasecmp(var->name, "displayconnects")) {
+ displayconnects = ast_true(val);
+@@ -4153,17 +5227,20 @@
+ } else {
+ ast_log(LOG_NOTICE, "Invalid keyword <%s> = <%s> in manager.conf [general]\n",
+ var->name, val);
+- }
++ }
+ }
+
+- if (manager_enabled)
++ if (manager_enabled) {
+ ami_desc.local_address.sin_family = AF_INET;
+- if (!have_sslbindaddr)
++ }
++ /* if the amis address has not been set, default is the same as non secure ami */
++ if (!amis_desc.local_address.sin_addr.s_addr) {
+ amis_desc.local_address.sin_addr = ami_desc.local_address.sin_addr;
+- if (ami_tls_cfg.enabled)
++ }
++ if (ami_tls_cfg.enabled) {
+ amis_desc.local_address.sin_family = AF_INET;
++ }
+
+-
+ AST_RWLIST_WRLOCK(&users);
+
+ /* First, get users from users.conf */
+@@ -4173,9 +5250,10 @@
+ int genhasmanager = ast_true(ast_variable_retrieve(ucfg, "general", "hasmanager"));
+
+ while ((cat = ast_category_browse(ucfg, cat))) {
+- if (!strcasecmp(cat, "general"))
++ if (!strcasecmp(cat, "general")) {
+ continue;
+-
++ }
++
+ hasmanager = ast_variable_retrieve(ucfg, cat, "hasmanager");
+ if ((!hasmanager && genhasmanager) || ast_true(hasmanager)) {
+ const char *user_secret = ast_variable_retrieve(ucfg, cat, "secret");
+@@ -4183,13 +5261,14 @@
+ const char *user_write = ast_variable_retrieve(ucfg, cat, "write");
+ const char *user_displayconnects = ast_variable_retrieve(ucfg, cat, "displayconnects");
+ const char *user_writetimeout = ast_variable_retrieve(ucfg, cat, "writetimeout");
+-
++
+ /* Look for an existing entry,
+ * if none found - create one and add it to the list
+ */
+ if (!(user = get_manager_by_name_locked(cat))) {
+- if (!(user = ast_calloc(1, sizeof(*user))))
++ if (!(user = ast_calloc(1, sizeof(*user)))) {
+ break;
++ }
+
+ /* Copy name over */
+ ast_copy_string(user->username, cat, sizeof(user->username));
+@@ -4204,36 +5283,45 @@
+ user->writetimeout = 100;
+ }
+
+- if (!user_secret)
++ if (!user_secret) {
+ user_secret = ast_variable_retrieve(ucfg, "general", "secret");
+- if (!user_read)
++ }
++ if (!user_read) {
+ user_read = ast_variable_retrieve(ucfg, "general", "read");
+- if (!user_write)
++ }
++ if (!user_write) {
+ user_write = ast_variable_retrieve(ucfg, "general", "write");
+- if (!user_displayconnects)
++ }
++ if (!user_displayconnects) {
+ user_displayconnects = ast_variable_retrieve(ucfg, "general", "displayconnects");
+- if (!user_writetimeout)
++ }
++ if (!user_writetimeout) {
+ user_writetimeout = ast_variable_retrieve(ucfg, "general", "writetimeout");
++ }
+
+ if (!ast_strlen_zero(user_secret)) {
+- if (user->secret)
++ if (user->secret) {
+ ast_free(user->secret);
++ }
+ user->secret = ast_strdup(user_secret);
+ }
+
+- if (user_read)
++ if (user_read) {
+ user->readperm = get_perm(user_read);
+- if (user_write)
++ }
++ if (user_write) {
+ user->writeperm = get_perm(user_write);
+- if (user_displayconnects)
++ }
++ if (user_displayconnects) {
+ user->displayconnects = ast_true(user_displayconnects);
+-
++ }
+ if (user_writetimeout) {
+ int value = atoi(user_writetimeout);
+- if (value < 100)
++ if (value < 100) {
+ ast_log(LOG_WARNING, "Invalid writetimeout value '%s' at users.conf line %d\n", var->value, var->lineno);
+- else
++ } else {
+ user->writetimeout = value;
++ }
+ }
+ }
+ }
+@@ -4245,13 +5333,15 @@
+ while ((cat = ast_category_browse(cfg, cat))) {
+ struct ast_ha *oldha;
+
+- if (!strcasecmp(cat, "general"))
++ if (!strcasecmp(cat, "general")) {
+ continue;
++ }
+
+ /* Look for an existing entry, if none found - create one and add it to the list */
+ if (!(user = get_manager_by_name_locked(cat))) {
+- if (!(user = ast_calloc(1, sizeof(*user))))
++ if (!(user = ast_calloc(1, sizeof(*user)))) {
+ break;
++ }
+ /* Copy name over */
+ ast_copy_string(user->username, cat, sizeof(user->username));
+
+@@ -4274,8 +5364,9 @@
+ var = ast_variable_browse(cfg, cat);
+ for (; var; var = var->next) {
+ if (!strcasecmp(var->name, "secret")) {
+- if (user->secret)
++ if (user->secret) {
+ ast_free(user->secret);
++ }
+ user->secret = ast_strdup(var->value);
+ } else if (!strcasecmp(var->name, "deny") ||
+ !strcasecmp(var->name, "permit")) {
+@@ -4288,12 +5379,14 @@
+ user->displayconnects = ast_true(var->value);
+ } else if (!strcasecmp(var->name, "writetimeout")) {
+ int value = atoi(var->value);
+- if (value < 100)
++ if (value < 100) {
+ ast_log(LOG_WARNING, "Invalid writetimeout value '%s' at line %d\n", var->value, var->lineno);
+- else
++ } else {
+ user->writetimeout = value;
+- } else
++ }
++ } else {
+ ast_debug(1, "%s is an unknown option.\n", var->name);
++ }
+ }
+ ast_free_ha(oldha);
+ }
+@@ -4303,13 +5396,25 @@
+ AST_RWLIST_TRAVERSE_SAFE_BEGIN(&users, user, list) {
+ if (user->keep) { /* valid record. clear flag for the next round */
+ user->keep = 0;
++
++ /* Calculate A1 for Digest auth */
++ snprintf(a1, sizeof(a1), "%s:%s:%s", user->username, global_realm, user->secret);
++ ast_md5_hash(a1_hash,a1);
++ if (user->a1_hash) {
++ ast_free(user->a1_hash);
++ }
++ user->a1_hash = ast_strdup(a1_hash);
+ continue;
+ }
+ /* We do not need to keep this user so take them out of the list */
+ AST_RWLIST_REMOVE_CURRENT(list);
+ /* Free their memory now */
+- if (user->secret)
++ if (user->a1_hash) {
++ ast_free(user->a1_hash);
++ }
++ if (user->secret) {
+ ast_free(user->secret);
++ }
+ ast_free_ha(user->ha);
+ ast_free(user);
+ }
+@@ -4317,11 +5422,21 @@
+
+ AST_RWLIST_UNLOCK(&users);
+
++ if (!reload) {
++ /* If you have a NULL hash fn, you only need a single bucket */
++ sessions = ao2_container_alloc(1, NULL, mansession_cmp_fn);
++ }
++
+ if (webmanager_enabled && manager_enabled) {
+ if (!webregged) {
++
+ ast_http_uri_link(&rawmanuri);
+ ast_http_uri_link(&manageruri);
+ ast_http_uri_link(&managerxmluri);
++
++ ast_http_uri_link(&arawmanuri);
++ ast_http_uri_link(&amanageruri);
++ ast_http_uri_link(&amanagerxmluri);
+ webregged = 1;
+ }
+ } else {
+@@ -4329,18 +5444,24 @@
+ ast_http_uri_unlink(&rawmanuri);
+ ast_http_uri_unlink(&manageruri);
+ ast_http_uri_unlink(&managerxmluri);
++
++ ast_http_uri_unlink(&arawmanuri);
++ ast_http_uri_unlink(&amanageruri);
++ ast_http_uri_unlink(&amanagerxmluri);
+ webregged = 0;
+ }
+ }
+
+- if (newhttptimeout > 0)
++ if (newhttptimeout > 0) {
+ httptimeout = newhttptimeout;
++ }
+
+ manager_event(EVENT_FLAG_SYSTEM, "Reload", "Module: Manager\r\nStatus: %s\r\nMessage: Manager reload Requested\r\n", manager_enabled ? "Enabled" : "Disabled");
+
+ ast_tcptls_server_start(&ami_desc);
+- if (ast_ssl_setup(amis_desc.tls_cfg))
++ if (ast_ssl_setup(amis_desc.tls_cfg)) {
+ ast_tcptls_server_start(&amis_desc);
++ }
+ return 0;
+ }
+
+@@ -4369,7 +5490,7 @@
+ struct ast_datastore *astman_datastore_find(struct mansession *s, const struct ast_datastore_info *info, const char *uid)
+ {
+ struct ast_datastore *datastore = NULL;
+-
++
+ if (info == NULL)
+ return NULL;
+
+Index: main/ast_expr2f.c
+===================================================================
+--- a/main/ast_expr2f.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/main/ast_expr2f.c (.../trunk) (revision 202568)
+@@ -2379,7 +2379,7 @@
+
+ void ast_yyfree(void *ptr, yyscan_t yyscanner)
+ {
+- if (ptr) /* the normal generated ast_yyfree func just frees its first arg;
++ /* the normal generated ast_yyfree func just frees its first arg;
+ this get complaints on some systems, as sometimes this
+ arg is a nil ptr! It's usually not fatal, but is irritating! */
+ free( (char *) ptr );
+@@ -2416,15 +2416,40 @@
+ else
+ buf[0] = 0;
+ return_value = strlen(buf);
+- if (io.val->u.s)
+- free(io.val->u.s);
++ free(io.val->u.s);
+ }
+ free(io.val);
+ }
+ return return_value;
+ }
+
++#if !defined(STANDALONE)
++int ast_str_expr(struct ast_str **str, ssize_t maxlen, struct ast_channel *chan, char *expr)
++{
++ struct parse_io io = { .string = expr, .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) {
++ ast_str_set(str, maxlen, "0");
++ } else {
++ if (io.val->type == AST_EXPR_number) {
++ int res_length;
++ ast_str_set(str, maxlen, FP___PRINTF, io.val->u.i);
++ } else if (io.val->u.s) {
++ ast_str_set(str, maxlen, "%s", io.val->u.s);
++ free(io.val->u.s);
++ }
++ free(io.val);
++ }
++ return ast_str_strlen(*str);
++}
++#endif
++
++
+ char extra_error_message[4095];
+ int extra_error_message_supplied = 0;
+ void ast_expr_register_extra_error_info(char *message);
+Index: main/features.c
+===================================================================
+--- a/main/features.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/main/features.c (.../trunk) (revision 202568)
+@@ -154,6 +154,61 @@
+ <ref type="application">ParkedCall</ref>
+ </see-also>
+ </application>
++ <manager name="ParkedCalls" language="en_US">
++ <synopsis>
++ List parked calls.
++ </synopsis>
++ <syntax>
++ <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
++ </syntax>
++ <description>
++ <para>List parked calls.</para>
++ </description>
++ </manager>
++ <manager name="Park" language="en_US">
++ <synopsis>
++ Park a channel.
++ </synopsis>
++ <syntax>
++ <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
++ <parameter name="Channel" required="true">
++ <para>Channel name to park.</para>
++ </parameter>
++ <parameter name="Channel2" required="true">
++ <para>Channel to announce park info to (and return to if timeout).</para>
++ </parameter>
++ <parameter name="Timeout">
++ <para>Number of milliseconds to wait before callback.</para>
++ </parameter>
++ </syntax>
++ <description>
++ <para>Park a channel.</para>
++ </description>
++ </manager>
++ <manager name="Bridge" language="en_US">
++ <synopsis>
++ Bridge two channels already in the PBX.
++ </synopsis>
++ <syntax>
++ <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
++ <parameter name="Channel1" required="true">
++ <para>Channel to Bridge to Channel2.</para>
++ </parameter>
++ <parameter name="Channel2" required="true">
++ <para>Channel to Bridge to Channel1.</para>
++ </parameter>
++ <parameter name="Tone">
++ <para>Play courtesy tone to Channel 2.</para>
++ <enumlist>
++ <enum name="yes" />
++ <enum name="no" />
++ </enumlist>
++ </parameter>
++ </syntax>
++ <description>
++ <para>Bridge together two channels already in the PBX.</para>
++ </description>
++ </manager>
+ ***/
+
+ #define DEFAULT_PARK_TIME 45000
+@@ -284,17 +339,17 @@
+ memcpy(df_copy, df, sizeof(*df));
+
+ return df_copy;
+- }
+-
+- static void dial_features_destroy(void *data)
+- {
++}
++
++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 = {
++}
++
++static const struct ast_datastore_info dial_features_info = {
+ .type = "dial-features",
+ .destroy = dial_features_destroy,
+ .duplicate = dial_features_duplicate,
+@@ -720,11 +775,13 @@
+ if ((c = strrchr(other_side, ';'))) {
+ *++c = '1';
+ }
+- if ((tmpchan = ast_get_channel_by_name_locked(other_side))) {
++ if ((tmpchan = ast_channel_get_by_name(other_side))) {
++ ast_channel_lock(tmpchan);
+ if ((base_peer = ast_bridged_channel(tmpchan))) {
+ ast_copy_string(pu->peername, base_peer->name, sizeof(pu->peername));
+ }
+ ast_channel_unlock(tmpchan);
++ tmpchan = ast_channel_unref(tmpchan);
+ }
+ } else {
+ ast_copy_string(pu->peername, S_OR(args->orig_chan_name, peer->name), sizeof(pu->peername));
+@@ -889,9 +946,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
+@@ -922,7 +976,7 @@
+ * Setup channel, set return exten,priority to 's,1'
+ * answer chan, sleep chan, park call
+ */
+-static int builtin_parkcall(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
++static int builtin_parkcall(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, const char *code, int sense, void *data)
+ {
+ struct ast_channel *parker;
+ struct ast_channel *parkee;
+@@ -992,7 +1046,7 @@
+ * \retval AST_FEATURE_RETURN_SUCCESS on success.
+ * \retval -1 on error.
+ */
+-static int builtin_automonitor(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
++static int builtin_automonitor(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, const char *code, int sense, void *data)
+ {
+ char *caller_chan_id = NULL, *callee_chan_id = NULL, *args = NULL, *touch_filename = NULL;
+ int x = 0;
+@@ -1085,7 +1139,7 @@
+ return -1;
+ }
+
+-static int builtin_automixmonitor(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
++static int builtin_automixmonitor(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, const char *code, int sense, void *data)
+ {
+ char *caller_chan_id = NULL, *callee_chan_id = NULL, *args = NULL, *touch_filename = NULL;
+ int x = 0;
+@@ -1195,7 +1249,7 @@
+
+ }
+
+-static int builtin_disconnect(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
++static int builtin_disconnect(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, const char *code, int sense, void *data)
+ {
+ ast_verb(4, "User hit '%s' to disconnect call.\n", code);
+ return AST_FEATURE_RETURN_HANGUP;
+@@ -1245,7 +1299,7 @@
+ * \retval AST_FEATURE_RETURN_SUCCESS.
+ * \retval -1 on failure.
+ */
+-static int builtin_blindtransfer(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
++static int builtin_blindtransfer(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, const char *code, int sense, void *data)
+ {
+ struct ast_channel *transferer;
+ struct ast_channel *transferee;
+@@ -1323,6 +1377,9 @@
+ /* Set the channel's new extension, since it exists, using transferer context */
+ ast_set_flag(transferee, AST_FLAG_BRIDGE_HANGUP_DONT); /* don't let the after-bridge code run the h-exten */
+ ast_log(LOG_DEBUG,"ABOUT TO AST_ASYNC_GOTO, have a pbx... set HANGUP_DONT on chan=%s\n", transferee->name);
++ if (ast_channel_connected_line_macro(transferee, transferer, &transferer->connected, 1, 0)) {
++ ast_channel_update_connected_line(transferee, &transferer->connected);
++ }
+ set_c_e_p(transferee, transferer_real_context, xferto, 0);
+ }
+ check_goto_on_transfer(transferer);
+@@ -1376,7 +1433,7 @@
+ *
+ * \return -1 on failure
+ */
+-static int builtin_atxfer(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
++static int builtin_atxfer(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, const char *code, int sense, void *data)
+ {
+ struct ast_channel *transferer;
+ struct ast_channel *transferee;
+@@ -1390,6 +1447,7 @@
+ struct ast_bridge_config bconfig;
+ struct ast_frame *f;
+ int l;
++ struct ast_party_connected_line connected_line;
+ struct ast_datastore *features_datastore;
+ struct ast_dial_features *dialfeatures = NULL;
+
+@@ -1459,6 +1517,7 @@
+ newchan = feature_request_and_dial(transferer, transferee, "Local", ast_best_codec(transferer->nativeformats),
+ xferto, atxfernoanswertimeout, &outstate, transferer->cid.cid_num, transferer->cid.cid_name, 1, transferer->language);
+
++ ast_party_connected_line_init(&connected_line);
+ if (!ast_check_hangup(transferer)) {
+ /* Transferer is up - old behaviour */
+ ast_indicate(transferer, -1);
+@@ -1481,6 +1540,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 +1558,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 +1574,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 +1600,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 +1635,48 @@
+ 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.
++ */
++
++ /* xferchan is transferee, and newchan is the transfer target
++ * So...in a transfer, who is the caller and who is the callee?
++ *
++ * When the call is originally made, it is clear who is caller and callee.
++ * When a transfer occurs, it is my humble opinion that the transferee becomes
++ * the caller, and the transfer target is the callee.
++ *
++ * The problem is that these macros were set with the intention of the original
++ * caller and callee taking those roles. A transfer can totally mess things up,
++ * to be technical. What sucks even more is that you can't effectively change
++ * the macros in the dialplan during the call from the transferer to the transfer
++ * target because the transferee is stuck with whatever role he originally had.
++ *
++ * I think the answer here is just to make sure that it is well documented that
++ * during a transfer, the transferee is the "caller" and the transfer target
++ * is the "callee."
++ *
++ * This means that if party A calls party B, and party A transfers party B to
++ * party C, then B has switched roles for the call. Now party B will have the
++ * caller macro called on his channel instead of the callee macro.
++ *
++ * Luckily, the method by which the bridge is launched here ensures that the
++ * transferee is the "chan" on the bridge and the transfer target is the "peer,"
++ * so my idea for the roles post-transfer does not require extensive code changes.
++ */
++ connected_line.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER;
++ if (ast_channel_connected_line_macro(newchan, xferchan, &connected_line, 1, 0)) {
++ 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;
++ if (ast_channel_connected_line_macro(xferchan, newchan, &connected_line, 0, 0)) {
++ 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 +1773,28 @@
+ 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;
++ if (ast_channel_connected_line_macro(newchan, xferchan, &connected_line, 1, 0)) {
++ 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;
++ if (ast_channel_connected_line_macro(xferchan, newchan, &connected_line, 0, 0)) {
++ 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);
+@@ -1677,8 +1811,7 @@
+
+ AST_RWLOCK_DEFINE_STATIC(features_lock);
+
+-static struct ast_call_feature builtin_features[] =
+-{
++static struct ast_call_feature builtin_features[] = {
+ { AST_FEATURE_REDIRECT, "Blind Transfer", "blindxfer", "#", "#", builtin_blindtransfer, AST_FEATURE_FLAG_NEEDSDTMF, "" },
+ { AST_FEATURE_REDIRECT, "Attended Transfer", "atxfer", "", "", builtin_atxfer, AST_FEATURE_FLAG_NEEDSDTMF, "" },
+ { AST_FEATURE_AUTOMON, "One Touch Monitor", "automon", "", "", builtin_automonitor, AST_FEATURE_FLAG_NEEDSDTMF, "" },
+@@ -1883,7 +2016,7 @@
+ * \retval -1 error.
+ * \retval -2 when an application cannot be found.
+ */
+-static int feature_exec_app(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
++static int feature_exec_app(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, const char *code, int sense, void *data)
+ {
+ struct ast_app *app;
+ struct ast_call_feature *feature = data;
+@@ -1969,53 +2102,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, const 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 +2148,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 +2163,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 +2181,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, const 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, const 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 +2267,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 +2333,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;
+@@ -2238,6 +2412,10 @@
+ f = NULL;
+ ready=1;
+ break;
++ } else if (f->subclass == AST_CONTROL_CONNECTED_LINE) {
++ if (ast_channel_connected_line_macro(chan, caller, f, 1, 1)) {
++ 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);
+ }
+@@ -2433,7 +2611,6 @@
+ int hadfeatures=0;
+ int autoloopflag;
+ struct ast_option_header *aoh;
+- struct ast_bridge_config backup_config;
+ struct ast_cdr *bridge_cdr = NULL;
+ struct ast_cdr *orig_peer_cdr = NULL;
+ struct ast_cdr *chan_cdr = pick_unlocked_cdr(chan->cdr); /* the proper chan cdr, if there are forked cdrs */
+@@ -2441,10 +2618,6 @@
+ struct ast_cdr *new_chan_cdr = NULL; /* the proper chan cdr, if there are forked cdrs */
+ struct ast_cdr *new_peer_cdr = NULL; /* the proper chan cdr, if there are forked cdrs */
+
+- memset(&backup_config, 0, sizeof(backup_config));
+-
+- config->start_time = ast_tvnow();
+-
+ if (chan && peer) {
+ pbx_builtin_setvar_helper(chan, "BRIDGEPEER", peer->name);
+ pbx_builtin_setvar_helper(peer, "BRIDGEPEER", chan->name);
+@@ -2465,7 +2638,7 @@
+ if (monitor_ok) {
+ const char *monitor_exec;
+ struct ast_channel *src = NULL;
+- if (!monitor_app) {
++ if (!monitor_app) {
+ if (!(monitor_app = pbx_findapp("Monitor")))
+ monitor_ok=0;
+ }
+@@ -2480,7 +2653,6 @@
+ }
+
+ set_config_flags(chan, peer, config);
+- config->firstpass = 1;
+
+ /* Answer if need be */
+ if (chan->_state != AST_STATE_UP) {
+@@ -2565,8 +2737,8 @@
+ 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);
++ /* Update feature timer for next pass */
++ diff = ast_tvdiff_ms(ast_tvnow(), config->feature_start_time);
+ 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
+@@ -2577,18 +2749,7 @@
+ }
+
+ if (hasfeatures) {
+- /* Running on backup config, meaning a feature might be being
+- activated, but that's no excuse to keep things going
+- indefinitely! */
+- if (backup_config.feature_timer && ((backup_config.feature_timer -= diff) <= 0)) {
+- ast_debug(1, "Timed out, realtime this time!\n");
+- config->feature_timer = 0;
+- who = chan;
+- if (f)
+- ast_frfree(f);
+- f = NULL;
+- res = 0;
+- } else if (config->feature_timer <= 0) {
++ if (config->feature_timer <= 0) {
+ /* Not *really* out of time, just out of time for
+ digits to come in for features. */
+ ast_debug(1, "Timed out for feature!\n");
+@@ -2604,9 +2765,8 @@
+ ast_frfree(f);
+ hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
+ if (!hasfeatures) {
+- /* Restore original (possibly time modified) bridge config */
+- memcpy(config, &backup_config, sizeof(struct ast_bridge_config));
+- memset(&backup_config, 0, sizeof(backup_config));
++ /* No more digits expected - reset the timer */
++ config->feature_timer = 0;
+ }
+ hadfeatures = hasfeatures;
+ /* Continue as we were */
+@@ -2630,13 +2790,14 @@
+ }
+ }
+ if (res < 0) {
+- if (!ast_test_flag(chan, AST_FLAG_ZOMBIE) && !ast_test_flag(peer, AST_FLAG_ZOMBIE) && !ast_check_hangup(chan) && !ast_check_hangup(peer))
++ if (!ast_test_flag(chan, AST_FLAG_ZOMBIE) && !ast_test_flag(peer, AST_FLAG_ZOMBIE) && !ast_check_hangup(chan) && !ast_check_hangup(peer)) {
+ ast_log(LOG_WARNING, "Bridge failed on channels %s and %s\n", chan->name, peer->name);
++ }
+ goto before_you_go;
+ }
+
+ if (!f || (f->frametype == AST_FRAME_CONTROL &&
+- (f->subclass == AST_CONTROL_HANGUP || f->subclass == AST_CONTROL_BUSY ||
++ (f->subclass == AST_CONTROL_HANGUP || f->subclass == AST_CONTROL_BUSY ||
+ f->subclass == AST_CONTROL_CONGESTION))) {
+ res = -1;
+ break;
+@@ -2650,6 +2811,11 @@
+ case -1:
+ ast_indicate(other, f->subclass);
+ break;
++ case AST_CONTROL_CONNECTED_LINE:
++ if (!ast_channel_connected_line_macro(who, other, f, who != chan, 1)) {
++ break;
++ }
++ /* The implied "else" falls through purposely */
+ case AST_CONTROL_HOLD:
+ case AST_CONTROL_UNHOLD:
+ ast_indicate_data(other, f->subclass, f->data.ptr, f->datalen);
+@@ -2686,7 +2852,7 @@
+ /* Get rid of the frame before we start doing "stuff" with the channels */
+ ast_frfree(f);
+ f = NULL;
+- config->feature_timer = backup_config.feature_timer;
++ config->feature_timer = 0;
+ res = feature_interpret(chan, peer, config, featurecode, sense);
+ switch(res) {
+ case AST_FEATURE_RETURN_PASSDIGITS:
+@@ -2698,30 +2864,21 @@
+ }
+ if (res >= AST_FEATURE_RETURN_PASSDIGITS) {
+ res = 0;
+- } else
++ } else {
+ break;
++ }
+ hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
+ if (hadfeatures && !hasfeatures) {
+- /* Restore backup */
+- memcpy(config, &backup_config, sizeof(struct ast_bridge_config));
+- memset(&backup_config, 0, sizeof(struct ast_bridge_config));
++ /* Feature completed or timed out */
++ config->feature_timer = 0;
+ } else if (hasfeatures) {
+- if (!hadfeatures) {
+- /* Backup configuration */
+- memcpy(&backup_config, config, sizeof(struct ast_bridge_config));
+- /* Setup temporary config options */
+- config->play_warning = 0;
+- ast_clear_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING);
+- ast_clear_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING);
+- config->warning_freq = 0;
+- config->warning_sound = NULL;
+- config->end_sound = NULL;
+- config->start_sound = NULL;
+- config->firstpass = 0;
++ if (config->timelimit) {
++ /* No warning next time - we are waiting for future */
++ ast_set_flag(config, AST_FEATURE_WARNING_ACTIVE);
+ }
+- config->start_time = ast_tvnow();
++ config->feature_start_time = ast_tvnow();
+ config->feature_timer = featuredigittimeout;
+- ast_debug(1, "Set time limit to %ld\n", config->feature_timer);
++ ast_debug(1, "Set feature timer to %ld\n", config->feature_timer);
+ }
+ }
+ if (f)
+@@ -2795,7 +2952,9 @@
+ bridge_cdr = NULL;
+ }
+ }
+- ast_set_flag(chan, AST_FLAG_BRIDGE_HANGUP_RUN);
++ if (chan->priority != 1 || !spawn_error) {
++ ast_set_flag(chan, AST_FLAG_BRIDGE_HANGUP_RUN);
++ }
+ ast_channel_unlock(chan);
+ /* protect the lastapp/lastdata against the effects of the hangup/dialplan code */
+ if (bridge_cdr) {
+@@ -2839,33 +2998,35 @@
+ to attend to; if the chan or peer changed names,
+ we have the before and after attached CDR's.
+ */
+-
++
+ if (new_chan_cdr) {
+ struct ast_channel *chan_ptr = NULL;
+-
+- if (strcasecmp(orig_channame, chan->name) != 0) {
+- /* old channel */
+- chan_ptr = ast_get_channel_by_name_locked(orig_channame);
+- if (chan_ptr) {
+- if (!ast_bridged_channel(chan_ptr)) {
+- struct ast_cdr *cur;
+- for (cur = chan_ptr->cdr; cur; cur = cur->next) {
+- if (cur == chan_cdr) {
+- break;
+- }
+- }
+- if (cur)
+- ast_cdr_specialized_reset(chan_cdr,0);
+- }
+- ast_channel_unlock(chan_ptr);
+- }
+- /* new channel */
+- ast_cdr_specialized_reset(new_chan_cdr,0);
+- } else {
+- ast_cdr_specialized_reset(chan_cdr,0); /* nothing changed, reset the chan_cdr */
+- }
++
++ if (strcasecmp(orig_channame, chan->name) != 0) {
++ /* old channel */
++ if ((chan_ptr = ast_channel_get_by_name(orig_channame))) {
++ ast_channel_lock(chan_ptr);
++ if (!ast_bridged_channel(chan_ptr)) {
++ struct ast_cdr *cur;
++ for (cur = chan_ptr->cdr; cur; cur = cur->next) {
++ if (cur == chan_cdr) {
++ break;
++ }
++ }
++ if (cur) {
++ ast_cdr_specialized_reset(chan_cdr, 0);
++ }
++ }
++ ast_channel_unlock(chan_ptr);
++ chan_ptr = ast_channel_unref(chan_ptr);
++ }
++ /* new channel */
++ ast_cdr_specialized_reset(new_chan_cdr, 0);
++ } else {
++ ast_cdr_specialized_reset(chan_cdr, 0); /* nothing changed, reset the chan_cdr */
++ }
+ }
+-
++
+ {
+ struct ast_channel *chan_ptr = NULL;
+ new_peer_cdr = pick_unlocked_cdr(peer->cdr); /* the proper chan cdr, if there are forked cdrs */
+@@ -2873,8 +3034,8 @@
+ ast_set_flag(new_peer_cdr, AST_CDR_FLAG_POST_DISABLED); /* DISABLED is viral-- it will propagate across a bridge */
+ if (strcasecmp(orig_peername, peer->name) != 0) {
+ /* old channel */
+- chan_ptr = ast_get_channel_by_name_locked(orig_peername);
+- if (chan_ptr) {
++ if ((chan_ptr = ast_channel_get_by_name(orig_peername))) {
++ ast_channel_lock(chan_ptr);
+ if (!ast_bridged_channel(chan_ptr)) {
+ struct ast_cdr *cur;
+ for (cur = chan_ptr->cdr; cur; cur = cur->next) {
+@@ -2882,15 +3043,17 @@
+ break;
+ }
+ }
+- if (cur)
+- ast_cdr_specialized_reset(peer_cdr,0);
++ if (cur) {
++ ast_cdr_specialized_reset(peer_cdr, 0);
++ }
+ }
+ ast_channel_unlock(chan_ptr);
++ chan_ptr = ast_channel_unref(chan_ptr);
+ }
+ /* new channel */
+- ast_cdr_specialized_reset(new_peer_cdr,0);
++ ast_cdr_specialized_reset(new_peer_cdr, 0);
+ } else {
+- ast_cdr_specialized_reset(peer_cdr,0); /* nothing changed, reset the peer_cdr */
++ ast_cdr_specialized_reset(peer_cdr, 0); /* nothing changed, reset the peer_cdr */
+ }
+ }
+
+@@ -3196,7 +3359,7 @@
+ END_OPTIONS );
+
+ /*! \brief Park a call */
+-static int park_call_exec(struct ast_channel *chan, void *data)
++static int park_call_exec(struct ast_channel *chan, const char *data)
+ {
+ /* Cache the original channel name in case we get masqueraded in the middle
+ * of a park--it is still theoretically possible for a transfer to happen before
+@@ -3282,7 +3445,7 @@
+ }
+
+ /*! \brief Pickup parked call */
+-static int park_exec_full(struct ast_channel *chan, void *data, struct ast_parkinglot *parkinglot)
++static int park_exec_full(struct ast_channel *chan, const char *data, struct ast_parkinglot *parkinglot)
+ {
+ int res = 0;
+ struct ast_channel *peer=NULL;
+@@ -3292,7 +3455,7 @@
+ struct ast_bridge_config config;
+
+ if (data)
+- park = atoi((char *)data);
++ park = atoi((char *) data);
+
+ parkinglot = find_parkinglot(findparkinglotname(chan));
+ if (!parkinglot)
+@@ -3445,7 +3608,7 @@
+ return -1;
+ }
+
+-static int park_exec(struct ast_channel *chan, void *data)
++static int park_exec(struct ast_channel *chan, const char *data)
+ {
+ return park_exec_full(chan, data, default_parkinglot);
+ }
+@@ -3627,7 +3790,7 @@
+ char old_parking_ext[AST_MAX_EXTENSION];
+ char old_parking_con[AST_MAX_EXTENSION] = "";
+ char *ctg;
+- static const char *categories[] = {
++ static const char * const categories[] = {
+ /* Categories in features.conf that are not
+ * to be parsed as group categories
+ */
+@@ -4052,14 +4215,6 @@
+ return CLI_SUCCESS;
+ }
+
+-static char mandescr_bridge[] =
+-"Description: Bridge together two channels already in the PBX\n"
+-"Variables: ( Headers marked with * are required )\n"
+-" *Channel1: Channel to Bridge to Channel2\n"
+-" *Channel2: Channel to Bridge to Channel1\n"
+-" Tone: (Yes|No) Play courtesy tone to Channel 2\n"
+-"\n";
+-
+ /*!
+ * \brief Actual bridge
+ * \param chan
+@@ -4113,12 +4268,8 @@
+ 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));
++ chana = ast_channel_get_by_name_prefix(channela, strlen(channela));
+
+ /* send errors if any of the channels could not be found/locked */
+ if (!chana) {
+@@ -4136,16 +4287,16 @@
+ 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);
++ chana = ast_channel_unref(chana);
+ return 1;
+ }
+
+ do_bridge_masquerade(chana, tmpchana);
+- ast_channel_unlock(chana);
+- chana = NULL;
+
++ chana = ast_channel_unref(chana);
++
+ /* now do chanb */
+- chanb = ast_get_channel_by_name_prefix_locked(channelb, strlen(channelb));
++ chanb = ast_channel_get_by_name_prefix(channelb, strlen(channelb));
+ /* send errors if any of the channels could not be found/locked */
+ if (!chanb) {
+ char buf[256];
+@@ -4164,13 +4315,14 @@
+ NULL, NULL, 0, "Bridge/%s", chanb->name))) {
+ astman_send_error(s, m, "Unable to create temporary channels!");
+ ast_hangup(tmpchana);
+- ast_channel_unlock(chanb);
++ chanb = ast_channel_unref(chanb);
+ return 1;
+ }
++
+ do_bridge_masquerade(chanb, tmpchanb);
+- ast_channel_unlock(chanb);
+- chanb = NULL;
+
++ chanb = ast_channel_unref(chanb);
++
+ /* 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);
+@@ -4328,13 +4480,6 @@
+ return RESULT_SUCCESS;
+ }
+
+-static char mandescr_park[] =
+-"Description: Park a channel.\n"
+-"Variables: (Names marked with * are required)\n"
+-" *Channel: Channel name to park\n"
+-" *Channel2: Channel to announce park info to (and return to if timeout)\n"
+-" Timeout: Number of milliseconds to wait before callback.\n";
+-
+ /*!
+ * \brief Create manager event for parked calls
+ * \param s
+@@ -4364,21 +4509,24 @@
+ return 0;
+ }
+
+- ch1 = ast_get_channel_by_name_locked(channel);
+- if (!ch1) {
++ if (!(ch1 = ast_channel_get_by_name(channel))) {
+ snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel);
+ astman_send_error(s, m, buf);
+ return 0;
+ }
+
+- ch2 = ast_get_channel_by_name_locked(channel2);
+- if (!ch2) {
++ if (!(ch2 = ast_channel_get_by_name(channel2))) {
+ snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel2);
+ astman_send_error(s, m, buf);
+- ast_channel_unlock(ch1);
++ ast_channel_unref(ch1);
+ return 0;
+ }
+
++ ast_channel_lock(ch1);
++ while (ast_channel_trylock(ch2)) {
++ CHANNEL_DEADLOCK_AVOIDANCE(ch1);
++ }
++
+ if (!ast_strlen_zero(timeout)) {
+ sscanf(timeout, "%d", &to);
+ }
+@@ -4394,19 +4542,26 @@
+ ast_channel_unlock(ch1);
+ ast_channel_unlock(ch2);
+
++ ch1 = ast_channel_unref(ch1);
++ ch2 = ast_channel_unref(ch2);
++
+ return 0;
+ }
+
+-static int find_channel_by_group(struct ast_channel *c, void *data) {
+- struct ast_channel *chan = data;
++static int find_channel_by_group(void *obj, void *arg, void *data, int flags)
++{
++ struct ast_channel *c = data;
++ struct ast_channel *chan = obj;
+
+- return !c->pbx &&
++ int i = !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));
++
++ return i ? CMP_MATCH | CMP_STOP : 0;
+ }
+
+ /*!
+@@ -4419,32 +4574,59 @@
+ */
+ int ast_pickup_call(struct ast_channel *chan)
+ {
+- struct ast_channel *cur = ast_channel_search_locked(find_channel_by_group, chan);
++ struct ast_channel *cur;
++ struct ast_party_connected_line connected_caller;
++ int res;
++ const char *chan_name;
++ const char *cur_name;
+
+- if (cur) {
+- int res = -1;
+- ast_debug(1, "Call pickup on chan '%s' by '%s'\n",cur->name, chan->name);
+- res = ast_answer(chan);
+- if (res)
+- ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name);
+- res = ast_queue_control(chan, AST_CONTROL_ANSWER);
+- if (res)
+- ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name);
+- 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 {
++ if (!(cur = ast_channel_callback(find_channel_by_group, NULL, chan, 0))) {
+ ast_debug(1, "No call pickup possible...\n");
+ if (!ast_strlen_zero(pickupfailsound)) {
+ ast_stream_and_wait(chan, pickupfailsound, "");
+ }
++ return -1;
+ }
+- return -1;
++
++ ast_channel_lock_both(cur, chan);
++
++ cur_name = ast_strdupa(cur->name);
++ chan_name = ast_strdupa(chan->name);
++
++ 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;
++ if (ast_channel_connected_line_macro(NULL, chan, &connected_caller, 0, 0)) {
++ 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);
++
++ ast_channel_unlock(cur);
++ ast_channel_unlock(chan);
++
++ if (ast_answer(chan)) {
++ ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan_name);
++ }
++
++ if (ast_queue_control(chan, AST_CONTROL_ANSWER)) {
++ ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan_name);
++ }
++
++ if ((res = ast_channel_masquerade(cur, chan))) {
++ ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan_name, cur_name);
++ }
++
++ if (!ast_strlen_zero(pickupsound)) {
++ ast_stream_and_wait(cur, pickupsound, "");
++ }
++
++ cur = ast_channel_unref(cur);
++
++ return res;
+ }
+
+ static char *app_bridge = "Bridge";
+@@ -4466,7 +4648,7 @@
+ * answer call if not already, check compatible channels, setup bridge config
+ * now bridge call, if transfered party hangs up return to PBX extension.
+ */
+-static int bridge_exec(struct ast_channel *chan, void *data)
++static int bridge_exec(struct ast_channel *chan, const char *data)
+ {
+ struct ast_channel *current_dest_chan, *final_dest_chan;
+ char *tmp_data = NULL;
+@@ -4504,8 +4686,8 @@
+ }
+
+ /* make sure we have a valid end point */
+- if (!(current_dest_chan = ast_get_channel_by_name_prefix_locked(args.dest_chan,
+- strlen(args.dest_chan)))) {
++ if (!(current_dest_chan = ast_channel_get_by_name_prefix(args.dest_chan,
++ strlen(args.dest_chan)))) {
+ ast_log(LOG_WARNING, "Bridge failed because channel %s does not exists or we "
+ "cannot get its lock\n", args.dest_chan);
+ manager_event(EVENT_FLAG_CALL, "BridgeExec",
+@@ -4518,8 +4700,9 @@
+ }
+
+ /* answer the channel if needed */
+- if (current_dest_chan->_state != AST_STATE_UP)
++ if (current_dest_chan->_state != AST_STATE_UP) {
+ ast_answer(current_dest_chan);
++ }
+
+ /* try to allocate a place holder where current_dest_chan will be placed */
+ if (!(final_dest_chan = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL,
+@@ -4546,6 +4729,7 @@
+ "Channel2: %s\r\n", chan->name, final_dest_chan->name);
+ ast_hangup(final_dest_chan); /* may be we should return this channel to the PBX? */
+ pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "INCOMPATIBLE");
++ current_dest_chan = ast_channel_unref(current_dest_chan);
+ return 0;
+ }
+
+@@ -4563,6 +4747,8 @@
+ }
+ }
+
++ current_dest_chan = ast_channel_unref(current_dest_chan);
++
+ /* do the bridge */
+ ast_bridge_call(chan, final_dest_chan, &bconfig);
+
+@@ -4602,9 +4788,9 @@
+ if (!res)
+ 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);
+- ast_manager_register2("Bridge", EVENT_FLAG_CALL, action_bridge, "Bridge two channels already in the PBX", mandescr_bridge);
++ ast_manager_register_xml("ParkedCalls", 0, manager_parking_status);
++ ast_manager_register_xml("Park", EVENT_FLAG_CALL, manager_park);
++ ast_manager_register_xml("Bridge", EVENT_FLAG_CALL, action_bridge);
+ }
+
+ res |= ast_devstate_prov_add("Park", metermaidstate);
+Index: main/http.c
+===================================================================
+--- a/main/http.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/main/http.c (.../trunk) (revision 202568)
+@@ -17,14 +17,14 @@
+ */
+
+ /*!
+- * \file
++ * \file
+ * \brief http server for AMI access
+ *
+ * \author Mark Spencer <markster@digium.com>
+ *
+ * This program implements a tiny http server
+- * and was inspired by micro-httpd by Jef Poskanzer
+- *
++ * and was inspired by micro-httpd by Jef Poskanzer
++ *
+ * \ref AstHTTP - AMI over the http protocol
+ */
+
+@@ -98,6 +98,7 @@
+ const char *mtype;
+ } mimetypes[] = {
+ { "png", "image/png" },
++ { "xml", "text/xml" },
+ { "jpg", "image/jpeg" },
+ { "js", "application/x-javascript" },
+ { "wav", "audio/x-wav" },
+@@ -115,8 +116,24 @@
+
+ static AST_RWLIST_HEAD_STATIC(uri_redirects, http_uri_redirect);
+
+-static const char *ftype2mtype(const char *ftype, char *wkspace, int wkspacelen)
++static const struct ast_cfhttp_methods_text {
++ enum ast_http_method method;
++ const char text[];
++} ast_http_methods_text[] = {
++ { AST_HTTP_UNKNOWN, "UNKNOWN" },
++ { AST_HTTP_GET, "GET" },
++ { AST_HTTP_POST, "POST" },
++ { AST_HTTP_HEAD, "HEAD" },
++ { AST_HTTP_PUT, "PUT" },
++};
++
++const char *ast_get_http_method(enum ast_http_method method)
+ {
++ return ast_http_methods_text[method].text;
++}
++
++const char *ast_http_ftype2mtype(const char *ftype)
++{
+ int x;
+
+ if (ftype) {
+@@ -126,21 +143,24 @@
+ }
+ }
+ }
+-
+- snprintf(wkspace, wkspacelen, "text/%s", S_OR(ftype, "plain"));
+-
+- return wkspace;
++ return NULL;
+ }
+
+-static uint32_t manid_from_vars(struct ast_variable *sid) {
+- uint32_t mngid;
++uint32_t ast_http_manid_from_vars(struct ast_variable *headers)
++{
++ uint32_t mngid = 0;
++ struct ast_variable *v, *cookies;
+
+- while (sid && strcmp(sid->name, "mansession_id"))
+- sid = sid->next;
+-
+- if (!sid || sscanf(sid->value, "%x", &mngid) != 1)
+- return 0;
+-
++ cookies = ast_http_get_cookies(headers);
++ for (v = cookies; v; v = v->next) {
++ if (!strcasecmp(v->name, "mansession_id")) {
++ sscanf(v->value, "%x", &mngid);
++ break;
++ }
++ }
++ if (cookies) {
++ ast_variables_destroy(cookies);
++ }
+ return mngid;
+ }
+
+@@ -151,20 +171,31 @@
+ }
+ }
+
+-static struct ast_str *static_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)
++static int static_callback(struct ast_tcptls_session_instance *ser,
++ const struct ast_http_uri *urih, const char *uri,
++ enum ast_http_method method, struct ast_variable *get_vars,
++ struct ast_variable *headers)
+ {
+ char *path;
+- char *ftype;
++ const char *ftype;
+ const char *mtype;
+ char wkspace[80];
+ struct stat st;
+ int len;
+ int fd;
+- struct timeval now = ast_tvnow();
+- char buf[256];
++ struct ast_str *http_header;
++ struct timeval tv;
+ struct ast_tm tm;
++ char timebuf[80], etag[23];
++ struct ast_variable *v;
++ int not_modified = 0;
+
+- /* Yuck. I'm not really sold on this, but if you don't deliver static content it makes your configuration
++ if (method != AST_HTTP_GET && method != AST_HTTP_HEAD) {
++ ast_http_error(ser, 501, "Not Implemented", "Attempt to use unimplemented / unsupported method");
++ return -1;
++ }
++
++ /* Yuck. I'm not really sold on this, but if you don't deliver static content it makes your configuration
+ substantially more challenging, but this seems like a rather irritating feature creep on Asterisk. */
+ if (!enablestatic || ast_strlen_zero(uri)) {
+ goto out403;
+@@ -178,18 +209,20 @@
+ if (strstr(uri, "/..")) {
+ goto out403;
+ }
+-
++
+ if ((ftype = strrchr(uri, '.'))) {
+ ftype++;
+ }
+
+- mtype = ftype2mtype(ftype, wkspace, sizeof(wkspace));
+-
++ if (!(mtype = ast_http_ftype2mtype(ftype))) {
++ snprintf(wkspace, sizeof(wkspace), "text/%s", S_OR(ftype, "plain"));
++ }
++
+ /* Cap maximum length */
+ if ((len = strlen(uri) + strlen(ast_config_AST_DATA_DIR) + strlen("/static-http/") + 5) > 1024) {
+ goto out403;
+ }
+-
++
+ path = alloca(len);
+ sprintf(path, "%s/static-http/%s", ast_config_AST_DATA_DIR, uri);
+ if (stat(path, &st)) {
+@@ -198,142 +231,275 @@
+
+ if (S_ISDIR(st.st_mode)) {
+ goto out404;
+- }
++ }
+
+- if ((fd = open(path, O_RDONLY)) < 0) {
++ fd = open(path, O_RDONLY);
++ if (fd < 0) {
+ goto out403;
+ }
+
+- if (strstr(path, "/private/") && !astman_is_authed(manid_from_vars(vars))) {
++ if (strstr(path, "/private/") && !astman_is_authed(ast_http_manid_from_vars(headers))) {
+ goto out403;
+ }
+
+- ast_strftime(buf, sizeof(buf), "%a, %d %b %Y %H:%M:%S %Z", ast_localtime(&now, &tm, "GMT"));
+- fprintf(ser->f, "HTTP/1.1 200 OK\r\n"
+- "Server: Asterisk/%s\r\n"
+- "Date: %s\r\n"
+- "Connection: close\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);
++ /* make "Etag:" http header value */
++ snprintf(etag, sizeof(etag), "\"%ld\"", (long)st.st_mtime);
+
+- while ((len = read(fd, buf, sizeof(buf))) > 0) {
+- if (fwrite(buf, 1, len, ser->f) != len) {
+- ast_log(LOG_WARNING, "fwrite() failed: %s\n", strerror(errno));
++ /* make "Last-Modified:" http header value */
++ tv.tv_sec = st.st_mtime;
++ tv.tv_usec = 0;
++ ast_strftime(timebuf, sizeof(timebuf), "%a, %d %b %Y %H:%M:%S GMT", ast_localtime(&tv, &tm, "GMT"));
++
++ /* check received "If-None-Match" request header and Etag value for file */
++ for (v = headers; v; v = v->next) {
++ if (!strcasecmp(v->name, "If-None-Match")) {
++ if (!strcasecmp(v->value, etag)) {
++ not_modified = 1;
++ }
++ break;
+ }
+ }
+
++ if ( (http_header = ast_str_create(255)) == NULL) {
++ return -1;
++ }
++
++ ast_str_set(&http_header, 0, "Content-type: %s\r\n"
++ "ETag: %s\r\n"
++ "Last-Modified: %s",
++ mtype,
++ etag,
++ timebuf);
++
++ /* ast_http_send() frees http_header, so we don't need to do it before returning */
++ if (not_modified) {
++ ast_http_send(ser, method, 304, "Not Modified", http_header, NULL, 0, 1);
++ } else {
++ ast_http_send(ser, method, 200, NULL, http_header, NULL, fd, 1); /* static content flag is set */
++ }
+ close(fd);
++ return 0;
+
+- return NULL;
+-
+ out404:
+- return ast_http_error((*status = 404),
+- (*title = ast_strdup("Not Found")),
+- NULL, "The requested URL was not found on this server.");
++ ast_http_error(ser, 404, "Not Found", "The requested URL was not found on this server.");
++ return -1;
+
+ out403:
+- return ast_http_error((*status = 403),
+- (*title = ast_strdup("Access Denied")),
+- NULL, "You do not have permission to access the requested URL.");
++ ast_http_error(ser, 403, "Access Denied", "You do not have permission to access the requested URL.");
++ return -1;
+ }
+
+-
+-static struct ast_str *httpstatus_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)
++static int httpstatus_callback(struct ast_tcptls_session_instance *ser,
++ const struct ast_http_uri *urih, const char *uri,
++ enum ast_http_method method, struct ast_variable *get_vars,
++ struct ast_variable *headers)
+ {
+- struct ast_str *out = ast_str_create(512);
+- struct ast_variable *v;
++ struct ast_str *out;
++ struct ast_variable *v, *cookies = NULL;
+
+- if (out == NULL) {
+- return out;
++ if (method != AST_HTTP_GET && method != AST_HTTP_HEAD) {
++ ast_http_error(ser, 501, "Not Implemented", "Attempt to use unimplemented / unsupported method");
++ return -1;
+ }
+
++ if ( (out = ast_str_create(512)) == NULL) {
++ return -1;
++ }
++
+ ast_str_append(&out, 0,
+- "\r\n"
+- "<title>Asterisk HTTP Status</title>\r\n"
+- "<body bgcolor=\"#ffffff\">\r\n"
+- "<table bgcolor=\"#f1f1f1\" align=\"center\"><tr><td bgcolor=\"#e0e0ff\" colspan=\"2\" width=\"500\">\r\n"
+- "<h2>&nbsp;&nbsp;Asterisk&trade; HTTP Status</h2></td></tr>\r\n");
++ "<title>Asterisk HTTP Status</title>\r\n"
++ "<body bgcolor=\"#ffffff\">\r\n"
++ "<table bgcolor=\"#f1f1f1\" align=\"center\"><tr><td bgcolor=\"#e0e0ff\" colspan=\"2\" width=\"500\">\r\n"
++ "<h2>&nbsp;&nbsp;Asterisk&trade; HTTP Status</h2></td></tr>\r\n");
++
+ ast_str_append(&out, 0, "<tr><td><i>Prefix</i></td><td><b>%s</b></td></tr>\r\n", prefix);
+ ast_str_append(&out, 0, "<tr><td><i>Bind Address</i></td><td><b>%s</b></td></tr>\r\n",
+ ast_inet_ntoa(http_desc.old_address.sin_addr));
+ ast_str_append(&out, 0, "<tr><td><i>Bind Port</i></td><td><b>%d</b></td></tr>\r\n",
+ ntohs(http_desc.old_address.sin_port));
+-
+ if (http_tls_cfg.enabled) {
+ ast_str_append(&out, 0, "<tr><td><i>SSL Bind Port</i></td><td><b>%d</b></td></tr>\r\n",
+ ntohs(https_desc.old_address.sin_port));
+ }
+-
+ ast_str_append(&out, 0, "<tr><td colspan=\"2\"><hr></td></tr>\r\n");
+-
+- for (v = vars; v; v = v->next) {
+- if (strncasecmp(v->name, "cookie_", 7)) {
+- ast_str_append(&out, 0, "<tr><td><i>Submitted Variable '%s'</i></td><td>%s</td></tr>\r\n", v->name, v->value);
+- }
++ for (v = get_vars; v; v = v->next) {
++ ast_str_append(&out, 0, "<tr><td><i>Submitted GET Variable '%s'</i></td><td>%s</td></tr>\r\n", v->name, v->value);
+ }
+-
+ ast_str_append(&out, 0, "<tr><td colspan=\"2\"><hr></td></tr>\r\n");
+
+- for (v = vars; v; v = v->next) {
+- if (!strncasecmp(v->name, "cookie_", 7)) {
+- ast_str_append(&out, 0, "<tr><td><i>Cookie '%s'</i></td><td>%s</td></tr>\r\n", v->name, v->value);
+- }
++ cookies = ast_http_get_cookies(headers);
++ for (v = cookies; v; v = v->next) {
++ ast_str_append(&out, 0, "<tr><td><i>Cookie '%s'</i></td><td>%s</td></tr>\r\n", v->name, v->value);
+ }
++ ast_variables_destroy(cookies);
+
+ ast_str_append(&out, 0, "</table><center><font size=\"-1\"><i>Asterisk and Digium are registered trademarks of Digium, Inc.</i></font></center></body>\r\n");
+- return out;
++ ast_http_send(ser, method, 200, NULL, NULL, out, 0, 0);
++ return 0;
+ }
+
+ static struct ast_http_uri statusuri = {
+ .callback = httpstatus_callback,
+ .description = "Asterisk HTTP General Status",
+ .uri = "httpstatus",
+- .supports_get = 1,
++ .has_subtree = 0,
+ .data = NULL,
+ .key = __FILE__,
+ };
+-
++
+ static struct ast_http_uri staticuri = {
+ .callback = static_callback,
+ .description = "Asterisk HTTP Static Delivery",
+ .uri = "static",
+ .has_subtree = 1,
+- .static_content = 1,
+- .supports_get = 1,
+ .data = NULL,
+ .key= __FILE__,
+ };
+-
+-struct ast_str *ast_http_error(int status, const char *title, const char *extra_header, const char *text)
++
++
++/* send http/1.1 responce */
++/* free content variable and close socket*/
++void ast_http_send(struct ast_tcptls_session_instance *ser,
++ enum ast_http_method method, int status_code, const char *status_title,
++ struct ast_str *http_header, struct ast_str *out, const int fd,
++ unsigned int static_content)
+ {
++ struct timeval now = ast_tvnow();
++ struct ast_tm tm;
++ char timebuf[80];
++ int content_length = 0;
++
++ if (!ser || 0 == ser->f) {
++ return;
++ }
++
++ ast_strftime(timebuf, sizeof(timebuf), "%a, %d %b %Y %H:%M:%S GMT", ast_localtime(&now, &tm, "GMT"));
++
++ /* calc conetnt length */
++ if (out) {
++ content_length += strlen(ast_str_buffer(out));
++ }
++
++ if (fd) {
++ content_length += lseek(fd, 0, SEEK_END);
++ lseek(fd, 0, SEEK_SET);
++ }
++
++ /* send http header */
++ fprintf(ser->f, "HTTP/1.1 %d %s\r\n"
++ "Server: Asterisk/%s\r\n"
++ "Date: %s\r\n"
++ "Connection: close\r\n"
++ "%s"
++ "Content-Length: %d\r\n"
++ "%s\r\n\r\n",
++ status_code, status_title ? status_title : "OK",
++ ast_get_version(),
++ timebuf,
++ static_content ? "" : "Cache-Control: no-cache, no-store\r\n",
++ content_length,
++ http_header ? ast_str_buffer(http_header) : ""
++ );
++
++ /* send content */
++ if (method != AST_HTTP_HEAD || status_code >= 400) {
++ if (out) {
++ fprintf(ser->f, "%s", ast_str_buffer(out));
++ }
++
++ if (fd) {
++ char buf[256];
++ int len;
++ while ((len = read(fd, buf, sizeof(buf))) > 0) {
++ if (fwrite(buf, len, 1, ser->f) != len) {
++ ast_log(LOG_WARNING, "fwrite() failed: %s\n", strerror(errno));
++ }
++ }
++ }
++ }
++
++ if (http_header) {
++ ast_free(http_header);
++ }
++ if (out) {
++ ast_free(out);
++ }
++
++ fclose(ser->f);
++ ser->f = 0;
++ return;
++}
++
++/* Send http "401 Unauthorized" responce and close socket*/
++void ast_http_auth(struct ast_tcptls_session_instance *ser, const char *realm,
++ const unsigned long nonce, const unsigned long opaque, int stale,
++ const char *text)
++{
++ struct ast_str *http_headers = ast_str_create(128);
+ struct ast_str *out = ast_str_create(512);
+
+- if (out == NULL) {
+- return out;
++ if (!http_headers || !out) {
++ ast_free(http_headers);
++ ast_free(out);
++ return;
+ }
+
++ ast_str_set(&http_headers, 0,
++ "WWW-authenticate: Digest algorithm=MD5, realm=\"%s\", nonce=\"%08lx\", qop=\"auth\", opaque=\"%08lx\"%s\r\n"
++ "Content-type: text/html",
++ realm ? realm : "Asterisk",
++ nonce,
++ opaque,
++ stale ? ", stale=true" : "");
++
+ ast_str_set(&out, 0,
+- "Content-type: text/html\r\n"
+- "%s"
+- "\r\n"
+- "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\r\n"
+- "<html><head>\r\n"
+- "<title>%d %s</title>\r\n"
+- "</head><body>\r\n"
+- "<h1>%s</h1>\r\n"
+- "<p>%s</p>\r\n"
+- "<hr />\r\n"
+- "<address>Asterisk Server</address>\r\n"
+- "</body></html>\r\n",
+- (extra_header ? extra_header : ""), status, title, title, text);
++ "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\r\n"
++ "<html><head>\r\n"
++ "<title>401 Unauthorized</title>\r\n"
++ "</head><body>\r\n"
++ "<h1>401 Unauthorized</h1>\r\n"
++ "<p>%s</p>\r\n"
++ "<hr />\r\n"
++ "<address>Asterisk Server</address>\r\n"
++ "</body></html>\r\n",
++ text ? text : "");
+
+- return out;
++ ast_http_send(ser, AST_HTTP_UNKNOWN, 401, "Unauthorized", http_headers, out, 0, 0);
++ return;
+ }
+
+-/*! \brief
+- * Link the new uri into the list.
++/* send http error responce and close socket*/
++void ast_http_error(struct ast_tcptls_session_instance *ser, int status_code, const char *status_title, const char *text)
++{
++ struct ast_str *http_headers = ast_str_create(40);
++ struct ast_str *out = ast_str_create(256);
++
++ if (!http_headers || !out) {
++ ast_free(http_headers);
++ ast_free(out);
++ return;
++ }
++
++ ast_str_set(&http_headers, 0, "Content-type: text/html");
++
++ ast_str_set(&out, 0,
++ "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\r\n"
++ "<html><head>\r\n"
++ "<title>%d %s</title>\r\n"
++ "</head><body>\r\n"
++ "<h1>%s</h1>\r\n"
++ "<p>%s</p>\r\n"
++ "<hr />\r\n"
++ "<address>Asterisk Server</address>\r\n"
++ "</body></html>\r\n",
++ status_code, status_title, status_title, text);
++
++ ast_http_send(ser, AST_HTTP_UNKNOWN, status_code, status_title, http_headers, out, 0, 0);
++ return;
++}
++
++/*! \brief
++ * Link the new uri into the list.
+ *
+ * They are sorted by length of
+ * the string, not alphabetically. Duplicate entries are not replaced,
+@@ -346,25 +512,19 @@
+ struct ast_http_uri *uri;
+ int len = strlen(urih->uri);
+
+- if (!(urih->supports_get || urih->supports_post)) {
+- ast_log(LOG_WARNING, "URI handler does not provide either GET or POST method: %s (%s)\n", urih->uri, urih->description);
+- return -1;
+- }
+-
+ AST_RWLIST_WRLOCK(&uris);
+
+- if (AST_RWLIST_EMPTY(&uris) || strlen(AST_RWLIST_FIRST(&uris)->uri) <= len) {
++ if ( AST_RWLIST_EMPTY(&uris) || strlen(AST_RWLIST_FIRST(&uris)->uri) <= len ) {
+ AST_RWLIST_INSERT_HEAD(&uris, urih, entry);
+ AST_RWLIST_UNLOCK(&uris);
+-
+ return 0;
+ }
+
+ AST_RWLIST_TRAVERSE(&uris, uri, entry) {
+ if (AST_RWLIST_NEXT(uri, entry) &&
+- strlen(AST_RWLIST_NEXT(uri, entry)->uri) <= len) {
++ strlen(AST_RWLIST_NEXT(uri, entry)->uri) <= len) {
+ AST_RWLIST_INSERT_AFTER(&uris, uri, urih, entry);
+- AST_RWLIST_UNLOCK(&uris);
++ AST_RWLIST_UNLOCK(&uris);
+
+ return 0;
+ }
+@@ -373,9 +533,9 @@
+ AST_RWLIST_INSERT_TAIL(&uris, urih, entry);
+
+ AST_RWLIST_UNLOCK(&uris);
+-
++
+ return 0;
+-}
++}
+
+ void ast_http_uri_unlink(struct ast_http_uri *urih)
+ {
+@@ -411,91 +571,121 @@
+ static void http_decode(char *s)
+ {
+ char *t;
+-
++
+ for (t = s; *t; t++) {
+- if (*t == '+')
++ if (*t == '+') {
+ *t = ' ';
++ }
+ }
+
+ ast_uri_decode(s);
+ }
+
+-static struct ast_str *handle_uri(struct ast_tcptls_session_instance *ser, char *uri, enum ast_http_method method,
+- int *status, char **title, int *contentlength, struct ast_variable **cookies, struct ast_variable *headers,
+- unsigned int *static_content)
++/*
++ * get post variables from client Request Entity-Body, if content type is
++ * application/x-www-form-urlencoded
++ */
++struct ast_variable *ast_http_get_post_vars(
++ struct ast_tcptls_session_instance *ser, struct ast_variable *headers)
+ {
++ int content_length = 0;
++ struct ast_variable *v, *post_vars=NULL, *prev = NULL;
++ char *buf, *var, *val;
++
++ for (v = headers; v; v = v->next) {
++ if (!strcasecmp(v->name, "Content-Type")) {
++ if (strcasecmp(v->value, "application/x-www-form-urlencoded")) {
++ return NULL;
++ }
++ break;
++ }
++ }
++
++ for (v = headers; v; v = v->next) {
++ if (!strcasecmp(v->name, "Content-Length")) {
++ content_length = atoi(v->value) + 1;
++ break;
++ }
++ }
++
++ if (!content_length) {
++ return NULL;
++ }
++
++ if (!(buf = alloca(content_length))) {
++ return NULL;
++ }
++ if (!fgets(buf, content_length, ser->f)) {
++ return NULL;
++ }
++
++ while ((val = strsep(&buf, "&"))) {
++ var = strsep(&val, "=");
++ if (val) {
++ http_decode(val);
++ } else {
++ val = "";
++ }
++ http_decode(var);
++ if ((v = ast_variable_new(var, val, ""))) {
++ if (post_vars) {
++ prev->next = v;
++ } else {
++ post_vars = v;
++ }
++ prev = v;
++ }
++ }
++ return post_vars;
++}
++
++static int handle_uri(struct ast_tcptls_session_instance *ser, char *uri,
++ enum ast_http_method method, struct ast_variable *headers)
++{
+ char *c;
+- struct ast_str *out = NULL;
++ int res = -1;
+ char *params = uri;
+ struct ast_http_uri *urih = NULL;
+ int l;
+- struct ast_variable *vars = NULL, *v, *prev = NULL;
++ struct ast_variable *get_vars = NULL, *v, *prev = NULL;
+ struct http_uri_redirect *redirect;
+- int saw_method = 0;
+
+- /* preserve previous behavior of only support URI parameters on GET requests */
+- if (method == AST_HTTP_GET) {
+- strsep(&params, "?");
+-
+- /* Extract arguments from the request and store them in variables.
+- * Note that a request can have multiple arguments with the same
+- * name, and we store them all in the list of variables.
+- * It is up to the application to handle multiple values.
+- */
+- if (params) {
+- char *var, *val;
+-
+- while ((val = strsep(&params, "&"))) {
+- var = strsep(&val, "=");
+- if (val) {
+- http_decode(val);
++ strsep(&params, "?");
++ /* Extract arguments from the request and store them in variables. */
++ if (params) {
++ char *var, *val;
++
++ while ((val = strsep(&params, "&"))) {
++ var = strsep(&val, "=");
++ if (val) {
++ http_decode(val);
++ } else {
++ val = "";
++ }
++ http_decode(var);
++ if ((v = ast_variable_new(var, val, ""))) {
++ if (get_vars) {
++ prev->next = v;
+ } else {
+- val = "";
++ get_vars = v;
+ }
+- http_decode(var);
+- if ((v = ast_variable_new(var, val, ""))) {
+- if (vars) {
+- prev->next = v;
+- } else {
+- vars = v;
+- }
+- prev = v;
+- }
++ prev = v;
+ }
+ }
+ }
+-
+- /*
+- * Append the cookies to the list of variables.
+- * This saves a pass in the cookies list, but has the side effect
+- * that a variable might mask a cookie with the same name if the
+- * application stops at the first match.
+- * Note that this is the same behaviour as $_REQUEST variables in PHP.
+- */
+- if (prev) {
+- prev->next = *cookies;
+- } else {
+- vars = *cookies;
+- }
+- *cookies = NULL;
+-
+ http_decode(uri);
+
+ AST_RWLIST_RDLOCK(&uri_redirects);
+ AST_RWLIST_TRAVERSE(&uri_redirects, redirect, entry) {
+ if (!strcasecmp(uri, redirect->target)) {
+- char buf[512];
++ struct ast_str *http_header = ast_str_create(128);
++ ast_str_set(&http_header, 0, "Location: %s\r\n", redirect->dest);
++ ast_http_send(ser, method, 302, "Moved Temporarily", http_header, NULL, 0, 0);
+
+- snprintf(buf, sizeof(buf), "Location: %s\r\n", redirect->dest);
+- out = ast_http_error((*status = 302),
+- (*title = ast_strdup("Moved Temporarily")),
+- buf, "Redirecting...");
+-
+ break;
+ }
+ }
+ AST_RWLIST_UNLOCK(&uri_redirects);
+-
+ if (redirect) {
+ goto cleanup;
+ }
+@@ -508,70 +698,31 @@
+ AST_RWLIST_RDLOCK(&uris);
+ AST_RWLIST_TRAVERSE(&uris, urih, entry) {
+ ast_debug(2, "match request [%s] with handler [%s] len %d\n", uri, urih->uri, l);
+- if (!saw_method) {
+- switch (method) {
+- case AST_HTTP_GET:
+- if (urih->supports_get) {
+- saw_method = 1;
+- }
+- break;
+- case AST_HTTP_POST:
+- if (urih->supports_post) {
+- saw_method = 1;
+- }
+- break;
+- }
+- }
+-
+ l = strlen(urih->uri);
+ c = uri + l; /* candidate */
+-
+- if (strncasecmp(urih->uri, uri, l) || /* no match */
+- (*c && *c != '/')) { /* substring */
++ if (strncasecmp(urih->uri, uri, l) /* no match */
++ || (*c && *c != '/')) { /* substring */
+ continue;
+ }
+-
+ if (*c == '/') {
+ c++;
+ }
+-
+ if (!*c || urih->has_subtree) {
+- if (((method == AST_HTTP_GET) && urih->supports_get) ||
+- ((method == AST_HTTP_POST) && urih->supports_post)) {
+- uri = c;
+-
+- break;
+- }
++ uri = c;
++ break;
+ }
+ }
+-
+- if (!urih) {
+- AST_RWLIST_UNLOCK(&uris);
+- }
++ AST_RWLIST_UNLOCK(&uris);
+ }
+-
+- if (method == AST_HTTP_POST && !astman_is_authed(manid_from_vars(vars))) {
+- out = ast_http_error((*status = 403),
+- (*title = ast_strdup("Access Denied")),
+- NULL, "You do not have permission to access the requested URL.");
+- } else if (urih) {
+- *static_content = urih->static_content;
+- out = urih->callback(ser, urih, uri, method, vars, headers, status, title, contentlength);
+- AST_RWLIST_UNLOCK(&uris);
+- } else if (saw_method) {
+- out = ast_http_error((*status = 404),
+- (*title = ast_strdup("Not Found")), NULL,
+- "The requested URL was not found on this server.");
++ if (urih) {
++ res = urih->callback(ser, urih, uri, method, get_vars, headers);
+ } else {
+- out = ast_http_error((*status = 501),
+- (*title = ast_strdup("Not Implemented")), NULL,
+- "Attempt to use unimplemented / unsupported method");
++ ast_http_error(ser, 404, "Not Found", "The requested URL was not found on this server.");
+ }
+
+ cleanup:
+- ast_variables_destroy(vars);
+-
+- return out;
++ ast_variables_destroy(get_vars);
++ return res;
+ }
+
+ #ifdef DO_SSL
+@@ -624,12 +775,9 @@
+ char *cur;
+ struct ast_variable *vars = NULL, *var;
+
+- /* Skip Cookie: */
+- cookies += 8;
+-
+ while ((cur = strsep(&cookies, ";"))) {
+ char *name, *val;
+-
++
+ name = val = cur;
+ strsep(&val, "=");
+
+@@ -656,27 +804,55 @@
+ return vars;
+ }
+
++/* get cookie from Request headers */
++struct ast_variable *ast_http_get_cookies(struct ast_variable *headers)
++{
++ struct ast_variable *v, *cookies=NULL;
++
++ for (v = headers; v; v = v->next) {
++ if (!strncasecmp(v->name, "Cookie", 6)) {
++ if (cookies) {
++ ast_variables_destroy(cookies);
++ }
++
++ cookies = parse_cookies((char *)v->value);
++ }
++ }
++ return cookies;
++}
++
++
+ static void *httpd_helper_thread(void *data)
+ {
+ char buf[4096];
+- char cookie[4096];
++ char header_line[4096];
+ struct ast_tcptls_session_instance *ser = data;
+- struct ast_variable *vars=NULL, *headers = NULL;
+- char *uri, *title=NULL;
+- int status = 200, contentlength = 0;
+- struct ast_str *out = NULL;
+- unsigned int static_content = 0;
++ struct ast_variable *headers = NULL;
+ struct ast_variable *tail = headers;
++ char *uri, *method;
++ enum ast_http_method http_method = AST_HTTP_UNKNOWN;
+
+ if (!fgets(buf, sizeof(buf), ser->f)) {
+ goto done;
+ }
+
+- uri = ast_skip_nonblanks(buf); /* Skip method */
++ /* Get method */
++ method = ast_skip_blanks(buf);
++ uri = ast_skip_nonblanks(method);
+ if (*uri) {
+ *uri++ = '\0';
+ }
+
++ if (!strcasecmp(method,"GET")) {
++ http_method = AST_HTTP_GET;
++ } else if (!strcasecmp(method,"POST")) {
++ http_method = AST_HTTP_POST;
++ } else if (!strcasecmp(method,"HEAD")) {
++ http_method = AST_HTTP_HEAD;
++ } else if (!strcasecmp(method,"PUT")) {
++ http_method = AST_HTTP_PUT;
++ }
++
+ uri = ast_skip_blanks(uri); /* Skip white space */
+
+ if (*uri) { /* terminate at the first blank */
+@@ -687,101 +863,56 @@
+ }
+ }
+
+- /* process "Cookie: " lines */
+- while (fgets(cookie, sizeof(cookie), ser->f)) {
++ /* process "Request Headers" lines */
++ while (fgets(header_line, sizeof(header_line), ser->f)) {
++ char *name, *value;
++
+ /* Trim trailing characters */
+- ast_trim_blanks(cookie);
+- if (ast_strlen_zero(cookie)) {
++ ast_trim_blanks(header_line);
++ if (ast_strlen_zero(header_line)) {
+ break;
+ }
+- if (!strncasecmp(cookie, "Cookie: ", 8)) {
+- vars = parse_cookies(cookie);
+- } else {
+- char *name, *val;
+
+- val = cookie;
+- name = strsep(&val, ":");
+- if (ast_strlen_zero(name) || ast_strlen_zero(val)) {
+- continue;
+- }
+- ast_trim_blanks(name);
+- val = ast_skip_blanks(val);
++ value = header_line;
++ name = strsep(&value, ":");
++ if (!value) {
++ continue;
++ }
+
+- if (!headers) {
+- headers = ast_variable_new(name, val, __FILE__);
+- tail = headers;
+- } else {
+- tail->next = ast_variable_new(name, val, __FILE__);
+- tail = tail->next;
+- }
++ value = ast_skip_blanks(value);
++ if (ast_strlen_zero(value) || ast_strlen_zero(name)) {
++ continue;
+ }
++
++ ast_trim_blanks(name);
++
++ if (!headers) {
++ headers = ast_variable_new(name, value, __FILE__);
++ tail = headers;
++ } else {
++ tail->next = ast_variable_new(name, value, __FILE__);
++ tail = tail->next;
++ }
+ }
+
+ if (!*uri) {
+- out = ast_http_error(400, "Bad Request", NULL, "Invalid Request");
+- } else if (strcasecmp(buf, "post") && strcasecmp(buf, "get")) {
+- out = ast_http_error(501, "Not Implemented", NULL,
+- "Attempt to use unimplemented / unsupported method");
+- } else { /* try to serve it */
+- out = handle_uri(ser, uri, (!strcasecmp(buf, "get")) ? AST_HTTP_GET : AST_HTTP_POST,
+- &status, &title, &contentlength, &vars, headers, &static_content);
++ ast_http_error(ser, 400, "Bad Request", "Invalid Request");
++ return NULL;
+ }
+
+- /* If they aren't mopped up already, clean up the cookies */
+- if (vars) {
+- ast_variables_destroy(vars);
+- }
++ handle_uri(ser, uri, http_method, headers);
++
+ /* Clean up all the header information pulled as well */
+ if (headers) {
+ ast_variables_destroy(headers);
+ }
+
+- if (out) {
+- struct timeval now = ast_tvnow();
+- char timebuf[256];
+- struct ast_tm tm;
+-
+- ast_strftime(timebuf, sizeof(timebuf), "%a, %d %b %Y %H:%M:%S %Z", ast_localtime(&now, &tm, "GMT"));
+- fprintf(ser->f,
+- "HTTP/1.1 %d %s\r\n"
+- "Server: Asterisk/%s\r\n"
+- "Date: %s\r\n"
+- "Connection: close\r\n"
+- "%s",
+- status, title ? title : "OK", ast_get_version(), timebuf,
+- static_content ? "" : "Cache-Control: no-cache, no-store\r\n");
+- /* We set the no-cache headers only for dynamic content.
+- * If you want to make sure the static file you requested is not from cache,
+- * 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", ast_str_buffer(out));
+- } else {
+- 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(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 ) {
+- ast_log(LOG_WARNING, "fwrite() failed: %s\n", strerror(errno));
+- }
+- }
+- }
+- ast_free(out);
++done:
++ if (ser->f) {
++ fclose(ser->f);
+ }
+-
+- if (title) {
+- ast_free(title);
+- }
+-
+-done:
+- fclose(ser->f);
+ ao2_ref(ser, -1);
+ ser = NULL;
+-
+ return NULL;
+ }
+
+@@ -814,7 +945,6 @@
+ if (!(redirect = ast_calloc(1, total_len))) {
+ return;
+ }
+-
+ redirect->dest = redirect->target + target_len;
+ strcpy(redirect->target, target);
+ strcpy(redirect->dest, dest);
+@@ -822,8 +952,8 @@
+ AST_RWLIST_WRLOCK(&uri_redirects);
+
+ target_len--; /* So we can compare directly with strlen() */
+- if (AST_RWLIST_EMPTY(&uri_redirects)
+- || strlen(AST_RWLIST_FIRST(&uri_redirects)->target) <= target_len) {
++ if (AST_RWLIST_EMPTY(&uri_redirects)
++ || strlen(AST_RWLIST_FIRST(&uri_redirects)->target) <= target_len ) {
+ AST_RWLIST_INSERT_HEAD(&uri_redirects, redirect, entry);
+ AST_RWLIST_UNLOCK(&uri_redirects);
+
+@@ -831,11 +961,10 @@
+ }
+
+ AST_RWLIST_TRAVERSE(&uri_redirects, cur, entry) {
+- if (AST_RWLIST_NEXT(cur, entry)
+- && strlen(AST_RWLIST_NEXT(cur, entry)->target) <= target_len) {
++ if (AST_RWLIST_NEXT(cur, entry)
++ && strlen(AST_RWLIST_NEXT(cur, entry)->target) <= target_len ) {
+ AST_RWLIST_INSERT_AFTER(&uri_redirects, cur, redirect, entry);
+- AST_RWLIST_UNLOCK(&uri_redirects);
+-
++ AST_RWLIST_UNLOCK(&uri_redirects);
+ return;
+ }
+ }
+@@ -854,7 +983,6 @@
+ struct hostent *hp;
+ struct ast_hostent ahp;
+ char newprefix[MAX_PREFIX] = "";
+- int have_sslbindaddr = 0;
+ struct http_uri_redirect *redirect;
+ struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
+
+@@ -875,6 +1003,12 @@
+ ast_free(http_tls_cfg.certfile);
+ }
+ http_tls_cfg.certfile = ast_strdup(AST_CERTFILE);
++
++ if (http_tls_cfg.pvtfile) {
++ ast_free(http_tls_cfg.pvtfile);
++ }
++ http_tls_cfg.pvtfile = ast_strdup("");
++
+ if (http_tls_cfg.cipher) {
+ ast_free(http_tls_cfg.cipher);
+ }
+@@ -889,29 +1023,18 @@
+ if (cfg) {
+ v = ast_variable_browse(cfg, "general");
+ for (; v; v = v->next) {
++
++ /* handle tls conf */
++ if (!ast_tls_read_conf(&http_tls_cfg, &https_desc, v->name, v->value)) {
++ continue;
++ }
++
+ if (!strcasecmp(v->name, "enabled")) {
+ enabled = ast_true(v->value);
+- } else if (!strcasecmp(v->name, "sslenable")) {
+- http_tls_cfg.enabled = ast_true(v->value);
+- } else if (!strcasecmp(v->name, "sslbindport")) {
+- https_desc.local_address.sin_port = htons(atoi(v->value));
+- } else if (!strcasecmp(v->name, "sslcert")) {
+- ast_free(http_tls_cfg.certfile);
+- http_tls_cfg.certfile = ast_strdup(v->value);
+- } else if (!strcasecmp(v->name, "sslcipher")) {
+- ast_free(http_tls_cfg.cipher);
+- http_tls_cfg.cipher = ast_strdup(v->value);
+ } else if (!strcasecmp(v->name, "enablestatic")) {
+ newenablestatic = ast_true(v->value);
+ } else if (!strcasecmp(v->name, "bindport")) {
+ http_desc.local_address.sin_port = htons(atoi(v->value));
+- } else if (!strcasecmp(v->name, "sslbindaddr")) {
+- if ((hp = ast_gethostbyname(v->value, &ahp))) {
+- memcpy(&https_desc.local_address.sin_addr, hp->h_addr, sizeof(https_desc.local_address.sin_addr));
+- have_sslbindaddr = 1;
+- } else {
+- ast_log(LOG_WARNING, "Invalid bind address '%s'\n", v->value);
+- }
+ } else if (!strcasecmp(v->name, "bindaddr")) {
+ if ((hp = ast_gethostbyname(v->value, &ahp))) {
+ memcpy(&http_desc.local_address.sin_addr, hp->h_addr, sizeof(http_desc.local_address.sin_addr));
+@@ -934,8 +1057,8 @@
+
+ ast_config_destroy(cfg);
+ }
+-
+- if (!have_sslbindaddr) {
++ /* if the https addres has not been set, default is the same as non secure http */
++ if (!https_desc.local_address.sin_addr.s_addr) {
+ https_desc.local_address.sin_addr = http_desc.local_address.sin_addr;
+ }
+ if (enabled) {
+@@ -961,14 +1084,14 @@
+ switch (cmd) {
+ case CLI_INIT:
+ e->command = "http show status";
+- e->usage =
++ e->usage =
+ "Usage: http show status\n"
+ " Lists status of internal HTTP engine\n";
+ return NULL;
+ case CLI_GENERATE:
+ return NULL;
+ }
+-
++
+ if (a->argc != 3) {
+ return CLI_SHOWUSAGE;
+ }
+@@ -992,17 +1115,15 @@
+ if (AST_RWLIST_EMPTY(&uris)) {
+ ast_cli(a->fd, "None.\n");
+ } else {
+- AST_RWLIST_TRAVERSE(&uris, urih, entry) {
+- ast_cli(a->fd, "%s/%s%s => %s\n", prefix, urih->uri, (urih->has_subtree ? "/..." : ""), urih->description);
+- }
++ AST_RWLIST_TRAVERSE(&uris, urih, entry)
++ ast_cli(a->fd, "%s/%s%s => %s\n", prefix, urih->uri, (urih->has_subtree ? "/..." : "" ), urih->description);
+ }
+ AST_RWLIST_UNLOCK(&uris);
+
+ ast_cli(a->fd, "\nEnabled Redirects:\n");
+ AST_RWLIST_RDLOCK(&uri_redirects);
+- AST_RWLIST_TRAVERSE(&uri_redirects, redirect, entry) {
++ AST_RWLIST_TRAVERSE(&uri_redirects, redirect, entry)
+ ast_cli(a->fd, " %s => %s\n", redirect->target, redirect->dest);
+- }
+ if (AST_RWLIST_EMPTY(&uri_redirects)) {
+ ast_cli(a->fd, " None.\n");
+ }
+Index: main/app.c
+===================================================================
+--- a/main/app.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/main/app.c (.../trunk) (revision 202568)
+@@ -180,7 +180,7 @@
+ /* The lock type used by ast_lock_path() / ast_unlock_path() */
+ static enum AST_LOCK_TYPE ast_lock_type = AST_LOCK_TYPE_LOCKFILE;
+
+-int ast_app_getdata_full(struct ast_channel *c, char *prompt, char *s, int maxlen, int timeout, int audiofd, int ctrlfd)
++int ast_app_getdata_full(struct ast_channel *c, const char *prompt, char *s, int maxlen, int timeout, int audiofd, int ctrlfd)
+ {
+ int res, to = 2000, fto = 6000;
+
+@@ -203,6 +203,28 @@
+ return res;
+ }
+
++int ast_app_run_macro(struct ast_channel *autoservice_chan, struct ast_channel *macro_chan, const char * const macro_name, const char * const macro_args)
++{
++ struct ast_app *macro_app;
++ int res;
++ char buf[1024];
++
++ macro_app = pbx_findapp("Macro");
++ if (!macro_app) {
++ ast_log(LOG_WARNING, "Cannot run macro '%s' because the 'Macro' application in not available\n", macro_name);
++ return -1;
++ }
++ snprintf(buf, sizeof(buf), "%s%s%s", macro_name, ast_strlen_zero(macro_args) ? "" : ",", S_OR(macro_args, ""));
++ if (autoservice_chan) {
++ ast_autoservice_start(autoservice_chan);
++ }
++ res = pbx_exec(macro_chan, macro_app, buf);
++ if (autoservice_chan) {
++ ast_autoservice_stop(autoservice_chan);
++ }
++ return res;
++}
++
+ static int (*ast_has_voicemail_func)(const char *mailbox, const char *folder) = NULL;
+ static int (*ast_inboxcount_func)(const char *mailbox, int *newmsgs, int *oldmsgs) = NULL;
+ static int (*ast_inboxcount2_func)(const char *mailbox, int *urgentmsgs, int *newmsgs, int *oldmsgs) = NULL;
+@@ -949,8 +971,8 @@
+ return res;
+ }
+
+-static char default_acceptdtmf[] = "#";
+-static char default_canceldtmf[] = "";
++static const char default_acceptdtmf[] = "#";
++static const char default_canceldtmf[] = "";
+
+ int ast_play_and_record_full(struct ast_channel *chan, const char *playfile, const char *recordfile, int maxtime, const char *fmt, int *duration, int silencethreshold, int maxsilence, const char *path, const char *acceptdtmf, const char *canceldtmf)
+ {
+Index: main/image.c
+===================================================================
+--- a/main/image.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/main/image.c (.../trunk) (revision 202568)
+@@ -81,7 +81,7 @@
+ return 0;
+ }
+
+-static void make_filename(char *buf, int len, char *filename, const char *preflang, char *ext)
++static void make_filename(char *buf, int len, const char *filename, const char *preflang, char *ext)
+ {
+ if (filename[0] == '/') {
+ if (!ast_strlen_zero(preflang))
+@@ -96,7 +96,7 @@
+ }
+ }
+
+-struct ast_frame *ast_read_image(char *filename, const char *preflang, int format)
++struct ast_frame *ast_read_image(const char *filename, const char *preflang, int format)
+ {
+ struct ast_imager *i;
+ char buf[256];
+@@ -152,7 +152,7 @@
+ return f;
+ }
+
+-int ast_send_image(struct ast_channel *chan, char *filename)
++int ast_send_image(struct ast_channel *chan, const char *filename)
+ {
+ struct ast_frame *f;
+ int res = -1;
+@@ -197,7 +197,7 @@
+ return CLI_SUCCESS;
+ }
+
+-struct ast_cli_entry cli_image[] = {
++static struct ast_cli_entry cli_image[] = {
+ AST_CLI_DEFINE(handle_core_show_image_formats, "Displays image formats")
+ };
+
+Index: main/db.c
+===================================================================
+--- a/main/db.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/main/db.c (.../trunk) (revision 202568)
+@@ -48,6 +48,58 @@
+ #include "asterisk/manager.h"
+ #include "db1-ast/include/db.h"
+
++/*** DOCUMENTATION
++ <manager name="DBGet" language="en_US">
++ <synopsis>
++ Get DB Entry.
++ </synopsis>
++ <syntax>
++ <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
++ <parameter name="Family" required="true" />
++ <parameter name="Key" required="true" />
++ </syntax>
++ <description>
++ </description>
++ </manager>
++ <manager name="DBPut" language="en_US">
++ <synopsis>
++ Put DB entry.
++ </synopsis>
++ <syntax>
++ <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
++ <parameter name="Family" required="true" />
++ <parameter name="Key" required="true" />
++ <parameter name="Val" />
++ </syntax>
++ <description>
++ </description>
++ </manager>
++ <manager name="DBDel" language="en_US">
++ <synopsis>
++ Delete DB entry.
++ </synopsis>
++ <syntax>
++ <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
++ <parameter name="Family" required="true" />
++ <parameter name="Key" required="true" />
++ </syntax>
++ <description>
++ </description>
++ </manager>
++ <manager name="DBDelTree" language="en_US">
++ <synopsis>
++ Delete DB Tree.
++ </synopsis>
++ <syntax>
++ <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
++ <parameter name="Family" required="true" />
++ <parameter name="Key" />
++ </syntax>
++ <description>
++ </description>
++ </manager>
++ ***/
++
+ static DB *astdb;
+ AST_MUTEX_DEFINE_STATIC(dblock);
+
+@@ -542,7 +594,7 @@
+ }
+ }
+
+-struct ast_cli_entry cli_database[] = {
++static struct ast_cli_entry cli_database[] = {
+ AST_CLI_DEFINE(handle_cli_database_show, "Shows database contents"),
+ AST_CLI_DEFINE(handle_cli_database_showkey, "Shows database contents"),
+ AST_CLI_DEFINE(handle_cli_database_get, "Gets database value"),
+@@ -666,9 +718,9 @@
+ {
+ dbinit();
+ 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");
+- ast_manager_register("DBDelTree", EVENT_FLAG_SYSTEM, manager_dbdeltree, "Delete DB Tree");
++ ast_manager_register_xml("DBGet", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, manager_dbget);
++ ast_manager_register_xml("DBPut", EVENT_FLAG_SYSTEM, manager_dbput);
++ ast_manager_register_xml("DBDel", EVENT_FLAG_SYSTEM, manager_dbdel);
++ ast_manager_register_xml("DBDelTree", EVENT_FLAG_SYSTEM, manager_dbdeltree);
+ return 0;
+ }
+Index: main/ast_expr2.fl
+===================================================================
+--- a/main/ast_expr2.fl (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/main/ast_expr2.fl (.../trunk) (revision 202568)
+@@ -313,7 +313,7 @@
+ extra_error_message[0] = 0;
+ }
+
+-static char *expr2_token_equivs1[] =
++static const char * const expr2_token_equivs1[] =
+ {
+ "TOKEN",
+ "TOK_COND",
+@@ -339,7 +339,7 @@
+ "TOK_LP"
+ };
+
+-static char *expr2_token_equivs2[] =
++static const char * const expr2_token_equivs2[] =
+ {
+ "<token>",
+ "?",
+Index: main/Makefile
+===================================================================
+--- a/main/Makefile (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/main/Makefile (.../trunk) (revision 202568)
+@@ -17,29 +17,15 @@
+
+ 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 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 \
+- astmm.o astfd.o enum.o srv.o dns.o aescrypt.o aestab.o aeskey.o \
+- utils.o plc.o jitterbuf.o dnsmgr.o devicestate.o \
+- netsock.o slinfactory.o ast_expr2.o ast_expr2f.o \
+- 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 xml.o xmldoc.o \
+- strings.o bridging.o poll.o
++SRC=$(wildcard *.c)
++OBJSFILTER=fskmodem_int.o fskmodem_float.o cygload.o buildinfo.o
++OBJS=$(filter-out $(OBJSFILTER),$(SRC:.c=.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
+ # objects use it.
+ OBJS+=stdtime/localtime.o
+
+-# At the moment say.o is an optional component which can be overridden
+-# by a module.
+-OBJS+=say.o
+-
+ AST_LIBS += $(OPENSSL_LIB)
+ AST_LIBS += $(BKTR_LIB)
+ AST_LIBS += $(LIBXML2_LIB)
+@@ -58,9 +44,7 @@
+
+ ifneq ($(findstring darwin,$(OSARCH)),)
+ AST_LIBS+=-lresolv
+- ifneq ($(findstring LOADABLE_MODULES,$(MENUSELECT_CFLAGS)),)
+- ASTLINK=-Wl,-dynamic
+- endif
++ ASTLINK=-undefined suppress -force_flat_namespace
+ else
+ # These are used for all but Darwin
+ ifneq ($(findstring LOADABLE_MODULES,$(MENUSELECT_CFLAGS)),)
+@@ -103,6 +87,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 +151,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/slinfactory.c
+===================================================================
+--- a/main/slinfactory.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/main/slinfactory.c (.../trunk) (revision 202568)
+@@ -73,7 +73,7 @@
+ int ast_slinfactory_feed(struct ast_slinfactory *sf, struct ast_frame *f)
+ {
+ struct ast_frame *begin_frame = f, *duped_frame = NULL, *frame_ptr;
+- unsigned int x;
++ unsigned int x = 0;
+
+ /* In some cases, we can be passed a frame which has no data in it, but
+ * which has a positive number of samples defined. Once such situation is
+@@ -100,15 +100,17 @@
+ sf->format = f->subclass;
+ }
+
+- if (!(begin_frame = ast_translate(sf->trans, f, 0)))
++ if (!(begin_frame = ast_translate(sf->trans, f, 0))) {
+ return 0;
++ }
+
+- duped_frame = ast_frdup(begin_frame);
++ if (!(duped_frame = ast_frisolate(begin_frame))) {
++ return 0;
++ }
+
+- ast_frfree(begin_frame);
+-
+- if (!duped_frame)
+- return 0;
++ if (duped_frame != begin_frame) {
++ ast_frfree(begin_frame);
++ }
+ } else {
+ if (sf->trans) {
+ ast_translator_free_path(sf->trans);
+@@ -118,15 +120,18 @@
+ return 0;
+ }
+
+- x = 0;
+ AST_LIST_TRAVERSE(&sf->queue, frame_ptr, frame_list) {
+ x++;
+ }
+
+- AST_LIST_INSERT_TAIL(&sf->queue, duped_frame, frame_list);
++ /* if the frame was translated, the translator may have returned multiple
++ frames, so process each of them
++ */
++ for (begin_frame = duped_frame; begin_frame; begin_frame = AST_LIST_NEXT(begin_frame, frame_list)) {
++ AST_LIST_INSERT_TAIL(&sf->queue, begin_frame, frame_list);
++ sf->size += begin_frame->samples;
++ }
+
+- sf->size += duped_frame->samples;
+-
+ return x;
+ }
+
+Index: main/ast_expr2.c
+===================================================================
+--- a/main/ast_expr2.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/main/ast_expr2.c (.../trunk) (revision 202568)
+@@ -2415,6 +2415,7 @@
+ free_value (struct val *vp)
+ {
+ if (vp==NULL) {
++ free(vp);
+ return;
+ }
+ if (vp->type == AST_EXPR_string || vp->type == AST_EXPR_numeric_string)
+Index: main/db1-ast/recno/rec_open.c
+===================================================================
+--- a/main/db1-ast/recno/rec_open.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/main/db1-ast/recno/rec_open.c (.../trunk) (revision 202568)
+@@ -169,7 +169,7 @@
+ t->bt_msize = sb.st_size;
+ if ((t->bt_smap = mmap(NULL, t->bt_msize,
+ PROT_READ, MAP_PRIVATE, rfd,
+- (off_t)0)) == (caddr_t)-1)
++ (off_t)0)) == MAP_FAILED
+ goto slow;
+ t->bt_cmap = t->bt_smap;
+ t->bt_emap = t->bt_smap + sb.st_size;
+Index: main/abstract_jb.c
+===================================================================
+--- a/main/abstract_jb.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/main/abstract_jb.c (.../trunk) (revision 202568)
+@@ -110,8 +110,7 @@
+ static void jb_empty_and_reset_adaptive(void *jb);
+
+ /* Available jb implementations */
+-static struct ast_jb_impl avail_impl[] =
+-{
++static const struct ast_jb_impl avail_impl[] = {
+ {
+ .name = "fixed",
+ .create = jb_create_fixed,
+@@ -150,13 +149,13 @@
+ };
+
+ /* Translations between impl and abstract return codes */
+-static int fixed_to_abstract_code[] =
++static const int fixed_to_abstract_code[] =
+ {JB_IMPL_OK, JB_IMPL_DROP, JB_IMPL_INTERP, JB_IMPL_NOFRAME};
+-static int adaptive_to_abstract_code[] =
++static const int adaptive_to_abstract_code[] =
+ {JB_IMPL_OK, JB_IMPL_NOFRAME, JB_IMPL_NOFRAME, JB_IMPL_INTERP, JB_IMPL_DROP, JB_IMPL_OK};
+
+ /* JB_GET actions (used only for the frames log) */
+-static char *jb_get_actions[] = {"Delivered", "Dropped", "Interpolated", "No"};
++static const char * const jb_get_actions[] = {"Delivered", "Dropped", "Interpolated", "No"};
+
+ /*! \brief Macros for the frame log files */
+ #define jb_framelog(...) do { \
+@@ -181,7 +180,7 @@
+ {
+ struct ast_jb *jb = &chan->jb;
+ struct ast_jb_conf *jbconf = &jb->conf;
+- struct ast_jb_impl *test_impl;
++ const struct ast_jb_impl *test_impl;
+ int i, avail_impl_count = ARRAY_LEN(avail_impl);
+
+ jb->impl = &avail_impl[default_impl];
+@@ -303,7 +302,7 @@
+ int ast_jb_put(struct ast_channel *chan, struct ast_frame *f)
+ {
+ struct ast_jb *jb = &chan->jb;
+- struct ast_jb_impl *jbimpl = jb->impl;
++ const struct ast_jb_impl *jbimpl = jb->impl;
+ void *jbobj = jb->jbobj;
+ struct ast_frame *frr;
+ long now = 0;
+@@ -385,7 +384,7 @@
+ static void jb_get_and_deliver(struct ast_channel *chan)
+ {
+ struct ast_jb *jb = &chan->jb;
+- struct ast_jb_impl *jbimpl = jb->impl;
++ const struct ast_jb_impl *jbimpl = jb->impl;
+ void *jbobj = jb->jbobj;
+ struct ast_frame *f, finterp;
+ long now;
+@@ -450,7 +449,7 @@
+ {
+ struct ast_jb *jb = &chan->jb;
+ struct ast_jb_conf *jbconf = &jb->conf;
+- struct ast_jb_impl *jbimpl = jb->impl;
++ const struct ast_jb_impl *jbimpl = jb->impl;
+ void *jbobj;
+ struct ast_channel *bridged;
+ long now;
+@@ -534,7 +533,7 @@
+ void ast_jb_destroy(struct ast_channel *chan)
+ {
+ struct ast_jb *jb = &chan->jb;
+- struct ast_jb_impl *jbimpl = jb->impl;
++ const struct ast_jb_impl *jbimpl = jb->impl;
+ void *jbobj = jb->jbobj;
+ struct ast_frame *f;
+
+Index: main/event.c
+===================================================================
+--- a/main/event.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/main/event.c (.../trunk) (revision 202568)
+@@ -39,7 +39,7 @@
+ #include "asterisk/taskprocessor.h"
+ #include "asterisk/astobj2.h"
+
+-struct ast_taskprocessor *event_dispatcher;
++static struct ast_taskprocessor *event_dispatcher;
+
+ /*!
+ * \brief An event information element
+@@ -311,6 +311,7 @@
+ ast_free(ie_val->payload.raw);
+ break;
+ case AST_EVENT_IE_PLTYPE_UINT:
++ case AST_EVENT_IE_PLTYPE_BITFLAGS:
+ case AST_EVENT_IE_PLTYPE_EXISTS:
+ case AST_EVENT_IE_PLTYPE_UNKNOWN:
+ break;
+@@ -339,60 +340,104 @@
+ ie_type = va_arg(ap, enum ast_event_type))
+ {
+ struct ast_event_ie_val *ie_value = alloca(sizeof(*ie_value));
++ int insert = 1;
+ memset(ie_value, 0, sizeof(*ie_value));
+ ie_value->ie_type = ie_type;
+ ie_value->ie_pltype = va_arg(ap, enum ast_event_ie_pltype);
+- if (ie_value->ie_pltype == AST_EVENT_IE_PLTYPE_UINT)
++ switch (ie_value->ie_pltype) {
++ case AST_EVENT_IE_PLTYPE_UINT:
+ ie_value->payload.uint = va_arg(ap, uint32_t);
+- else if (ie_value->ie_pltype == AST_EVENT_IE_PLTYPE_STR)
+- ie_value->payload.str = ast_strdupa(va_arg(ap, const char *));
+- else if (ie_value->ie_pltype == AST_EVENT_IE_PLTYPE_RAW) {
++ break;
++ case AST_EVENT_IE_PLTYPE_BITFLAGS:
++ ie_value->payload.uint = va_arg(ap, uint32_t);
++ break;
++ case AST_EVENT_IE_PLTYPE_STR:
++ ie_value->payload.str = 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);
+ ie_value->payload.raw = alloca(datalen);
+ memcpy(ie_value->payload.raw, data, datalen);
+ ie_value->raw_datalen = datalen;
++ break;
+ }
+- AST_LIST_INSERT_TAIL(&ie_vals, ie_value, entry);
++ case AST_EVENT_IE_PLTYPE_UNKNOWN:
++ insert = 0;
++ case AST_EVENT_IE_PLTYPE_EXISTS:
++ break;
++ }
++
++ if (insert) {
++ AST_LIST_INSERT_TAIL(&ie_vals, ie_value, entry);
++ }
+ }
+ va_end(ap);
+
+ AST_RWDLLIST_RDLOCK(&ast_event_subs[type]);
+ AST_RWDLLIST_TRAVERSE(&ast_event_subs[type], sub, entry) {
+ AST_LIST_TRAVERSE(&ie_vals, ie_val, entry) {
++ int break_out = 0;
++
+ AST_LIST_TRAVERSE(&sub->ie_vals, sub_ie_val, entry) {
+- if (sub_ie_val->ie_type == ie_val->ie_type)
++ if (sub_ie_val->ie_type == ie_val->ie_type) {
+ break;
++ }
+ }
++
+ if (!sub_ie_val) {
+- if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_EXISTS)
+- break;
++ /* This subscriber doesn't care about this IE, so consider
++ * it matched. */
+ continue;
+ }
+- /* The subscriber doesn't actually care what the value is */
+- if (sub_ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_EXISTS)
+- continue;
+- if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_UINT &&
+- ie_val->payload.uint != sub_ie_val->payload.uint)
++
++ switch (ie_val->ie_pltype) {
++ case AST_EVENT_IE_PLTYPE_UINT:
++ break_out = (ie_val->payload.uint != sub_ie_val->payload.uint);
+ break;
+- if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_STR &&
+- strcmp(ie_val->payload.str, sub_ie_val->payload.str))
++ case AST_EVENT_IE_PLTYPE_BITFLAGS:
++ /* if the subscriber has requested *any* of the bitflags we are providing,
++ * then it's a match
++ */
++ break_out = (ie_val->payload.uint & sub_ie_val->payload.uint);
+ break;
+- if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_RAW &&
+- memcmp(ie_val->payload.raw, sub_ie_val->payload.raw, ie_val->raw_datalen))
++ case AST_EVENT_IE_PLTYPE_STR:
++ break_out = strcmp(ie_val->payload.str, sub_ie_val->payload.str);
+ break;
++ case AST_EVENT_IE_PLTYPE_RAW:
++ break_out = memcmp(ie_val->payload.raw,
++ sub_ie_val->payload.raw, ie_val->raw_datalen);
++ break;
++ case AST_EVENT_IE_PLTYPE_EXISTS:
++ /* The subscriber doesn't actually care what the value is */
++ break_out = 1;
++ break;
++ case AST_EVENT_IE_PLTYPE_UNKNOWN:
++ break;
++ }
++
++ if (break_out) {
++ break;
++ }
+ }
+- if (!ie_val)
++
++ if (!ie_val) {
++ /* Everything matched */
+ break;
++ }
+ }
+ AST_RWDLLIST_UNLOCK(&ast_event_subs[type]);
+
+- if (sub) /* All parameters were matched */
++ if (sub) {
++ /* All parameters were matched */
+ return AST_EVENT_SUB_EXISTS;
++ }
+
+ AST_RWDLLIST_RDLOCK(&ast_event_subs[AST_EVENT_ALL]);
+- if (!AST_DLLIST_EMPTY(&ast_event_subs[AST_EVENT_ALL]))
++ if (!AST_DLLIST_EMPTY(&ast_event_subs[AST_EVENT_ALL])) {
+ res = AST_EVENT_SUB_EXISTS;
++ }
+ AST_RWDLLIST_UNLOCK(&ast_event_subs[AST_EVENT_ALL]);
+
+ return res;
+@@ -401,14 +446,26 @@
+ 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) {
++ switch (ie_val->ie_pltype) {
++ case AST_EVENT_IE_PLTYPE_UINT:
++ {
+ uint32_t val = event2 ? ast_event_get_ie_uint(event2, ie_val->ie_type) : ie_val->payload.uint;
+- if (val == ast_event_get_ie_uint(event, ie_val->ie_type))
+- return 1;
+- return 0;
++
++ return (val == ast_event_get_ie_uint(event, ie_val->ie_type)) ? 1 : 0;
+ }
+
+- if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_STR) {
++ case AST_EVENT_IE_PLTYPE_BITFLAGS:
++ {
++ uint32_t flags = event2 ? ast_event_get_ie_uint(event2, ie_val->ie_type) : ie_val->payload.uint;
++
++ /* if the subscriber has requested *any* of the bitflags that this event provides,
++ * then it's a match
++ */
++ return (flags & ast_event_get_ie_bitflags(event, ie_val->ie_type)) ? 1 : 0;
++ }
++
++ case AST_EVENT_IE_PLTYPE_STR:
++ {
+ const char *str;
+ uint32_t hash;
+
+@@ -425,16 +482,19 @@
+ return 0;
+ }
+
+- if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_RAW) {
++ case AST_EVENT_IE_PLTYPE_RAW:
++ {
+ const void *buf = event2 ? ast_event_get_ie_raw(event2, ie_val->ie_type) : ie_val->payload.raw;
+- if (buf && !memcmp(buf, ast_event_get_ie_raw(event, ie_val->ie_type), ie_val->raw_datalen))
+- return 1;
+- return 0;
++
++ return (buf && !memcmp(buf, ast_event_get_ie_raw(event, ie_val->ie_type), ie_val->raw_datalen)) ? 1 : 0;
+ }
+
+- if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_EXISTS) {
+- if (ast_event_get_ie_raw(event, ie_val->ie_type))
+- return 1;
++ case AST_EVENT_IE_PLTYPE_EXISTS:
++ {
++ return ast_event_get_ie_raw(event, ie_val->ie_type) ? 1 : 0;
++ }
++
++ case AST_EVENT_IE_PLTYPE_UNKNOWN:
+ return 0;
+ }
+
+@@ -492,6 +552,9 @@
+ case AST_EVENT_IE_PLTYPE_UINT:
+ ast_event_append_ie_uint(&event, ie_val->ie_type, ie_val->payload.uint);
+ break;
++ case AST_EVENT_IE_PLTYPE_BITFLAGS:
++ ast_event_append_ie_bitflags(&event, ie_val->ie_type, ie_val->payload.uint);
++ break;
+ case AST_EVENT_IE_PLTYPE_STR:
+ ast_event_append_ie_str(&event, ie_val->ie_type, ie_val->payload.str);
+ break;
+@@ -529,13 +592,15 @@
+
+ AST_RWDLLIST_RDLOCK(&ast_event_subs[event_type]);
+ AST_RWDLLIST_TRAVERSE(&ast_event_subs[event_type], sub, entry) {
+- if (event_sub == sub)
++ if (event_sub == sub) {
+ continue;
++ }
+
+ event = gen_sub_event(sub);
+
+- if (!event)
++ if (!event) {
+ continue;
++ }
+
+ event_sub->cb(event, event_sub->userdata);
+
+@@ -544,7 +609,7 @@
+ AST_RWDLLIST_UNLOCK(&ast_event_subs[event_type]);
+ }
+
+-struct ast_event_sub *ast_event_subscribe_new(enum ast_event_type type,
++struct ast_event_sub *ast_event_subscribe_new(enum ast_event_type type,
+ ast_event_cb_t cb, void *userdata)
+ {
+ struct ast_event_sub *sub;
+@@ -554,8 +619,9 @@
+ return NULL;
+ }
+
+- if (!(sub = ast_calloc(1, sizeof(*sub))))
++ if (!(sub = ast_calloc(1, sizeof(*sub)))) {
+ return NULL;
++ }
+
+ sub->type = type;
+ sub->cb = cb;
+@@ -570,11 +636,13 @@
+ {
+ struct ast_event_ie_val *ie_val;
+
+- if (ie_type < 0 || ie_type > AST_EVENT_IE_MAX)
++ if (ie_type < 0 || ie_type > AST_EVENT_IE_MAX) {
+ return -1;
++ }
+
+- if (!(ie_val = ast_calloc(1, sizeof(*ie_val))))
++ if (!(ie_val = ast_calloc(1, sizeof(*ie_val)))) {
+ return -1;
++ }
+
+ ie_val->ie_type = ie_type;
+ ie_val->payload.uint = unsigned_int;
+@@ -585,8 +653,8 @@
+ return 0;
+ }
+
+-int ast_event_sub_append_ie_exists(struct ast_event_sub *sub,
+- enum ast_event_ie_type ie_type)
++int ast_event_sub_append_ie_bitflags(struct ast_event_sub *sub,
++ enum ast_event_ie_type ie_type, uint32_t flags)
+ {
+ struct ast_event_ie_val *ie_val;
+
+@@ -597,6 +665,28 @@
+ return -1;
+
+ ie_val->ie_type = ie_type;
++ ie_val->payload.uint = flags;
++ ie_val->ie_pltype = AST_EVENT_IE_PLTYPE_BITFLAGS;
++
++ AST_LIST_INSERT_TAIL(&sub->ie_vals, ie_val, entry);
++
++ return 0;
++}
++
++int ast_event_sub_append_ie_exists(struct ast_event_sub *sub,
++ enum ast_event_ie_type ie_type)
++{
++ struct ast_event_ie_val *ie_val;
++
++ if (ie_type < 0 || ie_type > AST_EVENT_IE_MAX) {
++ return -1;
++ }
++
++ if (!(ie_val = ast_calloc(1, sizeof(*ie_val)))) {
++ return -1;
++ }
++
++ ie_val->ie_type = ie_type;
+ ie_val->ie_pltype = AST_EVENT_IE_PLTYPE_EXISTS;
+
+ AST_LIST_INSERT_TAIL(&sub->ie_vals, ie_val, entry);
+@@ -604,16 +694,18 @@
+ return 0;
+ }
+
+-int ast_event_sub_append_ie_str(struct ast_event_sub *sub,
++int ast_event_sub_append_ie_str(struct ast_event_sub *sub,
+ enum ast_event_ie_type ie_type, const char *str)
+ {
+ struct ast_event_ie_val *ie_val;
+
+- if (ie_type < 0 || ie_type > AST_EVENT_IE_MAX)
++ if (ie_type < 0 || ie_type > AST_EVENT_IE_MAX) {
+ return -1;
++ }
+
+- if (!(ie_val = ast_calloc(1, sizeof(*ie_val))))
++ if (!(ie_val = ast_calloc(1, sizeof(*ie_val)))) {
+ return -1;
++ }
+
+ ie_val->ie_type = ie_type;
+ ie_val->ie_pltype = AST_EVENT_IE_PLTYPE_STR;
+@@ -630,16 +722,18 @@
+ return 0;
+ }
+
+-int ast_event_sub_append_ie_raw(struct ast_event_sub *sub,
++int ast_event_sub_append_ie_raw(struct ast_event_sub *sub,
+ enum ast_event_ie_type ie_type, void *data, size_t raw_datalen)
+ {
+ struct ast_event_ie_val *ie_val;
+
+- if (ie_type < 0 || ie_type > AST_EVENT_IE_MAX)
++ if (ie_type < 0 || ie_type > AST_EVENT_IE_MAX) {
+ return -1;
++ }
+
+- if (!(ie_val = ast_calloc(1, sizeof(*ie_val))))
++ if (!(ie_val = ast_calloc(1, sizeof(*ie_val)))) {
+ return -1;
++ }
+
+ ie_val->ie_type = ie_type;
+ ie_val->ie_pltype = AST_EVENT_IE_PLTYPE_RAW;
+@@ -666,8 +760,9 @@
+
+ event = gen_sub_event(sub);
+
+- if (event)
++ if (event) {
+ ast_event_queue(event);
++ }
+ }
+
+ AST_RWDLLIST_WRLOCK(&ast_event_subs[sub->type]);
+@@ -677,15 +772,16 @@
+ return 0;
+ }
+
+-struct ast_event_sub *ast_event_subscribe(enum ast_event_type type, ast_event_cb_t cb,
++struct ast_event_sub *ast_event_subscribe(enum ast_event_type type, ast_event_cb_t cb,
+ void *userdata, ...)
+ {
+ va_list ap;
+ enum ast_event_ie_type ie_type;
+ struct ast_event_sub *sub;
+
+- if (!(sub = ast_event_subscribe_new(type, cb, userdata)))
++ if (!(sub = ast_event_subscribe_new(type, cb, userdata))) {
+ return NULL;
++ }
+
+ va_start(ap, userdata);
+ for (ie_type = va_arg(ap, enum ast_event_type);
+@@ -705,6 +801,12 @@
+ ast_event_sub_append_ie_uint(sub, ie_type, unsigned_int);
+ break;
+ }
++ case AST_EVENT_IE_PLTYPE_BITFLAGS:
++ {
++ uint32_t unsigned_int = va_arg(ap, uint32_t);
++ ast_event_sub_append_ie_bitflags(sub, ie_type, unsigned_int);
++ break;
++ }
+ case AST_EVENT_IE_PLTYPE_STR:
+ {
+ const char *str = va_arg(ap, const char *);
+@@ -734,8 +836,9 @@
+ {
+ struct ast_event_ie_val *ie_val;
+
+- while ((ie_val = AST_LIST_REMOVE_HEAD(&sub->ie_vals, entry)))
++ while ((ie_val = AST_LIST_REMOVE_HEAD(&sub->ie_vals, entry))) {
+ ast_event_ie_val_destroy(ie_val);
++ }
+
+ ast_free(sub);
+ }
+@@ -751,14 +854,15 @@
+ if (ast_event_check_subscriber(AST_EVENT_UNSUB,
+ AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, sub->type,
+ AST_EVENT_IE_END) != AST_EVENT_SUB_NONE) {
+-
++
+ event = ast_event_new(AST_EVENT_UNSUB,
+ AST_EVENT_IE_UNIQUEID, AST_EVENT_IE_PLTYPE_UINT, sub->uniqueid,
+ AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, sub->type,
+ AST_EVENT_IE_END);
+
+- if (event)
++ if (event) {
+ ast_event_queue(event);
++ }
+ }
+
+ ast_event_sub_destroy(sub);
+@@ -771,7 +875,6 @@
+ iterator->event_len = ntohs(event->event_len);
+ iterator->event = event;
+ iterator->ie = (struct ast_event_ie *) ( ((char *) event) + sizeof(*event) );
+- return;
+ }
+
+ int ast_event_iterator_next(struct ast_event_iterator *iterator)
+@@ -790,6 +893,11 @@
+ return ntohl(get_unaligned_uint32(iterator->ie->ie_payload));
+ }
+
++uint32_t ast_event_iterator_get_ie_bitflags(struct ast_event_iterator *iterator)
++{
++ return ntohl(get_unaligned_uint32(iterator->ie->ie_payload));
++}
++
+ const char *ast_event_iterator_get_ie_str(struct ast_event_iterator *iterator)
+ {
+ const struct ast_event_ie_str_payload *str_payload;
+@@ -818,6 +926,15 @@
+ return ie_val ? ntohl(get_unaligned_uint32(ie_val)) : 0;
+ }
+
++uint32_t ast_event_get_ie_bitflags(const struct ast_event *event, enum ast_event_ie_type ie_type)
++{
++ const uint32_t *ie_val;
++
++ ie_val = ast_event_get_ie_raw(event, ie_type);
++
++ 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;
+@@ -842,8 +959,9 @@
+ int res = 0;
+
+ for (ast_event_iterator_init(&iterator, event); !res; res = ast_event_iterator_next(&iterator)) {
+- if (ast_event_iterator_get_ie_type(&iterator) == ie_type)
++ if (ast_event_iterator_get_ie_type(&iterator) == ie_type) {
+ return ast_event_iterator_get_ie_raw(&iterator);
++ }
+ }
+
+ return NULL;
+@@ -871,6 +989,13 @@
+ return ast_event_append_ie_raw(event, ie_type, &data, sizeof(data));
+ }
+
++int ast_event_append_ie_bitflags(struct ast_event **event, enum ast_event_ie_type ie_type,
++ uint32_t flags)
++{
++ flags = htonl(flags);
++ return ast_event_append_ie_raw(event, ie_type, &flags, sizeof(flags));
++}
++
+ int ast_event_append_ie_raw(struct ast_event **event, enum ast_event_ie_type ie_type,
+ const void *data, size_t data_len)
+ {
+@@ -881,8 +1006,9 @@
+ event_len = ntohs((*event)->event_len);
+ extra_len = sizeof(*ie) + data_len;
+
+- if (!(*event = ast_realloc(*event, event_len + extra_len)))
++ if (!(*event = ast_realloc(*event, event_len + extra_len))) {
+ return -1;
++ }
+
+ ie = (struct ast_event_ie *) ( ((char *) *event) + event_len );
+ ie->ie_type = htons(ie_type);
+@@ -915,40 +1041,76 @@
+ ie_type = va_arg(ap, enum ast_event_type))
+ {
+ struct ast_event_ie_val *ie_value = alloca(sizeof(*ie_value));
++ int insert = 1;
+ memset(ie_value, 0, sizeof(*ie_value));
+ ie_value->ie_type = ie_type;
+ ie_value->ie_pltype = va_arg(ap, enum ast_event_ie_pltype);
+- if (ie_value->ie_pltype == AST_EVENT_IE_PLTYPE_UINT)
++ switch (ie_value->ie_pltype) {
++ case AST_EVENT_IE_PLTYPE_UINT:
+ ie_value->payload.uint = va_arg(ap, uint32_t);
+- else if (ie_value->ie_pltype == AST_EVENT_IE_PLTYPE_STR)
+- ie_value->payload.str = ast_strdupa(va_arg(ap, const char *));
+- else if (ie_value->ie_pltype == AST_EVENT_IE_PLTYPE_RAW) {
++ break;
++ case AST_EVENT_IE_PLTYPE_BITFLAGS:
++ ie_value->payload.uint = va_arg(ap, uint32_t);
++ break;
++ case AST_EVENT_IE_PLTYPE_STR:
++ ie_value->payload.str = 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);
+ ie_value->payload.raw = alloca(datalen);
+ memcpy(ie_value->payload.raw, data, datalen);
+ ie_value->raw_datalen = datalen;
++ break;
+ }
+- AST_LIST_INSERT_TAIL(&ie_vals, ie_value, entry);
++ case AST_EVENT_IE_PLTYPE_UNKNOWN:
++ insert = 0;
++ break;
++ case AST_EVENT_IE_PLTYPE_EXISTS:
++ break;
++ }
++
++ if (insert) {
++ AST_LIST_INSERT_TAIL(&ie_vals, ie_value, entry);
++ }
+ }
+ va_end(ap);
+
+- if (!(event = ast_calloc(1, sizeof(*event))))
++ if (!(event = ast_calloc(1, sizeof(*event)))) {
+ return NULL;
++ }
+
+ event->type = htons(type);
+ event->event_len = htons(sizeof(*event));
+
+ AST_LIST_TRAVERSE(&ie_vals, ie_val, entry) {
+- if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_STR)
++ switch (ie_val->ie_pltype) {
++ case AST_EVENT_IE_PLTYPE_STR:
+ ast_event_append_ie_str(&event, ie_val->ie_type, ie_val->payload.str);
+- else if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_UINT)
++ break;
++ case AST_EVENT_IE_PLTYPE_UINT:
+ ast_event_append_ie_uint(&event, ie_val->ie_type, ie_val->payload.uint);
+- else if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_RAW)
+- ast_event_append_ie_raw(&event, ie_val->ie_type, ie_val->payload.raw, ie_val->raw_datalen);
++ break;
++ case AST_EVENT_IE_PLTYPE_BITFLAGS:
++ ast_event_append_ie_bitflags(&event, ie_val->ie_type, ie_val->payload.uint);
++ break;
++ case AST_EVENT_IE_PLTYPE_RAW:
++ ast_event_append_ie_raw(&event, ie_val->ie_type,
++ ie_val->payload.raw, ie_val->raw_datalen);
++ break;
++ case AST_EVENT_IE_PLTYPE_EXISTS:
++ ast_log(LOG_WARNING, "PLTYPE_EXISTS unsupported in event_new\n");
++ break;
++ case AST_EVENT_IE_PLTYPE_UNKNOWN:
++ ast_log(LOG_WARNING, "PLTYPE_UNKNOWN passed as an IE type "
++ "for a new event\n");
++ break;
++ }
+
+- if (!event)
++ if (!event) {
+ break;
++ }
+ }
+
+ if (!ast_event_get_ie_raw(event, AST_EVENT_IE_EID)) {
+@@ -1027,6 +1189,9 @@
+ 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_BITFLAGS:
++ ast_event_append_ie_bitflags(&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;
+Index: main/astmm.c
+===================================================================
+--- a/main/astmm.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/main/astmm.c (.../trunk) (revision 202568)
+@@ -324,7 +324,7 @@
+
+ static char *handle_memory_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+ {
+- char *fn = NULL;
++ const char *fn = NULL;
+ struct ast_region *reg;
+ unsigned int x;
+ unsigned int len = 0;
+@@ -386,7 +386,7 @@
+
+ static char *handle_memory_show_summary(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+ {
+- char *fn = NULL;
++ const char *fn = NULL;
+ int x;
+ struct ast_region *reg;
+ unsigned int len = 0;
+Index: main/asterisk.c
+===================================================================
+--- a/main/asterisk.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/main/asterisk.c (.../trunk) (revision 202568)
+@@ -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"
+@@ -139,8 +138,6 @@
+ #include "asterisk/xmldoc.h"
+ #include "asterisk/poll-compat.h"
+
+-#include "asterisk/doxyref.h" /* Doxygen documentation */
+-
+ #include "../defaults.h"
+
+ #ifndef AF_LOCAL
+@@ -768,7 +765,7 @@
+ static char *handle_show_profile(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+ {
+ int i, min, max;
+- char *search = NULL;
++ const char *search = NULL;
+ switch (cmd) {
+ case CLI_INIT:
+ e->command = "core show profile";
+@@ -803,7 +800,7 @@
+ static char *handle_clear_profile(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+ {
+ int i, min, max;
+- char *search = NULL;
++ const char *search = NULL;
+ switch (cmd) {
+ case CLI_INIT:
+ e->command = "core clear profile";
+@@ -944,8 +941,7 @@
+ AST_RWLIST_TRAVERSE_SAFE_END;
+ AST_RWLIST_UNLOCK(&atexits);
+
+- if (ae)
+- free(ae);
++ free(ae);
+ }
+
+ /* Sending commands from consoles back to the daemon requires a terminating NULL */
+@@ -3608,7 +3604,6 @@
+ exit(1);
+ }
+
+- ast_rtp_init();
+ ast_dsp_init();
+ ast_udptl_init();
+
+@@ -3657,6 +3652,8 @@
+ /* loads the cli_permissoins.conf file needed to implement cli restrictions. */
+ ast_cli_perms_init(0);
+
++ ast_stun_init();
++
+ dnsmgr_start_refresh();
+
+ /* We might have the option of showing a console, but for now just
+Index: main/dsp.c
+===================================================================
+--- a/main/dsp.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/main/dsp.c (.../trunk) (revision 202568)
+@@ -283,24 +283,17 @@
+ } td;
+ } digit_detect_state_t;
+
+-static float dtmf_row[] =
+-{
++static const float dtmf_row[] = {
+ 697.0, 770.0, 852.0, 941.0
+ };
+-static float dtmf_col[] =
+-{
++static const float dtmf_col[] = {
+ 1209.0, 1336.0, 1477.0, 1633.0
+ };
+-
+-static float mf_tones[] =
+-{
++static const float mf_tones[] = {
+ 700.0, 900.0, 1100.0, 1300.0, 1500.0, 1700.0
+ };
+-
+-static char dtmf_positions[] = "123A" "456B" "789C" "*0#D";
+-
+-static char bell_mf_positions[] = "1247C-358A--69*---0B----#";
+-
++static const char dtmf_positions[] = "123A" "456B" "789C" "*0#D";
++static const char bell_mf_positions[] = "1247C-358A--69*---0B----#";
+ static int thresholds[THRESHOLD_MAX];
+
+ static inline void goertzel_sample(goertzel_state_t *s, short sample)
+Index: main/udptl.c
+===================================================================
+--- a/main/udptl.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/main/udptl.c (.../trunk) (revision 202568)
+@@ -1134,7 +1134,7 @@
+ if (strncasecmp(a->argv[3], "ip", 2))
+ return CLI_SHOWUSAGE;
+ port = 0;
+- arg = a->argv[4];
++ arg = ast_strdupa(a->argv[4]);
+ p = strstr(arg, ":");
+ if (p) {
+ *p = '\0';
+Index: main/autoservice.c
+===================================================================
+--- a/main/autoservice.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/main/autoservice.c (.../trunk) (revision 202568)
+@@ -163,15 +163,22 @@
+ continue;
+ }
+
+- if ((dup_f = ast_frdup(defer_frame))) {
+- AST_LIST_INSERT_HEAD(&ents[i]->deferred_frames, dup_f, frame_list);
++ if (defer_frame != f) {
++ if ((dup_f = ast_frdup(defer_frame))) {
++ AST_LIST_INSERT_HEAD(&ents[i]->deferred_frames, dup_f, frame_list);
++ }
++ } else {
++ if ((dup_f = ast_frisolate(defer_frame))) {
++ if (dup_f != defer_frame) {
++ ast_frfree(defer_frame);
++ }
++ AST_LIST_INSERT_HEAD(&ents[i]->deferred_frames, dup_f, frame_list);
++ }
+ }
+
+ break;
+ }
+- }
+-
+- if (f) {
++ } else if (f) {
+ ast_frfree(f);
+ }
+ }
+Index: main/frame.c
+===================================================================
+--- a/main/frame.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/main/frame.c (.../trunk) (revision 202568)
+@@ -40,11 +40,6 @@
+ #include "asterisk/dsp.h"
+ #include "asterisk/file.h"
+
+-#ifdef TRACE_FRAMES
+-static int headers;
+-static AST_LIST_HEAD_STATIC(headerlist, ast_frame);
+-#endif
+-
+ #if !defined(LOW_MEMORY)
+ static void frame_cache_cleanup(void *data);
+
+@@ -318,12 +313,6 @@
+ #endif
+
+ f->mallocd_hdr_len = sizeof(*f);
+-#ifdef TRACE_FRAMES
+- AST_LIST_LOCK(&headerlist);
+- headers++;
+- AST_LIST_INSERT_HEAD(&headerlist, f, frame_list);
+- AST_LIST_UNLOCK(&headerlist);
+-#endif
+
+ return f;
+ }
+@@ -341,7 +330,7 @@
+ }
+ #endif
+
+-void ast_frame_free(struct ast_frame *fr, int cache)
++static void __frame_free(struct ast_frame *fr, int cache)
+ {
+ if (ast_test_flag(fr, AST_FRFLAG_FROM_TRANSLATOR)) {
+ ast_translate_frame_freed(fr);
+@@ -360,8 +349,8 @@
+ * to keep things simple... */
+ struct ast_frame_cache *frames;
+
+- if ((frames = ast_threadstorage_get(&frame_cache, sizeof(*frames)))
+- && frames->size < FRAME_CACHE_MAX_SIZE) {
++ if ((frames = ast_threadstorage_get(&frame_cache, sizeof(*frames))) &&
++ (frames->size < FRAME_CACHE_MAX_SIZE)) {
+ AST_LIST_INSERT_HEAD(&frames->list, fr, frame_list);
+ frames->size++;
+ return;
+@@ -375,19 +364,25 @@
+ }
+ if (fr->mallocd & AST_MALLOCD_SRC) {
+ if (fr->src)
+- ast_free((char *)fr->src);
++ ast_free((void *) fr->src);
+ }
+ if (fr->mallocd & AST_MALLOCD_HDR) {
+-#ifdef TRACE_FRAMES
+- AST_LIST_LOCK(&headerlist);
+- headers--;
+- AST_LIST_REMOVE(&headerlist, fr, frame_list);
+- AST_LIST_UNLOCK(&headerlist);
+-#endif
+ ast_free(fr);
+ }
+ }
+
++
++void ast_frame_free(struct ast_frame *frame, int cache)
++{
++ struct ast_frame *next;
++
++ for (next = AST_LIST_NEXT(frame, frame_list);
++ frame;
++ frame = next, next = frame ? AST_LIST_NEXT(frame, frame_list) : NULL) {
++ __frame_free(frame, cache);
++ }
++}
++
+ /*!
+ * \brief 'isolates' a frame by duplicating non-malloc'ed components
+ * (header, src, data).
+@@ -398,19 +393,29 @@
+ struct ast_frame *out;
+ void *newdata;
+
+- ast_clear_flag(fr, AST_FRFLAG_FROM_TRANSLATOR);
+- ast_clear_flag(fr, AST_FRFLAG_FROM_DSP);
++ /* if none of the existing frame is malloc'd, let ast_frdup() do it
++ since it is more efficient
++ */
++ if (fr->mallocd == 0) {
++ return ast_frdup(fr);
++ }
+
++ /* if everything is already malloc'd, we are done */
++ if ((fr->mallocd & (AST_MALLOCD_HDR | AST_MALLOCD_SRC | AST_MALLOCD_DATA)) ==
++ (AST_MALLOCD_HDR | AST_MALLOCD_SRC | AST_MALLOCD_DATA)) {
++ return fr;
++ }
++
+ if (!(fr->mallocd & AST_MALLOCD_HDR)) {
+ /* Allocate a new header if needed */
+- if (!(out = ast_frame_header_new()))
++ if (!(out = ast_frame_header_new())) {
+ return NULL;
++ }
+ out->frametype = fr->frametype;
+ out->subclass = fr->subclass;
+ out->datalen = fr->datalen;
+ out->samples = fr->samples;
+ out->offset = fr->offset;
+- out->data = fr->data;
+ /* Copy the timing data */
+ ast_copy_flags(out, fr, AST_FRFLAG_HAS_TIMING_INFO);
+ if (ast_test_flag(fr, AST_FRFLAG_HAS_TIMING_INFO)) {
+@@ -418,26 +423,34 @@
+ out->len = fr->len;
+ out->seqno = fr->seqno;
+ }
+- } else
++ } else {
++ ast_clear_flag(fr, AST_FRFLAG_FROM_TRANSLATOR);
++ ast_clear_flag(fr, AST_FRFLAG_FROM_DSP);
++ ast_clear_flag(fr, AST_FRFLAG_FROM_FILESTREAM);
+ out = fr;
++ }
+
+- if (!(fr->mallocd & AST_MALLOCD_SRC)) {
+- if (fr->src) {
+- if (!(out->src = ast_strdup(fr->src))) {
+- if (out != fr)
+- ast_free(out);
+- return NULL;
++ if (!(fr->mallocd & AST_MALLOCD_SRC) && fr->src) {
++ if (!(out->src = ast_strdup(fr->src))) {
++ if (out != fr) {
++ ast_free(out);
+ }
++ return NULL;
+ }
+- } else
++ } else {
+ out->src = fr->src;
++ fr->src = NULL;
++ fr->mallocd &= ~AST_MALLOCD_SRC;
++ }
+
+ if (!(fr->mallocd & AST_MALLOCD_DATA)) {
+ if (!(newdata = ast_malloc(fr->datalen + AST_FRIENDLY_OFFSET))) {
+- if (out->src != fr->src)
++ if (out->src != fr->src) {
+ ast_free((void *) out->src);
+- if (out != fr)
++ }
++ if (out != fr) {
+ ast_free(out);
++ }
+ return NULL;
+ }
+ newdata += AST_FRIENDLY_OFFSET;
+@@ -445,6 +458,10 @@
+ out->datalen = fr->datalen;
+ memcpy(newdata, fr->data.ptr, fr->datalen);
+ out->data.ptr = newdata;
++ } else {
++ out->data = fr->data;
++ memset(&fr->data, 0, sizeof(fr->data));
++ fr->mallocd &= ~AST_MALLOCD_DATA;
+ }
+
+ out->mallocd = AST_MALLOCD_HDR | AST_MALLOCD_SRC | AST_MALLOCD_DATA;
+@@ -939,44 +956,10 @@
+ }
+
+
+-#ifdef TRACE_FRAMES
+-static char *show_frame_stats(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+-{
+- struct ast_frame *f;
+- int x=1;
+-
+- switch (cmd) {
+- case CLI_INIT:
+- e->command = "core show frame stats";
+- e->usage =
+- "Usage: core show frame stats\n"
+- " Displays debugging statistics from framer\n";
+- return NULL;
+- case CLI_GENERATE:
+- return NULL;
+- }
+-
+- if (a->argc != 4)
+- return CLI_SHOWUSAGE;
+- AST_LIST_LOCK(&headerlist);
+- ast_cli(a->fd, " Framer Statistics \n");
+- ast_cli(a->fd, "---------------------------\n");
+- ast_cli(a->fd, "Total allocated headers: %d\n", headers);
+- ast_cli(a->fd, "Queue Dump:\n");
+- AST_LIST_TRAVERSE(&headerlist, f, frame_list)
+- ast_cli(a->fd, "%d. Type %d, subclass %d from %s\n", x++, f->frametype, f->subclass, f->src ? f->src : "<Unknown>");
+- AST_LIST_UNLOCK(&headerlist);
+- return CLI_SUCCESS;
+-}
+-#endif
+-
+ /* Builtin Asterisk CLI-commands for debugging */
+ static struct ast_cli_entry my_clis[] = {
+ AST_CLI_DEFINE(show_codecs, "Displays a list of codecs"),
+ AST_CLI_DEFINE(show_codec_n, "Shows a specific codec"),
+-#ifdef TRACE_FRAMES
+- AST_CLI_DEFINE(show_frame_stats, "Shows frame statistics"),
+-#endif
+ };
+
+ int init_framer(void)
+@@ -1354,7 +1337,7 @@
+
+ static int speex_get_wb_sz_at(unsigned char *data, int len, int bit)
+ {
+- static int SpeexWBSubModeSz[] = {
++ static const int SpeexWBSubModeSz[] = {
+ 0, 36, 112, 192,
+ 352, 0, 0, 0 };
+ int off = bit;
+@@ -1384,12 +1367,12 @@
+
+ static int speex_samples(unsigned char *data, int len)
+ {
+- static int SpeexSubModeSz[] = {
++ static const int SpeexSubModeSz[] = {
+ 5, 43, 119, 160,
+ 220, 300, 364, 492,
+ 79, 0, 0, 0,
+ 0, 0, 0, 0 };
+- static int SpeexInBandSz[] = {
++ static const int SpeexInBandSz[] = {
+ 1, 1, 4, 4,
+ 4, 4, 4, 4,
+ 8, 8, 16, 16,
+Index: main/say.c
+===================================================================
+--- a/main/say.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/main/say.c (.../trunk) (revision 202568)
+@@ -349,6 +349,7 @@
+ static int ast_say_number_full_ge(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options, int audiofd, int ctrlfd);
+ static int ast_say_number_full_hu(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd);
+ static int ast_say_number_full_th(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd);
++static int ast_say_number_full_ur(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options, int audiofd, int ctrlfd);
+
+ /* Forward declarations of language specific variants of ast_say_enumeration_full */
+ static int ast_say_enumeration_full_en(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd);
+@@ -467,6 +468,8 @@
+ return(ast_say_number_full_ru(chan, num, ints, language, options, audiofd, ctrlfd));
+ } else if (!strcasecmp(language, "th") ) { /* Thai syntax */
+ return(ast_say_number_full_th(chan, num, ints, language, audiofd, ctrlfd));
++ } else if (!strcasecmp(language, "ur") ) { /* Urdu syntax */
++ return(ast_say_number_full_ur(chan, num, ints, language, options, audiofd, ctrlfd));
+ } else if (!strcasecmp(language, "ge") ) { /* Georgian syntax */
+ return(ast_say_number_full_ge(chan, num, ints, language, options, audiofd, ctrlfd));
+ }
+@@ -2352,7 +2355,68 @@
+ return res;
+ }
+
++/*!\internal
++ * \brief Counting in Urdu, the national language of Pakistan
++ * \since 1.6.3
++ */
++static int ast_say_number_full_ur(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options, int audiofd, int ctrlfd)
++{
++ int res = 0;
++ int playh = 0;
++ char fn[256] = "";
+
++ if (!num) {
++ return ast_say_digits_full(chan, 0, ints, language, audiofd, ctrlfd);
++ }
++
++ while (!res && (num || playh)) {
++ if (playh) {
++ snprintf(fn, sizeof(fn), "digits/hundred");
++ playh = 0;
++ } else if (num < 100) {
++ snprintf(fn, sizeof(fn), "digits/%d", num);
++ num = 0;
++ } else if (num < 1000) {
++ snprintf(fn, sizeof(fn), "digits/%d", (num / 100));
++ playh++;
++ num -= ((num / 100) * 100);
++ } else if (num < 100000) { /* 1,00,000 */
++ if ((res = ast_say_number_full_ur(chan, num / 1000, ints, language, options, audiofd, ctrlfd))) {
++ return res;
++ }
++ num = num % 1000;
++ snprintf(fn, sizeof(fn), "digits/thousand");
++ } else if (num < 10000000) { /* 1,00,00,000 */
++ if ((res = ast_say_number_full_ur(chan, num / 100000, ints, language, options, audiofd, ctrlfd))) {
++ return res;
++ }
++ num = num % 100000;
++ snprintf(fn, sizeof(fn), "digits/lac");
++ } else if (num < 1000000000) { /* 1,00,00,00,000 */
++ if ((res = ast_say_number_full_ur(chan, num / 10000000, ints, language, options, audiofd, ctrlfd))) {
++ return res;
++ }
++ num = num % 10000000;
++ snprintf(fn, sizeof(fn), "digits/crore");
++ } else {
++ ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
++ res = -1;
++ }
++
++ if (!res) {
++ if (!ast_streamfile(chan, fn, language)) {
++ if ((audiofd > -1) && (ctrlfd > -1)) {
++ res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
++ } else {
++ res = ast_waitstream(chan, ints);
++ }
++ }
++ ast_stopstream(chan);
++ }
++ }
++ return res;
++}
++
+ /*! \brief determine last digits for thousands/millions (ru) */
+ static int get_lastdigits_ru(int num) {
+ if (num < 20) {
+Index: main/threadstorage.c
+===================================================================
+--- a/main/threadstorage.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/main/threadstorage.c (.../trunk) (revision 202568)
+@@ -125,7 +125,7 @@
+
+ static char *handle_cli_threadstorage_show_allocations(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+ {
+- char *fn = NULL;
++ const char *fn = NULL;
+ size_t len = 0;
+ unsigned int count = 0;
+ struct tls_object *to;
+@@ -169,7 +169,7 @@
+
+ static char *handle_cli_threadstorage_show_summary(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+ {
+- char *fn = NULL;
++ const char *fn = NULL;
+ size_t len = 0;
+ unsigned int count = 0;
+ struct tls_object *to;
+Index: main/devicestate.c
+===================================================================
+--- a/main/devicestate.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/main/devicestate.c (.../trunk) (revision 202568)
+@@ -128,7 +128,7 @@
+ #include "asterisk/event.h"
+
+ /*! \brief Device state strings for printing */
+-static const char *devstatestring[][2] = {
++static const char * const 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 */
+@@ -190,7 +190,7 @@
+ char device[1];
+ };
+
+-struct {
++static struct {
+ pthread_t thread;
+ struct ast_event_sub *event_sub;
+ ast_cond_t cond;
+@@ -268,19 +268,15 @@
+ char match[AST_CHANNEL_NAME];
+ enum ast_device_state res;
+
+- ast_copy_string(match, device, sizeof(match)-1);
+- strcat(match, "-");
+- chan = ast_get_channel_by_name_prefix_locked(match, strlen(match));
++ snprintf(match, sizeof(match), "%s-", device);
+
+- if (!chan)
++ if (!(chan = ast_channel_get_by_name_prefix(match, strlen(match)))) {
+ return AST_DEVICE_UNKNOWN;
++ }
+
+- if (chan->_state == AST_STATE_RINGING)
+- res = AST_DEVICE_RINGING;
+- else
+- res = AST_DEVICE_INUSE;
++ res = (chan->_state == AST_STATE_RINGING) ? AST_DEVICE_RINGING : AST_DEVICE_INUSE;
+
+- ast_channel_unlock(chan);
++ chan = ast_channel_unref(chan);
+
+ return res;
+ }
+Index: main/autochan.c
+===================================================================
+--- a/main/autochan.c (.../tags/1.6.2.0-beta3) (revision 0)
++++ b/main/autochan.c (.../trunk) (revision 202568)
+@@ -0,0 +1,94 @@
++/*
++ * Asterisk -- An open source telephony toolkit.
++ *
++ * Copyright (C) 2009, 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
++ * \brief "smart" channels
++ *
++ * \author Mark Michelson <mmichelson@digium.com>
++ */
++
++#include "asterisk.h"
++
++ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
++
++#include "asterisk/autochan.h"
++#include "asterisk/utils.h"
++#include "asterisk/linkedlists.h"
++#include "asterisk/options.h"
++#include "asterisk/channel.h"
++
++struct ast_autochan *ast_autochan_setup(struct ast_channel *chan)
++{
++ struct ast_autochan *autochan;
++
++ if (!chan) {
++ return NULL;
++ }
++
++ if (!(autochan = ast_calloc(1, sizeof(*autochan)))) {
++ return NULL;
++ }
++
++ autochan->chan = ast_channel_ref(chan);
++
++ ast_channel_lock(autochan->chan);
++ AST_LIST_INSERT_TAIL(&autochan->chan->autochans, autochan, list);
++ ast_channel_unlock(autochan->chan);
++
++ ast_debug(1, "Created autochan %p to hold channel %s (%p)\n", autochan, chan->name, chan);
++
++ return autochan;
++}
++
++void ast_autochan_destroy(struct ast_autochan *autochan)
++{
++ struct ast_autochan *autochan_iter;
++
++ ast_channel_lock(autochan->chan);
++ AST_LIST_TRAVERSE_SAFE_BEGIN(&autochan->chan->autochans, autochan_iter, list) {
++ if (autochan_iter == autochan) {
++ AST_LIST_REMOVE_CURRENT(list);
++ ast_debug(1, "Removed autochan %p from the list, about to free it\n", autochan);
++ break;
++ }
++ }
++ AST_LIST_TRAVERSE_SAFE_END;
++ ast_channel_unlock(autochan->chan);
++
++ autochan->chan = ast_channel_unref(autochan->chan);
++
++ ast_free(autochan);
++}
++
++void ast_autochan_new_channel(struct ast_channel *old_chan, struct ast_channel *new_chan)
++{
++ struct ast_autochan *autochan;
++
++ AST_LIST_APPEND_LIST(&new_chan->autochans, &old_chan->autochans, list);
++
++ AST_LIST_TRAVERSE(&new_chan->autochans, autochan, list) {
++ if (autochan->chan == old_chan) {
++ autochan->chan = ast_channel_unref(old_chan);
++ autochan->chan = ast_channel_ref(new_chan);
++
++ ast_debug(1, "Autochan %p used to hold channel %s (%p) but now holds channel %s (%p)\n",
++ autochan, old_chan->name, old_chan, new_chan->name, new_chan);
++ }
++ }
++}
+
+Property changes on: main/autochan.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+Added: svn:mime-type
+ + text/plain
+Added: svn:keywords
+ + Author Date Id Revision
+
+Index: main/taskprocessor.c
+===================================================================
+--- a/main/taskprocessor.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/main/taskprocessor.c (.../trunk) (revision 202568)
+@@ -62,7 +62,7 @@
+ /*! \brief A ast_taskprocessor structure is a singleton by name */
+ struct ast_taskprocessor {
+ /*! \brief Friendly name of the taskprocessor */
+- char *name;
++ const char *name;
+ /*! \brief Thread poll condition */
+ ast_cond_t poll_cond;
+ /*! \brief Taskprocessor thread */
+@@ -189,7 +189,7 @@
+ static char *cli_tps_ping(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+ {
+ struct timeval begin, end, delta;
+- char *name;
++ const char *name;
+ struct timeval when;
+ struct timespec ts;
+ struct ast_taskprocessor *tps = NULL;
+@@ -366,7 +366,7 @@
+ ast_free(t->stats);
+ t->stats = NULL;
+ }
+- ast_free(t->name);
++ ast_free((char *) t->name);
+ }
+
+ /* pop the front task and return it */
+@@ -404,7 +404,7 @@
+ /* Provide a reference to a taskprocessor. Create the taskprocessor if necessary, but don't
+ * create the taskprocessor if we were told via ast_tps_options to return a reference only
+ * if it already exists */
+-struct ast_taskprocessor *ast_taskprocessor_get(char *name, enum ast_tps_options create)
++struct ast_taskprocessor *ast_taskprocessor_get(const char *name, enum ast_tps_options create)
+ {
+ struct ast_taskprocessor *p, tmp_tps = {
+ .name = name,
+Index: main/enum.c
+===================================================================
+--- a/main/enum.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/main/enum.c (.../trunk) (revision 202568)
+@@ -41,7 +41,7 @@
+ *
+ * \par Possible improvement
+ * \todo Implement a caching mechanism for multile enum lookups
+- * - See http://bugs.digium.com/view.php?id=6739
++ * - See https://issues.asterisk.org/view.php?id=6739
+ * \todo The service type selection needs to be redone.
+ */
+
+Index: main/astobj2.c
+===================================================================
+--- a/main/astobj2.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/main/astobj2.c (.../trunk) (revision 202568)
+@@ -134,19 +134,19 @@
+
+ /* the underlying functions common to debug and non-debug versions */
+
+-static int __ao2_ref(void *user_data, const int delta);
+-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 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);
+@@ -168,7 +168,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);
+@@ -190,7 +190,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);
+@@ -226,7 +226,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);
+
+@@ -235,7 +235,7 @@
+
+ if (delta != 0) {
+ FILE *refo = fopen(REF_FILE,"a");
+- fprintf(refo, "%p %s%d %s:%d:%s (%s) [@%d]\n", user_data, (delta<0? "":"+"), delta, file, line, funcname, tag, obj->priv_data.ref_counter);
++ fprintf(refo, "%p %s%d %s:%d:%s (%s) [@%d]\n", user_data, (delta<0? "":"+"), delta, file, line, funcname, tag, obj ? obj->priv_data.ref_counter : -1);
+ fclose(refo);
+ }
+ if (obj->priv_data.ref_counter + delta == 0 && obj->priv_data.destructor_fn != NULL) { /* this isn't protected with lock; just for o/p */
+@@ -243,20 +243,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;
+@@ -302,7 +302,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, const char *file, int line, const char *funcname)
++static void *internal_ao2_alloc(size_t data_size, ao2_destructor_fn destructor_fn, const char *file, int line, const char *funcname)
+ {
+ /* allocation */
+ struct astobj2 *obj;
+@@ -335,18 +335,18 @@
+ return EXTERNAL_OBJ(obj);
+ }
+
+-void *_ao2_alloc_debug(size_t data_size, ao2_destructor_fn destructor_fn, char *tag,
+- const char *file, int line, const char *funcname, int ref_debug)
++void *__ao2_alloc_debug(size_t data_size, ao2_destructor_fn destructor_fn, char *tag,
++ const char *file, int line, const char *funcname, int ref_debug)
+ {
+ /* allocation */
+ void *obj;
+ FILE *refo = ref_debug ? fopen(REF_FILE,"a") : NULL;
+
+- obj = __ao2_alloc(data_size, destructor_fn, file, line, funcname);
++ if ((obj = internal_ao2_alloc(data_size, destructor_fn, file, line, funcname)) == NULL) {
++ fclose(refo);
++ return NULL;
++ }
+
+- if (obj == NULL)
+- return NULL;
+-
+ if (refo) {
+ fprintf(refo, "%p =1 %s:%d:%s (%s)\n", obj, file, line, funcname, tag);
+ fclose(refo);
+@@ -356,9 +356,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, __FILE__, __LINE__, __FUNCTION__);
++ return internal_ao2_alloc(data_size, destructor_fn, __FILE__, __LINE__, __FUNCTION__);
+ }
+
+
+@@ -422,8 +422,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 */
+@@ -432,7 +432,7 @@
+ return NULL;
+
+ c->version = 1; /* 0 is a reserved value here */
+- c->n_buckets = n_buckets;
++ c->n_buckets = hash_fn ? n_buckets : 1;
+ c->hash_fn = hash_fn ? hash_fn : hash_zero;
+ c->cmp_fn = cmp_fn;
+
+@@ -443,29 +443,30 @@
+ return c;
+ }
+
+-struct ao2_container *_ao2_container_alloc_debug(const unsigned int n_buckets, ao2_hash_fn *hash_fn,
++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, int ref_debug)
+ {
+ /* 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, ref_debug);
++ const unsigned int num_buckets = hash_fn ? n_buckets : 1;
++ size_t container_size = sizeof(struct ao2_container) + num_buckets * sizeof(struct bucket);
++ struct ao2_container *c = __ao2_alloc_debug(container_size, container_destruct_debug, tag, file, line, funcname, ref_debug);
+
+- return __ao2_container_alloc(c, n_buckets, hash_fn, cmp_fn);
++ return internal_ao2_container_alloc(c, num_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);
++ const unsigned int num_buckets = hash_fn ? n_buckets : 1;
++ size_t container_size = sizeof(struct ao2_container) + num_buckets * sizeof(struct bucket);
++ 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, num_buckets, hash_fn, cmp_fn);
+ }
+
+ /*!
+@@ -491,7 +492,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 */
+@@ -521,23 +522,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;
+@@ -555,23 +556,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;
+ }
+@@ -600,9 +601,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;
+@@ -680,9 +681,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 */
+@@ -694,9 +695,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 */
+ }
+
+@@ -720,45 +721,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);
+ }
+
+ /*!
+@@ -777,7 +778,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;
+@@ -832,16 +833,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))
+@@ -850,16 +851,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))
+@@ -873,13 +874,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;
+ }
+
+@@ -888,7 +889,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;
+@@ -908,7 +909,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;
+@@ -926,10 +927,10 @@
+ #ifdef AO2_DEBUG
+ static int print_cb(void *obj, void *arg, int flag)
+ {
+- int *fd = arg;
++ struct ast_cli_args *a = (struct ast_cli_args *) arg;
+ char *s = (char *)obj;
+
+- ast_cli(*fd, "string <%s>\n", s);
++ ast_cli(a->fd, "string <%s>\n", s);
+ return 0;
+ }
+
+@@ -1016,7 +1017,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, "test callback");
+ ast_cli(a->fd, "testing iterators, remove every second object\n");
+ {
+ struct ao2_iterator ai;
+@@ -1037,7 +1038,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, "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/asterisk.exports
+===================================================================
+--- a/main/asterisk.exports (.../tags/1.6.2.0-beta3) (revision 0)
++++ b/main/asterisk.exports (.../trunk) (revision 202568)
+@@ -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-beta3) (revision 202568)
++++ b/main/cli.c (.../trunk) (revision 202568)
+@@ -74,7 +74,7 @@
+ * it is already running. */
+ AST_MUTEX_DEFINE_STATIC(permsconfiglock);
+ /*! \brief List of users and permissions. */
+-AST_RWLIST_HEAD_STATIC(cli_perms, usergroup_cli_perm);
++static AST_RWLIST_HEAD_STATIC(cli_perms, usergroup_cli_perm);
+
+ /*!
+ * \brief map a debug or verbose value to a filename
+@@ -235,8 +235,7 @@
+ c += (strlen(ast_config_AST_MODULE_DIR) + 1);
+ if (c)
+ c = ast_strdup(c);
+- if (d)
+- free(d);
++ free(d);
+
+ return c;
+ }
+@@ -365,13 +364,13 @@
+ int atleast = 0;
+ int fd = a->fd;
+ int argc = a->argc;
+- char **argv = a->argv;
+- char *argv3 = a->argv ? S_OR(a->argv[3], "") : "";
++ const char * const *argv = a->argv;
++ const char *argv3 = a->argv ? S_OR(a->argv[3], "") : "";
+ int *dst;
+ char *what;
+ struct debug_file_list *dfl;
+ struct ast_debug_file *adf;
+- char *fn;
++ const char *fn;
+
+ switch (cmd) {
+ case CLI_INIT:
+@@ -387,7 +386,7 @@
+
+ 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], "");
++ const 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);
+@@ -534,7 +533,7 @@
+ /* "module unload mod_1 [mod_2 .. mod_N]" */
+ int x;
+ int force = AST_FORCE_SOFT;
+- char *s;
++ const char *s;
+
+ switch (cmd) {
+ case CLI_INIT:
+@@ -685,7 +684,7 @@
+
+ static char *handle_modlist(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+ {
+- char *like;
++ const char *like;
+
+ switch (cmd) {
+ case CLI_INIT:
+@@ -787,8 +786,7 @@
+
+ struct ast_channel *c = NULL;
+ int numchans = 0, concise = 0, verbose = 0, count = 0;
+- int fd, argc;
+- char **argv;
++ struct ast_channel_iterator *iter = NULL;
+
+ switch (cmd) {
+ case CLI_INIT:
+@@ -807,16 +805,13 @@
+ case CLI_GENERATE:
+ return NULL;
+ }
+- fd = a->fd;
+- argc = a->argc;
+- argv = a->argv;
+
+ if (a->argc == e->args) {
+- if (!strcasecmp(argv[e->args-1],"concise"))
++ if (!strcasecmp(a->argv[e->args-1],"concise"))
+ concise = 1;
+- else if (!strcasecmp(argv[e->args-1],"verbose"))
++ else if (!strcasecmp(a->argv[e->args-1],"verbose"))
+ verbose = 1;
+- else if (!strcasecmp(argv[e->args-1],"count"))
++ else if (!strcasecmp(a->argv[e->args-1],"count"))
+ count = 1;
+ else
+ return CLI_SHOWUSAGE;
+@@ -825,16 +820,24 @@
+
+ if (!count) {
+ if (!concise && !verbose)
+- ast_cli(fd, FORMAT_STRING2, "Channel", "Location", "State", "Application(Data)");
++ ast_cli(a->fd, FORMAT_STRING2, "Channel", "Location", "State", "Application(Data)");
+ else if (verbose)
+- ast_cli(fd, VERBOSE_FORMAT_STRING2, "Channel", "Context", "Extension", "Priority", "State", "Application", "Data",
++ ast_cli(a->fd, VERBOSE_FORMAT_STRING2, "Channel", "Context", "Extension", "Priority", "State", "Application", "Data",
+ "CallerID", "Duration", "Accountcode", "BridgedTo");
+ }
+
+- while ((c = ast_channel_walk_locked(c)) != NULL) {
+- struct ast_channel *bc = ast_bridged_channel(c);
++ if (!count && !(iter = ast_channel_iterator_all_new(0))) {
++ return CLI_FAILURE;
++ }
++
++ for (; iter && (c = ast_channel_iterator_next(iter)); ast_channel_unref(c)) {
++ struct ast_channel *bc;
+ char durbuf[10] = "-";
+
++ ast_channel_lock(c);
++
++ bc = ast_bridged_channel(c);
++
+ if (!count) {
+ if ((concise || verbose) && c->cdr && !ast_tvzero(c->cdr->start)) {
+ int duration = (int)(ast_tvdiff_ms(ast_tvnow(), c->cdr->start) / 1000);
+@@ -848,7 +851,7 @@
+ }
+ }
+ if (concise) {
+- ast_cli(fd, CONCISE_FORMAT_STRING, c->name, c->context, c->exten, c->priority, ast_state2str(c->_state),
++ ast_cli(a->fd, CONCISE_FORMAT_STRING, c->name, c->context, c->exten, c->priority, ast_state2str(c->_state),
+ c->appl ? c->appl : "(None)",
+ S_OR(c->data, ""), /* XXX different from verbose ? */
+ S_OR(c->cid.cid_num, ""),
+@@ -858,7 +861,7 @@
+ bc ? bc->name : "(None)",
+ c->uniqueid);
+ } else if (verbose) {
+- ast_cli(fd, VERBOSE_FORMAT_STRING, c->name, c->context, c->exten, c->priority, ast_state2str(c->_state),
++ ast_cli(a->fd, VERBOSE_FORMAT_STRING, c->name, c->context, c->exten, c->priority, ast_state2str(c->_state),
+ c->appl ? c->appl : "(None)",
+ c->data ? S_OR(c->data, "(Empty)" ): "(None)",
+ S_OR(c->cid.cid_num, ""),
+@@ -873,23 +876,29 @@
+ snprintf(locbuf, sizeof(locbuf), "%s@%s:%d", c->exten, c->context, c->priority);
+ if (c->appl)
+ snprintf(appdata, sizeof(appdata), "%s(%s)", c->appl, S_OR(c->data, ""));
+- ast_cli(fd, FORMAT_STRING, c->name, locbuf, ast_state2str(c->_state), appdata);
++ ast_cli(a->fd, FORMAT_STRING, c->name, locbuf, ast_state2str(c->_state), appdata);
+ }
+ }
+- numchans++;
+ ast_channel_unlock(c);
+ }
++
++ if (iter) {
++ ast_channel_iterator_destroy(iter);
++ }
++
+ if (!concise) {
+- ast_cli(fd, "%d active channel%s\n", numchans, ESS(numchans));
++ numchans = ast_active_channels();
++ ast_cli(a->fd, "%d active channel%s\n", numchans, ESS(numchans));
+ if (option_maxcalls)
+- ast_cli(fd, "%d of %d max active call%s (%5.2f%% of capacity)\n",
++ ast_cli(a->fd, "%d of %d max active call%s (%5.2f%% of capacity)\n",
+ ast_active_calls(), option_maxcalls, ESS(ast_active_calls()),
+ ((double)ast_active_calls() / (double)option_maxcalls) * 100.0);
+ else
+- ast_cli(fd, "%d active call%s\n", ast_active_calls(), ESS(ast_active_calls()));
++ ast_cli(a->fd, "%d active call%s\n", ast_active_calls(), ESS(ast_active_calls()));
+
+- ast_cli(fd, "%d call%s processed\n", ast_processed_calls(), ESS(ast_processed_calls()));
++ ast_cli(a->fd, "%d call%s processed\n", ast_processed_calls(), ESS(ast_processed_calls()));
+ }
++
+ return CLI_SUCCESS;
+
+ #undef FORMAT_STRING
+@@ -914,15 +923,21 @@
+ case CLI_GENERATE:
+ return ast_complete_channels(a->line, a->word, a->pos, a->n, e->args);
+ }
+- if (a->argc != 4)
++
++ if (a->argc != 4) {
+ return CLI_SHOWUSAGE;
+- c = ast_get_channel_by_name_locked(a->argv[3]);
+- if (c) {
++ }
++
++ if ((c = ast_channel_get_by_name(a->argv[3]))) {
++ ast_channel_lock(c);
+ ast_cli(a->fd, "Requested Hangup on channel '%s'\n", c->name);
+ ast_softhangup(c, AST_SOFTHANGUP_EXPLICIT);
+ ast_channel_unlock(c);
+- } else
++ c = ast_channel_unref(c);
++ } else {
+ ast_cli(a->fd, "%s is not a known channel\n", a->argv[3]);
++ }
++
+ return CLI_SUCCESS;
+ }
+
+@@ -1174,10 +1189,41 @@
+ return CLI_SUCCESS;
+ }
+
++struct channel_set_debug_args {
++ int fd;
++ int is_off;
++};
++
++static int channel_set_debug(void *obj, void *arg, void *data, int flags)
++{
++ struct ast_channel *chan = obj;
++ struct channel_set_debug_args *args = data;
++
++ ast_channel_lock(chan);
++
++ if (!(chan->fin & DEBUGCHAN_FLAG) || !(chan->fout & DEBUGCHAN_FLAG)) {
++ if (args->is_off) {
++ chan->fin &= ~DEBUGCHAN_FLAG;
++ chan->fout &= ~DEBUGCHAN_FLAG;
++ } else {
++ chan->fin |= DEBUGCHAN_FLAG;
++ chan->fout |= DEBUGCHAN_FLAG;
++ }
++ ast_cli(args->fd, "Debugging %s on channel %s\n", args->is_off ? "disabled" : "enabled",
++ chan->name);
++ }
++
++ ast_channel_unlock(chan);
++
++ return 0;
++}
++
+ static char *handle_core_set_debug_channel(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+ {
+ struct ast_channel *c = NULL;
+- int is_all, is_off = 0;
++ struct channel_set_debug_args args = {
++ .fd = a->fd,
++ };
+
+ switch (cmd) {
+ case CLI_INIT:
+@@ -1186,72 +1232,73 @@
+ "Usage: core set debug channel <all|channel> [off]\n"
+ " Enables/disables debugging on all or on a specific channel.\n";
+ return NULL;
+-
+ case CLI_GENERATE:
+ /* XXX remember to handle the optional "off" */
+ if (a->pos != e->args)
+ return NULL;
+ return a->n == 0 ? ast_strdup("all") : ast_complete_channels(a->line, a->word, a->pos, a->n - 1, e->args);
+ }
+- /* 'core set debug channel {all|chan_id}' */
+- if (a->argc == e->args + 2) {
++
++ if (cmd == (CLI_HANDLER + 1000)) {
++ /* called from handle_nodebugchan_deprecated */
++ args.is_off = 1;
++ } else if (a->argc == e->args + 2) {
++ /* 'core set debug channel {all|chan_id}' */
+ if (!strcasecmp(a->argv[e->args + 1], "off"))
+- is_off = 1;
++ args.is_off = 1;
+ else
+ return CLI_SHOWUSAGE;
+- } else if (a->argc != e->args + 1)
++ } else if (a->argc != e->args + 1) {
+ return CLI_SHOWUSAGE;
++ }
+
+- is_all = !strcasecmp("all", a->argv[e->args]);
+- if (is_all) {
+- if (is_off) {
++ if (!strcasecmp("all", a->argv[e->args])) {
++ if (args.is_off) {
+ global_fin &= ~DEBUGCHAN_FLAG;
+ global_fout &= ~DEBUGCHAN_FLAG;
+ } else {
+ global_fin |= DEBUGCHAN_FLAG;
+ global_fout |= DEBUGCHAN_FLAG;
+ }
+- c = ast_channel_walk_locked(NULL);
++ ast_channel_callback(channel_set_debug, NULL, &args, OBJ_NODATA | OBJ_MULTIPLE);
+ } else {
+- c = ast_get_channel_by_name_locked(a->argv[e->args]);
+- if (c == NULL)
++ if ((c = ast_channel_get_by_name(a->argv[e->args]))) {
++ channel_set_debug(c, NULL, &args, 0);
++ ast_channel_unref(c);
++ } else {
+ ast_cli(a->fd, "No such channel %s\n", a->argv[e->args]);
+- }
+- while (c) {
+- if (!(c->fin & DEBUGCHAN_FLAG) || !(c->fout & DEBUGCHAN_FLAG)) {
+- if (is_off) {
+- c->fin &= ~DEBUGCHAN_FLAG;
+- c->fout &= ~DEBUGCHAN_FLAG;
+- } else {
+- c->fin |= DEBUGCHAN_FLAG;
+- c->fout |= DEBUGCHAN_FLAG;
+- }
+- ast_cli(a->fd, "Debugging %s on channel %s\n", is_off ? "disabled" : "enabled", c->name);
+ }
+- ast_channel_unlock(c);
+- if (!is_all)
+- break;
+- c = ast_channel_walk_locked(c);
+ }
+- ast_cli(a->fd, "Debugging on new channels is %s\n", is_off ? "disabled" : "enabled");
++
++ ast_cli(a->fd, "Debugging on new channels is %s\n", args.is_off ? "disabled" : "enabled");
++
+ return CLI_SUCCESS;
+ }
+
+ static char *handle_nodebugchan_deprecated(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+ {
+ char *res;
+- if (cmd == CLI_HANDLER) {
+- if (a->argc != e->args + 1)
+- return CLI_SHOWUSAGE;
+- /* pretend we have an extra "off" at the end. We can do this as the array
+- * is NULL terminated so we overwrite that entry.
+- */
+- a->argv[e->args+1] = "off";
+- a->argc++;
++
++ switch (cmd) {
++ case CLI_INIT:
++ e->command = "no debug channel";
++ return NULL;
++ case CLI_HANDLER:
++ /* exit out of switch statement */
++ break;
++ default:
++ return NULL;
+ }
+- res = handle_core_set_debug_channel(e, cmd, a);
+- if (cmd == CLI_INIT)
+- e->command = "no debug channel";
++
++ if (a->argc != e->args + 1)
++ return CLI_SHOWUSAGE;
++
++ /* add a 'magic' value to the CLI_HANDLER command so that
++ * handle_core_set_debug_channel() will act as if 'off'
++ * had been specified as part of the command
++ */
++ res = handle_core_set_debug_channel(e, CLI_HANDLER + 1000, a);
++
+ return res;
+ }
+
+@@ -1279,22 +1326,29 @@
+ return ast_complete_channels(a->line, a->word, a->pos, a->n, 3);
+ }
+
+- if (a->argc != 4)
++ if (a->argc != 4) {
+ return CLI_SHOWUSAGE;
++ }
++
+ now = ast_tvnow();
+- c = ast_get_channel_by_name_locked(a->argv[3]);
+- if (!c) {
++
++ if (!(c = ast_channel_get_by_name(a->argv[3]))) {
+ ast_cli(a->fd, "%s is not a known channel\n", a->argv[3]);
+ return CLI_SUCCESS;
+ }
++
++ ast_channel_lock(c);
++
+ if (c->cdr) {
+ elapsed_seconds = now.tv_sec - c->cdr->start.tv_sec;
+ hour = elapsed_seconds / 3600;
+ min = (elapsed_seconds % 3600) / 60;
+ sec = elapsed_seconds % 60;
+ snprintf(cdrtime, sizeof(cdrtime), "%dh%dm%ds", hour, min, sec);
+- } else
++ } else {
+ strcpy(cdrtime, "N/A");
++ }
++
+ ast_cli(a->fd,
+ " -- General --\n"
+ " Name: %s\n"
+@@ -1347,17 +1401,24 @@
+ ( c-> data ? S_OR(c->data, "(Empty)") : "(None)"),
+ (ast_test_flag(c, AST_FLAG_BLOCKING) ? c->blockproc : "(Not Blocking)"));
+
+- if (pbx_builtin_serialize_variables(c, &out))
++ if (pbx_builtin_serialize_variables(c, &out)) {
+ ast_cli(a->fd," Variables:\n%s\n", ast_str_buffer(out));
+- if (c->cdr && ast_cdr_serialize_variables(c->cdr, &out, '=', '\n', 1))
++ }
++
++ if (c->cdr && ast_cdr_serialize_variables(c->cdr, &out, '=', '\n', 1)) {
+ 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", ast_str_buffer(out));
+ #endif
++
+ ast_channel_unlock(c);
++ c = ast_channel_unref(c);
++
+ return CLI_SUCCESS;
+ }
+
+@@ -1365,7 +1426,7 @@
+ * helper function to generate CLI matches from a fixed set of values.
+ * A NULL word is acceptable.
+ */
+-char *ast_cli_complete(const char *word, char *const choices[], int state)
++char *ast_cli_complete(const char *word, const char * const choices[], int state)
+ {
+ int i, which = 0, len;
+ len = ast_strlen_zero(word) ? 0 : strlen(word);
+@@ -1381,20 +1442,27 @@
+ {
+ struct ast_channel *c = NULL;
+ int which = 0;
+- int wordlen;
+ char notfound = '\0';
+ char *ret = &notfound; /* so NULL can break the loop */
++ struct ast_channel_iterator *iter;
+
+- if (pos != rpos)
++ if (pos != rpos) {
+ return NULL;
++ }
+
+- wordlen = strlen(word);
++ if (!(iter = ast_channel_iterator_by_name_new(0, word, strlen(word)))) {
++ return NULL;
++ }
+
+- while (ret == &notfound && (c = ast_channel_walk_locked(c))) {
+- if (!strncasecmp(word, c->name, wordlen) && ++which > state)
++ while (ret == &notfound && (c = ast_channel_iterator_next(iter))) {
++ if (++which > state) {
++ ast_channel_lock(c);
+ ret = ast_strdup(c->name);
+- ast_channel_unlock(c);
++ ast_channel_unlock(c);
++ }
++ ast_channel_unref(c);
+ }
++
+ return ret == &notfound ? NULL : ret;
+ }
+
+@@ -1760,15 +1828,15 @@
+ * 1 true only on complete, exact match.
+ *
+ */
+-static struct ast_cli_entry *find_cli(char *const cmds[], int match_type)
++static struct ast_cli_entry *find_cli(const char * const cmds[], int match_type)
+ {
+ int matchlen = -1; /* length of longest match so far */
+ struct ast_cli_entry *cand = NULL, *e=NULL;
+
+ while ( (e = cli_next(e)) ) {
+ /* word-by word regexp comparison */
+- char * const *src = cmds;
+- char * const *dst = e->cmda;
++ const char * const *src = cmds;
++ const char * const *dst = e->cmda;
+ int n = 0;
+ for (;; dst++, src += n) {
+ n = word_match(*src, *dst);
+@@ -1804,16 +1872,15 @@
+ return e ? e : cand;
+ }
+
+-static char *find_best(char *argv[])
++static char *find_best(const char *argv[])
+ {
+ static char cmdline[80];
+ int x;
+ /* See how close we get, then print the candidate */
+- char *myargv[AST_MAX_CMD_LEN];
+- for (x=0;x<AST_MAX_CMD_LEN;x++)
+- myargv[x]=NULL;
++ const char *myargv[AST_MAX_CMD_LEN] = { NULL, };
++
+ AST_RWLIST_RDLOCK(&helpers);
+- for (x=0;argv[x];x++) {
++ for (x = 0; argv[x]; x++) {
+ myargv[x] = argv[x];
+ if (!find_cli(myargv, -1))
+ break;
+@@ -1939,7 +2006,7 @@
+ /*! \brief helper for final part of handle_help
+ * if locked = 1, assume the list is already locked
+ */
+-static char *help1(int fd, char *match[], int locked)
++static char *help1(int fd, const char * const match[], int locked)
+ {
+ char matchstr[80] = "";
+ struct ast_cli_entry *e = NULL;
+@@ -2014,7 +2081,7 @@
+ return res;
+ }
+
+-static char *parse_args(const char *s, int *argc, char *argv[], int max, int *trailingwhitespace)
++static char *parse_args(const char *s, int *argc, const char *argv[], int max, int *trailingwhitespace)
+ {
+ char *duplicate, *cur;
+ int x = 0;
+@@ -2145,7 +2212,7 @@
+ }
+
+ /*! \brief returns true if there are more words to match */
+-static int more_words (char * const *dst)
++static int more_words (const char * const *dst)
+ {
+ int i;
+ for (i = 0; dst[i]; i++) {
+@@ -2160,7 +2227,7 @@
+ */
+ static char *__ast_cli_generator(const char *text, const char *word, int state, int lock)
+ {
+- char *argv[AST_MAX_ARGS];
++ const char *argv[AST_MAX_ARGS];
+ struct ast_cli_entry *e = NULL;
+ int x = 0, argindex, matchlen;
+ int matchnum=0;
+@@ -2248,7 +2315,7 @@
+
+ int ast_cli_command_full(int uid, int gid, int fd, const char *s)
+ {
+- char *args[AST_MAX_ARGS + 1];
++ const 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);
+Index: main/ulaw.c
+===================================================================
+--- a/main/ulaw.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/main/ulaw.c (.../trunk) (revision 202568)
+@@ -177,7 +177,7 @@
+ #ifndef G711_NEW_ALGORITHM
+ for (i = 0;i < 256;i++) {
+ short mu,e,f,y;
+- static short etab[]={0,132,396,924,1980,4092,8316,16764};
++ static const short etab[]={0,132,396,924,1980,4092,8316,16764};
+
+ mu = 255-i;
+ e = (mu & 0x70)/16;
+Index: main/dial.c
+===================================================================
+--- a/main/dial.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/main/dial.c (.../trunk) (revision 202568)
+@@ -37,6 +37,7 @@
+ #include "asterisk/dial.h"
+ #include "asterisk/pbx.h"
+ #include "asterisk/musiconhold.h"
++#include "asterisk/app.h"
+
+ /*! \brief Main dialing structure. Contains global options, channels being dialed, and more! */
+ struct ast_dial {
+@@ -274,20 +275,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 +429,16 @@
+ 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);
++ if (ast_channel_connected_line_macro(channel->owner, chan, fr, 1, 1)) {
++ 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/logger.c
+===================================================================
+--- a/main/logger.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/main/logger.c (.../trunk) (revision 202568)
+@@ -54,7 +54,7 @@
+ from <syslog.h> which is included by logger.h */
+ #include <syslog.h>
+
+-static int syslog_level_map[] = {
++static const int syslog_level_map[] = {
+ LOG_DEBUG,
+ LOG_INFO, /* arbitrary equivalent of LOG_EVENT */
+ LOG_NOTICE,
+@@ -89,16 +89,15 @@
+ #else
+ #define GETTID() getpid()
+ #endif
+-
+ static char dateformat[256] = "%b %e %T"; /* Original Asterisk Format */
+
+ static char queue_log_name[256] = QUEUELOG;
+ static char exec_after_rotate[256] = "";
+
+ static int filesize_reload_needed;
+-static int global_logmask = -1;
++static unsigned int global_logmask = 0xFFFF;
+
+-enum rotatestrategy {
++static enum rotatestrategy {
+ SEQUENTIAL = 1 << 0, /* Original method - create a new file, in order */
+ ROTATE = 1 << 1, /* Rotate all files, such that the oldest file has the highest suffix */
+ TIMESTAMP = 1 << 2, /* Append the epoch timestamp onto the end of the archived file */
+@@ -106,8 +105,7 @@
+
+ static struct {
+ unsigned int queue_log:1;
+- unsigned int event_log:1;
+-} logfiles = { 1, 1 };
++} logfiles = { 1 };
+
+ static char hostname[MAXHOSTNAMELEN];
+
+@@ -118,13 +116,24 @@
+ };
+
+ struct logchannel {
+- int logmask; /* What to log to this channel */
+- int disabled; /* If this channel is disabled or not */
+- int facility; /* syslog facility */
+- enum logtypes type; /* Type of log channel */
+- FILE *fileptr; /* logfile logging file pointer */
+- char filename[256]; /* Filename */
++ /*! What to log to this channel */
++ unsigned int logmask;
++ /*! If this channel is disabled or not */
++ int disabled;
++ /*! syslog facility */
++ int facility;
++ /*! Type of log channel */
++ enum logtypes type;
++ /*! logfile logging file pointer */
++ FILE *fileptr;
++ /*! Filename */
++ char filename[PATH_MAX];
++ /*! field for linking to list */
+ AST_LIST_ENTRY(logchannel) list;
++ /*! Line number from configuration file */
++ int lineno;
++ /*! Components (levels) from last config load */
++ char components[0];
+ };
+
+ static AST_RWLIST_HEAD_STATIC(logchannels, logchannel);
+@@ -136,14 +145,17 @@
+
+ struct logmsg {
+ enum logmsgtypes type;
+- char date[256];
+ int level;
+- char file[80];
+ int line;
+- char function[80];
+ long process_id;
++ AST_DECLARE_STRING_FIELDS(
++ AST_STRING_FIELD(date);
++ AST_STRING_FIELD(file);
++ AST_STRING_FIELD(function);
++ AST_STRING_FIELD(message);
++ AST_STRING_FIELD(level_name);
++ );
+ AST_LIST_ENTRY(logmsg) list;
+- char str[0];
+ };
+
+ static AST_LIST_HEAD_STATIC(logmsgs, logmsg);
+@@ -151,29 +163,63 @@
+ static ast_cond_t logcond;
+ static int close_logger_thread;
+
+-static FILE *eventlog;
+ static FILE *qlog;
+
+-/*! \brief Logging channels used in the Asterisk logging system */
+-static char *levels[] = {
++/*! \brief Logging channels used in the Asterisk logging system
++ *
++ * The first 16 levels are reserved for system usage, and the remaining
++ * levels are reserved for usage by dynamic levels registered via
++ * ast_logger_register_level.
++ */
++
++/* Modifications to this array are protected by the rwlock in the
++ * logchannels list.
++ */
++
++static char *levels[32] = {
+ "DEBUG",
+- "EVENT",
++ "---EVENT---", /* no longer used */
+ "NOTICE",
+ "WARNING",
+ "ERROR",
+ "VERBOSE",
+- "DTMF"
++ "DTMF",
+ };
+
+ /*! \brief Colors used in the console for logging */
+-static int colors[] = {
++static const int colors[32] = {
+ COLOR_BRGREEN,
+- COLOR_BRBLUE,
++ COLOR_BRBLUE, /* no longer used */
+ COLOR_YELLOW,
+ COLOR_BRRED,
+ COLOR_RED,
+ COLOR_GREEN,
+- COLOR_BRGREEN
++ COLOR_BRGREEN,
++ 0,
++ 0,
++ 0,
++ 0,
++ 0,
++ 0,
++ 0,
++ 0,
++ 0,
++ COLOR_BRBLUE,
++ COLOR_BRBLUE,
++ COLOR_BRBLUE,
++ COLOR_BRBLUE,
++ COLOR_BRBLUE,
++ COLOR_BRBLUE,
++ COLOR_BRBLUE,
++ COLOR_BRBLUE,
++ COLOR_BRBLUE,
++ COLOR_BRBLUE,
++ COLOR_BRBLUE,
++ COLOR_BRBLUE,
++ COLOR_BRBLUE,
++ COLOR_BRBLUE,
++ COLOR_BRBLUE,
++ COLOR_BRBLUE,
+ };
+
+ AST_THREADSTORAGE(verbose_buf);
+@@ -182,30 +228,24 @@
+ AST_THREADSTORAGE(log_buf);
+ #define LOG_BUF_INIT_SIZE 256
+
+-static int make_components(const char *s, int lineno)
++static unsigned int make_components(const char *s, int lineno)
+ {
+ char *w;
+- int res = 0;
++ unsigned int res = 0;
+ char *stringp = ast_strdupa(s);
++ unsigned int x;
+
+ while ((w = strsep(&stringp, ","))) {
++ int found = 0;
++
+ w = ast_skip_blanks(w);
+- if (!strcasecmp(w, "error"))
+- res |= (1 << __LOG_ERROR);
+- else if (!strcasecmp(w, "warning"))
+- res |= (1 << __LOG_WARNING);
+- else if (!strcasecmp(w, "notice"))
+- res |= (1 << __LOG_NOTICE);
+- else if (!strcasecmp(w, "event"))
+- res |= (1 << __LOG_EVENT);
+- else if (!strcasecmp(w, "debug"))
+- res |= (1 << __LOG_DEBUG);
+- else if (!strcasecmp(w, "verbose"))
+- res |= (1 << __LOG_VERBOSE);
+- else if (!strcasecmp(w, "dtmf"))
+- res |= (1 << __LOG_DTMF);
+- else {
+- fprintf(stderr, "Logfile Warning: Unknown keyword '%s' at line %d of logger.conf\n", w, lineno);
++
++ for (x = 0; x < ARRAY_LEN(levels); x++) {
++ if (levels[x] && !strcasecmp(w, levels[x])) {
++ res |= (1 << x);
++ found = 1;
++ break;
++ }
+ }
+ }
+
+@@ -220,9 +260,12 @@
+ CODE *cptr;
+ #endif
+
+- if (ast_strlen_zero(channel) || !(chan = ast_calloc(1, sizeof(*chan))))
++ if (ast_strlen_zero(channel) || !(chan = ast_calloc(1, sizeof(*chan) + strlen(components) + 1)))
+ return NULL;
+
++ strcpy(chan->components, components);
++ chan->lineno = lineno;
++
+ if (!strcasecmp(channel, "console")) {
+ chan->type = LOGTYPE_CONSOLE;
+ } else if (!strncasecmp(channel, "syslog", 6)) {
+@@ -296,7 +339,7 @@
+ }
+
+ chan->type = LOGTYPE_SYSLOG;
+- snprintf(chan->filename, sizeof(chan->filename), "%s", channel);
++ ast_copy_string(chan->filename, channel, sizeof(chan->filename));
+ openlog("asterisk", LOG_PID, chan->facility);
+ } else {
+ if (!ast_strlen_zero(hostname)) {
+@@ -306,14 +349,14 @@
+ snprintf(chan->filename, sizeof(chan->filename), "%s/%s",
+ channel[0] != '/' ? ast_config_AST_LOG_DIR : "", channel);
+ }
+- chan->fileptr = fopen(chan->filename, "a");
+- if (!chan->fileptr) {
++ if (!(chan->fileptr = fopen(chan->filename, "a"))) {
+ /* Can't log here, since we're called with a lock */
+ fprintf(stderr, "Logger Warning: Unable to open log file '%s': %s\n", chan->filename, strerror(errno));
+ }
+ chan->type = LOGTYPE_FILE;
+ }
+- chan->logmask = make_components(components, lineno);
++ chan->logmask = make_components(chan->components, lineno);
++
+ return chan;
+ }
+
+@@ -333,10 +376,10 @@
+ AST_RWLIST_WRLOCK(&logchannels);
+ while ((chan = AST_RWLIST_REMOVE_HEAD(&logchannels, list)))
+ ast_free(chan);
++ global_logmask = 0;
+ if (!locked)
+ AST_RWLIST_UNLOCK(&logchannels);
+
+- global_logmask = 0;
+ errno = 0;
+ /* close syslog */
+ closelog();
+@@ -350,13 +393,13 @@
+ if (!(chan = ast_calloc(1, sizeof(*chan))))
+ return;
+ chan->type = LOGTYPE_CONSOLE;
+- chan->logmask = 28; /*warning,notice,error */
++ chan->logmask = __LOG_WARNING | __LOG_NOTICE | __LOG_ERROR;
+ if (!locked)
+ AST_RWLIST_WRLOCK(&logchannels);
+ AST_RWLIST_INSERT_HEAD(&logchannels, chan, list);
++ global_logmask |= chan->logmask;
+ if (!locked)
+ AST_RWLIST_UNLOCK(&logchannels);
+- global_logmask |= chan->logmask;
+ return;
+ }
+
+@@ -376,8 +419,6 @@
+ ast_copy_string(dateformat, "%b %e %T", sizeof(dateformat));
+ if ((s = ast_variable_retrieve(cfg, "general", "queue_log")))
+ logfiles.queue_log = ast_true(s);
+- if ((s = ast_variable_retrieve(cfg, "general", "event_log")))
+- logfiles.event_log = ast_true(s);
+ if ((s = ast_variable_retrieve(cfg, "general", "queue_log_name")))
+ ast_copy_string(queue_log_name, s, sizeof(queue_log_name));
+ if ((s = ast_variable_retrieve(cfg, "general", "exec_after_rotate")))
+@@ -578,7 +619,7 @@
+ if (ast_safe_system(buf) != -1) {
+ ast_log(LOG_WARNING, "error executing '%s'\n", buf);
+ }
+- ast_channel_free(c);
++ c = ast_channel_release(c);
+ }
+ return res;
+ }
+@@ -586,29 +627,13 @@
+ static int reload_logger(int rotate)
+ {
+ char old[PATH_MAX] = "";
+- int event_rotate = rotate, queue_rotate = rotate;
++ int queue_rotate = rotate;
+ struct logchannel *f;
+ int res = 0;
+ struct stat st;
+
+ AST_RWLIST_WRLOCK(&logchannels);
+
+- if (eventlog) {
+- if (rotate < 0) {
+- /* Check filesize - this one typically doesn't need an auto-rotate */
+- snprintf(old, sizeof(old), "%s/%s", ast_config_AST_LOG_DIR, EVENTLOG);
+- if (stat(old, &st) != 0 || st.st_size > 0x40000000) { /* Arbitrarily, 1 GB */
+- fclose(eventlog);
+- eventlog = NULL;
+- } else
+- event_rotate = 0;
+- } else {
+- fclose(eventlog);
+- eventlog = NULL;
+- }
+- } else
+- event_rotate = 0;
+-
+ if (qlog) {
+ if (rotate < 0) {
+ /* Check filesize - this one typically doesn't need an auto-rotate */
+@@ -644,21 +669,6 @@
+
+ init_logger_chain(1 /* locked */);
+
+- if (logfiles.event_log) {
+- snprintf(old, sizeof(old), "%s/%s", ast_config_AST_LOG_DIR, EVENTLOG);
+- if (event_rotate)
+- rotate_file(old);
+-
+- eventlog = fopen(old, "a");
+- if (eventlog) {
+- ast_log(LOG_EVENT, "Restarted Asterisk Event Logger\n");
+- ast_verb(1, "Asterisk Event Logger restarted\n");
+- } else {
+- ast_log(LOG_ERROR, "Unable to create event log: %s\n", strerror(errno));
+- res = -1;
+- }
+- }
+-
+ if (logfiles.queue_log) {
+ snprintf(old, sizeof(old), "%s/%s", ast_config_AST_LOG_DIR, queue_log_name);
+ if (queue_rotate)
+@@ -669,7 +679,6 @@
+ AST_RWLIST_UNLOCK(&logchannels);
+ ast_queue_log("NONE", "NONE", "NONE", "CONFIGRELOAD", "%s", "");
+ AST_RWLIST_WRLOCK(&logchannels);
+- ast_log(LOG_EVENT, "Restarted Asterisk Queue Logger\n");
+ ast_verb(1, "Asterisk Queue Logger restarted\n");
+ } else {
+ ast_log(LOG_ERROR, "Unable to create queue log: %s\n", strerror(errno));
+@@ -749,13 +758,17 @@
+ if (a->argc < 5)
+ return CLI_SHOWUSAGE;
+
+- for (x = 0; x <= NUMLOGLEVELS; x++) {
+- if (!strcasecmp(a->argv[3], levels[x])) {
++ AST_RWLIST_WRLOCK(&logchannels);
++
++ for (x = 0; x < ARRAY_LEN(levels); x++) {
++ if (levels[x] && !strcasecmp(a->argv[3], levels[x])) {
+ level = x;
+ break;
+ }
+ }
+
++ AST_RWLIST_UNLOCK(&logchannels);
++
+ state = ast_true(a->argv[4]) ? 1 : 0;
+
+ if (level != -1) {
+@@ -788,23 +801,16 @@
+ ast_cli(a->fd, "-------------\n");
+ AST_RWLIST_RDLOCK(&logchannels);
+ AST_RWLIST_TRAVERSE(&logchannels, chan, list) {
++ unsigned int level;
++
+ ast_cli(a->fd, FORMATL, chan->filename, chan->type == LOGTYPE_CONSOLE ? "Console" : (chan->type == LOGTYPE_SYSLOG ? "Syslog" : "File"),
+ chan->disabled ? "Disabled" : "Enabled");
+ ast_cli(a->fd, " - ");
+- if (chan->logmask & (1 << __LOG_DEBUG))
+- ast_cli(a->fd, "Debug ");
+- if (chan->logmask & (1 << __LOG_DTMF))
+- ast_cli(a->fd, "DTMF ");
+- if (chan->logmask & (1 << __LOG_VERBOSE))
+- ast_cli(a->fd, "Verbose ");
+- if (chan->logmask & (1 << __LOG_WARNING))
+- ast_cli(a->fd, "Warning ");
+- if (chan->logmask & (1 << __LOG_NOTICE))
+- ast_cli(a->fd, "Notice ");
+- if (chan->logmask & (1 << __LOG_ERROR))
+- ast_cli(a->fd, "Error ");
+- if (chan->logmask & (1 << __LOG_EVENT))
+- ast_cli(a->fd, "Event ");
++ for (level = 0; level < ARRAY_LEN(levels); level++) {
++ if (chan->logmask & (1 << level)) {
++ ast_cli(a->fd, "%s ", levels[level]);
++ }
++ }
+ ast_cli(a->fd, "\n");
+ }
+ AST_RWLIST_UNLOCK(&logchannels);
+@@ -834,7 +840,7 @@
+ return 0;
+ }
+
+-static void ast_log_vsyslog(int level, const char *file, int line, const char *function, char *str, long pid)
++static void ast_log_vsyslog(int level, const char *file, int line, const char *function, const char *str, long pid)
+ {
+ char buf[BUFSIZ];
+
+@@ -867,13 +873,6 @@
+
+ AST_RWLIST_RDLOCK(&logchannels);
+
+- if (logfiles.event_log && logmsg->level == __LOG_EVENT) {
+- fprintf(eventlog, "%s asterisk[%ld]: %s", logmsg->date, (long)getpid(), logmsg->str);
+- fflush(eventlog);
+- AST_RWLIST_UNLOCK(&logchannels);
+- return;
+- }
+-
+ if (!AST_RWLIST_EMPTY(&logchannels)) {
+ AST_RWLIST_TRAVERSE(&logchannels, chan, list) {
+ /* If the channel is disabled, then move on to the next one */
+@@ -881,7 +880,7 @@
+ continue;
+ /* Check syslog channels */
+ if (chan->type == LOGTYPE_SYSLOG && (chan->logmask & (1 << logmsg->level))) {
+- ast_log_vsyslog(logmsg->level, logmsg->file, logmsg->line, logmsg->function, logmsg->str, logmsg->process_id);
++ ast_log_vsyslog(logmsg->level, logmsg->file, logmsg->line, logmsg->function, logmsg->message, logmsg->process_id);
+ /* Console channels */
+ } else if (chan->type == LOGTYPE_CONSOLE && (chan->logmask & (1 << logmsg->level))) {
+ char linestr[128];
+@@ -896,12 +895,12 @@
+ /* Build string to print out */
+ snprintf(buf, sizeof(buf), "[%s] %s[%ld]: %s:%s %s: %s",
+ logmsg->date,
+- term_color(tmp1, levels[logmsg->level], colors[logmsg->level], 0, sizeof(tmp1)),
++ term_color(tmp1, logmsg->level_name, colors[logmsg->level], 0, sizeof(tmp1)),
+ logmsg->process_id,
+ term_color(tmp2, logmsg->file, COLOR_BRWHITE, 0, sizeof(tmp2)),
+ term_color(tmp3, linestr, COLOR_BRWHITE, 0, sizeof(tmp3)),
+ term_color(tmp4, logmsg->function, COLOR_BRWHITE, 0, sizeof(tmp4)),
+- logmsg->str);
++ logmsg->message);
+ /* Print out */
+ ast_console_puts_mutable(buf, logmsg->level);
+ /* File channels */
+@@ -914,8 +913,8 @@
+
+ /* Print out to the file */
+ res = fprintf(chan->fileptr, "[%s] %s[%ld] %s: %s",
+- logmsg->date, levels[logmsg->level], logmsg->process_id, logmsg->file, logmsg->str);
+- if (res <= 0 && !ast_strlen_zero(logmsg->str)) {
++ logmsg->date, logmsg->level_name, logmsg->process_id, logmsg->file, logmsg->message);
++ if (res <= 0 && !ast_strlen_zero(logmsg->message)) {
+ fprintf(stderr, "**** Asterisk Logging Error: ***********\n");
+ if (errno == ENOMEM || errno == ENOSPC)
+ fprintf(stderr, "Asterisk logging error: Out of disk space, can't log to log file %s\n", chan->filename);
+@@ -929,7 +928,7 @@
+ }
+ }
+ } else if (logmsg->level != __LOG_VERBOSE) {
+- fputs(logmsg->str, stdout);
++ fputs(logmsg->message, stdout);
+ }
+
+ AST_RWLIST_UNLOCK(&logchannels);
+@@ -937,7 +936,6 @@
+ /* If we need to reload because of the file size, then do so */
+ if (filesize_reload_needed) {
+ reload_logger(-1);
+- ast_log(LOG_EVENT, "Rotated Logs Per SIGXFSZ (Exceeded file size limit)\n");
+ ast_verb(1, "Rotated Logs Per SIGXFSZ (Exceeded file size limit)\n");
+ }
+
+@@ -952,7 +950,7 @@
+ /* Iterate through the list of verbosers and pass them the log message string */
+ AST_RWLIST_RDLOCK(&verbosers);
+ AST_RWLIST_TRAVERSE(&verbosers, v, list)
+- v->verboser(logmsg->str);
++ v->verboser(logmsg->message);
+ AST_RWLIST_UNLOCK(&verbosers);
+
+ return;
+@@ -1023,19 +1021,6 @@
+ /* create log channels */
+ init_logger_chain(0 /* locked */);
+
+- /* create the eventlog */
+- if (logfiles.event_log) {
+- snprintf(tmp, sizeof(tmp), "%s/%s", ast_config_AST_LOG_DIR, EVENTLOG);
+- eventlog = fopen(tmp, "a");
+- if (eventlog) {
+- ast_log(LOG_EVENT, "Started Asterisk Event Logger\n");
+- ast_verb(1, "Asterisk Event Logger Started %s\n", tmp);
+- } else {
+- ast_log(LOG_ERROR, "Unable to create event log: %s\n", strerror(errno));
+- res = -1;
+- }
+- }
+-
+ if (logfiles.queue_log) {
+ snprintf(tmp, sizeof(tmp), "%s/%s", ast_config_AST_LOG_DIR, queue_log_name);
+ qlog = fopen(tmp, "a");
+@@ -1059,11 +1044,6 @@
+
+ AST_RWLIST_WRLOCK(&logchannels);
+
+- if (eventlog) {
+- fclose(eventlog);
+- eventlog = NULL;
+- }
+-
+ if (qlog) {
+ fclose(qlog);
+ qlog = NULL;
+@@ -1094,6 +1074,7 @@
+ struct timeval now = ast_tvnow();
+ int res = 0;
+ va_list ap;
++ char datestring[256];
+
+ if (!(buf = ast_str_thread_get(&log_buf, LOG_BUF_INIT_SIZE)))
+ return;
+@@ -1139,24 +1120,26 @@
+ return;
+
+ /* Create a new logging message */
+- if (!(logmsg = ast_calloc(1, sizeof(*logmsg) + res + 1)))
++ if (!(logmsg = ast_calloc_with_stringfields(1, struct logmsg, res + 128)))
+ return;
+
+ /* Copy string over */
+- strcpy(logmsg->str, ast_str_buffer(buf));
++ ast_string_field_set(logmsg, message, ast_str_buffer(buf));
+
+ /* Set type to be normal */
+ logmsg->type = LOGMSG_NORMAL;
+
+ /* Create our date/time */
+ ast_localtime(&now, &tm, NULL);
+- ast_strftime(logmsg->date, sizeof(logmsg->date), dateformat, &tm);
++ ast_strftime(datestring, sizeof(datestring), dateformat, &tm);
++ ast_string_field_set(logmsg, date, datestring);
+
+ /* Copy over data */
+ logmsg->level = level;
+ logmsg->line = line;
+- ast_copy_string(logmsg->file, file, sizeof(logmsg->file));
+- ast_copy_string(logmsg->function, function, sizeof(logmsg->function));
++ ast_string_field_set(logmsg, level_name, levels[level]);
++ ast_string_field_set(logmsg, file, file);
++ ast_string_field_set(logmsg, function, function);
+ logmsg->process_id = (long) GETTID();
+
+ /* If the logger thread is active, append it to the tail end of the list - otherwise skip that step */
+@@ -1225,6 +1208,9 @@
+ for (i = 0; i < bt->num_frames; i++) {
+ ast_log(LOG_DEBUG, "#%d: [%p] %s\n", i, bt->addresses[i], strings[i]);
+ }
++
++ /* MALLOC_DEBUG will erroneously report an error here, unless we undef the macro. */
++#undef free
+ free(strings);
+ } else {
+ ast_debug(1, "Could not allocate memory for backtrace\n");
+@@ -1269,12 +1255,12 @@
+ if (res == AST_DYNSTR_BUILD_FAILED)
+ return;
+
+- if (!(logmsg = ast_calloc(1, sizeof(*logmsg) + res + 1)))
++ if (!(logmsg = ast_calloc_with_stringfields(1, struct logmsg, res + 128)))
+ return;
+
+- strcpy(logmsg->str, ast_str_buffer(buf));
++ ast_string_field_set(logmsg, message, ast_str_buffer(buf));
+
+- ast_log(__LOG_VERBOSE, file, line, func, "%s", logmsg->str + 1);
++ ast_log(__LOG_VERBOSE, file, line, func, "%s", logmsg->message + 1);
+
+ /* Set type */
+ logmsg->type = LOGMSG_VERBOSE;
+@@ -1294,6 +1280,7 @@
+ void __ast_verbose(const char *file, int line, const char *func, const char *fmt, ...)
+ {
+ va_list ap;
++
+ va_start(ap, fmt);
+ __ast_verbose_ap(file, line, func, fmt, ap);
+ va_end(ap);
+@@ -1305,6 +1292,7 @@
+ void ast_verbose(const char *fmt, ...)
+ {
+ va_list ap;
++
+ va_start(ap, fmt);
+ __ast_verbose_ap("", 0, "", fmt, ap);
+ va_end(ap);
+@@ -1343,3 +1331,102 @@
+
+ return cur ? 0 : -1;
+ }
++
++static void update_logchannels(void)
++{
++ struct logchannel *cur;
++
++ AST_RWLIST_WRLOCK(&logchannels);
++
++ global_logmask = 0;
++
++ AST_RWLIST_TRAVERSE(&logchannels, cur, list) {
++ cur->logmask = make_components(cur->components, cur->lineno);
++ global_logmask |= cur->logmask;
++ }
++
++ AST_RWLIST_UNLOCK(&logchannels);
++}
++
++int ast_logger_register_level(const char *name)
++{
++ unsigned int level;
++ unsigned int available = 0;
++
++ AST_RWLIST_WRLOCK(&logchannels);
++
++ for (level = 0; level < ARRAY_LEN(levels); level++) {
++ if ((level >= 16) && !available && !levels[level]) {
++ available = level;
++ continue;
++ }
++
++ if (levels[level] && !strcasecmp(levels[level], name)) {
++ ast_log(LOG_WARNING,
++ "Unable to register dynamic logger level '%s': a standard logger level uses that name.\n",
++ name);
++ AST_RWLIST_UNLOCK(&logchannels);
++
++ return -1;
++ }
++ }
++
++ if (!available) {
++ ast_log(LOG_WARNING,
++ "Unable to register dynamic logger level '%s'; maximum number of levels registered.\n",
++ name);
++ AST_RWLIST_UNLOCK(&logchannels);
++
++ return -1;
++ }
++
++ levels[available] = ast_strdup(name);
++
++ AST_RWLIST_UNLOCK(&logchannels);
++
++ ast_debug(1, "Registered dynamic logger level '%s' with index %d.\n", name, available);
++
++ update_logchannels();
++
++ return available;
++}
++
++void ast_logger_unregister_level(const char *name)
++{
++ unsigned int found = 0;
++ unsigned int x;
++
++ AST_RWLIST_WRLOCK(&logchannels);
++
++ for (x = 16; x < ARRAY_LEN(levels); x++) {
++ if (!levels[x]) {
++ continue;
++ }
++
++ if (strcasecmp(levels[x], name)) {
++ continue;
++ }
++
++ found = 1;
++ break;
++ }
++
++ if (found) {
++ /* take this level out of the global_logmask, to ensure that no new log messages
++ * will be queued for it
++ */
++
++ global_logmask &= ~(1 << x);
++
++ free(levels[x]);
++ levels[x] = NULL;
++ AST_RWLIST_UNLOCK(&logchannels);
++
++ ast_debug(1, "Unregistered dynamic logger level '%s' with index %d.\n", name, x);
++
++ update_logchannels();
++ } else {
++ AST_RWLIST_UNLOCK(&logchannels);
++ }
++}
++
+Index: main/pbx.c
+===================================================================
+--- a/main/pbx.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/main/pbx.c (.../trunk) (revision 202568)
+@@ -717,6 +717,24 @@
+ <ref type="application">RaiseException</ref>
+ </see-also>
+ </function>
++ <manager name="ShowDialPlan" language="en_US">
++ <synopsis>
++ La merde se produit.
++ </synopsis>
++ <syntax>
++ <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
++ <parameter name="Extension">
++ <para>Show a specific extension.</para>
++ </parameter>
++ <parameter name="Context">
++ <para>Show a specific context.</para>
++ </parameter>
++ </syntax>
++ <description>
++ <para>Show dialplan contexts and extensions. Be aware that showing the full dialplan
++ may take a lot of capacity.</para>
++ </description>
++ </manager>
+ ***/
+
+ #ifdef LOW_MEMORY
+@@ -819,11 +837,11 @@
+ {
+ int is_pattern; /* the pattern started with '_' */
+ int deleted; /* if this is set, then... don't return it */
+- char *x; /* the pattern itself-- matches a single char */
+ int specificity; /* simply the strlen of x, or 10 for X, 9 for Z, and 8 for N; and '.' and '!' will add 11 ? */
+ struct match_char *alt_char;
+ struct match_char *next_char;
+ struct ast_exten *exten; /* attached to last char of a pattern for exten */
++ char x[1]; /* the pattern itself-- matches a single char */
+ };
+
+ struct scoreboard /* make sure all fields are 0 before calling new_find_extension */
+@@ -855,7 +873,7 @@
+
+ /*! \brief ast_app: A registered application */
+ struct ast_app {
+- int (*execute)(struct ast_channel *chan, void *data);
++ int (*execute)(struct ast_channel *chan, const char *data);
+ 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;' */
+@@ -863,7 +881,9 @@
+ AST_STRING_FIELD(arguments); /*!< Arguments description */
+ AST_STRING_FIELD(seealso); /*!< See also */
+ );
+- enum ast_doc_src docsrc;/*!< Where the documentation come from. */
++#ifdef AST_XML_DOCS
++ enum ast_doc_src docsrc; /*!< Where the documentation come from. */
++#endif
+ 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 */
+@@ -919,38 +939,38 @@
+ int priority; /*!< Priority associated with this exception */
+ };
+
+-static int pbx_builtin_answer(struct ast_channel *, void *);
+-static int pbx_builtin_goto(struct ast_channel *, void *);
+-static int pbx_builtin_hangup(struct ast_channel *, void *);
+-static int pbx_builtin_background(struct ast_channel *, void *);
+-static int pbx_builtin_wait(struct ast_channel *, void *);
+-static int pbx_builtin_waitexten(struct ast_channel *, void *);
+-static int pbx_builtin_incomplete(struct ast_channel *, void *);
+-static int pbx_builtin_resetcdr(struct ast_channel *, void *);
+-static int pbx_builtin_setamaflags(struct ast_channel *, void *);
+-static int pbx_builtin_ringing(struct ast_channel *, void *);
+-static int pbx_builtin_proceeding(struct ast_channel *, void *);
+-static int pbx_builtin_progress(struct ast_channel *, void *);
+-static int pbx_builtin_congestion(struct ast_channel *, void *);
+-static int pbx_builtin_busy(struct ast_channel *, void *);
+-static int pbx_builtin_noop(struct ast_channel *, void *);
+-static int pbx_builtin_gotoif(struct ast_channel *, void *);
+-static int pbx_builtin_gotoiftime(struct ast_channel *, void *);
+-static int pbx_builtin_execiftime(struct ast_channel *, void *);
+-static int pbx_builtin_saynumber(struct ast_channel *, void *);
+-static int pbx_builtin_saydigits(struct ast_channel *, void *);
+-static int pbx_builtin_saycharacters(struct ast_channel *, void *);
+-static int pbx_builtin_sayphonetic(struct ast_channel *, void *);
++static int pbx_builtin_answer(struct ast_channel *, const char *);
++static int pbx_builtin_goto(struct ast_channel *, const char *);
++static int pbx_builtin_hangup(struct ast_channel *, const char *);
++static int pbx_builtin_background(struct ast_channel *, const char *);
++static int pbx_builtin_wait(struct ast_channel *, const char *);
++static int pbx_builtin_waitexten(struct ast_channel *, const char *);
++static int pbx_builtin_incomplete(struct ast_channel *, const char *);
++static int pbx_builtin_resetcdr(struct ast_channel *, const char *);
++static int pbx_builtin_setamaflags(struct ast_channel *, const char *);
++static int pbx_builtin_ringing(struct ast_channel *, const char *);
++static int pbx_builtin_proceeding(struct ast_channel *, const char *);
++static int pbx_builtin_progress(struct ast_channel *, const char *);
++static int pbx_builtin_congestion(struct ast_channel *, const char *);
++static int pbx_builtin_busy(struct ast_channel *, const char *);
++static int pbx_builtin_noop(struct ast_channel *, const char *);
++static int pbx_builtin_gotoif(struct ast_channel *, const char *);
++static int pbx_builtin_gotoiftime(struct ast_channel *, const char *);
++static int pbx_builtin_execiftime(struct ast_channel *, const char *);
++static int pbx_builtin_saynumber(struct ast_channel *, const char *);
++static int pbx_builtin_saydigits(struct ast_channel *, const char *);
++static int pbx_builtin_saycharacters(struct ast_channel *, const char *);
++static int pbx_builtin_sayphonetic(struct ast_channel *, const char *);
+ static int matchcid(const char *cidpattern, const char *callerid);
+-int pbx_builtin_setvar(struct ast_channel *, void *);
+-void log_match_char_tree(struct match_char *node, char *prefix); /* for use anywhere */
+-int pbx_builtin_setvar_multiple(struct ast_channel *, void *);
+-static int pbx_builtin_importvar(struct ast_channel *, void *);
++#ifdef NEED_DEBUG
++static void log_match_char_tree(struct match_char *node, char *prefix); /* for use anywhere */
++#endif
++static int pbx_builtin_importvar(struct ast_channel *, const char *);
+ 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 struct match_char *already_in_tree(struct match_char *current, char *pat);
++static struct match_char *already_in_tree(struct match_char *current, char *pat, int is_pattern);
+ 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,
+@@ -959,11 +979,9 @@
+ 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);
+-int ast_hashtab_compare_contexts(const void *ah_a, const void *ah_b);
+ static int hashtab_compare_extens(const void *ha_a, const void *ah_b);
+ static int hashtab_compare_exten_numbers(const void *ah_a, const void *ah_b);
+ static int hashtab_compare_exten_labels(const void *ah_a, const void *ah_b);
+-unsigned int ast_hashtab_hash_contexts(const void *obj);
+ static unsigned int hashtab_hash_extens(const void *obj);
+ static unsigned int hashtab_hash_priority(const void *obj);
+ static unsigned int hashtab_hash_labels(const void *obj);
+@@ -1083,7 +1101,7 @@
+ /*! \brief Declaration of builtin applications */
+ static struct pbx_builtin {
+ char name[AST_MAX_APP];
+- int (*execute)(struct ast_channel *chan, void *data);
++ int (*execute)(struct ast_channel *chan, const char *data);
+ } builtins[] =
+ {
+ /* These applications are built into the PBX core and do not
+@@ -1320,9 +1338,9 @@
+ /*
+ \note This function is special. It saves the stack so that no matter
+ how many times it is called, it returns to the same place */
+-int pbx_exec(struct ast_channel *c, /*!< Channel */
+- struct ast_app *app, /*!< Application */
+- void *data) /*!< Data for execution */
++int pbx_exec(struct ast_channel *c, /*!< Channel */
++ struct ast_app *app, /*!< Application */
++ const char *data) /*!< Data for execution */
+ {
+ int res;
+ struct ast_module_user *u = NULL;
+@@ -1492,14 +1510,15 @@
+ #endif
+ }
+
+-void log_match_char_tree(struct match_char *node, char *prefix)
++#ifdef NEED_DEBUG
++static void log_match_char_tree(struct match_char *node, char *prefix)
+ {
+ char extenstr[40];
+ struct ast_str *my_prefix = ast_str_alloca(1024);
+
+ extenstr[0] = '\0';
+
+- if (node && node->exten && node->exten)
++ if (node && node->exten)
+ snprintf(extenstr, sizeof(extenstr), "(%p)", node->exten);
+
+ if (strlen(node->x) > 1) {
+@@ -1520,6 +1539,7 @@
+ if (node->alt_char)
+ log_match_char_tree(node->alt_char, prefix);
+ }
++#endif
+
+ static void cli_match_char_tree(struct match_char *node, char *prefix, int fd)
+ {
+@@ -1528,7 +1548,7 @@
+
+ extenstr[0] = '\0';
+
+- if (node && node->exten && node->exten)
++ if (node && node->exten)
+ snprintf(extenstr, sizeof(extenstr), "(%p)", node->exten);
+
+ if (strlen(node->x) > 1) {
+@@ -1603,6 +1623,7 @@
+ return e3;
+ }
+ }
++
+ return NULL;
+ }
+
+@@ -1638,117 +1659,123 @@
+ ast_log(LOG_NOTICE,"new_find_extension called with %s on (sub)tree NULL action=%s\n", str, action2str(action));
+ #endif
+ for (p = tree; p; p = p->alt_char) {
+- if (p->x[0] == 'N') {
+- if (p->x[1] == 0 && *str >= '2' && *str <= '9' ) {
+-#define NEW_MATCHER_CHK_MATCH \
+- if (p->exten && !(*(str + 1))) { /* if a shorter pattern matches along the way, might as well report it */ \
+- if (action == E_MATCH || action == E_SPAWN || action == E_FINDLABEL) { /* if in CANMATCH/MATCHMORE, don't let matches get in the way */ \
+- update_scoreboard(score, length + 1, spec + p->specificity, p->exten, 0, callerid, p->deleted, p); \
+- if (!p->deleted) { \
+- if (action == E_FINDLABEL) { \
+- if (ast_hashtab_lookup(score->exten->peer_label_table, &pattern)) { \
+- ast_debug(4, "Found label in preferred extension\n"); \
+- return; \
+- } \
+- } else { \
+- ast_debug(4,"returning an exact match-- first found-- %s\n", p->exten->exten); \
+- return; /* the first match, by definition, will be the best, because of the sorted tree */ \
+- } \
+- } \
+- } \
++ if (p->is_pattern) {
++ if (p->x[0] == 'N') {
++ if (p->x[1] == 0 && *str >= '2' && *str <= '9' ) {
++#define NEW_MATCHER_CHK_MATCH \
++ if (p->exten && !(*(str + 1))) { /* if a shorter pattern matches along the way, might as well report it */ \
++ if (action == E_MATCH || action == E_SPAWN || action == E_FINDLABEL) { /* if in CANMATCH/MATCHMORE, don't let matches get in the way */ \
++ update_scoreboard(score, length + 1, spec + p->specificity, p->exten, 0, callerid, p->deleted, p); \
++ if (!p->deleted) { \
++ if (action == E_FINDLABEL) { \
++ if (ast_hashtab_lookup(score->exten->peer_label_table, &pattern)) { \
++ ast_debug(4, "Found label in preferred extension\n"); \
++ return; \
++ } \
++ } else { \
++ ast_debug(4, "returning an exact match-- first found-- %s\n", p->exten->exten); \
++ return; /* the first match, by definition, will be the best, because of the sorted tree */ \
++ } \
++ } \
++ } \
++ }
++
++#define NEW_MATCHER_RECURSE \
++ if (p->next_char && (*(str + 1) || (p->next_char->x[0] == '/' && p->next_char->x[1] == 0) \
++ || p->next_char->x[0] == '!')) { \
++ if (*(str + 1) || p->next_char->x[0] == '!') { \
++ new_find_extension(str + 1, score, p->next_char, length + 1, spec + p->specificity, callerid, label, action); \
++ if (score->exten) { \
++ ast_debug(4 ,"returning an exact match-- %s\n", score->exten->exten); \
++ return; /* the first match is all we need */ \
++ } \
++ } else { \
++ new_find_extension("/", score, p->next_char, length + 1, spec + p->specificity, callerid, label, action); \
++ if (score->exten || ((action == E_CANMATCH || action == E_MATCHMORE) && score->canmatch)) { \
++ ast_debug(4,"returning a (can/more) match--- %s\n", score->exten ? score->exten->exten : \
++ "NULL"); \
++ return; /* the first match is all we need */ \
++ } \
++ } \
++ } else if (p->next_char && !*(str + 1)) { \
++ score->canmatch = 1; \
++ score->canmatch_exten = get_canmatch_exten(p); \
++ if (action == E_CANMATCH || action == E_MATCHMORE) { \
++ ast_debug(4, "returning a canmatch/matchmore--- str=%s\n", str); \
++ return; \
++ } \
++ }
++
++ NEW_MATCHER_CHK_MATCH;
++ NEW_MATCHER_RECURSE;
+ }
+-
+-#define NEW_MATCHER_RECURSE \
+- if (p->next_char && ( *(str + 1) || (p->next_char->x[0] == '/' && p->next_char->x[1] == 0) \
+- || p->next_char->x[0] == '!')) { \
+- if (*(str + 1) || p->next_char->x[0] == '!') { \
+- new_find_extension(str + 1, score, p->next_char, length + 1, spec+p->specificity, callerid, label, action); \
+- if (score->exten) { \
+- ast_debug(4, "returning an exact match-- %s\n", score->exten->exten); \
+- return; /* the first match is all we need */ \
+- } \
+- } else { \
+- new_find_extension("/", score, p->next_char, length + 1, spec+p->specificity, callerid, label, action); \
+- if (score->exten || ((action == E_CANMATCH || action == E_MATCHMORE) && score->canmatch)) { \
+- ast_debug(4,"returning a (can/more) match--- %s\n", score->exten ? score->exten->exten : \
+- "NULL"); \
+- return; /* the first match is all we need */ \
+- } \
+- } \
+- } else if (p->next_char && !*(str + 1)) { \
+- score->canmatch = 1; \
+- score->canmatch_exten = get_canmatch_exten(p); \
+- if (action == E_CANMATCH || action == E_MATCHMORE) { \
+- ast_debug(4, "returning a canmatch/matchmore--- str=%s\n", str); \
+- return; \
+- } \
++ } else if (p->x[0] == 'Z') {
++ if (p->x[1] == 0 && *str >= '1' && *str <= '9' ) {
++ NEW_MATCHER_CHK_MATCH;
++ NEW_MATCHER_RECURSE;
+ }
+-
+- NEW_MATCHER_CHK_MATCH;
+- NEW_MATCHER_RECURSE;
+- }
+- } else if (p->x[0] == 'Z') {
+- if (p->x[1] == 0 && *str >= '1' && *str <= '9' ) {
+- NEW_MATCHER_CHK_MATCH;
+- NEW_MATCHER_RECURSE;
+- }
+- } else if (p->x[0] == 'X') {
+- if (p->x[1] == 0 && *str >= '0' && *str <= '9' ) {
+- NEW_MATCHER_CHK_MATCH;
+- NEW_MATCHER_RECURSE;
+- }
+- } else if (p->x[0] == '.' && p->x[1] == 0) {
+- /* how many chars will the . match against? */
+- int i = 0;
+- const char *str2 = str;
+- while (*str2 && *str2 != '/') {
+- str2++;
+- i++;
+- }
+- if (p->exten && *str2 != '/') {
+- update_scoreboard(score, length+i, spec+(i*p->specificity), p->exten, '.', callerid, p->deleted, p);
+- if (score->exten) {
+- ast_debug(4,"return because scoreboard has a match with '/'--- %s\n", score->exten->exten);
+- return; /* the first match is all we need */
++ } else if (p->x[0] == 'X') {
++ if (p->x[1] == 0 && *str >= '0' && *str <= '9' ) {
++ NEW_MATCHER_CHK_MATCH;
++ NEW_MATCHER_RECURSE;
+ }
+- }
+- if (p->next_char && p->next_char->x[0] == '/' && p->next_char->x[1] == 0) {
+- new_find_extension("/", score, p->next_char, length+i, spec+(p->specificity*i), callerid, label, action);
+- if (score->exten || ((action == E_CANMATCH || action == E_MATCHMORE) && score->canmatch)) {
+- ast_debug(4, "return because scoreboard has exact match OR CANMATCH/MATCHMORE & canmatch set--- %s\n", score->exten ? score->exten->exten : "NULL");
+- return; /* the first match is all we need */
++ } else if (p->x[0] == '.' && p->x[1] == 0) {
++ /* how many chars will the . match against? */
++ int i = 0;
++ const char *str2 = str;
++ while (*str2 && *str2 != '/') {
++ str2++;
++ i++;
+ }
+- }
+- } else if (p->x[0] == '!' && p->x[1] == 0) {
+- /* how many chars will the . match against? */
+- int i = 1;
+- const char *str2 = str;
+- while (*str2 && *str2 != '/') {
+- str2++;
+- i++;
+- }
+- if (p->exten && *str2 != '/') {
+- update_scoreboard(score, length + 1, spec+(p->specificity * i), p->exten, '!', callerid, p->deleted, p);
+- if (score->exten) {
+- ast_debug(4, "return because scoreboard has a '!' match--- %s\n", score->exten->exten);
+- return; /* the first match is all we need */
++ if (p->exten && *str2 != '/') {
++ update_scoreboard(score, length + i, spec + (i * p->specificity), p->exten, '.', callerid, p->deleted, p);
++ if (score->exten) {
++ ast_debug(4,"return because scoreboard has a match with '/'--- %s\n", score->exten->exten);
++ return; /* the first match is all we need */
++ }
+ }
+- }
+- if (p->next_char && p->next_char->x[0] == '/' && p->next_char->x[1] == 0) {
+- new_find_extension("/", score, p->next_char, length + i, spec + (p->specificity * i), callerid, label, action);
+- if (score->exten || ((action == E_CANMATCH || action == E_MATCHMORE) && score->canmatch)) {
+- ast_debug(4,"return because scoreboard has exact match OR CANMATCH/MATCHMORE & canmatch set with '/' and '!'--- %s\n", score->exten ? score->exten->exten : "NULL");
+- return; /* the first match is all we need */
++ if (p->next_char && p->next_char->x[0] == '/' && p->next_char->x[1] == 0) {
++ new_find_extension("/", score, p->next_char, length + i, spec+(p->specificity*i), callerid, label, action);
++ if (score->exten || ((action == E_CANMATCH || action == E_MATCHMORE) && score->canmatch)) {
++ ast_debug(4, "return because scoreboard has exact match OR CANMATCH/MATCHMORE & canmatch set--- %s\n", score->exten ? score->exten->exten : "NULL");
++ return; /* the first match is all we need */
++ }
+ }
+- }
+- } else if (p->x[0] == '/' && p->x[1] == 0) {
+- /* the pattern in the tree includes the cid match! */
+- if (p->next_char && callerid && *callerid) {
+- new_find_extension(callerid, score, p->next_char, length+1, spec, callerid, label, action);
+- if (score->exten || ((action == E_CANMATCH || action == E_MATCHMORE) && score->canmatch)) {
+- ast_debug(4, "return because scoreboard has exact match OR CANMATCH/MATCHMORE & canmatch set with '/'--- %s\n", score->exten ? score->exten->exten : "NULL");
+- return; /* the first match is all we need */
++ } else if (p->x[0] == '!' && p->x[1] == 0) {
++ /* how many chars will the . match against? */
++ int i = 1;
++ const char *str2 = str;
++ while (*str2 && *str2 != '/') {
++ str2++;
++ i++;
+ }
++ if (p->exten && *str2 != '/') {
++ update_scoreboard(score, length + 1, spec + (p->specificity * i), p->exten, '!', callerid, p->deleted, p);
++ if (score->exten) {
++ ast_debug(4, "return because scoreboard has a '!' match--- %s\n", score->exten->exten);
++ return; /* the first match is all we need */
++ }
++ }
++ if (p->next_char && p->next_char->x[0] == '/' && p->next_char->x[1] == 0) {
++ new_find_extension("/", score, p->next_char, length + i, spec + (p->specificity * i), callerid, label, action);
++ if (score->exten || ((action == E_CANMATCH || action == E_MATCHMORE) && score->canmatch)) {
++ ast_debug(4, "return because scoreboard has exact match OR CANMATCH/MATCHMORE & canmatch set with '/' and '!'--- %s\n", score->exten ? score->exten->exten : "NULL");
++ return; /* the first match is all we need */
++ }
++ }
++ } else if (p->x[0] == '/' && p->x[1] == 0) {
++ /* the pattern in the tree includes the cid match! */
++ if (p->next_char && callerid && *callerid) {
++ new_find_extension(callerid, score, p->next_char, length + 1, spec, callerid, label, action);
++ if (score->exten || ((action == E_CANMATCH || action == E_MATCHMORE) && score->canmatch)) {
++ ast_debug(4, "return because scoreboard has exact match OR CANMATCH/MATCHMORE & canmatch set with '/'--- %s\n", score->exten ? score->exten->exten : "NULL");
++ return; /* the first match is all we need */
++ }
++ }
++ } else if (strchr(p->x, *str)) {
++ ast_debug(4, "Nothing strange about this match\n");
++ NEW_MATCHER_CHK_MATCH;
++ NEW_MATCHER_RECURSE;
+ }
+ } else if (strchr(p->x, *str)) {
+ ast_debug(4, "Nothing strange about this match\n");
+@@ -1776,7 +1803,7 @@
+ * where the "|" (or) operator is allowed, I guess, in a way, sort of...
+ */
+
+-static struct match_char *already_in_tree(struct match_char *current, char *pat)
++static struct match_char *already_in_tree(struct match_char *current, char *pat, int is_pattern)
+ {
+ struct match_char *t;
+
+@@ -1785,7 +1812,7 @@
+ }
+
+ for (t = current; t; t = t->alt_char) {
+- if (!strcmp(pat, t->x)) { /* uh, we may want to sort exploded [] contents to make matching easy */
++ if (is_pattern == t->is_pattern && !strcmp(pat, t->x)) {/* uh, we may want to sort exploded [] contents to make matching easy */
+ return t;
+ }
+ }
+@@ -1805,42 +1832,44 @@
+ sorted in increasing value as you go to the leaves */
+ if (!(*parent_ptr)) {
+ *parent_ptr = node;
+- } else {
+- if ((*parent_ptr)->specificity > node->specificity) {
+- /* insert at head */
+- node->alt_char = (*parent_ptr);
+- *parent_ptr = node;
+- } else {
+- lcurr = *parent_ptr;
+- for (curr = (*parent_ptr)->alt_char; curr; curr = curr->alt_char) {
+- if (curr->specificity > node->specificity) {
+- node->alt_char = curr;
+- lcurr->alt_char = node;
+- break;
+- }
+- lcurr = curr;
+- }
+- if (!curr) {
+- lcurr->alt_char = node;
+- }
++ return;
++ }
++
++ if ((*parent_ptr)->specificity > node->specificity) {
++ /* insert at head */
++ node->alt_char = (*parent_ptr);
++ *parent_ptr = node;
++ return;
++ }
++
++ lcurr = *parent_ptr;
++ for (curr = (*parent_ptr)->alt_char; curr; curr = curr->alt_char) {
++ if (curr->specificity > node->specificity) {
++ node->alt_char = curr;
++ lcurr->alt_char = node;
++ break;
+ }
++ lcurr = curr;
+ }
+-}
+
++ if (!curr) {
++ lcurr->alt_char = node;
++ }
+
++}
+
+ 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 **nextcharptr)
+ {
+ struct match_char *m;
+-
+- if (!(m = ast_calloc(1, sizeof(*m)))) {
++
++ if (!(m = ast_calloc(1, sizeof(*m) + strlen(pattern)))) {
+ return NULL;
+ }
+
+- if (!(m->x = ast_strdup(pattern))) {
+- ast_free(m);
+- return NULL;
+- }
++ /* strcpy is safe here since we know its size and have allocated
++ * just enough space for when we allocated m
++ */
++ strcpy(m->x, pattern);
+
+ /* the specificity scores are the same as used in the old
+ pattern matcher. */
+@@ -1903,25 +1932,25 @@
+ pattern = 1;
+ s1++;
+ }
+- while( *s1 ) {
+- if (pattern && *s1 == '[' && *(s1-1) != '\\') {
++ while (*s1) {
++ if (pattern && *s1 == '[' && *(s1 - 1) != '\\') {
+ char *s2 = buf;
+ buf[0] = 0;
+ s1++; /* get past the '[' */
+- while (*s1 != ']' && *(s1 - 1) != '\\' ) {
++ while (*s1 != ']' && *(s1 - 1) != '\\') {
+ if (*s1 == '\\') {
+ if (*(s1 + 1) == ']') {
+ *s2++ = ']';
+- s1++; s1++;
++ s1 += 2;
+ } else if (*(s1 + 1) == '\\') {
+ *s2++ = '\\';
+- s1++; s1++;
++ s1 += 2;
+ } else if (*(s1 + 1) == '-') {
+ *s2++ = '-';
+- s1++; s1++;
++ s1 += 2;
+ } else if (*(s1 + 1) == '[') {
+ *s2++ = '[';
+- s1++; s1++;
++ s1 += 2;
+ }
+ } else if (*s1 == '-') { /* remember to add some error checking to all this! */
+ char s3 = *(s1 - 1);
+@@ -1929,7 +1958,7 @@
+ for (s3++; s3 <= s4; s3++) {
+ *s2++ = s3;
+ }
+- s1++; s1++;
++ s1 += 2;
+ } else if (*s1 == '\0') {
+ ast_log(LOG_WARNING, "A matching ']' was not found for '[' in pattern string '%s'\n", extenbuf);
+ break;
+@@ -1945,18 +1974,18 @@
+ specif <<= 8;
+ specif += buf[0];
+ } else {
+-
+ if (*s1 == '\\') {
+ s1++;
+ buf[0] = *s1;
+ } else {
+ if (pattern) {
+- if (*s1 == 'n') /* make sure n,x,z patterns are canonicalized to N,X,Z */
++ if (*s1 == 'n') { /* make sure n,x,z patterns are canonicalized to N,X,Z */
+ *s1 = 'N';
+- else if (*s1 == 'x')
++ } else if (*s1 == 'x') {
+ *s1 = 'X';
+- else if (*s1 == 'z')
++ } else if (*s1 == 'z') {
+ *s1 = 'Z';
++ }
+ }
+ buf[0] = *s1;
+ }
+@@ -1964,9 +1993,12 @@
+ specif = 1;
+ }
+ m2 = 0;
+- if (already && (m2 = already_in_tree(m1,buf)) && m2->next_char) {
++ if (already && (m2 = already_in_tree(m1, buf, pattern)) && m2->next_char) {
+ if (!(*(s1 + 1))) { /* if this is the end of the pattern, but not the end of the tree, then mark this node with the exten...
+- * a shorter pattern might win if the longer one doesn't match */
++ a shorter pattern might win if the longer one doesn't match */
++ if (m2->exten) {
++ ast_log(LOG_WARNING, "Found duplicate exten. Had %s found %s\n", m2->exten->exten, e1->exten);
++ }
+ m2->exten = e1;
+ m2->deleted = 0;
+ }
+@@ -1982,15 +2014,22 @@
+ if (findonly) {
+ return m1;
+ }
+- m1 = add_pattern_node(con, m1, buf, pattern, already,specif, m0); /* m1 is the node just added */
++ if (!(m1 = add_pattern_node(con, m1, buf, pattern, already,specif, m0))) { /* m1 is the node just added */
++ return NULL;
++ }
+ m0 = &m1->next_char;
+ }
+-
+ if (!(*(s1 + 1))) {
++ if (m2 && m2->exten) {
++ ast_log(LOG_WARNING, "Found duplicate exten. Had %s found %s\n", m2->exten->exten, e1->exten);
++ }
+ m1->deleted = 0;
+ m1->exten = e1;
+ }
+
++ /* The 'already' variable is a mini-optimization designed to make it so that we
++ * don't have to call already_in_tree when we know it will return false.
++ */
+ already = 0;
+ }
+ s1++; /* advance to next char */
+@@ -2005,7 +2044,7 @@
+ #ifdef NEED_DEBUG
+ int biggest_bucket, resizes, numobjs, numbucks;
+
+- ast_log(LOG_DEBUG,"Creating Extension Trie for context %s\n", con->name);
++ ast_log(LOG_DEBUG,"Creating Extension Trie for context %s(%p)\n", con->name, con);
+ ast_hashtab_get_stats(con->root_table, &biggest_bucket, &resizes, &numobjs, &numbucks);
+ ast_log(LOG_DEBUG,"This tree has %d objects in %d bucket lists, longest list=%d objects, and has resized %d times\n",
+ numobjs, numbucks, biggest_bucket, resizes);
+@@ -2034,10 +2073,7 @@
+ pattern_tree->next_char = 0;
+ }
+ pattern_tree->exten = 0; /* never hurts to make sure there's no pointers laying around */
+- if (pattern_tree->x) {
+- free(pattern_tree->x);
+- }
+- free(pattern_tree);
++ ast_free(pattern_tree);
+ }
+
+ /*
+@@ -2496,14 +2532,6 @@
+ 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)) ) {
+- if (!strcmp(tmp->name, context)) {
+- break;
+- }
+- }
+-#endif
+ if (!tmp) {
+ return NULL;
+ }
+@@ -2686,19 +2714,6 @@
+ } else {
+ e = ast_hashtab_lookup(eroot->peer_table, &pattern);
+ }
+-#ifdef NOTNOW
+- while ( (e = ast_walk_extension_priorities(eroot, e)) ) {
+- /* Match label or priority */
+- if (action == E_FINDLABEL) {
+- if (q->status < STATUS_NO_LABEL)
+- q->status = STATUS_NO_LABEL;
+- if (label && e->label && !strcmp(label, e->label))
+- break; /* found it */
+- } else if (e->priority == priority) {
+- break; /* found it */
+- } /* else keep searching */
+- }
+-#endif
+ if (e) { /* found a valid match */
+ q->status = STATUS_SUCCESS;
+ q->foundcontext = context;
+@@ -2843,6 +2858,54 @@
+ return ret;
+ }
+
++static const char *ast_str_substring(struct ast_str *value, int offset, int length)
++{
++ int lr; /* length of the input string after the copy */
++
++ lr = ast_str_strlen(value); /* compute length after copy, so we never go out of the workspace */
++
++ /* Quick check if no need to do anything */
++ if (offset == 0 && length >= lr) /* take the whole string */
++ return ast_str_buffer(value);
++
++ if (offset < 0) { /* translate negative offset into positive ones */
++ offset = lr + offset;
++ if (offset < 0) /* If the negative offset was greater than the length of the string, just start at the beginning */
++ offset = 0;
++ }
++
++ /* too large offset result in empty string so we know what to return */
++ if (offset >= lr) {
++ ast_str_reset(value);
++ return ast_str_buffer(value);
++ }
++
++ if (offset > 0) {
++ /* Go ahead and chop off the beginning */
++ memcpy(ast_str_buffer(value), ast_str_buffer(value) + offset, ast_str_strlen(value) - offset + 1);
++ lr -= offset;
++ }
++
++ if (length >= 0 && length < lr) { /* truncate if necessary */
++ char *tmp = ast_str_buffer(value);
++ tmp[length] = '\0';
++ ast_str_update(value);
++ } else if (length < 0) {
++ if (lr > -length) { /* After we remove from the front and from the rear, is there anything left? */
++ char *tmp = ast_str_buffer(value);
++ tmp[lr + length] = '\0';
++ ast_str_update(value);
++ } else {
++ ast_str_reset(value);
++ }
++ } else {
++ /* Nothing to do, but update the buffer length */
++ ast_str_update(value);
++ }
++
++ return ast_str_buffer(value);
++}
++
+ /*! \brief Support for Asterisk built-in variables in the dialplan
+
+ \note See also
+@@ -2851,8 +2914,20 @@
+ */
+ void pbx_retrieve_variable(struct ast_channel *c, const char *var, char **ret, char *workspace, int workspacelen, struct varshead *headp)
+ {
++ struct ast_str *str = ast_str_create(16);
++ const char *cret;
++
++ cret = ast_str_retrieve_variable(&str, 0, c, headp, var);
++ ast_copy_string(workspace, ast_str_buffer(str), workspacelen);
++ *ret = cret ? workspace : NULL;
++ ast_free(str);
++}
++
++const char *ast_str_retrieve_variable(struct ast_str **str, ssize_t maxlen, struct ast_channel *c, struct varshead *headp, const char *var)
++{
+ const char not_found = '\0';
+ char *tmpvar;
++ const char *ret;
+ const char *s; /* the result */
+ int offset, length;
+ int i, need_substring;
+@@ -2891,47 +2966,48 @@
+ if (!strncmp(var, "CALL", 4)) {
+ if (!strncmp(var + 4, "ING", 3)) {
+ if (!strcmp(var + 7, "PRES")) { /* CALLINGPRES */
+- snprintf(workspace, workspacelen, "%d", c->cid.cid_pres);
+- s = workspace;
++ ast_str_set(str, maxlen, "%d", c->cid.cid_pres);
++ s = ast_str_buffer(*str);
+ } else if (!strcmp(var + 7, "ANI2")) { /* CALLINGANI2 */
+- snprintf(workspace, workspacelen, "%d", c->cid.cid_ani2);
+- s = workspace;
++ ast_str_set(str, maxlen, "%d", c->cid.cid_ani2);
++ s = ast_str_buffer(*str);
+ } else if (!strcmp(var + 7, "TON")) { /* CALLINGTON */
+- snprintf(workspace, workspacelen, "%d", c->cid.cid_ton);
+- s = workspace;
++ ast_str_set(str, maxlen, "%d", c->cid.cid_ton);
++ s = ast_str_buffer(*str);
+ } else if (!strcmp(var + 7, "TNS")) { /* CALLINGTNS */
+- snprintf(workspace, workspacelen, "%d", c->cid.cid_tns);
+- s = workspace;
++ ast_str_set(str, maxlen, "%d", c->cid.cid_tns);
++ s = ast_str_buffer(*str);
+ }
+ }
+ } else if (!strcmp(var, "HINT")) {
+- s = ast_get_hint(workspace, workspacelen, NULL, 0, c, c->context, c->exten) ? workspace : NULL;
++ s = ast_str_get_hint(str, maxlen, NULL, 0, c, c->context, c->exten) ? ast_str_buffer(*str) : NULL;
+ } else if (!strcmp(var, "HINTNAME")) {
+- s = ast_get_hint(NULL, 0, workspace, workspacelen, c, c->context, c->exten) ? workspace : NULL;
++ s = ast_str_get_hint(NULL, 0, str, maxlen, c, c->context, c->exten) ? ast_str_buffer(*str) : NULL;
+ } else if (!strcmp(var, "EXTEN")) {
+ s = c->exten;
+ } else if (!strcmp(var, "CONTEXT")) {
+ s = c->context;
+ } else if (!strcmp(var, "PRIORITY")) {
+- snprintf(workspace, workspacelen, "%d", c->priority);
+- s = workspace;
++ ast_str_set(str, maxlen, "%d", c->priority);
++ s = ast_str_buffer(*str);
+ } else if (!strcmp(var, "CHANNEL")) {
+ s = c->name;
+ } else if (!strcmp(var, "UNIQUEID")) {
+ s = c->uniqueid;
+ } else if (!strcmp(var, "HANGUPCAUSE")) {
+- snprintf(workspace, workspacelen, "%d", c->hangupcause);
+- s = workspace;
++ ast_str_set(str, maxlen, "%d", c->hangupcause);
++ s = ast_str_buffer(*str);
+ }
+ }
+ if (s == &not_found) { /* look for more */
+ if (!strcmp(var, "EPOCH")) {
+- snprintf(workspace, workspacelen, "%u",(int)time(NULL));
+- s = workspace;
++ ast_str_set(str, maxlen, "%u", (int) time(NULL));
++ s = ast_str_buffer(*str);
+ } else if (!strcmp(var, "SYSTEMNAME")) {
+ s = ast_config_AST_SYSTEM_NAME;
+ } else if (!strcmp(var, "ENTITYID")) {
+- ast_eid_to_str(workspace, workspacelen, &ast_eid_default);
++ char workspace[20];
++ ast_eid_to_str(workspace, sizeof(workspace), &ast_eid_default);
+ s = workspace;
+ }
+ }
+@@ -2951,18 +3027,25 @@
+ if (places[i] == &globals)
+ ast_rwlock_unlock(&globalslock);
+ }
+- if (s == &not_found || s == NULL)
+- *ret = NULL;
+- else {
+- if (s != workspace)
+- ast_copy_string(workspace, s, workspacelen);
+- *ret = workspace;
+- if (need_substring)
+- *ret = substring(*ret, offset, length, workspace, workspacelen);
++ if (s == &not_found || s == NULL) {
++ ast_debug(5, "Result of '%s' is NULL\n", var);
++ ret = NULL;
++ } else {
++ ast_debug(5, "Result of '%s' is '%s'\n", var, s);
++ if (s != ast_str_buffer(*str)) {
++ ast_str_set(str, maxlen, "%s", s);
++ }
++ ret = ast_str_buffer(*str);
++ if (need_substring) {
++ ret = ast_str_substring(*str, offset, length);
++ ast_debug(2, "Final result of '%s' is '%s'\n", var, ret);
++ }
+ }
+
+- if (c)
++ if (c) {
+ ast_channel_unlock(c);
++ }
++ return ret;
+ }
+
+ static void exception_store_free(void *data)
+@@ -2977,9 +3060,8 @@
+ .destroy = exception_store_free,
+ };
+
+-int pbx_builtin_raise_exception(struct ast_channel *chan, void *vreason)
++int pbx_builtin_raise_exception(struct ast_channel *chan, const char *reason)
+ {
+- const char *reason = vreason;
+ struct ast_datastore *ds = ast_channel_datastore_find(chan, &exception_store_info, NULL);
+ struct pbx_exception *exception = NULL;
+
+@@ -3205,9 +3287,11 @@
+
+ AST_RWLIST_WRLOCK(&acf_root);
+ if ((cur = AST_RWLIST_REMOVE(&acf_root, acf, acflist))) {
++#ifdef AST_XML_DOCS
+ if (cur->docsrc == AST_XML_DOC) {
+ ast_string_field_free_memory(acf);
+ }
++#endif
+ ast_verb(2, "Unregistered custom function %s\n", cur->name);
+ }
+ AST_RWLIST_UNLOCK(&acf_root);
+@@ -3278,7 +3362,9 @@
+ }
+
+ acf->mod = mod;
++#ifdef AST_XML_DOCS
+ acf->docsrc = AST_STATIC_DOC;
++#endif
+
+ if (acf_retrieve_docs(acf)) {
+ return -1;
+@@ -3340,24 +3426,83 @@
+ char *copy = ast_strdupa(function);
+ char *args = func_args(copy);
+ struct ast_custom_function *acfptr = ast_custom_function_find(copy);
++ int res;
++ struct ast_module_user *u = NULL;
+
+- if (acfptr == NULL)
++ if (acfptr == NULL) {
+ ast_log(LOG_ERROR, "Function %s not registered\n", copy);
+- else if (!acfptr->read)
++ } else if (!acfptr->read && !acfptr->read2) {
+ ast_log(LOG_ERROR, "Function %s cannot be read\n", copy);
+- else {
+- int res;
+- struct ast_module_user *u = NULL;
+- if (acfptr->mod)
++ } else if (acfptr->read) {
++ if (acfptr->mod) {
+ u = __ast_module_user_add(acfptr->mod, chan);
++ }
+ res = acfptr->read(chan, copy, args, workspace, len);
+- if (acfptr->mod && u)
++ if (acfptr->mod && u) {
+ __ast_module_user_remove(acfptr->mod, u);
++ }
+ return res;
++ } else {
++ struct ast_str *str = ast_str_create(16);
++ if (acfptr->mod) {
++ u = __ast_module_user_add(acfptr->mod, chan);
++ }
++ res = acfptr->read2(chan, copy, args, &str, 0);
++ if (acfptr->mod && u) {
++ __ast_module_user_remove(acfptr->mod, u);
++ }
++ ast_copy_string(workspace, ast_str_buffer(str), len > ast_str_size(str) ? ast_str_size(str) : len);
++ ast_free(str);
++ return res;
+ }
+ return -1;
+ }
+
++int ast_func_read2(struct ast_channel *chan, const char *function, struct ast_str **str, ssize_t maxlen)
++{
++ char *copy = ast_strdupa(function);
++ char *args = func_args(copy);
++ struct ast_custom_function *acfptr = ast_custom_function_find(copy);
++ int res;
++ struct ast_module_user *u = NULL;
++
++ if (acfptr == NULL) {
++ ast_log(LOG_ERROR, "Function %s not registered\n", copy);
++ } else if (!acfptr->read && !acfptr->read2) {
++ ast_log(LOG_ERROR, "Function %s cannot be read\n", copy);
++ } else {
++ if (acfptr->mod) {
++ u = __ast_module_user_add(acfptr->mod, chan);
++ }
++ if (acfptr->read2) {
++ /* ast_str enabled */
++ ast_str_reset(*str);
++ res = acfptr->read2(chan, copy, args, str, maxlen);
++ } else {
++ /* Legacy function pointer, allocate buffer for result */
++ int maxsize = ast_str_size(*str);
++ if (maxlen > -1) {
++ if (maxlen == 0) {
++ if (acfptr->read_max) {
++ maxsize = acfptr->read_max;
++ } else {
++ maxsize = VAR_BUF_SIZE;
++ }
++ } else {
++ maxsize = maxlen;
++ }
++ ast_str_make_space(str, maxsize);
++ }
++ res = acfptr->read(chan, copy, args, ast_str_buffer(*str), maxsize);
++ }
++ if (acfptr->mod && u) {
++ __ast_module_user_remove(acfptr->mod, u);
++ }
++ return res;
++ }
++ return -1;
++}
++
+ int ast_func_write(struct ast_channel *chan, const char *function, const char *value)
+ {
+ char *copy = ast_strdupa(function);
+@@ -3382,10 +3527,198 @@
+ return -1;
+ }
+
++void ast_str_substitute_variables_full(struct ast_str **buf, ssize_t maxlen, struct ast_channel *c, struct varshead *headp, const char *templ, size_t *used)
++{
++ /* Substitutes variables into buf, based on string templ */
++ char *cp4 = NULL;
++ const char *tmp, *whereweare;
++ int orig_size = 0;
++ int offset, offset2, isfunction;
++ const char *nextvar, *nextexp, *nextthing;
++ const char *vars, *vare;
++ char *finalvars;
++ int pos, brackets, needsub, len;
++ struct ast_str *substr1 = ast_str_create(16), *substr2 = NULL, *substr3 = ast_str_create(16);
++
++ ast_str_reset(*buf);
++ whereweare = tmp = templ;
++ while (!ast_strlen_zero(whereweare)) {
++ /* Assume we're copying the whole remaining string */
++ pos = strlen(whereweare);
++ nextvar = NULL;
++ nextexp = NULL;
++ nextthing = strchr(whereweare, '$');
++ if (nextthing) {
++ switch (nextthing[1]) {
++ case '{':
++ nextvar = nextthing;
++ pos = nextvar - whereweare;
++ break;
++ case '[':
++ nextexp = nextthing;
++ pos = nextexp - whereweare;
++ break;
++ default:
++ pos = 1;
++ }
++ }
++
++ if (pos) {
++ /* Copy that many bytes */
++ ast_str_append_substr(buf, maxlen, whereweare, pos);
++
++ templ += pos;
++ whereweare += pos;
++ }
++
++ if (nextvar) {
++ /* We have a variable. Find the start and end, and determine
++ if we are going to have to recursively call ourselves on the
++ contents */
++ vars = vare = nextvar + 2;
++ brackets = 1;
++ needsub = 0;
++
++ /* Find the end of it */
++ while (brackets && *vare) {
++ if ((vare[0] == '$') && (vare[1] == '{')) {
++ needsub++;
++ } else if (vare[0] == '{') {
++ brackets++;
++ } else if (vare[0] == '}') {
++ brackets--;
++ } else if ((vare[0] == '$') && (vare[1] == '['))
++ needsub++;
++ vare++;
++ }
++ if (brackets)
++ ast_log(LOG_WARNING, "Error in extension logic (missing '}')\n");
++ len = vare - vars - 1;
++
++ /* Skip totally over variable string */
++ whereweare += (len + 3);
++
++ /* Store variable name (and truncate) */
++ ast_str_set_substr(&substr1, 0, vars, len);
++ ast_debug(5, "Evaluating '%s' (from '%s' len %d)\n", ast_str_buffer(substr1), vars, len);
++
++ /* Substitute if necessary */
++ if (needsub) {
++ size_t used;
++ if (!substr2) {
++ substr2 = ast_str_create(16);
++ }
++
++ ast_str_substitute_variables_full(&substr2, 0, c, headp, ast_str_buffer(substr1), &used);
++ finalvars = ast_str_buffer(substr2);
++ } else {
++ finalvars = ast_str_buffer(substr1);
++ }
++
++ parse_variable_name(finalvars, &offset, &offset2, &isfunction);
++ if (isfunction) {
++ /* Evaluate function */
++ if (c || !headp) {
++ cp4 = ast_func_read2(c, finalvars, &substr3, 0) ? NULL : ast_str_buffer(substr3);
++ } else {
++ struct varshead old;
++ struct ast_channel *bogus = ast_channel_alloc(0, 0, "", "", "", "", "", 0, "Bogus/%p", vars);
++ if (bogus) {
++ memcpy(&old, &bogus->varshead, sizeof(old));
++ memcpy(&bogus->varshead, headp, sizeof(bogus->varshead));
++ cp4 = ast_func_read2(c, finalvars, &substr3, 0) ? NULL : ast_str_buffer(substr3);
++ /* Don't deallocate the varshead that was passed in */
++ memcpy(&bogus->varshead, &old, sizeof(bogus->varshead));
++ ast_channel_release(bogus);
++ } else {
++ ast_log(LOG_ERROR, "Unable to allocate bogus channel for variable substitution. Function results may be blank.\n");
++ }
++ }
++ ast_debug(2, "Function result is '%s'\n", cp4 ? cp4 : "(null)");
++ } else {
++ /* Retrieve variable value */
++ ast_str_retrieve_variable(&substr3, 0, c, headp, finalvars);
++ cp4 = ast_str_buffer(substr3);
++ }
++ if (cp4) {
++ ast_str_substring(substr3, offset, offset2);
++ ast_str_append(buf, maxlen, "%s", ast_str_buffer(substr3));
++ }
++ } else if (nextexp) {
++ /* We have an expression. Find the start and end, and determine
++ if we are going to have to recursively call ourselves on the
++ contents */
++ vars = vare = nextexp + 2;
++ brackets = 1;
++ needsub = 0;
++
++ /* Find the end of it */
++ while (brackets && *vare) {
++ if ((vare[0] == '$') && (vare[1] == '[')) {
++ needsub++;
++ brackets++;
++ vare++;
++ } else if (vare[0] == '[') {
++ brackets++;
++ } else if (vare[0] == ']') {
++ brackets--;
++ } else if ((vare[0] == '$') && (vare[1] == '{')) {
++ needsub++;
++ vare++;
++ }
++ vare++;
++ }
++ if (brackets)
++ ast_log(LOG_WARNING, "Error in extension logic (missing ']')\n");
++ len = vare - vars - 1;
++
++ /* Skip totally over expression */
++ whereweare += (len + 3);
++
++ /* Store variable name (and truncate) */
++ ast_str_set_substr(&substr1, 0, vars, len);
++
++ /* Substitute if necessary */
++ if (needsub) {
++ size_t used;
++ if (!substr2) {
++ substr2 = ast_str_create(16);
++ }
++
++ ast_str_substitute_variables_full(&substr2, 0, c, headp, ast_str_buffer(substr1), &used);
++ finalvars = ast_str_buffer(substr2);
++ } else {
++ finalvars = ast_str_buffer(substr1);
++ }
++
++ if (ast_str_expr(&substr3, 0, c, finalvars)) {
++ ast_debug(2, "Expression result is '%s'\n", ast_str_buffer(substr3));
++ }
++ ast_str_append(buf, maxlen, "%s", ast_str_buffer(substr3));
++ }
++ }
++ *used = ast_str_strlen(*buf) - orig_size;
++ ast_free(substr1);
++ ast_free(substr2);
++ ast_free(substr3);
++}
++
++void ast_str_substitute_variables(struct ast_str **buf, ssize_t maxlen, struct ast_channel *chan, const char *templ)
++{
++ size_t used;
++ ast_str_substitute_variables_full(buf, maxlen, chan, NULL, templ, &used);
++}
++
++void ast_str_substitute_variables_varshead(struct ast_str **buf, ssize_t maxlen, struct varshead *headp, const char *templ)
++{
++ size_t used;
++ ast_str_substitute_variables_full(buf, maxlen, NULL, headp, templ, &used);
++}
++
+ 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;
++ char *cp4 = NULL;
+ const char *tmp, *whereweare, *orig_cp2 = cp2;
+ int length, offset, offset2, isfunction;
+ char *workspace = NULL;
+@@ -3495,9 +3828,10 @@
+ cp4 = ast_func_read(bogus, vars, workspace, VAR_BUF_SIZE) ? NULL : workspace;
+ /* Don't deallocate the varshead that was passed in */
+ memcpy(&bogus->varshead, &old, sizeof(bogus->varshead));
+- ast_channel_free(bogus);
+- } else
++ bogus = ast_channel_release(bogus);
++ } else {
+ ast_log(LOG_ERROR, "Unable to allocate bogus channel for variable substitution. Function results may be blank.\n");
++ }
+ }
+ ast_debug(2, "Function result is '%s'\n", cp4 ? cp4 : "(null)");
+ } else {
+@@ -4114,6 +4448,27 @@
+ return 0;
+ }
+
++/*! \brief Get hint for channel */
++int ast_str_get_hint(struct ast_str **hint, ssize_t hintsize, struct ast_str **name, ssize_t namesize, struct ast_channel *c, const char *context, const char *exten)
++{
++ struct ast_exten *e = ast_hint_extension(c, context, exten);
++
++ if (!e) {
++ return 0;
++ }
++
++ if (hint) {
++ ast_str_set(hint, hintsize, "%s", ast_get_extension_app(e));
++ }
++ if (name) {
++ const char *tmp = ast_get_extension_app_data(e);
++ if (tmp) {
++ ast_str_set(name, namesize, "%s", tmp);
++ }
++ }
++ return -1;
++}
++
+ int ast_exists_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
+ {
+ return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_MATCH, 0, 0);
+@@ -4635,13 +4990,6 @@
+ ast_rdlock_contexts();
+ c = ast_hashtab_lookup(contexts_table,&item);
+
+-#ifdef NOTNOW
+-
+- while ( (c = ast_walk_contexts(c)) ) {
+- if (!strcmp(ast_get_context_name(c), context))
+- return c;
+- }
+-#endif
+ if (!c)
+ ast_unlock_contexts();
+
+@@ -4968,18 +5316,6 @@
+ c = ast_hashtab_lookup(contexts_table,&item);
+ if (c)
+ ret = 0;
+-
+-
+-#ifdef NOTNOW
+-
+- while ((c = ast_walk_contexts(c))) {
+- if (!strcmp(ast_get_context_name(c), context)) {
+- ret = 0;
+- break;
+- }
+- }
+-
+-#endif
+ ast_unlock_contexts();
+
+ /* if we found context, lock macrolock */
+@@ -5008,16 +5344,6 @@
+ c = ast_hashtab_lookup(contexts_table,&item);
+ if (c)
+ ret = 0;
+-#ifdef NOTNOW
+-
+- while ((c = ast_walk_contexts(c))) {
+- if (!strcmp(ast_get_context_name(c), context)) {
+- ret = 0;
+- break;
+- }
+- }
+-
+-#endif
+ ast_unlock_contexts();
+
+ /* if we found context, unlock macrolock */
+@@ -5029,7 +5355,7 @@
+ }
+
+ /*! \brief Dynamically register a new dial plan application */
+-int ast_register_application2(const char *app, int (*execute)(struct ast_channel *, void *), const char *synopsis, const char *description, void *mod)
++int ast_register_application2(const char *app, int (*execute)(struct ast_channel *, const char *), const char *synopsis, const char *description, void *mod)
+ {
+ struct ast_app *tmp, *cur = NULL;
+ char tmps[80];
+@@ -5093,8 +5419,8 @@
+ #endif
+ ast_string_field_set(tmp, synopsis, synopsis);
+ ast_string_field_set(tmp, description, description);
++#ifdef AST_XML_DOCS
+ tmp->docsrc = AST_STATIC_DOC;
+-#ifdef AST_XML_DOCS
+ }
+ #endif
+
+@@ -5232,9 +5558,6 @@
+ {
+ struct ast_app *aa;
+ int app, no_registered_app = 1;
+- char *ret = NULL;
+- int which = 0;
+- int wordlen;
+
+ switch (cmd) {
+ case CLI_INIT:
+@@ -5249,18 +5572,7 @@
+ * application at one time. You can type 'show application Dial Echo' and
+ * you will see informations about these two applications ...
+ */
+- wordlen = strlen(a->word);
+- /* return the n-th [partial] matching entry */
+- AST_RWLIST_RDLOCK(&apps);
+- AST_RWLIST_TRAVERSE(&apps, aa, list) {
+- if (!strncasecmp(a->word, aa->name, wordlen) && ++which > a->n) {
+- ret = ast_strdup(aa->name);
+- break;
+- }
+- }
+- AST_RWLIST_UNLOCK(&apps);
+-
+- return ret;
++ return ast_complete_applications(a->line, a->word, a->n);
+ }
+
+ if (a->argc < 4) {
+@@ -5454,7 +5766,7 @@
+ int like = 0, describing = 0;
+ int total_match = 0; /* Number of matches in like clause */
+ int total_apps = 0; /* Number of apps registered */
+- static char* choices[] = { "like", "describing", NULL };
++ static const char * const choices[] = { "like", "describing", NULL };
+
+ switch (cmd) {
+ case CLI_INIT:
+@@ -5824,7 +6136,7 @@
+ if (ast_strlen_zero(exten))
+ exten = NULL;
+ } else { /* no '@' char, only context given */
+- context = a->argv[2];
++ context = ast_strdupa(a->argv[2]);
+ }
+ if (ast_strlen_zero(context))
+ context = NULL;
+@@ -5892,7 +6204,7 @@
+ if (ast_strlen_zero(exten))
+ exten = NULL;
+ } else { /* no '@' char, only context given */
+- context = a->argv[2];
++ context = ast_strdupa(a->argv[2]);
+ }
+ if (ast_strlen_zero(context))
+ context = NULL;
+@@ -6114,15 +6426,6 @@
+ return 0;
+ }
+
+-static char mandescr_show_dialplan[] =
+-"Description: Show dialplan contexts and extensions.\n"
+-"Be aware that showing the full dialplan may take a lot of capacity\n"
+-"Variables: \n"
+-" ActionID: <id> Action ID for this AMI transaction (optional)\n"
+-" Extension: <extension> Extension (Optional)\n"
+-" Context: <context> Context (Optional)\n"
+-"\n";
+-
+ /*! \brief CLI support for listing global variables in a parseable way */
+ static char *handle_show_globals(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+ {
+@@ -6171,16 +6474,19 @@
+ if (a->argc != e->args + 1)
+ return CLI_SHOWUSAGE;
+
+- if (!(chan = ast_get_channel_by_name_locked(a->argv[e->args]))) {
++ if (!(chan = ast_channel_get_by_name(a->argv[e->args]))) {
+ ast_cli(a->fd, "Channel '%s' not found\n", a->argv[e->args]);
+ return CLI_FAILURE;
+ }
+
+ pbx_builtin_serialize_variables(chan, &vars);
++
+ 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);
++
++ chan = ast_channel_unref(chan);
++
+ return CLI_SUCCESS;
+ }
+
+@@ -6229,13 +6535,15 @@
+ var_name = a->argv[e->args + 1];
+ var_value = a->argv[e->args + 2];
+
+- if (!(chan = ast_get_channel_by_name_locked(chan_name))) {
++ if (!(chan = ast_channel_get_by_name(chan_name))) {
+ ast_cli(a->fd, "Channel '%s' not found\n", chan_name);
+ return CLI_FAILURE;
+ }
+
+ pbx_builtin_setvar_helper(chan, var_name, var_value);
+- ast_channel_unlock(chan);
++
++ chan = ast_channel_unref(chan);
++
+ ast_cli(a->fd, "\n -- Channel variable '%s' set to '%s' for '%s'\n", var_name, var_value, chan_name);
+
+ return CLI_SUCCESS;
+@@ -6717,7 +7025,7 @@
+ * 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)
++static int lookup_name(const char *s, const char * const names[], int max)
+ {
+ int i;
+
+@@ -6740,7 +7048,7 @@
+ /*! \brief helper function to return a range up to max (7, 12, 31 respectively).
+ * names, if supplied, is an array of names that should be mapped to numbers.
+ */
+-static unsigned get_range(char *src, int max, char *const names[], const char *msg)
++static unsigned get_range(char *src, int max, const char * const names[], const char *msg)
+ {
+ int start, end; /* start and ending position */
+ unsigned int mask = 0;
+@@ -6843,7 +7151,7 @@
+ return;
+ }
+
+-static char *days[] =
++static const char * const days[] =
+ {
+ "sun",
+ "mon",
+@@ -6855,7 +7163,7 @@
+ NULL,
+ };
+
+-static char *months[] =
++static const char * const months[] =
+ {
+ "jan",
+ "feb",
+@@ -7335,11 +7643,11 @@
+ struct ast_channel *chan;
+ int res = -1;
+
+- chan = ast_get_channel_by_name_locked(channame);
+- if (chan) {
++ if ((chan = ast_channel_get_by_name(channame))) {
+ res = ast_async_goto(chan, context, exten, priority);
+- ast_channel_unlock(chan);
++ chan = ast_channel_unref(chan);
+ }
++
+ return res;
+ }
+
+@@ -7597,12 +7905,10 @@
+
+ /* If we are adding a hint evalulate in variables and global variables */
+ if (priority == PRIORITY_HINT && strstr(application, "${") && !strstr(extension, "_")) {
+- struct ast_channel c = {0, };
+-
+- ast_copy_string(c.exten, extension, sizeof(c.exten));
+- ast_copy_string(c.context, con->name, sizeof(c.context));
+- pbx_substitute_variables_helper(&c, application, expand_buf, sizeof(expand_buf));
++ struct ast_channel *c = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", extension, con->name, 0, "Bogus/%s", __PRETTY_FUNCTION__);
++ pbx_substitute_variables_helper(c, application, expand_buf, sizeof(expand_buf));
+ application = expand_buf;
++ ast_channel_release(c);
+ }
+
+ length = sizeof(struct ast_exten);
+@@ -7855,7 +8161,7 @@
+
+ if (!chan->cdr) {
+ /* allocation of the cdr failed */
+- ast_channel_free(chan); /* free the channel */
++ chan = ast_channel_release(chan); /* free the channel */
+ return -1; /* return failure */
+ }
+
+@@ -7866,7 +8172,7 @@
+ ast_cdr_failed(chan->cdr); /* set the status to failed */
+ ast_cdr_detach(chan->cdr); /* post and free the record */
+ chan->cdr = NULL;
+- ast_channel_free(chan); /* free the channel */
++ chan = ast_channel_release(chan); /* free the channel */
+
+ return 0; /* success */
+ }
+@@ -8353,7 +8659,7 @@
+ ast_unlock_contexts();
+ }
+
+-static void wait_for_hangup(struct ast_channel *chan, void *data)
++static void wait_for_hangup(struct ast_channel *chan, const void *data)
+ {
+ int res;
+ struct ast_frame *f;
+@@ -8378,7 +8684,7 @@
+ /*!
+ * \ingroup applications
+ */
+-static int pbx_builtin_proceeding(struct ast_channel *chan, void *data)
++static int pbx_builtin_proceeding(struct ast_channel *chan, const char *data)
+ {
+ ast_indicate(chan, AST_CONTROL_PROCEEDING);
+ return 0;
+@@ -8387,7 +8693,7 @@
+ /*!
+ * \ingroup applications
+ */
+-static int pbx_builtin_progress(struct ast_channel *chan, void *data)
++static int pbx_builtin_progress(struct ast_channel *chan, const char *data)
+ {
+ ast_indicate(chan, AST_CONTROL_PROGRESS);
+ return 0;
+@@ -8396,7 +8702,7 @@
+ /*!
+ * \ingroup applications
+ */
+-static int pbx_builtin_ringing(struct ast_channel *chan, void *data)
++static int pbx_builtin_ringing(struct ast_channel *chan, const char *data)
+ {
+ ast_indicate(chan, AST_CONTROL_RINGING);
+ return 0;
+@@ -8405,7 +8711,7 @@
+ /*!
+ * \ingroup applications
+ */
+-static int pbx_builtin_busy(struct ast_channel *chan, void *data)
++static int pbx_builtin_busy(struct ast_channel *chan, const char *data)
+ {
+ ast_indicate(chan, AST_CONTROL_BUSY);
+ /* Don't change state of an UP channel, just indicate
+@@ -8421,7 +8727,7 @@
+ /*!
+ * \ingroup applications
+ */
+-static int pbx_builtin_congestion(struct ast_channel *chan, void *data)
++static int pbx_builtin_congestion(struct ast_channel *chan, const char *data)
+ {
+ ast_indicate(chan, AST_CONTROL_CONGESTION);
+ /* Don't change state of an UP channel, just indicate
+@@ -8435,7 +8741,7 @@
+ /*!
+ * \ingroup applications
+ */
+-static int pbx_builtin_answer(struct ast_channel *chan, void *data)
++static int pbx_builtin_answer(struct ast_channel *chan, const char *data)
+ {
+ int delay = 0;
+ int answer_cdr = 1;
+@@ -8467,9 +8773,9 @@
+ return __ast_answer(chan, delay, answer_cdr);
+ }
+
+-static int pbx_builtin_incomplete(struct ast_channel *chan, void *data)
++static int pbx_builtin_incomplete(struct ast_channel *chan, const char *data)
+ {
+- char *options = data;
++ const char *options = data;
+ int answer = 1;
+
+ /* Some channels can receive DTMF in unanswered state; some cannot */
+@@ -8497,7 +8803,7 @@
+ /*!
+ * \ingroup applications
+ */
+-static int pbx_builtin_resetcdr(struct ast_channel *chan, void *data)
++static int pbx_builtin_resetcdr(struct ast_channel *chan, const char *data)
+ {
+ char *args;
+ struct ast_flags flags = { 0 };
+@@ -8515,7 +8821,7 @@
+ /*!
+ * \ingroup applications
+ */
+-static int pbx_builtin_setamaflags(struct ast_channel *chan, void *data)
++static int pbx_builtin_setamaflags(struct ast_channel *chan, const char *data)
+ {
+ /* Copy the AMA Flags as specified */
+ ast_cdr_setamaflags(chan, data ? data : "");
+@@ -8525,7 +8831,7 @@
+ /*!
+ * \ingroup applications
+ */
+-static int pbx_builtin_hangup(struct ast_channel *chan, void *data)
++static int pbx_builtin_hangup(struct ast_channel *chan, const char *data)
+ {
+ if (!ast_strlen_zero(data)) {
+ int cause;
+@@ -8555,7 +8861,7 @@
+ /*!
+ * \ingroup applications
+ */
+-static int pbx_builtin_gotoiftime(struct ast_channel *chan, void *data)
++static int pbx_builtin_gotoiftime(struct ast_channel *chan, const char *data)
+ {
+ char *s, *ts, *branch1, *branch2, *branch;
+ struct ast_timing timing;
+@@ -8590,12 +8896,12 @@
+ /*!
+ * \ingroup applications
+ */
+-static int pbx_builtin_execiftime(struct ast_channel *chan, void *data)
++static int pbx_builtin_execiftime(struct ast_channel *chan, const char *data)
+ {
+ 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>[,<timezone>]?<appname>[(<appargs>)]";
++ static const char * const 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);
+@@ -8644,7 +8950,7 @@
+ /*!
+ * \ingroup applications
+ */
+-static int pbx_builtin_wait(struct ast_channel *chan, void *data)
++static int pbx_builtin_wait(struct ast_channel *chan, const char *data)
+ {
+ double s;
+ int ms;
+@@ -8660,7 +8966,7 @@
+ /*!
+ * \ingroup applications
+ */
+-static int pbx_builtin_waitexten(struct ast_channel *chan, void *data)
++static int pbx_builtin_waitexten(struct ast_channel *chan, const char *data)
+ {
+ int ms, res;
+ double s;
+@@ -8729,7 +9035,7 @@
+ /*!
+ * \ingroup applications
+ */
+-static int pbx_builtin_background(struct ast_channel *chan, void *data)
++static int pbx_builtin_background(struct ast_channel *chan, const char *data)
+ {
+ int res = 0;
+ int mres = 0;
+@@ -8827,7 +9133,7 @@
+ /*! Goto
+ * \ingroup applications
+ */
+-static int pbx_builtin_goto(struct ast_channel *chan, void *data)
++static int pbx_builtin_goto(struct ast_channel *chan, const char *data)
+ {
+ int res = ast_parseable_goto(chan, data);
+ if (!res)
+@@ -8996,7 +9302,7 @@
+ ast_rwlock_unlock(&globalslock);
+ }
+
+-int pbx_builtin_setvar(struct ast_channel *chan, void *data)
++int pbx_builtin_setvar(struct ast_channel *chan, const char *data)
+ {
+ char *name, *value, *mydata;
+
+@@ -9019,7 +9325,7 @@
+ return(0);
+ }
+
+-int pbx_builtin_setvar_multiple(struct ast_channel *chan, void *vdata)
++int pbx_builtin_setvar_multiple(struct ast_channel *chan, const char *vdata)
+ {
+ char *data;
+ int x;
+@@ -9055,7 +9361,7 @@
+ return 0;
+ }
+
+-int pbx_builtin_importvar(struct ast_channel *chan, void *data)
++int pbx_builtin_importvar(struct ast_channel *chan, const char *data)
+ {
+ char *name;
+ char *value;
+@@ -9077,14 +9383,14 @@
+ name = strsep(&value,"=");
+ channel = strsep(&value,",");
+ if (channel && value && name) { /*! \todo XXX should do !ast_strlen_zero(..) of the args ? */
+- struct ast_channel *chan2 = ast_get_channel_by_name_locked(channel);
++ struct ast_channel *chan2 = ast_channel_get_by_name(channel);
+ if (chan2) {
+ char *s = alloca(strlen(value) + 4);
+ if (s) {
+ sprintf(s, "${%s}", value);
+ pbx_substitute_variables_helper(chan2, s, tmp, sizeof(tmp) - 1);
+ }
+- ast_channel_unlock(chan2);
++ chan2 = ast_channel_unref(chan2);
+ }
+ pbx_builtin_setvar_helper(chan, name, tmp);
+ }
+@@ -9092,7 +9398,7 @@
+ return(0);
+ }
+
+-static int pbx_builtin_noop(struct ast_channel *chan, void *data)
++static int pbx_builtin_noop(struct ast_channel *chan, const char *data)
+ {
+ return 0;
+ }
+@@ -9119,7 +9425,7 @@
+ }
+ }
+
+-static int pbx_builtin_gotoif(struct ast_channel *chan, void *data)
++static int pbx_builtin_gotoif(struct ast_channel *chan, const char *data)
+ {
+ char *condition, *branch1, *branch2, *branch;
+ char *stringp;
+@@ -9143,7 +9449,7 @@
+ return pbx_builtin_goto(chan, branch);
+ }
+
+-static int pbx_builtin_saynumber(struct ast_channel *chan, void *data)
++static int pbx_builtin_saynumber(struct ast_channel *chan, const char *data)
+ {
+ char tmp[256];
+ char *number = tmp;
+@@ -9171,7 +9477,7 @@
+ return 0;
+ }
+
+-static int pbx_builtin_saydigits(struct ast_channel *chan, void *data)
++static int pbx_builtin_saydigits(struct ast_channel *chan, const char *data)
+ {
+ int res = 0;
+
+@@ -9180,7 +9486,7 @@
+ return res;
+ }
+
+-static int pbx_builtin_saycharacters(struct ast_channel *chan, void *data)
++static int pbx_builtin_saycharacters(struct ast_channel *chan, const char *data)
+ {
+ int res = 0;
+
+@@ -9189,7 +9495,7 @@
+ return res;
+ }
+
+-static int pbx_builtin_sayphonetic(struct ast_channel *chan, void *data)
++static int pbx_builtin_sayphonetic(struct ast_channel *chan, const char *data)
+ {
+ int res = 0;
+
+@@ -9241,7 +9547,7 @@
+ }
+
+ /* Register manager application */
+- ast_manager_register2("ShowDialPlan", EVENT_FLAG_CONFIG | EVENT_FLAG_REPORTING, manager_show_dialplan, "List dialplan", mandescr_show_dialplan);
++ ast_manager_register_xml("ShowDialPlan", EVENT_FLAG_CONFIG | EVENT_FLAG_REPORTING, manager_show_dialplan);
+
+ if (!(device_state_sub = ast_event_subscribe(AST_EVENT_DEVICE_STATE, device_state_cb, NULL,
+ AST_EVENT_IE_END))) {
+@@ -9481,8 +9787,9 @@
+ goto_func = (async) ? ast_async_goto : ast_explicit_goto;
+ if (ast_exists_extension(chan, context, exten, priority, chan->cid.cid_num))
+ return goto_func(chan, context, exten, priority);
+- else
+- return -3;
++ else {
++ return AST_PBX_GOTO_FAILED;
++ }
+ }
+
+ int ast_goto_if_exists(struct ast_channel *chan, const char* context, const char *exten, int priority)
+@@ -9557,3 +9864,22 @@
+ {
+ return pbx_parseable_goto(chan, goto_string, 1);
+ }
++
++char *ast_complete_applications(const char *line, const char *word, int state)
++{
++ struct ast_app *app = NULL;
++ int which = 0;
++ char *ret = NULL;
++ size_t wordlen = strlen(word);
++
++ AST_RWLIST_RDLOCK(&apps);
++ AST_RWLIST_TRAVERSE(&apps, app, list) {
++ if (!strncasecmp(word, app->name, wordlen) && ++which > state) {
++ ret = ast_strdup(app->name);
++ break;
++ }
++ }
++ AST_RWLIST_UNLOCK(&apps);
++
++ return ret;
++}
+Index: main/strings.c
+===================================================================
+--- a/main/strings.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/main/strings.c (.../trunk) (revision 202568)
+@@ -109,17 +109,6 @@
+ 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;
+Index: main/stun.c
+===================================================================
+--- a/main/stun.c (.../tags/1.6.2.0-beta3) (revision 0)
++++ b/main/stun.c (.../trunk) (revision 202568)
+@@ -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/tcptls.c
+===================================================================
+--- a/main/tcptls.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/main/tcptls.c (.../trunk) (revision 202568)
+@@ -173,7 +173,7 @@
+ X509_NAME *name = X509_get_subject_name(peer);
+ int pos = -1;
+ int found = 0;
+-
++
+ for (;;) {
+ /* Walk the certificate to check all available "Common Name" */
+ /* XXX Probably should do a gethostbyname on the hostname and compare that as well */
+@@ -229,7 +229,7 @@
+ socklen_t sinlen;
+ struct ast_tcptls_session_instance *tcptls_session;
+ pthread_t launched;
+-
++
+ for (;;) {
+ int i, flags;
+
+@@ -261,7 +261,7 @@
+ memcpy(&tcptls_session->remote_address, &sin, sizeof(tcptls_session->remote_address));
+
+ tcptls_session->client = 0;
+-
++
+ if (ast_pthread_create_detached_background(&launched, NULL, handle_tls_connection, tcptls_session)) {
+ ast_log(LOG_WARNING, "Unable to launch helper thread: %s\n", strerror(errno));
+ close(tcptls_session->fd);
+@@ -283,23 +283,50 @@
+ SSL_load_error_strings();
+ SSLeay_add_ssl_algorithms();
+
+- if (!(cfg->ssl_ctx = SSL_CTX_new( client ? SSLv23_client_method() : SSLv23_server_method() ))) {
++ if (client) {
++ if (ast_test_flag(&cfg->flags, AST_SSL_SSLV2_CLIENT)) {
++ cfg->ssl_ctx = SSL_CTX_new(SSLv2_client_method());
++ } else if (ast_test_flag(&cfg->flags, AST_SSL_SSLV3_CLIENT)) {
++ cfg->ssl_ctx = SSL_CTX_new(SSLv3_client_method());
++ } else if (ast_test_flag(&cfg->flags, AST_SSL_TLSV1_CLIENT)) {
++ cfg->ssl_ctx = SSL_CTX_new(TLSv1_client_method());
++ } else {
++ /* SSLv23_client_method() sends SSLv2, this was the original
++ * default for ssl clients before the option was given to
++ * pick what protocol a client should use. In order not
++ * to break expected behavior it remains the default. */
++ cfg->ssl_ctx = SSL_CTX_new(SSLv23_client_method());
++ }
++ } else {
++ /* SSLv23_server_method() supports TLSv1, SSLv2, and SSLv3 inbound connections. */
++ cfg->ssl_ctx = SSL_CTX_new(SSLv23_server_method());
++ }
++
++ if (!cfg->ssl_ctx) {
+ ast_debug(1, "Sorry, SSL_CTX_new call returned null...\n");
+ cfg->enabled = 0;
+ return 0;
+ }
+ if (!ast_strlen_zero(cfg->certfile)) {
+- if (SSL_CTX_use_certificate_file(cfg->ssl_ctx, cfg->certfile, SSL_FILETYPE_PEM) == 0 ||
+- SSL_CTX_use_PrivateKey_file(cfg->ssl_ctx, cfg->certfile, SSL_FILETYPE_PEM) == 0 ||
+- SSL_CTX_check_private_key(cfg->ssl_ctx) == 0 ) {
++ char *tmpprivate = ast_strlen_zero(cfg->pvtfile) ? cfg->certfile : cfg->pvtfile;
++ if (SSL_CTX_use_certificate_file(cfg->ssl_ctx, cfg->certfile, SSL_FILETYPE_PEM) == 0) {
+ if (!client) {
+ /* Clients don't need a certificate, but if its setup we can use it */
+- ast_verb(0, "SSL cert error <%s>", cfg->certfile);
++ ast_verb(0, "SSL error loading cert file. <%s>", cfg->certfile);
+ sleep(2);
+ cfg->enabled = 0;
+ return 0;
+ }
+ }
++ if ((SSL_CTX_use_PrivateKey_file(cfg->ssl_ctx, tmpprivate, SSL_FILETYPE_PEM) == 0) || (SSL_CTX_check_private_key(cfg->ssl_ctx) == 0 )) {
++ if (!client) {
++ /* Clients don't need a private key, but if its setup we can use it */
++ ast_verb(0, "SSL error loading private key file. <%s>", tmpprivate);
++ sleep(2);
++ cfg->enabled = 0;
++ return 0;
++ }
++ }
+ }
+ if (!ast_strlen_zero(cfg->cipher)) {
+ if (SSL_CTX_set_cipher_list(cfg->ssl_ctx, cfg->cipher) == 0 ) {
+@@ -409,22 +436,22 @@
+ {
+ int flags;
+ int x = 1;
+-
++
+ /* Do nothing if nothing has changed */
+ if (!memcmp(&desc->old_address, &desc->local_address, sizeof(desc->old_address))) {
+ ast_debug(1, "Nothing changed in %s\n", desc->name);
+ return;
+ }
+-
++
+ desc->old_address = desc->local_address;
+-
++
+ /* Shutdown a running server if there is one */
+ if (desc->master != AST_PTHREADT_NULL) {
+ pthread_cancel(desc->master);
+ pthread_kill(desc->master, SIGURG);
+ pthread_join(desc->master, NULL);
+ }
+-
++
+ if (desc->accept_fd != -1)
+ close(desc->accept_fd);
+
+@@ -439,7 +466,7 @@
+ ast_log(LOG_ERROR, "Unable to allocate socket for %s: %s\n", desc->name, strerror(errno));
+ return;
+ }
+-
++
+ setsockopt(desc->accept_fd, SOL_SOCKET, SO_REUSEADDR, &x, sizeof(x));
+ if (bind(desc->accept_fd, (struct sockaddr *) &desc->local_address, sizeof(desc->local_address))) {
+ ast_log(LOG_ERROR, "Unable to bind %s to %s:%d: %s\n",
+@@ -480,3 +507,53 @@
+ desc->accept_fd = -1;
+ ast_debug(2, "Stopped server :: %s\n", desc->name);
+ }
++
++int ast_tls_read_conf(struct ast_tls_config *tls_cfg, struct ast_tcptls_session_args *tls_desc, const char *varname, const char *value)
++{
++ if (!strcasecmp(varname, "tlsenable") || !strcasecmp(varname, "sslenable")) {
++ tls_cfg->enabled = ast_true(value) ? 1 : 0;
++ tls_desc->local_address.sin_family = AF_INET;
++ } else if (!strcasecmp(varname, "tlscertfile") || !strcasecmp(varname, "sslcert") || !strcasecmp(varname, "tlscert")) {
++ ast_free(tls_cfg->certfile);
++ tls_cfg->certfile = ast_strdup(value);
++ } else if (!strcasecmp(varname, "tlsprivatekey") || !strcasecmp(varname, "sslprivatekey")) {
++ ast_free(tls_cfg->pvtfile);
++ tls_cfg->pvtfile = ast_strdup(value);
++ } else if (!strcasecmp(varname, "tlscipher") || !strcasecmp(varname, "sslcipher")) {
++ ast_free(tls_cfg->cipher);
++ tls_cfg->cipher = ast_strdup(value);
++ } else if (!strcasecmp(varname, "tlscafile")) {
++ ast_free(tls_cfg->cafile);
++ tls_cfg->cafile = ast_strdup(value);
++ } else if (!strcasecmp(varname, "tlscapath")) {
++ ast_free(tls_cfg->capath);
++ tls_cfg->capath = ast_strdup(value);
++ } else if (!strcasecmp(varname, "tlsverifyclient")) {
++ ast_set2_flag(&tls_cfg->flags, ast_true(value), AST_SSL_VERIFY_CLIENT);
++ } else if (!strcasecmp(varname, "tlsdontverifyserver")) {
++ ast_set2_flag(&tls_cfg->flags, ast_true(value), AST_SSL_DONT_VERIFY_SERVER);
++ } else if (!strcasecmp(varname, "tlsbindaddr") || !strcasecmp(varname, "sslbindaddr")) {
++ if (ast_parse_arg(value, PARSE_INADDR, &tls_desc->local_address))
++ ast_log(LOG_WARNING, "Invalid %s '%s'\n", varname, value);
++ } else if (!strcasecmp(varname, "tlsbindport") || !strcasecmp(varname, "sslbindport")) {
++ tls_desc->local_address.sin_port = htons(atoi(value));
++ } else if (!strcasecmp(varname, "tlsclientmethod") || !strcasecmp(varname, "sslclientmethod")) {
++ if (!strcasecmp(value, "tlsv1")) {
++ ast_set_flag(&tls_cfg->flags, AST_SSL_TLSV1_CLIENT);
++ ast_clear_flag(&tls_cfg->flags, AST_SSL_SSLV3_CLIENT);
++ ast_clear_flag(&tls_cfg->flags, AST_SSL_SSLV2_CLIENT);
++ } else if (!strcasecmp(value, "sslv3")) {
++ ast_set_flag(&tls_cfg->flags, AST_SSL_SSLV3_CLIENT);
++ ast_clear_flag(&tls_cfg->flags, AST_SSL_SSLV2_CLIENT);
++ ast_clear_flag(&tls_cfg->flags, AST_SSL_TLSV1_CLIENT);
++ } else if (!strcasecmp(value, "sslv2")) {
++ ast_set_flag(&tls_cfg->flags, AST_SSL_SSLV2_CLIENT);
++ ast_clear_flag(&tls_cfg->flags, AST_SSL_TLSV1_CLIENT);
++ ast_clear_flag(&tls_cfg->flags, AST_SSL_SSLV3_CLIENT);
++ }
++ } else {
++ return -1;
++ }
++
++ return 0;
++}
+Index: main/file.c
+===================================================================
+--- a/main/file.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/main/file.c (.../trunk) (revision 202568)
+@@ -187,14 +187,20 @@
+ struct ast_frame *trf;
+ fs->lastwriteformat = f->subclass;
+ /* Get the translated frame but don't consume the original in case they're using it on another stream */
+- trf = ast_translate(fs->trans, f, 0);
+- if (trf) {
+- res = fs->fmt->write(fs, trf);
++ if ((trf = ast_translate(fs->trans, f, 0))) {
++ struct ast_frame *cur;
++
++ /* the translator may have returned multiple frames, so process them */
++ for (cur = trf; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
++ if ((res = fs->fmt->write(fs, trf))) {
++ ast_log(LOG_WARNING, "Translated frame write failed\n");
++ break;
++ }
++ }
+ ast_frfree(trf);
+- if (res)
+- ast_log(LOG_WARNING, "Translated frame write failed\n");
+- } else
++ } else {
+ res = 0;
++ }
+ }
+ }
+ return res;
+@@ -1365,7 +1371,7 @@
+ #undef FORMAT2
+ }
+
+-struct ast_cli_entry cli_file[] = {
++static struct ast_cli_entry cli_file[] = {
+ AST_CLI_DEFINE(handle_cli_core_show_file_formats, "Displays file formats")
+ };
+
+Index: main/callerid.c
+===================================================================
+--- a/main/callerid.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/main/callerid.c (.../trunk) (revision 202568)
+@@ -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-beta3) (revision 202568)
++++ b/main/audiohook.c (.../trunk) (revision 202568)
+@@ -20,7 +20,7 @@
+ *
+ * \brief Audiohooks Architecture
+ *
+- * \author Joshua 'file' Colp <jcolp@digium.com>
++ * \author Joshua Colp <jcolp@digium.com>
+ */
+
+ #include "asterisk.h"
+Index: main/xmldoc.c
+===================================================================
+--- a/main/xmldoc.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/main/xmldoc.c (.../trunk) (revision 202568)
+@@ -19,6 +19,8 @@
+ * \brief XML Documentation API
+ *
+ * \author Eliel C. Sardanons (LU1ALY) <eliels@gmail.com>
++ *
++ * \extref libxml2 http://www.xmlsoft.org/
+ */
+
+ #include "asterisk.h"
+@@ -984,19 +986,77 @@
+ return ret;
+ }
+
++/*! \internal
++ * \brief Generate an AMI action syntax.
++ * \param fixnode The manager action node pointer.
++ * \param name The name of the manager action.
++ * \retval The generated syntax.
++ * \retval NULL on error.
++ */
++static char *xmldoc_get_syntax_manager(struct ast_xml_node *fixnode, const char *name)
++{
++ struct ast_str *syntax;
++ struct ast_xml_node *node = fixnode;
++ const char *paramtype, *attrname;
++ int required;
++ char *ret;
++
++ syntax = ast_str_create(128);
++ if (!syntax) {
++ return ast_strdup(name);
++ }
++
++ ast_str_append(&syntax, 0, "Action: %s", name);
++
++ 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;
++ }
++
++ /* Is this parameter required? */
++ required = 0;
++ paramtype = ast_xml_get_attribute(node, "required");
++ if (paramtype) {
++ required = ast_true(paramtype);
++ ast_xml_free_attr(paramtype);
++ }
++
++ attrname = ast_xml_get_attribute(node, "name");
++ if (!attrname) {
++ /* ignore this bogus parameter and continue. */
++ continue;
++ }
++
++ ast_str_append(&syntax, 0, "\n%s%s:%s <value>",
++ (required ? "" : "["),
++ attrname,
++ (required ? "" : "]"));
++
++ ast_xml_free_attr(attrname);
++ }
++
++ /* 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,
++ MANAGER_SYNTAX,
+ COMMAND_SYNTAX
+ };
+
+ /*! \brief Mapping between type of node and type of syntax to generate. */
+-struct strsyntaxtype {
++static struct strsyntaxtype {
+ const char *type;
+ enum syntaxtype stxtype;
+ } stxtype[] = {
+ { "function", FUNCTION_SYNTAX },
+ { "application", FUNCTION_SYNTAX },
++ { "manager", MANAGER_SYNTAX },
+ { "agi", COMMAND_SYNTAX }
+ };
+
+@@ -1034,10 +1094,18 @@
+ }
+
+ if (node) {
+- if (xmldoc_get_syntax_type(type) == FUNCTION_SYNTAX) {
++ switch (xmldoc_get_syntax_type(type)) {
++ case FUNCTION_SYNTAX:
+ syntax = xmldoc_get_syntax_fun(node, name, "parameter", 1, 1);
+- } else {
++ break;
++ case COMMAND_SYNTAX:
+ syntax = xmldoc_get_syntax_cmd(node, name, 1);
++ break;
++ case MANAGER_SYNTAX:
++ syntax = xmldoc_get_syntax_manager(node, name);
++ break;
++ default:
++ syntax = xmldoc_get_syntax_fun(node, name, "parameter", 1, 1);
+ }
+ }
+ return syntax;
+Index: main/rtp_engine.c
+===================================================================
+--- a/main/rtp_engine.c (.../tags/1.6.2.0-beta3) (revision 0)
++++ b/main/rtp_engine.c (.../trunk) (revision 202568)
+@@ -0,0 +1,1617 @@
++/*
++ * 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"
++#include "asterisk/translate.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;
++ /*! Alternate address that we are receiving RTP from */
++ struct sockaddr_in alt_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 sockaddr_in address = { 0, };
++ 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;
++ instance->local_address.sin_family = AF_INET;
++ instance->local_address.sin_addr = sin->sin_addr;
++ instance->remote_address.sin_family = AF_INET;
++ address.sin_addr = sin->sin_addr;
++
++ 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, &address, 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)
++{
++ instance->local_address.sin_addr = address->sin_addr;
++ instance->local_address.sin_port = address->sin_port;
++ return 0;
++}
++
++int ast_rtp_instance_set_remote_address(struct ast_rtp_instance *instance, struct sockaddr_in *address)
++{
++ instance->remote_address.sin_addr = address->sin_addr;
++ instance->remote_address.sin_port = address->sin_port;
++
++ /* moo */
++
++ if (instance->engine->remote_address_set) {
++ instance->engine->remote_address_set(instance, &instance->remote_address);
++ }
++
++ return 0;
++}
++
++int ast_rtp_instance_set_alt_remote_address(struct ast_rtp_instance *instance, struct sockaddr_in *address)
++{
++ instance->alt_remote_address.sin_addr = address->sin_addr;
++ instance->alt_remote_address.sin_port = address->sin_port;
++
++ /* oink */
++
++ if (instance->engine->alt_remote_address_set) {
++ instance->engine->alt_remote_address_set(instance, &instance->alt_remote_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)) ||
++ (codec0 != oldcodec0)) {
++ 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_debug(1, "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 need to get DTMF see if we can do it outside of the RTP stream itself */
++ if ((flags & AST_BRIDGE_DTMF_CHANNEL_0) && instance0->properties[AST_RTP_PROPERTY_DTMF]) {
++ res = AST_BRIDGE_FAILED_NOWARN;
++ goto done;
++ }
++ if ((flags & AST_BRIDGE_DTMF_CHANNEL_1) && instance1->properties[AST_RTP_PROPERTY_DTMF]) {
++ 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_debug(1, "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 = { 0, };
++ 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);
++ ao2_ref(peer_instance, -1);
++ peer_instance = NULL;
++ return -1;
++ }
++
++ res = instance->engine->make_compatible(chan, instance, peer, peer_instance);
++
++ ast_channel_unlock(peer);
++
++ ao2_ref(peer_instance, -1);
++ peer_instance = NULL;
++
++ return res;
++}
++
++int ast_rtp_instance_available_formats(struct ast_rtp_instance *instance, int to_endpoint, int to_asterisk)
++{
++ int formats;
++
++ if (instance->engine->available_formats && (formats = instance->engine->available_formats(instance, to_endpoint, to_asterisk))) {
++ return formats;
++ }
++
++ return ast_translate_available_formats(to_endpoint, to_asterisk);
++}
++
++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/adtranvofr.conf.sample
+===================================================================
+--- a/configs/adtranvofr.conf.sample (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/configs/adtranvofr.conf.sample (.../trunk) (revision 202568)
+@@ -1,39 +0,0 @@
+-;
+-; Voice over Frame Relay (Adtran style)
+-;
+-; Configuration file
+-
+-[interfaces]
+-;
+-; Default language
+-;
+-;language=en
+-;
+-; Lines for which we are the user termination. They accept incoming
+-; and outgoing calls. We use the default context on the first 8 lines
+-; used by internal phones.
+-;
+-context=default
+-;user => voice00
+-;user => voice01
+-;user => voice02
+-;user => voice03
+-;user => voice04
+-;user => voice05
+-;user => voice06
+-;user => voice07
+-; Calls on 16 and 17 come from the outside world, so they get
+-; a little bit special treatment
+-context=remote
+-;user => voice16
+-;user => voice17
+-;
+-; Next we have lines which we only accept calls on, and typically
+-; do not send outgoing calls on (i.e. these are where we are the
+-; network termination)
+-;
+-;network => voice08
+-;network => voice09
+-;network => voice10
+-;network => voice11
+-;network => voice12
+Index: configs/skinny.conf.sample
+===================================================================
+--- a/configs/skinny.conf.sample (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/configs/skinny.conf.sample (.../trunk) (revision 202568)
+@@ -15,12 +15,12 @@
+
+ ; If regcontext is specified, Asterisk will dynamically create and destroy a
+ ; NoOp priority 1 extension for a given line which registers or unregisters with
+-; us and have a "regexten=" configuration item.
+-; Multiple contexts may be specified by separating them with '&'. The
++; us and have a "regexten=" configuration item.
++; Multiple contexts may be specified by separating them with '&'. The
+ ; actual extension is the 'regexten' parameter of the registering line or its
+ ; name if 'regexten' is not provided. If more than one context is provided,
+ ; the context must be specified within regexten by appending the desired
+-; context after '@'. More than one regexten may be supplied if they are
++; context after '@'. More than one regexten may be supplied if they are
+ ; separated by '&'. Patterns may be used in regexten.
+ ;
+ ;regcontext=skinnyregistrations
+@@ -93,7 +93,7 @@
+ ;vmexten=8500 ; Device level voicemailmain pilot number
+ ;regexten=100
+ ;context=inbound
+-;linelabel="Support Line" ; Displays next to the line
++;linelabel="Support Line" ; Displays next to the line
+ ; button on 7940's and 7960s
+ ;[110]
+ ;callerid="John Chambers" <408-526-4000>
+Index: configs/meetme.conf.sample
+===================================================================
+--- a/configs/meetme.conf.sample (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/configs/meetme.conf.sample (.../trunk) (revision 202568)
+@@ -34,12 +34,12 @@
+ ;
+ [rooms]
+ ;
+-; Usage is conf => confno[,pin][,adminpin]
++; Usage is conf => confno[,pin][,adminpin]
+ ;
+ ; Note that once a participant has called the conference, a change to the pin
+ ; number done in this file will not take effect until there are no more users
+ ; in the conference and it goes away. When it is created again, it will have
+ ; the new pin number.
+ ;
+-;conf => 1234
++;conf => 1234
+ ;conf => 2345,9938
+Index: configs/ais.conf.sample
+===================================================================
+--- a/configs/ais.conf.sample (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/configs/ais.conf.sample (.../trunk) (revision 202568)
+@@ -1,5 +1,5 @@
+ ;
+-; Sample configuration file for res_ais
++; Sample configuration file for res_ais
+ ; * SAForum AIS (Application Interface Specification)
+ ;
+ ; More information on the AIS specification is available from the SAForum.
+@@ -76,7 +76,7 @@
+ ;
+ ; This example would be used for a node that has phones directly registered
+ ; to it, but does not have direct access to voicemail. So, this node wants
+-; to be informed about MWI state changes on other voicemail server nodes, but
++; to be informed about MWI state changes on other voicemail server nodes, but
+ ; is not capable of publishing any state changes.
+ ;
+ ; [mwi]
+Index: configs/iax.conf.sample
+===================================================================
+--- a/configs/iax.conf.sample (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/configs/iax.conf.sample (.../trunk) (revision 202568)
+@@ -16,7 +16,7 @@
+ ; bindaddr if followed by colon and port
+ ; (e.g. bindaddr=192.168.0.1:4569)
+ ;bindaddr=192.168.0.1 ; more than once to bind to multiple
+-; ; addresses, but the first will be the
++; ; addresses, but the first will be the
+ ; ; default
+ ;
+ ; Set iaxcompat to yes if you plan to use layered switches or
+@@ -36,7 +36,7 @@
+ ;
+ ; For increased security against brute force password attacks
+ ; enable "delayreject" which will delay the sending of authentication
+-; reject for REGREQ or AUTHREP if there is a password.
++; reject for REGREQ or AUTHREP if there is a password.
+ ;
+ ;delayreject=yes
+ ;
+@@ -60,7 +60,7 @@
+ ;
+ ;accountcode=lss0101
+ ;
+-; You may specify a global default language for users.
++; You may specify a global default language for users.
+ ; Can be specified also on a per-user basis
+ ; If omitted, will fallback to english
+ ;
+@@ -111,7 +111,7 @@
+ ;
+ ; forcejitterbuffer=yes|no: in the ideal world, when we bridge VoIP channels
+ ; we don't want to do jitterbuffering on the switch, since the endpoints
+-; can each handle this. However, some endpoints may have poor jitterbuffers
++; can each handle this. However, some endpoints may have poor jitterbuffers
+ ; themselves, so this option will force * to always jitterbuffer, even in this
+ ; case.
+ ;
+@@ -166,7 +166,7 @@
+ ;
+ ; With a large amount of traffic on IAX2 trunks, there is a risk of bad voice quality due to
+ ; the fact that the IAX2 trunking scheme depends on the Linux system to handle fragmentation of
+-; UDP packets. This may not be very efficient.
++; UDP packets. This may not be very efficient.
+ ; 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.
+ ;
+@@ -177,7 +177,7 @@
+ ; encryption = yes
+ ;
+ ; Force encryption insures no connection is established unless both sides support
+-; encryption. By turning this option on, encryption is automatically turned on as well.
++; encryption. By turning this option on, encryption is automatically turned on as well.
+ ;
+ ; forceencryption = yes
+
+@@ -211,7 +211,7 @@
+ ; Sample Registration for iaxtel
+ ;
+ ; Visit http://www.iaxtel.com to register with iaxtel. Replace "user"
+-; and "pass" with your username and password for iaxtel. Incoming
++; and "pass" with your username and password for iaxtel. Incoming
+ ; calls arrive at the "s" extension of "default" context.
+ ;
+ ;register => user:pass@iaxtel.com
+@@ -228,7 +228,7 @@
+ ;register => FWDNumber:passwd@iax.fwdnet.net
+ ;
+ ;
+-; You can disable authentication debugging to reduce the amount of
++; You can disable authentication debugging to reduce the amount of
+ ; debugging traffic.
+ ;
+ ;authdebug=no
+@@ -256,7 +256,7 @@
+ autokill=yes
+ ;
+ ; codecpriority controls the codec negotiation of an inbound IAX call.
+-; This option is inherited to all user entities. It can also be defined
++; This option is inherited to all user entities. It can also be defined
+ ; in each user entity separately which will override the setting in general.
+ ;
+ ; The valid values are:
+@@ -287,6 +287,9 @@
+ ; just like friends added from the config file only on a
+ ; as-needed basis? (yes|no)
+
++;rtsavesysname=yes ; Save systemname in realtime database at registration
++ ; Default = no
++
+ ;rtupdate=yes ; Send registry updates to database using realtime? (yes|no)
+ ; If set to yes, when a IAX2 peer registers successfully,
+ ; the ip address, the origination port, the registration period,
+@@ -357,7 +360,7 @@
+ ; across the net. "md5" uses a challenge/response md5 sum arrangement, but
+ ; still requires both ends have plain text access to the secret. "rsa" allows
+ ; unidirectional secret knowledge through public/private keys. If "rsa"
+-; authentication is used, "inkeys" is a list of acceptable public keys on the
++; authentication is used, "inkeys" is a list of acceptable public keys on the
+ ; local system that can be used to authenticate the remote peer, separated by
+ ; the ":" character. "outkey" is a single, private key to use to authenticate
+ ; to the other side. Public keys are named /var/lib/asterisk/keys/<name>.pub
+@@ -382,7 +385,7 @@
+ ; an attended transfer.
+ ;dbsecret=mysecrets/place ; Secrets can be stored in astdb, too
+ ;transfer=no ; Disable IAX native transfer
+-;transfer=mediaonly ; When doing IAX native transfers, transfer
++;transfer=mediaonly ; When doing IAX native transfers, transfer
+ ; only media stream
+ ;jitterbuffer=yes ; Override global setting an enable jitter buffer
+ ; ; for this user
+@@ -395,10 +398,10 @@
+ ;language=en ; Use english as default language
+ ;encryption=yes ; Enable IAX2 encryption. The default is no.
+ ;keyrotate=off ; 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.
++; ; IAX2 that do not support key rotation with encryption.
++; ; This option will disable the IAX_COMMAND_RTENC message.
+ ; ; default is on.
+-; ;
++; ;
+ ;
+ ; Peers may also be specified, with a secret and
+ ; a remote hostname.
+@@ -424,10 +427,10 @@
+ ;
+ ;encryption=yes ; Enable IAX2 encryption. The default is no.
+ ;keyrotate=off ; 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.
++; ; IAX2 that do not support key rotation with encryption.
++; ; This option will disable the IAX_COMMAND_RTENC message.
+ ; ; default is on.
+-; ;
++; ;
+ ; Peers can remotely register as well, so that they can be mobile. Default
+ ; IP's can also optionally be given but are not required. Caller*ID can be
+ ; suggested to the other side as well if it is for example a phone instead of
+Index: configs/mgcp.conf.sample
+===================================================================
+--- a/configs/mgcp.conf.sample (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/configs/mgcp.conf.sample (.../trunk) (revision 202568)
+@@ -47,27 +47,27 @@
+
+ ;; The MGCP channel supports the following service codes:
+ ;; # - Transfer
+-;; *67 - Calling Number Delivery Blocking
+-;; *70 - Cancel Call Waiting
+-;; *72 - Call Forwarding Activation
+-;; *73 - Call Forwarding Deactivation
+-;; *78 - Do Not Disturb Activation
+-;; *79 - Do Not Disturb Deactivation
++;; *67 - Calling Number Delivery Blocking
++;; *70 - Cancel Call Waiting
++;; *72 - Call Forwarding Activation
++;; *73 - Call Forwarding Deactivation
++;; *78 - Do Not Disturb Activation
++;; *79 - Do Not Disturb Deactivation
+ ;; *8 - Call pick-up
+ ;
+-; known to work with Swissvoice IP10s
+-;[192.168.1.20]
+-;context=local
+-;host=192.168.1.20
+-;callerid = "John Doe" <123>
++; known to work with Swissvoice IP10s
++;[192.168.1.20]
++;context=local
++;host=192.168.1.20
++;callerid = "John Doe" <123>
+ ;callgroup=0 ; in the range from 0 to 63
+ ;pickupgroup=0 ; in the range from 0 to 63
+-;nat=no
+-;threewaycalling=yes
++;nat=no
++;threewaycalling=yes
+ ;transfer=yes ; transfer requires threewaycalling=yes. Use FLASH to transfer
+ ;callwaiting=yes ; this might be a cause of trouble for ip10s
+-;cancallforward=yes
+-;line => aaln/1
++;cancallforward=yes
++;line => aaln/1
+ ;
+
+ ;[dph100]
+@@ -90,7 +90,7 @@
+ ; 'documentation', or 'omit'
+ ;context = local
+ ;host = 192.168.1.20
+-;wcardep = aaln/* ; enables wildcard endpoint and sets it to 'aaln/*'
++;wcardep = aaln/* ; enables wildcard endpoint and sets it to 'aaln/*'
+ ; another common format is '*'
+ ;callerid = "Duane Cox" <123> ; now lets setup line 1 using per endpoint configuration...
+ ;callwaiting = no
+Index: configs/extensions.lua.sample
+===================================================================
+--- a/configs/extensions.lua.sample (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/configs/extensions.lua.sample (.../trunk) (revision 202568)
+@@ -22,20 +22,20 @@
+ -- an extension name is prefixed by a '_' character, it is interpreted as
+ -- a pattern rather than a literal. In patterns, some characters have
+ -- special meanings:
+---
++--
+ -- X - any digit from 0-9
+ -- Z - any digit from 1-9
+ -- N - any digit from 2-9
+ -- [1235-9] - any digit in the brackets (in this example, 1,2,3,5,6,7,8,9)
+--- . - wildcard, matches anything remaining (e.g. _9011. matches
++-- . - wildcard, matches anything remaining (e.g. _9011. matches
+ -- anything starting with 9011 excluding 9011 itself)
+ -- ! - wildcard, causes the matching process to complete as soon as
+ -- it can unambiguously determine that no other matches are possible
+---
++--
+ -- For example the extension _NXXXXXX would match normal 7 digit
+ -- dialings, while _1NXXNXXXXXX would represent an area code plus phone
+ -- number preceded by a one.
+---
++--
+ -- If your extension has special characters in it such as '.' and '!' you must
+ -- explicitly make it a string in the tabale definition:
+ --
+@@ -44,7 +44,7 @@
+ --
+ -- There are no priorities. All extensions to asterisk appear to have a single
+ -- priority as if they consist of a single priority.
+---
++--
+ -- Each context is defined as a table in the extensions table. The
+ -- context names should be strings.
+ --
+@@ -52,7 +52,7 @@
+ -- extension. This extension should be set to a table containing a list
+ -- of context names. Do not put references to tables in the includes
+ -- table.
+---
++--
+ -- include = {"a", "b", "c"};
+ --
+ -- Channel variables can be accessed thorugh the global 'channel' table.
+@@ -79,8 +79,8 @@
+ -- Also notice the absence of the following constructs from the examples above:
+ -- channel.func_name(1,2,3) = "value" -- this will NOT work
+ -- value = channel.func_name(1,2,3) -- this will NOT work as expected
+---
+ --
++--
+ -- Dialplan applications can be accessed through the global 'app' table.
+ --
+ -- app.Dial("DAHDI/1")
+Index: configs/sip.conf.sample
+===================================================================
+--- a/configs/sip.conf.sample (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/configs/sip.conf.sample (.../trunk) (revision 202568)
+@@ -3,7 +3,7 @@
+ ;
+ ; SIP dial strings
+ ;-----------------------------------------------------------
+-; In the dialplan (extensions.conf) you can use several
++; In the dialplan (extensions.conf) you can use several
+ ; syntaxes for dialing SIP devices.
+ ; SIP/devicename
+ ; SIP/username@domain (SIP uri)
+@@ -17,11 +17,11 @@
+ ; username@domain
+ ; Call any SIP user on the Internet
+ ; (Don't forget to enable DNS SRV records if you want to use this)
+-;
++;
+ ; devicename/extension
+ ; If you define a SIP proxy as a peer below, you may call
+-; SIP/proxyhostname/user or SIP/user@proxyhostname
+-; where the proxyhostname is defined in a section below
++; SIP/proxyhostname/user or SIP/user@proxyhostname
++; where the proxyhostname is defined in a section below
+ ; This syntax also works with ATA's with FXO ports
+ ;
+ ; SIP/username[:password[:md5secret[:authname]]]@host[:port]
+@@ -54,7 +54,7 @@
+ ; When naming devices, make sure you understand how Asterisk matches calls
+ ; that come in.
+ ; 1. Asterisk checks the SIP From: address username and matches against
+-; names of devices with type=user
++; names of devices with type=user
+ ; The name is the text between square brackets [name]
+ ; 2. Asterisk checks the From: addres and matches the list of devices
+ ; with a type=peer
+@@ -64,14 +64,14 @@
+ ; 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
++; (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
+-; to "defaultuser" which is a better name, since it is used in
++; to "defaultuser" which is a better name, since it is used in
+ ; combination with the "defaultip" setting.
+ ;-----------------------------------------------------------------------------
+
+@@ -81,7 +81,7 @@
+ ; You are encouraged to use the dialplan groupcount functionality
+ ; to enforce call limits instead of using this channel-specific method.
+ ;
+-; You can still set limits per device in sip.conf or in a database by using
++; You can still set limits per device in sip.conf or in a database by using
+ ; "setvar" to set variables that can be used in the dialplan for various limits.
+
+ [general]
+@@ -117,38 +117,46 @@
+ ; Remember that the IP address must match the common name (hostname) in the
+ ; certificate, so you don't want to bind a TLS socket to multiple IP addresses.
+
+-;tlscertfile=asterisk.pem ; Certificate file (*.pem only) to use for TLS connections
+- ; default is to look for "asterisk.pem" in current directory
++;tlscertfile=</path/to/certificate.pem> ; Certificate file (*.pem only) to use for TLS connections
++ ; default is to look for "asterisk.pem" in current directory
+
++;tlsprivatekey=</path/to/private.pem> ; Private key file (*.pem only) for TLS connections.
++ ; If no tlsprivatekey is specified, tlscertfile is searched for
++ ; for both public and private key.
++
+ ;tlscafile=</path/to/certificate>
+ ; If the server your connecting to uses a self signed certificate
+-; you should have their certificate installed here so the code can
++; you should have their certificate installed here so the code can
+ ; verify the authenticity of their certificate.
+
+ ;tlscadir=</path/to/ca/dir>
+-; A directory full of CA certificates. The files must be named with
+-; the CA subject name hash value.
+-; (see man SSL_CTX_load_verify_locations for more info)
++; A directory full of CA certificates. The files must be named with
++; the CA subject name hash value.
++; (see man SSL_CTX_load_verify_locations for more info)
+
+ ;tlsdontverifyserver=[yes|no]
+-; If set to yes, don't verify the servers certificate when acting as
++; If set to yes, don't verify the servers certificate when acting as
+ ; a client. If you don't have the server's CA certificate you can
+ ; set this and it will connect without requiring tlscafile to be set.
+ ; Default is no.
+
+ ;tlscipher=<SSL cipher string>
+ ; A string specifying which SSL ciphers to use or not use
+-; A list of valid SSL cipher strings can be found at:
++; A list of valid SSL cipher strings can be found at:
+ ; http://www.openssl.org/docs/apps/ciphers.html#CIPHER_STRINGS
++;
++;tlsclientmethod=tlsv1 ; values include tlsv1, sslv3, sslv2.
++ ; Specify protocol for outbound client connections.
++ ; If left unspecified, the default is sslv2.
+
+ srvlookup=yes ; Enable DNS SRV lookups on outbound calls
+- ; Note: Asterisk only uses the first host
++ ; Note: Asterisk only uses the first host
+ ; in SRV records
+- ; Disabling DNS SRV lookups disables the
+- ; ability to place SIP calls based on domain
++ ; Disabling DNS SRV lookups disables the
++ ; ability to place SIP calls based on domain
+ ; names to some other SIP users on the Internet
+
+-;pedantic=yes ; Enable checking of tags in headers,
++;pedantic=yes ; Enable checking of tags in headers,
+ ; international character conversions in URIs
+ ; and multiline formatted headers for strict
+ ; SIP compatibility (defaults to "no")
+@@ -169,7 +177,7 @@
+ ;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
++;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
+@@ -179,9 +187,19 @@
+ ;buggymwi=no ; Cisco SIP firmware doesn't support the MWI RFC
+ ; fully. Enable this option to not get error messages
+ ; when sending MWI to phones with this bug.
+-;vmexten=voicemail ; dialplan extension to reach mailbox sets the
+- ; Message-Account in the MWI notify message
++;mwi_from=asterisk ; When sending MWI NOTIFY requests, use this setting in
++ ; the From: header as the "name" portion. Also fill the
++ ; "user" portion of the URI in the From: header with this
++ ; value if no fromuser is set
++ ; Default: empty
++;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 +227,18 @@
+ ;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_update = no ; In certain cases, the only method by which a connected line
++ ; change may be immediately transmitted is with a SIP UPDATE request.
++ ; If communicating with another Asterisk server, and you wish to be able
++ ; transmit such UPDATE messages to it, then you must enable this option.
++ ; Otherwise, we will have to wait until we can send a reinvite to
++ ; transmit the information.
++
+ ;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
+@@ -229,7 +259,7 @@
+ ;usereqphone = no ; If yes, ";user=phone" is added to uri that contains
+ ; a valid phone number
+ ;dtmfmode = rfc2833 ; Set default dtmfmode for sending DTMF. Default: rfc2833
+- ; Other options:
++ ; Other options:
+ ; info : SIP INFO messages (application/dtmf-relay)
+ ; shortinfo : SIP INFO messages (application/dtmf)
+ ; inband : Inband audio (requires 64 kbit codec -alaw, ulaw)
+@@ -251,7 +281,7 @@
+ ;maxcallbitrate=384 ; Maximum bitrate for video calls (default 384 kb/s)
+ ; Videosupport and maxcallbitrate is settable
+ ; for peers and users as well
+-;callevents=no ; generate manager events when sip ua
++;callevents=no ; generate manager events when sip ua
+ ; performs events (e.g. hold)
+ ;authfailureevents=no ; generate manager "peerstatus" events when peer can't
+ ; authenticate with Asterisk. Peerstatus will be "rejected".
+@@ -270,7 +300,7 @@
+ ;outboundproxy=proxy.provider.domain ; send outbound signaling to this proxy, not directly to the devices
+ ;outboundproxy=proxy.provider.domain:8080 ; send outbound signaling to this proxy, not directly to the devices
+ ;outboundproxy=proxy.provider.domain,force ; Send ALL outbound signalling to proxy, ignoring route: headers
+-;outboundproxy=tls://proxy.provider.domain ; same as '=proxy.provider.domain' except we try to connect with tls
++;outboundproxy=tls://proxy.provider.domain ; same as '=proxy.provider.domain' except we try to connect with tls
+ ; ; (could also be tcp,udp) - defining transports on the proxy line only
+ ; ; applies for the global proxy, otherwise use the transport= option
+ ;matchexterniplocally = yes ; Only substitute the externip or externhost setting if it matches
+@@ -287,15 +317,17 @@
+ ;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
+-; us and have a "regexten=" configuration item.
+-; Multiple contexts may be specified by separating them with '&'. The
++; us and have a "regexten=" configuration item.
++; Multiple contexts may be specified by separating them with '&'. The
+ ; actual extension is the 'regexten' parameter of the registering peer or its
+ ; name if 'regexten' is not provided. If more than one context is provided,
+ ; the context must be specified within regexten by appending the desired
+-; context after '@'. More than one regexten may be supplied if they are
++; context after '@'. More than one regexten may be supplied if they are
+ ; separated by '&'. Patterns may be used in regexten.
+ ;
+ ;regcontext=sipregistrations
+@@ -305,7 +337,7 @@
+ ; extension for the peer
+ ;
+ ;--------------------------- SIP timers ----------------------------------------------------
+-; These timers are used primarily in INVITE transactions.
++; These timers are used primarily in INVITE transactions.
+ ; The default for Timer T1 is 500 ms or the measured run-trip time between
+ ; Asterisk and the device if you have qualify=yes for the device.
+ ;
+@@ -372,7 +404,7 @@
+ ;--------------------------- SIP DEBUGGING ---------------------------------------------------
+ ;sipdebug = yes ; Turn on SIP debugging by default, from
+ ; the moment the channel loads this configuration
+-;recordhistory=yes ; Record SIP history by default
++;recordhistory=yes ; Record SIP history by default
+ ; (see sip history / sip no history)
+ ;dumphistory=yes ; Dump SIP history at end of SIP dialogue
+ ; SIP history is output to the DEBUG logging channel
+@@ -381,12 +413,12 @@
+ ;--------------------------- STATUS NOTIFICATIONS (SUBSCRIPTIONS) ----------------------------
+ ; You can subscribe to the status of extensions with a "hint" priority
+ ; (See extensions.conf.sample for examples)
+-; chan_sip support two major formats for notifications: dialog-info and SIMPLE
++; chan_sip support two major formats for notifications: dialog-info and SIMPLE
+ ;
+ ; You will get more detailed reports (busy etc) if you have a call counter enabled
+-; for a device.
++; for a device.
+ ;
+-; If you set the busylevel, we will indicate busy when we have a number of calls that
++; If you set the busylevel, we will indicate busy when we have a number of calls that
+ ; matches the busylevel treshold.
+ ;
+ ; For queues, you will need this level of detail in status reporting, regardless
+@@ -427,9 +459,9 @@
+ ;
+ ; This setting is available in the [general] section as well as in device configurations.
+ ; Setting this to yes, enables T.38 fax (UDPTL) passthrough on SIP to SIP calls, provided
+-; both parties have T38 support enabled in their Asterisk configuration
++; both parties have T38 support enabled in their Asterisk configuration
+ ; This has to be enabled in the general section for all devices to work. You can then
+-; disable it on a per device basis.
++; disable it on a per device basis.
+ ;
+ ; T.38 faxing only works in SIP to SIP calls, with no local or agent channel being used.
+ ;
+@@ -437,21 +469,21 @@
+ ;
+ ; 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
+ ;
++; 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:
+ ; register => [transport://]user[@domain][:secret[:authuser]]@host[:port][/extension][~expiry]
+ ;
+-;
+ ;
+-; domain is either
++;
++; domain is either
+ ; - domain in DNS
+ ; - host name in DNS
+ ; - the name of a peer defined below or in realtime
+-; The domain is where you register your username, so your SIP uri you are registering to
++; The domain is where you register your username, so your SIP uri you are registering to
+ ; is username@domain
+ ;
+ ; If no extension is given, the 's' extension is used. The extension needs to
+@@ -482,7 +514,7 @@
+ ;
+ ; Examples:
+ ;
+-;register => 1234:password@mysipprovider.com
++;register => 1234:password@mysipprovider.com
+ ;
+ ; This will pass incoming calls to the 's' extension
+ ;
+@@ -501,7 +533,7 @@
+ ;
+ ; 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
+@@ -603,7 +635,7 @@
+ ; nat = no ; default. Use NAT mode only according to RFC3581 (;rport)
+ ; nat = yes ; Always ignore info and assume NAT
+ ; nat = never ; Never attempt NAT mode or RFC3581 support
+-; nat = route ; route = Assume NAT, don't send rport
++; nat = route ; route = Assume NAT, don't send rport
+ ; ; (work around more UNIDEN bugs)
+
+ ;----------------------------------- MEDIA HANDLING --------------------------------
+@@ -627,7 +659,7 @@
+
+ ;directrtpsetup=yes ; Enable the new experimental direct RTP setup. This sets up
+ ; the call directly with media peer-2-peer without re-invites.
+- ; Will not work for video and cases where the callee sends
++ ; Will not work for video and cases where the callee sends
+ ; RTP payloads and fmtp headers in the 200 OK that does not match the
+ ; callers INVITE. This will also fail if canreinvite is enabled when
+ ; the device is actually behind NAT.
+@@ -666,7 +698,7 @@
+ ;rtupdate=yes ; Send registry updates to database using realtime? (yes|no)
+ ; If set to yes, when a SIP UA registers successfully, the ip address,
+ ; the origination port, the registration period, and the username of
+- ; the UA will be set to database via realtime.
++ ; the UA will be set to database via realtime.
+ ; If not present, defaults to 'yes'. Note: realtime peers will
+ ; probably not function across reloads in the way that you expect, if
+ ; you turn this option off.
+@@ -686,8 +718,8 @@
+ ;
+ ; For realtime peers, when the peer is retrieved from realtime storage,
+ ; the registration information will be used regardless of whether
+- ; it has expired or not; if it expires while the realtime peer
+- ; is still in memory (due to caching or other reasons), the
++ ; it has expired or not; if it expires while the realtime peer
++ ; is still in memory (due to caching or other reasons), the
+ ; information will not be removed from realtime storage
+
+ ;----------------------------------------- SIP DOMAIN SUPPORT ------------------------
+@@ -727,7 +759,7 @@
+ ; address. This is to be polite and
+ ; it may be a mandatory requirement for some
+ ; destinations which do not have a prior
+- ; account relationship with your server.
++ ; account relationship with your server.
+
+ ;------------------------------ JITTER BUFFER CONFIGURATION --------------------------
+ ; jbenable = yes ; Enables the use of a jitterbuffer on the receiving side of a
+@@ -761,20 +793,20 @@
+ ; any credentials in peer/register definition if realm is matched.
+ ;
+ ; This way, Asterisk can authenticate for outbound calls to other
+-; realms. We match realm on the proxy challenge and pick an set of
++; realms. We match realm on the proxy challenge and pick an set of
+ ; credentials from this list
+ ; Syntax:
+ ; auth = <user>:<secret>@<realm>
+ ; auth = <user>#<md5secret>@<realm>
+ ; Example:
+ ;auth=mark:topsecret@digium.com
+-;
+-; You may also add auth= statements to [peer] definitions
++;
++; You may also add auth= statements to [peer] definitions
+ ; Peer auth= override all other authentication settings if we match on realm
+
+ ;------------------------------------------------------------------------------
+ ; 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.
+@@ -785,16 +817,16 @@
+ ; trunks.
+ ;
+ ; 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 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
+-; --------------------
++;
++; Configuration options available
++; --------------------
+ ; context
+ ; callingpres
+ ; permit
+@@ -863,7 +895,7 @@
+
+ ;[sip_proxy]
+ ; For incoming calls only. Example: FWD (Free World Dialup)
+-; We match on IP address of the proxy for incoming calls
++; We match on IP address of the proxy for incoming calls
+ ; since we can not match on username (caller id)
+ ;type=peer
+ ;context=from-fwd
+@@ -874,7 +906,7 @@
+ ;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
++;fromdomain=provider.sip.domain
+ ;host=box.provider.com
+ ;transport=udp,tcp ; This sets the default transport type to udp for outgoing, and will
+ ; ; accept both tcp and udp. The default transport type is only used for
+@@ -947,7 +979,7 @@
+ ; Standard configurations not using templates look like this:
+ ;
+ ;[grandstream1]
+-;type=friend
++;type=friend
+ ;context=from-sip ; Where to start in the dialplan when this phone calls
+ ;callerid=John Doe <1234> ; Full caller ID, to override the phones config
+ ; on incoming calls to Asterisk
+@@ -997,14 +1029,14 @@
+ ;context=from-sip ; Context for incoming calls from this user
+ ;secret=blah
+ ;subscribecontext=localextensions ; Only allow SUBSCRIBE for local extensions
+-;language=de ; Use German prompts for this user
++;language=de ; Use German prompts for this user
+ ;host=dynamic ; This peer register with us
+ ;dtmfmode=inband ; Choices are inband, rfc2833, or info
+ ;defaultip=192.168.0.59 ; IP used until peer registers
+ ;mailbox=1234@context,2345 ; Mailbox(-es) for message waiting indicator
+-;subscribemwi=yes ; Only send notifications if this phone
++;subscribemwi=yes ; Only send notifications if this phone
+ ; subscribes for mailbox notification
+-;vmexten=voicemail ; dialplan extension to reach mailbox
++;vmexten=voicemail ; dialplan extension to reach mailbox
+ ; sets the Message-Account in the MWI notify message
+ ; defaults to global vmexten which defaults to "asterisk"
+ ;disallow=all
+@@ -1029,14 +1061,14 @@
+ ;type=friend
+ ;secret=blah
+ ;host=dynamic
+-;insecure=port ; Allow matching of peer by IP address without
++;insecure=port ; Allow matching of peer by IP address without
+ ; matching port number
+ ;insecure=invite ; Do not require authentication of incoming INVITEs
+ ;insecure=port,invite ; (both)
+ ;qualify=1000 ; Consider it down if it's 1 second to reply
+ ; Helps with NAT session
+ ; qualify=yes uses default value
+-;qualifyfreq=60 ; Qualification: How often to check for the
++;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
+@@ -1054,13 +1086,13 @@
+ ;secret=blah
+ ;qualify=200 ; Qualify peer is no more than 200ms away
+ ;nat=yes ; This phone may be natted
+- ; Send SIP and RTP to the IP address that packet is
+- ; received from instead of trusting SIP headers
++ ; Send SIP and RTP to the IP address that packet is
++ ; received from instead of trusting SIP headers
+ ;host=dynamic ; This device registers with us
+ ;canreinvite=no ; Asterisk by default tries to redirect the
+ ; RTP media stream (audio) to go directly from
+ ; the caller to the callee. Some devices do not
+- ; support this (especially if one of them is
++ ; support this (especially if one of them is
+ ; behind a NAT).
+ ;defaultip=192.168.0.4 ; IP address to use until registration
+ ;defaultuser=goran ; Username to use when calling this device before registration
+Index: configs/say.conf.sample
+===================================================================
+--- a/configs/say.conf.sample (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/configs/say.conf.sample (.../trunk) (revision 202568)
+@@ -1,4 +1,4 @@
+-;
++;
+ ; language configuration
+ ;
+
+@@ -66,7 +66,7 @@
+ ; date:M:200604172030.00-4-102
+ ; date:p:200604172030.00-4-102
+ ;
+-;
++;
+ ; Remember, normally X Z N are special, and the search is
+ ; case insensitive, so you must use [X] [N] [Z] .. if you
+ ; want exact match.
+Index: configs/queuerules.conf.sample
+===================================================================
+--- a/configs/queuerules.conf.sample (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/configs/queuerules.conf.sample (.../trunk) (revision 202568)
+@@ -1,12 +1,12 @@
+-; It is possible to change the value of the QUEUE_MAX_PENALTY and QUEUE_MIN_PENALTY
++; It is possible to change the value of the QUEUE_MAX_PENALTY and QUEUE_MIN_PENALTY
+ ; channel variables in mid-call by defining rules in the queue for when to do so. This can allow for
+-; a call to be opened to more members or potentially a different set of members.
+-; The advantage to changing members this way as opposed to inserting the caller into a
+-; different queue with more members or reinserting the caller into the same queue with a different
+-; QUEUE_MAX_PENALTY or QUEUE_MIN_PENALTY set is that the caller does not lose his place in the queue.
++; a call to be opened to more members or potentially a different set of members.
++; The advantage to changing members this way as opposed to inserting the caller into a
++; different queue with more members or reinserting the caller into the same queue with a different
++; QUEUE_MAX_PENALTY or QUEUE_MIN_PENALTY set is that the caller does not lose his place in the queue.
+ ;
+-; Note: There is a limitation to these rules; a caller will follow the penaltychange rules for
+-; the queue that were defined at the time the caller entered the queue. If an update to the rules is
++; Note: There is a limitation to these rules; a caller will follow the penaltychange rules for
++; the queue that were defined at the time the caller entered the queue. If an update to the rules is
+ ; made during the the caller's stay in the queue, these will not be reflected for that caller.
+ ;
+ ; The syntax for these rules is
+Index: configs/indications.conf.sample
+===================================================================
+--- a/configs/indications.conf.sample (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/configs/indications.conf.sample (.../trunk) (revision 202568)
+@@ -516,7 +516,7 @@
+ dialrecall = 425/500,0/50
+ ; RECORDTONE - not specified
+ record = 1400/500,0/15000
+-; 950/1400/1800 3x0.33 on 1.0 off repeated 3 times
++; 950/1400/1800 3x0.33 on 1.0 off repeated 3 times
+ info = !950/330,!1400/330,!1800/330,!0/1000,!950/330,!1400/330,!1800/330,!0/1000,!950/330,!1400/330,!1800/330,!0/1000
+ ; STUTTER - not specified
+ stutter = !425/100,!0/100,!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,425
+@@ -567,7 +567,7 @@
+ [sg]
+ description = Singapore
+ ; Singapore
+-; Reference: http://www.ida.gov.sg/idaweb/doc/download/I397/ida_ts_pstn1_i4r2.pdf
++; Reference: http://www.ida.gov.sg/idaweb/doc/download/I397/ida_ts_pstn1_i4r2.pdf
+ ; Frequency specs are: 425 Hz +/- 20Hz; 24 Hz +/- 2Hz; modulation depth 100%; SIT +/- 50Hz
+ ringcadence = 400,200,400,2000
+ dial = 425
+@@ -691,7 +691,7 @@
+ stutter = !350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,350+440
+
+ [ve]
+-; Tone definition source for ve found on
++; Tone definition source for ve found on
+ ; Reference: http://www.itu.int/ITU-T/inr/forms/files/tones-0203.pdf
+ description = Venezuela / South America
+ ringcadence = 1000,4000
+Index: configs/jingle.conf.sample
+===================================================================
+--- a/configs/jingle.conf.sample (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/configs/jingle.conf.sample (.../trunk) (revision 202568)
+@@ -5,16 +5,16 @@
+ ;;list of peers
+ ;
+ ;[guest] ;;special account for options on guest account
+-;disallow=all
++;disallow=all
+ ;allow=ulaw
+ ;context=guest
+ ;
+ ;[ogorman]
+-;username=ogorman@gmail.com ;;username of the peer your
++;username=ogorman@gmail.com ;;username of the peer your
+ ;;calling or accepting calls from
+ ;disallow=all
+ ;allow=ulaw
+-;context=default
++;context=default
+ ;connection=asterisk ;;client or component in jabber.conf
+ ;;for the call to leave on.
+ ;
+Index: configs/voicemail.conf.sample
+===================================================================
+--- a/configs/voicemail.conf.sample (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/configs/voicemail.conf.sample (.../trunk) (revision 202568)
+@@ -65,7 +65,7 @@
+ ;userscontext=default
+ ;
+ ; If you need to have an external program, i.e. /usr/bin/myapp
+-; called when a voicemail is left, delivered, or your voicemailbox
++; called when a voicemail is left, delivered, or your voicemailbox
+ ; is checked, uncomment this.
+ ;externnotify=/usr/bin/myapp
+
+@@ -93,7 +93,7 @@
+ ;directoryintro=dir-intro
+ ; The character set for voicemail messages can be specified here
+ ;charset=ISO-8859-1
+-; The ADSI feature descriptor number to download to
++; The ADSI feature descriptor number to download to
+ ;adsifdn=0000000F
+ ; The ADSI security lock code
+ ;adsisec=9BDBF7AC
+@@ -156,59 +156,59 @@
+ ; ; enables polling mailboxes for changes. Normally, it will
+ ; ; expect that changes are only made when someone called in
+ ; ; to one of the voicemail applications.
+-; ; Examples of situations that would require this option are
+-; ; web interfaces to voicemail or an email client in the case
++; ; Examples of situations that would require this option are
++; ; web interfaces to voicemail or an email client in the case
+ ; ; of using IMAP storage.
+ ;
+ ;pollfreq=30 ; If the "pollmailboxes" option is enabled, this option
+ ; ; sets the polling frequency. The default is once every
+ ; ; 30 seconds.
+-; If using IMAP storage, specify whether voicemail greetings should be stored
++; If using IMAP storage, specify whether voicemail greetings should be stored
+ ; via IMAP. If no, then greetings are stored as if IMAP storage were not enabled
+ ;imapgreetings=no
+ ; If imapgreetings=yes, then specify which folder to store your greetings in. If
+ ; you do not specify a folder, then INBOX will be used
+ ;greetingsfolder=INBOX
+-; Some IMAP server implementations store folders under INBOX instead of
++; Some IMAP server implementations store folders under INBOX instead of
+ ; using a top level folder (ex. INBOX/Friends). In this case, user
+ ; imapparentfolder to set the parent folder. For example, Cyrus IMAP does
+ ; NOT use INBOX as the parent. Default is to have no parent folder set.
+ ;imapparentfolder=INBOX
+-;
+-; Users may be located in different timezones, or may have different
+-; message announcements for their introductory message when they enter
+-; the voicemail system. Set the message and the timezone each user
+-; hears here. Set the user into one of these zones with the tz= attribute
+-; in the options field of the mailbox. Of course, language substitution
+-; still applies here so you may have several directory trees that have
+-; alternate language choices.
+-;
+-; Look in /usr/share/zoneinfo/ for names of timezones.
+-; Look at the manual page for strftime for a quick tutorial on how the
+-; variable substitution is done on the values below.
+-;
+-; Supported values:
++;
++; Users may be located in different timezones, or may have different
++; message announcements for their introductory message when they enter
++; the voicemail system. Set the message and the timezone each user
++; hears here. Set the user into one of these zones with the tz= attribute
++; in the options field of the mailbox. Of course, language substitution
++; still applies here so you may have several directory trees that have
++; alternate language choices.
++;
++; Look in /usr/share/zoneinfo/ for names of timezones.
++; Look at the manual page for strftime for a quick tutorial on how the
++; variable substitution is done on the values below.
++;
++; Supported values:
+ ; 'filename' filename of a soundfile (single ticks around the filename
+ ; required)
+-; ${VAR} variable substitution
+-; A or a Day of week (Saturday, Sunday, ...)
+-; B or b or h Month name (January, February, ...)
+-; d or e numeric day of month (first, second, ..., thirty-first)
+-; Y Year
+-; I or l Hour, 12 hour clock
+-; H Hour, 24 hour clock (single digit hours preceded by "oh")
+-; k Hour, 24 hour clock (single digit hours NOT preceded by "oh")
+-; M Minute, with 00 pronounced as "o'clock"
++; ${VAR} variable substitution
++; A or a Day of week (Saturday, Sunday, ...)
++; B or b or h Month name (January, February, ...)
++; d or e numeric day of month (first, second, ..., thirty-first)
++; Y Year
++; I or l Hour, 12 hour clock
++; H Hour, 24 hour clock (single digit hours preceded by "oh")
++; k Hour, 24 hour clock (single digit hours NOT preceded by "oh")
++; M Minute, with 00 pronounced as "o'clock"
+ ; N Minute, with 00 pronounced as "hundred" (US military time)
+-; P or p AM or PM
++; P or p AM or PM
+ ; Q "today", "yesterday" or ABdY
+-; (*note: not standard strftime value)
++; (*note: not standard strftime value)
+ ; q "" (for today), "yesterday", weekday, or ABdY
+-; (*note: not standard strftime value)
+-; R 24 hour time, including minute
+-;
+-;
++; (*note: not standard strftime value)
++; R 24 hour time, including minute
+ ;
++;
++;
+ ; Each mailbox is listed in the form <mailbox>=<password>,<name>,<email>,<pager_email>,<options>
+ ; if the e-mail is specified, a message will be sent when a message is
+ ; received, to the given mailbox. If pager is specified, a message will be
+@@ -218,7 +218,7 @@
+ ; Advanced options example is extension 4069
+ ; NOTE: All options can be expressed globally in the general section, and
+ ; overridden in the per-mailbox settings, unless listed otherwise.
+-;
++;
+ ; tz=central ; Timezone from zonemessages below. Irrelevant if envelope=no.
+ ; attach=yes ; Attach the voicemail to the notification email *NOT* the pager email
+ ; attachfmt=wav49 ; Which format to attach to the email. Normally this is the
+@@ -226,16 +226,16 @@
+ ; option lets you customize the format sent to particular mailboxes.
+ ; Useful if Windows users want wav49, but Linux users want gsm.
+ ; [per-mailbox only]
+-; saycid=yes ; Say the caller id information before the message. If not described,
++; saycid=yes ; Say the caller id information before the message. If not described,
+ ; or set to no, it will be in the envelope
+-; cidinternalcontexts=intern ; Internal Context for Name Playback instead of
++; cidinternalcontexts=intern ; Internal Context for Name Playback instead of
+ ; extension digits when saying caller id.
+ ; sayduration=no ; Turn on/off the duration information before the message. [ON by default]
+ ; saydurationm=2 ; Specify the minimum duration to say. Default is 2 minutes
+-; dialout=fromvm ; Context to dial out from [option 4 from mailbox's advanced menu].
+- ; If not specified, option 4 will not be listed and dialing out
++; dialout=fromvm ; Context to dial out from [option 4 from mailbox's advanced menu].
++ ; If not specified, option 4 will not be listed and dialing out
+ ; from within VoiceMailMain() will not be permitted.
+-sendvoicemail=yes ; Allow the user to compose and send a voicemail while inside
++sendvoicemail=yes ; Allow the user to compose and send a voicemail while inside
+ ; VoiceMailMain() [option 5 from mailbox's advanced menu].
+ ; If set to 'no', option 5 will not be listed.
+ ; searchcontexts=yes ; Current default behavior is to search only the default context
+@@ -244,7 +244,7 @@
+ ; Note: If you have this option enabled, then you will be required to have
+ ; unique mailbox names across all contexts. Otherwise, an ambiguity is created
+ ; since it is impossible to know which mailbox to retrieve when one is requested.
+-; callback=fromvm ; Context to call back from
++; callback=fromvm ; Context to call back from
+ ; if not listed, calling the sender back will not be permitted
+ ; exitcontext=fromvm ; Context to go to on user exit such as * or 0
+ ; The default is the current context.
+@@ -253,10 +253,10 @@
+ ; 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]
++; 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]
+- ; This is intended for use with users who wish to receive their
++ ; This is intended for use with users who wish to receive their
+ ; voicemail ONLY by email. Note: "deletevoicemail" is provided as an
+ ; equivalent option for Realtime configuration.
+ ; volgain=0.0 ; Emails bearing the voicemail may arrive in a volume too
+@@ -264,7 +264,7 @@
+ ; much gain to add to the message when sending a voicemail.
+ ; NOTE: sox must be installed for this option to work.
+ ; nextaftercmd=yes ; Skips to the next message after hitting 7 or 9 to delete/save current message.
+- ; [global option only at this time]
++ ; [global option only at this time]
+ ; forcename=yes ; Forces a new user to record their name. A new user is
+ ; determined by the password being the same as
+ ; the mailbox number. The default is "no".
+Index: configs/misdn.conf.sample
+===================================================================
+--- a/configs/misdn.conf.sample (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/configs/misdn.conf.sample (.../trunk) (revision 202568)
+@@ -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
+@@ -176,13 +161,16 @@
+ language=en
+
+ ;
+-; sets the musiconhold class
++; 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
++; the peer channel did not suggest a class to use.
+ ;
+ musicclass=default
+
+ ;
+ ; Either if we should produce DTMF Tones ourselves
+-;
++;
+ senddtmf=yes
+
+ ;
+@@ -205,14 +193,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.
++; Incoming number prefixes for the indicated Type-Of-Number. These are
++; inserted before any number (caller, dialed, connected, redirecting,
++; redirection) received from the ISDN link if that number has the
++; corresponding 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 +222,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 +232,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 +258,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
+@@ -280,30 +293,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
+@@ -313,7 +327,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
+
+@@ -321,16 +335,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
+@@ -338,7 +352,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
+@@ -346,9 +360,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
+@@ -369,6 +383,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
+@@ -376,11 +392,38 @@
+ ; 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
+
++; Select what to do with outgoing COLP information on this port.
++;
++; 0 - Send out COLP information unaltered. (default)
++; 1 - Force COLP to restricted on all outgoing COLP information.
++; 2 - Do not send COLP information.
++outgoing_colp=0
++
++; 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.
+@@ -391,18 +434,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
+
+ ;
+@@ -412,7 +446,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
+@@ -420,8 +454,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,8 +466,19 @@
+ ;
+ max_outgoing=-1
+
++;
++; Enable/disable the call-completion retention option support (ptp only).
++;
++; Note: To use the CCBS/CCNR supplementary service feature and other
++; supplementary services using FACILITY messages requires a
++; modified version of mISDN from:
++; http://svn.digium.com/svn/thirdparty/mISDN/trunk
++; http://svn.digium.com/svn/thirdparty/mISDNuser/trunk
++;
++cc_request_retention=yes
++
+ [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
+@@ -445,21 +490,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/festival.conf.sample
+===================================================================
+--- a/configs/festival.conf.sample (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/configs/festival.conf.sample (.../trunk) (revision 202568)
+@@ -15,9 +15,9 @@
+ ;
+ ;usecache=yes
+ ;
+-; If usecache=yes, a directory to store waveform cache files.
++; If usecache=yes, a directory to store waveform cache files.
+ ; The cache is never cleared (yet), so you must take care of cleaning it
+-; yourself (just delete any or all files from the cache).
++; yourself (just delete any or all files from the cache).
+ ; THIS DIRECTORY *MUST* EXIST and must be writable from the asterisk process.
+ ; Defaults to /tmp/
+ ;
+@@ -25,10 +25,10 @@
+ ;
+ ; Festival command to send to the server.
+ ; Defaults to: (tts_textasterisk "%s" 'file)(quit)\n
+-; %s is replaced by the desired text to say. The command MUST end with a
+-; (quit) directive, or the cache handling mechanism will hang. Do not
+-; forget the \n at the end.
+-;
++; %s is replaced by the desired text to say. The command MUST end with a
++; (quit) directive, or the cache handling mechanism will hang. Do not
++; forget the \n at the end.
++;
+ ;festivalcommand=(tts_textasterisk "%s" 'file)(quit)\n
+ ;
+ ;
+Index: configs/http.conf.sample
+===================================================================
+--- a/configs/http.conf.sample (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/configs/http.conf.sample (.../trunk) (revision 202568)
+@@ -38,7 +38,7 @@
+ ;enablestatic=yes
+ ;
+ ; Redirect one URI to another. This is how you would set a
+-; default page.
++; default page.
+ ; Syntax: redirect=<from here> <to there>
+ ; For example, if you are using the Asterisk-gui,
+ ; it is convenient to enable the following redirect:
+@@ -46,18 +46,21 @@
+ ;redirect = / /static/config/cfgbasic.html
+ ;
+ ; HTTPS support. In addition to enabled=yes, you need to
+-; explicitly enable ssl, define the port to use,
++; explicitly enable tls, define the port to use,
+ ; and have a certificate somewhere.
+-; sslenable=yes ; enable ssl - default no.
+-; sslbindport=4433 ; port to use - default is 8089
+-; sslbindaddr=0.0.0.0 ; address to bind to - default is bindaddr.
++;tlsenable=yes ; enable tls - default no.
++;tlsbindport=4433 ; port to use - default is 8089
++;tlsbindaddr=0.0.0.0 ; address to bind to - default is bindaddr.
+ ;
+-; sslcert=/tmp/foo.pem ; path to the certificate
++;tlscertfile=</path/to/certificate.pem> ; path to the certificate file (*.pem) only.
++;tlsprivatekey=</path/to/private.pem> ; path to private key file (*.pem) only.
++; If no path is given for tlscertfile or tlsprivatekey, default is to look in current
++; directory. If no tlsprivatekey is given, default is to search tlscertfile for private key.
+ ;
+-; To produce a certificate you can e.g. use openssl
+-; openssl req -new -x509 -days 365 -nodes -out /tmp/foo.pem -keyout /tmp/foo.pem
++; To produce a certificate you can e.g. use openssl. This places both the cert and
++; private in same .pem file.
++; openssl req -new -x509 -days 365 -nodes -out /tmp/foo.pem -keyout /tmp/foo.pem
+ ;
+-
+ ; The post_mappings section maps URLs to real paths on the filesystem. If a
+ ; POST is done from within an authenticated manager session to one of the
+ ; configured POST mappings, then any files in the POST will be placed in the
+Index: configs/phoneprov.conf.sample
+===================================================================
+--- a/configs/phoneprov.conf.sample (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/configs/phoneprov.conf.sample (.../trunk) (revision 202568)
+@@ -14,7 +14,7 @@
+ ; You can define profiles for different phones specifying what files to register
+ ; with the provisioning server. You can define either static files, or dynamically
+ ; generated files that can have dynamic names and point to templates that variables
+-; can be substituted into. You can also set arbitrary variables for the profiles
++; can be substituted into. You can also set arbitrary variables for the profiles
+ ; templates to have access to. Example:
+
+ ;[example]
+@@ -44,7 +44,7 @@
+ [polycom]
+ staticdir => configs/ ; Sub directory of AST_DATA_DIR/phoneprov that static files reside
+ ; in. This allows a request to /phoneprov/sip.cfg to pull the file
+- ; from /phoneprov/configs/sip.cfg
++ ; from /phoneprov/configs/sip.cfg
+ mime_type => text/xml ; Default mime type to use if one isn't specified or the
+ ; extension isn't recognized
+ static_file => bootrom.ld,application/octet-stream ; Static files the phone will download
+@@ -53,38 +53,38 @@
+ static_file => sip.ver,plain/text
+ static_file => sip.cfg
+ static_file => custom.cfg
+-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 => 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-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-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
+@@ -112,6 +112,6 @@
+
+ ${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
++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/alarmreceiver.conf.sample
+===================================================================
+--- a/configs/alarmreceiver.conf.sample (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/configs/alarmreceiver.conf.sample (.../trunk) (revision 202568)
+@@ -7,10 +7,10 @@
+
+ [general]
+
+-;
++;
+ ; Specify a timestamp format for the metadata section of the event files
+ ; Default is %a %b %d, %Y @ %H:%M:%S %Z
+-
++
+ timestampformat = %a %b %d, %Y @ %H:%M:%S %Z
+
+ ;
+@@ -32,7 +32,7 @@
+
+ eventspooldir = /tmp
+
+-;
++;
+ ; The alarmreceiver app can either log the events one-at-a-time to individual
+ ; files in the spool directory, or it can store them until the caller
+ ; disconnects and write them all to one file.
+@@ -46,7 +46,7 @@
+ ; The timeout for receiving the first DTMF digit is adjustable from 1000 msec.
+ ; to 10000 msec. The default is 2000 msec. Note: if you wish to test the
+ ; receiver by entering digits manually, set this to a reasonable time out
+-; like 10000 milliseconds.
++; like 10000 milliseconds.
+
+ fdtimeout = 2000
+
+@@ -54,7 +54,7 @@
+ ; The timeout for receiving subsequent DTMF digits is adjustable from
+ ; 110 msec. to 4000 msec. The default is 200 msec. Note: if you wish to test
+ ; the receiver by entering digits manually, set this to a reasonable time out
+-; like 4000 milliseconds.
++; like 4000 milliseconds.
+ ;
+
+ sdtimeout = 200
+Index: configs/musiconhold.conf.sample
+===================================================================
+--- a/configs/musiconhold.conf.sample (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/configs/musiconhold.conf.sample (.../trunk) (revision 202568)
+@@ -8,9 +8,9 @@
+
+
+ ; valid mode options:
+-; files -- read files from a directory in any Asterisk supported
++; files -- read files from a directory in any Asterisk supported
+ ; media format
+-; quietmp3 -- default
++; quietmp3 -- default
+ ; mp3 -- loud
+ ; mp3nb -- unbuffered
+ ; quietmp3nb -- quiet unbuffered
+Index: configs/iaxprov.conf.sample
+===================================================================
+--- a/configs/iaxprov.conf.sample (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/configs/iaxprov.conf.sample (.../trunk) (revision 202568)
+@@ -7,7 +7,7 @@
+ ; Templates provide a group of settings from which provisioning takes place.
+ ; A template may be based upon any template that has been specified before
+ ; it. If the template that an entry is based on is not specified then it is
+-; presumed to be 'default' (unless it is the first of course).
++; presumed to be 'default' (unless it is the first of course).
+ ;
+ ; Templates which begin with 'si-' are used for provisioning units with
+ ; specific service identifiers. For example the entry "si-000364000126"
+Index: configs/unistim.conf.sample
+===================================================================
+--- a/configs/unistim.conf.sample (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/configs/unistim.conf.sample (.../trunk) (revision 202568)
+@@ -69,7 +69,7 @@
+ ;bookmark=Hans C.@123 ; Use a softkey to dial 123. Name : 9 char max
+ ;bookmark=Mailbox@011@54 ; 54 shows a mailbox icon. See #define FAV_ICON_ for other values (32 to 63)
+ ;bookmark=Test@*@USTM/violet ; Display an icon if violet is connected (dynamic), only for unistim device
+-;bookmark=4@Pager@54321@51 ; Display a pager icon and dial 54321 when softkey 4 is pressed
++;bookmark=4@Pager@54321@51 ; Display a pager icon and dial 54321 when softkey 4 is pressed
+
+ ;[violet]
+ ;device=006038abcdef
+Index: configs/extensions.conf.sample
+===================================================================
+--- a/configs/extensions.conf.sample (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/configs/extensions.conf.sample (.../trunk) (revision 202568)
+@@ -1,21 +1,21 @@
+ ; extensions.conf - the Asterisk dial plan
+ ;
+ ; Static extension configuration file, used by
+-; the pbx_config module. This is where you configure all your
+-; inbound and outbound calls in Asterisk.
+-;
+-; This configuration file is reloaded
++; the pbx_config module. This is where you configure all your
++; inbound and outbound calls in Asterisk.
++;
++; This configuration file is reloaded
+ ; - With the "dialplan reload" command in the CLI
+ ; - With the "reload" command (that reloads everything) in the CLI
+
+ ;
+-; The "General" category is for certain variables.
++; The "General" category is for certain variables.
+ ;
+ [general]
+ ;
+ ; If static is set to no, or omitted, then the pbx_config will rewrite
+ ; this file when extensions are modified. Remember that all comments
+-; made in the file will be lost when that happens.
++; made in the file will be lost when that happens.
+ ;
+ ; XXX Not yet implemented XXX
+ ;
+@@ -30,8 +30,8 @@
+ ; things to do, it will terminate the call with BUSY, CONGESTION
+ ; or HANGUP depending on Asterisk's best guess. This is the default.
+ ;
+-; If autofallthrough is not set, then if an extension runs out of
+-; things to do, Asterisk will wait for a new extension to be dialed
++; If autofallthrough is not set, then if an extension runs out of
++; things to do, Asterisk will wait for a new extension to be dialed
+ ; (this is the original behavior of Asterisk 1.0 and earlier).
+ ;
+ ;autofallthrough=no
+@@ -41,7 +41,7 @@
+ ; If extenpatternmatchnew is set (true, yes, etc), then a new algorithm that uses
+ ; a Trie to find the best matching pattern is used. In dialplans
+ ; with more than about 20-40 extensions in a single context, this
+-; new algorithm can provide a noticeable speedup.
++; new algorithm can provide a noticeable speedup.
+ ; With 50 extensions, the speedup is 1.32x
+ ; with 88 extensions, the speedup is 2.23x
+ ; with 138 extensions, the speedup is 3.44x
+@@ -49,27 +49,27 @@
+ ; with 438 extensions, the speedup is 10.4x
+ ; With 1000 extensions, the speedup is ~25x
+ ; with 10,000 extensions, the speedup is 374x
+-; Basically, the new algorithm provides a flat response
++; Basically, the new algorithm provides a flat response
+ ; time, no matter the number of extensions.
+ ;
+-; By default, the old pattern matcher is used.
++; By default, the old pattern matcher is used.
+ ;
+ ; ****This is a new feature! *********************
+-; The new pattern matcher is for the brave, the bold, and
++; The new pattern matcher is for the brave, the bold, and
+ ; the desperate. If you have large dialplans (more than about 50 extensions
+-; in a context), and/or high call volume, you might consider setting
++; in a context), and/or high call volume, you might consider setting
+ ; this value to "yes" !!
+ ; Please, if you try this out, and are forced to return to the
+ ; old pattern matcher, please report your reasons in a bug report
+-; on bugs.digium.com. We have made good progress in providing something
+-; compatible with the old matcher; help us finish the job!
++; on https://issues.asterisk.org. We have made good progress in providing
++; something compatible with the old matcher; help us finish the job!
+ ;
+ ; This value can be switched at runtime using the cli command "dialplan set extenpatternmatchnew true"
+ ; or "dialplan set extenpatternmatchnew false", so you can experiment to your hearts content.
+ ;
+ ;extenpatternmatchnew=no
+ ;
+-; If clearglobalvars is set, global variables will be cleared
++; If clearglobalvars is set, global variables will be cleared
+ ; and reparsed on a dialplan reload, or Asterisk reload.
+ ;
+ ; If clearglobalvars is not set, then global variables will persist
+@@ -108,7 +108,7 @@
+ ;#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
++; 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.
+@@ -153,8 +153,8 @@
+ ; yourself a ton of grief.
+ ; WARNING WARNING WARNING WARNING
+ ;
+-; Any category other than "General" and "Globals" represent
+-; extension contexts, which are collections of extensions.
++; Any category other than "General" and "Globals" represent
++; extension contexts, which are collections of extensions.
+ ;
+ ; Extension names may be numbers, letters, or combinations
+ ; thereof. If an extension name is prefixed by a '_'
+@@ -165,12 +165,12 @@
+ ; Z - any digit from 1-9
+ ; N - any digit from 2-9
+ ; [1235-9] - any digit in the brackets (in this example, 1,2,3,5,6,7,8,9)
+-; . - wildcard, matches anything remaining (e.g. _9011. matches
++; . - wildcard, matches anything remaining (e.g. _9011. matches
+ ; anything starting with 9011 excluding 9011 itself)
+ ; ! - wildcard, causes the matching process to complete as soon as
+ ; it can unambiguously determine that no other matches are possible
+ ;
+-; For example, the extension _NXXXXXX would match normal 7 digit dialings,
++; For example, the extension _NXXXXXX would match normal 7 digit dialings,
+ ; while _1NXXNXXXXXX would represent an area code plus phone number
+ ; preceded by a one.
+ ;
+@@ -197,7 +197,7 @@
+ ;[context]
+ ;exten => someexten,{priority|label{+|-}offset}[(alias)],application(arg1,arg2,...)
+ ;
+-; Timing list for includes is
++; Timing list for includes is
+ ;
+ ; <time range>,<days of week>,<days of month>,<months>[,<timezone>]
+ ;
+@@ -246,7 +246,7 @@
+ ;
+ ; If you are freely delivering calls to the PSTN, list them here
+ ;
+-;exten => _1256428XXXX,1,Dial(DAHDI/G2/${EXTEN:7}) ; Expose all of 256-428
++;exten => _1256428XXXX,1,Dial(DAHDI/G2/${EXTEN:7}) ; Expose all of 256-428
+ ;exten => _1256325XXXX,1,Dial(DAHDI/G2/${EXTEN:7}) ; Ditto for 256-325
+
+ [dundi-e164-local]
+@@ -272,15 +272,15 @@
+ include => dundi-e164-local
+ include => dundi-e164-switch
+ ;
+-; DUNDi can also be implemented as a Macro instead of using
+-; the Local channel driver.
++; DUNDi can also be implemented as a Macro instead of using
++; the Local channel driver.
+ ;
+ [macro-dundi-e164]
+ ;
+ ; ARG1 is the extension to Dial
+ ;
+ ; Extension "s" is not a wildcard extension that matches "anything".
+-; In macros, it is the start extension. In most other cases,
++; In macros, it is the start extension. In most other cases,
+ ; you have to goto "s" to execute that extension.
+ ;
+ ; For wildcard matches, see above - all pattern matches start with
+@@ -367,10 +367,10 @@
+ include => parkedcalls
+ ;
+ ; You can use an alternative switch type as well, to resolve
+-; extensions that are not known here, for example with remote
++; extensions that are not known here, for example with remote
+ ; IAX switching you transparently get access to the remote
+ ; Asterisk PBX
+-;
++;
+ ; switch => IAX2/user:password@bigserver/local
+ ;
+ ; An "lswitch" is like a switch but is literal, in that
+@@ -388,7 +388,7 @@
+
+ [macro-trunkdial]
+ ;
+-; Standard trunk dial macro (hangs up on a dialstatus that should
++; Standard trunk dial macro (hangs up on a dialstatus that should
+ ; terminate call)
+ ; ${ARG1} - What to dial
+ ;
+@@ -458,7 +458,7 @@
+ 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
++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)
+
+@@ -520,7 +520,7 @@
+ ; We also create an example user, 1234, who is on the console and has
+ ; voicemail, etc.
+ ;
+-exten => 1234,1,Playback(transfer,skip) ; "Please hold while..."
++exten => 1234,1,Playback(transfer,skip) ; "Please hold while..."
+ ; (but skip if channel is not up)
+ exten => 1234,n,Gosub(stdexten(1234,${GLOBAL(CONSOLE)}))
+ exten => 1234,n,Goto(default,s,1) ; exited Voicemail
+@@ -583,7 +583,7 @@
+
+ ;
+ ; The page context calls up the page macro that sets variables needed for auto-answer
+-; It is in is own context to make calling it from the Page() application as simple as
++; It is in is own context to make calling it from the Page() application as simple as
+ ; Local/{peername}@page
+ ;
+ [page]
+@@ -610,7 +610,7 @@
+
+ [default]
+ ;
+-; By default we include the demo. In a production system, you
++; By default we include the demo. In a production system, you
+ ; probably don't want to have the demo there.
+ ;
+ include => demo
+@@ -723,7 +723,7 @@
+ ; friendly Asterisk CLI prompt.
+ ;
+ ; "core show application <command>" will show details of how you
+-; use that particular application in this file, the dial plan.
++; use that particular application in this file, the dial plan.
+ ; "core show functions" will list all dialplan functions
+ ; "core show function <COMMAND>" will show you more information about
+ ; one function. Remember that function names are UPPER CASE.
+Index: configs/asterisk.adsi
+===================================================================
+--- a/configs/asterisk.adsi (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/configs/asterisk.adsi (.../trunk) (revision 202568)
+@@ -86,10 +86,10 @@
+ IFEVENT OFFHOOK THEN
+ CLEAR
+ CLEARFLAG "nocallwaiting"
+- CLEARDISPLAY
++ CLEARDISPLAY
+ SHOWDISPLAY "titles" AT 1
+- SHOWKEYS "vmail"
+- SHOWKEYS "cidblock"
++ SHOWKEYS "vmail"
++ SHOWKEYS "cidblock"
+ SHOWKEYS "cwdisable" UNLESS "nocallwaiting"
+ GOTO "offHook"
+ ENDIF
+@@ -117,9 +117,9 @@
+ SHOWKEYS "vmail_OH"
+ ENDIF
+ IFEVENT TIMER THEN
+- CLEAR
++ CLEAR
+ SHOWDISPLAY "empty" AT 4
+- ENDIF
++ ENDIF
+ ENDSUB
+
+ SUB "offHook" IS
+Index: configs/users.conf.sample
+===================================================================
+--- a/configs/users.conf.sample (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/configs/users.conf.sample (.../trunk) (revision 202568)
+@@ -2,11 +2,11 @@
+ ; User configuration
+ ;
+ ; Creating entries in users.conf is a "shorthand" for creating individual
+-; entries in each configuration file. Using users.conf is not intended to
++; entries in each configuration file. Using users.conf is not intended to
+ ; provide you with as much flexibility as using the separate configuration
+ ; files (e.g. sip.conf, iax.conf, etc) but is intended to accelerate the
+ ; simple task of adding users. Note that creating individual items (e.g.
+-; custom SIP peers, IAX friends, etc.) will allow you to override specific
++; custom SIP peers, IAX friends, etc.) will allow you to override specific
+ ; parameters within this file. Parameter names here are the same as they
+ ; appear in the other configuration files. There is no way to change the
+ ; value of a parameter here for just one subsystem.
+Index: configs/gtalk.conf.sample
+===================================================================
+--- a/configs/gtalk.conf.sample (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/configs/gtalk.conf.sample (.../trunk) (revision 202568)
+@@ -5,16 +5,16 @@
+ ;;list of peers
+ ;
+ ;[guest] ;;special account for options on guest account
+-;disallow=all
++;disallow=all
+ ;allow=ulaw
+ ;context=guest
+ ;
+ ;[ogorman]
+-;username=ogorman@gmail.com ;;username of the peer your
++;username=ogorman@gmail.com ;;username of the peer your
+ ;;calling or accepting calls from
+ ;disallow=all
+ ;allow=ulaw
+-;context=default
++;context=default
+ ;connection=asterisk ;;client or component in jabber.conf
+ ;;for the call to leave on.
+ ;
+Index: configs/rpt.conf.sample
+===================================================================
+--- a/configs/rpt.conf.sample (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/configs/rpt.conf.sample (.../trunk) (revision 202568)
+@@ -86,7 +86,7 @@
+ ; specify the rxchannel and the txchannel will be assumed from the rxchannel
+ ;txchannel = DAHDI/6 ; Tx audio/signalling channel
+ ;functions = functions-remote
+-;remote = ft897 ; Set remote=y for dumb remote or
++;remote = ft897 ; Set remote=y for dumb remote or
+ ; remote=ft897 for Yaesu FT-897 or
+ ; remote=rbi for Doug Hall RBI1
+ ;iobase = 0x378 ; Specify IO port for parallel port (optional)
+@@ -106,7 +106,7 @@
+ ;6=autopatchup ; Autopatch up
+ ;0=autopatchdn ; Autopatch down
+
+-;90=cop,1 ; System warm boot
++;90=cop,1 ; System warm boot
+ ;91=cop,2 ; System enable
+ ;92=cop,3 ; System disable
+
+@@ -135,7 +135,7 @@
+ ; Single frequencies are created by setting freq1 or freq2 to zero.
+ ;
+ ; |m - Morse escape sequence
+-;
++;
+ ; Sends Morse code at the telemetry amplitude and telemetry frequency as defined in the
+ ; [morse] section.
+ ;
+@@ -150,15 +150,15 @@
+
+
+ ;ct1=|t(350,0,100,2048)(500,0,100,2048)(660,0,100,2048)
+-;ct2=|t(660,880,150,2048)
+-;ct3=|t(440,0,150,2048)
++;ct2=|t(660,880,150,2048)
++;ct3=|t(440,0,150,2048)
+ ;ct4=|t(550,0,150,2048)
+ ;ct5=|t(660,0,150,2048)
+ ;ct6=|t(880,0,150,2048)
+ ;ct7=|t(660,440,150,2048)
+ ;ct8=|t(700,1100,150,2048)
+-;remotetx=|t(2000,0,75,2048)(0,0,75,0)(1600,0,75,2048);
+-;remotemon=|t(1600,0,75,2048)
++;remotetx=|t(2000,0,75,2048)(0,0,75,0)(1600,0,75,2048);
++;remotemon=|t(1600,0,75,2048)
+ ;cmdmode=|t(900,903,200,2048)
+ ;functcomplete=|t(1000,0,100,2048)(0,0,100,0)(1000,0,100,2048)
+
+@@ -168,7 +168,7 @@
+ ;speed=20 ; Approximate speed in WPM
+ ;frequency=800 ; Morse Telemetry Frequency
+ ;amplitude=4096 ; Morse Telemetry Amplitude
+-;idfrequency=330 ; Morse ID Frequency
++;idfrequency=330 ; Morse ID Frequency
+ ;idamplitude=2048 ; Morse ID Amplitude
+
+ ;[nodes]
+Index: configs/rtp.conf.sample
+===================================================================
+--- a/configs/rtp.conf.sample (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/configs/rtp.conf.sample (.../trunk) (revision 202568)
+@@ -18,7 +18,7 @@
+ ; allowed to continue (in 'samples', 1/8000 of a second)
+ ;
+ ;dtmftimeout=3000
+-; rtcpinterval = 5000 ; Milliseconds between rtcp reports
++; rtcpinterval = 5000 ; Milliseconds between rtcp reports
+ ;(min 500, max 60000, default 5000)
+ ;
+ ; Enable strict RTP protection. This will drop RTP packets that
+Index: configs/cli_aliases.conf.sample
+===================================================================
+--- a/configs/cli_aliases.conf.sample (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/configs/cli_aliases.conf.sample (.../trunk) (revision 202568)
+@@ -13,7 +13,7 @@
+ ;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
++ ; includes a list of aliases from an external
+ ; file
+
+
+@@ -70,7 +70,7 @@
+ ; 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
++; [general] section
+
+ [asterisk12_tpl](!)
+ show channeltypes=core show channeltypes
+@@ -92,7 +92,7 @@
+ show applications=core show applications
+ show functions=core show functions
+ show switches=core show switches
+-show hints=core show hints
++show hints=core show hints
+ show globals=core show globals
+ show function=core show function
+ show application=core show application
+@@ -102,7 +102,7 @@
+ 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
++show codec=core show codec
+ moh classes show=moh show classes
+ moh files show=moh show files
+ agi no debug=agi debug off
+Index: configs/extensions.ael.sample
+===================================================================
+--- a/configs/extensions.ael.sample (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/configs/extensions.ael.sample (.../trunk) (revision 202568)
+@@ -3,16 +3,16 @@
+ //
+ //
+ // Static extension configuration file, used by
+-// the pbx_ael module. This is where you configure all your
+-// inbound and outbound calls in Asterisk.
+-//
+-// This configuration file is reloaded
++// the pbx_ael module. This is where you configure all your
++// inbound and outbound calls in Asterisk.
++//
++// This configuration file is reloaded
+ // - With the "ael reload" command in the CLI
+ // - With the "reload" command (that reloads everything) in the CLI
+
+ // The "Globals" category contains global variables that can be referenced
+ // in the dialplan by using the GLOBAL dialplan function:
+-// ${GLOBAL(VARIABLE)}
++// ${GLOBAL(VARIABLE)}
+ // ${${GLOBAL(VARIABLE)}} or ${text${GLOBAL(VARIABLE)}} or any hybrid
+ // Unix/Linux environmental variables are reached with the ENV dialplan
+ // function: ${ENV(VARIABLE)}
+@@ -44,8 +44,8 @@
+ };
+
+ //
+-// Any category other than "General" and "Globals" represent
+-// extension contexts, which are collections of extensions.
++// Any category other than "General" and "Globals" represent
++// extension contexts, which are collections of extensions.
+ //
+ // Extension names may be numbers, letters, or combinations
+ // thereof. If an extension name is prefixed by a '_'
+@@ -56,12 +56,12 @@
+ // Z - any digit from 1-9
+ // N - any digit from 2-9
+ // [1235-9] - any digit in the brackets (in this example, 1,2,3,5,6,7,8,9)
+-// . - wildcard, matches anything remaining (e.g. _9011. matches
++// . - wildcard, matches anything remaining (e.g. _9011. matches
+ // anything starting with 9011 excluding 9011 itself)
+ // ! - wildcard, causes the matching process to complete as soon as
+ // it can unambiguously determine that no other matches are possible
+ //
+-// For example the extension _NXXXXXX would match normal 7 digit dialings,
++// For example the extension _NXXXXXX would match normal 7 digit dialings,
+ // while _1NXXNXXXXXX would represent an area code plus phone number
+ // preceded by a one.
+ //
+@@ -72,8 +72,8 @@
+ // The priority "same" or "s" means the same as the previously specified
+ // priority, again regardless of whether the previous entry was for the
+ // same extension. Priorities may be immediately followed by a plus sign
+-// and another integer to add that amount (most useful with 's' or 'n').
+-// Priorities may then also have an alias, or label, in
++// and another integer to add that amount (most useful with 's' or 'n').
++// Priorities may then also have an alias, or label, in
+ // parenthesis after their name which can be used in goto situations
+ //
+ // Contexts contain several lines, one for each step of each
+@@ -87,11 +87,11 @@
+ // exten-name => {
+ // application(arg1,arg2,...);
+ //
+-// Timing list for includes is
++// Timing list for includes is
+ //
+ // <time range>|<days of week>|<days of month>|<months>
+ //
+-// includes {
++// includes {
+ // daytime|9:00-17:00|mon-fri|*|*;
+ // };
+ //
+@@ -129,7 +129,7 @@
+ //
+ // If you are freely delivering calls to the PSTN, list them here
+ //
+- //_1256428XXXX => Dial(DAHDI/G2/${EXTEN:7}); // Expose all of 256-428
++ //_1256428XXXX => Dial(DAHDI/G2/${EXTEN:7}); // Expose all of 256-428
+ //_1256325XXXX => Dial(DAHDI/G2/${EXTEN:7}); // Ditto for 256-325
+ };
+
+@@ -149,8 +149,8 @@
+ //
+ // Just a wrapper for the switch
+ //
+-
+- switches {
++
++ switches {
+ DUNDi/e164;
+ };
+ };
+@@ -168,8 +168,8 @@
+ };
+
+ //
+-// DUNDi can also be implemented as a Macro instead of using
+-// the Local channel driver.
++// DUNDi can also be implemented as a Macro instead of using
++// the Local channel driver.
+ //
+ macro ael-dundi-e164(exten) {
+ //
+@@ -240,7 +240,7 @@
+ //
+ // Long distance context accessed through trunk interface
+ //
+-
++
+ _91800NXXXXXX => Dial(${TRUNK}/${EXTEN:${TRUNKMSD}});
+ _91888NXXXXXX => Dial(${TRUNK}/${EXTEN:${TRUNKMSD}});
+ _91877NXXXXXX => Dial(${TRUNK}/${EXTEN:${TRUNKMSD}});
+@@ -285,10 +285,10 @@
+
+ //
+ // You can use an alternative switch type as well, to resolve
+-// extensions that are not known here, for example with remote
++// extensions that are not known here, for example with remote
+ // IAX switching you transparently get access to the remote
+ // Asterisk PBX
+-//
++//
+ // switch => IAX2/user:password@bigserver/local
+ //
+ // An "lswitch" is like a switch but is literal, in that
+@@ -380,7 +380,7 @@
+
+ context ael-default {
+
+-// By default we include the demo. In a production system, you
++// By default we include the demo. In a production system, you
+ // probably don't want to have the demo there.
+
+ includes {
+@@ -443,6 +443,6 @@
+ // friendly Asterisk CLI prompt.
+ //
+ // 'show application <command>' will show details of how you
+-// use that particular application in this file, the dial plan.
++// use that particular application in this file, the dial plan.
+ //
+ }
+Index: configs/extensions_minivm.conf.sample
+===================================================================
+--- a/configs/extensions_minivm.conf.sample (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/configs/extensions_minivm.conf.sample (.../trunk) (revision 202568)
+@@ -1,4 +1,4 @@
+-; MINI-VOICEMAIL dialplan example
++; MINI-VOICEMAIL dialplan example
+ ; ---------------------------------------------------------------------------------------
+ ; ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+ ;
+@@ -10,8 +10,8 @@
+ ; A macro to test the MINIVMACCOUNT dialplan function
+ ; Currently, accountcode and pincode is not used in the application
+ ; They where added to be used in dialplan scripting
+-;
+ ;
++;
+ [macro-minivmfunctest]
+ exten => s,1,set(account=${ARGV1})
+ exten => minivm,n,verbose(1,-------------------- Minivm Function test - Accoutn ${account} -------------)
+Index: configs/followme.conf.sample
+===================================================================
+--- a/configs/followme.conf.sample (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/configs/followme.conf.sample (.../trunk) (revision 202568)
+@@ -29,7 +29,7 @@
+ 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.
+ ;
+ ;
+@@ -41,9 +41,9 @@
+ number=>01233456,25
+ ; The a follow-me number to call. The format is:
+ ; number=> <number to call[&2nd #[&3rd #]]> [, <timeout value in seconds> [, <order in follow-me>] ]
+-; You can specify as many of these numbers as you like. They will be dialed in the
++; You can specify as many of these numbers as you like. They will be dialed in the
+ ; order that you specify them in the config file OR as specified with the order field
+-; on the number prompt. As you can see from the example, forked dialing of multiple
++; on the number prompt. As you can see from the example, forked dialing of multiple
+ ; numbers in the same step is supported with this application if you'd like to dial
+ ; multiple numbers in the same followme step.
+ ; It's also important to note that the timeout value is not the same
+@@ -79,7 +79,7 @@
+ ; The 'The party you're calling isn't at their desk' message prompt.
+ ; Default is the global default.
+ ;
+-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/minivm.conf.sample
+===================================================================
+--- a/configs/minivm.conf.sample (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/configs/minivm.conf.sample (.../trunk) (revision 202568)
+@@ -16,7 +16,7 @@
+ ; Change the from, body and/or subject, variables:
+ ; MVM_NAME, MVM_DUR, MVM_MSGNUM, VM_MAILBOX, MVM_CALLERID, MVM_CIDNUM,
+ ; MVM_CIDNAME, MVM_DATE
+-;
++;
+ ; In addition to these, you can set the MVM_COUNTER channel variable in the
+ ; dial plan and use that as a counter. It will also be used in the file name
+ ; of the media file attached to the message
+@@ -89,43 +89,43 @@
+ ;pagersubject=New VM ${MVM_COUNTER}
+ ;pagerbody=New ${MVM_DUR} long msg in box ${MVM_MAILBOX}\nfrom ${MVM_CALLERID}, on ${MVM_DATE}
+ ;
+-;
++;
+ ;--------------Timezone definitions (used in voicemail accounts) -------------------
+ ;
+-; Users may be located in different timezones, or may have different
+-; message announcements for their introductory message when they enter
+-; the voicemail system. Set the message and the timezone each user
+-; hears here. Set the user into one of these zones with the tz= attribute
+-; in the options field of the mailbox. Of course, language substitution
+-; still applies here so you may have several directory trees that have
+-; alternate language choices.
+-;
+-; Look in /usr/share/zoneinfo/ for names of timezones.
+-; Look at the manual page for strftime for a quick tutorial on how the
+-; variable substitution is done on the values below.
+-;
+-; Supported values:
++; Users may be located in different timezones, or may have different
++; message announcements for their introductory message when they enter
++; the voicemail system. Set the message and the timezone each user
++; hears here. Set the user into one of these zones with the tz= attribute
++; in the options field of the mailbox. Of course, language substitution
++; still applies here so you may have several directory trees that have
++; alternate language choices.
++;
++; Look in /usr/share/zoneinfo/ for names of timezones.
++; Look at the manual page for strftime for a quick tutorial on how the
++; variable substitution is done on the values below.
++;
++; Supported values:
+ ; 'filename' filename of a soundfile (single ticks around the filename
+ ; required)
+-; ${VAR} variable substitution
+-; A or a Day of week (Saturday, Sunday, ...)
+-; B or b or h Month name (January, February, ...)
+-; d or e numeric day of month (first, second, ..., thirty-first)
+-; Y Year
+-; I or l Hour, 12 hour clock
+-; H Hour, 24 hour clock (single digit hours preceded by "oh")
+-; k Hour, 24 hour clock (single digit hours NOT preceded by "oh")
+-; M Minute, with 00 pronounced as "o'clock"
++; ${VAR} variable substitution
++; A or a Day of week (Saturday, Sunday, ...)
++; B or b or h Month name (January, February, ...)
++; d or e numeric day of month (first, second, ..., thirty-first)
++; Y Year
++; I or l Hour, 12 hour clock
++; H Hour, 24 hour clock (single digit hours preceded by "oh")
++; k Hour, 24 hour clock (single digit hours NOT preceded by "oh")
++; M Minute, with 00 pronounced as "o'clock"
+ ; N Minute, with 00 pronounced as "hundred" (US military time)
+-; P or p AM or PM
++; P or p AM or PM
+ ; Q "today", "yesterday" or ABdY
+-; (*note: not standard strftime value)
++; (*note: not standard strftime value)
+ ; q "" (for today), "yesterday", weekday, or ABdY
+-; (*note: not standard strftime value)
+-; R 24 hour time, including minute
+-;
++; (*note: not standard strftime value)
++; R 24 hour time, including minute
++;
+ ; The message here is not used in mini-voicemail, but stays for
+-; backwards compatibility
++; backwards compatibility
+
+ [zonemessages]
+ eastern=America/New_York|'vm-received' Q 'digits/at' IMp
+@@ -141,27 +141,27 @@
+ ; attachmedia = yes | no ; Add media file as attachment?
+ ; dateformat = <formatstring> ; See above
+ ; charset = <charset> ; Mime charset definition for e-mail messages
+-; locale = <locale> ; Locale for LC_TIME - to get weekdays in local language
++; locale = <locale> ; Locale for LC_TIME - to get weekdays in local language
+ ; ; See your O/S documentation for proper settings for setlocale()
+ ; templatefile = <filename> ; File name (relative to Asterisk configuration directory,
+ ; or absolute
+ ; messagebody = Format ; Message body definition with variables
+ ;
+-[template-sv_SE_email]
++[template-sv_SE_email]
+ messagebody=Hej ${MVM_NAME}:\n\n\tDu har fått ett röstbrevlåde-meddelande från ${MVM_CALLERID}.\nLängd: ${MVM_DUR}\nMailbox ${MVM_MAILBOX}\nDatum: ${MVM_DATE}. \nMeddelandet bifogas det här brevet. Om du inte kan läsa det, kontakta intern support. \nHälsningar\n\n\t\t\t\t--Asterisk\n
+ subject = Du har fått röstmeddelande (se bilaga)
+ fromemail = swedish-voicemail-service@stockholm.example.com
+ fromaddress = Asterisk Röstbrevlåda
+ charset=iso-8859-1
+-attachmedia=yes
++attachmedia=yes
+ dateformat=%A, %d %B %Y at %H:%M:%S
+ locale=sv_SE
+
+-[template-en_US_email]
++[template-en_US_email]
+ messagebody=Dear ${MVM_NAME}:\n\n\tjust wanted to let you know you were just left a ${MVM_DUR} long message \nin mailbox ${MVM_MAILBOX} from ${MVM_CALLERID}, on ${MVM_DATE}, so you might\nwant to check it when you get a chance. Thanks!\n\n\t\t\t\t--Asterisk\n
+ subject = New voicemail
+ charset=ascii
+-attachmedia=yes
++attachmedia=yes
+ dateformat=%A, %B %d, %Y at %r
+
+ ;[template-sv_SE_pager]
+@@ -180,12 +180,12 @@
+ ;[template-en_US_email_southern]
+ ;templatefile = templates/email_en_US.txt
+ ;subject = Y'all got voicemail, honey!
+-;charset=ascii
++;charset=ascii
+
+ ;[template-en_UK_email]
+ ;templatefile = templates/email_en_us.txt
+ ;subject = Dear old chap, you've got an electronic communique
+-;charset=ascii
++;charset=ascii
+
+ ;----------------------- Mailbox accounts --------------------------
+ ;Template for mailbox definition - all options
+Index: configs/osp.conf.sample
+===================================================================
+--- a/configs/osp.conf.sample (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/configs/osp.conf.sample (.../trunk) (revision 202568)
+@@ -1,25 +1,34 @@
+ ;
+ ; Open Settlement Protocol Sample Configuration File
+ ;
+-; This file contains configuration of OSP server providers that are used by the
+-; Asterisk OSP module. The section "general" is reserved for global options.
+-; All other sections describe specific OSP Providers. The provider "default"
+-; is used when no provider is otherwise specified.
++; This file contains configuration of OSP server providers that are used by the
++; Asterisk OSP module. The section "general" is reserved for global options.
++; All other sections describe specific OSP Providers. The provider "default"
++; is used when no provider is otherwise specified.
+ ;
+-; The "servicepoint" and "source" parameters must be configured. For most
++; The "servicepoint" and "source" parameters must be configured. For most
+ ; implementations the other parameters in this file can be left unchanged.
+ ;
+ [general]
+ ;
+-; Enable cryptographic acceleration hardware.
++; Enable cryptographic acceleration hardware.
++; The default value is no.
+ ;
+ ;accelerate=no
+ ;
+-; Defines the status of tokens that Asterisk will validate.
+-; 0 - signed tokens only
+-; 1 - unsigned tokens only
++; Enable security features.
++; If security features are disabled, Asterisk cannot validate signed tokens and
++; all certificate file name parameters are ignored.
++; The default value is no.
++;
++;securityfeatures=no
++;
++; Defines the status of tokens that Asterisk will validate.
++; 0 - signed tokens only
++; 1 - unsigned tokens only
+ ; 2 - both signed and unsigned
+ ; The default value is 0, i.e. the Asterisk will only validate signed tokens.
++; If securityfeatures are disabled, Asterisk cannot validate signed tokens.
+ ;
+ ;tokenformat=0
+ ;
+@@ -36,34 +45,37 @@
+ ;source=domain name or [IP address in brackets]
+ ;
+ ; Define path and file name of crypto files.
+-; The default path for crypto file is /var/lib/asterisk/keys. If no path is
++; The default path for crypto file is /var/lib/asterisk/keys. If no path is
+ ; defined, crypto files will in /var/lib/asterisk/keys directory.
+ ;
+-; Specify the private key file name.
+-; If this parameter is unspecified or not present, the default name will be the
+-; osp.conf section name followed by "-privatekey.pem" (for example:
++; Specify the private key file name.
++; If this parameter is unspecified or not present, the default name will be the
++; osp.conf section name followed by "-privatekey.pem" (for example:
+ ; default-privatekey.pem)
++; If securityfeatures are disabled, this parameter is ignored.
+ ;
+ ;privatekey=pkey.pem
+ ;
+-; Specify the local certificate file.
+-; If this parameter is unspecified or not present, the default name will be the
+-; osp.conf section name followed by "- localcert.pem " (for example:
+-; default-localcert.pem)
++; Specify the local certificate file.
++; If this parameter is unspecified or not present, the default name will be the
++; osp.conf section name followed by "- localcert.pem " (for example:
++; default-localcert.pem)
++; If securityfeatures are disabled, this parameter is ignored.
+ ;
+ ;localcert=localcert.pem
+ ;
+-; Specify one or more Certificate Authority key file names. If none are listed,
+-; a single Certificate Authority key file name is added with the default name of
+-; the osp.conf section name followed by "-cacert_0.pem " (for example:
++; Specify one or more Certificate Authority key file names. If none are listed,
++; a single Certificate Authority key file name is added with the default name of
++; the osp.conf section name followed by "-cacert_0.pem " (for example:
+ ; default-cacert_0.pem)
++; If securityfeatures are disabled, this parameter is ignored.
+ ;
+ ;cacert=cacert_0.pem
+ ;
+-; Configure parameters for OSP communication between Asterisk OSP client and OSP
+-; servers.
++; Configure parameters for OSP communication between Asterisk OSP client and OSP
++; servers.
+ ;
+-; maxconnections: Max number of simultaneous connections to the provider OSP
++; maxconnections: Max number of simultaneous connections to the provider OSP
+ ; server (default=20)
+ ; retrydelay: Extra delay between retries (default=0)
+ ; retrylimit: Max number of retries before giving up (default=2)
+@@ -74,17 +86,18 @@
+ ;retrylimit=2
+ ;timeout=500
+ ;
+-; Set the authentication policy.
++; Set the authentication policy.
+ ; 0 - NO - Accept all calls.
+-; 1 - YES - Accept calls with valid token or no token. Block calls with
+-; invalid token.
+-; 2 - EXCLUSIVE - Accept calls with valid token. Block calls with invalid token
++; 1 - YES - Accept calls with valid token or no token. Block calls with
++; invalid token.
++; 2 - EXCLUSIVE - Accept calls with valid token. Block calls with invalid token
+ ; or no token.
+ ; Default is 1,
++; If securityfeatures are disabled, Asterisk cannot validate signed tokens.
+ ;
+ ;authpolicy=1
+ ;
+-; Set the default destination protocol. The OSP module supports SIP, H323, and
++; Set the default destination protocol. The OSP module supports SIP, H323, and
+ ; IAX protocols. The default protocol is set to SIP.
+ ;
+ ;defaultprotocol=SIP
+Index: configs/cdr_custom.conf.sample
+===================================================================
+--- a/configs/cdr_custom.conf.sample (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/configs/cdr_custom.conf.sample (.../trunk) (revision 202568)
+@@ -1,10 +1,12 @@
+ ;
+ ; Mappings for custom config file
+ ;
+-; to get your csv output in a format tailored to your liking, uncomment the following
+-; and look for the output in the cdr-custom/Master.csv file (usually in /var/log/asterisk).
+-;
++; To get your CSV output in a format tailored to your liking, uncomment the
++; following lines and look for the output in the cdr-custom directory (usually
++; in /var/log/asterisk). Depending on which mapping you uncomment, you may see
++; Master.csv, Simple.csv, or both.
+ ;
+ ;[mappings]
+ ;Master.csv => "${CDR(clid)}","${CDR(src)}","${CDR(dst)}","${CDR(dcontext)}","${CDR(channel)}","${CDR(dstchannel)}","${CDR(lastapp)}","${CDR(lastdata)}","${CDR(start)}","${CDR(answer)}","${CDR(end)}","${CDR(duration)}","${CDR(billsec)}","${CDR(disposition)}","${CDR(amaflags)}","${CDR(accountcode)}","${CDR(uniqueid)}","${CDR(userfield)}"
++;Simple.csv => "${EPOCH}","${CDR(src)}","${CDR(dst)}"
+
+Index: configs/chan_dahdi.conf.sample
+===================================================================
+--- a/configs/chan_dahdi.conf.sample (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/configs/chan_dahdi.conf.sample (.../trunk) (revision 202568)
+@@ -6,7 +6,7 @@
+ ; 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
+ ; un-comment those lines.
+@@ -21,11 +21,11 @@
+ ;
+ ; Trunk groups are used for NFAS or GR-303 connections.
+ ;
+-; Group: Defines a trunk group.
++; Group: Defines a trunk group.
+ ; trunkgroup => <trunkgroup>,<dchannel>[,<backup1>...]
+ ;
+ ; trunkgroup is the numerical trunk group to create
+-; dchannel is the DAHDI channel which will have the
++; dchannel is the DAHDI channel which will have the
+ ; d-channel for the trunk.
+ ; backup1 is an optional list of backup d-channels.
+ ;
+@@ -74,6 +74,9 @@
+ ;
+ ;nsf=none
+ ;
++;service_message_support=yes
++; Enable service message support for channel. Must be set after switchtype.
++;
+ ; PRI Dialplan: The ISDN-level Type Of Number (TON) or numbering plan, used for
+ ; the dialed number. For most installations, leaving this as 'unknown' (the
+ ; default) works in the most cases. In some very unusual circumstances, you
+@@ -82,7 +85,7 @@
+ ; example, if you set 'national', you will be unable to dial local or
+ ; international numbers.
+ ;
+-; PRI Local Dialplan: Only RARELY used for PRI (sets the calling number's
++; PRI Local Dialplan: Only RARELY used for PRI (sets the calling number's
+ ; numbering plan). In North America, the typical use is sending the 10 digit
+ ; callerID number and setting the prilocaldialplan to 'national' (the default).
+ ; Only VERY rarely will you need to change this.
+@@ -95,12 +98,12 @@
+ ; national: National ISDN
+ ; international: International ISDN
+ ; dynamic: Dynamically selects the appropriate dialplan
+-; redundant: Same as dynamic, except that the underlying number is not
++; redundant: Same as dynamic, except that the underlying number is not
+ ; changed (not common)
+ ;
+ ;pridialplan=unknown
+ ;prilocaldialplan=national
+-;
++;
+ ; pridialplan may be also set at dialtime, by prefixing the dialled number with
+ ; one of the following letters:
+ ; U - Unknown
+@@ -130,27 +133,27 @@
+ ;
+ ; PRI caller ID prefixes based on the given TON/NPI (dialplan)
+ ; This is especially needed for EuroISDN E1-PRIs
+-;
++;
+ ; None of the prefix settings can be changed on reload.
+ ;
+-; sample 1 for Germany
++; sample 1 for Germany
+ ;internationalprefix = 00
+ ;nationalprefix = 0
+ ;localprefix = 0711
+ ;privateprefix = 07115678
+-;unknownprefix =
++;unknownprefix =
+ ;
+-; sample 2 for Germany
++; sample 2 for Germany
+ ;internationalprefix = +
+ ;nationalprefix = +49
+ ;localprefix = +49711
+ ;privateprefix = +497115678
+-;unknownprefix =
++;unknownprefix =
+ ;
+ ; PRI resetinterval: sets the time in seconds between restart of unused
+ ; B channels; defaults to 'never'.
+ ;
+-;resetinterval = 3600
++;resetinterval = 3600
+ ;
+ ; Overlap dialing mode (sending overlap digits)
+ ; Cannot be changed on a reload.
+@@ -165,7 +168,7 @@
+ ; Enable this to report Busy and Congestion on a PRI using out-of-band
+ ; notification. Inband indication, as used by Asterisk doesn't seem to work
+ ; with all telcos.
+-;
++;
+ ; outofband: Signal Busy/Congestion out of band with RELEASE/DISCONNECT
+ ; inband: Signal Busy/Congestion using in-band tones (default)
+ ;
+@@ -203,7 +206,7 @@
+ ; T203: Layer 2 max time without frames being exchanged (default 10000 ms)
+ ; T305: Wait for DISCONNECT acknowledge (default 30000 ms)
+ ; T308: Wait for RELEASE acknowledge (default 4000 ms)
+-; T309: Maintain active calls on Layer 2 disconnection (default -1,
++; T309: Maintain active calls on Layer 2 disconnection (default -1,
+ ; Asterisk clears calls)
+ ; EuroISDN: 6000 to 12000 ms, according to (N200 + 1) x T200 + 2s
+ ; May vary in other ISDN standards (Q.931 1993 : 90000 ms)
+@@ -281,11 +284,11 @@
+ ; (see below). The 'signalling' format specified will be the inbound signalling
+ ; format. If you only specify 'signalling', then it will be the format for
+ ; both inbound and outbound.
+-;
+-; outsignalling can only be one of:
++;
++; outsignalling can only be one of:
+ ; em, em_e1, em_w, sf, sf_w, sf_featd, sf_featdmf, sf_featb, featd,
+ ; featdmf, featdmf_ta, e911, fgccama, fgccamamf
+-;
++;
+ ; outsignalling cannot be changed on a reload.
+ ;
+ ;signalling=featdmf
+@@ -315,9 +318,9 @@
+ ; None of them will update on a reload.
+ ;
+ ; How long generated tones (DTMF and MF) will be played on the channel
+-; (in milliseconds).
++; (in milliseconds).
+ ;
+-; This is a global, rather than a per-channel setting. It will not be
++; This is a global, rather than a per-channel setting. It will not be
+ ; updated on a reload.
+ ;
+ ;toneduration=100
+@@ -351,7 +354,7 @@
+ ; What signals the start of caller ID
+ ; ring = a ring signals the start (default)
+ ; polarity = polarity reversal signals the start
+-; polarity_IN = polarity reversal signals the start, for India,
++; polarity_IN = polarity reversal signals the start, for India,
+ ; for dtmf dialtone detection; using DTMF.
+ ; (see doc/India-CID.txt)
+ ;
+@@ -378,7 +381,7 @@
+ ; fsk,rpas - the FXO line is monitored for MWI FSK spills preceded
+ ; by a ring pulse alert signal.
+ ; neon - The fxo line is monitored for the presence of NEON pulses
+-; indicating MWI.
++; indicating MWI.
+ ; When detected, an internal Asterisk MWI event is generated so that any other
+ ; part of Asterisk that cares about MWI state changes is notified, just as if
+ ; the state change came from app_voicemail.
+@@ -429,7 +432,7 @@
+ ;
+ ; Some countries (UK) have ring tones with different ring tones (ring-ring),
+ ; which means the caller ID needs to be set later on, and not just after
+-; the first ring, as per the default (1).
++; the first ring, as per the default (1).
+ ;
+ ;sendcalleridafter = 2
+ ;
+@@ -469,10 +472,10 @@
+ ;
+ callreturn=yes
+ ;
+-; Stutter dialtone support: If a mailbox is specified without a voicemail
+-; context, then when voicemail is received in a mailbox in the default
++; Stutter dialtone support: If a mailbox is specified without a voicemail
++; context, then when voicemail is received in a mailbox in the default
+ ; voicemail context in voicemail.conf, taking the phone off hook will cause a
+-; stutter dialtone instead of a normal one.
++; stutter dialtone instead of a normal one.
+ ;
+ ; If a mailbox is specified *with* a voicemail context, the same will result
+ ; if voicemail received in mailbox in the specified voicemail context.
+@@ -483,9 +486,9 @@
+ ;
+ ; for any other voicemail context, the following will produce the stutter tone:
+ ;
+-;mailbox=1234@context
++;mailbox=1234@context
+ ;
+-; Enable echo cancellation
++; Enable echo cancellation
+ ; Use either "yes", "no", or a power of two from 32 to 256 if you wish to
+ ; actually set the number of taps of cancellation.
+ ;
+@@ -549,7 +552,7 @@
+ ;
+ ; There are several independent gain settings:
+ ; rxgain: gain for the rx (receive - into Asterisk) channel. Default: 0.0
+-; txgain: gain for the tx (transmit - out of Asterisk Asterisk) channel.
++; txgain: gain for the tx (transmit - out of Asterisk Asterisk) channel.
+ ; Default: 0.0
+ ; cid_rxgain: set the gain just for the caller ID sounds Asterisk
+ ; emits. Default: 5.0 .
+@@ -597,10 +600,10 @@
+ ;
+ ; caller ID can be set to "asreceived" or a specific number if you want to
+ ; override it. Note that "asreceived" only applies to trunk interfaces.
+-; fullname sets just the
++; fullname sets just the
+ ;
+ ; fullname: sets just the name part.
+-; cid_number: sets just the number part:
++; cid_number: sets just the number part:
+ ;
+ ;callerid = 123456
+ ;
+@@ -639,7 +642,7 @@
+ ;smdiport=/dev/ttyS0
+ ;
+ ; On trunk interfaces (FXS) and E&M interfaces (E&M, Wink, Feature Group D
+-; etc, it can be useful to perform busy detection either in an effort to
++; etc, it can be useful to perform busy detection either in an effort to
+ ; detect hangup or for detecting busies. This enables listening for
+ ; the beep-beep busy pattern.
+ ;
+@@ -682,8 +685,8 @@
+ ;
+ ;hanguponpolarityswitch=yes
+ ;
+-; polarityonanswerdelay: minimal time period (ms) between the answer
+-; polarity switch and hangup polarity switch.
++; polarityonanswerdelay: minimal time period (ms) between the answer
++; polarity switch and hangup polarity switch.
+ ; (default: 600ms)
+ ;
+ ; On trunk interfaces (FXS) it can be useful to attempt to follow the progress
+@@ -696,7 +699,7 @@
+ ; with "progzone".
+ ;
+ ; progzone also affects the pattern used for buzydetect (unless
+-; busypattern is set explicitly). The possible values are:
++; busypattern is set explicitly). The possible values are:
+ ; us (default)
+ ; ca (alias for 'us')
+ ; cr (Costa Rica)
+@@ -738,7 +741,7 @@
+ ;faxdetect=no
+ ;
+ ; When 'faxdetect' is used, one could use 'faxbuffers' to configure the DAHDI
+-; transmit buffer policy. The default is *OFF*. When this configuration
++; 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
+@@ -831,7 +834,7 @@
+ ; parameters that were specified above its declaration.
+ ;
+ ; For GR-303, CRV's are created like channels except they must start with the
+-; trunk group followed by a colon, e.g.:
++; trunk group followed by a colon, e.g.:
+ ;
+ ; crv => 1:1
+ ; crv => 2:1-2,5-8
+@@ -905,15 +908,15 @@
+ ; A range of -1 will force it to always match.
+ ; Anything lower than -1 would presumably cause it to never match.
+ ;
+-;dring1=95,0,0
+-;dring1context=internal1
++;dring1=95,0,0
++;dring1context=internal1
+ ;dring1range=10
+-;dring2=325,95,0
+-;dring2context=internal2
++;dring2=325,95,0
++;dring2context=internal2
+ ;dring2range=10
+ ; If no pattern is matched here is where we go.
+ ;context=default
+-;channel => 1
++;channel => 1
+
+ ; ---------------- Options for use with signalling=ss7 -----------------
+ ; None of them can be changed by a reload.
+@@ -942,12 +945,12 @@
+ ;
+ ;ss7_calling_nai=dynamic
+ ;
+-;
+-; sample 1 for Germany
++;
++; sample 1 for Germany
+ ;ss7_internationalprefix = 00
+ ;ss7_nationalprefix = 0
+-;ss7_subscriberprefix =
+-;ss7_unknownprefix =
++;ss7_subscriberprefix =
++;ss7_unknownprefix =
+ ;
+
+ ; This option is used to disable automatic sending of ACM when the call is started
+@@ -997,8 +1000,19 @@
+
+ ; ---------------- Options for use with signalling=mfcr2 --------------
+
++; MFC-R2 signaling has lots of variants from country to country and even sometimes
++; minor variants inside the same country. The only mandatory parameters here are:
++; mfcr2_variant, mfcr2_max_ani and mfcr2_max_dnis.
++; IT IS RECOMMENDED that you leave the default values (leaving it commented) for the
++; other parameters unless you have problems or you have been instructed to change some
++; parameter. OpenR2 library uses the mfcr2_variant parameter to try to determine the
++; best defaults for your country, also refer to the OpenR2 package directory
++; doc/asterisk/ where you can find sample configurations for some countries. If you
++; want to contribute your configs for a particular country send them to the e-mail
++; of the primary OpenR2 developer that you can find in the AUTHORS file of the OpenR2 package
++
+ ; MFC/R2 variant. This depends on the OpenR2 supported variants
+-; A list of values can be found at libopenr2.org
++; A list of values can be found by executing the openr2 command r2test -l
+ ; some valid values are:
+ ; ar (Argentina)
+ ; br (Brazil)
+@@ -1007,17 +1021,17 @@
+ ; itu (per ITU spec)
+ ; mfcr2_variant=mx
+
+-; whether or not to get the ANI before getting DNIS.
+-; some telcos require ANI first some others do not care
+-; if this go wrong, change this value
+-; mfcr2_get_ani_first=no
+-
+ ; Max amount of ANI to ask for
+ ; mfcr2_max_ani=10
+
+ ; Max amount of DNIS to ask for
+ ; mfcr2_max_dnis=4
+
++; whether or not to get the ANI before getting DNIS.
++; some telcos require ANI first some others do not care
++; if this go wrong, change this value
++; mfcr2_get_ani_first=no
++
+ ; Caller Category to send
+ ; national_subscriber
+ ; national_priority_subscriber
+@@ -1028,9 +1042,8 @@
+ ; you can change this setting from the dialplan
+ ; by setting the variable MFCR2_CATEGORY
+ ; (remember to set _MFCR2_CATEGORY from originating channels)
+-; MFCR2_CATEGORY will also be a variable available
+-; on incoming calls set to the value received from
+-; the far end
++; MFCR2_CATEGORY will also be a variable available in your context
++; on incoming calls set to the value received from the far end
+ ; mfcr2_category=national_subscriber
+
+ ; Call logging is stored at the Asterisk
+@@ -1053,7 +1066,7 @@
+ ; 'stack' is for very verbose output of the channel and context call stack, only useful
+ ; if you are debugging a crash or want to learn how the library works. The stack logging
+ ; will be only enabled if the openr2 library was compiled with -DOR2_TRACE_STACKS
+-; You can mix up values, like: loglevel=error,debug,mf to log just error, debug and
++; You can mix up values, like: loglevel=error,debug,mf to log just error, debug and
+ ; multi frequency messages
+ ; 'all' is a special value to log all the activity
+ ; 'nothing' is a clean-up value, in case you want to not log any activity for
+@@ -1107,20 +1120,24 @@
+
+ ; You most likely dont need this feature. Default is yes.
+ ; When this is set to yes, all calls that are offered (incoming calls) which
+-; DNIS is valid (exists in extensions.conf) and pass collect call validation
++; DNIS is valid (exists in extensions.conf) and pass collect call validation
+ ; will be accepted with a Group B tone (either call with charge or not, depending on mfcr2_charge_calls)
+ ; with this set to 'no' then the call will NOT be accepted on offered, and the call will start its
+ ; execution in extensions.conf without being accepted until the channel is answered (either with Answer() or
+-; any other application resulting in the channel being answered).
++; any other application resulting in the channel being answered).
+ ; This can be set to 'no' if your telco or PBX needs the hangup cause to be set accurately
+ ; when this option is set to no you must explicitly accept the call with DAHDIAcceptR2Call
+-; or implicitly through the Answer() application.
++; or implicitly through the Answer() application.
+ ; mfcr2_accept_on_offer=yes
+
++; Skip request of calling party category and ANI
++; you need openr2 >= 1.2.0 to use this feature
++; mfcr2_skip_category=no
++
+ ; WARNING: advanced users only! I really mean it
+ ; this parameter is commented by default because
+ ; YOU DON'T NEED IT UNLESS YOU REALLY GROK MFC/R2
+-; READ COMMENTS on doc/r2proto.conf in openr2 package
++; READ COMMENTS on doc/r2proto.conf in openr2 package
+ ; for more info
+ ; mfcr2_advanced_protocol_file=/path/to/r2proto.conf
+
+@@ -1168,7 +1185,7 @@
+ ; chan_dahdi.conf and [general] in users.conf - one section's configuration
+ ; does not affect another one's.
+ ;
+-; Instead of letting common configuration values "slide through" you can
++; Instead of letting common configuration values "slide through" you can
+ ; use configuration templates to easily keep the common part in one
+ ; place and override where needed.
+ ;
+Index: configs/console.conf.sample
+===================================================================
+--- a/configs/console.conf.sample (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/configs/console.conf.sample (.../trunk) (revision 202568)
+@@ -5,7 +5,7 @@
+ [general]
+
+ ; Set this option to "yes" to enable automatically answering calls on the
+-; console. This is very useful if the console is used as an intercom.
++; console. This is very useful if the console is used as an intercom.
+ ; The default value is "no".
+ ;
+ ;autoanswer = no
+@@ -21,7 +21,7 @@
+ ;extension = s
+
+ ; Set the default CallerID for created channels.
+-;
++;
+ ;callerid = MyName Here <(256) 428-6000>
+
+ ; Set the default language for created channels.
+Index: configs/dundi.conf.sample
+===================================================================
+--- a/configs/dundi.conf.sample (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/configs/dundi.conf.sample (.../trunk) (revision 202568)
+@@ -1,6 +1,6 @@
+ ;
+ ; DUNDi configuration file
+-;
++;
+ ; For more information about DUNDi, see http://www.dundi.com
+ ;
+ ;
+@@ -50,9 +50,9 @@
+ ttl=32
+ ;
+ ; If we don't get ACK to our DPDISCOVER within 2000ms, and autokill is set
+-; to yes, then we cancel the whole thing (that's enough time for one
++; to yes, then we cancel the whole thing (that's enough time for one
+ ; retransmission only). This is used to keep things from stalling for a long
+-; time for a host that is not available, but would be ill advised for bad
++; time for a host that is not available, but would be ill advised for bad
+ ; connections. In addition to 'yes' or 'no' you can also specify a number
+ ; of milliseconds. See 'qualify' for individual peers to turn on for just
+ ; a specific peer.
+@@ -60,7 +60,7 @@
+ autokill=yes
+ ;
+ ; pbx_dundi creates a rotating key called "secret", under the family
+-; 'secretpath'. The default family is dundi (resulting in
++; 'secretpath'. The default family is dundi (resulting in
+ ; the key being held at dundi/secret).
+ ;
+ ;secretpath=dundi
+@@ -78,8 +78,8 @@
+ ;
+ ; The "mappings" section maps DUNDi contexts
+ ; to contexts on the local asterisk system. Remember
+-; that numbers that are made available under the e164
+-; DUNDi context are regulated by the DUNDi General Peering
++; that numbers that are made available under the e164
++; DUNDi context are regulated by the DUNDi General Peering
+ ; Agreement (GPA) if you are a member of the DUNDi E.164
+ ; Peering System.
+ ;
+@@ -108,14 +108,14 @@
+ ;
+ ; Further options may include:
+ ;
+-; nounsolicited: No unsolicited calls of any type permitted via this
++; nounsolicited: No unsolicited calls of any type permitted via this
+ ; route
+-; nocomunsolicit: No commercial unsolicited calls permitted via
++; nocomunsolicit: No commercial unsolicited calls permitted via
+ ; this route
+ ; residential: This number is known to be a residence
+ ; commercial: This number is known to be a business
+ ; mobile: This number is known to be a mobile phone
+-; nocomunsolicit: No commercial unsolicited calls permitted via
++; nocomunsolicit: No commercial unsolicited calls permitted via
+ ; this route
+ ; nopartial: Do not search for partial matches
+ ;
+@@ -163,7 +163,7 @@
+ ;
+ ; host - What their host is
+ ;
+-; order - What search order to use. May be 'primary', 'secondary',
++; order - What search order to use. May be 'primary', 'secondary',
+ ; 'tertiary' or 'quartiary'. In large systems, it is beneficial
+ ; to only query one up-stream host in order to maximize caching
+ ; value. Adding one with primary and one with secondary gives you
+@@ -187,7 +187,7 @@
+ ; the local system. Set "all" to deny this host to
+ ; lookup all contexts.
+ ;
+-; model - inbound, outbound, or symmetric for whether we receive
++; model - inbound, outbound, or symmetric for whether we receive
+ ; requests only, transmit requests only, or do both.
+ ;
+ ; precache - Utilize/Permit precaching with this peer (to pre
+@@ -241,7 +241,7 @@
+ ;inkey = littleguy
+ ;outkey = ourkey
+ ;include = e164 ; In this case used only for precaching
+-;permit = e164
++;permit = e164
+ ;qualify = yes
+
+ ;
+@@ -254,7 +254,7 @@
+ ;register = yes
+ ;inkey = dhcp34
+ ;permit = all ; In this case used only for precaching
+-;include = all
++;include = all
+ ;qualify = yes
+ ;outkey=foo
+
+Index: configs/oss.conf.sample
+===================================================================
+--- a/configs/oss.conf.sample (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/configs/oss.conf.sample (.../trunk) (revision 202568)
+@@ -130,7 +130,7 @@
+ region = # rect 152 146 201 146 28
+ region = pickup rect 229 15 267 15 40
+ region = hangup rect 230 66 270 64 40
+- region = mute circle 232 141 264 141 33
++ region = mute circle 232 141 264 141 33
+ region = sendvideo circle 235 185 266 185 33
+ region = autoanswer rect 228 212 275 212 50
+
+Index: configs/queues.conf.sample
+===================================================================
+--- a/configs/queues.conf.sample (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/configs/queues.conf.sample (.../trunk) (revision 202568)
+@@ -13,12 +13,12 @@
+ ; Keep queue statistics during a reload. Default is 'no'
+ ;
+ keepstats = no
+-;
++;
+ ; AutoFill Behavior
+-; The old/current behavior of the queue has a serial type behavior
++; The old/current behavior of the queue has a serial type behavior
+ ; in that the queue will make all waiting callers wait in the queue
+ ; even if there is more than one available member ready to take
+-; calls until the head caller is connected with the member they
++; calls until the head caller is connected with the member they
+ ; were trying to get to. The next waiting caller in line then
+ ; becomes the head caller, and they are then connected with the
+ ; next available member and all available members and waiting callers
+@@ -26,8 +26,8 @@
+ ; autofill=yes makes sure that when the waiting callers are connecting
+ ; with available members in a parallel fashion until there are
+ ; no more available members or no more waiting callers. This is
+-; probably more along the lines of how a queue should work and
+-; in most cases, you will want to enable this behavior. If you
++; probably more along the lines of how a queue should work and
++; in most cases, you will want to enable this behavior. If you
+ ; do not specify or comment out this option, it will default to no
+ ; to keep backward compatibility with the old behavior.
+ ;
+@@ -36,22 +36,22 @@
+ ; Monitor Type
+ ; By setting monitor-type = MixMonitor, when specifying monitor-format
+ ; to enable recording of queue member conversations, app_queue will
+-; now use the new MixMonitor application instead of Monitor so
++; now use the new MixMonitor application instead of Monitor so
+ ; the concept of "joining/mixing" the in/out files now goes away
+ ; when this is enabled. You can set the default type for all queues
+ ; here, and then also change monitor-type for individual queues within
+-; queue by using the same configuration parameter within a queue
++; queue by using the same configuration parameter within a queue
+ ; configuration block. If you do not specify or comment out this option,
+ ; it will default to the old 'Monitor' behavior to keep backward
+-; compatibility.
++; compatibility.
+ ;
+ monitor-type = MixMonitor
+ ;
+-; UpdateCDR behavior.
++; UpdateCDR behavior.
+ ; This option is implemented to mimic chan_agents behavior of populating
+-; CDR dstchannel field of a call with an agent name, which you can set
+-; at the login time with AddQueueMember membername parameter.
+-;
++; CDR dstchannel field of a call with an agent name, which you can set
++; at the login time with AddQueueMember membername parameter.
++;
+ ; updatecdr = no
+
+ ;
+@@ -134,7 +134,7 @@
+ ; The member's phone is rung for 5 seconds and he does not answer.
+ ; The retry time of 4 seconds occurs.
+ ; The queue selects a second member to call.
+-;
++;
+ ; How long does that second member's phone ring? Does it ring for 5 seconds
+ ; since the timeout set in app_queue is 5 seconds? Does it ring for 1 second since
+ ; the caller has been in the queue for 9 seconds and is supposed to be removed after
+@@ -143,8 +143,8 @@
+ ; rather use the time specified in the configuration file even if it means having the
+ ; caller stay in the queue longer than the time specified in the application argument.
+ ; For the scenario described above, timeoutpriority=conf would result in the second
+-; member's phone ringing for 5 seconds. By specifying "app" as the value for
+-; timeoutpriority, you are saying that the timeout specified as the argument to the
++; member's phone ringing for 5 seconds. By specifying "app" as the value for
++; timeoutpriority, you are saying that the timeout specified as the argument to the
+ ; Queue application is more important. In the scenario above, timeoutpriority=app
+ ; would result in the second member's phone ringing for 1 second.
+ ;
+@@ -152,7 +152,7 @@
+ ; and the configuration file timeout is set to 0, but the application argument timeout is
+ ; non-zero, then the timeoutpriority is ignored and the application argument is used as
+ ; the timeout. Furthermore, if no application argument timeout is specified, then the
+-; timeoutpriority option is ignored and the configuration file timeout is always used
++; timeoutpriority option is ignored and the configuration file timeout is always used
+ ; when calling queue members.
+ ;
+ ; In timeoutpriority=conf mode however timeout specified in config file will take higher
+@@ -170,8 +170,8 @@
+ ;timeoutpriority = app|conf
+ ;
+ ;-----------------------END QUEUE TIMING OPTIONS---------------------------------
+-; Weight of queue - when compared to other queues, higher weights get
+-; first shot at available channels when the same channel is included in
++; Weight of queue - when compared to other queues, higher weights get
++; first shot at available channels when the same channel is included in
+ ; more than one queue.
+ ;
+ ;weight=0
+@@ -196,21 +196,21 @@
+ ;
+ ;maxlen = 0
+ ;
+-; If set to yes, just prior to the caller being bridged with a queue member
++; If set to yes, just prior to the caller being bridged with a queue member
+ ; the following variables will be set
+ ; MEMBERINTERFACE is the interface name (eg. Agent/1234)
+ ; MEMBERNAME is the member name (eg. Joe Soap)
+-; MEMBERCALLS is the number of calls that interface has taken,
+-; MEMBERLASTCALL is the last time the member took a call.
+-; MEMBERPENALTY is the penalty of the member
++; MEMBERCALLS is the number of calls that interface has taken,
++; MEMBERLASTCALL is the last time the member took a call.
++; MEMBERPENALTY is the penalty of the member
+ ; MEMBERDYNAMIC indicates if a member is dynamic or not
+ ; MEMBERREALTIME indicates if a member is realtime or not
+ ;
+ ;setinterfacevar=no
+ ;
+-; If set to yes, just prior to the caller being bridged with a queue member
++; If set to yes, just prior to the caller being bridged with a queue member
+ ; the following variables will be set:
+-; QEHOLDTIME callers hold time
++; QEHOLDTIME callers hold time
+ ; QEORIGINALPOS original position of the caller in the queue
+ ;
+ ;setqueueentryvar=no
+@@ -220,7 +220,7 @@
+ ; and just prior to the caller leaving the queue
+ ; QUEUENAME name of the queue
+ ; QUEUEMAX maxmimum number of calls allowed
+-; QUEUESTRATEGY the strategy of the queue;
++; QUEUESTRATEGY the strategy of the queue;
+ ; QUEUECALLS number of calls currently in the queue
+ ; QUEUEHOLDTIME current average hold time
+ ; QUEUECOMPLETED number of completed calls for the queue
+@@ -231,17 +231,17 @@
+ ;setqueuevar=no
+ ;
+ ; if set, run this macro when connected to the queue member
+-; you can override this macro by setting the macro option on
++; you can override this macro by setting the macro option on
+ ; the queue application
+ ;
+ ; membermacro=somemacro
+
+-; How often to announce queue position and/or estimated
++; How often to announce queue position and/or estimated
+ ; holdtime to caller (0=off)
+ ; Note that this value is ignored if the caller's queue
+ ; position has changed (see min-announce-frequency)
+ ;
+-;announce-frequency = 90
++;announce-frequency = 90
+ ;
+ ; The absolute minimum time between the start of each
+ ; queue position and/or estimated holdtime announcement
+@@ -301,7 +301,7 @@
+ ; queue-thankyou=
+ ;
+ ; ("You are now first in line.")
+-;queue-youarenext = queue-youarenext
++;queue-youarenext = queue-youarenext
+ ; ("There are")
+ ;queue-thereare = queue-thereare
+ ; ("calls waiting.")
+@@ -319,7 +319,7 @@
+ ; ("All reps busy / wait for next")
+ ;periodic-announce = queue-periodic-announce
+ ;
+-; A set of periodic announcements can be defined by separating
++; A set of periodic announcements can be defined by separating
+ ; periodic announcements to reproduce by commas. For example:
+ ;periodic-announce = queue-periodic-announce,your-call-is-important,please-wait
+ ;
+@@ -358,7 +358,7 @@
+ ;
+ ; You can specify the options supplied to MixMonitor by calling
+ ; Set(MONITOR_OPTIONS=av(<x>)V(<x>)W(<x>))
+-; The 'b' option for MixMonitor (only save audio to the file while bridged) is
++; The 'b' option for MixMonitor (only save audio to the file while bridged) is
+ ; implied.
+ ;
+ ; You can specify a post recording command to be executed after the end of
+@@ -379,9 +379,9 @@
+ ; 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
++; 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
+@@ -394,14 +394,14 @@
+ ; 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:
+ ;
+ ;joinempty = paused,inuse,invalid
+@@ -411,7 +411,7 @@
+ ;
+ ;leavewhenempty = inuse,ringing
+ ;
+-; A caller will be removed from the queue if at least one member cannot be found
++; 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.
+ ;
+ ; For the sake of backwards-compatibility, the joinempty and leavewhenempty
+@@ -461,7 +461,7 @@
+ ;
+ ; timeoutrestart = no
+ ;
+-; If you wish to implement a rule defined in queuerules.conf (see
++; If you wish to implement a rule defined in queuerules.conf (see
+ ; configs/queuerules.conf.sample from the asterisk source directory for
+ ; more information about penalty rules) by default, you may specify this
+ ; by setting defaultrule to the rule's name
+Index: configs/cdr.conf.sample
+===================================================================
+--- a/configs/cdr.conf.sample (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/configs/cdr.conf.sample (.../trunk) (revision 202568)
+@@ -14,12 +14,12 @@
+ ;enable=yes
+
+ ; Define whether or not to log unanswered calls. Setting this to "yes" will
+-; report every attempt to ring a phone in dialing attempts, when it was not
++; report every attempt to ring a phone in dialing attempts, when it was not
+ ; answered. For example, if you try to dial 3 extensions, and this option is "yes",
+ ; you will get 3 CDR's, one for each phone that was rung. Default is "no". Some
+ ; find this information horribly useless. Others find it very valuable. Note, in "yes"
+ ; mode, you will see one CDR, with one of the call targets on one side, and the originating
+-; channel on the other, and then one CDR for each channel attempted. This may seem
++; channel on the other, and then one CDR for each channel attempted. This may seem
+ ; redundant, but cannot be helped.
+ ;unanswered = no
+
+@@ -67,7 +67,7 @@
+
+ ; 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
++; 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
+@@ -78,19 +78,19 @@
+ ;
+ ; CHOOSING A CDR "BACKEND" (what kind of output to generate)
+ ;
+-; To choose a backend, you have to make sure either the right category is
+-; defined in this file, or that the appropriate config file exists, and has the
++; To choose a backend, you have to make sure either the right category is
++; defined in this file, or that the appropriate config file exists, and has the
+ ; proper definitions in it. If there are any problems, usually, the entry will
+ ; silently ignored, and you get no output.
+-;
+-; Also, please note that you can generate CDR records in as many formats as you
++;
++; Also, please note that you can generate CDR records in as many formats as you
+ ; wish. If you configure 5 different CDR formats, then each event will be logged
+ ; in 5 different places! In the example config files, all formats are commented
+ ; out except for the cdr-csv format.
+ ;
+ ; Here are all the possible back ends:
+ ;
+-; csv, custom, manager, odbc, pgsql, radius, sqlite, tds
++; csv, custom, manager, odbc, pgsql, radius, sqlite, tds
+ ; (also, mysql is available via the asterisk-addons, due to licensing
+ ; requirements)
+ ; (please note, also, that other backends can be created, by creating
+@@ -104,7 +104,7 @@
+ ; backend is marked with XXX, you know that the "configure" command could not find
+ ; the required libraries for that option.
+ ;
+-; To get CDRs to be logged to the plain-jane /var/log/asterisk/cdr-csv/Master.csv
++; To get CDRs to be logged to the plain-jane /var/log/asterisk/cdr-csv/Master.csv
+ ; file, define the [csv] category in this file. No database necessary. The example
+ ; config files are set up to provide this kind of output by default.
+ ;
+@@ -126,7 +126,7 @@
+ ; shows that the modules are available, and the cdr_pgsql.conf file exists, and
+ ; has a [global] section with the proper variables defined.
+ ;
+-; For logging to radius databases, make sure all the proper libs are installed, that
++; For logging to radius databases, make sure all the proper libs are installed, that
+ ; "make menuselect" shows that the modules are available, and the [radius]
+ ; category is defined in this file, and in that section, make sure the 'radiuscfg'
+ ; variable is properly pointing to an existing radiusclient.conf file.
+@@ -135,7 +135,7 @@
+ ; which is usually /var/log/asterisk. Of course, the proper libraries should be available
+ ; during the 'configure' operation.
+ ;
+-; For tds logging, make sure the proper libraries are available during the 'configure'
++; For tds logging, make sure the proper libraries are available during the 'configure'
+ ; phase, and that cdr_tds.conf exists and is properly set up with a [global] category.
+ ;
+ ; Also, remember, that if you wish to log CDR info to a database, you will have to define
+Index: configs/calendar.conf.sample
+===================================================================
+--- a/configs/calendar.conf.sample (.../tags/1.6.2.0-beta3) (revision 0)
++++ b/configs/calendar.conf.sample (.../trunk) (revision 202568)
+@@ -0,0 +1,84 @@
++;[calendar1]
++;type = ical ; type of calendar--currently supported: ical, caldav, or exchange
++;url = https://example.com/home/jdoe/Calendar/ ; URL to shared calendar (Zimbra example)
++;user = jdoe ; web username
++;secret = supersecret ; web password
++;refresh = 15 ; refresh calendar every n minutes
++;timeframe = 60 ; number of minutes of calendar data to pull for each refresh period
++; ; should always be >= refresh
++;
++; You can set up res_icalendar to execute a call upon an upcoming busy status
++; The following fields are available from the ${CALENDAR_EVENT(<field>)} dialplan function:
++;
++; summary : The VEVENT Summary property or Exchange subject
++; description : The text description of the vent
++; organizer : The organizer of the event
++; location : The location field of the event
++; calendar : The name of the calendar tied to the event
++; uid : The unique ID for this event
++; start : Start time of the event
++; end : The end time of the event
++; busystate : 0=FREE, 1=TENTATIVE, 2=BUSY
++;
++;autoreminder = 10 ; Override event-defined reminder before each busy status (in mins)
++;
++;channel = SIP/60001 ; Channel to dial
++;context = default ; Context to connect to on answer
++;extension = 123 ; Extension to connect to on answer
++;
++; or
++;
++;app = Playback ; Application to execute on answer (instead of context/extension)
++;appdata = tt-weasels ; Data part of application to execute on answer
++;
++;waittime = 30 ; How long to wait for an answer
++
++;[calendar2]
++; Note: Exchange support has only been tested on Exchange Server 2003
++; Forms-based authentication is not supported at this time
++; Querying attendees is not supported with Exchange at this time
++;
++;type = exchange ; type of calendar--currently supported: ical, caldav, or exchange
++;url = https://example.com/exchange/jdoe ; URL to MS Exchange OWA for user (usually includes exchange/user)
++;user = jdoe ; Exchange username
++;secret = mysecret ; Exchange password
++;refresh = 15 ; refresh calendar every n minutes
++;timeframe = 60 ; number of minutes of calendar data to pull for each refresh period
++; ; should always be >= refresh
++;
++; You can set up res_icalendar to execute a call upon an upcoming busy status
++;autoreminder = 10 ; Override event-defined reminder before each busy status (in mins)
++;
++;channel = SIP/1234 ; Channel to dial
++;context = default ; Context to connect to on answer
++;extension = 1234 ; Extension to connect to on answer
++;
++; or
++;
++;app = Playback ; Application to execute on answer (instead of context/extension)
++;appdata = tt-weasels ; Data part of application to execute on answer
++;
++;waittime = 30 ; How long to wait for an answer
++
++;[calendar3]
++;type = caldav ; type of calendar--currently supported: ical, caldav, or exchange
++;url = https://www.google.com/calendar/dav/username@gmail.com/events/ ; Main GMail calendar (the trailing slash is significant!)
++;user = jdoe@gmail.com ; username
++;secret = mysecret ; password
++;refresh = 15 ; refresh calendar every n minutes
++;timeframe = 60 ; number of minutes of calendar data to pull for each refresh period
++; ; should always be >= refresh
++;
++; You can set up res_icalendar to execute a call upon an upcoming busy status
++;autoreminder = 10 ; Override event-defined reminder before each busy status (in mins)
++;
++;channel = SIP/1234 ; Channel to dial
++;context = default ; Context to connect to on answer
++;extension = 1234 ; Extension to connect to on answer
++;
++; or
++;
++;app = Playback ; Application to execute on answer (instead of context/extension)
++;appdata = tt-weasels ; Data part of application to execute on answer
++;
++;waittime = 30 ; How long to wait for an answer
+
+Property changes on: configs/calendar.conf.sample
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+Added: svn:mime-type
+ + text/plain
+Added: svn:keywords
+ + Author Date Id Revision
+
+Index: configs/manager.conf.sample
+===================================================================
+--- a/configs/manager.conf.sample (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/configs/manager.conf.sample (.../trunk) (revision 202568)
+@@ -1,6 +1,6 @@
+ ;
+ ; AMI - The Asterisk Manager Interface
+-;
++;
+ ; Third party application call management support and PBX event supervision
+ ;
+ ; This configuration file is read every time someone logs in
+@@ -13,11 +13,11 @@
+ ; ---------------------------- SECURITY NOTE -------------------------------
+ ; Note that you should not enable the AMI on a public IP address. If needed,
+ ; block this TCP port with iptables (or another FW software) and reach it
+-; with IPsec, SSH, or SSL vpn tunnel. You can also make the manager
++; with IPsec, SSH, or SSL vpn tunnel. You can also make the manager
+ ; interface available over http/https if Asterisk's http server is enabled in
+ ; http.conf and if both "enabled" and "webenabled" are set to yes in
+-; this file. Both default to no. httptimeout provides the maximum
+-; timeout in seconds before a web based session is discarded. The
++; this file. Both default to no. httptimeout provides the maximum
++; timeout in seconds before a web based session is discarded. The
+ ; default is 60 seconds.
+ ;
+ [general]
+@@ -27,9 +27,9 @@
+
+ ;httptimeout = 60
+ ; a) httptimeout sets the Max-Age of the http cookie
+-; b) httptimeout is the amount of time the webserver waits
++; b) httptimeout is the amount of time the webserver waits
+ ; on a action=waitevent request (actually its httptimeout-10)
+-; c) httptimeout is also the amount of time the webserver keeps
++; c) httptimeout is also the amount of time the webserver keeps
+ ; a http session alive after completing a successful action
+
+ bindaddr = 0.0.0.0
+@@ -39,13 +39,14 @@
+ ;
+ ; openssl s_client -connect my_host:5039
+ ;
+-; sslenable=no ; set to YES to enable it
+-; sslbindport=5039 ; the port to bind to
+-; sslbindaddr=0.0.0.0 ; address to bind to, default to bindaddr
+-; sslcert=/tmp/asterisk.pem ; path to the certificate.
+-; sslcipher=<cipher string> ; string specifying which SSL ciphers to use or not use
+-
+-
++;tlsenable=no ; set to YES to enable it
++;tlsbindport=5039 ; the port to bind to
++;tlsbindaddr=0.0.0.0 ; address to bind to, default to bindaddr
++;tlscertfile=/tmp/asterisk.pem ; path to the certificate.
++;tlsprivatekey=/tmp/private.pem ; path to the private key, if no private given,
++ ; if no tlsprivatekey is given, default is to search
++ ; tlscertfile for private key.
++;tlscipher=<cipher string> ; string specifying which SSL ciphers to use or not use
+ ;
+ ;allowmultiplelogin = yes ; IF set to no, rejects manager logins that are already in use.
+ ; ; The default is yes.
+@@ -71,7 +72,7 @@
+ ;
+ ;displayconnects = yes ; Display on CLI user login/logoff
+ ;
+-; Authorization for various classes
++; Authorization for various classes
+ ;
+ ; Read authorization permits you to receive asynchronous events, in general.
+ ; Write authorization permits you to send commands and get back responses. The
+Index: configs/features.conf.sample
+===================================================================
+--- a/configs/features.conf.sample (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/configs/features.conf.sample (.../trunk) (revision 202568)
+@@ -9,12 +9,12 @@
+ ; and increments with one for the next parked call.
+ context => parkedcalls ; Which context parked calls are in (default parking lot)
+ ;parkinghints = no ; Add hints priorities automatically for parking slots (default is no).
+-;parkingtime => 45 ; Number of seconds a call can be parked for
++;parkingtime => 45 ; Number of seconds a call can be parked for
+ ; (default is 45 seconds)
+ ;comebacktoorigin = yes ; Whether to return to the original calling extension upon parking
+ ; timeout or to send the call to context 'parkedcallstimeout' at
+ ; extension 's', priority '1' (default is yes).
+-;courtesytone = beep ; Sound file to play to the parked caller
++;courtesytone = beep ; Sound file to play to the parked caller
+ ; when someone dials a parked call
+ ; or the Touch Monitor is activated/deactivated.
+ ;parkedplay = caller ; Who to play the courtesy tone to when picking up a parked call
+@@ -28,7 +28,7 @@
+ ;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.
++;findslot => next ; Continue to the 'next' free parking space.
+ ; Defaults to 'first' available
+ ;parkedmusicclass=default ; This is the MOH class to use for the parked channel
+ ; as long as the class is not set on the channel directly
+@@ -41,7 +41,7 @@
+ ;pickupexten = *8 ; Configure the pickup extension. (default is *8)
+ ;pickupsound = beep ; to indicate a successful pickup (default: no sound)
+ ;pickupfailsound = beeperr ; to indicate that the pickup failed (default: no sound)
+-;featuredigittimeout = 1000 ; Max time (ms) between digits for
++;featuredigittimeout = 1000 ; Max time (ms) between digits for
+ ; feature activation (default is 1000 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
+Index: configs/logger.conf.sample
+===================================================================
+--- a/configs/logger.conf.sample (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/configs/logger.conf.sample (.../trunk) (revision 202568)
+@@ -15,7 +15,7 @@
+ ; see strftime(3) Linux manual for format specifiers. Note that there is also
+ ; a fractional second parameter which may be used in this field. Use %1q
+ ; for tenths, %2q for hundredths, etc.
+-;
++;
+ ;dateformat=%F %T ; ISO 8601 date format
+ ;dateformat=%F %T.%3q ; with milliseconds
+ ;
+@@ -47,11 +47,7 @@
+ ;
+ ; exec_after_rotate=gzip -9 ${filename}.2
+ ;
+-; This determines whether or not we log generic events to a file
+-; (defaults to yes).
+-;event_log = no
+ ;
+-;
+ ; For each file, specify what to log.
+ ;
+ ; For console logging, you set options at start of
+@@ -94,7 +90,7 @@
+ messages => notice,warning,error
+ ;full => notice,warning,error,debug,verbose
+
+-;syslog keyword : This special keyword logs to syslog facility
++;syslog keyword : This special keyword logs to syslog facility
+ ;
+ ;syslog.local0 => notice,warning,error
+ ;
+Index: configs/h323.conf.sample
+===================================================================
+--- a/configs/h323.conf.sample (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/configs/h323.conf.sample (.../trunk) (revision 202568)
+@@ -44,7 +44,7 @@
+ ; or
+ ;dtmfmode=cisco:121
+ ;
+-; Set the gatekeeper
++; Set the gatekeeper
+ ; DISCOVER - Find the Gk address using multicast
+ ; DISABLE - Disable the use of a GK
+ ; <IP address> or <Host name> - The acutal IP address or hostname of your GK
+@@ -70,9 +70,9 @@
+ ;
+ ;UserByAlias=no
+ ;
+-; Default context gets used in siutations where you are using
+-; the GK routed model or no type=user was found. This gives you
+-; the ability to either play an invalid message or to simply not
++; Default context gets used in siutations where you are using
++; the GK routed model or no type=user was found. This gives you
++; the ability to either play an invalid message or to simply not
+ ; use user authentication at all.
+ ;
+ ;context=default
+@@ -153,7 +153,7 @@
+ ; and Gatekeeper, if there is one.
+ ;
+ ; Example: if someone calls time@your.asterisk.box.com
+-; Asterisk will send the call to the extension 'time'
++; Asterisk will send the call to the extension 'time'
+ ; in the context default
+ ;
+ ; [default]
+@@ -161,13 +161,13 @@
+ ; exten => time,2,Playback,current-time
+ ;
+ ; Keyword's 'prefix' and 'e164' are only make sense when
+-; used with a gatekeeper. You can specify either a prefix
++; used with a gatekeeper. You can specify either a prefix
+ ; or E.164 this endpoint is responsible for terminating.
+-;
++;
+ ; Example: The H.323 alias 'det-gw' will tell the gatekeeper
+ ; to route any call with the prefix 1248 to this alias. Keyword
+ ; e164 is used when you want to specifiy a full telephone
+-; number. So a call to the number 18102341212 would be
++; number. So a call to the number 18102341212 would be
+ ; routed to the H.323 alias 'time'.
+ ;
+ ;[time]
+@@ -182,10 +182,10 @@
+ ;
+ ;
+ ; Inbound H.323 calls from BillyBob would land in the incoming
+-; context with a maximum of 4 concurrent incoming calls
+-;
++; context with a maximum of 4 concurrent incoming calls
+ ;
+-; Note: If keyword 'incominglimit' are omitted Asterisk will not
++;
++; Note: If keyword 'incominglimit' are omitted Asterisk will not
+ ; enforce any maximum number of concurrent calls.
+ ;
+ ;[BillyBob]
+Index: configs/sla.conf.sample
+===================================================================
+--- a/configs/sla.conf.sample (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/configs/sla.conf.sample (.../trunk) (revision 202568)
+@@ -27,12 +27,12 @@
+ ; require some indirect configuration which is
+ ; described in doc/asterisk.pdf.
+
+-;autocontext=line1 ; This supports automatic generation of the dialplan entries
+- ; if the autocontext option is used. Each trunk should have
++;autocontext=line1 ; This supports automatic generation of the dialplan entries
++ ; if the autocontext option is used. Each trunk should have
+ ; a unique context name. Then, in chan_dahdi.conf, this device
+ ; should be configured to have incoming calls go to this context.
+
+-;ringtimeout=30 ; Set how long to allow this trunk to ring on an inbound call before hanging
++;ringtimeout=30 ; Set how long to allow this trunk to ring on an inbound call before hanging
+ ; it up as an unanswered call. The value is in seconds.
+
+ ;barge=no ; If this option is set to "no", then no station will be
+@@ -75,12 +75,12 @@
+
+ ;device=SIP/station1 ; Each station must be mapped to a device.
+
+-;autocontext=sla_stations ; This supports automatic generation of the dialplan entries if
+- ; the autocontext option is used. All stations can use the same
+- ; context without conflict. The device for this station should
++;autocontext=sla_stations ; This supports automatic generation of the dialplan entries if
++ ; the autocontext option is used. All stations can use the same
++ ; context without conflict. The device for this station should
+ ; have its context configured to the same one listed here.
+
+-;ringtimeout=10 ; Set a timeout for how long to allow the station to ring for an
++;ringtimeout=10 ; Set a timeout for how long to allow the station to ring for an
+ ; incoming call, in seconds.
+
+ ;ringdelay=10 ; Set a time for how long to wait before beginning to ring this station
+@@ -97,8 +97,8 @@
+ ; "private" - This means that once this station puts a
+ ; call on hold, no other station will be
+ ; allowed to retrieve the call from hold.
+-
+
++
+ ;trunk=line1 ; Individually list all of the trunks that will appear on this station. This
+ ; order is significant. It should be the same order as they appear on the
+ ; phone. The order here defines the order of preference that the trunks will
+@@ -121,9 +121,9 @@
+ ;type=station
+ ;autocontext=sla_stations
+ ;trunk=line1
+-;trunk=line2
++;trunk=line2
+ ;trunk=line3
+-;trunk=line4
++;trunk=line4
+
+ ;[station2](station) ; Define a station that uses the configuration from the template "station".
+ ;device=SIP/station2
+Index: configs/res_odbc.conf.sample
+===================================================================
+--- a/configs/res_odbc.conf.sample (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/configs/res_odbc.conf.sample (.../trunk) (revision 202568)
+@@ -1,4 +1,4 @@
+-;;; odbc setup file
++;;; odbc setup file
+
+ ; ENV is a global set of environmental variables that will get set.
+ ; Note that all environmental variables can be seen by all connections,
+Index: configs/agents.conf.sample
+===================================================================
+--- a/configs/agents.conf.sample (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/configs/agents.conf.sample (.../trunk) (revision 202568)
+@@ -3,13 +3,6 @@
+ ;
+
+ [general]
+-;
+-; Define whether callbacklogins should be stored in astdb for
+-; persistence. Persistent logins will be reloaded after
+-; Asterisk restarts.
+-;
+-persistentagents=yes
+-
+ ; Enable or disable a single extension from logging in as multiple agents.
+ ; The default value is "yes".
+ ;multiplelogin=yes
+@@ -32,16 +25,15 @@
+ ; Define autologoffunavail to have agents automatically logged
+ ; out when the extension that they are at returns a CHANUNAVAIL
+ ; status when a call is attempted to be sent there.
+-; Default is "no".
++; Default is "no".
+ ;
+ ;autologoffunavail=yes
+ ;
+ ; Define ackcall to require a DTMF acknowledgement when
+-; an agent logs in using agentcallbacklogin. Default is "no".
+-; Can also be set to "always", which will also require AgentLogin
+-; agents to acknowledge calls. Use the acceptdtmf option to
+-; configure what DTMF key press should be used to acknowledge the
+-; call. The default is '#'.
++; an agent logs in using AgentLogin. Default is "no".
++; Use the acceptdtmf option to configure what DTMF key
++; press should be used to acknowledge the call. The
++; default is '#'.
+ ;
+ ;ackcall=no
+ ;acceptdtmf=#
+@@ -70,14 +62,14 @@
+ ;
+ ;goodbye => goodbye_file
+ ;
+-; Define updatecdr. This is whether or not to change the source
+-; channel in the CDR record for this call to agent/agent_id so
++; Define updatecdr. This is whether or not to change the source
++; channel in the CDR record for this call to agent/agent_id so
+ ; that we know which agent generates the call
+ ;
+ ;updatecdr=no
+ ;
+ ; Group memberships for agents (may change in mid-file)
+-;
++;
+ ;group=3
+ ;group=1,2
+ ;group=
+@@ -85,7 +77,7 @@
+ ; --------------------------------------------------
+ ; This section is devoted to recording agent's calls
+ ; The keywords are global to the chan_agent channel driver
+-;
++;
+ ; Enable recording calls addressed to agents. It's turned off by default.
+ ;recordagentcalls=yes
+ ;
+@@ -100,7 +92,7 @@
+ ; /var/spool/asterisk/monitor
+ ;savecallsin=/var/calls
+ ;
+-; An optional custom beep sound file to play to always-connected agents.
++; An optional custom beep sound file to play to always-connected agents.
+ ;custom_beep=beep
+ ;
+ ; --------------------------------------------------
+Index: configs/res_snmp.conf.sample
+===================================================================
+--- a/configs/res_snmp.conf.sample (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/configs/res_snmp.conf.sample (.../trunk) (revision 202568)
+@@ -15,7 +15,7 @@
+
+ [general]
+ ; We run as a subagent per default -- to run as a full agent
+-; we must run as root (to be able to bind to port 161)
++; we must run as root (to be able to bind to port 161)
+ ;subagent = yes
+ ; SNMP must be explicitly enabled to be active
+ ;enabled = yes
+Index: configs/extconfig.conf.sample
+===================================================================
+--- a/configs/extconfig.conf.sample (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/configs/extconfig.conf.sample (.../trunk) (revision 202568)
+@@ -7,7 +7,7 @@
+ ;
+ [settings]
+ ;
+-; Static configuration files:
++; Static configuration files:
+ ;
+ ; file.conf => driver,database[,table]
+ ;
+Index: configs/modules.conf.sample
+===================================================================
+--- a/configs/modules.conf.sample (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/configs/modules.conf.sample (.../trunk) (revision 202568)
+@@ -21,7 +21,7 @@
+ ; Uncomment the following if you wish to use the Speech Recognition API
+ ;preload => res_speech.so
+ ;
+-; If you want, load the GTK console right away.
++; If you want, load the GTK console right away.
+ ;
+ noload => pbx_gtkconsole.so
+ ;load => pbx_gtkconsole.so
+Index: configs/phone.conf.sample
+===================================================================
+--- a/configs/phone.conf.sample (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/configs/phone.conf.sample (.../trunk) (revision 202568)
+@@ -6,8 +6,8 @@
+ [interfaces]
+ ;
+ ; Select a mode, either the phone jack provides dialtone, reads digits,
+-; then starts PBX with the given extension (dialtone mode), or
+-; immediately provides the PBX without reading any digits or providing
++; then starts PBX with the given extension (dialtone mode), or
++; immediately provides the PBX without reading any digits or providing
+ ; any dialtone (this is the immediate mode, the default). Also, you
+ ; can set the mode to "fxo" if you have a linejack to make it operate
+ ; properly. If you are using a Sigma Designs board you may set this to
+Index: makeopts.in
+===================================================================
+--- a/makeopts.in (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/makeopts.in (.../trunk) (revision 202568)
+@@ -47,6 +47,8 @@
+ PTHREAD_CFLAGS=@PTHREAD_CFLAGS@
+ PTHREAD_LIBS=@PTHREAD_LIBS@
+
++GNU_LD=@GNU_LD@
++
+ prefix = @prefix@
+ exec_prefix = @exec_prefix@
+
+@@ -103,6 +105,9 @@
+ GTK2_INCLUDE=@GTK2_INCLUDE@
+ GTK2_LIB=@GTK2_LIB@
+
++ICAL_INCLUDE=@ICAL_INCLUDE@
++ICAL_LIB=@ICAL_LIB@
++
+ ICONV_INCLUDE=@ICONV_INCLUDE@
+ ICONV_LIB=@ICONV_LIB@
+
+@@ -131,6 +136,9 @@
+ NCURSES_LIB=@NCURSES_LIB@
+ NCURSES_DIR=@NCURSES_DIR@
+
++NEON_INCLUDE=@NEON_INCLUDE@
++NEON_LIB=@NEON_LIB@
++
+ NETSNMP_INCLUDE=@NETSNMP_INCLUDE@
+ NETSNMP_LIB=@NETSNMP_LIB@
+
+Index: res/res_config_sqlite.c
+===================================================================
+--- a/res/res_config_sqlite.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/res/res_config_sqlite.c (.../trunk) (revision 202568)
+@@ -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-beta3) (revision 0)
++++ b/res/res_speech.exports (.../trunk) (revision 202568)
+@@ -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-beta3) (revision 202568)
++++ b/res/res_config_odbc.c (.../trunk) (revision 202568)
+@@ -903,6 +903,9 @@
+ case SQL_CHAR:
+ case SQL_VARCHAR:
+ case SQL_LONGVARCHAR:
++ case SQL_WCHAR:
++ case SQL_WVARCHAR:
++ case SQL_WLONGVARCHAR:
+ case SQL_BINARY:
+ case SQL_VARBINARY:
+ case SQL_LONGVARBINARY:
+@@ -984,7 +987,7 @@
+ if (type != RQ_UINTEGER1 && type != RQ_INTEGER1 &&
+ type != RQ_UINTEGER2 && type != RQ_INTEGER2 &&
+ type != RQ_UINTEGER3 && type != RQ_INTEGER3 &&
+- type != RQ_UINTEGER4) {
++ type != RQ_INTEGER4) {
+ WARN_TYPE_OR_LENGTH(size)
+ }
+ break;
+@@ -1003,7 +1006,7 @@
+ type != RQ_UINTEGER2 && type != RQ_INTEGER2 &&
+ type != RQ_UINTEGER3 && type != RQ_INTEGER3 &&
+ type != RQ_UINTEGER4 && type != RQ_INTEGER4 &&
+- type != RQ_UINTEGER8) {
++ type != RQ_INTEGER8) {
+ WARN_TYPE_OR_LENGTH(size)
+ }
+ break;
+@@ -1067,7 +1070,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-beta3) (revision 202568)
++++ b/res/res_agi.c (.../trunk) (revision 202568)
+@@ -130,6 +130,32 @@
+ </enumlist>
+ </description>
+ </agi>
++ <agi name="control stream file" language="en_US">
++ <synopsis>
++ Sends audio file on channel and allows the listner to control the stream.
++ </synopsis>
++ <syntax>
++ <parameter name="filename" required="true">
++ <para>The file extension must not be included in the filename.</para>
++ </parameter>
++ <parameter name="escape_digits" required="true" />
++ <parameter name="skipms" />
++ <parameter name="ffchar">
++ <para>Defaults to <literal>*</literal></para>
++ </parameter>
++ <parameter name="rewchr">
++ <para>Defaults to <literal>#</literal></para>
++ </parameter>
++ <parameter name="pausechr" />
++ </syntax>
++ <description>
++ <para>Send the given file, allowing playback to be controled by the given
++ digits, if any. Use double quotes for the digits if you wish none to be
++ permitted. Returns <literal>0</literal> if playback completes without a digit
++ being pressed, or the ASCII numerical value of the digit if one was pressed,
++ or <literal>-1</literal> on error or if the channel was disconnected.</para>
++ </description>
++ </agi>
+ <agi name="database del" language="en_US">
+ <synopsis>
+ Removes database key/value
+@@ -288,6 +314,265 @@
+ <para>Does nothing.</para>
+ </description>
+ </agi>
++ <agi name="receive char" language="en_US">
++ <synopsis>
++ Receives one character from channels supporting it.
++ </synopsis>
++ <syntax>
++ <parameter name="timeout" required="true">
++ <para>The maximum time to wait for input in milliseconds, or <literal>0</literal>
++ for infinite. Most channels</para>
++ </parameter>
++ </syntax>
++ <description>
++ <para>Receives a character of text on a channel. Most channels do not support
++ the reception of text. Returns the decimal value of the character
++ if one is received, or <literal>0</literal> if the channel does not support
++ text reception. Returns <literal>-1</literal> only on error/hangup.</para>
++ </description>
++ </agi>
++ <agi name="receive text" language="en_US">
++ <synopsis>
++ Receives text from channels supporting it.
++ </synopsis>
++ <syntax>
++ <parameter name="timeout" required="true">
++ <para>The timeout to be the maximum time to wait for input in
++ milliseconds, or <literal>0</literal> for infinite.</para>
++ </parameter>
++ </syntax>
++ <description>
++ <para>Receives a string of text on a channel. Most channels
++ do not support the reception of text. Returns <literal>-1</literal> for failure
++ or <literal>1</literal> for success, and the string in parenthesis.</para>
++ </description>
++ </agi>
++ <agi name="record file" language="en_US">
++ <synopsis>
++ Records to a given file.
++ </synopsis>
++ <syntax>
++ <parameter name="filename" required="true" />
++ <parameter name="format" required="true" />
++ <parameter name="escape_digits" required="true" />
++ <parameter name="timeout" required="true" />
++ <parameter name="offset samples" />
++ <parameter name="BEEP" />
++ <parameter name="s=silence" />
++ </syntax>
++ <description>
++ <para>Record to a file until a given dtmf digit in the sequence is received.
++ Returns <literal>-1</literal> on hangup or error. The format will specify what kind of file
++ will be recorded. The <replaceable>timeout</replaceable> is the maximum record time in
++ milliseconds, or <literal>-1</literal> for no <replaceable>timeout</replaceable>.
++ <replaceable>offset samples</replaceable> is optional, and, if provided, will seek
++ to the offset without exceeding the end of the file. <replaceable>silence</replaceable> is
++ the number of seconds of silence allowed before the function returns despite the
++ lack of dtmf digits or reaching <replaceable>timeout</replaceable>. <replaceable>silence</replaceable>
++ value must be preceeded by <literal>s=</literal> and is also optional.</para>
++ </description>
++ </agi>
++ <agi name="say alpha" language="en_US">
++ <synopsis>
++ Says a given character string.
++ </synopsis>
++ <syntax>
++ <parameter name="number" required="true" />
++ <parameter name="escape_digits" required="true" />
++ </syntax>
++ <description>
++ <para>Say a given character string, returning early if any of the given DTMF digits
++ are received on the channel. Returns <literal>0</literal> if playback completes
++ without a digit being pressed, or the ASCII numerical value of the digit if one
++ was pressed or <literal>-1</literal> on error/hangup.</para>
++ </description>
++ </agi>
++ <agi name="say digits" language="en_US">
++ <synopsis>
++ Says a given digit string.
++ </synopsis>
++ <syntax>
++ <parameter name="number" required="true" />
++ <parameter name="escape_digits" required="true" />
++ </syntax>
++ <description>
++ <para>Say a given digit string, returning early if any of the given DTMF digits
++ are received on the channel. Returns <literal>0</literal> if playback completes
++ without a digit being pressed, or the ASCII numerical value of the digit if one
++ was pressed or <literal>-1</literal> on error/hangup.</para>
++ </description>
++ </agi>
++ <agi name="say number" language="en_US">
++ <synopsis>
++ Says a given number.
++ </synopsis>
++ <syntax>
++ <parameter name="number" required="true" />
++ <parameter name="escape_digits" required="true" />
++ <parameter name="gender" />
++ </syntax>
++ <description>
++ <para>Say a given number, returning early if any of the given DTMF digits
++ are received on the channel. Returns <literal>0</literal> if playback
++ completes without a digit being pressed, or the ASCII numerical value of
++ the digit if one was pressed or <literal>-1</literal> on error/hangup.</para>
++ </description>
++ </agi>
++ <agi name="say phonetic" language="en_US">
++ <synopsis>
++ Says a given character string with phonetics.
++ </synopsis>
++ <syntax>
++ <parameter name="string" required="true" />
++ <parameter name="escape_digits" required="true" />
++ </syntax>
++ <description>
++ <para>Say a given character string with phonetics, returning early if any of the
++ given DTMF digits are received on the channel. Returns <literal>0</literal> if
++ playback completes without a digit pressed, the ASCII numerical value of the digit
++ if one was pressed, or <literal>-1</literal> on error/hangup.</para>
++ </description>
++ </agi>
++ <agi name="say date" language="en_US">
++ <synopsis>
++ Says a given date.
++ </synopsis>
++ <syntax>
++ <parameter name="date" required="true">
++ <para>Is number of seconds elapsed since 00:00:00 on January 1, 1970.
++ Coordinated Universal Time (UTC).</para>
++ </parameter>
++ <parameter name="escape_digits" required="true" />
++ </syntax>
++ <description>
++ <para>Say a given date, returning early if any of the given DTMF digits are
++ received on the channel. Returns <literal>0</literal> if playback
++ completes without a digit being pressed, or the ASCII numerical value of the
++ digit if one was pressed or <literal>-1</literal> on error/hangup.</para>
++ </description>
++ </agi>
++ <agi name="say time" language="en_US">
++ <synopsis>
++ Says a given time.
++ </synopsis>
++ <syntax>
++ <parameter name="time" required="true">
++ <para>Is number of seconds elapsed since 00:00:00 on January 1, 1970.
++ Coordinated Universal Time (UTC).</para>
++ </parameter>
++ <parameter name="escape_digits" required="true" />
++ </syntax>
++ <description>
++ <para>Say a given time, returning early if any of the given DTMF digits are
++ received on the channel. Returns <literal>0</literal> if playback completes
++ without a digit being pressed, or the ASCII numerical value of the digit if
++ one was pressed or <literal>-1</literal> on error/hangup.</para>
++ </description>
++ </agi>
++ <agi name="say datetime" language="en_US">
++ <synopsis>
++ Says a given time as specfied by the format given.
++ </synopsis>
++ <syntax>
++ <parameter name="time" required="true">
++ <para>Is number of seconds elapsed since 00:00:00
++ on January 1, 1970, Coordinated Universal Time (UTC)</para>
++ </parameter>
++ <parameter name="escape_digits" required="true" />
++ <parameter name="format">
++ <para>Is the format the time should be said in. See
++ <filename>voicemail.conf</filename> (defaults to <literal>ABdY
++ 'digits/at' IMp</literal>).</para>
++ </parameter>
++ <parameter name="timezone">
++ <para>Acceptable values can be found in <filename>/usr/share/zoneinfo</filename>
++ Defaults to machine default.</para>
++ </parameter>
++ </syntax>
++ <description>
++ <para>Say a given time, returning early if any of the given DTMF digits are
++ received on the channel. Returns <literal>0</literal> if playback
++ completes without a digit being pressed, or the ASCII numerical value of the
++ digit if one was pressed or <literal>-1</literal> on error/hangup.</para>
++ </description>
++ </agi>
++ <agi name="send image" language="en_US">
++ <synopsis>
++ Sends images to channels supporting it.
++ </synopsis>
++ <syntax>
++ <parameter name="image" required="true" />
++ </syntax>
++ <description>
++ <para>Sends the given image on a channel. Most channels do not support the
++ transmission of images. Returns <literal>0</literal> if image is sent, or if
++ the channel does not support image transmission. Returns <literal>-1</literal>
++ only on error/hangup. Image names should not include extensions.</para>
++ </description>
++ </agi>
++ <agi name="send text" language="en_US">
++ <synopsis>
++ Sends text to channels supporting it.
++ </synopsis>
++ <syntax>
++ <parameter name="text to send" required="true">
++ <para>Text consisting of greater than one word should be placed
++ in quotes since the command only accepts a single argument.</para>
++ </parameter>
++ </syntax>
++ <description>
++ <para>Sends the given text on a channel. Most channels do not support the
++ transmission of text. Returns <literal>0</literal> if text is sent, or if the
++ channel does not support text transmission. Returns <literal>-1</literal> only
++ on error/hangup.</para>
++ </description>
++ </agi>
++ <agi name="set autohangup" language="en_US">
++ <synopsis>
++ Autohangup channel in some time.
++ </synopsis>
++ <syntax>
++ <parameter name="time" required="true" />
++ </syntax>
++ <description>
++ <para>Cause the channel to automatically hangup at <replaceable>time</replaceable>
++ seconds in the future. Of course it can be hungup before then as well. Setting to
++ <literal>0</literal> will cause the autohangup feature to be disabled on this channel.</para>
++ </description>
++ </agi>
++ <agi name="set callerid" language="en_US">
++ <synopsis>
++ Sets callerid for the current channel.
++ </synopsis>
++ <syntax>
++ <parameter name="number" required="true" />
++ </syntax>
++ <description>
++ <para>Changes the callerid of the current channel.</para>
++ </description>
++ </agi>
++ <agi name="set context" language="en_US">
++ <synopsis>
++ Sets channel context.
++ </synopsis>
++ <syntax>
++ <parameter name="desired context" required="true" />
++ </syntax>
++ <description>
++ <para>Sets the context for continuation upon exiting the application.</para>
++ </description>
++ </agi>
++ <agi name="set extension" language="en_US">
++ <synopsis>
++ Changes channel extension.
++ </synopsis>
++ <syntax>
++ <parameter name="new extension" required="true" />
++ </syntax>
++ <description>
++ <para>Changes the extension for continuation upon exiting the application.</para>
++ </description>
++ </agi>
+ <agi name="set music" language="en_US">
+ <synopsis>
+ Enable/Disable Music on hold generator
+@@ -312,6 +597,300 @@
+ <para>Always returns <literal>0</literal>.</para>
+ </description>
+ </agi>
++ <agi name="set priority" language="en_US">
++ <synopsis>
++ Set channel dialplan priority.
++ </synopsis>
++ <syntax>
++ <parameter name="priority" required="true" />
++ </syntax>
++ <description>
++ <para>Changes the priority for continuation upon exiting the application.
++ The priority must be a valid priority or label.</para>
++ </description>
++ </agi>
++ <agi name="set variable" language="en_US">
++ <synopsis>
++ Sets a channel variable.
++ </synopsis>
++ <syntax>
++ <parameter name="variablename" required="true" />
++ <parameter name="value" required="true" />
++ </syntax>
++ <description>
++ <para>Sets a variable to the current channel.</para>
++ </description>
++ </agi>
++ <agi name="stream file" language="en_US">
++ <synopsis>
++ Sends audio file on channel.
++ </synopsis>
++ <syntax>
++ <parameter name="filename" required="true">
++ <para>File name to play. The file extension must not be
++ included in the <replaceable>filename</replaceable>.</para>
++ </parameter>
++ <parameter name="escape_digits" required="true">
++ <para>Use double quotes for the digits if you wish none to be
++ permitted.</para>
++ </parameter>
++ <parameter name="sample offset">
++ <para>If sample offset is provided then the audio will seek to sample
++ offset before play starts.</para>
++ </parameter>
++ </syntax>
++ <description>
++ <para>Send the given file, allowing playback to be interrupted by the given
++ digits, if any. Returns <literal>0</literal> if playback completes without a digit
++ being pressed, or the ASCII numerical value of the digit if one was pressed,
++ or <literal>-1</literal> on error or if the channel was disconnected.</para>
++ </description>
++ <see-also>
++ <ref type="agi">control stream file</ref>
++ </see-also>
++ </agi>
++ <agi name="tdd mode" language="en_US">
++ <synopsis>
++ Toggles TDD mode (for the deaf).
++ </synopsis>
++ <syntax>
++ <parameter name="boolean" required="true">
++ <enumlist>
++ <enum name="on" />
++ <enum name="off" />
++ </enumlist>
++ </parameter>
++ </syntax>
++ <description>
++ <para>Enable/Disable TDD transmission/reception on a channel. Returns <literal>1</literal> if
++ successful, or <literal>0</literal> if channel is not TDD-capable.</para>
++ </description>
++ </agi>
++ <agi name="verbose" language="en_US">
++ <synopsis>
++ Logs a message to the asterisk verbose log.
++ </synopsis>
++ <syntax>
++ <parameter name="message" required="true" />
++ <parameter name="level" required="true" />
++ </syntax>
++ <description>
++ <para>Sends <replaceable>message</replaceable> to the console via verbose
++ message system. <replaceable>level</replaceable> is the the verbose level (1-4).
++ Always returns <literal>1</literal></para>
++ </description>
++ </agi>
++ <agi name="wait for digit" language="en_US">
++ <synopsis>
++ Waits for a digit to be pressed.
++ </synopsis>
++ <syntax>
++ <parameter name="timeout" required="true" />
++ </syntax>
++ <description>
++ <para>Waits up to <replaceable>timeout</replaceable> milliseconds for channel to
++ receive a DTMF digit. Returns <literal>-1</literal> on channel failure, <literal>0</literal>
++ if no digit is received in the timeout, or the numerical value of the ascii of the digit if
++ one is received. Use <literal>-1</literal> for the <replaceable>timeout</replaceable> value if
++ you desire the call to block indefinitely.</para>
++ </description>
++ </agi>
++ <agi name="speech create" language="en_US">
++ <synopsis>
++ Creates a speech object.
++ </synopsis>
++ <syntax>
++ <parameter name="engine" required="true" />
++ </syntax>
++ <description>
++ <para>Create a speech object to be used by the other Speech AGI commands.</para>
++ </description>
++ </agi>
++ <agi name="speech set" language="en_US">
++ <synopsis>
++ Sets a speech engine setting.
++ </synopsis>
++ <syntax>
++ <parameter name="name" required="true" />
++ <parameter name="value" required="true" />
++ </syntax>
++ <description>
++ <para>Set an engine-specific setting.</para>
++ </description>
++ </agi>
++ <agi name="speech destroy" language="en_US">
++ <synopsis>
++ Destroys a speech object.
++ </synopsis>
++ <syntax>
++ </syntax>
++ <description>
++ <para>Destroy the speech object created by <literal>SPEECH CREATE</literal>.</para>
++ </description>
++ <see-also>
++ <ref type="agi">speech create</ref>
++ </see-also>
++ </agi>
++ <agi name="speech load grammar" language="en_US">
++ <synopsis>
++ Loads a grammar.
++ </synopsis>
++ <syntax>
++ <parameter name="grammar name" required="true" />
++ <parameter name="path to grammar" required="true" />
++ </syntax>
++ <description>
++ <para>Loads the specified grammar as the specified name.</para>
++ </description>
++ </agi>
++ <agi name="speech unload grammar" language="en_US">
++ <synopsis>
++ Unloads a grammar.
++ </synopsis>
++ <syntax>
++ <parameter name="grammar name" required="true" />
++ </syntax>
++ <description>
++ <para>Unloads the specified grammar.</para>
++ </description>
++ </agi>
++ <agi name="speech activate grammar" language="en_US">
++ <synopsis>
++ Activates a grammar.
++ </synopsis>
++ <syntax>
++ <parameter name="grammar name" required="true" />
++ </syntax>
++ <description>
++ <para>Activates the specified grammar on the speech object.</para>
++ </description>
++ </agi>
++ <agi name="speech deactivate grammar" language="en_US">
++ <synopsis>
++ Deactivates a grammar.
++ </synopsis>
++ <syntax>
++ <parameter name="grammar name" required="true" />
++ </syntax>
++ <description>
++ <para>Deactivates the specified grammar on the speech object.</para>
++ </description>
++ </agi>
++ <agi name="speech recognize" language="en_US">
++ <synopsis>
++ Recognizes speech.
++ </synopsis>
++ <syntax>
++ <parameter name="prompt" required="true" />
++ <parameter name="timeout" required="true" />
++ <parameter name="offset" />
++ </syntax>
++ <description>
++ <para>Plays back given <replaceable>prompt</replaceable> while listening for
++ speech and dtmf.</para>
++ </description>
++ </agi>
++ <application name="AGI" language="en_US">
++ <synopsis>
++ Executes an AGI compliant application.
++ </synopsis>
++ <syntax>
++ <parameter name="command" required="true" />
++ <parameter name="args">
++ <argument name="arg1" required="true" />
++ <argument name="arg2" multiple="yes" />
++ </parameter>
++ </syntax>
++ <description>
++ <para>Executes an Asterisk Gateway Interface compliant
++ program on a channel. AGI allows Asterisk to launch external programs written
++ in any language to control a telephony channel, play audio, read DTMF digits,
++ etc. by communicating with the AGI protocol on <emphasis>stdin</emphasis> and
++ <emphasis>stdout</emphasis>. As of <literal>1.6.0</literal>, this channel will
++ not stop dialplan execution on hangup inside of this application. Dialplan
++ execution will continue normally, even upon hangup until the AGI application
++ signals a desire to stop (either by exiting or, in the case of a net script, by
++ closing the connection). A locally executed AGI script will receive SIGHUP on
++ hangup from the channel except when using DeadAGI. A fast AGI server will
++ correspondingly receive a HANGUP in OOB data. Both of these signals may be disabled
++ by setting the <variable>AGISIGHUP</variable> channel variable to <literal>no</literal>
++ before executing the AGI application.</para>
++ <para>Use the CLI command <literal>agi show commnands</literal> to list available agi
++ commands.</para>
++ <para>This application sets the following channel variable upon completion:</para>
++ <variablelist>
++ <variable name="AGISTATUS">
++ <para>The status of the attempt to the run the AGI script
++ text string, one of:</para>
++ <value name="SUCCESS" />
++ <value name="FAILURE" />
++ <value name="NOTFOUND" />
++ <value name="HANGUP" />
++ </variable>
++ </variablelist>
++ </description>
++ <see-also>
++ <ref type="application">EAGI</ref>
++ <ref type="application">DeadAGI</ref>
++ </see-also>
++ </application>
++ <application name="EAGI" language="en_US">
++ <synopsis>
++ Executes an EAGI compliant application.
++ </synopsis>
++ <syntax>
++ <xi:include xpointer="xpointer(/docs/application[@name='AGI']/syntax/parameter[@name='command'])" />
++ <xi:include xpointer="xpointer(/docs/application[@name='AGI']/syntax/parameter[@name='args'])" />
++ </syntax>
++ <description>
++ <para>Using 'EAGI' provides enhanced AGI, with incoming audio available out of band
++ on file descriptor 3.</para>
++ <xi:include xpointer="xpointer(/docs/application[@name='AGI']/description/para)" />
++ <xi:include xpointer="xpointer(/docs/application[@name='AGI']/description/variablelist)" />
++ </description>
++ <see-also>
++ <ref type="application">AGI</ref>
++ <ref type="application">DeadAGI</ref>
++ </see-also>
++ </application>
++ <application name="DeadAGI" language="en_US">
++ <synopsis>
++ Executes AGI on a hungup channel.
++ </synopsis>
++ <syntax>
++ <xi:include xpointer="xpointer(/docs/application[@name='AGI']/syntax/parameter[@name='command'])" />
++ <xi:include xpointer="xpointer(/docs/application[@name='AGI']/syntax/parameter[@name='args'])" />
++ </syntax>
++ <description>
++ <xi:include xpointer="xpointer(/docs/application[@name='AGI']/description/para)" />
++ <xi:include xpointer="xpointer(/docs/application[@name='AGI']/description/variablelist)" />
++ </description>
++ <see-also>
++ <ref type="application">AGI</ref>
++ <ref type="application">EAGI</ref>
++ </see-also>
++ </application>
++ <manager name="AGI" language="en_US">
++ <synopsis>
++ Add an AGI command to execute by Async AGI.
++ </synopsis>
++ <syntax>
++ <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
++ <parameter name="Channel" required="true">
++ <para>Channel that is currently in Async AGI.</para>
++ </parameter>
++ <parameter name="Command" required="true">
++ <para>Application to execute.</para>
++ </parameter>
++ <parameter name="CommandID">
++ <para>This will be sent back in CommandID header of AsyncAGI exec
++ event notification.</para>
++ </parameter>
++ </syntax>
++ <description>
++ <para>Add an AGI command to the execute queue of the channel in Async AGI.</para>
++ </description>
++ </manager>
+ ***/
+
+ #define MAX_ARGS 128
+@@ -325,30 +904,6 @@
+
+ static char *deadapp = "DeadAGI";
+
+-static char *synopsis = "Executes an AGI compliant application";
+-static char *esynopsis = "Executes an EAGI compliant application";
+-static char *deadsynopsis = "Executes AGI on a hungup channel";
+-
+-static char *descrip =
+-" [E|Dead]AGI(command,args): Executes an Asterisk Gateway Interface compliant\n"
+-"program on a channel. AGI allows Asterisk to launch external programs written\n"
+-"in any language to control a telephony channel, play audio, read DTMF digits,\n"
+-"etc. by communicating with the AGI protocol on stdin and stdout.\n"
+-" As of 1.6.0, this channel will not stop dialplan execution on hangup inside\n"
+-"of this application. Dialplan execution will continue normally, even upon\n"
+-"hangup until the AGI application signals a desire to stop (either by exiting\n"
+-"or, in the case of a net script, by closing the connection).\n"
+-" A locally executed AGI script will receive SIGHUP on hangup from the channel\n"
+-"except when using DeadAGI. A fast AGI server will correspondingly receive a\n"
+-"HANGUP in OOB data. Both of these signals may be disabled by setting the\n"
+-"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 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";
+-
+ static int agidebug = 0;
+
+ #define TONE_BLOCK_SIZE 200
+@@ -367,12 +922,12 @@
+ AGI_RESULT_HANGUP,
+ };
+
+-static agi_command *find_command(char *cmds[], int exact);
++static agi_command *find_command(const char * const cmds[], int exact);
+
+ AST_THREADSTORAGE(agi_buf);
+ #define AGI_BUF_INITSIZE 256
+
+-int ast_agi_send(int fd, struct ast_channel *chan, char *fmt, ...)
++int AST_OPTIONAL_API_NAME(ast_agi_send)(int fd, struct ast_channel *chan, char *fmt, ...)
+ {
+ int res = 0;
+ va_list ap;
+@@ -435,14 +990,6 @@
+ .destroy = agi_destroy_commands_cb
+ };
+
+-static const char mandescr_asyncagi[] =
+-"Description: Add an AGI command to the execute queue of the channel in Async AGI\n"
+-"Variables:\n"
+-" *Channel: Channel that is currently in Async AGI\n"
+-" *Command: Application to execute\n"
+-" CommandID: comand id. This will be sent back in CommandID header of AsyncAGI exec event notification\n"
+-"\n";
+-
+ static struct agi_cmd *get_agi_cmd(struct ast_channel *chan)
+ {
+ struct ast_datastore *store;
+@@ -556,20 +1103,27 @@
+ return NULL;
+ }
+
+- if (a->argc < 4)
++ if (a->argc < 4) {
+ return CLI_SHOWUSAGE;
+- chan = ast_get_channel_by_name_locked(a->argv[2]);
+- if (!chan) {
++ }
++
++ if (!(chan = ast_channel_get_by_name(a->argv[2]))) {
+ ast_log(LOG_WARNING, "Channel %s does not exists or cannot lock it\n", a->argv[2]);
+ return CLI_FAILURE;
+ }
++
+ if (add_agi_cmd(chan, a->argv[3], (a->argc > 4 ? a->argv[4] : ""))) {
+ ast_log(LOG_WARNING, "failed to add AGI command to queue of channel %s\n", chan->name);
+ ast_channel_unlock(chan);
++ chan = ast_channel_unref(chan);
+ return CLI_FAILURE;
+ }
++
+ ast_log(LOG_DEBUG, "Added AGI command to channel %s queue\n", chan->name);
++
+ ast_channel_unlock(chan);
++ chan = ast_channel_unref(chan);
++
+ return CLI_SUCCESS;
+ }
+
+@@ -591,24 +1145,33 @@
+ const char *cmdid = astman_get_header(m, "CommandID");
+ struct ast_channel *chan;
+ char buf[256];
++
+ if (ast_strlen_zero(channel) || ast_strlen_zero(cmdbuff)) {
+ astman_send_error(s, m, "Both, Channel and Command are *required*");
+ return 0;
+ }
+- chan = ast_get_channel_by_name_locked(channel);
+- if (!chan) {
++
++ if (!(chan = ast_channel_get_by_name(channel))) {
+ snprintf(buf, sizeof(buf), "Channel %s does not exists or cannot get its lock", channel);
+ astman_send_error(s, m, buf);
+ return 0;
+ }
++
++ ast_channel_lock(chan);
++
+ if (add_agi_cmd(chan, cmdbuff, cmdid)) {
+ snprintf(buf, sizeof(buf), "Failed to add AGI command to channel %s queue", chan->name);
+ astman_send_error(s, m, buf);
+ ast_channel_unlock(chan);
++ chan = ast_channel_unref(chan);
+ return 0;
+ }
++
++ ast_channel_unlock(chan);
++ chan = ast_channel_unref(chan);
++
+ astman_send_ack(s, m, "Added AGI command to queue");
+- ast_channel_unlock(chan);
++
+ return 0;
+ }
+
+@@ -1019,7 +1582,7 @@
+ ast_agi_send(fd, chan, "\n");
+ }
+
+-static int handle_answer(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
++static int handle_answer(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
+ {
+ int res = 0;
+
+@@ -1031,13 +1594,13 @@
+ return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
+ }
+
+-static int handle_asyncagi_break(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
++static int handle_asyncagi_break(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
+ {
+ ast_agi_send(agi->fd, chan, "200 result=0\n");
+ return RESULT_FAILURE;
+ }
+
+-static int handle_waitfordigit(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
++static int handle_waitfordigit(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
+ {
+ int res, to;
+
+@@ -1050,7 +1613,7 @@
+ return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
+ }
+
+-static int handle_sendtext(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
++static int handle_sendtext(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
+ {
+ int res;
+
+@@ -1069,7 +1632,7 @@
+ return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
+ }
+
+-static int handle_recvchar(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
++static int handle_recvchar(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
+ {
+ int res;
+
+@@ -1089,7 +1652,7 @@
+ return RESULT_FAILURE;
+ }
+
+-static int handle_recvtext(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
++static int handle_recvtext(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
+ {
+ char *buf;
+
+@@ -1106,7 +1669,7 @@
+ return RESULT_SUCCESS;
+ }
+
+-static int handle_tddmode(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
++static int handle_tddmode(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
+ {
+ int res, x;
+
+@@ -1133,7 +1696,7 @@
+ return RESULT_SUCCESS;
+ }
+
+-static int handle_sendimage(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
++static int handle_sendimage(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
+ {
+ int res;
+
+@@ -1149,10 +1712,10 @@
+ return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
+ }
+
+-static int handle_controlstreamfile(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
++static int handle_controlstreamfile(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
+ {
+ int res = 0, skipms = 3000;
+- char *fwd = "#", *rev = "*", *suspend = NULL, *stop = NULL; /* Default values */
++ const char *fwd = "#", *rev = "*", *suspend = NULL, *stop = NULL; /* Default values */
+
+ if (argc < 5 || argc > 9) {
+ return RESULT_SHOWUSAGE;
+@@ -1185,12 +1748,12 @@
+ return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
+ }
+
+-static int handle_streamfile(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
++static int handle_streamfile(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
+ {
+ int res, vres;
+ struct ast_filestream *fs, *vfs;
+ long sample_offset = 0, max_length;
+- char *edigits = "";
++ const char *edigits = "";
+
+ if (argc < 4 || argc > 5)
+ return RESULT_SHOWUSAGE;
+@@ -1235,13 +1798,13 @@
+ }
+
+ /*! \brief get option - really similar to the handle_streamfile, but with a timeout */
+-static int handle_getoption(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
++static int handle_getoption(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
+ {
+ int res, vres;
+ struct ast_filestream *fs, *vfs;
+ long sample_offset = 0, max_length;
+ int timeout = 0;
+- char *edigits = "";
++ const char *edigits = "";
+
+ if ( argc < 4 || argc > 5 )
+ return RESULT_SHOWUSAGE;
+@@ -1304,7 +1867,7 @@
+
+ /*! \brief Say number in various language syntaxes */
+ /* While waiting, we're sending a NULL. */
+-static int handle_saynumber(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
++static int handle_saynumber(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
+ {
+ int res, num;
+
+@@ -1319,7 +1882,7 @@
+ return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
+ }
+
+-static int handle_saydigits(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
++static int handle_saydigits(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
+ {
+ int res, num;
+
+@@ -1335,7 +1898,7 @@
+ return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
+ }
+
+-static int handle_sayalpha(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
++static int handle_sayalpha(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
+ {
+ int res;
+
+@@ -1349,7 +1912,7 @@
+ return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
+ }
+
+-static int handle_saydate(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
++static int handle_saydate(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
+ {
+ int res, num;
+
+@@ -1364,7 +1927,7 @@
+ return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
+ }
+
+-static int handle_saytime(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
++static int handle_saytime(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
+ {
+ int res, num;
+
+@@ -1379,11 +1942,11 @@
+ return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
+ }
+
+-static int handle_saydatetime(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
++static int handle_saydatetime(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
+ {
+ int res = 0;
+ time_t unixtime;
+- char *format, *zone = NULL;
++ const char *format, *zone = NULL;
+
+ if (argc < 4)
+ return RESULT_SHOWUSAGE;
+@@ -1413,7 +1976,7 @@
+ return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
+ }
+
+-static int handle_sayphonetic(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
++static int handle_sayphonetic(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
+ {
+ int res;
+
+@@ -1427,7 +1990,7 @@
+ return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
+ }
+
+-static int handle_getdata(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
++static int handle_getdata(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
+ {
+ int res, max, timeout;
+ char data[1024];
+@@ -1454,7 +2017,7 @@
+ return RESULT_SUCCESS;
+ }
+
+-static int handle_setcontext(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
++static int handle_setcontext(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
+ {
+
+ if (argc != 3)
+@@ -1464,7 +2027,7 @@
+ return RESULT_SUCCESS;
+ }
+
+-static int handle_setextension(struct ast_channel *chan, AGI *agi, int argc, char **argv)
++static int handle_setextension(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
+ {
+ if (argc != 3)
+ return RESULT_SHOWUSAGE;
+@@ -1473,7 +2036,7 @@
+ return RESULT_SUCCESS;
+ }
+
+-static int handle_setpriority(struct ast_channel *chan, AGI *agi, int argc, char **argv)
++static int handle_setpriority(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
+ {
+ int pri;
+
+@@ -1490,7 +2053,7 @@
+ return RESULT_SUCCESS;
+ }
+
+-static int handle_recordfile(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
++static int handle_recordfile(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
+ {
+ struct ast_filestream *fs;
+ struct ast_frame *f;
+@@ -1667,7 +2230,7 @@
+ return RESULT_SUCCESS;
+ }
+
+-static int handle_autohangup(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
++static int handle_autohangup(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
+ {
+ double timeout;
+ struct timeval whentohangup = { 0, 0 };
+@@ -1687,7 +2250,7 @@
+ return RESULT_SUCCESS;
+ }
+
+-static int handle_hangup(struct ast_channel *chan, AGI *agi, int argc, char **argv)
++static int handle_hangup(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
+ {
+ struct ast_channel *c;
+
+@@ -1698,12 +2261,11 @@
+ return RESULT_SUCCESS;
+ } else if (argc == 2) {
+ /* one argument: look for info on the specified channel */
+- c = ast_get_channel_by_name_locked(argv[1]);
+- if (c) {
++ if ((c = ast_channel_get_by_name(argv[1]))) {
+ /* we have a matching channel */
+- ast_softhangup(c,AST_SOFTHANGUP_EXPLICIT);
++ ast_softhangup(c, AST_SOFTHANGUP_EXPLICIT);
++ c = ast_channel_unref(c);
+ ast_agi_send(agi->fd, chan, "200 result=1\n");
+- ast_channel_unlock(c);
+ return RESULT_SUCCESS;
+ }
+ /* if we get this far no channel name matched the argument given */
+@@ -1714,7 +2276,7 @@
+ }
+ }
+
+-static int handle_exec(struct ast_channel *chan, AGI *agi, int argc, char **argv)
++static int handle_exec(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
+ {
+ int res;
+ struct ast_app *app_to_exec;
+@@ -1729,7 +2291,8 @@
+ ast_masq_park_call(chan, NULL, 0, NULL);
+ }
+ if (ast_compat_res_agi && !ast_strlen_zero(argv[2])) {
+- char *compat = alloca(strlen(argv[2]) * 2 + 1), *cptr, *vptr;
++ char *compat = alloca(strlen(argv[2]) * 2 + 1), *cptr;
++ const char *vptr;
+ for (cptr = compat, vptr = argv[2]; *vptr; vptr++) {
+ if (*vptr == ',') {
+ *cptr++ = '\\';
+@@ -1755,7 +2318,7 @@
+ return res;
+ }
+
+-static int handle_setcallerid(struct ast_channel *chan, AGI *agi, int argc, char **argv)
++static int handle_setcallerid(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
+ {
+ char tmp[256]="";
+ char *l = NULL, *n = NULL;
+@@ -1776,7 +2339,7 @@
+ return RESULT_SUCCESS;
+ }
+
+-static int handle_channelstatus(struct ast_channel *chan, AGI *agi, int argc, char **argv)
++static int handle_channelstatus(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
+ {
+ struct ast_channel *c;
+ if (argc == 2) {
+@@ -1785,10 +2348,9 @@
+ return RESULT_SUCCESS;
+ } else if (argc == 3) {
+ /* one argument: look for info on the specified channel */
+- c = ast_get_channel_by_name_locked(argv[2]);
+- if (c) {
++ if ((c = ast_channel_get_by_name(argv[2]))) {
+ ast_agi_send(agi->fd, chan, "200 result=%d\n", c->_state);
+- ast_channel_unlock(c);
++ c = ast_channel_unref(c);
+ return RESULT_SUCCESS;
+ }
+ /* if we get this far no channel name matched the argument given */
+@@ -1799,7 +2361,7 @@
+ }
+ }
+
+-static int handle_setvariable(struct ast_channel *chan, AGI *agi, int argc, char **argv)
++static int handle_setvariable(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
+ {
+ if (argv[3])
+ pbx_builtin_setvar_helper(chan, argv[2], argv[3]);
+@@ -1808,7 +2370,7 @@
+ return RESULT_SUCCESS;
+ }
+
+-static int handle_getvariable(struct ast_channel *chan, AGI *agi, int argc, char **argv)
++static int handle_getvariable(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
+ {
+ char *ret;
+ char tempstr[1024];
+@@ -1831,30 +2393,41 @@
+ return RESULT_SUCCESS;
+ }
+
+-static int handle_getvariablefull(struct ast_channel *chan, AGI *agi, int argc, char **argv)
++static int handle_getvariablefull(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
+ {
+- char tmp[4096];
+- struct ast_channel *chan2=NULL;
++ struct ast_channel *chan2 = NULL;
+
+- if ((argc != 4) && (argc != 5))
++ if (argc != 4 && argc != 5) {
+ return RESULT_SHOWUSAGE;
++ }
++
+ if (argc == 5) {
+- chan2 = ast_get_channel_by_name_locked(argv[4]);
++ chan2 = ast_channel_get_by_name(argv[4]);
+ } else {
+- chan2 = chan;
++ chan2 = ast_channel_ref(chan);
+ }
++
+ if (chan2) {
+- pbx_substitute_variables_helper(chan2, argv[3], tmp, sizeof(tmp) - 1);
+- ast_agi_send(agi->fd, chan, "200 result=1 (%s)\n", tmp);
++ struct ast_str *str = ast_str_create(16);
++ if (!str) {
++ ast_agi_send(agi->fd, chan, "200 result=0\n");
++ return RESULT_SUCCESS;
++ }
++ ast_str_substitute_variables(&str, 0, chan2, argv[3]);
++ ast_agi_send(agi->fd, chan, "200 result=1 (%s)\n", ast_str_buffer(str));
++ ast_free(str);
+ } else {
+ ast_agi_send(agi->fd, chan, "200 result=0\n");
+ }
+- if (chan2 && (chan2 != chan))
+- ast_channel_unlock(chan2);
++
++ if (chan2) {
++ chan2 = ast_channel_unref(chan2);
++ }
++
+ return RESULT_SUCCESS;
+ }
+
+-static int handle_verbose(struct ast_channel *chan, AGI *agi, int argc, char **argv)
++static int handle_verbose(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
+ {
+ int level = 0;
+
+@@ -1871,7 +2444,7 @@
+ return RESULT_SUCCESS;
+ }
+
+-static int handle_dbget(struct ast_channel *chan, AGI *agi, int argc, char **argv)
++static int handle_dbget(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
+ {
+ int res;
+ struct ast_str *buf;
+@@ -1904,7 +2477,7 @@
+ return RESULT_SUCCESS;
+ }
+
+-static int handle_dbput(struct ast_channel *chan, AGI *agi, int argc, char **argv)
++static int handle_dbput(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
+ {
+ int res;
+
+@@ -1915,7 +2488,7 @@
+ return RESULT_SUCCESS;
+ }
+
+-static int handle_dbdel(struct ast_channel *chan, AGI *agi, int argc, char **argv)
++static int handle_dbdel(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
+ {
+ int res;
+
+@@ -1926,7 +2499,7 @@
+ return RESULT_SUCCESS;
+ }
+
+-static int handle_dbdeltree(struct ast_channel *chan, AGI *agi, int argc, char **argv)
++static int handle_dbdeltree(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
+ {
+ int res;
+
+@@ -1970,13 +2543,13 @@
+ return CLI_SUCCESS;
+ }
+
+-static int handle_noop(struct ast_channel *chan, AGI *agi, int arg, char *argv[])
++static int handle_noop(struct ast_channel *chan, AGI *agi, int arg, const char * const argv[])
+ {
+ ast_agi_send(agi->fd, chan, "200 result=0\n");
+ return RESULT_SUCCESS;
+ }
+
+-static int handle_setmusic(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
++static int handle_setmusic(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
+ {
+ if (!strncasecmp(argv[2], "on", 2))
+ ast_moh_start(chan, argc > 3 ? argv[3] : NULL, NULL);
+@@ -1986,7 +2559,7 @@
+ return RESULT_SUCCESS;
+ }
+
+-static int handle_speechcreate(struct ast_channel *chan, AGI *agi, int argc, char **argv)
++static int handle_speechcreate(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
+ {
+ /* If a structure already exists, return an error */
+ if (agi->speech) {
+@@ -2002,7 +2575,7 @@
+ return RESULT_SUCCESS;
+ }
+
+-static int handle_speechset(struct ast_channel *chan, AGI *agi, int argc, char **argv)
++static int handle_speechset(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
+ {
+ /* Check for minimum arguments */
+ if (argc != 3)
+@@ -2020,7 +2593,7 @@
+ return RESULT_SUCCESS;
+ }
+
+-static int handle_speechdestroy(struct ast_channel *chan, AGI *agi, int argc, char **argv)
++static int handle_speechdestroy(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
+ {
+ if (agi->speech) {
+ ast_speech_destroy(agi->speech);
+@@ -2033,7 +2606,7 @@
+ return RESULT_SUCCESS;
+ }
+
+-static int handle_speechloadgrammar(struct ast_channel *chan, AGI *agi, int argc, char **argv)
++static int handle_speechloadgrammar(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
+ {
+ if (argc != 5)
+ return RESULT_SHOWUSAGE;
+@@ -2051,7 +2624,7 @@
+ return RESULT_SUCCESS;
+ }
+
+-static int handle_speechunloadgrammar(struct ast_channel *chan, AGI *agi, int argc, char **argv)
++static int handle_speechunloadgrammar(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
+ {
+ if (argc != 4)
+ return RESULT_SHOWUSAGE;
+@@ -2069,7 +2642,7 @@
+ return RESULT_SUCCESS;
+ }
+
+-static int handle_speechactivategrammar(struct ast_channel *chan, AGI *agi, int argc, char **argv)
++static int handle_speechactivategrammar(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
+ {
+ if (argc != 4)
+ return RESULT_SHOWUSAGE;
+@@ -2087,7 +2660,7 @@
+ return RESULT_SUCCESS;
+ }
+
+-static int handle_speechdeactivategrammar(struct ast_channel *chan, AGI *agi, int argc, char **argv)
++static int handle_speechdeactivategrammar(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
+ {
+ if (argc != 4)
+ return RESULT_SHOWUSAGE;
+@@ -2124,10 +2697,11 @@
+ return 0;
+ }
+
+-static int handle_speechrecognize(struct ast_channel *chan, AGI *agi, int argc, char **argv)
++static int handle_speechrecognize(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
+ {
+ struct ast_speech *speech = agi->speech;
+- char *prompt, dtmf = 0, tmp[4096] = "", *buf = tmp;
++ const char *prompt;
++ char dtmf = 0, tmp[4096] = "", *buf = tmp;
+ int timeout = 0, offset = 0, old_read_format = 0, res = 0, i = 0;
+ long current_offset = 0;
+ const char *reason = NULL;
+@@ -2271,198 +2845,6 @@
+ return RESULT_SUCCESS;
+ }
+
+-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_setvariable[] =
+-" Usage: SET VARIABLE <variablename> <value>\n";
+-
+-static char usage_setcallerid[] =
+-" Usage: SET CALLERID <number>\n"
+-" Changes the callerid of the current channel.\n";
+-
+-static char usage_waitfordigit[] =
+-" Usage: WAIT FOR DIGIT <timeout>\n"
+-" Waits up to 'timeout' milliseconds for channel to receive a DTMF digit.\n"
+-" Returns -1 on channel failure, 0 if no digit is received in the timeout, or\n"
+-" the numerical value of the ascii of the digit if one is received. Use -1\n"
+-" for the timeout value if you desire the call to block indefinitely.\n";
+-
+-static char usage_sendtext[] =
+-" Usage: SEND TEXT \"<text to send>\"\n"
+-" Sends the given text on a channel. Most channels do not support the\n"
+-" transmission of text. Returns 0 if text is sent, or if the channel does not\n"
+-" support text transmission. Returns -1 only on error/hangup. Text\n"
+-" consisting of greater than one word should be placed in quotes since the\n"
+-" command only accepts a single argument.\n";
+-
+-static char usage_recvchar[] =
+-" Usage: RECEIVE CHAR <timeout>\n"
+-" Receives a character of text on a channel. Specify timeout to be the\n"
+-" maximum time to wait for input in milliseconds, or 0 for infinite. Most channels\n"
+-" do not support the reception of text. Returns the decimal value of the character\n"
+-" if one is received, or 0 if the channel does not support text reception. Returns\n"
+-" -1 only on error/hangup.\n";
+-
+-static char usage_recvtext[] =
+-" Usage: RECEIVE TEXT <timeout>\n"
+-" Receives a string of text on a channel. Specify timeout to be the\n"
+-" maximum time to wait for input in milliseconds, or 0 for infinite. Most channels\n"
+-" do not support the reception of text. Returns -1 for failure or 1 for success, and the string in parentheses.\n";
+-
+-static char usage_tddmode[] =
+-" Usage: TDD MODE <on|off>\n"
+-" Enable/Disable TDD transmission/reception on a channel. Returns 1 if\n"
+-" successful, or 0 if channel is not TDD-capable.\n";
+-
+-static char usage_sendimage[] =
+-" Usage: SEND IMAGE <image>\n"
+-" Sends the given image on a channel. Most channels do not support the\n"
+-" transmission of images. Returns 0 if image is sent, or if the channel does not\n"
+-" support image transmission. Returns -1 only on error/hangup. Image names\n"
+-" should not include extensions.\n";
+-
+-static char usage_streamfile[] =
+-" Usage: STREAM FILE <filename> <escape digits> [sample offset]\n"
+-" Send the given file, allowing playback to be interrupted by the given\n"
+-" digits, if any. Use double quotes for the digits if you wish none to be\n"
+-" permitted. If sample offset is provided then the audio will seek to sample\n"
+-" offset before play starts. Returns 0 if playback completes without a digit\n"
+-" being pressed, or the ASCII numerical value of the digit if one was pressed,\n"
+-" or -1 on error or if the channel was disconnected. Remember, the file\n"
+-" extension must not be included in the filename.\n";
+-
+-static char usage_controlstreamfile[] =
+-" Usage: CONTROL STREAM FILE <filename> <escape digits> [skipms] [ffchar] [rewchr] [pausechr]\n"
+-" Send the given file, allowing playback to be controled by the given\n"
+-" digits, if any. Use double quotes for the digits if you wish none to be\n"
+-" permitted. Returns 0 if playback completes without a digit\n"
+-" being pressed, or the ASCII numerical value of the digit if one was pressed,\n"
+-" or -1 on error or if the channel was disconnected. Remember, the file\n"
+-" extension must not be included in the filename.\n\n"
+-" Note: ffchar and rewchar default to * and # respectively.\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"
+-" are received on the channel. Returns 0 if playback completes without a digit\n"
+-" being pressed, or the ASCII numerical value of the digit if one was pressed or\n"
+-" -1 on error/hangup.\n";
+-
+-static char usage_saydigits[] =
+-" Usage: SAY DIGITS <number> <escape digits>\n"
+-" Say a given digit string, returning early if any of the given DTMF digits\n"
+-" are received on the channel. Returns 0 if playback completes without a digit\n"
+-" being pressed, or the ASCII numerical value of the digit if one was pressed or\n"
+-" -1 on error/hangup.\n";
+-
+-static char usage_sayalpha[] =
+-" Usage: SAY ALPHA <number> <escape digits>\n"
+-" Say a given character string, returning early if any of the given DTMF digits\n"
+-" are received on the channel. Returns 0 if playback completes without a digit\n"
+-" being pressed, or the ASCII numerical value of the digit if one was pressed or\n"
+-" -1 on error/hangup.\n";
+-
+-static char usage_saydate[] =
+-" Usage: SAY DATE <date> <escape digits>\n"
+-" Say a given date, returning early if any of the given DTMF digits are\n"
+-" received on the channel. <date> is number of seconds elapsed since 00:00:00\n"
+-" on January 1, 1970, Coordinated Universal Time (UTC). Returns 0 if playback\n"
+-" completes without a digit being pressed, or the ASCII numerical value of the\n"
+-" digit if one was pressed or -1 on error/hangup.\n";
+-
+-static char usage_saytime[] =
+-" Usage: SAY TIME <time> <escape digits>\n"
+-" Say a given time, returning early if any of the given DTMF digits are\n"
+-" received on the channel. <time> is number of seconds elapsed since 00:00:00\n"
+-" on January 1, 1970, Coordinated Universal Time (UTC). Returns 0 if playback\n"
+-" completes without a digit being pressed, or the ASCII numerical value of the\n"
+-" digit if one was pressed or -1 on error/hangup.\n";
+-
+-static char usage_saydatetime[] =
+-" Usage: SAY DATETIME <time> <escape digits> [format] [timezone]\n"
+-" Say a given time, returning early if any of the given DTMF digits are\n"
+-" received on the channel. <time> is number of seconds elapsed since 00:00:00\n"
+-" on January 1, 1970, Coordinated Universal Time (UTC). [format] is the format\n"
+-" the time should be said in. See voicemail.conf (defaults to \"ABdY\n"
+-" 'digits/at' IMp\"). Acceptable values for [timezone] can be found in\n"
+-" /usr/share/zoneinfo. Defaults to machine default. Returns 0 if playback\n"
+-" completes without a digit being pressed, or the ASCII numerical value of the\n"
+-" digit if one was pressed or -1 on error/hangup.\n";
+-
+-static char usage_sayphonetic[] =
+-" Usage: SAY PHONETIC <string> <escape digits>\n"
+-" Say a given character string with phonetics, returning early if any of the\n"
+-" given DTMF digits are received on the channel. Returns 0 if playback\n"
+-" 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_setcontext[] =
+-" Usage: SET CONTEXT <desired context>\n"
+-" Sets the context for continuation upon exiting the application.\n";
+-
+-static char usage_setextension[] =
+-" Usage: SET EXTENSION <new extension>\n"
+-" Changes the extension for continuation upon exiting the application.\n";
+-
+-static char usage_setpriority[] =
+-" Usage: SET PRIORITY <priority>\n"
+-" Changes the priority for continuation upon exiting the application.\n"
+-" The priority must be a valid priority or label.\n";
+-
+-static char usage_recordfile[] =
+-" Usage: RECORD FILE <filename> <format> <escape digits> <timeout> \\\n"
+-" [offset samples] [BEEP] [s=silence]\n"
+-" Record to a file until a given dtmf digit in the sequence is received\n"
+-" Returns -1 on hangup or error. The format will specify what kind of file\n"
+-" will be recorded. The timeout is the maximum record time in milliseconds, or\n"
+-" -1 for no timeout. \"Offset samples\" is optional, and, if provided, will seek\n"
+-" to the offset without exceeding the end of the file. \"silence\" is the number\n"
+-" of seconds of silence allowed before the function returns despite the\n"
+-" lack of dtmf digits or reaching timeout. Silence value must be\n"
+-" preceeded by \"s=\" and is also optional.\n";
+-
+-static char usage_autohangup[] =
+-" Usage: SET AUTOHANGUP <time>\n"
+-" Cause the channel to automatically hangup at <time> seconds in the\n"
+-" 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_speechcreate[] =
+-" Usage: SPEECH CREATE <engine>\n"
+-" Create a speech object to be used by the other Speech AGI commands.\n";
+-
+-static char usage_speechset[] =
+-" Usage: SPEECH SET <name> <value>\n"
+-" Set an engine-specific setting.\n";
+-
+-static char usage_speechdestroy[] =
+-" Usage: SPEECH DESTROY\n"
+-" Destroy the speech object created by SPEECH CREATE.\n";
+-
+-static char usage_speechloadgrammar[] =
+-" Usage: SPEECH LOAD GRAMMAR <grammar name> <path to grammar>\n"
+-" Loads the specified grammar as the specified name.\n";
+-
+-static char usage_speechunloadgrammar[] =
+-" Usage: SPEECH UNLOAD GRAMMAR <grammar name>\n"
+-" Unloads the specified grammar.\n";
+-
+-static char usage_speechactivategrammar[] =
+-" Usage: SPEECH ACTIVATE GRAMMAR <grammar name>\n"
+-" Activates the specified grammar on the speech object.\n";
+-
+-static char usage_speechdeactivategrammar[] =
+-" Usage: SPEECH DEACTIVATE GRAMMAR <grammar name>\n"
+-" Deactivates the specified grammar on the speech object.\n";
+-
+-static char usage_speechrecognize[] =
+-" Usage: SPEECH RECOGNIZE <prompt> <timeout> [<offset>]\n"
+-" Plays back given prompt while listening for speech and dtmf.\n";
+-
+ /*!
+ * \brief AGI commands list
+ */
+@@ -2481,43 +2863,43 @@
+ { { "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 },
+- { { "say", "alpha", NULL }, handle_sayalpha, "Says a given character string", usage_sayalpha , 0 },
+- { { "say", "digits", NULL }, handle_saydigits, "Says a given digit string", usage_saydigits , 0 },
+- { { "say", "number", NULL }, handle_saynumber, "Says a given number", usage_saynumber , 0 },
+- { { "say", "phonetic", NULL }, handle_sayphonetic, "Says a given character string with phonetics", usage_sayphonetic , 0 },
+- { { "say", "date", NULL }, handle_saydate, "Says a given date", usage_saydate , 0 },
+- { { "say", "time", NULL }, handle_saytime, "Says a given time", usage_saytime , 0 },
+- { { "say", "datetime", NULL }, handle_saydatetime, "Says a given time as specfied by the format given", usage_saydatetime , 0 },
+- { { "send", "image", NULL }, handle_sendimage, "Sends images to channels supporting it", usage_sendimage , 0 },
+- { { "send", "text", NULL }, handle_sendtext, "Sends text to channels supporting it", usage_sendtext , 0 },
+- { { "set", "autohangup", NULL }, handle_autohangup, "Autohangup channel in some time", usage_autohangup , 0 },
+- { { "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 },
++ { { "receive", "char", NULL }, handle_recvchar, NULL, NULL, 0 },
++ { { "receive", "text", NULL }, handle_recvtext, NULL, NULL, 0 },
++ { { "record", "file", NULL }, handle_recordfile, NULL, NULL, 0 },
++ { { "say", "alpha", NULL }, handle_sayalpha, NULL, NULL, 0},
++ { { "say", "digits", NULL }, handle_saydigits, NULL, NULL, 0 },
++ { { "say", "number", NULL }, handle_saynumber, NULL, NULL, 0 },
++ { { "say", "phonetic", NULL }, handle_sayphonetic, NULL, NULL, 0},
++ { { "say", "date", NULL }, handle_saydate, NULL, NULL, 0},
++ { { "say", "time", NULL }, handle_saytime, NULL, NULL, 0},
++ { { "say", "datetime", NULL }, handle_saydatetime, NULL, NULL, 0},
++ { { "send", "image", NULL }, handle_sendimage, NULL, NULL, 0},
++ { { "send", "text", NULL }, handle_sendtext, NULL, NULL, 0},
++ { { "set", "autohangup", NULL }, handle_autohangup, NULL, NULL, 0},
++ { { "set", "callerid", NULL }, handle_setcallerid, NULL, NULL, 0},
++ { { "set", "context", NULL }, handle_setcontext, NULL, NULL, 0},
++ { { "set", "extension", NULL }, handle_setextension, NULL, NULL, 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 },
+- { { "control", "stream", "file", NULL }, handle_controlstreamfile, "Sends audio file on channel and allows the listner to control the stream", usage_controlstreamfile , 0 },
+- { { "tdd", "mode", NULL }, handle_tddmode, "Toggles TDD mode (for the deaf)", usage_tddmode , 0 },
+- { { "verbose", NULL }, handle_verbose, "Logs a message to the asterisk verbose log", usage_verbose , 1 },
+- { { "wait", "for", "digit", NULL }, handle_waitfordigit, "Waits for a digit to be pressed", usage_waitfordigit , 0 },
+- { { "speech", "create", NULL }, handle_speechcreate, "Creates a speech object", usage_speechcreate, 0 },
+- { { "speech", "set", NULL }, handle_speechset, "Sets a speech engine setting", usage_speechset, 0 },
+- { { "speech", "destroy", NULL }, handle_speechdestroy, "Destroys a speech object", usage_speechdestroy, 1 },
+- { { "speech", "load", "grammar", NULL }, handle_speechloadgrammar, "Loads a grammar", usage_speechloadgrammar, 0 },
+- { { "speech", "unload", "grammar", NULL }, handle_speechunloadgrammar, "Unloads a grammar", usage_speechunloadgrammar, 1 },
+- { { "speech", "activate", "grammar", NULL }, handle_speechactivategrammar, "Activates a grammar", usage_speechactivategrammar, 0 },
+- { { "speech", "deactivate", "grammar", NULL }, handle_speechdeactivategrammar, "Deactivates a grammar", usage_speechdeactivategrammar, 0 },
+- { { "speech", "recognize", NULL }, handle_speechrecognize, "Recognizes speech", usage_speechrecognize, 0 },
++ { { "set", "priority", NULL }, handle_setpriority, NULL, NULL, 0 },
++ { { "set", "variable", NULL }, handle_setvariable, NULL, NULL, 1 },
++ { { "stream", "file", NULL }, handle_streamfile, NULL, NULL, 0 },
++ { { "control", "stream", "file", NULL }, handle_controlstreamfile, NULL, NULL, 0 },
++ { { "tdd", "mode", NULL }, handle_tddmode, NULL, NULL, 0 },
++ { { "verbose", NULL }, handle_verbose, NULL, NULL, 1 },
++ { { "wait", "for", "digit", NULL }, handle_waitfordigit, NULL, NULL, 0 },
++ { { "speech", "create", NULL }, handle_speechcreate, NULL, NULL, 0 },
++ { { "speech", "set", NULL }, handle_speechset, NULL, NULL, 0 },
++ { { "speech", "destroy", NULL }, handle_speechdestroy, NULL, NULL, 1 },
++ { { "speech", "load", "grammar", NULL }, handle_speechloadgrammar, NULL, NULL, 0 },
++ { { "speech", "unload", "grammar", NULL }, handle_speechunloadgrammar, NULL, NULL, 1 },
++ { { "speech", "activate", "grammar", NULL }, handle_speechactivategrammar, NULL, NULL, 0 },
++ { { "speech", "deactivate", "grammar", NULL }, handle_speechdeactivategrammar, NULL, NULL, 0 },
++ { { "speech", "recognize", NULL }, handle_speechrecognize, NULL, NULL, 0 },
+ };
+
+ static AST_RWLIST_HEAD_STATIC(agi_commands, agi_command);
+
+-static char *help_workhorse(int fd, char *match[])
++static char *help_workhorse(int fd, const char * const match[])
+ {
+ char fullcmd[MAX_CMD_LEN], matchstr[MAX_CMD_LEN];
+ struct agi_command *e;
+@@ -2543,21 +2925,21 @@
+ return CLI_SUCCESS;
+ }
+
+-int ast_agi_register(struct ast_module *mod, agi_command *cmd)
++int AST_OPTIONAL_API_NAME(ast_agi_register)(struct ast_module *mod, agi_command *cmd)
+ {
+ char fullcmd[MAX_CMD_LEN];
+
+ ast_join(fullcmd, sizeof(fullcmd), cmd->cmda);
+
+- if (!find_command(cmd->cmda,1)) {
+- cmd->docsrc = AST_STATIC_DOC;
++ if (!find_command(cmd->cmda, 1)) {
+ #ifdef AST_XML_DOCS
++ *((enum ast_doc_src *) &cmd->docsrc) = AST_STATIC_DOC;
+ 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;
++ *((char **) &cmd->summary) = ast_xmldoc_build_synopsis("agi", fullcmd);
++ *((char **) &cmd->usage) = ast_xmldoc_build_description("agi", fullcmd);
++ *((char **) &cmd->syntax) = ast_xmldoc_build_syntax("agi", fullcmd);
++ *((char **) &cmd->seealso) = ast_xmldoc_build_seealso("agi", fullcmd);
++ *((enum ast_doc_src *) &cmd->docsrc) = AST_XML_DOC;
+ }
+ #endif
+ cmd->mod = mod;
+@@ -2574,7 +2956,7 @@
+ }
+ }
+
+-int ast_agi_unregister(struct ast_module *mod, agi_command *cmd)
++int AST_OPTIONAL_API_NAME(ast_agi_unregister)(struct ast_module *mod, agi_command *cmd)
+ {
+ struct agi_command *e;
+ int unregistered = 0;
+@@ -2590,12 +2972,14 @@
+ 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;
++ ast_free((char *) e->summary);
++ ast_free((char *) e->usage);
++ ast_free((char *) e->syntax);
++ ast_free((char *) e->seealso);
++ *((char **) &e->summary) = NULL;
++ *((char **) &e->usage) = NULL;
++ *((char **) &e->syntax) = NULL;
++ *((char **) &e->seealso) = NULL;
+ }
+ #endif
+ unregistered=1;
+@@ -2611,7 +2995,7 @@
+ return unregistered;
+ }
+
+-int ast_agi_register_multiple(struct ast_module *mod, struct agi_command *cmd, unsigned int len)
++int AST_OPTIONAL_API_NAME(ast_agi_register_multiple)(struct ast_module *mod, struct agi_command *cmd, unsigned int len)
+ {
+ unsigned int i, x = 0;
+
+@@ -2641,7 +3025,7 @@
+ return 0;
+ }
+
+-int ast_agi_unregister_multiple(struct ast_module *mod, struct agi_command *cmd, unsigned int len)
++int AST_OPTIONAL_API_NAME(ast_agi_unregister_multiple)(struct ast_module *mod, struct agi_command *cmd, unsigned int len)
+ {
+ unsigned int i;
+ int res = 0;
+@@ -2657,7 +3041,7 @@
+ return res;
+ }
+
+-static agi_command *find_command(char *cmds[], int exact)
++static agi_command *find_command(const char * const cmds[], int exact)
+ {
+ int y, match;
+ struct agi_command *e;
+@@ -2695,7 +3079,7 @@
+ return NULL;
+ }
+
+-static int parse_args(char *s, int *max, char *argv[])
++static int parse_args(char *s, int *max, const char *argv[])
+ {
+ int x = 0, quoted = 0, escaped = 0, whitespace = 1;
+ char *cur;
+@@ -2760,7 +3144,7 @@
+
+ static int agi_handle_command(struct ast_channel *chan, AGI *agi, char *buf, int dead)
+ {
+- char *argv[MAX_ARGS];
++ const char *argv[MAX_ARGS];
+ int argc = MAX_ARGS, res;
+ agi_command *c;
+ const char *ami_res = "Unknown Result";
+@@ -3107,7 +3491,7 @@
+ return;
+ }
+
+-static int write_htmldump(char *filename)
++static int write_htmldump(const char *filename)
+ {
+ struct agi_command *command;
+ char fullcmd[MAX_CMD_LEN];
+@@ -3138,9 +3522,9 @@
+ 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;
++ stringp = ast_strdup(stringptmp);
+ #else
+- stringp = command->usage;
++ stringp = ast_strdup(command->usage);
+ #endif
+ tempstr = strsep(&stringp, "\n");
+
+@@ -3155,6 +3539,7 @@
+ }
+ fprintf(htmlfile, "</TD></TR>\n");
+ fprintf(htmlfile, "</TABLE></TD></TR>\n\n");
++ ast_free(stringp);
+ #ifdef AST_XML_DOCS
+ ast_free(stringptmp);
+ #endif
+@@ -3189,10 +3574,10 @@
+ return CLI_SUCCESS;
+ }
+
+-static int agi_exec_full(struct ast_channel *chan, void *data, int enhanced, int dead)
++static int agi_exec_full(struct ast_channel *chan, const char *data, int enhanced, int dead)
+ {
+ enum agi_result res;
+- char buf[AGI_BUF_LEN] = "", *tmp = buf;
++ char *buf;
+ int fds[2], efd = -1, pid;
+ AST_DECLARE_APP_ARGS(args,
+ AST_APP_ARG(arg)[MAX_ARGS];
+@@ -3205,9 +3590,9 @@
+ }
+ if (dead)
+ ast_debug(3, "Hungup channel detected, running agi in dead mode.\n");
+- ast_copy_string(buf, data, sizeof(buf));
+ memset(&agi, 0, sizeof(agi));
+- AST_STANDARD_APP_ARGS(args, tmp);
++ buf = ast_strdupa(data);
++ AST_STANDARD_APP_ARGS(args, buf);
+ args.argv[args.argc] = NULL;
+ #if 0
+ /* Answer if need be */
+@@ -3256,7 +3641,7 @@
+ return 0;
+ }
+
+-static int agi_exec(struct ast_channel *chan, void *data)
++static int agi_exec(struct ast_channel *chan, const char *data)
+ {
+ if (!ast_check_hangup(chan))
+ return agi_exec_full(chan, data, 0, 0);
+@@ -3264,7 +3649,7 @@
+ return agi_exec_full(chan, data, 0, 1);
+ }
+
+-static int eagi_exec(struct ast_channel *chan, void *data)
++static int eagi_exec(struct ast_channel *chan, const char *data)
+ {
+ int readformat, res;
+
+@@ -3286,7 +3671,7 @@
+ return res;
+ }
+
+-static int deadagi_exec(struct ast_channel *chan, void *data)
++static int deadagi_exec(struct ast_channel *chan, const char *data)
+ {
+ ast_log(LOG_WARNING, "DeadAGI has been deprecated, please use AGI in all cases!\n");
+ return agi_exec(chan, data);
+@@ -3319,10 +3704,10 @@
+ no other commands have been registered yet
+ */
+ (void) ast_agi_register_multiple(ast_module_info->self, commands, ARRAY_LEN(commands));
+- ast_register_application(deadapp, deadagi_exec, deadsynopsis, descrip);
+- ast_register_application(eapp, eagi_exec, esynopsis, descrip);
+- ast_manager_register2("AGI", EVENT_FLAG_AGI, action_add_agi_cmd, "Add an AGI command to execute by Async AGI", mandescr_asyncagi);
+- return ast_register_application(app, agi_exec, synopsis, descrip);
++ ast_register_application_xml(deadapp, deadagi_exec);
++ ast_register_application_xml(eapp, eagi_exec);
++ ast_manager_register_xml("AGI", EVENT_FLAG_AGI, action_add_agi_cmd);
++ return ast_register_application_xml(app, agi_exec);
+ }
+
+ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "Asterisk Gateway Interface (AGI)",
+Index: res/res_adsi.exports
+===================================================================
+--- a/res/res_adsi.exports (.../tags/1.6.2.0-beta3) (revision 0)
++++ b/res/res_adsi.exports (.../trunk) (revision 202568)
+@@ -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-beta3) (revision 202568)
++++ b/res/res_config_ldap.c (.../trunk) (revision 202568)
+@@ -1271,10 +1271,8 @@
+ ldap_err2string(result));
+
+ ast_mutex_unlock(&ldap_lock);
+- if (filter)
+- free(filter);
+- if (clean_basedn)
+- free(clean_basedn);
++ free(filter);
++ free(clean_basedn);
+ ldap_msgfree(ldap_result_msg);
+ ldap_mods_free(ldap_mods, 0);
+ return -1;
+@@ -1297,10 +1295,8 @@
+ }
+
+ ast_mutex_unlock(&ldap_lock);
+- if (filter)
+- free(filter);
+- if (clean_basedn)
+- free(clean_basedn);
++ free(filter);
++ free(clean_basedn);
+ ldap_msgfree(ldap_result_msg);
+ ldap_mods_free(ldap_mods, 0);
+ return num_entries;
+@@ -1458,10 +1454,8 @@
+ ldap_err2string(result));
+
+ ast_mutex_unlock(&ldap_lock);
+- if (filter)
+- free(filter);
+- if (clean_basedn)
+- free(clean_basedn);
++ free(filter);
++ free(clean_basedn);
+ ldap_msgfree(ldap_result_msg);
+ ldap_mods_free(ldap_mods, 0);
+ return -1;
+@@ -1758,7 +1752,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/ael/ael_lex.c
+===================================================================
+--- a/res/ael/ael_lex.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/res/ael/ael_lex.c (.../trunk) (revision 202568)
+@@ -3221,8 +3221,7 @@
+
+ void ael_yyfree(void *ptr, yyscan_t yyscanner)
+ {
+- if (ptr)
+- free( (char*) ptr );
++ free( (char*) ptr );
+ }
+
+ static int pbcpop(char x)
+@@ -3361,8 +3360,7 @@
+ *errors = 1;
+ return 0;
+ }
+- if (my_file)
+- free(my_file);
++ free(my_file);
+ my_file = strdup(filename);
+ stat(filename, &stats);
+ buffer = (char*)malloc(stats.st_size+2);
+Index: res/res_odbc.c
+===================================================================
+--- a/res/res_odbc.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/res/res_odbc.c (.../trunk) (revision 202568)
+@@ -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);
+
+@@ -1045,7 +1045,7 @@
+ return obj->parent->backslash_is_escape;
+ }
+
+-static int commit_exec(struct ast_channel *chan, void *data)
++static int commit_exec(struct ast_channel *chan, const char *data)
+ {
+ struct odbc_txn_frame *tx;
+ SQLINTEGER nativeerror=0, numfields=0;
+@@ -1082,7 +1082,7 @@
+ return 0;
+ }
+
+-static int rollback_exec(struct ast_channel *chan, void *data)
++static int rollback_exec(struct ast_channel *chan, const char *data)
+ {
+ struct odbc_txn_frame *tx;
+ SQLINTEGER nativeerror=0, numfields=0;
+@@ -1594,8 +1594,8 @@
+ .write = acf_transaction_write,
+ };
+
+-static const char *app_commit = "ODBC_Commit";
+-static const char *app_rollback = "ODBC_Rollback";
++static const char * const app_commit = "ODBC_Commit";
++static const char * const app_rollback = "ODBC_Rollback";
+
+ static int reload(void)
+ {
+Index: res/res_calendar.c
+===================================================================
+--- a/res/res_calendar.c (.../tags/1.6.2.0-beta3) (revision 0)
++++ b/res/res_calendar.c (.../trunk) (revision 202568)
+@@ -0,0 +1,1607 @@
++/*
++ * Asterisk -- An open source telephony toolkit.
++ *
++ * Copyright (C) 2008 - 2009, Digium, Inc.
++ *
++ * Terry Wilson <twilson@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 Calendaring API
++ *
++ * \todo Support responding to a meeting invite
++ * \todo Support writing attendees
++ */
++
++#include "asterisk.h"
++
++ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
++
++#include "asterisk/_private.h"
++#include "asterisk/calendar.h"
++#include "asterisk/utils.h"
++#include "asterisk/astobj2.h"
++#include "asterisk/module.h"
++#include "asterisk/config.h"
++#include "asterisk/channel.h"
++#include "asterisk/devicestate.h"
++#include "asterisk/linkedlists.h"
++#include "asterisk/sched.h"
++#include "asterisk/dial.h"
++#include "asterisk/cli.h"
++#include "asterisk/pbx.h"
++#include "asterisk/app.h"
++
++/*** DOCUMENTATION
++ <function name="CALENDAR_BUSY" language="en_US">
++ <synopsis>
++ Determine if the calendar is marked busy at this time.
++ </synopsis>
++ <syntax>
++ <parameter name="calendar" required="true" />
++ </syntax>
++ <description>
++ <para>Check the specified calendar's current busy status.</para>
++ </description>
++ </function>
++ <function name="CALENDAR_EVENT" language="en_US">
++ <synopsis>
++ Get calendar event notification data from a notification call.
++ </synopsis>
++ <syntax>
++ <parameter name="field" required="true">
++ <enumlist>
++ <enum name="summary"><para>The VEVENT SUMMARY property or Exchange event 'subject'</para></enum>
++ <enum name="description"><para>The text description of the event</para></enum>
++ <enum name="organizer"><para>The organizer of the event</para></enum>
++ <enum name="location"><para>The location of the eventt</para></enum>
++ <enum name="calendar"><para>The name of the calendar associated with the event</para></enum>
++ <enum name="uid"><para>The unique identifier for this event</para></enum>
++ <enum name="start"><para>The start time of the event</para></enum>
++ <enum name="end"><para>The end time of the event</para></enum>
++ <enum name="busystate"><para>The busy state of the event 0=FREE, 1=TENTATIVE, 2=BUSY</para></enum>
++ </enumlist>
++ </parameter>
++ </syntax>
++ <description>
++ <para>Whenever a calendar event notification call is made, the event data
++ may be accessed with this function.</para>
++ </description>
++ </function>
++ <function name="CALENDAR_QUERY" language="en_US">
++ <synopsis>Query a calendar server and store the data on a channel
++ </synopsis>
++ <syntax>
++ <parameter name="calendar" required="true">
++ <para>The calendar that should be queried</para>
++ </parameter>
++ <parameter name="start" required="false">
++ <para>The start time of the query (in seconds since epoch)</para>
++ </parameter>
++ <parameter name="end" required="false">
++ <para>The end time of the query (in seconds since epoch)</para>
++ </parameter>
++ </syntax>
++ <description>
++ <para>Get a list of events in the currently accessible timeframe of the <replaceable>calendar</replaceable>
++ The function returns the id for accessing the result with CALENDAR_QUERY_RESULT()</para>
++ </description>
++ </function>
++ <function name="CALENDAR_QUERY_RESULT" language="en_US">
++ <synopsis>
++ Retrieve data from a previously run CALENDAR_QUERY() call
++ </synopsis>
++ <syntax>
++ <parameter name="id" required="true">
++ <para>The query ID returned by <literal>CALENDAR_QUERY</literal></para>
++ </parameter>
++ <parameter name="field" required="true">
++ <enumlist>
++ <enum name="getnum"><para>number of events occurring during time range</para></enum>
++ <enum name="summary"><para>A summary of the event</para></enum>
++ <enum name="description"><para>The full event description</para></enum>
++ <enum name="organizer"><para>The event organizer</para></enum>
++ <enum name="location"><para>The event location</para></enum>
++ <enum name="calendar"><para>The name of the calendar associted with the event</para></enum>
++ <enum name="uid"><para>The unique identifier for the event</para></enum>
++ <enum name="start"><para>The start time of the event (in seconds since epoch)</para></enum>
++ <enum name="end"><para>The end time of the event (in seconds since epoch)</para></enum>
++ <enum name="busystate"><para>The busy status of the event 0=FREE, 1=TENTATIVE, 2=BUSY</para></enum>
++ </enumlist>
++ </parameter>
++ <parameter name="entry" required="false" default="1">
++ <para>Return data from a specific event returned by the query</para>
++ </parameter>
++ </syntax>
++ <description>
++ <para>After running CALENDAR_QUERY and getting a result <replaceable>id</replaceable>, calling
++ <literal>CALENDAR_QUERY</literal> with that <replaceable>id</replaceable> and a <replaceable>field</replaceable>
++ will return the data for that field. If multiple events matched the query, and <replaceable>entry</replaceable>
++ is provided, information from that event will be returned.</para>
++ </description>
++ </function>
++ <function name="CALENDAR_WRITE" language="en_US">
++ <synopsis>Write an event to a calendar</synopsis>
++ <syntax>
++ <parameter name="calendar" required="true">
++ <para>The calendar to write to</para>
++ </parameter>
++ <parameter name="field" multiple="true" required="true">
++ <enumlist>
++ <enum name="summary"><para>A summary of the event</para></enum>
++ <enum name="description"><para>The full event description</para></enum>
++ <enum name="organizer"><para>The event organizer</para></enum>
++ <enum name="location"><para>The event location</para></enum>
++ <enum name="uid"><para>The unique identifier for the event</para></enum>
++ <enum name="start"><para>The start time of the event (in seconds since epoch)</para></enum>
++ <enum name="end"><para>The end time of the event (in seconds since epoch)</para></enum>
++ <enum name="busystate"><para>The busy status of the event 0=FREE, 1=TENTATIVE, 2=BUSY</para></enum>
++ </enumlist>
++ </parameter>
++ </syntax>
++ <description>
++ <para>Example: CALENDAR_WRITE(calendar,field1,field2,field3)=val1,val2,val3</para>
++ <para>The field and value arguments can easily be set/passed using the HASHKEYS() and HASH() functions</para>
++ </description>
++ </function>
++
++***/
++#define CALENDAR_BUCKETS 19
++
++static struct ao2_container *calendars;
++static struct sched_context *sched;
++static pthread_t refresh_thread = AST_PTHREADT_NULL;
++static ast_mutex_t refreshlock;
++static ast_cond_t refresh_condition;
++static ast_mutex_t reloadlock;
++
++static void event_notification_destroy(void *data);
++static void *event_notification_duplicate(void *data);
++static void eventlist_destroy(void *data);
++static void *eventlist_duplicate(void *data);
++
++static const struct ast_datastore_info event_notification_datastore = {
++ .type = "EventNotification",
++ .destroy = event_notification_destroy,
++ .duplicate = event_notification_duplicate,
++};
++
++static const struct ast_datastore_info eventlist_datastore_info = {
++ .type = "CalendarEventList",
++ .destroy = eventlist_destroy,
++ .duplicate = eventlist_duplicate,
++};
++
++struct evententry {
++ struct ast_calendar_event *event;
++ AST_LIST_ENTRY(evententry) list;
++};
++
++static AST_LIST_HEAD_STATIC(techs, ast_calendar_tech);
++AST_LIST_HEAD_NOLOCK(eventlist, evententry); /* define the type */
++
++struct ast_config *ast_calendar_config;
++
++static struct ast_calendar *unref_calendar(struct ast_calendar *cal)
++{
++ ao2_ref(cal, -1);
++ return NULL;
++}
++
++static int calendar_hash_fn(const void *obj, const int flags)
++{
++ const struct ast_calendar *cal = obj;
++ return ast_str_case_hash(cal->name);
++}
++
++static int calendar_cmp_fn(void *obj, void *arg, int flags)
++{
++ const struct ast_calendar *one = obj, *two = arg;
++ return !strcasecmp(one->name, two->name) ? CMP_MATCH | CMP_STOP: 0;
++}
++
++static struct ast_calendar *find_calendar(const char *name)
++{
++ struct ast_calendar tmp = {
++ .name = name,
++ };
++ return ao2_find(calendars, &tmp, OBJ_POINTER);
++}
++
++static int event_hash_fn(const void *obj, const int flags)
++{
++ const struct ast_calendar_event *event = obj;
++ return ast_str_hash(event->uid);
++}
++
++static int event_cmp_fn(void *obj, void *arg, int flags)
++{
++ const struct ast_calendar_event *one = obj, *two = arg;
++ return !strcmp(one->uid, two->uid) ? CMP_MATCH | CMP_STOP : 0;
++}
++
++static struct ast_calendar_event *find_event(struct ao2_container *events, const char *uid)
++{
++ struct ast_calendar_event tmp = {
++ .uid = uid,
++ };
++ return ao2_find(events, &tmp, OBJ_POINTER);
++}
++
++struct ast_calendar_event *ast_calendar_unref_event(struct ast_calendar_event *event)
++{
++ ao2_ref(event, -1);
++ return NULL;
++}
++
++static void calendar_destructor(void *obj)
++{
++ struct ast_calendar *cal = obj;
++
++ ast_debug(3, "Destroying calendar %s\n", cal->name);
++
++ ao2_lock(cal);
++ cal->unloading = 1;
++ ast_cond_signal(&cal->unload);
++ pthread_join(cal->thread, NULL);
++ if (cal->tech_pvt) {
++ cal->tech_pvt = cal->tech->unref_calendar(cal->tech_pvt);
++ }
++ ast_calendar_clear_events(cal);
++ ast_string_field_free_memory(cal);
++ ao2_ref(cal->events, -1);
++ ao2_unlock(cal);
++}
++
++static void eventlist_destructor(void *obj)
++{
++ struct eventlist *events = obj;
++ struct evententry *entry;
++
++ while ((entry = AST_LIST_REMOVE_HEAD(events, list))) {
++ ao2_ref(entry->event, -1);
++ ast_free(entry);
++ }
++}
++
++static int calendar_busy_callback(void *obj, void *arg, int flags)
++{
++ struct ast_calendar_event *event = obj;
++ int *is_busy = arg;
++ struct timeval tv = ast_tvnow();
++
++ if (tv.tv_sec >= event->start && tv.tv_sec <= event->end && event->busy_state > AST_CALENDAR_BS_FREE) {
++ *is_busy = 1;
++ return CMP_STOP;
++ }
++
++ return 0;
++}
++
++static int calendar_is_busy(struct ast_calendar *cal)
++{
++ int is_busy = 0;
++
++ ao2_callback(cal->events, OBJ_NODATA, calendar_busy_callback, &is_busy);
++
++ return is_busy;
++}
++
++static enum ast_device_state calendarstate(const char *data)
++{
++ struct ast_calendar *cal;
++
++ if (ast_strlen_zero(data) || (!(cal = find_calendar(data)))) {
++ return AST_DEVICE_INVALID;
++ }
++
++ if (cal->tech->is_busy) {
++ return cal->tech->is_busy(cal) ? AST_DEVICE_INUSE : AST_DEVICE_NOT_INUSE;
++ }
++
++ return calendar_is_busy(cal) ? AST_DEVICE_INUSE : AST_DEVICE_NOT_INUSE;
++}
++
++static struct ast_calendar *build_calendar(struct ast_config *cfg, const char *cat, const struct ast_calendar_tech *tech)
++{
++ struct ast_calendar *cal;
++ struct ast_variable *v;
++ int new_calendar = 0;
++
++ if (!(cal = find_calendar(cat))) {
++ new_calendar = 1;
++ if (!(cal = ao2_alloc(sizeof(*cal), calendar_destructor))) {
++ ast_log(LOG_ERROR, "Could not allocate calendar structure. Stopping.\n");
++ return NULL;
++ }
++
++ if (!(cal->events = ao2_container_alloc(CALENDAR_BUCKETS, event_hash_fn, event_cmp_fn))) {
++ ast_log(LOG_ERROR, "Could not allocate events container for %s\n", cat);
++ cal = unref_calendar(cal);
++ return NULL;
++ }
++
++ if (ast_string_field_init(cal, 32)) {
++ ast_log(LOG_ERROR, "Couldn't create string fields for %s\n", cat);
++ cal = unref_calendar(cal);
++ return NULL;
++ }
++ } else {
++ cal->pending_deletion = 0;
++ }
++
++ ast_string_field_set(cal, name, cat);
++ cal->tech = tech;
++
++ cal->refresh = 3600;
++ cal->timeframe = 60;
++
++ for (v = ast_variable_browse(cfg, cat); v; v = v->next) {
++ if (!strcasecmp(v->name, "autoreminder")) {
++ cal->autoreminder = atoi(v->value);
++ } else if (!strcasecmp(v->name, "channel")) {
++ ast_string_field_set(cal, notify_channel, v->value);
++ } else if (!strcasecmp(v->name, "context")) {
++ ast_string_field_set(cal, notify_context, v->value);
++ } else if (!strcasecmp(v->name, "extension")) {
++ ast_string_field_set(cal, notify_extension, v->value);
++ } else if (!strcasecmp(v->name, "waittime")) {
++ cal->notify_waittime = atoi(v->value);
++ } else if (!strcasecmp(v->name, "app")) {
++ ast_string_field_set(cal, notify_app, v->value);
++ } else if (!strcasecmp(v->name, "appdata")) {
++ ast_string_field_set(cal, notify_appdata, v->value);
++ } else if (!strcasecmp(v->name, "refresh")) {
++ cal->refresh = atoi(v->value);
++ } else if (!strcasecmp(v->name, "timeframe")) {
++ cal->timeframe = atoi(v->value);
++ }
++ }
++
++ if (new_calendar) {
++ cal->thread = AST_PTHREADT_NULL;
++ ast_cond_init(&cal->unload, NULL);
++ ao2_link(calendars, cal);
++ if (ast_pthread_create(&cal->thread, NULL, cal->tech->load_calendar, cal)) {
++ /* If we start failing to create threads, go ahead and return NULL
++ * and the tech module will be unregistered
++ */
++ ao2_unlink(calendars, cal);
++ cal = unref_calendar(cal);
++ }
++ }
++
++ return cal;
++}
++
++static int load_tech_calendars(struct ast_calendar_tech *tech)
++{
++ struct ast_calendar *cal;
++ const char *cat = NULL;
++ const char *val;
++
++ if (!ast_calendar_config) {
++ ast_log(LOG_WARNING, "Calendar support disabled, not loading %s calendar module\n", tech->type);
++ return -1;
++ }
++
++ while ((cat = ast_category_browse(ast_calendar_config, cat))) {
++ if (!strcasecmp(cat, "general")) {
++ continue;
++ }
++
++ if (!(val = ast_variable_retrieve(ast_calendar_config, cat, "type")) || strcasecmp(val, tech->type)) {
++ continue;
++ }
++
++ /* A serious error occurred loading calendars from this tech and it should be disabled */
++ if (!(cal = build_calendar(ast_calendar_config, cat, tech))) {
++ ast_calendar_unregister(tech);
++ return -1;
++ }
++
++ cal = unref_calendar(cal);
++ }
++
++ return 0;
++}
++
++int ast_calendar_register(struct ast_calendar_tech *tech)
++{
++ struct ast_calendar_tech *iter;
++
++ AST_LIST_LOCK(&techs);
++ AST_LIST_TRAVERSE(&techs, iter, list) {
++ if(!strcasecmp(tech->type, iter->type)) {
++ ast_log(LOG_WARNING, "Already have a handler for calendar type '%s'\n", tech->type);
++ AST_LIST_UNLOCK(&techs);
++ return -1;
++ }
++ }
++ AST_LIST_INSERT_HEAD(&techs, tech, list);
++ AST_LIST_UNLOCK(&techs);
++
++ ast_verb(2, "Registered calendar type '%s' (%s)\n", tech->type, tech->description);
++
++ return load_tech_calendars(tech);
++}
++
++static int match_caltech_cb(void *user_data, void *arg, int flags)
++{
++ struct ast_calendar *cal = user_data;
++ struct ast_calendar_tech *tech = arg;
++
++ if (cal->tech == tech) {
++ return CMP_MATCH;
++ }
++
++ return 0;
++}
++
++void ast_calendar_unregister(struct ast_calendar_tech *tech)
++{
++ struct ast_calendar_tech *iter;
++
++ AST_LIST_LOCK(&techs);
++ AST_LIST_TRAVERSE_SAFE_BEGIN(&techs, iter, list) {
++ if (iter != tech) {
++ continue;
++ }
++
++ ao2_callback(calendars, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, match_caltech_cb, tech);
++
++ AST_LIST_REMOVE_CURRENT(list);
++ ast_verb(2, "Unregistered calendar type '%s'\n", tech->type);
++ break;
++ }
++ AST_LIST_TRAVERSE_SAFE_END;
++ AST_LIST_UNLOCK(&techs);
++
++}
++
++static void calendar_event_destructor(void *obj)
++{
++ struct ast_calendar_event *event = obj;
++ struct ast_calendar_attendee *attendee;
++
++ ast_debug(3, "Destroying event for calendar '%s'\n", event->owner->name);
++ ast_string_field_free_memory(event);
++ while ((attendee = AST_LIST_REMOVE_HEAD(&event->attendees, next))) {
++ if (attendee->data) {
++ ast_free(attendee->data);
++ }
++ ast_free(attendee);
++ }
++}
++
++/* This is only called from ao2_callbacks that are going to unref the event for us,
++ * so we don't unref the event here. */
++static struct ast_calendar_event *destroy_event(struct ast_calendar_event *event)
++{
++ if (event->notify_sched > -1 && ast_sched_del(sched, event->notify_sched)) {
++ ast_debug(3, "Notification running, can't delete sched entry\n");
++ }
++ if (event->bs_start_sched > -1 && ast_sched_del(sched, event->bs_start_sched)) {
++ ast_debug(3, "Devicestate update (start) running, can't delete sched entry\n");
++ }
++ if (event->bs_end_sched > -1 && ast_sched_del(sched, event->bs_end_sched)) {
++ ast_debug(3, "Devicestate update (end) running, can't delete sched entry\n");
++ }
++
++ /* If an event is being deleted and we've fired an event changing the status at the beginning,
++ * but haven't hit the end event yet, go ahead and set the devicestate to the current busy status */
++ if (event->bs_start_sched < 0 && event->bs_end_sched >= 0) {
++ if (!calendar_is_busy(event->owner)) {
++ ast_devstate_changed(AST_DEVICE_NOT_INUSE, "Calendar/%s", event->owner->name);
++ } else {
++ ast_devstate_changed(AST_DEVICE_BUSY, "Calendar/%s", event->owner->name);
++ }
++ }
++
++ return NULL;
++}
++
++static int clear_events_cb(void *user_data, void *arg, int flags)
++{
++ struct ast_calendar_event *event = user_data;
++
++ event = destroy_event(event);
++
++ return CMP_MATCH;
++}
++
++void ast_calendar_clear_events(struct ast_calendar *cal)
++{
++ ast_debug(3, "Clearing all events for calendar %s\n", cal->name);
++
++ ao2_callback(cal->events, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, clear_events_cb, NULL);
++}
++
++struct ast_calendar_event *ast_calendar_event_alloc(struct ast_calendar *cal)
++{
++ struct ast_calendar_event *event;
++ if (!(event = ao2_alloc(sizeof(*event), calendar_event_destructor))) {
++ return NULL;
++ }
++
++ if (ast_string_field_init(event, 32)) {
++ event = ast_calendar_unref_event(event);
++ return NULL;
++ }
++
++ event->owner = cal;
++ event->notify_sched = -1;
++ event->bs_start_sched = -1;
++ event->bs_end_sched = -1;
++
++ AST_LIST_HEAD_INIT_NOLOCK(&event->attendees);
++
++ return event;
++}
++
++struct ao2_container *ast_calendar_event_container_alloc(void)
++{
++ return ao2_container_alloc(CALENDAR_BUCKETS, event_hash_fn, event_cmp_fn);
++}
++
++static void event_notification_destroy(void *data)
++{
++ struct ast_calendar_event *event = data;
++
++ event = ast_calendar_unref_event(event);
++
++}
++
++static void *event_notification_duplicate(void *data)
++{
++ struct ast_calendar_event *event = data;
++
++ if (!event) {
++ return NULL;
++ }
++
++ ao2_ref(event, +1);
++
++ return event;
++}
++
++/*! \brief Generate 32 byte random string (stolen from chan_sip.c)*/
++static char *generate_random_string(char *buf, size_t size)
++{
++ long val[4];
++ int x;
++
++ for (x = 0; x < 4; x++) {
++ val[x] = ast_random();
++ }
++ snprintf(buf, size, "%08lx%08lx%08lx%08lx", val[0], val[1], val[2], val[3]);
++
++ return buf;
++}
++
++static int calendar_event_notify(const void *data)
++{
++ struct ast_calendar_event *event = (void *)data;
++ char tech[256], dest[256], buf[8], *tmp;
++ struct ast_dial *dial = NULL;
++ struct ast_channel *chan = NULL;
++ struct ast_str *apptext = NULL;
++ int res = -1;
++ char start[12], end[12], busystate[2];
++ struct ast_datastore *datastore;
++
++ if (!(event && event->owner)) {
++ ast_log(LOG_ERROR, "Extremely low-cal...in fact cal is NULL!\n");
++ goto notify_cleanup;
++ }
++
++ ao2_ref(event, +1);
++ event->notify_sched = -1;
++
++ ast_copy_string(tech, event->owner->notify_channel, sizeof(tech));
++
++ if ((tmp = strchr(tech, '/'))) {
++ *tmp = '\0';
++ tmp++;
++ ast_copy_string(dest, tmp, sizeof(dest));
++ } else {
++ ast_log(LOG_WARNING, "Channel should be in form Tech/Dest\n");
++ goto notify_cleanup;
++ }
++
++ if (!(dial = ast_dial_create())) {
++ ast_log(LOG_ERROR, "Could not create dial structure\n");
++ goto notify_cleanup;
++ }
++
++ if (ast_dial_append(dial, tech, dest) < 0) {
++ ast_log(LOG_ERROR, "Could not append channel\n");
++ goto notify_cleanup;
++ }
++
++ ast_dial_set_global_timeout(dial, event->owner->notify_waittime);
++ generate_random_string(buf, sizeof(buf));
++ if (!(chan = ast_channel_alloc(1, AST_STATE_DOWN, 0, 0, 0, 0, 0, 0, "Calendar/%s-%s", event->owner->name, buf))) {
++ ast_log(LOG_ERROR, "Could not allocate notification channel\n");
++ goto notify_cleanup;
++ }
++
++ snprintf(busystate, sizeof(busystate), "%d", event->busy_state);
++ snprintf(start, sizeof(start), "%lu", event->start);
++ snprintf(end, sizeof(end), "%lu", event->end);
++
++ chan->nativeformats = AST_FORMAT_SLINEAR;
++
++ if (!(datastore = ast_datastore_alloc(&event_notification_datastore, NULL))) {
++ ast_log(LOG_ERROR, "Could not allocate datastore, notification not being sent!\n");
++ goto notify_cleanup;
++ }
++
++ datastore->data = event;
++ datastore->inheritance = DATASTORE_INHERIT_FOREVER;
++
++ ao2_ref(event, +1);
++ res = ast_channel_datastore_add(chan, datastore);
++
++ if (!(apptext = ast_str_create(32))) {
++ goto notify_cleanup;
++ }
++
++ if (!ast_strlen_zero(event->owner->notify_app)) {
++ ast_str_set(&apptext, 0, "%s,%s", event->owner->notify_app, event->owner->notify_appdata);
++ } else {
++ ast_str_set(&apptext, 0, "Dial,Local/%s@%s", event->owner->notify_extension, event->owner->notify_context);
++ }
++ ast_dial_option_global_enable(dial, AST_DIAL_OPTION_ANSWER_EXEC, ast_str_buffer(apptext));
++
++ ast_dial_run(dial, chan, 1);
++ res = 0;
++
++notify_cleanup:
++ event = ast_calendar_unref_event(event);
++ if (res == -1 && dial) {
++ ast_dial_destroy(dial);
++ }
++ if (apptext) {
++ ast_free(apptext);
++ }
++ if (chan) {
++ ast_channel_release(chan);
++ }
++
++ return res;
++}
++
++static int calendar_devstate_change(const void *data)
++{
++ struct ast_calendar_event *event = (struct ast_calendar_event *)data;
++ struct timeval now = ast_tvnow();
++ int is_end_event;
++
++ if (!event) {
++ ast_log(LOG_WARNING, "Event was NULL!\n");
++ return 0;
++ }
++
++ ao2_ref(event, +1);
++
++ is_end_event = event->end <= now.tv_sec;
++
++ if (is_end_event) {
++ event->bs_end_sched = -1;
++ } else {
++ event->bs_start_sched = -1;
++ }
++
++ /* We can have overlapping events, so ignore the event->busy_state and check busy state
++ * based on all events in the calendar */
++ if (!calendar_is_busy(event->owner)) {
++ ast_devstate_changed(AST_DEVICE_NOT_INUSE, "Calendar/%s", event->owner->name);
++ } else {
++ ast_devstate_changed(AST_DEVICE_BUSY, "Calendar/%s", event->owner->name);
++ }
++
++ event = ast_calendar_unref_event(event);
++
++ return 0;
++}
++
++static void copy_event_data(struct ast_calendar_event *dst, struct ast_calendar_event *src)
++{
++ struct ast_calendar_attendee *attendee;
++
++ ast_string_field_set(dst, summary, src->summary);
++ ast_string_field_set(dst, description, src->description);
++ ast_string_field_set(dst, organizer, src->organizer);
++ ast_string_field_set(dst, location, src->location);
++ ast_string_field_set(dst, uid, src->uid);
++ dst->owner = src->owner;
++ dst->start = src->start;
++ dst->end = src->end;
++ dst->alarm = src->alarm;
++ dst->busy_state = src->busy_state;
++
++ while ((attendee = AST_LIST_REMOVE_HEAD(&src->attendees, next))) {
++ AST_LIST_INSERT_TAIL(&dst->attendees, attendee, next);
++ }
++}
++
++static int schedule_calendar_event(struct ast_calendar *cal, struct ast_calendar_event *old_event, struct ast_calendar_event *cmp_event)
++{
++ struct timeval now = ast_tvnow();
++ struct ast_calendar_event *event;
++ time_t alarm_notify_sched = 0, devstate_sched_start, devstate_sched_end;
++ int changed = 0;
++
++ event = cmp_event ? cmp_event : old_event;
++
++ ao2_lock(event);
++ if (!cmp_event || old_event->alarm != event->alarm) {
++ changed = 1;
++ if (cal->autoreminder) {
++ alarm_notify_sched = (event->start - (60 * cal->autoreminder) - now.tv_sec) * 1000;
++ } else if (event->alarm) {
++ alarm_notify_sched = (event->alarm - now.tv_sec) * 1000;
++ }
++
++ /* For now, send the notification if we missed it, but the meeting hasn't happened yet */
++ if (event->start >= now.tv_sec) {
++ if (alarm_notify_sched <= 0) {
++ alarm_notify_sched = 1;
++ }
++ ast_mutex_lock(&refreshlock);
++ AST_SCHED_REPLACE(old_event->notify_sched, sched, alarm_notify_sched, calendar_event_notify, old_event);
++ ast_mutex_unlock(&refreshlock);
++ ast_debug(3, "Calendar alarm event notification scheduled to happen in %ld ms\n", alarm_notify_sched);
++ }
++ }
++
++ if (!cmp_event || old_event->start != event->start) {
++ changed = 1;
++ devstate_sched_start = (event->start - now.tv_sec) * 1000;
++
++ if (devstate_sched_start < 1) {
++ devstate_sched_start = 1;
++ }
++
++ ast_mutex_lock(&refreshlock);
++ AST_SCHED_REPLACE(old_event->bs_start_sched, sched, devstate_sched_start, calendar_devstate_change, old_event);
++ ast_mutex_unlock(&refreshlock);
++ ast_debug(3, "Calendar bs_start event notification scheduled to happen in %ld ms\n", devstate_sched_start);
++ }
++
++ if (!cmp_event || old_event->end != event->end) {
++ changed = 1;
++ devstate_sched_end = (event->end - now.tv_sec) * 1000;
++ ast_mutex_lock(&refreshlock);
++ AST_SCHED_REPLACE(old_event->bs_end_sched, sched, devstate_sched_end, calendar_devstate_change, old_event);
++ ast_mutex_unlock(&refreshlock);
++ ast_debug(3, "Calendar bs_end event notification scheduled to happen in %ld ms\n", devstate_sched_end);
++ }
++
++ if (changed) {
++ ast_cond_signal(&refresh_condition);
++ }
++
++ ao2_unlock(event);
++
++ return 0;
++}
++
++static int merge_events_cb(void *obj, void *arg, int flags)
++{
++ struct ast_calendar_event *old_event = obj, *new_event;
++ struct ao2_container *new_events = arg;
++
++ /* If we don't find the old_event in new_events, then we can safely delete the old_event */
++ if (!(new_event = find_event(new_events, old_event->uid))) {
++ old_event = destroy_event(old_event);
++ return CMP_MATCH;
++ }
++
++ /* We have events to merge. If any data that will affect a scheduler event has changed,
++ * then we need to replace the scheduler event */
++ schedule_calendar_event(old_event->owner, old_event, new_event);
++
++ /* Since we don't want to mess with cancelling sched events and adding new ones, just
++ * copy the internals of the new_event to the old_event */
++ copy_event_data(old_event, new_event);
++
++ /* Now we can go ahead and unlink the new_event from new_events and unref it so that only completely
++ * new events remain in the container */
++ ao2_unlink(new_events, new_event);
++ new_event = ast_calendar_unref_event(new_event);
++
++ return 0;
++}
++
++static int add_new_event_cb(void *obj, void *arg, int flags)
++{
++ struct ast_calendar_event *new_event = obj;
++ struct ao2_container *events = arg;
++
++ ao2_link(events, new_event);
++ schedule_calendar_event(new_event->owner, new_event, NULL);
++ return CMP_MATCH;
++}
++
++void ast_calendar_merge_events(struct ast_calendar *cal, struct ao2_container *new_events)
++{
++ /* Loop through all events attached to the calendar. If there is a matching new event
++ * merge its data over and handle any schedule changes that need to be made. Then remove
++ * the new_event from new_events so that we are left with only new_events that we can add later. */
++ ao2_callback(cal->events, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, merge_events_cb, new_events);
++
++ /* Now, we should only have completely new events in new_events. Loop through and add them */
++ ao2_callback(new_events, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, add_new_event_cb, cal->events);
++}
++
++
++static int load_config(void *data)
++{
++ struct ast_flags config_flags = { CONFIG_FLAG_FILEUNCHANGED };
++ struct ast_config *tmpcfg;
++
++ if (!(tmpcfg = ast_config_load2("calendar.conf", "calendar", config_flags)) ||
++ tmpcfg == CONFIG_STATUS_FILEINVALID) {
++ ast_log(LOG_ERROR, "Unable to load config calendar.conf\n");
++ return -1;
++ }
++
++ if (tmpcfg == CONFIG_STATUS_FILEUNCHANGED) {
++ return 0;
++ }
++
++ if (ast_calendar_config) {
++ ast_config_destroy(ast_calendar_config);
++ }
++
++ ast_calendar_config = tmpcfg;
++
++ return 0;
++}
++
++/*! \brief A dialplan function that can be used to determine the busy status of a calendar */
++static int calendar_busy_exec(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
++{
++ struct ast_calendar *cal;
++
++ if (ast_strlen_zero(data)) {
++ ast_log(LOG_WARNING, "CALENDAR_BUSY requires an argument: CALENDAR_BUSY(<calendar_name>)\n");
++ return -1;
++ }
++
++ cal = find_calendar(data);
++
++ if (!cal) {
++ ast_log(LOG_WARNING, "Could not find calendar '%s'\n", data);
++ return -1;
++ }
++
++ strcpy(buf, calendar_is_busy(cal) ? "1" : "0");
++
++ return 0;
++}
++
++static struct ast_custom_function calendar_busy_function = {
++ .name = "CALENDAR_BUSY",
++ .read = calendar_busy_exec,
++};
++
++static int add_event_to_list(struct eventlist *events, struct ast_calendar_event *event, time_t start, time_t end)
++{
++ struct evententry *entry, *iter;
++ int event_startdiff = abs(start - event->start);
++ int event_enddiff = abs(end - event->end);
++ int i = 0;
++
++ if (!(entry = ast_calloc(1, sizeof(*entry)))) {
++ ast_log(LOG_ERROR, "Unable to allocate memory for event list\n");
++ return -1;
++ }
++
++ entry->event = event;
++ ao2_ref(event, +1);
++
++ if (start == end) {
++ AST_LIST_TRAVERSE_SAFE_BEGIN(events, iter, list) {
++ int startdiff = abs(iter->event->start - start);
++
++ ast_debug(10, "Comparing %s with startdiff %d to %s with startdiff %d\n", event->summary, event_startdiff, iter->event->summary, startdiff);
++ ++i;
++ if (startdiff > event_startdiff) {
++ AST_LIST_INSERT_BEFORE_CURRENT(entry, list);
++ return i;
++ }
++ if (startdiff == event_startdiff) {
++ int enddiff = abs(iter->event->end - end);
++
++ if (enddiff > event_enddiff) {
++ AST_LIST_INSERT_BEFORE_CURRENT(entry, list);
++ return i;
++ }
++ if (event_startdiff == enddiff) {
++ if (strcmp(event->uid, iter->event->uid) < 0) {
++ AST_LIST_INSERT_BEFORE_CURRENT(entry, list);
++ return i;
++ }
++ }
++ }
++ }
++ AST_LIST_TRAVERSE_SAFE_END;
++
++ AST_LIST_INSERT_TAIL(events, entry, list);
++
++ return i;
++ }
++
++ AST_LIST_TRAVERSE_SAFE_BEGIN(events, iter, list) {
++ ++i;
++ if (iter->event->start > event->start) {
++ AST_LIST_INSERT_BEFORE_CURRENT(entry, list);
++ return i;
++ }
++
++ if (iter->event->start == event->start) {
++ if ((iter->event->end - iter->event->start) == (event->end - event->start)) {
++ if (strcmp(event->uid, iter->event->uid) < 0) {
++ AST_LIST_INSERT_BEFORE_CURRENT(entry, list);
++ return i;
++ }
++ }
++ if ((iter->event->end - iter->event->start) < (event->end - event->start)) {
++ AST_LIST_INSERT_BEFORE_CURRENT(entry, list);
++ return i;
++ }
++ }
++ }
++ AST_LIST_TRAVERSE_SAFE_END;
++
++ AST_LIST_INSERT_TAIL(events, entry, list);
++
++ return i;
++}
++
++static void eventlist_destroy(void *data)
++{
++ struct eventlist *events = data;
++
++ ao2_ref(events, -1);
++}
++
++static void *eventlist_duplicate(void *data)
++{
++ struct eventlist *events = data;
++
++ if (!events) {
++ return NULL;
++ }
++
++ ao2_ref(events, +1);
++
++ return events;
++}
++
++static int calendar_query_exec(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
++{
++ struct ast_calendar *cal;
++ struct ao2_iterator i;
++ struct ast_calendar_event *event;
++ struct eventlist *events;
++ time_t start = INT_MIN, end = INT_MAX;
++ struct ast_datastore *eventlist_datastore;
++ AST_DECLARE_APP_ARGS(args,
++ AST_APP_ARG(calendar);
++ AST_APP_ARG(start);
++ AST_APP_ARG(end);
++ );
++
++ if (!chan) {
++ ast_log(LOG_WARNING, "%s requires a channel to store the data on\n", cmd);
++ return -1;
++ }
++
++ AST_STANDARD_APP_ARGS(args, data);
++
++ if (ast_strlen_zero(args.calendar)) {
++ ast_log(LOG_WARNING, "%s requires a calendar argument\n", cmd);
++ return -1;
++ }
++
++ if (!(cal = find_calendar(args.calendar))) {
++ ast_log(LOG_WARNING, "Unknown calendar '%s'\n", args.calendar);
++ return -1;
++ }
++
++ if (!(events = ao2_alloc(sizeof(*events), eventlist_destructor))) {
++ ast_log(LOG_ERROR, "Unable to allocate memory for event list\n");
++ cal = unref_calendar(cal);
++ return -1;
++ }
++
++ if (!ast_strlen_zero(args.start)) {
++ start = atoi(args.start);
++ }
++
++ if (!ast_strlen_zero(args.end)) {
++ end = atoi(args.end);
++ }
++
++ i = ao2_iterator_init(cal->events, 0);
++ while ((event = ao2_iterator_next(&i))) {
++ if (!(start > event->end || end < event->start)) {
++ ast_debug(10, "%s (%ld - %ld) overlapped with (%ld - %ld)\n", event->summary, event->start, event->end, start, end);
++ if (add_event_to_list(events, event, start, end) < 0) {
++ event = ast_calendar_unref_event(event);
++ return -1;
++ }
++ }
++
++ event = ast_calendar_unref_event(event);
++ }
++
++ ast_channel_lock(chan);
++ do {
++ generate_random_string(buf, len);
++ } while (ast_channel_datastore_find(chan, &eventlist_datastore_info, buf));
++ ast_channel_unlock(chan);
++
++ if (!(eventlist_datastore = ast_datastore_alloc(&eventlist_datastore_info, buf))) {
++ ast_log(LOG_ERROR, "Could not allocate datastore!\n");
++ return -1;
++ }
++
++ eventlist_datastore->inheritance = DATASTORE_INHERIT_FOREVER;
++ eventlist_datastore->data = events;
++
++ ast_channel_lock(chan);
++ ast_channel_datastore_add(chan, eventlist_datastore);
++ ast_channel_unlock(chan);
++
++ return 0;
++}
++
++static struct ast_custom_function calendar_query_function = {
++ .name = "CALENDAR_QUERY",
++ .read = calendar_query_exec,
++};
++
++static void calendar_join_attendees(struct ast_calendar_event *event, char *buf, size_t len)
++{
++ struct ast_str *tmp;
++ struct ast_calendar_attendee *attendee;
++
++ if (!(tmp = ast_str_create(32))) {
++ ast_log(LOG_ERROR, "Could not allocate memory for attendees!\n");
++ return;
++ }
++
++ AST_LIST_TRAVERSE(&event->attendees, attendee, next) {
++ ast_str_append(&tmp, 0, "%s%s", attendee == AST_LIST_FIRST(&event->attendees) ? "" : ",", attendee->data);
++ }
++
++ ast_copy_string(buf, ast_str_buffer(tmp), len);
++ ast_free(tmp);
++}
++
++static int calendar_query_result_exec(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
++{
++ struct ast_datastore *datastore;
++ struct eventlist *events;
++ struct evententry *entry;
++ int row = 1;
++ AST_DECLARE_APP_ARGS(args,
++ AST_APP_ARG(id);
++ AST_APP_ARG(field);
++ AST_APP_ARG(row);
++ );
++
++ if (!chan) {
++ ast_log(LOG_WARNING, "%s requires a channel\n", cmd);
++ return -1;
++ }
++
++ AST_STANDARD_APP_ARGS(args, data);
++
++ if (ast_strlen_zero(args.id) || ast_strlen_zero(args.field)) {
++ ast_log(LOG_WARNING, "%s requires an id and a field", cmd);
++ return -1;
++ }
++
++ ast_channel_lock(chan);
++ if (!(datastore = ast_channel_datastore_find(chan, &eventlist_datastore_info, args.id))) {
++ ast_log(LOG_WARNING, "There is no event notification datastore with id '%s' on '%s'!\n", args.id, chan->name);
++ ast_channel_unlock(chan);
++ return -1;
++ }
++ ast_channel_unlock(chan);
++
++ if (!(events = datastore->data)) {
++ ast_log(LOG_WARNING, "The datastore contains no data!\n");
++ return -1;
++ }
++
++ if (!ast_strlen_zero(args.row)) {
++ row = atoi(args.row);
++ }
++
++ AST_LIST_TRAVERSE(events, entry, list) {
++ if (--row) {
++ continue;
++ }
++ if (!strcasecmp(args.field, "summary")) {
++ ast_copy_string(buf, entry->event->summary, len);
++ } else if (!strcasecmp(args.field, "description")) {
++ ast_copy_string(buf, entry->event->description, len);
++ } else if (!strcasecmp(args.field, "organizer")) {
++ ast_copy_string(buf, entry->event->organizer, len);
++ } else if (!strcasecmp(args.field, "location")) {
++ ast_copy_string(buf, entry->event->location, len);
++ } else if (!strcasecmp(args.field, "calendar")) {
++ ast_copy_string(buf, entry->event->owner->name, len);
++ } else if (!strcasecmp(args.field, "uid")) {
++ ast_copy_string(buf, entry->event->uid, len);
++ } else if (!strcasecmp(args.field, "start")) {
++ snprintf(buf, len, "%ld", entry->event->start);
++ } else if (!strcasecmp(args.field, "end")) {
++ snprintf(buf, len, "%ld", entry->event->end);
++ } else if (!strcasecmp(args.field, "busystate")) {
++ snprintf(buf, len, "%d", entry->event->busy_state);
++ } else if (!strcasecmp(args.field, "attendees")) {
++ calendar_join_attendees(entry->event, buf, len);
++ } else {
++ ast_log(LOG_WARNING, "Unknown field '%s'\n", args.field);
++ }
++ break;
++ }
++
++ return 0;
++}
++
++static struct ast_custom_function calendar_query_result_function = {
++ .name = "CALENDAR_QUERY_RESULT",
++ .read = calendar_query_result_exec,
++};
++
++static int calendar_write_exec(struct ast_channel *chan, const char *cmd, char *data, const char *value)
++{
++ int i, j, ret = -1;
++ char *val_dup = NULL;
++ struct ast_calendar *cal = NULL;
++ struct ast_calendar_event *event = NULL;
++ AST_DECLARE_APP_ARGS(fields,
++ AST_APP_ARG(field)[10];
++ );
++ AST_DECLARE_APP_ARGS(values,
++ AST_APP_ARG(value)[10];
++ );
++
++ if (!(val_dup = ast_strdup(value))) {
++ ast_log(LOG_ERROR, "Could not allocate memory for values\n");
++ return -1;
++ }
++
++ AST_STANDARD_APP_ARGS(fields, data);
++ AST_STANDARD_APP_ARGS(values, val_dup);
++
++ /* XXX Eventually we will support unnamed calendars, so if we don't find one, we parse
++ * for a calendar type and create it */
++ if (!(cal = find_calendar(fields.field[0]))) {
++ ast_log(LOG_WARNING, "Couldn't find calendar '%s'\n", fields.field[0]);
++ goto write_cleanup;
++ }
++
++ if (!(cal->tech->write_event)) {
++ ast_log(LOG_WARNING, "Calendar '%s' has no write function!\n", cal->name);
++ goto write_cleanup;
++ }
++
++ if (!(event = ast_calendar_event_alloc(cal))) {
++ goto write_cleanup;
++ }
++
++ if (ast_strlen_zero(fields.field[0])) {
++ ast_log(LOG_WARNING, "CALENDAR_WRITE requires a calendar name!\n");
++ goto write_cleanup;
++ }
++
++ if (fields.argc - 1 != values.argc) {
++ ast_log(LOG_WARNING, "CALENDAR_WRITE should have the same number of fields (%d) and values (%d)!\n", fields.argc - 1, values.argc);
++ goto write_cleanup;
++ }
++
++ event->owner = cal;
++
++ for (i = 1, j = 0; i < fields.argc; i++, j++) {
++ if (!strcasecmp(fields.field[i], "summary")) {
++ ast_string_field_set(event, summary, values.value[j]);
++ } else if (!strcasecmp(fields.field[i], "description")) {
++ ast_string_field_set(event, description, values.value[j]);
++ } else if (!strcasecmp(fields.field[i], "organizer")) {
++ ast_string_field_set(event, organizer, values.value[j]);
++ } else if (!strcasecmp(fields.field[i], "location")) {
++ ast_string_field_set(event, location, values.value[j]);
++ } else if (!strcasecmp(fields.field[i], "uid")) {
++ ast_string_field_set(event, uid, values.value[j]);
++ } else if (!strcasecmp(fields.field[i], "start")) {
++ event->start = atoi(values.value[j]);
++ } else if (!strcasecmp(fields.field[i], "end")) {
++ event->end = atoi(values.value[j]);
++ } else if (!strcasecmp(fields.field[i], "busystate")) {
++ event->busy_state = atoi(values.value[j]);
++ } else {
++ ast_log(LOG_WARNING, "Unknown calendar event field '%s'\n", fields.field[i]);
++ }
++ }
++
++ if((ret = cal->tech->write_event(event))) {
++ ast_log(LOG_WARNING, "Writing event to calendar '%s' failed!\n", cal->name);
++ }
++
++write_cleanup:
++ if (cal) {
++ cal = unref_calendar(cal);
++ }
++ if (event) {
++ event = ast_calendar_unref_event(event);
++ }
++ if (val_dup) {
++ ast_free(val_dup);
++ }
++
++ return ret;
++}
++
++static struct ast_custom_function calendar_write_function = {
++ .name = "CALENDAR_WRITE",
++ .write = calendar_write_exec,
++};
++
++/*! \brief CLI command to list available calendars */
++static char *handle_show_calendars(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
++{
++#define FORMAT "%-20.20s %-10.10s %-6.6s\n"
++ struct ao2_iterator i;
++ struct ast_calendar *cal;
++
++ switch(cmd) {
++ case CLI_INIT:
++ e->command = "calendar show calendars";
++ e->usage =
++ "Usage: calendar show calendars\n"
++ " Lists all registered calendars.\n";
++ return NULL;
++ case CLI_GENERATE:
++ return NULL;
++ }
++
++ ast_cli(a->fd, FORMAT, "Calendar", "Type", "Status");
++ ast_cli(a->fd, FORMAT, "--------", "----", "------");
++ i = ao2_iterator_init(calendars, 0);
++ while ((cal = ao2_iterator_next(&i))) {
++ ast_cli(a->fd, FORMAT, cal->name, cal->tech->type, calendar_is_busy(cal) ? "busy" : "free");
++ cal = unref_calendar(cal);
++ }
++
++ return CLI_SUCCESS;
++#undef FORMAT
++}
++
++static char *epoch_to_string(char *buf, size_t buflen, time_t epoch)
++{
++ struct ast_tm tm;
++ struct timeval tv = {
++ .tv_sec = epoch,
++ };
++
++ if (!epoch) {
++ *buf = '\0';
++ return buf;
++ }
++ ast_localtime(&tv, &tm, NULL);
++ ast_strftime(buf, buflen, "%F %r", &tm);
++
++ return buf;
++}
++
++static char *handle_show_calendar(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
++{
++#define FORMAT "%-17.17s : %-20.20s\n"
++#define FORMAT2 "%-12.12s: %-40.60s\n"
++ struct ao2_iterator i;
++ struct ast_calendar *cal;
++ struct ast_calendar_event *event;
++ int which = 0;
++ char *ret = NULL;
++
++ switch(cmd) {
++ case CLI_INIT:
++ e->command = "calendar show calendar";
++ e->usage =
++ "Usage: calendar show calendar <calendar name>\n"
++ " Displays information about a calendar\n";
++ return NULL;
++
++ case CLI_GENERATE:
++ if (a->pos != 3) {
++ return NULL;
++ }
++ i = ao2_iterator_init(calendars, 0);
++ while ((cal = ao2_iterator_next(&i))) {
++ if (!strncasecmp(a->word, cal->name, strlen(a->word)) && ++which > a->n) {
++ ret = ast_strdup(cal->name);
++ cal = unref_calendar(cal);
++ break;
++ }
++ cal = unref_calendar(cal);
++ }
++ return ret;
++ }
++
++ if (a->argc != 4) {
++ return CLI_SHOWUSAGE;
++ }
++
++ if (!(cal = find_calendar(a->argv[3]))) {
++ return NULL;
++ }
++
++ ast_cli(a->fd, FORMAT, "Name", cal->name);
++ ast_cli(a->fd, FORMAT, "Notify channel", cal->notify_channel);
++ ast_cli(a->fd, FORMAT, "Notify context", cal->notify_context);
++ ast_cli(a->fd, FORMAT, "Notify extension", cal->notify_extension);
++ ast_cli(a->fd, FORMAT, "Notify application", cal->notify_app);
++ ast_cli(a->fd, FORMAT, "Notify appdata", cal->notify_appdata);
++ ast_cli(a->fd, "%-17.17s : %d\n", "Refresh time", cal->refresh);
++ ast_cli(a->fd, "%-17.17s : %d\n", "Timeframe", cal->timeframe);
++ ast_cli(a->fd, "%-17.17s : %d\n", "Autoreminder", cal->autoreminder);
++ ast_cli(a->fd, "%s\n", "Events");
++ ast_cli(a->fd, "%s\n", "------");
++
++ i = ao2_iterator_init(cal->events, 0);
++ while ((event = ao2_iterator_next(&i))) {
++ char buf[100];
++
++ ast_cli(a->fd, FORMAT2, "Summary", event->summary);
++ ast_cli(a->fd, FORMAT2, "Description", event->description);
++ ast_cli(a->fd, FORMAT2, "Organizer", event->organizer);
++ ast_cli(a->fd, FORMAT2, "Location", event->location);
++ ast_cli(a->fd, FORMAT2, "UID", event->uid);
++ ast_cli(a->fd, FORMAT2, "Start", epoch_to_string(buf, sizeof(buf), event->start));
++ ast_cli(a->fd, FORMAT2, "End", epoch_to_string(buf, sizeof(buf), event->end));
++ ast_cli(a->fd, FORMAT2, "Alarm", epoch_to_string(buf, sizeof(buf), event->alarm));
++ ast_cli(a->fd, "\n");
++
++ event = ast_calendar_unref_event(event);
++ }
++ cal = unref_calendar(cal);
++ return CLI_SUCCESS;
++#undef FORMAT
++#undef FORMAT2
++}
++
++static char *handle_dump_sched(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
++{
++ switch(cmd) {
++ case CLI_INIT:
++ e->command = "calendar dump sched";
++ e->usage =
++ "Usage: calendar dump sched\n"
++ " Dump the calendar sched context";
++ return NULL;
++
++ case CLI_GENERATE:
++ return NULL;
++ }
++
++ ast_sched_dump(sched);
++
++ return CLI_SUCCESS;
++}
++
++static struct ast_cli_entry calendar_cli[] = {
++ AST_CLI_DEFINE(handle_show_calendar, "Display information about a calendar"),
++ AST_CLI_DEFINE(handle_show_calendars, "Show registered calendars"),
++ AST_CLI_DEFINE(handle_dump_sched, "Dump calendar sched context"),
++};
++
++static int calendar_event_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
++{
++ struct ast_datastore *datastore;
++ struct ast_calendar_event *event;
++
++ if (ast_strlen_zero(data)) {
++ ast_log(LOG_WARNING, "%s requires an argument\n", cmd);
++ return -1;
++ }
++
++ ast_channel_lock(chan);
++ if (!(datastore = ast_channel_datastore_find(chan, &event_notification_datastore, NULL))) {
++ ast_log(LOG_WARNING, "There is no event notification datastore on '%s'!\n", chan->name);
++ ast_channel_unlock(chan);
++ return -1;
++ }
++ ast_channel_unlock(chan);
++
++ if (!(event = datastore->data)) {
++ ast_log(LOG_WARNING, "The datastore contains no data!\n");
++ return -1;
++ }
++
++ if (!strcasecmp(data, "summary")) {
++ ast_copy_string(buf, event->summary, len);
++ } else if (!strcasecmp(data, "description")) {
++ ast_copy_string(buf, event->description, len);
++ } else if (!strcasecmp(data, "organizer")) {
++ ast_copy_string(buf, event->organizer, len);
++ } else if (!strcasecmp(data, "location")) {
++ ast_copy_string(buf, event->location, len);
++ } else if (!strcasecmp(data, "calendar")) {
++ ast_copy_string(buf, event->owner->name, len);
++ } else if (!strcasecmp(data, "uid")) {
++ ast_copy_string(buf, event->uid, len);
++ } else if (!strcasecmp(data, "start")) {
++ snprintf(buf, len, "%ld", (long)event->start);
++ } else if (!strcasecmp(data, "end")) {
++ snprintf(buf, len, "%ld", (long)event->end);
++ } else if (!strcasecmp(data, "busystate")) {
++ snprintf(buf, len, "%d", event->busy_state);
++ } else if (!strcasecmp(data, "attendees")) {
++ calendar_join_attendees(event, buf, len);
++ }
++
++
++ return 0;
++}
++
++static struct ast_custom_function calendar_event_function = {
++ .name = "CALENDAR_EVENT",
++ .read = calendar_event_read,
++};
++
++static int cb_pending_deletion(void *user_data, void *arg, int flags)
++{
++ struct ast_calendar *cal = user_data;
++
++ cal->pending_deletion = 1;
++
++ return CMP_MATCH;
++}
++
++static int cb_rm_pending_deletion(void *user_data, void *arg, int flags)
++{
++ struct ast_calendar *cal = user_data;
++
++ return cal->pending_deletion ? CMP_MATCH : 0;
++}
++
++static int reload(void)
++{
++ struct ast_calendar_tech *iter;
++
++ ast_mutex_lock(&reloadlock);
++
++ /* Mark existing calendars for deletion */
++ ao2_callback(calendars, OBJ_NODATA | OBJ_MULTIPLE, cb_pending_deletion, NULL);
++ load_config(NULL);
++
++ AST_LIST_LOCK(&techs);
++ AST_LIST_TRAVERSE(&techs, iter, list) {
++ if (load_tech_calendars(iter)) {
++ ast_log(LOG_WARNING, "Failed to reload %s calendars, module disabled\n", iter->type);
++ }
++ }
++ AST_LIST_UNLOCK(&techs);
++
++ /* Delete calendars that no longer show up in the config */
++ ao2_callback(calendars, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, cb_rm_pending_deletion, NULL);
++
++ ast_mutex_unlock(&reloadlock);
++
++ return 0;
++}
++
++static void *do_refresh(void *data)
++{
++ for (;;) {
++ struct timeval now = ast_tvnow();
++ struct timespec ts = {0,};
++ int res, wait;
++
++ ast_mutex_lock(&refreshlock);
++
++ if ((wait = ast_sched_wait(sched)) < 0) {
++ wait = 1000;
++ }
++
++ ts.tv_sec = (now.tv_sec + wait / 1000) + 1;
++ res = ast_cond_timedwait(&refresh_condition, &refreshlock, &ts);
++
++ ast_mutex_unlock(&refreshlock);
++
++ ast_sched_runq(sched);
++ }
++
++ return NULL;
++}
++
++/* If I were to allow unloading it would look something like this */
++static int unload_module(void)
++{
++ struct ast_calendar_tech *tech;
++
++ ast_devstate_prov_del("calendar");
++ ast_custom_function_unregister(&calendar_busy_function);
++ ast_custom_function_unregister(&calendar_event_function);
++ ast_custom_function_unregister(&calendar_query_function);
++ ast_custom_function_unregister(&calendar_query_result_function);
++ ast_custom_function_unregister(&calendar_write_function);
++ ast_cli_unregister_multiple(calendar_cli, ARRAY_LEN(calendar_cli));
++
++ /* Remove all calendars */
++ ao2_callback(calendars, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL);
++
++ AST_LIST_LOCK(&techs);
++ AST_LIST_TRAVERSE_SAFE_BEGIN(&techs, tech, list) {
++ ast_unload_resource(tech->module, 0);
++ }
++ AST_LIST_TRAVERSE_SAFE_END;
++ AST_LIST_UNLOCK(&techs);
++
++ return 0;
++}
++
++static int load_module(void)
++{
++ if (load_config(NULL)) {
++ /* We don't have calendar support enabled */
++ return 0;
++ }
++
++ if (!(calendars = ao2_container_alloc(CALENDAR_BUCKETS, calendar_hash_fn, calendar_cmp_fn))) {
++ ast_log(LOG_ERROR, "Unable to allocate calendars container!\n");
++ return -1;
++ }
++
++ ast_mutex_init(&refreshlock);
++ ast_cond_init(&refresh_condition, NULL);
++ ast_mutex_init(&reloadlock);
++
++ if (!(sched = sched_context_create())) {
++ ast_log(LOG_ERROR, "Unable to create sched context\n");
++ return -1;
++ }
++
++ if (ast_pthread_create_background(&refresh_thread, NULL, do_refresh, NULL) < 0) {
++ ast_log(LOG_ERROR, "Unable to start refresh thread--notifications disabled!\n");
++ }
++
++ ast_custom_function_register(&calendar_busy_function);
++ ast_custom_function_register(&calendar_event_function);
++ ast_custom_function_register(&calendar_query_function);
++ ast_custom_function_register(&calendar_query_result_function);
++ ast_custom_function_register(&calendar_write_function);
++ ast_cli_register_multiple(calendar_cli, ARRAY_LEN(calendar_cli));
++
++ ast_devstate_prov_add("Calendar", calendarstate);
++
++ /* Since other modules depend on this, disable unloading */
++ ast_module_ref(ast_module_info->self);
++
++ return 0;
++}
++AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "Asterisk Calendar integration",
++ .load = load_module,
++ .unload = unload_module,
++ .reload = reload,
++ );
+
+Property changes on: res/res_calendar.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+Added: svn:mime-type
+ + text/plain
+Added: svn:keywords
+ + Author Date Id Revision
+
+Index: res/res_calendar_exchange.c
+===================================================================
+--- a/res/res_calendar_exchange.c (.../tags/1.6.2.0-beta3) (revision 0)
++++ b/res/res_calendar_exchange.c (.../trunk) (revision 202568)
+@@ -0,0 +1,757 @@
++/*
++ * Asterisk -- An open source telephony toolkit.
++ *
++ * Copyright (C) 2008 - 2009, Digium, Inc.
++ *
++ * Terry Wilson <twilson@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 Resource for handling iCalnedar calendars
++ */
++
++/*** MODULEINFO
++ <depend>neon</depend>
++ <depend>ical</depend>
++ <depend>iksemel</depend>
++***/
++#include "asterisk.h"
++
++ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
++
++#include <libical/ical.h>
++#include <neon/ne_session.h>
++#include <neon/ne_uri.h>
++#include <neon/ne_request.h>
++#include <neon/ne_auth.h>
++#include <iksemel.h>
++
++#include "asterisk/module.h"
++#include "asterisk/calendar.h"
++#include "asterisk/lock.h"
++#include "asterisk/config.h"
++#include "asterisk/astobj2.h"
++
++static void *exchangecal_load_calendar(void *data);
++static void *unref_exchangecal(void *obj);
++static int exchangecal_write_event(struct ast_calendar_event *event);
++
++static struct ast_calendar_tech exchangecal_tech = {
++ .type = "exchange",
++ .description = "MS Exchange calendars",
++ .module = AST_MODULE,
++ .load_calendar = exchangecal_load_calendar,
++ .unref_calendar = unref_exchangecal,
++ .write_event = exchangecal_write_event,
++};
++
++struct exchangecal_pvt {
++ AST_DECLARE_STRING_FIELDS(
++ AST_STRING_FIELD(url);
++ AST_STRING_FIELD(user);
++ AST_STRING_FIELD(secret);
++ );
++ struct ast_calendar *owner;
++ ne_uri uri;
++ ne_session *session;
++ struct ao2_container *events;
++};
++
++struct xmlstate {
++ char tag[80];
++ int in_response;
++ int in_propstat;
++ int in_prop;
++ void *ptr;
++ struct exchangecal_pvt *pvt;
++};
++
++static int parse_tag(void *data, char *name, char **atts, int type)
++{
++ struct xmlstate *state = data;
++ char *tmp;
++
++ if ((tmp = strchr(name, ':'))) {
++ tmp++;
++ } else {
++ return IKS_HOOK;
++ }
++
++ ast_copy_string(state->tag, tmp, sizeof(state->tag));
++
++ switch (type) {
++ case IKS_OPEN:
++ if (!strcasecmp(state->tag, "response")) {
++ struct ast_calendar_event *event;
++
++ state->in_response = 1;
++ if (!(event = ast_calendar_event_alloc(state->pvt->owner))) {
++ return IKS_NOMEM;
++ }
++ state->ptr = event;
++ } else if (!strcasecmp(state->tag, "propstat")) {
++ state->in_propstat = 1;
++ } else if (!strcasecmp(state->tag, "prop")) {
++ state->in_prop = 1;
++ }
++ break;
++
++ case IKS_CLOSE:
++ if (!strcasecmp(state->tag, "response")) {
++ struct ao2_container *events = state->pvt->events;
++ struct ast_calendar_event *event = state->ptr;
++
++ state->in_response = 0;
++ if (ast_strlen_zero(event->uid)) {
++ ast_log(LOG_ERROR, "This event has no UID, something has gone wrong\n");
++ event = ast_calendar_unref_event(event);
++ return IKS_HOOK;
++ }
++ ao2_link(events, event);
++ event = ast_calendar_unref_event(event);
++ } else if (!strcasecmp(state->tag, "propstat")) {
++ state->in_propstat = 0;
++ } else if (!strcasecmp(state->tag, "prop")) {
++ state->in_prop = 0;
++ }
++ break;
++
++ default:
++ return IKS_OK;
++ }
++
++ return IKS_OK;
++}
++
++static time_t mstime_to_time_t(char *mstime)
++{
++ char *read, *write;
++ icaltimetype tt;
++ for (read = write = mstime; *read; read++) {
++ if (*read == '.') {
++ *write++ = 'Z';
++ *write = '\0';
++ break;
++ }
++ if (*read == '-' || *read == ':')
++ continue;
++ *write = *read;
++ write++;
++ }
++
++ tt = icaltime_from_string(mstime);
++ return icaltime_as_timet(tt);
++}
++
++static enum ast_calendar_busy_state msbusy_to_bs(const char *msbusy)
++{
++ if (!strcasecmp(msbusy, "FREE")) {
++ return AST_CALENDAR_BS_FREE;
++ } else if (!strcasecmp(msbusy, "TENTATIVE")) {
++ return AST_CALENDAR_BS_BUSY_TENTATIVE;
++ } else {
++ return AST_CALENDAR_BS_BUSY;
++ }
++}
++
++static int parse_cdata(void *data, char *value, size_t len)
++{
++ char *str;
++ struct xmlstate *state = data;
++ struct ast_calendar_event *event = state->ptr;
++
++
++ str = ast_skip_blanks(value);
++
++ if (str == value + len)
++ return IKS_OK;
++
++ if (!(str = ast_calloc(1, len + 1))) {
++ return IKS_NOMEM;
++ }
++ memcpy(str, value, len);
++ if (!(state->in_response && state->in_propstat && state->in_prop)) {
++ ast_free(str);
++ return IKS_OK;
++ }
++ /* We use ast_string_field_build here because libiksemel is parsing CDATA with &lt; as
++ * new elements which is a bit odd and shouldn't happen */
++ if (!strcasecmp(state->tag, "subject")) {
++ ast_string_field_build(event, summary, "%s%s", event->summary, str);
++ } else if (!strcasecmp(state->tag, "location")) {
++ ast_string_field_build(event, location, "%s%s", event->location, str);
++ } else if (!strcasecmp(state->tag, "uid")) {
++ ast_string_field_build(event, uid, "%s%s", event->location, str);
++ } else if (!strcasecmp(state->tag, "organizer")) {
++ ast_string_field_build(event, organizer, "%s%s", event->organizer, str);
++ } else if (!strcasecmp(state->tag, "textdescription")) {
++ ast_string_field_build(event, description, "%s%s", event->description, str);
++ } else if (!strcasecmp(state->tag, "dtstart")) {
++ event->start = mstime_to_time_t(str);
++ } else if (!strcasecmp(state->tag, "dtend")) {
++ event->end = mstime_to_time_t(str);
++ } else if (!strcasecmp(state->tag, "busystatus")) {
++ event->busy_state = msbusy_to_bs(str);
++ } else if (!strcasecmp(state->tag, "reminderoffset")) {
++ /*XXX Currently we rely on event->start being set first which means we rely on the response order
++ * which technically should be fine since the query returns in the order we ask for, but ... */
++ event->alarm = event->start - atoi(str);
++ }
++
++ ast_free(str);
++ return IKS_OK;
++}
++
++static int cb_true(void *user_data, void *arg, int flags)
++{
++ return CMP_MATCH;
++}
++
++static void exchangecal_destructor(void *obj)
++{
++ struct exchangecal_pvt *pvt = obj;
++
++ ast_debug(1, "Destroying pvt for Exchange calendar %s\n", pvt->owner->name);
++ if (pvt->session) {
++ ne_session_destroy(pvt->session);
++ }
++ ast_string_field_free_memory(pvt);
++
++ ao2_callback(pvt->events, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, cb_true, NULL);
++
++ ao2_ref(pvt->events, -1);
++}
++
++static void *unref_exchangecal(void *obj)
++{
++ struct exchangecal_pvt *pvt = obj;
++
++ ao2_ref(pvt, -1);
++ return NULL;
++}
++
++/* It is very important to use the return value of this function as a realloc could occur */
++static struct ast_str *generate_exchange_uuid(struct ast_str *uid)
++{
++ unsigned short val[8];
++ int x;
++
++ for (x = 0; x < 8; x++) {
++ val[x] = ast_random();
++ }
++ ast_str_set(&uid, 0, "%04x%04x-%04x-%04x-%04x-%04x%04x%04x", val[0], val[1], val[2], val[3], val[4], val[5], val[6], val[7]);
++
++ return uid;
++}
++
++static int is_valid_uuid(struct ast_str *uid)
++{
++ int i;
++
++ if (ast_str_strlen(uid) != 36) {
++ return 0;
++ }
++
++ for (i = 0; i < ast_str_strlen(uid); i++) {
++ if (i == 8 || i == 13 || i == 18 || i == 23) {
++ if (ast_str_buffer(uid)[i] != '-') {
++ return 0;
++ }
++ } else if (!((ast_str_buffer(uid)[i] > 47 && ast_str_buffer(uid)[i] < 58) || (ast_str_buffer(uid)[i] > 96 && ast_str_buffer(uid)[i] < 103))) {
++ return 0;
++ }
++ }
++
++ return 1;
++}
++
++static struct ast_str *xml_encode_str(struct ast_str *dst, const char *src)
++{
++ const char *tmp;
++ char buf[7];
++
++ for (tmp = src; *tmp; tmp++) {
++ switch (*tmp) {
++ case '\"':
++ strcpy(buf, "&quot;");
++ break;
++
++ case '\'':
++ strcpy(buf, "&apos;");
++ break;
++
++ case '&':
++ strcpy(buf, "&amp;");
++ break;
++
++ case '<':
++ strcpy(buf, "&lt;");
++ break;
++
++ case '>':
++ strcpy(buf, "&gt;");
++ break;
++
++ default:
++ sprintf(buf, "%c", *tmp);
++ }
++
++ ast_str_append(&dst, 0, "%s", buf);
++ }
++
++ return dst;
++}
++
++static struct ast_str *epoch_to_exchange_time(struct ast_str *dst, time_t epoch)
++{
++ icaltimezone *utc = icaltimezone_get_utc_timezone();
++ icaltimetype tt = icaltime_from_timet_with_zone(epoch, 0, utc);
++ char tmp[30];
++ int i;
++
++ ast_copy_string(tmp, icaltime_as_ical_string(tt), sizeof(tmp));
++ for (i = 0; tmp[i]; i++) {
++ ast_str_append(&dst, 0, "%c", tmp[i]);
++ if (i == 3 || i == 5)
++ ast_str_append(&dst, 0, "%c", '-');
++ if (i == 10 || i == 12)
++ ast_str_append(&dst, 0, "%c", ':');
++ if (i == 14)
++ ast_str_append(&dst, 0, "%s", ".000");
++ }
++
++ return dst;
++}
++
++static struct ast_str *bs_to_exchange_bs(struct ast_str *dst, enum ast_calendar_busy_state bs)
++{
++ switch (bs) {
++ case AST_CALENDAR_BS_BUSY:
++ ast_str_set(&dst, 0, "%s", "BUSY");
++ break;
++
++ case AST_CALENDAR_BS_BUSY_TENTATIVE:
++ ast_str_set(&dst, 0, "%s", "TENTATIVE");
++ break;
++
++ default:
++ ast_str_set(&dst, 0, "%s", "FREE");
++ }
++
++ return dst;
++}
++
++static int fetch_response_reader(void *data, const char *block, size_t len)
++{
++ struct ast_str **response = data;
++ unsigned char *tmp;
++
++ if (!(tmp = ast_malloc(len + 1))) {
++ return -1;
++ }
++ memcpy(tmp, block, len);
++ tmp[len] = '\0';
++ ast_str_append(response, 0, "%s", tmp);
++ ast_free(tmp);
++
++ return 0;
++}
++
++static int auth_credentials(void *userdata, const char *realm, int attempts, char *username, char *secret)
++{
++ struct exchangecal_pvt *pvt = userdata;
++
++ if (attempts > 1) {
++ ast_log(LOG_WARNING, "Invalid username or password for Exchange calendar '%s'\n", pvt->owner->name);
++ return -1;
++ }
++
++ ne_strnzcpy(username, pvt->user, NE_ABUFSIZ);
++ ne_strnzcpy(secret, pvt->secret, NE_ABUFSIZ);
++
++ return 0;
++}
++
++static struct ast_str *exchangecal_request(struct exchangecal_pvt *pvt, const char *method, struct ast_str *req_body, struct ast_str *subdir)
++{
++ struct ast_str *response;
++ ne_request *req;
++ int ret;
++ char buf[1000];
++
++ if (!pvt) {
++ ast_log(LOG_ERROR, "There is no private!\n");
++ return NULL;
++ }
++
++ if (!(response = ast_str_create(512))) {
++ ast_log(LOG_ERROR, "Could not allocate memory for response.\n");
++ return NULL;
++ }
++
++ snprintf(buf, sizeof(buf), "%s%s", pvt->uri.path, subdir ? ast_str_buffer(subdir) : "");
++
++ req = ne_request_create(pvt->session, method, buf);
++ ne_add_response_body_reader(req, ne_accept_2xx, fetch_response_reader, &response);
++ ne_set_request_body_buffer(req, ast_str_buffer(req_body), ast_str_strlen(req_body));
++ ne_add_request_header(req, "Content-type", "text/xml");
++
++ ret = ne_request_dispatch(req);
++
++ if (ret != NE_OK || !ast_str_strlen(response)) {
++ ast_log(LOG_WARNING, "Unknown response to CalDAV calendar %s, request %s to %s: %s\n", pvt->owner->name, method, pvt->url, ne_get_error(pvt->session));
++ ast_free(response);
++ return NULL;
++ }
++
++ return response;
++}
++
++static int exchangecal_write_event(struct ast_calendar_event *event)
++{
++ struct ast_str *body = NULL, *response = NULL, *subdir = NULL;
++ struct ast_str *uid = NULL, *summary = NULL, *description = NULL, *organizer = NULL,
++ *location = NULL, *start = NULL, *end = NULL, *busystate = NULL;
++ int ret = -1;
++
++ if (!event) {
++ ast_log(LOG_WARNING, "No event passed!\n");
++ return -1;
++ }
++
++ if (!(event->start && event->end)) {
++ ast_log(LOG_WARNING, "The event must contain a start and an end\n");
++ return -1;
++ }
++ if (!(body = ast_str_create(512)) ||
++ !(subdir = ast_str_create(32)) ||
++ !(response = ast_str_create(512))) {
++ ast_log(LOG_ERROR, "Could not allocate memory for request and response!\n");
++ goto write_cleanup;
++ }
++
++ if (!(uid = ast_str_create(32)) ||
++ !(summary = ast_str_create(32)) ||
++ !(description = ast_str_create(32)) ||
++ !(organizer = ast_str_create(32)) ||
++ !(location = ast_str_create(32)) ||
++ !(start = ast_str_create(32)) ||
++ !(end = ast_str_create(32)) ||
++ !(busystate = ast_str_create(32))) {
++ ast_log(LOG_ERROR, "Unable to allocate memory for request values\n");
++ goto write_cleanup;
++ }
++
++ if (ast_strlen_zero(event->uid)) {
++ uid = generate_exchange_uuid(uid);
++ } else {
++ ast_str_set(&uid, 36, "%s", event->uid);
++ }
++
++ if (!is_valid_uuid(uid)) {
++ ast_log(LOG_WARNING, "An invalid uid was provided, you may leave this field blank to have one generated for you\n");
++ goto write_cleanup;
++ }
++
++ summary = xml_encode_str(summary, event->summary);
++ description = xml_encode_str(description, event->description);
++ organizer = xml_encode_str(organizer, event->organizer);
++ location = xml_encode_str(location, event->location);
++ start = epoch_to_exchange_time(start, event->start);
++ end = epoch_to_exchange_time(end, event->end);
++ busystate = bs_to_exchange_bs(busystate, event->busy_state);
++
++ ast_str_append(&body, 0,
++ "<?xml version=\"1.0\"?>\n"
++ "<a:propertyupdate\n"
++ " xmlns:a=\"DAV:\"\n"
++ " xmlns:e=\"http://schemas.microsoft.com/exchange/\"\n"
++ " xmlns:mapi=\"http://schemas.microsoft.com/mapi/\"\n"
++ " xmlns:mapit=\"http://schemas.microsoft.com/mapi/proptag/\"\n"
++ " xmlns:x=\"xml:\" xmlns:cal=\"urn:schemas:calendar:\"\n"
++ " xmlns:dt=\"uuid:%s/\"\n" /* uid */
++ " xmlns:header=\"urn:schemas:mailheader:\"\n"
++ " xmlns:mail=\"urn:schemas:httpmail:\"\n"
++ ">\n"
++ " <a:set>\n"
++ " <a:prop>\n"
++ " <a:contentclass>urn:content-classes:appointment</a:contentclass>\n"
++ " <e:outlookmessageclass>IPM.Appointment</e:outlookmessageclass>\n"
++ " <mail:subject>%s</mail:subject>\n" /* summary */
++ " <mail:description>%s</mail:description>\n" /* description */
++ " <header:to>%s</header:to>\n" /* organizer */
++ " <cal:location>%s</cal:location>\n" /* location */
++ " <cal:dtstart dt:dt=\"dateTime.tz\">%s</cal:dtstart>\n" /* start */
++ " <cal:dtend dt:dt=\"dateTime.tz\">%s</cal:dtend>\n" /* end */
++ " <cal:instancetype dt:dt=\"int\">0</cal:instancetype>\n"
++ " <cal:busystatus>%s</cal:busystatus>\n" /* busy_state (BUSY, FREE, BUSY_TENTATIVE) */
++ " <cal:meetingstatus>CONFIRMED</cal:meetingstatus>\n"
++ " <cal:alldayevent dt:dt=\"boolean\">0</cal:alldayevent>\n" /* XXX need to add event support for all day events */
++ " <cal:responserequested dt:dt=\"boolean\">0</cal:responserequested>\n"
++ " <mapi:finvited dt:dt=\"boolean\">1</mapi:finvited>\n"
++ " </a:prop>\n"
++ " </a:set>\n"
++ "</a:propertyupdate>\n",
++ ast_str_buffer(uid), ast_str_buffer(summary), ast_str_buffer(description), ast_str_buffer(organizer), ast_str_buffer(location), ast_str_buffer(start), ast_str_buffer(end), ast_str_buffer(busystate));
++ ast_verb(0, "\n\n%s\n\n", ast_str_buffer(body));
++ ast_str_set(&subdir, 0, "/Calendar/%s.eml", ast_str_buffer(uid));
++
++ response = exchangecal_request(event->owner->tech_pvt, "PROPPATCH", body, subdir);
++
++ ret = 0;
++write_cleanup:
++ if (uid) {
++ ast_free(uid);
++ }
++ if (summary) {
++ ast_free(summary);
++ }
++ if (description) {
++ ast_free(description);
++ }
++ if (organizer) {
++ ast_free(organizer);
++ }
++ if (location) {
++ ast_free(location);
++ }
++ if (start) {
++ ast_free(start);
++ }
++ if (end) {
++ ast_free(end);
++ }
++ if (busystate) {
++ ast_free(busystate);
++ }
++ if (body) {
++ ast_free(body);
++ }
++ if (response) {
++ ast_free(response);
++ }
++ if (subdir) {
++ ast_free(subdir);
++ }
++
++ return ret;
++}
++
++
++static struct ast_str *exchangecal_get_events_between(struct exchangecal_pvt *pvt, time_t start_time, time_t end_time)
++{
++ struct ast_str *body, *response;
++ char start[80], end[80];
++ struct timeval tv = {0,};
++ struct ast_tm tm;
++
++ tv.tv_sec = start_time;
++ ast_localtime(&tv, &tm, "UTC");
++ ast_strftime(start, sizeof(start), "%Y/%m/%d %T", &tm);
++
++ tv.tv_sec = end_time;
++ ast_localtime(&tv, &tm, "UTC");
++ ast_strftime(end, sizeof(end), "%Y/%m/%d %T", &tm);
++
++ if (!(body = ast_str_create(512))) {
++ ast_log(LOG_ERROR, "Could not allocate memory for body of request!\n");
++ return NULL;
++ }
++
++ ast_str_append(&body, 0,
++ "<?xml version=\"1.0\"?>\n"
++ "<g:searchrequest xmlns:g=\"DAV:\">\n"
++ " <g:sql> SELECT \"urn:schemas:calendar:location\", \"urn:schemas:httpmail:subject\",\n"
++ " \"urn:schemas:calendar:dtstart\", \"urn:schemas:calendar:dtend\",\n"
++ " \"urn:schemas:calendar:busystatus\", \"urn:schemas:calendar:instancetype\",\n"
++ " \"urn:schemas:calendar:uid\", \"urn:schemas:httpmail:textdescription\",\n"
++ " \"urn:schemas:calendar:organizer\", \"urn:schemas:calendar:reminderoffset\"\n"
++ " FROM Scope('SHALLOW TRAVERSAL OF \"%s/Calendar\"')\n"
++ " WHERE NOT \"urn:schemas:calendar:instancetype\" = 1\n"
++ " AND \"DAV:contentclass\" = 'urn:content-classes:appointment'\n"
++ " AND NOT (\"urn:schemas:calendar:dtend\" &lt; '%s'\n"
++ " OR \"urn:schemas:calendar:dtstart\" &gt; '%s')\n"
++ " ORDER BY \"urn:schemas:calendar:dtstart\" ASC\n"
++ " </g:sql>\n"
++ "</g:searchrequest>\n", pvt->url, start, end);
++
++ ast_debug(5, "Request:\n%s\n", ast_str_buffer(body));
++ response = exchangecal_request(pvt, "SEARCH", body, NULL);
++ ast_debug(5, "Response:\n%s\n", ast_str_buffer(response));
++ ast_free(body);
++
++ return response;
++}
++
++static int update_exchangecal(struct exchangecal_pvt *pvt)
++{
++ struct xmlstate state;
++ struct timeval now = ast_tvnow();
++ time_t start, end;
++ struct ast_str *response;
++ iksparser *p;
++
++ state.pvt = pvt;
++ start = now.tv_sec;
++ end = now.tv_sec + 60 * pvt->owner->timeframe;
++ if (!(response = exchangecal_get_events_between(pvt, start, end))) {
++ return -1;
++ }
++
++ p = iks_sax_new(&state, parse_tag, parse_cdata);
++ iks_parse(p, ast_str_buffer(response), ast_str_strlen(response), 1);
++ ast_calendar_merge_events(pvt->owner, pvt->events);
++ ast_free(response);
++
++ return 0;
++}
++
++static void *exchangecal_load_calendar(void *void_data)
++{
++ struct exchangecal_pvt *pvt;
++ struct ast_variable *v;
++ struct ast_calendar *cal = void_data;
++ ast_mutex_t refreshlock;
++
++ if (!(cal && ast_calendar_config)) {
++ ast_log(LOG_ERROR, "You must enable calendar support for res_exchangecal to load\n");
++ return NULL;
++ }
++
++ if (ao2_trylock(cal)) {
++ if (cal->unloading) {
++ ast_log(LOG_WARNING, "Unloading module, load_calendar cancelled.\n");
++ } else {
++ ast_log(LOG_WARNING, "Could not lock calendar, aborting!\n");
++ }
++ return NULL;
++ }
++
++ if (!(pvt = ao2_alloc(sizeof(*pvt), exchangecal_destructor))) {
++ ast_log(LOG_ERROR, "Could not allocate exchangecal_pvt structure for calendar: %s\n", cal->name);
++ return NULL;
++ }
++
++ pvt->owner = cal;
++
++ if (!(pvt->events = ast_calendar_event_container_alloc())) {
++ ast_log(LOG_ERROR, "Could not allocate space for fetching events for calendar: %s\n", cal->name);
++ pvt = unref_exchangecal(pvt);
++ ao2_unlock(cal);
++ return NULL;
++ }
++
++ if (ast_string_field_init(pvt, 32)) {
++ ast_log(LOG_ERROR, "Couldn't allocate string field space for calendar: %s\n", cal->name);
++ pvt = unref_exchangecal(pvt);
++ ao2_unlock(cal);
++ return NULL;
++ }
++
++ for (v = ast_variable_browse(ast_calendar_config, cal->name); v; v = v->next) {
++ if (!strcasecmp(v->name, "url")) {
++ ast_string_field_set(pvt, url, v->value);
++ } else if (!strcasecmp(v->name, "user")) {
++ ast_string_field_set(pvt, user, v->value);
++ } else if (!strcasecmp(v->name, "secret")) {
++ ast_string_field_set(pvt, secret, v->value);
++ }
++ }
++
++ if (ast_strlen_zero(pvt->url)) {
++ ast_log(LOG_WARNING, "No URL was specified for Exchange calendar '%s' - skipping.\n", cal->name);
++ pvt = unref_exchangecal(pvt);
++ ao2_unlock(cal);
++ return NULL;
++ }
++
++ if (ne_uri_parse(pvt->url, &pvt->uri) || pvt->uri.host == NULL || pvt->uri.path == NULL) {
++ ast_log(LOG_WARNING, "Could not parse url '%s' for Exchange calendar '%s' - skipping.\n", pvt->url, cal->name);
++ pvt = unref_exchangecal(pvt);
++ ao2_unlock(cal);
++ return NULL;
++ }
++
++ if (pvt->uri.scheme == NULL) {
++ pvt->uri.scheme = "http";
++ }
++
++ if (pvt->uri.port == 0) {
++ pvt->uri.port = ne_uri_defaultport(pvt->uri.scheme);
++ }
++
++ pvt->session = ne_session_create(pvt->uri.scheme, pvt->uri.host, pvt->uri.port);
++ ne_set_server_auth(pvt->session, auth_credentials, pvt);
++ if (!strncasecmp(pvt->uri.scheme, "https", sizeof(pvt->uri.scheme))) {
++ ne_ssl_trust_default_ca(pvt->session);
++ }
++
++ cal->tech_pvt = pvt;
++
++ ast_mutex_init(&refreshlock);
++
++ /* Load it the first time */
++ update_exchangecal(pvt);
++
++ ao2_unlock(cal);
++
++ /* The only writing from another thread will be if unload is true */
++ for (;;) {
++ struct timeval tv = ast_tvnow();
++ struct timespec ts = {0,};
++
++ ts.tv_sec = tv.tv_sec + (60 * pvt->owner->refresh);
++
++ ast_mutex_lock(&refreshlock);
++ while (!pvt->owner->unloading) {
++ if (ast_cond_timedwait(&pvt->owner->unload, &refreshlock, &ts) == ETIMEDOUT) {
++ break;
++ }
++ }
++ ast_mutex_unlock(&refreshlock);
++
++ if (pvt->owner->unloading) {
++ ast_debug(10, "Skipping refresh since we got a shutdown signal\n");
++ return NULL;
++ }
++
++ ast_debug(10, "Refreshing after %d minute timeout\n", pvt->owner->refresh);
++
++ update_exchangecal(pvt);
++ }
++
++ return NULL;
++}
++
++static int load_module(void)
++{
++ ne_sock_init();
++ if (ast_calendar_register(&exchangecal_tech)) {
++ ne_sock_exit();
++ return AST_MODULE_LOAD_DECLINE;
++ }
++
++ return AST_MODULE_LOAD_SUCCESS;
++}
++
++static int unload_module(void)
++{
++ ast_calendar_unregister(&exchangecal_tech);
++ ne_sock_exit();
++ return 0;
++}
++
++AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Asterisk MS Exchange Calendar Integration",
++ .load = load_module,
++ .unload = unload_module,
++ );
+
+Property changes on: res/res_calendar_exchange.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+Added: svn:mime-type
+ + text/plain
+Added: svn:keywords
+ + Author Date Id Revision
+
+Index: res/res_snmp.c
+===================================================================
+--- a/res/res_snmp.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/res/res_snmp.c (.../trunk) (revision 202568)
+@@ -34,7 +34,7 @@
+
+ int res_snmp_agentx_subagent;
+ int res_snmp_dont_stop;
+-int res_snmp_enabled;
++static int res_snmp_enabled;
+
+ static pthread_t thread = AST_PTHREADT_NULL;
+
+@@ -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/res_limit.c
+===================================================================
+--- a/res/res_limit.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/res/res_limit.c (.../trunk) (revision 202568)
+@@ -40,7 +40,7 @@
+ #endif
+ #endif
+
+-static struct limits {
++static const struct limits {
+ int resource;
+ char limit[3];
+ char desc[40];
+@@ -154,7 +154,7 @@
+
+ if (a->argc == 1) {
+ char arg2[15];
+- char *newargv[2] = { "ulimit", arg2 };
++ const char * const 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].clicmd, sizeof(arg2));
+Index: res/res_agi.exports
+===================================================================
+--- a/res/res_agi.exports (.../tags/1.6.2.0-beta3) (revision 0)
++++ b/res/res_agi.exports (.../trunk) (revision 202568)
+@@ -0,0 +1,10 @@
++{
++ global:
++ *ast_agi_register;
++ *ast_agi_unregister;
++ *ast_agi_register_multiple;
++ *ast_agi_unregister_multiple;
++ *ast_agi_send;
++ 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_jabber.c
+===================================================================
+--- a/res/res_jabber.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/res/res_jabber.c (.../trunk) (revision 202568)
+@@ -166,6 +166,26 @@
+ </enumlist>
+ </description>
+ </function>
++ <manager name="JabberSend" language="en_US">
++ <synopsis>
++ Sends a message to a Jabber Client.
++ </synopsis>
++ <syntax>
++ <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
++ <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>Sends a message to a Jabber Client.</para>
++ </description>
++ </manager>
+ ***/
+
+ /*! \todo This should really be renamed to xmpp.conf. For backwards compatibility, we
+@@ -183,8 +203,6 @@
+ /*-- Forward declarations */
+ static void aji_buddy_destroy(struct aji_buddy *obj);
+ static void aji_client_destroy(struct aji_client *obj);
+-static int aji_send_exec(struct ast_channel *chan, void *data);
+-static int aji_status_exec(struct ast_channel *chan, void *data);
+ static int aji_is_secure(struct aji_client *client);
+ #ifdef HAVE_OPENSSL
+ static int aji_start_tls(struct aji_client *client);
+@@ -243,8 +261,8 @@
+
+ static char *app_ajistatus = "JabberStatus";
+
+-struct aji_client_container clients;
+-struct aji_capabilities *capabilities = NULL;
++static struct aji_client_container clients;
++static struct aji_capabilities *capabilities = NULL;
+
+ /*! \brief Global flags, initialized to default values */
+ static struct ast_flags globalflags = { AJI_AUTOREGISTER };
+@@ -429,7 +447,7 @@
+ * \param data
+ * \return 0 on success, -1 on error
+ */
+-static int aji_status_exec(struct ast_channel *chan, void *data)
++static int aji_status_exec(struct ast_channel *chan, const char *data)
+ {
+ struct aji_client *client = NULL;
+ struct aji_buddy *buddy = NULL;
+@@ -545,7 +563,7 @@
+ * \param data Data is sender|reciever|message.
+ * \return 0 on success,-1 on error.
+ */
+-static int aji_send_exec(struct ast_channel *chan, void *data)
++static int aji_send_exec(struct ast_channel *chan, const char *data)
+ {
+ struct aji_client *client = NULL;
+ char *s;
+@@ -563,7 +581,7 @@
+
+ AST_STANDARD_APP_ARGS(args, s);
+ if (args.argc < 3) {
+- ast_log(LOG_ERROR, "JabberSend requires 3 arguments: '%s'\n", (char *) data);
++ ast_log(LOG_ERROR, "JabberSend requires 3 arguments: '%s'\n", data);
+ return -1;
+ }
+
+@@ -2982,13 +3000,6 @@
+ return &clients;
+ }
+
+-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"
+-" 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
+ * \param s mansession Manager session
+@@ -3091,8 +3102,7 @@
+ ASTOBJ_CONTAINER_INIT(&clients);
+ if(!aji_reload(0))
+ 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_manager_register_xml("JabberSend", EVENT_FLAG_SYSTEM, manager_jabber_send);
+ 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));
+Index: res/res_monitor.c
+===================================================================
+--- a/res/res_monitor.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/res/res_monitor.c (.../trunk) (revision 202568)
+@@ -45,6 +45,200 @@
+ #include "asterisk/config.h"
+ #include "asterisk/options.h"
+
++/*** DOCUMENTATION
++ <application name="Monitor" language="en_US">
++ <synopsis>
++ Monitor a channel.
++ </synopsis>
++ <syntax>
++ <parameter name="file_format" argsep=":">
++ <argument name="file_format" required="true">
++ <para>optional, if not set, defaults to <literal>wav</literal></para>
++ </argument>
++ <argument name="urlbase" />
++ </parameter>
++ <parameter name="fname_base">
++ <para>if set, changes the filename used to the one specified.</para>
++ </parameter>
++ <parameter name="options">
++ <optionlist>
++ <option name="m">
++ <para>when the recording ends mix the two leg files into one and
++ delete the two leg files. If the variable <variable>MONITOR_EXEC</variable>
++ is set, the application referenced in it will be executed instead of
++ soxmix/sox and the raw leg files will NOT be deleted automatically.
++ soxmix/sox or <variable>MONITOR_EXEC</variable> is handed 3 arguments,
++ the two leg files and a target mixed file name which is the same as
++ the leg file names only without the in/out designator.</para>
++ <para>If <variable>MONITOR_EXEC_ARGS</variable> is set, the contents
++ will be passed on as additional arguments to <variable>MONITOR_EXEC</variable>.
++ Both <variable>MONITOR_EXEC</variable> and the Mix flag can be set from the
++ administrator interface.</para>
++ </option>
++ <option name="b">
++ <para>Don't begin recording unless a call is bridged to another channel.</para>
++ </option>
++ <option name="i">
++ <para>Skip recording of input stream (disables <literal>m</literal> option).</para>
++ </option>
++ <option name="o">
++ <para>Skip recording of output stream (disables <literal>m</literal> option).</para>
++ </option>
++ </optionlist>
++ </parameter>
++ </syntax>
++ <description>
++ <para>Used to start monitoring a channel. The channel's input and output
++ voice packets are logged to files until the channel hangs up or
++ monitoring is stopped by the StopMonitor application.</para>
++ <para>By default, files are stored to <filename>/var/spool/asterisk/monitor/</filename>.
++ Returns <literal>-1</literal> if monitor files can't be opened or if the channel is
++ already monitored, otherwise <literal>0</literal>.</para>
++ </description>
++ <see-also>
++ <ref type="application">StopMonitor</ref>
++ </see-also>
++ </application>
++ <application name="StopMonitor" language="en_US">
++ <synopsis>
++ Stop monitoring a channel.
++ </synopsis>
++ <syntax />
++ <description>
++ <para>Stops monitoring a channel. Has no effect if the channel is not monitored.</para>
++ </description>
++ </application>
++ <application name="ChangeMonitor" language="en_US">
++ <synopsis>
++ Change monitoring filename of a channel.
++ </synopsis>
++ <syntax>
++ <parameter name="filename_base" required="true">
++ <para>The new filename base to use for monitoring this channel.</para>
++ </parameter>
++ </syntax>
++ <description>
++ <para>Changes monitoring filename of a channel. Has no effect if the
++ channel is not monitored.</para>
++ </description>
++ </application>
++ <application name="PauseMonitor" language="en_US">
++ <synopsis>
++ Pause monitoring of a channel.
++ </synopsis>
++ <syntax />
++ <description>
++ <para>Pauses monitoring of a channel until it is re-enabled by a call to UnpauseMonitor.</para>
++ </description>
++ <see-also>
++ <ref type="application">UnpauseMonitor</ref>
++ </see-also>
++ </application>
++ <application name="UnpauseMonitor" language="en_US">
++ <synopsis>
++ Unpause monitoring of a channel.
++ </synopsis>
++ <syntax />
++ <description>
++ <para>Unpauses monitoring of a channel on which monitoring had
++ previously been paused with PauseMonitor.</para>
++ </description>
++ <see-also>
++ <ref type="application">PauseMonitor</ref>
++ </see-also>
++ </application>
++ <manager name="Monitor" language="en_US">
++ <synopsis>
++ Monitor a channel.
++ </synopsis>
++ <syntax>
++ <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
++ <parameter name="Channel" required="true">
++ <para>Used to specify the channel to record.</para>
++ </parameter>
++ <parameter name="File">
++ <para>Is the name of the file created in the monitor spool directory.
++ Defaults to the same name as the channel (with slashes replaced with dashes).</para>
++ </parameter>
++ <parameter name="Format">
++ <para>Is the audio recording format. Defaults to <literal>wav</literal>.</para>
++ </parameter>
++ <parameter name="Mix">
++ <para>Boolean parameter as to whether to mix the input and output channels
++ together after the recording is finished.</para>
++ </parameter>
++ </syntax>
++ <description>
++ <para>This action may be used to record the audio on a
++ specified channel.</para>
++ </description>
++ </manager>
++ <manager name="StopMonitor" language="en_US">
++ <synopsis>
++ Stop monitoring a channel.
++ </synopsis>
++ <syntax>
++ <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
++ <parameter name="Channel" required="true">
++ <para>The name of the channel monitored.</para>
++ </parameter>
++ </syntax>
++ <description>
++ <para>This action may be used to end a previously started 'Monitor' action.</para>
++ </description>
++ </manager>
++ <manager name="ChangeMonitor" language="en_US">
++ <synopsis>
++ Change monitoring filename of a channel.
++ </synopsis>
++ <syntax>
++ <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
++ <parameter name="Channel" required="true">
++ <para>Used to specify the channel to record.</para>
++ </parameter>
++ <parameter name="File" required="true">
++ <para>Is the new name of the file created in the
++ monitor spool directory.</para>
++ </parameter>
++ </syntax>
++ <description>
++ <para>This action may be used to change the file
++ started by a previous 'Monitor' action.</para>
++ </description>
++ </manager>
++ <manager name="PauseMonitor" language="en_US">
++ <synopsis>
++ Pause monitoring of a channel.
++ </synopsis>
++ <syntax>
++ <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
++ <parameter name="Channel" required="true">
++ <para>Used to specify the channel to record.</para>
++ </parameter>
++ </syntax>
++ <description>
++ <para>This action may be used to temporarily stop the
++ recording of a channel.</para>
++ </description>
++ </manager>
++ <manager name="UnpauseMonitor" language="en_US">
++ <synopsis>
++ Unpause monitoring of a channel.
++ </synopsis>
++ <syntax>
++ <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
++ <parameter name="Channel" required="true">
++ <para>Used to specify the channel to record.</para>
++ </parameter>
++ </syntax>
++ <description>
++ <para>This action may be used to re-enable recording
++ of a channel after calling PauseMonitor.</para>
++ </description>
++ </manager>
++
++ ***/
++
+ AST_MUTEX_DEFINE_STATIC(monitorlock);
+
+ #define LOCK_IF_NEEDED(lock, needed) do { \
+@@ -59,62 +253,6 @@
+
+ static unsigned long seq = 0;
+
+-static char *monitor_synopsis = "Monitor a channel";
+-
+-static char *monitor_descrip = " Monitor([file_format[:urlbase],[fname_base],[options]]):\n"
+-"Used to start monitoring a channel. The channel's input and output\n"
+-"voice packets are logged to files until the channel hangs up or\n"
+-"monitoring is stopped by the StopMonitor application.\n"
+-" file_format optional, if not set, defaults to \"wav\"\n"
+-" fname_base if set, changes the filename used to the one specified.\n"
+-" options:\n"
+-" m - when the recording ends mix the two leg files into one and\n"
+-" delete the two leg files. If the variable MONITOR_EXEC is set, the\n"
+-" application referenced in it will be executed instead of\n"
+-#ifdef HAVE_SOXMIX
+-" soxmix and the raw leg files will NOT be deleted automatically.\n"
+-" soxmix or MONITOR_EXEC is handed 3 arguments, the two leg files\n"
+-#else
+-" sox and the raw leg files will NOT be deleted automatically.\n"
+-" sox or MONITOR_EXEC is handed 3 arguments, the two leg files\n"
+-#endif
+-" and a target mixed file name which is the same as the leg file names\n"
+-" only without the in/out designator.\n"
+-" If MONITOR_EXEC_ARGS is set, the contents will be passed on as\n"
+-" additional arguments to MONITOR_EXEC\n"
+-" Both MONITOR_EXEC and the Mix flag can be set from the\n"
+-" administrator interface\n"
+-"\n"
+-" b - Don't begin recording unless a call is bridged to another channel\n"
+-" i - Skip recording of input stream (disables m option)\n"
+-" o - Skip recording of output stream (disables m option)\n"
+-"\nBy default, files are stored to /var/spool/asterisk/monitor/.\n"
+-"\nReturns -1 if monitor files can't be opened or if the channel is already\n"
+-"monitored, otherwise 0.\n"
+-;
+-
+-static char *stopmonitor_synopsis = "Stop monitoring a channel";
+-
+-static char *stopmonitor_descrip = " StopMonitor():\n"
+- "Stops monitoring a channel. Has no effect if the channel is not monitored\n";
+-
+-static char *changemonitor_synopsis = "Change monitoring filename of a channel";
+-
+-static char *changemonitor_descrip = " ChangeMonitor(filename_base):\n"
+- "Changes monitoring filename of a channel. Has no effect if the channel is not monitored.\n"
+- "The argument is the new filename base to use for monitoring this channel.\n";
+-
+-static char *pausemonitor_synopsis = "Pause monitoring of a channel";
+-
+-static char *pausemonitor_descrip = " PauseMonitor():\n"
+- "Pauses monitoring of a channel until it is re-enabled by a call to UnpauseMonitor.\n";
+-
+-static char *unpausemonitor_synopsis = "Unpause monitoring of a channel";
+-
+-static char *unpausemonitor_descrip = " UnpauseMonitor():\n"
+- "Unpauses monitoring of a channel on which monitoring had\n"
+- "previously been paused with PauseMonitor.\n";
+-
+ /*!
+ * \brief Change state of monitored channel
+ * \param chan
+@@ -145,8 +283,8 @@
+ * \retval 0 on success
+ * \retval -1 on failure
+ */
+-int ast_monitor_start( struct ast_channel *chan, const char *format_spec,
+- const char *fname_base, int need_lock, int stream_action)
++int AST_OPTIONAL_API_NAME(ast_monitor_start)(struct ast_channel *chan, const char *format_spec,
++ const char *fname_base, int need_lock, int stream_action)
+ {
+ int res = 0;
+
+@@ -285,7 +423,7 @@
+ * Stop the recording, close any open streams, mix in/out channels if required
+ * \return Always 0
+ */
+-int ast_monitor_stop(struct ast_channel *chan, int need_lock)
++int AST_OPTIONAL_API_NAME(ast_monitor_stop)(struct ast_channel *chan, int need_lock)
+ {
+ int delfiles = 0;
+
+@@ -378,25 +516,25 @@
+
+
+ /*! \brief Pause monitoring of channel */
+-int ast_monitor_pause(struct ast_channel *chan)
++int AST_OPTIONAL_API_NAME(ast_monitor_pause)(struct ast_channel *chan)
+ {
+ return ast_monitor_set_state(chan, AST_MONITOR_PAUSED);
+ }
+
+ /*! \brief Unpause monitoring of channel */
+-int ast_monitor_unpause(struct ast_channel *chan)
++int AST_OPTIONAL_API_NAME(ast_monitor_unpause)(struct ast_channel *chan)
+ {
+ return ast_monitor_set_state(chan, AST_MONITOR_RUNNING);
+ }
+
+ /*! \brief Wrapper for ast_monitor_pause */
+-static int pause_monitor_exec(struct ast_channel *chan, void *data)
++static int pause_monitor_exec(struct ast_channel *chan, const char *data)
+ {
+ return ast_monitor_pause(chan);
+ }
+
+ /*! \brief Wrapper for ast_monitor_unpause */
+-static int unpause_monitor_exec(struct ast_channel *chan, void *data)
++static int unpause_monitor_exec(struct ast_channel *chan, const char *data)
+ {
+ return ast_monitor_unpause(chan);
+ }
+@@ -409,7 +547,7 @@
+ * \retval 0 on success.
+ * \retval -1 on failure.
+ */
+-int ast_monitor_change_fname(struct ast_channel *chan, const char *fname_base, int need_lock)
++int AST_OPTIONAL_API_NAME(ast_monitor_change_fname)(struct ast_channel *chan, const char *fname_base, int need_lock)
+ {
+ if (ast_strlen_zero(fname_base)) {
+ ast_log(LOG_WARNING, "Cannot change monitor filename of channel %s to null\n", chan->name);
+@@ -457,7 +595,7 @@
+ * \retval 0 on success.
+ * \retval -1 on failure.
+ */
+-static int start_monitor_exec(struct ast_channel *chan, void *data)
++static int start_monitor_exec(struct ast_channel *chan, const char *data)
+ {
+ char *arg = NULL;
+ char *options = NULL;
+@@ -476,12 +614,12 @@
+ );
+
+ /* Parse arguments. */
+- if (ast_strlen_zero((char*)data)) {
++ if (ast_strlen_zero(data)) {
+ ast_log(LOG_ERROR, "Monitor requires an argument\n");
+ return 0;
+ }
+
+- parse = ast_strdupa((char*)data);
++ parse = ast_strdupa(data);
+ AST_STANDARD_APP_ARGS(args, parse);
+
+ if (!ast_strlen_zero(args.options)) {
+@@ -541,31 +679,17 @@
+ }
+
+ /*! \brief Wrapper function \see ast_monitor_stop */
+-static int stop_monitor_exec(struct ast_channel *chan, void *data)
++static int stop_monitor_exec(struct ast_channel *chan, const char *data)
+ {
+ return ast_monitor_stop(chan, 1);
+ }
+
+ /*! \brief Wrapper function \see ast_monitor_change_fname */
+-static int change_monitor_exec(struct ast_channel *chan, void *data)
++static int change_monitor_exec(struct ast_channel *chan, const char *data)
+ {
+- return ast_monitor_change_fname(chan, (const char*)data, 1);
++ return ast_monitor_change_fname(chan, data, 1);
+ }
+
+-static char start_monitor_action_help[] =
+-"Description: The 'Monitor' action may be used to record the audio on a\n"
+-" specified channel. The following parameters may be used to control\n"
+-" this:\n"
+-" Channel - Required. Used to specify the channel to record.\n"
+-" File - Optional. Is the name of the file created in the\n"
+-" monitor spool directory. Defaults to the same name\n"
+-" as the channel (with slashes replaced with dashes).\n"
+-" Format - Optional. Is the audio recording format. Defaults\n"
+-" to \"wav\".\n"
+-" Mix - Optional. Boolean parameter as to whether to mix\n"
+-" the input and output channels together after the\n"
+-" recording is finished.\n";
+-
+ /*! \brief Start monitoring a channel by manager connection */
+ static int start_monitor_action(struct mansession *s, const struct message *m)
+ {
+@@ -580,105 +704,111 @@
+ astman_send_error(s, m, "No channel specified");
+ return 0;
+ }
+- c = ast_get_channel_by_name_locked(name);
+- if (!c) {
++
++ if (!(c = ast_channel_get_by_name(name))) {
+ astman_send_error(s, m, "No such channel");
+ return 0;
+ }
+
+ if (ast_strlen_zero(fname)) {
+- /* No filename base specified, default to channel name as per CLI */
++ /* No filename base specified, default to channel name as per CLI */
++ ast_channel_lock(c);
+ fname = ast_strdupa(c->name);
++ ast_channel_unlock(c);
+ /* Channels have the format technology/channel_name - have to replace that / */
+- if ((d = strchr(fname, '/')))
++ if ((d = strchr(fname, '/'))) {
+ *d = '-';
++ }
+ }
+
+ if (ast_monitor_start(c, format, fname, 1, X_REC_IN | X_REC_OUT)) {
+ if (ast_monitor_change_fname(c, fname, 1)) {
+ astman_send_error(s, m, "Could not start monitoring channel");
+- ast_channel_unlock(c);
++ c = ast_channel_unref(c);
+ return 0;
+ }
+ }
+
+ if (ast_true(mix)) {
++ ast_channel_lock(c);
+ ast_monitor_setjoinfiles(c, 1);
++ ast_channel_unlock(c);
+ }
+
+- ast_channel_unlock(c);
++ c = ast_channel_unref(c);
++
+ astman_send_ack(s, m, "Started monitoring channel");
++
+ return 0;
+ }
+
+-static char stop_monitor_action_help[] =
+-"Description: The 'StopMonitor' action may be used to end a previously\n"
+-" started 'Monitor' action. The only parameter is 'Channel', the name\n"
+-" of the channel monitored.\n";
+-
+ /*! \brief Stop monitoring a channel by manager connection */
+ static int stop_monitor_action(struct mansession *s, const struct message *m)
+ {
+ struct ast_channel *c = NULL;
+ const char *name = astman_get_header(m, "Channel");
+ int res;
++
+ if (ast_strlen_zero(name)) {
+ astman_send_error(s, m, "No channel specified");
+ return 0;
+ }
+- c = ast_get_channel_by_name_locked(name);
+- if (!c) {
++
++ if (!(c = ast_channel_get_by_name(name))) {
+ astman_send_error(s, m, "No such channel");
+ return 0;
+ }
++
+ res = ast_monitor_stop(c, 1);
+- ast_channel_unlock(c);
++
++ c = ast_channel_unref(c);
++
+ if (res) {
+ astman_send_error(s, m, "Could not stop monitoring channel");
+ return 0;
+ }
++
+ astman_send_ack(s, m, "Stopped monitoring channel");
++
+ return 0;
+ }
+
+-static char change_monitor_action_help[] =
+-"Description: The 'ChangeMonitor' action may be used to change the file\n"
+-" started by a previous 'Monitor' action. The following parameters may\n"
+-" be used to control this:\n"
+-" Channel - Required. Used to specify the channel to record.\n"
+-" File - Required. Is the new name of the file created in the\n"
+-" monitor spool directory.\n";
+-
+ /*! \brief Change filename of a monitored channel by manager connection */
+ static int change_monitor_action(struct mansession *s, const struct message *m)
+ {
+ struct ast_channel *c = NULL;
+ const char *name = astman_get_header(m, "Channel");
+ const char *fname = astman_get_header(m, "File");
++
+ if (ast_strlen_zero(name)) {
+ astman_send_error(s, m, "No channel specified");
+ return 0;
+ }
++
+ if (ast_strlen_zero(fname)) {
+ astman_send_error(s, m, "No filename specified");
+ return 0;
+ }
+- c = ast_get_channel_by_name_locked(name);
+- if (!c) {
++
++ if (!(c = ast_channel_get_by_name(name))) {
+ astman_send_error(s, m, "No such channel");
+ return 0;
+ }
++
+ if (ast_monitor_change_fname(c, fname, 1)) {
++ c = ast_channel_unref(c);
+ astman_send_error(s, m, "Could not change monitored filename of channel");
+- ast_channel_unlock(c);
+ return 0;
+ }
+- ast_channel_unlock(c);
++
++ c = ast_channel_unref(c);
++
+ astman_send_ack(s, m, "Changed monitor filename");
++
+ return 0;
+ }
+
+-void ast_monitor_setjoinfiles(struct ast_channel *chan, int turnon)
++void AST_OPTIONAL_API_NAME(ast_monitor_setjoinfiles)(struct ast_channel *chan, int turnon)
+ {
+ if (chan->monitor)
+ chan->monitor->joinfiles = turnon;
+@@ -689,50 +819,40 @@
+ MONITOR_ACTION_PAUSE,
+ MONITOR_ACTION_UNPAUSE
+ };
+-
++
+ static int do_pause_or_unpause(struct mansession *s, const struct message *m, int action)
+ {
+ struct ast_channel *c = NULL;
+ const char *name = astman_get_header(m, "Channel");
+-
++
+ if (ast_strlen_zero(name)) {
+ astman_send_error(s, m, "No channel specified");
+ return -1;
+ }
+-
+- c = ast_get_channel_by_name_locked(name);
+- if (!c) {
++
++ if (!(c = ast_channel_get_by_name(name))) {
+ astman_send_error(s, m, "No such channel");
+ return -1;
+ }
+
+- if (action == MONITOR_ACTION_PAUSE)
++ if (action == MONITOR_ACTION_PAUSE) {
+ ast_monitor_pause(c);
+- else
++ } else {
+ ast_monitor_unpause(c);
+-
+- ast_channel_unlock(c);
++ }
++
++ c = ast_channel_unref(c);
++
+ astman_send_ack(s, m, (action == MONITOR_ACTION_PAUSE ? "Paused monitoring of the channel" : "Unpaused monitoring of the channel"));
+- return 0;
++
++ return 0;
+ }
+
+-static char pause_monitor_action_help[] =
+- "Description: The 'PauseMonitor' action may be used to temporarily stop the\n"
+- " recording of a channel. The following parameters may\n"
+- " be used to control this:\n"
+- " Channel - Required. Used to specify the channel to record.\n";
+-
+ static int pause_monitor_action(struct mansession *s, const struct message *m)
+ {
+ return do_pause_or_unpause(s, m, MONITOR_ACTION_PAUSE);
+ }
+
+-static char unpause_monitor_action_help[] =
+- "Description: The 'UnpauseMonitor' action may be used to re-enable recording\n"
+- " of a channel after calling PauseMonitor. The following parameters may\n"
+- " be used to control this:\n"
+- " Channel - Required. Used to specify the channel to record.\n";
+-
+ static int unpause_monitor_action(struct mansession *s, const struct message *m)
+ {
+ return do_pause_or_unpause(s, m, MONITOR_ACTION_UNPAUSE);
+@@ -741,16 +861,16 @@
+
+ static int load_module(void)
+ {
+- ast_register_application("Monitor", start_monitor_exec, monitor_synopsis, monitor_descrip);
+- ast_register_application("StopMonitor", stop_monitor_exec, stopmonitor_synopsis, stopmonitor_descrip);
+- ast_register_application("ChangeMonitor", change_monitor_exec, changemonitor_synopsis, changemonitor_descrip);
+- ast_register_application("PauseMonitor", pause_monitor_exec, pausemonitor_synopsis, pausemonitor_descrip);
+- ast_register_application("UnpauseMonitor", unpause_monitor_exec, unpausemonitor_synopsis, unpausemonitor_descrip);
+- ast_manager_register2("Monitor", EVENT_FLAG_CALL, start_monitor_action, monitor_synopsis, start_monitor_action_help);
+- ast_manager_register2("StopMonitor", EVENT_FLAG_CALL, stop_monitor_action, stopmonitor_synopsis, stop_monitor_action_help);
+- ast_manager_register2("ChangeMonitor", EVENT_FLAG_CALL, change_monitor_action, changemonitor_synopsis, change_monitor_action_help);
+- ast_manager_register2("PauseMonitor", EVENT_FLAG_CALL, pause_monitor_action, pausemonitor_synopsis, pause_monitor_action_help);
+- ast_manager_register2("UnpauseMonitor", EVENT_FLAG_CALL, unpause_monitor_action, unpausemonitor_synopsis, unpause_monitor_action_help);
++ ast_register_application_xml("Monitor", start_monitor_exec);
++ ast_register_application_xml("StopMonitor", stop_monitor_exec);
++ ast_register_application_xml("ChangeMonitor", change_monitor_exec);
++ ast_register_application_xml("PauseMonitor", pause_monitor_exec);
++ ast_register_application_xml("UnpauseMonitor", unpause_monitor_exec);
++ ast_manager_register_xml("Monitor", EVENT_FLAG_CALL, start_monitor_action);
++ ast_manager_register_xml("StopMonitor", EVENT_FLAG_CALL, stop_monitor_action);
++ ast_manager_register_xml("ChangeMonitor", EVENT_FLAG_CALL, change_monitor_action);
++ ast_manager_register_xml("PauseMonitor", EVENT_FLAG_CALL, pause_monitor_action);
++ ast_manager_register_xml("UnpauseMonitor", EVENT_FLAG_CALL, unpause_monitor_action);
+
+ return AST_MODULE_LOAD_SUCCESS;
+ }
+Index: res/res_odbc.exports
+===================================================================
+--- a/res/res_odbc.exports (.../tags/1.6.2.0-beta3) (revision 0)
++++ b/res/res_odbc.exports (.../trunk) (revision 202568)
+@@ -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_config_curl.c
+===================================================================
+--- a/res/res_config_curl.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/res/res_config_curl.c (.../trunk) (revision 202568)
+@@ -43,7 +43,11 @@
+ #include "asterisk/module.h"
+ #include "asterisk/lock.h"
+ #include "asterisk/utils.h"
++#include "asterisk/threadstorage.h"
+
++AST_THREADSTORAGE(query_buf);
++AST_THREADSTORAGE(result_buf);
++
+ /*!
+ * \brief Execute a curl query and return ast_variable list
+ * \param url The base URL from which to retrieve data
+@@ -55,25 +59,24 @@
+ */
+ static struct ast_variable *realtime_curl(const char *url, const char *unused, va_list ap)
+ {
+- struct ast_str *query;
+- char buf1[200], buf2[200];
++ struct ast_str *query, *buffer;
++ char buf1[256], buf2[256];
+ const char *newparam, *newval;
+ char *stringp, *pair, *key;
+ int i;
+- struct ast_variable *var=NULL, *prev=NULL;
+- const int EncodeSpecialChars = 1, bufsize = 64000;
+- char *buffer;
++ struct ast_variable *var = NULL, *prev = NULL;
++ const int EncodeSpecialChars = 1;
+
+ 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 NULL;
+ }
+
+- if (!(query = ast_str_create(1000)))
++ if (!(query = ast_str_thread_get(&query_buf, 16))) {
+ return NULL;
++ }
+
+- if (!(buffer = ast_malloc(bufsize))) {
+- ast_free(query);
++ if (!(buffer = ast_str_thread_get(&result_buf, 16))) {
+ return NULL;
+ }
+
+@@ -88,31 +91,33 @@
+ va_end(ap);
+
+ ast_str_append(&query, 0, ")}");
+- pbx_substitute_variables_helper(NULL, ast_str_buffer(query), buffer, bufsize);
++ ast_str_substitute_variables(&buffer, 0, NULL, ast_str_buffer(query));
+
+ /* Remove any trailing newline characters */
+- if ((stringp = strchr(buffer, '\r')) || (stringp = strchr(buffer, '\n')))
++ if ((stringp = strchr(ast_str_buffer(buffer), '\r')) || (stringp = strchr(ast_str_buffer(buffer), '\n'))) {
+ *stringp = '\0';
++ }
+
+- stringp = buffer;
++ stringp = ast_str_buffer(buffer);
+ while ((pair = strsep(&stringp, "&"))) {
+ key = strsep(&pair, "=");
+ ast_uri_decode(key);
+- if (pair)
++ if (pair) {
+ ast_uri_decode(pair);
++ }
+
+ if (!ast_strlen_zero(key)) {
+ if (prev) {
+ prev->next = ast_variable_new(key, S_OR(pair, ""), "");
+- if (prev->next)
++ if (prev->next) {
+ prev = prev->next;
+- } else
++ }
++ } else {
+ prev = var = ast_variable_new(key, S_OR(pair, ""), "");
++ }
+ }
+ }
+
+- ast_free(buffer);
+- ast_free(query);
+ return var;
+ }
+
+@@ -127,27 +132,26 @@
+ */
+ static struct ast_config *realtime_multi_curl(const char *url, const char *unused, va_list ap)
+ {
+- struct ast_str *query;
+- char buf1[200], buf2[200];
++ struct ast_str *query, *buffer;
++ char buf1[256], buf2[256];
+ const char *newparam, *newval;
+ char *stringp, *line, *pair, *key, *initfield = NULL;
+ int i;
+- const int EncodeSpecialChars = 1, bufsize = 256000;
+- struct ast_variable *var=NULL;
+- struct ast_config *cfg=NULL;
+- struct ast_category *cat=NULL;
+- char *buffer;
++ const int EncodeSpecialChars = 1;
++ struct ast_variable *var = NULL;
++ struct ast_config *cfg = NULL;
++ struct ast_category *cat = NULL;
+
+ 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 NULL;
+ }
+
+- if (!(query = ast_str_create(1000)))
++ if (!(query = ast_str_thread_get(&query_buf, 16))) {
+ return NULL;
++ }
+
+- if (!(buffer = ast_malloc(bufsize))) {
+- ast_free(query);
++ if (!(buffer = ast_str_thread_get(&result_buf, 16))) {
+ return NULL;
+ }
+
+@@ -170,28 +174,33 @@
+ ast_str_append(&query, 0, ")}");
+
+ /* Do the CURL query */
+- pbx_substitute_variables_helper(NULL, ast_str_buffer(query), buffer, bufsize);
++ ast_str_substitute_variables(&buffer, 0, NULL, ast_str_buffer(query));
+
+- if (!(cfg = ast_config_new()))
+- goto exit_multi;
++ if (!(cfg = ast_config_new())) {
++ return NULL;
++ }
+
+ /* Line oriented output */
+- stringp = buffer;
++ stringp = ast_str_buffer(buffer);
+ while ((line = strsep(&stringp, "\r\n"))) {
+- if (ast_strlen_zero(line))
++ if (ast_strlen_zero(line)) {
+ continue;
++ }
+
+- if (!(cat = ast_category_new("", "", 99999)))
++ if (!(cat = ast_category_new("", "", 99999))) {
+ continue;
++ }
+
+ while ((pair = strsep(&line, "&"))) {
+ key = strsep(&pair, "=");
+ ast_uri_decode(key);
+- if (pair)
++ if (pair) {
+ ast_uri_decode(pair);
++ }
+
+- if (!strcasecmp(key, initfield) && pair)
++ if (!strcasecmp(key, initfield) && pair) {
+ ast_category_rename(cat, pair);
++ }
+
+ if (!ast_strlen_zero(key)) {
+ var = ast_variable_new(key, S_OR(pair, ""), "");
+@@ -201,9 +210,6 @@
+ ast_category_append(cfg, cat);
+ }
+
+-exit_multi:
+- ast_free(buffer);
+- ast_free(query);
+ return cfg;
+ }
+
+@@ -224,24 +230,23 @@
+ */
+ static int update_curl(const char *url, const char *unused, const char *keyfield, const char *lookup, va_list ap)
+ {
+- struct ast_str *query;
+- char buf1[200], buf2[200];
++ struct ast_str *query, *buffer;
++ char buf1[256], buf2[256];
+ const char *newparam, *newval;
+ char *stringp;
+ int i, rowcount = -1;
+- const int EncodeSpecialChars = 1, bufsize = 100;
+- char *buffer;
++ const int EncodeSpecialChars = 1;
+
+ 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)))
++ if (!(query = ast_str_thread_get(&query_buf, 16))) {
+ return -1;
++ }
+
+- if (!(buffer = ast_malloc(bufsize))) {
+- ast_free(query);
++ if (!(buffer = ast_str_thread_get(&result_buf, 16))) {
+ return -1;
+ }
+
+@@ -258,43 +263,40 @@
+ va_end(ap);
+
+ ast_str_append(&query, 0, ")}");
+- pbx_substitute_variables_helper(NULL, ast_str_buffer(query), buffer, bufsize);
++ ast_str_substitute_variables(&buffer, 0, NULL, ast_str_buffer(query));
+
+ /* Line oriented output */
+- stringp = buffer;
+- while (*stringp <= ' ')
++ stringp = ast_str_buffer(buffer);
++ while (*stringp <= ' ') {
+ stringp++;
++ }
+ sscanf(stringp, "%d", &rowcount);
+
+- ast_free(buffer);
+- ast_free(query);
+-
+- if (rowcount >= 0)
++ if (rowcount >= 0) {
+ return (int)rowcount;
++ }
+
+ return -1;
+ }
+
+ static int update2_curl(const char *url, const char *unused, va_list ap)
+ {
+- struct ast_str *query;
++ struct ast_str *query, *buffer;
+ 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;
++ const int EncodeSpecialChars = 1;
+
+ 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)))
++ if (!(query = ast_str_thread_get(&query_buf, 1000)))
+ return -1;
+
+- if (!(buffer = ast_malloc(bufsize))) {
+- ast_free(query);
++ if (!(buffer = ast_str_thread_get(&result_buf, 16))) {
+ return -1;
+ }
+
+@@ -316,24 +318,27 @@
+ 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);
++ first = 0;
+ }
+ va_end(ap);
+
+ ast_str_append(&query, 0, ")}");
+- /* TODO: Make proxies work */
+- pbx_substitute_variables_helper(NULL, ast_str_buffer(query), buffer, bufsize);
++ /* Proxies work, by setting CURLOPT options in the [globals] section of
++ * extensions.conf. Unfortunately, this means preloading pbx_config.so
++ * so that they have an opportunity to be set prior to startup realtime
++ * queries. */
++ ast_str_substitute_variables(&buffer, 0, NULL, ast_str_buffer(query));
+
+ /* Line oriented output */
+- stringp = buffer;
+- while (*stringp <= ' ')
++ stringp = ast_str_buffer(buffer);
++ while (*stringp <= ' ') {
+ stringp++;
++ }
+ sscanf(stringp, "%d", &rowcount);
+
+- ast_free(buffer);
+- ast_free(query);
+-
+- if (rowcount >= 0)
++ if (rowcount >= 0) {
+ return (int)rowcount;
++ }
+
+ return -1;
+ }
+@@ -353,24 +358,23 @@
+ */
+ static int store_curl(const char *url, const char *unused, va_list ap)
+ {
+- struct ast_str *query;
+- char buf1[200], buf2[200];
++ struct ast_str *query, *buffer;
++ char buf1[256], buf2[256];
+ const char *newparam, *newval;
+ char *stringp;
+ int i, rowcount = -1;
+- const int EncodeSpecialChars = 1, bufsize = 100;
+- char *buffer;
++ const int EncodeSpecialChars = 1;
+
+ 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)))
++ if (!(query = ast_str_thread_get(&query_buf, 1000))) {
+ return -1;
++ }
+
+- if (!(buffer = ast_malloc(bufsize))) {
+- ast_free(query);
++ if (!(buffer = ast_str_thread_get(&result_buf, 16))) {
+ return -1;
+ }
+
+@@ -385,19 +389,18 @@
+ va_end(ap);
+
+ ast_str_append(&query, 0, ")}");
+- pbx_substitute_variables_helper(NULL, ast_str_buffer(query), buffer, bufsize);
++ ast_str_substitute_variables(&buffer, 0, NULL, ast_str_buffer(query));
+
+- stringp = buffer;
+- while (*stringp <= ' ')
++ stringp = ast_str_buffer(buffer);
++ while (*stringp <= ' ') {
+ stringp++;
++ }
+ sscanf(stringp, "%d", &rowcount);
+
+- ast_free(buffer);
+- ast_free(query);
++ if (rowcount >= 0) {
++ return rowcount;
++ }
+
+- if (rowcount >= 0)
+- return (int)rowcount;
+-
+ return -1;
+ }
+
+@@ -418,24 +421,23 @@
+ */
+ static int destroy_curl(const char *url, const char *unused, const char *keyfield, const char *lookup, va_list ap)
+ {
+- struct ast_str *query;
++ struct ast_str *query, *buffer;
+ char buf1[200], buf2[200];
+ const char *newparam, *newval;
+ char *stringp;
+ int i, rowcount = -1;
+- const int EncodeSpecialChars = 1, bufsize = 100;
+- char *buffer;
++ const int EncodeSpecialChars = 1;
+
+ 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)))
++ if (!(query = ast_str_thread_get(&query_buf, 1000))) {
+ return -1;
++ }
+
+- if (!(buffer = ast_malloc(bufsize))) {
+- ast_free(query);
++ if (!(buffer = ast_str_thread_get(&result_buf, 16))) {
+ return -1;
+ }
+
+@@ -452,27 +454,26 @@
+ va_end(ap);
+
+ ast_str_append(&query, 0, ")}");
+- pbx_substitute_variables_helper(NULL, ast_str_buffer(query), buffer, bufsize);
++ ast_str_substitute_variables(&buffer, 0, NULL, ast_str_buffer(query));
+
+ /* Line oriented output */
+- stringp = buffer;
+- while (*stringp <= ' ')
++ stringp = ast_str_buffer(buffer);
++ while (*stringp <= ' ') {
+ stringp++;
++ }
+ sscanf(stringp, "%d", &rowcount);
+
+- ast_free(buffer);
+- ast_free(query);
+-
+- if (rowcount >= 0)
++ if (rowcount >= 0) {
+ return (int)rowcount;
++ }
+
+ return -1;
+ }
+
+ static int require_curl(const char *url, const char *unused, va_list ap)
+ {
+- struct ast_str *query;
+- char *elm, field[256], buffer[128];
++ struct ast_str *query, *buffer;
++ char *elm, field[256];
+ int type, size;
+ const int EncodeSpecialChars = 1;
+
+@@ -481,10 +482,14 @@
+ return -1;
+ }
+
+- if (!(query = ast_str_create(100))) {
++ if (!(query = ast_str_thread_get(&query_buf, 100))) {
+ return -1;
+ }
+
++ if (!(buffer = ast_str_thread_get(&result_buf, 16))) {
++ return -1;
++ }
++
+ ast_str_set(&query, 0, "${CURL(%s/require,", url);
+
+ while ((elm = va_arg(ap, char *))) {
+@@ -511,19 +516,19 @@
+ va_end(ap);
+
+ ast_str_append(&query, 0, ")}");
+- pbx_substitute_variables_helper(NULL, ast_str_buffer(query), buffer, sizeof(buffer));
+- return atoi(buffer);
++ ast_str_substitute_variables(&buffer, 0, NULL, ast_str_buffer(query));
++ return atoi(ast_str_buffer(buffer));
+ }
+
+ static struct ast_config *config_curl(const char *url, const char *unused, const char *file, struct ast_config *cfg, struct ast_flags flags, const char *sugg_incl, const char *who_asked)
+ {
+- struct ast_str *query;
++ struct ast_str *query, *buffer;
+ char buf1[200];
+ char *stringp, *line, *pair, *key;
+- const int EncodeSpecialChars = 1, bufsize = 256000;
++ const int EncodeSpecialChars = 1;
+ int last_cat_metric = -1, cat_metric = -1;
+- struct ast_category *cat=NULL;
+- char *buffer, *cur_cat = "";
++ struct ast_category *cat = NULL;
++ char *cur_cat = "";
+ char *category = "", *var_name = "", *var_val = "";
+ struct ast_flags loader_flags = { 0 };
+
+@@ -532,11 +537,11 @@
+ return NULL;
+ }
+
+- if (!(query = ast_str_create(1000)))
++ if (!(query = ast_str_thread_get(&query_buf, 100))) {
+ return NULL;
++ }
+
+- if (!(buffer = ast_malloc(bufsize))) {
+- ast_free(query);
++ if (!(buffer = ast_str_thread_get(&result_buf, 16))) {
+ return NULL;
+ }
+
+@@ -544,30 +549,33 @@
+ ast_str_set(&query, 0, "${CURL(%s/static?file=%s)}", url, buf1);
+
+ /* Do the CURL query */
+- pbx_substitute_variables_helper(NULL, ast_str_buffer(query), buffer, bufsize);
++ ast_str_substitute_variables(&buffer, 0, NULL, ast_str_buffer(query));
+
+ /* Line oriented output */
+- stringp = buffer;
++ stringp = ast_str_buffer(buffer);
+ cat = ast_config_get_current_category(cfg);
+
+ while ((line = strsep(&stringp, "\r\n"))) {
+- if (ast_strlen_zero(line))
++ if (ast_strlen_zero(line)) {
+ continue;
++ }
+
+ while ((pair = strsep(&line, "&"))) {
+ key = strsep(&pair, "=");
+ ast_uri_decode(key);
+- if (pair)
++ if (pair) {
+ ast_uri_decode(pair);
++ }
+
+- if (!strcasecmp(key, "category"))
++ if (!strcasecmp(key, "category")) {
+ category = S_OR(pair, "");
+- else if (!strcasecmp(key, "var_name"))
++ } else if (!strcasecmp(key, "var_name")) {
+ var_name = S_OR(pair, "");
+- else if (!strcasecmp(key, "var_val"))
++ } else if (!strcasecmp(key, "var_val")) {
+ var_val = S_OR(pair, "");
+- else if (!strcasecmp(key, "cat_metric"))
++ } else if (!strcasecmp(key, "cat_metric")) {
+ cat_metric = pair ? atoi(pair) : 0;
++ }
+ }
+
+ if (!strcmp(var_name, "#include")) {
+@@ -585,8 +593,6 @@
+ ast_variable_append(cat, ast_variable_new(var_name, var_val, ""));
+ }
+
+- ast_free(buffer);
+- ast_free(query);
+ return cfg;
+ }
+
+Index: res/res_calendar.exports
+===================================================================
+--- a/res/res_calendar.exports (.../tags/1.6.2.0-beta3) (revision 0)
++++ b/res/res_calendar.exports (.../trunk) (revision 202568)
+@@ -0,0 +1,7 @@
++{
++ global:
++ ast_*;
++ calendar_config;
++ local:
++ *;
++};
+
+Property changes on: res/res_calendar.exports
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+Added: svn:mime-type
+ + text/plain
+Added: svn:keywords
+ + Author Date Id Revision
+
+Index: res/res_smdi.c
+===================================================================
+--- a/res/res_smdi.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/res/res_smdi.c (.../trunk) (revision 202568)
+@@ -57,6 +57,100 @@
+ /* Message expiry time in milliseconds */
+ #define SMDI_MSG_EXPIRY_TIME 30000 /* 30 seconds */
+
++/*** DOCUMENTATION
++
++ <function name="SMDI_MSG_RETRIEVE" language="en_US">
++ <synopsis>
++ Retrieve an SMDI message.
++ </synopsis>
++ <syntax>
++ <parameter name="smdi port" required="true" />
++ <parameter name="search key" required="true" />
++ <parameter name="timeout" />
++ <parameter name="options">
++ <enumlist>
++ <enum name="t">
++ <para>Instead of searching on the forwarding station, search on the message desk terminal.</para>
++ </enum>
++ <enum name="n">
++ <para>Instead of searching on the forwarding station, search on the message desk number.</para>
++ </enum>
++ </enumlist>
++ </parameter>
++ </syntax>
++ <description>
++ <para>This function is used to retrieve an incoming SMDI message. It returns
++ an ID which can be used with the SMDI_MSG() function to access details of
++ the message. Note that this is a destructive function in the sense that
++ once an SMDI message is retrieved using this function, it is no longer in
++ the global SMDI message queue, and can not be accessed by any other Asterisk
++ channels. The timeout for this function is optional, and the default is
++ 3 seconds. When providing a timeout, it should be in milliseconds.
++ </para>
++ <para>The default search is done on the forwarding station ID. However, if
++ you set one of the search key options in the options field, you can change
++ this behavior.
++ </para>
++ </description>
++ <see-also>
++ <ref type="function">SMDI_MSG</ref>
++ </see-also>
++ </function>
++ <function name="SMDI_MSG" language="en_US">
++ <synopsis>
++ Retrieve details about an SMDI message.
++ </synopsis>
++ <syntax>
++ <parameter name="message_id" required="true" />
++ <parameter name="component" required="true">
++ <para>Valid message components are:</para>
++ <enumlist>
++ <enum name="number">
++ <para>The message desk number</para>
++ </enum>
++ <enum name="terminal">
++ <para>The message desk terminal</para>
++ </enum>
++ <enum name="station">
++ <para>The forwarding station</para>
++ </enum>
++ <enum name="callerid">
++ <para>The callerID of the calling party that was forwarded</para>
++ </enum>
++ <enum name="type">
++ <para>The call type. The value here is the exact character
++ that came in on the SMDI link. Typically, example values
++ are:</para>
++ <para>Options:</para>
++ <enumlist>
++ <enum name="D">
++ <para>Direct Calls</para>
++ </enum>
++ <enum name="A">
++ <para>Forward All Calls</para>
++ </enum>
++ <enum name="B">
++ <para>Forward Busy Calls</para>
++ </enum>
++ <enum name="N">
++ <para>Forward No Answer Calls</para>
++ </enum>
++ </enumlist>
++ </enum>
++ </enumlist>
++ </parameter>
++ </syntax>
++ <description>
++ <para>This function is used to access details of an SMDI message that was
++ pulled from the incoming SMDI message queue using the SMDI_MSG_RETRIEVE()
++ function.</para>
++ </description>
++ <see-also>
++ <ref type="function">SMDI_MSG_RETRIEVE</ref>
++ </see-also>
++ </function>
++ ***/
++
+ static const char config_file[] = "smdi.conf";
+
+ /*! \brief SMDI message desk message queue. */
+@@ -86,7 +180,7 @@
+ };
+
+ /*! \brief SMDI interface container. */
+-struct ast_smdi_interface_container {
++static struct ast_smdi_interface_container {
+ ASTOBJ_CONTAINER_COMPONENTS(struct ast_smdi_interface);
+ } smdi_ifaces;
+
+@@ -157,7 +251,7 @@
+ ast_module_unref(ast_module_info->self);
+ }
+
+-void ast_smdi_interface_unref(struct ast_smdi_interface *iface)
++void AST_OPTIONAL_API_NAME(ast_smdi_interface_unref)(struct ast_smdi_interface *iface)
+ {
+ ASTOBJ_UNREF(iface, ast_smdi_interface_destroy);
+ }
+@@ -217,17 +311,17 @@
+ return 0;
+ }
+
+-int ast_smdi_mwi_set(struct ast_smdi_interface *iface, const char *mailbox)
++int AST_OPTIONAL_API_NAME(ast_smdi_mwi_set)(struct ast_smdi_interface *iface, const char *mailbox)
+ {
+ return smdi_toggle_mwi(iface, mailbox, 1);
+ }
+
+-int ast_smdi_mwi_unset(struct ast_smdi_interface *iface, const char *mailbox)
++int AST_OPTIONAL_API_NAME(ast_smdi_mwi_unset)(struct ast_smdi_interface *iface, const char *mailbox)
+ {
+ return smdi_toggle_mwi(iface, mailbox, 0);
+ }
+
+-void ast_smdi_md_message_putback(struct ast_smdi_interface *iface, struct ast_smdi_md_message *md_msg)
++void AST_OPTIONAL_API_NAME(ast_smdi_md_message_putback)(struct ast_smdi_interface *iface, struct ast_smdi_md_message *md_msg)
+ {
+ ast_mutex_lock(&iface->md_q_lock);
+ ASTOBJ_CONTAINER_LINK_START(&iface->md_q, md_msg);
+@@ -235,7 +329,7 @@
+ ast_mutex_unlock(&iface->md_q_lock);
+ }
+
+-void ast_smdi_mwi_message_putback(struct ast_smdi_interface *iface, struct ast_smdi_mwi_message *mwi_msg)
++void AST_OPTIONAL_API_NAME(ast_smdi_mwi_message_putback)(struct ast_smdi_interface *iface, struct ast_smdi_mwi_message *mwi_msg)
+ {
+ ast_mutex_lock(&iface->mwi_q_lock);
+ ASTOBJ_CONTAINER_LINK_START(&iface->mwi_q, mwi_msg);
+@@ -496,36 +590,36 @@
+ return NULL;
+ }
+
+-struct ast_smdi_md_message *ast_smdi_md_message_pop(struct ast_smdi_interface *iface)
++struct ast_smdi_md_message * AST_OPTIONAL_API_NAME(ast_smdi_md_message_pop)(struct ast_smdi_interface *iface)
+ {
+ return smdi_msg_pop(iface, SMDI_MD);
+ }
+
+-struct ast_smdi_md_message *ast_smdi_md_message_wait(struct ast_smdi_interface *iface, int timeout)
++struct ast_smdi_md_message * AST_OPTIONAL_API_NAME(ast_smdi_md_message_wait)(struct ast_smdi_interface *iface, int timeout)
+ {
+ struct ast_flags options = { 0 };
+ return smdi_message_wait(iface, timeout, SMDI_MD, NULL, options);
+ }
+
+-struct ast_smdi_mwi_message *ast_smdi_mwi_message_pop(struct ast_smdi_interface *iface)
++struct ast_smdi_mwi_message * AST_OPTIONAL_API_NAME(ast_smdi_mwi_message_pop)(struct ast_smdi_interface *iface)
+ {
+ return smdi_msg_pop(iface, SMDI_MWI);
+ }
+
+-struct ast_smdi_mwi_message *ast_smdi_mwi_message_wait(struct ast_smdi_interface *iface, int timeout)
++struct ast_smdi_mwi_message * AST_OPTIONAL_API_NAME(ast_smdi_mwi_message_wait)(struct ast_smdi_interface *iface, int timeout)
+ {
+ struct ast_flags options = { 0 };
+ return smdi_message_wait(iface, timeout, SMDI_MWI, NULL, options);
+ }
+
+-struct ast_smdi_mwi_message *ast_smdi_mwi_message_wait_station(struct ast_smdi_interface *iface, int timeout,
++struct ast_smdi_mwi_message * AST_OPTIONAL_API_NAME(ast_smdi_mwi_message_wait_station)(struct ast_smdi_interface *iface, int timeout,
+ const char *station)
+ {
+ struct ast_flags options = { 0 };
+ return smdi_message_wait(iface, timeout, SMDI_MWI, station, options);
+ }
+
+-struct ast_smdi_interface *ast_smdi_interface_find(const char *iface_name)
++struct ast_smdi_interface * AST_OPTIONAL_API_NAME(ast_smdi_interface_find)(const char *iface_name)
+ {
+ return (ASTOBJ_CONTAINER_FIND(&smdi_ifaces, iface_name));
+ }
+@@ -722,12 +816,12 @@
+ return NULL;
+ }
+
+-void ast_smdi_md_message_destroy(struct ast_smdi_md_message *msg)
++void AST_OPTIONAL_API_NAME(ast_smdi_md_message_destroy)(struct ast_smdi_md_message *msg)
+ {
+ ast_free(msg);
+ }
+
+-void ast_smdi_mwi_message_destroy(struct ast_smdi_mwi_message *msg)
++void AST_OPTIONAL_API_NAME(ast_smdi_mwi_message_destroy)(struct ast_smdi_mwi_message *msg)
+ {
+ ast_free(msg);
+ }
+@@ -1044,7 +1138,7 @@
+ ASTOBJ_UNREF(iface, ast_smdi_interface_destroy);
+
+ if (!(iface = ASTOBJ_CONTAINER_FIND(&smdi_ifaces, v->value))) {
+- ast_log(LOG_NOTICE, "SMDI interface %s not found\n", iface->name);
++ ast_log(LOG_NOTICE, "SMDI interface %s not found\n", v->value);
+ continue;
+ }
+ } else if (!strcasecmp(v->name, "pollinginterval")) {
+@@ -1292,46 +1386,11 @@
+
+ static struct ast_custom_function smdi_msg_retrieve_function = {
+ .name = "SMDI_MSG_RETRIEVE",
+- .synopsis = "Retrieve an SMDI message.",
+- .syntax = "SMDI_MSG_RETRIEVE(<smdi port>,<search key>[,timeout[,options]])",
+- .desc =
+- " This function is used to retrieve an incoming SMDI message. It returns\n"
+- "an ID which can be used with the SMDI_MSG() function to access details of\n"
+- "the message. Note that this is a destructive function in the sense that\n"
+- "once an SMDI message is retrieved using this function, it is no longer in\n"
+- "the global SMDI message queue, and can not be accessed by any other Asterisk\n"
+- "channels. The timeout for this function is optional, and the default is\n"
+- "3 seconds. When providing a timeout, it should be in milliseconds.\n"
+- " The default search is done on the forwarding station ID. However, if\n"
+- "you set one of the search key options in the options field, you can change\n"
+- "this behavior.\n"
+- " Options:\n"
+- " t - Instead of searching on the forwarding station, search on the message\n"
+- " desk terminal.\n"
+- " n - Instead of searching on the forwarding station, search on the message\n"
+- " desk number.\n"
+- "",
+ .read = smdi_msg_retrieve_read,
+ };
+
+ static struct ast_custom_function smdi_msg_function = {
+ .name = "SMDI_MSG",
+- .synopsis = "Retrieve details about an SMDI message.",
+- .syntax = "SMDI_MSG(<message_id>,<component>)",
+- .desc =
+- " This function is used to access details of an SMDI message that was\n"
+- "pulled from the incoming SMDI message queue using the SMDI_MSG_RETRIEVE()\n"
+- "function.\n"
+- " Valid message components are:\n"
+- " number - The message desk number\n"
+- " terminal - The message desk terminal\n"
+- " station - The forwarding station\n"
+- " callerid - The callerID of the calling party that was forwarded\n"
+- " type - The call type. The value here is the exact character\n"
+- " that came in on the SMDI link. Typically, example values\n"
+- " are: D - Direct Calls, A - Forward All Calls,\n"
+- " B - Forward Busy Calls, N - Forward No Answer Calls\n"
+- "",
+ .read = smdi_msg_read,
+ };
+
+Index: res/res_features.exports
+===================================================================
+--- a/res/res_features.exports (.../tags/1.6.2.0-beta3) (revision 0)
++++ b/res/res_features.exports (.../trunk) (revision 202568)
+@@ -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-beta3) (revision 202568)
++++ b/res/res_curl.c (.../trunk) (revision 202568)
+@@ -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-beta3) (revision 0)
++++ b/res/res_ael_share.exports (.../trunk) (revision 202568)
+@@ -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-beta3) (revision 0)
++++ b/res/res_jabber.exports (.../trunk) (revision 202568)
+@@ -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_speech.c
+===================================================================
+--- a/res/res_speech.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/res/res_speech.c (.../trunk) (revision 202568)
+@@ -40,7 +40,7 @@
+ static struct ast_speech_engine *default_engine = NULL;
+
+ /*! \brief Find a speech recognition engine of specified name, if NULL then use the default one */
+-static struct ast_speech_engine *find_engine(char *engine_name)
++static struct ast_speech_engine *find_engine(const char *engine_name)
+ {
+ struct ast_speech_engine *engine = NULL;
+
+@@ -60,25 +60,25 @@
+ }
+
+ /*! \brief Activate a loaded (either local or global) grammar */
+-int ast_speech_grammar_activate(struct ast_speech *speech, char *grammar_name)
++int ast_speech_grammar_activate(struct ast_speech *speech, const char *grammar_name)
+ {
+ return (speech->engine->activate ? speech->engine->activate(speech, grammar_name) : -1);
+ }
+
+ /*! \brief Deactivate a loaded grammar on a speech structure */
+-int ast_speech_grammar_deactivate(struct ast_speech *speech, char *grammar_name)
++int ast_speech_grammar_deactivate(struct ast_speech *speech, const char *grammar_name)
+ {
+ return (speech->engine->deactivate ? speech->engine->deactivate(speech, grammar_name) : -1);
+ }
+
+ /*! \brief Load a local grammar on a speech structure */
+-int ast_speech_grammar_load(struct ast_speech *speech, char *grammar_name, char *grammar)
++int ast_speech_grammar_load(struct ast_speech *speech, const char *grammar_name, const char *grammar)
+ {
+ return (speech->engine->load ? speech->engine->load(speech, grammar_name, grammar) : -1);
+ }
+
+ /*! \brief Unload a local grammar from a speech structure */
+-int ast_speech_grammar_unload(struct ast_speech *speech, char *grammar_name)
++int ast_speech_grammar_unload(struct ast_speech *speech, const char *grammar_name)
+ {
+ return (speech->engine->unload ? speech->engine->unload(speech, grammar_name) : -1);
+ }
+@@ -163,13 +163,13 @@
+ }
+
+ /*! \brief Change an engine specific attribute */
+-int ast_speech_change(struct ast_speech *speech, char *name, const char *value)
++int ast_speech_change(struct ast_speech *speech, const char *name, const char *value)
+ {
+ return (speech->engine->change ? speech->engine->change(speech, name, value) : -1);
+ }
+
+ /*! \brief Create a new speech structure using the engine specified */
+-struct ast_speech *ast_speech_new(char *engine_name, int formats)
++struct ast_speech *ast_speech_new(const char *engine_name, int formats)
+ {
+ struct ast_speech_engine *engine = NULL;
+ struct ast_speech *new_speech = NULL;
+@@ -299,7 +299,7 @@
+ }
+
+ /*! \brief Unregister a speech recognition engine */
+-int ast_speech_unregister(char *engine_name)
++int ast_speech_unregister(const char *engine_name)
+ {
+ struct ast_speech_engine *engine = NULL;
+ int res = -1;
+Index: res/res_monitor.exports
+===================================================================
+--- a/res/res_monitor.exports (.../tags/1.6.2.0-beta3) (revision 0)
++++ b/res/res_monitor.exports (.../trunk) (revision 202568)
+@@ -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_clioriginate.c
+===================================================================
+--- a/res/res_clioriginate.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/res/res_clioriginate.c (.../trunk) (revision 202568)
+@@ -16,12 +16,12 @@
+ * at the top of the source tree.
+ */
+
+-/*!
++/*!
+ * \file
+ * \author Russell Bryant <russell@digium.com>
+ *
+ * \brief Originate calls via the CLI
+- *
++ *
+ */
+
+ #include "asterisk.h"
+@@ -52,12 +52,12 @@
+ char *chantech;
+ char *chandata;
+ int reason = 0;
+-
++
+ if (ast_strlen_zero(app))
+ return CLI_SHOWUSAGE;
+
+ chandata = ast_strdupa(chan);
+-
++
+ chantech = strsep(&chandata, "/");
+ if (!chandata) {
+ ast_cli(fd, "*** No data provided after channel type! ***\n");
+@@ -86,7 +86,7 @@
+ int reason = 0;
+
+ chandata = ast_strdupa(chan);
+-
++
+ chantech = strsep(&chandata, "/");
+ if (!chandata) {
+ ast_cli(fd, "*** No data provided after channel type! ***\n");
+@@ -102,7 +102,7 @@
+ exten = "s";
+ if (ast_strlen_zero(context))
+ context = "default";
+-
++
+ ast_pbx_outgoing_exten(chantech, AST_FORMAT_SLINEAR, chandata, TIMEOUT * 1000, context, exten, 1, &reason, 0, NULL, NULL, NULL, NULL, NULL);
+
+ return CLI_SUCCESS;
+@@ -114,16 +114,15 @@
+ * \param cmd operation to execute
+ * \param a structure that contains either application or extension arguments
+ * \retval CLI_SUCCESS on success.
+- * \retval CLI_SHOWUSAGE on failure.
+-*/
++ * \retval CLI_SHOWUSAGE on failure.*/
+ static char *handle_orig(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+ {
+- static char *choices[] = { "application", "extension", NULL };
+- char *res;
++ static const char * const choices[] = { "application", "extension", NULL };
++ char *res = NULL;
+ switch (cmd) {
+ case CLI_INIT:
+ e->command = "channel originate";
+- e->usage =
++ 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"
+@@ -141,14 +140,16 @@
+ "used. If no extension is given, the 's' extension will be used.\n";
+ return NULL;
+ case CLI_GENERATE:
+- if (a->pos != 3)
+- return NULL;
+-
+ /* ugly, can be removed when CLI entries have ast_module pointers */
+ ast_module_ref(ast_module_info->self);
+- res = ast_cli_complete(a->word, choices, a->n);
++ if (a->pos == 3) {
++ res = ast_cli_complete(a->word, choices, a->n);
++ } else if (a->pos == 4) {
++ if (!strcasecmp("application", a->argv[3])) {
++ res = ast_complete_applications(a->line, a->word, a->n);
++ }
++ }
+ ast_module_unref(ast_module_info->self);
+-
+ return res;
+ }
+
+@@ -159,7 +160,7 @@
+ ast_module_ref(ast_module_info->self);
+
+ if (!strcasecmp("application", a->argv[3])) {
+- res = orig_app(a->fd, a->argv[2], a->argv[4], a->argv[5]);
++ 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 {
+@@ -201,15 +202,14 @@
+ name = a->argv[2];
+ dest = a->argv[3];
+
+- chan = ast_get_channel_by_name_locked(name);
+- if (!chan) {
++ if (!(chan = ast_channel_get_by_name(name))) {
+ ast_cli(a->fd, "Channel '%s' not found\n", name);
+ return CLI_FAILURE;
+ }
+
+ res = ast_async_parseable_goto(chan, dest);
+
+- ast_channel_unlock(chan);
++ chan = ast_channel_unref(chan);
+
+ if (!res) {
+ ast_cli(a->fd, "Channel '%s' successfully redirected to %s\n", name, dest);
+Index: res/res_rtp_asterisk.c
+===================================================================
+--- a/res/res_rtp_asterisk.c (.../tags/1.6.2.0-beta3) (revision 0)
++++ b/res/res_rtp_asterisk.c (.../trunk) (revision 202568)
+@@ -0,0 +1,2649 @@
++/*
++ * 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 (150 * (8000 / 1000)) /*!< 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;
++ unsigned int dtmf_duration; /*!< Total duration in samples since the digit start event */
++ unsigned int dtmf_timeout; /*!< When this timestamp is reached we consider END frame lost and forcibly abort digit */
++ 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 sockaddr_in alt_rtp_address; /*!<Alternate remote address information */
++
++ 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 void ast_rtp_alt_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,
++ .alt_remote_address_set = ast_rtp_alt_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 (;;) {
++ sin->sin_port = htons(x);
++ /* Try to bind, this will tell us whether the port is available or not */
++ if (!bind(rtp->s, (struct sockaddr *)sin, sizeof(*sin))) {
++ ast_debug(1, "Allocated port %d for RTP instance '%p'\n", x, instance);
++ ast_rtp_instance_set_local_address(instance, sin);
++ 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 = { 0, };
++ 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 = { 0, };
++ 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 = { 0, };
++ 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 = { 0, };
++
++ 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;
++ /* 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, pred/ts/samples %d/%d/%d\n", abs(rtp->lastts - pred), ms, 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 = { 0, };
++ 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 0;
++ }
++
++ /* 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 0;
++ }
++
++ /* 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 = { 0, };
++
++ 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 = { 0, };
++ 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;
++
++ if (rtp_debug_test_addr(&remote_address)) {
++ 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->dtmf_timeout = 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 {
++ /* The duration parameter measures the complete
++ duration of the event (from the beginning) - RFC2833.
++ Account for the fact that duration is only 16 bits long
++ (about 8 seconds at 8000 Hz) and can wrap is digit
++ is hold for too long. */
++ unsigned int new_duration = rtp->dtmf_duration;
++ unsigned int last_duration = new_duration & 0xFFFF;
++
++ if (last_duration > 64000 && samples < last_duration) {
++ new_duration += 0xFFFF + 1;
++ }
++ new_duration = (new_duration & ~0xFFFF) | samples;
++
++ if (event_end & 0x80) {
++ /* End event */
++ if ((rtp->lastevent != seqno) && rtp->resp) {
++ rtp->dtmf_duration = new_duration;
++ f = send_dtmf(instance, AST_FRAME_DTMF_END, 0);
++ f->len = ast_tvdiff_ms(ast_samp2tv(rtp->dtmf_duration, 8000), ast_tv(0, 0));
++ rtp->resp = 0;
++ rtp->dtmf_duration = rtp->dtmf_timeout = 0;
++ }
++ } else {
++ /* Begin/continuation */
++
++ if (rtp->resp && rtp->resp != resp) {
++ /* Another digit already began. End it */
++ f = send_dtmf(instance, AST_FRAME_DTMF_END, 0);
++ f->len = ast_tvdiff_ms(ast_samp2tv(rtp->dtmf_duration, 8000), ast_tv(0, 0));
++ rtp->resp = 0;
++ rtp->dtmf_duration = rtp->dtmf_timeout = 0;
++ }
++
++ if (rtp->resp) {
++ /* Digit continues */
++ rtp->dtmf_duration = new_duration;
++ } else {
++ /* New digit began */
++ rtp->resp = resp;
++ f = send_dtmf(instance, AST_FRAME_DTMF_BEGIN, 0);
++ rtp->dtmf_duration = samples;
++ }
++
++ rtp->dtmf_timeout = timestamp + rtp->dtmf_duration + dtmftimeout;
++ }
++
++ 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->dtmf_timeout = 0;
++
++ 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 = { 0, };
++
++ 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 = { 0, };
++
++ /* 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 = { 0, };
++
++ /* 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)) {
++ /* Hmm, not the strict addres. Perhaps we're getting audio from the alternate? */
++ if ((rtp->alt_rtp_address.sin_addr.s_addr == sin.sin_addr.s_addr) && (rtp->alt_rtp_address.sin_port == sin.sin_port)) {
++ /* ooh, we did! You're now the new expected address, son! */
++ rtp->strict_rtp_address = sin;
++ } else {
++ 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;
++
++ if (rtp->dtmf_timeout && rtp->dtmf_timeout < timestamp) {
++ rtp->dtmf_timeout = 0;
++
++ if (rtp->resp) {
++ struct ast_frame *f;
++ f = send_dtmf(instance, AST_FRAME_DTMF_END, 0);
++ f->len = ast_tvdiff_ms(ast_samp2tv(rtp->dtmf_duration, 8000), ast_tv(0, 0));
++ rtp->resp = 0;
++ rtp->dtmf_timeout = rtp->dtmf_duration = 0;
++ return f;
++ }
++ }
++
++ 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;
++}
++
++static void ast_rtp_alt_remote_address_set(struct ast_rtp_instance *instance, struct sockaddr_in *sin)
++{
++ struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
++
++ /* No need to futz with rtp->rtcp here because ast_rtcp_read is already able to adjust if receiving
++ * RTCP from an "unexpected" source
++ */
++ rtp->alt_rtp_address = *sin;
++
++ 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 = ast_strdupa(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 = ast_strdupa(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 > 64000)) {
++ 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-beta3) (revision 202568)
++++ b/res/res_config_pgsql.c (.../trunk) (revision 202568)
+@@ -49,7 +49,7 @@
+
+ #define RES_CONFIG_PGSQL_CONF "res_pgsql.conf"
+
+-PGconn *pgsqlConn = NULL;
++static PGconn *pgsqlConn = NULL;
+
+ #define MAX_DB_OPTION_SIZE 64
+
+@@ -84,7 +84,7 @@
+ static char *handle_cli_realtime_pgsql_status(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
+ static char *handle_cli_realtime_pgsql_cache(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
+
+-enum { RQ_WARN, RQ_CREATECLOSE, RQ_CREATECHAR } requirements;
++static enum { RQ_WARN, RQ_CREATECLOSE, RQ_CREATECHAR } requirements;
+
+ static struct ast_cli_entry cli_realtime[] = {
+ AST_CLI_DEFINE(handle_cli_realtime_pgsql_status, "Shows connection information for the PostgreSQL RealTime driver"),
+@@ -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_calendar_icalendar.c
+===================================================================
+--- a/res/res_calendar_icalendar.c (.../tags/1.6.2.0-beta3) (revision 0)
++++ b/res/res_calendar_icalendar.c (.../trunk) (revision 202568)
+@@ -0,0 +1,470 @@
++/*
++ * Asterisk -- An open source telephony toolkit.
++ *
++ * Copyright (C) 2008 - 2009, Digium, Inc.
++ *
++ * Terry Wilson <twilson@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 Resource for handling iCalnedar calendars
++ */
++
++/*** MODULEINFO
++ <depend>neon</depend>
++ <depend>ical</depend>
++***/
++#include "asterisk.h"
++
++ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
++
++#include <libical/ical.h>
++#include <neon/ne_session.h>
++#include <neon/ne_uri.h>
++#include <neon/ne_request.h>
++#include <neon/ne_auth.h>
++
++#include "asterisk/module.h"
++#include "asterisk/calendar.h"
++#include "asterisk/lock.h"
++#include "asterisk/config.h"
++#include "asterisk/astobj2.h"
++
++static void *ical_load_calendar(void *data);
++static void *unref_icalendar(void *obj);
++
++static struct ast_calendar_tech ical_tech = {
++ .type = "ical",
++ .module = AST_MODULE,
++ .description = "iCalendar .ics calendars",
++ .load_calendar = ical_load_calendar,
++ .unref_calendar = unref_icalendar,
++};
++
++struct icalendar_pvt {
++ AST_DECLARE_STRING_FIELDS(
++ AST_STRING_FIELD(url);
++ AST_STRING_FIELD(user);
++ AST_STRING_FIELD(secret);
++ );
++ struct ast_calendar *owner;
++ ne_uri uri;
++ ne_session *session;
++ icalcomponent *data;
++ struct ao2_container *events;
++};
++
++static int cb_true(void *user_data, void *arg, int flags)
++{
++ return CMP_MATCH;
++}
++
++static void icalendar_destructor(void *obj)
++{
++ struct icalendar_pvt *pvt = obj;
++
++ ast_debug(1, "Destroying pvt for iCalendar %s\n", pvt->owner->name);
++ if (pvt->session) {
++ ne_session_destroy(pvt->session);
++ }
++ if (pvt->data) {
++ icalcomponent_free(pvt->data);
++ }
++ ast_string_field_free_memory(pvt);
++
++ ao2_callback(pvt->events, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, cb_true, NULL);
++
++ ao2_ref(pvt->events, -1);
++}
++
++static void *unref_icalendar(void *obj)
++{
++ struct icalendar_pvt *pvt = obj;
++
++ ao2_ref(pvt, -1);
++ return NULL;
++}
++
++static int fetch_response_reader(void *data, const char *block, size_t len)
++{
++ struct ast_str **response = data;
++ unsigned char *tmp;
++
++ if (!(tmp = ast_malloc(len + 1))) {
++ return -1;
++ }
++ memcpy(tmp, block, len);
++ tmp[len] = '\0';
++ ast_str_append(response, 0, "%s", tmp);
++ ast_free(tmp);
++
++ return 0;
++}
++
++static int auth_credentials(void *userdata, const char *realm, int attempts, char *username, char *secret)
++{
++ struct icalendar_pvt *pvt = userdata;
++
++ if (attempts > 1) {
++ ast_log(LOG_WARNING, "Invalid username or password for iCalendar '%s'\n", pvt->owner->name);
++ return -1;
++ }
++
++ ne_strnzcpy(username, pvt->user, NE_ABUFSIZ);
++ ne_strnzcpy(secret, pvt->secret, NE_ABUFSIZ);
++
++ return 0;
++}
++
++static icalcomponent *fetch_icalendar(struct icalendar_pvt *pvt)
++{
++ int ret;
++ struct ast_str *response;
++ ne_request *req;
++ icalcomponent *comp = NULL;
++
++ if (!pvt) {
++ ast_log(LOG_ERROR, "There is no private!\n");
++ }
++
++ if (!(response = ast_str_create(512))) {
++ ast_log(LOG_ERROR, "Could not allocate memory for response.\n");
++ return NULL;
++ }
++
++ req = ne_request_create(pvt->session, "GET", pvt->uri.path);
++ ne_add_response_body_reader(req, ne_accept_2xx, fetch_response_reader, &response);
++
++ ret = ne_request_dispatch(req);
++ if (ret != NE_OK || !ast_str_strlen(response)) {
++ ast_log(LOG_WARNING, "Unable to retrieve iCalendar '%s' from '%s': %s\n", pvt->owner->name, pvt->url, ne_get_error(pvt->session));
++ ast_free(response);
++ return NULL;
++ }
++
++ if (!ast_strlen_zero(ast_str_buffer(response))) {
++ comp = icalparser_parse_string(ast_str_buffer(response));
++ }
++ ast_free(response);
++
++ return comp;
++}
++
++static void icalendar_add_event(icalcomponent *comp, struct icaltime_span *span, void *data)
++{
++ struct icalendar_pvt *pvt = data;
++ struct ast_calendar_event *event;
++ icaltimezone *utc = icaltimezone_get_utc_timezone();
++ icaltimetype start, end, tmp;
++ icalcomponent *valarm;
++ icalproperty *prop;
++ struct icaltriggertype trigger;
++
++ if (!(pvt && pvt->owner)) {
++ ast_log(LOG_ERROR, "Require a private structure with an ownenr\n");
++ return;
++ }
++
++ if (!(event = ast_calendar_event_alloc(pvt->owner))) {
++ ast_log(LOG_ERROR, "Could not allocate an event!\n");
++ return;
++ }
++
++ start = icaltime_from_timet_with_zone(span->start, 0, utc);
++ end = icaltime_from_timet_with_zone(span->end, 0, utc);
++ event->start = span->start;
++ event->end = span->end;
++
++ switch(icalcomponent_get_status(comp)) {
++ case ICAL_STATUS_CONFIRMED:
++ event->busy_state = AST_CALENDAR_BS_BUSY;
++ break;
++
++ case ICAL_STATUS_TENTATIVE:
++ event->busy_state = AST_CALENDAR_BS_BUSY_TENTATIVE;
++ break;
++
++ default:
++ event->busy_state = AST_CALENDAR_BS_FREE;
++ }
++
++ if ((prop = icalcomponent_get_first_property(comp, ICAL_SUMMARY_PROPERTY))) {
++ ast_string_field_set(event, summary, icalproperty_get_value_as_string(prop));
++ }
++
++ if ((prop = icalcomponent_get_first_property(comp, ICAL_DESCRIPTION_PROPERTY))) {
++ ast_string_field_set(event, description, icalproperty_get_value_as_string(prop));
++ }
++
++ if ((prop = icalcomponent_get_first_property(comp, ICAL_ORGANIZER_PROPERTY))) {
++ ast_string_field_set(event, organizer, icalproperty_get_value_as_string(prop));
++ }
++
++ if ((prop = icalcomponent_get_first_property(comp, ICAL_LOCATION_PROPERTY))) {
++ ast_string_field_set(event, location, icalproperty_get_value_as_string(prop));
++ }
++
++ if ((prop = icalcomponent_get_first_property(comp, ICAL_UID_PROPERTY))) {
++ ast_string_field_set(event, uid, icalproperty_get_value_as_string(prop));
++ } else {
++ ast_log(LOG_WARNING, "No UID found, but one is required. Generating, but updates may not be acurate\n");
++ if (!ast_strlen_zero(event->summary)) {
++ ast_string_field_set(event, uid, event->summary);
++ } else {
++ char tmp[100];
++ snprintf(tmp, sizeof(tmp), "%lu", event->start);
++ ast_string_field_set(event, uid, tmp);
++ }
++ }
++
++ /* Get the attendees */
++ for (prop = icalcomponent_get_first_property(comp, ICAL_ATTENDEE_PROPERTY);
++ prop; prop = icalcomponent_get_next_property(comp, ICAL_ATTENDEE_PROPERTY)) {
++ struct ast_calendar_attendee *attendee;
++ const char *data;
++
++ if (!(attendee = ast_calloc(1, sizeof(*attendee)))) {
++ event = ast_calendar_unref_event(event);
++ return;
++ }
++ data = icalproperty_get_attendee(prop);
++ if (!ast_strlen_zero(data)) {
++ attendee->data = ast_strdup(data);;
++ AST_LIST_INSERT_TAIL(&event->attendees, attendee, next);
++ }
++ }
++
++
++ /* Only set values for alarm based on VALARM. Can be overriden in main/calendar.c by autoreminder
++ * therefore, go ahead and add events even if their is no VALARM or it is malformed
++ * Currently we are only getting the first VALARM and are handling repitition in main/calendar.c from calendar.conf */
++ if (!(valarm = icalcomponent_get_first_component(comp, ICAL_VALARM_COMPONENT))) {
++ ao2_link(pvt->events, event);
++ event = ast_calendar_unref_event(event);
++ return;
++ }
++
++ if (!(prop = icalcomponent_get_first_property(valarm, ICAL_TRIGGER_PROPERTY))) {
++ ast_log(LOG_WARNING, "VALARM has no TRIGGER, skipping!\n");
++ ao2_link(pvt->events, event);
++ event = ast_calendar_unref_event(event);
++ return;
++ }
++
++ trigger = icalproperty_get_trigger(prop);
++
++ if (icaltriggertype_is_null_trigger(trigger)) {
++ ast_log(LOG_WARNING, "Bad TRIGGER for VALARM, skipping!\n");
++ ao2_link(pvt->events, event);
++ event = ast_calendar_unref_event(event);
++ return;
++ }
++
++ if (!icaltime_is_null_time(trigger.time)) { /* This is an absolute time */
++ tmp = icaltime_convert_to_zone(trigger.time, utc);
++ event->alarm = icaltime_as_timet_with_zone(tmp, utc);
++ } else { /* Offset from either dtstart or dtend */
++ /* XXX Technically you can check RELATED to see if the event fires from the END of the event
++ * But, I'm not sure I've ever seen anyone implement it in calendaring software, so I'm ignoring for now */
++ tmp = icaltime_add(start, trigger.duration);
++ event->alarm = icaltime_as_timet_with_zone(tmp, utc);
++ }
++
++ ao2_link(pvt->events, event);
++ event = ast_calendar_unref_event(event);
++
++ return;
++}
++
++ static void icalendar_update_events(struct icalendar_pvt *pvt)
++{
++ struct icaltimetype start_time, end_time;
++ icalcomponent *iter;
++
++ if (!pvt) {
++ ast_log(LOG_ERROR, "iCalendar is NULL\n");
++ return;
++ }
++
++ if (!pvt->owner) {
++ ast_log(LOG_ERROR, "iCalendar is an orphan!\n");
++ return;
++ }
++
++ if (!pvt->data) {
++ ast_log(LOG_ERROR, "The iCalendar has not been parsed!\n");
++ return;
++ }
++
++ start_time = icaltime_current_time_with_zone(icaltimezone_get_utc_timezone());
++ end_time = icaltime_current_time_with_zone(icaltimezone_get_utc_timezone());
++ end_time.second += pvt->owner->timeframe * 60;
++ icaltime_normalize(end_time);
++
++ for (iter = icalcomponent_get_first_component(pvt->data, ICAL_VEVENT_COMPONENT);
++ iter;
++ iter = icalcomponent_get_next_component(pvt->data, ICAL_VEVENT_COMPONENT))
++ {
++ icalcomponent_foreach_recurrence(iter, start_time, end_time, icalendar_add_event, pvt);
++ }
++
++ ast_calendar_merge_events(pvt->owner, pvt->events);
++}
++
++static void *ical_load_calendar(void *void_data)
++{
++ struct icalendar_pvt *pvt;
++ struct ast_variable *v;
++ struct ast_calendar *cal = void_data;
++ ast_mutex_t refreshlock;
++
++ if (!(cal && ast_calendar_config)) {
++ ast_log(LOG_ERROR, "You must enable calendar support for res_icalendar to load\n");
++ return NULL;
++ }
++ if (ao2_trylock(cal)) {
++ if (cal->unloading) {
++ ast_log(LOG_WARNING, "Unloading module, load_calendar cancelled.\n");
++ } else {
++ ast_log(LOG_WARNING, "Could not lock calendar, aborting!\n");
++ }
++ return NULL;
++ }
++
++ if (!(pvt = ao2_alloc(sizeof(*pvt), icalendar_destructor))) {
++ ast_log(LOG_ERROR, "Could not allocate icalendar_pvt structure for calendar: %s\n", cal->name);
++ return NULL;
++ }
++
++ pvt->owner = cal;
++
++ if (!(pvt->events = ast_calendar_event_container_alloc())) {
++ ast_log(LOG_ERROR, "Could not allocate space for fetching events for calendar: %s\n", cal->name);
++ pvt = unref_icalendar(pvt);
++ ao2_unlock(cal);
++ return NULL;
++ }
++
++ if (ast_string_field_init(pvt, 32)) {
++ ast_log(LOG_ERROR, "Couldn't allocate string field space for calendar: %s\n", cal->name);
++ pvt = unref_icalendar(pvt);
++ ao2_unlock(cal);
++ return NULL;
++ }
++
++ for (v = ast_variable_browse(ast_calendar_config, cal->name); v; v = v->next) {
++ if (!strcasecmp(v->name, "url")) {
++ ast_string_field_set(pvt, url, v->value);
++ } else if (!strcasecmp(v->name, "user")) {
++ ast_string_field_set(pvt, user, v->value);
++ } else if (!strcasecmp(v->name, "secret")) {
++ ast_string_field_set(pvt, secret, v->value);
++ }
++ }
++
++ if (ast_strlen_zero(pvt->url)) {
++ ast_log(LOG_WARNING, "No URL was specified for iCalendar '%s' - skipping.\n", cal->name);
++ pvt = unref_icalendar(pvt);
++ ao2_unlock(cal);
++ return NULL;
++ }
++
++ if (ne_uri_parse(pvt->url, &pvt->uri) || pvt->uri.host == NULL || pvt->uri.path == NULL) {
++ ast_log(LOG_WARNING, "Could not parse url '%s' for iCalendar '%s' - skipping.\n", pvt->url, cal->name);
++ pvt = unref_icalendar(pvt);
++ ao2_unlock(cal);
++ return NULL;
++ }
++
++ if (pvt->uri.scheme == NULL) {
++ pvt->uri.scheme = "http";
++ }
++
++ if (pvt->uri.port == 0) {
++ pvt->uri.port = ne_uri_defaultport(pvt->uri.scheme);
++ }
++
++ pvt->session = ne_session_create(pvt->uri.scheme, pvt->uri.host, pvt->uri.port);
++ ne_set_server_auth(pvt->session, auth_credentials, pvt);
++ if (!strncasecmp(pvt->uri.scheme, "https", sizeof(pvt->uri.scheme))) {
++ ne_ssl_trust_default_ca(pvt->session);
++ }
++
++ cal->tech_pvt = pvt;
++
++ ast_mutex_init(&refreshlock);
++
++ /* Load it the first time */
++ if (!(pvt->data = fetch_icalendar(pvt))) {
++ ast_log(LOG_WARNING, "Unable to parse iCalendar '%s'\n", cal->name);
++ }
++
++ icalendar_update_events(pvt);
++
++ ao2_unlock(cal);
++
++ /* The only writing from another thread will be if unload is true */
++ for(;;) {
++ struct timeval tv = ast_tvnow();
++ struct timespec ts = {0,};
++
++ ts.tv_sec = tv.tv_sec + (60 * pvt->owner->refresh);
++
++ ast_mutex_lock(&refreshlock);
++ while (!pvt->owner->unloading) {
++ if (ast_cond_timedwait(&pvt->owner->unload, &refreshlock, &ts) == ETIMEDOUT) {
++ break;
++ }
++ }
++ ast_mutex_unlock(&refreshlock);
++
++ if (pvt->owner->unloading) {
++ ast_debug(10, "Skipping refresh since we got a shutdown signal\n");
++ return NULL;
++ }
++
++ ast_debug(10, "Refreshing after %d minute timeout\n", pvt->owner->refresh);
++
++ if (!(pvt->data = fetch_icalendar(pvt))) {
++ ast_log(LOG_WARNING, "Unable to parse iCalendar '%s'\n", pvt->owner->name);
++ continue;
++ }
++
++ icalendar_update_events(pvt);
++ }
++
++ return NULL;
++}
++
++static int load_module(void)
++{
++ ne_sock_init();
++ if (ast_calendar_register(&ical_tech)) {
++ ne_sock_exit();
++ return AST_MODULE_LOAD_DECLINE;
++ }
++
++ return AST_MODULE_LOAD_SUCCESS;
++}
++
++static int unload_module(void)
++{
++ ast_calendar_unregister(&ical_tech);
++ ne_sock_exit();
++ return 0;
++}
++
++AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Asterisk iCalendar .ics file integration",
++ .load = load_module,
++ .unload = unload_module,
++ );
+
+Property changes on: res/res_calendar_icalendar.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+Added: svn:mime-type
+ + text/plain
+Added: svn:keywords
+ + Author Date Id Revision
+
+Index: res/res_smdi.exports
+===================================================================
+--- a/res/res_smdi.exports (.../tags/1.6.2.0-beta3) (revision 0)
++++ b/res/res_smdi.exports (.../trunk) (revision 202568)
+@@ -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-beta3) (revision 202568)
++++ b/res/res_phoneprov.c (.../trunk) (revision 202568)
+@@ -65,6 +65,37 @@
+
+ #define VAR_BUF_SIZE 4096
+
++/*** DOCUMENTATION
++ <function name="PP_EACH_EXTENSION" language="en_US">
++ <synopsis>
++ Execute specified template for each extension.
++ </synopsis>
++ <syntax>
++ <parameter name="mac" required="true" />
++ <parameter name="template" required="true" />
++ </syntax>
++ <description>
++ <para>Output the specified template for each extension associated with the specified MAC address.</para>
++ </description>
++ </function>
++ <function name="PP_EACH_USER" language="en_US">
++ <synopsis>
++ Generate a string for each phoneprov user.
++ </synopsis>
++ <syntax>
++ <parameter name="string" required="true" />
++ <parameter name="exclude_mac" required="true" />
++ </syntax>
++ <description>
++ <para>Pass in a string, with phoneprov variables you want substituted in the format of
++ %{VARNAME}, and you will get the string rendered for each user in phoneprov
++ excluding ones with MAC address <replaceable>exclude_mac</replaceable>. Probably not
++ useful outside of res_phoneprov.</para>
++ <para>Example: ${PP_EACH_USER(&lt;item&gt;&lt;fn&gt;%{DISPLAY_NAME}&lt;/fn&gt;&lt;/item&gt;|${MAC})</para>
++ </description>
++ </function>
++ ***/
++
+ /*! \brief for use in lookup_iface */
+ static struct in_addr __ourip = { .s_addr = 0x00000000, };
+
+@@ -155,19 +186,6 @@
+ static struct ao2_container *http_routes;
+ static struct ao2_container *users;
+
+-/*! \brief Extensions whose mime types we think we know */
+-static struct {
+- char *ext;
+- char *mtype;
+-} mimetypes[] = {
+- { "png", "image/png" },
+- { "xml", "text/xml" },
+- { "jpg", "image/jpeg" },
+- { "js", "application/x-javascript" },
+- { "wav", "audio/x-wav" },
+- { "mp3", "audio/mpeg" },
+-};
+-
+ 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 */
+@@ -176,22 +194,6 @@
+ static struct varshead global_variables;
+ static ast_mutex_t globals_lock;
+
+-/*! \brief Return mime type based on extension */
+-static char *ftype2mtype(const char *ftype)
+-{
+- int x;
+-
+- if (ast_strlen_zero(ftype))
+- return NULL;
+-
+- for (x = 0;x < ARRAY_LEN(mimetypes);x++) {
+- if (!strcasecmp(ftype, mimetypes[x].ext))
+- return mimetypes[x].mtype;
+- }
+-
+- return NULL;
+-}
+-
+ /* iface is the interface (e.g. eth0); address is the return value */
+ static int lookup_iface(const char *iface, struct in_addr *address)
+ {
+@@ -398,21 +400,25 @@
+ }
+
+ /*! \brief Callback that is executed everytime an http request is received by this module */
+-static struct ast_str *phoneprov_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)
++static int phoneprov_callback(struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_vars, struct ast_variable *headers)
+ {
+ struct http_route *route;
+ struct http_route search_route = {
+ .uri = uri,
+ };
+- struct ast_str *result = ast_str_create(512);
++ struct ast_str *result;
+ char path[PATH_MAX];
+ char *file = NULL;
+ int len;
+ int fd;
+ char buf[256];
+- struct timeval now = ast_tvnow();
+- struct ast_tm tm;
++ struct ast_str *http_header;
+
++ if (method != AST_HTTP_GET && method != AST_HTTP_HEAD) {
++ ast_http_error(ser, 501, "Not Implemented", "Attempt to use unimplemented / unsupported method");
++ return -1;
++ }
++
+ if (!(route = ao2_find(http_routes, &search_route, OBJ_POINTER))) {
+ goto out404;
+ }
+@@ -434,15 +440,9 @@
+ goto out500;
+ }
+
+- ast_strftime(buf, sizeof(buf), "%a, %d %b %Y %H:%M:%S %Z", ast_localtime(&now, &tm, "GMT"));
+- fprintf(ser->f, "HTTP/1.1 200 OK\r\n"
+- "Server: Asterisk/%s\r\n"
+- "Date: %s\r\n"
+- "Connection: close\r\n"
+- "Cache-Control: no-cache, no-store\r\n"
+- "Content-Length: %d\r\n"
+- "Content-Type: %s\r\n\r\n",
+- ast_get_version(), buf, len, route->file->mime_type);
++ http_header = ast_str_create(80);
++ ast_str_set(&http_header, 0, "Content-type: %s\r\n",
++ route->file->mime_type);
+
+ while ((len = read(fd, buf, sizeof(buf))) > 0) {
+ if (fwrite(buf, 1, len, ser->f) != len) {
+@@ -455,12 +455,12 @@
+ }
+ }
+
++ ast_http_send(ser, method, 200, NULL, http_header, NULL, fd, 0);
+ close(fd);
+ route = unref_route(route);
+- return NULL;
++ return 0;
+ } else { /* Dynamic file */
+- int bufsize;
+- char *tmp;
++ struct ast_str *tmp;
+
+ len = load_file(path, &file);
+ if (len < 0) {
+@@ -476,12 +476,7 @@
+ goto out500;
+ }
+
+- /* 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))) {
++ if (!(tmp = ast_str_create(len))) {
+ if (file) {
+ ast_free(file);
+ }
+@@ -510,39 +505,42 @@
+ }
+ }
+
+- pbx_substitute_variables_varshead(AST_LIST_FIRST(&route->user->extensions)->headp, file, tmp, bufsize);
++ ast_str_substitute_variables_varshead(&tmp, 0, AST_LIST_FIRST(&route->user->extensions)->headp, file);
+
+ if (file) {
+ ast_free(file);
+ }
+
+- ast_str_append(&result, 0,
+- "Content-Type: %s\r\n"
+- "Content-length: %d\r\n"
+- "\r\n"
+- "%s", route->file->mime_type, (int) strlen(tmp), tmp);
++ ast_str_set(&http_header, 0, "Content-type: %s\r\n",
++ route->file->mime_type);
+
++ if (!(result = ast_str_create(512))) {
++ ast_log(LOG_ERROR, "Could not create result string!\n");
++ if (tmp) {
++ ast_free(tmp);
++ }
++ goto out500;
++ }
++ ast_str_append(&result, 0, "%s", ast_str_buffer(tmp));
++
++ ast_http_send(ser, method, 200, NULL, http_header, result, 0, 0);
+ if (tmp) {
+ ast_free(tmp);
+ }
+
+ route = unref_route(route);
+
+- return result;
++ return 0;
+ }
+
+ out404:
+- *status = 404;
+- *title = strdup("Not Found");
+- *contentlength = 0;
+- return ast_http_error(404, "Not Found", NULL, "The requested URL was not found on this server.");
++ ast_http_error(ser, 404, "Not Found", "Nothing to see here. Move along.");
++ return -1;
+
+ out500:
+ route = unref_route(route);
+- *status = 500;
+- *title = strdup("Internal Server Error");
+- *contentlength = 0;
+- return ast_http_error(500, "Internal Error", NULL, "An internal error has occured.");
++ ast_http_error(ser, 500, "Internal Error", "An internal error has occured.");
++ return -1;
+ }
+
+ /*! \brief Build a route structure and add it to the list of available http routes
+@@ -656,7 +654,8 @@
+ * 3) Default mime type specified in profile
+ * 4) text/plain
+ */
+- ast_string_field_set(pp_file, mime_type, S_OR(args.mimetype, (S_OR(S_OR(ftype2mtype(file_extension), profile->default_mime_type), "text/plain"))));
++ ast_string_field_set(pp_file, mime_type, S_OR(args.mimetype,
++ (S_OR(S_OR(ast_http_ftype2mtype(file_extension), profile->default_mime_type), "text/plain"))));
+
+ if (!strcasecmp(v->name, "static_file")) {
+ ast_string_field_set(pp_file, format, args.filename);
+@@ -856,18 +855,25 @@
+ static int add_user_extension(struct user *user, struct extension *exten)
+ {
+ struct ast_var_t *var;
++ struct ast_str *str = ast_str_create(16);
+
++ if (!str) {
++ return -1;
++ }
++
+ /* Append profile variables here, and substitute variables on profile
+ * setvars, so that we can use user specific variables in them */
+ AST_LIST_TRAVERSE(user->profile->headp, var, entries) {
+- char expand_buf[VAR_BUF_SIZE] = {0,};
+ struct ast_var_t *var2;
+
+- pbx_substitute_variables_varshead(exten->headp, var->value, expand_buf, sizeof(expand_buf));
+- if ((var2 = ast_var_assign(var->name, expand_buf)))
++ ast_str_substitute_variables_varshead(&str, 0, exten->headp, var->value);
++ if ((var2 = ast_var_assign(var->name, ast_str_buffer(str)))) {
+ AST_LIST_INSERT_TAIL(exten->headp, var2, entries);
++ }
+ }
+
++ ast_free(str);
++
+ if (AST_LIST_EMPTY(&user->extensions)) {
+ AST_LIST_INSERT_HEAD(&user->extensions, exten, entry);
+ } else {
+@@ -893,14 +899,18 @@
+ static int build_user_routes(struct user *user)
+ {
+ struct phoneprov_file *pp_file;
++ struct ast_str *str;
+
++ if (!(str = ast_str_create(16))) {
++ return -1;
++ }
++
+ AST_LIST_TRAVERSE(&user->profile->dynamic_files, pp_file, entry) {
+- char expand_buf[VAR_BUF_SIZE] = { 0, };
+-
+- pbx_substitute_variables_varshead(AST_LIST_FIRST(&user->extensions)->headp, pp_file->format, expand_buf, sizeof(expand_buf));
+- build_route(pp_file, user, expand_buf);
++ ast_str_substitute_variables_varshead(&str, 0, AST_LIST_FIRST(&user->extensions)->headp, pp_file->format);
++ build_route(pp_file, user, ast_str_buffer(str));
+ }
+
++ ast_free(str);
+ return 0;
+ }
+
+@@ -1079,17 +1089,22 @@
+ }
+
+ /*! \brief A dialplan function that can be used to print a string for each phoneprov user */
+-static int pp_each_user_exec(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
++static int pp_each_user_helper(struct ast_channel *chan, char *data, char *buf, struct ast_str **bufstr, int len)
+ {
+- char *tmp, expand_buf[VAR_BUF_SIZE] = {0,};
++ char *tmp;
+ struct ao2_iterator i;
+ struct user *user;
++ struct ast_str *str;
+ AST_DECLARE_APP_ARGS(args,
+ AST_APP_ARG(string);
+ AST_APP_ARG(exclude_mac);
+ );
+ AST_STANDARD_APP_ARGS(args, data);
+
++ if (!(str = ast_str_create(16))) {
++ return -1;
++ }
++
+ /* Fix data by turning %{ into ${ */
+ while ((tmp = strstr(args.string, "%{")))
+ *tmp = '$';
+@@ -1099,35 +1114,45 @@
+ if (!ast_strlen_zero(args.exclude_mac) && !strcasecmp(user->macaddress, args.exclude_mac)) {
+ continue;
+ }
+- pbx_substitute_variables_varshead(AST_LIST_FIRST(&user->extensions)->headp, args.string, expand_buf, sizeof(expand_buf));
+- ast_build_string(&buf, &len, "%s", expand_buf);
++ ast_str_substitute_variables_varshead(&str, len, AST_LIST_FIRST(&user->extensions)->headp, args.string);
++ if (buf) {
++ size_t slen = len;
++ ast_build_string(&buf, &slen, "%s", ast_str_buffer(str));
++ } else {
++ ast_str_append(bufstr, len, "%s", ast_str_buffer(str));
++ }
+ user = unref_user(user);
+ }
+
++ ast_free(str);
+ return 0;
+ }
+
++static int pp_each_user_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
++{
++ return pp_each_user_helper(chan, data, buf, NULL, len);
++}
++
++static int pp_each_user_read2(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t len)
++{
++ return pp_each_user_helper(chan, data, NULL, buf, len);
++}
++
+ static struct ast_custom_function pp_each_user_function = {
+ .name = "PP_EACH_USER",
+- .synopsis = "Generate a string for each phoneprov user",
+- .syntax = "PP_EACH_USER(<string>|<exclude_mac>)",
+- .desc =
+- "Pass in a string, with phoneprov variables you want substituted in the format of\n"
+- "%{VARNAME}, and you will get the string rendered for each user in phoneprov\n"
+- "excluding ones with MAC address <exclude_mac>. Probably not useful outside of\n"
+- "res_phoneprov.\n"
+- "\nExample: ${PP_EACH_USER(<item><fn>%{DISPLAY_NAME}</fn></item>|${MAC})",
+- .read = pp_each_user_exec,
++ .read = pp_each_user_read,
++ .read2 = pp_each_user_read2,
+ };
+
+ /*! \brief A dialplan function that can be used to output a template for each extension attached to a user */
+-static int pp_each_extension_exec(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
++static int pp_each_extension_helper(struct ast_channel *chan, const char *cmd, char *data, char *buf, struct ast_str **bufstr, int len)
+ {
+ struct user *user;
+ struct extension *exten;
+ char path[PATH_MAX];
+ char *file;
+ int filelen;
++ struct ast_str *str;
+ AST_DECLARE_APP_ARGS(args,
+ AST_APP_ARG(mac);
+ AST_APP_ARG(template);
+@@ -1159,27 +1184,42 @@
+ return 0;
+ }
+
++ if (!(str = ast_str_create(filelen))) {
++ return 0;
++ }
++
+ AST_LIST_TRAVERSE(&user->extensions, exten, entry) {
+- char expand_buf[VAR_BUF_SIZE] = {0,};
+- pbx_substitute_variables_varshead(exten->headp, file, expand_buf, sizeof(expand_buf));
+- ast_build_string(&buf, &len, "%s", expand_buf);
++ ast_str_substitute_variables_varshead(&str, 0, exten->headp, file);
++ if (buf) {
++ size_t slen = len;
++ ast_build_string(&buf, &slen, "%s", ast_str_buffer(str));
++ } else {
++ ast_str_append(bufstr, len, "%s", ast_str_buffer(str));
++ }
+ }
+
+ ast_free(file);
++ ast_free(str);
+
+ user = unref_user(user);
+
+ return 0;
+ }
+
++static int pp_each_extension_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
++{
++ return pp_each_extension_helper(chan, cmd, data, buf, NULL, len);
++}
++
++static int pp_each_extension_read2(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t len)
++{
++ return pp_each_extension_helper(chan, cmd, data, NULL, buf, len);
++}
++
+ static struct ast_custom_function pp_each_extension_function = {
+ .name = "PP_EACH_EXTENSION",
+- .synopsis = "Execute specified template for each extension",
+- .syntax = "PP_EACH_EXTENSION(<mac>|<template>)",
+- .desc =
+- "Output the specified template for each extension associated with the specified\n"
+- "MAC address.",
+- .read = pp_each_extension_exec,
++ .read = pp_each_extension_read,
++ .read2 = pp_each_extension_read2,
+ };
+
+ /*! \brief CLI command to list static and dynamic routes */
+@@ -1233,7 +1273,6 @@
+ .description = "Asterisk HTTP Phone Provisioning Tool",
+ .uri = "phoneprov",
+ .has_subtree = 1,
+- .supports_get = 1,
+ .data = NULL,
+ .key = __FILE__,
+ };
+@@ -1305,7 +1344,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: res/res_calendar_caldav.c
+===================================================================
+--- a/res/res_calendar_caldav.c (.../tags/1.6.2.0-beta3) (revision 0)
++++ b/res/res_calendar_caldav.c (.../trunk) (revision 202568)
+@@ -0,0 +1,675 @@
++/*
++ * Asterisk -- An open source telephony toolkit.
++ *
++ * Copyright (C) 2008 - 2009, Digium, Inc.
++ *
++ * Terry Wilson <twilson@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 Resource for handling iCalnedar calendars
++ */
++
++/*** MODULEINFO
++ <depend>neon</depend>
++ <depend>ical</depend>
++ <depend>libxml2</depend>
++***/
++#include "asterisk.h"
++
++ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
++
++#include <libical/ical.h>
++#include <neon/ne_session.h>
++#include <neon/ne_uri.h>
++#include <neon/ne_request.h>
++#include <neon/ne_auth.h>
++#include <libxml/xmlmemory.h>
++#include <libxml/parser.h>
++
++#include "asterisk/module.h"
++#include "asterisk/calendar.h"
++#include "asterisk/lock.h"
++#include "asterisk/config.h"
++#include "asterisk/astobj2.h"
++
++static void *caldav_load_calendar(void *data);
++static void *unref_caldav(void *obj);
++static int caldav_write_event(struct ast_calendar_event *event);
++
++static struct ast_calendar_tech caldav_tech = {
++ .type = "caldav",
++ .description = "CalDAV calendars",
++ .module = AST_MODULE,
++ .load_calendar = caldav_load_calendar,
++ .unref_calendar = unref_caldav,
++ .write_event = caldav_write_event,
++};
++
++struct caldav_pvt {
++ AST_DECLARE_STRING_FIELDS(
++ AST_STRING_FIELD(url);
++ AST_STRING_FIELD(user);
++ AST_STRING_FIELD(secret);
++ );
++ struct ast_calendar *owner;
++ ne_uri uri;
++ ne_session *session;
++ struct ao2_container *events;
++};
++
++static int cb_true(void *user_data, void *arg, int flags)
++{
++ return CMP_MATCH;
++}
++
++static void caldav_destructor(void *obj)
++{
++ struct caldav_pvt *pvt = obj;
++
++ ast_debug(1, "Destroying pvt for CalDAV calendar %s\n", pvt->owner->name);
++ if (pvt->session) {
++ ne_session_destroy(pvt->session);
++ }
++ ast_string_field_free_memory(pvt);
++
++ ao2_callback(pvt->events, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, cb_true, NULL);
++
++ ao2_ref(pvt->events, -1);
++}
++
++static void *unref_caldav(void *obj)
++{
++ struct caldav_pvt *pvt = obj;
++
++ ao2_ref(pvt, -1);
++ return NULL;
++}
++
++static int fetch_response_reader(void *data, const char *block, size_t len)
++{
++ struct ast_str **response = data;
++ unsigned char *tmp;
++
++ if (!(tmp = ast_malloc(len + 1))) {
++ return -1;
++ }
++ memcpy(tmp, block, len);
++ tmp[len] = '\0';
++ ast_str_append(response, 0, "%s", tmp);
++ ast_free(tmp);
++
++ return 0;
++}
++
++static int auth_credentials(void *userdata, const char *realm, int attempts, char *username, char *secret)
++{
++ struct caldav_pvt *pvt = userdata;
++
++ if (attempts > 1) {
++ ast_log(LOG_WARNING, "Invalid username or password for CalDAV calendar '%s'\n", pvt->owner->name);
++ return -1;
++ }
++
++ ne_strnzcpy(username, pvt->user, NE_ABUFSIZ);
++ ne_strnzcpy(secret, pvt->secret, NE_ABUFSIZ);
++
++ return 0;
++}
++
++static struct ast_str *caldav_request(struct caldav_pvt *pvt, const char *method, struct ast_str *req_body, struct ast_str *subdir, const char *content_type)
++{
++ struct ast_str *response;
++ ne_request *req;
++ int ret;
++ char buf[1000];
++
++ if (!pvt) {
++ ast_log(LOG_ERROR, "There is no private!\n");
++ return NULL;
++ }
++
++ if (!(response = ast_str_create(512))) {
++ ast_log(LOG_ERROR, "Could not allocate memory for response.\n");
++ return NULL;
++ }
++
++ snprintf(buf, sizeof(buf), "%s%s", pvt->uri.path, subdir ? ast_str_buffer(subdir) : "");
++
++ req = ne_request_create(pvt->session, method, buf);
++ ne_add_response_body_reader(req, ne_accept_2xx, fetch_response_reader, &response);
++ ne_set_request_body_buffer(req, ast_str_buffer(req_body), ast_str_strlen(req_body));
++ ne_add_request_header(req, "Content-type", ast_strlen_zero(content_type) ? "text/xml" : content_type);
++
++ ret = ne_request_dispatch(req);
++ ne_request_destroy(req);
++
++ if (ret != NE_OK || !ast_str_strlen(response)) {
++ ast_log(LOG_WARNING, "Unknown response to CalDAV calendar %s, request %s to %s: %s\n", pvt->owner->name, method, pvt->url, ne_get_error(pvt->session));
++ ast_free(response);
++ return NULL;
++ }
++
++ return response;
++}
++
++static int caldav_write_event(struct ast_calendar_event *event)
++{
++ struct ast_str *body = NULL, *response = NULL, *subdir = NULL;
++ icalcomponent *calendar, *icalevent;
++ icaltimezone *utc = icaltimezone_get_utc_timezone();
++ int ret = -1;
++
++ if (!event) {
++ ast_log(LOG_WARNING, "No event passed!\n");
++ return -1;
++ }
++
++ if (!(event->start && event->end)) {
++ ast_log(LOG_WARNING, "The event must contain a start and an end\n");
++ return -1;
++ }
++ if (!(body = ast_str_create(512)) ||
++ !(subdir = ast_str_create(32)) ||
++ !(response = ast_str_create(512))) {
++ ast_log(LOG_ERROR, "Could not allocate memory for request and response!\n");
++ goto write_cleanup;
++ }
++
++ if (ast_strlen_zero(event->uid)) {
++ unsigned short val[8];
++ int x;
++ for (x = 0; x < 8; x++) {
++ val[x] = ast_random();
++ }
++ ast_string_field_build(event, uid, "%04x%04x-%04x-%04x-%04x-%04x%04x%04x", val[0], val[1], val[2], val[3], val[4], val[5], val[6], val[7]);
++ }
++
++ calendar = icalcomponent_new(ICAL_VCALENDAR_COMPONENT);
++ icalcomponent_add_property(calendar, icalproperty_new_version("2.0"));
++ icalcomponent_add_property(calendar, icalproperty_new_prodid("-//Digium, Inc.//res_caldav//EN"));
++
++ icalevent = icalcomponent_new(ICAL_VEVENT_COMPONENT);
++ icalcomponent_add_property(icalevent, icalproperty_new_dtstamp(icaltime_current_time_with_zone(utc)));
++ icalcomponent_add_property(icalevent, icalproperty_new_uid(event->uid));
++ icalcomponent_add_property(icalevent, icalproperty_new_dtstart(icaltime_from_timet_with_zone(event->start, 0, utc)));
++ icalcomponent_add_property(icalevent, icalproperty_new_dtend(icaltime_from_timet_with_zone(event->end, 0, utc)));
++ if (!ast_strlen_zero(event->organizer)) {
++ icalcomponent_add_property(icalevent, icalproperty_new_organizer(event->organizer));
++ }
++ if (!ast_strlen_zero(event->summary)) {
++ icalcomponent_add_property(icalevent, icalproperty_new_summary(event->summary));
++ }
++ if (!ast_strlen_zero(event->description)) {
++ icalcomponent_add_property(icalevent, icalproperty_new_description(event->description));
++ }
++ if (!ast_strlen_zero(event->location)) {
++ icalcomponent_add_property(icalevent, icalproperty_new_location(event->location));
++ }
++
++ switch (event->busy_state) {
++ case AST_CALENDAR_BS_BUSY:
++ icalcomponent_add_property(icalevent, icalproperty_new_status(ICAL_STATUS_CONFIRMED));
++ break;
++
++ case AST_CALENDAR_BS_BUSY_TENTATIVE:
++ icalcomponent_add_property(icalevent, icalproperty_new_status(ICAL_STATUS_TENTATIVE));
++ break;
++
++ default:
++ icalcomponent_add_property(icalevent, icalproperty_new_status(ICAL_STATUS_NONE));
++ }
++
++ icalcomponent_add_component(calendar, icalevent);
++
++ ast_str_append(&body, 0, "%s", icalcomponent_as_ical_string(calendar));
++ ast_str_set(&subdir, 0, "%s%s.ics", ast_str_buffer(body)[ast_str_strlen(body)] == '/' ? "" : "/", event->uid);
++
++ response = caldav_request(event->owner->tech_pvt, "PUT", body, subdir, "text/calendar");
++
++ ret = 0;
++
++write_cleanup:
++ if (body) {
++ ast_free(body);
++ }
++ if (response) {
++ ast_free(response);
++ }
++ if (subdir) {
++ ast_free(subdir);
++ }
++
++ return ret;
++}
++
++static struct ast_str *caldav_get_events_between(struct caldav_pvt *pvt, time_t start_time, time_t end_time)
++{
++ struct ast_str *body, *response;
++ icaltimezone *utc = icaltimezone_get_utc_timezone();
++ icaltimetype start, end;
++ const char *start_str, *end_str;
++
++ if (!(body = ast_str_create(512))) {
++ ast_log(LOG_ERROR, "Could not allocate memory for body of request!\n");
++ return NULL;
++ }
++
++ start = icaltime_from_timet_with_zone(start_time, 0, utc);
++ end = icaltime_from_timet_with_zone(end_time, 0, utc);
++ start_str = icaltime_as_ical_string(start);
++ end_str = icaltime_as_ical_string(end);
++
++ /* If I was really being efficient, I would store a collection of event URIs and etags,
++ * first doing a query of just the etag and seeing if anything had changed. If it had,
++ * then I would do a request for each of the events that had changed, and only bother
++ * updating those. Oh well. */
++ ast_str_append(&body, 0,
++ "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n"
++ "<C:calendar-query xmlns:D=\"DAV:\" xmlns:C=\"urn:ietf:params:xml:ns:caldav\">\n"
++ " <D:prop>\n"
++ " <C:calendar-data>\n"
++ " <C:expand start=\"%s\" end=\"%s\"/>\n"
++ " </C:calendar-data>\n"
++ " </D:prop>\n"
++ " <C:filter>\n"
++ " <C:comp-filter name=\"VCALENDAR\">\n"
++ " <C:comp-filter name=\"VEVENT\">\n"
++ " <C:time-range start=\"%s\" end=\"%s\"/>\n"
++ " </C:comp-filter>\n"
++ " </C:comp-filter>\n"
++ " </C:filter>\n"
++ "</C:calendar-query>\n", start_str, end_str, start_str, end_str);
++
++ response = caldav_request(pvt, "REPORT", body, NULL, NULL);
++ ast_free(body);
++
++ return response;
++}
++
++static void caldav_add_event(icalcomponent *comp, struct icaltime_span *span, void *data)
++{
++ struct caldav_pvt *pvt = data;
++ struct ast_calendar_event *event;
++ icaltimezone *utc = icaltimezone_get_utc_timezone();
++ icaltimetype start, end, tmp;
++ icalcomponent *valarm;
++ icalproperty *prop;
++ struct icaltriggertype trigger;
++
++ if (!(pvt && pvt->owner)) {
++ ast_log(LOG_ERROR, "Require a private structure with an owner\n");
++ return;
++ }
++
++ if (!(event = ast_calendar_event_alloc(pvt->owner))) {
++ ast_log(LOG_ERROR, "Could not allocate an event!\n");
++ return;
++ }
++
++ start = icaltime_from_timet_with_zone(span->start, 0, utc);
++ end = icaltime_from_timet_with_zone(span->end, 0, utc);
++ event->start = span->start;
++ event->end = span->end;
++
++ switch(icalcomponent_get_status(comp)) {
++ case ICAL_STATUS_CONFIRMED:
++ event->busy_state = AST_CALENDAR_BS_BUSY;
++ break;
++
++ case ICAL_STATUS_TENTATIVE:
++ event->busy_state = AST_CALENDAR_BS_BUSY_TENTATIVE;
++ break;
++
++ default:
++ event->busy_state = AST_CALENDAR_BS_FREE;
++ }
++
++ if ((prop = icalcomponent_get_first_property(comp, ICAL_SUMMARY_PROPERTY))) {
++ ast_string_field_set(event, summary, icalproperty_get_value_as_string(prop));
++ }
++
++ if ((prop = icalcomponent_get_first_property(comp, ICAL_DESCRIPTION_PROPERTY))) {
++ ast_string_field_set(event, description, icalproperty_get_value_as_string(prop));
++ }
++
++ if ((prop = icalcomponent_get_first_property(comp, ICAL_ORGANIZER_PROPERTY))) {
++ ast_string_field_set(event, organizer, icalproperty_get_value_as_string(prop));
++ }
++
++ if ((prop = icalcomponent_get_first_property(comp, ICAL_LOCATION_PROPERTY))) {
++ ast_string_field_set(event, location, icalproperty_get_value_as_string(prop));
++ }
++
++ if ((prop = icalcomponent_get_first_property(comp, ICAL_UID_PROPERTY))) {
++ ast_string_field_set(event, uid, icalproperty_get_value_as_string(prop));
++ } else {
++ ast_log(LOG_WARNING, "No UID found, but one is required. Generating, but updates may not be acurate\n");
++ if (!ast_strlen_zero(event->summary)) {
++ ast_string_field_set(event, uid, event->summary);
++ } else {
++ char tmp[100];
++ snprintf(tmp, sizeof(tmp), "%lu", event->start);
++ ast_string_field_set(event, uid, tmp);
++ }
++ }
++
++ /* Get the attendees */
++ for (prop = icalcomponent_get_first_property(comp, ICAL_ATTENDEE_PROPERTY);
++ prop; prop = icalcomponent_get_next_property(comp, ICAL_ATTENDEE_PROPERTY)) {
++ struct ast_calendar_attendee *attendee;
++ const char *data;
++
++ if (!(attendee = ast_calloc(1, sizeof(*attendee)))) {
++ event = ast_calendar_unref_event(event);
++ return;
++ }
++ data = icalproperty_get_attendee(prop);
++ if (!ast_strlen_zero(data)) {
++ attendee->data = ast_strdup(data);;
++ AST_LIST_INSERT_TAIL(&event->attendees, attendee, next);
++ }
++ }
++
++
++ /* Only set values for alarm based on VALARM. Can be overriden in main/calendar.c by autoreminder
++ * therefore, go ahead and add events even if their is no VALARM or it is malformed
++ * Currently we are only getting the first VALARM and are handling repitition in main/calendar.c from calendar.conf */
++ if (!(valarm = icalcomponent_get_first_component(comp, ICAL_VALARM_COMPONENT))) {
++ ao2_link(pvt->events, event);
++ event = ast_calendar_unref_event(event);
++ return;
++ }
++
++ if (!(prop = icalcomponent_get_first_property(valarm, ICAL_TRIGGER_PROPERTY))) {
++ ast_log(LOG_WARNING, "VALARM has no TRIGGER, skipping!\n");
++ ao2_link(pvt->events, event);
++ event = ast_calendar_unref_event(event);
++ return;
++ }
++
++ trigger = icalproperty_get_trigger(prop);
++
++ if (icaltriggertype_is_null_trigger(trigger)) {
++ ast_log(LOG_WARNING, "Bad TRIGGER for VALARM, skipping!\n");
++ ao2_link(pvt->events, event);
++ event = ast_calendar_unref_event(event);
++ return;
++ }
++
++ if (!icaltime_is_null_time(trigger.time)) { /* This is an absolute time */
++ tmp = icaltime_convert_to_zone(trigger.time, utc);
++ event->alarm = icaltime_as_timet_with_zone(tmp, utc);
++ } else { /* Offset from either dtstart or dtend */
++ /* XXX Technically you can check RELATED to see if the event fires from the END of the event
++ * But, I'm not sure I've ever seen anyone implement it in calendaring software, so I'm ignoring for now */
++ tmp = icaltime_add(start, trigger.duration);
++ event->alarm = icaltime_as_timet_with_zone(tmp, utc);
++ }
++
++ ao2_link(pvt->events, event);
++ event = ast_calendar_unref_event(event);
++
++ return;
++}
++
++struct xmlstate {
++ int in_caldata;
++ struct caldav_pvt *pvt;
++ struct ast_str *cdata;
++ time_t start;
++ time_t end;
++};
++
++static void handle_start_element(void *data, const xmlChar *fullname, const xmlChar **atts)
++{
++ struct xmlstate *state = data;
++
++ if (!xmlStrcasecmp(fullname, BAD_CAST "C:calendar-data")) {
++ state->in_caldata = 1;
++ ast_str_reset(state->cdata);
++ }
++}
++
++static void handle_end_element(void *data, const xmlChar *name)
++{
++ struct xmlstate *state = data;
++ struct icaltimetype start, end;
++ icaltimezone *utc = icaltimezone_get_utc_timezone();
++ icalcomponent *iter;
++ icalcomponent *comp;
++
++ if (xmlStrcasecmp(name, BAD_CAST "C:calendar-data")) {
++ return;
++ }
++
++ state->in_caldata = 0;
++ if (!(state->cdata && ast_str_strlen(state->cdata))) {
++ return;
++ }
++ /* XXX Parse the calendar blurb for recurrence events in the time range,
++ * create an event, and add it to pvt->events */
++ start = icaltime_from_timet_with_zone(state->start, 0, utc);
++ end = icaltime_from_timet_with_zone(state->end, 0, utc);
++ comp = icalparser_parse_string(ast_str_buffer(state->cdata));
++
++ for (iter = icalcomponent_get_first_component(comp, ICAL_VEVENT_COMPONENT);
++ iter;
++ iter = icalcomponent_get_next_component(comp, ICAL_VEVENT_COMPONENT))
++ {
++ icalcomponent_foreach_recurrence(iter, start, end, caldav_add_event, state->pvt);
++ }
++
++ icalcomponent_free(comp);
++}
++
++static void handle_characters(void *data, const xmlChar *ch, int len)
++{
++ struct xmlstate *state = data;
++ xmlChar *tmp;
++
++ if (!state->in_caldata) {
++ return;
++ }
++
++ tmp = xmlStrndup(ch, len);
++ ast_str_append(&state->cdata, 0, "%s", (char *)tmp);
++ xmlFree(tmp);
++}
++
++static int update_caldav(struct caldav_pvt *pvt)
++{
++ struct timeval now = ast_tvnow();
++ time_t start, end;
++ struct ast_str *response;
++ xmlSAXHandler saxHandler;
++ struct xmlstate state = {
++ .in_caldata = 0,
++ .pvt = pvt
++ };
++
++ start = now.tv_sec;
++ end = now.tv_sec + 60 * pvt->owner->timeframe;
++ if (!(response = caldav_get_events_between(pvt, start, end))) {
++ return -1;
++ }
++
++ if (!(state.cdata = ast_str_create(512))) {
++ ast_free(response);
++ return -1;
++ }
++
++ state.start = start;
++ state.end = end;
++
++ memset(&saxHandler, 0, sizeof(saxHandler));
++ saxHandler.startElement = handle_start_element;
++ saxHandler.endElement = handle_end_element;
++ saxHandler.characters = handle_characters;
++
++ xmlSAXUserParseMemory(&saxHandler, &state, ast_str_buffer(response), ast_str_strlen(response));
++
++ ast_calendar_merge_events(pvt->owner, pvt->events);
++
++ ast_free(response);
++ ast_free(state.cdata);
++
++ return 0;
++}
++
++static int verify_cert(void *userdata, int failures, const ne_ssl_certificate *cert)
++{
++ /* Verify all certs */
++ return 0;
++}
++
++static void *caldav_load_calendar(void *void_data)
++{
++ struct caldav_pvt *pvt;
++ struct ast_variable *v;
++ struct ast_calendar *cal = void_data;
++ ast_mutex_t refreshlock;
++
++ if (!(cal && ast_calendar_config)) {
++ ast_log(LOG_ERROR, "You must enable calendar support for res_caldav to load\n");
++ return NULL;
++ }
++
++ if (ao2_trylock(cal)) {
++ if (cal->unloading) {
++ ast_log(LOG_WARNING, "Unloading module, load_calendar cancelled.\n");
++ } else {
++ ast_log(LOG_WARNING, "Could not lock calendar, aborting!\n");
++ }
++ return NULL;
++ }
++
++ if (!(pvt = ao2_alloc(sizeof(*pvt), caldav_destructor))) {
++ ast_log(LOG_ERROR, "Could not allocate caldav_pvt structure for calendar: %s\n", cal->name);
++ return NULL;
++ }
++
++ pvt->owner = cal;
++
++ if (!(pvt->events = ast_calendar_event_container_alloc())) {
++ ast_log(LOG_ERROR, "Could not allocate space for fetching events for calendar: %s\n", cal->name);
++ pvt = unref_caldav(pvt);
++ ao2_unlock(cal);
++ return NULL;
++ }
++
++ if (ast_string_field_init(pvt, 32)) {
++ ast_log(LOG_ERROR, "Couldn't allocate string field space for calendar: %s\n", cal->name);
++ pvt = unref_caldav(pvt);
++ ao2_unlock(cal);
++ return NULL;
++ }
++
++ for (v = ast_variable_browse(ast_calendar_config, cal->name); v; v = v->next) {
++ if (!strcasecmp(v->name, "url")) {
++ ast_string_field_set(pvt, url, v->value);
++ } else if (!strcasecmp(v->name, "user")) {
++ ast_string_field_set(pvt, user, v->value);
++ } else if (!strcasecmp(v->name, "secret")) {
++ ast_string_field_set(pvt, secret, v->value);
++ }
++ }
++
++ if (ast_strlen_zero(pvt->url)) {
++ ast_log(LOG_WARNING, "No URL was specified for CalDAV calendar '%s' - skipping.\n", cal->name);
++ pvt = unref_caldav(pvt);
++ ao2_unlock(cal);
++ return NULL;
++ }
++
++ if (ne_uri_parse(pvt->url, &pvt->uri) || pvt->uri.host == NULL || pvt->uri.path == NULL) {
++ ast_log(LOG_WARNING, "Could not parse url '%s' for CalDAV calendar '%s' - skipping.\n", pvt->url, cal->name);
++ pvt = unref_caldav(pvt);
++ ao2_unlock(cal);
++ return NULL;
++ }
++
++ if (pvt->uri.scheme == NULL) {
++ pvt->uri.scheme = "http";
++ }
++
++ if (pvt->uri.port == 0) {
++ pvt->uri.port = ne_uri_defaultport(pvt->uri.scheme);
++ }
++
++ pvt->session = ne_session_create(pvt->uri.scheme, pvt->uri.host, pvt->uri.port);
++ ne_set_server_auth(pvt->session, auth_credentials, pvt);
++ if (!strncasecmp(pvt->uri.scheme, "https", sizeof(pvt->uri.scheme))) {
++ ne_ssl_trust_default_ca(pvt->session);
++ ne_ssl_set_verify(pvt->session, verify_cert, NULL);
++ }
++
++ cal->tech_pvt = pvt;
++
++ ast_mutex_init(&refreshlock);
++
++ /* Load it the first time */
++ update_caldav(pvt);
++
++ ao2_unlock(cal);
++
++ /* The only writing from another thread will be if unload is true */
++ for (;;) {
++ struct timeval tv = ast_tvnow();
++ struct timespec ts = {0,};
++
++ ts.tv_sec = tv.tv_sec + (60 * pvt->owner->refresh);
++
++ ast_mutex_lock(&refreshlock);
++ while (!pvt->owner->unloading) {
++ if (ast_cond_timedwait(&pvt->owner->unload, &refreshlock, &ts) == ETIMEDOUT) {
++ break;
++ }
++ }
++ ast_mutex_unlock(&refreshlock);
++
++ if (pvt->owner->unloading) {
++ ast_debug(10, "Skipping refresh since we got a shutdown signal\n");
++ return NULL;
++ }
++
++ ast_debug(10, "Refreshing after %d minute timeout\n", pvt->owner->refresh);
++
++ update_caldav(pvt);
++ }
++
++ return NULL;
++}
++
++static int load_module(void)
++{
++ ne_sock_init();
++ if (ast_calendar_register(&caldav_tech)) {
++ ne_sock_exit();
++ return AST_MODULE_LOAD_DECLINE;
++ }
++
++ return AST_MODULE_LOAD_SUCCESS;
++}
++
++static int unload_module(void)
++{
++ ast_calendar_unregister(&caldav_tech);
++ ne_sock_exit();
++ return 0;
++}
++
++AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Asterisk CalDAV Calendar Integration",
++ .load = load_module,
++ .unload = unload_module,
++ );
+
+Property changes on: res/res_calendar_caldav.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+Added: svn:mime-type
+ + text/plain
+Added: svn:keywords
+ + Author Date Id Revision
+
+Index: res/snmp/agent.c
+===================================================================
+--- a/res/snmp/agent.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/res/snmp/agent.c (.../trunk) (revision 202568)
+@@ -236,19 +236,32 @@
+ u_char *ret = NULL;
+ int i, bit;
+ struct ast_str *out = ast_str_alloca(2048);
++ struct ast_channel_iterator *iter;
+
+ if (header_simple_table(vp, name, length, exact, var_len, write_method, ast_active_channels()))
+ return NULL;
+
+ i = name[*length - 1] - 1;
+- for (chan = ast_channel_walk_locked(NULL);
+- chan && i;
+- chan = ast_channel_walk_locked(chan), i--)
+- ast_channel_unlock(chan);
+- if (chan == NULL)
++
++ if (!(iter = ast_channel_iterator_all_new(0))) {
+ return NULL;
++ }
++
++ while ((chan = ast_channel_iterator_next(iter)) && i) {
++ ast_channel_unref(chan);
++ i--;
++ }
++
++ iter = ast_channel_iterator_destroy(iter);
++
++ if (chan == NULL) {
++ return NULL;
++ }
++
+ *var_len = sizeof(long_ret);
+
++ ast_channel_lock(chan);
++
+ switch (vp->magic) {
+ case ASTCHANINDEX:
+ long_ret = name[*length - 1];
+@@ -503,7 +516,10 @@
+ default:
+ break;
+ }
++
+ ast_channel_unlock(chan);
++ chan = ast_channel_unref(chan);
++
+ return ret;
+ }
+
+@@ -567,13 +583,26 @@
+ long_ret = tech->transfer ? 1 : 2;
+ return (u_char *)&long_ret;
+ case ASTCHANTYPECHANNELS:
++ {
++ struct ast_channel_iterator *iter;
++
+ long_ret = 0;
+- for (chan = ast_channel_walk_locked(NULL); chan; chan = ast_channel_walk_locked(chan)) {
+- if (chan->tech == tech)
++
++ if (!(iter = ast_channel_iterator_all_new(0))) {
++ return NULL;
++ }
++
++ while ((chan = ast_channel_iterator_next(iter))) {
++ if (chan->tech == tech) {
+ long_ret++;
+- ast_channel_unlock(chan);
++ }
++ chan = ast_channel_unref(chan);
+ }
++
++ ast_channel_iterator_destroy(iter);
++
+ return (u_char *)&long_ret;
++ }
+ default:
+ break;
+ }
+@@ -585,15 +614,25 @@
+ {
+ static unsigned long long_ret;
+ struct ast_channel *chan = NULL;
++ struct ast_channel_iterator *iter;
+
+ long_ret = 0;
+- if (header_generic(vp, name, length, exact, var_len, write_method))
++
++ if (header_generic(vp, name, length, exact, var_len, write_method)) {
+ return NULL;
++ }
+
+- while ((chan = ast_channel_walk_locked(chan))) {
+- if (ast_bridged_channel(chan))
++ if (!(iter = ast_channel_iterator_all_new(0))) {
++ return NULL;
++ }
++
++ while ((chan = ast_channel_iterator_next(iter))) {
++ ast_channel_lock(chan);
++ if (ast_bridged_channel(chan)) {
+ long_ret++;
++ }
+ ast_channel_unlock(chan);
++ chan = ast_channel_unref(chan);
+ }
+
+ *var_len = sizeof(long_ret);
+Index: res/res_http_post.c
+===================================================================
+--- a/res/res_http_post.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/res/res_http_post.c (.../trunk) (revision 202568)
+@@ -156,7 +156,6 @@
+ return cbinfo.count;
+ }
+
+-
+ /* Find a sequence of bytes within a binary array. */
+ static int find_sequence(char * inbuf, int inlen, char * matchbuf, int matchlen)
+ {
+@@ -292,10 +291,9 @@
+ 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)
++static int 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 *get_vars, struct ast_variable *headers)
+ {
+- struct ast_variable *var;
++ struct ast_variable *var, *cookies;
+ unsigned long ident = 0;
+ FILE *f;
+ int content_len = 0;
+@@ -304,41 +302,45 @@
+ int message_count = 0;
+ char * boundary_marker = NULL;
+
+- if (!urih) {
+- return ast_http_error((*status = 400),
+- (*title = ast_strdup("Missing URI handle")),
+- NULL, "There was an error parsing the request");
++ if (method != AST_HTTP_POST) {
++ ast_http_error(ser, 501, "Not Implemented", "Attempt to use unimplemented / unsupported method");
++ return -1;
+ }
+
+- for (var = vars; var; var = var->next) {
+- if (strcasecmp(var->name, "mansession_id")) {
+- continue;
+- }
++ if (!astman_is_authed(ast_http_manid_from_vars(headers))) {
++ ast_http_error(ser, 403, "Access Denied", "Sorry, I cannot let you do that, Dave.");
++ return -1;
++ }
+
+- if (sscanf(var->value, "%lx", &ident) != 1) {
+- return ast_http_error((*status = 400),
+- (*title = ast_strdup("Bad Request")),
+- NULL, "The was an error parsing the request.");
+- }
++ if (!urih) {
++ ast_http_error(ser, 400, "Missing URI handle", "There was an error parsing the request");
++ return -1;
++ }
+
+- if (!astman_verify_session_writepermissions(ident, EVENT_FLAG_CONFIG)) {
+- return ast_http_error((*status = 401),
+- (*title = ast_strdup("Unauthorized")),
+- NULL, "You are not authorized to make this request.");
++ cookies = ast_http_get_cookies(headers);
++ for (var = cookies; var; var = var->next) {
++ if (!strcasecmp(var->name, "mansession_id")) {
++ sscanf(var->value, "%lx", &ident);
++ break;
+ }
+-
+- break;
+ }
++ if (cookies) {
++ ast_variables_destroy(cookies);
++ }
+
+- if (!var) {
+- return ast_http_error((*status = 401),
+- (*title = ast_strdup("Unauthorized")),
+- NULL, "You are not authorized to make this request.");
++ if (ident == 0) {
++ ast_http_error(ser, 401, "Unauthorized", "You are not authorized to make this request.");
++ return -1;
+ }
++ if (!astman_verify_session_writepermissions(ident, EVENT_FLAG_CONFIG)) {
++ ast_http_error(ser, 401, "Unauthorized", "You are not authorized to make this request.");
++ return -1;
++ }
+
+ if (!(f = tmpfile())) {
+ ast_log(LOG_ERROR, "Could not create temp file.\n");
+- return NULL;
++ ast_http_error(ser, 500, "Internal server error", "Could not create temp file.");
++ return -1;
+ }
+
+ for (var = headers; var; var = var->next) {
+@@ -348,8 +350,8 @@
+ if ((sscanf(var->value, "%u", &content_len)) != 1) {
+ ast_log(LOG_ERROR, "Invalid Content-Length in POST request!\n");
+ fclose(f);
+-
+- return NULL;
++ ast_http_error(ser, 500, "Internal server error", "Invalid Content-Length in POST request!");
++ return -1;
+ }
+ ast_debug(1, "Got a Content-Length of %d\n", content_len);
+ } else if (!strcasecmp(var->name, "Content-Type")) {
+@@ -367,15 +369,15 @@
+ ast_log(LOG_DEBUG, "Cannot find boundary marker in POST request.\n");
+ }
+ fclose(f);
+-
+- return NULL;
++
++ return -1;
+ }
+
+ if (fseek(f, SEEK_SET, 0)) {
+ ast_log(LOG_ERROR, "Failed to seek temp file back to beginning.\n");
+ fclose(f);
+-
+- return NULL;
++ ast_http_error(ser, 500, "Internal server error", "Failed to seek temp file back to beginning.");
++ return -1;
+ }
+
+ post_dir = urih->data;
+@@ -385,24 +387,20 @@
+ if (!message) {
+ ast_log(LOG_ERROR, "Error parsing MIME data\n");
+
+- return ast_http_error((*status = 400),
+- (*title = ast_strdup("Bad Request")),
+- NULL, "The was an error parsing the request.");
++ ast_http_error(ser, 400, "Bad Request", "The was an error parsing the request.");
++ return -1;
+ }
+
+ 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),
+- (*title = ast_strdup("Bad Request")),
+- NULL, "The was an error parsing the request.");
++ ast_http_error(ser, 400, "Bad Request", "The was an error parsing the request.");
++ return -1;
+ }
+-
+ g_object_unref(message);
+
+- return ast_http_error((*status = 200),
+- (*title = ast_strdup("OK")),
+- NULL, "File successfully uploaded.");
++ ast_http_error(ser, 200, "OK", "File successfully uploaded.");
++ return 0;
+ }
+
+ static int __ast_http_post_load(int reload)
+@@ -450,8 +448,6 @@
+ ast_str_set(&ds, 0, "%s/%s", prefix, v->value);
+ urih->data = ds;
+ urih->has_subtree = 0;
+- urih->supports_get = 0;
+- urih->supports_post = 1;
+ urih->callback = http_post_callback;
+ urih->key = __FILE__;
+ urih->mallocd = urih->dmallocd = 1;
+Index: res/res_musiconhold.c
+===================================================================
+--- a/res/res_musiconhold.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/res/res_musiconhold.c (.../trunk) (revision 202568)
+@@ -70,54 +70,83 @@
+
+ #define INITIAL_NUM_FILES 8
+
+-static char *play_moh = "MusicOnHold";
+-static char *wait_moh = "WaitMusicOnHold";
+-static char *set_moh = "SetMusicOnHold";
+-static char *start_moh = "StartMusicOnHold";
+-static char *stop_moh = "StopMusicOnHold";
++/*** DOCUMENTATION
++ <application name="MusicOnHold" language="en_US">
++ <synopsis>
++ Play Music On Hold indefinitely.
++ </synopsis>
++ <syntax>
++ <parameter name="class" required="true" />
++ <parameter name="duration" />
++ </syntax>
++ <description>
++ <para>Plays hold music specified by class. If omitted, the default music
++ source for the channel will be used. Change the default class with
++ Set(CHANNEL(musicclass)=...). If duration is given, hold music will be played
++ specified number of seconds. If duration is ommited, music plays indefinitely.
++ Returns <literal>0</literal> when done, <literal>-1</literal> on hangup.</para>
++ </description>
++ </application>
++ <application name="WaitMusicOnHold" language="en_US">
++ <synopsis>
++ Wait, playing Music On Hold.
++ </synopsis>
++ <syntax>
++ <parameter name="delay" required="true" />
++ </syntax>
++ <description>
++ <para> !!! DEPRECATED. Use MusicOnHold instead !!!</para>
++ <para>Plays hold music specified number of seconds. Returns <literal>0</literal> when done,
++ or <literal>-1</literal> on hangup. If no hold music is available, the delay will still occur
++ with no sound.</para>
++ <para> !!! DEPRECATED. Use MusicOnHold instead !!!</para>
++ </description>
++ </application>
++ <application name="SetMusicOnHold" language="en_US">
++ <synopsis>
++ Set default Music On Hold class.
++ </synopsis>
++ <syntax>
++ <parameter name="class" required="yes" />
++ </syntax>
++ <description>
++ <para>!!! DEPRECATED. USe Set(CHANNEL(musicclass)=...) instead !!!</para>
++ <para>Sets the default class for music on hold for a given channel.
++ When music on hold is activated, this class will be used to select which
++ music is played.</para>
++ <para>!!! DEPRECATED. USe Set(CHANNEL(musicclass)=...) instead !!!</para>
++ </description>
++ </application>
++ <application name="StartMusicOnHold" language="en_US">
++ <synopsis>
++ Play Music On Hold.
++ </synopsis>
++ <syntax>
++ <parameter name="class" required="true" />
++ </syntax>
++ <description>
++ <para>Starts playing music on hold, uses default music class for channel.
++ Starts playing music specified by class. If omitted, the default music
++ source for the channel will be used. Always returns <literal>0</literal>.</para>
++ </description>
++ </application>
++ <application name="StopMusicOnHold" language="en_US">
++ <synopsis>
++ Stop playing Music On Hold.
++ </synopsis>
++ <syntax />
++ <description>
++ <para>Stops playing music on hold.</para>
++ </description>
++ </application>
++ ***/
+
+-static char *play_moh_syn = "Play Music On Hold indefinitely";
+-static char *wait_moh_syn = "Wait, playing Music On Hold";
+-static char *set_moh_syn = "Set default Music On Hold class";
+-static char *start_moh_syn = "Play Music On Hold";
+-static char *stop_moh_syn = "Stop Playing Music On Hold";
++static const char play_moh[] = "MusicOnHold";
++static const char wait_moh[] = "WaitMusicOnHold";
++static const char set_moh[] = "SetMusicOnHold";
++static const char start_moh[] = "StartMusicOnHold";
++static const char stop_moh[] = "StopMusicOnHold";
+
+-static char *play_moh_desc = " MusicOnHold(class[,duration]):\n"
+-"Plays hold music specified by class. If omitted, the default\n"
+-"music source for the channel will be used. Change the default \n"
+-"class with Set(CHANNEL(musicclass)=...).\n"
+-"If duration is given, hold music will be played specified number\n"
+-"of seconds. If duration is ommited, music plays indefinitely.\n"
+-"Returns 0 when done, -1 on hangup.\n";
+-
+-static char *wait_moh_desc = " WaitMusicOnHold(delay):\n"
+-"\n"
+-" !!! DEPRECATED. Use MusicOnHold instead !!!\n"
+-"\n"
+-"Plays hold music specified number of seconds. Returns 0 when\n"
+-"done, or -1 on hangup. If no hold music is available, the delay will\n"
+-"still occur with no sound.\n"
+-"\n"
+-" !!! DEPRECATED. Use MusicOnHold instead !!!\n";
+-
+-static char *set_moh_desc = " SetMusicOnHold(class):\n"
+-"\n"
+-" !!! DEPRECATED. USe Set(CHANNEL(musicclass)=...) instead !!!\n"
+-"\n"
+-"Sets the default class for music on hold for a given channel. When\n"
+-"music on hold is activated, this class will be used to select which\n"
+-"music is played.\n"
+-"\n"
+-" !!! DEPRECATED. USe Set(CHANNEL(musicclass)=...) instead !!!\n";
+-
+-static char *start_moh_desc = " StartMusicOnHold(class):\n"
+-"Starts playing music on hold, uses default music class for channel.\n"
+-"Starts playing music specified by class. If omitted, the default\n"
+-"music source for the channel will be used. Always returns 0.\n";
+-
+-static char *stop_moh_desc = " StopMusicOnHold(): "
+-"Stops playing music on hold.\n";
+-
+ static int respawn_time = 20;
+
+ struct moh_files_state {
+@@ -606,7 +635,7 @@
+ return NULL;
+ }
+
+-static int play_moh_exec(struct ast_channel *chan, void *data)
++static int play_moh_exec(struct ast_channel *chan, const char *data)
+ {
+ char *parse;
+ char *class;
+@@ -646,7 +675,7 @@
+ return res;
+ }
+
+-static int wait_moh_exec(struct ast_channel *chan, void *data)
++static int wait_moh_exec(struct ast_channel *chan, const char *data)
+ {
+ static int deprecation_warning = 0;
+ int res;
+@@ -669,7 +698,7 @@
+ return res;
+ }
+
+-static int set_moh_exec(struct ast_channel *chan, void *data)
++static int set_moh_exec(struct ast_channel *chan, const char *data)
+ {
+ static int deprecation_warning = 0;
+
+@@ -686,7 +715,7 @@
+ return 0;
+ }
+
+-static int start_moh_exec(struct ast_channel *chan, void *data)
++static int start_moh_exec(struct ast_channel *chan, const char *data)
+ {
+ char *parse;
+ char *class;
+@@ -705,7 +734,7 @@
+ return 0;
+ }
+
+-static int stop_moh_exec(struct ast_channel *chan, void *data)
++static int stop_moh_exec(struct ast_channel *chan, const char *data)
+ {
+ ast_moh_stop(chan);
+
+@@ -1395,9 +1424,10 @@
+ while ((member = AST_LIST_REMOVE_HEAD(&class->members, list))) {
+ free(member);
+ }
+-
++
+ if (class->thread) {
+ pthread_cancel(class->thread);
++ pthread_join(class->thread, NULL);
+ class->thread = AST_PTHREADT_NULL;
+ }
+
+@@ -1667,17 +1697,17 @@
+ local_ast_moh_cleanup);
+ }
+
+- res = ast_register_application(play_moh, play_moh_exec, play_moh_syn, play_moh_desc);
++ res = ast_register_application_xml(play_moh, play_moh_exec);
+ ast_register_atexit(ast_moh_destroy);
+ 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);
++ res = ast_register_application_xml(wait_moh, wait_moh_exec);
+ if (!res)
+- res = ast_register_application(set_moh, set_moh_exec, set_moh_syn, set_moh_desc);
++ res = ast_register_application_xml(set_moh, set_moh_exec);
+ if (!res)
+- res = ast_register_application(start_moh, start_moh_exec, start_moh_syn, start_moh_desc);
++ res = ast_register_application_xml(start_moh, start_moh_exec);
+ if (!res)
+- res = ast_register_application(stop_moh, stop_moh_exec, stop_moh_syn, stop_moh_desc);
++ res = ast_register_application_xml(stop_moh, stop_moh_exec);
+
+ return AST_MODULE_LOAD_SUCCESS;
+ }
+Index: sample.call
+===================================================================
+--- a/sample.call (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/sample.call (.../trunk) (revision 202568)
+@@ -6,7 +6,7 @@
+ # Comments are indicated by a '#' character that begins a line, or follows
+ # a space or tab character. To be consistent with the configuration files
+ # in Asterisk, comments can also be indicated by a semicolon. However, the
+-# multiline comments (;-- --;) used in Asterisk configuration files are not
++# multiline comments (;-- --;) used in Asterisk configuration files are not
+ # supported. Semicolons can be escaped by a backslash.
+ #
+
+@@ -76,8 +76,8 @@
+
+ #
+ # Setting Archive to yes the call file is never deleted, but is moved
+-# in the subdir "outgoing_done" of the spool directory. In this case
+-# will be appended a line with "Status: value", where value can be
++# in the subdir "outgoing_done" of the spool directory. In this case
++# will be appended a line with "Status: value", where value can be
+ # Completed, Expired or Failed.
+ #
+ #Archive: yes
+Index: contrib/init.d/rc.debian.asterisk
+===================================================================
+--- a/contrib/init.d/rc.debian.asterisk (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/contrib/init.d/rc.debian.asterisk (.../trunk) (revision 202568)
+@@ -73,7 +73,7 @@
+ fi
+ if [ $AST_GROUP ] ; then
+ ASTARGS="$ASTARGS -G $AST_GROUP"
+- chown $AST_GROUP $ASTVARRUNDIR
++ chgrp $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
+Index: contrib/scripts/asterisk.ldap-schema
+===================================================================
+--- a/contrib/scripts/asterisk.ldap-schema (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/contrib/scripts/asterisk.ldap-schema (.../trunk) (revision 202568)
+@@ -8,7 +8,7 @@
+ # https://issues.asterisk.org/view.php?id=15155
+ # - Added AstAccountLastQualifyMilliseconds - 28/05/2009
+ # https://issues.asterisk.org/view.php?id=15156
+-# - http://bugs.digium.com/view.php?id=12860 - 04/07/2008
++# - https://issues.asterisk.org/view.php?id=12860 - 04/07/2008
+ # - Fixed wrong DESC - 07/05/2008
+ #
+ # Author: Gavin Henry - <ghenry@suretecsystems.com>
+Index: contrib/scripts/asterisk.ldif
+===================================================================
+--- a/contrib/scripts/asterisk.ldif (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/contrib/scripts/asterisk.ldif (.../trunk) (revision 202568)
+@@ -8,7 +8,7 @@
+ # https://issues.asterisk.org/view.php?id=15155
+ # - Added AstAccountLastQualifyMilliseconds - 28/05/2009
+ # https://issues.asterisk.org/view.php?id=15156
+-# - http://bugs.digium.com/view.php?id=12860 - 04/07/2008
++# - https://issues.asterisk.org/view.php?id=12860 - 04/07/2008
+ # - Fixed wrong DESC - 07/05/2008
+ #
+ # Author: Gavin Henry - <ghenry@suretecsystems.com>
+Index: contrib/scripts/ast_grab_core
+===================================================================
+--- a/contrib/scripts/ast_grab_core (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/contrib/scripts/ast_grab_core (.../trunk) (revision 202568)
+@@ -67,4 +67,4 @@
+ echo Done.
+ echo
+ echo Reproducible deadlocks should be posted with a full backtrace and instructions
+-echo to reproduce the issue at http://bugs.digium.com/ Thanks!
++echo to reproduce the issue at https://issues.asterisk.org/ Thanks!
+Index: contrib/scripts/get_ilbc_source.sh
+===================================================================
+--- a/contrib/scripts/get_ilbc_source.sh (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/contrib/scripts/get_ilbc_source.sh (.../trunk) (revision 202568)
+@@ -22,7 +22,7 @@
+
+ wget -P codecs/ilbc http://www.ietf.org/rfc/rfc3951.txt
+
+-wget -q -O - http://www.ilbcfreeware.org/documentation/extract-cfile.awk | sed -e 's/\r//g' > codecs/ilbc/extract-cfile.awk
++wget -q -O - http://www.ilbcfreeware.org/documentation/extract-cfile.awk | tr -d '\r' > codecs/ilbc/extract-cfile.awk
+
+ (cd codecs/ilbc && awk -f extract-cfile.awk rfc3951.txt)
+
+Index: contrib/upstart/asterisk.upstart-0.3.9
+===================================================================
+--- a/contrib/upstart/asterisk.upstart-0.3.9 (.../tags/1.6.2.0-beta3) (revision 0)
++++ b/contrib/upstart/asterisk.upstart-0.3.9 (.../trunk) (revision 202568)
+@@ -0,0 +1,36 @@
++# asterisk
++#
++# Upstart control file for the Asterisk PBX
++#
++# To install, rename this file to 'asterisk' and copy it to /etc/event.d/
++#
++# To start asterisk manually:
++# sudo start asterisk
++#
++# To stop asterisk manually:
++# sudo stop asterisk
++
++description "Asterisk PBX"
++version "1.6.3"
++
++start on runlevel 2
++start on runlevel 3
++start on runlevel 4
++start on runlevel 5
++
++stop on runlevel 0
++stop on runlevel 1
++stop on runlevel 6
++
++pre-start script
++ # Since Ubuntu clears /var/run on reboot, create this before we try to start
++ mkdir -p /var/run/asterisk
++end script
++
++respawn
++exec /usr/sbin/asterisk -vvvvvvvg -cf
++
++post-stop script
++ # Might as well clean up after ourselves, too.
++ rm -rf /var/run/asterisk
++end script
+
+Property changes on: contrib/upstart/asterisk.upstart-0.3.9
+___________________________________________________________________
+Added: svn:mime-type
+ + text/plain
+Added: svn:keywords
+ + Author Date Id Revision
+Added: svn:eol-style
+ + native
+
+Index: contrib/asterisk-ng-doxygen
+===================================================================
+--- a/contrib/asterisk-ng-doxygen (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/contrib/asterisk-ng-doxygen (.../trunk) (revision 202568)
+@@ -475,6 +475,7 @@
+ funcs \
+ include \
+ include/asterisk \
++ include/asterisk/doxygen \
+ main \
+ main/stdtime \
+ pbx \
+Index: codecs/gsm/src/gsm_destroy.c
+===================================================================
+--- a/codecs/gsm/src/gsm_destroy.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/codecs/gsm/src/gsm_destroy.c (.../trunk) (revision 202568)
+@@ -22,5 +22,5 @@
+
+ void gsm_destroy P1((S), gsm S)
+ {
+- if (S) free((char *)S);
++ free((char *)S);
+ }
+Index: utils/ael_main.c
+===================================================================
+--- a/utils/ael_main.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/utils/ael_main.c (.../trunk) (revision 202568)
+@@ -299,8 +299,7 @@
+ }
+
+ /* since add_extension2 is responsible for the malloc'd data stuff */
+- if( data )
+- free(data);
++ free(data);
+ return 0;
+ }
+
+Index: utils/extconf.c
+===================================================================
+--- a/utils/extconf.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/utils/extconf.c (.../trunk) (revision 202568)
+@@ -2993,8 +2993,7 @@
+
+ static void ast_var_delete(struct ast_var_t *var)
+ {
+- if (var)
+- free(var);
++ free(var);
+ }
+
+
+@@ -3090,7 +3089,7 @@
+
+ }
+
+-static int pbx_builtin_setvar(struct ast_channel *chan, void *data)
++static int pbx_builtin_setvar(struct ast_channel *chan, const void *data)
+ {
+ char *name, *value, *mydata;
+ int argc;
+@@ -3125,9 +3124,9 @@
+ return(0);
+ }
+
+-int localized_pbx_builtin_setvar(struct ast_channel *chan, void *data);
++int localized_pbx_builtin_setvar(struct ast_channel *chan, const void *data);
+
+-int localized_pbx_builtin_setvar(struct ast_channel *chan, void *data)
++int localized_pbx_builtin_setvar(struct ast_channel *chan, const void *data)
+ {
+ return pbx_builtin_setvar(chan, data);
+ }
+Index: utils/muted.c
+===================================================================
+--- a/utils/muted.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/utils/muted.c (.../trunk) (revision 202568)
+@@ -684,6 +684,7 @@
+ fclose(astf);
+ exit(1);
+ }
++#if HAVE_WORKING_FORK
+ if (needfork) {
+ #ifndef HAVE_SBIN_LAUNCHD
+ if (daemon(0,0) < 0) {
+@@ -695,6 +696,7 @@
+ exit(1);
+ #endif
+ }
++#endif
+ for(;;) {
+ if (wait_event()) {
+ fclose(astf);
+Index: utils/conf2ael.c
+===================================================================
+--- a/utils/conf2ael.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/utils/conf2ael.c (.../trunk) (revision 202568)
+@@ -471,7 +471,7 @@
+ if (mon) {
+ *mon++ = 0;
+ /* now all 4 fields are set; what do we do? */
+- pvalIncludesAddIncludeWithTimeConstraints(incl, all, hr, dow, dom, mon);
++ pvalIncludesAddIncludeWithTimeConstraints(incl, strdup(all), strdup(hr), strdup(dow), strdup(dom), strdup(mon));
+ /* the original data is always best to keep (no 2-min rounding) */
+ } else {
+ ast_log(LOG_ERROR,"No month spec attached to include!\n");
+@@ -483,6 +483,7 @@
+ ast_log(LOG_ERROR,"No day of week spec attached to include!\n");
+ }
+ }
++ free(all);
+ }
+ tmpi = tmpi->next;
+ }
+@@ -568,7 +569,7 @@
+
+ /* ==================================== for linking internal stuff to external stuff */
+
+-int pbx_builtin_setvar(struct ast_channel *chan, void *data)
++int pbx_builtin_setvar(struct ast_channel *chan, const char *data)
+ {
+ return localized_pbx_builtin_setvar(chan, data);
+ }
+Index: utils/stereorize.c
+===================================================================
+--- a/utils/stereorize.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/utils/stereorize.c (.../trunk) (revision 202568)
+@@ -156,4 +156,7 @@
+ }
+ }
+ /* That was an endless loop. This point is never reached. */
++ free(leftsample);
++ free(rightsample);
++ free(stereosample);
+ }
+Index: Makefile.rules
+===================================================================
+--- a/Makefile.rules (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/Makefile.rules (.../trunk) (revision 202568)
+@@ -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_pgsql.c
+===================================================================
+--- a/cdr/cdr_pgsql.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/cdr/cdr_pgsql.c (.../trunk) (revision 202568)
+@@ -331,10 +331,9 @@
+ static int unload_module(void)
+ {
+ struct columns *current;
++
+ ast_cdr_unregister(name);
+
+- /* Give all threads time to finish */
+- usleep(1);
+ PQfinish(conn);
+
+ if (pghostname)
+Index: cdr/cdr_custom.c
+===================================================================
+--- a/cdr/cdr_custom.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/cdr/cdr_custom.c (.../trunk) (revision 202568)
+@@ -1,7 +1,7 @@
+ /*
+ * Asterisk -- An open source telephony toolkit.
+ *
+- * Copyright (C) 1999 - 2005, Digium, Inc.
++ * Copyright (C) 1999 - 2009, Digium, Inc.
+ *
+ * Mark Spencer <markster@digium.com>
+ *
+@@ -44,127 +44,171 @@
+ #include "asterisk/pbx.h"
+ #include "asterisk/utils.h"
+ #include "asterisk/lock.h"
++#include "asterisk/threadstorage.h"
++#include "asterisk/strings.h"
+
+ #define CUSTOM_LOG_DIR "/cdr_custom"
++#define CONFIG "cdr_custom.conf"
+
+-#define DATE_FORMAT "%Y-%m-%d %T"
++AST_THREADSTORAGE(custom_buf);
+
+-AST_MUTEX_DEFINE_STATIC(lock);
+-AST_MUTEX_DEFINE_STATIC(mf_lock);
++static const char name[] = "cdr-custom";
+
+-static char *name = "cdr-custom";
++struct cdr_config {
++ AST_DECLARE_STRING_FIELDS(
++ AST_STRING_FIELD(filename);
++ AST_STRING_FIELD(format);
++ );
++ ast_mutex_t lock;
++ AST_RWLIST_ENTRY(cdr_config) list;
++};
+
+-static char master[PATH_MAX];
+-static char format[1024]="";
++static AST_RWLIST_HEAD_STATIC(sinks, cdr_config);
+
+-static int load_config(int reload)
++static void free_config(void)
+ {
++ struct cdr_config *sink;
++ while ((sink = AST_RWLIST_REMOVE_HEAD(&sinks, list))) {
++ ast_mutex_destroy(&sink->lock);
++ ast_free(sink);
++ }
++}
++
++static int load_config(void)
++{
+ struct ast_config *cfg;
+ struct ast_variable *var;
+- struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
+- int res = -1;
++ struct ast_flags config_flags = { 0 };
++ int res = 0;
+
+- 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;
++ cfg = ast_config_load(CONFIG, config_flags);
++ if (!cfg || cfg == CONFIG_STATUS_FILEINVALID) {
++ ast_log(LOG_ERROR, "Unable to load " CONFIG ". Not logging custom CSV CDRs.\n");
++ return -1;
+ }
+
+- strcpy(format, "");
+- strcpy(master, "");
+- ast_mutex_lock(&lock);
+- if (cfg) {
+- var = ast_variable_browse(cfg, "mappings");
+- while(var) {
+- if (!ast_strlen_zero(var->name) && !ast_strlen_zero(var->value)) {
+- if (strlen(var->value) > (sizeof(format) - 1))
+- ast_log(LOG_WARNING, "Format string too long, will be truncated, at line %d\n", var->lineno);
+- ast_copy_string(format, var->value, sizeof(format) - 1);
+- strcat(format,"\n");
+- snprintf(master, sizeof(master),"%s/%s/%s", ast_config_AST_LOG_DIR, name, var->name);
+- if (var->next) {
+- ast_log(LOG_NOTICE, "Sorry, only one mapping is supported at this time, mapping '%s' will be ignored at line %d.\n", var->next->name, var->next->lineno);
+- break;
+- }
+- } else
+- ast_log(LOG_NOTICE, "Mapping must have both filename and format at line %d\n", var->lineno);
+- var = var->next;
++ var = ast_variable_browse(cfg, "mappings");
++ while (var) {
++ if (!ast_strlen_zero(var->name) && !ast_strlen_zero(var->value)) {
++ struct cdr_config *sink = ast_calloc_with_stringfields(1, struct cdr_config, 1024);
++
++ if (!sink) {
++ ast_log(LOG_ERROR, "Unable to allocate memory for configuration settings.\n");
++ res = -2;
++ break;
++ }
++
++ ast_string_field_build(sink, format, "%s\n", var->value);
++ ast_string_field_build(sink, filename, "%s/%s/%s", ast_config_AST_LOG_DIR, name, var->name);
++ ast_mutex_init(&sink->lock);
++
++ AST_RWLIST_INSERT_TAIL(&sinks, sink, list);
++ } else {
++ ast_log(LOG_NOTICE, "Mapping must have both a filename and a format at line %d\n", var->lineno);
+ }
+- ast_config_destroy(cfg);
+- res = 0;
+- } else {
+- 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");
++ var = var->next;
+ }
+- ast_mutex_unlock(&lock);
++ ast_config_destroy(cfg);
+
+ return res;
+ }
+
+-
+-
+ static int custom_log(struct ast_cdr *cdr)
+ {
+- FILE *mf = NULL;
++ struct ast_channel *dummy;
++ struct ast_str *str;
++ struct cdr_config *config;
+
+- /* Make sure we have a big enough buf */
+- char buf[2048];
+- struct ast_channel dummy;
++ /* Batching saves memory management here. Otherwise, it's the same as doing an allocation and free each time. */
++ if (!(str = ast_str_thread_get(&custom_buf, 16))) {
++ return -1;
++ }
+
+- /* Abort if no master file is specified */
+- if (ast_strlen_zero(master))
+- return 0;
++ dummy = ast_channel_alloc(0, 0, "", "", "", "", "", 0, "Substitution/%p", cdr);
+
+- /* Quite possibly the first use of a static struct ast_channel, we need it so the var funcs will work */
+- memset(&dummy, 0, sizeof(dummy));
+- dummy.cdr = cdr;
+- pbx_substitute_variables_helper(&dummy, format, buf, sizeof(buf) - 1);
++ if (!dummy) {
++ ast_log(LOG_ERROR, "Unable to allocate channel for variable subsitution.\n");
++ return -1;
++ }
+
+- /* because of the absolutely unconditional need for the
+- highest reliability possible in writing billing records,
+- we open write and close the log file each time */
+- ast_mutex_lock(&mf_lock);
+- mf = fopen(master, "a");
+- if (mf) {
+- fputs(buf, mf);
+- fflush(mf); /* be particularly anal here */
+- fclose(mf);
+- mf = NULL;
+- ast_mutex_unlock(&mf_lock);
+- } else {
+- ast_log(LOG_ERROR, "Unable to re-open master file %s : %s\n", master, strerror(errno));
+- ast_mutex_unlock(&mf_lock);
++ /* We need to dup here since the cdr actually belongs to the other channel,
++ so when we release this channel we don't want the CDR getting cleaned
++ up prematurely. */
++ dummy->cdr = ast_cdr_dup(cdr);
++
++ AST_RWLIST_RDLOCK(&sinks);
++
++ AST_LIST_TRAVERSE(&sinks, config, list) {
++ FILE *out;
++
++ ast_str_substitute_variables(&str, 0, dummy, config->format);
++
++ /* Even though we have a lock on the list, we could be being chased by
++ another thread and this lock ensures that we won't step on anyone's
++ toes. Once each CDR backend gets it's own thread, this lock can be
++ removed. */
++ ast_mutex_lock(&config->lock);
++
++ /* Because of the absolutely unconditional need for the
++ highest reliability possible in writing billing records,
++ we open write and close the log file each time */
++ if ((out = fopen(config->filename, "a"))) {
++ fputs(ast_str_buffer(str), out);
++ fflush(out); /* be particularly anal here */
++ fclose(out);
++ } else {
++ ast_log(LOG_ERROR, "Unable to re-open master file %s : %s\n", config->filename, strerror(errno));
++ }
++
++ ast_mutex_unlock(&config->lock);
+ }
+
++ AST_RWLIST_UNLOCK(&sinks);
++
++ ast_channel_release(dummy);
++
+ return 0;
+ }
+
+ static int unload_module(void)
+ {
+ ast_cdr_unregister(name);
++
++ if (AST_RWLIST_WRLOCK(&sinks)) {
++ ast_cdr_register(name, ast_module_info->description, custom_log);
++ ast_log(LOG_ERROR, "Unable to lock sink list. Unload failed.\n");
++ return -1;
++ }
++
++ free_config();
++ AST_RWLIST_UNLOCK(&sinks);
+ return 0;
+ }
+
+-static int load_module(void)
++static enum ast_module_load_result load_module(void)
+ {
+- int res = 0;
++ if (AST_RWLIST_WRLOCK(&sinks)) {
++ ast_log(LOG_ERROR, "Unable to lock sink list. Load failed.\n");
++ return AST_MODULE_LOAD_FAILURE;
++ }
+
+- if (!load_config(0)) {
+- res = ast_cdr_register(name, ast_module_info->description, custom_log);
+- if (res)
+- ast_log(LOG_ERROR, "Unable to register custom CDR handling\n");
+- return res;
+- } else
+- return AST_MODULE_LOAD_DECLINE;
++ load_config();
++ AST_RWLIST_UNLOCK(&sinks);
++ ast_cdr_register(name, ast_module_info->description, custom_log);
++ return AST_MODULE_LOAD_SUCCESS;
+ }
+
+ static int reload(void)
+ {
+- return load_config(1);
++ if (AST_RWLIST_WRLOCK(&sinks)) {
++ ast_log(LOG_ERROR, "Unable to lock sink list. Load failed.\n");
++ return AST_MODULE_LOAD_FAILURE;
++ }
++
++ free_config();
++ load_config();
++ AST_RWLIST_UNLOCK(&sinks);
++ return AST_MODULE_LOAD_SUCCESS;
+ }
+
+ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Customizable Comma Separated Values CDR Backend",
+Index: cdr/cdr_manager.c
+===================================================================
+--- a/cdr/cdr_manager.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/cdr/cdr_manager.c (.../trunk) (revision 202568)
+@@ -46,8 +46,10 @@
+ static char *name = "cdr_manager";
+
+ static int enablecdr = 0;
+-struct ast_str *customfields;
+
++static struct ast_str *customfields;
++AST_RWLOCK_DEFINE_STATIC(customfields_lock);
++
+ static int manager_log(struct ast_cdr *cdr);
+
+ static int load_config(int reload)
+@@ -59,28 +61,33 @@
+ int newenablecdr = 0;
+
+ cfg = ast_config_load(CONF_FILE, config_flags);
+- if (cfg == CONFIG_STATUS_FILEUNCHANGED)
++ 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;
++ return -1;
+ }
+
+- if (reload && customfields) {
+- ast_free(customfields);
+- }
+- customfields = NULL;
+-
+ if (!cfg) {
+ /* Standard configuration */
+ ast_log(LOG_WARNING, "Failed to load configuration file. Module not activated.\n");
+ if (enablecdr)
+ ast_cdr_unregister(name);
+ enablecdr = 0;
+- return 0;
++ return -1;
+ }
+
++ if (reload) {
++ ast_rwlock_wrlock(&customfields_lock);
++ }
++
++ if (reload && customfields) {
++ ast_free(customfields);
++ customfields = NULL;
++ }
++
+ while ( (cat = ast_category_browse(cfg, cat)) ) {
+ if (!strcasecmp(cat, "general")) {
+ v = ast_variable_browse(cfg, cat);
+@@ -109,6 +116,10 @@
+ }
+ }
+
++ if (reload) {
++ ast_rwlock_unlock(&customfields_lock);
++ }
++
+ ast_config_destroy(cfg);
+
+ if (enablecdr && !newenablecdr)
+@@ -117,7 +128,7 @@
+ ast_cdr_register(name, "Asterisk Manager Interface CDR Backend", manager_log);
+ enablecdr = newenablecdr;
+
+- return 1;
++ return 0;
+ }
+
+ static int manager_log(struct ast_cdr *cdr)
+@@ -127,7 +138,6 @@
+ char strAnswerTime[80] = "";
+ char strEndTime[80] = "";
+ char buf[CUSTOM_FIELDS_BUF_SIZE];
+- struct ast_channel dummy;
+
+ if (!enablecdr)
+ return 0;
+@@ -143,13 +153,19 @@
+ ast_localtime(&cdr->end, &timeresult, NULL);
+ ast_strftime(strEndTime, sizeof(strEndTime), DATE_FORMAT, &timeresult);
+
+- buf[0] = 0;
+- /* Custom fields handling */
+- if (customfields != NULL && ast_str_strlen(customfields)) {
+- memset(&dummy, 0, sizeof(dummy));
+- dummy.cdr = cdr;
+- pbx_substitute_variables_helper(&dummy, ast_str_buffer(customfields), buf, sizeof(buf) - 1);
++ buf[0] = '\0';
++ ast_rwlock_rdlock(&customfields_lock);
++ if (customfields && ast_str_strlen(customfields)) {
++ struct ast_channel *dummy = ast_channel_alloc(0, 0, "", "", "", "", "", 0, "Substitution/%p", cdr);
++ if (!dummy) {
++ ast_log(LOG_ERROR, "Unable to allocate channel for variable substitution.\n");
++ return 0;
++ }
++ dummy->cdr = ast_cdr_dup(cdr);
++ pbx_substitute_variables_helper(dummy, ast_str_buffer(customfields), buf, sizeof(buf) - 1);
++ ast_channel_release(dummy);
+ }
++ ast_rwlock_unlock(&customfields_lock);
+
+ manager_event(EVENT_FLAG_CDR, "Cdr",
+ "AccountCode: %s\r\n"
+@@ -190,9 +206,9 @@
+
+ static int load_module(void)
+ {
+- /* Configuration file */
+- if (!load_config(0))
++ if (load_config(0)) {
+ return AST_MODULE_LOAD_DECLINE;
++ }
+
+ return AST_MODULE_LOAD_SUCCESS;
+ }
+Index: cdr/cdr_sqlite3_custom.c
+===================================================================
+--- a/cdr/cdr_sqlite3_custom.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/cdr/cdr_sqlite3_custom.c (.../trunk) (revision 202568)
+@@ -56,8 +56,8 @@
+
+ static const char config_file[] = "cdr_sqlite3_custom.conf";
+
+-static char *desc = "Customizable SQLite3 CDR Backend";
+-static char *name = "cdr_sqlite3_custom";
++static const char desc[] = "Customizable SQLite3 CDR Backend";
++static const char name[] = "cdr_sqlite3_custom";
+ static sqlite3 *db = NULL;
+
+ static char table[80];
+@@ -70,7 +70,7 @@
+
+ static AST_LIST_HEAD_STATIC(sql_values, values);
+
+-static int free_config(void);
++static void free_config(void);
+
+ static int load_column_config(const char *tmp)
+ {
+@@ -166,11 +166,8 @@
+ free_config();
+ }
+
+- ast_mutex_lock(&lock);
+-
+ if (!(mappingvar = ast_variable_browse(cfg, "master"))) {
+ /* Nothing configured */
+- ast_mutex_unlock(&lock);
+ ast_config_destroy(cfg);
+ return -1;
+ }
+@@ -185,7 +182,6 @@
+
+ /* Columns */
+ if (load_column_config(ast_variable_retrieve(cfg, "master", "columns"))) {
+- ast_mutex_unlock(&lock);
+ ast_config_destroy(cfg);
+ free_config();
+ return -1;
+@@ -193,7 +189,6 @@
+
+ /* Values */
+ if (load_values_config(ast_variable_retrieve(cfg, "master", "values"))) {
+- ast_mutex_unlock(&lock);
+ ast_config_destroy(cfg);
+ free_config();
+ return -1;
+@@ -201,18 +196,15 @@
+
+ ast_verb(3, "cdr_sqlite3_custom: Logging CDR records to table '%s' in 'master.db'\n", table);
+
+- ast_mutex_unlock(&lock);
+ ast_config_destroy(cfg);
+
+ return 0;
+ }
+
+-static int free_config(void)
++static void free_config(void)
+ {
+ struct values *value;
+
+- ast_mutex_lock(&lock);
+-
+ if (db) {
+ sqlite3_close(db);
+ db = NULL;
+@@ -226,10 +218,6 @@
+ while ((value = AST_LIST_REMOVE_HEAD(&sql_values, list))) {
+ ast_free(value);
+ }
+-
+- ast_mutex_unlock(&lock);
+-
+- return 0;
+ }
+
+ static int sqlite3_log(struct ast_cdr *cdr)
+@@ -237,7 +225,6 @@
+ int res = 0;
+ char *error = NULL;
+ char *sql = NULL;
+- struct ast_channel dummy = { 0, };
+ int count = 0;
+
+ if (db == NULL) {
+@@ -245,25 +232,35 @@
+ return 0;
+ }
+
++ ast_mutex_lock(&lock);
++
+ { /* Make it obvious that only sql should be used outside of this block */
+ char *escaped;
+ char subst_buf[2048];
+ struct values *value;
++ struct ast_channel *dummy;
+ struct ast_str *value_string = ast_str_create(1024);
+- dummy.cdr = cdr;
++
++ dummy = ast_channel_alloc(0, 0, "", "", "", "", "", 0, "Substitution/%p", cdr);
++ if (!dummy) {
++ ast_log(LOG_ERROR, "Unable to allocate channel for variable subsitution.\n");
++ ast_free(value_string);
++ ast_mutex_unlock(&lock);
++ return 0;
++ }
++ dummy->cdr = ast_cdr_dup(cdr);
+ AST_LIST_TRAVERSE(&sql_values, value, list) {
+- pbx_substitute_variables_helper(&dummy, value->expression, subst_buf, sizeof(subst_buf) - 1);
++ pbx_substitute_variables_helper(dummy, value->expression, subst_buf, sizeof(subst_buf) - 1);
+ escaped = sqlite3_mprintf("%q", subst_buf);
+ 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, ast_str_buffer(value_string));
+ ast_debug(1, "About to log: %s\n", sql);
++ ast_channel_release(dummy);
+ ast_free(value_string);
+ }
+
+- ast_mutex_lock(&lock);
+-
+ /* XXX This seems awful arbitrary... */
+ for (count = 0; count < 5; count++) {
+ res = sqlite3_exec(db, sql, NULL, NULL, &error);
+@@ -289,10 +286,10 @@
+
+ static int unload_module(void)
+ {
++ ast_cdr_unregister(name);
++
+ free_config();
+
+- ast_cdr_unregister(name);
+-
+ return 0;
+ }
+
+@@ -303,14 +300,7 @@
+ int res;
+ char *sql;
+
+- if (!load_config(0)) {
+- res = ast_cdr_register(name, desc, sqlite3_log);
+- if (res) {
+- ast_log(LOG_ERROR, "Unable to register custom SQLite3 CDR handling\n");
+- free_config();
+- return AST_MODULE_LOAD_DECLINE;
+- }
+- } else {
++ if (load_config(0)) {
+ return AST_MODULE_LOAD_DECLINE;
+ }
+
+@@ -340,12 +330,25 @@
+ }
+ }
+
+- return 0;
++ res = ast_cdr_register(name, desc, sqlite3_log);
++ if (res) {
++ ast_log(LOG_ERROR, "Unable to register custom SQLite3 CDR handling\n");
++ free_config();
++ return AST_MODULE_LOAD_DECLINE;
++ }
++
++ return AST_MODULE_LOAD_SUCCESS;
+ }
+
+ static int reload(void)
+ {
+- return load_config(1);
++ int res = 0;
++
++ ast_mutex_lock(&lock);
++ res = load_config(1);
++ ast_mutex_unlock(&lock);
++
++ return res;
+ }
+
+ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "SQLite3 Custom CDR Module",
+Index: cdr/cdr_sqlite.c
+===================================================================
+--- a/cdr/cdr_sqlite.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/cdr/cdr_sqlite.c (.../trunk) (revision 202568)
+@@ -61,7 +61,7 @@
+ AST_MUTEX_DEFINE_STATIC(sqlite_lock);
+
+ /*! \brief SQL table format */
+-static char sql_create_table[] = "CREATE TABLE cdr ("
++static const char sql_create_table[] = "CREATE TABLE cdr ("
+ " AcctId INTEGER PRIMARY KEY,"
+ " clid VARCHAR(80),"
+ " src VARCHAR(80),"
+Index: cdr/cdr_adaptive_odbc.c
+===================================================================
+--- a/cdr/cdr_adaptive_odbc.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/cdr/cdr_adaptive_odbc.c (.../trunk) (revision 202568)
+@@ -282,7 +282,6 @@
+ static SQLHSTMT generic_prepare(struct odbc_obj *obj, void *data)
+ {
+ int res, i;
+- char *sql = data;
+ SQLHSTMT stmt;
+ SQLINTEGER nativeerror = 0, numfields = 0;
+ SQLSMALLINT diagbytes = 0;
+@@ -294,9 +293,9 @@
+ return NULL;
+ }
+
+- res = SQLPrepare(stmt, (unsigned char *)sql, SQL_NTS);
++ res = SQLPrepare(stmt, (unsigned char *) data, SQL_NTS);
+ if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
+- ast_log(LOG_WARNING, "SQL Prepare failed![%s]\n", sql);
++ ast_log(LOG_WARNING, "SQL Prepare failed![%s]\n", (char *) data);
+ 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);
+@@ -664,7 +663,6 @@
+ static int unload_module(void)
+ {
+ ast_cdr_unregister(name);
+- usleep(1);
+ if (AST_RWLIST_WRLOCK(&odbc_tables)) {
+ ast_cdr_register(name, ast_module_info->description, odbc_log);
+ ast_log(LOG_ERROR, "Unable to lock column list. Unload failed.\n");
+Index: formats/format_gsm.c
+===================================================================
+--- a/formats/format_gsm.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/formats/format_gsm.c (.../trunk) (revision 202568)
+@@ -42,7 +42,7 @@
+
+ /* silent gsm frame */
+ /* begin binary data: */
+-char gsm_silence[] = /* 33 */
++static const char gsm_silence[] = /* 33 */
+ {0xD8,0x20,0xA2,0xE1,0x5A,0x50,0x00,0x49,0x24,0x92,0x49,0x24,0x50,0x00,0x49
+ ,0x24,0x92,0x49,0x24,0x50,0x00,0x49,0x24,0x92,0x49,0x24,0x50,0x00,0x49,0x24
+ ,0x92,0x49,0x24};
+Index: formats/format_wav_gsm.c
+===================================================================
+--- a/formats/format_wav_gsm.c (.../tags/1.6.2.0-beta3) (revision 202568)
++++ b/formats/format_wav_gsm.c (.../trunk) (revision 202568)
+@@ -48,7 +48,7 @@
+ #define MSGSM_SAMPLES (2*GSM_SAMPLES) /* samples in an MSGSM block */
+
+ /* begin binary data: */
+-char msgsm_silence[] = /* 65 */
++static char msgsm_silence[] = /* 65 */
+ {0x48,0x17,0xD6,0x84,0x02,0x80,0x24,0x49,0x92,0x24,0x89,0x02,0x80,0x24,0x49
+ ,0x92,0x24,0x89,0x02,0x80,0x24,0x49,0x92,0x24,0x89,0x02,0x80,0x24,0x49,0x92
+ ,0x24,0x09,0x82,0x74,0x61,0x4D,0x28,0x00,0x48,0x92,0x24,0x49,0x92,0x28,0x00
+
+Property changes on: .
+___________________________________________________________________
+Deleted: trunk-blocked
+ - /trunk:182362,182521,182762,182960,183124,183148,183196,183239,183553-183555,184986,185299,185532,185581,185704,185741,185777,186078,186382,186525,186563,186566,186620,186624,186653,186687,186953,186957,187105,187138,187179,187211,187269,187491,187560,187634-187636,187680,187714,187830,188342,188378,188515,188544,188705,188901,188942,190217,190349,190421,190423,190457,190484,190577,190586,190626,190989,190991,191028,191116,191140,191177,191211,191213,191411,191630,191739,191781,191785,191848,191919,191997,192362,192772,192853,193459,193678,193832,193886,194477,194610,195165,195210,195279,195365,195589,195763,195798,195949,195992,196072,196114,196227,196268,196270,196272,196308,196344,196381,196417,196488,196520,196622,196725,196758,196893,196907,197189,197338,197528,197535,197570,197701,197738,197740,197775,197824,197861,197959,197996,198088,198139,198217,198434,198438,198442,198498,198500,198529-198530,198561,198565,198597,198661,198670,198725,198727,198762,198954,198958,199091,199370,199372,199374,199376,199409,199411,199413,199446,199479,199514,199547,199781,199923,200000
+Deleted: trunk-merged
+ - /trunk:1-182359,182408,182450,182525,182530,182553,182722,182847,183028,183057,183108,183117,183242,183244,183321,183511,183560,183652,183701,183766,183865,183914,184037,184043,184079,184147,184151,184219-184220,184280,184339,184344,184448,184512,184515,184531,184566,184628,184630,184639,184673,184677,184693,184726,184762,184838,184843,184910,184948,185072,185122-185123,185197,185261,185363,185469,185600,185604,185664,185772,185912,185953,186021,186060,186101,186175,186230,186286,186297,186321,186444-186447,186461,186720,186799,186833,186837,186842,186899,186928,186985,187046,187050,187302,187363,187381,187421-187424,187483,187488,187599,187674-187675,187721,187764,187906,188032,188067,188102,188206,188210,188247,188413,188470,188585,188647,188774,188836,188938,188947,189010,189077,189097,189137,189204,189278,189350,189464,189495-189516,189539,189771,189813,189911,189951,189993,190057,190093,190250,190287,190352,190371,190622,190663,190725-190726,190830,190861,190865,190904,190946,190993,191136,191219-191220,191283,191367,191489,191494,191560,191700,191775,191884,191955,192032,192059,192096,192132,192171,192214,192279,192318,192357,192387,192430,192462,192525,192634,192700,192736,192808,192861,192933,192938,193006,193077,193120,193194,193263,193274,193349,193387,193461,193502,193545,193614,193718,193756,193870,193954,193956,194057,194138,194209,194357,194430,194434,194496,194520,194635,194649,194714,194718,194722,194765,194833,194874,194945,194982,195021,195075,195089,195096,195162,195207,195316,195320,195369-195370,195449,195521,195636,195698,195839,195882,195995,196117,196377,196416,196456,196658,196721,196792,196843,196945-196946,196948,196988,197089,197209,197260,197335,197374,197467,197538,197543,197606,197621,197697,197828,197960,198000,198064,198072,198083,198146,198183,198186,198248,198285,198312,198371,198375,198437,198470,198626,198729,198791,198824,198856,199051,199139,199227,199298,199368,199588,199630,199743,199818,199857,199957-199958,200039
+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,186565,187135,187865,187962,188149,189537,189991,190187,191041,191096,191422,191628-191629,191778,193880,194356,197024,197124,197264,198665,198891,198957,200037,200185,202022
+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,186719,186775,186832,186841,186984,187045,187209,187300-187301,187362,187428,187482,187484,187763,188582,188646,188773,188833-189134,189203,189277,189391,189462-189463,189465,189601,189664,189849,190286,190356,190661-190662,190721,191220,191488,191559,192213,192429,192454,192524,192633,192858,192932,193050,193119,193193,193262,193544,193613,193755,193955,194028,194137,194208,194484,194509,194557-194685,194764,194873,195020,195095,195206,195366,195448,195520,195635,195688,195881,195991,196116,196657,196826,197194,197466,197537,197562,197588,197998,198068,198251,198311,198370,199022,199138,199297,199626-199628,199856,200360,200513,200875,200991,201261,201380,201423,201450,201600,201828,201993,202336,202341-202342,202414,202496
+Modified: svn:externals
+ - menuselect http://svn.digium.com/svn/menuselect/tags/autotag_for_asterisk/1.6.2.0-beta3
+
+ + menuselect http://svn.digium.com/svn/menuselect/trunk
+
+
diff --git a/testing/asterisk/asterisk-07-issue14068.patch b/testing/asterisk/asterisk-07-issue14068.patch
index 49cad168..dd57aa69 100644
--- a/testing/asterisk/asterisk-07-issue14068.patch
+++ b/testing/asterisk/asterisk-07-issue14068.patch
@@ -668,756 +668,3 @@ Index: CHANGES
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
-