diff -ruN asterisk-1.4.20.1_original/aclocal.m4 asterisk-1.4.20.1_updated/aclocal.m4
--- asterisk-1.4.20.1_original/aclocal.m4	1970-01-01 01:00:00.000000000 +0100
+++ asterisk-1.4.20.1_updated/aclocal.m4	2008-06-05 18:15:09.000000000 +0200
@@ -0,0 +1,986 @@
+# AST_GCC_ATTRIBUTE([attribute name])
+
+AC_DEFUN([AST_GCC_ATTRIBUTE],
+[
+AC_MSG_CHECKING(for compiler 'attribute $1' support)
+saved_CFLAGS="$CFLAGS"
+CFLAGS="$CFLAGS -Werror"
+AC_COMPILE_IFELSE(
+	AC_LANG_PROGRAM([static void __attribute__(($1)) *test(void *muffin, ...) {}],
+			[]),
+	AC_MSG_RESULT(yes)
+	AC_DEFINE_UNQUOTED([HAVE_ATTRIBUTE_$1], 1, [Define to 1 if your GCC C compiler supports the '$1' attribute.]),
+	AC_MSG_RESULT(no))
+]
+CFLAGS="$saved_CFLAGS"
+)
+
+# AST_EXT_LIB_SETUP([package symbol name], [package friendly name], [package option name], [additional help text])
+
+AC_DEFUN([AST_EXT_LIB_SETUP],
+[
+$1_DESCRIP="$2"
+$1_OPTION="$3"
+AC_ARG_WITH([$3], AC_HELP_STRING([--with-$3=PATH],[use $2 files in PATH $4]),[
+case ${withval} in
+     n|no)
+     USE_$1=no
+     ;;
+     y|ye|yes)
+     $1_MANDATORY="yes"
+     ;;
+     *)
+     $1_DIR="${withval}"
+     $1_MANDATORY="yes"
+     ;;
+esac
+])
+PBX_$1=0
+AC_SUBST([$1_LIB])
+AC_SUBST([$1_INCLUDE])
+AC_SUBST([$1_DIR])
+AC_SUBST([PBX_$1])
+])
+
+# AST_EXT_LIB_CHECK([package symbol name], [package library name], [function to check], [package header], [additional LIB data])
+
+AC_DEFUN([AST_EXT_LIB_CHECK],
+[
+if test "${USE_$1}" != "no"; then
+   pbxlibdir=""
+   if test "x${$1_DIR}" != "x"; then
+      if test -d ${$1_DIR}/lib; then
+      	 pbxlibdir="-L${$1_DIR}/lib"
+      else
+      	 pbxlibdir="-L${$1_DIR}"
+      fi
+   fi
+   AC_CHECK_LIB([$2], [$3], [AST_$1_FOUND=yes], [AST_$1_FOUND=no], ${pbxlibdir} $5)
+
+   if test "${AST_$1_FOUND}" = "yes"; then
+      $1_LIB="-l$2 $5"
+      $1_HEADER_FOUND="1"
+      if test "x${$1_DIR}" != "x"; then
+         $1_LIB="${pbxlibdir} ${$1_LIB}"
+	 $1_INCLUDE="-I${$1_DIR}/include"
+	 saved_cppflags="${CPPFLAGS}"
+	 CPPFLAGS="${CPPFLAGS} -I${$1_DIR}/include"
+	 if test "x$4" != "x" ; then
+	    AC_CHECK_HEADER([${$1_DIR}/include/$4], [$1_HEADER_FOUND=1], [$1_HEADER_FOUND=0])
+	 fi
+	 CPPFLAGS="${saved_cppflags}"
+      else
+	 if test "x$4" != "x" ; then
+            AC_CHECK_HEADER([$4], [$1_HEADER_FOUND=1], [$1_HEADER_FOUND=0])
+	 fi
+      fi
+      if test "x${$1_HEADER_FOUND}" = "x0" ; then
+         if test -n "${$1_MANDATORY}" ;
+         then
+            AC_MSG_NOTICE([***])
+            AC_MSG_NOTICE([*** It appears that you do not have the $2 development package installed.])
+            AC_MSG_NOTICE([*** Please install it to include ${$1_DESCRIP} support, or re-run configure])
+            AC_MSG_NOTICE([*** without explicitly specifying --with-${$1_OPTION}])
+            exit 1
+         fi
+         $1_LIB=""
+         $1_INCLUDE=""
+         PBX_$1=0
+      else
+         PBX_$1=1
+         AC_DEFINE_UNQUOTED([HAVE_$1], 1, [Define to indicate the ${$1_DESCRIP} library])
+      fi
+   elif test -n "${$1_MANDATORY}";
+   then
+      AC_MSG_NOTICE([***])
+      AC_MSG_NOTICE([*** The ${$1_DESCRIP} installation on this system appears to be broken.])
+      AC_MSG_NOTICE([*** Either correct the installation, or run configure])
+      AC_MSG_NOTICE([*** without explicitly specifying --with-${$1_OPTION}])
+      exit 1
+   fi
+fi
+])
+
+# AST_C_COMPILE_CHECK can be used for testing for various items in header files
+
+# AST_C_COMPILE_CHECK([package], [expression], [header file], [version])
+AC_DEFUN([AST_C_COMPILE_CHECK],
+[
+    if test "x${PBX_$1}" != "x1" -a "${USE_$1}" != "no"; then
+	AC_MSG_CHECKING([if "$2" compiles using $3])
+	saved_cppflags="${CPPFLAGS}"
+	if test "x${$1_DIR}" != "x"; then
+	    $1_INCLUDE="-I${$1_DIR}/include"
+	fi
+	CPPFLAGS="${CPPFLAGS} ${$1_INCLUDE}"
+
+	AC_COMPILE_IFELSE(
+	    [ AC_LANG_PROGRAM( [#include <$3>],
+			       [ $2; ]
+			       )],
+	    [   AC_MSG_RESULT(yes)
+		PBX_$1=1
+		AC_DEFINE([HAVE_$1], 1, [Define if your system has the $1 headers.])
+		AC_DEFINE([HAVE_$1_VERSION], $4, [Define $1 headers version])
+	    ],
+	    [       AC_MSG_RESULT(no) ] 
+	)
+	CPPFLAGS="${saved_cppflags}"
+    fi
+])
+
+AC_DEFUN(
+[AST_CHECK_GNU_MAKE], [AC_CACHE_CHECK(for GNU make, GNU_MAKE,
+   GNU_MAKE='Not Found' ;
+   GNU_MAKE_VERSION_MAJOR=0 ;
+   GNU_MAKE_VERSION_MINOR=0 ;
+   for a in make gmake gnumake ; do
+      if test -z "$a" ; then continue ; fi ;
+      if ( sh -c "$a --version" 2> /dev/null | grep GNU  2>&1 > /dev/null ) ;  then
+         GNU_MAKE=$a ;
+         GNU_MAKE_VERSION_MAJOR=`$GNU_MAKE --version | grep "GNU Make" | cut -f3 -d' ' | cut -f1 -d'.'`
+         GNU_MAKE_VERSION_MINOR=`$GNU_MAKE --version | grep "GNU Make" | cut -f2 -d'.' | cut -c1-2`
+         break;
+      fi
+   done ;
+) ;
+if test  "x$GNU_MAKE" = "xNot Found"  ; then
+   AC_MSG_ERROR( *** Please install GNU make.  It is required to build Asterisk!)
+   exit 1
+fi
+AC_SUBST([GNU_MAKE])
+])
+
+
+AC_DEFUN(
+[AST_CHECK_PWLIB], [
+PWLIB_INCDIR=
+PWLIB_LIBDIR=
+AC_LANG_PUSH([C++])
+if test "${PWLIBDIR:-unset}" != "unset" ; then
+  AC_CHECK_HEADER(${PWLIBDIR}/version.h, HAS_PWLIB=1, )
+fi
+if test "${HAS_PWLIB:-unset}" = "unset" ; then
+  if test "${OPENH323DIR:-unset}" != "unset"; then
+    AC_CHECK_HEADER(${OPENH323DIR}/../pwlib/version.h, HAS_PWLIB=1, )
+  fi
+  if test "${HAS_PWLIB:-unset}" != "unset" ; then
+    PWLIBDIR="${OPENH323DIR}/../pwlib"
+  else
+    AC_CHECK_HEADER(${HOME}/pwlib/include/ptlib.h, HAS_PWLIB=1, )
+    if test "${HAS_PWLIB:-unset}" != "unset" ; then
+      PWLIBDIR="${HOME}/pwlib"
+    else
+      AC_CHECK_HEADER(/usr/local/include/ptlib.h, HAS_PWLIB=1, )
+      if test "${HAS_PWLIB:-unset}" != "unset" ; then
+        AC_PATH_PROG(PTLIB_CONFIG, ptlib-config, , /usr/local/bin)
+        if test "${PTLIB_CONFIG:-unset}" = "unset" ; then
+          AC_PATH_PROG(PTLIB_CONFIG, ptlib-config, , /usr/local/share/pwlib/make)
+        fi
+        PWLIB_INCDIR="/usr/local/include"
+        PWLIB_LIBDIR=`${PTLIB_CONFIG} --pwlibdir`
+        if test "${PWLIB_LIBDIR:-unset}" = "unset"; then
+          if test "x$LIB64" != "x"; then
+            PWLIB_LIBDIR="/usr/local/lib64"
+          else
+            PWLIB_LIBDIR="/usr/local/lib"
+          fi
+        fi
+        PWLIB_LIB=`${PTLIB_CONFIG} --ldflags --libs`
+        PWLIB_LIB="-L${PWLIB_LIBDIR} `echo ${PWLIB_LIB}`"
+      else
+        AC_CHECK_HEADER(/usr/include/ptlib.h, HAS_PWLIB=1, )
+        if test "${HAS_PWLIB:-unset}" != "unset" ; then
+          AC_PATH_PROG(PTLIB_CONFIG, ptlib-config, , /usr/share/pwlib/make)
+          PWLIB_INCDIR="/usr/include"
+          PWLIB_LIBDIR=`${PTLIB_CONFIG} --pwlibdir`
+          if test "${PWLIB_LIBDIR:-unset}" = "unset"; then
+            if test "x$LIB64" != "x"; then
+              PWLIB_LIBDIR="/usr/lib64"
+            else
+              PWLIB_LIBDIR="/usr/lib"
+            fi
+          fi
+          PWLIB_LIB=`${PTLIB_CONFIG} --ldflags --libs`
+          PWLIB_LIB="-L${PWLIB_LIBDIR} `echo ${PWLIB_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"
+    if test "x$LIB64" != "x"; then
+      PWLIB_LIBDIR="/usr/lib64"
+    else
+      PWLIB_LIBDIR="/usr/lib"
+    fi
+  fi
+  if test "x$PWLIBDIR" = "x/usr/local" -o "x$PWLIBDIR" = "x/usr/"; then
+    PWLIBDIR="/usr/local/share/pwlib"
+    PWLIB_INCDIR="/usr/local/include"
+    if test "x$LIB64" != "x"; then
+      PWLIB_LIBDIR="/usr/local/lib64"
+    else
+      PWLIB_LIBDIR="/usr/local/lib"
+    fi
+  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_LANG_POP([C++])
+])
+
+
+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=
+AC_LANG_PUSH([C++])
+if test "${OPENH323DIR:-unset}" != "unset" ; then
+  AC_CHECK_HEADER(${OPENH323DIR}/version.h, HAS_OPENH323=1, )
+fi
+if test "${HAS_OPENH323:-unset}" = "unset" ; then
+  AC_CHECK_HEADER(${PWLIBDIR}/../openh323/version.h, OPENH323DIR="${PWLIBDIR}/../openh323"; HAS_OPENH323=1, )
+  if test "${HAS_OPENH323:-unset}" != "unset" ; then
+    OPENH323DIR="${PWLIBDIR}/../openh323"
+    saved_cppflags="${CPPFLAGS}"
+    CPPFLAGS="${CPPFLAGS} -I${PWLIB_INCDIR}/openh323 -I${PWLIB_INCDIR}"
+    AC_CHECK_HEADER(${OPENH323DIR}/include/h323.h, , OPENH323_INCDIR="${PWLIB_INCDIR}/openh323"; OPENH323_LIBDIR="${PWLIB_LIBDIR}", [#include <ptlib.h>])
+    CPPFLAGS="${saved_cppflags}"
+  else
+    saved_cppflags="${CPPFLAGS}"
+    CPPFLAGS="${CPPFLAGS} -I${HOME}/openh323/include -I${PWLIB_INCDIR}"
+    AC_CHECK_HEADER(${HOME}/openh323/include/h323.h, HAS_OPENH323=1, )
+    CPPFLAGS="${saved_cppflags}"
+    if test "${HAS_OPENH323:-unset}" != "unset" ; then
+      OPENH323DIR="${HOME}/openh323"
+    else
+      saved_cppflags="${CPPFLAGS}"
+      CPPFLAGS="${CPPFLAGS} -I/usr/local/include/openh323 -I${PWLIB_INCDIR}"
+      AC_CHECK_HEADER(/usr/local/include/openh323/h323.h, HAS_OPENH323=1, )
+      CPPFLAGS="${saved_cppflags}"
+      if test "${HAS_OPENH323:-unset}" != "unset" ; then
+        OPENH323DIR="/usr/local/share/openh323"
+        OPENH323_INCDIR="/usr/local/include/openh323"
+        if test "x$LIB64" != "x"; then
+          OPENH323_LIBDIR="/usr/local/lib64"
+        else
+          OPENH323_LIBDIR="/usr/local/lib"
+        fi
+      else
+        saved_cppflags="${CPPFLAGS}"
+        CPPFLAGS="${CPPFLAGS} -I/usr/include/openh323 -I${PWLIB_INCDIR}"
+        AC_CHECK_HEADER(/usr/include/openh323/h323.h, HAS_OPENH323=1, , [#include <ptlib.h>])
+        CPPFLAGS="${saved_cppflags}"
+        if test "${HAS_OPENH323:-unset}" != "unset" ; then
+          OPENH323DIR="/usr/share/openh323"
+          OPENH323_INCDIR="/usr/include/openh323"
+          if test "x$LIB64" != "x"; then
+            OPENH323_LIBDIR="/usr/lib64"
+          else
+            OPENH323_LIBDIR="/usr/lib"
+          fi
+        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
+
+  OPENH323_LIBDIR="`cd ${OPENH323_LIBDIR}; pwd`"
+  OPENH323_INCDIR="`cd ${OPENH323_INCDIR}; pwd`"
+  OPENH323DIR="`cd ${OPENH323DIR}; pwd`"
+
+  AC_SUBST([OPENH323DIR])
+  AC_SUBST([OPENH323_INCDIR])
+  AC_SUBST([OPENH323_LIBDIR])
+fi
+  AC_LANG_POP([C++])
+])
+
+
+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}"
+	   if test "${$2_LIB:-unset}" != "unset"; then
+	      LIBS="${LIBS} ${$2_LIB} $7"
+	   else
+    	      LIBS="${LIBS} -L${$2_LIBDIR} -l${PLATFORM_$2} $7"
+	   fi
+	   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_LIB:-undef}" = "undef"; 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
+	      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=
+		prefixes="h323_${PWLIB_PLATFORM}_ h323_ openh323"
+		for pfx in $prefixes; do
+			files=`ls -l ${OPENH323_LIBDIR}/lib${pfx}*.so* 2>/dev/null`
+			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 -n "$libfile"; then
+				OPENH323_PREFIX=$pfx
+				break;
+			fi
+		done
+		if test "${libfile:-unset}" != "unset"; then
+			OPENH323_SUFFIX=`eval "echo ${libfile} | sed -e 's/lib${OPENH323_PREFIX}\(@<:@^.@:>@*\)\..*/\1/'"`
+		fi
+		case "${OPENH323_SUFFIX}" in
+			n)
+				OPENH323_BUILD="notrace";;
+			r)
+				OPENH323_BUILD="opt";;
+			d)
+				OPENH323_BUILD="debug";;
+			*)
+				if test "${OPENH323_PREFIX:-undef}" = "openh323"; then
+					notrace=`eval "grep NOTRACE ${OPENH323DIR}/openh323u.mak | grep = | sed -e 's/@<:@A-Z0-9_@:>@*@<:@ 	@:>@*=@<:@ 	@:>@*//'"`
+					if test "x$notrace" = "x"; then
+						notrace="0"
+					fi
+					if test "$notrace" -ne 0; then
+						OPENH323_BUILD="notrace"
+					else
+						OPENH323_BUILD="opt"
+					fi
+					OPENH323_LIB="-l${OPENH323_PREFIX}"
+				else
+					OPENH323_BUILD="notrace"
+				fi
+				;;
+		esac
+		AC_MSG_RESULT(${OPENH323_BUILD})
+
+		AC_SUBST([OPENH323_SUFFIX])
+		AC_SUBST([OPENH323_BUILD])
+	fi
+])
+
+
+# AST_FUNC_FORK
+# -------------
+AN_FUNCTION([fork],  [AST_FUNC_FORK])
+AN_FUNCTION([vfork], [AST_FUNC_FORK])
+AC_DEFUN([AST_FUNC_FORK],
+[AC_REQUIRE([AC_TYPE_PID_T])dnl
+AC_CHECK_HEADERS(vfork.h)
+AC_CHECK_FUNCS(fork vfork)
+if test "x$ac_cv_func_fork" = xyes; then
+  _AST_FUNC_FORK
+else
+  ac_cv_func_fork_works=$ac_cv_func_fork
+fi
+if test "x$ac_cv_func_fork_works" = xcross; then
+  case $host in
+    *-*-amigaos* | *-*-msdosdjgpp* | *-*-uclinux* | *-*-linux-uclibc* )
+      # Override, as these systems have only a dummy fork() stub
+      ac_cv_func_fork_works=no
+      ;;
+    *)
+      ac_cv_func_fork_works=yes
+      ;;
+  esac
+  AC_MSG_WARN([result $ac_cv_func_fork_works guessed because of cross compilation])
+fi
+ac_cv_func_vfork_works=$ac_cv_func_vfork
+if test "x$ac_cv_func_vfork" = xyes; then
+  _AC_FUNC_VFORK
+fi;
+if test "x$ac_cv_func_fork_works" = xcross; then
+  ac_cv_func_vfork_works=$ac_cv_func_vfork
+  AC_MSG_WARN([result $ac_cv_func_vfork_works guessed because of cross compilation])
+fi
+
+if test "x$ac_cv_func_vfork_works" = xyes; then
+  AC_DEFINE(HAVE_WORKING_VFORK, 1, [Define to 1 if `vfork' works.])
+else
+  AC_DEFINE(vfork, fork, [Define as `fork' if `vfork' does not work.])
+fi
+if test "x$ac_cv_func_fork_works" = xyes; then
+  AC_DEFINE(HAVE_WORKING_FORK, 1, [Define to 1 if `fork' works.])
+fi
+])# AST_FUNC_FORK
+
+
+# _AST_FUNC_FORK
+# -------------
+AC_DEFUN([_AST_FUNC_FORK],
+  [AC_CACHE_CHECK(for working fork, ac_cv_func_fork_works,
+    [AC_RUN_IFELSE(
+      [AC_LANG_PROGRAM([AC_INCLUDES_DEFAULT],
+	[
+	  /* By Ruediger Kuhlmann. */
+	  return fork () < 0;
+	])],
+      [ac_cv_func_fork_works=yes],
+      [ac_cv_func_fork_works=no],
+      [ac_cv_func_fork_works=cross])])]
+)# _AST_FUNC_FORK
+
+# AST_PROG_LD
+# ----------
+# find the pathname to the GNU or non-GNU linker
+AC_DEFUN([AST_PROG_LD],
+[AC_ARG_WITH([gnu-ld],
+    [AC_HELP_STRING([--with-gnu-ld],
+	[assume the C compiler uses GNU ld @<:@default=no@:>@])],
+    [test "$withval" = no || with_gnu_ld=yes],
+    [with_gnu_ld=no])
+AC_REQUIRE([AST_PROG_SED])dnl
+AC_REQUIRE([AC_PROG_CC])dnl
+AC_REQUIRE([AC_CANONICAL_HOST])dnl
+AC_REQUIRE([AC_CANONICAL_BUILD])dnl
+ac_prog=ld
+if test "$GCC" = yes; then
+  # Check if gcc -print-prog-name=ld gives a path.
+  AC_MSG_CHECKING([for ld used by $CC])
+  case $host in
+  *-*-mingw*)
+    # gcc leaves a trailing carriage return which upsets mingw
+    ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
+  *)
+    ac_prog=`($CC -print-prog-name=ld) 2>&5` ;;
+  esac
+  case $ac_prog in
+    # Accept absolute paths.
+    [[\\/]]* | ?:[[\\/]]*)
+      re_direlt='/[[^/]][[^/]]*/\.\./'
+      # Canonicalize the pathname of ld
+      ac_prog=`echo $ac_prog| $SED 's%\\\\%/%g'`
+      while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do
+	ac_prog=`echo $ac_prog| $SED "s%$re_direlt%/%"`
+      done
+      test -z "$LD" && LD="$ac_prog"
+      ;;
+  "")
+    # If it fails, then pretend we aren't using GCC.
+    ac_prog=ld
+    ;;
+  *)
+    # If it is relative, then search for the first ld in PATH.
+    with_gnu_ld=unknown
+    ;;
+  esac
+elif test "$with_gnu_ld" = yes; then
+  AC_MSG_CHECKING([for GNU ld])
+else
+  AC_MSG_CHECKING([for non-GNU ld])
+fi
+AC_CACHE_VAL(lt_cv_path_LD,
+[if test -z "$LD"; then
+  lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+  for ac_dir in $PATH; do
+    IFS="$lt_save_ifs"
+    test -z "$ac_dir" && ac_dir=.
+    if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
+      lt_cv_path_LD="$ac_dir/$ac_prog"
+      # Check to see if the program is GNU ld.  I'd rather use --version,
+      # but apparently some variants of GNU ld only accept -v.
+      # Break only if it was the GNU/non-GNU ld that we prefer.
+      case `"$lt_cv_path_LD" -v 2>&1 </dev/null` in
+      *GNU* | *'with BFD'*)
+	test "$with_gnu_ld" != no && break
+	;;
+      *)
+	test "$with_gnu_ld" != yes && break
+	;;
+      esac
+    fi
+  done
+  IFS="$lt_save_ifs"
+else
+  lt_cv_path_LD="$LD" # Let the user override the test with a path.
+fi])
+LD="$lt_cv_path_LD"
+if test -n "$LD"; then
+  AC_MSG_RESULT($LD)
+else
+  AC_MSG_RESULT(no)
+fi
+test -z "$LD" && AC_MSG_ERROR([no acceptable ld found in \$PATH])
+AST_PROG_LD_GNU
+])# AST_PROG_LD
+
+
+# AST_PROG_LD_GNU
+# --------------
+AC_DEFUN([AST_PROG_LD_GNU],
+[AC_REQUIRE([AST_PROG_EGREP])dnl
+AC_CACHE_CHECK([if the linker ($LD) is GNU ld], lt_cv_prog_gnu_ld,
+[# I'd rather use --version here, but apparently some GNU lds only accept -v.
+case `$LD -v 2>&1 </dev/null` in
+*GNU* | *'with BFD'*)
+  lt_cv_prog_gnu_ld=yes
+  ;;
+*)
+  lt_cv_prog_gnu_ld=no
+  ;;
+esac])
+with_gnu_ld=$lt_cv_prog_gnu_ld
+])# AST_PROG_LD_GNU
+
+# AST_PROG_EGREP
+# -------------
+m4_ifndef([AST_PROG_EGREP], [AC_DEFUN([AST_PROG_EGREP],
+[AC_CACHE_CHECK([for egrep], [ac_cv_prog_egrep],
+   [if echo a | (grep -E '(a|b)') >/dev/null 2>&1
+    then ac_cv_prog_egrep='grep -E'
+    else ac_cv_prog_egrep='egrep'
+    fi])
+ EGREP=$ac_cv_prog_egrep
+ AC_SUBST([EGREP])
+])]) # AST_PROG_EGREP
+
+# AST_PROG_SED
+# -----------
+# Check for a fully functional sed program that truncates
+# as few characters as possible.  Prefer GNU sed if found.
+AC_DEFUN([AST_PROG_SED],
+[AC_CACHE_CHECK([for a sed that does not truncate output], ac_cv_path_SED,
+    [dnl ac_script should not contain more than 99 commands (for HP-UX sed),
+     dnl but more than about 7000 bytes, to catch a limit in Solaris 8 /usr/ucb/sed.
+     ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/
+     for ac_i in 1 2 3 4 5 6 7; do
+       ac_script="$ac_script$as_nl$ac_script"
+     done
+     echo "$ac_script" | sed 99q >conftest.sed
+     $as_unset ac_script || ac_script=
+     _AC_PATH_PROG_FEATURE_CHECK(SED, [sed gsed],
+	[_AC_FEATURE_CHECK_LENGTH([ac_path_SED], [ac_cv_path_SED],
+		["$ac_path_SED" -f conftest.sed])])])
+ SED="$ac_cv_path_SED"
+ AC_SUBST([SED])dnl
+ rm -f conftest.sed
+])# AST_PROG_SED
+
+dnl @synopsis ACX_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]])
+dnl
+dnl @summary figure out how to build C programs using POSIX threads
+dnl
+dnl This macro figures out how to build C programs using POSIX threads.
+dnl It sets the PTHREAD_LIBS output variable to the threads library and
+dnl linker flags, and the PTHREAD_CFLAGS output variable to any special
+dnl C compiler flags that are needed. (The user can also force certain
+dnl compiler flags/libs to be tested by setting these environment
+dnl variables.)
+dnl
+dnl Also sets PTHREAD_CC to any special C compiler that is needed for
+dnl multi-threaded programs (defaults to the value of CC otherwise).
+dnl (This is necessary on AIX to use the special cc_r compiler alias.)
+dnl
+dnl NOTE: You are assumed to not only compile your program with these
+dnl flags, but also link it with them as well. e.g. you should link
+dnl with $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS
+dnl $LIBS
+dnl
+dnl If you are only building threads programs, you may wish to use
+dnl these variables in your default LIBS, CFLAGS, and CC:
+dnl
+dnl        LIBS="$PTHREAD_LIBS $LIBS"
+dnl        CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+dnl        CC="$PTHREAD_CC"
+dnl
+dnl In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute
+dnl constant has a nonstandard name, defines PTHREAD_CREATE_JOINABLE to
+dnl that name (e.g. PTHREAD_CREATE_UNDETACHED on AIX).
+dnl
+dnl ACTION-IF-FOUND is a list of shell commands to run if a threads
+dnl library is found, and ACTION-IF-NOT-FOUND is a list of commands to
+dnl run it if it is not found. If ACTION-IF-FOUND is not specified, the
+dnl default action will define HAVE_PTHREAD.
+dnl
+dnl Please let the authors know if this macro fails on any platform, or
+dnl if you have any other suggestions or comments. This macro was based
+dnl on work by SGJ on autoconf scripts for FFTW (www.fftw.org) (with
+dnl help from M. Frigo), as well as ac_pthread and hb_pthread macros
+dnl posted by Alejandro Forero Cuervo to the autoconf macro repository.
+dnl We are also grateful for the helpful feedback of numerous users.
+dnl
+dnl @category InstalledPackages
+dnl @author Steven G. Johnson <stevenj@alum.mit.edu>
+dnl @version 2006-05-29
+dnl @license GPLWithACException
+
+AC_DEFUN([ACX_PTHREAD], [
+AC_REQUIRE([AC_CANONICAL_HOST])
+AC_LANG_SAVE
+AC_LANG_C
+acx_pthread_ok=no
+
+# We used to check for pthread.h first, but this fails if pthread.h
+# requires special compiler flags (e.g. on True64 or Sequent).
+# It gets checked for in the link test anyway.
+
+# First of all, check if the user has set any of the PTHREAD_LIBS,
+# etcetera environment variables, and if threads linking works using
+# them:
+if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then
+        save_CFLAGS="$CFLAGS"
+        CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+        save_LIBS="$LIBS"
+        LIBS="$PTHREAD_LIBS $LIBS"
+        AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS])
+        AC_TRY_LINK_FUNC(pthread_join, acx_pthread_ok=yes)
+        AC_MSG_RESULT($acx_pthread_ok)
+        if test x"$acx_pthread_ok" = xno; then
+                PTHREAD_LIBS=""
+                PTHREAD_CFLAGS=""
+        fi
+        LIBS="$save_LIBS"
+        CFLAGS="$save_CFLAGS"
+fi
+
+# We must check for the threads library under a number of different
+# names; the ordering is very important because some systems
+# (e.g. DEC) have both -lpthread and -lpthreads, where one of the
+# libraries is broken (non-POSIX).
+
+# Create a list of thread flags to try.  Items starting with a "-" are
+# C compiler flags, and other items are library names, except for "none"
+# which indicates that we try without any flags at all, and "pthread-config"
+# which is a program returning the flags for the Pth emulation library.
+
+acx_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config"
+
+# The ordering *is* (sometimes) important.  Some notes on the
+# individual items follow:
+
+# pthreads: AIX (must check this before -lpthread)
+# none: in case threads are in libc; should be tried before -Kthread and
+#       other compiler flags to prevent continual compiler warnings
+# -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h)
+# -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able)
+# lthread: LinuxThreads port on FreeBSD (also preferred to -pthread)
+# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads)
+# -pthreads: Solaris/gcc
+# -mthreads: Mingw32/gcc, Lynx/gcc
+# -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it
+#      doesn't hurt to check since this sometimes defines pthreads too;
+#      also defines -D_REENTRANT)
+#      ... -mt is also the pthreads flag for HP/aCC
+# pthread: Linux, etcetera
+# --thread-safe: KAI C++
+# pthread-config: use pthread-config program (for GNU Pth library)
+
+case "${host_cpu}-${host_os}" in
+        *solaris*)
+
+        # On Solaris (at least, for some versions), libc contains stubbed
+        # (non-functional) versions of the pthreads routines, so link-based
+        # tests will erroneously succeed.  (We need to link with -pthreads/-mt/
+        # -lpthread.)  (The stubs are missing pthread_cleanup_push, or rather
+        # a function called by this macro, so we could check for that, but
+        # who knows whether they'll stub that too in a future libc.)  So,
+        # we'll just look for -pthreads and -lpthread first:
+
+        acx_pthread_flags="-pthreads pthread -mt -pthread $acx_pthread_flags"
+        ;;
+esac
+
+if test x"$acx_pthread_ok" = xno; then
+for flag in $acx_pthread_flags; do
+
+        case $flag in
+                none)
+                AC_MSG_CHECKING([whether pthreads work without any flags])
+                ;;
+
+                -*)
+                AC_MSG_CHECKING([whether pthreads work with $flag])
+                PTHREAD_CFLAGS="$flag"
+                ;;
+
+		pthread-config)
+		AC_CHECK_PROG(acx_pthread_config, pthread-config, yes, no)
+		if test x"$acx_pthread_config" = xno; then continue; fi
+		PTHREAD_CFLAGS="`pthread-config --cflags`"
+		PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`"
+		;;
+
+                *)
+                AC_MSG_CHECKING([for the pthreads library -l$flag])
+                PTHREAD_LIBS="-l$flag"
+                ;;
+        esac
+
+        save_LIBS="$LIBS"
+        save_CFLAGS="$CFLAGS"
+        LIBS="$PTHREAD_LIBS $LIBS"
+        CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+
+        # Check for various functions.  We must include pthread.h,
+        # since some functions may be macros.  (On the Sequent, we
+        # need a special flag -Kthread to make this header compile.)
+        # We check for pthread_join because it is in -lpthread on IRIX
+        # while pthread_create is in libc.  We check for pthread_attr_init
+        # due to DEC craziness with -lpthreads.  We check for
+        # pthread_cleanup_push because it is one of the few pthread
+        # functions on Solaris that doesn't have a non-functional libc stub.
+        # We try pthread_create on general principles.
+        AC_TRY_LINK([#include <pthread.h>],
+                    [pthread_t th; pthread_join(th, 0);
+                     pthread_attr_init(0); pthread_cleanup_push(0, 0);
+                     pthread_create(0,0,0,0); pthread_cleanup_pop(0); ],
+                    [acx_pthread_ok=yes])
+
+        LIBS="$save_LIBS"
+        CFLAGS="$save_CFLAGS"
+
+        AC_MSG_RESULT($acx_pthread_ok)
+        if test "x$acx_pthread_ok" = xyes; then
+                break;
+        fi
+
+        PTHREAD_LIBS=""
+        PTHREAD_CFLAGS=""
+done
+fi
+
+# Various other checks:
+if test "x$acx_pthread_ok" = xyes; then
+        save_LIBS="$LIBS"
+        LIBS="$PTHREAD_LIBS $LIBS"
+        save_CFLAGS="$CFLAGS"
+        CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+
+        # Detect AIX lossage: JOINABLE attribute is called UNDETACHED.
+	AC_MSG_CHECKING([for joinable pthread attribute])
+	attr_name=unknown
+	for attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do
+	    AC_TRY_LINK([#include <pthread.h>], [int attr=$attr; return attr;],
+                        [attr_name=$attr; break])
+	done
+        AC_MSG_RESULT($attr_name)
+        if test "$attr_name" != PTHREAD_CREATE_JOINABLE; then
+            AC_DEFINE_UNQUOTED(PTHREAD_CREATE_JOINABLE, $attr_name,
+                               [Define to necessary symbol if this constant
+                                uses a non-standard name on your system.])
+        fi
+
+        AC_MSG_CHECKING([if more special flags are required for pthreads])
+        flag=no
+        case "${host_cpu}-${host_os}" in
+            *-aix* | *-freebsd* | *-darwin*) flag="-D_THREAD_SAFE";;
+            *solaris* | *-osf* | *-hpux*) flag="-D_REENTRANT";;
+        esac
+        AC_MSG_RESULT(${flag})
+        if test "x$flag" != xno; then
+            PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS"
+        fi
+
+        LIBS="$save_LIBS"
+        CFLAGS="$save_CFLAGS"
+
+        # More AIX lossage: must compile with xlc_r or cc_r
+	if test x"$GCC" != xyes; then
+          AC_CHECK_PROGS(PTHREAD_CC, xlc_r cc_r, ${CC})
+        else
+          PTHREAD_CC=$CC
+	fi
+else
+        PTHREAD_CC="$CC"
+fi
+
+AC_SUBST(PTHREAD_LIBS)
+AC_SUBST(PTHREAD_CFLAGS)
+AC_SUBST(PTHREAD_CC)
+
+# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND:
+if test x"$acx_pthread_ok" = xyes; then
+        ifelse([$1],,AC_DEFINE(HAVE_PTHREAD,1,[Define if you have POSIX threads libraries and header files.]),[$1])
+        :
+else
+        acx_pthread_ok=no
+        $2
+fi
+AC_LANG_RESTORE
+])dnl ACX_PTHREAD
diff -ruN asterisk-1.4.20.1_original/apps/app_fax.c asterisk-1.4.20.1_updated/apps/app_fax.c
--- asterisk-1.4.20.1_original/apps/app_fax.c	1970-01-01 01:00:00.000000000 +0100
+++ asterisk-1.4.20.1_updated/apps/app_fax.c	2008-06-20 21:25:29.000000000 +0200
@@ -0,0 +1,798 @@
+/*
+ * Asterisk -- A telephony toolkit for Linux.
+ *
+ * Simple fax applications
+ * 
+ * 2007-2008, Dmitry Andrianov <asterisk@dima.spb.ru>
+ *
+ * Code based on original implementation by Steve Underwood <steveu@coppice.org>
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License
+ *
+ */
+
+/*** MODULEINFO
+	 <depend>spandsp</depend>
+***/
+ 
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision: 1.1.1.1 $")
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <inttypes.h>
+#include <pthread.h>
+#include <errno.h>
+#include <tiffio.h>
+
+#include <spandsp.h>
+
+#include "asterisk/lock.h"
+#include "asterisk/file.h"
+#include "asterisk/logger.h"
+#include "asterisk/channel.h"
+#include "asterisk/pbx.h"
+#include "asterisk/app.h"
+#include "asterisk/dsp.h"
+#include "asterisk/module.h"
+#include "asterisk/manager.h"
+
+static char *app_sndfax_name = "SendFAX";
+static char *app_sndfax_synopsis = "Send a FAX";
+static char *app_sndfax_desc = 
+"  SendFAX(filename[|options]):\n"
+"Send a given TIFF file to the channel as a FAX.\n"
+"The option string may contain zero or more of the following characters:\n"
+"     'a' -- makes the application behave as an answering machine\n"
+"	    The default behaviour is to behave as a calling machine.\n"
+"\n"
+"This application uses following variables:\n"
+"     LOCALSTATIONID to identify itself to the remote end.\n"
+"     LOCALHEADERINFO to generate a header line on each page.\n"
+"\n"
+"This application sets the following channel variables upon completion:\n"
+"     FAXSTATUS       - status of operation:\n"
+"			   SUCCESS | FAILED\n"
+"     FAXERROR	- Error when FAILED\n"
+"     REMOTESTATIONID - CSID of the remote side.\n"
+"     FAXPAGES	- number of pages sent.\n"
+"     FAXBITRATE      - transmition rate.\n"
+"     FAXRESOLUTION   - resolution.\n"
+"\n"
+"Returns -1 in case of user hang up or any channel error.\n"
+"Returns 0 on success.\n";
+
+static char *app_rcvfax_name = "ReceiveFAX";
+static char *app_rcvfax_synopsis = "Receive a FAX";
+static char *app_rcvfax_desc = 
+"  ReceiveFAX(filename[|options]):\n"
+"Receives a fax from the channel into the given filename overwriting\n"
+"the file if it already exists. File created will have TIFF format.\n"
+"The option string may contain zero or more of the following characters:\n"
+"     'c' -- makes the application behave as a calling machine\n"
+"	    The default behaviour is to behave as an answering machine.\n"
+"\n"
+"This application uses following variables:\n"
+"     LOCALSTATIONID to identify itself to the remote end.\n"
+"     LOCALHEADERINFO to generate a header line on each page.\n"
+"\n"
+"This application sets the following channel variables upon completion:\n"
+"     FAXSTATUS       - status of operation:\n"
+"			   SUCCESS | FAILED\n"
+"     FAXERROR	- Error when FAILED\n"
+"     REMOTESTATIONID - CSID of the remote side.\n"
+"     FAXPAGES	- number of pages sent.\n"
+"     FAXBITRATE      - transmition rate.\n"
+"     FAXRESOLUTION   - resolution.\n"
+"\n"
+"Returns -1 in case of user hang up or any channel error.\n"
+"Returns 0 on success.\n";
+
+#define MAX_SAMPLES 240
+
+/* Watchdog. I have seen situations when remote fax disconnects (because of poor line
+   quality) while SpanDSP continues staying in T30_STATE_IV_CTC state forever.
+   To avoid this, we terminate when we see that T30 state does not change for 5 minutes.
+   We also terminate application when more than 30 minutes passed regardless of
+   state changes. This is just a precaution measure - no fax should take that long */
+
+#define WATCHDOG_TOTAL_TIMEOUT	30 * 60
+#define WATCHDOG_STATE_TIMEOUT	5 * 60
+
+/* 
+   Definition is taken from spandsp.
+   
+   T.30 defines the following call phases:
+   Phase A: Call set-up.
+       Exchange of CNG, CED and the called terminal identification.
+   Phase B: Pre-message procedure for identifying and selecting the required facilities.
+       Capabilities negotiation, and training, up the the confirmation to receive.
+   Phase C: Message transmission (includes phasing and synchronization where appropriate).
+       Transfer of the message at high speed.
+   Phase D: Post-message procedure, including end-of-message and confirmation and multi-document procedures.
+       End of message and acknowledgement.
+   Phase E: Call release
+       Final call disconnect. */
+enum
+{
+    T30_PHASE_IDLE = 0,     /* Freshly initialised */
+    T30_PHASE_A_CED,        /* Doing the CED (answer) sequence */
+    T30_PHASE_A_CNG,        /* Doing the CNG (caller) sequence */
+    T30_PHASE_B_RX,         /* Receiving pre-message control messages */
+    T30_PHASE_B_TX,         /* Transmitting pre-message control messages */
+    T30_PHASE_C_NON_ECM_RX, /* Receiving a document message in non-ECM mode */
+    T30_PHASE_C_NON_ECM_TX, /* Transmitting a document message in non-ECM mode */
+    T30_PHASE_C_ECM_RX,     /* Receiving a document message in ECM (HDLC) mode */
+    T30_PHASE_C_ECM_TX,     /* Transmitting a document message in ECM (HDLC) mode */
+    T30_PHASE_D_RX,         /* Receiving post-message control messages */
+    T30_PHASE_D_TX,         /* Transmitting post-message control messages */
+    T30_PHASE_E,            /* In phase E */
+    T30_PHASE_CALL_FINISHED /* Call completely finished */
+};
+
+typedef struct {
+	struct ast_channel *chan;
+	enum ast_t38_state t38state;	/* T38 state of the channel */
+	int direction;			/* Fax direction: 0 - receiving, 1 - sending */
+	int caller_mode;
+	char *file_name;
+	volatile int finished;
+} fax_session;
+
+static void span_message(int level, const char *msg)
+{
+	if (level == SPAN_LOG_ERROR)
+		ast_log(LOG_ERROR, msg);
+	else if (level == SPAN_LOG_WARNING)
+		ast_log(LOG_WARNING, msg);
+	else
+		ast_log(LOG_DEBUG, msg);
+}
+
+static int t38_tx_packet_handler(t38_core_state_t *s, void *user_data, const uint8_t *buf, int len, int count)
+{
+	struct ast_channel *chan = (struct ast_channel *) user_data;
+
+	struct ast_frame outf = {
+		.frametype = AST_FRAME_MODEM,
+		.subclass = AST_MODEM_T38,
+		.src = __FUNCTION__,
+	};
+
+	/* TODO: Asterisk does not provide means of resending the same packet multiple
+	  times so count is ignored at the moment */
+
+	AST_FRAME_SET_BUFFER(&outf, buf, 0, len);
+
+	ast_log(LOG_DEBUG, "t38_tx_packet_handler \n");
+	
+	if (ast_write(chan, &outf) < 0) {
+		ast_log(LOG_WARNING, "Unable to write frame to channel; %s\n", strerror(errno));
+		return -1;
+	}
+
+	return 0;
+}
+
+static void phase_e_handler(t30_state_t *f, void *user_data, int result)
+{
+	char local_ident[T30_MAX_IDENT_LEN];
+	char far_ident[T30_MAX_IDENT_LEN];
+	char buf[20];
+	fax_session *s = (fax_session *) user_data;
+	t30_stats_t stat;
+
+	ast_log(LOG_DEBUG, "Fax phase E handler. result=%d\n", result);
+
+	t30_get_transfer_statistics(f, &stat);
+
+	s = (fax_session *) user_data;
+
+	if (result != T30_ERR_OK) {
+		s->finished = -1;
+
+		/* FAXSTATUS is already set to FAILED */
+		pbx_builtin_setvar_helper(s->chan, "FAXERROR", t30_completion_code_to_str(result));
+
+		ast_log(LOG_WARNING, "Error transmitting fax. result=%d: %s.\n", result, t30_completion_code_to_str(result));
+
+		return;
+	}
+	
+	s->finished = 1; 
+	
+//	t30_get_local_ident(f, local_ident);
+//	t30_get_far_ident(f, far_ident);
+	pbx_builtin_setvar_helper(s->chan, "FAXSTATUS", "SUCCESS"); 
+	pbx_builtin_setvar_helper(s->chan, "FAXERROR", NULL); 
+	pbx_builtin_setvar_helper(s->chan, "REMOTESTATIONID", far_ident);
+	snprintf(buf, sizeof(buf), "%d", stat.pages_transferred);
+	pbx_builtin_setvar_helper(s->chan, "FAXPAGES", buf);
+	snprintf(buf, sizeof(buf), "%d", stat.y_resolution);
+	pbx_builtin_setvar_helper(s->chan, "FAXRESOLUTION", buf);
+	snprintf(buf, sizeof(buf), "%d", stat.bit_rate);
+	pbx_builtin_setvar_helper(s->chan, "FAXBITRATE", buf); 
+	
+	//ast_debug(1, "Fax transmitted successfully.\n");
+	//ast_debug(1, "  Remote station ID: %s\n", far_ident);  
+	//ast_debug(1, "  Pages transferred: %d\n", stat.pages_transferred);
+	//ast_debug(1, "  Image resolution:  %d x %d\n", stat.x_resolution, stat.y_resolution);
+	//ast_debug(1, "  Transfer Rate:     %d\n", stat.bit_rate);
+	
+	manager_event(EVENT_FLAG_CALL,
+		      s->direction ? "FaxSent" : "FaxReceived", 
+		      "Channel: %s\r\n"
+		      "Exten: %s\r\n"
+		      "CallerID: %s\r\n"
+		      "RemoteStationID: %s\r\n"
+		      "LocalStationID: %s\r\n"
+		      "PagesTransferred: %d\r\n"
+		      "Resolution: %d\r\n"
+		      "TransferRate: %d\r\n"
+		      "FileName: %s\r\n",
+		      s->chan->name,
+		      s->chan->exten,
+		      S_OR(s->chan->cid.cid_num, ""),
+		      far_ident,
+		      local_ident,
+		      stat.pages_transferred,
+		      stat.y_resolution,
+		      stat.bit_rate,
+		      s->file_name);
+}
+
+/* === Helper functions to configure fax === */
+
+/* Setup SPAN logging according to Asterisk debug level */
+static int set_logging(logging_state_t *state)
+{
+	int level = SPAN_LOG_WARNING;// + option_debug;
+
+	span_log_set_message_handler(state, span_message);
+	span_log_set_level(state, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | level);
+	
+	return 0;
+}
+
+static void set_local_info(t30_state_t *state, fax_session *s)
+{
+	const char *x;
+
+	x = pbx_builtin_getvar_helper(s->chan, "LOCALSTATIONID");
+//	if (!ast_strlen_zero(x))
+//		t30_set_local_ident(state, x);
+
+	x = pbx_builtin_getvar_helper(s->chan, "LOCALHEADERINFO");
+//	if (!ast_strlen_zero(x))
+//		t30_set_header_info(state, x);
+}
+
+static void set_file(t30_state_t *state, fax_session *s)
+{
+	if (s->direction)
+		t30_set_tx_file(state, s->file_name, -1, -1);
+	else
+		t30_set_rx_file(state, s->file_name, -1);
+}
+
+static void set_ecm(t30_state_t *state, int ecm)
+{
+	t30_set_ecm_capability(state, ecm);
+	t30_set_supported_compressions(state, T30_SUPPORT_T4_1D_COMPRESSION | T30_SUPPORT_T4_2D_COMPRESSION | T30_SUPPORT_T6_COMPRESSION);
+}
+
+/* === Generator === */
+
+/* This function is only needed to return passed params so
+   generator_activate will save it to channel's generatordata */
+static void *fax_generator_alloc(struct ast_channel *chan, void *params)
+{
+	return params;
+}
+
+static int fax_generator_generate(struct ast_channel *chan, void *data, int len, int samples)
+{
+	fax_state_t *fax = (fax_state_t*) data;
+	uint8_t buffer[AST_FRIENDLY_OFFSET + MAX_SAMPLES * sizeof(uint16_t)];
+	int16_t *buf = (int16_t *) (buffer + AST_FRIENDLY_OFFSET);
+    
+	struct ast_frame outf = {
+		.frametype = AST_FRAME_VOICE,
+		.subclass = AST_FORMAT_SLINEAR,
+		.src = __FUNCTION__,
+	};
+
+	if (samples > MAX_SAMPLES) {
+		ast_log(LOG_WARNING, "Only generating %d samples, where %d requested\n", MAX_SAMPLES, samples);
+		samples = MAX_SAMPLES;
+	}
+	
+	if ((len = fax_tx(fax, buf, samples)) > 0) {
+		outf.samples = len;
+		AST_FRAME_SET_BUFFER(&outf, buffer, AST_FRIENDLY_OFFSET, len * sizeof(int16_t));
+
+		if (ast_write(chan, &outf) < 0) {
+			ast_log(LOG_WARNING, "Failed to write frame to '%s': %s\n", chan->name, strerror(errno));
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+struct ast_generator generator = {
+	alloc:		fax_generator_alloc,
+	generate: 	fax_generator_generate,
+};
+
+
+/* === Transmission === */
+
+static int transmit_audio(fax_session *s)
+{
+	int res = -1;
+	int original_read_fmt = AST_FORMAT_SLINEAR;
+	int original_write_fmt = AST_FORMAT_SLINEAR;
+//	int len;
+//	int samples;
+	fax_state_t fax;
+	struct ast_dsp *dsp = NULL;
+	int detect_tone = 0;
+	struct ast_frame *inf = NULL;
+//	struct ast_frame outf;
+	struct ast_frame *fr;
+//	uint8_t buffer[AST_FRIENDLY_OFFSET + MAX_SAMPLES * sizeof(uint16_t)];
+//	int16_t *buf = (int16_t *) (buffer + AST_FRIENDLY_OFFSET);
+	int last_state = 0;
+	struct timeval now, start, state_change;
+	enum ast_control_t38 t38control;
+	
+	ast_log(LOG_DEBUG, "transmit_audio entry\n");
+	original_read_fmt = s->chan->readformat;
+	if (original_read_fmt != AST_FORMAT_SLINEAR) {
+		res = ast_set_read_format(s->chan, AST_FORMAT_SLINEAR);
+		if (res < 0) {
+			ast_log(LOG_WARNING, "Unable to set to linear read mode, giving up\n");
+			goto done;
+		}
+	}
+
+	original_write_fmt = s->chan->writeformat;
+	if (original_write_fmt != AST_FORMAT_SLINEAR) {
+		res = ast_set_write_format(s->chan, AST_FORMAT_SLINEAR);
+		if (res < 0) {
+			ast_log(LOG_WARNING, "Unable to set to linear write mode, giving up\n");
+			goto done;
+		}
+	}
+
+	/* Initialize T30 terminal */
+	fax_init(&fax, s->caller_mode);
+
+	/* Setup logging */
+	set_logging(&fax.logging);
+	set_logging(&fax.t30_state.logging);
+
+	/* Configure terminal */
+	set_local_info(&fax.t30_state, s);
+	set_file(&fax.t30_state, s);
+	set_ecm(&fax.t30_state, TRUE);
+
+	fax_set_transmit_on_idle(&fax, TRUE);
+
+	t30_set_phase_e_handler(&fax.t30_state, phase_e_handler, s);
+
+	if (s->t38state == T38_STATE_UNAVAILABLE) {
+		ast_log(LOG_DEBUG, "T38 is unavailable on %s\n", s->chan->name);
+	} else if (!s->direction) {
+		/* We are receiving side and this means we are the side which should
+		   request T38 when the fax is detected. Use DSP to detect fax tone */
+		//ast_debug(1, "Setting up CNG detection on %s\n", s->chan->name);
+		dsp = ast_dsp_new();
+		ast_dsp_set_features(dsp, DSP_FEATURE_FAX_DETECT);
+		ast_dsp_set_faxmode(dsp, DSP_FAXMODE_DETECT_CNG);
+		detect_tone = 1;
+	}
+
+	start = state_change = ast_tvnow();
+
+	ast_activate_generator(s->chan, &generator, &fax);
+
+	while (!s->finished) {
+		res = ast_waitfor(s->chan, 20);
+		if (res < 0)
+			break;
+		else if (res > 0)
+			res = 0;
+
+		inf = ast_read(s->chan);
+		if (inf == NULL) {
+			ast_log(LOG_DEBUG, "Channel hangup\n");
+			res = 0;
+			break;
+		}
+
+		//ast_debug(10, "frame %d/%d, len=%d\n", inf->frametype, inf->subclass, inf->datalen);
+
+		/* Detect fax tone */
+		if (detect_tone && inf->frametype == AST_FRAME_VOICE) {
+			/* Duplicate frame because ast_dsp_process may free the frame passed */
+			fr = ast_frdup(inf);
+
+			/* Do not pass channel to ast_dsp_process otherwise it may queue modified audio frame back */
+			fr = ast_dsp_process(NULL, dsp, fr);
+			if (fr && fr->frametype == AST_FRAME_DTMF && fr->subclass == 'f') {
+				ast_log(LOG_DEBUG, "Fax tone detected. Requesting T38\n");
+				t38control = AST_T38_REQUEST_NEGOTIATE;
+				ast_indicate_data(s->chan, AST_CONTROL_T38, &t38control, sizeof(t38control));
+				detect_tone = 0;
+			}
+
+			ast_frfree(fr);
+		}
+
+
+		/* Check the frame type. Format also must be checked because there is a chance
+		   that a frame in old format was already queued before we set chanel format
+		   to slinear so it will still be received by ast_read */
+		if (inf->frametype == AST_FRAME_VOICE && inf->subclass == AST_FORMAT_SLINEAR) {
+			ast_log(LOG_DEBUG, "Got frame voice g711\n");
+			if (fax_rx(&fax, inf->data, inf->samples) < 0) {
+				/* I know fax_rx never returns errors. The check here is for good style only */
+				ast_log(LOG_WARNING, "fax_rx returned error\n");
+				res = -1;
+				break;
+			}
+
+			/* Watchdog */
+			if (last_state != fax.t30_state.state) {
+				state_change = ast_tvnow();
+				last_state = fax.t30_state.state;
+			}
+		} else if (inf->frametype == AST_FRAME_CONTROL && inf->subclass == AST_CONTROL_T38 &&
+				inf->datalen == sizeof(enum ast_control_t38)) {
+			t38control =*((enum ast_control_t38 *) inf->data);
+			if (t38control == AST_T38_NEGOTIATED) {
+				/* T38 switchover completed */
+				ast_log(LOG_DEBUG, "T38 negotiated, finishing audio loop\n");
+				res = 1;
+				break;
+			}
+		}
+
+		ast_frfree(inf);
+		inf = NULL;
+
+		/* Watchdog */
+		now = ast_tvnow();
+		if (ast_tvdiff_sec(now, start) > WATCHDOG_TOTAL_TIMEOUT || ast_tvdiff_sec(now, state_change) > WATCHDOG_STATE_TIMEOUT) {
+			ast_log(LOG_WARNING, "It looks like we hung. Aborting.\n");
+			res = -1;
+			break;
+		}
+	}
+
+	//ast_debug(1, "Loop finished, res=%d\n", res);
+
+	if (inf)
+		ast_frfree(inf);
+
+	if (dsp)
+		ast_dsp_free(dsp);
+
+	ast_deactivate_generator(s->chan);
+
+	/* Remove phase E handler because we do not want it to be executed
+	   only because we called t30_terminate */
+	t30_set_phase_e_handler(&fax.t30_state, NULL, NULL);
+
+	t30_terminate(&fax.t30_state);
+	fax_release(&fax);
+
+done:
+	if (fax.t30_state.phase == T30_PHASE_CALL_FINISHED)
+	{
+		s->finished = 1;
+	}
+
+	
+	if (original_write_fmt != AST_FORMAT_SLINEAR) {
+		if (ast_set_write_format(s->chan, original_write_fmt) < 0)
+			ast_log(LOG_WARNING, "Unable to restore write format on '%s'\n", s->chan->name);
+	}
+
+	if (original_read_fmt != AST_FORMAT_SLINEAR) {
+		if (ast_set_read_format(s->chan, original_read_fmt) < 0)
+			ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", s->chan->name);
+	}
+	
+
+	return res;
+
+}
+
+static int transmit_t38(fax_session *s)
+{
+	int res = 0;
+//	int len;
+//	int samples;
+	t38_terminal_state_t t38;
+	struct ast_frame *inf = NULL;
+	int last_state = 0;
+	struct timeval now, start, state_change, last_frame;
+	enum ast_control_t38 t38control;
+
+	/* Initialize terminal */
+	memset(&t38, 0, sizeof(t38));
+	if (t38_terminal_init(&t38, s->caller_mode, t38_tx_packet_handler, s->chan) == NULL) {
+		ast_log(LOG_WARNING, "Unable to start T.38 termination.\n");
+		return -1;
+	}
+
+	/* Setup logging */
+	set_logging(&t38.logging);
+	set_logging(&t38.t30_state.logging);
+	set_logging(&t38.t38.logging);
+
+	/* Configure terminal */
+	set_local_info(&t38.t30_state, s);
+	set_file(&t38.t30_state, s);
+	set_ecm(&t38.t30_state, TRUE);
+
+	t30_set_phase_e_handler(&t38.t30_state, phase_e_handler, s);
+
+	now = start = state_change = ast_tvnow();
+
+	while (!s->finished) {
+
+		res = ast_waitfor(s->chan, 20);
+		if (res < 0)
+			break;
+		else if (res > 0)
+			res = 0;
+
+		last_frame = now;
+		now = ast_tvnow();
+		
+		t38_terminal_send_timeout(&t38, ast_tvdiff_us(now, last_frame) / (1000000 / 8000));
+		
+		// ast_log(LOG_DEBUG, "After t38_terminal_send_timeout samples %d ret %d\n", samples, retBool);
+		
+		inf = ast_read(s->chan);
+		if (inf == NULL) {
+			ast_log(LOG_DEBUG, "Channel hangup\n");
+			res = 0;
+			break;
+		}
+
+		// ast_log(LOG_DEBUG, "frame %d  %d, len= %d \n", inf->frametype, inf->subclass, inf->datalen);
+
+		if (inf->frametype == AST_FRAME_MODEM && inf->subclass == AST_MODEM_T38) {
+			t38_core_rx_ifp_packet(&t38.t38, inf->data, inf->datalen, inf->seqno);
+
+			/* Watchdog */
+			if (last_state != t38.t30_state.state) {
+				state_change = ast_tvnow();
+				last_state = t38.t30_state.state;
+			}
+		} else if (inf->frametype == AST_FRAME_CONTROL && inf->subclass == AST_CONTROL_T38 &&
+				inf->datalen == sizeof(enum ast_control_t38)) {
+
+			t38control = *((enum ast_control_t38 *) inf->data);
+
+			if (t38control == AST_T38_TERMINATED || t38control == AST_T38_REFUSED) {
+				//ast_debug(1, "T38 down, terminating\n");
+				res = -1;
+				break;
+			}
+		}
+
+		ast_frfree(inf);
+		inf = NULL;
+
+		/* Watchdog */
+		if (ast_tvdiff_sec(now, start) > WATCHDOG_TOTAL_TIMEOUT || ast_tvdiff_sec(now, state_change) > WATCHDOG_STATE_TIMEOUT) {
+			ast_log(LOG_WARNING, "It looks like we hung. Aborting.\n");
+			res = -1;
+			break;
+		}
+	}
+
+	//ast_debug(1, "Loop finished, res=%d\n", res);
+
+	if (inf)
+		ast_frfree(inf);
+
+	/* Remove phase E handler because we do not want it to be executed
+	   only because we called t30_terminate */
+	t30_set_phase_e_handler(&t38.t30_state, NULL, NULL);
+
+	t30_terminate(&t38.t30_state);
+	
+	if (t38.t30_state.phase == T30_PHASE_CALL_FINISHED)
+	{
+		s->finished = 1;
+	}
+
+	return res;
+}
+
+static int transmit(fax_session *s)
+{
+	int res = 0;
+//	enum ast_t38_state t38state;
+
+	/* Clear all channel variables which to be set by the application.
+	   Pre-set status to error so in case of any problems we can just leave */
+	pbx_builtin_setvar_helper(s->chan, "FAXSTATUS", "FAILED"); 
+	pbx_builtin_setvar_helper(s->chan, "FAXERROR", "Channel problems"); 
+
+	pbx_builtin_setvar_helper(s->chan, "REMOTESTATIONID", NULL);
+	pbx_builtin_setvar_helper(s->chan, "FAXPAGES", NULL);
+	pbx_builtin_setvar_helper(s->chan, "FAXRESOLUTION", NULL);
+	pbx_builtin_setvar_helper(s->chan, "FAXBITRATE", NULL); 
+
+	if (s->chan->_state != AST_STATE_UP) {
+		/* Shouldn't need this, but checking to see if channel is already answered
+		 * Theoretically asterisk should already have answered before running the app */
+		res = ast_answer(s->chan);
+		if (res) {
+			ast_log(LOG_WARNING, "Could not answer channel '%s'\n", s->chan->name);
+			return res;
+		}
+	}
+
+	s->t38state = ast_channel_get_t38_state(s->chan);
+	if (s->t38state != T38_STATE_NEGOTIATED) {
+		/* T38 is not negotiated on the channel yet. First start regular transmission. If it switches to T38, follow */	
+		res = transmit_audio(s);
+		if (res > 0) {
+			/* transmit_audio reports switchover to T38. Update t38state */
+			s->t38state = ast_channel_get_t38_state(s->chan);
+			if (s->t38state != T38_STATE_NEGOTIATED) {
+				ast_log(LOG_ERROR, "Audio loop reports T38 switchover but t38state != T38_STATE_NEGOTIATED\n");
+			}
+		}
+	}
+
+	if (s->t38state == T38_STATE_NEGOTIATED) {
+		res = transmit_t38(s);
+	}
+	
+	if (res) {
+		ast_log(LOG_WARNING, "Transmission error\n");
+		res = -1;
+	} else if (s->finished < 0) {
+		ast_log(LOG_WARNING, "Transmission failed\n");
+	} else if (s->finished > 0) {
+		ast_log(LOG_DEBUG, "Transmission finished Ok\n");
+	}
+
+	return res;
+}
+
+/* === Application functions === */
+
+static int sndfax_exec(struct ast_channel *chan, void *data)
+{
+	int res = 0;
+	char *parse;
+	fax_session session;
+
+	AST_DECLARE_APP_ARGS(args,
+		AST_APP_ARG(file_name);
+		AST_APP_ARG(options);
+	);
+
+	if (chan == NULL) {
+		ast_log(LOG_ERROR, "Fax channel is NULL. Giving up.\n");
+		return -1;
+	}
+
+	/* The next few lines of code parse out the filename and header from the input string */
+	if (ast_strlen_zero(data)) {
+		/* No data implies no filename or anything is present */
+		ast_log(LOG_ERROR, "SendFAX requires an argument (filename)\n");
+		return -1;
+	}
+
+	parse = ast_strdupa(data);
+	AST_STANDARD_APP_ARGS(args, parse);
+	
+	session.caller_mode = TRUE;
+
+	if (args.options) {
+		if (strchr(args.options, 'a'))
+			session.caller_mode = FALSE;
+	}
+
+	pbx_builtin_setvar_helper(chan, "T38CALL", "1"); 
+	
+	/* Done parsing */
+	session.direction = 1;
+	session.file_name = args.file_name;
+	session.chan = chan;
+	session.finished = 0;
+	
+	res = transmit(&session);
+
+	return res;
+}
+
+static int rcvfax_exec(struct ast_channel *chan, void *data)
+{
+	int res = 0;
+	char *parse;
+	fax_session session;
+
+	AST_DECLARE_APP_ARGS(args,
+		AST_APP_ARG(file_name);
+		AST_APP_ARG(options);
+	);
+
+	if (chan == NULL) {
+		ast_log(LOG_ERROR, "Fax channel is NULL. Giving up.\n");
+		return -1;
+	}
+
+	/* The next few lines of code parse out the filename and header from the input string */
+	if (ast_strlen_zero(data)) {
+		/* No data implies no filename or anything is present */
+		ast_log(LOG_ERROR, "ReceiveFAX requires an argument (filename)\n");
+		return -1;
+	}
+
+	parse = ast_strdupa(data);
+	AST_STANDARD_APP_ARGS(args, parse);
+	
+	session.caller_mode = FALSE;
+
+	if (args.options) {
+		if (strchr(args.options, 'c'))
+			session.caller_mode = TRUE;
+	}
+
+	/* Done parsing */
+	session.direction = 0;
+	session.file_name = args.file_name;
+	session.chan = chan;
+	session.finished = 0;
+
+	res = transmit(&session);
+
+	return res;
+}
+
+static int unload_module(void)
+{
+	int res;
+
+	res = ast_unregister_application(app_sndfax_name);	
+	res |= ast_unregister_application(app_rcvfax_name);	
+
+	return res;
+}
+
+static int load_module(void)
+{
+	int res ;
+
+	res = ast_register_application(app_sndfax_name, sndfax_exec, app_sndfax_synopsis, app_sndfax_desc);
+	res |= ast_register_application(app_rcvfax_name, rcvfax_exec, app_rcvfax_synopsis, app_rcvfax_desc);
+
+	/* The default SPAN message handler prints to stderr. It is something we do not want */
+	span_set_message_handler(NULL);
+
+	return res;
+}
+
+
+AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Simple FAX Application",
+		.load = load_module,
+		.unload = unload_module,
+		);
+
+
diff -ruN asterisk-1.4.20.1_original/apps/app_faxgateway.c asterisk-1.4.20.1_updated/apps/app_faxgateway.c
--- asterisk-1.4.20.1_original/apps/app_faxgateway.c	1970-01-01 01:00:00.000000000 +0100
+++ asterisk-1.4.20.1_updated/apps/app_faxgateway.c	2008-06-25 23:51:43.000000000 +0200
@@ -0,0 +1,939 @@
+/*
+ * Asterisk -- A telephony toolkit for Linux.
+ *
+ * Simple fax gateway applications
+ * 
+ * 2008, Daniel Ferenci <daniel.ferenci@nethemba.com> 
+ * Created by Nethemba s.r.o. http://www.nethemba.com
+ * Sponsored by IPEX a.s. http://www.ipex.cz
+ * 
+ * Code based on original implementation by Steve Underwood <steveu@coppice.org>
+ * and Dmitry Andrianov <asterisk@dima.spb.ru>
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License
+ *
+ */
+
+/*
+Todo:
+	1. switch over to T38 when CED or CNG detected
+	2. to make things compatible use macros
+*/
+ 
+/*** MODULEINFO
+	 <depend>spandsp</depend>
+***/
+ 
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision: 1.19 $")
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <inttypes.h>
+#include <pthread.h>
+#include <errno.h>
+#include <tiffio.h>
+
+#include <spandsp.h>
+
+#include "asterisk/lock.h"
+#include "asterisk/file.h"
+#include "asterisk/logger.h"
+#include "asterisk/channel.h"
+#include "asterisk/pbx.h"
+#include "asterisk/app.h"
+#include "asterisk/dsp.h"
+#include "asterisk/module.h"
+#include "asterisk/manager.h"
+#include "asterisk/causes.h"
+#include "asterisk/musiconhold.h"
+#include "asterisk/rtp.h"
+
+static char *app_faxgw_name = "FaxGateway";
+static char *app_faxgw_synopsis = "FAX Gateway";
+static char *app_faxgw_desc = 
+"  FaxGateway(dialstring[, timeout]):\n"
+"Send a given TIFF file to the channel as a FAX.\n"
+"This application uses following variables:\n"
+"\n"
+"This application sets the following channel variables upon completion:\n"
+"     FAXSTATUS - status of operation:\n"
+"		  SUCCESS | FAILED\n"
+"     FAXERROR	- Error when FAILED\n"
+"\n"
+"Returns -1 in case of user hang up or any channel error.\n"
+"Returns 0 on success.\n";
+
+#define DONE_WITH_ERROR -1
+#define RUNNING 1
+#define DONE 0
+
+#define MAX_BLOCK_SIZE 240
+
+#define MAX_SAMPLES 240
+
+#define ready_to_talk(chan,peer) ((!chan  ||  !peer  ||  ast_check_hangup(chan)  ||  ast_check_hangup(peer))  ?  0  :  1)
+
+#define clean_frame(f) if(f) {ast_frfree(f); f = NULL;}
+
+/* Watchdog. I have seen situations when remote fax disconnects (because of poor line
+   quality) while SpanDSP continues staying in T30_STATE_IV_CTC state forever.
+   To avoid this, we terminate when we see that T30 state does not change for 5 minutes.
+   We also terminate application when more than 30 minutes passed regardless of
+   state changes. This is just a precaution measure - no fax should take that long */
+
+#define WATCHDOG_TOTAL_TIMEOUT	30 * 60
+#define WATCHDOG_STATE_TIMEOUT	5 * 60
+
+/* free the buffer if allocated, and set the pointer to the second arg */
+#define S_REPLACE(s, new_val)		\
+	do {				\
+		if (s)			\
+			ast_free(s);	\
+		s = (new_val);		\
+	} while (0)
+ 
+typedef struct {
+	struct ast_channel *chan;
+	struct ast_channel *peer;
+	enum ast_t38_state chan_t38state;	/* T38 state of the channel */
+	enum ast_t38_state peer_t38state;	/* T38 state of the peer */
+	int direction;			/* Fax direction: 0 - receiving, 1 - sending */
+	int caller_mode;
+	int verbose;
+	char *dest;
+	char * dest_type;
+	int timeout;
+	volatile int finished;
+} fax_session;
+
+static void senddialevent(struct ast_channel *src, struct ast_channel *dst, const char *dialstring)
+{
+	manager_event(EVENT_FLAG_CALL, "Dial",
+		"SubEvent: Begin\r\n"
+		"Channel: %s\r\n"
+		"Destination: %s\r\n"
+		"CallerIDNum: %s\r\n"
+		"CallerIDName: %s\r\n"
+		"UniqueID: %s\r\n"
+		"DestUniqueID: %s\r\n"
+		"Dialstring: %s\r\n",
+		src->name, dst->name, S_OR(src->cid.cid_num, "<unknown>"),
+		S_OR(src->cid.cid_name, "<unknown>"), src->uniqueid,
+		dst->uniqueid, dialstring ? dialstring : "");
+}
+
+struct cause_args {
+	struct ast_channel *chan;
+	int busy;
+	int congestion;
+	int nochan;
+};
+
+static void handle_cause(int cause, struct cause_args *num)
+{
+	struct ast_cdr *cdr = num->chan->cdr;
+
+	switch(cause) {
+	case AST_CAUSE_BUSY:
+		if (cdr)
+			ast_cdr_busy(cdr);
+		num->busy++;
+		break;
+
+	case AST_CAUSE_CONGESTION:
+		if (cdr)
+			ast_cdr_failed(cdr);
+		num->congestion++;
+		break;
+
+	case AST_CAUSE_UNREGISTERED:
+		if (cdr)
+			ast_cdr_failed(cdr);
+		num->nochan++;
+		break;
+
+	case AST_CAUSE_NORMAL_CLEARING:
+		break;
+
+	default:
+		num->nochan++;
+		break;
+	}
+}
+
+static void span_message(int level, const char *msg)
+{
+	if (level == SPAN_LOG_ERROR)
+		ast_log(LOG_ERROR, msg);
+	else if (level == SPAN_LOG_WARNING)
+		ast_log(LOG_WARNING, msg);
+	else
+		ast_log(LOG_DEBUG, msg);
+}
+
+static int t38_tx_packet_handler(t38_core_state_t *s, void *user_data, const uint8_t *buf, int len, int count)
+{
+	ast_log(LOG_DEBUG, "t38_tx_packet_handler entry.");
+	
+	struct ast_channel *chan = (struct ast_channel *) user_data;
+
+	struct ast_frame outf = {
+		.frametype = AST_FRAME_MODEM,
+		.subclass = AST_MODEM_T38,
+		.src = __FUNCTION__,
+	};
+
+	AST_FRAME_SET_BUFFER(&outf, buf, 0, len);
+
+	if (ast_write(chan, &outf) < 0) {
+		ast_log(LOG_WARNING, "Unable to write frame to channel; %s\n", strerror(errno));
+		return -1;
+	}
+
+	return 0;
+}
+
+/* === Gateway === */
+
+static int ast_bridge_frames(fax_session *s)
+{
+    struct ast_channel *active = NULL;
+    struct ast_channel *inactive = NULL;
+    struct ast_channel *channels[2];
+    struct ast_frame *f;
+    struct ast_frame *fr2;
+    int timeout = -1;
+    int running = RUNNING;
+    struct ast_dsp *dsp_cng = NULL;
+    struct ast_dsp *dsp_ced = NULL;
+    enum ast_control_t38 t38control;
+
+    ast_log(LOG_DEBUG, "faxGw - ast_bridge_frames entry \n");
+    
+    if ((dsp_cng = ast_dsp_new()) == NULL)
+    {
+        ast_log(LOG_WARNING, "Unable to allocate DSP!\n");
+    }
+    else
+    {
+        ast_dsp_set_threshold(dsp_cng, 256); 
+        ast_dsp_set_features(dsp_cng, DSP_FEATURE_FAX_DETECT | DSP_FAXMODE_DETECT_CNG);
+        ast_dsp_digitmode(dsp_cng, DSP_DIGITMODE_DTMF | DSP_DIGITMODE_RELAXDTMF);
+    }
+
+    if ((dsp_ced = ast_dsp_new()) == NULL)
+    {
+        ast_log(LOG_WARNING, "Unable to allocate DSP!\n");
+    }
+    else
+    {
+        ast_dsp_set_threshold(dsp_ced, 256); 
+        ast_dsp_set_features(dsp_ced, DSP_FAXMODE_DETECT_CED);
+    }
+
+    
+    channels[0] = s->chan;
+    channels[1] = s->peer;
+
+    while (running == RUNNING  &&  (running = ready_to_talk(channels[0], channels[1])))
+    {
+
+//      ast_log(LOG_NOTICE, "br: t38 status: [%d,%d]\n", s->chan_t38state, s->peer_t38state);
+//	ast_log(LOG_NOTICE, "br: %s %s \n", s->chan->name , s->peer->name);
+	
+        if ((active = ast_waitfor_n(channels, 2, &timeout)))
+        {
+            inactive = (active == channels[0])  ?   channels[1]  :  channels[0];
+            if ((f = ast_read(active)))
+            {
+
+                if (dsp_ced  &&  dsp_cng)
+                    fr2 = ast_frdup(f);
+                else
+                    fr2 = NULL;
+
+    		if (( s->chan_t38state == T38_STATE_NEGOTIATING ) || ( s->peer_t38state == T38_STATE_NEGOTIATING )) 
+		{
+		/*  TODO 
+		    This is a very BASIC method to mute a channel. It should be improved
+		    and we should send EMPTY frames (not just avoid sending them) 
+		*/
+		    ast_log(LOG_DEBUG, "channels are muted.\n");
+		}
+		else
+		{
+		    //ast_log(LOG_NOTICE, "do write on %p\n", inactive);	
+            	    int ret = ast_write(inactive, f);
+		    if (ret !=0 )
+		    {
+			   ast_log(LOG_NOTICE, "write error %d\n", ret); 
+		    }
+		}
+		    
+                clean_frame(f);
+                channels[0] = inactive;
+                channels[1] = active;
+
+                if (active == s->chan)
+                {
+                    /* Look for FAX CNG tone */
+                    if (fr2  &&  dsp_cng)
+                    {
+                        if ((fr2 = ast_dsp_process(active, dsp_cng, fr2)))
+                        {
+                            if (fr2->frametype == AST_FRAME_DTMF)
+                            {
+                                if (fr2->subclass == 'f')
+                                {
+                                    ast_log(LOG_DEBUG, "FAX CNG detected in T38 Gateway !!!\n");
+                                    // switch over to t38
+				    t38control = AST_T38_REQUEST_NEGOTIATE;
+				    ast_indicate_data(s->chan, AST_CONTROL_T38, &t38control, sizeof(t38control));
+                                }
+                            }
+                        }
+                    }
+                }
+                else
+                {
+                    /* Look for FAX CED tone or V.21 preamble */
+                    if (fr2  &&  dsp_ced)
+                    {
+                        if ((fr2 = ast_dsp_process(active, dsp_ced, fr2)))
+                        {
+                            if (fr2->frametype == AST_FRAME_DTMF)
+                            {
+                                if (fr2->subclass == 'F')
+                                {
+                                    ast_log(LOG_DEBUG, "FAX CED detected in T38 Gateway !!!\n");
+                                    // switch over to t38
+				    t38control = AST_T38_REQUEST_NEGOTIATE;
+				    ast_indicate_data(s->chan, AST_CONTROL_T38, &t38control, sizeof(t38control));
+	                        }
+                            }
+                        }
+                    }
+                }
+                if (f != fr2)
+                {
+                    if (fr2)
+                        ast_frfree(fr2);
+                    fr2 = NULL;
+                }
+            }
+            else
+            {
+                running = DONE;
+            }
+        }
+
+	s->chan_t38state = ast_channel_get_t38_state(s->chan);
+	s->peer_t38state = ast_channel_get_t38_state(s->peer);
+
+        /* Check if we need to change to gateway operation */
+        if ( 
+	        ( s->chan_t38state != T38_STATE_NEGOTIATING ) 
+	     && ( s->peer_t38state != T38_STATE_NEGOTIATING )
+	     && ( s->chan_t38state != s->peer_t38state) 
+	   ) {
+            ast_log(LOG_DEBUG, "Stop bridging frames. [ %d,%d]\n", s->chan_t38state, s->peer_t38state);
+            running = RUNNING;
+            break;
+	}
+    }
+
+    if (dsp_cng)
+        ast_dsp_free(dsp_cng);
+    if (dsp_ced)
+        ast_dsp_free(dsp_ced);
+
+    return running;
+}
+
+
+static int ast_t38_gateway(fax_session *s)
+{
+    struct ast_channel *active = NULL;
+    struct ast_channel *inactive = NULL;
+    struct ast_channel *channels[2];
+    enum ast_t38_state states[2];
+
+    struct ast_frame *f;
+    struct ast_frame outf;
+    int timeout = 60;
+    int running = RUNNING;
+    int original_read_fmt;
+    int original_write_fmt;
+    int res;
+    int samples;
+    int len;
+    s->verbose = 1;
+    
+    enum ast_control_t38 t38control;
+    t38_gateway_state_t t38_state;
+    
+    uint8_t __buf[sizeof(uint16_t)*MAX_BLOCK_SIZE + 2*AST_FRIENDLY_OFFSET];
+    uint8_t *buf = __buf + AST_FRIENDLY_OFFSET;
+    
+    ast_log(LOG_DEBUG, "faxGw - ast_t38_gateway entry \n");
+
+    if ( s->chan_t38state == T38_STATE_NEGOTIATED )
+    {
+        channels[0] = s->chan;
+        channels[1] = s->peer;
+	states[0] = s->chan_t38state;
+	states[1] = s->peer_t38state;
+    }
+    else
+    {
+        channels[0] = s->peer;
+        channels[1] = s->chan;
+	states[0] = s->peer_t38state;
+	states[1] = s->chan_t38state;
+    }
+    
+    ast_log(LOG_DEBUG, "chan %p  peer %p channels[0] %p channels[1] %p\n", s->chan, s->peer, channels[0], channels[1]);
+
+    original_read_fmt = channels[1]->readformat;
+    original_write_fmt = channels[1]->writeformat;
+    if ( states[1] != T38_STATE_NEGOTIATED)
+    {
+        if (original_read_fmt != AST_FORMAT_SLINEAR)
+        {
+            if ((res = ast_set_read_format(channels[1], AST_FORMAT_SLINEAR)) < 0)
+            {
+                ast_log(LOG_WARNING, "Unable to set to linear read mode, giving up\n");
+                return -1;
+            }
+        }
+        if (original_write_fmt != AST_FORMAT_SLINEAR)
+        {
+            if ((res = ast_set_write_format(channels[1], AST_FORMAT_SLINEAR)) < 0)
+            {
+                ast_log(LOG_WARNING, "Unable to set to linear write mode, giving up\n");
+                if ((res = ast_set_read_format(channels[1], original_read_fmt)))
+                    ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", channels[1]->name);
+                return -1;
+            }
+        }
+    }
+
+    if (t38_gateway_init(&t38_state, t38_tx_packet_handler, channels[0]) == NULL)
+    {
+        ast_log(LOG_WARNING, "Unable to start the T.38 gateway\n");
+        return -1;
+    }
+    ast_log(LOG_NOTICE, "T.38 gateway started\n");
+    t38_gateway_set_transmit_on_idle(&t38_state, TRUE);
+
+    span_log_set_message_handler(&t38_state.logging, span_message);
+    span_log_set_message_handler(&t38_state.t38.logging, span_message);
+    if (s->verbose)
+    {
+        span_log_set_level(&t38_state.logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW);
+        span_log_set_level(&t38_state.t38.logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW);
+    }
+    t38_set_t38_version(&t38_state.t38, 0);
+    t38_gateway_set_ecm_capability(&t38_state, 1);
+
+
+    while (running == RUNNING  &&  (running = ready_to_talk(channels[0], channels[1])))
+    {
+        // ast_log(LOG_NOTICE, "gw: t38status: [%d,%d]\n", s->chan_t38state, s->peer_t38state);
+        if ( 
+	        ( s->chan_t38state == T38_STATE_NEGOTIATED ) 
+	     && ( s->peer_t38state == T38_STATE_NEGOTIATED )
+	   ) {
+            ast_log(LOG_DEBUG, "Stop gateway-ing frames (both channels are in t38 mode). [ %d,%d]\n", s->chan_t38state, s->peer_t38state);
+            running = RUNNING;
+            break;
+	}
+
+        if ((active = ast_waitfor_n(channels, 2, &timeout)))
+        {
+//	    char tmpString[20];
+//	    if (active == s->chan)
+//	    {
+//		 strncpy(tmpString, "chan", 20);   
+//	    }
+//	    if (active == s->peer)
+//	    {
+//  		 strncpy(tmpString, "peer", 20);   
+//	    }
+//	    ast_log(LOG_DEBUG, "Fax gw - active - %s \n" , tmpString);
+            if (active == channels[0])
+            {
+                if ((f = ast_read(active)))
+                {
+//		    ast_log(LOG_DEBUG, "ast_t38_gateway received %d \n" , f->frametype);
+		    if (f->frametype == AST_FRAME_MODEM && f->subclass == AST_MODEM_T38)
+		    {
+			    t38_core_rx_ifp_packet(&t38_state.t38, f->data, f->datalen, f->seqno);
+			    
+		    }
+		    else if (f->frametype == AST_FRAME_CONTROL && f->subclass == AST_CONTROL_T38 &&
+				f->datalen == sizeof(enum ast_control_t38)) {
+
+			t38control = *((enum ast_control_t38 *) f->data);
+
+			if (t38control == AST_T38_TERMINATED || t38control == AST_T38_REFUSED) {
+				ast_log(LOG_DEBUG, "T38 down, terminating\n");
+				res = -1;
+				break;
+			}
+		    }
+                    clean_frame(f);
+                }
+                else
+                {
+                    running = DONE;
+                }
+            }
+            else
+            {
+                if ((f = ast_read(active)))
+                {
+                    if (t38_gateway_rx(&t38_state, f->data, f->samples))
+                        break;
+
+                    samples = (f->samples <= MAX_BLOCK_SIZE)  ?  f->samples  :  MAX_BLOCK_SIZE;
+
+                    if ((len = t38_gateway_tx(&t38_state, (int16_t *) &buf[AST_FRIENDLY_OFFSET], samples)))
+                    {
+			outf.frametype = AST_FRAME_VOICE;
+			outf.subclass = AST_FORMAT_SLINEAR;
+			outf.src = "T38Gateway";
+                        outf.datalen = len*sizeof(int16_t);
+                        outf.samples = len;
+                        outf.data = &buf[AST_FRIENDLY_OFFSET];
+                        outf.offset = AST_FRIENDLY_OFFSET;
+			outf.mallocd = 0;
+			outf.offset = 0;
+			
+//			ast_log(LOG_DEBUG, "t38 gateway write to %p\n", channels[1]);
+                        if (ast_write(channels[1], &outf) < 0)
+                        {
+                            ast_log(LOG_WARNING, "Unable to write frame to channel; %s\n", strerror(errno));
+                            break;
+                        }
+                    }
+                    clean_frame(f);
+                }
+                else
+                {
+                    running = DONE;
+                }
+                inactive = (active == channels[0])  ?   channels[1]  :  channels[0];
+            }
+        }
+    }
+
+    if (original_read_fmt != AST_FORMAT_SLINEAR)
+    {
+        if ((res = ast_set_read_format(channels[1], original_read_fmt)))
+            ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", channels[1]->name);
+    }
+    if (original_write_fmt != AST_FORMAT_SLINEAR)
+    {
+        if ((res = ast_set_write_format(channels[1], original_write_fmt)))
+            ast_log(LOG_WARNING, "Unable to restore write format on '%s'\n", channels[1]->name);
+    }
+    return running;
+}
+
+
+static int transmit(fax_session *s)
+{
+	int res = 0;
+	struct ast_channel *active = NULL;
+	struct ast_channel *channels[2];
+	char status[256];
+	struct ast_frame *f;
+	int state = 0, ready = 0;
+	
+	ast_log(LOG_DEBUG, "faxGw - transmit entry. \n");
+	
+	/* Clear all channel variables which to be set by the application.
+	   Pre-set status to error so in case of any problems we can just leave */
+	pbx_builtin_setvar_helper(s->chan, "FAXSTATUS", "FAILED"); 
+	pbx_builtin_setvar_helper(s->chan, "FAXERROR", "Channel problems"); 
+	
+	ast_log(LOG_DEBUG, "FaxGw - transmit - type %s destination %s\n", s->dest_type, s->dest);
+	/* Call to the peer side of the gateway */
+	/* By default try to initiate t38 call */
+	pbx_builtin_setvar_helper(s->peer, "T38CALL", "1"); 
+	
+	res = ast_call(s->peer, s->dest, 0);
+	/* check the results of ast_call */
+	if (res) {
+		ast_log(LOG_WARNING, "Could not answer channel '%s'\n", s->chan->name);
+		ast_log(LOG_DEBUG, "ast call on peer returned %d\n", res);
+		ast_verbose("Couldn't call %s\n", s->chan->name);
+		ast_hangup(s->peer);
+		s->peer = NULL;
+		return res;
+	} else {
+		senddialevent(s->chan, s->peer, s->dest);
+		ast_verbose("Called %s\n", s->dest);
+	}
+
+	if (s->chan->cdr)
+		ast_cdr_setdestchan(s->chan->cdr, s->peer->name);
+	
+	ast_log(LOG_DEBUG, "faxGw - after ast_call.\n");
+	
+	strncpy(status, "CHANUNAVAIL", sizeof(status) - 1); /* assume as default */
+	channels[0] = s->peer;
+	channels[1] = s->chan;
+
+	/* Building up a peer connection while we haven't timed out and we still have no channel up */
+	while (s->timeout  &&  (s->peer->_state != AST_STATE_UP))
+	{
+		/* check the activity on both channels */
+		/* active = pointer to active channel */
+		ast_log(LOG_DEBUG, "faxGw - waiting for activity on channels \n");
+		
+		active = ast_waitfor_n(channels, 2, &s->timeout);
+		if (active)
+		{
+			/* Timed out, so we are done trying */
+			if (s->timeout == 0)
+			{
+				strncpy(status, "NOANSWER", sizeof(status) - 1);
+				ast_log(LOG_DEBUG, "Timeout on peer\n");
+				break;
+			}
+			/* -1 means go forever */
+			if (s->timeout > -1)
+			{
+				/* res holds the number of milliseconds remaining */
+				if (s->timeout < 0)
+				{
+					s->timeout = 0;
+					strncpy(status, "NOANSWER", sizeof(status) - 1);
+				}
+			}
+			/* peer activity => check what is it about */
+			if (active == s->peer)
+			{
+				ast_log(LOG_DEBUG, "faxGw - something happend on peer\n");
+				/* Read the frame f */	
+				f = ast_read(active);
+				if (f == NULL)
+				{
+					ast_log(LOG_NOTICE, "faxGw - peer hanged up\n");
+					/* HANG UP */
+					state = AST_CONTROL_HANGUP;
+					s->chan->hangupcause = s->peer->hangupcause;
+					res = 0;
+					break;
+				}
+				
+				/* the frame is signaling = control frame */
+				if (f->frametype == AST_FRAME_CONTROL)
+				{
+					ast_log(LOG_DEBUG, "faxGw - AST_FRAME_CONTROL\n");
+					if (f->subclass == AST_CONTROL_RINGING)
+					{
+						ast_log(LOG_DEBUG, "faxGw - AST_CONTROL_RINGING\n");
+						/* ringing */
+						 state = f->subclass;
+						 ast_indicate(s->chan, AST_CONTROL_RINGING);
+						 ast_frfree(f);
+						 continue;
+					}
+					else if ((f->subclass == AST_CONTROL_BUSY)  ||  (f->subclass == AST_CONTROL_CONGESTION))
+					{
+						ast_log(LOG_DEBUG, "faxGw - AST_CONTROL_BUSY\n");
+						/* busy */
+						 state = f->subclass;
+						 s->chan->hangupcause = s->peer->hangupcause;
+						 ast_frfree(f);
+						 break;
+					}
+					else if (f->subclass == AST_CONTROL_ANSWER)
+					{
+						ast_log(LOG_DEBUG, "faxGw - AST_CONTROL_ANSWER\n");
+						/* This is what we are hoping for :-) */
+						state = f->subclass;
+						ast_frfree(f);
+						ready = 1;
+						break;
+					}
+					/* else who cares :-) */
+				}
+			}
+			else
+			{
+				ast_log(LOG_DEBUG, "faxGw - something happend on channel\n");
+				/* orig channel reports something */
+				f = ast_read(active);
+				if (f == NULL)
+				{
+					/* initiator hanged */
+					state = AST_CONTROL_HANGUP;
+					ast_log(LOG_DEBUG, "Hangup from remote channel\n");
+					res = 0;
+					break;
+				}
+				if (f->frametype == AST_FRAME_CONTROL)
+				{
+					if (f->subclass == AST_CONTROL_HANGUP)
+					{
+						state = f->subclass;
+						res = 0;
+						ast_frfree(f);
+						break;
+					}
+				}
+			}
+			ast_frfree(f);
+		}
+		else
+		{
+			ast_log(LOG_DEBUG, "Timeout while waiting\n");
+		}
+	}
+	
+	/* SS7 channel doesn't return control packets */
+	if (strncmp(s->peer->tech->type, "SS7", 3) == 0)
+	{
+		ready = 1;
+	}
+	
+		
+	res = 1;
+	int res2 = ready_to_talk(s->chan, s->peer);
+	ast_log(LOG_DEBUG, "faxGw - connections build - ready %d and erady to talk - %d\n", ready, res2);
+	
+	if (ready  &&  res2)
+	{
+
+		ast_log(LOG_DEBUG, "faxGw - ready to do gatewaing \n");
+
+		if (!ast_channel_make_compatible(s->chan, s->peer))
+		{
+			/* pick up originating call */
+			if (s->chan->_state != AST_STATE_UP) {
+				/* Shouldn't need this, but checking to see if channel is already answered
+				 * Theoretically asterisk should already have answered before running the app */
+				res = ast_answer(s->chan); //
+				if (res) {
+					ast_log(LOG_WARNING, "Could not answer channel '%s'\n", s->chan->name);
+					return res;
+				}
+				ast_log(LOG_NOTICE, "faxGw - original call answered \n");
+			}
+
+			s->peer->appl = app_faxgw_name;
+			
+			ast_set_callerid(s->peer, s->chan->cid.cid_name, s->chan->cid.cid_num, s->chan->cid.cid_num);
+			s->chan->hangupcause = AST_CAUSE_NORMAL_CLEARING;
+			
+			res = RUNNING;
+			s->chan_t38state = ast_channel_get_t38_state(s->chan);
+			s->peer_t38state = ast_channel_get_t38_state(s->peer);
+			
+			while ( res == RUNNING ) 
+			{
+				s->chan_t38state = ast_channel_get_t38_state(s->chan);
+				s->peer_t38state = ast_channel_get_t38_state(s->peer);
+
+				if ( res && (s->chan_t38state == s->peer_t38state))
+				{
+					// Same on both sides, so just bridge 
+					ast_log(LOG_NOTICE, "Bridging frames [ %d,%d]\n", s->chan_t38state, s->peer_t38state);
+					res = ast_bridge_frames(s);
+				}
+				
+				if (
+					( res == RUNNING )
+					&& ( ( s->chan_t38state == T38_STATE_UNKNOWN ) || ( s->peer_t38state == T38_STATE_UNKNOWN ) || 
+					     ( s->chan_t38state == T38_STATE_UNAVAILABLE ) || ( s->peer_t38state == T38_STATE_UNAVAILABLE ))
+					&& ( s->chan_t38state != s->peer_t38state ) 
+				)
+				{
+					// Different on each side, so gateway 
+					ast_log(LOG_NOTICE, "Doing T.38 gateway [ %d,%d]\n", s->chan_t38state, s->peer_t38state);
+					res = ast_t38_gateway(s);
+				}
+				// ast_log(LOG_NOTICE," res = %d, RUNNING defined as %d, chan_Status [%d,%d] UNKNOWN set to %d ", res, RUNNING, s->chan_t38state, s->peer_t38state, T38_STATE_UNKNOWN  );
+			}
+		}
+		else
+		{
+			ast_log(LOG_ERROR, "failed to make remote_channel %s/%s Compatible\n", s->dest_type, s->dest);
+		}
+	}
+	else
+	{
+		ast_log(LOG_ERROR, "failed to get remote_channel %s %s\n", s->dest_type, s->dest);
+	}
+	
+	if (state == AST_CONTROL_ANSWER)
+		strncpy(status, "ANSWER", sizeof(status) - 1);
+	if (state == AST_CONTROL_BUSY)
+		strncpy(status, "BUSY", sizeof(status) - 1);
+	if (state == AST_CONTROL_CONGESTION)
+		strncpy(status, "CONGESTION", sizeof(status) - 1);
+	if (state == AST_CONTROL_HANGUP)
+		strncpy(status, "CANCEL", sizeof(status) - 1);
+	pbx_builtin_setvar_helper(s->chan, "DIALSTATUS", status);
+	
+	ast_log(LOG_NOTICE, "FaxGateway exit with %s\n", status);
+	if (s->peer)
+		ast_hangup(s->peer);
+
+	if (res) {
+		ast_log(LOG_WARNING, "Transmission error\n");
+		pbx_builtin_setvar_helper(s->chan, "FAXSTATUS", "FAILED"); 
+		pbx_builtin_setvar_helper(s->chan, "FAXERROR", "Transmission error"); 
+		res = -1;
+	} else if (s->finished < 0) {
+		ast_log(LOG_WARNING, "Transmission failed\n");
+		pbx_builtin_setvar_helper(s->chan, "FAXSTATUS", "FAILED"); 
+		pbx_builtin_setvar_helper(s->chan, "FAXERROR", "Channel problems"); 
+	} else if (s->finished > 0) {
+		ast_log(LOG_DEBUG, "Transmission finished Ok\n");
+		pbx_builtin_setvar_helper(s->chan, "FAXSTATUS", "PASSED"); 
+		pbx_builtin_setvar_helper(s->chan, "FAXERROR", "OK"); 
+	}
+
+	return res;
+}
+
+/* === Application functions === */
+static int faxgw_exec(struct ast_channel *chan, void *data)
+{
+	int res = 0;
+	char *parse;
+	fax_session session;
+	int cause;
+	struct cause_args num = { chan, 0, 0, 0 };
+	
+	session.chan = chan;
+	session.timeout = 6000;
+	
+	AST_DECLARE_APP_ARGS(args,
+		AST_APP_ARG(dest);
+		AST_APP_ARG(timeout);
+	);
+
+	if (chan == NULL) {
+		ast_log(LOG_ERROR, "Fax channel is NULL. Giving up.\n");
+		return -1;
+	}
+
+	parse = ast_strdupa(data);
+	AST_STANDARD_APP_ARGS(args, parse);
+	
+	ast_channel_lock(chan);
+	session.caller_mode = FALSE;
+	ast_channel_unlock(chan);
+	
+	ast_cdr_reset(chan->cdr, NULL);
+	
+	struct ast_channel *tc; /* channel for this destination */
+	/* Get a technology/[device:]number pair */
+	char *number = args.dest;
+	char *tech = strsep(&number, "/");
+	if (!number) {
+		ast_log(LOG_WARNING, "Dial argument takes format (technology/[device:]number1)\n");
+		return -1;
+	}
+	char numsubst[256];
+	session.dest = number;
+	session.dest_type = tech;
+	ast_copy_string(numsubst, number, sizeof(numsubst));
+	/* Request the peer */
+ 	tc = ast_request(tech, session.chan->nativeformats, numsubst, &cause);
+	if (!tc) 
+	{
+		/* If we can't, just go on to the next call */
+		ast_log(LOG_WARNING, "Unable to create channel of type '%s' (cause %d - %s)\n",	tech, cause, ast_cause2str(cause));
+		handle_cause(cause, &num);
+		session.chan->hangupcause = cause;
+			return -1;
+	}
+	session.peer = tc;
+	pbx_builtin_setvar_helper(tc, "DIALEDPEERNUMBER", numsubst);
+
+	/* Setup outgoing SDP to match incoming one */
+	ast_rtp_make_compatible(tc, session.chan, 1);
+		
+	/* Inherit specially named variables from parent channel */
+	ast_channel_inherit_variables(session.chan, tc);
+	tc->appl = "AppDial";
+	tc->data = "(Outgoing Line)";
+	tc->whentohangup = 0;
+
+	S_REPLACE(tc->cid.cid_num, ast_strdup(chan->cid.cid_num));
+	S_REPLACE(tc->cid.cid_name, ast_strdup(chan->cid.cid_name));
+	S_REPLACE(tc->cid.cid_ani, ast_strdup(chan->cid.cid_ani));
+	S_REPLACE(tc->cid.cid_rdnis, ast_strdup(chan->cid.cid_rdnis));
+		
+	/* Copy language from incoming to outgoing */
+	ast_string_field_set(tc, language, chan->language);
+	ast_string_field_set(tc, accountcode, chan->accountcode);
+	tc->cdrflags = chan->cdrflags;
+	if (ast_strlen_zero(tc->musicclass))
+		ast_string_field_set(tc, musicclass, chan->musicclass);
+	/* Pass callingpres, type of number, tns, ADSI CPE, transfer capability */
+	tc->cid.cid_pres = chan->cid.cid_pres;
+	tc->cid.cid_ton = chan->cid.cid_ton;
+	tc->cid.cid_tns = chan->cid.cid_tns;
+	tc->cid.cid_ani2 = chan->cid.cid_ani2;
+	tc->adsicpe = chan->adsicpe;
+	tc->transfercapability = chan->transfercapability;
+
+	/* Inherit context and extension */
+	if (!ast_strlen_zero(chan->macrocontext))
+		ast_copy_string(tc->dialcontext, chan->macrocontext, sizeof(tc->dialcontext));
+	else
+		ast_copy_string(tc->dialcontext, chan->context, sizeof(tc->dialcontext));
+	if (!ast_strlen_zero(chan->macroexten))
+		ast_copy_string(tc->exten, chan->macroexten, sizeof(tc->exten));
+	else
+		ast_copy_string(tc->exten, chan->exten, sizeof(tc->exten));
+
+//        ast_log(LOG_DEBUG, "chan %p peer %p \n", session.chan, session.peer);
+	/* Done parsing */
+	session.finished = 0;
+
+	res = transmit(&session);
+
+	return res;
+}
+
+static int unload_module(void)
+{
+	int res;
+
+	res = ast_unregister_application(app_faxgw_name);	
+
+	return res;
+}
+
+static int load_module(void)
+{
+	int res ;
+
+	res = ast_register_application(app_faxgw_name, faxgw_exec, app_faxgw_synopsis, app_faxgw_desc);
+
+	/* The default SPAN message handler prints to stderr. It is something we do not want */
+	span_set_message_handler(NULL);
+
+	return res;
+}
+
+
+AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Simple FAX Gateway",
+		.load = load_module,
+		.unload = unload_module,
+		);
+
+
diff -ruN asterisk-1.4.20.1_original/build_tools/menuselect-deps.in asterisk-1.4.20.1_updated/build_tools/menuselect-deps.in
--- asterisk-1.4.20.1_original/build_tools/menuselect-deps.in	2008-05-06 00:10:05.000000000 +0200
+++ asterisk-1.4.20.1_updated/build_tools/menuselect-deps.in	2008-06-05 17:06:04.000000000 +0200
@@ -39,3 +39,4 @@
 MISDN=@PBX_MISDN@
 SUPPSERV=@PBX_SUPPSERV@
 GNU_LD=@GNU_LD@
+SPANDSP=@PBX_SPANDSP@
diff -ruN asterisk-1.4.20.1_original/channels/chan_sip.c asterisk-1.4.20.1_updated/channels/chan_sip.c
--- asterisk-1.4.20.1_original/channels/chan_sip.c	2008-05-14 14:51:06.000000000 +0200
+++ asterisk-1.4.20.1_updated/channels/chan_sip.c	2008-06-08 21:42:10.000000000 +0200
@@ -1230,6 +1230,7 @@
 static int sip_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
 static int sip_senddigit_begin(struct ast_channel *ast, char digit);
 static int sip_senddigit_end(struct ast_channel *ast, char digit, unsigned int duration);
+static int sip_queryoption(struct ast_channel *chan, int option, void *data, int *datalen);
 
 /*--- Transmitting responses and requests */
 static int sipsock_read(int *id, int fd, short events, void *ignore);
@@ -1298,7 +1299,7 @@
 static const char* get_sdp_iterate(int* start, struct sip_request *req, const char *name);
 static const char *get_sdp(struct sip_request *req, const char *name);
 static int find_sdp(struct sip_request *req);
-static int process_sdp(struct sip_pvt *p, struct sip_request *req);
+static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action);
 static void add_codec_to_sdp(const struct sip_pvt *p, int codec, int sample_rate,
 			     char **m_buf, size_t *m_size, char **a_buf, size_t *a_size,
 			     int debug, int *min_packet_size);
