diff --git a/Makefile b/Makefile
index f5f0205e5a854345234afff0856bbe95663961df..0b381dbdbd40763477b0a1d59f89963f1f53bc66 100644
--- a/Makefile
+++ b/Makefile
@@ -641,7 +641,7 @@ uninstall-all: _uninstall
 	rm -rf $(DESTDIR)$(ASTLOGDIR)
 
 menuselect: menuselect/menuselect menuselect-tree
-	-@menuselect/menuselect $(GLOBAL_MAKEOPTS) $(USER_MAKEOPTS) menuselect.makeopts && echo "menuselect changes saved!" || echo "menuselect changes NOT saved!"
+	-@menuselect/menuselect $(GLOBAL_MAKEOPTS) $(USER_MAKEOPTS) menuselect.makeopts && (echo "menuselect changes saved!"; rm -f channels/h323/Makefile.ast main/asterisk) || echo "menuselect changes NOT saved!"
 
 menuselect/menuselect: makeopts menuselect/menuselect.c menuselect/menuselect_curses.c menuselect/menuselect_stub.c menuselect/menuselect.h menuselect/linkedlists.h makeopts
 	@unset CC LD AR RANLIB && $(MAKE) -C menuselect CONFIGURE_SILENT="--silent"
diff --git a/acinclude.m4 b/acinclude.m4
index 71ae301849427529d2f6ab76ddf886451ae48047..7029161484949761a78f7d4c4cf92ec50d76e675 100644
--- a/acinclude.m4
+++ b/acinclude.m4
@@ -116,6 +116,320 @@ fi
 AC_SUBST([GNU_MAKE])
 ])
 
+
+AC_DEFUN(
+[AST_CHECK_PWLIB], [
+PWLIB_INCDIR=
+PWLIB_LIBDIR=
+if test "${PWLIBDIR:-unset}" != "unset" ; then
+  AC_CHECK_FILE(${PWLIBDIR}/version.h, HAS_PWLIB=1, )
+fi
+if test "${HAS_PWLIB:-unset}" = "unset" ; then
+  if test "${OPENH323DIR:-unset}" != "unset"; then
+    AC_CHECK_FILE(${OPENH323DIR}/../pwlib/version.h, HAS_PWLIB=1, )
+  fi
+  if test "${HAS_PWLIB:-unset}" != "unset" ; then
+    PWLIBDIR="${OPENH323DIR}/../pwlib"
+  else
+    AC_CHECK_FILE(${HOME}/pwlib/include/ptlib.h, HAS_PWLIB=1, )
+    if test "${HAS_PWLIB:-unset}" != "unset" ; then
+      PWLIBDIR="${HOME}/pwlib"
+    else
+      AC_CHECK_FILE(/usr/local/include/ptlib.h, HAS_PWLIB=1, )
+      if test "${HAS_PWLIB:-unset}" != "unset" ; then
+        AC_PATH_PROG(PTLIB_CONFIG, ptlib-config, , /usr/local/bin)
+        if test "${PTLIB_CONFIG:-unset}" = "unset" ; then
+          AC_PATH_PROG(PTLIB_CONFIG, ptlib-config, , /usr/local/share/pwlib/make)
+        fi
+        PWLIB_INCDIR="/usr/local/include"
+        PWLIB_LIBDIR="/usr/local/lib"
+      else
+        AC_CHECK_FILE(/usr/include/ptlib.h, HAS_PWLIB=1, )
+        if test "${HAS_PWLIB:-unset}" != "unset" ; then
+          AC_PATH_PROG(PTLIB_CONFIG, ptlib-config, , /usr/share/pwlib/make)
+          PWLIB_INCDIR="/usr/include"
+          PWLIB_LIBDIR="/usr/lib"
+        fi
+      fi
+    fi
+  fi
+fi
+
+#if test "${HAS_PWLIB:-unset}" = "unset" ; then
+#  echo "Cannot find pwlib - please install or set PWLIBDIR and try again"
+#  exit
+#fi
+
+if test "${HAS_PWLIB:-unset}" != "unset" ; then
+  if test "${PWLIBDIR:-unset}" = "unset" ; then
+    if test "${PTLIB_CONFIG:-unset}" != "unset" ; then
+      PWLIBDIR=`$PTLIB_CONFIG --prefix`
+    else
+      echo "Cannot find ptlib-config - please install and try again"
+      exit
+    fi
+  fi
+
+  if test "x$PWLIBDIR" = "x/usr" -o "x$PWLIBDIR" = "x/usr/"; then
+    PWLIBDIR="/usr/share/pwlib"
+    PWLIB_INCDIR="/usr/include"
+    PWLIB_LIBDIR="/usr/lib"
+  fi
+  if test "x$PWLIBDIR" = "x/usr/local" -o "x$PWLIBDIR" = "x/usr/"; then
+    PWLIBDIR="/usr/local/share/pwlib"
+    PWLIB_INCDIR="/usr/local/include"
+    PWLIB_LIBDIR="/usr/local/lib"
+  fi
+
+  if test "${PWLIB_INCDIR:-unset}" = "unset"; then
+    PWLIB_INCDIR="${PWLIBDIR}/include"
+  fi
+  if test "${PWLIB_LIBDIR:-unset}" = "unset"; then
+    PWLIB_LIBDIR="${PWLIBDIR}/lib"
+  fi
+
+  AC_SUBST([PWLIBDIR])
+  AC_SUBST([PWLIB_INCDIR])
+  AC_SUBST([PWLIB_LIBDIR])
+fi
+])
+
+
+AC_DEFUN(
+[AST_CHECK_OPENH323_PLATFORM], [
+PWLIB_OSTYPE=
+case "$host_os" in
+  linux*)          PWLIB_OSTYPE=linux ;
+  		;;
+  freebsd* )       PWLIB_OSTYPE=FreeBSD ;
+  		;;
+  openbsd* )       PWLIB_OSTYPE=OpenBSD ;
+				   ENDLDLIBS="-lossaudio" ;
+		;;
+  netbsd* )        PWLIB_OSTYPE=NetBSD ;
+				   ENDLDLIBS="-lossaudio" ;
+		;;
+  solaris* | sunos* ) PWLIB_OSTYPE=solaris ;
+		;;
+  darwin* )	       PWLIB_OSTYPE=Darwin ;
+		;;
+  beos*)           PWLIB_OSTYPE=beos ;
+                   STDCCFLAGS="$STDCCFLAGS -D__BEOS__"
+		;;
+  cygwin*)         PWLIB_OSTYPE=cygwin ;
+		;;
+  mingw*)	       PWLIB_OSTYPE=mingw ;
+		           STDCCFLAGS="$STDCCFLAGS -mms-bitfields" ;
+		           ENDLDLIBS="-lwinmm -lwsock32 -lsnmpapi -lmpr -lcomdlg32 -lgdi32 -lavicap32" ;
+		;;
+  * )		       PWLIB_OSTYPE="$host_os" ;
+		           AC_MSG_WARN("OS $PWLIB_OSTYPE not recognized - proceed with caution!") ;
+		;;
+esac
+
+PWLIB_MACHTYPE=
+case "$host_cpu" in
+   x86 | i686 | i586 | i486 | i386 ) PWLIB_MACHTYPE=x86
+                   ;;
+
+   x86_64)	   PWLIB_MACHTYPE=x86_64 ;
+		   P_64BIT=1 ;
+                   LIB64=1 ;
+		   ;;
+
+   alpha | alphaev56 | alphaev6 | alphaev67 | alphaev7) PWLIB_MACHTYPE=alpha ;
+		   P_64BIT=1 ;
+		   ;;
+
+   sparc )         PWLIB_MACHTYPE=sparc ;
+		   ;;
+
+   powerpc )       PWLIB_MACHTYPE=ppc ;
+		   ;;
+
+   ppc )           PWLIB_MACHTYPE=ppc ;
+		   ;;
+
+   powerpc64 )     PWLIB_MACHTYPE=ppc64 ;
+		   P_64BIT=1 ;
+                   LIB64=1 ;
+		   ;;
+
+   ppc64 )         PWLIB_MACHTYPE=ppc64 ;
+		   P_64BIT=1 ;
+                   LIB64=1 ;
+		   ;;
+
+   ia64)	   PWLIB_MACHTYPE=ia64 ;
+		   P_64BIT=1 ;
+	  	   ;;
+
+   s390x)	   PWLIB_MACHTYPE=s390x ;
+		   P_64BIT=1 ;
+                   LIB64=1 ;
+		   ;;
+
+   s390)	   PWLIB_MACHTYPE=s390 ;
+		   ;;
+
+   * )		   PWLIB_MACHTYPE="$host_cpu";
+		   AC_MSG_WARN("CPU $PWLIB_MACHTYPE not recognized - proceed with caution!") ;;
+esac
+
+PWLIB_PLATFORM="${PWLIB_OSTYPE}_${PWLIB_MACHTYPE}"
+
+AC_SUBST([PWLIB_PLATFORM])
+])
+
+
+AC_DEFUN(
+[AST_CHECK_OPENH323], [
+OPENH323_INCDIR=
+OPENH323_LIBDIR=
+if test "${OPENH323DIR:-unset}" != "unset" ; then
+  AC_CHECK_FILE(${OPENH323DIR}/version.h, HAS_OPENH323=1, )
+fi
+if test "${HAS_OPENH323:-unset}" = "unset" ; then
+  AC_CHECK_FILE(${PWLIBDIR}/../openh323/version.h, OPENH323DIR="${PWLIBDIR}/../openh323"; HAS_OPENH323=1, )
+  if test "${HAS_OPENH323:-unset}" != "unset" ; then
+    OPENH323DIR="${PWLIBDIR}/../openh323"
+    AC_CHECK_FILE(${OPENH323DIR}/include/h323.h, , OPENH323_INCDIR="${PWLIB_INCDIR}/openh323"; OPENH323_LIBDIR="${PWLIB_LIBDIR}")
+  else
+    AC_CHECK_FILE(${HOME}/openh323/include/h323.h, HAS_OPENH323=1, )
+    if test "${HAS_OPENH323:-unset}" != "unset" ; then
+      OPENH323DIR="${HOME}/openh323"
+    else
+      AC_CHECK_FILE(/usr/local/include/openh323/h323.h, HAS_OPENH323=1, )
+      if test "${HAS_OPENH323:-unset}" != "unset" ; then
+        OPENH323DIR="/usr/local/share/openh323"
+        OPENH323_INCDIR="/usr/local/include/openh323"
+        OPENH323_LIBDIR="/usr/local/lib"
+      else
+        AC_CHECK_FILE(/usr/include/openh323/h323.h, HAS_OPENH323=1, )
+        if test "${HAS_OPENH323:-unset}" != "unset" ; then
+          OPENH323DIR="/usr/share/openh323"
+          OPENH323_INCDIR="/usr/include/openh323"
+          OPENH323_LIBDIR="/usr/lib"
+        fi
+      fi
+    fi
+  fi
+fi
+
+if test "${HAS_OPENH323:-unset}" != "unset" ; then
+  if test "${OPENH323_INCDIR:-unset}" = "unset"; then
+    OPENH323_INCDIR="${OPENH323DIR}/include"
+  fi
+  if test "${OPENH323_LIBDIR:-unset}" = "unset"; then
+    OPENH323_LIBDIR="${OPENH323DIR}/lib"
+  fi
+
+  AC_SUBST([OPENH323DIR])
+  AC_SUBST([OPENH323_INCDIR])
+  AC_SUBST([OPENH323_LIBDIR])
+fi
+])
+
+
+AC_DEFUN(
+[AST_CHECK_PWLIB_VERSION], [
+	if test "${HAS_$2:-unset}" != "unset"; then
+		$2_VERSION=`grep "$2_VERSION" ${$2_INCDIR}/$3 | cut -f2 -d ' ' | sed -e 's/"//g'`
+		$2_MAJOR_VERSION=`echo ${$2_VERSION} | cut -f1 -d.`
+		$2_MINOR_VERSION=`echo ${$2_VERSION} | cut -f2 -d.`
+		$2_BUILD_NUMBER=`echo ${$2_VERSION} | cut -f3 -d.`
+		let $2_VER=${$2_MAJOR_VERSION}*10000+${$2_MINOR_VERSION}*100+${$2_BUILD_NUMBER}
+		let $2_REQ=$4*10000+$5*100+$6
+
+		AC_MSG_CHECKING(if $1 version ${$2_VERSION} is compatible with chan_h323)
+		if test ${$2_VER} -lt ${$2_REQ}; then
+			AC_MSG_RESULT(no)
+			unset HAS_$2
+		else
+			AC_MSG_RESULT(yes)
+		fi
+	fi
+])
+
+
+AC_DEFUN(
+[AST_CHECK_PWLIB_BUILD], [
+	if test "${HAS_$2:-unset}" != "unset"; then
+	   AC_MSG_CHECKING($1 installation validity)
+
+	   saved_cppflags="${CPPFLAGS}"
+	   saved_libs="${LIBS}"
+	   LIBS="${LIBS} -L${$2_LIBDIR} -l${PLATFORM_$2} $7"
+	   CPPFLAGS="${CPPFLAGS} -I${$2_INCDIR} $6"
+
+	   AC_LANG_PUSH([C++])
+
+	   AC_LINK_IFELSE(
+		[AC_LANG_PROGRAM([$4],[$5])],
+		[	AC_MSG_RESULT(yes) 
+			ac_cv_lib_$2="yes" 
+		],
+		[	AC_MSG_RESULT(no) 
+			ac_cv_lib_$2="no" 
+		]
+		)
+
+	   AC_LANG_POP([C++])
+
+	   LIBS="${saved_libs}"
+	   CPPFLAGS="${saved_cppflags}"
+
+	   if test "${ac_cv_lib_$2}" = "yes"; then
+	      if test "${$2_LIBDIR}" != "" -a "${$2_LIBDIR}" != "/usr/lib"; then
+	         $2_LIB="-L${$2_LIBDIR} -l${PLATFORM_$2}"
+	      else
+	         $2_LIB="-l${PLATFORM_$2}"
+	      fi
+	      if test "${$2_INCDIR}" != "" -a "${$2_INCDIR}" != "/usr/include"; then
+	         $2_INCLUDE="-I${$2_INCDIR}"
+	      fi
+	   	  PBX_$2=1
+	   	  AC_DEFINE([HAVE_$2], 1, [$3])
+	   fi
+	fi
+])
+
+AC_DEFUN(
+[AST_CHECK_OPENH323_BUILD], [
+	if test "${HAS_OPENH323:-unset}" != "unset"; then
+		AC_MSG_CHECKING(OpenH323 build option)
+		OPENH323_SUFFIX=
+		files=`ls -l ${OPENH323_LIBDIR}/libh323_${PWLIB_PLATFORM}_*.so*`
+		libfile=
+		if test -n "$files"; then
+			for f in $files; do
+				if test -f $f -a ! -L $f; then
+					libfile=`basename $f`
+					break;
+				fi
+			done
+		fi
+		if test "${libfile:-unset}" != "unset"; then
+			OPENH323_SUFFIX=`eval "echo ${libfile} | sed -e 's/libh323_${PWLIB_PLATFORM}_\(@<:@^.@:>@*\)\..*/\1/'"`
+		fi
+		case "${OPENH323_SUFFIX}" in
+			n)
+				OPENH323_BUILD="notrace";;
+			r)
+				OPENH323_BUILD="opt";;
+			d)
+				OPENH323_BUILD="debug";;
+			*)
+				OPENH323_BUILD="notrace";;
+		esac
+		AC_MSG_RESULT(${OPENH323_BUILD})
+
+		AC_SUBST([OPENH323_SUFFIX])
+		AC_SUBST([OPENH323_BUILD])
+	fi
+])
+
+
 # AST_FUNC_FORK
 # -------------
 AN_FUNCTION([fork],  [AST_FUNC_FORK])
diff --git a/build_tools/cflags.xml b/build_tools/cflags.xml
index e7c1e4edf864a7d5d0a61089a63ade10a568ba9a..7c2fbddffb707e95388f7f3486e363caa1582b0e 100644
--- a/build_tools/cflags.xml
+++ b/build_tools/cflags.xml
@@ -7,6 +7,8 @@
 		</member>
 		<member name="DETECT_DEADLOCKS" displayname="Detect Deadlocks">
 		</member>
+		<member name="DO_CRASH" displayname="Crash on fatal errors">
+		</member>
 		<member name="DONT_OPTIMIZE" displayname="Disable Optimizations by the Compiler">
 		</member>
 		<member name="DUMP_SCHEDULER" displayname="Dump Scheduler Contents for Debugging">
diff --git a/build_tools/menuselect-deps.in b/build_tools/menuselect-deps.in
index 005e1537baefc2760552af01f20a8aefcb3c07eb..5c790e0f1b629e8508161f4f52fb30145e193a88 100644
--- a/build_tools/menuselect-deps.in
+++ b/build_tools/menuselect-deps.in
@@ -4,6 +4,7 @@ FREETDS=@PBX_FREETDS@
 GSM=@PBX_GSM@
 GTK=@PBX_GTK@
 H323=@PBX_H323@
+OPENH323=@PBX_OPENH323@
 IKSEMEL=@PBX_IKSEMEL@
 IMAP_TK=@PBX_IMAP_TK@
 IXJUSER=@PBX_IXJUSER@
diff --git a/channels/Makefile b/channels/Makefile
index 13c6b16461275f4b79e4a4fd27233572deba2b46..b0c2bf72b02207359f3d5bc8339468bd855183b6 100644
--- a/channels/Makefile
+++ b/channels/Makefile
@@ -63,7 +63,20 @@ clean::
 	rm -f busy.h ringtone.h gentone
 	$(MAKE) -C misdn clean
 
--include $(PWD)/Makefile.ast
+ifneq ($(wildcard h323/Makefile.ast),)
+  include h323/Makefile.ast
+H323LDFLAGS += -Wl,--version-script=h323/noexport.map
+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
 
 $(eval $(call ast_make_final_host,gentone,gentone.c))
 gentone: LIBS+=-lm
@@ -81,11 +94,13 @@ $(chan_iax2): iax2-parser.o iax2-provision.o
 chan_alsa.o: busy.h ringtone.h
 
 ifeq ($(OSARCH),linux-gnu)
-chan_h323.so: chan_h323.o h323_module_interface.so h323/libchanh323.a h323/Makefile.ast
-	$(CC) $(SOLINK) $(H323LDFLAGS) -o $@ $^ h323/libchanh323.a $(H323LDLIBS) -lstdc++
+chan_h323.so: chan_h323.o h323/libchanh323.a h323/Makefile.ast
+	$(ECHO_PREFIX) echo "   [LD] $^ -> $@"
+	$(CMD_PREFIX) $(CXX) $(SOLINK) $(H323LDFLAGS) -o $@ $< h323/libchanh323.a $(H323LDLIBS)
 else
-chan_h323.so: chan_h323.o h323_module_interface.so h323/libchanh323.a
-	$(CC) $(SOLINK) -o $@ $^ h323/libchanh323.a $(CHANH323LIB) -L$(PWLIBDIR)/lib $(PTLIB) -L$(OPENH323DIR)/lib $(H323LIB) -L/usr/lib -lcrypto -lssl -lexpat
+chan_h323.so: chan_h323.o h323/libchanh323.a
+	$(ECHO_PREFIX) echo "   [LD] $^ -> $@"
+	$(CMD_PREFIX) $(CXX) $(SOLINK) -o $@ $< h323/libchanh323.a $(CHANH323LIB) -L$(PWLIBDIR)/lib $(PTLIB) -L$(OPENH323DIR)/lib $(H323LIB) -L/usr/lib -lcrypto -lssl -lexpat
 endif
 
 chan_misdn.o: CFLAGS+=-Imisdn -DCHAN_MISDN_VERSION=\"0.3.0\" 
diff --git a/channels/chan_h323.c b/channels/chan_h323.c
index c4e44fddd7e4e0b16e84e6cd4087290b292a74bd..3b7c66da7a3e4dded40c0041542d74b932993f6e 100644
--- a/channels/chan_h323.c
+++ b/channels/chan_h323.c
@@ -5,7 +5,7 @@
  *
  * OpenH323 Channel Driver for ASTERISK PBX.
  *			By Jeremy McNamara
- *                      For The NuFone Network 
+ *                      For The NuFone Network
  *
  * chan_h323 has been derived from code created by
  *               Michael Manousos and Mark Spencer
@@ -34,12 +34,13 @@
  */
 
 /*** MODULEINFO
-	<depend>h323</depend>
+	<depend>openh323</depend>
+	<defaultenabled>no</defaultenabled>
  ***/
 
 #ifdef __cplusplus
 extern "C" {
-#endif   
+#endif
 
 #include "asterisk.h"
 
@@ -72,13 +73,14 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #ifdef __cplusplus
 extern "C" {
-#endif   
+#endif
 
 #include "asterisk/lock.h"
 #include "asterisk/logger.h"
 #include "asterisk/channel.h"
 #include "asterisk/config.h"
 #include "asterisk/module.h"
+#include "asterisk/musiconhold.h"
 #include "asterisk/pbx.h"
 #include "asterisk/options.h"
 #include "asterisk/utils.h"
@@ -93,6 +95,7 @@ extern "C" {
 #include "asterisk/causes.h"
 #include "asterisk/stringfields.h"
 #include "asterisk/abstract_jb.h"
+#include "asterisk/astobj.h"
 
 #ifdef __cplusplus
 }
@@ -100,11 +103,11 @@ extern "C" {
 
 #include "h323/chan_h323.h"
 
-send_digit_cb on_send_digit; 
-on_rtp_cb on_external_rtp_create; 
-start_rtp_cb on_start_rtp_channel; 
+receive_digit_cb on_receive_digit;
+on_rtp_cb on_external_rtp_create;
+start_rtp_cb on_start_rtp_channel;
 setup_incoming_cb on_incoming_call;
-setup_outbound_cb on_outgoing_call; 
+setup_outbound_cb on_outgoing_call;
 chan_ringing_cb	on_chan_ringing;
 con_established_cb on_connection_established;
 clear_con_cb on_connection_cleared;
@@ -113,6 +116,7 @@ progress_cb on_progress;
 rfc2833_cb on_set_rfc2833_payload;
 hangup_cb on_hangup;
 setcapabilities_cb on_setcapabilities;
+setpeercapabilities_cb on_setpeercapabilities;
 
 /* global debug flag */
 int h323debug;
@@ -128,7 +132,7 @@ static struct ast_jb_conf default_jbconf =
 static struct ast_jb_conf global_jbconf;
 
 /** Variables required by Asterisk */
-static const char desc[] = "The NuFone Network's Open H.323 Channel Driver";
+static const char tdesc[] = "The NuFone Network's Open H.323 Channel Driver";
 static const char config[] = "h323.conf";
 static char default_context[AST_MAX_CONTEXT] = "default";
 static struct sockaddr_in bindaddr;
@@ -140,10 +144,10 @@ static int h323_signalling_port = 1720;
 static char gatekeeper[100];
 static int gatekeeper_disable = 1;
 static int gatekeeper_discover = 0;
-static int usingGk = 0;
 static int gkroute = 0;
 /* Find user by alias (h.323 id) is default, alternative is the incomming call's source IP address*/
 static int userbyalias = 1;
+static int acceptAnonymous = 1;
 static int tos = 0;
 static char secret[50];
 static unsigned int unique = 0;
@@ -153,46 +157,53 @@ static call_options_t global_options;
 /** Private structure of a OpenH323 channel */
 struct oh323_pvt {
 	ast_mutex_t lock;					/* Channel private lock */
-	call_options_t options;					/* Options to be used during call setup */
+	call_options_t options;				/* Options to be used during call setup */
 	int alreadygone;					/* Whether or not we've already been destroyed by our peer */
 	int needdestroy;					/* if we need to be destroyed */
 	call_details_t cd;					/* Call details */
-	struct ast_channel *owner;				/* Who owns us */
-	struct sockaddr_in sa;                  		/* Our peer */
-	struct sockaddr_in redirip; 			        /* Where our RTP should be going if not to us */
-	int nonCodecCapability;					/* non-audio capability */
+	struct ast_channel *owner;			/* Who owns us */
+	struct sockaddr_in sa;				/* Our peer */
+	struct sockaddr_in redirip;			/* Where our RTP should be going if not to us */
+	int nonCodecCapability;				/* non-audio capability */
 	int outgoing;						/* Outgoing or incoming call? */
-	char exten[AST_MAX_EXTENSION];				/* Requested extension */
-	char context[AST_MAX_CONTEXT];				/* Context where to start */
-	char accountcode[256];					/* Account code */
-	char cid_num[80];					/* Caller*id number, if available */
-	char cid_name[80];					/* Caller*id name, if available */
+	char exten[AST_MAX_EXTENSION];		/* Requested extension */
+	char context[AST_MAX_CONTEXT];		/* Context where to start */
+	char accountcode[256];				/* Account code */
 	char rdnis[80];						/* Referring DNIS, if available */
 	int amaflags;						/* AMA Flags */
-	struct ast_rtp *rtp;					/* RTP Session */
-	struct ast_dsp *vad;					/* Used for in-band DTMF detection */
+	struct ast_rtp *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 */
 	int hangupcause;					/* Hangup cause from OpenH323 layer */
 	int newstate;						/* Pending state change */
 	int newcontrol;						/* Pending control to send */
 	int newdigit;						/* Pending DTMF digit to send */
+	int newduration;					/* Pending DTMF digit duration to send */
+	int pref_codec;						/* Preferred codec */
+	int peercapability;					/* Capabilities learned from peer */
+	int jointcapability;				/* Common capabilities for local and remote side */
+	int dtmf_pt;						/* Payload code used for RFC2833 messages */
+	int curDTMF;						/* DTMF tone being generated to Asterisk side */
+	int DTMFsched;						/* Scheduler descriptor for DTMF */
+	int update_rtp_info;				/* Configuration of fd's array is pending */
+	int recvonly;						/* Peer isn't wish to receive our voice stream */
+	int txDtmfDigit;					/* DTMF digit being to send to H.323 side */
+	int noInbandDtmf;					/* Inband DTMF processing by DSP isn't available */
+	int connection_established;			/* Call got CONNECT message */
 	struct oh323_pvt *next;				/* Next channel in list */
 } *iflist = NULL;
 
 static struct ast_user_list {
-	struct oh323_user *users;
-	ast_mutex_t lock;
+	ASTOBJ_CONTAINER_COMPONENTS(struct oh323_user);
 } userl;
 
 static struct ast_peer_list {
-	struct oh323_peer *peers;
-	ast_mutex_t lock;
+	ASTOBJ_CONTAINER_COMPONENTS(struct oh323_peer);
 } peerl;
 
 static struct ast_alias_list {
-	struct oh323_alias *aliases;
-	ast_mutex_t lock;
+	ASTOBJ_CONTAINER_COMPONENTS(struct oh323_alias);
 } aliasl;
 
 /** Asterisk RTP stuff */
@@ -214,7 +225,7 @@ AST_MUTEX_DEFINE_STATIC(h323_reload_lock);
 static int h323_reloading = 0;
 
 /* This is the thread for the monitor which checks for input on the channels
-   which are not currently in use.  */
+   which are not currently in use. */
 static pthread_t monitor_thread = AST_PTHREADT_NULL;
 static int restart_monitor(void);
 static int h323_do_reload(void);
@@ -251,6 +262,76 @@ static const struct ast_channel_tech oh323_tech = {
 #endif
 };
 
+static const char* redirectingreason2str(int redirectingreason)
+{
+	switch (redirectingreason) {
+	case 0:
+		return "UNKNOWN";
+	case 1:
+		return "BUSY";
+	case 2:
+		return "NO_REPLY";
+	case 0xF:
+		return "UNCONDITIONAL";
+	default:
+		return "NOREDIRECT";
+	}
+}
+
+static void oh323_destroy_alias(struct oh323_alias *alias)
+{
+	if (h323debug)
+		ast_log(LOG_DEBUG, "Destroying alias '%s'\n", alias->name);
+	free(alias);
+}
+
+static void oh323_destroy_user(struct oh323_user *user)
+{
+	if (h323debug)
+		ast_log(LOG_DEBUG, "Destroying user '%s'\n", user->name);
+	ast_free_ha(user->ha);
+	free(user);
+}
+
+static void oh323_destroy_peer(struct oh323_peer *peer)
+{
+	if (h323debug)
+		ast_log(LOG_DEBUG, "Destroying peer '%s'\n", peer->name);
+	ast_free_ha(peer->ha);
+	free(peer);
+}
+
+static int oh323_simulate_dtmf_end(void *data)
+{
+	struct oh323_pvt *pvt = data;
+
+	if (pvt) {
+		ast_mutex_lock(&pvt->lock);
+		/* Don't hold pvt lock while trying to lock the channel */
+		while(pvt->owner && ast_channel_trylock(pvt->owner)) {
+			ast_mutex_unlock(&pvt->lock);
+			usleep(1);
+			ast_mutex_lock(&pvt->lock);
+		}
+
+		if (pvt->owner) {
+			struct ast_frame f = {
+				.frametype = AST_FRAME_DTMF_END,
+				.subclass = pvt->curDTMF,
+				.samples = 0,
+				.src = "SIMULATE_DTMF_END",
+			};
+			ast_queue_frame(pvt->owner, &f);
+			ast_channel_unlock(pvt->owner);
+		}
+
+		pvt->DTMFsched = -1;
+		ast_mutex_unlock(&pvt->lock);
+	}
+
+	return 0;
+}
+
 /* Channel and private structures should be already locked */
 static void __oh323_update_info(struct ast_channel *c, struct oh323_pvt *pvt)
 {
@@ -268,7 +349,7 @@ static void __oh323_update_info(struct ast_channel *c, struct oh323_pvt *pvt)
 		c->hangupcause = pvt->hangupcause;
 		ast_queue_hangup(c);
 		pvt->needhangup = 0;
-		pvt->newstate = pvt->newcontrol = pvt->newdigit = -1;
+		pvt->newstate = pvt->newcontrol = pvt->newdigit = pvt->DTMFsched = -1;
 	}
 	if (pvt->newstate >= 0) {
 		ast_setstate(c, pvt->newstate);
@@ -280,15 +361,40 @@ static void __oh323_update_info(struct ast_channel *c, struct oh323_pvt *pvt)
 	}
 	if (pvt->newdigit >= 0) {
 		struct ast_frame f = {
-			.frametype = AST_FRAME_DTMF,
+			.frametype = AST_FRAME_DTMF_END,
 			.subclass = pvt->newdigit,
-			.samples = 800,
+			.samples = pvt->newduration * 8,
 			.src = "UPDATE_INFO",
 		};
-
+		if (pvt->newdigit == ' ') {		/* signalUpdate message */
+			f.subclass = pvt->curDTMF;
+			if (pvt->DTMFsched >= 0) {
+				ast_sched_del(sched, pvt->DTMFsched);
+				pvt->DTMFsched = -1;
+			}
+		} else {						/* Regular input or signal message */
+			if (pvt->newduration) {		/* This is a signal, signalUpdate follows */
+				f.frametype = AST_FRAME_DTMF_BEGIN;
+				if (pvt->DTMFsched >= 0)
+					ast_sched_del(sched, pvt->DTMFsched);
+				pvt->DTMFsched = ast_sched_add(sched, pvt->newduration, oh323_simulate_dtmf_end, pvt);
+				if (h323debug)
+					ast_log(LOG_DTMF, "Scheduled DTMF END simulation for %d ms, id=%d\n", pvt->newduration, pvt->DTMFsched);
+			}
+			pvt->curDTMF = pvt->newdigit;
+		}
 		ast_queue_frame(c, &f);
 		pvt->newdigit = -1;
 	}
+	if (pvt->update_rtp_info > 0) {
+		if (pvt->rtp) {
+			ast_jb_configure(c, &global_jbconf);
+			c->fds[0] = ast_rtp_fd(pvt->rtp);
+			c->fds[1] = ast_rtcp_fd(pvt->rtp);
+			ast_queue_frame(pvt->owner, &ast_null_frame);	/* Tell Asterisk to apply changes */
+		}
+		pvt->update_rtp_info = -1;
+	}
 }
 
 /* Only channel structure should be locked */
@@ -303,46 +409,55 @@ static void oh323_update_info(struct ast_channel *c)
 	}
 }
 