@@ -1547,6 +1548,7 @@
 static int transmit_reinvite_with_t38_sdp(struct sip_pvt *p);
 static struct ast_udptl *sip_get_udptl_peer(struct ast_channel *chan);
 static int sip_set_udptl_peer(struct ast_channel *chan, struct ast_udptl *udptl);
+static void change_t38_state(struct sip_pvt *p, int state);
 
 /*! \brief Definition of this channel for PBX channel registration */
 static const struct ast_channel_tech sip_tech = {
@@ -1570,6 +1572,7 @@
 	.bridge = ast_rtp_bridge,
 	.send_text = sip_sendtext,
 	.func_channel_read = acf_channel_read,
+	.queryoption = sip_queryoption,
 };
 
 /*! \brief This version of the sip channel tech has no send_digit_begin
@@ -1606,6 +1609,12 @@
 		(head) = (element)->next;	\
 	} while (0)
 
+enum t38_action_flag {
+	SDP_T38_NONE = 0, /*!< Do not modify T38 information at all */
+	SDP_T38_INITIATE, /*!< Remote side has requested T38 with us */
+	SDP_T38_ACCEPT,   /*!< Remote side accepted our T38 request */
+};
+
 /*! \brief Interface structure with callbacks used to connect to RTP module */
 static struct ast_rtp_protocol sip_rtp = {
 	type: "SIP",
@@ -1615,6 +1624,10 @@
 	get_codec: sip_get_codec,
 };
 