-static void cleanup_call_details(call_details_t *cd) 
-{
-        if (cd->call_token) {
-                free(cd->call_token);
-                cd->call_token = NULL;
-        }
-        if (cd->call_source_aliases) {
-                free(cd->call_source_aliases);
-                cd->call_source_aliases = NULL;
-        }
-        if (cd->call_dest_alias) {
-                free(cd->call_dest_alias);
-                cd->call_dest_alias = NULL;
-	}
-        if (cd->call_source_name) { 
-                free(cd->call_source_name);
-                cd->call_source_name = NULL;
-        }
-        if (cd->call_source_e164) {
-                free(cd->call_source_e164);
-                cd->call_source_e164 = NULL;
-        }
-        if (cd->call_dest_e164) {
-                free(cd->call_dest_e164);
-                cd->call_dest_e164 = NULL;
-        }
-        if (cd->sourceIp) {
-                free(cd->sourceIp);
-                cd->sourceIp = NULL;
-        }
+static void cleanup_call_details(call_details_t *cd)
+{
+	if (cd->call_token) {
+		free(cd->call_token);
+		cd->call_token = NULL;
+	}
+	if (cd->call_source_aliases) {
+		free(cd->call_source_aliases);
+		cd->call_source_aliases = NULL;
+	}
+	if (cd->call_dest_alias) {
+		free(cd->call_dest_alias);
+		cd->call_dest_alias = NULL;
+	}
+	if (cd->call_source_name) {
+		free(cd->call_source_name);
+		cd->call_source_name = NULL;
+	}
+	if (cd->call_source_e164) {
+		free(cd->call_source_e164);
+		cd->call_source_e164 = NULL;
+	}
+	if (cd->call_dest_e164) {
+		free(cd->call_dest_e164);
+		cd->call_dest_e164 = NULL;
+	}
+	if (cd->sourceIp) {
+		free(cd->sourceIp);
+		cd->sourceIp = NULL;
+	}
+	if (cd->redirect_number) {
+		free(cd->redirect_number);
+		cd->redirect_number = NULL;
+	}
 }
 
 static void __oh323_destroy(struct oh323_pvt *pvt)
 {
 	struct oh323_pvt *cur, *prev = NULL;
-	
+
+	if (pvt->DTMFsched >= 0) {
+		ast_sched_del(sched, pvt->DTMFsched);
+		pvt->DTMFsched = -1;
+	}
+
 	if (pvt->rtp) {
 		ast_rtp_destroy(pvt->rtp);
 	}
-	
+
 	/* Free dsp used for in-band DTMF detection */
 	if (pvt->vad) {
 		ast_dsp_free(pvt->vad);
@@ -351,10 +466,11 @@ static void __oh323_destroy(struct oh323_pvt *pvt)
 
 	/* Unlink us from the owner if we have one */
 	if (pvt->owner) {
-		ast_mutex_lock(&pvt->owner->lock);
-		ast_log(LOG_DEBUG, "Detaching from %s\n", pvt->owner->name);
+		ast_channel_lock(pvt->owner);
+		if (h323debug)
+			ast_log(LOG_DEBUG, "Detaching from %s\n", pvt->owner->name);
 		pvt->owner->tech_pvt = NULL;
-		ast_mutex_unlock(&pvt->owner->lock);
+		ast_channel_unlock(pvt->owner);
 	}
 	cur = iflist;
 	while(cur) {
@@ -371,6 +487,7 @@ static void __oh323_destroy(struct oh323_pvt *pvt)
 	if (!cur) {
 		ast_log(LOG_WARNING, "%p is not in list?!?! \n", cur);
 	} else {
+		ast_mutex_unlock(&pvt->lock);
 		ast_mutex_destroy(&pvt->lock);
 		free(pvt);
 	}
@@ -378,20 +495,53 @@ static void __oh323_destroy(struct oh323_pvt *pvt)
 
 static void oh323_destroy(struct oh323_pvt *pvt)
 {
+	if (h323debug) {
+		ast_log(LOG_DEBUG, "Destroying channel %s\n", (pvt->owner ? pvt->owner->name : "<unknown>"));
+	}
 	ast_mutex_lock(&iflock);
+	ast_mutex_lock(&pvt->lock);
 	__oh323_destroy(pvt);
 	ast_mutex_unlock(&iflock);
 }
 
-static int oh323_digit_begin(struct ast_channel *chan, char digit)
+static int oh323_digit_begin(struct ast_channel *c, char digit)
 {
-	/* XXX Implement me, plz, kthx */
+	struct oh323_pvt *pvt = (struct oh323_pvt *) c->tech_pvt;
+	char *token;
+
+	if (!pvt) {
+		ast_log(LOG_ERROR, "No private structure?! This is bad\n");
+		return -1;
+	}
+	ast_mutex_lock(&pvt->lock);
+	if (pvt->rtp && (pvt->options.dtmfmode & H323_DTMF_RFC2833) && (pvt->dtmf_pt > 0)) {
+		/* out-of-band DTMF */
+		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_mutex_unlock(&pvt->lock);
+	} else if (pvt->txDtmfDigit != digit) {
+		/* in-band DTMF */
+		if (h323debug) {
+			ast_log(LOG_DTMF, "Begin sending inband digit %c on %s\n", digit, c->name);
+		}
+		pvt->txDtmfDigit = digit;
+		token = pvt->cd.call_token ? strdup(pvt->cd.call_token) : NULL;
+		ast_mutex_unlock(&pvt->lock);
+		h323_send_tone(token, digit);
+		if (token) {
+			free(token);
+		}
+	} else
+		ast_mutex_unlock(&pvt->lock);
+	oh323_update_info(c);
 	return 0;
 }
 
 /**
  * Send (play) the specified digit to the channel.
- * 
+ *
  */
 static int oh323_digit_end(struct ast_channel *c, char digit)
 {
@@ -403,21 +553,22 @@ static int oh323_digit_end(struct ast_channel *c, char digit)
 		return -1;
 	}
 	ast_mutex_lock(&pvt->lock);
-	if (pvt->rtp && (pvt->options.dtmfmode & H323_DTMF_RFC2833)) {
+	if (pvt->rtp && (pvt->options.dtmfmode & H323_DTMF_RFC2833) && (pvt->dtmf_pt > 0)) {
 		/* out-of-band DTMF */
 		if (h323debug) {
-			ast_log(LOG_DEBUG, "Sending out-of-band digit %c on %s\n", digit, c->name);
+			ast_log(LOG_DTMF, "End sending out-of-band digit %c on %s\n", digit, c->name);
 		}
-		ast_rtp_senddigit(pvt->rtp, digit);
+		ast_rtp_senddigit_end(pvt->rtp, digit);
 		ast_mutex_unlock(&pvt->lock);
 	} else {
 		/* in-band DTMF */
 		if (h323debug) {
-			ast_log(LOG_DEBUG, "Sending inband digit %c on %s\n", digit, c->name);
+			ast_log(LOG_DTMF, "End sending inband digit %c on %s\n", digit, c->name);
 		}
+		pvt->txDtmfDigit = ' ';
 		token = pvt->cd.call_token ? strdup(pvt->cd.call_token) : NULL;
 		ast_mutex_unlock(&pvt->lock);
-		h323_send_tone(token, digit);
+		h323_send_tone(token, ' ');
 		if (token) {
 			free(token);
 		}
@@ -427,15 +578,15 @@ static int oh323_digit_end(struct ast_channel *c, char digit)
 }
 
 /**
- * Make a call over the specified channel to the specified 
+ * Make a call over the specified channel to the specified
  * destination.
  * Returns -1 on error, 0 on success.
  */
 static int oh323_call(struct ast_channel *c, char *dest, int timeout)
-{  
+{
 	int res = 0;
 	struct oh323_pvt *pvt = (struct oh323_pvt *)c->tech_pvt;
-	char addr[INET_ADDRSTRLEN];
+	const char *addr;
 	char called_addr[1024];
 
 	if (h323debug) {
@@ -446,15 +597,15 @@ static int oh323_call(struct ast_channel *c, char *dest, int timeout)
 		return -1;
 	}
 	ast_mutex_lock(&pvt->lock);
-	if (usingGk) {
+	if (!gatekeeper_disable) {
 		if (ast_strlen_zero(pvt->exten)) {
 			strncpy(called_addr, dest, sizeof(called_addr));
 		} else {
 			snprintf(called_addr, sizeof(called_addr), "%s@%s", pvt->exten, dest);
 		}
 	} else {
-		ast_inet_ntoa(addr, sizeof(addr), pvt->sa.sin_addr);
 		res = htons(pvt->sa.sin_port);
+		addr = ast_inet_ntoa(pvt->sa.sin_addr);
 		if (ast_strlen_zero(pvt->exten)) {
 			snprintf(called_addr, sizeof(called_addr), "%s:%d", addr, res);
 		} else {
@@ -462,19 +613,37 @@ static int oh323_call(struct ast_channel *c, char *dest, int timeout)
 		}
 	}
 	/* make sure null terminated */
-	called_addr[sizeof(called_addr) - 1] = '\0'; 
+	called_addr[sizeof(called_addr) - 1] = '\0';
 
-	if (c->cid.cid_num) {
+	if (c->cid.cid_num)
 		strncpy(pvt->options.cid_num, c->cid.cid_num, sizeof(pvt->options.cid_num));
-	}
-	if (c->cid.cid_name) {
+
+	if (c->cid.cid_name)
 		strncpy(pvt->options.cid_name, c->cid.cid_name, sizeof(pvt->options.cid_name));
+
+	if (c->cid.cid_rdnis) {
+		strncpy(pvt->options.cid_rdnis, c->cid.cid_rdnis, sizeof(pvt->options.cid_rdnis));
 	}
 
+	if ((addr = pbx_builtin_getvar_helper(c, "PRIREDIRECTREASON"))) {
+		if (!strcasecmp(addr, "UNKNOWN"))
+			pvt->options.redirect_reason = 0;
+		else if (!strcasecmp(addr, "BUSY"))
+			pvt->options.redirect_reason = 1;
+		else if (!strcasecmp(addr, "NO_REPLY"))
+			pvt->options.redirect_reason = 2;
+		else if (!strcasecmp(addr, "UNCONDITIONAL"))
+			pvt->options.redirect_reason = 15;
+		else
+			pvt->options.redirect_reason = -1;
+	} else
+		pvt->options.redirect_reason = -1;
+
 	/* indicate that this is an outgoing call */
 	pvt->outgoing = 1;
 
-	ast_log(LOG_DEBUG, "Placing outgoing call to %s, %d\n", called_addr, pvt->options.dtmfcodec);
+	if (h323debug)
+		ast_log(LOG_DEBUG, "Placing outgoing call to %s, %d\n", called_addr, pvt->options.dtmfcodec);
 	ast_mutex_unlock(&pvt->lock);
 	res = h323_make_call(called_addr, &(pvt->cd), &pvt->options);
 	if (res) {
@@ -511,16 +680,15 @@ static int oh323_answer(struct ast_channel *c)
 static int oh323_hangup(struct ast_channel *c)
 {
 	struct oh323_pvt *pvt = (struct oh323_pvt *) c->tech_pvt;
-	int needcancel = 0;
 	int q931cause = AST_CAUSE_NORMAL_CLEARING;
 	char *call_token;
 
 
 	if (h323debug)
-		ast_log(LOG_DEBUG, "Hanging up call %s\n", c->name);
+		ast_log(LOG_DEBUG, "Hanging up and scheduling destroy of call %s\n", c->name);
 
 	if (!c->tech_pvt) {
-		ast_log(LOG_DEBUG, "Asked to hangup channel not connected\n");
+		ast_log(LOG_WARNING, "Asked to hangup channel not connected\n");
 		return 0;
 	}
 	ast_mutex_lock(&pvt->lock);
@@ -530,10 +698,7 @@ static int oh323_hangup(struct ast_channel *c)
 		ast_mutex_unlock(&pvt->lock);
 		return 0;
 	}
-	if (!c || (c->_state != AST_STATE_UP)) {
-		needcancel = 1;
-	}
-	
+
 	pvt->owner = NULL;
 	c->tech_pvt = NULL;
 
@@ -562,25 +727,25 @@ static int oh323_hangup(struct ast_channel *c)
 		if (call_token) {
 			/* Release lock to eliminate deadlock */
 			ast_mutex_unlock(&pvt->lock);
-			if (h323_clear_call(call_token, q931cause)) { 
-				ast_log(LOG_DEBUG, "ClearCall failed.\n");
+			if (h323_clear_call(call_token, q931cause)) {
+				ast_log(LOG_WARNING, "ClearCall failed.\n");
 			}
 			free(call_token);
 			ast_mutex_lock(&pvt->lock);
 		}
-	} 
+	}
 	pvt->needdestroy = 1;
+	ast_mutex_unlock(&pvt->lock);
 
 	/* Update usage counter */
-	ast_mutex_unlock(&pvt->lock);
-	ast_atomic_fetchadd_int(&__mod_desc->usecnt, -1);
-	ast_update_use_count();
+	ast_module_unref(ast_module_info->self);
+
 	return 0;
 }
 
 static struct ast_frame *oh323_rtp_read(struct oh323_pvt *pvt)
 {
-	/* Retrieve audio/etc from channel.  Assumes pvt->lock is already held. */
+	/* Retrieve audio/etc from channel. Assumes pvt->lock is already held. */
 	struct ast_frame *f;
 
 	/* Only apply it for the first packet, we just need the correct ip/port */
@@ -599,27 +764,34 @@ static struct ast_frame *oh323_rtp_read(struct oh323_pvt *pvt)
 		if (f->frametype == AST_FRAME_VOICE) {
 			if (f->subclass != pvt->owner->nativeformats) {
 				/* Try to avoid deadlock */
-				if (ast_mutex_trylock(&pvt->owner->lock)) {
+				if (ast_channel_trylock(pvt->owner)) {
 					ast_log(LOG_NOTICE, "Format changed but channel is locked. Ignoring frame...\n");
 					return &ast_null_frame;
 				}
-				ast_log(LOG_DEBUG, "Oooh, format changed to %d\n", f->subclass);
+				if (h323debug)
+					ast_log(LOG_DEBUG, "Oooh, format changed to %d\n", f->subclass);
 				pvt->owner->nativeformats = f->subclass;
 				pvt->nativeformats = f->subclass;
 				ast_set_read_format(pvt->owner, pvt->owner->readformat);
 				ast_set_write_format(pvt->owner, pvt->owner->writeformat);
-				ast_mutex_unlock(&pvt->owner->lock);
-			}	
+				ast_channel_unlock(pvt->owner);
+			}
 			/* Do in-band DTMF detection */
 			if ((pvt->options.dtmfmode & H323_DTMF_INBAND) && pvt->vad) {
-				if (!ast_mutex_trylock(&pvt->owner->lock)) {
-					f = ast_dsp_process(pvt->owner,pvt->vad,f);
-					ast_mutex_unlock(&pvt->owner->lock);
+				if ((pvt->nativeformats & (AST_FORMAT_SLINEAR | AST_FORMAT_ALAW | AST_FORMAT_ULAW))) {
+					if (!ast_channel_trylock(pvt->owner)) {
+						f = ast_dsp_process(pvt->owner, pvt->vad, f);
+						ast_channel_unlock(pvt->owner);
+					}
+					else
+						ast_log(LOG_NOTICE, "Unable to process inband DTMF while channel is locked\n");
+				} else if (pvt->nativeformats && !pvt->noInbandDtmf) {
+					ast_log(LOG_NOTICE, "Inband DTMF is not supported on codec %s. Use RFC2833\n", ast_getformatname(f->subclass));
+					pvt->noInbandDtmf = 1;
 				}
-				else
-					ast_log(LOG_NOTICE, "Unable to process inband DTMF while channel is locked\n");
 				if (f &&(f->frametype == AST_FRAME_DTMF)) {
-					ast_log(LOG_DEBUG, "Received in-band digit %c.\n", f->subclass);
+					if (h323debug)
+						ast_log(LOG_DTMF, "Received in-band digit %c.\n", f->subclass);
 				}
 			}
 		}
@@ -633,7 +805,21 @@ static struct ast_frame *oh323_read(struct ast_channel *c)
 	struct oh323_pvt *pvt = (struct oh323_pvt *)c->tech_pvt;
 	ast_mutex_lock(&pvt->lock);
 	__oh323_update_info(c, pvt);
-	fr = oh323_rtp_read(pvt);
+	switch(c->fdno) {
+	case 0:
+		fr = oh323_rtp_read(pvt);
+		break;
+	case 1:
+		if (pvt->rtp)
+			fr = ast_rtcp_read(pvt->rtp);
+		else
+			fr = &ast_null_frame;
+		break;
+	default:
+		ast_log(LOG_ERROR, "Unable to handle fd %d on channel %s\n", c->fdno, c->name);
+		fr = &ast_null_frame;
+		break;
+	}
 	ast_mutex_unlock(&pvt->lock);
 	return fr;
 }
@@ -658,9 +844,8 @@ static int oh323_write(struct ast_channel *c, struct ast_frame *frame)
 	}
 	if (pvt) {
 		ast_mutex_lock(&pvt->lock);
-		if (pvt->rtp) {
-			res =  ast_rtp_write(pvt->rtp, frame);
-		}
+		if (pvt->rtp && !pvt->recvonly)
+			res = ast_rtp_write(pvt->rtp, frame);
 		__oh323_update_info(c, pvt);
 		ast_mutex_unlock(&pvt->lock);
 	}
@@ -684,10 +869,10 @@ static int oh323_indicate(struct ast_channel *c, int condition, const void *data
 	case AST_CONTROL_RINGING:
 		if (c->_state == AST_STATE_RING || c->_state == AST_STATE_RINGING) {
 			h323_send_alerting(token);
- 			break;
- 		}
- 		if (token)
- 			free(token);
+			break;
+		}
+		if (token)
+			free(token);
 		return -1;
 	case AST_CONTROL_PROGRESS:
 		if (c->_state != AST_STATE_UP) {
@@ -697,14 +882,13 @@ static int oh323_indicate(struct ast_channel *c, int condition, const void *data
 		if (token)
 			free(token);
 		return -1;
-
 	case AST_CONTROL_BUSY:
 		if (c->_state != AST_STATE_UP) {
 			h323_answering_call(token, 1);
 			ast_mutex_lock(&pvt->lock);
 			pvt->alreadygone = 1;
 			ast_mutex_unlock(&pvt->lock);
-			ast_softhangup_nolock(c, AST_SOFTHANGUP_DEV);			
+			ast_softhangup_nolock(c, AST_SOFTHANGUP_DEV);
 			break;
 		}
 		if (token)
@@ -767,48 +951,102 @@ static int oh323_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
 	return 0;
 }
 
+static int __oh323_rtp_create(struct oh323_pvt *pvt)
+{
+	struct in_addr our_addr;
+
+	if (pvt->rtp)
+		return 0;
+
+	if (ast_find_ourip(&our_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);
+	if (!pvt->rtp) {
+		ast_mutex_unlock(&pvt->lock);
+		ast_log(LOG_WARNING, "Unable to create RTP session: %s\n", strerror(errno));
+		return -1;
+	}
+	if (h323debug)
+		ast_log(LOG_DEBUG, "Created RTP channel\n");
+
+	ast_rtp_settos(pvt->rtp, tos);
+
+	if (h323debug)
+		ast_log(LOG_DEBUG, "Setting NAT on RTP to %d\n", pvt->options.nat);
+	ast_rtp_setnat(pvt->rtp, pvt->options.nat);
+
+	if (pvt->dtmf_pt > 0)
+		ast_rtp_set_rtpmap_type(pvt->rtp, pvt->dtmf_pt, "audio", "telephone-event", 0);
+
+	if (pvt->owner && !ast_channel_trylock(pvt->owner)) {
+		ast_jb_configure(pvt->owner, &global_jbconf);
+		pvt->owner->fds[0] = ast_rtp_fd(pvt->rtp);
+		pvt->owner->fds[1] = ast_rtcp_fd(pvt->rtp);
+		ast_queue_frame(pvt->owner, &ast_null_frame);	/* Tell Asterisk to apply changes */
+		ast_channel_unlock(pvt->owner);
+	} else
+		pvt->update_rtp_info = 1;
+
+	return 0;
+}
+
 /* Private structure should be locked on a call */
 static struct ast_channel *__oh323_new(struct oh323_pvt *pvt, int state, const char *host)
 {
 	struct ast_channel *ch;
 	int fmt;
-	
+
 	/* Don't hold a oh323_pvt lock while we allocate a chanel */
 	ast_mutex_unlock(&pvt->lock);
 	ch = ast_channel_alloc(1);
 	/* Update usage counter */
-	ast_atomic_fetchadd_int(&__mod_desc->usecnt, +1);
-	ast_update_use_count();
+	ast_module_ref(ast_module_info->self);
 	ast_mutex_lock(&pvt->lock);
 	if (ch) {
 		ch->tech = &oh323_tech;
 		ast_string_field_build(ch, name, "H323/%s", host);
-		ch->nativeformats = pvt->options.capability;
-		if (!ch->nativeformats) {
-			ch->nativeformats = global_options.capability;
-		}
+		if (!(fmt = pvt->jointcapability) && !(fmt = pvt->options.capability))
+			fmt = global_options.capability;
+		ch->nativeformats = ast_codec_choose(&pvt->options.prefs, fmt, 1)/* | (pvt->jointcapability & AST_FORMAT_VIDEO_MASK)*/;
 		pvt->nativeformats = ch->nativeformats;
 		fmt = ast_best_codec(ch->nativeformats);
-		ch->fds[0] = ast_rtp_fd(pvt->rtp);
-		if (state == AST_STATE_RING) {
-			ch->rings = 1;
-		}
 		ch->writeformat = fmt;
 		ch->rawwriteformat = fmt;
 		ch->readformat = fmt;
 		ch->rawreadformat = fmt;
+#if 0
+		ch->fds[0] = ast_rtp_fd(pvt->rtp);
+		ch->fds[1] = ast_rtcp_fd(pvt->rtp);
+#endif
+#ifdef VIDEO_SUPPORT
+		if (pvt->vrtp) {
+			ch->fds[2] = ast_rtp_fd(pvt->vrtp);
+			ch->fds[3] = ast_rtcp_fd(pvt->vrtp);
+		}
+#endif
+#ifdef T38_SUPPORT
+		if (pvt->udptl) {
+			ch->fds[4] = ast_udptl_fd(pvt->udptl);
+		}
+#endif
+		if (state == AST_STATE_RING) {
+			ch->rings = 1;
+		}
 		/* Allocate dsp for in-band DTMF support */
 		if (pvt->options.dtmfmode & H323_DTMF_INBAND) {
 			pvt->vad = ast_dsp_new();
 			ast_dsp_set_features(pvt->vad, DSP_FEATURE_DTMF_DETECT);
-        	}
+		}
 		/* Register channel functions. */
 		ch->tech_pvt = pvt;
-		/*  Set the owner of this channel */
+		/* Set the owner of this channel */
 		pvt->owner = ch;
-		
+
 		strncpy(ch->context, pvt->context, sizeof(ch->context) - 1);
-		strncpy(ch->exten, pvt->exten, sizeof(ch->exten) - 1);		
+		strncpy(ch->exten, pvt->exten, sizeof(ch->exten) - 1);
 		ch->priority = 1;
 		if (!ast_strlen_zero(pvt->accountcode)) {
 			ast_string_field_set(ch, accountcode, pvt->accountcode);
@@ -816,25 +1054,33 @@ static struct ast_channel *__oh323_new(struct oh323_pvt *pvt, int state, const c
 		if (pvt->amaflags) {
 			ch->amaflags = pvt->amaflags;
 		}
-		
+
 		/* Don't use ast_set_callerid() here because it will
 		 * generate a NewCallerID event before the NewChannel event */
-		if (!ast_strlen_zero(pvt->cid_num)) {
-			ch->cid.cid_num = ast_strdup(pvt->cid_num);
-			ch->cid.cid_ani = ast_strdup(pvt->cid_num);
+		if (!ast_strlen_zero(pvt->options.cid_num)) {
+			ch->cid.cid_num = ast_strdup(pvt->options.cid_num);
+			ch->cid.cid_ani = ast_strdup(pvt->options.cid_num);
 		} else {
 			ch->cid.cid_num = ast_strdup(pvt->cd.call_source_e164);
 			ch->cid.cid_ani = ast_strdup(pvt->cd.call_source_e164);
 		}
-		ch->cid.cid_name = ast_strdup(pvt->cid_name);
-		ch->cid.cid_rdnis = ast_strdup(pvt->rdnis);
-		
+		if (!ast_strlen_zero(pvt->options.cid_name))
+			ch->cid.cid_name = ast_strdup(pvt->options.cid_name);
+		else
+			ch->cid.cid_name = ast_strdup(pvt->cd.call_source_name);
+		if (pvt->cd.redirect_reason >= 0) {
+			ch->cid.cid_rdnis = ast_strdup(pvt->cd.redirect_number);
+			pbx_builtin_setvar_helper(ch, "PRIREDIRECTREASON", redirectingreason2str(pvt->cd.redirect_reason));
+		}
+
 		if (!ast_strlen_zero(pvt->exten) && strcmp(pvt->exten, "s")) {
 			ch->cid.cid_dnid = strdup(pvt->exten);
 		}
 		ast_setstate(ch, state);
+#if 0
 		if (pvt->rtp)
 			ast_jb_configure(ch, &global_jbconf);
+#endif
 		if (state != AST_STATE_DOWN) {
 			if (ast_pbx_start(ch)) {
 				ast_log(LOG_WARNING, "Unable to start PBX on %s\n", ch->name);
@@ -842,7 +1088,7 @@ static struct ast_channel *__oh323_new(struct oh323_pvt *pvt, int state, const c
 				ch = NULL;
 			}
 		}
-	} else  {
+	} else {
 		ast_log(LOG_WARNING, "Unable to allocate channel structure\n");
 	}
 	return ch;
@@ -858,6 +1104,8 @@ static struct oh323_pvt *oh323_alloc(int callid)
 		return NULL;
 	}
 	memset(pvt, 0, sizeof(struct oh323_pvt));
+	pvt->cd.redirect_reason = -1;
+#if 0
 	pvt->rtp = ast_rtp_new_with_bindaddr(sched, io, 1, 0,bindaddr.sin_addr);
 	if (!pvt->rtp) {
 		ast_log(LOG_WARNING, "Unable to create RTP session: %s\n", strerror(errno));
@@ -865,25 +1113,31 @@ static struct oh323_pvt *oh323_alloc(int callid)
 		return NULL;
 	}
 	ast_rtp_settos(pvt->rtp, tos);
-	ast_mutex_init(&pvt->lock);
-	/* Ensure the call token is allocated */
-	if ((pvt->cd).call_token == NULL) {
-		(pvt->cd).call_token = (char *)malloc(128);
-	}
-	if (!pvt->cd.call_token) {
-		ast_log(LOG_ERROR, "Not enough memory to alocate call token\n");
-		return NULL;
+#endif
+	/* Ensure the call token is allocated for outgoing call */
+	if (!callid) {
+		if ((pvt->cd).call_token == NULL) {
+			(pvt->cd).call_token = (char *)malloc(128);
+		}
+		if (!pvt->cd.call_token) {
+			ast_log(LOG_ERROR, "Not enough memory to alocate call token\n");
+			ast_rtp_destroy(pvt->rtp);
+			free(pvt);
+			return NULL;
+		}
+		memset((char *)(pvt->cd).call_token, 0, 128);
+		pvt->cd.call_reference = callid;
 	}
-	memset((char *)(pvt->cd).call_token, 0, 128);
-	pvt->cd.call_reference = callid;
 	memcpy(&pvt->options, &global_options, sizeof(pvt->options));
+	pvt->jointcapability = pvt->options.capability;
 	if (pvt->options.dtmfmode & H323_DTMF_RFC2833) {
 		pvt->nonCodecCapability |= AST_RTP_DTMF;
 	} else {
 		pvt->nonCodecCapability &= ~AST_RTP_DTMF;
 	}
 	strncpy(pvt->context, default_context, sizeof(pvt->context) - 1);
-	pvt->newstate = pvt->newcontrol = pvt->newdigit = -1;
+	pvt->newstate = pvt->newcontrol = pvt->newdigit = pvt->update_rtp_info = pvt->DTMFsched = -1;
+	ast_mutex_init(&pvt->lock);
 	/* Add to interface list */
 	ast_mutex_lock(&iflock);
 	pvt->next = iflist;
@@ -893,14 +1147,14 @@ static struct oh323_pvt *oh323_alloc(int callid)
 }
 
 static struct oh323_pvt *find_call_locked(int call_reference, const char *token)
-{  
+{
 	struct oh323_pvt *pvt;
 
 	ast_mutex_lock(&iflock);
-	pvt = iflist; 
+	pvt = iflist;
 	while(pvt) {
 		if (!pvt->needdestroy && ((signed int)pvt->cd.call_reference == call_reference)) {
-			/* Found the call */             
+			/* Found the call */
 			if ((token != NULL) && (!strcmp(pvt->cd.call_token, token))) {
 				ast_mutex_lock(&pvt->lock);
 				ast_mutex_unlock(&iflock);
@@ -912,7 +1166,7 @@ static struct oh323_pvt *find_call_locked(int call_reference, const char *token)
 				return pvt;
 			}
 		}
-		pvt = pvt->next; 
+		pvt = pvt->next;
 	}
 	ast_mutex_unlock(&iflock);
 	return NULL;
@@ -922,11 +1176,12 @@ static int update_state(struct oh323_pvt *pvt, int state, int signal)
 {
 	if (!pvt)
 		return 0;
-	if (pvt->owner && !ast_mutex_trylock(&pvt->owner->lock)) {
+	if (pvt->owner && !ast_channel_trylock(pvt->owner)) {
 		if (state >= 0)
 			ast_setstate(pvt->owner, state);
 		if (signal >= 0)
 			ast_queue_control(pvt->owner, signal);
+		ast_channel_unlock(pvt->owner);
 		return 1;
 	}
 	else {
@@ -938,122 +1193,494 @@ static int update_state(struct oh323_pvt *pvt, int state, int signal)
 	}
 }
 
-struct oh323_user *find_user(const call_details_t *cd)
+static struct oh323_alias *build_alias(const char *name, struct ast_variable *v, struct ast_variable *alt, int realtime)
 {
-	struct oh323_user *u;
-	char iabuf[INET_ADDRSTRLEN];
-	u = userl.users;
-	if (userbyalias) {
-		while(u) {
-			if (!strcasecmp(u->name, cd->call_source_aliases)) {
-				break;
-			}
-			u = u->next;
-		}
-	} else {
-		while(u) {
-			if (!strcasecmp(cd->sourceIp, ast_inet_ntoa(iabuf, sizeof(iabuf), u->addr.sin_addr))) {
-				break;
+	struct oh323_alias *alias;
+	int found = 0;
+
+	alias = ASTOBJ_CONTAINER_FIND_UNLINK_FULL(&aliasl, name, name, 0, 0, strcasecmp);
+
+	if (alias)
+		found++;
+	else {
+		if (!(alias = (struct oh323_alias *)calloc(1, sizeof(*alias))))
+			return NULL;
+		ASTOBJ_INIT(alias);
+	}
+	if (!found && name)
+		strncpy(alias->name, name, sizeof(alias->name) - 1);
+	for (; v || ((v = alt) && !(alt = NULL)); v = v->next) {
+		if (!strcasecmp(v->name, "e164")) {
+			strncpy(alias->e164, v->value, sizeof(alias->e164) - 1);
+		} else if (!strcasecmp(v->name, "prefix")) {
+			strncpy(alias->prefix, v->value, sizeof(alias->prefix) - 1);
+		} else if (!strcasecmp(v->name, "context")) {
+			strncpy(alias->context, v->value, sizeof(alias->context) - 1);
+		} else if (!strcasecmp(v->name, "secret")) {
+			strncpy(alias->secret, v->value, sizeof(alias->secret) - 1);
+		} else {
+			if (strcasecmp(v->value, "h323")) {
+				ast_log(LOG_WARNING, "Keyword %s does not make sense in type=h323\n", v->name);
 			}
-			u = u->next;
 		}
 	}
-	return u;
+	ASTOBJ_UNMARK(alias);
+	return alias;
 }
 
-struct oh323_peer *find_peer(const char *peer, struct sockaddr_in *sin)
+static struct oh323_alias *realtime_alias(const char *alias)
 {
-	struct oh323_peer *p = NULL;
-       	static char iabuf[INET_ADDRSTRLEN];
+	struct ast_variable *var, *tmp;
+	struct oh323_alias *a;
 
-	p = peerl.peers;
-	if (peer) {
-		while(p) {
-			if (!strcasecmp(p->name, peer)) {
-				ast_log(LOG_DEBUG, "Found peer %s by name\n", peer);
-				break;
-			}
-			p = p->next;
+	var = ast_load_realtime("h323", "name", alias, NULL);
+
+	if (!var)
+		return NULL;
+
+	for (tmp = var; tmp; tmp = tmp->next) {
+		if (!strcasecmp(tmp->name, "type") &&
+		!(!strcasecmp(tmp->value, "alias") || !strcasecmp(tmp->value, "h323"))) {
+			ast_variables_destroy(var);
+			return NULL;
 		}
-	} else {
-		/* find by sin */
-		if (sin) {
-			while (p) {
-				if ((!inaddrcmp(&p->addr, sin)) || 
-					(p->addr.sin_addr.s_addr == sin->sin_addr.s_addr)) {
-					ast_log(LOG_DEBUG, "Found peer %s/%s by addr\n", peer, ast_inet_ntoa(iabuf, sizeof(iabuf), p->addr.sin_addr));
-					break;
-				}
-				p = p->next;
-			}
-		}	
 	}
-	if (!p) {
-		ast_log(LOG_DEBUG, "Could not find peer %s by name or address\n", peer);
-	}
-	return p;
+
+	a = build_alias(alias, var, NULL, 1);
+
+	ast_variables_destroy(var);
+
+	return a;
 }
 
-static int create_addr(struct oh323_pvt *pvt, char *opeer)
+#define DEPRECATED(_v, _new_opt) \
+	ast_log(LOG_WARNING, "Option %s found at line %d has beed deprecated. Use %s instead.\n", (_v)->name, (_v)->lineno, (_new_opt))
+
+static int update_common_options(struct ast_variable *v, struct call_options *options)
 {
-	struct hostent *hp;
-	struct ast_hostent ahp;
-	struct oh323_peer *p;
-	int portno;
-	int found = 0;
-	char *port;
-	char *hostn;
-	char peer[256] = "";
+	int tmp;
 
-	strncpy(peer, opeer, sizeof(peer) - 1);
-	port = strchr(peer, ':');
-	if (port) {
-		*port = '\0';
-		port++;
-	}
-	pvt->sa.sin_family = AF_INET;
-	ast_mutex_lock(&peerl.lock);
-	p = find_peer(peer, NULL);
-	if (p) {
-		found++;
-		memcpy(&pvt->options, &p->options, sizeof(pvt->options));
-		if (pvt->rtp) {
-			ast_log(LOG_DEBUG, "Setting NAT on RTP to %d\n", pvt->options.nat);
-			ast_rtp_setnat(pvt->rtp, pvt->options.nat);
-		}
-		if (pvt->options.dtmfmode) {
-			if (pvt->options.dtmfmode & H323_DTMF_RFC2833) {
-				pvt->nonCodecCapability |= AST_RTP_DTMF;
-			} else {
-				pvt->nonCodecCapability &= ~AST_RTP_DTMF;
-			}
+	if (!strcasecmp(v->name, "allow")) {
+		ast_parse_allow_disallow(&options->prefs, &options->capability, v->value, 1);
+	} else if (!strcasecmp(v->name, "disallow")) {
+		ast_parse_allow_disallow(&options->prefs, &options->capability, v->value, 0);
+	} else if (!strcasecmp(v->name, "dtmfmode")) {
+		if (!strcasecmp(v->value, "inband")) {
+			options->dtmfmode = H323_DTMF_INBAND;
+		} else if (!strcasecmp(v->value, "rfc2833")) {
+			options->dtmfmode = H323_DTMF_RFC2833;
+		} else {
+			ast_log(LOG_WARNING, "Unknown dtmf mode '%s', using rfc2833\n", v->value);
+			options->dtmfmode = H323_DTMF_RFC2833;
 		}
-		if (p->addr.sin_addr.s_addr) {
-			pvt->sa.sin_addr = p->addr.sin_addr;	
-			pvt->sa.sin_port = p->addr.sin_port;	
-		} 
-	}
-	ast_mutex_unlock(&peerl.lock);
-	if (!p && !found) {
+	} else if (!strcasecmp(v->name, "dtmfcodec")) {
+		tmp = atoi(v->value);
+		if (tmp < 96)
+			ast_log(LOG_WARNING, "Invalid %s value %s at line %d\n", v->name, v->value, v->lineno);
+		else
+			options->dtmfcodec = tmp;
+	} else if (!strcasecmp(v->name, "bridge")) {
+		options->bridge = ast_true(v->value);
+	} else if (!strcasecmp(v->name, "nat")) {
+		options->nat = ast_true(v->value);
+	} else if (!strcasecmp(v->name, "noFastStart")) {
+		DEPRECATED(v, "fastStart");
+		options->fastStart = !ast_true(v->value);
+	} else if (!strcasecmp(v->name, "fastStart")) {
+		options->fastStart = ast_true(v->value);
+	} else if (!strcasecmp(v->name, "noH245Tunneling")) {
+		DEPRECATED(v, "h245Tunneling");
+		options->h245Tunneling = !ast_true(v->value);
+	} else if (!strcasecmp(v->name, "h245Tunneling")) {
+		options->h245Tunneling = ast_true(v->value);
+	} else if (!strcasecmp(v->name, "noSilenceSuppression")) {
+		DEPRECATED(v, "silenceSuppression");
+		options->silenceSuppression = !ast_true(v->value);
+	} else if (!strcasecmp(v->name, "silenceSuppression")) {
+		options->silenceSuppression = ast_true(v->value);
+	} else if (!strcasecmp(v->name, "progress_setup")) {
+		tmp = atoi(v->value);
+		if ((tmp != 0) && (tmp != 1) && (tmp != 3) && (tmp != 8)) {
+			ast_log(LOG_WARNING, "Invalid value %s for %s at line %d, assuming 0\n", v->value, v->name, v->lineno);
+			tmp = 0;
+		}
+		options->progress_setup = tmp;
+	} else if (!strcasecmp(v->name, "progress_alert")) {
+		tmp = atoi(v->value);
+		if ((tmp != 0) && (tmp != 1) && (tmp != 8)) {
+			ast_log(LOG_WARNING, "Invalid value %s for %s at line %d, assuming 0\n", v->value, v->name, v->lineno);
+			tmp = 0;
+		}
+		options->progress_alert = tmp;
+	} else if (!strcasecmp(v->name, "progress_audio")) {
+		options->progress_audio = ast_true(v->value);
+	} else if (!strcasecmp(v->name, "callerid")) {
+		ast_callerid_split(v->value, options->cid_name, sizeof(options->cid_name), options->cid_num, sizeof(options->cid_num));
+	} else if (!strcasecmp(v->name, "fullname")) {
+		ast_copy_string(options->cid_name, v->value, sizeof(options->cid_name));
+	} else if (!strcasecmp(v->name, "cid_number")) {
+		ast_copy_string(options->cid_num, v->value, sizeof(options->cid_num));
+	} else if (!strcasecmp(v->name, "tunneling")) {
+		if (!strcasecmp(v->value, "none"))
+			options->tunnelOptions = 0;
+		else if (!strcasecmp(v->value, "cisco"))
+			options->tunnelOptions |= H323_TUNNEL_CISCO;
+		else if (!strcasecmp(v->value, "qsig"))
+			options->tunnelOptions |= H323_TUNNEL_QSIG;
+		else
+			ast_log(LOG_WARNING, "Invalid value %s for %s at line %d\n", v->value, v->name, v->lineno);
+	} else
+		return 1;
+
+	return 0;
+}
+#undef DEPRECATED
+
+static struct oh323_user *build_user(char *name, struct ast_variable *v, struct ast_variable *alt, int realtime)
+{
+	struct oh323_user *user;
+	struct ast_ha *oldha;
+	int found = 0;
+	int format;
+
+	user = ASTOBJ_CONTAINER_FIND_UNLINK_FULL(&userl, name, name, 0, 0, strcmp);
+
+	if (user)
+		found++;
+	else {
+		if (!(user = (struct oh323_user *)calloc(1, sizeof(*user))))
+			return NULL;
+		ASTOBJ_INIT(user);
+	}
+	oldha = user->ha;
+	user->ha = (struct ast_ha *)NULL;
+	memcpy(&user->options, &global_options, sizeof(user->options));
+	/* Set default context */
+	strncpy(user->context, default_context, sizeof(user->context) - 1);
+	if (user && !found)
+		strncpy(user->name, name, sizeof(user->name) - 1);
+
+#if 0 /* XXX Port channel variables functionality from chan_sip XXX */
+	if (user->chanvars) {
+		ast_variables_destroy(user->chanvars);
+		user->chanvars = NULL;
+	}
+#endif
+
+	for (; v || ((v = alt) && !(alt = NULL)); v = v->next) {
+		if (!update_common_options(v, &user->options))
+			continue;
+		if (!strcasecmp(v->name, "context")) {
+			strncpy(user->context, v->value, sizeof(user->context) - 1);
+		} else if (!strcasecmp(v->name, "secret")) {
+			strncpy(user->secret, v->value, sizeof(user->secret) - 1);
+		} else if (!strcasecmp(v->name, "accountcode")) {
+			strncpy(user->accountcode, v->value, sizeof(user->accountcode) - 1);
+		} else if (!strcasecmp(v->name, "host")) {
+			if (!strcasecmp(v->value, "dynamic")) {
+				ast_log(LOG_ERROR, "A dynamic host on a type=user does not make any sense\n");
+				ASTOBJ_UNREF(user, oh323_destroy_user);
+				return NULL;
+			} else if (ast_get_ip(&user->addr, v->value)) {
+				ASTOBJ_UNREF(user, oh323_destroy_user);
+				return NULL;
+			}
+			/* Let us know we need to use ip authentication */
+			user->host = 1;
+		} else if (!strcasecmp(v->name, "amaflags")) {
+			format = ast_cdr_amaflags2int(v->value);
+			if (format < 0) {
+				ast_log(LOG_WARNING, "Invalid AMA Flags: %s at line %d\n", v->value, v->lineno);
+			} else {
+				user->amaflags = format;
+			}
+		} else if (!strcasecmp(v->name, "permit") ||
+					!strcasecmp(v->name, "deny")) {
+			user->ha = ast_append_ha(v->name, v->value, user->ha);
+		}
+	}
+	ASTOBJ_UNMARK(user);
+	ast_free_ha(oldha);
+	return user;
+}
+
+static struct oh323_user *realtime_user(const call_details_t *cd)
+{
+	struct ast_variable *var, *tmp;
+	struct oh323_user *user;
+	char *username;
+
+	if (userbyalias)
+		var = ast_load_realtime("h323", "name", username = cd->call_source_aliases, NULL);
+	else {
+		username = (char *)NULL;
+		var = ast_load_realtime("h323", "host", cd->sourceIp, NULL);
+	}
+
+	if (!var)
+		return NULL;
+
+	for (tmp = var; tmp; tmp = tmp->next) {
+		if (!strcasecmp(tmp->name, "type") &&
+		!(!strcasecmp(tmp->value, "user") || !strcasecmp(tmp->value, "friend"))) {
+			ast_variables_destroy(var);
+			return NULL;
+		} else if (!username && !strcasecmp(tmp->name, "name"))
+			username = tmp->value;
+	}
+
+	if (!username) {
+		ast_log(LOG_WARNING, "Cannot determine user name for IP address %s\n", cd->sourceIp);
+		ast_variables_destroy(var);
+		return NULL;
+	}
+
+	user = build_user(username, var, NULL, 1);
+
+	ast_variables_destroy(var);
+
+	return user;
+}
+
+static struct oh323_peer *build_peer(const char *name, struct ast_variable *v, struct ast_variable *alt, int realtime)
+{
+	struct oh323_peer *peer;
+	struct ast_ha *oldha;
+	int found = 0;
+
+	peer = ASTOBJ_CONTAINER_FIND_UNLINK_FULL(&peerl, name, name, 0, 0, strcmp);
+
+	if (peer)
+		found++;
+	else {
+		if (!(peer = (struct oh323_peer*)calloc(1, sizeof(*peer))))
+			return NULL;
+		ASTOBJ_INIT(peer);
+	}
+	oldha = peer->ha;
+	peer->ha = NULL;
+	memcpy(&peer->options, &global_options, sizeof(peer->options));
+	peer->addr.sin_port = htons(h323_signalling_port);
+	peer->addr.sin_family = AF_INET;
+	if (!found && name)
+		strncpy(peer->name, name, sizeof(peer->name) - 1);
+
+#if 0 /* XXX Port channel variables functionality from chan_sip XXX */
+	if (peer->chanvars) {
+		ast_variables_destroy(peer->chanvars);
+		peer->chanvars = NULL;
+	}
+#endif
+	/* Default settings for mailbox */
+	peer->mailbox[0] = '\0';
+
+	for (; v || ((v = alt) && !(alt = NULL)); v = v->next) {
+		if (!update_common_options(v, &peer->options))
+			continue;
+		if (!strcasecmp(v->name, "host")) {
+			if (!strcasecmp(v->value, "dynamic")) {
+				ast_log(LOG_ERROR, "Dynamic host configuration not implemented.\n");
+				ASTOBJ_UNREF(peer, oh323_destroy_peer);
+				return NULL;
+			}
+			if (ast_get_ip(&peer->addr, v->value)) {
+				ast_log(LOG_ERROR, "Could not determine IP for %s\n", v->value);
+				ASTOBJ_UNREF(peer, oh323_destroy_peer);
+				return NULL;
+			}
+		} else if (!strcasecmp(v->name, "port")) {
+			peer->addr.sin_port = htons(atoi(v->value));
+		} else if (!strcasecmp(v->name, "permit") ||
+					!strcasecmp(v->name, "deny")) {
+			peer->ha = ast_append_ha(v->name, v->value, peer->ha);
+		} else if (!strcasecmp(v->name, "mailbox")) {
+			ast_copy_string(peer->mailbox, v->value, sizeof(peer->mailbox));
+		}
+	}
+	ASTOBJ_UNMARK(peer);
+	ast_free_ha(oldha);
+	return peer;
+}
+
+static struct oh323_peer *realtime_peer(const char *peername, struct sockaddr_in *sin)
+{
+	struct oh323_peer *peer;
+	struct ast_variable *var;
+	struct ast_variable *tmp;
+	const char *addr;
+
+	/* First check on peer name */
+	if (peername)
+		var = ast_load_realtime("h323", "name", peername, addr = NULL);
+	else if (sin) /* Then check on IP address for dynamic peers */
+		var = ast_load_realtime("h323", "host", addr = ast_inet_ntoa(sin->sin_addr), NULL);
+	else
+		return NULL;
+
+	if (!var)
+		return NULL;
+
+	for (tmp = var; tmp; tmp = tmp->next) {
+		/* If this is type=user, then skip this object. */
+		if (!strcasecmp(tmp->name, "type") &&
+				!(!strcasecmp(tmp->value, "peer") || !strcasecmp(tmp->value, "friend"))) {
+			ast_variables_destroy(var);
+			return NULL;
+		} else if (!peername && !strcasecmp(tmp->name, "name")) {
+			peername = tmp->value;
+		}
+	}
+
+	if (!peername) {	/* Did not find peer in realtime */
+		ast_log(LOG_WARNING, "Cannot determine peer name for IP address %s\n", addr);
+		ast_variables_destroy(var);
+		return NULL;
+	}
+
+	/* Peer found in realtime, now build it in memory */
+	peer = build_peer(peername, var, NULL, 1);
+
+	ast_variables_destroy(var);
+
+	return peer;
+}
+
+static int oh323_addrcmp_str(struct in_addr inaddr, char *addr)
+{
+	return strcmp(ast_inet_ntoa(inaddr), addr);
+}
+
+static struct oh323_user *find_user(const call_details_t *cd, int realtime)
+{
+	struct oh323_user *u;
+
+	if (userbyalias)
+		u = ASTOBJ_CONTAINER_FIND(&userl, cd->call_source_aliases);
+	else
+		u = ASTOBJ_CONTAINER_FIND_FULL(&userl, cd->sourceIp, addr.sin_addr, 0, 0, oh323_addrcmp_str);
+
+	if (!u && realtime)
+		u = realtime_user(cd);
+
+	if (!u && h323debug)
+		ast_log(LOG_DEBUG, "Could not find user by name %s or address %s\n", cd->call_source_aliases, cd->sourceIp);
+
+	return u;
+}
+
+static int oh323_addrcmp(struct sockaddr_in addr, struct sockaddr_in *sin)
+{
+	int res;
+
+	if (!sin)
+		res = -1;
+	else
+		res = inaddrcmp(&addr , sin);
+
+	return res;
+}
+
+static struct oh323_peer *find_peer(const char *peer, struct sockaddr_in *sin, int realtime)
+{
+	struct oh323_peer *p;
+
+	if (peer)
+		p = ASTOBJ_CONTAINER_FIND(&peerl, peer);
+	else
+		p = ASTOBJ_CONTAINER_FIND_FULL(&peerl, sin, addr, 0, 0, oh323_addrcmp);
+
+	if (!p && realtime)
+		p = realtime_peer(peer, sin);
+
+	if (!p && h323debug)
+		ast_log(LOG_DEBUG, "Could not find peer by name %s or address %s\n", (peer ? peer : "<NONE>"), (sin ? ast_inet_ntoa(sin->sin_addr) : "<NONE>"));
+
+	return p;
+}
+
+static int create_addr(struct oh323_pvt *pvt, char *opeer)
+{
+	struct hostent *hp;
+	struct ast_hostent ahp;
+	struct oh323_peer *p;
+	int portno;
+	int found = 0;
+	char *port;
+	char *hostn;
+	char peer[256] = "";
+
+	strncpy(peer, opeer, sizeof(peer) - 1);
+	port = strchr(peer, ':');
+	if (port) {
+		*port = '\0';
+		port++;
+	}
+	pvt->sa.sin_family = AF_INET;
+	p = find_peer(peer, NULL, 1);
+	if (p) {
+		found++;
+		memcpy(&pvt->options, &p->options, sizeof(pvt->options));
+		pvt->jointcapability = pvt->options.capability;
+#if 0
+		if (pvt->rtp) {
+			if (h323debug)
+				ast_log(LOG_DEBUG, "Setting NAT on RTP to %d\n", pvt->options.nat);
+			ast_rtp_setnat(pvt->rtp, pvt->options.nat);
+		}
+#endif
+		if (pvt->options.dtmfmode) {
+			if (pvt->options.dtmfmode & H323_DTMF_RFC2833) {
+				pvt->nonCodecCapability |= AST_RTP_DTMF;
+			} else {
+				pvt->nonCodecCapability &= ~AST_RTP_DTMF;
+			}
+		}
+		if (p->addr.sin_addr.s_addr) {
+			pvt->sa.sin_addr = p->addr.sin_addr;
+			pvt->sa.sin_port = p->addr.sin_port;
+		}
+		ASTOBJ_UNREF(p, oh323_destroy_peer);
+	}
+	if (!p && !found) {
 		hostn = peer;
 		if (port) {
 			portno = atoi(port);
 		} else {
 			portno = h323_signalling_port;
-		}		
+		}
 		hp = ast_gethostbyname(hostn, &ahp);
 		if (hp) {
-			memcpy(&pvt->options, &global_options, sizeof(pvt->options));
 			memcpy(&pvt->sa.sin_addr, hp->h_addr, sizeof(pvt->sa.sin_addr));
 			pvt->sa.sin_port = htons(portno);
-			return 0;	
+			/* Look peer by address */
+			p = find_peer(NULL, &pvt->sa, 1);
+			memcpy(&pvt->options, (p ? &p->options : &global_options), sizeof(pvt->options));
+			pvt->jointcapability = pvt->options.capability;
+			if (p) {
+				ASTOBJ_UNREF(p, oh323_destroy_peer);
+			}
+#if 0
+			if (pvt->rtp) {
+				if (h323debug)
+					ast_log(LOG_DEBUG, "Setting NAT on RTP to %d\n", pvt->options.nat);
+				ast_rtp_setnat(pvt->rtp, pvt->options.nat);
+			}
+#endif
+			if (pvt->options.dtmfmode) {
+				if (pvt->options.dtmfmode & H323_DTMF_RFC2833) {
+					pvt->nonCodecCapability |= AST_RTP_DTMF;
+				} else {
+					pvt->nonCodecCapability &= ~AST_RTP_DTMF;
+				}
+			}
+			return 0;
 		} else {
 			ast_log(LOG_WARNING, "No such host: %s\n", peer);
 			return -1;
 		}
-	} else if (!p) {
+	} else if (!found) {
 		return -1;
-	} else {	
+	} else {
 		return 0;
 	}
 }
@@ -1066,49 +1693,64 @@ static struct ast_channel *oh323_request(const char *type, int format, void *dat
 	char *ext, *host;
 	char *h323id = NULL;
 	char tmp[256], tmp1[256];
-	
-	ast_log(LOG_DEBUG, "type=%s, format=%d, data=%s.\n", type, format, (char *)data);
+
+	if (h323debug)
+		ast_log(LOG_DEBUG, "type=%s, format=%d, data=%s.\n", type, format, (char *)data);
+
 	pvt = oh323_alloc(0);
 	if (!pvt) {
 		ast_log(LOG_WARNING, "Unable to build pvt data for '%s'\n", (char *)data);
 		return NULL;
-	}	
+	}
 	oldformat = format;
 	format &= ((AST_FORMAT_MAX_AUDIO << 1) - 1);
 	if (!format) {
 		ast_log(LOG_NOTICE, "Asked to get a channel of unsupported format '%d'\n", format);
+		oh323_destroy(pvt);
+		if (cause)
+			*cause = AST_CAUSE_INCOMPATIBLE_DESTINATION;
 		return NULL;
 	}
-	strncpy(tmp, dest, sizeof(tmp) - 1);	
+	strncpy(tmp, dest, sizeof(tmp) - 1);
 	host = strchr(tmp, '@');
 	if (host) {
 		*host = '\0';
 		host++;
 		ext = tmp;
 	} else {
+		ext = strrchr(tmp, '/');
+		if (ext)
+			*ext++ = '\0';
 		host = tmp;
-		ext = NULL;
 	}
-	strtok_r(host, "/", &(h323id));		
+	strtok_r(host, "/", &(h323id));
 	if (!ast_strlen_zero(h323id)) {
 		h323_set_id(h323id);
 	}
 	if (ext) {
 		strncpy(pvt->exten, ext, sizeof(pvt->exten) - 1);
 	}
-	ast_log(LOG_DEBUG, "Extension: %s Host: %s\n",  pvt->exten, host);
-	if (!usingGk) {
+	if (h323debug)
+		ast_log(LOG_DEBUG, "Extension: %s Host: %s\n", pvt->exten, host);
+
+	if (gatekeeper_disable) {
 		if (create_addr(pvt, host)) {
 			oh323_destroy(pvt);
+			if (cause)
+				*cause = AST_CAUSE_DESTINATION_OUT_OF_ORDER;
 			return NULL;
 		}
 	}
 	else {
 		memcpy(&pvt->options, &global_options, sizeof(pvt->options));
+		pvt->jointcapability = pvt->options.capability;
+#if 0
 		if (pvt->rtp) {
-			ast_log(LOG_DEBUG, "Setting NAT on RTP to %d\n", pvt->options.nat);
+			if (h323debug)
+				ast_log(LOG_DEBUG, "Setting NAT on RTP to %d\n", pvt->options.nat);
 			ast_rtp_setnat(pvt->rtp, pvt->options.nat);
 		}
+#endif
 		if (pvt->options.dtmfmode) {
 			if (pvt->options.dtmfmode & H323_DTMF_RFC2833) {
 				pvt->nonCodecCapability |= AST_RTP_DTMF;
@@ -1129,6 +1771,8 @@ static struct ast_channel *oh323_request(const char *type, int format, void *dat
 	ast_mutex_unlock(&pvt->lock);
 	if (!tmpc) {
 		oh323_destroy(pvt);
+		if (cause)
+			*cause = AST_CAUSE_NORMAL_TEMPORARY_FAILURE;
 	}
 	ast_update_use_count();
 	restart_monitor();
@@ -1136,17 +1780,15 @@ static struct ast_channel *oh323_request(const char *type, int format, void *dat
 }
 
 /** Find a call by alias */
-struct oh323_alias *find_alias(const char *source_aliases)
+static struct oh323_alias *find_alias(const char *source_aliases, int realtime)
 {
 	struct oh323_alias *a;
 
-	a = aliasl.aliases;
-	while(a) {
-		if (!strcasecmp(a->name, source_aliases)) {
-			break;
-		}
-		a = a->next;
-	}
+	a = ASTOBJ_CONTAINER_FIND(&aliasl, source_aliases);
+
+	if (!a && realtime)
+		a = realtime_alias(source_aliases);
+
 	return a;
 }
 
@@ -1154,29 +1796,56 @@ struct oh323_alias *find_alias(const char *source_aliases)
   * Callback for sending digits from H.323 up to asterisk
   *
   */
-int send_digit(unsigned call_reference, char digit, const char *token)
+static int receive_digit(unsigned call_reference, char digit, const char *token, int duration)
 {
 	struct oh323_pvt *pvt;
 	int res;
 
-	ast_log(LOG_DEBUG, "Received Digit: %c\n", digit);
-	pvt = find_call_locked(call_reference, token); 
+	pvt = find_call_locked(call_reference, token);
 	if (!pvt) {
-		ast_log(LOG_ERROR, "Private structure not found in send_digit.\n");
+		ast_log(LOG_ERROR, "Received digit '%c' (%u ms) for call %s without private structure\n", digit, duration, token);
 		return -1;
 	}
-	if (pvt->owner && !ast_mutex_trylock(&pvt->owner->lock)) {
-		struct ast_frame f = {
-			.frametype = AST_FRAME_DTMF,
-			.subclass = digit,
-			.samples = 800,
-			.src = "SEND_DIGIT",
-		};
-
-		res = ast_queue_frame(pvt->owner, &f);
-		ast_mutex_unlock(&pvt->owner->lock);
+	if (h323debug)
+		ast_log(LOG_DTMF, "Received %s digit '%c' (%u ms) for call %s\n", (digit == ' ' ? "update for" : "new"), (digit == ' ' ? pvt->curDTMF : digit), duration, token);
+
+	if (pvt->owner && !ast_channel_trylock(pvt->owner)) {
+		if (digit == '!')
+			res = ast_queue_control(pvt->owner, AST_CONTROL_FLASH);
+		else {
+			struct ast_frame f = {
+				.frametype = AST_FRAME_DTMF_END,
+				.subclass = digit,
+				.samples = duration * 8,
+				.src = "SEND_DIGIT",
+			};
+			if (digit == ' ') {		/* signalUpdate message */
+				f.subclass = pvt->curDTMF;
+				if (pvt->DTMFsched >= 0) {
+					ast_sched_del(sched, pvt->DTMFsched);
+					pvt->DTMFsched = -1;
+				}
+			} else {				/* Regular input or signal message */
+				if (duration) {		/* This is a signal, signalUpdate follows */
+					f.frametype = AST_FRAME_DTMF_BEGIN;
+					if (pvt->DTMFsched >= 0)
+						ast_sched_del(sched, pvt->DTMFsched);
+					pvt->DTMFsched = ast_sched_add(sched, duration, oh323_simulate_dtmf_end, pvt);
+					if (h323debug)
+						ast_log(LOG_DTMF, "Scheduled DTMF END simulation for %d ms, id=%d\n", duration, pvt->DTMFsched);
+				}
+				pvt->curDTMF = digit;
+			}
+			res = ast_queue_frame(pvt->owner, &f);
+		}
+		ast_channel_unlock(pvt->owner);
 	} else {
-		pvt->newdigit = digit;
+		if (digit == '!')
+			pvt->newcontrol = AST_CONTROL_FLASH;
+		else {
+			pvt->newduration = duration;
+			pvt->newdigit = digit;
+		}
 		res = 0;
 	}
 	ast_mutex_unlock(&pvt->lock);
@@ -1188,8 +1857,8 @@ int send_digit(unsigned call_reference, char digit, const char *token)
   *
   * Returns the local RTP information
   */
-struct rtp_info *external_rtp_create(unsigned call_reference, const char * token)
-{	
+static struct rtp_info *external_rtp_create(unsigned call_reference, const char * token)
+{
 	struct oh323_pvt *pvt;
 	struct sockaddr_in us;
 	struct rtp_info *info;
@@ -1199,17 +1868,26 @@ struct rtp_info *external_rtp_create(unsigned call_reference, const char * token
 		ast_log(LOG_ERROR, "Unable to allocated info structure, this is very bad\n");
 		return NULL;
 	}
-	pvt = find_call_locked(call_reference, token); 
+	pvt = find_call_locked(call_reference, token);
 	if (!pvt) {
 		free(info);
 		ast_log(LOG_ERROR, "Unable to find call %s(%d)\n", token, call_reference);
 		return NULL;
 	}
+	if (!pvt->rtp)
+		__oh323_rtp_create(pvt);
+	if (!pvt->rtp) {
+		ast_mutex_unlock(&pvt->lock);
+		free(info);
+		ast_log(LOG_ERROR, "No RTP stream is available for call %s (%d)", token, call_reference);
+		return NULL;
+	}
 	/* figure out our local RTP port and tell the H.323 stack about it */
 	ast_rtp_get_us(pvt->rtp, &us);
 	ast_mutex_unlock(&pvt->lock);
 
-	ast_inet_ntoa(info->addr, sizeof(info->addr), us.sin_addr);
+	strncpy(info->addr, ast_inet_ntoa(us.sin_addr), sizeof(info->addr));
+	info->addr[sizeof(info->addr)-1] = '\0';
 	info->port = ntohs(us.sin_port);
 	if (h323debug)
 		ast_log(LOG_DEBUG, "Sending RTP 'US' %s:%d\n", info->addr, info->port);
@@ -1220,26 +1898,28 @@ struct rtp_info *external_rtp_create(unsigned call_reference, const char * token
  * Definition taken from rtp.c for rtpPayloadType because we need it here.
  */
 struct rtpPayloadType {
-	int isAstFormat;        /* whether the following code is an AST_FORMAT */
+	int isAstFormat;	/* whether the following code is an AST_FORMAT */
 	int code;
 };
 
 /**
-  * Call-back function passing remote ip/port information from H.323 to asterisk 
+  * Call-back function passing remote ip/port information from H.323 to asterisk
   *
-  * Returns nothing 
+  * Returns nothing
   */
-void setup_rtp_connection(unsigned call_reference, const char *remoteIp, int remotePort, const char *token, int pt)
+static void setup_rtp_connection(unsigned call_reference, const char *remoteIp, int remotePort, const char *token, int pt)
 {
 	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;
 
 	if (h323debug)
 		ast_log(LOG_DEBUG, "Setting up RTP connection for %s\n", token);
 
 	/* Find the call or allocate a private structure if call not found */
-	pvt = find_call_locked(call_reference, token); 
+	pvt = find_call_locked(call_reference, token);
 	if (!pvt) {
 		ast_log(LOG_ERROR, "Something is wrong: rtp\n");
 		return;
@@ -1248,29 +1928,78 @@ void setup_rtp_connection(unsigned call_reference, const char *remoteIp, int rem
 		ast_mutex_unlock(&pvt->lock);
 		return;
 	}
-	rtptype = ast_rtp_lookup_pt(pvt->rtp, pt);
-	pvt->nativeformats = rtptype.code;
-	if (pvt->owner && !ast_mutex_trylock(&pvt->owner->lock)) {
-		pvt->owner->nativeformats = pvt->nativeformats;
-		ast_set_read_format(pvt->owner, pvt->owner->readformat);
-		ast_set_write_format(pvt->owner, pvt->owner->writeformat);
-		if (pvt->options.progress_audio)
-			ast_queue_control(pvt->owner, AST_CONTROL_PROGRESS);
-		ast_mutex_unlock(&pvt->owner->lock);
-	}
-	else {
-		if (pvt->options.progress_audio)
-			pvt->newcontrol = AST_CONTROL_PROGRESS;
-		if (h323debug)
-			ast_log(LOG_DEBUG, "RTP connection preparation for %s is pending...\n", token);
-	}
+
+	if (!pvt->rtp)
+		__oh323_rtp_create(pvt);
 
 	them.sin_family = AF_INET;
 	/* only works for IPv4 */
-	them.sin_addr.s_addr = inet_addr(remoteIp); 
+	them.sin_addr.s_addr = inet_addr(remoteIp);
 	them.sin_port = htons(remotePort);
-	ast_rtp_set_peer(pvt->rtp, &them);
 
+	if (them.sin_addr.s_addr) {
+		ast_rtp_set_peer(pvt->rtp, &them);
+		if (pvt->recvonly) {
+			pvt->recvonly = 0;
+			rtp_change = NEED_UNHOLD;
+		}
+	} else {
+		ast_rtp_stop(pvt->rtp);
+		if (!pvt->recvonly) {
+			pvt->recvonly = 1;
+			rtp_change = NEED_HOLD;
+		}
+	}
+
+	/* 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);
+		if (h323debug)
+			ast_log(LOG_DEBUG, "Native format is set to %d from %d by RTP payload type %d\n", rtptype.code, pvt->nativeformats, pt);
+		if (pvt->nativeformats != rtptype.code) {
+			pvt->nativeformats = rtptype.code;
+			nativeformats_changed = 1;
+		}
+	} else if (h323debug)
+		ast_log(LOG_NOTICE, "Payload type is unknown, formats isn't changed\n");
+
+	/* Don't try to lock the channel if nothing changed */
+	if (nativeformats_changed || pvt->options.progress_audio || (rtp_change != NEED_NONE)) {
+		if (pvt->owner && !ast_channel_trylock(pvt->owner)) {
+			/* Re-build translation path only if native format(s) has been changed */
+			if (pvt->owner->nativeformats != pvt->nativeformats) {
+				if (h323debug)
+					ast_log(LOG_DEBUG, "Native format changed to %d from %d, read format is %d, write format is %d\n", pvt->nativeformats, pvt->owner->nativeformats, pvt->owner->readformat, pvt->owner->writeformat);
+				pvt->owner->nativeformats = pvt->nativeformats;
+				ast_set_read_format(pvt->owner, pvt->owner->readformat);
+				ast_set_write_format(pvt->owner, pvt->owner->writeformat);
+			}
+			if (pvt->options.progress_audio)
+				ast_queue_control(pvt->owner, AST_CONTROL_PROGRESS);
+			switch (rtp_change) {
+			case NEED_HOLD:
+				ast_queue_control(pvt->owner, AST_CONTROL_HOLD);
+				break;
+			case NEED_UNHOLD:
+				ast_queue_control(pvt->owner, AST_CONTROL_UNHOLD);
+				break;
+			default:
+				break;
+			}
+			ast_channel_unlock(pvt->owner);
+		}
+		else {
+			if (pvt->options.progress_audio)
+				pvt->newcontrol = AST_CONTROL_PROGRESS;
+			else if (rtp_change == NEED_HOLD)
+				pvt->newcontrol = AST_CONTROL_HOLD;
+			else if (rtp_change == NEED_UNHOLD)
+				pvt->newcontrol = AST_CONTROL_UNHOLD;
+			if (h323debug)
+				ast_log(LOG_DEBUG, "RTP connection preparation for %s is pending...\n", token);
+		}
+	}
 	ast_mutex_unlock(&pvt->lock);
 
 	if (h323debug)
@@ -1279,18 +2008,18 @@ void setup_rtp_connection(unsigned call_reference, const char *remoteIp, int rem
 	return;
 }
 
-/**  
-  *	Call-back function to signal asterisk that the channel has been answered 
+/**
+  *	Call-back function to signal asterisk that the channel has been answered
   * Returns nothing
   */
-void connection_made(unsigned call_reference, const char *token)
+static void connection_made(unsigned call_reference, const char *token)
 {
 	struct oh323_pvt *pvt;
 
 	if (h323debug)
 		ast_log(LOG_DEBUG, "Call %s answered\n", token);
 
-	pvt = find_call_locked(call_reference, token); 
+	pvt = find_call_locked(call_reference, token);
 	if (!pvt) {
 		ast_log(LOG_ERROR, "Something is wrong: connection\n");
 		return;
@@ -1301,17 +2030,21 @@ void connection_made(unsigned call_reference, const char *token)
 		ast_mutex_unlock(&pvt->lock);
 		return;
 	}
-	if (update_state(pvt, AST_STATE_UP, AST_CONTROL_ANSWER))
-		ast_mutex_unlock(&pvt->owner->lock);
+	/* Do not send ANSWER message more than once */
+	if (!pvt->connection_established) {
+		pvt->connection_established = 1;
+		update_state(pvt, -1, AST_CONTROL_ANSWER);
+	}
 	ast_mutex_unlock(&pvt->lock);
 	return;
 }
 
-int progress(unsigned call_reference, const char *token, int inband)
+static int progress(unsigned call_reference, const char *token, int inband)
 {
 	struct oh323_pvt *pvt;
 
-	ast_log(LOG_DEBUG, "Received ALERT/PROGRESS message for %s tones\n", (inband ? "inband" : "self-generated"));
+	if (h323debug)
+		ast_log(LOG_DEBUG, "Received ALERT/PROGRESS message for %s tones\n", (inband ? "inband" : "self-generated"));
 
 	pvt = find_call_locked(call_reference, token);
 	if (!pvt) {
@@ -1323,8 +2056,7 @@ int progress(unsigned call_reference, const char *token, int inband)
 		ast_log(LOG_ERROR, "No Asterisk channel associated with private structure.\n");
 		return -1;
 	}
-	if (update_state(pvt, -1, (inband ? AST_CONTROL_PROGRESS : AST_CONTROL_RINGING)))
-		ast_mutex_unlock(&pvt->owner->lock);
+	update_state(pvt, -1, (inband ? AST_CONTROL_PROGRESS : AST_CONTROL_RINGING));
 	ast_mutex_unlock(&pvt->lock);
 
 	return 0;
@@ -1335,12 +2067,11 @@ int progress(unsigned call_reference, const char *token, int inband)
  *
  *  Returns 1 on success
  */
-call_options_t *setup_incoming_call(call_details_t *cd)
+static call_options_t *setup_incoming_call(call_details_t *cd)
 {
 	struct oh323_pvt *pvt;
 	struct oh323_user *user = NULL;
 	struct oh323_alias *alias = NULL;
-	char iabuf[INET_ADDRSTRLEN];
 
 	if (h323debug)
 		ast_log(LOG_DEBUG, "Setting up incoming call for %s\n", cd->call_token);
@@ -1350,63 +2081,74 @@ call_options_t *setup_incoming_call(call_details_t *cd)
 
 	if (!pvt) {
 		ast_log(LOG_ERROR, "Unable to allocate private structure, this is bad.\n");
+		cleanup_call_details(cd);
 		return NULL;
 	}
 
 	/* Populate the call details in the private structure */
 	memcpy(&pvt->cd, cd, sizeof(pvt->cd));
 	memcpy(&pvt->options, &global_options, sizeof(pvt->options));
+	pvt->jointcapability = pvt->options.capability;
 
 	if (h323debug) {
 		ast_verbose(VERBOSE_PREFIX_3 "Setting up Call\n");
-		ast_verbose(VERBOSE_PREFIX_3 "\tCall token:  [%s]\n", pvt->cd.call_token);
-		ast_verbose(VERBOSE_PREFIX_3 "\tCalling party name:  [%s]\n", pvt->cd.call_source_name);
-		ast_verbose(VERBOSE_PREFIX_3 "\tCalling party number:  [%s]\n", pvt->cd.call_source_e164);
-		ast_verbose(VERBOSE_PREFIX_3 "\tCalled party name:  [%s]\n", pvt->cd.call_dest_alias);
-		ast_verbose(VERBOSE_PREFIX_3 "\tCalled party number:  [%s]\n", pvt->cd.call_dest_e164);
+		ast_verbose(VERBOSE_PREFIX_3 " \tCall token:  [%s]\n", pvt->cd.call_token);
+		ast_verbose(VERBOSE_PREFIX_3 " \tCalling party name:  [%s]\n", pvt->cd.call_source_name);
+		ast_verbose(VERBOSE_PREFIX_3 " \tCalling party number:  [%s]\n", pvt->cd.call_source_e164);
+		ast_verbose(VERBOSE_PREFIX_3 " \tCalled party name:  [%s]\n", pvt->cd.call_dest_alias);
+		ast_verbose(VERBOSE_PREFIX_3 " \tCalled party number:  [%s]\n", pvt->cd.call_dest_e164);
+		if (pvt->cd.redirect_reason >= 0)
+			ast_verbose(VERBOSE_PREFIX_3 " \tRedirecting party number:  [%s] (reason %d)\n", pvt->cd.redirect_number, pvt->cd.redirect_reason);
+		ast_verbose(VERBOSE_PREFIX_3 " \tCalling party IP:  [%s]\n", pvt->cd.sourceIp);
 	}
 
 	/* Decide if we are allowing Gatekeeper routed calls*/
-	if ((!strcasecmp(cd->sourceIp, gatekeeper)) && (gkroute == -1) && (usingGk)) {
+	if ((!strcasecmp(cd->sourceIp, gatekeeper)) && (gkroute == -1) && !gatekeeper_disable) {
 		if (!ast_strlen_zero(cd->call_dest_e164)) {
 			strncpy(pvt->exten, cd->call_dest_e164, sizeof(pvt->exten) - 1);
-			strncpy(pvt->context, default_context, sizeof(pvt->context) - 1); 
+			strncpy(pvt->context, default_context, sizeof(pvt->context) - 1);
 		} else {
-			alias = find_alias(cd->call_dest_alias);
+			alias = find_alias(cd->call_dest_alias, 1);
 			if (!alias) {
 				ast_log(LOG_ERROR, "Call for %s rejected, alias not found\n", cd->call_dest_alias);
+				oh323_destroy(pvt);
 				return NULL;
 			}
 			strncpy(pvt->exten, alias->name, sizeof(pvt->exten) - 1);
 			strncpy(pvt->context, alias->context, sizeof(pvt->context) - 1);
 		}
 	} else {
-		/* Either this call is not from the Gatekeeper 
+		/* Either this call is not from the Gatekeeper
 		   or we are not allowing gk routed calls */
-		user  = find_user(cd);
+		user = find_user(cd, 1);
 		if (!user) {
-			if (!ast_strlen_zero(pvt->cd.call_dest_e164)) {
-				strncpy(pvt->exten, cd->call_dest_e164, sizeof(pvt->exten) - 1);
-			} else {
-				strncpy(pvt->exten, cd->call_dest_alias, sizeof(pvt->exten) - 1);
+			if (!acceptAnonymous) {
+				ast_log(LOG_NOTICE, "Anonymous call from '%s@%s' rejected\n", pvt->cd.call_source_aliases, pvt->cd.sourceIp);
+				oh323_destroy(pvt);
+				return NULL;
 			}
 			if (ast_strlen_zero(default_context)) {
-				ast_log(LOG_ERROR, "Call from '%s' rejected due to no default context\n", pvt->cd.call_source_aliases);
+				ast_log(LOG_ERROR, "Call from '%s@%s' rejected due to no default context\n", pvt->cd.call_source_aliases, pvt->cd.sourceIp);
+				oh323_destroy(pvt);
 				return NULL;
 			}
 			strncpy(pvt->context, default_context, sizeof(pvt->context) - 1);
-			ast_log(LOG_DEBUG, "Sending %s to context [%s]\n", cd->call_source_aliases, pvt->context);
-			/* XXX: Is it really required??? */
-#if 0
-			memset(&pvt->options, 0, sizeof(pvt->options));
-#endif
+			if (!ast_strlen_zero(pvt->cd.call_dest_e164)) {
+				strncpy(pvt->exten, cd->call_dest_e164, sizeof(pvt->exten) - 1);
+			} else {
+				strncpy(pvt->exten, cd->call_dest_alias, sizeof(pvt->exten) - 1);
+			}
+			if (h323debug)
+				ast_log(LOG_DEBUG, "Sending %s@%s to context [%s] extension %s\n", cd->call_source_aliases, cd->sourceIp, pvt->context, pvt->exten);
 		} else {
 			if (user->host) {
-				if (strcasecmp(cd->sourceIp, ast_inet_ntoa(iabuf, sizeof(iabuf), user->addr.sin_addr))) {
+				if (strcasecmp(cd->sourceIp, ast_inet_ntoa(user->addr.sin_addr))) {
 					if (ast_strlen_zero(user->context)) {
 						if (ast_strlen_zero(default_context)) {
 							ast_log(LOG_ERROR, "Call from '%s' rejected due to non-matching IP address (%s) and no default context\n", user->name, cd->sourceIp);
-                					return NULL;
+							oh323_destroy(pvt);
+							ASTOBJ_UNREF(user, oh323_destroy_user);
+							return NULL;
 						}
 						strncpy(pvt->context, default_context, sizeof(pvt->context) - 1);
 					} else {
@@ -1415,11 +2157,14 @@ call_options_t *setup_incoming_call(call_details_t *cd)
 					pvt->exten[0] = 'i';
 					pvt->exten[1] = '\0';
 					ast_log(LOG_ERROR, "Call from '%s' rejected due to non-matching IP address (%s)s\n", user->name, cd->sourceIp);
+					oh323_destroy(pvt);
+					ASTOBJ_UNREF(user, oh323_destroy_user);
 					return NULL;	/* XXX: Hmmm... Why to setup context if we drop connection immediately??? */
 				}
 			}
 			strncpy(pvt->context, user->context, sizeof(pvt->context) - 1);
 			memcpy(&pvt->options, &user->options, sizeof(pvt->options));
+			pvt->jointcapability = pvt->options.capability;
 			if (!ast_strlen_zero(pvt->cd.call_dest_e164)) {
 				strncpy(pvt->exten, cd->call_dest_e164, sizeof(pvt->exten) - 1);
 			} else {
@@ -1427,11 +2172,12 @@ call_options_t *setup_incoming_call(call_details_t *cd)
 			}
 			if (!ast_strlen_zero(user->accountcode)) {
 				strncpy(pvt->accountcode, user->accountcode, sizeof(pvt->accountcode) - 1);
-			} 
+			}
 			if (user->amaflags) {
 				pvt->amaflags = user->amaflags;
-			} 
-		} 
+			}
+			ASTOBJ_UNREF(user, oh323_destroy_user);
+		}
 	}
 	return &pvt->options;
 }
@@ -1445,16 +2191,64 @@ static int answer_call(unsigned call_reference, const char *token)
 {
 	struct oh323_pvt *pvt;
 	struct ast_channel *c = NULL;
+	enum {ext_original, ext_s, ext_i, ext_notexists} try_exten;
+	char tmp_exten[sizeof(pvt->exten)];
 
 	if (h323debug)
 		ast_log(LOG_DEBUG, "Preparing Asterisk to answer for %s\n", token);
 
 	/* Find the call or allocate a private structure if call not found */
-	pvt = find_call_locked(call_reference, token); 
+	pvt = find_call_locked(call_reference, token);
 	if (!pvt) {
 		ast_log(LOG_ERROR, "Something is wrong: answer_call\n");
 		return 0;
 	}
+	/* Check if requested extension@context pair exists in the dialplan */
+	strncpy(tmp_exten, pvt->exten, sizeof(tmp_exten));
+
+	/* Try to find best extension in specified context */
+	if ((tmp_exten[0] != '\0') && (tmp_exten[1] == '\0')) {
+		if (tmp_exten[0] == 's')
+			try_exten = ext_s;
+		else if (tmp_exten[0] == 'i')
+			try_exten = ext_i;
+		else
+			try_exten = ext_original;
+	} else
+		try_exten = ext_original;
+	do {
+		if (ast_exists_extension(NULL, pvt->context, tmp_exten, 1, NULL))
+			break;
+		switch (try_exten) {
+		case ext_original:
+			tmp_exten[0] = 's';
+			tmp_exten[1] = '\0';
+			try_exten = ext_s;
+			break;
+		case ext_s:
+			tmp_exten[0] = 'i';
+			try_exten = ext_i;
+			break;
+		case ext_i:
+			try_exten = ext_notexists;
+			break;
+		default:
+			break;
+		}
+	} while (try_exten != ext_notexists);
+
+	/* Drop the call if we don't have <exten>, s and i extensions */
+	if (try_exten == ext_notexists) {
+		ast_log(LOG_NOTICE, "Dropping call because extensions '%s', 's' and 'i' doesn't exists in context [%s]\n", pvt->exten, pvt->context);
+		ast_mutex_unlock(&pvt->lock);
+		h323_clear_call(token, AST_CAUSE_UNALLOCATED);
+		return 0;
+	} else if ((try_exten != ext_original) && (strcmp(pvt->exten, tmp_exten) != 0)) {
+		if (h323debug)
+			ast_log(LOG_DEBUG, "Going to extension %s@%s because %s@%s isn't exists\n", tmp_exten, pvt->context, pvt->exten, pvt->context);
+		strncpy(pvt->exten, tmp_exten, sizeof(pvt->exten));
+	}
+
 	/* allocate a channel and tell asterisk about it */
 	c = __oh323_new(pvt, AST_STATE_RINGING, pvt->cd.call_token);
 
@@ -1469,10 +2263,10 @@ static int answer_call(unsigned call_reference, const char *token)
 
 /**
  * Call-back function to establish an outgoing H.323 call
- * 
- * Returns 1 on success 
+ *
+ * Returns 1 on success
  */
-int setup_outgoing_call(call_details_t *cd)
+static int setup_outgoing_call(call_details_t *cd)
 {
 	/* Use argument here or free it immediately */
 	cleanup_call_details(cd);
@@ -1484,14 +2278,14 @@ int setup_outgoing_call(call_details_t *cd)
   *  Call-back function to signal asterisk that the channel is ringing
   *  Returns nothing
   */
-void chan_ringing(unsigned call_reference, const char *token)
+static void chan_ringing(unsigned call_reference, const char *token)
 {
 	struct oh323_pvt *pvt;
 
 	if (h323debug)
 		ast_log(LOG_DEBUG, "Ringing on %s\n", token);
 
-	pvt = find_call_locked(call_reference, token); 
+	pvt = find_call_locked(call_reference, token);
 	if (!pvt) {
 		ast_log(LOG_ERROR, "Something is wrong: ringing\n");
 		return;
@@ -1501,8 +2295,7 @@ void chan_ringing(unsigned call_reference, const char *token)
 		ast_log(LOG_ERROR, "Channel has no owner\n");
 		return;
 	}
-	if (update_state(pvt, AST_STATE_RINGING, AST_CONTROL_RINGING))
-		ast_mutex_unlock(&pvt->owner->lock);
+	update_state(pvt, AST_STATE_RINGING, AST_CONTROL_RINGING);
 	ast_mutex_unlock(&pvt->lock);
 	return;
 }
@@ -1512,19 +2305,20 @@ void chan_ringing(unsigned call_reference, const char *token)
   * Returns nothing,
   */
 static void cleanup_connection(unsigned call_reference, const char *call_token)
-{	
+{
 	struct oh323_pvt *pvt;
 
-	ast_log(LOG_DEBUG, "Cleaning connection to %s\n", call_token);
-	
+	if (h323debug)
+		ast_log(LOG_DEBUG, "Cleaning connection to %s\n", call_token);
+
 	while (1) {
-		pvt = find_call_locked(call_reference, call_token); 
+		pvt = find_call_locked(call_reference, call_token);
 		if (!pvt) {
 			if (h323debug)
 				ast_log(LOG_DEBUG, "No connection for %s\n", call_token);
 			return;
 		}
-		if (!pvt->owner || !ast_mutex_trylock(&pvt->owner->lock))
+		if (!pvt->owner || !ast_channel_trylock(pvt->owner))
 			break;
 #if 1
 #ifdef DEBUG_THREADS
@@ -1548,43 +2342,49 @@ static void cleanup_connection(unsigned call_reference, const char *call_token)
 	}
 	cleanup_call_details(&pvt->cd);
 	pvt->alreadygone = 1;
-	/* Send hangup */	
+	/* Send hangup */
 	if (pvt->owner) {
 		pvt->owner->_softhangup |= AST_SOFTHANGUP_DEV;
 		ast_queue_hangup(pvt->owner);
-		ast_mutex_unlock(&pvt->owner->lock);
+		ast_channel_unlock(pvt->owner);
 	}
 	ast_mutex_unlock(&pvt->lock);
 	if (h323debug)
 		ast_log(LOG_DEBUG, "Connection to %s cleaned\n", call_token);
-	return;	
+	return;
 }
 
 static void hangup_connection(unsigned int call_reference, const char *token, int cause)
 {
 	struct oh323_pvt *pvt;
 
-	ast_log(LOG_DEBUG, "Hanging up connection to %s with cause %d\n", token, cause);
-	
-	pvt = find_call_locked(call_reference, token); 
+	if (h323debug) {
+		ast_log(LOG_DEBUG, "Hanging up connection to %s with cause %d\n", token, cause);
+	}
+
+	pvt = find_call_locked(call_reference, token);
 	if (!pvt) {
+		if (h323debug) {
+			ast_log(LOG_DEBUG, "Connection to %s already cleared\n", token);
+		}
 		return;
 	}
-	if (pvt->owner && !ast_mutex_trylock(&pvt->owner->lock)) {
+	if (pvt->owner && !ast_channel_trylock(pvt->owner)) {
 		pvt->owner->_softhangup |= AST_SOFTHANGUP_DEV;
 		pvt->owner->hangupcause = pvt->hangupcause = cause;
 		ast_queue_hangup(pvt->owner);
-		ast_mutex_unlock(&pvt->owner->lock);
+		ast_channel_unlock(pvt->owner);
 	}
 	else {
 		pvt->needhangup = 1;
 		pvt->hangupcause = cause;
-		ast_log(LOG_DEBUG, "Hangup for %s is pending\n", token);
+		if (h323debug)
+			ast_log(LOG_DEBUG, "Hangup for %s is pending\n", token);
 	}
 	ast_mutex_unlock(&pvt->lock);
 }
 
-void set_dtmf_payload(unsigned call_reference, const char *token, int payload)
+static void set_dtmf_payload(unsigned call_reference, const char *token, int payload)
 {
 	struct oh323_pvt *pvt;
 
@@ -1596,17 +2396,34 @@ void set_dtmf_payload(unsigned call_reference, const char *token, int payload)
 		return;
 	}
 	if (pvt->rtp) {
-		ast_rtp_set_rtpmap_type(pvt->rtp, payload, "audio", "telephone-event");
+		ast_rtp_set_rtpmap_type(pvt->rtp, payload, "audio", "telephone-event", 0);
 	}
+	pvt->dtmf_pt = payload;
 	ast_mutex_unlock(&pvt->lock);
 	if (h323debug)
 		ast_log(LOG_DEBUG, "DTMF payload on %s set to %d\n", token, payload);
 }
 
+static void set_peer_capabilities(unsigned call_reference, const char *token, int capabilities)
+{
+	struct oh323_pvt *pvt;
+
+	if (h323debug)
+		ast_log(LOG_DEBUG, "Got remote capabilities from connection %s\n", token);
+
+	pvt = find_call_locked(call_reference, token);
+	if (!pvt)
+		return;
+	pvt->peercapability = capabilities;
+	pvt->jointcapability = pvt->options.capability & capabilities;
+	ast_mutex_unlock(&pvt->lock);
+}
+
 static void set_local_capabilities(unsigned call_reference, const char *token)
 {
 	struct oh323_pvt *pvt;
-	int capability, dtmfmode;
+	int capability, dtmfmode, pref_codec;
+	struct ast_codec_pref prefs;
 
 	if (h323debug)
 		ast_log(LOG_DEBUG, "Setting capabilities for connection %s\n", token);
@@ -1614,10 +2431,12 @@ static void set_local_capabilities(unsigned call_reference, const char *token)
 	pvt = find_call_locked(call_reference, token);
 	if (!pvt)
 		return;
-	capability = pvt->options.capability;
+	capability = (pvt->jointcapability) ? pvt->jointcapability : pvt->options.capability;
 	dtmfmode = pvt->options.dtmfmode;
+	prefs = pvt->options.prefs;
+	pref_codec = pvt->pref_codec;
 	ast_mutex_unlock(&pvt->lock);
-	h323_set_capabilities(token, capability, dtmfmode);
+	h323_set_capabilities(token, capability, dtmfmode, &prefs, pref_codec);
 
 	if (h323debug)
 		ast_log(LOG_DEBUG, "Capabilities for connection %s is set\n", token);
@@ -1628,7 +2447,7 @@ static void *do_monitor(void *data)
 	int res;
 	int reloading;
 	struct oh323_pvt *oh323 = NULL;
-	
+
 	for(;;) {
 		/* Check for a reload request */
 		ast_mutex_lock(&h323_reload_lock);
@@ -1643,15 +2462,32 @@ static void *do_monitor(void *data)
 		}
 		/* Check for interfaces needing to be killed */
 		ast_mutex_lock(&iflock);
-restartsearch:		
+#if 1
+		do {
+			for (oh323 = iflist; oh323; oh323 = oh323->next) {
+				if (!ast_mutex_trylock(&oh323->lock)) {
+					if (oh323->needdestroy) {
+						__oh323_destroy(oh323);
+						break;
+					}
+					ast_mutex_unlock(&oh323->lock);
+				}
+			}
+		} while (/*oh323*/ 0);
+#else
+restartsearch:
 		oh323 = iflist;
 		while(oh323) {
-			if (oh323->needdestroy) {
-				__oh323_destroy(oh323);
-				goto restartsearch;
+			if (!ast_mutex_trylock(&oh323->lock)) {
+				if (oh323->needdestroy) {
+					__oh323_destroy(oh323);
+					goto restartsearch;
+				}
+				ast_mutex_unlock(&oh323->lock);
+				oh323 = oh323->next;
 			}
-			oh323 = oh323->next;
 		}
+#endif
 		ast_mutex_unlock(&iflock);
 		pthread_testcancel();
 		/* Wait for sched or io */
@@ -1659,6 +2495,9 @@ restartsearch:
 		if ((res < 0) || (res > 1000)) {
 			res = 1000;
 		}
+		/* Do not wait if some channel(s) is destroyed, probably, more available too */
+		if (oh323)
+			res = 1;
 		res = ast_io_wait(io, res);
 		pthread_testcancel();
 		ast_mutex_lock(&monlock);
@@ -1675,13 +2514,14 @@ static int restart_monitor(void)
 {
 	pthread_attr_t attr;
 	/* If we're supposed to be stopped -- stay stopped */
-	if (monitor_thread == AST_PTHREADT_STOP) {
-		return 0;
-	}
 	if (ast_mutex_lock(&monlock)) {
 		ast_log(LOG_WARNING, "Unable to lock monitor\n");
 		return -1;
 	}
+	if (monitor_thread == AST_PTHREADT_STOP) {
+		ast_mutex_unlock(&monlock);
+		return 0;
+	}
 	if (monitor_thread == pthread_self()) {
 		ast_mutex_unlock(&monlock);
 		ast_log(LOG_WARNING, "Cannot kill myself\n");
@@ -1690,16 +2530,16 @@ static int restart_monitor(void)
 	if (monitor_thread && (monitor_thread != AST_PTHREADT_NULL)) {
 		/* Wake up the thread */
 		pthread_kill(monitor_thread, SIGURG);
-	} else {	
-	 	pthread_attr_init(&attr);
-                pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
-                /* Start a new monitor */
-                if (ast_pthread_create(&monitor_thread, &attr, do_monitor, NULL) < 0) {
-                        ast_mutex_unlock(&monlock);
-                        ast_log(LOG_ERROR, "Unable to start monitor thread.\n");
-                        return -1;
-                }
-
+	} else {
+		pthread_attr_init(&attr);
+		pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+		/* Start a new monitor */
+		if (ast_pthread_create(&monitor_thread, &attr, do_monitor, NULL) < 0) {
+			monitor_thread = AST_PTHREADT_NULL;
+			ast_mutex_unlock(&monlock);
+			ast_log(LOG_ERROR, "Unable to start monitor thread.\n");
+			return -1;
+		}
 	}
 	ast_mutex_unlock(&monlock);
 	return 0;
@@ -1731,7 +2571,7 @@ static int h323_do_debug(int fd, int argc, char *argv[])
 		return RESULT_SHOWUSAGE;
 	}
 	h323debug = 1;
-	ast_cli(fd, "H323 debug enabled\n");
+	ast_cli(fd, "H.323 debug enabled\n");
 	return RESULT_SUCCESS;
 }
 
@@ -1741,36 +2581,34 @@ static int h323_no_debug(int fd, int argc, char *argv[])
 		return RESULT_SHOWUSAGE;
 	}
 	h323debug = 0;
-	ast_cli(fd, "H323 Debug disabled\n");
+	ast_cli(fd, "H.323 debug disabled\n");
 	return RESULT_SUCCESS;
 }
 
 static int h323_gk_cycle(int fd, int argc, char *argv[])
 {
-#if 0
 	if (argc != 3) {
 		return RESULT_SHOWUSAGE;
-	}	
+	}
 	h323_gk_urq();
-	
+
 	/* Possibly register with a GK */
 	if (!gatekeeper_disable) {
 		if (h323_set_gk(gatekeeper_discover, gatekeeper, secret)) {
 			ast_log(LOG_ERROR, "Gatekeeper registration failed.\n");
 		}
 	}
-#endif
 	return RESULT_SUCCESS;
 }
 
 static int h323_ep_hangup(int fd, int argc, char *argv[])
 {
-        if (argc != 3) {
-                return RESULT_SHOWUSAGE;
+	if (argc != 3) {
+		return RESULT_SHOWUSAGE;
 	}
 	if (h323_soft_hangup(argv[2])) {
 		ast_verbose(VERBOSE_PREFIX_3 "Hangup succeeded on %s\n", argv[2]);
-	} else { 
+	} else {
 		ast_verbose(VERBOSE_PREFIX_3 "Hangup failed for %s\n", argv[2]);
 	}
 	return RESULT_SUCCESS;
@@ -1778,50 +2616,46 @@ static int h323_ep_hangup(int fd, int argc, char *argv[])
 
 static int h323_tokens_show(int fd, int argc, char *argv[])
 {
-        if (argc != 3) {
-                return RESULT_SHOWUSAGE;
+	if (argc != 3) {
+		return RESULT_SHOWUSAGE;
 	}
 	h323_show_tokens();
 	return RESULT_SUCCESS;
 }
 
-static char trace_usage[] = 
+static char trace_usage[] =
 "Usage: h.323 trace <level num>\n"
 "       Enables H.323 stack tracing for debugging purposes\n";
 
-static char no_trace_usage[] = 
+static char no_trace_usage[] =
 "Usage: h.323 no trace\n"
 "       Disables H.323 stack tracing for debugging purposes\n";
 
-static char debug_usage[] = 
+static char debug_usage[] =
 "Usage: h.323 debug\n"
 "       Enables H.323 debug output\n";
 
-static char no_debug_usage[] = 
+static char no_debug_usage[] =
 "Usage: h.323 no debug\n"
 "       Disables H.323 debug output\n";
 
-static char show_codec_usage[] = 
-"Usage: h.323 show codec\n"
-"       Shows all enabled codecs\n";
-
-static char show_cycle_usage[] = 
+static char show_cycle_usage[] =
 "Usage: h.323 gk cycle\n"
 "       Manually re-register with the Gatekeper (Currently Disabled)\n";
 
-static char show_hangup_usage[] = 
+static char show_hangup_usage[] =
 "Usage: h.323 hangup <token>\n"
 "       Manually try to hang up call identified by <token>\n";
 
-static char show_tokens_usage[] = 
+static char show_tokens_usage[] =
 "Usage: h.323 show tokens\n"
 "       Print out all active call tokens\n";
 
 static char h323_reload_usage[] =
 "Usage: h323 reload\n"
-"       Reloads H.323 configuration from sip.conf\n";
+"       Reloads H.323 configuration from h323.conf\n";
 
-static struct ast_cli_entry  cli_h323[] = {
+static struct ast_cli_entry cli_h323[] = {
 	{ { "h.323", "trace", NULL },
 	h323_do_trace, "Enable H.323 Stack Tracing",
 	trace_usage },
@@ -1838,10 +2672,6 @@ static struct ast_cli_entry  cli_h323[] = {
 	h323_no_debug, "Disable H.323 debug",
 	no_debug_usage },
 
-	{ { "h.323", "show", "codecs", NULL },
-	h323_show_codec, "Show enabled codecs",
-	show_codec_usage },
-
 	{ { "h.323", "gk", "cycle", NULL },
 	h323_gk_cycle, "Manually re-register with the Gatekeper",
 	show_cycle_usage },
@@ -1853,232 +2683,23 @@ static struct ast_cli_entry  cli_h323[] = {
 	{ { "h.323", "show", "tokens", NULL },
 	h323_tokens_show, "Show all active call tokens",
 	show_tokens_usage },
-
-	{ { "h.323", "reload", NULL },
-	h323_reload, "Reload H.323 configuration",
-	h323_reload_usage },
 };
 
-static int update_common_options(struct ast_variable *v, struct call_options *options)
-{
-	unsigned int format;
-	int tmp;
-
-	if (!strcasecmp(v->name, "allow")) {
-		format = ast_getformatbyname(v->value);
-		if (format < 1) 
-			ast_log(LOG_WARNING, "Cannot allow unknown format '%s'\n", v->value);
-		else
-			options->capability |= format;
-	} else if (!strcasecmp(v->name, "disallow")) {
-		format = ast_getformatbyname(v->value);
-		if (format < 1) 
-			ast_log(LOG_WARNING, "Cannot disallow unknown format '%s'\n", v->value);
-		else
-			options->capability &= ~format;
-	} else if (!strcasecmp(v->name, "dtmfmode")) {
-		if (!strcasecmp(v->value, "inband")) {
-			options->dtmfmode = H323_DTMF_INBAND;
-		} else if (!strcasecmp(v->value, "rfc2833")) {
-			options->dtmfmode = H323_DTMF_RFC2833;
-		} else {
-			ast_log(LOG_WARNING, "Unknown dtmf mode '%s', using rfc2833\n", v->value);
-			options->dtmfmode = H323_DTMF_RFC2833;
-		}
-	} else if (!strcasecmp(v->name, "dtmfcodec")) {
-		tmp = atoi(v->value);
-		if (tmp < 96)
-			ast_log(LOG_WARNING, "Invalid global dtmfcodec value %s\n", v->value);
-		else
-			options->dtmfcodec = tmp;
-	} else if (!strcasecmp(v->name, "bridge")) {
-		options->bridge = ast_true(v->value);
-	} else if (!strcasecmp(v->name, "nat")) {
-		options->nat = ast_true(v->value);
-	} else if (!strcasecmp(v->name, "noFastStart")) {
-		options->noFastStart = ast_true(v->value);
-	} else if (!strcasecmp(v->name, "noH245Tunneling")) {
-		options->noH245Tunneling = ast_true(v->value);
-	} else if (!strcasecmp(v->name, "noSilenceSuppression")) {
-		options->noSilenceSuppression = ast_true(v->value);
-	} else if (!strcasecmp(v->name, "progress_setup")) {
-		tmp = atoi(v->value);
-		if ((tmp != 0) && (tmp != 1) && (tmp != 3) && (tmp != 8)) {
-			ast_log(LOG_WARNING, "Invalid value %d for progress_setup at line %d, assuming 0\n", tmp, v->lineno);
-			tmp = 0;
-		}
-		options->progress_setup = tmp;
-	} else if (!strcasecmp(v->name, "progress_alert")) {
-		tmp = atoi(v->value);
-		if ((tmp != 0) && (tmp != 8)) {
-			ast_log(LOG_WARNING, "Invalud value %d for progress_alert at line %d, assuming 0\n", tmp, v->lineno);
-			tmp = 0;
-		}
-		options->progress_alert = tmp;
-	} else if (!strcasecmp(v->name, "progress_audio")) {
-		options->progress_audio = ast_true(v->value);
-	} else
-		return 1;
-
-	return 0;
-}
-
-static struct oh323_alias *build_alias(char *name, struct ast_variable *v)
+static int reload_config(int is_reload)
 {
-	struct oh323_alias *alias;
-
-	alias = (struct oh323_alias *)malloc(sizeof(struct oh323_alias));
-	if (alias) {
-		memset(alias, 0, sizeof(struct oh323_alias));
-		strncpy(alias->name, name, sizeof(alias->name) - 1);
-		while (v) {
-			if (!strcasecmp(v->name, "e164")) {
-				strncpy(alias->e164,  v->value, sizeof(alias->e164) - 1);
-			} else if (!strcasecmp(v->name, "prefix")) {
-				strncpy(alias->prefix,  v->value, sizeof(alias->prefix) - 1);
-			} else if (!strcasecmp(v->name, "context")) {
-				strncpy(alias->context,  v->value, sizeof(alias->context) - 1);
-			} else if (!strcasecmp(v->name, "secret")) {
-				strncpy(alias->secret,  v->value, sizeof(alias->secret) - 1);
-			} else {
-				if (strcasecmp(v->value, "h323")) { 	
-					ast_log(LOG_WARNING, "Keyword %s does not make sense in type=h323\n", v->value);
-				}
-			}
-			v = v->next;
-		}
-	}
-	return alias;
-}
-
-static struct oh323_user *build_user(char *name, struct ast_variable *v)
-{
-	struct oh323_user *user;
-	int format;
-
-	user = (struct oh323_user *)malloc(sizeof(struct oh323_user));
-	if (user) {
-		memset(user, 0, sizeof(struct oh323_user));
-		strncpy(user->name, name, sizeof(user->name) - 1);
-		memcpy(&user->options, &global_options, sizeof(user->options));
-		/* Set default context */
-		strncpy(user->context, default_context, sizeof(user->context) - 1);
-		while(v) {
-			if (!strcasecmp(v->name, "context")) {
-				strncpy(user->context, v->value, sizeof(user->context) - 1);
-			} else if (!update_common_options(v, &user->options)) {
-				/* dummy */
-			} else if (!strcasecmp(v->name, "secret")) {
-				strncpy(user->secret, v->value, sizeof(user->secret) - 1);
-			} else if (!strcasecmp(v->name, "callerid")) {
-				strncpy(user->callerid, v->value, sizeof(user->callerid) - 1);
-			} else if (!strcasecmp(v->name, "accountcode")) {
-				strncpy(user->accountcode, v->value, sizeof(user->accountcode) - 1);
-			} else if (!strcasecmp(v->name, "host")) {
-				if (!strcasecmp(v->value, "dynamic")) {
-					ast_log(LOG_ERROR, "A dynamic host on a type=user does not make any sense\n");
-					free(user);
-					return NULL;
-				} else if (ast_get_ip(&user->addr, v->value)) {
-					free(user);
-					return NULL;
-				} 
-				/* Let us know we need to use ip authentication */
-				user->host = 1;
-			} else if (!strcasecmp(v->name, "amaflags")) {
-				format = ast_cdr_amaflags2int(v->value);
-				if (format < 0) {
-					ast_log(LOG_WARNING, "Invalid AMA Flags: %s at line %d\n", v->value, v->lineno);
-				} else {
-					user->amaflags = format;
-				}
-			}
-			v = v->next;
-		}
-	}
-	return user;
-}
-
-static struct oh323_peer *build_peer(char *name, struct ast_variable *v)
-{
-	struct oh323_peer *peer;
-	struct oh323_peer *prev;
-	struct ast_ha *oldha = NULL;
-	int found=0;
-
-	prev = NULL;
-	ast_mutex_lock(&peerl.lock);
-	peer = peerl.peers;
-
-	while(peer) {
-		if (!strcasecmp(peer->name, name)) {	
-			break;
-		}
-		prev = peer;
-		peer = peer->next;
-	}
-
-	if (peer) {
-		found++;
-		/* Already in the list, remove it and it will be added back (or FREE'd) */
-		if (prev) {
-			prev->next = peer->next;
-		} else {
-			peerl.peers = peer->next;
-		}
-		ast_mutex_unlock(&peerl.lock);
-	} else {
-		ast_mutex_unlock(&peerl.lock);
-		peer = (struct oh323_peer*)malloc(sizeof(struct oh323_peer));
-		if (peer)
-			memset(peer, 0, sizeof(struct oh323_peer));
-	}
-	if (peer) {
-		if (!found) {
-			strncpy(peer->name, name, sizeof(peer->name) - 1);
-			peer->addr.sin_port = htons(h323_signalling_port);
-			peer->addr.sin_family = AF_INET;
-		}
-		oldha = peer->ha;
-		peer->ha = NULL;
-		peer->addr.sin_family = AF_INET;
-		memcpy(&peer->options, &global_options, sizeof(peer->options));
-
-		while(v) {
-			if (!update_common_options(v, &peer->options)) {
-				/* dummy */
-			} else if (!strcasecmp(v->name, "host")) {
-				if (!strcasecmp(v->value, "dynamic")) {
-					ast_log(LOG_ERROR, "Dynamic host configuration not implemented.\n");
-					free(peer);
-					return NULL;
-				}
-				if (ast_get_ip(&peer->addr, v->value)) {
-						ast_log(LOG_ERROR, "Could not determine IP for %s\n", v->value);
-						free(peer);
-						return NULL;
-				}
-			} else if (!strcasecmp(v->name, "port")) {
-				peer->addr.sin_port = htons(atoi(v->value));
-			}
-			v=v->next;
-		}
-	}
-	return peer;
-}
-
-int reload_config(void)
-{	
 	int format;
-	struct ast_config *cfg;
+	struct ast_config *cfg, *ucfg;
 	struct ast_variable *v;
-	struct oh323_peer *peer   = NULL;
-	struct oh323_user *user   = NULL;
+	struct oh323_peer *peer = NULL;
+	struct oh323_user *user = NULL;
 	struct oh323_alias *alias = NULL;
 	struct ast_hostent ahp; struct hostent *hp;
 	char *cat;
-    	char *utype;
-	
+	char *utype;
+	int is_user, is_peer, is_alias;
+	char _gatekeeper[100];
+	int gk_discover, gk_disable, gk_changed;
+
 	cfg = ast_config_load(config);
 
 	/* We *must* have a config file otherwise stop immediately */
@@ -2086,30 +2707,62 @@ int reload_config(void)
 		ast_log(LOG_NOTICE, "Unable to load config %s, H.323 disabled\n", config);
 		return 1;
 	}
-	
-       /* fire up the H.323 Endpoint */       
+
+	/* fire up the H.323 Endpoint */
 	if (!h323_end_point_exist()) {
-	       h323_end_point_create();        
+		h323_end_point_create();
 	}
-	h323debug = 0;
+	strncpy(_gatekeeper, gatekeeper, sizeof(_gatekeeper));
+	gk_discover = gatekeeper_discover;
+	gk_disable = gatekeeper_disable;
 	memset(&bindaddr, 0, sizeof(bindaddr));
 	memset(&global_options, 0, sizeof(global_options));
+	global_options.fastStart = 1;
+	global_options.h245Tunneling = 1;
 	global_options.dtmfcodec = 101;
 	global_options.dtmfmode = H323_DTMF_RFC2833;
 	global_options.capability = GLOBAL_CAPABILITY;
 	global_options.bridge = 1;		/* Do native bridging by default */
+	strncpy(default_context, "default", sizeof(default_context) - 1);
+	h323_signalling_port = 1720;
+	gatekeeper_disable = 1;
+	gatekeeper_discover = 0;
+	gkroute = 0;
+	userbyalias = 1;
+	acceptAnonymous = 1;
+	tos = 0;
 
 	/* Copy the default jb config over global_jbconf */
 	memcpy(&global_jbconf, &default_jbconf, sizeof(struct ast_jb_conf));
 
-	v = ast_variable_browse(cfg, "general");
-	while (v) {
-		/* handle jb conf */
-                if (!ast_jb_read_conf(&global_jbconf, v->name, v->value)) {
-			v = v->next;
-			continue;
+	/* Load configuration from users.conf */
+	ucfg = ast_config_load("users.conf");
+	if (ucfg) {
+		struct ast_variable *gen;
+		int genhas_h323;
+		char *has_h323;
+
+		genhas_h323 = ast_true(ast_variable_retrieve(ucfg, "general", "hash323"));
+		gen = ast_variable_browse(ucfg, "general");
+		for (cat = ast_category_browse(ucfg, NULL); cat; cat = ast_category_browse(ucfg, cat)) {
+			if (strcasecmp(cat, "general")) {
+				has_h323 = ast_variable_retrieve(ucfg, cat, "hash323");
+				if (ast_true(has_h323) || (!has_h323 && genhas_h323)) {
+					user = build_user(cat, gen, ast_variable_browse(ucfg, cat), 0);
+					if (user) {
+						ASTOBJ_CONTAINER_LINK(&userl, user);
+						ASTOBJ_UNREF(user, oh323_destroy_user);
+					}
+				}
+			}
 		}
+		ast_config_destroy(ucfg);
+	}
 
+	for (v = ast_variable_browse(cfg, "general"); v; v = v->next) {
+		/* handle jb conf */
+		if (!ast_jb_read_conf(&global_jbconf, v->name, v->value))
+			continue;
 		/* Create the interface list */
 		if (!strcasecmp(v->name, "port")) {
 			h323_signalling_port = (int)strtol(v->value, NULL, 10);
@@ -2138,14 +2791,11 @@ int reload_config(void)
 		} else if (!strcasecmp(v->name, "gatekeeper")) {
 			if (!strcasecmp(v->value, "DISABLE")) {
 				gatekeeper_disable = 1;
-				usingGk = 0;
 			} else if (!strcasecmp(v->value, "DISCOVER")) {
 				gatekeeper_disable = 0;
 				gatekeeper_discover = 1;
-				usingGk = 1;
 			} else {
 				gatekeeper_disable = 0;
-				usingGk = 1;
 				strncpy(gatekeeper, v->value, sizeof(gatekeeper) - 1);
 			}
 		} else if (!strcasecmp(v->name, "secret")) {
@@ -2154,141 +2804,143 @@ int reload_config(void)
 			gkroute = ast_true(v->value);
 		} else if (!strcasecmp(v->name, "context")) {
 			strncpy(default_context, v->value, sizeof(default_context) - 1);
-			ast_verbose(VERBOSE_PREFIX_2 "Setting default context to %s\n", default_context);	
+			ast_verbose(VERBOSE_PREFIX_2 "Setting default context to %s\n", default_context);
 		} else if (!strcasecmp(v->name, "UserByAlias")) {
 			userbyalias = ast_true(v->value);
+		} else if (!strcasecmp(v->name, "AcceptAnonymous")) {
+			acceptAnonymous = ast_true(v->value);
 		} else if (!update_common_options(v, &global_options)) {
 			/* dummy */
 		}
-		v = v->next;	
 	}
-	
-	cat = ast_category_browse(cfg, NULL);
-	while(cat) {
+
+	for (cat = ast_category_browse(cfg, NULL); cat; cat = ast_category_browse(cfg, cat)) {
 		if (strcasecmp(cat, "general")) {
 			utype = ast_variable_retrieve(cfg, cat, "type");
 			if (utype) {
-				if (!strcasecmp(utype, "user")) {
-					user = build_user(cat, ast_variable_browse(cfg, cat));
-					if (user) {
-						ast_mutex_lock(&userl.lock);
-						user->next = userl.users;
-						userl.users = user;
-						ast_mutex_unlock(&userl.lock);
-					}
-				}  else if (!strcasecmp(utype, "peer")) {
-					peer = build_peer(cat, ast_variable_browse(cfg, cat));
-					if (peer) {
-						ast_mutex_lock(&peerl.lock);
-						peer->next = peerl.peers;
-						peerl.peers = peer;
-						ast_mutex_unlock(&peerl.lock);
-					}
-				}  else if (!strcasecmp(utype, "friend")) {
-					user = build_user(cat, ast_variable_browse(cfg, cat));
-					peer = build_peer(cat, ast_variable_browse(cfg, cat));
+				is_user = is_peer = is_alias = 0;
+				if (!strcasecmp(utype, "user"))
+					is_user = 1;
+				else if (!strcasecmp(utype, "peer"))
+					is_peer = 1;
+				else if (!strcasecmp(utype, "friend"))
+					is_user = is_peer = 1;
+				else if (!strcasecmp(utype, "h323") || !strcasecmp(utype, "alias"))
+					is_alias = 1;
+				else {
+					ast_log(LOG_WARNING, "Unknown type '%s' for '%s' in %s\n", utype, cat, config);
+					continue;
+				}
+				if (is_user) {
+					user = build_user(cat, ast_variable_browse(cfg, cat), NULL, 0);
 					if (user) {
-						ast_mutex_lock(&userl.lock);
-						user->next = userl.users;
-						userl.users = user;
-						ast_mutex_unlock(&userl.lock);
+						ASTOBJ_CONTAINER_LINK(&userl, user);
+						ASTOBJ_UNREF(user, oh323_destroy_user);
 					}
+				}
+				if (is_peer) {
+					peer = build_peer(cat, ast_variable_browse(cfg, cat), NULL, 0);
 					if (peer) {
-						ast_mutex_lock(&peerl.lock);
-						peer->next = peerl.peers;
-						peerl.peers = peer;
-						ast_mutex_unlock(&peerl.lock);
+						ASTOBJ_CONTAINER_LINK(&peerl, peer);
+						ASTOBJ_UNREF(peer, oh323_destroy_peer);
 					}
-				}  else if (!strcasecmp(utype, "h323") || !strcasecmp(utype, "alias")) {
-					alias = build_alias(cat, ast_variable_browse(cfg, cat));
+				}
+				if (is_alias) {
+					alias = build_alias(cat, ast_variable_browse(cfg, cat), NULL, 0);
 					if (alias) {
-						ast_mutex_lock(&aliasl.lock);
-						alias->next = aliasl.aliases;
-						aliasl.aliases = alias;
-						ast_mutex_unlock(&aliasl.lock);
+						ASTOBJ_CONTAINER_LINK(&aliasl, alias);
+						ASTOBJ_UNREF(alias, oh323_destroy_alias);
 					}
-				} else {
-					ast_log(LOG_WARNING, "Unknown type '%s' for '%s' in %s\n", utype, cat, config);
 				}
 			} else {
 				ast_log(LOG_WARNING, "Section '%s' lacks type\n", cat);
 			}
 		}
-		cat = ast_category_browse(cfg, cat);
 	}
 	ast_config_destroy(cfg);
 
 	/* Register our H.323 aliases if any*/
-	while (alias) {		
-		if (h323_set_alias(alias)) {
+	ASTOBJ_CONTAINER_WRLOCK(&aliasl);
+	ASTOBJ_CONTAINER_TRAVERSE(&aliasl, 1, do {
+		ASTOBJ_RDLOCK(iterator);
+		if (h323_set_alias(iterator)) {
 			ast_log(LOG_ERROR, "Alias %s rejected by endpoint\n", alias->name);
-			return -1;
-		}	
-		alias = alias->next;
+			ASTOBJ_UNLOCK(iterator);
+			continue;
+		}
+		ASTOBJ_UNLOCK(iterator);
+	} while (0) );
+	ASTOBJ_CONTAINER_UNLOCK(&aliasl);
+
+	/* Don't touch GK if nothing changed because URQ will drop all existing calls */
+	gk_changed = 0;
+	if (gatekeeper_disable != gk_disable)
+		gk_changed = is_reload;
+	else if(!gatekeeper_disable && (gatekeeper_discover != gk_discover))
+		gk_changed = is_reload;
+	else if(!gatekeeper_disable && (strncmp(_gatekeeper, gatekeeper, sizeof(_gatekeeper)) != 0))
+		gk_changed = is_reload;
+	if (gk_changed) {
+		if(!gk_disable)
+			h323_gk_urq();
+		if (!gatekeeper_disable) {
+			if (h323_set_gk(gatekeeper_discover, gatekeeper, secret)) {
+				ast_log(LOG_ERROR, "Gatekeeper registration failed.\n");
+				gatekeeper_disable = 1;
+			}
+		}
 	}
-
 	return 0;
 }
 
-void delete_users(void)
+static void delete_users(void)
 {
-	struct oh323_user *user, *userlast;
-	struct oh323_peer *peer;
-	
-	/* Delete all users */
-	ast_mutex_lock(&userl.lock);
-	for (user=userl.users;user;) {
-		userlast = user;
-		user=user->next;
-		free(userlast);
-	}
-	userl.users=NULL;
-	ast_mutex_unlock(&userl.lock);
-	ast_mutex_lock(&peerl.lock);
-	for (peer=peerl.peers;peer;) {
-		/* Assume all will be deleted, and we'll find out for sure later */
-		peer->delme = 1;
-		peer = peer->next;
-	}
-	ast_mutex_unlock(&peerl.lock);
-}
+	int pruned = 0;
 
-void delete_aliases(void)
-{
-	struct oh323_alias *alias, *aliaslast;
-		
 	/* Delete all users */
-	ast_mutex_lock(&aliasl.lock);
-	for (alias=aliasl.aliases;alias;) {
-		aliaslast = alias;
-		alias=alias->next;
-		free(aliaslast);
+	ASTOBJ_CONTAINER_WRLOCK(&userl);
+	ASTOBJ_CONTAINER_TRAVERSE(&userl, 1, do {
+		ASTOBJ_RDLOCK(iterator);
+		ASTOBJ_MARK(iterator);
+		++pruned;
+		ASTOBJ_UNLOCK(iterator);
+	} while (0) );
+	if (pruned) {
+		ASTOBJ_CONTAINER_PRUNE_MARKED(&userl, oh323_destroy_user);
+	}
+	ASTOBJ_CONTAINER_UNLOCK(&userl);
+
+	ASTOBJ_CONTAINER_WRLOCK(&peerl);
+	ASTOBJ_CONTAINER_TRAVERSE(&peerl, 1, do {
+		ASTOBJ_RDLOCK(iterator);
+		ASTOBJ_MARK(iterator);
+		ASTOBJ_UNLOCK(iterator);
+	} while (0) );
+	ASTOBJ_CONTAINER_UNLOCK(&peerl);
+}
+
+static void delete_aliases(void)
+{
+	int pruned = 0;
+
+	/* Delete all aliases */
+	ASTOBJ_CONTAINER_WRLOCK(&aliasl);
+	ASTOBJ_CONTAINER_TRAVERSE(&aliasl, 1, do {
+		ASTOBJ_RDLOCK(iterator);
+		ASTOBJ_MARK(iterator);
+		++pruned;
+		ASTOBJ_UNLOCK(iterator);
+	} while (0) );
+	if (pruned) {
+		ASTOBJ_CONTAINER_PRUNE_MARKED(&aliasl, oh323_destroy_alias);
 	}
-	aliasl.aliases=NULL;
-	ast_mutex_unlock(&aliasl.lock);
+	ASTOBJ_CONTAINER_UNLOCK(&aliasl);
 }
 
-void prune_peers(void)
+static void prune_peers(void)
 {
 	/* Prune peers who still are supposed to be deleted */
-	struct oh323_peer *peer, *peerlast, *peernext;
-	ast_mutex_lock(&peerl.lock);
-	peerlast = NULL;
-	for (peer=peerl.peers;peer;) {
-		peernext = peer->next;
-		if (peer->delme) {
-			free(peer);
-			if (peerlast) {
-				peerlast->next = peernext;
-			} else {
-				peerl.peers = peernext;
-			}
-		} else {
-			peerlast = peer;
-		}
-		peer = peernext;
-	}
-	ast_mutex_unlock(&peerl.lock);
+	ASTOBJ_CONTAINER_PRUNE_MARKED(&peerl, oh323_destroy_peer);
 }
 
 static int h323_reload(int fd, int argc, char *argv[])
@@ -2309,29 +2961,42 @@ static int h323_do_reload(void)
 	delete_users();
 	delete_aliases();
 	prune_peers();
-	reload_config();
-	restart_monitor();
+	reload_config(1);
 	return 0;
 }
 
-static int reload(void *mod)
+static int reload(void)
 {
 	return h323_reload(0, 0, NULL);
 }
 
-static struct ast_rtp *oh323_get_rtp_peer(struct ast_channel *chan)
+static struct ast_cli_entry cli_h323_reload =
+	{ { "h.323", "reload", NULL },
+	h323_reload, "Reload H.323 configuration",
+	h323_reload_usage
+};
+
+static enum ast_rtp_get_result oh323_get_rtp_peer(struct ast_channel *chan, struct ast_rtp **rtp)
 {
 	struct oh323_pvt *pvt;
-	pvt = (struct oh323_pvt *) chan->tech_pvt;
-	if (pvt && pvt->rtp && pvt->options.bridge) {
-		return pvt->rtp;
+	enum ast_rtp_get_result res = AST_RTP_GET_FAILED;
+
+	if (!(pvt = (struct oh323_pvt *)chan->tech_pvt))
+		return res;
+
+	ast_mutex_lock(&pvt->lock);
+	if (pvt->rtp && pvt->options.bridge) {
+		*rtp = pvt->rtp;
+		res = AST_RTP_TRY_NATIVE;
 	}
-	return NULL;
+	ast_mutex_unlock(&pvt->lock);
+
+	return res;
 }
 
-static struct ast_rtp *oh323_get_vrtp_peer(struct ast_channel *chan)
+static enum ast_rtp_get_result oh323_get_vrtp_peer(struct ast_channel *chan, struct ast_rtp **rtp)
 {
-	return NULL;
+	return AST_RTP_GET_FAILED;
 }
 
 static char *convertcap(int cap)
@@ -2366,21 +3031,22 @@ static int oh323_set_rtp_peer(struct ast_channel *chan, struct ast_rtp *rtp, str
 	struct sockaddr_in them;
 	struct sockaddr_in us;
 	char *mode;
-	char iabuf[INET_ADDRSTRLEN];
 
 	if (!rtp) {
 		return 0;
 	}
 
-	mode = convertcap(chan->writeformat); 
+	mode = convertcap(chan->writeformat);
 	pvt = (struct oh323_pvt *) chan->tech_pvt;
 	if (!pvt) {
 		ast_log(LOG_ERROR, "No Private Structure, this is bad\n");
 		return -1;
 	}
-	ast_rtp_get_peer(rtp, &them);	
+	ast_rtp_get_peer(rtp, &them);
 	ast_rtp_get_us(rtp, &us);
-	h323_native_bridge(pvt->cd.call_token, ast_inet_ntoa(iabuf, sizeof(iabuf), them.sin_addr), mode);
+#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;
 }
 
@@ -2388,61 +3054,93 @@ static struct ast_rtp_protocol oh323_rtp = {
 	.type = "H323",
 	.get_rtp_info = oh323_get_rtp_peer,
 	.get_vrtp_info = oh323_get_vrtp_peer,
-	.set_rtp_peer=  oh323_set_rtp_peer,
+	.set_rtp_peer = oh323_set_rtp_peer,
 };
 
-static int load_module(void *mod)
+static enum ast_module_load_result load_module(void)
 {
 	int res;
-	ast_mutex_init(&userl.lock);
-	ast_mutex_init(&peerl.lock);
-	ast_mutex_init(&aliasl.lock);
+
+	h323debug = 0;
 	sched = sched_context_create();
 	if (!sched) {
 		ast_log(LOG_WARNING, "Unable to create schedule context\n");
+		return AST_MODULE_LOAD_FAILURE;
 	}
 	io = io_context_create();
 	if (!io) {
 		ast_log(LOG_WARNING, "Unable to create I/O context\n");
+		return AST_MODULE_LOAD_FAILURE;
 	}
-	res = reload_config();
+	ast_cli_register(&cli_h323_reload);
+	ASTOBJ_CONTAINER_INIT(&userl);
+	ASTOBJ_CONTAINER_INIT(&peerl);
+	ASTOBJ_CONTAINER_INIT(&aliasl);
+	res = reload_config(0);
 	if (res) {
 		return AST_MODULE_LOAD_DECLINE;
 	} else {
 		/* Make sure we can register our channel type */
 		if (ast_channel_register(&oh323_tech)) {
 			ast_log(LOG_ERROR, "Unable to register channel class 'H323'\n");
+			ast_cli_unregister(&cli_h323_reload);
 			h323_end_process();
-			return -1;
+			io_context_destroy(io);
+			sched_context_destroy(sched);
+
+			ASTOBJ_CONTAINER_DESTROYALL(&userl, oh323_destroy_user);
+			ASTOBJ_CONTAINER_DESTROY(&userl);
+			ASTOBJ_CONTAINER_DESTROYALL(&peerl, oh323_destroy_peer);
+			ASTOBJ_CONTAINER_DESTROY(&peerl);
+			ASTOBJ_CONTAINER_DESTROYALL(&aliasl, oh323_destroy_alias);
+			ASTOBJ_CONTAINER_DESTROY(&aliasl);
+
+			return AST_MODULE_LOAD_FAILURE;
 		}
 		ast_cli_register_multiple(cli_h323, sizeof(cli_h323) / sizeof(struct ast_cli_entry));
 
 		ast_rtp_proto_register(&oh323_rtp);
 
 		/* Register our callback functions */
-		h323_callback_register(setup_incoming_call, 
-						setup_outgoing_call,							 
-						external_rtp_create, 
-						setup_rtp_connection, 
-						cleanup_connection, 
+		h323_callback_register(setup_incoming_call,
+						setup_outgoing_call,
+						external_rtp_create,
+						setup_rtp_connection,
+						cleanup_connection,
 						chan_ringing,
-						connection_made, 
-						send_digit,
+						connection_made,
+						receive_digit,
 						answer_call,
 						progress,
 						set_dtmf_payload,
 						hangup_connection,
-						set_local_capabilities);
+						set_local_capabilities,
+						set_peer_capabilities);
 		/* start the h.323 listener */
 		if (h323_start_listener(h323_signalling_port, bindaddr)) {
 			ast_log(LOG_ERROR, "Unable to create H323 listener.\n");
-			return -1;
+			ast_rtp_proto_unregister(&oh323_rtp);
+			ast_cli_unregister_multiple(cli_h323, sizeof(cli_h323) / sizeof(struct ast_cli_entry));
+			ast_cli_unregister(&cli_h323_reload);
+			h323_end_process();
+			io_context_destroy(io);
+			sched_context_destroy(sched);
+
+			ASTOBJ_CONTAINER_DESTROYALL(&userl, oh323_destroy_user);
+			ASTOBJ_CONTAINER_DESTROY(&userl);
+			ASTOBJ_CONTAINER_DESTROYALL(&peerl, oh323_destroy_peer);
+			ASTOBJ_CONTAINER_DESTROY(&peerl);
+			ASTOBJ_CONTAINER_DESTROYALL(&aliasl, oh323_destroy_alias);
+			ASTOBJ_CONTAINER_DESTROY(&aliasl);
+
+			return AST_MODULE_LOAD_FAILURE;
 		}
 		/* Possibly register with a GK */
 		if (!gatekeeper_disable) {
 			if (h323_set_gk(gatekeeper_discover, gatekeeper, secret)) {
 				ast_log(LOG_ERROR, "Gatekeeper registration failed.\n");
-				return 0;
+				gatekeeper_disable = 1;
+				return AST_MODULE_LOAD_SUCCESS;
 			}
 		}
 		/* And start the monitor for the first time */
@@ -2451,15 +3149,17 @@ static int load_module(void *mod)
 	return res;
 }
 
-static int unload_module(void *mod)
+static int unload_module(void)
 {
 	struct oh323_pvt *p, *pl;
 
 	/* unregister commands */
 	ast_cli_unregister_multiple(cli_h323, sizeof(cli_h323) / sizeof(struct ast_cli_entry));
-	ast_rtp_proto_unregister(&oh323_rtp);
+	ast_cli_unregister(&cli_h323_reload);
+
 	ast_channel_unregister(&oh323_tech);
-		
+	ast_rtp_proto_unregister(&oh323_rtp);
+
 	if (!ast_mutex_lock(&iflock)) {
 		/* hangup all interfaces if they have an owner */
 		p = iflist;
@@ -2476,9 +3176,10 @@ static int unload_module(void *mod)
 		return -1;
 	}
 	if (!ast_mutex_lock(&monlock)) {
-		if (monitor_thread && (monitor_thread != AST_PTHREADT_STOP)) {
+		if ((monitor_thread != AST_PTHREADT_STOP) && (monitor_thread != AST_PTHREADT_NULL)) {
 			/* this causes a seg, anyone know why? */
-			pthread_cancel(monitor_thread);
+			if (monitor_thread != pthread_self())
+				pthread_cancel(monitor_thread);
 			pthread_kill(monitor_thread, SIGURG);
 			pthread_join(monitor_thread, NULL);
 		}
@@ -2504,21 +3205,24 @@ static int unload_module(void *mod)
 		ast_log(LOG_WARNING, "Unable to lock the interface list\n");
 		return -1;
 	}
-	h323_gk_urq();
+	if (!gatekeeper_disable)
+		h323_gk_urq();
 	h323_end_process();
 	io_context_destroy(io);
 	sched_context_destroy(sched);
-	delete_users();
-	delete_aliases();
-	prune_peers();
-	ast_mutex_destroy(&aliasl.lock);
-	ast_mutex_destroy(&userl.lock);
-	ast_mutex_destroy(&peerl.lock);
-	return 0; 
-} 
+
+	ASTOBJ_CONTAINER_DESTROYALL(&userl, oh323_destroy_user);
+	ASTOBJ_CONTAINER_DESTROY(&userl);
+	ASTOBJ_CONTAINER_DESTROYALL(&peerl, oh323_destroy_peer);
+	ASTOBJ_CONTAINER_DESTROY(&peerl);
+	ASTOBJ_CONTAINER_DESTROYALL(&aliasl, oh323_destroy_alias);
+	ASTOBJ_CONTAINER_DESTROY(&aliasl);
+
+	return 0;
+}
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "The NuFone Network's OpenH323 Channel Driver",
 		.load = load_module,
 		.unload = unload_module,
 		.reload = reload,
-               );
+);
diff --git a/channels/h323/Makefile b/channels/h323/Makefile
index 2b9fb4d4c64438ae6080c2d0380efdbb7808bebd..df309e6f62e34fe844c78dae22c29dd823966889 100644
--- a/channels/h323/Makefile
+++ b/channels/h323/Makefile
@@ -4,34 +4,50 @@
 # Make file for OpenH323 support layer
 #
 
-.PHONY: Makefile.ast
+.PHONY: Makefile.ast clean
+
+default::	opt
 
 # Verify those options with main Makefile
-STDCCFLAGS	+= -DNDEBUG
-STDCCFLAGS	+= $(shell grep ^DEBUG_THREADS ../../Makefile | sed -e "s/^DEBUG_THREADS[ 	]*=//" -e "s/\([^\#]*\)\#.*/\1/")
-STDCCFLAGS	+= -I../../include -include autoconfig.h
+STDCCFLAGS	= -DNDEBUG
+STDCCFLAGS	+= -I../../include -include ../../include/asterisk/autoconfig.h
+STDCCFLAGS	+= -fPIC
 #OPTCCFLAGS	+=
-CFLAGS		+= -pipe
-TARGET		+= libchanh323.a
+CFLAGS		= -pipe
+TARGET		= libchanh323.a
 TARGET		+= Makefile.ast
-SOURCES		= ast_h323.cxx
+SOURCES		= ast_h323.cxx compat_h323.cxx cisco-h225.cxx
 OBJDIR		= .
+OBJS		=
 
 ifndef OPENH323DIR
-OPENH323DIR=$(HOME)/openh323
+OPENH323DIR=/usr/src/OpenH323/openh323
 endif
 
 include $(OPENH323DIR)/openh323u.mak
 
-$(SOURCES)::	$(SOURCES:.cxx=.cpp)
-	ln -f $< $@
+notrace::
+	$(MAKE) NOTRACE=1 opt
+
+define module_cxx_template
+$(1)::	$(2)
+	ln -f $(2) $(1)
+endef
+
+$(foreach mod,$(SOURCES),$(eval $(call module_cxx_template,$(mod),$(mod:.cxx=.cpp))))
+#$(SOURCES)::	$(SOURCES:.cxx=.cpp)
+#	ln -f $(patsubst %.cxx, %.cpp, $@) $@
 
 $(SOURCES)::	Makefile ../../Makefile
-	touch $(SOURCES)
+	touch $@
 
 libchanh323.a:	$(OBJS)
 	ar crv $@ $(OBJS)
 
+cisco-h225.cpp::	cisco-h225.asn
+	asnparser -m CISCO_H225 -c $<
+	mv -f cisco-h225.cxx cisco-h225.cpp
+
 Makefile.ast:
 	@echo H323CFLAGS  = $(STDCCFLAGS) $(OPTCCFLAGS) $(CFLAGS) >$@.tmp
 	@echo H323LDFLAGS = $(CFLAGS) $(LDFLAGS) >>$@.tmp
@@ -39,4 +55,4 @@ Makefile.ast:
 	@if [ -r $@ ] && cmp -s $@ $@.tmp; then rm -f $@.tmp; else mv -f $@.tmp $@; fi
 
 clean::
-	rm -f ast_h323.cxx libchanh323.a Makefile.ast *.dep
+	rm -f $(SOURCES) $(TARGET) $(OBJS) Makefile.ast *.dep
diff --git a/channels/h323/README b/channels/h323/README
index ff94bc42ee8359dc5292e7ab4f87a3929cde26aa..875bf3668b4d11c7f1fe22446a34ffc14ab8488c 100644
--- a/channels/h323/README
+++ b/channels/h323/README
@@ -4,13 +4,15 @@
 
 	     First public release on November 10th, 2002
 
-		Dependancies:	openssl-0.9.6b+
-				openssl-devel-0.9.6b+
-	       			expat-1.95+
-	       			expat-dev-1.95+
-
-Tested with Open H.323 version v1.17.1, PWLib v1.9.0 and GCC v3.2.2. Usage of any
-other versions is not supported. 
+		Dependancies (based on OpenH323/PWLib ones):
+						openssl-0.9.6b+
+						openssl-devel-0.9.6b+
+						expat-1.95+
+						expat-dev-1.95+
+
+Tested with Open H.323 version v1.18.0, PWLib v1.10.0 and GCC v3.2.2. Usage of any
+other (especially prior OpenH323 v1.17.3 and PWLib v1.9.2) versions is not
+supported.
 
 NOTICE: Whatever you do, DO NOT USE distrubution specific installs
 of Open H.323 and PWLib. In fact, you should check to make sure 
diff --git a/channels/h323/TODO b/channels/h323/TODO
index b72a9f1d1faefd123419a481cdbcc25c54df3551..1e114ca3bd71a06c9335ab477d82f2978e1e2608 100644
--- a/channels/h323/TODO
+++ b/channels/h323/TODO
@@ -2,11 +2,6 @@ The NuFone Network's Open H.323 Channel Driver for Asterisk
 	     
 	TODO:
 
-		- Fix Gatekeeper re-registration seg (HELP)
-
-		- Track down why calls to invalid extensions always
-		  get sent to 's' in context 'default'
-
 		- H.323 Native Bridging
 
 		- Gatekeeping support (started)
diff --git a/channels/h323/ast_h323.cpp b/channels/h323/ast_h323.cpp
index 4a0db06f5505a53d507f7d6b712a3095286e175f..7d0c01f4396ba3129ba5892e062d4ee58eff8359 100644
--- a/channels/h323/ast_h323.cpp
+++ b/channels/h323/ast_h323.cpp
@@ -7,7 +7,7 @@
  * OpenH323 Channel Driver for ASTERISK PBX.
  *			By  Jeremy McNamara
  *			For The NuFone Network
- * 
+ *
  * chan_h323 has been derived from code created by
  *               Michael Manousos and Mark Spencer
  *
@@ -16,15 +16,15 @@
  * chan_h323 is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version. 
+ * (at your option) any later version.
  *
- * chan_h323 is distributed WITHOUT ANY WARRANTY; without even 
- * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
- * PURPOSE. See the GNU General Public License for more details. 
+ * chan_h323 is distributed WITHOUT ANY WARRANTY; without even
+ * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
  * Version Info: $Id$
  */
@@ -45,12 +45,14 @@ extern "C" {
 #endif
 #include "asterisk/logger.h"
 #include "asterisk/channel.h"
+#include "asterisk/astobj.h"
 #ifdef __cplusplus
 }
 #endif
 
 #include "chan_h323.h"
 #include "ast_h323.h"
+#include "cisco-h225.h"
 
 /* PWlib Required Components  */
 #define MAJOR_VERSION 1
@@ -59,20 +61,21 @@ extern "C" {
 #define BUILD_NUMBER  0
 
 /** Counter for the number of connections */
-int channelsOpen;
-
-/* DTMF Mode */
-int mode = H323_DTMF_RFC2833;
+static int channelsOpen;
 
 /**
  * We assume that only one endPoint should exist.
  * The application cannot run the h323_end_point_create() more than once
  * FIXME: Singleton this, for safety
  */
-MyH323EndPoint *endPoint = NULL;
+static MyH323EndPoint *endPoint = NULL;
 
 /** PWLib entry point */
-MyProcess *localProcess = NULL;
+static MyProcess *localProcess = NULL;
+
+static int _timerChangePipe[2];
+
+static unsigned traceOptions = PTrace::Timestamp | PTrace::Thread | PTrace::FileAndLine;
 
 class PAsteriskLog : public PObject, public iostream {
 	PCLASSINFO(PAsteriskLog, PObject);
@@ -143,27 +146,62 @@ int PAsteriskLog::Buffer::sync()
 	return 0;
 }
 
-#define cout (*logstream)
+static ostream &my_endl(ostream &os)
+{
+	if (logstream) {
+		PTrace::SetOptions(traceOptions);
+		return PTrace::End(os);
+	}
+	return endl(os);
+}
+
+#define cout \
+	(logstream ? (PTrace::ClearOptions((unsigned)-1), PTrace::Begin(0, __FILE__, __LINE__)) : std::cout)
+#define endl my_endl
 
-MyProcess::MyProcess(): PProcess("The NuFone Network's", "H.323 Channel Driver for Asterisk",
-             MAJOR_VERSION, MINOR_VERSION, BUILD_TYPE, BUILD_NUMBER)
+/* Special class designed to call cleanup code on module destruction */
+class MyH323_Shutdown {
+	public:
+	MyH323_Shutdown() { };
+	~MyH323_Shutdown()
+	{
+		h323_end_process();
+	};
+};
+
+MyProcess::MyProcess(): PProcess("The NuFone Network's",
+			"H.323 Channel Driver for Asterisk",
+			MAJOR_VERSION, MINOR_VERSION, BUILD_TYPE, BUILD_NUMBER)
 {
+	/* Call shutdown when module being unload or asterisk has been stopped */
+	static MyH323_Shutdown x;
+
 	/* Fix missed one in PWLib */
 	PX_firstTimeStart = FALSE;
 	Resume();
 }
 
+MyProcess::~MyProcess()
+{
+	_timerChangePipe[0] = timerChangePipe[0];
+	_timerChangePipe[1] = timerChangePipe[1];
+}
+
 void MyProcess::Main()
 {
+	PTrace::Initialise(PTrace::GetLevel(), NULL, traceOptions);
+	PTrace::SetStream(logstream);
+
 	cout << "  == Creating H.323 Endpoint" << endl;
+	if (endPoint) {
+		cout << "  == ENDPOINT ALREADY CREATED" << endl;
+		return;
+	}
 	endPoint = new MyH323EndPoint();
 	/* Due to a bug in the H.323 recomendation/stack we should request a sane
-	   amount of bandwidth from the GK - this function is ignored if not using a GK 
+	   amount of bandwidth from the GK - this function is ignored if not using a GK
 	   We are requesting 128 (64k in each direction), which is the worst case codec. */
-        endPoint->SetInitialBandwidth(1280);
-
-	PTrace::Initialise(0, NULL, PTrace::Timestamp | PTrace::Thread | PTrace::FileAndLine);
-	PTrace::SetStream(logstream);
+	endPoint->SetInitialBandwidth(1280);
 }
 
 void PAssertFunc(const char *msg)
@@ -175,122 +213,187 @@ void PAssertFunc(const char *msg)
 H323_REGISTER_CAPABILITY(H323_G7231Capability, OPAL_G7231);
 H323_REGISTER_CAPABILITY(AST_G729Capability,  OPAL_G729);
 H323_REGISTER_CAPABILITY(AST_G729ACapability, OPAL_G729A);
+H323_REGISTER_CAPABILITY(AST_GSM0610Capability, OPAL_GSM0610);
 
+/*
+ * Capability: G.723.1
+ */
 H323_G7231Capability::H323_G7231Capability(BOOL annexA_)
-  : H323AudioCapability(7, 4)
+	: H323AudioCapability(7, 4)
 {
-  	annexA = annexA_;
+	annexA = annexA_;
 }
 
 PObject::Comparison H323_G7231Capability::Compare(const PObject & obj) const
 {
-  	Comparison result = H323AudioCapability::Compare(obj);
-  	if (result != EqualTo) {
-    		return result;
+	Comparison result = H323AudioCapability::Compare(obj);
+	if (result != EqualTo) {
+		return result;
 	}
-  	PINDEX otherAnnexA = ((const H323_G7231Capability &)obj).annexA;
-  	if (annexA < otherAnnexA) {
-    		return LessThan;
+	PINDEX otherAnnexA = ((const H323_G7231Capability &)obj).annexA;
+	if (annexA < otherAnnexA) {
+		return LessThan;
 	}
-  	if (annexA > otherAnnexA) {
-    		return GreaterThan;
+	if (annexA > otherAnnexA) {
+		return GreaterThan;
 	}
 	return EqualTo;
 }
 
 PObject * H323_G7231Capability::Clone() const
 {
- 	 return new H323_G7231Capability(*this);
+	return new H323_G7231Capability(*this);
 }
 
 PString H323_G7231Capability::GetFormatName() const
 {
-  	return OPAL_G7231;
+	return (annexA ? OPAL_G7231 "A" : OPAL_G7231);
 }
 
 unsigned H323_G7231Capability::GetSubType() const
 {
-  	return H245_AudioCapability::e_g7231;
+	return H245_AudioCapability::e_g7231;
 }
 
 BOOL H323_G7231Capability::OnSendingPDU(H245_AudioCapability & cap,
-                                          unsigned packetSize) const
+										unsigned packetSize) const
 {
-  	cap.SetTag(H245_AudioCapability::e_g7231);
-  	H245_AudioCapability_g7231 & g7231 = cap;
-  	g7231.m_maxAl_sduAudioFrames = packetSize;
-  	g7231.m_silenceSuppression = annexA;
-  	return TRUE;
+	cap.SetTag(H245_AudioCapability::e_g7231);
+	H245_AudioCapability_g7231 & g7231 = cap;
+	g7231.m_maxAl_sduAudioFrames = packetSize;
+	g7231.m_silenceSuppression = annexA;
+	return TRUE;
 }
 
 BOOL H323_G7231Capability::OnReceivedPDU(const H245_AudioCapability & cap,
-                                           unsigned & packetSize)
+										unsigned & packetSize)
 {
 	if (cap.GetTag() != H245_AudioCapability::e_g7231) {
-    		return FALSE;
+		return FALSE;
 	}
-  	const H245_AudioCapability_g7231 & g7231 = cap;
-  	packetSize = g7231.m_maxAl_sduAudioFrames;
-  	annexA = g7231.m_silenceSuppression;
-  	return TRUE;
+	const H245_AudioCapability_g7231 & g7231 = cap;
+	packetSize = g7231.m_maxAl_sduAudioFrames;
+	annexA = g7231.m_silenceSuppression;
+	return TRUE;
 }
 
 H323Codec * H323_G7231Capability::CreateCodec(H323Codec::Direction direction) const
 {
-  	return NULL;
+	return NULL;
 }
 
+/*
+ * Capability: G.729
+ */
 AST_G729Capability::AST_G729Capability()
-  : H323AudioCapability(24, 2)
+	: H323AudioCapability(24, 2)
 {
 }
 
 PObject * AST_G729Capability::Clone() const
 {
-  	return new AST_G729Capability(*this);
+	return new AST_G729Capability(*this);
 }
 
 unsigned AST_G729Capability::GetSubType() const
 {
-  	return H245_AudioCapability::e_g729;
+	return H245_AudioCapability::e_g729;
 }
 
 PString AST_G729Capability::GetFormatName() const
 {
-  	return OPAL_G729;
+	return OPAL_G729;
 }
 
 H323Codec * AST_G729Capability::CreateCodec(H323Codec::Direction direction) const
 {
-  	return NULL;
+	return NULL;
 }
 
+/*
+ * Capability: G.729A
+ */
 AST_G729ACapability::AST_G729ACapability()
-  : H323AudioCapability(24, 6)
+	: H323AudioCapability(24, 6)
 {
 }
 
 PObject * AST_G729ACapability::Clone() const
 {
-  	return new AST_G729ACapability(*this);
+	return new AST_G729ACapability(*this);
 }
 
 unsigned AST_G729ACapability::GetSubType() const
 {
-  	return H245_AudioCapability::e_g729AnnexA;
+	return H245_AudioCapability::e_g729AnnexA;
 }
 
 PString AST_G729ACapability::GetFormatName() const
 {
-  	return OPAL_G729A;
+	return OPAL_G729A;
 }
 
 H323Codec * AST_G729ACapability::CreateCodec(H323Codec::Direction direction) const
 {
-  	return NULL;
+	return NULL;
+}
+
+/*
+ * Capability: GSM full rate
+ */
+AST_GSM0610Capability::AST_GSM0610Capability(int comfortNoise_, int scrambled_)
+	: H323AudioCapability(24, 2)
+{
+	comfortNoise = comfortNoise_;
+	scrambled = scrambled_;
+}
+
+PObject * AST_GSM0610Capability::Clone() const
+{
+	return new AST_GSM0610Capability(*this);
+}
+
+unsigned AST_GSM0610Capability::GetSubType() const
+{
+	return H245_AudioCapability::e_gsmFullRate;
+}
+
+BOOL AST_GSM0610Capability::OnSendingPDU(H245_AudioCapability & cap,
+										unsigned packetSize) const
+{
+	cap.SetTag(H245_AudioCapability::e_gsmFullRate);
+	H245_GSMAudioCapability & gsm = cap;
+	gsm.m_audioUnitSize = packetSize;
+	gsm.m_comfortNoise = comfortNoise;
+	gsm.m_scrambled = scrambled;
+	return TRUE;
+}
+
+BOOL AST_GSM0610Capability::OnReceivedPDU(const H245_AudioCapability & cap,
+										unsigned & packetSize)
+{
+	if (cap.GetTag() != H245_AudioCapability::e_gsmFullRate)
+		return FALSE;
+	const H245_GSMAudioCapability & gsm = cap;
+	packetSize = gsm.m_audioUnitSize;
+	comfortNoise = gsm.m_comfortNoise;
+	scrambled = gsm.m_scrambled;
+
+	return TRUE;
+}
+
+PString AST_GSM0610Capability::GetFormatName() const
+{
+	return OPAL_GSM0610;
 }
 
-/** MyH323EndPoint 
+H323Codec * AST_GSM0610Capability::CreateCodec(H323Codec::Direction direction) const
+{
+	return NULL;
+}
+
+
+/** MyH323EndPoint
   */
 MyH323EndPoint::MyH323EndPoint()
 		: H323EndPoint()
@@ -306,10 +409,13 @@ MyH323EndPoint::MyH323EndPoint()
   *					transport = ip.
   *					port = 1720.
   */
-int MyH323EndPoint::MakeCall(const PString & dest, PString & token, unsigned int *callReference, call_options_t *opts)
+int MyH323EndPoint::MyMakeCall(const PString & dest, PString & token, void *_callReference, void *_opts)
 {
 	PString fullAddress;
 	MyH323Connection * connection;
+	H323Transport *transport = NULL;
+	unsigned int *callReference = (unsigned int *)_callReference;
+	call_options_t *opts = (call_options_t *)_opts;
 
 	/* Determine whether we are using a gatekeeper or not. */
 	if (GetGatekeeper()) {
@@ -318,28 +424,35 @@ int MyH323EndPoint::MakeCall(const PString & dest, PString & token, unsigned int
 			cout << " -- Making call to " << fullAddress << " using gatekeeper." << endl;
 		}
 	} else {
-		fullAddress = dest; 
+		fullAddress = dest;
 		if (h323debug) {
 			cout << " -- Making call to " << fullAddress << " without gatekeeper." << endl;
 		}
+		/* Use bindaddr for outgoing calls too if we don't use gatekeeper */
+		if (listeners.GetSize() > 0) {
+			H323TransportAddress taddr = listeners[0].GetTransportAddress();
+			PIPSocket::Address addr;
+			WORD port;
+			if (taddr.GetIpAndPort(addr, port)) {
+				/* Create own transport for specific addresses only */
+				if (addr) {
+					if (h323debug)
+						cout << "Using " << addr << " for outbound call" << endl;
+					transport = new MyH323TransportTCP(*this, addr);
+					if (!transport)
+						cout << "Unable to create transport for outgoing call" << endl;
+				}
+			} else
+				cout << "Unable to get address and port" << endl;
+		}
 	}
-	if (!(connection = (MyH323Connection *)H323EndPoint::MakeCallLocked(fullAddress, token, opts))) {
+	if (!(connection = (MyH323Connection *)H323EndPoint::MakeCallLocked(fullAddress, token, opts, transport))) {
 		if (h323debug) {
 			cout << "Error making call to \"" << fullAddress << '"' << endl;
 		}
 		return 1;
 	}
-	*callReference = connection->GetCallReference();	
-
-	if (opts->cid_num) {
-		connection->ast_cid_num = PString(opts->cid_num);
-	}
-	if (opts->cid_name) {
-		connection->ast_cid_name = PString(opts->cid_name);
-		connection->SetLocalPartyName(connection->ast_cid_name);
-	}
-
-	connection->dtmfCodec = (RTP_DataFrame::PayloadTypes)opts->dtmfcodec;
+	*callReference = connection->GetCallReference();
 
 	if (h323debug) {
 		cout << "\t-- " << GetLocalUserName() << " is calling host " << fullAddress << endl;
@@ -347,28 +460,28 @@ int MyH323EndPoint::MakeCall(const PString & dest, PString & token, unsigned int
 		cout << "\t-- Call reference is " << *callReference << endl;
 		cout << "\t-- DTMF Payload is " << connection->dtmfCodec << endl;
 	}
-	connection->Unlock(); 	
+	connection->Unlock();
 	return 0;
 }
 
 void MyH323EndPoint::SetEndpointTypeInfo( H225_EndpointType & info ) const
 {
-  	H323EndPoint::SetEndpointTypeInfo(info);
+	H323EndPoint::SetEndpointTypeInfo(info);
 
 	if (terminalType == e_GatewayOnly){
 		info.RemoveOptionalField(H225_EndpointType::e_terminal);
 		info.IncludeOptionalField(H225_EndpointType::e_gateway);
 	}
 
-  	info.m_gateway.IncludeOptionalField(H225_GatewayInfo::e_protocol);
-  	info.m_gateway.m_protocol.SetSize(1);
-  	H225_SupportedProtocols &protocol=info.m_gateway.m_protocol[0];
-  	protocol.SetTag(H225_SupportedProtocols::e_voice);
-  	PINDEX as=SupportedPrefixes.GetSize();
-  	((H225_VoiceCaps &)protocol).m_supportedPrefixes.SetSize(as);
-  	for (PINDEX p=0; p<as; p++) {
+	info.m_gateway.IncludeOptionalField(H225_GatewayInfo::e_protocol);
+	info.m_gateway.m_protocol.SetSize(1);
+	H225_SupportedProtocols &protocol=info.m_gateway.m_protocol[0];
+	protocol.SetTag(H225_SupportedProtocols::e_voice);
+	PINDEX as=SupportedPrefixes.GetSize();
+	((H225_VoiceCaps &)protocol).m_supportedPrefixes.SetSize(as);
+	for (PINDEX p=0; p<as; p++) {
 		H323SetAliasAddress(SupportedPrefixes[p], ((H225_VoiceCaps &)protocol).m_supportedPrefixes[p].m_prefix, H225_AliasAddress::e_dialedDigits);
-  	}
+	}
 }
 
 void MyH323EndPoint::SetGateway(void)
@@ -379,7 +492,11 @@ void MyH323EndPoint::SetGateway(void)
 BOOL MyH323EndPoint::ClearCall(const PString & token, H323Connection::CallEndReason reason)
 {
 	if (h323debug) {
+#ifdef PTRACING
 		cout << "\t-- ClearCall: Request to clear call with token " << token << ", cause " << reason << endl;
+#else
+		cout << "\t-- ClearCall: Request to clear call with token " << token << ", cause [" << (int)reason << "]" << endl;
+#endif
 	}
 	return H323EndPoint::ClearCall(token, reason);
 }
@@ -395,7 +512,7 @@ BOOL MyH323EndPoint::ClearCall(const PString & token)
 void MyH323EndPoint::SendUserTone(const PString &token, char tone)
 {
 	H323Connection *connection = NULL;
-		
+
 	connection = FindConnectionWithLock(token);
 	if (connection != NULL) {
 		connection->SendUserInputTone(tone, 500);
@@ -413,22 +530,22 @@ void MyH323EndPoint::OnClosedLogicalChannel(H323Connection & connection, const H
 }
 
 BOOL MyH323EndPoint::OnConnectionForwarded(H323Connection & connection,
- 		const PString & forwardParty,
- 		const H323SignalPDU & pdu)
- {
- 	if (h323debug) {
-	 	cout << "\t-- Call Forwarded to " << forwardParty << endl;
- 	}
+		const PString & forwardParty,
+		const H323SignalPDU & pdu)
+{
+	if (h323debug) {
+		cout << "\t-- Call Forwarded to " << forwardParty << endl;
+	}
 	return FALSE;
- }
- 
+}
+
 BOOL MyH323EndPoint::ForwardConnection(H323Connection & connection,
- 		const PString & forwardParty,
- 		const H323SignalPDU & pdu)
+		const PString & forwardParty,
+		const H323SignalPDU & pdu)
 {
- 	if (h323debug) {
- 		cout << "\t-- Forwarding call to " << forwardParty << endl;
- 	}
+	if (h323debug) {
+		cout << "\t-- Forwarding call to " << forwardParty << endl;
+	}
 	return H323EndPoint::ForwardConnection(connection, forwardParty, pdu);
 }
 
@@ -442,7 +559,7 @@ void MyH323EndPoint::OnConnectionEstablished(H323Connection & connection, const
 }
 
 /** OnConnectionCleared callback function is called upon the dropping of an established
-  * H323 connection. 
+  * H323 connection.
   */
 void MyH323EndPoint::OnConnectionCleared(H323Connection & connection, const PString & clearedCallToken)
 {
@@ -535,53 +652,72 @@ void MyH323EndPoint::OnConnectionCleared(H323Connection & connection, const PStr
 			}
 			break;
 		default:
-			if (h323debug)
+			if (h323debug) {
+#ifdef PTRACING
 				cout << " -- Call with " << remoteName << " completed (" << connection.GetCallEndReason() << ")" << endl;
-
+#else
+				cout << " -- Call with " << remoteName << " completed ([" << (int)connection.GetCallEndReason() << "])" << endl;
+#endif
+			}
 	}
 
 	if (connection.IsEstablished()) {
 		if (h323debug) {
 			cout << "\t-- Call duration " << setprecision(0) << setw(5) << (PTime() - connection.GetConnectionStartTime()) << endl;
 		}
-	}	
+	}
 	/* Invoke the PBX application registered callback */
 	on_connection_cleared(connection.GetCallReference(), clearedCallToken);
 	return;
 }
 
-H323Connection * MyH323EndPoint::CreateConnection(unsigned callReference, void *o)
+H323Connection * MyH323EndPoint::CreateConnection(unsigned callReference, void *userData, H323Transport *transport, H323SignalPDU *setupPDU)
 {
 	unsigned options = 0;
-	call_options_t *opts = (call_options_t *)o;
+	call_options_t *opts = (call_options_t *)userData;
+	MyH323Connection *conn;
 
-	if (opts && opts->noFastStart) {
-		options |= H323Connection::FastStartOptionDisable;
-	} else {
+	if (opts && opts->fastStart) {
 		options |= H323Connection::FastStartOptionEnable;
-	}
-	if (opts && opts->noH245Tunneling) {
-		options |= H323Connection::H245TunnelingOptionDisable;
 	} else {
+		options |= H323Connection::FastStartOptionDisable;
+	}
+	if (opts && opts->h245Tunneling) {
 		options |= H323Connection::H245TunnelingOptionEnable;
+	} else {
+		options |= H323Connection::H245TunnelingOptionDisable;
 	}
 /* Disable until I can figure out the proper way to deal with this */
 #if 0
-	if (opts->noSilenceSuppression) {
-		options |= H323Connection::SilenceSuppresionOptionDisable;
+	if (opts->silenceSuppression) {
+		options |= H323Connection::SilenceSuppresionOptionEnable;
 	} else {
-		options |= H323Connection::SilenceSUppressionOptionEnable;
+		options |= H323Connection::SilenceSUppressionOptionDisable;
 	}
 #endif
-	return new MyH323Connection(*this, callReference, options);
+	conn = new MyH323Connection(*this, callReference, options);
+	if (conn) {
+		if (opts)
+			conn->SetCallOptions(opts, (setupPDU ? TRUE : FALSE));
+	}
+	return conn;
 }
 
-/* MyH323Connection Implementation */    
+/* MyH323Connection Implementation */
 MyH323Connection::MyH323Connection(MyH323EndPoint & ep, unsigned callReference,
 							unsigned options)
 	: H323Connection(ep, callReference, options)
 {
 	cause = -1;
+	sessionId = 0;
+	bridging = FALSE;
+	progressSetup = progressAlert = 0;
+	dtmfMode = 0;
+	dtmfCodec = (RTP_DataFrame::PayloadTypes)0;
+	redirect_reason = -1;
+#ifdef TUNNELLING
+	tunnelOptions = remoteTunnelOptions = 0;
+#endif
 	if (h323debug) {
 		cout << "	== New H.323 Connection created." << endl;
 	}
@@ -610,7 +746,7 @@ BOOL MyH323Connection::OnReceivedProgress(const H323SignalPDU &pdu)
 	if (h323debug) {
 		cout << "\t- Progress Indicator: " << pi << endl;
 	}
-	
+
 	switch(pi) {
 	case Q931::ProgressNotEndToEndISDN:
 	case Q931::ProgressInbandInformationAvailable:
@@ -625,13 +761,13 @@ BOOL MyH323Connection::OnReceivedProgress(const H323SignalPDU &pdu)
 }
 
 H323Connection::AnswerCallResponse MyH323Connection::OnAnswerCall(const PString & caller,
-								  const H323SignalPDU & setupPDU,
-								  H323SignalPDU & /*connectPDU*/)
+								const H323SignalPDU & setupPDU,
+								H323SignalPDU & connectPDU)
 {
 	unsigned pi;
 
 	if (h323debug) {
-               cout << "\t=-= In OnAnswerCall for call " << GetCallReference() << endl;
+		cout << "\t=-= In OnAnswerCall for call " << GetCallReference() << endl;
 	}
 
 	if (connectionState == ShuttingDownConnection)
@@ -648,27 +784,33 @@ H323Connection::AnswerCallResponse MyH323Connection::OnAnswerCall(const PString
 	} else if (pi == Q931::ProgressOriginNotISDN) {
 		pi = Q931::ProgressInbandInformationAvailable;
 	}
-	if (pi) {
+	if (pi && alertingPDU) {
 		alertingPDU->GetQ931().SetProgressIndicator(pi);
 	}
 	if (h323debug) {
 		cout << "\t\t- Inserting PI of " << pi << " into ALERTING message" << endl;
 	}
 
+#ifdef TUNNELLING
+	if (alertingPDU)
+		EmbedTunneledInfo(*alertingPDU);
+	EmbedTunneledInfo(connectPDU);
+#endif
+
 	if (!on_answer_call(GetCallReference(), (const char *)GetCallToken())) {
 		return H323Connection::AnswerCallDenied;
 	}
 	/* The call will be answered later with "AnsweringCall()" function.
-	 */ 
-	return H323Connection::AnswerCallDeferredWithMedia;
+	 */
+	return ((pi || (fastStartState != FastStartDisabled)) ? AnswerCallDeferredWithMedia : AnswerCallDeferred);
 }
 
 BOOL MyH323Connection::OnAlerting(const H323SignalPDU & alertingPDU, const PString & username)
 {
 	if (h323debug) {
-	        cout << "\t=-= In OnAlerting for call " << GetCallReference()
-	              << ": sessionId=" << sessionId << endl;
-                 cout << "\t-- Ringing phone for \"" << username << "\"" << endl;
+		cout << "\t=-= In OnAlerting for call " << GetCallReference()
+			<< ": sessionId=" << sessionId << endl;
+		cout << "\t-- Ringing phone for \"" << username << "\"" << endl;
 	}
 
 	if (on_progress) {
@@ -681,7 +823,7 @@ BOOL MyH323Connection::OnAlerting(const H323SignalPDU & alertingPDU, const PStri
 		if (h323debug) {
 			cout << "\t\t- Progress Indicator: " << alertingPI << endl;
 		}
-		
+
 		switch(alertingPI) {
 		case Q931::ProgressNotEndToEndISDN:
 		case Q931::ProgressInbandInformationAvailable:
@@ -692,80 +834,457 @@ BOOL MyH323Connection::OnAlerting(const H323SignalPDU & alertingPDU, const PStri
 		}
 		on_progress(GetCallReference(), (const char *)GetCallToken(), isInband);
 	}
-        on_chan_ringing(GetCallReference(), (const char *)GetCallToken() );
-        return connectionState != ShuttingDownConnection;
+	on_chan_ringing(GetCallReference(), (const char *)GetCallToken() );
+	return connectionState != ShuttingDownConnection;
 }
 
-BOOL MyH323Connection::OnReceivedSignalSetup(const H323SignalPDU & setupPDU)
+void MyH323Connection::SetCallOptions(void *o, BOOL isIncoming)
+{
+	call_options_t *opts = (call_options_t *)o;
+
+	progressSetup = opts->progress_setup;
+	progressAlert = opts->progress_alert;
+	dtmfCodec = (RTP_DataFrame::PayloadTypes)opts->dtmfcodec;
+	dtmfMode = opts->dtmfmode;
+
+	if (isIncoming) {
+		fastStartState = (opts->fastStart ? FastStartInitiate : FastStartDisabled);
+		h245Tunneling = (opts->h245Tunneling ? TRUE : FALSE);
+	} else {
+		SetLocalPartyName(PString(opts->cid_num));
+		SetDisplayName(PString(opts->cid_name));
+		if (opts->redirect_reason >= 0) {
+			rdnis = PString(opts->cid_rdnis);
+			redirect_reason = opts->redirect_reason;
+		}
+	}
+	tunnelOptions = opts->tunnelOptions;
+}
+
+void MyH323Connection::SetCallDetails(void *callDetails, const H323SignalPDU &setupPDU, BOOL isIncoming)
 {
-	call_details_t cd;
 	PString sourceE164;
 	PString destE164;
-	PString sourceName;
-	PString sourceAliases;	
+	PString sourceAliases;
 	PString destAliases;
-	PIPSocket::Address Ip;
-	WORD sourcePort;
-	char *s, *s1; 
-
-	if (h323debug) {
-		cout << ("\t--Received SETUP message\n");
-	}
+	char *s, *s1;
+	call_details_t *cd = (call_details_t *)callDetails;
 
-	if (connectionState == ShuttingDownConnection)
-		return FALSE;
+	memset(cd, 0, sizeof(*cd));
+	cd->call_reference = GetCallReference();
+	cd->call_token = strdup((const char *)GetCallToken());
 
-	sourceAliases = setupPDU.GetSourceAliases();
-	destAliases = setupPDU.GetDestinationAlias();
-			
 	sourceE164 = "";
 	setupPDU.GetSourceE164(sourceE164);
-	sourceName = "";
-	sourceName=setupPDU.GetQ931().GetDisplayName();
+	cd->call_source_e164 = strdup((const char *)sourceE164);
+
 	destE164 = "";
 	setupPDU.GetDestinationE164(destE164);
+	cd->call_dest_e164 = strdup((const char *)destE164);
+
+	/* XXX Is it possible to have this information for outgoing calls too? XXX */
+	if (isIncoming) {
+		PString sourceName;
+		PIPSocket::Address Ip;
+		WORD sourcePort;
+		PString redirect_number;
+		unsigned redirect_reason;
+
+		sourceName = setupPDU.GetQ931().GetDisplayName();
+		cd->call_source_name = strdup((const char *)sourceName);
+
+		GetSignallingChannel()->GetRemoteAddress().GetIpAndPort(Ip, sourcePort);
+		cd->sourceIp = strdup((const char *)Ip.AsString());
+
+		if(setupPDU.GetQ931().GetRedirectingNumber(redirect_number, NULL, NULL, NULL, NULL, &redirect_reason, 0, 0, 0)) {
+			cd->redirect_number = strdup((const char *)redirect_number);
+			cd->redirect_reason = redirect_reason;
+		}
+		else
+			cd->redirect_reason = -1;
+	}
 
 	/* Convert complex strings */
-	//  FIXME: deal more than one source alias 
-    	if ((s = strchr(sourceAliases, ' ')) != NULL) {
-                *s = '\0';
+	//  FIXME: deal more than one source alias
+	sourceAliases = setupPDU.GetSourceAliases();
+	s1 = strdup((const char *)sourceAliases);
+	if ((s = strchr(s1, ' ')) != NULL)
+		*s = '\0';
+	if ((s = strchr(s1, '\t')) != NULL)
+		*s = '\0';
+	cd->call_source_aliases = s1;
+
+	destAliases = setupPDU.GetDestinationAlias();
+	s1 = strdup((const char *)destAliases);
+	if ((s = strchr(s1, ' ')) != NULL)
+		*s = '\0';
+	if ((s = strchr(s1, '\t')) != NULL)
+		*s = '\0';
+	cd->call_dest_alias = s1;
+}
+
+#ifdef TUNNELLING
+static BOOL FetchInformationElements(Q931 &q931, const PBYTEArray &data)
+{
+	PINDEX offset = 0;
+
+	while (offset < data.GetSize()) {
+		// Get field discriminator
+		int discriminator = data[offset++];
+
+#if 0
+		/* Do not overwrite existing IEs */
+		if (q931.HasIE((Q931::InformationElementCodes)discriminator)) {
+			if ((discriminatir & 0x80) == 0)
+				offset += data[offset++];
+			if (offset > data.GetSize())
+				return FALSE;
+			continue;
+		}
+#endif
+
+		PBYTEArray * item = new PBYTEArray;
+
+		// For discriminator with high bit set there is no data
+		if ((discriminator & 0x80) == 0) {
+			int len = data[offset++];
+
+#if 0		// That is not H.225 but regular Q.931 (ISDN) IEs
+			if (discriminator == UserUserIE) {
+				// Special case of User-user field. See 7.2.2.31/H.225.0v4.
+				len <<= 8;
+				len |= data[offset++];
+
+				// we also have a protocol discriminator, which we ignore
+				offset++;
+
+				// before decrementing the length, make sure it is not zero
+				if (len == 0)
+					return FALSE;
+
+				// adjust for protocol discriminator
+				len--;
+			}
+#endif
+
+			if (offset + len > data.GetSize()) {
+				delete item;
+				return FALSE;
+			}
+
+			memcpy(item->GetPointer(len), (const BYTE *)data+offset, len);
+			offset += len;
+		}
+
+		q931.SetIE((Q931::InformationElementCodes)discriminator, *item);
+		delete item;
 	}
-    	if ((s = strchr(sourceAliases, '\t')) != NULL) {
-                *s = '\0';
+	return TRUE;
+}
+
+static BOOL FetchCiscoTunneledInfo(Q931 &q931, const H323SignalPDU &pdu)
+{
+	BOOL res = FALSE;
+	const H225_H323_UU_PDU &uuPDU = pdu.m_h323_uu_pdu;
+
+	if(uuPDU.HasOptionalField(H225_H323_UU_PDU::e_nonStandardControl)) {
+		for(int i = 0; i < uuPDU.m_nonStandardControl.GetSize(); ++i) {
+			const H225_NonStandardParameter &np = uuPDU.m_nonStandardControl[i];
+			const H225_NonStandardIdentifier &id = np.m_nonStandardIdentifier;
+			if (id.GetTag() == H225_NonStandardIdentifier::e_h221NonStandard) {
+				const H225_H221NonStandard &ni = id;
+				/* Check for Cisco */
+				if ((ni.m_t35CountryCode == 181) && (ni.m_t35Extension == 0) && (ni.m_manufacturerCode == 18)) {
+					const PBYTEArray &data = np.m_data;
+					if (h323debug)
+						cout << setprecision(0) << "Received non-standard Cisco extension data " << np.m_data << endl;
+					CISCO_H225_H323_UU_NonStdInfo c;
+					PPER_Stream strm(data);
+					if (c.Decode(strm)) {
+						BOOL haveIEs = FALSE;
+						if (h323debug)
+							cout << setprecision(0) << "H323_UU_NonStdInfo = " << c << endl;
+						if (c.HasOptionalField(CISCO_H225_H323_UU_NonStdInfo::e_protoParam)) {
+							FetchInformationElements(q931, c.m_protoParam.m_qsigNonStdInfo.m_rawMesg);
+							haveIEs = TRUE;
+						}
+						if (c.HasOptionalField(CISCO_H225_H323_UU_NonStdInfo::e_commonParam)) {
+							FetchInformationElements(q931, c.m_commonParam.m_redirectIEinfo.m_redirectIE);
+							haveIEs = TRUE;
+						}
+						if (haveIEs && h323debug)
+							cout << setprecision(0) << "Information elements collected:" << q931 << endl;
+						res = TRUE;
+					} else {
+						cout << "ERROR while decoding non-standard Cisco extension" << endl;
+						return FALSE;
+					}
+				}
+			}
+		}
+	}
+	return res;
+}
+
+static BOOL EmbedCiscoTunneledInfo(H323SignalPDU &pdu)
+{
+	const static Q931::InformationElementCodes codes[] =
+	{ Q931::RedirectingNumberIE, Q931::FacilityIE };
+
+	BOOL res = FALSE;
+	BOOL notRedirOnly = FALSE;
+	Q931 tmpQ931;
+	Q931 &q931 = pdu.GetQ931();
+
+	for(unsigned i = 0; i < (sizeof(codes) / sizeof(codes[0])); ++i) {
+		if (q931.HasIE(codes[i])) {
+			tmpQ931.SetIE(codes[i], q931.GetIE(codes[i]));
+			q931.RemoveIE(codes[i]);
+			if (codes[i] != Q931::RedirectingNumberIE)
+				notRedirOnly = TRUE;
+			res = TRUE;
+		}
 	}
- 	if ((s1 = strchr(destAliases, ' ')) != NULL) {
-         	*s1 = '\0';
+	/* Have something to embed */
+	if (res) {
+		PBYTEArray msg;
+		if (!tmpQ931.Encode(msg))
+			return FALSE;
+		PBYTEArray ies(msg.GetPointer() + 5, msg.GetSize() - 5);
+
+		H225_H323_UU_PDU &uuPDU = pdu.m_h323_uu_pdu;
+		if(!uuPDU.HasOptionalField(H225_H323_UU_PDU::e_nonStandardControl)) {
+			uuPDU.IncludeOptionalField(H225_H323_UU_PDU::e_nonStandardControl);
+			uuPDU.m_nonStandardControl.SetSize(0);
+		}
+		H225_NonStandardParameter *np = new H225_NonStandardParameter;
+		uuPDU.m_nonStandardControl.Append(np);
+		H225_NonStandardIdentifier &nsi = (*np).m_nonStandardIdentifier;
+		nsi.SetTag(H225_NonStandardIdentifier::e_h221NonStandard);
+		H225_H221NonStandard &ns = nsi;
+		ns.m_t35CountryCode = 181;
+		ns.m_t35Extension = 0;
+		ns.m_manufacturerCode = 18;
+
+		CISCO_H225_H323_UU_NonStdInfo c;
+		c.IncludeOptionalField(CISCO_H225_H323_UU_NonStdInfo::e_version);
+		c.m_version = 0;
+
+		if (notRedirOnly) {
+			c.IncludeOptionalField(CISCO_H225_H323_UU_NonStdInfo::e_protoParam);
+			CISCO_H225_QsigNonStdInfo &qsigInfo = c.m_protoParam.m_qsigNonStdInfo;
+			qsigInfo.m_iei = ies[0];
+			qsigInfo.m_rawMesg = ies;
+		} else {
+			c.IncludeOptionalField(CISCO_H225_H323_UU_NonStdInfo::e_commonParam);
+			c.m_commonParam.m_redirectIEinfo.m_redirectIE = ies;
+		}
+		PPER_Stream stream;
+		c.Encode(stream);
+		stream.CompleteEncoding();
+		(*np).m_data = stream;
 	}
-	if ((s1 = strchr(destAliases, '\t')) != NULL) {
-         	*s1 = '\0';
+	return res;
+}
+
+static const char OID_QSIG[] = "1.3.12.9";
+
+static BOOL FetchQSIGTunneledInfo(Q931 &q931, const H323SignalPDU &pdu)
+{
+	BOOL res = FALSE;
+	const H225_H323_UU_PDU &uuPDU = pdu.m_h323_uu_pdu;
+	if (uuPDU.HasOptionalField(H225_H323_UU_PDU::e_tunnelledSignallingMessage)) {
+		const H225_H323_UU_PDU_tunnelledSignallingMessage &sig = uuPDU.m_tunnelledSignallingMessage;
+		const H225_TunnelledProtocol_id &proto = sig.m_tunnelledProtocolID.m_id;
+		if ((proto.GetTag() == H225_TunnelledProtocol_id::e_tunnelledProtocolObjectID) &&
+				(((const PASN_ObjectId &)proto).AsString() == OID_QSIG)) {
+			const H225_ArrayOf_PASN_OctetString &sigs = sig.m_messageContent;
+			for(int i = 0; i < sigs.GetSize(); ++i) {
+				const PASN_OctetString &msg = sigs[i];
+				if (h323debug)
+					cout << setprecision(0) << "Q.931 message data is " << msg << endl;
+				if(!q931.Decode((const PBYTEArray &)msg)) {
+					cout << "Error while decoding Q.931 message" << endl;
+					return FALSE;
+				}
+				res = TRUE;
+				if (h323debug)
+					cout << setprecision(0) << "Received QSIG message " << q931 << endl;
+			}
+		}
 	}
+	return res;
+}
 
-	memset(&cd, 0, sizeof(cd));
-	cd.call_reference = GetCallReference();
-	cd.call_token = strdup((const char *)GetCallToken());
-	cd.call_source_aliases = strdup((const char *)sourceAliases);
-	cd.call_dest_alias = strdup((const char *)destAliases);
-	cd.call_source_e164 = strdup((const char *)sourceE164);
-	cd.call_dest_e164 = strdup((const char *)destE164);
-	cd.call_source_name = strdup((const char *)sourceName);
+static H225_EndpointType *GetEndpointType(H323SignalPDU &pdu)
+{
+	if (!pdu.GetQ931().HasIE(Q931::UserUserIE))
+		return NULL;
 
-	GetSignallingChannel()->GetRemoteAddress().GetIpAndPort(Ip, sourcePort);
- 	cd.sourceIp = strdup((const char *)Ip.AsString());
+	H225_H323_UU_PDU_h323_message_body &body = pdu.m_h323_uu_pdu.m_h323_message_body;
+	switch (body.GetTag()) {
+	case H225_H323_UU_PDU_h323_message_body::e_setup:
+		return &((H225_Setup_UUIE &)body).m_sourceInfo;
+	case H225_H323_UU_PDU_h323_message_body::e_callProceeding:
+		return &((H225_CallProceeding_UUIE &)body).m_destinationInfo;
+	case H225_H323_UU_PDU_h323_message_body::e_connect:
+		return &((H225_Connect_UUIE &)body).m_destinationInfo;
+	case H225_H323_UU_PDU_h323_message_body::e_alerting:
+		return &((H225_Alerting_UUIE &)body).m_destinationInfo;
+	case H225_H323_UU_PDU_h323_message_body::e_facility:
+		return &((H225_Facility_UUIE &)body).m_destinationInfo;
+	case H225_H323_UU_PDU_h323_message_body::e_progress:
+		return &((H225_Progress_UUIE &)body).m_destinationInfo;
+	}
+	return NULL;
+}
+
+static BOOL QSIGTunnelRequested(H323SignalPDU &pdu)
+{
+	H225_EndpointType *epType = GetEndpointType(pdu);
+	if (epType) {
+		if (!(*epType).HasOptionalField(H225_EndpointType::e_supportedTunnelledProtocols)) {
+			return FALSE;
+		}
+		H225_ArrayOf_TunnelledProtocol &protos = (*epType).m_supportedTunnelledProtocols;
+		for (int i = 0; i < protos.GetSize(); ++i)
+		{
+			if ((protos[i].GetTag() == H225_TunnelledProtocol_id::e_tunnelledProtocolObjectID) &&
+					(((const PASN_ObjectId &)protos[i]).AsString() == OID_QSIG)) {
+				return TRUE;
+			}
+		}
+	}
+	return FALSE;
+}
+
+static BOOL EmbedQSIGTunneledInfo(H323SignalPDU &pdu)
+{
+	const static Q931::InformationElementCodes codes[] =
+	{ Q931::RedirectingNumberIE, Q931::FacilityIE };
+
+	Q931 &q931 = pdu.GetQ931();
+	PBYTEArray message;
+
+	q931.Encode(message);
+
+	/* Remove non-standard IEs */
+	for(unsigned i = 0; i < (sizeof(codes) / sizeof(codes[0])); ++i) {
+		if (q931.HasIE(codes[i])) {
+			q931.RemoveIE(codes[i]);
+		}
+	}
+
+	H225_H323_UU_PDU &uuPDU = pdu.m_h323_uu_pdu;
+	H225_EndpointType *epType = GetEndpointType(pdu);
+	if (epType) {
+		if (!(*epType).HasOptionalField(H225_EndpointType::e_supportedTunnelledProtocols)) {
+			(*epType).IncludeOptionalField(H225_EndpointType::e_supportedTunnelledProtocols);
+			(*epType).m_supportedTunnelledProtocols.SetSize(0);
+		}
+		H225_ArrayOf_TunnelledProtocol &protos = (*epType).m_supportedTunnelledProtocols;
+		BOOL addQSIG = TRUE;
+		for (int i = 0; i < protos.GetSize(); ++i)
+		{
+			if ((protos[i].GetTag() == H225_TunnelledProtocol_id::e_tunnelledProtocolObjectID) &&
+					(((const PASN_ObjectId &)protos[i]).AsString() == OID_QSIG)) {
+				addQSIG = FALSE;
+				break;
+			}
+		}
+		if (addQSIG) {
+			H225_TunnelledProtocol *proto = new H225_TunnelledProtocol;
+			(*proto).m_id.SetTag(H225_TunnelledProtocol_id::e_tunnelledProtocolObjectID);
+			(PASN_ObjectId &)(proto->m_id) = OID_QSIG;
+			protos.Append(proto);
+		}
+	}
+	if (!uuPDU.HasOptionalField(H225_H323_UU_PDU::e_tunnelledSignallingMessage))
+		uuPDU.IncludeOptionalField(H225_H323_UU_PDU::e_tunnelledSignallingMessage);
+	H225_H323_UU_PDU_tunnelledSignallingMessage &sig = uuPDU.m_tunnelledSignallingMessage;
+	H225_TunnelledProtocol_id &proto = sig.m_tunnelledProtocolID.m_id;
+	if ((proto.GetTag() != H225_TunnelledProtocol_id::e_tunnelledProtocolObjectID) ||
+			(((const PASN_ObjectId &)proto).AsString() != OID_QSIG)) {
+		proto.SetTag(H225_TunnelledProtocol_id::e_tunnelledProtocolObjectID);
+		(PASN_ObjectId &)proto = OID_QSIG;
+		sig.m_messageContent.SetSize(0);
+	}
+	PASN_OctetString *msg = new PASN_OctetString;
+	sig.m_messageContent.Append(msg);
+	*msg = message;
+	return TRUE;
+}
+
+BOOL MyH323Connection::EmbedTunneledInfo(H323SignalPDU &pdu)
+{
+	if ((tunnelOptions & H323_TUNNEL_QSIG) || (remoteTunnelOptions & H323_TUNNEL_QSIG))
+		EmbedQSIGTunneledInfo(pdu);
+	if ((tunnelOptions & H323_TUNNEL_CISCO) || (remoteTunnelOptions & H323_TUNNEL_CISCO))
+		EmbedCiscoTunneledInfo(pdu);
+
+	return TRUE;
+}
+
+/* Handle tunneled messages */
+BOOL MyH323Connection::HandleSignalPDU(H323SignalPDU &pdu)
+{
+	if (pdu.GetQ931().HasIE(Q931::UserUserIE)) {
+		Q931 tunneledInfo;
+		const Q931 *q931Info;
+
+		q931Info = NULL;
+		if (FetchCiscoTunneledInfo(tunneledInfo, pdu)) {
+			q931Info = &tunneledInfo;
+			remoteTunnelOptions |= H323_TUNNEL_CISCO;
+		}
+		if (FetchQSIGTunneledInfo(tunneledInfo, pdu)) {
+			q931Info = &tunneledInfo;
+			remoteTunnelOptions |= H323_TUNNEL_QSIG;
+		}
+		if (!(remoteTunnelOptions & H323_TUNNEL_QSIG) && QSIGTunnelRequested(pdu)) {
+			remoteTunnelOptions |= H323_TUNNEL_QSIG;
+		}
+		if (q931Info) {
+			if (q931Info->HasIE(Q931::RedirectingNumberIE)) {
+				pdu.GetQ931().SetIE(Q931::RedirectingNumberIE, q931Info->GetIE(Q931::RedirectingNumberIE));
+				if (h323debug) {
+					PString number;
+					unsigned reason;
+					if(q931Info->GetRedirectingNumber(number, NULL, NULL, NULL, NULL, &reason, 0, 0, 0))
+						cout << "Got redirection from " << number << ", reason " << reason << endl;
+				}
+			}
+		}
+	}
+
+	return H323Connection::HandleSignalPDU(pdu);
+}
+#endif
+
+BOOL MyH323Connection::OnReceivedSignalSetup(const H323SignalPDU & setupPDU)
+{
+	call_details_t cd;
+
+	if (h323debug) {
+		cout << "\t--Received SETUP message" << endl;
+	}
+
+	if (connectionState == ShuttingDownConnection)
+		return FALSE;
+
+	SetCallDetails(&cd, setupPDU, TRUE);
 
 	/* Notify Asterisk of the request */
 	call_options_t *res = on_incoming_call(&cd);
 
 	if (!res) {
 		if (h323debug) {
-			cout << "	-- Call Failed" << endl;
+			cout << "\t-- Call Failed" << endl;
 		}
 		return FALSE;
 	}
 
-	progressSetup = res->progress_setup;
-	progressAlert = res->progress_alert;
-	dtmfCodec = (RTP_DataFrame::PayloadTypes)res->dtmfcodec;
-
+	SetCallOptions(res, TRUE);
 
 	return H323Connection::OnReceivedSignalSetup(setupPDU);
 }
@@ -773,54 +1292,27 @@ BOOL MyH323Connection::OnReceivedSignalSetup(const H323SignalPDU & setupPDU)
 BOOL MyH323Connection::OnSendSignalSetup(H323SignalPDU & setupPDU)
 {
 	call_details_t cd;
-	char *s, *s1;
 
-	if (h323debug) { 
-		cout << "	-- Sending SETUP message" << endl;
+	if (h323debug) {
+		cout << "\t-- Sending SETUP message" << endl;
 	}
 
 	if (connectionState == ShuttingDownConnection)
 		return FALSE;
 
-	if (!ast_cid_num.IsEmpty()) {
-		setupPDU.GetQ931().SetCallingPartyNumber(ast_cid_num);
-	}
-
-	if (!ast_cid_name.IsEmpty()) {
-		setupPDU.GetQ931().SetDisplayName(ast_cid_name);
-	}
-
-	sourceAliases = setupPDU.GetSourceAliases();
-	destAliases = setupPDU.GetDestinationAlias();
-
-	sourceE164 = "";
-	setupPDU.GetSourceE164(sourceE164);
-	destE164 = "";
-	setupPDU.GetDestinationE164(destE164);
+	if (progressSetup)
+		setupPDU.GetQ931().SetProgressIndicator(progressSetup);
 
-	/* Convert complex strings */
-	//  FIXME: deal more than one source alias 
-	
-    	if ((s = strchr(sourceAliases, ' ')) != NULL) {
-                *s = '\0';
-	}
-    	if ((s = strchr(sourceAliases, '\t')) != NULL) {
-                *s = '\0';
-	}
-    	if ((s1 = strchr(destAliases, ' ')) != NULL) {
-        	 *s1 = '\0';
-	}
-	if ((s1 = strchr(destAliases, '\t')) != NULL) {
-         	*s1 = '\0';
+	if (redirect_reason >= 0) {
+		setupPDU.GetQ931().SetRedirectingNumber(rdnis, 0, 0, 0, 0, redirect_reason);
+		/* OpenH323 incorrectly fills number IE when redirecting reason is specified - fix it */
+		PBYTEArray IE(setupPDU.GetQ931().GetIE(Q931::RedirectingNumberIE));
+		IE[0] = IE[0] & 0x7f;
+		IE[1] = IE[1] & 0x7f;
+		setupPDU.GetQ931().SetIE(Q931::RedirectingNumberIE, IE);
 	}
 
-	memset(&cd, 0, sizeof(cd));
-	cd.call_reference = GetCallReference();
-	cd.call_token = strdup((const char *)GetCallToken());
-	cd.call_source_aliases = strdup((const char *)sourceAliases);
-	cd.call_dest_alias = strdup((const char *)destAliases);
-	cd.call_source_e164 = strdup((const char *)sourceE164);
-	cd.call_dest_e164 = strdup((const char *)destE164);
+	SetCallDetails(&cd, setupPDU, FALSE);
 
 	int res = on_outgoing_call(&cd);
 	if (!res) {
@@ -830,9 +1322,10 @@ BOOL MyH323Connection::OnSendSignalSetup(H323SignalPDU & setupPDU)
 		return FALSE;
 	}
 
-	if (progressSetup) {
-		setupPDU.GetQ931().SetProgressIndicator(progressSetup);
-	}
+#ifdef TUNNELLING
+	EmbedTunneledInfo(setupPDU);
+#endif
+
 	return H323Connection::OnSendSignalSetup(setupPDU);
 }
 
@@ -843,6 +1336,11 @@ BOOL MyH323Connection::OnSendReleaseComplete(H323SignalPDU & releaseCompletePDU)
 	}
 	if (cause > 0)
 		releaseCompletePDU.GetQ931().SetCause((Q931::CauseValues)cause);
+
+#ifdef TUNNELLING
+	EmbedTunneledInfo(releaseCompletePDU);
+#endif
+
 	return H323Connection::OnSendReleaseComplete(releaseCompletePDU);
 }
 
@@ -850,14 +1348,14 @@ BOOL MyH323Connection::OnReceivedFacility(const H323SignalPDU & pdu)
 {
 	if (h323debug) {
 		cout << "\t-- Received Facility message... " << endl;
-	}	
+	}
 	return H323Connection::OnReceivedFacility(pdu);
 }
 
 void MyH323Connection::OnReceivedReleaseComplete(const H323SignalPDU & pdu)
 {
 	if (h323debug) {
-		cout <<  "\t-- Received RELEASE COMPLETE message..." << endl;
+		cout << "\t-- Received RELEASE COMPLETE message..." << endl;
 	}
 	if (on_hangup)
 		on_hangup(GetCallReference(), (const char *)GetCallToken(), pdu.GetQ931().GetCause());
@@ -872,34 +1370,35 @@ BOOL MyH323Connection::OnClosingLogicalChannel(H323Channel & channel)
 	return H323Connection::OnClosingLogicalChannel(channel);
 }
 
-void MyH323Connection::SendUserInputTone(char tone, unsigned duration)
+void MyH323Connection::SendUserInputTone(char tone, unsigned duration, unsigned logicalChannel, unsigned rtpTimestamp)
 {
-	if (h323debug) {
-		cout << "\t-- Sending user input tone (" << tone << ") to remote" << endl;
+	SendUserInputModes mode = GetRealSendUserInputMode();
+//	That is recursive call... Why?
+//	on_receive_digit(GetCallReference(), tone, (const char *)GetCallToken());
+	if ((tone != ' ') || (mode == SendUserInputAsTone) || (mode == SendUserInputAsInlineRFC2833)) {
+		if (h323debug) {
+			cout << "\t-- Sending user input tone (" << tone << ") to remote" << endl;
+		}
+		H323Connection::SendUserInputTone(tone, duration);
 	}
-	on_send_digit(GetCallReference(), tone, (const char *)GetCallToken());	
-	H323Connection::SendUserInputTone(tone, duration);
 }
 
 void MyH323Connection::OnUserInputTone(char tone, unsigned duration, unsigned logicalChannel, unsigned rtpTimestamp)
 {
-	if (mode == H323_DTMF_INBAND) {
+	if (dtmfMode == H323_DTMF_RFC2833) {
 		if (h323debug) {
 			cout << "\t-- Received user input tone (" << tone << ") from remote" << endl;
 		}
-		on_send_digit(GetCallReference(), tone, (const char *)GetCallToken());
+		on_receive_digit(GetCallReference(), tone, (const char *)GetCallToken(), duration);
 	}
-	H323Connection::OnUserInputTone(tone, duration, logicalChannel, rtpTimestamp);
 }
 
 void MyH323Connection::OnUserInputString(const PString &value)
 {
-	if (mode == H323_DTMF_RFC2833) {
-		if (h323debug) {
-			cout <<  "\t-- Received user input string (" << value << ") from remote." << endl;
-		}
-		on_send_digit(GetCallReference(), value[0], (const char *)GetCallToken());
-	}	
+	if (h323debug) {
+		cout << "\t-- Received user input string (" << value << ") from remote." << endl;
+	}
+	on_receive_digit(GetCallReference(), value[0], (const char *)GetCallToken(), 0);
 }
 
 void MyH323Connection::OnSendCapabilitySet(H245_TerminalCapabilitySet & pdu)
@@ -917,7 +1416,7 @@ void MyH323Connection::OnSendCapabilitySet(H245_TerminalCapabilitySet & pdu)
 			if (cap.GetTag() == H245_Capability::e_receiveRTPAudioTelephonyEventCapability) {
 				H245_AudioTelephonyEventCapability & atec = cap;
 				atec.m_dynamicRTPPayloadType = dtmfCodec;
-				on_set_rfc2833_payload(GetCallReference(), (const char *)GetCallToken(), (int)dtmfCodec);
+//				on_set_rfc2833_payload(GetCallReference(), (const char *)GetCallToken(), (int)dtmfCodec);
 				if (h323debug) {
 					cout << "\t-- Transmitting RFC2833 on payload " <<
 						atec.m_dynamicRTPPayloadType << endl;
@@ -934,9 +1433,42 @@ void MyH323Connection::OnSetLocalCapabilities()
 }
 
 BOOL MyH323Connection::OnReceivedCapabilitySet(const H323Capabilities & remoteCaps,
-					       const H245_MultiplexCapability * muxCap,
-					       H245_TerminalCapabilitySetReject & reject)
-{
+							const H245_MultiplexCapability * muxCap,
+							H245_TerminalCapabilitySetReject & reject)
+{
+	struct __codec__ {
+		unsigned int asterisk_codec;
+		unsigned int h245_cap;
+		const char *oid;
+	};
+	static const struct __codec__ codecs[] = {
+		{ AST_FORMAT_G723_1, H245_AudioCapability::e_g7231 },
+		{ AST_FORMAT_GSM, H245_AudioCapability::e_gsmFullRate },
+		{ AST_FORMAT_ULAW, H245_AudioCapability::e_g711Ulaw64k },
+		{ AST_FORMAT_ALAW, H245_AudioCapability::e_g711Alaw64k },
+		{ AST_FORMAT_G729A, H245_AudioCapability::e_g729AnnexA },
+		{ AST_FORMAT_G729A, H245_AudioCapability::e_g729 },
+#ifdef AST_FORMAT_MODEM
+		{ AST_FORMAT_MODEM, H245_DataApplicationCapability_application::e_t38fax },
+#endif
+		{ 0 }
+	};
+
+#if 0
+	static const struct __codec__ vcodecs[] = {
+#ifdef HAVE_H261
+		{ AST_FORMAT_H261, H245_VideoCapability::e_h261VideoCapability },
+#endif
+#ifdef HAVE_H263
+		{ AST_FORMAT_H263, H245_VideoCapability::e_h263VideoCapability },
+#endif
+#ifdef HAVE_H264
+		{ AST_FORMAT_H264, H245_VideoCapability::e_genericVideoCapability, "0.0.8.241.0.0.1" },
+#endif
+		{ 0 }
+	};
+#endif
+
 	if (!H323Connection::OnReceivedCapabilitySet(remoteCaps, muxCap, reject)) {
 		return FALSE;
 	}
@@ -945,124 +1477,258 @@ BOOL MyH323Connection::OnReceivedCapabilitySet(const H323Capabilities & remoteCa
 	if (cap != NULL) {
 		RTP_DataFrame::PayloadTypes pt = ((H323_UserInputCapability*)cap)->GetPayloadType();
 		on_set_rfc2833_payload(GetCallReference(), (const char *)GetCallToken(), (int)pt);
+		if ((dtmfMode == H323_DTMF_RFC2833) && (sendUserInputMode == SendUserInputAsTone))
+			sendUserInputMode = SendUserInputAsInlineRFC2833;
 		if (h323debug) {
 			cout << "\t-- Inbound RFC2833 on payload " << pt << endl;
 		}
 	}
+	int peer_capabilities = 0;
+	for (int i = 0; i < remoteCapabilities.GetSize(); ++i) {
+		unsigned int subType = remoteCapabilities[i].GetSubType();
+		if (h323debug) {
+			cout << "Peer capability is " << remoteCapabilities[i] << endl;
+		}
+		switch(remoteCapabilities[i].GetMainType()) {
+		case H323Capability::e_Audio:
+			for (int x = 0; codecs[x].asterisk_codec > 0; ++x) {
+				if (subType == codecs[x].h245_cap) {
+					if (h323debug) {
+						cout << "Found peer capability " << remoteCapabilities[i] << ", Asterisk code is " << codecs[x].asterisk_codec << endl;
+					}
+					peer_capabilities |= codecs[x].asterisk_codec;
+				}
+			}
+			break;
+#if 0
+		case H323Capability::e_Video:
+			for (int x = 0; vcodecs[x].asterisk_codec > 0; ++x) {
+				if (subType == vcodecs[x].h245_cap) {
+					H245_CapabilityIdentifier *cap = NULL;
+					H245_GenericCapability y;
+					if (vcodecs[x].oid) {
+						cap = new H245_CapabilityIdentifier(H245_CapabilityIdentifier::e_standard);
+						PASN_ObjectId &object_id = *cap;
+						object_id = vcodecs[x].oid;
+						y.m_capabilityIdentifier = *cap;
+					}
+					if ((subType != H245_VideoCapability::e_genericVideoCapability) ||
+							(vcodecs[x].oid && ((const H323GenericVideoCapability &)remoteCapabilities[i]).IsGenericMatch((const H245_GenericCapability)y))) {
+						if (h323debug) {
+							cout << "Found peer video capability " << remoteCapabilities[i] << ", Asterisk code is " << vcodecs[x].asterisk_codec << endl;
+						}
+						peer_capabilities |= vcodecs[x].asterisk_codec;
+					}
+					if (cap)
+						delete(cap);
+				}
+			}
+			break;
+#endif
+		default:
+			break;
+		}
+	}
+	if (h323debug) {
+		char caps_str[1024];
+		cout << "Peer capabilities = " << ast_getformatname_multiple(caps_str, sizeof(caps_str), peer_capabilities) << endl;
+	}
+#if 0
+	redir_capabilities &= peer_capabilities;
+#endif
+	if (on_setpeercapabilities)
+		on_setpeercapabilities(GetCallReference(), (const char *)callToken, peer_capabilities);
+
 	return TRUE;
 }
 
-H323Channel * MyH323Connection::CreateRealTimeLogicalChannel(const H323Capability & capability,	
-								   H323Channel::Directions dir,
-								   unsigned sessionID,
-		 					           const H245_H2250LogicalChannelParameters * /*param*/,
-								   RTP_QOS * /*param*/ )
+H323Channel * MyH323Connection::CreateRealTimeLogicalChannel(const H323Capability & capability,
+									H323Channel::Directions dir,
+									unsigned sessionID,
+									const H245_H2250LogicalChannelParameters * /*param*/,
+									RTP_QOS * /*param*/ )
 {
 	return new MyH323_ExternalRTPChannel(*this, capability, dir, sessionID);
 }
 
 /** This callback function is invoked once upon creation of each
-  * channel for an H323 session 
+  * channel for an H323 session
   */
 BOOL MyH323Connection::OnStartLogicalChannel(H323Channel & channel)
-{    
+{
 	/* Increase the count of channels we have open */
 	channelsOpen++;
 
 	if (h323debug) {
-		cout << "\t-- Started logical channel: ";
-		cout << ((channel.GetDirection()==H323Channel::IsTransmitter)?"sending ":((channel.GetDirection()==H323Channel::IsReceiver)?"receiving ":" "));
-		cout << (const char *)(channel.GetCapability()).GetFormatName() << endl;
-		cout <<  "\t\t-- channelsOpen = " << channelsOpen << endl;
+		cout << "\t-- Started logical channel: "
+				<< ((channel.GetDirection() == H323Channel::IsTransmitter) ? "sending " : ((channel.GetDirection() == H323Channel::IsReceiver) ? "receiving " : " "))
+				<< (const char *)(channel.GetCapability()).GetFormatName() << endl;
+		cout << "\t\t-- channelsOpen = " << channelsOpen << endl;
 	}
 	return connectionState != ShuttingDownConnection;
 }
 
-void MyH323Connection::SetCapabilities(int cap, int dtmfMode)
+void MyH323Connection::SetCapabilities(int cap, int dtmf_mode, void *_prefs, int pref_codec)
 {
 	int g711Frames = 20;
-//	int gsmFrames  = 4;
+	int gsmFrames = 4;
 	PINDEX lastcap = -1; /* last common capability index */
+	int alreadysent = 0;
+	int codec;
+	int x, y;
+	char caps_str[1024];
+	struct ast_codec_pref *prefs = (struct ast_codec_pref *)_prefs;
 
+	localCapabilities.RemoveAll();
+
+	if (h323debug) {
+		cout << "Setting capabilities to " << ast_getformatname_multiple(caps_str, sizeof(caps_str), cap) << endl;
+		ast_codec_pref_string(prefs, caps_str, sizeof(caps_str));
+		cout << "Capabilities in preference order is " << caps_str << endl;
+	}
+	/* Add audio codecs in preference order first, then
+	   audio codecs without preference as allowed by mask */
+	for (y = 0, x = -1; x < 32 + 32; ++x) {
+		if (x < 0)
+			codec = pref_codec;
+		else if (y || (!(codec = ast_codec_pref_index(prefs, x)))) {
+			if (!y)
+				y = 1;
+			else if (y == AST_FORMAT_MAX_AUDIO)
+				break;
+			else
+				y <<= 1;
+			codec = y;
+		}
+		if (!(cap & codec) || (alreadysent & codec) || !(codec & AST_FORMAT_AUDIO_MASK))
+			continue;
+		alreadysent |= codec;
+		switch(codec) {
 #if 0
-	if (cap & AST_FORMAT_SPEEX) {
-		/* Not real sure if Asterisk acutally supports all
-		   of the various different bit rates so add them 
-		   all and figure it out later*/
-
-		localCapabilities.SetCapability(0, 0, new SpeexNarrow2AudioCapability());
-		localCapabilities.SetCapability(0, 0, new SpeexNarrow3AudioCapability());
-		localCapabilities.SetCapability(0, 0, new SpeexNarrow4AudioCapability());
-		localCapabilities.SetCapability(0, 0, new SpeexNarrow5AudioCapability());
-		localCapabilities.SetCapability(0, 0, new SpeexNarrow6AudioCapability());
-	}
-#endif 
-	if (cap & AST_FORMAT_G729A) {
-		AST_G729ACapability *g729aCap;
-		AST_G729Capability *g729Cap;
-		lastcap = localCapabilities.SetCapability(0, 0, g729aCap = new AST_G729ACapability);
-		lastcap = localCapabilities.SetCapability(0, 0, g729Cap = new AST_G729Capability);
-	}
-	
-	if (cap & AST_FORMAT_G723_1) {
-		H323_G7231Capability *g7231Cap;
-		lastcap = localCapabilities.SetCapability(0, 0, g7231Cap = new H323_G7231Capability);
-	} 
-#if 0
-	if (cap & AST_FORMAT_GSM) {
-		H323_GSM0610Capability *gsmCap;
-	    	lastcap = localCapabilities.SetCapability(0, 0, gsmCap = new H323_GSM0610Capability);
-	    	gsmCap->SetTxFramesInPacket(gsmFrames);
-	} 
+		case AST_FORMAT_SPEEX:
+			/* Not real sure if Asterisk acutally supports all
+			   of the various different bit rates so add them
+			   all and figure it out later*/
+
+			lastcap = localCapabilities.SetCapability(0, 0, new SpeexNarrow2AudioCapability());
+			lastcap = localCapabilities.SetCapability(0, 0, new SpeexNarrow3AudioCapability());
+			lastcap = localCapabilities.SetCapability(0, 0, new SpeexNarrow4AudioCapability());
+			lastcap = localCapabilities.SetCapability(0, 0, new SpeexNarrow5AudioCapability());
+			lastcap = localCapabilities.SetCapability(0, 0, new SpeexNarrow6AudioCapability());
+			break;
 #endif
-	if (cap & AST_FORMAT_ULAW) {
-		H323_G711Capability *g711uCap;
-	    	lastcap = localCapabilities.SetCapability(0, 0, g711uCap = new H323_G711Capability(H323_G711Capability::muLaw));
-		g711uCap->SetTxFramesInPacket(g711Frames);
-	} 
-
-	if (cap & AST_FORMAT_ALAW) {
-		H323_G711Capability *g711aCap;
-		lastcap = localCapabilities.SetCapability(0, 0, g711aCap = new H323_G711Capability(H323_G711Capability::ALaw));
-		g711aCap->SetTxFramesInPacket(g711Frames);
+		case AST_FORMAT_G729A:
+			AST_G729ACapability *g729aCap;
+			AST_G729Capability *g729Cap;
+			lastcap = localCapabilities.SetCapability(0, 0, g729aCap = new AST_G729ACapability);
+			lastcap = localCapabilities.SetCapability(0, 0, g729Cap = new AST_G729Capability);
+			break;
+		case AST_FORMAT_G723_1:
+			H323_G7231Capability *g7231Cap;
+			lastcap = localCapabilities.SetCapability(0, 0, g7231Cap = new H323_G7231Capability(TRUE));
+			lastcap = localCapabilities.SetCapability(0, 0, g7231Cap = new H323_G7231Capability(FALSE));
+			break;
+		case AST_FORMAT_GSM:
+			AST_GSM0610Capability *gsmCap;
+			lastcap = localCapabilities.SetCapability(0, 0, gsmCap = new AST_GSM0610Capability);
+			gsmCap->SetTxFramesInPacket(gsmFrames);
+			break;
+		case AST_FORMAT_ULAW:
+			H323_G711Capability *g711uCap;
+			lastcap = localCapabilities.SetCapability(0, 0, g711uCap = new H323_G711Capability(H323_G711Capability::muLaw));
+			g711uCap->SetTxFramesInPacket(g711Frames);
+			break;
+		case AST_FORMAT_ALAW:
+			H323_G711Capability *g711aCap;
+			lastcap = localCapabilities.SetCapability(0, 0, g711aCap = new H323_G711Capability(H323_G711Capability::ALaw));
+			g711aCap->SetTxFramesInPacket(g711Frames);
+			break;
+		default:
+			alreadysent &= ~codec;
+			break;
+		}
 	}
 
 	lastcap++;
 	lastcap = localCapabilities.SetCapability(0, lastcap, new H323_UserInputCapability(H323_UserInputCapability::HookFlashH245));
 
 	lastcap++;
-	mode = dtmfMode;
-	if (dtmfMode == H323_DTMF_INBAND) {
-		localCapabilities.SetCapability(0, lastcap, new H323_UserInputCapability(H323_UserInputCapability::SignalToneH245));
-		sendUserInputMode = SendUserInputAsTone;
+	dtmfMode = dtmf_mode;
+	if (dtmf_mode == H323_DTMF_INBAND) {
+		localCapabilities.SetCapability(0, lastcap, new H323_UserInputCapability(H323_UserInputCapability::BasicString));
+		sendUserInputMode = SendUserInputAsString;
 	} else {
-		localCapabilities.SetCapability(0, lastcap, new H323_UserInputCapability(H323_UserInputCapability::SignalToneRFC2833));
-		sendUserInputMode = SendUserInputAsInlineRFC2833;
+		lastcap = localCapabilities.SetCapability(0, lastcap, new H323_UserInputCapability(H323_UserInputCapability::SignalToneRFC2833));
+		/* Cisco sends DTMF only through h245-alphanumeric or h245-signal, no support for RFC2833 */
+		lastcap = localCapabilities.SetCapability(0, lastcap, new H323_UserInputCapability(H323_UserInputCapability::SignalToneH245));
+		sendUserInputMode = SendUserInputAsTone;	/* RFC2833 transmission handled at Asterisk level */
 	}
 
 	if (h323debug) {
-		cout <<  "Allowed Codecs:\n\t" << setprecision(2) << localCapabilities << endl;
+		cout << "Allowed Codecs:\n\t" << setprecision(2) << localCapabilities << endl;
 	}
 }
 
+BOOL MyH323Connection::StartControlChannel(const H225_TransportAddress & h245Address)
+{
+	// Check that it is an IP address, all we support at the moment
+	if (h245Address.GetTag() != H225_TransportAddress::e_ipAddress
+#if P_HAS_IPV6
+		&& h245Address.GetTag() != H225_TransportAddress::e_ip6Address
+#endif
+	) {
+		PTRACE(1, "H225\tConnect of H245 failed: Unsupported transport");
+		return FALSE;
+	}
+
+	// Already have the H245 channel up.
+	if (controlChannel != NULL)
+		return TRUE;
+
+	PIPSocket::Address addr;
+	WORD port;
+	GetSignallingChannel()->GetLocalAddress().GetIpAndPort(addr, port);
+	if (addr) {
+		if (h323debug)
+			cout << "Using " << addr << " for outbound H.245 transport" << endl;
+		controlChannel = new MyH323TransportTCP(endpoint, addr);
+	} else
+		controlChannel = new H323TransportTCP(endpoint);
+	if (!controlChannel->SetRemoteAddress(h245Address)) {
+		PTRACE(1, "H225\tCould not extract H245 address");
+		delete controlChannel;
+		controlChannel = NULL;
+		return FALSE;
+	}
+	if (!controlChannel->Connect()) {
+		PTRACE(1, "H225\tConnect of H245 failed: " << controlChannel->GetErrorText());
+		delete controlChannel;
+		controlChannel = NULL;
+		return FALSE;
+	}
+
+	controlChannel->StartControlChannel(*this);
+	return TRUE;
+}
+
 /* MyH323_ExternalRTPChannel */
 MyH323_ExternalRTPChannel::MyH323_ExternalRTPChannel(MyH323Connection & connection,
-						     const H323Capability & capability,
-                                                     Directions direction,
-                                                     unsigned id)
- : H323_ExternalRTPChannel::H323_ExternalRTPChannel(connection, capability, direction, id)
-{   
+							const H323Capability & capability,
+							Directions direction,
+							unsigned id)
+	: H323_ExternalRTPChannel::H323_ExternalRTPChannel(connection, capability, direction, id)
+{
 	struct rtp_info *info;
 
 	/* Determine the Local (A side) IP Address and port */
-	info = on_external_rtp_create(connection.GetCallReference(), (const char *)connection.GetCallToken()); 
+	info = on_external_rtp_create(connection.GetCallReference(), (const char *)connection.GetCallToken());
 	if (!info) {
 		cout << "\tERROR: on_external_rtp_create failure" << endl;
 		return;
 	} else {
 		localIpAddr = info->addr;
 		localPort = info->port;
-		/* tell the H.323 stack  */ 
+		/* tell the H.323 stack */
 		SetExternalAddress(H323TransportAddress(localIpAddr, localPort), H323TransportAddress(localIpAddr, localPort + 1));
 		/* clean up allocated memory */
 		free(info);
@@ -1071,9 +1737,9 @@ MyH323_ExternalRTPChannel::MyH323_ExternalRTPChannel(MyH323Connection & connecti
 	/* Get the payload code	*/
 	OpalMediaFormat format(capability.GetFormatName(), FALSE);
 	payloadCode = format.GetPayloadType();
-} 
+}
 
-MyH323_ExternalRTPChannel::~MyH323_ExternalRTPChannel() 
+MyH323_ExternalRTPChannel::~MyH323_ExternalRTPChannel()
 {
 	if (h323debug) {
 		cout << "\tExternalRTPChannel Destroyed" << endl;
@@ -1098,42 +1764,40 @@ BOOL MyH323_ExternalRTPChannel::Start(void)
 	if (h323debug) {
 		cout << "\t\t-- remoteIpAddress: " << remoteIpAddr << endl;
 		cout << "\t\t-- remotePort: " << remotePort << endl;
-		cout << "\t\t-- ExternalIpAddress: " <<  localIpAddr << endl;
+		cout << "\t\t-- ExternalIpAddress: " << localIpAddr << endl;
 		cout << "\t\t-- ExternalPort: " << localPort << endl;
 	}
 	/* Notify Asterisk of remote RTP information */
-	on_start_rtp_channel(connection.GetCallReference(), (const char *)remoteIpAddr.AsString(), remotePort, 
+	on_start_rtp_channel(connection.GetCallReference(), (const char *)remoteIpAddr.AsString(), remotePort,
 		(const char *)connection.GetCallToken(), (int)payloadCode);
 	return TRUE;
 }
 
 BOOL MyH323_ExternalRTPChannel::OnReceivedAckPDU(const H245_H2250LogicalChannelAckParameters & param)
 {
-	PIPSocket::Address remoteIpAddress;
-	WORD remotePort;
-
 	if (h323debug) {
 		cout << "	MyH323_ExternalRTPChannel::OnReceivedAckPDU" << endl;
 	}
 
 	if (H323_ExternalRTPChannel::OnReceivedAckPDU(param)) {
-		GetRemoteAddress(remoteIpAddress, remotePort);
+		GetRemoteAddress(remoteIpAddr, remotePort);
 		if (h323debug) {
-			cout << "		-- remoteIpAddress: " << remoteIpAddress << endl;
+			cout << "		-- remoteIpAddress: " << remoteIpAddr << endl;
 			cout << "		-- remotePort: " << remotePort << endl;
 		}
-		on_start_rtp_channel(connection.GetCallReference(), (const char *)remoteIpAddress.AsString(),
+		on_start_rtp_channel(connection.GetCallReference(), (const char *)remoteIpAddr.AsString(),
 				remotePort, (const char *)connection.GetCallToken(), (int)payloadCode);
 		return TRUE;
 	}
 	return FALSE;
 }
 
+
 /** IMPLEMENTATION OF C FUNCTIONS */
 
 /**
- * The extern "C" directive takes care for 
- * the ANSI-C representation of linkable symbols 
+ * The extern "C" directive takes care for
+ * the ANSI-C representation of linkable symbols
  */
 
 extern "C" {
@@ -1145,12 +1809,12 @@ int h323_end_point_exist(void)
 	}
 	return 1;
 }
-    
+
 void h323_end_point_create(void)
 {
 	channelsOpen = 0;
 	logstream = new PAsteriskLog();
-	localProcess = new MyProcess();	
+	localProcess = new MyProcess();
 	localProcess->Main();
 }
 
@@ -1159,33 +1823,34 @@ void h323_gk_urq(void)
 	if (!h323_end_point_exist()) {
 		cout << " ERROR: [h323_gk_urq] No Endpoint, this is bad" << endl;
 		return;
-	}	
+	}
 	endPoint->RemoveGatekeeper();
 }
 
 void h323_debug(int flag, unsigned level)
 {
 	if (flag) {
-		PTrace:: SetLevel(level); 
-	} else { 
-		PTrace:: SetLevel(0); 
-	}
-}
-	
-/** Installs the callback functions on behalf of the PBX application  */
-void h323_callback_register(setup_incoming_cb  	ifunc,
-			    setup_outbound_cb  	sfunc,
- 			    on_rtp_cb   	rtpfunc,
-			    start_rtp_cb   	lfunc,
- 			    clear_con_cb	clfunc,
- 			    chan_ringing_cb     rfunc,
-			    con_established_cb 	efunc,
- 			    send_digit_cb	dfunc,
- 			    answer_call_cb	acfunc,
-			    progress_cb		pgfunc,
-			    rfc2833_cb		dtmffunc,
-			    hangup_cb		hangupfunc,
-			    setcapabilities_cb	capabilityfunc)
+		PTrace:: SetLevel(level);
+	} else {
+		PTrace:: SetLevel(0);
+	}
+}
+
+/** Installs the callback functions on behalf of the PBX application */
+void h323_callback_register(setup_incoming_cb		ifunc,
+							setup_outbound_cb		sfunc,
+							on_rtp_cb				rtpfunc,
+							start_rtp_cb			lfunc,
+							clear_con_cb			clfunc,
+							chan_ringing_cb			rfunc,
+							con_established_cb		efunc,
+							receive_digit_cb		dfunc,
+							answer_call_cb			acfunc,
+							progress_cb				pgfunc,
+							rfc2833_cb				dtmffunc,
+							hangup_cb				hangupfunc,
+							setcapabilities_cb		capabilityfunc,
+							setpeercapabilities_cb	peercapabilityfunc)
 {
 	on_incoming_call = ifunc;
 	on_outgoing_call = sfunc;
@@ -1194,18 +1859,19 @@ void h323_callback_register(setup_incoming_cb  	ifunc,
 	on_connection_cleared = clfunc;
 	on_chan_ringing = rfunc;
 	on_connection_established = efunc;
-	on_send_digit = dfunc;
+	on_receive_digit = dfunc;
 	on_answer_call = acfunc;
 	on_progress = pgfunc;
 	on_set_rfc2833_payload = dtmffunc;
 	on_hangup = hangupfunc;
 	on_setcapabilities = capabilityfunc;
+	on_setpeercapabilities = peercapabilityfunc;
 }
 
 /**
- * Add capability to the capability table of the end point. 
+ * Add capability to the capability table of the end point.
  */
-int h323_set_capabilities(const char *token, int cap, int dtmfMode)
+int h323_set_capabilities(const char *token, int cap, int dtmf_mode, struct ast_codec_pref *prefs, int pref_codec)
 {
 	MyH323Connection *conn;
 
@@ -1224,7 +1890,7 @@ int h323_set_capabilities(const char *token, int cap, int dtmfMode)
 		cout << " ERROR: [h323_set_capabilities] Unable to find connection " << token << endl;
 		return 1;
 	}
-	conn->SetCapabilities(cap, dtmfMode);
+	conn->SetCapabilities((/*conn->bridging ? conn->redir_capabilities :*/ cap), dtmf_mode, prefs, pref_codec);
 	conn->Unlock();
 
 	return 0;
@@ -1233,29 +1899,28 @@ int h323_set_capabilities(const char *token, int cap, int dtmfMode)
 /** Start the H.323 listener */
 int h323_start_listener(int listenPort, struct sockaddr_in bindaddr)
 {
-	
+
 	if (!h323_end_point_exist()) {
 		cout << "ERROR: [h323_start_listener] No Endpoint, this is bad!" << endl;
 		return 1;
 	}
-	
+
 	PIPSocket::Address interfaceAddress(bindaddr.sin_addr);
 	if (!listenPort) {
 		listenPort = 1720;
 	}
-	/** H.323 listener */  
+	/** H.323 listener */
 	H323ListenerTCP *tcpListener;
 	tcpListener = new H323ListenerTCP(*endPoint, interfaceAddress, (WORD)listenPort);
 	if (!endPoint->StartListener(tcpListener)) {
 		cout << "ERROR: Could not open H.323 listener port on " << ((H323ListenerTCP *) tcpListener)->GetListenerPort() << endl;
 		delete tcpListener;
 		return 1;
-		
 	}
 	cout << "  == H.323 listener started" << endl;
 	return 0;
 };
- 
+
 int h323_set_alias(struct oh323_alias *alias)
 {
 	char *p;
@@ -1263,14 +1928,14 @@ int h323_set_alias(struct oh323_alias *alias)
 	PString h323id(alias->name);
 	PString e164(alias->e164);
 	char *prefix;
-	
+
 	if (!h323_end_point_exist()) {
 		cout << "ERROR: [h323_set_alias] No Endpoint, this is bad!" << endl;
 		return 1;
 	}
 
 	cout << "== Adding alias \"" << h323id << "\" to endpoint" << endl;
-	endPoint->AddAliasName(h323id);	
+	endPoint->AddAliasName(h323id);
 	endPoint->RemoveAliasName(localProcess->GetUserName());
 
 	if (!e164.IsEmpty()) {
@@ -1306,7 +1971,7 @@ void h323_show_tokens(void)
 	cout << "Current call tokens: " << setprecision(2) << endPoint->GetAllConnections() << endl;
 }
 
-/** Establish Gatekeeper communiations, if so configured, 
+/** Establish Gatekeeper communiations, if so configured,
   *	register aliases for the H.323 endpoint to respond to.
   */
 int h323_set_gk(int gatekeeper_discover, char *gatekeeper, char *secret)
@@ -1329,14 +1994,14 @@ int h323_set_gk(int gatekeeper_discover, char *gatekeeper, char *secret)
 	}
 	if (gatekeeper_discover) {
 		/* discover the gk using multicast */
-		if (endPoint->DiscoverGatekeeper(new H323TransportUDP(*endPoint))) {
+		if (endPoint->DiscoverGatekeeper(new MyH323TransportUDP(*endPoint))) {
 			cout << "== Using " << (endPoint->GetGatekeeper())->GetName() << " as our Gatekeeper." << endl;
 		} else {
 			cout << "Warning: Could not find a gatekeeper." << endl;
 			return 1;
-		}	
+		}
 	} else {
-		rasChannel = new H323TransportUDP(*endPoint);
+		rasChannel = new MyH323TransportUDP(*endPoint);
 
 		if (!rasChannel) {
 			cout << "Error: No RAS Channel, this is bad" << endl;
@@ -1378,7 +2043,7 @@ int h323_make_call(char *dest, call_details_t *cd, call_options_t *call_options)
 		return 1;
 	}
 
-	res = endPoint->MakeCall(host, token, &cd->call_reference, call_options);
+	res = endPoint->MyMakeCall(host, token, &cd->call_reference, call_options);
 	memcpy((char *)(cd->call_token), (const unsigned char *)token, token.GetLength());
 	return res;
 };
@@ -1411,48 +2076,47 @@ int h323_clear_call(const char *call_token, int cause)
 /* Send Alerting PDU to H.323 caller */
 int h323_send_alerting(const char *token)
 {
-        const PString currentToken(token);
-        H323Connection * connection;
-
-        if (h323debug) {
-        	cout << "\tSending alerting\n" << endl;
-        }
-        connection = endPoint->FindConnectionWithLock(currentToken);
-        if (!connection) {
-                cout << "No connection found for " << token << endl;
-                return -1;
-        }
-        connection->AnsweringCall(H323Connection::AnswerCallPending);
-        connection->Unlock();
-        return 0; 
+	const PString currentToken(token);
+	H323Connection * connection;
 
+	if (h323debug) {
+		cout << "\tSending alerting" << endl;
+	}
+	connection = endPoint->FindConnectionWithLock(currentToken);
+	if (!connection) {
+		cout << "No connection found for " << token << endl;
+		return -1;
+	}
+	connection->AnsweringCall(H323Connection::AnswerCallPending);
+	connection->Unlock();
+	return 0;
 }
 
 /* Send Progress PDU to H.323 caller */
 int h323_send_progress(const char *token)
 {
-        const PString currentToken(token);
-        H323Connection * connection;
+	const PString currentToken(token);
+	H323Connection * connection;
 
-        connection = endPoint->FindConnectionWithLock(currentToken);
-        if (!connection) {
-                cout << "No connection found for " << token << endl;
-                return -1;
-        }
-        connection->AnsweringCall(H323Connection::AnswerCallDeferredWithMedia);
-        connection->Unlock();
-        return 0;  
+	connection = endPoint->FindConnectionWithLock(currentToken);
+	if (!connection) {
+		cout << "No connection found for " << token << endl;
+		return -1;
+	}
+	connection->AnsweringCall(H323Connection::AnswerCallDeferredWithMedia);
+	connection->Unlock();
+	return 0;
 }
 
-/** This function tells the h.323 stack to either 
-    answer or deny an incoming call  */
-int h323_answering_call(const char *token, int busy) 
+/** This function tells the h.323 stack to either
+    answer or deny an incoming call */
+int h323_answering_call(const char *token, int busy)
 {
 	const PString currentToken(token);
 	H323Connection * connection;
-	
+
 	connection = endPoint->FindConnectionWithLock(currentToken);
-	
+
 	if (!connection) {
 		cout << "No connection found for " << token << endl;
 		return -1;
@@ -1472,44 +2136,39 @@ int h323_answering_call(const char *token, int busy)
 	return 0;
 }
 
-int h323_show_codec(int fd, int argc, char *argv[])
-{
-	cout <<  "Allowed Codecs:\n\t" << setprecision(2) << endPoint->GetCapabilities() << endl;
-	return 0;
-}
-
 int h323_soft_hangup(const char *data)
 {
 	PString token(data);
 	BOOL result;
-	cout << "Soft hangup" << endl;	
-	result = endPoint->ClearCall(token);	
+	cout << "Soft hangup" << endl;
+	result = endPoint->ClearCall(token);
 	return result;
 }
 
-/* alas, this doesn't work :(   */
+/* alas, this doesn't work :( */
 void h323_native_bridge(const char *token, const char *them, char *capability)
 {
 	H323Channel *channel;
 	MyH323Connection *connection = (MyH323Connection *)endPoint->FindConnectionWithLock(token);
-	
+
 	if (!connection) {
-		cout << "ERROR: No connection found, this is bad\n";
+		cout << "ERROR: No connection found, this is bad" << endl;
 		return;
 	}
 
-	cout << "Native Bridge:  them [" << them << "]" << endl; 
+	cout << "Native Bridge:  them [" << them << "]" << endl;
 
 	channel = connection->FindChannel(connection->sessionId, TRUE);
 	connection->bridging = TRUE;
 	connection->CloseLogicalChannelNumber(channel->GetNumber());
-	
+
 	connection->Unlock();
 	return;
 
 }
 
 #undef cout
+#undef endl
 void h323_end_process(void)
 {
 	if (endPoint) {
@@ -1521,10 +2180,12 @@ void h323_end_process(void)
 	if (localProcess) {
 		delete localProcess;
 		localProcess = NULL;
+		close(_timerChangePipe[0]);
+		close(_timerChangePipe[1]);
 	}
-	PTrace::SetLevel(0);
-	PTrace::SetStream(&cout);
 	if (logstream) {
+		PTrace::SetLevel(0);
+		PTrace::SetStream(&cout);
 		delete logstream;
 		logstream = NULL;
 	}
diff --git a/channels/h323/ast_h323.h b/channels/h323/ast_h323.h
index 5bab9fc3bb15800149293cab0cf471998e83fe1c..b866e2cdef5ebb89e4774ef2ca79b0f7378ce545 100644
--- a/channels/h323/ast_h323.h
+++ b/channels/h323/ast_h323.h
@@ -13,24 +13,27 @@
  * chan_h323 is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version. 
+ * (at your option) any later version.
  *
- * chan_h323 is distributed WITHOUT ANY WARRANTY; without even 
- * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
- * PURPOSE. See the GNU General Public License for more details. 
+ * chan_h323 is distributed WITHOUT ANY WARRANTY; without even
+ * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
- * Version Info: $Id$ 
+ * Version Info: $Id$
  */
 
 #ifndef AST_H323_H
 #define AST_H323_H
 
+#define VERSION(a,b,c) ((a)*10000+(b)*100+(c))
+
+#if 0
 /**  These need to be redefined here because the C++
-	 side of this driver is blind to the asterisk headers */	
+     side of this driver is blind to the asterisk headers */
 /*! G.723.1 compression */
 #define AST_FORMAT_G723_1	(1 << 0)
 /*! GSM compression */
@@ -52,114 +55,149 @@
 /*! SpeeX Free Compression */
 #define AST_FORMAT_SPEEX	(1 << 9)
 /*! ILBC Free Codec */
-#define AST_FORMAT_ILBC         (1 << 10)
+#define AST_FORMAT_ILBC		(1 << 10)
+#endif
 
 /**This class describes the G.723.1 codec capability.
  */
 class H323_G7231Capability : public H323AudioCapability
 {
-    PCLASSINFO(H323_G7231Capability, H323AudioCapability);
-  public:
-    	H323_G7231Capability(BOOL annexA = TRUE);
-    	Comparison Compare(const PObject & obj) const;
-   	PObject * Clone() const;
-  	virtual H323Codec * CreateCodec(H323Codec::Direction direction) const;
-	unsigned GetSubType() const;
-	PString GetFormatName() const;
-    	BOOL OnSendingPDU(H245_AudioCapability & pdu, unsigned packetSize) const;
-	BOOL OnReceivedPDU(const H245_AudioCapability & pdu, unsigned & packetSize);
-  protected:
-    	BOOL annexA;
+	PCLASSINFO(H323_G7231Capability, H323AudioCapability);
+
+public:
+	H323_G7231Capability(BOOL annexA = TRUE);
+	Comparison Compare(const PObject & obj) const;
+	virtual PObject * Clone() const;
+	virtual H323Codec * CreateCodec(H323Codec::Direction direction) const;
+	virtual unsigned GetSubType() const;
+	virtual PString GetFormatName() const;
+	virtual BOOL OnSendingPDU(H245_AudioCapability & pdu, unsigned packetSize) const;
+	virtual BOOL OnReceivedPDU(const H245_AudioCapability & pdu, unsigned & packetSize);
+
+protected:
+	BOOL annexA;
 };
 
 /**This class describes the (fake) G729 codec capability.
  */
 class AST_G729Capability : public H323AudioCapability
 {
-  PCLASSINFO(AST_G729Capability, H323AudioCapability);
+	PCLASSINFO(AST_G729Capability, H323AudioCapability);
 
-  public:
-    AST_G729Capability();
-    /* Create a copy of the object. */
-    virtual PObject * Clone() const;
+public:
+	AST_G729Capability();
+	/* Create a copy of the object. */
+	virtual PObject * Clone() const;
 
-    /* Create the codec instance, allocating resources as required. */
-    virtual H323Codec * CreateCodec(H323Codec::Direction direction) const;
+	/* Create the codec instance, allocating resources as required. */
+	virtual H323Codec * CreateCodec(H323Codec::Direction direction) const;
 
-    /* Get the sub-type of the capability. This is a code dependent on the
-       main type of the capability.
+	/* Get the sub-type of the capability. This is a code dependent on the
+	   main type of the capability.
 
-       This returns one of the four possible combinations of mode and speed
-       using the enum values of the protocol ASN H245_AudioCapability class. */
-    virtual unsigned GetSubType() const;
-
-    /* Get the name of the media data format this class represents. */
-    virtual PString GetFormatName() const;
+	   This returns one of the four possible combinations of mode and speed
+	   using the enum values of the protocol ASN H245_AudioCapability class. */
+	virtual unsigned GetSubType() const;
 
+	/* Get the name of the media data format this class represents. */
+	virtual PString GetFormatName() const;
 };
 
 /* This class describes the VoiceAge G729A codec capability. */
 class AST_G729ACapability : public H323AudioCapability
 {
-  PCLASSINFO(AST_G729ACapability, H323AudioCapability);
+	PCLASSINFO(AST_G729ACapability, H323AudioCapability);
 
-  public:
-    /* Create a new G.729A capability. */
-    AST_G729ACapability();
+public:
+	/* Create a new G.729A capability. */
+	AST_G729ACapability();
 
-    /* Create a copy of the object. */
-    virtual PObject * Clone() const;
-    /* Create the codec instance, allocating resources as required. */
-    virtual H323Codec * CreateCodec(H323Codec::Direction direction) const;
+	/* Create a copy of the object. */
+	virtual PObject * Clone() const;
+	/* Create the codec instance, allocating resources as required. */
+	virtual H323Codec * CreateCodec(H323Codec::Direction direction) const;
 
-    /* Get the sub-type of the capability. This is a code dependent on the
-       main type of the capability.
+	/* Get the sub-type of the capability. This is a code dependent on the
+	   main type of the capability.
 
-       This returns one of the four possible combinations of mode and speed
-       using the enum values of the protocol ASN H245_AudioCapability class. */
-    virtual unsigned GetSubType() const;
+	   This returns one of the four possible combinations of mode and speed
+	   using the enum values of the protocol ASN H245_AudioCapability class. */
+	virtual unsigned GetSubType() const;
 
-    /* Get the name of the media data format this class represents. */
-    virtual PString GetFormatName() const;
+	/* Get the name of the media data format this class represents. */
+	virtual PString GetFormatName() const;
 };
 
-class MyH323EndPoint : public H323EndPoint {
+/* This class describes the GSM-06.10 codec capability. */
+class AST_GSM0610Capability : public H323AudioCapability
+{
+	PCLASSINFO(AST_GSM0610Capability, H323AudioCapability);
+
+public:
+	/* Create a new GSM capability. */
+	AST_GSM0610Capability(int comfortNoise = 0, int scrambled = 0);
+
+	/* Create a copy of the object. */
+	virtual PObject * Clone() const;
+
+	/* Create the codec instance, allocating resources as required. */
+	virtual H323Codec * CreateCodec(H323Codec::Direction direction) const;
 
+	/* Get the sub-type of the capability. This is a code dependent on the
+	   main type of the capability.
+
+	   This returns one of the four possible combinations of mode and speed
+	   using the enum values of the protocol ASN H245_AudioCapability class. */
+	virtual unsigned GetSubType() const;
+
+	/* Get the name of the media data format this class represents. */
+	virtual PString GetFormatName() const;
+
+	BOOL OnSendingPDU(H245_AudioCapability & pdu, unsigned packetSize) const;
+	BOOL OnReceivedPDU(const H245_AudioCapability & pdu, unsigned & packetSize);
+
+protected:
+	int comfortNoise;
+	int scrambled;
+};
+
+class MyH323EndPoint : public H323EndPoint
+{
 	PCLASSINFO(MyH323EndPoint, H323EndPoint);
 
-	public:
+public:
 	MyH323EndPoint();
-	int MakeCall(const PString &, PString &, unsigned int *, call_options_t *opts);
+	int MyMakeCall(const PString &, PString &, void *_callReference, void *_opts);
 	BOOL ClearCall(const PString &, H323Connection::CallEndReason reason);
 	BOOL ClearCall(const PString &);
 
 	void OnClosedLogicalChannel(H323Connection &, const H323Channel &);
 	void OnConnectionEstablished(H323Connection &, const PString &);
 	void OnConnectionCleared(H323Connection &, const PString &);
-	H323Connection * CreateConnection(unsigned, void *);
+	virtual H323Connection * CreateConnection(unsigned, void *, H323Transport *, H323SignalPDU *);
 	void SendUserTone(const PString &, char);
 	BOOL OnConnectionForwarded(H323Connection &, const PString &, const H323SignalPDU &);
 	BOOL ForwardConnection(H323Connection &, const PString &, const H323SignalPDU &);
-    	void SetEndpointTypeInfo( H225_EndpointType & info ) const;
-    	void SetGateway(void);
-	PStringArray SupportedPrefixes;	
+	void SetEndpointTypeInfo( H225_EndpointType & info ) const;
+	void SetGateway(void);
+	PStringArray SupportedPrefixes;
 };
 
-class MyH323Connection : public H323Connection {
-
+class MyH323Connection : public H323Connection
+{
 	PCLASSINFO(MyH323Connection, H323Connection);
 
-	public:
+public:
 	MyH323Connection(MyH323EndPoint &, unsigned, unsigned);
 	~MyH323Connection();
-	H323Channel * CreateRealTimeLogicalChannel(const H323Capability &, 
-						   H323Channel::Directions, 
-					 	   unsigned, 
-						   const H245_H2250LogicalChannelParameters *,
-						   RTP_QOS *);
-	H323Connection::AnswerCallResponse OnAnswerCall(const PString &, 
-							const H323SignalPDU &, 
-							H323SignalPDU &);
+	H323Channel * CreateRealTimeLogicalChannel(const H323Capability &,
+			H323Channel::Directions,
+			unsigned,
+			const H245_H2250LogicalChannelParameters *,
+			RTP_QOS *);
+	H323Connection::AnswerCallResponse OnAnswerCall(const PString &,
+			const H323SignalPDU &,
+			H323SignalPDU &);
 	void OnReceivedReleaseComplete(const H323SignalPDU &);
 	BOOL OnAlerting(const H323SignalPDU &, const PString &);
 	BOOL OnSendReleaseComplete(H323SignalPDU &);
@@ -167,46 +205,57 @@ class MyH323Connection : public H323Connection {
 	BOOL OnReceivedFacility(const H323SignalPDU &);
 	BOOL OnSendSignalSetup(H323SignalPDU &);
 	BOOL OnStartLogicalChannel(H323Channel &);
-	BOOL OnClosingLogicalChannel(H323Channel &);	
-	void SendUserInputTone(char, unsigned);
-	void OnUserInputTone(char, unsigned, unsigned, unsigned);
-	void OnUserInputString(const PString &value);
+	BOOL OnClosingLogicalChannel(H323Channel &);
+	virtual void SendUserInputTone(char tone, unsigned duration = 0, unsigned logicalChannel = 0, unsigned rtpTimestamp = 0);
+	virtual void OnUserInputTone(char, unsigned, unsigned, unsigned);
+	virtual void OnUserInputString(const PString &value);
 	BOOL OnReceivedProgress(const H323SignalPDU &);
 	void OnSendCapabilitySet(H245_TerminalCapabilitySet &);
 	void OnSetLocalCapabilities();
-	void SetCapabilities(int, int);
+	void SetCapabilities(int, int, void *, int);
 	BOOL OnReceivedCapabilitySet(const H323Capabilities &, const H245_MultiplexCapability *,
-				     H245_TerminalCapabilitySetReject &);
+			H245_TerminalCapabilitySetReject &);
 	void SetCause(int _cause) { cause = _cause; };
+	virtual BOOL StartControlChannel(const H225_TransportAddress & h245Address);
+	void SetCallOptions(void *opts, BOOL isIncoming);
+	void SetCallDetails(void *callDetails, const H323SignalPDU &setupPDU, BOOL isIncoming);
+#ifdef TUNNELLING
+	virtual BOOL HandleSignalPDU(H323SignalPDU &pdu);
+	BOOL EmbedTunneledInfo(H323SignalPDU &pdu);
+#endif
 
 	PString sourceAliases;
 	PString destAliases;
 	PString sourceE164;
 	PString destE164;
+	PString rdnis;
+	int redirect_reason;
 
 	WORD sessionId;
-	BOOL bridging;			
+	BOOL bridging;
+#ifdef TUNNELLING
+	int remoteTunnelOptions;
+	int tunnelOptions;
+#endif
 
 	unsigned progressSetup;
 	unsigned progressAlert;
 	int cause;
 
 	RTP_DataFrame::PayloadTypes dtmfCodec;
-
-	PString ast_cid_num;
-	PString ast_cid_name;
+	int dtmfMode;
 };
 
-class MyH323_ExternalRTPChannel : public H323_ExternalRTPChannel {
-
-        PCLASSINFO(MyH323_ExternalRTPChannel, H323_ExternalRTPChannel);
+class MyH323_ExternalRTPChannel : public H323_ExternalRTPChannel
+{
+	PCLASSINFO(MyH323_ExternalRTPChannel, H323_ExternalRTPChannel);
 
-        public:
+public:
 	MyH323_ExternalRTPChannel(
-		MyH323Connection & connection,
-      		const H323Capability & capability, 
-      		Directions direction,              
-      		unsigned sessionID);
+			MyH323Connection & connection,
+			const H323Capability & capability,
+			Directions direction,
+			unsigned sessionID);
 
 	~MyH323_ExternalRTPChannel();
 
@@ -214,26 +263,29 @@ class MyH323_ExternalRTPChannel : public H323_ExternalRTPChannel {
 	BOOL Start(void);
 	BOOL OnReceivedAckPDU(const H245_H2250LogicalChannelAckParameters & param);
 
-	protected:
+protected:
 	BYTE payloadCode;
 
 	PIPSocket::Address localIpAddr;
 	PIPSocket::Address remoteIpAddr;
-        WORD localPort;
-        WORD remotePort;
-}; 
+	WORD localPort;
+	WORD remotePort;
+};
 
 /**
- * The MyProcess is a necessary descendant PProcess class so that the H323EndPoint 
- * objected to be created from within that class. (Solves the who owns main() problem). 
+ * The MyProcess is a necessary descendant PProcess class so that the H323EndPoint
+ * objected to be created from within that class. (Solves the who owns main() problem).
  */
-class MyProcess : public PProcess {
-
+class MyProcess : public PProcess
+{
 	PCLASSINFO(MyProcess, PProcess);
-    
-	public:
+
+public:
 	MyProcess();
-	void Main(); 
+	~MyProcess();
+	void Main();
 };
 
+#include "compat_h323.h"
+
 #endif /* !defined AST_H323_H */
diff --git a/channels/h323/chan_h323.h b/channels/h323/chan_h323.h
index 1ca681c77df3c89b4b299154057ebf021485a130..d6be63f4f435ce0de711d4c93c03e52a31632db1 100644
--- a/channels/h323/chan_h323.h
+++ b/channels/h323/chan_h323.h
@@ -4,8 +4,8 @@
  * OpenH323 Channel Driver for ASTERISK PBX.
  *			By Jeremy McNamara
  * 			For The NuFone Network
- *	
- * This code has been derived from code created by 
+ *
+ * This code has been derived from code created by
  *		Michael Manousos and Mark Spencer
  *
  * This file is part of the chan_h323 driver for Asterisk
@@ -13,29 +13,42 @@
  * chan_h323 is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version. 
+ * (at your option) any later version.
  *
- * chan_h323 is distributed WITHOUT ANY WARRANTY; without even 
- * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
- * PURPOSE. See the GNU General Public License for more details. 
+ * chan_h323 is distributed WITHOUT ANY WARRANTY; without even
+ * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
  * Version Info: $Id$
  */
 
 #include <arpa/inet.h>
 
+/*
+ * Enable support for sending/reception of tunnelled Q.SIG messages and
+ * some sort of IEs (especially RedirectingNumber) which Cisco CallManager
+ * isn't like to pass in standard Q.931 message.
+ *
+ */
+#define TUNNELLING
+
+#define H323_TUNNEL_CISCO	(1 << 0)
+#define H323_TUNNEL_QSIG	(1 << 1)
+
 /** call_option struct holds various bits
  *         of information for each call */
 typedef struct call_options {
 	char			cid_num[80];
 	char			cid_name[80];
-	int				noFastStart;
-	int				noH245Tunneling;
-	int				noSilenceSuppression;
+	char			cid_rdnis[80];
+	int				redirect_reason;
+	int				fastStart;
+	int				h245Tunneling;
+	int				silenceSuppression;
 	int				progress_setup;
 	int				progress_alert;
 	int				progress_audio;
@@ -44,57 +57,58 @@ typedef struct call_options {
 	int				capability;
 	int				bridge;
 	int				nat;
+	int				tunnelOptions;
+	struct ast_codec_pref	prefs;
 } call_options_t;
 
 /* structure to hold the valid asterisk users */
 struct oh323_user {
-	char name[80];
+	ASTOBJ_COMPONENTS(struct oh323_user);
+//	char name[80];
 	char context[80];
 	char secret[80];
-	char callerid[80];
 	char accountcode[AST_MAX_ACCOUNT_CODE];
 	int amaflags;
 	int host;
 	struct sockaddr_in addr;
 	struct ast_ha *ha;
 	call_options_t options;
-	struct oh323_user *next;
 };
 
-/* structure to hold the valid asterisk peers 
+/* structure to hold the valid asterisk peers
    All peers are registered to a GK if there is one */
 struct oh323_peer {
-	char name[80];
+	ASTOBJ_COMPONENTS(struct oh323_peer);
 	char mailbox[80];
 	int delme;
 	struct sockaddr_in addr;
 	struct ast_ha *ha;
 	call_options_t options;
-	struct oh323_peer *next;
 };
 
-/* structure to hold the H.323 aliases which get registered to 
+/* structure to hold the H.323 aliases which get registered to
    the H.323 endpoint and gatekeeper */
 struct oh323_alias {
-	char name[80];
+	ASTOBJ_COMPONENTS(struct oh323_alias);
 	char e164[20];				/* tells a GK to route this E.164 to this alias */
 	char prefix[500];			/* tells a GK this alias supports these prefixes */
 	char secret[20];			/* the H.235 password to send to the GK for authentication */
 	char context[80];
-	struct oh323_alias *next;	
 };
 
-/** call_details struct call detail records 
-	to asterisk for processing and used for matching up 
+/** call_details struct call detail records
+	to asterisk for processing and used for matching up
 	asterisk channels to acutal h.323 connections */
-typedef struct call_details {	
+typedef struct call_details {
 	unsigned int call_reference;
-	char *call_token;				
+	char *call_token;
 	char *call_source_aliases;
 	char *call_dest_alias;
 	char *call_source_name;
 	char *call_source_e164;
 	char *call_dest_e164;
+	char *redirect_number;
+	int redirect_reason;
 	int presentation;
 	int screening;
 	char *sourceIp;
@@ -107,18 +121,18 @@ typedef struct rtp_info {
 
 /* This is a callback prototype function, called pass
    DTMF down the RTP. */
-typedef int (*send_digit_cb)(unsigned, char, const char *);
-extern send_digit_cb on_send_digit; 
+typedef int (*receive_digit_cb)(unsigned, char, const char *, int);
+extern receive_digit_cb on_receive_digit;
 
 /* This is a callback prototype function, called to collect
    the external RTP port from Asterisk. */
 typedef rtp_info_t *(*on_rtp_cb)(unsigned, const char *);
-extern on_rtp_cb on_external_rtp_create; 
+extern on_rtp_cb on_external_rtp_create;
 
 /* This is a callback prototype function, called to send
-   the remote IP and RTP port from H.323 to Asterisk */ 
+   the remote IP and RTP port from H.323 to Asterisk */
 typedef void (*start_rtp_cb)(unsigned int, const char *, int, const char *, int);
-extern start_rtp_cb on_start_rtp_channel; 
+extern start_rtp_cb on_start_rtp_channel;
 
 /* This is a callback that happens when call progress is
  * made, and handles inband progress */
@@ -133,7 +147,7 @@ extern setup_incoming_cb on_incoming_call;
 /* This is a callback prototype function, called upon
    an outbound call. */
 typedef int (*setup_outbound_cb)(call_details_t *);
-extern setup_outbound_cb on_outgoing_call; 
+extern setup_outbound_cb on_outgoing_call;
 
 /* This is a callback prototype function, called when
    OnAlerting is invoked */
@@ -151,7 +165,7 @@ typedef void (*clear_con_cb)(unsigned, const char *);
 extern clear_con_cb on_connection_cleared;
 
 /* This is a callback prototype function, called when
-    an H.323 call is answered */
+   an H.323 call is answered */
 typedef int (*answer_call_cb)(unsigned, const char *);
 extern answer_call_cb on_answer_call;
 
@@ -167,6 +181,9 @@ extern hangup_cb on_hangup;
 typedef void (*setcapabilities_cb)(unsigned, const char *);
 extern setcapabilities_cb on_setcapabilities;
 
+typedef void (*setpeercapabilities_cb)(unsigned, const char *, int);
+extern setpeercapabilities_cb on_setpeercapabilities;
+
 /* debug flag */
 extern int h323debug;
 
@@ -179,30 +196,31 @@ extern int h323debug;
 
 #ifdef __cplusplus
 extern "C" {
-#endif   
-    
+#endif
+
 	void h323_gk_urq(void);
 	void h323_end_point_create(void);
 	void h323_end_process(void);
 	int  h323_end_point_exist(void);
-    
+
 	void h323_debug(int, unsigned);
 
 	/* callback function handler*/
-	void h323_callback_register(setup_incoming_cb,  
-				    setup_outbound_cb,
- 				    on_rtp_cb,
-				    start_rtp_cb,
- 				    clear_con_cb,
- 				    chan_ringing_cb,
-				    con_established_cb,
- 				    send_digit_cb,
- 				    answer_call_cb,
-				    progress_cb,
-				    rfc2833_cb,
-				    hangup_cb,
-				    setcapabilities_cb);
-	int h323_set_capabilities(const char *, int, int);
+	void h323_callback_register(setup_incoming_cb,
+					setup_outbound_cb,
+					on_rtp_cb,
+					start_rtp_cb,
+					clear_con_cb,
+					chan_ringing_cb,
+					con_established_cb,
+					receive_digit_cb,
+					answer_call_cb,
+					progress_cb,
+					rfc2833_cb,
+					hangup_cb,
+					setcapabilities_cb,
+					setpeercapabilities_cb);
+	int h323_set_capabilities(const char *, int, int, struct ast_codec_pref *, int);
 	int h323_set_alias(struct oh323_alias *);
 	int h323_set_gk(int, char *, char *);
 	void h323_set_id(char *);
@@ -219,12 +237,12 @@ extern "C" {
 	/* H323 create and destroy sessions */
 	int h323_make_call(char *dest, call_details_t *cd, call_options_t *);
 	int h323_clear_call(const char *, int cause);
-	
+
 	/* H.323 alerting and progress */
 	int h323_send_alerting(const char *token);
 	int h323_send_progress(const char *token);
 	int h323_answering_call(const char *token, int);
-	int h323_soft_hangup(const char *data);	
+	int h323_soft_hangup(const char *data);
 	int h323_show_codec(int fd, int argc, char *argv[]);
 
 #ifdef __cplusplus
diff --git a/channels/h323/h323.conf.sample b/channels/h323/h323.conf.sample
index 16439758087beed699b212919c6456c0b190932b..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 100644
--- a/channels/h323/h323.conf.sample
+++ b/channels/h323/h323.conf.sample
@@ -1,149 +0,0 @@
-; The NuFone Network's
-; Open H.323 driver configuration
-;
-[general]
-port = 1720
-bindaddr = 1.2.3.4 	; this SHALL contain a single, valid IP address for this machine
-;tos=lowdelay
-;
-; You may specify a global default AMA flag for iaxtel calls.  It must be
-; one of 'default', 'omit', 'billing', or 'documentation'.  These flags
-; are used in the generation of call detail records.
-;
-;amaflags = default
-;
-; You may specify a default account for Call Detail Records in addition
-; to specifying on a per-user basis
-;
-;accountcode=lss0101
-;
-; You can fine tune codecs here using "allow" and "disallow" clauses
-; with specific codecs.  Use "all" to represent all formats.
-;
-disallow=all
-;allow=all		; turns on all installed codecs
-;disallow=g723.1	; Hm...  Proprietary, don't use it...
-allow=gsm		; Always allow GSM, it's cool :)
-;
-; User-Input Mode (DTMF)
-;
-; valid entries are:   rfc2833, inband
-; default is rfc2833
-;dtmfmode=rfc2833
-;
-; Default RTP Payload to send RFC2833 DTMF on.  This is used to
-; interoperate with broken gateways which cannot successfully
-; negotiate a RFC2833 payload type in the TerminalCapabilitySet.
-;
-; You may also specify on either a per-peer or per-user basis below.
-;dtmfcodec=101
-;
-; 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
-;gatekeeper = DISABLE
-;
-;
-; Tell Asterisk whether or not to accept Gatekeeper
-; routed calls or not. Normally this should always
-; be set to yes, unless you want to have finer control
-; over which users are allowed access to Asterisk.
-; Default: YES
-;
-;AllowGKRouted = yes
-;
-; Optionally you can determine a user by Source IP versus its H.323 alias.
-; Default behavour is to determine user by H.323 alias.
-;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 
-; use user authentication at all.
-;
-;context=default
-;------------------------------ JITTER BUFFER CONFIGURATION --------------------------
-; jbenable = yes              ; Enables the use of a jitterbuffer on the receiving side of a
-                              ; H323 channel. Defaults to "no". An enabled jitterbuffer will
-                              ; be used only if the sending side can create and the receiving
-                              ; side can not accept jitter. The H323 channel can accept jitter,
-                              ; thus an enabled jitterbuffer on the receive H323 side will only
-                              ; be used if the sending side can create jitter and jbforce is
-                              ; also set to yes.
-
-; jbforce = no                ; Forces the use of a jitterbuffer on the receive side of a H323
-                              ; channel. Defaults to "no".
-
-; jbmaxsize = 200             ; Max length of the jitterbuffer in milliseconds.
-
-; jbresyncthreshold = 1000    ; Jump in the frame timestamps over which the jitterbuffer is
-                              ; resynchronized. Useful to improve the quality of the voice, with
-                              ; big jumps in/broken timestamps, usualy sent from exotic devices
-                              ; and programs. Defaults to 1000.
-
-; jbimpl = fixed              ; Jitterbuffer implementation, used on the receiving side of a H323
-                              ; channel. Two implementations are currenlty available - "fixed"
-                              ; (with size always equals to jbmax-size) and "adaptive" (with
-                              ; variable size, actually the new jb of IAX2). Defaults to fixed.
-
-; jblog = no                  ; Enables jitterbuffer frame logging. Defaults to "no".
-;-----------------------------------------------------------------------------------
-;
-; H.323 Alias definitions
-;
-; Type 'h323' will register aliases to the endpoint
-; and Gatekeeper, if there is one.
-;
-; Example: if someone calls time@your.asterisk.box.com
-; Asterisk will send the call to the extension 'time' 
-; in the context default
-;
-;   [default]
-;   exten => time,1,Answer
-;   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 
-; 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 
-; routed to the H.323 alias 'time'.
-;
-;[time]
-;type=h323
-;e164=18102341212
-;context=default
-;
-;[det-gw]
-;type=h323
-;prefix=1248,1313
-;context=detroit
-;
-;
-; Inbound H.323 calls from BillyBob would land in the incoming
-; context with a maximum of 4 concurrent incoming calls 
-; 
-;
-; Note: If keyword 'incominglimit' are omitted Asterisk will not 
-; enforce any maximum number of concurrent calls.
-;
-;[BillyBob]
-;type=user
-;host=192.168.1.1
-;context=incoming
-;incominglimit=4
-;
-;
-; Outbound H.323 call to Larry using SlowStart
-;
-[Larry]
-type=peer
-host=192.168.2.1
-noFastStart=yes
-
-
-
diff --git a/configure.ac b/configure.ac
index 7f7fa4904d6e94013a7416d135fab9e8d6a66b78..167a402be75812b2151ead25b28a299b1531f136 100644
--- a/configure.ac
+++ b/configure.ac
@@ -195,6 +195,7 @@ AST_EXT_LIB_SETUP([POPT], [popt], [popt])
 AST_EXT_LIB_SETUP([PGSQL], [PostgreSQL], [postgres])
 AST_EXT_LIB_SETUP([PRI], [ISDN PRI], [pri])
 AST_EXT_LIB_SETUP([PWLIB], [PWlib], [pwlib])
+AST_EXT_LIB_SETUP([OPENH323], [OpenH323], [h323])
 AST_EXT_LIB_SETUP([QT], [Qt], [qt])
 AST_EXT_LIB_SETUP([RADIUS], [Radius Client], [radius])
 AST_EXT_LIB_SETUP([SPEEX], [Speex], [speex])
@@ -701,49 +702,58 @@ AST_EXT_LIB_CHECK([POPT], [popt], [poptStrerror], [popt.h])
 
 AST_EXT_LIB_CHECK([PRI], [pri], [pri_call], [libpri.h])
 
-PLATFORM_PTLIB="ptlib_${OSTYPE}_${MACHTYPE}_r"
 if test "${USE_PWLIB}" != "no"; then
-   AC_MSG_CHECKING(for existence of pwlib)
-	
-   saved_cppflags="${CPPFLAGS}"
-   saved_libs="${LIBS}"
-   LIBS="${LIBS} -L${PWLIB_DIR} -l${PLATFORM_PTLIB}"
-   CPPFLAGS="${CPPFLAGS} -I${PWLIB_DIR}/include"
-	
-   AC_LINK_IFELSE(
-	[
-	AC_LANG_PROGRAM(
-	[#include "ptime.h"],
-	[int q = PTime::IsDaylightSaving();])
-	],
-	[	AC_MSG_RESULT(yes) 
-		ac_cv_lib_pwlib="yes" 
-	],
-	[	AC_MSG_RESULT(no) 
-		ac_cv_lib_pwlib="no" 
-	]
-	)
+	if test ! -z "${PWLIB_DIR}"; then
+		PWLIBDIR="${PWLIB_DIR}"
+	fi
+	AST_CHECK_PWLIB()
+	AST_CHECK_PWLIB_VERSION([PWLib], [PWLIB], [ptbuildopts.h], [1], [9], [2])
+		
+	if test "${HAS_PWLIB:-unset}" != "unset"; then
+		AST_CHECK_OPENH323_PLATFORM()
 
-   LIBS="${saved_libs}"
-   CPPFLAGS="${saved_cppflags}"
+		PLATFORM_PWLIB="pt_${PWLIB_PLATFORM}_r"
 
-   if test "${ac_cv_lib_pwlib}" = "yes"; then
-      PWLIB_LIB="-l{PLATFORM_PWLIB}"
-      if test "${PWLIB_DIR}" != ""; then
-         PWLIB_LIB="-L${PWLIB_DIR}/lib ${PWLIB_LIB}"
-         PWLIB_INCLUDE="-I${PWLIB_DIR}/include"
-      fi
-   	PBX_PWLIB=1
-   	AC_DEFINE([HAVE_PWLIB], 1, [Define if your system has the pwlib libraries.])
-   elif test ! -z "${PWLIB_MANDATORY}"; then
-      AC_MSG_NOTICE(***)
-      AC_MSG_NOTICE(*** The PWLIB installation on this system appears to be broken.)
-      AC_MSG_NOTICE(*** Either correct the installation, or run configure)
-      AC_MSG_NOTICE(*** including --without-pwlib)
-      exit 1
-   fi
+		AST_CHECK_PWLIB_BUILD([PWLib], [PWLIB],
+			[Define if your system has the PWLib libraries.],
+			[#include "ptlib.h"],
+			[BOOL q = PTime::IsDaylightSavings();])
+	fi
+fi
+
+if test "${USE_PWLIB}" != "no" -a "x${ac_cv_lib_PWLIB}" != "xyes" -a ! -z "${PWLIB_MANDATORY}"; then
+   AC_MSG_NOTICE(***)
+   AC_MSG_NOTICE(*** The PWLIB installation on this system appears to be broken.)
+   AC_MSG_NOTICE(*** Either correct the installation, or run configure)
+   AC_MSG_NOTICE(*** including --without-pwlib)
+   exit 1
 fi
 
+if test "${PBX_PWLIB}" = "1" -a "${USE_OPENH323}" != "no" ; then
+	if test ! -z "${OPENH323_DIR}"; then
+		OPENH323DIR="${OPENH323_DIR}"
+	fi
+	AST_CHECK_OPENH323()
+	AST_CHECK_PWLIB_VERSION([OpenH323], [OPENH323], [openh323buildopts.h], [1], [17], [3])
+	AST_CHECK_OPENH323_BUILD()
+	PLATFORM_OPENH323="h323_${PWLIB_PLATFORM}_${OPENH323_SUFFIX}"
+	AST_CHECK_PWLIB_BUILD([OpenH323], [OPENH323],
+		[Define if your system has the OpenH323 libraries.],
+		[#include "ptlib.h"
+		#include "h323.h"
+		#include "h323ep.h"],
+		[H323EndPoint ep = H323EndPoint();],
+		[${PWLIB_INCLUDE}], [${PWLIB_LIB}])
+fi
+if test "${USE_OPENH323}" != "no" -a "x${ac_cv_lib_OPENH323}" != "xyes" -a ! -z "${OPENH323_MANDATORY}"; then
+   AC_MSG_NOTICE(***)
+   AC_MSG_NOTICE(*** The PWLIB installation on this system appears to be broken.)
+   AC_MSG_NOTICE(*** Either correct the installation, or run configure)
+   AC_MSG_NOTICE(*** including --without-pwlib)
+   exit 1
+fi
+
+
 AC_LANG_PUSH(C++)
 
 if test "${USE_QT}" != "no"; then
@@ -1000,7 +1010,7 @@ AC_SUBST(PBX_CURL)
 AC_SUBST(CURL_INCLUDE)
 AC_SUBST(CURL_LIB)
 
-AC_CONFIG_FILES([build_tools/menuselect-deps makeopts])
+AC_CONFIG_FILES([build_tools/menuselect-deps makeopts channels/h323/Makefile])
 AC_OUTPUT
 
 if test "x${silent}" != "xyes" ; then
diff --git a/doc/realtime.txt b/doc/realtime.txt
index af592024ac56caeef72c8999a1f133c063928b0b..b9bfad0f9a5fc603c566d56be5f47641c73c4ccf 100644
--- a/doc/realtime.txt
+++ b/doc/realtime.txt
@@ -52,6 +52,11 @@ the ones in static configuration.
 With caching, the device stays in memory for a specified time. More 
 information about this is to be found in the sip.conf sample file.
 
+* Realtime H.323 friends
+------------------------
+Like SIP realtime friends, H.323 friends aslo can be configured using
+dynamic realtime objects.
+
 * New function in the dial plan: The Realtime Switch
 ----------------------------------------------------
 The realtime switch is more than a port of functionality in v1.0 to the
diff --git a/main/Makefile b/main/Makefile
index c1b3978037486e40a4d4c45c3f5200d22654b80e..da2197f9b9d54b0f9e61cddf35e58490a0213d07 100644
--- a/main/Makefile
+++ b/main/Makefile
@@ -115,6 +115,13 @@ AST_EMBED_LDFLAGS:=$(foreach dep,$(EMBED_LDFLAGS),$(value $(dep)))
 AST_EMBED_LIBS:=$(foreach dep,$(EMBED_LIBS),$(value $(dep)))
 OBJS:=$(sort $(OBJS))
 
+ifneq ($(wildcard ../channels/h323/Makefile.ast),)
+  include ../channels/h323/Makefile.ast
+else
+  H323LDFLAGS=
+  H323LDLIBS=
+endif
+
 asterisk: $(OBJS) editline/libedit.a db1-ast/libdb1.a $(AST_EMBED_LDSCRIPTS)
 	@$(ASTTOPDIR)/build_tools/make_build_h > $(ASTTOPDIR)/include/asterisk/build.h.tmp
 	@if cmp -s $(ASTTOPDIR)/include/asterisk/build.h.tmp $(ASTTOPDIR)/include/asterisk/build.h ; then echo ; else \
@@ -123,7 +130,7 @@ asterisk: $(OBJS) editline/libedit.a db1-ast/libdb1.a $(AST_EMBED_LDSCRIPTS)
 	@rm -f $(ASTTOPDIR)/include/asterisk/build.h.tmp
 	@$(CC) -c -o buildinfo.o $(CFLAGS) buildinfo.c
 	$(ECHO_PREFIX) echo "   [LD] $^ -> $@"
-	$(CMD_PREFIX) $(CXX) $(STATIC_BUILD) -o asterisk $(ASTLINK) $(AST_EMBED_LDFLAGS) $(LDFLAGS) $^ buildinfo.o $(AST_LIBS) $(AST_EMBED_LIBS)
+	$(CMD_PREFIX) $(CXX) $(STATIC_BUILD) -o asterisk $(ASTLINK) $(AST_EMBED_LDFLAGS) $(LDFLAGS) $(H323LDFLAGS) $^ buildinfo.o $(AST_LIBS) $(AST_EMBED_LIBS) $(H323LDLIBS)
 
 clean::
 	rm -f asterisk