+#define sip_pvt_lock(x) ast_mutex_lock(&x->lock)
+#define sip_pvt_trylock(x) ast_mutex_trylock(&x->lock)
+#define sip_pvt_unlock(x) ast_mutex_unlock(&x->lock)
+
 /*! \brief Interface structure with callbacks used to connect to UDPTL module*/
 static struct ast_udptl_protocol sip_udptl = {
 	type: "SIP",
@@ -2308,6 +2321,53 @@
 	return res;
 }
 
+/*! \brief Query an option on a SIP dialog */
+static int sip_queryoption(struct ast_channel *chan, int option, void *data, int *datalen)
+{
+	int res = -1;
+	enum ast_t38_state state = T38_STATE_UNAVAILABLE;
+	struct sip_pvt *p = (struct sip_pvt *) chan->tech_pvt;
+
+	switch (option) {
+	case AST_OPTION_T38_STATE:
+		/* Make sure we got an ast_t38_state enum passed in */
+		if (*datalen != sizeof(enum ast_t38_state)) {
+			ast_log(LOG_ERROR, "Invalid datalen for AST_OPTION_T38_STATE option. Expected %d, got %d\n", (int)sizeof(enum ast_t38_state), *datalen);
+			return -1;
+		}
+
+		sip_pvt_lock(p);
+
+		/* Now if T38 support is enabled we need to look and see what the current state is to get what we want to report back */
+		if (ast_test_flag(&p->t38.t38support, SIP_PAGE2_T38SUPPORT)) {
+			switch (p->t38.state) {
+			case T38_LOCAL_DIRECT:
+			case T38_LOCAL_REINVITE:
+			case T38_PEER_DIRECT:
+			case T38_PEER_REINVITE:
+				state = T38_STATE_NEGOTIATING;
+				break;
+			case T38_ENABLED:
+				state = T38_STATE_NEGOTIATED;
+				break;
+			default:
+				state = T38_STATE_UNKNOWN;
+			}
+		}
+
+		sip_pvt_unlock(p);
+
+		*((enum ast_t38_state *) data) = state;
+		res = 0;
+
+		break;
+	default:
+		break;
+	}
+
+	return res;
+}
+
 /*! \brief Locate closing quote in a string, skipping escaped quotes.
  * optionally with a limit on the search.
  * start must be past the first quote.
@@ -2770,6 +2830,54 @@
 	}
 }
 
+/*! \brief Change the T38 state on a SIP dialog */
+static void change_t38_state(struct sip_pvt *p, int state)
+{
+	int old = p->t38.state;
+	struct ast_channel *chan = p->owner;
+	enum ast_control_t38 message = 0;
+
+	/* Don't bother changing if we are already in the state wanted */
+	if (old == state)
+		return;
+
+	p->t38.state = state;
+	// ast_debug(2, "T38 state changed to %d on channel %s\n", p->t38.state, chan ? chan->name : "<none>");
+
+	/* If no channel was provided we can't send off a control frame */
+	if (!chan)
+		return;
+
+	/* Given the state requested and old state determine what control frame we want to queue up */
+	if (state == T38_ENABLED)
+		message = AST_T38_NEGOTIATED;
+	else if (state == T38_DISABLED && old == T38_ENABLED)
+		message = AST_T38_TERMINATED;
+	else if (state == T38_DISABLED && old == T38_LOCAL_REINVITE)
+		message = AST_T38_REFUSED;
+	
+	ast_log(LOG_DEBUG, "change_t38_state chnaged state to: %d\n", state);
+	
+	/* Woot we got a message, create a control frame and send it on! */
+	if (message)
+		ast_queue_control_data(chan, AST_CONTROL_T38, &message, sizeof(message));
+}
+
+/*! \brief Set the global T38 capabilities on a SIP dialog structure */
+static void set_t38_capabilities(struct sip_pvt *p)
+{
+	p->t38.capability = global_t38_capability;
+	if (p->udptl) {
+		if (ast_udptl_get_error_correction_scheme(p->udptl) == UDPTL_ERROR_CORRECTION_FEC )
+			p->t38.capability |= T38FAX_UDP_EC_FEC;
+		else if (ast_udptl_get_error_correction_scheme(p->udptl) == UDPTL_ERROR_CORRECTION_REDUNDANCY )
+			p->t38.capability |= T38FAX_UDP_EC_REDUNDANCY;
+		else if (ast_udptl_get_error_correction_scheme(p->udptl) == UDPTL_ERROR_CORRECTION_NONE )
+			p->t38.capability |= T38FAX_UDP_EC_NONE;
+		p->t38.capability |= T38FAX_RATE_MANAGEMENT_TRANSFERED_TCF;
+	}
+}
+
 /*! \brief Create address structure from peer reference.
  *  return -1 on error, 0 on success.
  */
@@ -2791,7 +2899,7 @@
 	}
 	dialog->prefs = peer->prefs;
 	if (ast_test_flag(&dialog->flags[1], SIP_PAGE2_T38SUPPORT)) {
-		dialog->t38.capability = global_t38_capability;
+/*		dialog->t38.capability = global_t38_capability;
 		if (dialog->udptl) {
 			if (ast_udptl_get_error_correction_scheme(dialog->udptl) == UDPTL_ERROR_CORRECTION_FEC )
 				dialog->t38.capability |= T38FAX_UDP_EC_FEC;
@@ -2803,6 +2911,9 @@
 			if (option_debug > 1)
 				ast_log(LOG_DEBUG,"Our T38 capability (%d)\n", dialog->t38.capability);
 		}
+*/
+		ast_copy_flags(&dialog->t38.t38support, &peer->flags[1], SIP_PAGE2_T38SUPPORT);
+		set_t38_capabilities(dialog);
 		dialog->t38.jointcapability = dialog->t38.capability;
 	} else if (dialog->udptl) {
 		ast_udptl_destroy(dialog->udptl);
@@ -3684,7 +3795,7 @@
 		if (option_debug)
 			ast_log(LOG_DEBUG, "SIP answering channel: %s\n", ast->name);
 		if (p->t38.state == T38_PEER_DIRECT) {
-			p->t38.state = T38_ENABLED;
+			change_t38_state(p, T38_ENABLED);
 			if (option_debug > 1)
 				ast_log(LOG_DEBUG,"T38State change to %d on channel %s\n", p->t38.state, ast->name);
 			res = transmit_response_with_t38_sdp(p, "200 OK", &p->initreq, XMIT_CRITICAL);
@@ -3970,6 +4081,30 @@
 		} else
 			res = -1;
 		break;
+	case AST_CONTROL_T38:	/* T38 control frame */
+		if (datalen != sizeof(enum ast_control_t38)) {
+			ast_log(LOG_ERROR, "Invalid datalen for AST_CONTROL_T38. Expected %d, got %d\n", (int)sizeof(enum ast_control_t38), (int)datalen);
+		} else {
+			switch (*((enum ast_control_t38 *) data)) {
+			case AST_T38_REQUEST_NEGOTIATE:		/* Request T38 */
+				if (p->t38.state != T38_ENABLED) {
+					change_t38_state(p, T38_LOCAL_REINVITE);
+					//transmit_reinvite_with_sdp(p, TRUE, FALSE);
+					transmit_reinvite_with_sdp(p);
+				}
+				break;
+			case AST_T38_TERMINATED:
+			case AST_T38_REFUSED:
+			case AST_T38_REQUEST_TERMINATE:		/* Shutdown T38 */
+				if (p->t38.state == T38_ENABLED)
+					// transmit_reinvite_with_sdp(p, FALSE, FALSE);
+					transmit_reinvite_with_sdp(p);
+				break;
+			default:
+				break;
+			}
+		}
+		break;
 	case AST_CONTROL_SRCUPDATE:
 		ast_rtp_new_source(p->rtp);
 		break;
@@ -4380,7 +4515,7 @@
 			if (!p->pendinginvite) {
 				if (option_debug > 2)
 					ast_log(LOG_DEBUG, "Sending reinvite on SIP (%s) for T.38 negotiation.\n",ast->name);
-				p->t38.state = T38_LOCAL_REINVITE;
+				change_t38_state(p, T38_LOCAL_REINVITE);
 				transmit_reinvite_with_t38_sdp(p);
 				if (option_debug > 1)
 					ast_log(LOG_DEBUG, "T38 state changed to %d on channel %s\n", p->t38.state, ast->name);
@@ -4546,7 +4681,7 @@
 	    (ast_test_flag(&p->flags[0], SIP_DTMF) == SIP_DTMF_AUTO))
 		p->noncodeccapability |= AST_RTP_DTMF;
 	if (p->udptl) {
-		p->t38.capability = global_t38_capability;
+/*		p->t38.capability = global_t38_capability;
 		if (ast_udptl_get_error_correction_scheme(p->udptl) == UDPTL_ERROR_CORRECTION_REDUNDANCY)
 			p->t38.capability |= T38FAX_UDP_EC_REDUNDANCY;
 		else if (ast_udptl_get_error_correction_scheme(p->udptl) == UDPTL_ERROR_CORRECTION_FEC)
@@ -4554,6 +4689,9 @@
 		else if (ast_udptl_get_error_correction_scheme(p->udptl) == UDPTL_ERROR_CORRECTION_NONE)
 			p->t38.capability |= T38FAX_UDP_EC_NONE;
 		p->t38.capability |= T38FAX_RATE_MANAGEMENT_TRANSFERED_TCF;
+		*/
+		ast_copy_flags(&p->t38.t38support, &p->flags[1], SIP_PAGE2_T38SUPPORT);
+		set_t38_capabilities(p);
 		p->t38.jointcapability = p->t38.capability;
 	}
 	ast_string_field_set(p, context, default_context);
@@ -5014,7 +5152,7 @@
  	Return 0 on success, a negative value on errors.
 	Must be called after find_sdp().
 */
-static int process_sdp(struct sip_pvt *p, struct sip_request *req)
+static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action)
 {
 	const char *m;		/* SDP media offer */
 	const char *c;
@@ -5139,19 +5277,24 @@
 					ast_verbose("Found RTP video format %d\n", codec);
 				ast_rtp_set_m_type(newvideortp, codec);
 			}
-		} else if (p->udptl && ( (sscanf(m, "image %d udptl t38%n", &x, &len) == 1) || 
-		 (sscanf(m, "image %d UDPTL t38%n", &x, &len) == 1) )) {
+		} else if (p->udptl && 
+			( 
+				(sscanf(m, "image %d udptl t38%n", &x, &len) == 1) ||
+				(sscanf(m, "image %d UDPTL t38%n", &x, &len) == 1) ||
+				(sscanf(m, "image %d UDPTL t38", &x) == 1) ||
+				(sscanf(m, "image %d udptl t38", &x) == 1) 
+			)) {
 			if (debug)
 				ast_verbose("Got T.38 offer in SDP in dialog %s\n", p->callid);
 			udptlportno = x;
 			numberofmediastreams++;
 			
 			if (p->owner && p->lastinvite) {
-				p->t38.state = T38_PEER_REINVITE; /* T38 Offered in re-invite from remote party */
+				//p->t38.state = T38_PEER_REINVITE; /* T38 Offered in re-invite from remote party */
 				if (option_debug > 1)
 					ast_log(LOG_DEBUG, "T38 state changed to %d on channel %s\n", p->t38.state, p->owner ? p->owner->name : "<none>" );
 			} else {
-				p->t38.state = T38_PEER_DIRECT; /* T38 Offered directly from peer in first invite */
+				//p->t38.state = T38_PEER_DIRECT; /* T38 Offered directly from peer in first invite */
 				if (option_debug > 1)
 					ast_log(LOG_DEBUG, "T38 state changed to %d on channel %s\n", p->t38.state, p->owner ? p->owner->name : "<none>");
 			}
@@ -5464,8 +5607,19 @@
 				p->t38.capability,
 				p->t38.peercapability,
 				p->t38.jointcapability);
+		/* Remote party offers T38, we need to update state */
+		if (t38action == SDP_T38_ACCEPT) {
+			if (p->t38.state == T38_LOCAL_DIRECT || p->t38.state == T38_LOCAL_REINVITE)
+				change_t38_state(p, T38_ENABLED);
+		} else if (t38action == SDP_T38_INITIATE) {
+			if (p->owner && p->lastinvite) {
+				change_t38_state(p, T38_PEER_REINVITE); /* T38 Offered in re-invite from remote party */
+			} else {
+				change_t38_state(p, T38_PEER_DIRECT); /* T38 Offered directly from peer in first invite */
+			}
+		}
 	} else {
-		p->t38.state = T38_DISABLED;
+		change_t38_state(p, T38_DISABLED);
 		if (option_debug > 2)
 			ast_log(LOG_DEBUG, "T38 state changed to %d on channel %s\n", p->t38.state, p->owner ? p->owner->name : "<none>");
 	}
@@ -12173,7 +12327,7 @@
 		if (find_sdp(req)) {
 			if (p->invitestate != INV_CANCELLED)
 				p->invitestate = INV_EARLY_MEDIA;
-			res = process_sdp(p, req);
+			res = process_sdp(p, req, SDP_T38_NONE);
 			if (!ast_test_flag(req, SIP_PKT_IGNORE) && p->owner) {
 				/* Queue a progress frame only if we have SDP in 180 or 182 */
 				ast_queue_control(p->owner, AST_CONTROL_PROGRESS);
@@ -12189,7 +12343,7 @@
 		if (find_sdp(req)) {
 			if (p->invitestate != INV_CANCELLED)
 				p->invitestate = INV_EARLY_MEDIA;
-			res = process_sdp(p, req);
+			res = process_sdp(p, req, SDP_T38_NONE);
 			if (!ast_test_flag(req, SIP_PKT_IGNORE) && p->owner) {
 				/* Queue a progress frame */
 				ast_queue_control(p->owner, AST_CONTROL_PROGRESS);
@@ -12203,7 +12357,7 @@
 			ast_log(LOG_WARNING, "Unable to cancel SIP destruction.  Expect bad things.\n");
 		p->authtries = 0;
 		if (find_sdp(req)) {
-			if ((res = process_sdp(p, req)) && !ast_test_flag(req, SIP_PKT_IGNORE))
+			if ((res = process_sdp(p, req, SDP_T38_ACCEPT)) && !ast_test_flag(req, SIP_PKT_IGNORE))
 				if (!reinvite)
 					/* This 200 OK's SDP is not acceptable, so we need to ack, then hangup */
 					/* For re-invites, we try to recover */
@@ -12243,12 +12397,12 @@
 			if (bridgepeer->tech == &sip_tech || bridgepeer->tech == &sip_tech_info) {
 				bridgepvt = (struct sip_pvt*)(bridgepeer->tech_pvt);
 				if (bridgepvt->udptl) {
-					if (p->t38.state == T38_PEER_REINVITE) {
+					if (p->t38.state == T38_ENABLED && bridgepvt->t38.state == T38_PEER_REINVITE) {
 						sip_handle_t38_reinvite(bridgepeer, p, 0);
 						ast_rtp_set_rtptimers_onhold(p->rtp);
 						if (p->vrtp)
 							ast_rtp_set_rtptimers_onhold(p->vrtp);	/* Turn off RTP timers while we send fax */
-					} else if (p->t38.state == T38_DISABLED && bridgepeer && (bridgepvt->t38.state == T38_ENABLED)) {
+					} else if (p->t38.state == T38_DISABLED && bridgepvt->t38.state == T38_ENABLED) {
 						ast_log(LOG_WARNING, "RTP re-invite after T38 session not handled yet !\n");
 						/* Insted of this we should somehow re-invite the other side of the bridge to RTP */
 						/* XXXX Should we really destroy this session here, without any response at all??? */
@@ -12258,11 +12412,11 @@
 					if (option_debug > 1)
 						ast_log(LOG_DEBUG, "Strange... The other side of the bridge does not have a udptl struct\n");
 					ast_mutex_lock(&bridgepvt->lock);
-					bridgepvt->t38.state = T38_DISABLED;
+					change_t38_state(bridgepvt, T38_DISABLED);
 					ast_mutex_unlock(&bridgepvt->lock);
 					if (option_debug)
 						ast_log(LOG_DEBUG,"T38 state changed to %d on channel %s\n", bridgepvt->t38.state, bridgepeer->tech->type);
-					p->t38.state = T38_DISABLED;
+					change_t38_state(p, T38_DISABLED);
 					if (option_debug > 1)
 						ast_log(LOG_DEBUG,"T38 state changed to %d on channel %s\n", p->t38.state, p->owner ? p->owner->name : "<none>");
 				}
@@ -12270,17 +12424,17 @@
 				/* Other side is not a SIP channel */
 				if (option_debug > 1)
 					ast_log(LOG_DEBUG, "Strange... The other side of the bridge is not a SIP channel\n");
-				p->t38.state = T38_DISABLED;
+				change_t38_state(p, T38_DISABLED);
 				if (option_debug > 1)
 					ast_log(LOG_DEBUG,"T38 state changed to %d on channel %s\n", p->t38.state, p->owner ? p->owner->name : "<none>");
 			}
 		}
-		if ((p->t38.state == T38_LOCAL_REINVITE) || (p->t38.state == T38_LOCAL_DIRECT)) {
+//		if ((p->t38.state == T38_LOCAL_REINVITE) || (p->t38.state == T38_LOCAL_DIRECT)) {
 			/* If there was T38 reinvite and we are supposed to answer with 200 OK than this should set us to T38 negotiated mode */
-			p->t38.state = T38_ENABLED;
-			if (option_debug)
-				ast_log(LOG_DEBUG, "T38 changed state to %d on channel %s\n", p->t38.state, p->owner ? p->owner->name : "<none>");
-		}
+//			p->t38.state = T38_ENABLED;
+//			if (option_debug)
+//				ast_log(LOG_DEBUG, "T38 changed state to %d on channel %s\n", p->t38.state, p->owner ? p->owner->name : "<none>");
+//		}
 
 		if (!ast_test_flag(req, SIP_PKT_IGNORE) && p->owner) {
 			if (!reinvite) {
@@ -12373,7 +12527,7 @@
 			   terribly wrong since we don't renegotiate codecs,
 			   only IP/port .
 			*/
-			p->t38.state = T38_DISABLED;
+			change_t38_state(p, T38_DISABLED);
 			/* Try to reset RTP timers */
 			ast_rtp_set_rtptimers_onhold(p->rtp);
 			ast_log(LOG_ERROR, "Got error on T.38 re-invite. Bad configuration. Peer needs to have T.38 disabled.\n");
@@ -12389,11 +12543,11 @@
 			/* We tried to send T.38 out in an initial INVITE and the remote side rejected it,
 			   right now we can't fall back to audio so totally abort.
 			*/
-			p->t38.state = T38_DISABLED;
 			/* Try to reset RTP timers */
 			ast_rtp_set_rtptimers_onhold(p->rtp);
 			ast_log(LOG_ERROR, "Got error on T.38 initial invite. Bailing out.\n");
-
+			
+			change_t38_state(p, T38_DISABLED);
 			/* The dialog is now terminated */
 			if (p->owner && !ast_test_flag(req, SIP_PKT_IGNORE))
 				ast_queue_control(p->owner, AST_CONTROL_CONGESTION);
@@ -12988,7 +13142,7 @@
 					if (!ast_test_flag(req, SIP_PKT_IGNORE) && sip_cancel_destroy(p))
 						ast_log(LOG_WARNING, "Unable to cancel SIP destruction.  Expect bad things.\n");
 					if (find_sdp(req))
-						process_sdp(p, req);
+						process_sdp(p, req, SDP_T38_NONE);
 					if (p->owner) {
 						/* Queue a progress frame */
 						ast_queue_control(p->owner, AST_CONTROL_PROGRESS);
@@ -13930,7 +14084,7 @@
 			ast_clear_flag(&p->flags[0], SIP_OUTGOING);	/* This is now an inbound dialog */
 			/* Handle SDP here if we already have an owner */
 			if (find_sdp(req)) {
-				if (process_sdp(p, req)) {
+				if (process_sdp(p, req, SDP_T38_INITIATE)) {
 					transmit_response(p, "488 Not acceptable here", req);
 					if (!p->lastinvite)
 						sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
@@ -13977,7 +14131,7 @@
 
 		/* We have a succesful authentication, process the SDP portion if there is one */
 		if (find_sdp(req)) {
-			if (process_sdp(p, req)) {
+			if (process_sdp(p, req, SDP_T38_INITIATE)) {
 				/* Unacceptable codecs */
 				transmit_response_reliable(p, "488 Not acceptable here", req);
 				p->invitestate = INV_COMPLETED;	
@@ -14178,7 +14332,7 @@
 							} else { /* Something is wrong with peers udptl struct */
 								ast_log(LOG_WARNING, "Strange... The other side of the bridge don't have udptl struct\n");
 								ast_mutex_lock(&bridgepvt->lock);
-								bridgepvt->t38.state = T38_DISABLED;
+								change_t38_state(bridgepvt, T38_DISABLED);
 								ast_mutex_unlock(&bridgepvt->lock);
 								if (option_debug > 1)
 									ast_log(LOG_DEBUG,"T38 state changed to %d on channel %s\n", bridgepvt->t38.state, bridgepeer->name);
@@ -14191,7 +14345,7 @@
 						} else {
 							/* The other side is already setup for T.38 most likely so we need to acknowledge this too */
 							transmit_response_with_t38_sdp(p, "200 OK", req, XMIT_CRITICAL);
-							p->t38.state = T38_ENABLED;
+							change_t38_state(p, T38_ENABLED);
 							if (option_debug)
 								ast_log(LOG_DEBUG, "T38 state changed to %d on channel %s\n", p->t38.state, p->owner ? p->owner->name : "<none>");
 						}
@@ -14201,7 +14355,7 @@
 							transmit_response(p, "488 Not acceptable here", req);
 						else
 							transmit_response_reliable(p, "488 Not acceptable here", req);
-						p->t38.state = T38_DISABLED;
+						change_t38_state(p, T38_DISABLED);
 						if (option_debug > 1)
 							ast_log(LOG_DEBUG,"T38 state changed to %d on channel %s\n", p->t38.state, p->owner ? p->owner->name : "<none>");
 
@@ -14211,7 +14365,7 @@
 				} else {
 					/* we are not bridged in a call */
 					transmit_response_with_t38_sdp(p, "200 OK", req, XMIT_CRITICAL);
-					p->t38.state = T38_ENABLED;
+					change_t38_state(p, T38_ENABLED);
 					if (option_debug)
 						ast_log(LOG_DEBUG,"T38 state changed to %d on channel %s\n", p->t38.state, p->owner ? p->owner->name : "<none>");
 				}
@@ -15446,7 +15600,7 @@
 			p->pendinginvite = 0;
 			__sip_ack(p, seqno, FLAG_RESPONSE, 0);
 			if (find_sdp(req)) {
-				if (process_sdp(p, req))
+				if (process_sdp(p, req, SDP_T38_NONE))
 					return -1;
 			} 
 			check_pendings(p);
@@ -17573,6 +17727,7 @@
 					else
 						ast_log(LOG_DEBUG, "Sending reinvite on SIP '%s' - It's UDPTL soon redirected to us (IP %s)\n", p->callid, ast_inet_ntoa(p->ourip));
 				}
+				change_t38_state(p, T38_LOCAL_REINVITE);
 				transmit_reinvite_with_t38_sdp(p);
 			} else if (!ast_test_flag(&p->flags[0], SIP_PENDINGBYE)) {
 				if (option_debug > 2) {
@@ -17601,8 +17756,8 @@
 			else
 				ast_log(LOG_DEBUG, "Responding 200 OK on SIP '%s' - It's UDPTL soon redirected to us (IP %s)\n", p->callid, ast_inet_ntoa(p->ourip));
 		}
-		pvt->t38.state = T38_ENABLED;
-		p->t38.state = T38_ENABLED;
+		change_t38_state(pvt, T38_ENABLED);
+		change_t38_state(p, T38_ENABLED);
 		if (option_debug > 1) {
 			ast_log(LOG_DEBUG, "T38 changed state to %d on channel %s\n", pvt->t38.state, pvt->owner ? pvt->owner->name : "<none>");
 			ast_log(LOG_DEBUG, "T38 changed state to %d on channel %s\n", p->t38.state, chan ? chan->name : "<none>");
diff -ruN asterisk-1.4.20.1_original/configure asterisk-1.4.20.1_updated/configure
--- asterisk-1.4.20.1_original/configure	2008-05-09 18:34:08.000000000 +0200
+++ asterisk-1.4.20.1_updated/configure	2008-06-05 18:18:11.000000000 +0200
@@ -1,5 +1,5 @@
 #! /bin/sh
-# From configure.ac Revision: 115341 .
+# From configure.ac Revision: 115579 .
 # Guess values for system-dependent variables and create Makefiles.
 # Generated by GNU Autoconf 2.61 for asterisk 1.4.
 #
@@ -877,6 +877,10 @@
 ZAPTEL_INCLUDE
 ZAPTEL_DIR
 PBX_ZAPTEL
+SPANDSP_LIB
+SPANDSP_INCLUDE
+SPANDSP_DIR
+PBX_SPANDSP
 ALLOCA
 LIBOBJS
 POW_LIB
@@ -1551,6 +1555,7 @@
   --with-vpb=PATH         use Voicetronix API files in PATH
   --with-z=PATH           use zlib files in PATH
   --with-zaptel=PATH      use Zaptel files in PATH
+  --with-spandsp=PATH     use spandsp Library files in PATH
 
 Some influential environment variables:
   CC          C compiler command
@@ -7293,6 +7298,9 @@
 
 
 
+
+
+
 ac_ext=c
 ac_cpp='$CPP $CPPFLAGS'
 ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
@@ -7437,8 +7445,8 @@
                 PTHREAD_CFLAGS="$flag"
                 ;;
 
-		pthread-config)
-		# Extract the first word of "pthread-config", so it can be a program name with args.
+                pthread-config)
+                # Extract the first word of "pthread-config", so it can be a program name with args.
 set dummy pthread-config; ac_word=$2
 { echo "$as_me:$LINENO: checking for $ac_word" >&5
 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
@@ -7476,10 +7484,10 @@
 fi
 
 
-		if test x"$acx_pthread_config" = xno; then continue; fi
-		PTHREAD_CFLAGS="`pthread-config --cflags`"
-		PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`"
-		;;
+                if test x"$acx_pthread_config" = xno; then continue; fi
+                PTHREAD_CFLAGS="`pthread-config --cflags`"
+                PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`"
+                ;;
 
                 *)
                 { echo "$as_me:$LINENO: checking for the pthreads library -l$flag" >&5
@@ -7570,11 +7578,11 @@
         CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
 
         # Detect AIX lossage: JOINABLE attribute is called UNDETACHED.
-	{ echo "$as_me:$LINENO: checking for joinable pthread attribute" >&5
+        { echo "$as_me:$LINENO: checking for joinable pthread attribute" >&5
 echo $ECHO_N "checking for joinable pthread attribute... $ECHO_C" >&6; }
-	attr_name=unknown
-	for attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do
-	    cat >conftest.$ac_ext <<_ACEOF
+        attr_name=unknown
+        for attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do
+            cat >conftest.$ac_ext <<_ACEOF
 /* confdefs.h.  */
 _ACEOF
 cat confdefs.h >>conftest.$ac_ext
@@ -7617,7 +7625,7 @@
 
 rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
       conftest$ac_exeext conftest.$ac_ext
-	done
+        done
         { echo "$as_me:$LINENO: result: $attr_name" >&5
 echo "${ECHO_T}$attr_name" >&6; }
         if test "$attr_name" != PTHREAD_CREATE_JOINABLE; then
@@ -7645,7 +7653,7 @@
         CFLAGS="$save_CFLAGS"
 
         # More AIX lossage: must compile with xlc_r or cc_r
-	if test x"$GCC" != xyes; then
+        if test x"$GCC" != xyes; then
           for ac_prog in xlc_r cc_r
 do
   # Extract the first word of "$ac_prog", so it can be a program name with args.
@@ -7691,7 +7699,7 @@
 
         else
           PTHREAD_CC=$CC
-	fi
+        fi
 else
         PTHREAD_CC="$CC"
 fi
@@ -8864,6 +8872,443 @@
 
 
 
+
+SPANDSP_DESCRIP="spandsp Library"
+SPANDSP_OPTION="spandsp"
+
+# Check whether --with-spandsp was given.
+if test "${with_spandsp+set}" = set; then
+  withval=$with_spandsp;
+case ${withval} in
+     n|no)
+     USE_SPANDSP=no
+     ;;
+     y|ye|yes)
+     SPANDSP_MANDATORY="yes"
+     ;;
+     *)
+     SPANDSP_DIR="${withval}"
+     SPANDSP_MANDATORY="yes"
+     ;;
+esac
+
+fi
+
+PBX_SPANDSP=0
+
+
+
+
+
+
+if test "${USE_SPANDSP}" != "no"; then
+   pbxlibdir=""
+   if test "x${SPANDSP_DIR}" != "x"; then
+      if test -d ${SPANDSP_DIR}/lib; then
+      	 pbxlibdir="-L${SPANDSP_DIR}/lib"
+      else
+      	 pbxlibdir="-L${SPANDSP_DIR}"
+      fi
+   fi
+   { echo "$as_me:$LINENO: checking for fax_init in -lspandsp" >&5
+echo $ECHO_N "checking for fax_init in -lspandsp... $ECHO_C" >&6; }
+if test "${ac_cv_lib_spandsp_fax_init+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lspandsp ${pbxlibdir} -ltiff $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char fax_init ();
+int
+main ()
+{
+return fax_init ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+	 test -z "$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  ac_cv_lib_spandsp_fax_init=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	ac_cv_lib_spandsp_fax_init=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_lib_spandsp_fax_init" >&5
+echo "${ECHO_T}$ac_cv_lib_spandsp_fax_init" >&6; }
+if test $ac_cv_lib_spandsp_fax_init = yes; then
+  AST_SPANDSP_FOUND=yes
+else
+  AST_SPANDSP_FOUND=no
+fi
+
+
+   if test "${AST_SPANDSP_FOUND}" = "yes"; then
+      SPANDSP_LIB="-lspandsp -ltiff"
+      SPANDSP_HEADER_FOUND="1"
+      if test "x${SPANDSP_DIR}" != "x"; then
+         SPANDSP_LIB="${pbxlibdir} ${SPANDSP_LIB}"
+	 SPANDSP_INCLUDE="-I${SPANDSP_DIR}/include"
+	 saved_cppflags="${CPPFLAGS}"
+	 CPPFLAGS="${CPPFLAGS} -I${SPANDSP_DIR}/include"
+	 if test "xspandsp.h" != "x" ; then
+	    as_ac_Header=`echo "ac_cv_header_${SPANDSP_DIR}/include/spandsp.h" | $as_tr_sh`
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  { echo "$as_me:$LINENO: checking for ${SPANDSP_DIR}/include/spandsp.h" >&5
+echo $ECHO_N "checking for ${SPANDSP_DIR}/include/spandsp.h... $ECHO_C" >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+ac_res=`eval echo '${'$as_ac_Header'}'`
+	       { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+else
+  # Is the header compilable?
+{ echo "$as_me:$LINENO: checking ${SPANDSP_DIR}/include/spandsp.h usability" >&5
+echo $ECHO_N "checking ${SPANDSP_DIR}/include/spandsp.h usability... $ECHO_C" >&6; }
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+#include <${SPANDSP_DIR}/include/spandsp.h>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+	 test -z "$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_header_compiler=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	ac_header_compiler=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+{ echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6; }
+
+# Is the header present?
+{ echo "$as_me:$LINENO: checking ${SPANDSP_DIR}/include/spandsp.h presence" >&5
+echo $ECHO_N "checking ${SPANDSP_DIR}/include/spandsp.h presence... $ECHO_C" >&6; }
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <${SPANDSP_DIR}/include/spandsp.h>
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null && {
+	 test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       }; then
+  ac_header_preproc=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  ac_header_preproc=no
+fi
+
+rm -f conftest.err conftest.$ac_ext
+{ echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6; }
+
+# So?  What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+  yes:no: )
+    { echo "$as_me:$LINENO: WARNING: ${SPANDSP_DIR}/include/spandsp.h: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: ${SPANDSP_DIR}/include/spandsp.h: accepted by the compiler, rejected by the preprocessor!" >&2;}
+    { echo "$as_me:$LINENO: WARNING: ${SPANDSP_DIR}/include/spandsp.h: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: ${SPANDSP_DIR}/include/spandsp.h: proceeding with the compiler's result" >&2;}
+    ac_header_preproc=yes
+    ;;
+  no:yes:* )
+    { echo "$as_me:$LINENO: WARNING: ${SPANDSP_DIR}/include/spandsp.h: present but cannot be compiled" >&5
+echo "$as_me: WARNING: ${SPANDSP_DIR}/include/spandsp.h: present but cannot be compiled" >&2;}
+    { echo "$as_me:$LINENO: WARNING: ${SPANDSP_DIR}/include/spandsp.h:     check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: ${SPANDSP_DIR}/include/spandsp.h:     check for missing prerequisite headers?" >&2;}
+    { echo "$as_me:$LINENO: WARNING: ${SPANDSP_DIR}/include/spandsp.h: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: ${SPANDSP_DIR}/include/spandsp.h: see the Autoconf documentation" >&2;}
+    { echo "$as_me:$LINENO: WARNING: ${SPANDSP_DIR}/include/spandsp.h:     section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: ${SPANDSP_DIR}/include/spandsp.h:     section \"Present But Cannot Be Compiled\"" >&2;}
+    { echo "$as_me:$LINENO: WARNING: ${SPANDSP_DIR}/include/spandsp.h: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: ${SPANDSP_DIR}/include/spandsp.h: proceeding with the preprocessor's result" >&2;}
+    { echo "$as_me:$LINENO: WARNING: ${SPANDSP_DIR}/include/spandsp.h: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: ${SPANDSP_DIR}/include/spandsp.h: in the future, the compiler will take precedence" >&2;}
+    ( cat <<\_ASBOX
+## ------------------------------- ##
+## Report this to www.asterisk.org ##
+## ------------------------------- ##
+_ASBOX
+     ) | sed "s/^/$as_me: WARNING:     /" >&2
+    ;;
+esac
+{ echo "$as_me:$LINENO: checking for ${SPANDSP_DIR}/include/spandsp.h" >&5
+echo $ECHO_N "checking for ${SPANDSP_DIR}/include/spandsp.h... $ECHO_C" >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  eval "$as_ac_Header=\$ac_header_preproc"
+fi
+ac_res=`eval echo '${'$as_ac_Header'}'`
+	       { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+  SPANDSP_HEADER_FOUND=1
+else
+  SPANDSP_HEADER_FOUND=0
+fi
+
+
+	 fi
+	 CPPFLAGS="${saved_cppflags}"
+      else
+	 if test "xspandsp.h" != "x" ; then
+            if test "${ac_cv_header_spandsp_h+set}" = set; then
+  { echo "$as_me:$LINENO: checking for spandsp.h" >&5
+echo $ECHO_N "checking for spandsp.h... $ECHO_C" >&6; }
+if test "${ac_cv_header_spandsp_h+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_header_spandsp_h" >&5
+echo "${ECHO_T}$ac_cv_header_spandsp_h" >&6; }
+else
+  # Is the header compilable?
+{ echo "$as_me:$LINENO: checking spandsp.h usability" >&5
+echo $ECHO_N "checking spandsp.h usability... $ECHO_C" >&6; }
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+#include <spandsp.h>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+	 test -z "$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_header_compiler=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	ac_header_compiler=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+{ echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6; }
+
+# Is the header present?
+{ echo "$as_me:$LINENO: checking spandsp.h presence" >&5
+echo $ECHO_N "checking spandsp.h presence... $ECHO_C" >&6; }
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <spandsp.h>
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null && {
+	 test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       }; then
+  ac_header_preproc=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  ac_header_preproc=no
+fi
+
+rm -f conftest.err conftest.$ac_ext
+{ echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6; }
+
+# So?  What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+  yes:no: )
+    { echo "$as_me:$LINENO: WARNING: spandsp.h: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: spandsp.h: accepted by the compiler, rejected by the preprocessor!" >&2;}
+    { echo "$as_me:$LINENO: WARNING: spandsp.h: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: spandsp.h: proceeding with the compiler's result" >&2;}
+    ac_header_preproc=yes
+    ;;
+  no:yes:* )
+    { echo "$as_me:$LINENO: WARNING: spandsp.h: present but cannot be compiled" >&5
+echo "$as_me: WARNING: spandsp.h: present but cannot be compiled" >&2;}
+    { echo "$as_me:$LINENO: WARNING: spandsp.h:     check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: spandsp.h:     check for missing prerequisite headers?" >&2;}
+    { echo "$as_me:$LINENO: WARNING: spandsp.h: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: spandsp.h: see the Autoconf documentation" >&2;}
+    { echo "$as_me:$LINENO: WARNING: spandsp.h:     section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: spandsp.h:     section \"Present But Cannot Be Compiled\"" >&2;}
+    { echo "$as_me:$LINENO: WARNING: spandsp.h: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: spandsp.h: proceeding with the preprocessor's result" >&2;}
+    { echo "$as_me:$LINENO: WARNING: spandsp.h: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: spandsp.h: in the future, the compiler will take precedence" >&2;}
+    ( cat <<\_ASBOX
+## ------------------------------- ##
+## Report this to www.asterisk.org ##
+## ------------------------------- ##
+_ASBOX
+     ) | sed "s/^/$as_me: WARNING:     /" >&2
+    ;;
+esac
+{ echo "$as_me:$LINENO: checking for spandsp.h" >&5
+echo $ECHO_N "checking for spandsp.h... $ECHO_C" >&6; }
+if test "${ac_cv_header_spandsp_h+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_cv_header_spandsp_h=$ac_header_preproc
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_header_spandsp_h" >&5
+echo "${ECHO_T}$ac_cv_header_spandsp_h" >&6; }
+
+fi
+if test $ac_cv_header_spandsp_h = yes; then
+  SPANDSP_HEADER_FOUND=1
+else
+  SPANDSP_HEADER_FOUND=0
+fi
+
+
+	 fi
+      fi
+      if test "x${SPANDSP_HEADER_FOUND}" = "x0" ; then
+         if test -n "${SPANDSP_MANDATORY}" ;
+         then
+            { echo "$as_me:$LINENO: ***" >&5
+echo "$as_me: ***" >&6;}
+            { echo "$as_me:$LINENO: *** It appears that you do not have the spandsp development package installed." >&5
+echo "$as_me: *** It appears that you do not have the spandsp development package installed." >&6;}
+            { echo "$as_me:$LINENO: *** Please install it to include ${SPANDSP_DESCRIP} support, or re-run configure" >&5
+echo "$as_me: *** Please install it to include ${SPANDSP_DESCRIP} support, or re-run configure" >&6;}
+            { echo "$as_me:$LINENO: *** without explicitly specifying --with-${SPANDSP_OPTION}" >&5
+echo "$as_me: *** without explicitly specifying --with-${SPANDSP_OPTION}" >&6;}
+            exit 1
+         fi
+         SPANDSP_LIB=""
+         SPANDSP_INCLUDE=""
+         PBX_SPANDSP=0
+      else
+         PBX_SPANDSP=1
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_SPANDSP 1
+_ACEOF
+
+      fi
+   elif test -n "${SPANDSP_MANDATORY}";
+   then
+      { echo "$as_me:$LINENO: ***" >&5
+echo "$as_me: ***" >&6;}
+      { echo "$as_me:$LINENO: *** The ${SPANDSP_DESCRIP} installation on this system appears to be broken." >&5
+echo "$as_me: *** The ${SPANDSP_DESCRIP} installation on this system appears to be broken." >&6;}
+      { echo "$as_me:$LINENO: *** Either correct the installation, or run configure" >&5
+echo "$as_me: *** Either correct the installation, or run configure" >&6;}
+      { echo "$as_me:$LINENO: *** without explicitly specifying --with-${SPANDSP_OPTION}" >&5
+echo "$as_me: *** without explicitly specifying --with-${SPANDSP_OPTION}" >&6;}
+      exit 1
+   fi
+fi
+
+
 # check for basic system features and functionality before
 # checking for package libraries
 
@@ -36494,6 +36939,10 @@
 ZAPTEL_INCLUDE!$ZAPTEL_INCLUDE$ac_delim
 ZAPTEL_DIR!$ZAPTEL_DIR$ac_delim
 PBX_ZAPTEL!$PBX_ZAPTEL$ac_delim
+SPANDSP_LIB!$SPANDSP_LIB$ac_delim
+SPANDSP_INCLUDE!$SPANDSP_INCLUDE$ac_delim
+SPANDSP_DIR!$SPANDSP_DIR$ac_delim
+PBX_SPANDSP!$PBX_SPANDSP$ac_delim
 ALLOCA!$ALLOCA$ac_delim
 LIBOBJS!$LIBOBJS$ac_delim
 POW_LIB!$POW_LIB$ac_delim
@@ -36523,10 +36972,6 @@
 PBX_H323!$PBX_H323$ac_delim
 PBX_IXJUSER!$PBX_IXJUSER$ac_delim
 GTKCONFIG!$GTKCONFIG$ac_delim
-PBX_GTK!$PBX_GTK$ac_delim
-GTK_INCLUDE!$GTK_INCLUDE$ac_delim
-GTK_LIB!$GTK_LIB$ac_delim
-PKGCONFIG!$PKGCONFIG$ac_delim
 _ACEOF
 
   if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 97; then
@@ -36568,6 +37013,10 @@
 ac_delim='%!_!# '
 for ac_last_try in false false false false false :; do
   cat >conf$$subs.sed <<_ACEOF
+PBX_GTK!$PBX_GTK$ac_delim
+GTK_INCLUDE!$GTK_INCLUDE$ac_delim
+GTK_LIB!$GTK_LIB$ac_delim
+PKGCONFIG!$PKGCONFIG$ac_delim
 PBX_GTK2!$PBX_GTK2$ac_delim
 GTK2_INCLUDE!$GTK2_INCLUDE$ac_delim
 GTK2_LIB!$GTK2_LIB$ac_delim
@@ -36575,7 +37024,7 @@
 LTLIBOBJS!$LTLIBOBJS$ac_delim
 _ACEOF
 
-  if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 5; then
+  if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 9; then
     break
   elif $ac_last_try; then
     { { echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5
diff -ruN asterisk-1.4.20.1_original/configure.ac asterisk-1.4.20.1_updated/configure.ac
--- asterisk-1.4.20.1_original/configure.ac	2008-05-09 18:34:08.000000000 +0200
+++ asterisk-1.4.20.1_updated/configure.ac	2008-06-05 18:18:00.000000000 +0200
@@ -156,6 +156,203 @@
 	AC_DEFINE([HAVE_SOXMIX], 1, [Define to 1 if your system has soxmix application.])
 fi
 
+
+AC_DEFUN([ACX_PTHREAD], [
+AC_REQUIRE([AC_CANONICAL_HOST])
+AC_LANG_SAVE
+AC_LANG_C
+acx_pthread_ok=no
+
+# We used to check for pthread.h first, but this fails if pthread.h
+# requires special compiler flags (e.g. on True64 or Sequent).
+# It gets checked for in the link test anyway.
+
+# First of all, check if the user has set any of the PTHREAD_LIBS,
+# etcetera environment variables, and if threads linking works using
+# them:
+if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then
+        save_CFLAGS="$CFLAGS"
+        CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+        save_LIBS="$LIBS"
+        LIBS="$PTHREAD_LIBS $LIBS"
+        AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS])
+        AC_TRY_LINK_FUNC(pthread_join, acx_pthread_ok=yes)
+        AC_MSG_RESULT($acx_pthread_ok)
+        if test x"$acx_pthread_ok" = xno; then
+                PTHREAD_LIBS=""
+                PTHREAD_CFLAGS=""
+        fi
+        LIBS="$save_LIBS"
+        CFLAGS="$save_CFLAGS"
+fi
+
+# We must check for the threads library under a number of different
+# names; the ordering is very important because some systems
+# (e.g. DEC) have both -lpthread and -lpthreads, where one of the
+# libraries is broken (non-POSIX).
+
+# Create a list of thread flags to try.  Items starting with a "-" are
+# C compiler flags, and other items are library names, except for "none"
+# which indicates that we try without any flags at all, and "pthread-config"
+# which is a program returning the flags for the Pth emulation library.
+
+acx_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config"
+
+# The ordering *is* (sometimes) important.  Some notes on the
+# individual items follow:
+
+# pthreads: AIX (must check this before -lpthread)
+# none: in case threads are in libc; should be tried before -Kthread and
+#       other compiler flags to prevent continual compiler warnings
+# -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h)
+# -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able)
+# lthread: LinuxThreads port on FreeBSD (also preferred to -pthread)
+# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads)
+# -pthreads: Solaris/gcc
+# -mthreads: Mingw32/gcc, Lynx/gcc
+# -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it
+#      doesn't hurt to check since this sometimes defines pthreads too;
+#      also defines -D_REENTRANT)
+#      ... -mt is also the pthreads flag for HP/aCC
+# pthread: Linux, etcetera
+# --thread-safe: KAI C++
+# pthread-config: use pthread-config program (for GNU Pth library)
+
+case "${host_cpu}-${host_os}" in
+        *solaris*)
+
+        # On Solaris (at least, for some versions), libc contains stubbed
+        # (non-functional) versions of the pthreads routines, so link-based
+        # tests will erroneously succeed.  (We need to link with -pthreads/-mt/
+        # -lpthread.)  (The stubs are missing pthread_cleanup_push, or rather
+        # a function called by this macro, so we could check for that, but
+        # who knows whether they'll stub that too in a future libc.)  So,
+        # we'll just look for -pthreads and -lpthread first:
+
+        acx_pthread_flags="-pthreads pthread -mt -pthread $acx_pthread_flags"
+        ;;
+esac
+
+if test x"$acx_pthread_ok" = xno; then
+for flag in $acx_pthread_flags; do
+
+        case $flag in
+                none)
+                AC_MSG_CHECKING([whether pthreads work without any flags])
+                ;;
+
+                -*)
+                AC_MSG_CHECKING([whether pthreads work with $flag])
+                PTHREAD_CFLAGS="$flag"
+                ;;
+
+                pthread-config)
+                AC_CHECK_PROG(acx_pthread_config, pthread-config, yes, no)
+                if test x"$acx_pthread_config" = xno; then continue; fi
+                PTHREAD_CFLAGS="`pthread-config --cflags`"
+                PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`"
+                ;;
+
+                *)
+                AC_MSG_CHECKING([for the pthreads library -l$flag])
+                PTHREAD_LIBS="-l$flag"
+                ;;
+        esac
+
+        save_LIBS="$LIBS"
+        save_CFLAGS="$CFLAGS"
+        LIBS="$PTHREAD_LIBS $LIBS"
+        CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+
+        # Check for various functions.  We must include pthread.h,
+        # since some functions may be macros.  (On the Sequent, we
+        # need a special flag -Kthread to make this header compile.)
+        # We check for pthread_join because it is in -lpthread on IRIX
+        # while pthread_create is in libc.  We check for pthread_attr_init
+        # due to DEC craziness with -lpthreads.  We check for
+        # pthread_cleanup_push because it is one of the few pthread
+        # functions on Solaris that doesn't have a non-functional libc stub.
+        # We try pthread_create on general principles.
+        AC_TRY_LINK([#include <pthread.h>],
+                    [pthread_t th; pthread_join(th, 0);
+                     pthread_attr_init(0); pthread_cleanup_push(0, 0);
+                     pthread_create(0,0,0,0); pthread_cleanup_pop(0); ],
+                    [acx_pthread_ok=yes])
+
+        LIBS="$save_LIBS"
+        CFLAGS="$save_CFLAGS"
+
+        AC_MSG_RESULT($acx_pthread_ok)
+        if test "x$acx_pthread_ok" = xyes; then
+                break;
+        fi
+
+        PTHREAD_LIBS=""
+        PTHREAD_CFLAGS=""
+done
+fi
+
+# Various other checks:
+if test "x$acx_pthread_ok" = xyes; then
+        save_LIBS="$LIBS"
+        LIBS="$PTHREAD_LIBS $LIBS"
+        save_CFLAGS="$CFLAGS"
+        CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+
+        # Detect AIX lossage: JOINABLE attribute is called UNDETACHED.
+        AC_MSG_CHECKING([for joinable pthread attribute])
+        attr_name=unknown
+        for attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do
+            AC_TRY_LINK([#include <pthread.h>], [int attr=$attr; return attr;],
+                        [attr_name=$attr; break])
+        done
+        AC_MSG_RESULT($attr_name)
+        if test "$attr_name" != PTHREAD_CREATE_JOINABLE; then
+            AC_DEFINE_UNQUOTED(PTHREAD_CREATE_JOINABLE, $attr_name,
+                               [Define to necessary symbol if this constant
+                                uses a non-standard name on your system.])
+        fi
+
+        AC_MSG_CHECKING([if more special flags are required for pthreads])
+        flag=no
+        case "${host_cpu}-${host_os}" in
+            *-aix* | *-freebsd* | *-darwin*) flag="-D_THREAD_SAFE";;
+            *solaris* | *-osf* | *-hpux*) flag="-D_REENTRANT";;
+        esac
+        AC_MSG_RESULT(${flag})
+        if test "x$flag" != xno; then
+            PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS"
+        fi
+
+        LIBS="$save_LIBS"
+        CFLAGS="$save_CFLAGS"
+
+        # More AIX lossage: must compile with xlc_r or cc_r
+        if test x"$GCC" != xyes; then
+          AC_CHECK_PROGS(PTHREAD_CC, xlc_r cc_r, ${CC})
+        else
+          PTHREAD_CC=$CC
+        fi
+else
+        PTHREAD_CC="$CC"
+fi
+
+AC_SUBST(PTHREAD_LIBS)
+AC_SUBST(PTHREAD_CFLAGS)
+AC_SUBST(PTHREAD_CC)
+
+# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND:
+if test x"$acx_pthread_ok" = xyes; then
+        ifelse([$1],,AC_DEFINE(HAVE_PTHREAD,1,[Define if you have POSIX threads libraries and header files.]),[$1])
+        :
+else
+        acx_pthread_ok=no
+        $2
+fi
+AC_LANG_RESTORE
+])dnl ACX_PTHREAD
+
+
 ACX_PTHREAD
 
 AC_LANG(C)
@@ -213,6 +410,9 @@
 AST_EXT_LIB_SETUP([ZLIB], [zlib], [z])
 AST_EXT_LIB_SETUP([ZAPTEL], [Zaptel], [zaptel])
 
+AST_EXT_LIB_SETUP([SPANDSP], [spandsp Library], [spandsp])
+AST_EXT_LIB_CHECK([SPANDSP], [spandsp], [fax_init], [spandsp.h], [-ltiff])
+
 # check for basic system features and functionality before
 # checking for package libraries
 
diff -ruN asterisk-1.4.20.1_original/include/asterisk/channel.h asterisk-1.4.20.1_updated/include/asterisk/channel.h
--- asterisk-1.4.20.1_original/include/asterisk/channel.h	2008-03-13 22:38:16.000000000 +0100
+++ asterisk-1.4.20.1_updated/include/asterisk/channel.h	2008-06-05 22:06:06.000000000 +0200
@@ -336,6 +336,17 @@
 	AST_STATE_MUTE = (1 << 16),
 };
 
+/*!
+ * \brief Possible T38 states on channels
+ */
+enum ast_t38_state {
+	T38_STATE_UNAVAILABLE,	/*!< T38 is unavailable on this channel or disabled by configuration */
+	T38_STATE_UNKNOWN,	/*!< The channel supports T38 but the current status is unknown */
+	T38_STATE_NEGOTIATING,	/*!< T38 is being negotiated */
+	T38_STATE_REJECTED,	/*!< Remote side has rejected our offer */
+	T38_STATE_NEGOTIATED,	/*!< T38 established */
+};
+
 /*! \brief Main Channel structure associated with a channel. 
  * This is the side of it mostly used by the pbx and call management.
  *
@@ -1090,7 +1101,7 @@
  * Query the value of an option, optionally blocking until a reply is received
  * Works similarly to setoption except only reads the options.
  */
-struct ast_frame *ast_channel_queryoption(struct ast_channel *channel, int option, void *data, int *datalen, int block);
+int ast_channel_queryoption(struct ast_channel *channel, int option, void *data, int *datalen, int block);
 
 /*! Checks for HTML support on a channel */
 /*! Returns 0 if channel does not support HTML or non-zero if it does */
@@ -1340,6 +1351,18 @@
 #endif
 }
 
+/*! \brief Retrieves the current T38 state of a channel */
+static inline enum ast_t38_state ast_channel_get_t38_state(struct ast_channel *chan)
+{
+	enum ast_t38_state state = T38_STATE_UNAVAILABLE;
+	int datalen = sizeof(state);
+
+	ast_channel_queryoption(chan, AST_OPTION_T38_STATE, &state, &datalen, 0);
+
+	return state;
+}
+
+
 #ifdef DO_CRASH
 #define CRASH do { fprintf(stderr, "!! Forcing immediate crash a-la abort !!\n"); *((int *)0) = 0; } while(0)
 #else
diff -ruN asterisk-1.4.20.1_original/include/asterisk/dsp.h asterisk-1.4.20.1_updated/include/asterisk/dsp.h
--- asterisk-1.4.20.1_original/include/asterisk/dsp.h	2008-04-17 18:50:46.000000000 +0200
+++ asterisk-1.4.20.1_updated/include/asterisk/dsp.h	2008-06-05 21:04:23.000000000 +0200
@@ -28,20 +28,24 @@
 #define DSP_FEATURE_DTMF_DETECT		(1 << 3)
 #define DSP_FEATURE_FAX_DETECT		(1 << 4)
 
-#define	DSP_DIGITMODE_DTMF			0				/* Detect DTMF digits */
-#define DSP_DIGITMODE_MF			1				/* Detect MF digits */
+#define	DSP_DIGITMODE_DTMF			0				/*!< Detect DTMF digits */
+#define DSP_DIGITMODE_MF			1				/*!< Detect MF digits */
 
-#define DSP_DIGITMODE_NOQUELCH		(1 << 8)		/* Do not quelch DTMF from in-band */
-#define DSP_DIGITMODE_MUTECONF		(1 << 9)		/* Mute conference */
-#define DSP_DIGITMODE_MUTEMAX		(1 << 10)		/* Delay audio by a frame to try to extra quelch */
-#define DSP_DIGITMODE_RELAXDTMF		(1 << 11)		/* "Radio" mode (relaxed DTMF) */
-
-#define DSP_PROGRESS_TALK		(1 << 16)		/* Enable talk detection */
-#define DSP_PROGRESS_RINGING		(1 << 17)		/* Enable calling tone detection */
-#define DSP_PROGRESS_BUSY		(1 << 18)		/* Enable busy tone detection */
-#define DSP_PROGRESS_CONGESTION		(1 << 19)		/* Enable congestion tone detection */
+#define DSP_DIGITMODE_NOQUELCH		(1 << 8)		/*!< Do not quelch DTMF from in-band */
+#define DSP_DIGITMODE_MUTECONF		(1 << 9)		/*!< Mute conference */
+#define DSP_DIGITMODE_MUTEMAX		(1 << 10)		/*!< Delay audio by a frame to try to extra quelch */
+#define DSP_DIGITMODE_RELAXDTMF		(1 << 11)		/*!< "Radio" mode (relaxed DTMF) */
+
+#define DSP_PROGRESS_TALK		(1 << 16)		/*!< Enable talk detection */
+#define DSP_PROGRESS_RINGING		(1 << 17)		/*!< Enable calling tone detection */
+#define DSP_PROGRESS_BUSY		(1 << 18)		/*!< Enable busy tone detection */
+#define DSP_PROGRESS_CONGESTION		(1 << 19)		/*!< Enable congestion tone detection */
 #define DSP_FEATURE_CALL_PROGRESS	(DSP_PROGRESS_TALK | DSP_PROGRESS_RINGING | DSP_PROGRESS_BUSY | DSP_PROGRESS_CONGESTION)
 
+#define DSP_FAXMODE_DETECT_CNG	(1 << 0)
+#define DSP_FAXMODE_DETECT_CED	(1 << 1)
+#define DSP_FAXMODE_DETECT_ALL	(DSP_FAXMODE_DETECT_CNG | DSP_FAXMODE_DETECT_CED)
+
 #define DSP_TONE_STATE_SILENCE  0
 #define DSP_TONE_STATE_RINGING  1 
 #define DSP_TONE_STATE_DIALTONE 2
@@ -102,6 +106,9 @@
 /*! \brief Set digit mode */
 int ast_dsp_digitmode(struct ast_dsp *dsp, int digitmode);
 
+/*! \brief Set fax mode */
+int ast_dsp_set_faxmode(struct ast_dsp *dsp, int faxmode);
+
 /*! \brief Get tstate (Tone State) */
 int ast_dsp_get_tstate(struct ast_dsp *dsp);
 
@@ -120,5 +127,4 @@
  * \return nothing
  */
 void ast_dsp_frame_freed(struct ast_frame *fr);
-
 #endif /* _ASTERISK_DSP_H */
diff -ruN asterisk-1.4.20.1_original/include/asterisk/event.h asterisk-1.4.20.1_updated/include/asterisk/event.h
--- asterisk-1.4.20.1_original/include/asterisk/event.h	1970-01-01 01:00:00.000000000 +0100
+++ asterisk-1.4.20.1_updated/include/asterisk/event.h	2008-06-08 21:18:54.000000000 +0200
@@ -0,0 +1,485 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2007, Digium, Inc.
+ *
+ * Russell Bryant <russell@digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*!
+ * \file
+ * \author Russell Bryant <russell@digium.com>
+ * \ref AstGenericEvents
+ */
+
+/*!
+ * \page AstGenericEvents Generic event system
+ *
+ * The purpose of this API is to provide a generic way to share events between
+ * Asterisk modules.  Code can generate events, and other code can subscribe to
+ * them.
+ *
+ * Events have an associated event type, as well as information elements.  The
+ * information elements are the meta data that go along with each event.  For
+ * example, in the case of message waiting indication, the event type is MWI,
+ * and each MWI event contains at least three information elements: the
+ * mailbox, the number of new messages, and the number of old messages.
+ *
+ * Subscriptions to events consist of an event type and information elements,
+ * as well.  Subscriptions can be to all events, or a certain subset of events.
+ * If an event type is provided, only events of that type will be sent to this
+ * subscriber.  Furthermore, if information elements are supplied with the
+ * subscription, only events that contain the specified information elements
+ * with specified values will be sent to the subscriber.  For example, when a
+ * SIP phone subscribes to MWI for mailbox 1234, then chan_sip can subscribe
+ * to internal Asterisk MWI events with the MAILBOX information element with
+ * a value of "1234".
+ *
+ * Another key feature of this event system is the ability to cache events.
+ * It is useful for some types of events to be able to remember the last known
+ * value.  These are usually events that indicate some kind of state change.
+ * In the example of MWI, app_voicemail can instruct the event core to cache
+ * these events based on the mailbox.  So, the last known MWI state of each
+ * mailbox will be cached, and other modules can retrieve this information
+ * on demand without having to poll the mailbox directly.
+ */
+
+#ifndef AST_EVENT_H
+#define AST_EVENT_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+#include "asterisk/event_defs.h"
+
+/*! 
+ * \brief Subscriber event callback type
+ *
+ * \param event the event being passed to the subscriber
+ * \param userdata the data provider in the call to ast_event_subscribe()
+ *
+ * \return The event callbacks do not return anything.
+ */
+typedef void (*ast_event_cb_t)(const struct ast_event *event, void *userdata);
+
+/*! 
+ * \brief Subscribe to events
+ *
+ * \param event_type The type of events to subscribe to
+ * \param cb The function to be called with events
+ * \param userdata data to be passed to the event callback
+ *
+ * The rest of the arguments to this function specify additional parameters for
+ * the subscription to filter which events are passed to this subscriber.  The
+ * arguments must be in sets of:
+ * \code
+ *    <enum ast_event_ie_type>, [enum ast_event_ie_pltype, [payload] ]
+ * \endcode
+ * and must end with AST_EVENT_IE_END.
+ *
+ * If the ie_type specified is *not* AST_EVENT_IE_END, then it must be followed
+ * by a valid IE payload type.  If the payload type specified is
+ * AST_EVENT_IE_PLTYPE_EXISTS, then the 3rd argument should not be provided.
+ * Otherwise, a payload must also be specified.
+ *
+ * \return This returns a reference to the subscription for use with
+ *         un-subscribing later.  If there is a failure in creating the
+ *         subscription, NULL will be returned.
+ *
+ * Example usage:
+ *
+ * \code
+ * peer->mwi_event_sub = ast_event_subscribe(AST_EVENT_MWI, mwi_event_cb, peer,
+ *     AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, peer->mailbox,
+ *     AST_EVENT_IE_END);
+ * \endcode
+ *
+ * This creates a subscription to AST_EVENT_MWI events that contain an
+ * information element, AST_EVENT_IE_MAILBOX, with the same string value
+ * contained in peer->mailbox.  Also, the event callback will be passed a
+ * pointer to the peer.
+ */
+struct ast_event_sub *ast_event_subscribe(enum ast_event_type event_type, 
+	ast_event_cb_t cb, void *userdata, ...);
+
+/*!
+ * \brief Un-subscribe from events
+ *
+ * \param event_sub This is the reference to the subscription returned by
+ *        ast_event_subscribe.
+ * 
+ * \return Nothing
+ */
+void ast_event_unsubscribe(struct ast_event_sub *event_sub);
+
+/*!
+ * \brief Check if subscribers exist
+ *
+ * \param event_type This is the type of event that the caller would like to
+ *        check for subscribers to.
+ *
+ * The rest of the arguments to this function specify additional parameters for
+ * checking for subscriptions to subsets of an event type. The arguments must
+ * in sets of:
+ * \code
+ *    <enum ast_event_ie_type>, [enum ast_event_ie_pltype, [payload] ]
+ * \endcode
+ * and must end with AST_EVENT_IE_END.
+ *
+ * If the ie_type specified is *not* AST_EVENT_IE_END, then it must be followed
+ * by a valid IE payload type.  If the payload type specified is
+ * AST_EVENT_IE_PLTYPE_EXISTS, then the 3rd argument should not be provided.
+ * Otherwise, a payload must also be specified.
+ *
+ * \return This returns one of the values defined in the ast_event_subscriber_res
+ *         enum which will indicate if subscribers exist that match the given
+ *         criteria.
+ *
+ * Example usage:
+ *
+ * \code
+ * if (ast_event_check_subscriber(AST_EVENT_MWI,
+ *     AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, mailbox,
+ *     AST_EVENT_IE_END) == AST_EVENT_SUB_NONE) {
+ *       return;
+ * }
+ * \endcode
+ *
+ * This example will check if there are any subscribers to MWI events for the 
+ * mailbox defined in the "mailbox" variable.
+ */
+enum ast_event_subscriber_res ast_event_check_subscriber(enum ast_event_type event_type, ...);
+
+/*!
+ * \brief Report current subscriptions to a subscription subscriber
+ *
+ * \arg sub the subscription subscriber
+ *
+ * \return nothing
+ *
+ * This reports all of the current subscribers to a subscriber of
+ * subscribers to a specific event type.  (Try saying that a few times fast).
+ *
+ * The idea here is that it is sometimes very useful for a module to know when
+ * someone subscribes to events.  However, when they first subscribe, this
+ * provides that module the ability to request the event core report to them
+ * all of the subscriptions to that event type that already exist.
+ */
+void ast_event_report_subs(const struct ast_event_sub *sub);
+
+/*!
+ * \brief Create a new event
+ *
+ * \param event_type The type of event to create
+ *
+ * The rest of the arguments to this function specify information elements to
+ * add to the event.  They are specified in the form:
+ * \code
+ *    <enum ast_event_ie_type>, [enum ast_event_ie_pltype, [payload] ]
+ * \endcode
+ * and must end with AST_EVENT_IE_END.
+ *
+ * If the ie_type specified is *not* AST_EVENT_IE_END, then it must be followed
+ * by a valid IE payload type.  The payload type, EXISTS, should not be used here
+ * because it makes no sense to do so.  So, a payload must also be specified
+ * after the IE payload type.
+ *
+ * \return This returns the event that has been created.  If there is an error
+ *         creating the event, NULL will be returned.
+ *
+ * Example usage:
+ *
+ * \code
+ * if (!(event = ast_event_new(AST_EVENT_MWI,
+ *     AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, mailbox,
+ *     AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_UINT, new,
+ *     AST_EVENT_IE_OLDMSGS, AST_EVENT_IE_PLTYPE_UINT, old,
+ *     AST_EVENT_IE_END))) {
+ *       return;
+ * }
+ * \endcode
+ *
+ * This creates a MWI event with 3 information elements, a mailbox which is
+ * a string, and the number of new and old messages, specified as integers.
+ */
+struct ast_event *ast_event_new(enum ast_event_type event_type, ...);
+
+/*!
+ * \brief Destroy an event
+ *
+ * \param event the event to destroy
+ *
+ * \return Nothing
+ *
+ * \note Events that have been queued should *not* be destroyed by the code that
+ *       created the event.  It will be automatically destroyed after being
+ *       dispatched to the appropriate subscribers.
+ */
+void ast_event_destroy(struct ast_event *event);
+
+/*!
+ * \brief Queue an event
+ *
+ * \param event the event to be queued
+ *
+ * \retval zero success
+ * \retval non-zero failure
+ *
+ * This function queues an event to be dispatched to all of the appropriate
+ * subscribers.  This function will not block while the event is being
+ * dispatched because a pool of event dispatching threads handle the event 
+ * queue.
+ */
+int ast_event_queue(struct ast_event *event);
+
+/*!
+ * \brief Queue and cache an event
+ *
+ * \param event the event to be queued and cached
+ *
+ * The rest of the arguments to this function specify information elements to
+ * use for determining which events in the cache that this event should replace.
+ * All events in the cache that match the specified criteria will be removed from
+ * the cache and then this one will be added.  The arguments are specified in 
+ * the form:
+ *
+ * \code
+ *    <enum ast_event_ie_type>, [enum ast_event_ie_pltype]
+ * \endcode
+ * and must end with AST_EVENT_IE_END.
+ *
+ * If the ie_type specified is *not* AST_EVENT_IE_END, then it must be followed
+ * by a valid IE payload type.  If the payload type given is EXISTS, then all
+ * events that contain that information element will be removed from the cache.
+ * Otherwise, all events in the cache that contain an information element with
+ * the same value as the new event will be removed.
+ *
+ * \note If more than one IE parameter is specified, they *all* must match for
+ *       the event to be removed from the cache.
+ *
+ * Example usage:
+ *
+ * \code
+ * ast_event_queue_and_cache(event,
+ *     AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR,
+ *     AST_EVENT_IE_END);
+ * \endcode
+ *
+ * This example queues and caches an event.  Any events in the cache that have
+ * the same MAILBOX information element as this event will be removed.
+ *
+ * The purpose of caching events is so that the core can retain the last known
+ * information for events that represent some sort of state.  That way, when
+ * code needs to find out the current state, it can query the cache.
+ */
+int ast_event_queue_and_cache(struct ast_event *event, ...);
+
+/*!
+ * \brief Retrieve an event from the cache
+ *
+ * \param ast_event_type The type of event to retrieve from the cache
+ *
+ * The rest of the arguments to this function specify information elements to
+ * match for retrieving events from the cache.  They are specified in the form:
+ * \code
+ *    <enum ast_event_ie_type>, [enum ast_event_ie_pltype, [payload] ]
+ * \endcode
+ * and must end with AST_EVENT_IE_END.
+ *
+ * If the ie_type specified is *not* AST_EVENT_IE_END, then it must be followed
+ * by a valid IE payload type.  If the payload type specified is
+ * AST_EVENT_IE_PLTYPE_EXISTS, then the 3rd argument should not be provided.
+ * Otherwise, a payload must also be specified.
+ *
+ * \return A reference to an event retrieved from the cache.  If no event was
+ *         found that matches the specified criteria, then NULL will be returned.
+ *
+ * \note If more than one event in the cache matches the specified criteria, only
+ *       one will be returned, and it is undefined which one it will be.
+ *
+ * \note The caller of this function *must* call ast_event_destroy() on the
+ *       returned event after it is done using it.
+ *
+ * Example Usage:
+ *
+ * \code
+ * event = ast_event_get_cached(AST_EVENT_MWI,
+ *     AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, mailbox,
+ *     AST_EVENT_IE_END);
+ * \endcode
+ *
+ * This example will check for an MWI event in the cache that matches the
+ * specified mailbox.  This would be the way to find out the last known state
+ * of a mailbox without having to poll the mailbox directly.
+ */
+struct ast_event *ast_event_get_cached(enum ast_event_type, ...);
+
+/*!
+ * \brief Append an information element that has a string payload
+ *
+ * \param event the event that the IE will be appended to
+ * \param ie_type the type of IE to append
+ * \param str The string for the payload of the IE
+ *
+ * \retval 0 success
+ * \retval -1 failure
+ *
+ * The pointer to the event will get updated with the new location for the event
+ * that now contains the appended information element.  If the re-allocation of
+ * the memory for this event fails, it will be set to NULL.
+ */
+int ast_event_append_ie_str(struct ast_event **event, enum ast_event_ie_type ie_type,
+	const char *str);
+
+/*!
+ * \brief Append an information element that has an integer payload
+ *
+ * \param event the event that the IE will be appended to
+ * \param ie_type the type of IE to append
+ * \param data The integer for the payload of the IE
+ *
+ * \retval 0 success
+ * \retval -1 failure
+ *
+ * The pointer to the event will get updated with the new location for the event
+ * that now contains the appended information element.  If the re-allocation of
+ * the memory for this event fails, it will be set to NULL.
+ */
+int ast_event_append_ie_uint(struct ast_event **event, enum ast_event_ie_type ie_type,
+	uint32_t data);
+
+/*!
+ * \brief Append an information element that has a raw payload
+ *
+ * \param event the event that the IE will be appended to
+ * \param ie_type the type of IE to append
+ * \param data A pointer to the raw data for the payload of the IE
+ * \param data_len The amount of data to copy into the payload
+ *
+ * \retval 0 success
+ * \retval -1 failure
+ *
+ * The pointer to the event will get updated with the new location for the event
+ * that now contains the appended information element.  If the re-allocation of
+ * the memory for this event fails, it will be set to NULL.
+ */
+int ast_event_append_ie_raw(struct ast_event **event, enum ast_event_ie_type ie_type,
+	const void *data, size_t data_len);
+
+/*!
+ * \brief Get the value of an information element that has an integer payload
+ *
+ * \param event The event to get the IE from
+ * \param ie_type the type of information element to retrieve
+ * 
+ * \return This returns the payload of the information element with the given type.
+ *         However, an IE with a payload of 0, and the case where no IE is found
+ *         yield the same return value.
+ */
+uint32_t ast_event_get_ie_uint(const struct ast_event *event, enum ast_event_ie_type ie_type);
+
+/*!
+ * \brief Get the value of an information element that has a string payload
+ *
+ * \param event The event to get the IE from
+ * \param ie_type the type of information element to retrieve
+ * 
+ * \return This returns the payload of the information element with the given type.
+ *         If the information element isn't found, NULL will be returned.
+ */
+const char *ast_event_get_ie_str(const struct ast_event *event, enum ast_event_ie_type ie_type);
+
+/*!
+ * \brief Get the value of an information element that has a raw payload
+ *
+ * \param event The event to get the IE from
+ * \param ie_type the type of information element to retrieve
+ * 
+ * \return This returns the payload of the information element with the given type.
+ *         If the information element isn't found, NULL will be returned.
+ */
+const void *ast_event_get_ie_raw(const struct ast_event *event, enum ast_event_ie_type ie_type);
+
+/*!
+ * \brief Get the type for an event
+ *
+ * \param event the event to get the type for
+ *
+ * \return the event type as represented by one of the values in the
+ *         ast_event_type enum
+ */
+enum ast_event_type ast_event_get_type(const struct ast_event *event);
+
+/*!
+ * \brief Initialize an event iterator instance
+ *
+ * \param iterator The iterator instance to initialize
+ * \param event The event that will be iterated through
+ *
+ * \return Nothing
+ */
+void ast_event_iterator_init(struct ast_event_iterator *iterator, const struct ast_event *event);
+
+/*!
+ * \brief Move iterator instance to next IE
+ *
+ * \param iterator The iterator instance
+ *
+ * \retval 0 on success
+ * \retval -1 if end is reached
+ */
+int ast_event_iterator_next(struct ast_event_iterator *iterator);
+
+/*!
+ * \brief Get the type of the current IE in the iterator instance
+ *
+ * \param iterator The iterator instance
+ *
+ * \return the ie type as represented by one of the value sin the
+ *         ast_event_ie_type enum
+ */
+enum ast_event_ie_type ast_event_iterator_get_ie_type(struct ast_event_iterator *iterator);
+
+/*!
+ * \brief Get the value of the current IE in the ierator as an integer payload
+ *
+ * \param iterator The iterator instance
+ *
+ * \return This returns the payload of the information element as a uint.
+ */
+uint32_t ast_event_iterator_get_ie_uint(struct ast_event_iterator *iterator);
+
+/*!
+ * \brief Get the value of the current IE in the iterator as a string payload
+ *
+ * \param iterator The iterator instance
+ *
+ * \return This returns the payload of the information element as a string.
+ */
+const char *ast_event_iterator_get_ie_str(struct ast_event_iterator *iterator);
+
+/*!
+ * \brief Get the value of the current IE in the iterator instance that has a raw payload
+ *
+ * \param iterator The iterator instance
+ *
+ * \return This returns the payload of the information element as type raw.
+ */
+void *ast_event_iterator_get_ie_raw(struct ast_event_iterator *iterator);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif /* AST_EVENT_H */
diff -ruN asterisk-1.4.20.1_original/include/asterisk/frame.h asterisk-1.4.20.1_updated/include/asterisk/frame.h
--- asterisk-1.4.20.1_original/include/asterisk/frame.h	2008-04-17 18:28:03.000000000 +0200
+++ asterisk-1.4.20.1_updated/include/asterisk/frame.h	2008-06-01 13:17:58.000000000 +0200
@@ -295,9 +295,18 @@
 	AST_CONTROL_HOLD = 16,		/*!< Indicate call is placed on hold */
 	AST_CONTROL_UNHOLD = 17,	/*!< Indicate call is left from hold */
 	AST_CONTROL_VIDUPDATE = 18,	/*!< Indicate video frame update */
+	AST_CONTROL_T38 = 19,		/*!< T38 state change request/notification */	
 	AST_CONTROL_SRCUPDATE = 20,     /*!< Indicate source of media has changed */
 };
 
+enum ast_control_t38 {
+	AST_T38_REQUEST_NEGOTIATE = 1,	/*!< Request T38 on a channel (voice to fax) */
+	AST_T38_REQUEST_TERMINATE,	/*!< Terminate T38 on a channel (fax to voice) */
+	AST_T38_NEGOTIATED,		/*!< T38 negotiated (fax mode) */
+	AST_T38_TERMINATED,		/*!< T38 terminated (back to voice) */
+	AST_T38_REFUSED			/*!< T38 refused for some reason (usually rejected by remote end) */
+};
+
 #define AST_SMOOTHER_FLAG_G729		(1 << 0)
 #define AST_SMOOTHER_FLAG_BE		(1 << 1)
 
@@ -344,6 +353,8 @@
 /*! Explicitly enable or disable echo cancelation for the given channel */
 #define	AST_OPTION_ECHOCAN		8
 
+#define AST_OPTION_T38_STATE		10
+
 struct oprmode {
 	struct ast_channel *peer;
 	int mode;
diff -ruN asterisk-1.4.20.1_original/include/asterisk/netsock.h asterisk-1.4.20.1_updated/include/asterisk/netsock.h
--- asterisk-1.4.20.1_original/include/asterisk/netsock.h	2006-02-14 20:14:15.000000000 +0100
+++ asterisk-1.4.20.1_updated/include/asterisk/netsock.h	2008-06-08 22:24:35.000000000 +0200
@@ -53,6 +53,8 @@
 struct ast_netsock *ast_netsock_find(struct ast_netsock_list *list,
 				     struct sockaddr_in *sa);
 
+int ast_netsock_set_qos(int netsocket, int tos, int cos, const char *desc);
+
 int ast_netsock_sockfd(const struct ast_netsock *ns);
 
 const struct sockaddr_in *ast_netsock_boundaddr(const struct ast_netsock *ns);
diff -ruN asterisk-1.4.20.1_original/include/asterisk/time.h asterisk-1.4.20.1_updated/include/asterisk/time.h
--- asterisk-1.4.20.1_original/include/asterisk/time.h	2007-12-17 22:12:42.000000000 +0100
+++ asterisk-1.4.20.1_updated/include/asterisk/time.h	2008-06-11 23:55:10.000000000 +0200
@@ -25,6 +25,7 @@
 
 #include <sys/time.h>
 #include <stdlib.h>
+#include <stdint.h>
 
 #include "asterisk/inline_api.h"
 
@@ -35,6 +36,26 @@
 typedef typeof(tv.tv_sec) ast_time_t;
 typedef typeof(tv.tv_usec) ast_suseconds_t;
 
+
+/*!
+ * \brief Computes the difference (in seconds) between two \c struct \c timeval instances.
+ * \param end the end of the time period
+ * \param start the beginning of the time period
+ * \return the difference in seconds
+ */
+AST_INLINE_API(
+int ast_tvdiff_sec(struct timeval end, struct timeval start),
+{
+	int result = end.tv_sec - start.tv_sec;
+	if (result > 0 && end.tv_usec < start.tv_usec)
+		result--;
+	else if (result < 0 && end.tv_usec > start.tv_usec)
+		result++;
+
+	return result;
+}
+)
+
 /*!
  * \brief Computes the difference (in milliseconds) between two \c struct \c timeval instances.
  * \param end end of the time period
@@ -55,6 +76,21 @@
 )
 
 /*!
+ * \brief Computes the difference (in microseconds) between two \c struct \c timeval instances.
+ * \param ast_tvdiff_sec 
+ * \arg end the end of the time period
+ * \arg start the beginning of the time period
+ * \return the difference in microseconds
+ */
+AST_INLINE_API(
+int64_t ast_tvdiff_us(struct timeval end, struct timeval start),
+{
+	return (end.tv_sec - start.tv_sec) * (int64_t) 1000000 +
+		end.tv_usec - start.tv_usec;
+}
+)
+
+/*!
  * \brief Returns true if the argument is 0,0
  */
 AST_INLINE_API(
diff -ruN asterisk-1.4.20.1_original/include/asterisk/udptl.h asterisk-1.4.20.1_updated/include/asterisk/udptl.h
--- asterisk-1.4.20.1_original/include/asterisk/udptl.h	2006-06-14 16:12:56.000000000 +0200
+++ asterisk-1.4.20.1_updated/include/asterisk/udptl.h	2008-06-08 22:21:55.000000000 +0200
@@ -15,18 +15,25 @@
  * this code.
  */
 
+/*! \file
+ * \brief UDPTL support for T.38
+ * \author Steve Underwood <steveu@coppice.org>
+ * \ref udptl.c
+ * \todo add doxygen documentation to this file!
+ */
+
+
 #ifndef _ASTERISK_UDPTL_H
 #define _ASTERISK_UDPTL_H
 
+//#include "asterisk/network.h"
 #include "asterisk/frame.h"
 #include "asterisk/io.h"
 #include "asterisk/sched.h"
 #include "asterisk/channel.h"
 
-#include <netinet/in.h>
 
-enum
-{
+enum {
     UDPTL_ERROR_CORRECTION_NONE,
     UDPTL_ERROR_CORRECTION_FEC,
     UDPTL_ERROR_CORRECTION_REDUNDANCY
@@ -37,12 +44,12 @@
 #endif
 
 struct ast_udptl_protocol {
-	/* Get UDPTL struct, or NULL if unwilling to transfer */
+	/*! \brief Get UDPTL struct, or NULL if unwilling to transfer */
 	struct ast_udptl *(*get_udptl_info)(struct ast_channel *chan);
-	/* Set UDPTL peer */
+	/*! \brief Set UDPTL peer */
 	int (* const set_udptl_peer)(struct ast_channel *chan, struct ast_udptl *peer);
 	const char * const type;
-	struct ast_udptl_protocol *next;
+	AST_RWLIST_ENTRY(ast_udptl_protocol) list;
 };
 
 struct ast_udptl;
@@ -75,6 +82,8 @@
 
 int ast_udptl_settos(struct ast_udptl *udptl, int tos);
 
+int ast_udptl_setqos(struct ast_udptl *udptl, int tos, int cos);
+
 void ast_udptl_set_m_type(struct ast_udptl* udptl, int pt);
 
 void ast_udptl_set_udptlmap_type(struct ast_udptl* udptl, int pt,
diff -ruN asterisk-1.4.20.1_original/main/channel.c asterisk-1.4.20.1_updated/main/channel.c
--- asterisk-1.4.20.1_original/main/channel.c	2008-05-14 01:47:49.000000000 +0200
+++ asterisk-1.4.20.1_updated/main/channel.c	2008-06-05 22:03:56.000000000 +0200
@@ -4163,6 +4163,19 @@
 	return 0;
 }
 
+int ast_channel_queryoption(struct ast_channel *chan, int option, void *data, int *datalen, int block)
+{
+	if (!chan->tech->queryoption) {
+		errno = ENOSYS;
+		return -1;
+	}
+
+	if (block)
+		ast_log(LOG_ERROR, "XXX Blocking not implemented yet XXX\n");
+
+	return chan->tech->queryoption(chan, option, data, datalen);
+}
+
 struct tonepair_def {
 	int freq1;
 	int freq2;
diff -ruN asterisk-1.4.20.1_original/main/dsp.c asterisk-1.4.20.1_updated/main/dsp.c
--- asterisk-1.4.20.1_original/main/dsp.c	2008-04-17 18:28:03.000000000 +0200
+++ asterisk-1.4.20.1_updated/main/dsp.c	2008-06-08 22:42:46.000000000 +0200
@@ -30,35 +30,29 @@
 /* Some routines from tone_detect.c by Steven Underwood as published under the zapata library */
 /*
 	tone_detect.c - General telephony tone detection, and specific
-                        detection of DTMF.
+					detection of DTMF.
 
-        Copyright (C) 2001  Steve Underwood <steveu@coppice.org>
+	Copyright (C) 2001  Steve Underwood <steveu@coppice.org>
 
-        Despite my general liking of the GPL, I place this code in the
-        public domain for the benefit of all mankind - even the slimy
-        ones who might try to proprietize my work and use it to my
-        detriment.
+	Despite my general liking of the GPL, I place this code in the
+	public domain for the benefit of all mankind - even the slimy
+	ones who might try to proprietize my work and use it to my
+	detriment.
 */
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 114207 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision: 114210 $")
 
-#include <sys/types.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
 #include <math.h>
-#include <errno.h>
-#include <stdio.h>
 
 #include "asterisk/frame.h"
 #include "asterisk/channel.h"
-#include "asterisk/logger.h"
 #include "asterisk/dsp.h"
 #include "asterisk/ulaw.h"
 #include "asterisk/alaw.h"
 #include "asterisk/utils.h"
+#include "asterisk/options.h"
 
 /*! Number of goertzels for progress detect */
 enum gsamp_size {
@@ -153,112 +147,120 @@
  * Frequency tolerance +- 1.5% will detect, +-3.5% will reject
  */
 
-#define DTMF_THRESHOLD          8.0e7
-#define FAX_THRESHOLD           8.0e7
-#define FAX_2ND_HARMONIC        2.0     /* 4dB */
-
-#ifdef  RADIO_RELAX
-#define DTMF_NORMAL_TWIST               ((digitmode & DSP_DIGITMODE_RELAXDTMF) ? 11.3 : 6.3)    /* 8dB sph 12.3 was 6.3 */
-#define DTMF_REVERSE_TWIST              ((digitmode & DSP_DIGITMODE_RELAXDTMF) ? 9.5  : 2.5)    /* 4dB normal sph 12.5 : 5.5 was 6.5 : 2.5 */
-#define DTMF_RELATIVE_PEAK_ROW  ((digitmode & DSP_DIGITMODE_RELAXDTMF) ? 3.3  : 6.3)    /* 8dB sph was 6.3 */
-#define DTMF_RELATIVE_PEAK_COL  ((digitmode & DSP_DIGITMODE_RELAXDTMF) ? 3.3  : 6.3)    /* 8dB sph was 6.3 */
-#define DTMF_TO_TOTAL_ENERGY    ((digitmode & DSP_DIGITMODE_RELAXDTMF) ? 26.0 : 42.0)
+#define DTMF_THRESHOLD		8.0e7
+#define FAX_THRESHOLD		8.0e7
+#define FAX_2ND_HARMONIC	2.0     /* 4dB */
+#define DTMF_NORMAL_TWIST	6.3     /* 8dB */
+#ifdef	RADIO_RELAX
+#define DTMF_REVERSE_TWIST          ((digitmode & DSP_DIGITMODE_RELAXDTMF) ? 6.5 : 2.5)     /* 4dB normal */
 #else
-#define DTMF_NORMAL_TWIST               6.3
-#define DTMF_REVERSE_TWIST              ((digitmode & DSP_DIGITMODE_RELAXDTMF) ? 4.0  : 2.5)    /* 4dB normal */
-#define DTMF_RELATIVE_PEAK_ROW  6.3     /* 8dB */
-#define DTMF_RELATIVE_PEAK_COL  6.3     /* 8dB */
-#define DTMF_TO_TOTAL_ENERGY    42.0
+#define DTMF_REVERSE_TWIST          ((digitmode & DSP_DIGITMODE_RELAXDTMF) ? 4.0 : 2.5)     /* 4dB normal */
 #endif
-
-#ifdef OLD_DSP_ROUTINES
+#define DTMF_RELATIVE_PEAK_ROW	6.3     /* 8dB */
+#define DTMF_RELATIVE_PEAK_COL	6.3     /* 8dB */
 #define DTMF_2ND_HARMONIC_ROW       ((digitmode & DSP_DIGITMODE_RELAXDTMF) ? 1.7 : 2.5)     /* 4dB normal */
 #define DTMF_2ND_HARMONIC_COL	63.1    /* 18dB */
+#define DTMF_TO_TOTAL_ENERGY	42.0
 
-#define MF_THRESHOLD		8.0e7
-#define MF_NORMAL_TWIST		5.3     /* 8dB */
-#define MF_REVERSE_TWIST	4.0     /* was 2.5 */
-#define MF_RELATIVE_PEAK	5.3     /* 8dB */
-#define MF_2ND_HARMONIC		1.7	/* was 2.5  */
-#else
 #define BELL_MF_THRESHOLD	1.6e9
 #define BELL_MF_TWIST		4.0     /* 6dB */
 #define BELL_MF_RELATIVE_PEAK	12.6    /* 11dB */
-#endif
 
-#if !defined(BUSYDETECT_MARTIN) && !defined(BUSYDETECT) && !defined(BUSYDETECT_TONEONLY) && !defined(BUSYDETECT_COMPARE_TONE_AND_SILENCE)
-#define BUSYDETECT_MARTIN
+#if defined(BUSYDETECT_TONEONLY) && defined(BUSYDETECT_COMPARE_TONE_AND_SILENCE)
+#error You cant use BUSYDETECT_TONEONLY together with BUSYDETECT_COMPARE_TONE_AND_SILENCE
 #endif
 
+/* The CNG signal consists of the transmission of 1100 Hz for 1/2 second,
+ * followed by a 3 second silent (2100 Hz OFF) period.
+ */
+#define FAX_TONE_CNG_FREQ	1100
+#define FAX_TONE_CNG_DURATION	500
+#define FAX_TONE_CNG_DB		16
+
+/* This signal may be sent by the Terminating FAX machine anywhere between
+ * 1.8 to 2.5 seconds AFTER answering the call.  The CED signal consists
+ * of a 2100 Hz tone that is from 2.6 to 4 seconds in duration.
+*/
+#define FAX_TONE_CED_FREQ	2100
+#define FAX_TONE_CED_DURATION	2600
+#define FAX_TONE_CED_DB		16
+
+#define SAMPLE_RATE		8000
+
+/* How many samples a frame has.  This constant is used when calculating
+ * Goertzel block size for tone_detect.  It is only important if we want to
+ * remove (squelch) the tone. In this case it is important to have block
+ * size not to exceed size of voice frame.  Otherwise by the moment the tone
+ * is detected it is too late to squelch it from previous frames.
+ */
+#define SAMPLES_IN_FRAME	160
+
+
 typedef struct {
-	float v2;
-	float v3;
-	float fac;
-#ifndef OLD_DSP_ROUTINES
+	int v2;
+	int v3;
+	int chunky;
+	int fac;
 	int samples;
-#endif	
 } goertzel_state_t;
 
+typedef struct {
+	int value;
+	int power;
+} goertzel_result_t;
+
+typedef struct
+{
+	int freq;
+	int block_size;
+	int squelch;		/* Remove (squelch) tone */
+	goertzel_state_t tone;
+	float energy;		/* Accumulated energy of the current block */
+	int samples_pending;	/* Samples remain to complete the current block */
+
+	int hits_required;	/* How many successive blocks with tone we are looking for */
+	float threshold;	/* Energy of the tone relative to energy from all other signals to consider a hit */
+
+	int hit_count;		/* How many successive blocks we consider tone present */
+	int last_hit;		/* Indicates if the last processed block was a hit */
+
+} tone_detect_state_t;
+
 typedef struct
 {
 	goertzel_state_t row_out[4];
 	goertzel_state_t col_out[4];
-#ifdef FAX_DETECT
-	goertzel_state_t fax_tone;
-#endif
-#ifdef OLD_DSP_ROUTINES
-	goertzel_state_t row_out2nd[4];
-	goertzel_state_t col_out2nd[4];
-#ifdef FAX_DETECT
-	goertzel_state_t fax_tone2nd;    
-#endif
-	int hit1;
-	int hit2;
-	int hit3;
-	int hit4;
-#else
 	int lasthit;
-#endif	
-	int mhit;
+	int current_hit;
 	float energy;
 	int current_sample;
 
-	char digits[MAX_DTMF_DIGITS + 1];
-	
-	int current_digits;
-	int detected_digits;
-	int lost_digits;
-	int digit_hits[16];
-#ifdef FAX_DETECT
+	#ifdef FAX_DETECT
 	int fax_hits;
-#endif
+	#endif
+	
 } dtmf_detect_state_t;
 
 typedef struct
 {
 	goertzel_state_t tone_out[6];
-	int mhit;
-#ifdef OLD_DSP_ROUTINES
-	int hit1;
-	int hit2;
-	int hit3;
-	int hit4;
-	goertzel_state_t tone_out2nd[6];
-	float energy;
-#else
+	int current_hit;
 	int hits[5];
-#endif
 	int current_sample;
-	
-	char digits[MAX_DTMF_DIGITS + 1];
+} mf_detect_state_t;
 
+typedef struct
+{
+	char digits[MAX_DTMF_DIGITS + 1];
 	int current_digits;
 	int detected_digits;
 	int lost_digits;
-#ifdef FAX_DETECT
-	int fax_hits;
-#endif
-} mf_detect_state_t;
+
+	union {
+		dtmf_detect_state_t dtmf;
+		mf_detect_state_t mf;
+	} td;
+} digit_detect_state_t;
 
 static float dtmf_row[] =
 {
@@ -274,33 +276,25 @@
 	700.0, 900.0, 1100.0, 1300.0, 1500.0, 1700.0
 };
 
-#ifdef FAX_DETECT
-static float fax_freq = 1100.0;
-#endif
-
 static char dtmf_positions[] = "123A" "456B" "789C" "*0#D";
 
-#ifdef OLD_DSP_ROUTINES
-static char mf_hit[6][6] = {
-	/*  700 + */ {   0, '1', '2', '4', '7', 'C' },
-	/*  900 + */ { '1',   0, '3', '5', '8', 'A' },
-	/* 1100 + */ { '2', '3',   0, '6', '9', '*' },
-	/* 1300 + */ { '4', '5', '6',   0, '0', 'B' },
-	/* 1500 + */ { '7', '8', '9', '0',  0, '#' },
-	/* 1700 + */ { 'C', 'A', '*', 'B', '#',  0  },
-};
-#else
 static char bell_mf_positions[] = "1247C-358A--69*---0B----#";
-#endif
 
 static inline void goertzel_sample(goertzel_state_t *s, short sample)
 {
-	float v1;
-	float fsamp  = sample;
+	int v1;
 	
 	v1 = s->v2;
 	s->v2 = s->v3;
-	s->v3 = s->fac * s->v2 - v1 + fsamp;
+	
+	s->v3 = (s->fac * s->v2) >> 15;
+	s->v3 = s->v3 - v1 + (sample >> s->chunky);
+	if (abs(s->v3) > 32768) {
+		s->chunky++;
+		s->v3 = s->v3 >> 1;
+		s->v2 = s->v2 >> 1;
+		v1 = v1 >> 1;
+	}
 }
 
 static inline void goertzel_update(goertzel_state_t *s, short *samps, int count)
@@ -314,21 +308,23 @@
 
 static inline float goertzel_result(goertzel_state_t *s)
 {
-	return s->v3 * s->v3 + s->v2 * s->v2 - s->v2 * s->v3 * s->fac;
+	goertzel_result_t r;
+	r.value = (s->v3 * s->v3) + (s->v2 * s->v2);
+	r.value -= ((s->v2 * s->v3) >> 15) * s->fac;
+	r.power = s->chunky * 2;
+	return (float)r.value * (float)(1 << r.power);
 }
 
 static inline void goertzel_init(goertzel_state_t *s, float freq, int samples)
 {
-	s->v2 = s->v3 = 0.0;
-	s->fac = 2.0 * cos(2.0 * M_PI * (freq / 8000.0));
-#ifndef OLD_DSP_ROUTINES
+	s->v2 = s->v3 = s->chunky = 0.0;
+	s->fac = (int)(32768.0 * 2.0 * cos(2.0 * M_PI * freq / SAMPLE_RATE));
 	s->samples = samples;
-#endif
 }
 
 static inline void goertzel_reset(goertzel_state_t *s)
 {
-	s->v2 = s->v3 = 0.0;
+	s->v2 = s->v3 = s->chunky = 0.0;
 }
 
 struct ast_dsp {
@@ -352,91 +348,227 @@
 	int tstate;
 	int tcount;
 	int digitmode;
+	int faxmode;
 	int thinkdigit;
 	float genergy;
-	union {
-		dtmf_detect_state_t dtmf;
-		mf_detect_state_t mf;
-	} td;
+	digit_detect_state_t digit_state;
+	tone_detect_state_t cng_tone_state;
+	tone_detect_state_t ced_tone_state;
 };
 
+static void ast_tone_detect_init(tone_detect_state_t *s, int freq, int duration, int amp)
+{
+	int duration_samples;
+	float x;
+	int periods_in_block;
+
+	s->freq = freq;
+
+	/* Desired tone duration in samples */
+	duration_samples = duration * SAMPLE_RATE / 1000;
+	/* We want to allow 10% deviation of tone duration */
+	duration_samples = duration_samples * 9 / 10;
+
+	/* If we want to remove tone, it is important to have block size not
+	   to exceed frame size. Otherwise by the moment tone is detected it is too late
+ 	   to squelch it from previous frames */
+	s->block_size = SAMPLES_IN_FRAME;
+
+	periods_in_block = s->block_size * freq / SAMPLE_RATE;
+
+	/* Make sure we will have at least 5 periods at target frequency for analisys.
+	   This may make block larger than expected packet and will make squelching impossible
+	   but at least we will be detecting the tone */
+	if (periods_in_block < 5)
+		periods_in_block = 5;
+
+	/* Now calculate final block size. It will contain integer number of periods */
+	s->block_size = periods_in_block * SAMPLE_RATE / freq;
+
+	/* tone_detect is currently only used to detect fax tones and we
+	   do not need suqlching the fax tones */
+	s->squelch = 0;
+
+	/* Account for the first and the last block to be incomplete
+	   and thus no tone will be detected in them */
+	s->hits_required = (duration_samples - (s->block_size - 1)) / s->block_size;
+
+	goertzel_init(&s->tone, freq, s->block_size);
+
+	s->samples_pending = s->block_size;
+	s->hit_count = 0;
+	s->last_hit = 0;
+	s->energy = 0.0;
+
+	/* We want tone energy to be amp decibels above the rest of the signal (the noise).
+	   According to Parseval's theorem the energy computed in time domain equals to energy
+	   computed in frequency domain. So subtracting energy in the frequency domain (Goertzel result)
+	   from the energy in the time domain we will get energy of the remaining signal (without the tone
+	   we are detecting). We will be checking that
+		10*log(Ew / (Et - Ew)) > amp
+	   Calculate threshold so that we will be actually checking
+		Ew > Et * threshold
+	*/
+
+	x = pow(10.0, amp / 10.0);
+	s->threshold = x / (x + 1);
+
+	ast_log(LOG_DEBUG, "Setup tone %d Hz, %d ms, block_size=%d, hits_required=%d\n", freq, duration, s->block_size, s->hits_required);
+}
+
+static void ast_fax_detect_init(struct ast_dsp *s)
+{
+	ast_tone_detect_init(&s->cng_tone_state, FAX_TONE_CNG_FREQ, FAX_TONE_CNG_DURATION, FAX_TONE_CNG_DB);
+	ast_tone_detect_init(&s->ced_tone_state, FAX_TONE_CED_FREQ, FAX_TONE_CED_DURATION, FAX_TONE_CED_DB);
+}
+
 static void ast_dtmf_detect_init (dtmf_detect_state_t *s)
 {
 	int i;
 
-#ifdef OLD_DSP_ROUTINES
-	s->hit1 = 
-	s->mhit = 
-	s->hit3 =
-	s->hit4 = 
-	s->hit2 = 0;
-#else
 	s->lasthit = 0;
-#endif
+	s->current_hit = 0;
 	for (i = 0;  i < 4;  i++) {
 		goertzel_init (&s->row_out[i], dtmf_row[i], 102);
 		goertzel_init (&s->col_out[i], dtmf_col[i], 102);
-#ifdef OLD_DSP_ROUTINES
-		goertzel_init (&s->row_out2nd[i], dtmf_row[i] * 2.0, 102);
-		goertzel_init (&s->col_out2nd[i], dtmf_col[i] * 2.0, 102);
-#endif	
 		s->energy = 0.0;
 	}
-#ifdef FAX_DETECT
-	/* Same for the fax dector */
-	goertzel_init (&s->fax_tone, fax_freq, 102);
-
-#ifdef OLD_DSP_ROUTINES
-	/* Same for the fax dector 2nd harmonic */
-	goertzel_init (&s->fax_tone2nd, fax_freq * 2.0, 102);
-#endif	
-#endif /* FAX_DETECT */
 	s->current_sample = 0;
-	s->detected_digits = 0;
-	s->current_digits = 0;
-	memset(&s->digits, 0, sizeof(s->digits));
-	s->lost_digits = 0;
-	s->digits[0] = '\0';
 }
 
 static void ast_mf_detect_init (mf_detect_state_t *s)
 {
 	int i;
-#ifdef OLD_DSP_ROUTINES
-	s->hit1 = 
-	s->hit2 = 0;
-#else	
 	s->hits[0] = s->hits[1] = s->hits[2] = s->hits[3] = s->hits[4] = 0;
-#endif
 	for (i = 0;  i < 6;  i++) {
 		goertzel_init (&s->tone_out[i], mf_tones[i], 160);
-#ifdef OLD_DSP_ROUTINES
-		goertzel_init (&s->tone_out2nd[i], mf_tones[i] * 2.0, 160);
-		s->energy = 0.0;
-#endif
 	}
-	s->current_digits = 0;
-	memset(&s->digits, 0, sizeof(s->digits));
 	s->current_sample = 0;
+	s->current_hit = 0;
+}
+
+static void ast_digit_detect_init(digit_detect_state_t *s, int mf)
+{
+	s->current_digits = 0;
 	s->detected_digits = 0;
 	s->lost_digits = 0;
 	s->digits[0] = '\0';
-	s->mhit = 0;
+
+	if (mf)
+		ast_mf_detect_init(&s->td.mf);
+	else
+		ast_dtmf_detect_init(&s->td.dtmf);
+}
+
+static int tone_detect(tone_detect_state_t *s, int16_t *amp, int samples, 
+		 int *writeback)
+{
+	float tone_energy;
+	int i;
+	int hit = 0;
+	int limit;
+	int res = 0;
+	int16_t *ptr;
+
+	while (1) {
+		/* Process in blocks. */
+		limit = (samples < s->samples_pending) ? samples : s->samples_pending;
+
+		for (i = limit, ptr = amp ; i > 0; i--, ptr++) {
+			/* signed 32 bit int should be enough to suqare any possible signed 16 bit value */
+			s->energy += (int32_t) *ptr * (int32_t) *ptr;
+
+			goertzel_sample(&s->tone, *ptr);
+		}
+
+		s->samples_pending -= limit;
+
+		if (s->samples_pending) {
+			/* Finished incomplete (last) block */
+			if (s->last_hit && s->squelch) {
+				/* If we had a hit last time, go ahead and clear this out since likely it
+				   will be another hit */
+				memset(amp, 0, sizeof(*amp) * limit);
+				if (writeback)
+					*writeback = 1;
+			}
+			break;
+		}
+
+
+		tone_energy = goertzel_result(&s->tone);
+
+		/* Scale to make comparable */
+		tone_energy *= 2.0;
+		s->energy *= s->block_size;
+
+		ast_log(LOG_DEBUG, "tone %d, Ew=%f, Et=%f, s/n=%10.2f\n", s->freq, tone_energy, s->energy, tone_energy / (s->energy - tone_energy));
+		hit = 0;
+		if (tone_energy > s->energy * s->threshold) {
+
+			ast_log(LOG_DEBUG, "Hit! count=%d\n", s->hit_count);
+			hit = 1;
+
+			if (s->squelch) {
+				/* Zero out frame data */
+				memset(amp, 0, sizeof(*amp) * limit);
+				if (writeback)
+					*writeback = 1;
+			}
+		}
+
+		if (s->hit_count)
+			s->hit_count++;
+
+		if (hit == s->last_hit) {
+			if (!hit) {
+				/* Two successive misses. Tone ended */
+				s->hit_count = 0;
+			} else if (!s->hit_count) {
+				s->hit_count++;
+			}
+
+		}
+
+		if (s->hit_count == s->hits_required) {
+			ast_log(LOG_DEBUG, "%d Hz done detected\n", s->freq);
+			res = 1;
+		}
+
+		s->last_hit = hit;
+
+		/* Reset for the next block */
+		goertzel_reset(&s->tone);
+
+		/* Advance to the next block */
+		s->energy = 0.0;
+		s->samples_pending = s->block_size;
+
+		amp += limit;
+		samples -= limit;
+	}
+
+	return res;
 }
 
-static int dtmf_detect (dtmf_detect_state_t *s, int16_t amp[], int samples, 
-		 int digitmode, int *writeback, int faxdetect)
+static void store_digit(digit_detect_state_t *s, char digit)
+{
+	s->detected_digits++;
+	if (s->current_digits < MAX_DTMF_DIGITS) {
+		s->digits[s->current_digits++] = digit;
+		s->digits[s->current_digits] = '\0';
+	} else {
+		ast_log(LOG_WARNING, "Digit lost due to full buffer\n");
+		s->lost_digits++;
+	}
+}
+
+static int dtmf_detect(digit_detect_state_t *s, int16_t amp[], int samples, 
+		 int digitmode, int *writeback)
 {
 	float row_energy[4];
 	float col_energy[4];
-#ifdef FAX_DETECT
-	float fax_energy;
-#ifdef OLD_DSP_ROUTINES
-	float fax_energy_2nd;
-#endif	
-#endif /* FAX_DETECT */
 	float famp;
-	float v1;
 	int i;
 	int j;
 	int sample;
@@ -448,93 +580,28 @@
 	hit = 0;
 	for (sample = 0;  sample < samples;  sample = limit) {
 		/* 102 is optimised to meet the DTMF specs. */
-		if ((samples - sample) >= (102 - s->current_sample))
-			limit = sample + (102 - s->current_sample);
+		if ((samples - sample) >= (102 - s->td.dtmf.current_sample))
+			limit = sample + (102 - s->td.dtmf.current_sample);
 		else
 			limit = samples;
-#if defined(USE_3DNOW)
-		_dtmf_goertzel_update (s->row_out, amp + sample, limit - sample);
-		_dtmf_goertzel_update (s->col_out, amp + sample, limit - sample);
-#ifdef OLD_DSP_ROUTINES
-		_dtmf_goertzel_update (s->row_out2nd, amp + sample, limit2 - sample);
-		_dtmf_goertzel_update (s->col_out2nd, amp + sample, limit2 - sample);
-#endif		
-		/* XXX Need to fax detect for 3dnow too XXX */
-		#warning "Fax Support Broken"
-#else
 		/* The following unrolled loop takes only 35% (rough estimate) of the 
 		   time of a rolled loop on the machine on which it was developed */
-		for (j=sample;j<limit;j++) {
+		for (j = sample; j < limit; j++) {
 			famp = amp[j];
-			s->energy += famp*famp;
+			s->td.dtmf.energy += famp*famp;
 			/* With GCC 2.95, the following unrolled code seems to take about 35%
 			   (rough estimate) as long as a neat little 0-3 loop */
-			v1 = s->row_out[0].v2;
-			s->row_out[0].v2 = s->row_out[0].v3;
-			s->row_out[0].v3 = s->row_out[0].fac*s->row_out[0].v2 - v1 + famp;
-			v1 = s->col_out[0].v2;
-			s->col_out[0].v2 = s->col_out[0].v3;
-			s->col_out[0].v3 = s->col_out[0].fac*s->col_out[0].v2 - v1 + famp;
-			v1 = s->row_out[1].v2;
-			s->row_out[1].v2 = s->row_out[1].v3;
-			s->row_out[1].v3 = s->row_out[1].fac*s->row_out[1].v2 - v1 + famp;
-			v1 = s->col_out[1].v2;
-			s->col_out[1].v2 = s->col_out[1].v3;
-			s->col_out[1].v3 = s->col_out[1].fac*s->col_out[1].v2 - v1 + famp;
-			v1 = s->row_out[2].v2;
-			s->row_out[2].v2 = s->row_out[2].v3;
-			s->row_out[2].v3 = s->row_out[2].fac*s->row_out[2].v2 - v1 + famp;
-			v1 = s->col_out[2].v2;
-			s->col_out[2].v2 = s->col_out[2].v3;
-			s->col_out[2].v3 = s->col_out[2].fac*s->col_out[2].v2 - v1 + famp;
-			v1 = s->row_out[3].v2;
-			s->row_out[3].v2 = s->row_out[3].v3;
-			s->row_out[3].v3 = s->row_out[3].fac*s->row_out[3].v2 - v1 + famp;
-			v1 = s->col_out[3].v2;
-			s->col_out[3].v2 = s->col_out[3].v3;
-			s->col_out[3].v3 = s->col_out[3].fac*s->col_out[3].v2 - v1 + famp;
-#ifdef FAX_DETECT
-			/* Update fax tone */
-			v1 = s->fax_tone.v2;
-			s->fax_tone.v2 = s->fax_tone.v3;
-			s->fax_tone.v3 = s->fax_tone.fac*s->fax_tone.v2 - v1 + famp;
-#endif /* FAX_DETECT */
-#ifdef OLD_DSP_ROUTINES
-			v1 = s->col_out2nd[0].v2;
-			s->col_out2nd[0].v2 = s->col_out2nd[0].v3;
-			s->col_out2nd[0].v3 = s->col_out2nd[0].fac*s->col_out2nd[0].v2 - v1 + famp;
-			v1 = s->row_out2nd[0].v2;
-			s->row_out2nd[0].v2 = s->row_out2nd[0].v3;
-			s->row_out2nd[0].v3 = s->row_out2nd[0].fac*s->row_out2nd[0].v2 - v1 + famp;
-			v1 = s->col_out2nd[1].v2;
-			s->col_out2nd[1].v2 = s->col_out2nd[1].v3;
-			s->col_out2nd[1].v3 = s->col_out2nd[1].fac*s->col_out2nd[1].v2 - v1 + famp;
-			v1 = s->row_out2nd[1].v2;
-			s->row_out2nd[1].v2 = s->row_out2nd[1].v3;
-			s->row_out2nd[1].v3 = s->row_out2nd[1].fac*s->row_out2nd[1].v2 - v1 + famp;
-			v1 = s->col_out2nd[2].v2;
-			s->col_out2nd[2].v2 = s->col_out2nd[2].v3;
-			s->col_out2nd[2].v3 = s->col_out2nd[2].fac*s->col_out2nd[2].v2 - v1 + famp;
-			v1 = s->row_out2nd[2].v2;
-			s->row_out2nd[2].v2 = s->row_out2nd[2].v3;
-			s->row_out2nd[2].v3 = s->row_out2nd[2].fac*s->row_out2nd[2].v2 - v1 + famp;
-			v1 = s->col_out2nd[3].v2;
-			s->col_out2nd[3].v2 = s->col_out2nd[3].v3;
-			s->col_out2nd[3].v3 = s->col_out2nd[3].fac*s->col_out2nd[3].v2 - v1 + famp;
-			v1 = s->row_out2nd[3].v2;
-			s->row_out2nd[3].v2 = s->row_out2nd[3].v3;
-			s->row_out2nd[3].v3 = s->row_out2nd[3].fac*s->row_out2nd[3].v2 - v1 + famp;
-#ifdef FAX_DETECT
-			/* Update fax tone */            
-			v1 = s->fax_tone.v2;
-			s->fax_tone2nd.v2 = s->fax_tone2nd.v3;
-			s->fax_tone2nd.v3 = s->fax_tone2nd.fac*s->fax_tone2nd.v2 - v1 + famp;
-#endif /* FAX_DETECT */
-#endif
+			goertzel_sample(s->td.dtmf.row_out, amp[j]);
+			goertzel_sample(s->td.dtmf.col_out, amp[j]);
+			goertzel_sample(s->td.dtmf.row_out + 1, amp[j]);
+			goertzel_sample(s->td.dtmf.col_out + 1, amp[j]);
+			goertzel_sample(s->td.dtmf.row_out + 2, amp[j]);
+			goertzel_sample(s->td.dtmf.col_out + 2, amp[j]);
+			goertzel_sample(s->td.dtmf.row_out + 3, amp[j]);
+			goertzel_sample(s->td.dtmf.col_out + 3, amp[j]);
 		}
-#endif
-		s->current_sample += (limit - sample);
-		if (s->current_sample < 102) {
+		s->td.dtmf.current_sample += (limit - sample);
+		if (s->td.dtmf.current_sample < 102) {
 			if (hit && !((digitmode & DSP_DIGITMODE_NOQUELCH))) {
 				/* If we had a hit last time, go ahead and clear this out since likely it
 				   will be another hit */
@@ -544,20 +611,16 @@
 			}
 			continue;
 		}
-#ifdef FAX_DETECT
-		/* Detect the fax energy, too */
-		fax_energy = goertzel_result(&s->fax_tone);
-#endif
 		/* We are at the end of a DTMF detection block */
 		/* Find the peak row and the peak column */
-		row_energy[0] = goertzel_result (&s->row_out[0]);
-		col_energy[0] = goertzel_result (&s->col_out[0]);
+		row_energy[0] = goertzel_result (&s->td.dtmf.row_out[0]);
+		col_energy[0] = goertzel_result (&s->td.dtmf.col_out[0]);
 
 		for (best_row = best_col = 0, i = 1;  i < 4;  i++) {
-			row_energy[i] = goertzel_result (&s->row_out[i]);
+			row_energy[i] = goertzel_result (&s->td.dtmf.row_out[i]);
 			if (row_energy[i] > row_energy[best_row])
 				best_row = i;
-			col_energy[i] = goertzel_result (&s->col_out[i]);
+			col_energy[i] = goertzel_result (&s->td.dtmf.col_out[i]);
 			if (col_energy[i] > col_energy[best_col])
 				best_col = i;
 		}
@@ -576,17 +639,9 @@
 					break;
 				}
 			}
-#ifdef OLD_DSP_ROUTINES
-			/* ... and second harmonic test */
-			if (i >= 4 && 
-			    (row_energy[best_row] + col_energy[best_col]) > 42.0*s->energy &&
-                	    goertzel_result(&s->col_out2nd[best_col])*DTMF_2ND_HARMONIC_COL < col_energy[best_col]
-			    && goertzel_result(&s->row_out2nd[best_row])*DTMF_2ND_HARMONIC_ROW < row_energy[best_row]) {
-#else
 			/* ... and fraction of total energy test */
 			if (i >= 4 &&
-			    (row_energy[best_row] + col_energy[best_col]) > DTMF_TO_TOTAL_ENERGY*s->energy) {
-#endif
+			    (row_energy[best_row] + col_energy[best_col]) > DTMF_TO_TOTAL_ENERGY*s->td.dtmf.energy) {
 				/* Got a hit */
 				hit = dtmf_positions[(best_row << 2) + best_col];
 				if (!(digitmode & DSP_DIGITMODE_NOQUELCH)) {
@@ -595,136 +650,46 @@
 						amp[i] = 0;
 					*writeback = 1;
 				}
-#ifdef OLD_DSP_ROUTINES
-				/* Look for two successive similar results */
-				/* The logic in the next test is:
-				   We need two successive identical clean detects, with
-				   something different preceeding it. This can work with
-				   back to back differing digits. More importantly, it
-				   can work with nasty phones that give a very wobbly start
-				   to a digit */
-				if (hit == s->hit3  &&  s->hit3 != s->hit2) {
-					s->mhit = hit;
-					s->digit_hits[(best_row << 2) + best_col]++;
-					s->detected_digits++;
-					if (s->current_digits < MAX_DTMF_DIGITS) {
-						s->digits[s->current_digits++] = hit;
-						s->digits[s->current_digits] = '\0';
-					} else {
-						s->lost_digits++;
-					}
-				}
-#endif
 			}
 		} 
 
-#ifndef OLD_DSP_ROUTINES
-		/* Look for two successive similar results */
 		/* The logic in the next test is:
-		   We need two successive identical clean detects, with
+		   For digits we need two successive identical clean detects, with
 		   something different preceeding it. This can work with
 		   back to back differing digits. More importantly, it
 		   can work with nasty phones that give a very wobbly start
 		   to a digit */
-		if (hit == s->lasthit  &&  hit != s->mhit) {
-			if (hit) {
-				s->digit_hits[(best_row << 2) + best_col]++;
-				s->detected_digits++;
-				if (s->current_digits < MAX_DTMF_DIGITS) {
-					s->digits[s->current_digits++] = hit;
-					s->digits[s->current_digits] = '\0';
-				} else {
-					s->lost_digits++;
-				}
+		if (hit != s->td.dtmf.current_hit) {
+			if (hit && s->td.dtmf.lasthit == hit) {
+				s->td.dtmf.current_hit = hit;
+				store_digit(s, hit);
+			} else if (s->td.dtmf.lasthit != s->td.dtmf.current_hit) {
+				s->td.dtmf.current_hit = 0;
 			}
-			s->mhit = hit;
 		}
-#endif
+		s->td.dtmf.lasthit = hit;
 
-#ifdef FAX_DETECT
-		if (!hit && (fax_energy >= FAX_THRESHOLD) && 
-			(fax_energy >= DTMF_TO_TOTAL_ENERGY*s->energy) &&
-			(faxdetect)) {
-#if 0
-			printf("Fax energy/Second Harmonic: %f\n", fax_energy);
-#endif					
-			/* XXX Probably need better checking than just this the energy XXX */
-			hit = 'f';
-			s->fax_hits++;
-		} else {
-			if (s->fax_hits > 5) {
-				hit = 'f';
-				s->mhit = 'f';
-				s->detected_digits++;
-				if (s->current_digits < MAX_DTMF_DIGITS) {
-					s->digits[s->current_digits++] = hit;
-					s->digits[s->current_digits] = '\0';
-				} else {
-					s->lost_digits++;
-				}
-			}
-			s->fax_hits = 0;
-		}
-#endif /* FAX_DETECT */
-#ifdef OLD_DSP_ROUTINES
-		s->hit1 = s->hit2;
-		s->hit2 = s->hit3;
-		s->hit3 = hit;
-#else
-		s->lasthit = hit;
-#endif		
 		/* Reinitialise the detector for the next block */
 		for (i = 0;  i < 4;  i++) {
-			goertzel_reset(&s->row_out[i]);
-			goertzel_reset(&s->col_out[i]);
-#ifdef OLD_DSP_ROUTINES
-			goertzel_reset(&s->row_out2nd[i]);
-			goertzel_reset(&s->col_out2nd[i]);
-#endif			
-		}
-#ifdef FAX_DETECT
-		goertzel_reset (&s->fax_tone);
-#ifdef OLD_DSP_ROUTINES
-		goertzel_reset (&s->fax_tone2nd);
-#endif			
-#endif
-		s->energy = 0.0;
-		s->current_sample = 0;
-	}
-#ifdef OLD_DSP_ROUTINES
-	if ((!s->mhit) || (s->mhit != hit)) {
-		s->mhit = 0;
-		return(0);
+			goertzel_reset(&s->td.dtmf.row_out[i]);
+			goertzel_reset(&s->td.dtmf.col_out[i]);
+		}
+		s->td.dtmf.energy = 0.0;
+		s->td.dtmf.current_sample = 0;
 	}
-	return (hit);
-#else
-	return (s->mhit);	/* return the debounced hit */
-#endif
+	return (s->td.dtmf.current_hit);	/* return the debounced hit */
 }
 
 /* MF goertzel size */
-#ifdef OLD_DSP_ROUTINES
-#define	MF_GSIZE 160
-#else
 #define MF_GSIZE 120
-#endif
 
-static int mf_detect (mf_detect_state_t *s, int16_t amp[],
-                 int samples, int digitmode, int *writeback)
+static int mf_detect(digit_detect_state_t *s, int16_t amp[],
+	int samples, int digitmode, int *writeback)
 {
-#ifdef OLD_DSP_ROUTINES
-	float tone_energy[6];
-	int best1;
-	int best2;
-	float max;
-	int sofarsogood;
-#else
 	float energy[6];
 	int best;
 	int second_best;
-#endif
 	float famp;
-	float v1;
 	int i;
 	int j;
 	int sample;
@@ -734,71 +699,25 @@
 	hit = 0;
 	for (sample = 0;  sample < samples;  sample = limit) {
 		/* 80 is optimised to meet the MF specs. */
-		if ((samples - sample) >= (MF_GSIZE - s->current_sample))
-			limit = sample + (MF_GSIZE - s->current_sample);
+		if ((samples - sample) >= (MF_GSIZE - s->td.mf.current_sample))
+			limit = sample + (MF_GSIZE - s->td.mf.current_sample);
 		else
 			limit = samples;
-#if defined(USE_3DNOW)
-		_dtmf_goertzel_update (s->row_out, amp + sample, limit - sample);
-		_dtmf_goertzel_update (s->col_out, amp + sample, limit - sample);
-#ifdef OLD_DSP_ROUTINES
-		_dtmf_goertzel_update (s->row_out2nd, amp + sample, limit2 - sample);
-		_dtmf_goertzel_update (s->col_out2nd, amp + sample, limit2 - sample);
-#endif
-		/* XXX Need to fax detect for 3dnow too XXX */
-		#warning "Fax Support Broken"
-#else
 		/* The following unrolled loop takes only 35% (rough estimate) of the 
 		   time of a rolled loop on the machine on which it was developed */
 		for (j = sample;  j < limit;  j++) {
 			famp = amp[j];
-#ifdef OLD_DSP_ROUTINES
-			s->energy += famp*famp;
-#endif
 			/* With GCC 2.95, the following unrolled code seems to take about 35%
 			   (rough estimate) as long as a neat little 0-3 loop */
-			v1 = s->tone_out[0].v2;
-			s->tone_out[0].v2 = s->tone_out[0].v3;
-			s->tone_out[0].v3 = s->tone_out[0].fac*s->tone_out[0].v2 - v1 + famp;
-			v1 = s->tone_out[1].v2;
-			s->tone_out[1].v2 = s->tone_out[1].v3;
-			s->tone_out[1].v3 = s->tone_out[1].fac*s->tone_out[1].v2 - v1 + famp;
-			v1 = s->tone_out[2].v2;
-			s->tone_out[2].v2 = s->tone_out[2].v3;
-			s->tone_out[2].v3 = s->tone_out[2].fac*s->tone_out[2].v2 - v1 + famp;
-			v1 = s->tone_out[3].v2;
-			s->tone_out[3].v2 = s->tone_out[3].v3;
-			s->tone_out[3].v3 = s->tone_out[3].fac*s->tone_out[3].v2 - v1 + famp;
-			v1 = s->tone_out[4].v2;
-			s->tone_out[4].v2 = s->tone_out[4].v3;
-			s->tone_out[4].v3 = s->tone_out[4].fac*s->tone_out[4].v2 - v1 + famp;
-			v1 = s->tone_out[5].v2;
-			s->tone_out[5].v2 = s->tone_out[5].v3;
-			s->tone_out[5].v3 = s->tone_out[5].fac*s->tone_out[5].v2 - v1 + famp;
-#ifdef OLD_DSP_ROUTINES
-			v1 = s->tone_out2nd[0].v2;
-			s->tone_out2nd[0].v2 = s->tone_out2nd[0].v3;
-			s->tone_out2nd[0].v3 = s->tone_out2nd[0].fac*s->tone_out2nd[0].v2 - v1 + famp;
-			v1 = s->tone_out2nd[1].v2;
-			s->tone_out2nd[1].v2 = s->tone_out2nd[1].v3;
-			s->tone_out2nd[1].v3 = s->tone_out2nd[1].fac*s->tone_out2nd[1].v2 - v1 + famp;
-			v1 = s->tone_out2nd[2].v2;
-			s->tone_out2nd[2].v2 = s->tone_out2nd[2].v3;
-			s->tone_out2nd[2].v3 = s->tone_out2nd[2].fac*s->tone_out2nd[2].v2 - v1 + famp;
-			v1 = s->tone_out2nd[3].v2;
-			s->tone_out2nd[3].v2 = s->tone_out2nd[3].v3;
-			s->tone_out2nd[3].v3 = s->tone_out2nd[3].fac*s->tone_out2nd[3].v2 - v1 + famp;
-			v1 = s->tone_out2nd[4].v2;
-			s->tone_out2nd[4].v2 = s->tone_out2nd[4].v3;
-			s->tone_out2nd[4].v3 = s->tone_out2nd[4].fac*s->tone_out2nd[2].v2 - v1 + famp;
-			v1 = s->tone_out2nd[3].v2;
-			s->tone_out2nd[5].v2 = s->tone_out2nd[6].v3;
-			s->tone_out2nd[5].v3 = s->tone_out2nd[6].fac*s->tone_out2nd[3].v2 - v1 + famp;
-#endif
+			goertzel_sample(s->td.mf.tone_out, amp[j]);
+			goertzel_sample(s->td.mf.tone_out + 1, amp[j]);
+			goertzel_sample(s->td.mf.tone_out + 2, amp[j]);
+			goertzel_sample(s->td.mf.tone_out + 3, amp[j]);
+			goertzel_sample(s->td.mf.tone_out + 4, amp[j]);
+			goertzel_sample(s->td.mf.tone_out + 5, amp[j]);
 		}
-#endif
-		s->current_sample += (limit - sample);
-		if (s->current_sample < MF_GSIZE) {
+		s->td.mf.current_sample += (limit - sample);
+		if (s->td.mf.current_sample < MF_GSIZE) {
 			if (hit && !((digitmode & DSP_DIGITMODE_NOQUELCH))) {
 				/* If we had a hit last time, go ahead and clear this out since likely it
 				   will be another hit */
@@ -808,99 +727,6 @@
 			}
 			continue;
 		}
-#ifdef OLD_DSP_ROUTINES		
-		/* We're at the end of an MF detection block.  Go ahead and calculate
-		   all the energies. */
-		for (i=0;i<6;i++) {
-			tone_energy[i] = goertzel_result(&s->tone_out[i]);
-		}
-		/* Find highest */
-		best1 = 0;
-		max = tone_energy[0];
-		for (i=1;i<6;i++) {
-			if (tone_energy[i] > max) {
-				max = tone_energy[i];
-				best1 = i;
-			}
-		}
-
-		/* Find 2nd highest */
-		if (best1) {
-			max = tone_energy[0];
-			best2 = 0;
-		} else {
-			max = tone_energy[1];
-			best2 = 1;
-		}
-
-		for (i=0;i<6;i++) {
-			if (i == best1) continue;
-			if (tone_energy[i] > max) {
-				max = tone_energy[i];
-				best2 = i;
-			}
-		}
-		hit = 0;
-		if (best1 != best2) 
-			sofarsogood=1;
-		else 
-			sofarsogood=0;
-		/* Check for relative energies */
-		for (i=0;i<6;i++) {
-			if (i == best1) 
-				continue;
-			if (i == best2) 
-				continue;
-			if (tone_energy[best1] < tone_energy[i] * MF_RELATIVE_PEAK) {
-				sofarsogood = 0;
-				break;
-			}
-			if (tone_energy[best2] < tone_energy[i] * MF_RELATIVE_PEAK) {
-				sofarsogood = 0;
-				break;
-			}
-		}
-		
-		if (sofarsogood) {
-			/* Check for 2nd harmonic */
-			if (goertzel_result(&s->tone_out2nd[best1]) * MF_2ND_HARMONIC > tone_energy[best1]) 
-				sofarsogood = 0;
-			else if (goertzel_result(&s->tone_out2nd[best2]) * MF_2ND_HARMONIC > tone_energy[best2])
-				sofarsogood = 0;
-		}
-		if (sofarsogood) {
-			hit = mf_hit[best1][best2];
-			if (!(digitmode & DSP_DIGITMODE_NOQUELCH)) {
-				/* Zero out frame data if this is part DTMF */
-				for (i=sample;i<limit;i++) 
-					amp[i] = 0;
-				*writeback = 1;
-			}
-			/* Look for two consecutive clean hits */
-			if ((hit == s->hit3) && (s->hit3 != s->hit2)) {
-				s->mhit = hit;
-				s->detected_digits++;
-				if (s->current_digits < MAX_DTMF_DIGITS - 2) {
-					s->digits[s->current_digits++] = hit;
-					s->digits[s->current_digits] = '\0';
-				} else {
-					s->lost_digits++;
-				}
-			}
-		}
-		
-		s->hit1 = s->hit2;
-		s->hit2 = s->hit3;
-		s->hit3 = hit;
-		/* Reinitialise the detector for the next block */
-		for (i = 0;  i < 6;  i++) {
-			goertzel_reset(&s->tone_out[i]);
-			goertzel_reset(&s->tone_out2nd[i]);
-		}
-		s->energy = 0.0;
-		s->current_sample = 0;
-	}
-#else
 		/* We're at the end of an MF detection block.  */
 		/* Find the two highest energies. The spec says to look for
 		   two tones and two tones only. Taking this literally -ie
@@ -908,8 +734,8 @@
 		   well. The sinc function mess, due to rectangular windowing
 		   ensure that! Find the two highest energies and ensure they
 		   are considerably stronger than any of the others. */
-		energy[0] = goertzel_result(&s->tone_out[0]);
-		energy[1] = goertzel_result(&s->tone_out[1]);
+		energy[0] = goertzel_result(&s->td.mf.tone_out[0]);
+		energy[1] = goertzel_result(&s->td.mf.tone_out[1]);
 		if (energy[0] > energy[1]) {
 			best = 0;
 			second_best = 1;
@@ -919,7 +745,7 @@
 		}
 		/*endif*/
 		for (i=2;i<6;i++) {
-			energy[i] = goertzel_result(&s->tone_out[i]);
+			energy[i] = goertzel_result(&s->td.mf.tone_out[i]);
 			if (energy[i] >= energy[best]) {
 				second_best = best;
 				best = i;
@@ -959,47 +785,57 @@
 			   two blocks of something different preceeding it. For anything
 			   else we need two successive identical clean detects, with
 			   two blocks of something different preceeding it. */
-			if (hit == s->hits[4] && hit == s->hits[3] &&
-			   ((hit != '*' && hit != s->hits[2] && hit != s->hits[1])||
-			    (hit == '*' && hit == s->hits[2] && hit != s->hits[1] && 
-			    hit != s->hits[0]))) {
-				s->detected_digits++;
-				if (s->current_digits < MAX_DTMF_DIGITS) {
-					s->digits[s->current_digits++] = hit;
-					s->digits[s->current_digits] = '\0';
-				} else {
-					s->lost_digits++;
-				}
+			if (hit == s->td.mf.hits[4] && hit == s->td.mf.hits[3] &&
+			   ((hit != '*' && hit != s->td.mf.hits[2] && hit != s->td.mf.hits[1])||
+			    (hit == '*' && hit == s->td.mf.hits[2] && hit != s->td.mf.hits[1] && 
+			    hit != s->td.mf.hits[0]))) {
+				store_digit(s, hit);
 			}
-		} else {
-			hit = 0;
 		}
-		s->hits[0] = s->hits[1];
-		s->hits[1] = s->hits[2];
-		s->hits[2] = s->hits[3];
-		s->hits[3] = s->hits[4];
-		s->hits[4] = hit;
+
+
+		if (hit != s->td.mf.hits[4] && hit != s->td.mf.hits[3]) {
+			/* Two successive block without a hit terminate current digit */
+			s->td.mf.current_hit = 0;
+		}
+
+		s->td.mf.hits[0] = s->td.mf.hits[1];
+		s->td.mf.hits[1] = s->td.mf.hits[2];
+		s->td.mf.hits[2] = s->td.mf.hits[3];
+		s->td.mf.hits[3] = s->td.mf.hits[4];
+		s->td.mf.hits[4] = hit;
 		/* Reinitialise the detector for the next block */
 		for (i = 0;  i < 6;  i++)
-			goertzel_reset(&s->tone_out[i]);
-		s->current_sample = 0;
+			goertzel_reset(&s->td.mf.tone_out[i]);
+		s->td.mf.current_sample = 0;
 	}
-#endif	
-	if ((!s->mhit) || (s->mhit != hit)) {
-		s->mhit = 0;
-		return(0);
-	}
-	return (hit);
+
+	return (s->td.mf.current_hit); /* return the debounced hit */
 }
 
 static int __ast_dsp_digitdetect(struct ast_dsp *dsp, short *s, int len, int *writeback)
 {
-	int res;
+	int res = 0;
 	
-	if (dsp->digitmode & DSP_DIGITMODE_MF)
-		res = mf_detect(&dsp->td.mf, s, len, dsp->digitmode & DSP_DIGITMODE_RELAXDTMF, writeback);
-	else
-		res = dtmf_detect(&dsp->td.dtmf, s, len, dsp->digitmode & DSP_DIGITMODE_RELAXDTMF, writeback, dsp->features & DSP_FEATURE_FAX_DETECT);
+	if ((dsp->features & DSP_FEATURE_DTMF_DETECT) && (dsp->digitmode & DSP_DIGITMODE_MF))
+		res = mf_detect(&dsp->digit_state, s, len, dsp->digitmode & DSP_DIGITMODE_RELAXDTMF, writeback);
+	else if (dsp->features & DSP_FEATURE_DTMF_DETECT)
+		res = dtmf_detect(&dsp->digit_state, s, len, dsp->digitmode & DSP_DIGITMODE_RELAXDTMF, writeback);
+
+	if ((dsp->features & DSP_FEATURE_FAX_DETECT) && (dsp->faxmode & DSP_FAXMODE_DETECT_CNG)) {
+		if (tone_detect(&dsp->cng_tone_state, s, len, NULL)) {
+			store_digit(&dsp->digit_state, 'f');
+			res = 'f';
+		}
+	}
+
+	if ((dsp->features & DSP_FEATURE_FAX_DETECT) && (dsp->faxmode & DSP_FAXMODE_DETECT_CED)) {
+		if (tone_detect(&dsp->ced_tone_state, s, len, NULL)) {
+			store_digit(&dsp->digit_state, 'e');
+			res = 'e';
+		}
+	}
+
 	return res;
 }
 
@@ -1042,29 +878,17 @@
 	return 1;
 }
 
-int ast_dsp_getdigits (struct ast_dsp *dsp, char *buf, int max)
+int ast_dsp_getdigits(struct ast_dsp *dsp, char *buf, int max)
 {
-	if (dsp->digitmode & DSP_DIGITMODE_MF) {
-		if (max > dsp->td.mf.current_digits)
-			max = dsp->td.mf.current_digits;
-		if (max > 0) {
-			memcpy(buf, dsp->td.mf.digits, max);
-			memmove(dsp->td.mf.digits, dsp->td.mf.digits + max, dsp->td.mf.current_digits - max);
-			dsp->td.mf.current_digits -= max;
-		}
-		buf[max] = '\0';
-		return  max;
-	} else {
-		if (max > dsp->td.dtmf.current_digits)
-			max = dsp->td.dtmf.current_digits;
-		if (max > 0) {
-			memcpy (buf, dsp->td.dtmf.digits, max);
-			memmove (dsp->td.dtmf.digits, dsp->td.dtmf.digits + max, dsp->td.dtmf.current_digits - max);
-			dsp->td.dtmf.current_digits -= max;
-		}
-		buf[max] = '\0';
-		return  max;
+	if (max > dsp->digit_state.current_digits)
+		max = dsp->digit_state.current_digits;
+	if (max > 0) {
+		memcpy(buf, dsp->digit_state.digits, max);
+		memmove(dsp->digit_state.digits, dsp->digit_state.digits + max, dsp->digit_state.current_digits - max);
+		dsp->digit_state.current_digits -= max;
 	}
+	buf[max] = '\0';
+	return  max;
 }
 
 static int __ast_dsp_call_progress(struct ast_dsp *dsp, short *s, int len)
@@ -1074,7 +898,7 @@
 	int pass;
 	int newstate = DSP_TONE_STATE_SILENCE;
 	int res = 0;
-	while(len) {
+	while (len) {
 		/* Take the lesser of the number of samples we need and what we have */
 		pass = len;
 		if (pass > dsp->gsamp_size - dsp->gsamps) 
@@ -1091,12 +915,7 @@
 			float hz[7];
 			for (y=0;y<7;y++)
 				hz[y] = goertzel_result(&dsp->freqs[y]);
-#if 0
-			printf("\n350:     425:     440:     480:     620:     950:     1400:    1800:    Energy:   \n");
-			printf("%.2e %.2e %.2e %.2e %.2e %.2e %.2e %.2e %.2e\n", 
-				hz[HZ_350], hz[HZ_425], hz[HZ_440], hz[HZ_480], hz[HZ_620], hz[HZ_950], hz[HZ_1400], hz[HZ_1800], dsp->genergy);
-#endif
-			switch(dsp->progmode) {
+			switch (dsp->progmode) {
 			case PROG_MODE_NA:
 				if (pair_there(hz[HZ_480], hz[HZ_620], hz[HZ_350], hz[HZ_440], dsp->genergy)) {
 					newstate = DSP_TONE_STATE_BUSY;
@@ -1175,17 +994,13 @@
 						break;
 				}
 				if (dsp->ringtimeout==THRESH_RING2ANSWER) {
-#if 0
-					ast_log(LOG_NOTICE, "Consider call as answered because of timeout after last ring\n");
-#endif
+					ast_log(LOG_DEBUG, "Consider call as answered because of timeout after last ring\n");
 					res = AST_CONTROL_ANSWER;
 					dsp->features &= ~DSP_FEATURE_CALL_PROGRESS;
 				}
 			} else {
-#if 0
-				ast_log(LOG_NOTICE, "Stop state %d with duration %d\n", dsp->tstate, dsp->tcount);
-				ast_log(LOG_NOTICE, "Start state %d\n", newstate);
-#endif
+				ast_log(LOG_DEBUG, "Stop state %d with duration %d\n", dsp->tstate, dsp->tcount);
+				ast_log(LOG_DEBUG, "Start state %d\n", newstate);
 				dsp->tstate = newstate;
 				dsp->tcount = 1;
 			}
@@ -1197,10 +1012,7 @@
 			dsp->genergy = 0.0;
 		}
 	}
-#if 0
-	if (res)
-		printf("Returning %d\n", res);
-#endif		
+
 	return res;
 }
 
@@ -1272,7 +1084,6 @@
 	return res;
 }
 
-#ifdef BUSYDETECT_MARTIN
 int ast_dsp_busydetect(struct ast_dsp *dsp)
 {
 	int res = 0, x;
@@ -1318,9 +1129,6 @@
 	if ((hittone >= dsp->busycount - 1) && (avgtone >= BUSY_MIN && avgtone <= BUSY_MAX)) {
 #endif
 #ifdef BUSYDETECT_COMPARE_TONE_AND_SILENCE
-#ifdef BUSYDETECT_TONEONLY
-#error You cant use BUSYDETECT_TONEONLY together with BUSYDETECT_COMPARE_TONE_AND_SILENCE
-#endif
 		if (avgtone > avgsilence) {
 			if (avgtone - avgtone*BUSY_PERCENT/100 <= avgsilence)
 				res = 1;
@@ -1335,9 +1143,9 @@
 	/* If we know the expected busy tone length, check we are in the range */
 	if (res && (dsp->busy_tonelength > 0)) {
 		if (abs(avgtone - dsp->busy_tonelength) > (dsp->busy_tonelength*BUSY_PAT_PERCENT/100)) {
-#if 0
-			ast_log(LOG_NOTICE, "busy detector: avgtone of %d not close enough to desired %d\n",
-						avgtone, dsp->busy_tonelength);
+#ifdef BUSYDETECT_DEBUG
+			ast_log(LOG_DEBUG, "busy detector: avgtone of %d not close enough to desired %d\n",
+				avgtone, dsp->busy_tonelength);
 #endif
 			res = 0;
 		}
@@ -1346,68 +1154,23 @@
 	/* If we know the expected busy tone silent-period length, check we are in the range */
 	if (res && (dsp->busy_quietlength > 0)) {
 		if (abs(avgsilence - dsp->busy_quietlength) > (dsp->busy_quietlength*BUSY_PAT_PERCENT/100)) {
-#if 0
-			ast_log(LOG_NOTICE, "busy detector: avgsilence of %d not close enough to desired %d\n",
-						avgsilence, dsp->busy_quietlength);
+#ifdef BUSYDETECT_DEBUG
+		ast_log(LOG_DEBUG, "busy detector: avgsilence of %d not close enough to desired %d\n",
+			avgsilence, dsp->busy_quietlength);
 #endif
 			res = 0;
 		}
 	}
 #endif
-#ifndef BUSYDETECT_TONEONLY
-#if 1
-	if (res)
+#if !defined(BUSYDETECT_TONEONLY) && defined(BUSYDETECT_DEBUG)
+	if (res) {
 		ast_log(LOG_DEBUG, "ast_dsp_busydetect detected busy, avgtone: %d, avgsilence %d\n", avgtone, avgsilence);
-#endif
-#endif
-	return res;
-}
-#endif
-
-#ifdef BUSYDETECT
-int ast_dsp_busydetect(struct ast_dsp *dsp)
-{
-	int x;
-	int res = 0;
-	int max, min;
-
-#if 0
-	if (dsp->busy_hits > 5);
-	return 0;
-#endif
-	if (dsp->busymaybe) {
-#if 0
-		printf("Maybe busy!\n");
-#endif		
-		dsp->busymaybe = 0;
-		min = 9999;
-		max = 0;
-		for (x=DSP_HISTORY - dsp->busycount;x<DSP_HISTORY;x++) {
-#if 0
-			printf("Silence: %d, Noise: %d\n", dsp->historicsilence[x], dsp->historicnoise[x]);
-#endif			
-			if (dsp->historicsilence[x] < min)
-				min = dsp->historicsilence[x];
-			if (dsp->historicnoise[x] < min)
-				min = dsp->historicnoise[x];
-			if (dsp->historicsilence[x] > max)
-				max = dsp->historicsilence[x];
-			if (dsp->historicnoise[x] > max)
-				max = dsp->historicnoise[x];
-		}
-		if ((max - min < BUSY_THRESHOLD) && (max < BUSY_MAX) && (min > BUSY_MIN)) {
-#if 0
-			printf("Busy!\n");
-#endif			
-			res = 1;
-		}
-#if 0
-		printf("Min: %d, max: %d\n", min, max);
-#endif		
+	} else {
+		ast_log(LOG_DEBUG, "busy detector: FAILED with avgtone: %d, avgsilence %d\n", avgtone, avgsilence);
 	}
+#endif
 	return res;
 }
-#endif
 
 int ast_dsp_silence(struct ast_dsp *dsp, struct ast_frame *f, int *totalsilence)
 {
@@ -1440,7 +1203,7 @@
 
 #define FIX_INF(inf) do { \
 		if (writeback) { \
-			switch(inf->subclass) { \
+			switch (inf->subclass) { \
 			case AST_FORMAT_SLINEAR: \
 				break; \
 			case AST_FORMAT_ULAW: \
@@ -1462,7 +1225,7 @@
 	odata = af->data;
 	len = af->datalen;
 	/* Make sure we have short data */
-	switch(af->subclass) {
+	switch (af->subclass) {
 	case AST_FORMAT_SLINEAR:
 		shortdata = af->data;
 		len = af->datalen / 2;
@@ -1495,15 +1258,16 @@
 		dsp->f.frametype = AST_FRAME_CONTROL;
 		dsp->f.subclass = AST_CONTROL_BUSY;
 		ast_frfree(af);
+		ast_log(LOG_DEBUG, "Requesting Hangup because the busy tone was detected on channel %s\n", chan->name);
 		ast_set_flag(&dsp->f, AST_FRFLAG_FROM_DSP);
 		return &dsp->f;
 	}
-	if ((dsp->features & DSP_FEATURE_DTMF_DETECT)) {
+	if (((dsp->features & DSP_FEATURE_DTMF_DETECT) || (dsp->features & DSP_FEATURE_FAX_DETECT))) {
 		digit = __ast_dsp_digitdetect(dsp, shortdata, len, &writeback);
 #if 0
 		if (digit)
 			printf("Performing digit detection returned %d, digitmode is %d\n", digit, dsp->digitmode);
-#endif			
+#endif
 		if (dsp->digitmode & (DSP_DIGITMODE_MUTECONF | DSP_DIGITMODE_MUTEMAX)) {
 			if (!dsp->thinkdigit) {
 				if (digit) {
@@ -1566,43 +1330,28 @@
 					return &dsp->f;
 				}
 			}
-		} else if (!digit) {
-			/* Only check when there is *not* a hit... */
-			if (dsp->digitmode & DSP_DIGITMODE_MF) {
-				if (dsp->td.mf.current_digits) {
-					memset(&dsp->f, 0, sizeof(dsp->f));
-					dsp->f.frametype = AST_FRAME_DTMF;
-					dsp->f.subclass = dsp->td.mf.digits[0];
-					memmove(dsp->td.mf.digits, dsp->td.mf.digits + 1, dsp->td.mf.current_digits);
-					dsp->td.mf.current_digits--;
-					FIX_INF(af);
-					if (chan)
-						ast_queue_frame(chan, af);
-					ast_frfree(af);
-					ast_set_flag(&dsp->f, AST_FRFLAG_FROM_DSP);
-					return &dsp->f;
-				}
-			} else {
-				if (dsp->td.dtmf.current_digits) {
-					memset(&dsp->f, 0, sizeof(dsp->f));
-					dsp->f.frametype = AST_FRAME_DTMF_END;
-					dsp->f.subclass = dsp->td.dtmf.digits[0];
-					memmove(dsp->td.dtmf.digits, dsp->td.dtmf.digits + 1, dsp->td.dtmf.current_digits);
-					dsp->td.dtmf.current_digits--;
-					FIX_INF(af);
-					if (chan)
-						ast_queue_frame(chan, af);
-					ast_frfree(af);
-					ast_set_flag(&dsp->f, AST_FRFLAG_FROM_DSP);
-					return &dsp->f;
-				}
-			}
+		} else if (dsp->digit_state.current_digits > 1 ||
+			(dsp->digit_state.current_digits == 1 && digit != dsp->digit_state.digits[0])) {
+			/* Since we basically generate DTMF_END frames we do it only when a digit
+			   has finished. */
+
+			memset(&dsp->f, 0, sizeof(dsp->f));
+			dsp->f.frametype = AST_FRAME_DTMF;
+			dsp->f.subclass = dsp->digit_state.digits[0];
+			memmove(dsp->digit_state.digits, dsp->digit_state.digits + 1, dsp->digit_state.current_digits);
+			dsp->digit_state.current_digits--;
+			FIX_INF(af);
+			if (chan)
+				ast_queue_frame(chan, af);
+			ast_frfree(af);
+			ast_set_flag(&dsp->f, AST_FRFLAG_FROM_DSP);
+			return &dsp->f;
 		}
 	}
 	if ((dsp->features & DSP_FEATURE_CALL_PROGRESS)) {
 		res = __ast_dsp_call_progress(dsp, shortdata, len);
 		if (res) {
-			switch(res) {
+			switch (res) {
 			case AST_CONTROL_ANSWER:
 			case AST_CONTROL_BUSY:
 			case AST_CONTROL_RINGING:
@@ -1631,7 +1380,7 @@
 	
 	dsp->gsamp_size = modes[dsp->progmode].size;
 	dsp->gsamps = 0;
-	for (x=0;x<sizeof(modes[dsp->progmode].freqs) / sizeof(modes[dsp->progmode].freqs[0]);x++) {
+	for (x = 0; x < sizeof(modes[dsp->progmode].freqs) / sizeof(modes[dsp->progmode].freqs[0]); x++) {
 		if (modes[dsp->progmode].freqs[x]) {
 			goertzel_init(&dsp->freqs[x], (float)modes[dsp->progmode].freqs[x], dsp->gsamp_size);
 			max = x + 1;
@@ -1649,10 +1398,14 @@
 		dsp->threshold = DEFAULT_THRESHOLD;
 		dsp->features = DSP_FEATURE_SILENCE_SUPPRESS;
 		dsp->busycount = DSP_HISTORY;
-		/* Initialize DTMF detector */
-		ast_dtmf_detect_init(&dsp->td.dtmf);
+		dsp->digitmode = DSP_DIGITMODE_DTMF;
+		dsp->faxmode = DSP_FAXMODE_DETECT_CNG;
+		/* Initialize digit detector */
+		ast_digit_detect_init(&dsp->digit_state, dsp->digitmode & DSP_DIGITMODE_MF);
 		/* Initialize initial DSP progress detect parameters */
 		ast_dsp_prog_reset(dsp);
+		/* Initialize fax detector */
+		ast_fax_detect_init(dsp);
 	}
 	return dsp;
 }
@@ -1670,12 +1423,12 @@
 		 * When ast_frfree() gets called on that frame, this ast_trans_pvt
 		 * will get destroyed, too. */
 
-		/* Set the magic hint that this has been requested to be destroyed. */
+		/* Set the magic flag to destroy the dsp when the frame is freed */
 		dsp->freqcount = -1;
 
 		return;
 	}
-	free(dsp);
+	ast_free(dsp);
 }
 
 void ast_dsp_set_threshold(struct ast_dsp *dsp, int threshold)
@@ -1705,48 +1458,27 @@
 	
 	dsp->thinkdigit = 0;
 	if (dsp->digitmode & DSP_DIGITMODE_MF) {
-		memset(dsp->td.mf.digits, 0, sizeof(dsp->td.mf.digits));
-		dsp->td.mf.current_digits = 0;
+		mf_detect_state_t *s = &dsp->digit_state.td.mf;
 		/* Reinitialise the detector for the next block */
 		for (i = 0;  i < 6;  i++) {
-			goertzel_reset(&dsp->td.mf.tone_out[i]);
-#ifdef OLD_DSP_ROUTINES
-			goertzel_reset(&dsp->td.mf.tone_out2nd[i]);
-#endif			
-		}
-#ifdef OLD_DSP_ROUTINES
-		dsp->td.mf.energy = 0.0;
-		dsp->td.mf.hit1 = dsp->td.mf.hit2 = dsp->td.mf.hit3 = dsp->td.mf.hit4 = dsp->td.mf.mhit = 0;
-#else
-		dsp->td.mf.hits[4] = dsp->td.mf.hits[3] = dsp->td.mf.hits[2] = dsp->td.mf.hits[1] = dsp->td.mf.hits[0] = dsp->td.mf.mhit = 0;
-#endif		
-		dsp->td.mf.current_sample = 0;
+			goertzel_reset(&s->tone_out[i]);
+		}
+		s->hits[4] = s->hits[3] = s->hits[2] = s->hits[1] = s->hits[0] = s->current_hit = 0;
+		s->current_sample = 0;
 	} else {
-		memset(dsp->td.dtmf.digits, 0, sizeof(dsp->td.dtmf.digits));
-		dsp->td.dtmf.current_digits = 0;
+		dtmf_detect_state_t *s = &dsp->digit_state.td.dtmf;
 		/* Reinitialise the detector for the next block */
 		for (i = 0;  i < 4;  i++) {
-			goertzel_reset(&dsp->td.dtmf.row_out[i]);
-			goertzel_reset(&dsp->td.dtmf.col_out[i]);
-#ifdef OLD_DSP_ROUTINES
-			goertzel_reset(&dsp->td.dtmf.row_out2nd[i]);
-			goertzel_reset(&dsp->td.dtmf.col_out2nd[i]);
-#endif			
+			goertzel_reset(&s->row_out[i]);
+			goertzel_reset(&s->col_out[i]);
 		}
-#ifdef FAX_DETECT
-		goertzel_reset (&dsp->td.dtmf.fax_tone);
-#endif
-#ifdef OLD_DSP_ROUTINES
-#ifdef FAX_DETECT
-		goertzel_reset (&dsp->td.dtmf.fax_tone2nd);
-#endif
-		dsp->td.dtmf.hit1 = dsp->td.dtmf.hit2 = dsp->td.dtmf.hit3 = dsp->td.dtmf.hit4 = dsp->td.dtmf.mhit = 0;
-#else
-		dsp->td.dtmf.lasthit = dsp->td.dtmf.mhit = 0;
-#endif		
-		dsp->td.dtmf.energy = 0.0;
-		dsp->td.dtmf.current_sample = 0;
+		s->lasthit = s->current_hit = 0;
+		s->energy = 0.0;
+		s->current_sample = 0;
 	}
+
+	dsp->digit_state.digits[0] = '\0';
+	dsp->digit_state.current_digits = 0;
 }
 
 void ast_dsp_reset(struct ast_dsp *dsp)
@@ -1771,20 +1503,26 @@
 	new = digitmode & (DSP_DIGITMODE_DTMF | DSP_DIGITMODE_MF | DSP_DIGITMODE_MUTECONF | DSP_DIGITMODE_MUTEMAX);
 	if (old != new) {
 		/* Must initialize structures if switching from MF to DTMF or vice-versa */
-		if (new & DSP_DIGITMODE_MF)
-			ast_mf_detect_init(&dsp->td.mf);
-		else
-			ast_dtmf_detect_init(&dsp->td.dtmf);
+		ast_digit_detect_init(&dsp->digit_state, new & DSP_DIGITMODE_MF);
 	}
 	dsp->digitmode = digitmode;
 	return 0;
 }
 
+int ast_dsp_set_faxmode(struct ast_dsp *dsp, int faxmode)
+{
+	if (dsp->faxmode != faxmode) {
+		ast_fax_detect_init(dsp);
+	}
+	dsp->faxmode = faxmode;
+	return 0;
+}
+
 int ast_dsp_set_call_progress_zone(struct ast_dsp *dsp, char *zone)
 {
 	int x;
 	
-	for (x=0;x<sizeof(aliases) / sizeof(aliases[0]);x++) {
+	for (x = 0; x < ARRAY_LEN(aliases); x++) {
 		if (!strcasecmp(aliases[x].name, zone)) {
 			dsp->progmode = aliases[x].mode;
 			ast_dsp_prog_reset(dsp);
Binary files asterisk-1.4.20.1_original/main/editline/gmon.out and asterisk-1.4.20.1_updated/main/editline/gmon.out differ
diff -ruN asterisk-1.4.20.1_original/main/frame.c asterisk-1.4.20.1_updated/main/frame.c
--- asterisk-1.4.20.1_original/main/frame.c	2008-04-17 18:50:46.000000000 +0200
+++ asterisk-1.4.20.1_updated/main/frame.c	2008-06-01 14:59:59.000000000 +0200
@@ -762,6 +762,7 @@
 	char cn[60];
 	char cp[40];
 	char cmn[40];
+	const char *message = "Unknown";
 
 	if (!name)
 		name = noname;
@@ -832,6 +833,24 @@
 		case AST_CONTROL_RADIO_UNKEY:
 			strcpy(subclass, "Unkey Radio");
 			break;
+		case AST_CONTROL_T38:
+			if (f->datalen != sizeof(enum ast_control_t38)) {
+				message = "Invalid";
+			} else {
+				enum ast_control_t38 state = *((enum ast_control_t38 *) f->data);
+				if (state == AST_T38_REQUEST_NEGOTIATE)
+					message = "Negotiation Requested";
+				else if (state == AST_T38_REQUEST_TERMINATE)
+					message = "Negotiation Request Terminated";
+				else if (state == AST_T38_NEGOTIATED)
+					message = "Negotiated";
+				else if (state == AST_T38_TERMINATED)
+					message = "Terminated";
+				else if (state == AST_T38_REFUSED)
+					message = "Refused";
+			}
+			snprintf(subclass, sizeof(subclass), "T38/%s", message);
+			break;
 		case -1:
 			strcpy(subclass, "Stop generators");
 			break;
diff -ruN asterisk-1.4.20.1_original/main/netsock.c asterisk-1.4.20.1_updated/main/netsock.c
--- asterisk-1.4.20.1_original/main/netsock.c	2007-04-02 17:39:07.000000000 +0200
+++ asterisk-1.4.20.1_updated/main/netsock.c	2008-06-08 22:43:34.000000000 +0200
@@ -119,6 +119,25 @@
 	return sock;
 }
 
+int ast_netsock_set_qos(int netsocket, int tos, int cos, const char *desc)
+{
+	int res;
+	
+	if ((res = setsockopt(netsocket, IPPROTO_IP, IP_TOS, &tos, sizeof(tos))))
+		ast_log(LOG_WARNING, "Unable to set %s TOS to %d, may be you have no root privileges\n", desc, tos);
+	else if (tos)
+		ast_log(LOG_DEBUG, "Using %s TOS bits %d\n", desc, tos);
+
+#if defined(linux)								
+	if (setsockopt(netsocket, SOL_SOCKET, SO_PRIORITY, &cos, sizeof(cos)))
+		ast_log(LOG_WARNING, "Unable to set %s CoS to %d\n", desc, cos);
+	else if (cos)
+		ast_log(LOG_DEBUG, "Using %s CoS mark %d\n", desc, cos);
+#endif
+							
+	return res;
+}
+
 struct ast_netsock *ast_netsock_bindaddr(struct ast_netsock_list *list, struct io_context *ioc, struct sockaddr_in *bindaddr, int tos, ast_io_cb callback, void *data)
 {
 	int netsocket = -1;
diff -ruN asterisk-1.4.20.1_original/main/rtp.c asterisk-1.4.20.1_updated/main/rtp.c
--- asterisk-1.4.20.1_original/main/rtp.c	2008-04-22 23:14:55.000000000 +0200
+++ asterisk-1.4.20.1_updated/main/rtp.c	2008-06-01 14:43:46.000000000 +0200
@@ -2983,6 +2983,7 @@
 			if ((fr->subclass == AST_CONTROL_HOLD) ||
 			    (fr->subclass == AST_CONTROL_UNHOLD) ||
 			    (fr->subclass == AST_CONTROL_VIDUPDATE) ||
+			    (fr->subclass == AST_CONTROL_T38) ||
 			    (fr->subclass == AST_CONTROL_SRCUPDATE)) {
 				if (fr->subclass == AST_CONTROL_HOLD) {
 					/* If we someone went on hold we want the other side to reinvite back to us */
@@ -3215,6 +3216,7 @@
 			if ((fr->subclass == AST_CONTROL_HOLD) ||
 			    (fr->subclass == AST_CONTROL_UNHOLD) ||
 			    (fr->subclass == AST_CONTROL_VIDUPDATE) ||
+			    (fr->subclass == AST_CONTROL_T38) ||
 			    (fr->subclass == AST_CONTROL_SRCUPDATE)) {
 				/* If we are going on hold, then break callback mode and P2P bridging */
 				if (fr->subclass == AST_CONTROL_HOLD) {
diff -ruN asterisk-1.4.20.1_original/main/udptl.c asterisk-1.4.20.1_updated/main/udptl.c
--- asterisk-1.4.20.1_original/main/udptl.c	2008-03-11 12:04:29.000000000 +0100
+++ asterisk-1.4.20.1_updated/main/udptl.c	2008-06-25 01:08:30.000000000 +0200
@@ -8,43 +8,63 @@
  *
  * Steve Underwood <steveu@coppice.org>
  *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
  * This program is free software, distributed under the terms of
- * the GNU General Public License
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
  *
  * A license has been granted to Digium (via disclaimer) for the use of
  * this code.
  */
 
+/*! 
+ * \file 
+ *
+ * \brief UDPTL support for T.38 faxing
+ * 
+ *
+ * \author Mark Spencer <markster@digium.com>,  Steve Underwood <steveu@coppice.org>
+ * 
+ * \page T38fax_udptl T38 fax passhtrough :: UDPTL
+ *
+ * Asterisk supports T.38 fax passthrough. Asterisk will not be a client, server
+ * or any form of gateway. Currently fax passthrough is only implemented in the
+ * SIP channel for strict SIP to SIP calls. If you are using chan_local or chan_agent
+ * as a proxy channel, T.38 passthrough will not work.
+ *
+ * UDPTL is handled very much like RTP. It can be reinvited to go directly between
+ * the endpoints, without involving Asterisk in the media stream.
+ * 
+ * \b References:
+ * - chan_sip.c
+ * - udptl.c
+ */
+
+
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision: 107352 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision: 107374 $")
 
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
 #include <sys/time.h>
 #include <signal.h>
-#include <errno.h>
-#include <unistd.h>
-#include <netinet/in.h>
-#include <sys/time.h>
-#include <sys/socket.h>
-#include <arpa/inet.h>
 #include <fcntl.h>
+#include <errno.h>
 
 #include "asterisk/udptl.h"
 #include "asterisk/frame.h"
-#include "asterisk/logger.h"
-#include "asterisk/options.h"
 #include "asterisk/channel.h"
 #include "asterisk/acl.h"
-#include "asterisk/channel.h"
 #include "asterisk/config.h"
 #include "asterisk/lock.h"
 #include "asterisk/utils.h"
+#include "asterisk/netsock.h"
 #include "asterisk/cli.h"
 #include "asterisk/unaligned.h"
-#include "asterisk/utils.h"
 
 #define UDPTL_MTU		1200
 
@@ -57,8 +77,8 @@
 
 static int udptlstart;
 static int udptlend;
-static int udptldebug;	                  /* Are we debugging? */
-static struct sockaddr_in udptldebugaddr;   /* Debug packets to/from this host */
+static int udptldebug;	                    /*!< Are we debugging? */
+static struct sockaddr_in udptldebugaddr;   /*!< Debug packets to/from this host */
 #ifdef SO_NO_CHECK
 static int nochecksums;
 #endif
@@ -87,6 +107,7 @@
 	int fec_entries;
 } udptl_fec_rx_buffer_t;
 
+/*! \brief Structure for an UDPTL session */
 struct ast_udptl {
 	int fd;
 	char resp;
@@ -136,7 +157,7 @@
 	udptl_fec_rx_buffer_t rx[UDPTL_BUF_MASK + 1];
 };
 
-static struct ast_udptl_protocol *protos;
+static AST_RWLIST_HEAD_STATIC(protos, ast_udptl_protocol);
 
 static int udptl_rx_packet(struct ast_udptl *s, uint8_t *buf, int len);
 static int udptl_build_packet(struct ast_udptl *s, uint8_t *buf, uint8_t *ifp, int ifp_len);
@@ -658,15 +679,19 @@
 	}
 
 	if (udptl_debug_test_addr(&sin)) {
-		ast_verbose("Got UDPTL packet from %s:%d (type %d, seq %d, len %d)\n",
-			ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port), 0, seqno, res);
+		ast_log(LOG_DEBUG, "Got UDPTL packet from %s:%d (type %d, seq %d, len %d)\n",
+				ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port), 0, seqno, res);
 	}
 #if 0
 	printf("Got UDPTL packet from %s:%d (seq %d, len = %d)\n", ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port), seqno, res);
 #endif
-	if (udptl_rx_packet(udptl, udptl->rawdata + AST_FRIENDLY_OFFSET, res) < 1)
+	int ret = udptl_rx_packet(udptl, udptl->rawdata + AST_FRIENDLY_OFFSET, res);
+	ast_log(LOG_DEBUG, "udptl read - udptl_rx_packet ret %d \n", ret);
+	
+	if ( ret < 1)
+	{
 		return &ast_null_frame;
-
+	}
 	return &udptl->f[0];
 }
 
@@ -778,7 +803,7 @@
 	udptl->us.sin_family = AF_INET;
 
 	if ((udptl->fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
-		free(udptl);
+		ast_free(udptl);
 		ast_log(LOG_WARNING, "Unable to allocate socket: %s\n", strerror(errno));
 		return NULL;
 	}
@@ -799,7 +824,7 @@
 		if (errno != EADDRINUSE) {
 			ast_log(LOG_WARNING, "Unexpected bind error: %s\n", strerror(errno));
 			close(udptl->fd);
-			free(udptl);
+			ast_free(udptl);
 			return NULL;
 		}
 		if (++x > udptlend)
@@ -807,7 +832,7 @@
 		if (x == startplace) {
 			ast_log(LOG_WARNING, "No UDPTL ports remaining\n");
 			close(udptl->fd);
-			free(udptl);
+			ast_free(udptl);
 			return NULL;
 		}
 	}
@@ -836,6 +861,11 @@
 	return res;
 }
 
+int ast_udptl_setqos(struct ast_udptl *udptl, int tos, int cos)
+{
+	return ast_netsock_set_qos(udptl->fd, tos, cos, "UDPTL");
+}
+
 void ast_udptl_set_peer(struct ast_udptl *udptl, struct sockaddr_in *them)
 {
 	udptl->them.sin_port = them->sin_port;
@@ -867,7 +897,7 @@
 		ast_io_remove(udptl->io, udptl->ioid);
 	if (udptl->fd > -1)
 		close(udptl->fd);
-	free(udptl);
+	ast_free(udptl);
 }
 
 int ast_udptl_write(struct ast_udptl *s, struct ast_frame *f)
@@ -903,7 +933,7 @@
 		printf("Sent %d bytes of UDPTL data to %s:%d\n", res, ast_inet_ntoa(udptl->them.sin_addr), ntohs(udptl->them.sin_port));
 #endif
 		if (udptl_debug_test_addr(&s->them))
-			ast_verbose("Sent UDPTL packet to %s:%d (type %d, seq %d, len %d)\n",
+			ast_log(LOG_DEBUG, "Sent UDPTL packet to %s:%d (type %d, seq %d, len %d)\n",
 					ast_inet_ntoa(s->them.sin_addr),
 					ntohs(s->them.sin_port), 0, seq, len);
 	}
@@ -913,52 +943,40 @@
 
 void ast_udptl_proto_unregister(struct ast_udptl_protocol *proto)
 {
-	struct ast_udptl_protocol *cur;
-	struct ast_udptl_protocol *prev;
-
-	cur = protos;
-	prev = NULL;
-	while (cur) {
-		if (cur == proto) {
-			if (prev)
-				prev->next = proto->next;
-			else
-				protos = proto->next;
-			return;
-		}
-		prev = cur;
-		cur = cur->next;
-	}
+	AST_RWLIST_WRLOCK(&protos);
+	AST_RWLIST_REMOVE(&protos, proto, list);
+	AST_RWLIST_UNLOCK(&protos);
 }
 
 int ast_udptl_proto_register(struct ast_udptl_protocol *proto)
 {
 	struct ast_udptl_protocol *cur;
 
-	cur = protos;
-	while (cur) {
+	AST_RWLIST_WRLOCK(&protos);
+	AST_RWLIST_TRAVERSE(&protos, cur, list) {
 		if (cur->type == proto->type) {
 			ast_log(LOG_WARNING, "Tried to register same protocol '%s' twice\n", cur->type);
+			AST_RWLIST_UNLOCK(&protos);
 			return -1;
 		}
-		cur = cur->next;
 	}
-	proto->next = protos;
-	protos = proto;
+	AST_RWLIST_INSERT_TAIL(&protos, proto, list);
+	AST_RWLIST_UNLOCK(&protos);
 	return 0;
 }
 
 static struct ast_udptl_protocol *get_proto(struct ast_channel *chan)
 {
-	struct ast_udptl_protocol *cur;
+	struct ast_udptl_protocol *cur = NULL;
 
-	cur = protos;
-	while (cur) {
+	AST_RWLIST_RDLOCK(&protos);
+	AST_RWLIST_TRAVERSE(&protos, cur, list) {
 		if (cur->type == chan->tech->type)
-			return cur;
-		cur = cur->next;
+			break;
 	}
-	return NULL;
+	AST_RWLIST_UNLOCK(&protos);
+
+	return cur;
 }
 
 int ast_udptl_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc)
@@ -1086,7 +1104,7 @@
 	return -1;
 }
 
-static int udptl_do_debug_ip(int fd, int argc, char *argv[])
+/*static char *handle_cli_udptl_debug_deprecated(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
 	struct hostent *hp;
 	struct ast_hostent ahp;
@@ -1094,83 +1112,135 @@
 	char *p;
 	char *arg;
 
-	port = 0;
-	if (argc != 4)
-		return RESULT_SHOWUSAGE;
-	arg = argv[3];
-	p = strstr(arg, ":");
-	if (p) {
-		*p = '\0';
-		p++;
-		port = atoi(p);
-	}
-	hp = ast_gethostbyname(arg, &ahp);
-	if (hp == NULL)
-		return RESULT_SHOWUSAGE;
-	udptldebugaddr.sin_family = AF_INET;
-	memcpy(&udptldebugaddr.sin_addr, hp->h_addr, sizeof(udptldebugaddr.sin_addr));
-	udptldebugaddr.sin_port = htons(port);
-	if (port == 0)
-		ast_cli(fd, "UDPTL Debugging Enabled for IP: %s\n", ast_inet_ntoa(udptldebugaddr.sin_addr));
-	else
-		ast_cli(fd, "UDPTL Debugging Enabled for IP: %s:%d\n", ast_inet_ntoa(udptldebugaddr.sin_addr), port);
-	udptldebug = 1;
-	return RESULT_SUCCESS;
-}
+	switch (cmd) {
+	case CLI_INIT:
+		e->command = "udptl debug [off|ip]";
+		e->usage = 
+			"Usage: udptl debug [off]|[ip host[:port]]\n"
+			"       Enable or disable dumping of UDPTL packets.\n"
+			"       If ip is specified, limit the dumped packets to those to and from\n"
+			"       the specified 'host' with optional port.\n";
+		return NULL;
+	case CLI_GENERATE:
+		return NULL;
+	}
 
-static int udptl_do_debug(int fd, int argc, char *argv[])
-{
-	if (argc != 2) {
-		if (argc != 4)
-			return RESULT_SHOWUSAGE;
-		return udptl_do_debug_ip(fd, argc, argv);
+	if (a->argc < 2 || a->argc > 4)
+		return CLI_SHOWUSAGE;
+
+	if (a->argc == 2) { 
+		udptldebug = 1;
+		memset(&udptldebugaddr, 0, sizeof(udptldebugaddr));
+		ast_cli(a->fd, "UDPTL Debugging Enabled\n");
+	} else if (a->argc == 3) {
+		if (strncasecmp(a->argv[2], "off", 3))
+			return CLI_SHOWUSAGE;
+		udptldebug = 0;
+		ast_cli(a->fd, "UDPTL Debugging Disabled\n");
+	} else {
+		if (strncasecmp(a->argv[2], "ip", 2))
+			return CLI_SHOWUSAGE;
+		port = 0;
+		arg = a->argv[3];
+		p = strstr(arg, ":");
+		if (p) {
+			*p = '\0';
+			p++;
+			port = atoi(p);
+		}
+		hp = ast_gethostbyname(arg, &ahp);
+		if (hp == NULL)
+			return CLI_SHOWUSAGE;
+		udptldebugaddr.sin_family = AF_INET;
+		memcpy(&udptldebugaddr.sin_addr, hp->h_addr, sizeof(udptldebugaddr.sin_addr));
+		udptldebugaddr.sin_port = htons(port);
+		if (port == 0)
+			ast_cli(a->fd, "UDPTL Debugging Enabled for IP: %s\n", ast_inet_ntoa(udptldebugaddr.sin_addr));
+		else
+			ast_cli(a->fd, "UDPTL Debugging Enabled for IP: %s:%d\n", ast_inet_ntoa(udptldebugaddr.sin_addr), port);
+		udptldebug = 1;
 	}
-	udptldebug = 1;
-	memset(&udptldebugaddr,0,sizeof(udptldebugaddr));
-	ast_cli(fd, "UDPTL Debugging Enabled\n");
-	return RESULT_SUCCESS;
-}
 
-static int udptl_nodebug(int fd, int argc, char *argv[])
-{
-	if (argc != 3)
-		return RESULT_SHOWUSAGE;
-	udptldebug = 0;
-	ast_cli(fd,"UDPTL Debugging Disabled\n");
-	return RESULT_SUCCESS;
+	return CLI_SUCCESS;
 }
+*/
 
-static char debug_usage[] =
-  "Usage: udptl debug [ip host[:port]]\n"
-  "       Enable dumping of all UDPTL packets to and from host.\n";
+/*static char *handle_cli_udptl_set_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+	struct hostent *hp;
+	struct ast_hostent ahp;
+	int port;
+	char *p;
+	char *arg;
 
-static char nodebug_usage[] =
-  "Usage: udptl debug off\n"
-  "       Disable all UDPTL debugging\n";
+	switch (cmd) {
+	case CLI_INIT:
+		e->command = "udptl set debug {on|off|ip}";
+		e->usage = 
+			"Usage: udptl set debug {on|off|ip host[:port]}\n"
+			"       Enable or disable dumping of UDPTL packets.\n"
+			"       If ip is specified, limit the dumped packets to those to and from\n"
+			"       the specified 'host' with optional port.\n";
+		return NULL;
+	case CLI_GENERATE:
+		return NULL;
+	}
 
-static struct ast_cli_entry cli_udptl_no_debug = {
-	{ "udptl", "no", "debug", NULL },
-	udptl_nodebug, NULL,
-	NULL };
+	if (a->argc < 4 || a->argc > 5)
+		return CLI_SHOWUSAGE;
 
-static struct ast_cli_entry cli_udptl[] = {
-	{ { "udptl", "debug", NULL },
-	udptl_do_debug, "Enable UDPTL debugging",
-	debug_usage },
+	if (a->argc == 4) {
+		if (!strncasecmp(a->argv[3], "on", 2)) {
+			udptldebug = 1;
+			memset(&udptldebugaddr, 0, sizeof(udptldebugaddr));
+			ast_cli(a->fd, "UDPTL Debugging Enabled\n");
+		} else if (!strncasecmp(a->argv[3], "off", 3)) {
+			udptldebug = 0;
+			ast_cli(a->fd, "UDPTL Debugging Disabled\n");
+		} else {
+			return CLI_SHOWUSAGE;
+		}
+	} else {
+		if (strncasecmp(a->argv[3], "ip", 2))
+			return CLI_SHOWUSAGE;
+		port = 0;
+		arg = a->argv[4];
+		p = strstr(arg, ":");
+		if (p) {
+			*p = '\0';
+			p++;
+			port = atoi(p);
+		}
+		hp = ast_gethostbyname(arg, &ahp);
+		if (hp == NULL)
+			return CLI_SHOWUSAGE;
+		udptldebugaddr.sin_family = AF_INET;
+		memcpy(&udptldebugaddr.sin_addr, hp->h_addr, sizeof(udptldebugaddr.sin_addr));
+		udptldebugaddr.sin_port = htons(port);
+		if (port == 0)
+			ast_cli(a->fd, "UDPTL Debugging Enabled for IP: %s\n", ast_inet_ntoa(udptldebugaddr.sin_addr));
+		else
+			ast_cli(a->fd, "UDPTL Debugging Enabled for IP: %s:%d\n", ast_inet_ntoa(udptldebugaddr.sin_addr), port);
+		udptldebug = 1;
+	}
 
-	{ { "udptl", "debug", "ip", NULL },
-	udptl_do_debug, "Enable UDPTL debugging on IP",
-	debug_usage },
+	return CLI_SUCCESS;
+}
+*/
+//static struct ast_cli_entry cli_handle_udptl_debug_deprecated = AST_CLI_DEFINE(handle_cli_udptl_debug_deprecated, "Enable/Disable UDPTL debugging");
 
-	{ { "udptl", "debug", "off", NULL },
-	udptl_nodebug, "Disable UDPTL debugging",
-	nodebug_usage, NULL, &cli_udptl_no_debug },
-};
+//static struct ast_cli_entry cli_udptl[] = {
+//	AST_CLI_DEFINE(handle_cli_udptl_set_debug, "Enable/Disable UDPTL debugging", .deprecate_cmd = &cli_handle_udptl_debug_deprecated)
+//};
 
-void ast_udptl_reload(void)
+static void __ast_udptl_reload(int reload)
 {
 	struct ast_config *cfg;
 	const char *s;
+	struct ast_flags config_flags = { 0 };
+
+	if ((cfg = ast_config_load("udptl.conf")) == NULL)
+		return;
 
 	udptlstart = 4500;
 	udptlend = 4999;
@@ -1179,7 +1249,7 @@
 	udptlfecspan = 0;
 	udptlmaxdatagram = 0;
 
-	if ((cfg = ast_config_load("udptl.conf"))) {
+	if (cfg) {
 		if ((s = ast_variable_retrieve(cfg, "general", "udptlstart"))) {
 			udptlstart = atoi(s);
 			if (udptlstart < 1024)
@@ -1239,12 +1309,16 @@
 		udptlstart = 4500;
 		udptlend = 4999;
 	}
-	if (option_verbose > 1)
-		ast_verbose(VERBOSE_PREFIX_2 "UDPTL allocating from port range %d -> %d\n", udptlstart, udptlend);
+	ast_log(LOG_DEBUG, "UDPTL allocating from port range %d -> %d\n", udptlstart, udptlend);
+}
+
+void ast_udptl_reload(void)
+{
+	__ast_udptl_reload(1);
 }
 
 void ast_udptl_init(void)
 {
-	ast_cli_register_multiple(cli_udptl, sizeof(cli_udptl) / sizeof(struct ast_cli_entry));
-	ast_udptl_reload();
+//	ast_cli_register_multiple(cli_udptl, sizeof(cli_udptl) / sizeof(struct ast_cli_entry));
+	__ast_udptl_reload(0);
 }
diff -ruN asterisk-1.4.20.1_original/Makefile.rules asterisk-1.4.20.1_updated/Makefile.rules
--- asterisk-1.4.20.1_original/Makefile.rules	2008-04-30 14:14:07.000000000 +0200
+++ asterisk-1.4.20.1_updated/Makefile.rules	2008-06-25 23:55:33.000000000 +0200
@@ -34,10 +34,14 @@
 # ppro's, etc, as well as the AMD K6 and K7.  
 #K6OPT=-DK6OPT
 
-OPTIMIZE?=-O6
+OPTIMIZE?=-O2
 ASTCFLAGS+=$(OPTIMIZE)
 endif
 
+# profiling options
+# ASTCFLAGS+=-pg
+# ASTLDFLAGS+=-pg
+
 %.o: %.c
 	$(ECHO_PREFIX) echo "   [CC] $< -> $@"
 	$(CMD_PREFIX) $(CC) -o $@ -c $< $(PTHREAD_CFLAGS) $(ASTCFLAGS) -MD -MT $@ -MF .$(subst /,_,$@).d -MP
diff -ruN asterisk-1.4.20.1_original/makeopts.in asterisk-1.4.20.1_updated/makeopts.in
--- asterisk-1.4.20.1_original/makeopts.in	2008-03-11 15:07:59.000000000 +0100
+++ asterisk-1.4.20.1_updated/makeopts.in	2008-06-05 17:08:08.000000000 +0200
@@ -189,3 +189,6 @@
 TINFO_INCLUDE=@TINFO_INCLUDE@
 TINFO_LIB=@TINFO_LIB@
 TINFO_DIR=@TINFO_DIR@
+
+SPANDSP_INCLUDE=@SPANDSP_INCLUDE@
+SPANDSP_LIB=@SPANDSP_LIB@
