Revision
17141
Author
mikej
Date
2010-03-30 08:41:49 -0500 (Tue, 30 Mar 2010)

Log Message

Merge branch 'master' into svn

Added Paths

Diff

Added: freeswitch/trunk/libs/freetdm/.gitignore (0 => 17141)


--- freeswitch/trunk/libs/freetdm/.gitignore	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/.gitignore	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,13 @@
+*.o
+*.lo
+*.so
+*.a
+*.orig
+*.rej
+*.log
+
+Makefile
+config.*
+configure
+libtool
+aclocal.m4

Added: freeswitch/trunk/libs/freetdm/.update (0 => 17141)


--- freeswitch/trunk/libs/freetdm/.update	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/.update	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1 @@
+Fri Oct  3 17:54:41 EDT 2008

Added: freeswitch/trunk/libs/freetdm/AUTHORS ( => )



Added: freeswitch/trunk/libs/freetdm/ChangeLog
===================================================================

Added: freeswitch/trunk/libs/freetdm/Makefile.am (0 => 17141)


--- freeswitch/trunk/libs/freetdm/Makefile.am	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/Makefile.am	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,276 @@
+# Copyright (c) 2007, Anthony Minessale II
+# All rights reserved.
+# 
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 
+# * Neither the name of the original author; nor the names of any contributors
+# may be used to endorse or promote products derived from this software
+# without specific prior written permission.
+# 
+# 
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+# OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+PREFIX = $(prefix)
+SRC    = src
+
+moddir = @modinstdir@
+libdir = @libdir@
+library_includedir = $(PREFIX)/include
+
+INCS      = -I$(FT_SRCDIR)/$(SRC)/include -I$(FT_SRCDIR)/$(SRC)/isdn/include
+if HAVE_SCTP
+INCS +=  -I$(FT_SRCDIR)/$(SRC)/ftmod/ftmod_sangoma_boost 
+endif
+MY_CFLAGS = $(INCS) $(FTDM_CFLAGS) -DFTDM_CONFIG_DIR=\"@confdir@\" -DFTDM_MOD_DIR=\"$(moddir)\" @COMP_VENDOR_CFLAGS@ @DEFS@
+COMPILE   = $(CC) $(MY_CFLAGS) $(INCS)
+LTCOMPILE = $(LIBTOOL) --mode=compile --tag=CC $(COMPILE)
+LINK      = $(LIBTOOL) --mode=link --tag=CC $(CC) $(MY_CFLAGS) $(LDFLAGS) -o $@
+
+
+#
+# GNU pkgconfig file
+#
+EXTRA_DIST = freetdm.pc.in
+
+pkgconfigdir   = $(libdir)/pkgconfig
+pkgconfig_DATA = freetdm.pc
+
+
+#
+# libfreetdm
+#
+libfreetdm_la_SOURCES = \
+$(SRC)/hashtable.c \
+$(SRC)/hashtable_itr.c \
+$(SRC)/ftdm_io.c \
+$(SRC)/ftdm_queue.c \
+$(SRC)/ftdm_config.c \
+$(SRC)/ftdm_callerid.c \
+$(SRC)/fsk.c \
+$(SRC)/uart.c \
+$(SRC)/g711.c \
+$(SRC)/libteletone_detect.c \
+$(SRC)/libteletone_generate.c \
+$(SRC)/ftdm_buffer.c \
+$(SRC)/ftdm_threadmutex.c \
+$(SRC)/ftdm_dso.c
+
+library_include_HEADERS = \
+$(SRC)/include/fsk.h \
+$(SRC)/include/g711.h \
+$(SRC)/include/hashtable.h \
+$(SRC)/include/hashtable_itr.h \
+$(SRC)/include/hashtable_private.h \
+$(SRC)/include/libteletone_detect.h \
+$(SRC)/include/libteletone_generate.h \
+$(SRC)/include/libteletone.h \
+$(SRC)/include/freetdm.h \
+$(SRC)/include/sangoma_tdm_api.h \
+$(SRC)/include/uart.h \
+$(SRC)/include/ftdm_buffer.h \
+$(SRC)/include/ftdm_config.h \
+$(SRC)/include/ftdm_threadmutex.h \
+$(SRC)/include/ftdm_dso.h \
+$(SRC)/include/ftdm_types.h 
+
+lib_LTLIBRARIES	       = libfreetdm.la
+libfreetdm_la_CFLAGS   = $(AM_CFLAGS) $(MY_CFLAGS)
+libfreetdm_la_LDFLAGS  = -version-info 1:0:0 $(AM_LDFLAGS)
+libfreetdm_la_LIBADD   = $(LIBS)
+
+MYLIB = libfreetdm.la
+
+core: libfreetdm.la 
+core-install: install-libLTLIBRARIES
+
+#
+# tools & test programs
+#
+noinst_PROGRAMS = testtones detect_tones detect_dtmf testisdn testpri testr2 testanalog testapp testcid
+if HAVE_SCTP
+noinst_PROGRAMS += testboost
+endif
+noinst_PROGRAMS += testsangomaboost
+
+testapp_SOURCES = $(SRC)/testapp.c
+testapp_LDADD   = libfreetdm.la
+testapp_CFLAGS  = $(AM_CFLAGS) $(MY_CFLAGS)
+
+testcid_SOURCES = $(SRC)/testcid.c
+testcid_LDADD   = libfreetdm.la
+testcid_CFLAGS  = $(AM_CFLAGS) $(MY_CFLAGS)
+
+testtones_SOURCES = $(SRC)/testtones.c
+testtones_LDADD   = libfreetdm.la
+testtones_CFLAGS  = $(AM_CFLAGS) $(MY_CFLAGS)
+
+detect_tones_SOURCES = $(SRC)/detect_tones.c
+detect_tones_LDADD   = libfreetdm.la
+detect_tones_CFLAGS  = $(AM_CFLAGS) $(MY_CFLAGS)
+
+detect_dtmf_SOURCES = $(SRC)/detect_dtmf.c
+detect_dtmf_LDADD   = libfreetdm.la
+detect_dtmf_CFLAGS  = $(AM_CFLAGS) $(MY_CFLAGS)
+
+testisdn_SOURCES = $(SRC)/testisdn.c
+testisdn_LDADD   = libfreetdm.la
+testisdn_CFLAGS  = $(AM_CFLAGS) $(MY_CFLAGS)
+
+testpri_SOURCES = $(SRC)/testpri.c
+testpri_LDADD   = libfreetdm.la
+testpri_CFLAGS  = $(AM_CFLAGS) $(MY_CFLAGS)
+
+testr2_SOURCES = $(SRC)/testr2.c
+testr2_LDADD   = libfreetdm.la
+testr2_CFLAGS  = $(AM_CFLAGS) $(MY_CFLAGS)
+
+if HAVE_SCTP
+testboost_SOURCES = $(SRC)/testboost.c
+testboost_LDADD   = libfreetdm.la
+testboost_CFLAGS  = $(AM_CFLAGS) $(MY_CFLAGS)
+endif
+
+testsangomaboost_SOURCES = $(SRC)/testsangomaboost.c
+testsangomaboost_LDADD   = libfreetdm.la
+testsangomaboost_CFLAGS  = $(AM_CFLAGS) $(MY_CFLAGS)
+
+testanalog_SOURCES = $(SRC)/testanalog.c
+testanalog_LDADD   = libfreetdm.la
+testanalog_CFLAGS  = $(AM_CFLAGS) $(MY_CFLAGS)
+
+#
+# ftmod modules
+#
+mod_LTLIBRARIES = ftmod_zt.la ftmod_skel.la ftmod_isdn.la ftmod_analog.la ftmod_analog_em.la 
+
+
+if HAVE_SCTP 
+mod_LTLIBRARIES += ftmod_sangoma_boost.la
+endif
+
+if LIBSANGOMA
+mod_LTLIBRARIES += ftmod_wanpipe.la
+endif
+
+if LIBPRI
+mod_LTLIBRARIES += ftmod_libpri.la
+endif
+
+if OPENR2
+mod_LTLIBRARIES += ftmod_r2.la
+endif
+
+ftmod_zt_la_SOURCES = $(SRC)/ftmod/ftmod_zt/ftmod_zt.c
+ftmod_zt_la_CFLAGS  = $(AM_CFLAGS) $(MY_CFLAGS)
+ftmod_zt_la_LDFLAGS = -module -avoid-version
+ftmod_zt_la_LIBADD  = $(MYLIB)
+
+ftmod_skel_la_SOURCES = $(SRC)/ftmod/ftmod_skel/ftmod_skel.c
+ftmod_skel_la_CFLAGS  = $(AM_CFLAGS) $(MY_CFLAGS)
+ftmod_skel_la_LDFLAGS = -module -avoid-version
+ftmod_skel_la_LIBADD  = $(MYLIB)
+
+if LIBSANGOMA
+ftmod_wanpipe_la_SOURCES = $(SRC)/ftmod/ftmod_wanpipe/ftmod_wanpipe.c
+ftmod_wanpipe_la_CFLAGS  = $(AM_CFLAGS) $(MY_CFLAGS) -D__LINUX__ -I/usr/include/wanpipe
+ftmod_wanpipe_la_LDFLAGS = -module -avoid-version -lsangoma
+ftmod_wanpipe_la_LIBADD  = $(MYLIB)
+endif
+
+ftmod_isdn_la_SOURCES = \
+$(SRC)/isdn/EuroISDNStateNT.c \
+$(SRC)/isdn/EuroISDNStateTE.c \
+$(SRC)/isdn/mfifo.c \
+$(SRC)/isdn/Q921.c \
+$(SRC)/isdn/Q931api.c \
+$(SRC)/isdn/Q931.c \
+$(SRC)/isdn/Q931ie.c \
+$(SRC)/isdn/Q931mes.c \
+$(SRC)/isdn/Q931StateNT.c \
+$(SRC)/isdn/Q931StateTE.c \
+$(SRC)/isdn/nationalmes.c \
+$(SRC)/isdn/nationalStateNT.c \
+$(SRC)/isdn/nationalStateTE.c \
+$(SRC)/isdn/DMSmes.c \
+$(SRC)/isdn/DMSStateNT.c \
+$(SRC)/isdn/DMSStateTE.c \
+$(SRC)/isdn/5ESSmes.c \
+$(SRC)/isdn/5ESSStateNT.c \
+$(SRC)/isdn/5ESSStateTE.c \
+$(SRC)/isdn/Q932mes.c \
+$(SRC)/ftmod/ftmod_isdn/ftmod_isdn.c
+
+ftmod_isdn_la_CFLAGS  = $(AM_CFLAGS) $(MY_CFLAGS) -D_GNU_SOURCE
+ftmod_isdn_la_LDFLAGS = $(PCAP_LIB_FLAGS) -module -avoid-version
+ftmod_isdn_la_LIBADD  = $(MYLIB)
+
+ftmod_analog_la_SOURCES = $(SRC)/ftmod/ftmod_analog/ftmod_analog.c
+ftmod_analog_la_CFLAGS  = $(AM_CFLAGS) $(MY_CFLAGS)
+ftmod_analog_la_LDFLAGS = -module -avoid-version
+ftmod_analog_la_LIBADD  = $(MYLIB)
+
+ftmod_analog_em_la_SOURCES = $(SRC)/ftmod/ftmod_analog_em/ftmod_analog_em.c
+ftmod_analog_em_la_CFLAGS  = $(AM_CFLAGS) $(MY_CFLAGS)
+ftmod_analog_em_la_LDFLAGS = -module -avoid-version
+ftmod_analog_em_la_LIBADD  = $(MYLIB)
+
+if HAVE_SCTP
+ftmod_sangoma_boost_la_SOURCES = $(SRC)/ftmod/ftmod_sangoma_boost/sangoma_boost_client.c $(SRC)/ftmod/ftmod_sangoma_boost/ftmod_sangoma_boost.c
+ftmod_sangoma_boost_la_CFLAGS  = $(AM_CFLAGS) $(MY_CFLAGS)
+ftmod_sangoma_boost_la_LDFLAGS = -module -avoid-version
+ftmod_sangoma_boost_la_LIBADD  = $(MYLIB)
+endif
+
+if LIBPRI
+ftmod_libpri_la_SOURCES = $(SRC)/ftmod/ftmod_libpri/ftmod_libpri.c $(SRC)/ftmod/ftmod_libpri/lpwrap_pri.c
+ftmod_libpri_la_CFLAGS  = $(AM_CFLAGS) $(MY_CFLAGS)
+ftmod_libpri_la_LDFLAGS = -module  -avoid-version -lpri
+ftmod_libpri_la_LIBADD  = $(MYLIB)
+endif
+
+if OPENR2
+ftmod_r2_la_SOURCES = $(SRC)/ftmod/ftmod_r2/ftmod_r2.c 
+ftmod_r2_la_CFLAGS  = $(AM_CFLAGS) $(MY_CFLAGS)
+ftmod_r2_la_LDFLAGS = -module  -avoid-version -lopenr2
+ftmod_r2_la_LIBADD  = $(MYLIB)
+endif
+
+
+dox doxygen:
+	cd docs && doxygen $(FT_SRCDIR)/docs/Doxygen.conf
+
+mod_freetdm/mod_freetdm.$(DYNAMIC_LIB_EXTEN): $(MYLIB) mod_freetdm/mod_freetdm.c
+	cd mod_freetdm && make
+
+mod_freetdm: mod_freetdm/mod_freetdm.$(DYNAMIC_LIB_EXTEN)
+
+mod_freetdm-install: mod_freetdm
+	cd mod_freetdm && make install
+
+mod_freetdm-clean:
+	@if [ -f mod_freetdm/mod_freetdm.$(DYNAMIC_LIB_EXTEN) ] ; then cd mod_freetdm && make clean ; fi
+
+install-data-local:
+	$(mkinstalldirs) $(DESTDIR)$(PREFIX)
+	$(mkinstalldirs) $(DESTDIR)@confdir@
+	@[ -f "$(DESTDIR)@confdir@/freetdm.conf" ] || ( cp conf/*.conf $(DESTDIR)@confdir@)
+	@echo OpenFTDM Installed

Added: freeswitch/trunk/libs/freetdm/NEWS ( => )



Added: freeswitch/trunk/libs/freetdm/README
===================================================================
--- freeswitch/trunk/libs/freetdm/README	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/README	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,3 @@
+FREETDM (WORK IN PROGRESS)
+
+*shrug*

Added: freeswitch/trunk/libs/freetdm/TODO (0 => 17141)


--- freeswitch/trunk/libs/freetdm/TODO	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/TODO	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,9 @@
+== Interface inconsistency ==
+- enum_id member of ftdm_event_t is inconsistent. Most of the time is just for OOB events, the only other
+  type of event as of now is FTDM_EVENT_DTMF and is not using the enum_id member. I think we can get rid
+  of the FTDM_EVENT_DTMF and create ftdm_dtmf_event_t type instead of reusing ftdm_event_t
+  then ftdm_event_t would be renamed to ftdm_oob_event_t and the enum_id renamed to type, then ftdm_span_next_event()
+  will only return OOB events
+
+- query span hw status (connected/disconnected) on startup 
+

Added: freeswitch/trunk/libs/freetdm/acinclude.m4 (0 => 17141)


--- freeswitch/trunk/libs/freetdm/acinclude.m4	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/acinclude.m4	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1 @@
+m4_include([build/libpcap.m4])

Added: freeswitch/trunk/libs/freetdm/bootstrap (0 => 17141)


--- freeswitch/trunk/libs/freetdm/bootstrap	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/bootstrap	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,6 @@
+#!/bin/bash
+autoheader
+libtoolize --force --copy
+aclocal
+automake -f --copy --add-missing
+autoconf
Property changes on: freeswitch/trunk/libs/freetdm/bootstrap
___________________________________________________________________
Name: svn:executable
   + *

Added: freeswitch/trunk/libs/freetdm/build/libpcap.m4 (0 => 17141)


--- freeswitch/trunk/libs/freetdm/build/libpcap.m4	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/build/libpcap.m4	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,144 @@
+dnl libpcap.m4--PCAP libraries and includes
+dnl Derrick Brashear
+dnl from KTH krb and Arla
+dnl $Id: libpcap.m4,v 1.4 2006/01/20 20:21:09 snsimon Exp $
+
+AC_DEFUN([PCAP_INC_WHERE1], [
+ac_cv_found_pcap_inc=no
+if test -f "$1/pcap.h" ; then
+  ac_cv_found_pcap_inc=yes
+fi
+])
+
+AC_DEFUN([PCAP_INC_WHERE], [
+   for i in $1; do
+      AC_MSG_CHECKING(for pcap header in $i)
+      PCAP_INC_WHERE1($i)
+      if test "$ac_cv_found_pcap_inc" = "yes"; then
+        ac_cv_pcap_where_inc=$i
+        AC_MSG_RESULT(found)
+        break
+      else
+        AC_MSG_RESULT(no found)
+      fi
+    done
+])
+
+AC_DEFUN([PCAP_LIB_WHERE1], [
+saved_LIBS=$LIBS
+LIBS="$saved_LIBS -L$1 -lpcap"
+AC_TRY_LINK(,
+[pcap_lookupdev("");],
+[ac_cv_found_pcap_lib=yes],
+ac_cv_found_pcap_lib=no)
+LIBS=$saved_LIBS
+])
+
+AC_DEFUN([TEST_LIBPATH], [
+changequote(<<, >>)
+define(<<AC_CV_FOUND>>, translit(ac_cv_found_$2_lib, <<- *>>, <<__p>>))
+changequote([, ])
+if test "$AC_CV_FOUND" = "yes"; then
+  if test \! -r "$1/lib$2.a" -a \! -r "$1/lib$2.so" -a \! -r "$1/lib$2.sl" -a \! -r "$1/lib$2.dylib"; then
+    AC_CV_FOUND=no
+  fi
+fi
+])
+
+
+AC_DEFUN([PCAP_LIB_WHERE], [
+   for i in $1; do
+      AC_MSG_CHECKING(for pcap library in $i)
+      PCAP_LIB_WHERE1($i)
+      TEST_LIBPATH($i, pcap)
+      if test "$ac_cv_found_pcap_lib" = "yes" ; then
+        ac_cv_pcap_where_lib=$i
+        AC_MSG_RESULT(found)
+        break
+      else
+        AC_MSG_RESULT(no found)
+      fi
+    done
+])
+
+AC_DEFUN([FIND_LIB_SUBDIR],
+[dnl
+AC_ARG_WITH([lib-subdir], AC_HELP_STRING([--with-lib-subdir=DIR],[Find libraries in DIR instead of lib]))
+AC_CHECK_SIZEOF(long)
+AC_CACHE_CHECK([what directory libraries are found in], [ac_cv_cmu_lib_subdir],
+[test "X$with_lib_subdir" = "Xyes" && with_lib_subdir=
+test "X$with_lib_subdir" = "Xno" && with_lib_subdir=
+ if test "X$with_lib_subdir" = "X" ; then
+   ac_cv_cmu_lib_subdir=lib
+   if test $ac_cv_sizeof_long -eq 4 ; then
+     test -d /usr/lib32 && ac_cv_cmu_lib_subdir=lib32
+     test -r /usr/lib/libpcap.so && ac_cv_cmu_lib_subdir=lib
+   fi
+   if test $ac_cv_sizeof_long -eq 8 ; then
+     test -d /usr/lib64 && ac_cv_cmu_lib_subdir=lib64
+   fi
+ else
+   ac_cv_cmu_lib_subdir=$with_lib_subdir
+ fi])
+ AC_SUBST(LIB_SUBDIR, $ac_cv_cmu_lib_subdir)
+ ])
+ 
+
+AC_DEFUN([AX_LIB_PCAP], [
+AC_REQUIRE([FIND_LIB_SUBDIR])
+AC_ARG_WITH(pcap,
+	[  --with-pcap=PREFIX      Compile with PCAP support],
+	[if test "X$with_pcap" = "X"; then
+		with_pcap=yes
+	fi])
+AC_ARG_WITH(pcap-lib,
+	[  --with-pcap-lib=dir     use pcap libraries in dir],
+	[if test "$withval" = "yes" -o "$withval" = "no"; then
+		AC_MSG_ERROR([No argument for --with-pcap-lib])
+	fi])
+AC_ARG_WITH(pcap-include,
+	[  --with-pcap-include=dir use pcap headers in dir],
+	[if test "$withval" = "yes" -o "$withval" = "no"; then
+		AC_MSG_ERROR([No argument for --with-pcap-include])
+	fi])
+
+	if test "X$with_pcap" != "X"; then
+	  if test "$with_pcap" != "yes"; then
+	    ac_cv_pcap_where_lib=$with_pcap
+	    ac_cv_pcap_where_inc=$with_pcap/include
+	  fi
+	fi
+
+	if test "X$with_pcap_lib" != "X"; then
+	  ac_cv_pcap_where_lib=$with_pcap_lib
+	fi
+	if test "X$ac_cv_pcap_where_lib" = "X"; then
+	  PCAP_LIB_WHERE(/usr/$LIB_SUBDIR /usr/local/$LIB_SUBDIR)
+	fi
+
+	if test "X$with_pcap_include" != "X"; then
+	  ac_cv_pcap_where_inc=$with_pcap_include
+	fi
+	if test "X$ac_cv_pcap_where_inc" = "X"; then
+	  PCAP_INC_WHERE(/usr/ng/include /usr/include /usr/local/include)
+	fi
+
+	AC_MSG_CHECKING(whether to include pcap)
+	if test "X$ac_cv_pcap_where_lib" != "X" -a "X$ac_cv_pcap_where_inc" != "X"; then
+	  ac_cv_found_pcap=yes
+	  AC_MSG_RESULT(yes)
+	  PCAP_INC_DIR=$ac_cv_pcap_where_inc
+	  PCAP_LIB_DIR=$ac_cv_pcap_where_lib
+	  PCAP_INC_FLAGS="-I${PCAP_INC_DIR}"
+	  PCAP_LIB_FLAGS="-L${PCAP_LIB_DIR} -lpcap"
+	  AC_SUBST(PCAP_INC_DIR)
+	  AC_SUBST(PCAP_LIB_DIR)
+	  AC_SUBST(PCAP_INC_FLAGS)
+	  AC_SUBST(PCAP_LIB_FLAGS)
+	  AC_DEFINE([HAVE_LIBPCAP],[1],[libpcap])
+        else
+	  ac_cv_found_pcap=no
+	  AC_MSG_RESULT(no)
+	fi
+	])
+

Added: freeswitch/trunk/libs/freetdm/conf/freetdm.conf (0 => 17141)


--- freeswitch/trunk/libs/freetdm/conf/freetdm.conf	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/conf/freetdm.conf	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,19 @@
+[span wanpipe]
+name => FreeTDM
+number => 1
+fxs-channel => 1:3-4
+
+[span wanpipe]
+fxo-channel => 1:1-2
+
+[span zt]
+name => FreeTDM
+number => 2
+fxs-channel => 1
+
+[span zt]
+name => FreeTDM
+number => 2
+fxo-channel => 3
+
+

Added: freeswitch/trunk/libs/freetdm/conf/freetdm.conf.xml (0 => 17141)


--- freeswitch/trunk/libs/freetdm/conf/freetdm.conf.xml	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/conf/freetdm.conf.xml	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,45 @@
+<configuration name="freetdm.conf" description="FreeTDM Configuration">
+  <settings>
+    <param name="debug" value="0"/>
+    <!--<param name="hold-music" value="$${moh_uri}"/>-->
+    <!--<param name="enable-analog-option" value="call-swap"/>-->
+    <!--<param name="enable-analog-option" value="3-way"/>-->
+  </settings>
+   <pri_spans>
+     <span name="PRI_1">
+       <!-- Log Levels: none, alert, crit, err, warning, notice, info, debug -->
+       <param name="q921loglevel" value="alert"/>
+       <param name="q931loglevel" value="alert"/>
+       <param name="mode" value="user"/>
+       <param name="dialect" value="5ess"/>
+       <param name="dialplan" value="XML"/>
+       <param name="context" value="default"/>
+     </span>
+     <span name="PRI_2">
+       <param name="q921loglevel" value="alert"/>
+       <param name="q931loglevel" value="alert"/>
+       <param name="mode" value="user"/>
+       <param name="dialect" value="5ess"/>
+       <param name="dialplan" value="XML"/>
+       <param name="context" value="default"/>
+     </span>
+   </pri_spans>
+  <!-- one entry here per openzap span -->
+  <analog_spans>
+    <span id="1">
+      <!--<param name="hold-music" value="$${moh_uri}"/>-->
+      <!--<param name="enable-analog-option" value="call-swap"/>-->
+      <!--<param name="enable-analog-option" value="3-way"/>-->
+      <param name="tonegroup" value="us"/>
+      <param name="digit-timeout" value="2000"/>
+      <param name="max-digits" value="11"/>
+      <param name="dialplan" value="XML"/>
+      <param name="context" value="default"/>
+      <param name="enable-callerid" value="true"/>
+      <!-- regex to stop dialing when it matches -->
+      <!--<param name="dial-regex" value="5555"/>-->
+      <!-- regex to stop dialing when it does not match -->
+      <!--<param name="fail-dial-regex" value="^5"/>-->
+    </span>
+  </analog_spans>
+</configuration>

Added: freeswitch/trunk/libs/freetdm/conf/m3ua.conf (0 => 17141)


--- freeswitch/trunk/libs/freetdm/conf/m3ua.conf	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/conf/m3ua.conf	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,38 @@
+;M3UA SS7 Links Config
+;
+;ss7box-m3ua_mode => true
+;local_sctp_ip => localhost
+;local sctp_port => 30000
+;remote_sctp_ip => localhost
+;remote_sctp_port => 30001
+;opc => 0-0-0
+;dpc => 0-0-0
+
+
+; AP Specific Stuff.  This will likely move later.
+
+; CNAM Gateways
+cnam1_dpc => 0-0-0
+cnam1_ssn => 253
+cnam2_dpc => 0-0-0
+cnam2_ssn => 253
+cnam3_dpc => 0-0-0
+cnam3_ssn => 253
+
+;LNP Gateways
+lnp1_dpc => 0-0-0
+lnp1_ssn => 253
+lnp2_dpc => 0-0-0
+lnp2_ssn => 253
+lnp3_dpc => 0-0-0
+lnp3_ssn => 253
+
+;LNP Gateways
+sms8001_dpc => 0-0-0
+sms8001_ssn => 253
+sms8002_dpc => 0-0-0
+sms8002_ssn => 253
+sms8003_dpc => 0-0-0
+sms8003_ssn => 253
+
+

Added: freeswitch/trunk/libs/freetdm/conf/pika.conf (0 => 17141)


--- freeswitch/trunk/libs/freetdm/conf/pika.conf	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/conf/pika.conf	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,41 @@
+; each category is a config profile
+; to apply the profile append it to a channel def in
+; openzap.conf with @<profile_name>
+; e.g.
+; [span pika]
+; name => pika
+; number => pika
+; fxs-channel => 1:0:1-12@default
+
+[default]
+; region is na or eu
+;region => na
+;rx-gain => 0.00
+;rx-agc-enabled => false
+;rx-agc-targetPower => -15.00
+;rx-agc-minGain => -6.00
+;rx-agc-maxGain => 18.00
+;rx-agc-attackRate => 170
+;rx-agc-decayRate => 750
+;rx-agc-speechThreshold => -36.00
+;rx-vad-enabled => false
+;rx-vad-activationThreshold => -40.00
+;rx-vad-activationDebounceTime => 72
+;rx-vad-deactivationThreshold => -40.00
+;rx-vad-deactivationDebounceTime => 984
+;rx-vad-preSpeechBufferSize => 240
+;tx-gain => 0.00
+;tx-agc-enabled => true
+;tx-agc-targetPower => -15.00
+;tx-agc-minGain => -6.00
+;tx-agc-maxGain => 18.00
+;tx-agc-attackRate => 170
+;tx-agc-decayRate => 750
+;tx-agc-speechThreshold => -36.00
+;ec-enabled => false
+;ec-doubleTalkerThreshold => -6.00
+;ec-speechPresentThreshold => -40.00
+;ec-echoSuppressionThreshold => -18.00
+;ec-echoSuppressionEnabled => true
+;ec-comfortNoiseEnabled => true
+;ec-adaptationModeEnabled => true

Added: freeswitch/trunk/libs/freetdm/conf/tones.conf (0 => 17141)


--- freeswitch/trunk/libs/freetdm/conf/tones.conf	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/conf/tones.conf	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,63 @@
+[us]
+generate-dial => v=-7;%(1000,0,350,440)
+detect-dial => 350,440
+
+generate-ring => v=-7;%(2000,4000,440,480)
+detect-ring => 440,480
+
+generate-busy => v=-7;%(500,500,480,620)
+detect-busy => 480,620
+
+generate-attn => v=0;%(100,100,1400,2060,2450,2600)
+detect-attn => 1400,2060,2450,2600
+
+generate-callwaiting-sas => v=0;%(300,0,440)
+detect-callwaiting-sas => 440
+
+generate-callwaiting-cas => v=0;%(80,0,2750,2130)
+detect-callwaiting-cas => 2750,2130
+
+detect-fail1 => 913.8
+detect-fail2 => 1370.6
+detect-fail3 => 1776.7
+
+
+[sg]
+generate-dial => v=-7;%(1000,0,425)
+detect-dial => 425
+
+generate-ring => v=-7;%(2000,4000,425)
+detect-ring => 425
+
+generate-busy => v=-7;%(750,750,425)
+detect-busy => 425
+
+generate-attn => v=0;%(100,100,1400,2060,2450,2600)
+detect-attn => 1400,2060,2450,2600
+
+generate-callwaiting-sas => v=0;%(300,0,440)
+detect-callwaiting-sas => 440
+
+generate-callwaiting-cas => v=0;%(80,0,2750,2130)
+detect-callwaiting-cas => 2750,2130
+
+detect-fail1 => 913.8
+detect-fail2 => 1370.6
+detect-fail3 => 1776.7
+
+[ru]
+generate-dial => v=-7;%(1000,425)
+detect-dial => 0
+generate-ring => v=-7;%(800,5000,425,0)
+detect-ring => 425,0
+generate-busy => v=-7;%(350,350,425,0)
+detect-busy => 425,0
+generate-attn => v=0;%(100,100,1400,2060,2450,2600)
+detect-attn => 1400,2060,2450,2600
+generate-callwaiting-sas => v=0;%(300,0,440)
+detect-callwaiting-sas => 440,480
+generate-callwaiting-cas => v=0;%(80,0,2750,2130)
+detect-callwaiting-cas => 2750,2130
+detect-fail1 => 913.8
+detect-fail2 => 1370.6
+detect-fail3 => 1776.7

Added: freeswitch/trunk/libs/freetdm/conf/wanpipe.conf (0 => 17141)


--- freeswitch/trunk/libs/freetdm/conf/wanpipe.conf	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/conf/wanpipe.conf	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,4 @@
+[defaults]
+codec_ms => 20
+wink_ms => 150
+flash_ms => 750

Added: freeswitch/trunk/libs/freetdm/conf/zt.conf (0 => 17141)


--- freeswitch/trunk/libs/freetdm/conf/zt.conf	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/conf/zt.conf	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,8 @@
+[defaults]
+codec_ms => 20
+wink_ms => 150
+flash_ms => 750
+echo_cancel_level => 64
+rxgain => 0.0
+txgain => 0.0
+

Added: freeswitch/trunk/libs/freetdm/configure.ac (0 => 17141)


--- freeswitch/trunk/libs/freetdm/configure.ac	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/configure.ac	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,181 @@
+#                                               -*- Autoconf -*-
+# Process this file with autoconf to produce a configure script.
+
+AC_PREREQ(2.59)
+AC_INIT([freetdm],[pre-alpha],[bugs@freeswitch.org])
+AC_CONFIG_SRCDIR([src/ftdm_io.c])
+
+AC_CONFIG_AUX_DIR(build)
+AM_INIT_AUTOMAKE(libfreetdm,0.1)
+
+# Checks for programs.
+AC_PROG_CC
+AC_PROG_MAKE_SET
+AM_PROG_CC_C_O
+
+AC_PREFIX_DEFAULT(/usr/local/freetdm)
+# AC_PREFIX_DEFAULT does not get expanded until too late so we need to do this to use prefix in this script                                                     
+if test "x$prefix" = "xNONE" ; then
+    prefix='/usr/local/freetdm'
+fi
+
+# Absolute source/build directory
+FT_SRCDIR=`(cd $srcdir && pwd)`
+ft_builddir=`pwd`
+AC_SUBST(FT_SRCDIR)
+AC_SUBST(ft_builddir)
+
+if test "$sysconfdir" = "\${prefix}/etc" ; then
+    confdir="$prefix/conf"
+else
+    confdir="$sysconfdir"
+fi
+
+AC_SUBST(confdir)
+
+#override some default libtool behavior and invoke AC_PROG_LIBTOOL (see http://lists.gnu.org/archive/html/libtool/2007-03/msg00000.html)
+m4_defun([_LT_AC_LANG_F77_CONFIG], [:])
+m4_defun([_LT_AC_LANG_GCJ_CONFIG], [:])
+m4_defun([_LT_AC_LANG_RC_CONFIG], [:])
+#AM_PROG_CC_C_O
+AC_PROG_LIBTOOL
+AC_PROG_INSTALL
+
+# Check for com;iler type
+AC_DEFUN([AX_COMPILER_VENDOR],
+[
+AC_CACHE_CHECK([for _AC_LANG compiler vendor], ax_cv_[]_AC_LANG_ABBREV[]_compiler_vendor,
+ [ax_cv_[]_AC_LANG_ABBREV[]_compiler_vendor=unknown
+  # note: don't check for GCC first, since some other compilers define __GNUC__
+  for ventest in intel:__ICC,__ECC,__INTEL_COMPILER ibm:__xlc__,__xlC__,__IBMC__,__IBMCPP__ gnu:__GNUC__ sun:__SUNPRO_C,__SUNPRO_CC hp:__HP_cc,__HP_aCC dec:__DECC,__DECCXX,__DECC_VER,__DECCXX_VER borland:__BORLANDC__,__TURBOC__ comeau:__COMO__ cray:_CRAYC kai:__KCC lcc:__LCC__ metrowerks:__MWERKS__ sgi:__sgi,sgi microsoft:_MSC_VER watcom:__WATCOMC__ portland:__PGI; do
+	vencpp="defined("`echo $ventest | cut -d: -f2 | sed 's/,/) || defined(/g'`")"
+    AC_COMPILE_IFELSE([AC_LANG_PROGRAM(,[
+#if !($vencpp)
+      thisisanerror;
+#endif
+])], [ax_cv_]_AC_LANG_ABBREV[_compiler_vendor=`echo $ventest | cut -d: -f1`; break])
+  done
+ ])
+])
+AC_ARG_ENABLE([enable_64], [AS_HELP_STRING([--enable-64], [Enable 64bit compilation])], [enable_64="$enableval"], [enable_64="no"])
+
+AX_COMPILER_VENDOR
+
+case "${ax_cv_c_compiler_vendor}" in
+gnu)
+    COMP_VENDOR_CFLAGS="-ffast-math -Wall -Werror -Wunused-variable -Wwrite-strings -Wstrict-prototypes -Wmissing-prototypes -O0"
+    ;;
+sun)
+    COMP_VENDOR_CFLAGS="-xc99=all -mt -xCC -D__FUNCTION__=__func__ -xvpara"
+    if test "$enable_64" = "yes" ; then
+        COMP_VENDOR_CFLAGS="-m64 $COMP_VENDOR_CFLAGS"
+    fi
+    ;;
+*)
+    COMP_VENDOR_CFLAGS="-std=c99 -Wall -Wunused-variable -Wwrite-strings -Wstrict-prototypes -Wmissing-prototypes"
+    ;;
+esac
+
+
+#set SOLINK variable based on compiler and host
+if test "x${ax_cv_c_compiler_vendor}"  =  "xsun" ; then
+    SOLINK="-Bdynamic -dy -G"
+elif test "x${ax_cv_c_compiler_vendor}" = "xgnu" ; then
+    case "$host" in
+        *darwin*)
+            SOLINK="-dynamic -bundle -force-flat-namespace"
+        ;;
+        *-solaris2*)
+            SOLINK="-shared -Xlinker"
+        ;;
+        *)
+            SOLINK="-shared -Xlinker -x"
+        ;;
+    esac
+else
+    AC_ERROR([Please update configure.in with SOLINK values for your compiler])
+fi
+
+# set DYNAMIC_LIB_EXTEN
+# we should really be using libtool so we don't need to do this
+case "$host" in
+    *cygwin* | *mingw*)
+        DYNAMIC_LIB_EXTEN="dll"
+    ;;
+    *)
+        DYNAMIC_LIB_EXTEN="so"
+    ;;
+esac
+
+AC_SUBST(SOLINK)
+AC_SUBST(DYNAMIC_LIB_EXTEN)
+
+AC_CHECK_LIB([dl], [dlopen])
+AC_CHECK_LIB([pthread], [pthread_create])
+AC_CHECK_LIB([m], [cos])
+AX_LIB_PCAP
+
+AC_CHECK_HEADERS([netinet/sctp.h netdb.h sys/select.h])
+AM_CONDITIONAL([HAVE_SCTP],[test "${ac_cv_header_netinet_sctp_h}" = "yes"])
+
+AC_CHECK_FUNC([gethostbyname_r],
+	[], [AC_CHECK_LIB([nsl], [gethostbyname_r])]
+)
+if test "$ac_cv_func_gethostbyname_r" = "yes" -o "$ac_cv_lib_nsl_gethostbyname_r" = "yes" ; then
+
+AC_MSG_CHECKING([whether gethostbyname_r requires five arguments])
+
+ac_cv_func_gethostbyname_r_five_args="no"
+
+AC_TRY_COMPILE([#include <netdb.h>],
+	[char *name;
+	 struct hostent *he, *res;
+	 char buffer[2048];
+	 int buflen = 2048;
+	 (void)gethostbyname_r(name, he, buffer, buflen, &res)],
+	[ac_cv_func_gethostbyname_r_five_args="yes"
+         AC_DEFINE([HAVE_GETHOSTBYNAME_R_FIVE], [1], [gethostbyname_r has five arguments])]
+)
+
+    AC_MSG_RESULT([$ac_cv_func_gethostbyname_r_five_args])
+    AC_DEFINE([HAVE_GETHOSTBYNAME_R],[1],[threadsafe gethostbyname])
+fi
+
+#  Enable debugging
+AC_ARG_ENABLE(debug,
+[AC_HELP_STRING([--enable-debug],[build with debug information])],[enable_debug="$enableval"],[enable_debug="yes"])
+
+if test "${enable_debug}" = "yes"; then
+        AC_DEFINE([DEBUG],[],[Enable extra debugging.])
+
+	if test "x${ax_cv_c_compiler_vendor}" = "xgnu" ; then
+	   COMP_VENDOR_CFLAGS="$COMP_VENDOR_CFLAGS -g -ggdb"
+	fi
+fi
+
+# Where to install the modules
+AC_ARG_WITH([modinstdir],
+ [AS_HELP_STRING([--with-modinstdir=DIR], [Install modules into this location (default: $prefix/mod)])], [modinstdir="$withval"], [modinstdir="${prefix}/mod"])
+
+AC_SUBST(modinstdir)
+
+
+# libpri?
+AC_ARG_WITH([libpri],
+ [AS_HELP_STRING([--with-libpri], [Install ftmod_libpri])], [enable_libpri="yes"], [enable_libpri="no"])
+AC_SUBST(enable_libpri)
+
+AC_CHECK_LIB([sangoma], [sangoma_span_chan_toif], [have_libsangoma="yes"])
+AM_CONDITIONAL([LIBSANGOMA],[test "${have_libsangoma}" = "yes"])
+
+AM_CONDITIONAL([LIBPRI],[test "${enable_libpri}" = "yes"])
+
+AC_CHECK_LIB([openr2], [openr2_context_set_io_type], [have_openr2="yes"])
+AM_CONDITIONAL([OPENR2],[test "${have_openr2}" = "yes"])
+
+COMP_VENDOR_CFLAGS="$COMP_VENDOR_CFLAGS"
+AC_SUBST(COMP_VENDOR_CFLAGS)
+AC_CONFIG_FILES([Makefile
+		freetdm.pc
+		mod_freetdm/Makefile])
+AC_OUTPUT

Added: freeswitch/trunk/libs/freetdm/configure.gnu (0 => 17141)


--- freeswitch/trunk/libs/freetdm/configure.gnu	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/configure.gnu	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,3 @@
+#! /bin/sh
+./configure "$@" --with-pic
+

Added: freeswitch/trunk/libs/freetdm/cyginstall.sh (0 => 17141)


--- freeswitch/trunk/libs/freetdm/cyginstall.sh	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/cyginstall.sh	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,11 @@
+#!/bin/bash
+# this script must be run from openzap root dir and it is assuming
+# FreeSWITCH is trunk is located at ../../
+fsdir=../..
+set -x
+cp Debug/*.dll $fsdir/Debug/
+cp Debug/mod/*.dll $fsdir/Debug/mod/
+cp Debug/*.pdb $fsdir/Debug/
+echo "FRIENDLY REMINDER: RECOMPILE ftmod_wanpipe WHENEVER YOU INSTALL NEW DRIVERS"
+set +x 
+

Added: freeswitch/trunk/libs/freetdm/docs/Doxygen.conf (0 => 17141)


--- freeswitch/trunk/libs/freetdm/docs/Doxygen.conf	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/docs/Doxygen.conf	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,277 @@
+# Doxyfile 1.4.6
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+PROJECT_NAME           = OpenZAP
+PROJECT_NUMBER         = 
+OUTPUT_DIRECTORY       = .
+CREATE_SUBDIRS         = NO
+OUTPUT_LANGUAGE        = English
+USE_WINDOWS_ENCODING   = YES
+BRIEF_MEMBER_DESC      = YES
+REPEAT_BRIEF           = YES
+ABBREVIATE_BRIEF       = "The $name class" \
+                         "The $name widget" \
+                         "The $name file" \
+                         is \
+                         provides \
+                         specifies \
+                         contains \
+                         represents \
+                         a \
+                         an \
+                         the
+ALWAYS_DETAILED_SEC    = NO
+INLINE_INHERITED_MEMB  = NO
+FULL_PATH_NAMES        = NO
+STRIP_FROM_PATH        = 
+STRIP_FROM_INC_PATH    = 
+SHORT_NAMES            = NO
+JAVADOC_AUTOBRIEF      = NO
+MULTILINE_CPP_IS_BRIEF = NO
+DETAILS_AT_TOP         = NO
+INHERIT_DOCS           = YES
+SEPARATE_MEMBER_PAGES  = NO
+TAB_SIZE               = 8
+ALIASES                = 
+OPTIMIZE_OUTPUT_FOR_C  = YES
+OPTIMIZE_OUTPUT_JAVA   = NO
+DISTRIBUTE_GROUP_DOC   = NO
+SUBGROUPING            = YES
+IGNORE_PREFIX          = zap_ ZAP_ Q921 Q931
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+EXTRACT_ALL            = YES
+EXTRACT_PRIVATE        = YES 
+EXTRACT_STATIC         = YES
+EXTRACT_LOCAL_CLASSES  = YES
+EXTRACT_LOCAL_METHODS  = YES
+HIDE_UNDOC_MEMBERS     = YES
+HIDE_UNDOC_CLASSES     = YES
+HIDE_FRIEND_COMPOUNDS  = NO
+HIDE_IN_BODY_DOCS      = NO
+INTERNAL_DOCS          = NO
+CASE_SENSE_NAMES       = NO
+HIDE_SCOPE_NAMES       = NO
+SHOW_INCLUDE_FILES     = YES
+INLINE_INFO            = YES
+SORT_MEMBER_DOCS       = YES
+SORT_BRIEF_DOCS        = NO
+SORT_BY_SCOPE_NAME     = NO
+GENERATE_TODOLIST      = YES
+GENERATE_TESTLIST      = YES
+GENERATE_BUGLIST       = YES
+GENERATE_DEPRECATEDLIST= YES
+ENABLED_SECTIONS       = 
+MAX_INITIALIZER_LINES  = 30
+SHOW_USED_FILES        = YES
+SHOW_DIRECTORIES       = YES
+FILE_VERSION_FILTER    = 
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+QUIET                  = NO
+WARNINGS               = YES
+WARN_IF_UNDOCUMENTED   = YES
+WARN_IF_DOC_ERROR      = YES
+WARN_NO_PARAMDOC       = NO
+WARN_FORMAT            = "$file:$line: $text"
+WARN_LOGFILE           = 
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+INPUT                  = ../src ../src/include \
+                         ../src/isdn ../src/isdn/include \
+                         ../mod_openzap ../ \
+                         ../src/ozmod \
+                         ../src/ozmod/ozmod_analog \
+                         ../src/ozmod/ozmod_analog_em \
+                         ../src/ozmod/ozmod_isdn \
+                         ../src/ozmod/ozmod_pika \
+                         ../src/ozmod/ozmod_skel \
+                         ../src/ozmod/ozmod_ss7_boost \
+                         ../src/ozmod/ozmod_wanpipe \
+                         ../src/ozmod/ozmod_zt
+
+FILE_PATTERNS          = *.c \
+                         *.cc \
+                         *.cxx \
+                         *.cpp \
+                         *.c++ \
+                         *.d \
+                         *.java \
+                         *.ii \
+                         *.ixx \
+                         *.ipp \
+                         *.i++ \
+                         *.inl \
+                         *.h \
+                         *.hh \
+                         *.hxx \
+                         *.hpp \
+                         *.h++ \
+                         *.idl \
+                         *.odl \
+                         *.cs \
+                         *.php \
+                         *.php3 \
+                         *.inc \
+                         *.m \
+                         *.mm \
+                         *.dox \
+                         *.py
+RECURSIVE              = NO
+EXCLUDE                = 
+EXCLUDE_SYMLINKS       = NO
+EXCLUDE_PATTERNS       = 
+EXAMPLE_PATH           = 
+EXAMPLE_PATTERNS       = 
+EXAMPLE_RECURSIVE      = NO
+IMAGE_PATH             = 
+INPUT_FILTER           = 
+FILTER_PATTERNS        = 
+FILTER_SOURCE_FILES    = NO
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+SOURCE_BROWSER         = NO
+INLINE_SOURCES         = YES
+STRIP_CODE_COMMENTS    = YES
+REFERENCED_BY_RELATION = YES
+REFERENCES_RELATION    = YES
+USE_HTAGS              = YES
+VERBATIM_HEADERS       = NO
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+ALPHABETICAL_INDEX     = YES
+COLS_IN_ALPHA_INDEX    = 1
+IGNORE_PREFIX          = zap_
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+GENERATE_HTML          = YES
+HTML_OUTPUT            = html
+HTML_FILE_EXTENSION    = .html
+HTML_HEADER            = 
+HTML_FOOTER            = 
+HTML_STYLESHEET        = 
+HTML_ALIGN_MEMBERS     = YES
+GENERATE_HTMLHELP      = NO
+CHM_FILE               = freeswitch.chm
+HHC_LOCATION           = 
+GENERATE_CHI           = YES
+BINARY_TOC             = NO
+TOC_EXPAND             = NO
+DISABLE_INDEX          = NO
+ENUM_VALUES_PER_LINE   = 4
+GENERATE_TREEVIEW      = YES
+TREEVIEW_WIDTH         = 250
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+GENERATE_LATEX         = NO
+LATEX_OUTPUT           = latex
+LATEX_CMD_NAME         = latex
+MAKEINDEX_CMD_NAME     = makeindex
+COMPACT_LATEX          = NO
+PAPER_TYPE             = a4wide
+EXTRA_PACKAGES         = 
+LATEX_HEADER           = 
+PDF_HYPERLINKS         = NO
+USE_PDFLATEX           = NO
+LATEX_BATCHMODE        = NO
+LATEX_HIDE_INDICES     = NO
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+GENERATE_RTF           = NO
+RTF_OUTPUT             = rtf
+COMPACT_RTF            = NO
+RTF_HYPERLINKS         = NO
+RTF_STYLESHEET_FILE    = 
+RTF_EXTENSIONS_FILE    = 
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+GENERATE_MAN           = NO
+MAN_OUTPUT             = man
+MAN_EXTENSION          = .3
+MAN_LINKS              = NO
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+GENERATE_XML           = NO
+XML_OUTPUT             = xml
+XML_SCHEMA             = 
+XML_DTD                = 
+XML_PROGRAMLISTING     = YES
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+GENERATE_AUTOGEN_DEF   = NO
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+GENERATE_PERLMOD       = NO
+PERLMOD_LATEX          = NO
+PERLMOD_PRETTY         = YES
+PERLMOD_MAKEVAR_PREFIX = 
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor   
+#---------------------------------------------------------------------------
+ENABLE_PREPROCESSING   = YES
+MACRO_EXPANSION        = YES
+EXPAND_ONLY_PREDEF     = NO
+SEARCH_INCLUDES        = NO
+INCLUDE_PATH           = 
+INCLUDE_FILE_PATTERNS  = *.h
+PREDEFINED             = ZAP_DECLARE(x)=x \
+					APR_DECLARE(x)=x \
+					ZAP_MOD_DECLARE(x)=x \
+					DoxyDefine(x)=x
+					
+EXPAND_AS_DEFINED      = NO
+SKIP_FUNCTION_MACROS   = NO
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references   
+#---------------------------------------------------------------------------
+TAGFILES               = 
+GENERATE_TAGFILE       = 
+ALLEXTERNALS           = NO
+EXTERNAL_GROUPS        = YES
+PERL_PATH              = /usr/bin/perl
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool   
+#---------------------------------------------------------------------------
+CLASS_DIAGRAMS         = YES
+HIDE_UNDOC_RELATIONS   = YES
+HAVE_DOT               = YES
+CLASS_GRAPH            = YES
+COLLABORATION_GRAPH    = YES
+GROUP_GRAPHS           = YES
+UML_LOOK               = YES
+TEMPLATE_RELATIONS     = YES
+INCLUDE_GRAPH          = YES
+INCLUDED_BY_GRAPH      = YES
+CALL_GRAPH             = YES
+GRAPHICAL_HIERARCHY    = YES
+DIRECTORY_GRAPH        = YES
+DOT_IMAGE_FORMAT       = jpg
+DOT_PATH               = 
+DOTFILE_DIRS           = 
+MAX_DOT_GRAPH_WIDTH    = 1024
+MAX_DOT_GRAPH_HEIGHT   = 1024
+MAX_DOT_GRAPH_DEPTH    = 1000
+DOT_TRANSPARENT        = NO
+DOT_MULTI_TARGETS      = NO
+GENERATE_LEGEND        = YES
+DOT_CLEANUP            = YES
+#---------------------------------------------------------------------------
+# Configuration::additions related to the search engine   
+#---------------------------------------------------------------------------
+SEARCHENGINE           = NO

Added: freeswitch/trunk/libs/freetdm/freetdm.2008.sln (0 => 17141)


--- freeswitch/trunk/libs/freetdm/freetdm.2008.sln	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/freetdm.2008.sln	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,112 @@
+
+Microsoft Visual Studio Solution File, Format Version 10.00
+# Visual Studio 2008
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "freetdm", "msvc\freetdm.2008.vcproj", "{93B8812C-3EC4-4F78-8970-FFBFC99E167D}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testanalog", "msvc\testanalog\testanalog.2008.vcproj", "{BB833648-BAFF-4BE2-94DB-F8BB043C588C}"
+	ProjectSection(ProjectDependencies) = postProject
+		{93B8812C-3EC4-4F78-8970-FFBFC99E167D} = {93B8812C-3EC4-4F78-8970-FFBFC99E167D}
+	EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testisdn", "msvc\testisdn\testisdn.2008.vcproj", "{6DA6FD42-641D-4147-92F5-3BC4AAA6589B}"
+	ProjectSection(ProjectDependencies) = postProject
+		{93B8812C-3EC4-4F78-8970-FFBFC99E167D} = {93B8812C-3EC4-4F78-8970-FFBFC99E167D}
+	EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_freetdm", "mod_freetdm\mod_freetdm.2008.vcproj", "{FE3540C5-3303-46E0-A69E-D92F775687F1}"
+	ProjectSection(ProjectDependencies) = postProject
+		{93B8812C-3EC4-4F78-8970-FFBFC99E167D} = {93B8812C-3EC4-4F78-8970-FFBFC99E167D}
+	EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ftmod_analog", "src\ftmod\ftmod_analog\ftmod_analog.2008.vcproj", "{37C94798-6E33-4B4F-8EE0-C72A7DC91157}"
+	ProjectSection(ProjectDependencies) = postProject
+		{93B8812C-3EC4-4F78-8970-FFBFC99E167D} = {93B8812C-3EC4-4F78-8970-FFBFC99E167D}
+	EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ftmod_analog_em", "src\ftmod\ftmod_analog_em\ftmod_analog_em.2008.vcproj", "{B3F49375-2834-4937-9D8C-4AC2EC911010}"
+	ProjectSection(ProjectDependencies) = postProject
+		{93B8812C-3EC4-4F78-8970-FFBFC99E167D} = {93B8812C-3EC4-4F78-8970-FFBFC99E167D}
+	EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ftmod_isdn", "src\ftmod\ftmod_isdn\ftmod_isdn.2008.vcproj", "{729344A5-D5E9-434D-8EE8-AF8C6C795D15}"
+	ProjectSection(ProjectDependencies) = postProject
+		{93B8812C-3EC4-4F78-8970-FFBFC99E167D} = {93B8812C-3EC4-4F78-8970-FFBFC99E167D}
+	EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ftmod_pika", "src\ftmod\ftmod_pika\ftmod_pika.2008.vcproj", "{E886B4D5-AB4F-4092-B8F4-3B06E1E462EF}"
+	ProjectSection(ProjectDependencies) = postProject
+		{93B8812C-3EC4-4F78-8970-FFBFC99E167D} = {93B8812C-3EC4-4F78-8970-FFBFC99E167D}
+	EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ftmod_wanpipe", "src\ftmod\ftmod_wanpipe\ftmod_wanpipe.2008.vcproj", "{1A145EE9-BBD8-45E5-98CD-EB4BE99E1DCD}"
+	ProjectSection(ProjectDependencies) = postProject
+		{93B8812C-3EC4-4F78-8970-FFBFC99E167D} = {93B8812C-3EC4-4F78-8970-FFBFC99E167D}
+	EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ftmod_sangoma_boost", "src\ftmod\ftmod_sangoma_boost\ftmod_sangoma_boost.2008.vcproj", "{D021EF2A-460D-4827-A0F7-41FDECF46F1B}"
+	ProjectSection(ProjectDependencies) = postProject
+		{93B8812C-3EC4-4F78-8970-FFBFC99E167D} = {93B8812C-3EC4-4F78-8970-FFBFC99E167D}
+	EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testboost", "msvc\testboost\testboost.2008.vcproj", "{2B1BAF36-0241-43E7-B865-A8338AD48E2E}"
+	ProjectSection(ProjectDependencies) = postProject
+		{93B8812C-3EC4-4F78-8970-FFBFC99E167D} = {93B8812C-3EC4-4F78-8970-FFBFC99E167D}
+	EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testsangomaboost", "msvc\testboost\testsangomaboost.2008.vcproj", "{0DA69C18-4FA1-4E8C-89CE-12498637C5BE}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Win32 = Debug|Win32
+		Release|Win32 = Release|Win32
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{93B8812C-3EC4-4F78-8970-FFBFC99E167D}.Debug|Win32.ActiveCfg = Debug|Win32
+		{93B8812C-3EC4-4F78-8970-FFBFC99E167D}.Debug|Win32.Build.0 = Debug|Win32
+		{93B8812C-3EC4-4F78-8970-FFBFC99E167D}.Release|Win32.ActiveCfg = Release|Win32
+		{93B8812C-3EC4-4F78-8970-FFBFC99E167D}.Release|Win32.Build.0 = Release|Win32
+		{BB833648-BAFF-4BE2-94DB-F8BB043C588C}.Debug|Win32.ActiveCfg = Debug|Win32
+		{BB833648-BAFF-4BE2-94DB-F8BB043C588C}.Debug|Win32.Build.0 = Debug|Win32
+		{BB833648-BAFF-4BE2-94DB-F8BB043C588C}.Release|Win32.ActiveCfg = Release|Win32
+		{BB833648-BAFF-4BE2-94DB-F8BB043C588C}.Release|Win32.Build.0 = Release|Win32
+		{6DA6FD42-641D-4147-92F5-3BC4AAA6589B}.Debug|Win32.ActiveCfg = Debug|Win32
+		{6DA6FD42-641D-4147-92F5-3BC4AAA6589B}.Debug|Win32.Build.0 = Debug|Win32
+		{6DA6FD42-641D-4147-92F5-3BC4AAA6589B}.Release|Win32.ActiveCfg = Release|Win32
+		{6DA6FD42-641D-4147-92F5-3BC4AAA6589B}.Release|Win32.Build.0 = Release|Win32
+		{FE3540C5-3303-46E0-A69E-D92F775687F1}.Debug|Win32.ActiveCfg = Debug|Win32
+		{FE3540C5-3303-46E0-A69E-D92F775687F1}.Debug|Win32.Build.0 = Debug|Win32
+		{FE3540C5-3303-46E0-A69E-D92F775687F1}.Release|Win32.ActiveCfg = Release|Win32
+		{FE3540C5-3303-46E0-A69E-D92F775687F1}.Release|Win32.Build.0 = Release|Win32
+		{37C94798-6E33-4B4F-8EE0-C72A7DC91157}.Debug|Win32.ActiveCfg = Debug|Win32
+		{37C94798-6E33-4B4F-8EE0-C72A7DC91157}.Debug|Win32.Build.0 = Debug|Win32
+		{37C94798-6E33-4B4F-8EE0-C72A7DC91157}.Release|Win32.ActiveCfg = Release|Win32
+		{37C94798-6E33-4B4F-8EE0-C72A7DC91157}.Release|Win32.Build.0 = Release|Win32
+		{B3F49375-2834-4937-9D8C-4AC2EC911010}.Debug|Win32.ActiveCfg = Debug|Win32
+		{B3F49375-2834-4937-9D8C-4AC2EC911010}.Debug|Win32.Build.0 = Debug|Win32
+		{B3F49375-2834-4937-9D8C-4AC2EC911010}.Release|Win32.ActiveCfg = Release|Win32
+		{B3F49375-2834-4937-9D8C-4AC2EC911010}.Release|Win32.Build.0 = Release|Win32
+		{729344A5-D5E9-434D-8EE8-AF8C6C795D15}.Debug|Win32.ActiveCfg = Debug|Win32
+		{729344A5-D5E9-434D-8EE8-AF8C6C795D15}.Debug|Win32.Build.0 = Debug|Win32
+		{729344A5-D5E9-434D-8EE8-AF8C6C795D15}.Release|Win32.ActiveCfg = Release|Win32
+		{729344A5-D5E9-434D-8EE8-AF8C6C795D15}.Release|Win32.Build.0 = Release|Win32
+		{E886B4D5-AB4F-4092-B8F4-3B06E1E462EF}.Debug|Win32.ActiveCfg = Debug|Win32
+		{E886B4D5-AB4F-4092-B8F4-3B06E1E462EF}.Release|Win32.ActiveCfg = Release|Win32
+		{1A145EE9-BBD8-45E5-98CD-EB4BE99E1DCD}.Debug|Win32.ActiveCfg = Debug|Win32
+		{1A145EE9-BBD8-45E5-98CD-EB4BE99E1DCD}.Release|Win32.ActiveCfg = Release|Win32
+		{D021EF2A-460D-4827-A0F7-41FDECF46F1B}.Debug|Win32.ActiveCfg = Debug|Win32
+		{D021EF2A-460D-4827-A0F7-41FDECF46F1B}.Debug|Win32.Build.0 = Debug|Win32
+		{D021EF2A-460D-4827-A0F7-41FDECF46F1B}.Release|Win32.ActiveCfg = Release|Win32
+		{D021EF2A-460D-4827-A0F7-41FDECF46F1B}.Release|Win32.Build.0 = Release|Win32
+		{2B1BAF36-0241-43E7-B865-A8338AD48E2E}.Debug|Win32.ActiveCfg = Debug|Win32
+		{2B1BAF36-0241-43E7-B865-A8338AD48E2E}.Debug|Win32.Build.0 = Debug|Win32
+		{2B1BAF36-0241-43E7-B865-A8338AD48E2E}.Release|Win32.ActiveCfg = Release|Win32
+		{2B1BAF36-0241-43E7-B865-A8338AD48E2E}.Release|Win32.Build.0 = Release|Win32
+		{0DA69C18-4FA1-4E8C-89CE-12498637C5BE}.Debug|Win32.ActiveCfg = Debug|Win32
+		{0DA69C18-4FA1-4E8C-89CE-12498637C5BE}.Debug|Win32.Build.0 = Debug|Win32
+		{0DA69C18-4FA1-4E8C-89CE-12498637C5BE}.Release|Win32.ActiveCfg = Release|Win32
+		{0DA69C18-4FA1-4E8C-89CE-12498637C5BE}.Release|Win32.Build.0 = Release|Win32
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+EndGlobal

Added: freeswitch/trunk/libs/freetdm/freetdm.pc.in (0 => 17141)


--- freeswitch/trunk/libs/freetdm/freetdm.pc.in	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/freetdm.pc.in	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,17 @@
+#
+# OpenZAP pkg-config file
+#
+prefix=@prefix@
+exec_prefix=${prefix}
+libdir=${exec_prefix}/lib
+includedir=${prefix}/include
+
+Name: OpenZAP
+Description:
+Version: @PACKAGE_VERSION@
+URL: http://www.openzap.org/
+Requires:
+Conflicts:
+Libs: -L${libdir} -lopenzap
+Libs.private: -lm
+Cflags: -I${includedir}

Added: freeswitch/trunk/libs/freetdm/mod_freetdm/Makefile.in (0 => 17141)


--- freeswitch/trunk/libs/freetdm/mod_freetdm/Makefile.in	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/mod_freetdm/Makefile.in	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,23 @@
+FT_CFLAGS=@CFLAGS@ @COMP_VENDOR_CFLAGS@ @DEFS@
+
+BASE=../../..
+FT_DIR=..
+VERBOSE=1
+FTLA=$(FT_DIR)/libfreetdm.la
+LOCAL_CFLAGS=-I$(FT_DIR)/src/include -I$(FT_DIR)/src/isdn/include $(FT_CFLAGS)
+LOCAL_LDFLAGS=-L$(FT_DIR) -lfreetdm 
+include $(BASE)/build/modmake.rules
+
+local_depend: $(FTLA)
+
+$(FTLA): $(FT_DIR)/.update
+	cd $(FT_DIR) && $(MAKE)
+
+local_install:
+	cd $(FT_DIR) && $(MAKE) install
+	[ -f $(DESTDIR)@confdir@/autoload_configs/freetdm.conf.xml ] || cp -f $(FT_DIR)/conf/freetdm.conf.xml  $(DESTDIR)@confdir@/autoload_configs
+
+local_clean:
+	cd $(FT_DIR) && $(MAKE) clean
+
+

Added: freeswitch/trunk/libs/freetdm/mod_freetdm/mod_freetdm.2008.vcproj (0 => 17141)


--- freeswitch/trunk/libs/freetdm/mod_freetdm/mod_freetdm.2008.vcproj	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/mod_freetdm/mod_freetdm.2008.vcproj	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,369 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="9.00"
+	Name="mod_freetdm"
+	ProjectGUID="{FE3540C5-3303-46E0-A69E-D92F775687F1}"
+	RootNamespace="mod_freetdm"
+	Keyword="Win32Proj"
+	TargetFrameworkVersion="131072"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+		<Platform
+			Name="x64"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="2"
+			InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+			CharacterSet="2"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				AdditionalIncludeDirectories="../../../src/include;../src/include;../src/isdn/include"
+				PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS"
+				MinimalRebuild="true"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="3"
+				UsePrecompiledHeader="0"
+				WarningLevel="4"
+				WarnAsError="true"
+				Detect64BitPortabilityProblems="false"
+				DebugInformationFormat="3"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="FreeSwitchCore.lib"
+				OutputFile="$(SolutionDir)$(OutDir)/mod/mod_freetdm.dll"
+				LinkIncremental="2"
+				AdditionalLibraryDirectories="&quot;../../../w32/Library/$(OutDir)&quot;"
+				GenerateDebugInformation="true"
+				ProgramDatabaseFile="$(OutDir)$(TargetName).pdb"
+				SubSystem="2"
+				RandomizedBaseAddress="1"
+				DataExecutionPrevention="0"
+				ImportLibrary="$(OutDir)/mod_freetdm.lib"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="2"
+			InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+			CharacterSet="2"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalIncludeDirectories="../../../src/include;../src/include;../src/isdn/include"
+				PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS"
+				RuntimeLibrary="2"
+				UsePrecompiledHeader="0"
+				WarningLevel="4"
+				WarnAsError="true"
+				Detect64BitPortabilityProblems="false"
+				DebugInformationFormat="3"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="FreeSwitchCore.lib"
+				OutputFile="$(SolutionDir)$(OutDir)/mod/mod_freetdm.dll"
+				LinkIncremental="1"
+				AdditionalLibraryDirectories="&quot;../../../w32/Library/$(OutDir)&quot;"
+				GenerateDebugInformation="true"
+				ProgramDatabaseFile="$(OutDir)$(TargetName).pdb"
+				SubSystem="2"
+				OptimizeReferences="2"
+				EnableCOMDATFolding="2"
+				LinkTimeCodeGeneration="1"
+				RandomizedBaseAddress="1"
+				DataExecutionPrevention="0"
+				ImportLibrary="$(OutDir)/mod_freetdm.lib"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Debug|x64"
+			OutputDirectory="$(PlatformName)\$(ConfigurationName)"
+			IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+			ConfigurationType="2"
+			InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+			CharacterSet="2"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+				TargetEnvironment="3"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				AdditionalIncludeDirectories="../../../src/include;../src/include;../src/isdn/include"
+				PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS"
+				MinimalRebuild="true"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="3"
+				UsePrecompiledHeader="0"
+				WarningLevel="4"
+				WarnAsError="true"
+				Detect64BitPortabilityProblems="false"
+				DebugInformationFormat="3"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="FreeSwitchCore.lib"
+				OutputFile="$(SolutionDir)$(OutDir)/mod/mod_freetdm.dll"
+				LinkIncremental="2"
+				AdditionalLibraryDirectories="&quot;../../../w32/Library/$(OutDir)&quot;"
+				GenerateDebugInformation="true"
+				ProgramDatabaseFile="$(OutDir)$(TargetName).pdb"
+				SubSystem="2"
+				RandomizedBaseAddress="1"
+				DataExecutionPrevention="0"
+				ImportLibrary="$(OutDir)/mod_freetdm.lib"
+				TargetMachine="17"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|x64"
+			OutputDirectory="$(PlatformName)\$(ConfigurationName)"
+			IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+			ConfigurationType="2"
+			InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+			CharacterSet="2"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+				TargetEnvironment="3"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalIncludeDirectories="../../../src/include;../src/include;../src/isdn/include"
+				PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS"
+				RuntimeLibrary="2"
+				UsePrecompiledHeader="0"
+				WarningLevel="4"
+				WarnAsError="true"
+				Detect64BitPortabilityProblems="false"
+				DebugInformationFormat="3"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="FreeSwitchCore.lib"
+				OutputFile="$(SolutionDir)$(OutDir)/mod/mod_freetdm.dll"
+				LinkIncremental="1"
+				AdditionalLibraryDirectories="&quot;../../../w32/Library/$(OutDir)&quot;"
+				GenerateDebugInformation="true"
+				ProgramDatabaseFile="$(OutDir)$(TargetName).pdb"
+				SubSystem="2"
+				OptimizeReferences="2"
+				EnableCOMDATFolding="2"
+				LinkTimeCodeGeneration="1"
+				RandomizedBaseAddress="1"
+				DataExecutionPrevention="0"
+				ImportLibrary="$(OutDir)/mod_freetdm.lib"
+				TargetMachine="17"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<Filter
+			Name="Source Files"
+			Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+			>
+			<File
+				RelativePath=".\mod_freetdm.c"
+				>
+			</File>
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>

Added: freeswitch/trunk/libs/freetdm/mod_freetdm/mod_freetdm.c (0 => 17141)


--- freeswitch/trunk/libs/freetdm/mod_freetdm/mod_freetdm.c	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/mod_freetdm/mod_freetdm.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,3193 @@
+/* 
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ * Copyright (C) 2005/2006, Anthony Minessale II <anthmct@yahoo.com>
+ *
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mftilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mftilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ *
+ * The Initial Developer of the Original Code is
+ * Anthony Minessale II <anthmct@yahoo.com>
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * 
+ * Anthony Minessale II <anthmct@yahoo.com>
+ * Moises Silva <moy@sangoma.com>
+ *
+ *
+ * mod_freetdm.c -- FreeTDM Endpoint Module
+ *
+ */
+#include <switch.h>
+#include "freetdm.h"
+
+#ifndef __FUNCTION__
+#define __FUNCTION__ __SWITCH_FUNC__
+#endif
+
+#define FREETDM_VAR_PREFIX "freetdm_"
+#define FREETDM_VAR_PREFIX_LEN 8
+
+SWITCH_MODULE_LOAD_FUNCTION(mod_freetdm_load);
+SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_freetdm_shutdown);
+SWITCH_MODULE_DEFINITION(mod_freetdm, mod_freetdm_load, mod_freetdm_shutdown, NULL);
+
+switch_endpoint_interface_t *freetdm_endpoint_interface;
+
+static switch_memory_pool_t *module_pool = NULL;
+
+typedef enum {
+	ANALOG_OPTION_NONE = 0,
+	ANALOG_OPTION_3WAY = (1 << 0),
+	ANALOG_OPTION_CALL_SWAP = (1 << 1)
+} analog_option_t;
+
+struct span_config {
+	ftdm_span_t *span;
+	char dialplan[80];
+	char context[80];
+	char dial_regex[256];
+	char fail_dial_regex[256];
+	char hold_music[256];
+	char type[256];	
+	analog_option_t analog_options;
+};
+
+static struct span_config SPAN_CONFIG[FTDM_MAX_SPANS_INTERFACE] = {{0}};
+
+typedef enum {
+	TFLAG_IO = (1 << 0),
+	TFLAG_DTMF = (1 << 1),
+	TFLAG_CODEC = (1 << 2),
+	TFLAG_BREAK = (1 << 3),
+	TFLAG_HOLD = (1 << 4),
+	TFLAG_DEAD = (1 << 5)
+} TFLAGS;
+
+static struct {
+	int debug;
+	char *dialplan;
+	char *codec_string;
+	char *codec_order[SWITCH_MAX_CODECS];
+	int codec_order_last;
+	char *codec_rates_string;
+	char *codec_rates[SWITCH_MAX_CODECS];
+	int codec_rates_last;
+	unsigned int flags;
+	int fd;
+	int calls;
+	char hold_music[256];
+	switch_mutex_t *mutex;
+	analog_option_t analog_options;
+} globals;
+
+struct private_object {
+	unsigned int flags;
+	switch_codec_t read_codec;
+	switch_codec_t write_codec;
+	switch_frame_t read_frame;
+	unsigned char databuf[SWITCH_RECOMMENDED_BUFFER_SIZE];
+	switch_frame_t cng_frame;
+	unsigned char cng_databuf[SWITCH_RECOMMENDED_BUFFER_SIZE];
+	switch_core_session_t *session;
+	switch_caller_profile_t *caller_profile;
+	unsigned int codec;
+	unsigned int codecs;
+	unsigned short samprate;
+	switch_mutex_t *mutex;
+	switch_mutex_t *flag_mutex;
+	ftdm_channel_t *ftdmchan;
+	uint32_t wr_error;
+};
+
+typedef struct private_object private_t;
+
+
+static switch_status_t channel_on_init(switch_core_session_t *session);
+static switch_status_t channel_on_hangup(switch_core_session_t *session);
+static switch_status_t channel_on_destroy(switch_core_session_t *session);
+static switch_status_t channel_on_routing(switch_core_session_t *session);
+static switch_status_t channel_on_exchange_media(switch_core_session_t *session);
+static switch_status_t channel_on_soft_execute(switch_core_session_t *session);
+static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *session, switch_event_t *var_event,
+													switch_caller_profile_t *outbound_profile,
+													switch_core_session_t **new_session, 
+													switch_memory_pool_t **pool,
+													switch_originate_flag_t flags, switch_call_cause_t *cancel_cause);
+static switch_status_t channel_read_frame(switch_core_session_t *session, switch_frame_t **frame, switch_io_flag_t flags, int stream_id);
+static switch_status_t channel_write_frame(switch_core_session_t *session, switch_frame_t *frame, switch_io_flag_t flags, int stream_id);
+static switch_status_t channel_kill_channel(switch_core_session_t *session, int sig);
+ftdm_status_t ftdm_channel_from_event(ftdm_sigmsg_t *sigmsg, switch_core_session_t **sp);
+void dump_chan(ftdm_span_t *span, uint32_t chan_id, switch_stream_handle_t *stream);
+void dump_chan_xml(ftdm_span_t *span, uint32_t chan_id, switch_stream_handle_t *stream);
+
+static switch_core_session_t *ftdm_channel_get_session(ftdm_channel_t *channel, int32_t id)
+{
+	switch_core_session_t *session = NULL;
+
+	if (id > FTDM_MAX_TOKENS) {
+		return NULL;
+	}
+
+	if (!zstr(channel->tokens[id])) {
+		if (!(session = switch_core_session_locate(channel->tokens[id]))) {
+			ftdm_channel_clear_token(channel, channel->tokens[id]);
+		}
+	}
+
+	return session;
+}
+
+static const char *ftdm_channel_get_uuid(ftdm_channel_t *channel, int32_t id)
+{
+	if (id > FTDM_MAX_TOKENS) {
+		return NULL;
+	}
+
+	if (!zstr(channel->tokens[id])) {
+		return channel->tokens[id];
+	}
+	return NULL;
+}
+
+static void stop_hold(switch_core_session_t *session_a, const char *uuid)
+{
+	switch_core_session_t *session;
+	switch_channel_t *channel, *channel_a;
+	;
+
+	if (!uuid) {
+		return;
+	}
+
+	if ((session = switch_core_session_locate(uuid))) {
+		channel = switch_core_session_get_channel(session);
+
+		if (switch_channel_test_flag(channel, CF_HOLD)) {
+			channel_a = switch_core_session_get_channel(session_a);
+			switch_ivr_unhold(session);
+			switch_channel_clear_flag(channel_a, CF_SUSPEND);
+			switch_channel_clear_flag(channel_a, CF_HOLD);
+		} else {
+			switch_channel_stop_broadcast(channel);
+			switch_channel_wait_for_flag(channel, CF_BROADCAST, SWITCH_FALSE, 2000, NULL);
+		}
+
+		switch_core_session_rwunlock(session);
+	}
+}
+
+static void start_hold(ftdm_channel_t *ftdmchan, switch_core_session_t *session_a, const char *uuid, const char *stream)
+{
+	switch_core_session_t *session;
+	switch_channel_t *channel, *channel_a;
+
+	if (!uuid) {
+		return;
+	}
+	
+	
+	if ((session = switch_core_session_locate(uuid))) {
+		channel = switch_core_session_get_channel(session);
+		if (zstr(stream)) {
+			if (!strcasecmp(globals.hold_music, "indicate_hold")) {
+				stream = "indicate_hold";
+			}
+			if (!strcasecmp(SPAN_CONFIG[ftdmchan->span->span_id].hold_music, "indicate_hold")) {
+				stream = "indicate_hold";
+			}
+		}
+
+		if (zstr(stream)) {
+			stream = switch_channel_get_variable(channel, SWITCH_HOLD_MUSIC_VARIABLE);
+		}
+
+		if (zstr(stream)) {
+			stream = SPAN_CONFIG[ftdmchan->span->span_id].hold_music;
+		}
+
+		if (zstr(stream)) {
+			stream = globals.hold_music;
+		}
+		
+		
+		if (zstr(stream) && !(stream = switch_channel_get_variable(channel, SWITCH_HOLD_MUSIC_VARIABLE))) {
+			stream = globals.hold_music;
+		}
+
+		if (!zstr(stream)) {
+			if (!strcasecmp(stream, "indicate_hold")) {
+				channel_a = switch_core_session_get_channel(session_a);
+				switch_ivr_hold_uuid(uuid, NULL, 0);
+				switch_channel_set_flag(channel_a, CF_SUSPEND);
+				switch_channel_set_flag(channel_a, CF_HOLD);
+			} else {
+				switch_ivr_broadcast(switch_core_session_get_uuid(session), stream, SMF_ECHO_ALEG | SMF_LOOP);
+			}
+		}
+
+		switch_core_session_rwunlock(session);
+	}
+}
+
+
+static void cycle_foreground(ftdm_channel_t *ftdmchan, int flash, const char *bcast) {
+	uint32_t i = 0;
+	switch_core_session_t *session;
+	switch_channel_t *channel;
+	private_t *tech_pvt;
+	
+
+	for (i = 0; i < ftdmchan->token_count; i++) {
+		if ((session = ftdm_channel_get_session(ftdmchan, i))) {
+			const char *buuid;
+			tech_pvt = switch_core_session_get_private(session);
+			channel = switch_core_session_get_channel(session);
+			buuid = switch_channel_get_variable(channel, SWITCH_SIGNAL_BOND_VARIABLE);
+
+			
+			if (ftdmchan->token_count == 1 && flash) {
+				if (switch_test_flag(tech_pvt, TFLAG_HOLD)) {
+					stop_hold(session, buuid);
+					switch_clear_flag_locked(tech_pvt, TFLAG_HOLD);
+				} else {
+					start_hold(ftdmchan, session, buuid, bcast);
+					switch_set_flag_locked(tech_pvt, TFLAG_HOLD);
+				}
+			} else if (i) {
+				start_hold(ftdmchan, session, buuid, bcast);
+				switch_set_flag_locked(tech_pvt, TFLAG_HOLD);
+			} else {
+				stop_hold(session, buuid);
+				switch_clear_flag_locked(tech_pvt, TFLAG_HOLD);
+				if (!switch_channel_test_flag(channel, CF_ANSWERED)) {
+					switch_channel_mark_answered(channel);
+				}
+			}
+			switch_core_session_rwunlock(session);
+		}
+	}
+}
+
+
+
+
+static switch_status_t tech_init(private_t *tech_pvt, switch_core_session_t *session, ftdm_channel_t *ftdmchan)
+{
+	const char *dname = NULL;
+	uint32_t interval = 0, srate = 8000;
+	ftdm_codec_t codec;
+
+	tech_pvt->ftdmchan = ftdmchan;
+	tech_pvt->read_frame.data = tech_pvt->databuf;
+	tech_pvt->read_frame.buflen = sizeof(tech_pvt->databuf);
+	tech_pvt->cng_frame.data = tech_pvt->cng_databuf;
+	tech_pvt->cng_frame.buflen = sizeof(tech_pvt->cng_databuf);
+	tech_pvt->cng_frame.flags = SFF_CNG;
+	tech_pvt->cng_frame.codec = &tech_pvt->read_codec;
+	memset(tech_pvt->cng_frame.data, 255, tech_pvt->cng_frame.buflen);
+	switch_mutex_init(&tech_pvt->mutex, SWITCH_MUTEX_NESTED, switch_core_session_get_pool(session));
+	switch_mutex_init(&tech_pvt->flag_mutex, SWITCH_MUTEX_NESTED, switch_core_session_get_pool(session));
+	switch_core_session_set_private(session, tech_pvt);
+	tech_pvt->session = session;
+
+	if (FTDM_SUCCESS != ftdm_channel_command(ftdmchan, FTDM_COMMAND_GET_INTERVAL, &interval)) {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to retrieve channel interval.\n");
+		return SWITCH_STATUS_GENERR;
+	}
+
+	if (FTDM_SUCCESS != ftdm_channel_command(ftdmchan, FTDM_COMMAND_GET_CODEC, &codec)) {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to retrieve channel codec.\n");
+		return SWITCH_STATUS_GENERR;
+	}
+
+	switch(codec) {
+	case FTDM_CODEC_ULAW:
+		{
+			dname = "PCMU";
+		}
+		break;
+	case FTDM_CODEC_ALAW:
+		{
+			dname = "PCMA";
+		}
+		break;
+	case FTDM_CODEC_SLIN:
+		{
+			dname = "L16";
+		}
+		break;
+	default:
+		{
+			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid codec value retrieved from channel, codec value: %d\n", codec);
+			return SWITCH_STATUS_GENERR;
+		}
+	}
+
+
+	if (switch_core_codec_init(&tech_pvt->read_codec,
+							   dname,
+							   NULL,
+							   srate,
+							   interval,
+							   1,
+							   SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE,
+							   NULL, switch_core_session_get_pool(tech_pvt->session)) != SWITCH_STATUS_SUCCESS) {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't load codec?\n");
+		return SWITCH_STATUS_GENERR;
+	} else {
+		if (switch_core_codec_init(&tech_pvt->write_codec,
+								   dname,
+								   NULL,
+								   srate,
+								   interval,
+								   1,
+								   SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE,
+								   NULL, switch_core_session_get_pool(tech_pvt->session)) != SWITCH_STATUS_SUCCESS) {
+			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't load codec?\n");
+			switch_core_codec_destroy(&tech_pvt->read_codec);
+			return SWITCH_STATUS_GENERR;
+		}
+	}
+
+	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Set codec %s %dms\n", dname, interval);
+	switch_core_session_set_read_codec(tech_pvt->session, &tech_pvt->read_codec);
+	switch_core_session_set_write_codec(tech_pvt->session, &tech_pvt->write_codec);
+	switch_set_flag_locked(tech_pvt, TFLAG_CODEC);
+	tech_pvt->read_frame.codec = &tech_pvt->read_codec;
+	switch_set_flag_locked(tech_pvt, TFLAG_IO);
+
+	return SWITCH_STATUS_SUCCESS;
+	
+}
+
+static switch_status_t channel_on_init(switch_core_session_t *session)
+{
+	switch_channel_t *channel;
+	private_t *tech_pvt = NULL;
+
+	tech_pvt = switch_core_session_get_private(session);
+	assert(tech_pvt != NULL);
+
+	channel = switch_core_session_get_channel(session);
+	assert(channel != NULL);
+
+	if (switch_test_flag(tech_pvt, TFLAG_DEAD)) {
+		switch_channel_hangup(channel, SWITCH_CAUSE_LOSE_RACE);
+		return SWITCH_STATUS_SUCCESS;
+	} 
+	
+	/* Move channel's state machine to ROUTING */
+	switch_channel_set_state(channel, CS_ROUTING);
+	switch_mutex_lock(globals.mutex);
+	globals.calls++;
+	switch_mutex_unlock(globals.mutex);
+
+	ftdm_channel_init(tech_pvt->ftdmchan);
+
+	//switch_channel_set_flag(channel, CF_ACCEPT_CNG);
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t channel_on_routing(switch_core_session_t *session)
+{
+	switch_channel_t *channel = NULL;
+	private_t *tech_pvt = NULL;
+
+	channel = switch_core_session_get_channel(session);
+	assert(channel != NULL);
+
+	tech_pvt = switch_core_session_get_private(session);
+	assert(tech_pvt != NULL);
+
+	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s CHANNEL ROUTING\n", switch_channel_get_name(channel));
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t channel_on_execute(switch_core_session_t *session)
+{
+
+	switch_channel_t *channel = NULL;
+	private_t *tech_pvt = NULL;
+
+	channel = switch_core_session_get_channel(session);
+	assert(channel != NULL);
+
+	tech_pvt = switch_core_session_get_private(session);
+	assert(tech_pvt != NULL);
+
+	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s CHANNEL EXECUTE\n", switch_channel_get_name(channel));
+
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t channel_on_destroy(switch_core_session_t *session)
+{
+	private_t *tech_pvt = NULL;
+	
+	if ((tech_pvt = switch_core_session_get_private(session))) {
+
+		if (tech_pvt->read_codec.implementation) {
+			switch_core_codec_destroy(&tech_pvt->read_codec);
+		}
+		
+		if (tech_pvt->write_codec.implementation) {
+			switch_core_codec_destroy(&tech_pvt->write_codec);
+		}
+	}
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t channel_on_hangup(switch_core_session_t *session)
+{
+	switch_channel_t *channel = NULL;
+	private_t *tech_pvt = NULL;
+
+	channel = switch_core_session_get_channel(session);
+	assert(channel != NULL);
+
+	tech_pvt = switch_core_session_get_private(session);
+	assert(tech_pvt != NULL);
+
+	if (!tech_pvt->ftdmchan) {
+		goto end;
+	} 
+
+	ftdm_channel_clear_token(tech_pvt->ftdmchan, switch_core_session_get_uuid(session));
+	
+	switch (tech_pvt->ftdmchan->type) {
+	case FTDM_CHAN_TYPE_FXO:
+	case FTDM_CHAN_TYPE_EM:
+	case FTDM_CHAN_TYPE_CAS:
+		{
+			ftdm_set_state_locked(tech_pvt->ftdmchan, FTDM_CHANNEL_STATE_HANGUP);
+		}
+		break;
+	case FTDM_CHAN_TYPE_FXS:
+		{
+			if (tech_pvt->ftdmchan->state != FTDM_CHANNEL_STATE_BUSY && tech_pvt->ftdmchan->state != FTDM_CHANNEL_STATE_DOWN) {
+				if (tech_pvt->ftdmchan->token_count) {
+					cycle_foreground(tech_pvt->ftdmchan, 0, NULL);
+				} else {
+					ftdm_set_state_locked(tech_pvt->ftdmchan, FTDM_CHANNEL_STATE_HANGUP);
+				}
+			}
+		}
+		break;
+	case FTDM_CHAN_TYPE_B:
+		{
+			if (tech_pvt->ftdmchan->state != FTDM_CHANNEL_STATE_DOWN) {
+				if (tech_pvt->ftdmchan->state != FTDM_CHANNEL_STATE_TERMINATING) {
+					tech_pvt->ftdmchan->caller_data.hangup_cause = switch_channel_get_cause_q850(channel);
+					if (tech_pvt->ftdmchan->caller_data.hangup_cause < 1 || tech_pvt->ftdmchan->caller_data.hangup_cause > 127) {
+						tech_pvt->ftdmchan->caller_data.hangup_cause = FTDM_CAUSE_DESTINATION_OUT_OF_ORDER;
+					}
+				}
+				ftdm_set_state_locked(tech_pvt->ftdmchan, FTDM_CHANNEL_STATE_HANGUP);
+			}
+		}
+		break;
+	default: 
+		{
+			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Unhandled channel type %d for channel %s\n", tech_pvt->ftdmchan->type,
+                    switch_channel_get_name(channel));
+		}
+		break;
+	}
+
+ end:
+
+	switch_clear_flag_locked(tech_pvt, TFLAG_IO);
+	
+	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s CHANNEL HANGUP\n", switch_channel_get_name(channel));
+	switch_mutex_lock(globals.mutex);
+	globals.calls--;
+	if (globals.calls < 0) {
+		globals.calls = 0;
+	}
+	switch_mutex_unlock(globals.mutex);
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t channel_kill_channel(switch_core_session_t *session, int sig)
+{
+	switch_channel_t *channel = NULL;
+	private_t *tech_pvt = NULL;
+
+	channel = switch_core_session_get_channel(session);
+	assert(channel != NULL);
+
+	tech_pvt = switch_core_session_get_private(session);
+	assert(tech_pvt != NULL);
+
+	switch (sig) {
+	case SWITCH_SIG_KILL:
+		switch_clear_flag_locked(tech_pvt, TFLAG_IO);
+		switch_set_flag_locked(tech_pvt, TFLAG_DEAD);
+		break;
+	case SWITCH_SIG_BREAK:
+		switch_set_flag_locked(tech_pvt, TFLAG_BREAK);
+		break;
+	default:
+		break;
+	}
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t channel_on_exchange_media(switch_core_session_t *session)
+{
+	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "CHANNEL EXCHANGE_MEDIA\n");
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t channel_on_soft_execute(switch_core_session_t *session)
+{
+	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "CHANNEL SOFT_EXECUTE\n");
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t channel_send_dtmf(switch_core_session_t *session, const switch_dtmf_t *dtmf)
+{
+	private_t *tech_pvt = NULL;
+	char tmp[2] = "";
+
+	tech_pvt = switch_core_session_get_private(session);
+	assert(tech_pvt != NULL);
+
+	if (switch_test_flag(tech_pvt, TFLAG_DEAD)) {
+		switch_channel_hangup(switch_core_session_get_channel(session), SWITCH_CAUSE_LOSE_RACE);
+		return SWITCH_STATUS_FALSE;
+	} 
+
+	tmp[0] = dtmf->digit;
+	ftdm_channel_command(tech_pvt->ftdmchan, FTDM_COMMAND_SEND_DTMF, tmp);
+		
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t channel_read_frame(switch_core_session_t *session, switch_frame_t **frame, switch_io_flag_t flags, int stream_id)
+{
+	switch_channel_t *channel = NULL;
+	private_t *tech_pvt = NULL;
+	ftdm_size_t len;
+	ftdm_wait_flag_t wflags = FTDM_READ;
+	char dtmf[128] = "";
+	ftdm_status_t status;
+	int total_to;
+	int chunk, do_break = 0;
+
+
+	channel = switch_core_session_get_channel(session);
+	assert(channel != NULL);
+	
+	
+	tech_pvt = switch_core_session_get_private(session);
+	assert(tech_pvt != NULL);
+
+	if (switch_test_flag(tech_pvt, TFLAG_DEAD)) {
+		return SWITCH_STATUS_FALSE;
+	} 
+
+	/* Digium Cards sometimes timeout several times in a row here. 
+	   Yes, we support digium cards, ain't we nice.......
+	   6 double length intervals should compensate */
+	chunk = tech_pvt->ftdmchan->effective_interval * 2;
+	total_to = chunk * 6;
+
+ top:
+
+	if (switch_channel_test_flag(channel, CF_SUSPEND)) {
+		do_break = 1;
+	}
+
+	if (switch_test_flag(tech_pvt, TFLAG_BREAK)) {
+		switch_clear_flag_locked(tech_pvt, TFLAG_BREAK);
+		do_break = 1;
+	}
+
+	if (switch_test_flag(tech_pvt, TFLAG_HOLD) || do_break) {
+		switch_yield(tech_pvt->ftdmchan->effective_interval * 1000);
+		tech_pvt->cng_frame.datalen = tech_pvt->ftdmchan->packet_len;
+		tech_pvt->cng_frame.samples = tech_pvt->cng_frame.datalen;
+		tech_pvt->cng_frame.flags = SFF_CNG;
+		*frame = &tech_pvt->cng_frame;
+		if (tech_pvt->ftdmchan->effective_codec == FTDM_CODEC_SLIN) {
+			tech_pvt->cng_frame.samples /= 2;
+		}
+		return SWITCH_STATUS_SUCCESS;
+	}
+	
+	if (!switch_test_flag(tech_pvt, TFLAG_IO)) {
+		goto fail;
+	}
+
+	wflags = FTDM_READ;	
+	status = ftdm_channel_wait(tech_pvt->ftdmchan, &wflags, chunk);
+	
+	if (status == FTDM_FAIL) {
+		goto fail;
+	}
+	
+	if (status == FTDM_TIMEOUT) {
+		if (!switch_test_flag(tech_pvt, TFLAG_HOLD)) {
+			total_to -= chunk;
+			if (total_to <= 0) {
+				goto fail;
+			}
+		}
+
+		goto top;
+	}
+
+	if (!(wflags & FTDM_READ)) {
+		goto fail;
+	}
+
+	len = tech_pvt->read_frame.buflen;
+	if (ftdm_channel_read(tech_pvt->ftdmchan, tech_pvt->read_frame.data, &len) != FTDM_SUCCESS) {
+		goto fail;
+	}
+
+	*frame = &tech_pvt->read_frame;
+	tech_pvt->read_frame.datalen = (uint32_t)len;
+	tech_pvt->read_frame.samples = tech_pvt->read_frame.datalen;
+
+	if (tech_pvt->ftdmchan->effective_codec == FTDM_CODEC_SLIN) {
+		tech_pvt->read_frame.samples /= 2;
+	}
+
+	while (ftdm_channel_dequeue_dtmf(tech_pvt->ftdmchan, dtmf, sizeof(dtmf))) {
+		switch_dtmf_t _dtmf = { 0, SWITCH_DEFAULT_DTMF_DURATION };
+		char *p;
+		for (p = dtmf; p && *p; p++) {
+			if (is_dtmf(*p)) {
+				_dtmf.digit = *p;
+				ftdm_log(FTDM_LOG_DEBUG, "queue DTMF [%c]\n", *p);
+				switch_channel_queue_dtmf(channel, &_dtmf);
+			}
+		}
+	}
+	return SWITCH_STATUS_SUCCESS;
+
+ fail:
+	switch_clear_flag_locked(tech_pvt, TFLAG_IO);
+	return SWITCH_STATUS_GENERR;
+	
+
+}
+
+static switch_status_t channel_write_frame(switch_core_session_t *session, switch_frame_t *frame, switch_io_flag_t flags, int stream_id)
+{
+	switch_channel_t *channel = NULL;
+	private_t *tech_pvt = NULL;
+	ftdm_size_t len;
+	unsigned char data[SWITCH_RECOMMENDED_BUFFER_SIZE] = {0};
+	ftdm_wait_flag_t wflags = FTDM_WRITE;
+	ftdm_status_t status;
+
+	channel = switch_core_session_get_channel(session);
+	assert(channel != NULL);
+
+	tech_pvt = switch_core_session_get_private(session);
+	assert(tech_pvt != NULL);
+
+	if (!tech_pvt->ftdmchan) {
+		return SWITCH_STATUS_FALSE;
+	} 
+
+	if (switch_test_flag(tech_pvt, TFLAG_DEAD)) {
+		return SWITCH_STATUS_FALSE;
+	}
+
+	if (switch_test_flag(tech_pvt, TFLAG_HOLD)) {
+		return SWITCH_STATUS_SUCCESS;
+	}
+
+	if (!switch_test_flag(tech_pvt, TFLAG_IO)) {
+		goto fail;
+	}
+	
+	if (switch_test_flag(frame, SFF_CNG)) {
+		frame->data = data;
+		frame->buflen = sizeof(data);
+		if ((frame->datalen = tech_pvt->write_codec.implementation->encoded_bytes_per_packet) > frame->buflen) {
+			goto fail;
+		}
+		memset(data, 255, frame->datalen);
+	}
+
+
+	wflags = FTDM_WRITE;	
+	status = ftdm_channel_wait(tech_pvt->ftdmchan, &wflags, tech_pvt->ftdmchan->effective_interval * 10);
+	
+	if (!(wflags & FTDM_WRITE)) {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Dropping frame! (write not ready)\n");
+		return SWITCH_STATUS_SUCCESS;
+	}
+
+	len = frame->datalen;
+	if (ftdm_channel_write(tech_pvt->ftdmchan, frame->data, frame->buflen, &len) != FTDM_SUCCESS) {
+		if (++tech_pvt->wr_error > 10) {
+			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "too many I/O write errors!\n");
+			goto fail;
+		}
+	} else {
+		tech_pvt->wr_error = 0;
+	}
+
+	return SWITCH_STATUS_SUCCESS;
+
+ fail:
+	
+	switch_clear_flag_locked(tech_pvt, TFLAG_IO);
+	return SWITCH_STATUS_GENERR;
+
+}
+
+static switch_status_t channel_receive_message_cas(switch_core_session_t *session, switch_core_session_message_t *msg)
+{
+	switch_channel_t *channel;
+	private_t *tech_pvt;
+
+	channel = switch_core_session_get_channel(session);
+	assert(channel != NULL);
+			
+	tech_pvt = (private_t *) switch_core_session_get_private(session);
+	assert(tech_pvt != NULL);
+	
+	if (switch_test_flag(tech_pvt, TFLAG_DEAD)) {
+        switch_channel_hangup(channel, SWITCH_CAUSE_LOSE_RACE);
+        return SWITCH_STATUS_FALSE;
+    }
+	
+	ftdm_log(FTDM_LOG_DEBUG, "Got Freeswitch message in R2 channel %d [%d]\n", tech_pvt->ftdmchan->physical_chan_id, 
+            msg->message_id);
+
+	switch (msg->message_id) {
+	case SWITCH_MESSAGE_INDICATE_RINGING:
+		{
+			if (switch_channel_test_flag(channel, CF_OUTBOUND)) {
+				ftdm_set_flag_locked(tech_pvt->ftdmchan, FTDM_CHANNEL_PROGRESS);
+			} else {
+				ftdm_set_state_locked_wait(tech_pvt->ftdmchan, FTDM_CHANNEL_STATE_PROGRESS);
+			}
+		}
+		break;
+	case SWITCH_MESSAGE_INDICATE_PROGRESS:
+		{
+			if (switch_channel_test_flag(channel, CF_OUTBOUND)) {
+				ftdm_set_flag_locked(tech_pvt->ftdmchan, FTDM_CHANNEL_PROGRESS);
+				ftdm_set_flag_locked(tech_pvt->ftdmchan, FTDM_CHANNEL_MEDIA);
+			} else {
+				ftdm_set_state_locked_wait(tech_pvt->ftdmchan, FTDM_CHANNEL_STATE_PROGRESS);
+				ftdm_set_state_locked_wait(tech_pvt->ftdmchan, FTDM_CHANNEL_STATE_PROGRESS_MEDIA);
+			}
+		}
+		break;
+	case SWITCH_MESSAGE_INDICATE_ANSWER:
+		{
+			if (switch_channel_test_flag(channel, CF_OUTBOUND)) {
+				ftdm_set_flag_locked(tech_pvt->ftdmchan, FTDM_CHANNEL_ANSWERED);
+			} else {
+				/* lets make the ftmod_r2 module life easier by moving thru each
+                 * state waiting for completion, clumsy, but does the job
+				 */
+				if (tech_pvt->ftdmchan->state < FTDM_CHANNEL_STATE_PROGRESS) {
+					ftdm_set_state_locked_wait(tech_pvt->ftdmchan, FTDM_CHANNEL_STATE_PROGRESS);
+				}
+				if (tech_pvt->ftdmchan->state < FTDM_CHANNEL_STATE_PROGRESS_MEDIA) {
+					ftdm_set_state_locked_wait(tech_pvt->ftdmchan, FTDM_CHANNEL_STATE_PROGRESS_MEDIA);
+				}
+				ftdm_set_state_locked_wait(tech_pvt->ftdmchan, FTDM_CHANNEL_STATE_UP);
+			}
+		}
+		break;
+	default:
+		break;
+	}
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t channel_receive_message_b(switch_core_session_t *session, switch_core_session_message_t *msg)
+{
+	switch_channel_t *channel;
+	private_t *tech_pvt;
+
+	channel = switch_core_session_get_channel(session);
+	assert(channel != NULL);
+			
+	tech_pvt = (private_t *) switch_core_session_get_private(session);
+	assert(tech_pvt != NULL);
+
+	if (switch_test_flag(tech_pvt, TFLAG_DEAD)) {
+        switch_channel_hangup(channel, SWITCH_CAUSE_LOSE_RACE);
+        return SWITCH_STATUS_FALSE;
+    }
+
+	if (tech_pvt->ftdmchan->state == FTDM_CHANNEL_STATE_TERMINATING) {
+		ftdm_mutex_unlock(tech_pvt->ftdmchan->mutex);	
+		return SWITCH_STATUS_SUCCESS;
+	}
+
+	switch (msg->message_id) {
+	case SWITCH_MESSAGE_INDICATE_RINGING:
+		{
+			if (switch_channel_test_flag(channel, CF_OUTBOUND)) {
+				ftdm_set_flag(tech_pvt->ftdmchan, FTDM_CHANNEL_PROGRESS);
+			} else {
+				ftdm_set_state_wait(tech_pvt->ftdmchan, FTDM_CHANNEL_STATE_PROGRESS);
+			}
+		}
+		break;
+	case SWITCH_MESSAGE_INDICATE_PROGRESS:
+		{
+			if (switch_channel_test_flag(channel, CF_OUTBOUND)) {
+				ftdm_set_flag(tech_pvt->ftdmchan, FTDM_CHANNEL_PROGRESS);
+				ftdm_set_flag(tech_pvt->ftdmchan, FTDM_CHANNEL_MEDIA);
+			} else {
+				/* Don't skip messages in the ISDN call setup
+				 * TODO: make the isdn stack smart enough to handle that itself
+				 *       until then, this is here for safety...
+				 */
+				if (tech_pvt->ftdmchan->state < FTDM_CHANNEL_STATE_PROGRESS) {
+					ftdm_set_state_wait(tech_pvt->ftdmchan, FTDM_CHANNEL_STATE_PROGRESS);
+				}
+				ftdm_set_state_wait(tech_pvt->ftdmchan, FTDM_CHANNEL_STATE_PROGRESS_MEDIA);
+			}
+		}
+		break;
+	case SWITCH_MESSAGE_INDICATE_ANSWER:
+		{
+			if (switch_channel_test_flag(channel, CF_OUTBOUND)) {
+				ftdm_set_flag(tech_pvt->ftdmchan, FTDM_CHANNEL_ANSWERED);
+			} else {
+				/* Don't skip messages in the ISDN call setup
+				 * TODO: make the isdn stack smart enough to handle that itself
+				 *       until then, this is here for safety...
+				 */
+				if (tech_pvt->ftdmchan->state < FTDM_CHANNEL_STATE_PROGRESS) {
+					ftdm_set_state_wait(tech_pvt->ftdmchan, FTDM_CHANNEL_STATE_PROGRESS);
+				}
+				if (tech_pvt->ftdmchan->state < FTDM_CHANNEL_STATE_PROGRESS_MEDIA) {
+					ftdm_set_state_wait(tech_pvt->ftdmchan, FTDM_CHANNEL_STATE_PROGRESS_MEDIA);
+				}
+				ftdm_set_state_wait(tech_pvt->ftdmchan, FTDM_CHANNEL_STATE_UP);
+			}
+		}
+		break;
+	default:
+		break;
+	}
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t channel_receive_message_fxo(switch_core_session_t *session, switch_core_session_message_t *msg)
+{
+	switch_channel_t *channel;
+	private_t *tech_pvt;
+
+	channel = switch_core_session_get_channel(session);
+	assert(channel != NULL);
+			
+	tech_pvt = (private_t *) switch_core_session_get_private(session);
+	assert(tech_pvt != NULL);
+
+	if (switch_test_flag(tech_pvt, TFLAG_DEAD)) {
+        switch_channel_hangup(channel, SWITCH_CAUSE_LOSE_RACE);
+        return SWITCH_STATUS_FALSE;
+    }
+	
+	switch (msg->message_id) {
+	case SWITCH_MESSAGE_INDICATE_PROGRESS:
+	case SWITCH_MESSAGE_INDICATE_ANSWER:
+		if (switch_channel_test_flag(channel, CF_OUTBOUND)) {
+			ftdm_set_flag_locked(tech_pvt->ftdmchan, FTDM_CHANNEL_ANSWERED);
+			ftdm_set_flag_locked(tech_pvt->ftdmchan, FTDM_CHANNEL_PROGRESS);
+			ftdm_set_flag_locked(tech_pvt->ftdmchan, FTDM_CHANNEL_MEDIA);
+		} else {
+			ftdm_set_state_locked(tech_pvt->ftdmchan, FTDM_CHANNEL_STATE_UP);
+		}
+		break;
+	default:
+		break;
+	}
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t channel_receive_message_fxs(switch_core_session_t *session, switch_core_session_message_t *msg)
+{
+	switch_channel_t *channel;
+	private_t *tech_pvt;
+
+	channel = switch_core_session_get_channel(session);
+	assert(channel != NULL);
+			
+	tech_pvt = (private_t *) switch_core_session_get_private(session);
+	assert(tech_pvt != NULL);
+
+	if (switch_test_flag(tech_pvt, TFLAG_DEAD)) {
+        switch_channel_hangup(channel, SWITCH_CAUSE_LOSE_RACE);
+        return SWITCH_STATUS_FALSE;
+    }
+	
+	switch (msg->message_id) {
+	case SWITCH_MESSAGE_INDICATE_PROGRESS:
+	case SWITCH_MESSAGE_INDICATE_ANSWER:
+		if (!switch_channel_test_flag(channel, CF_OUTBOUND)) {
+			ftdm_set_flag_locked(tech_pvt->ftdmchan, FTDM_CHANNEL_ANSWERED);
+			ftdm_set_flag_locked(tech_pvt->ftdmchan, FTDM_CHANNEL_PROGRESS);
+			ftdm_set_flag_locked(tech_pvt->ftdmchan, FTDM_CHANNEL_MEDIA);
+			ftdm_set_state_locked(tech_pvt->ftdmchan, FTDM_CHANNEL_STATE_UP);
+			switch_channel_mark_answered(channel);
+		}
+		break;
+	case SWITCH_MESSAGE_INDICATE_RINGING:
+		if (!switch_channel_test_flag(channel, CF_OUTBOUND)) {
+			
+			if (!switch_channel_test_flag(channel, CF_ANSWERED) && 
+				!switch_channel_test_flag(channel, CF_EARLY_MEDIA) &&
+				!switch_channel_test_flag(channel, CF_RING_READY)
+				) {
+				ftdm_set_state_locked(tech_pvt->ftdmchan, FTDM_CHANNEL_STATE_RING);
+				switch_channel_mark_ring_ready(channel);
+			}
+		}
+		break;
+	default:
+		break;
+	}
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t channel_receive_message(switch_core_session_t *session, switch_core_session_message_t *msg)
+{
+	private_t *tech_pvt;
+	switch_status_t status;
+	switch_channel_t *channel;
+	const char *var;
+	ftdm_channel_t *ftdmchan = NULL;
+
+	tech_pvt = (private_t *) switch_core_session_get_private(session);
+	assert(tech_pvt != NULL);
+
+	channel = switch_core_session_get_channel(session);
+
+	if (switch_test_flag(tech_pvt, TFLAG_DEAD)) {
+        switch_channel_hangup(channel, SWITCH_CAUSE_LOSE_RACE);
+        return SWITCH_STATUS_FALSE;
+	}
+
+	if (!(ftdmchan = tech_pvt->ftdmchan)) {
+        switch_channel_hangup(channel, SWITCH_CAUSE_LOSE_RACE);
+        return SWITCH_STATUS_FALSE;
+    }
+
+	ftdm_mutex_lock(ftdmchan->mutex);	
+
+	if (!tech_pvt->ftdmchan) {
+		switch_channel_hangup(channel, SWITCH_CAUSE_LOSE_RACE);
+		status = SWITCH_STATUS_FALSE;
+		goto end;
+	}
+
+	switch (msg->message_id) {
+	case SWITCH_MESSAGE_INDICATE_PROGRESS:
+	case SWITCH_MESSAGE_INDICATE_ANSWER:
+		if (!switch_channel_test_flag(channel, CF_OUTBOUND)) {
+			if ((var = switch_channel_get_variable(channel, "freetdm_pre_buffer_size"))) {
+				int tmp = atoi(var);
+				if (tmp > -1) {
+					ftdm_channel_command(tech_pvt->ftdmchan, FTDM_COMMAND_SET_PRE_BUFFER_SIZE, &tmp);
+				}
+			}
+		}
+		break;
+	case SWITCH_MESSAGE_INDICATE_UUID_CHANGE:
+		{
+			ftdm_channel_replace_token(tech_pvt->ftdmchan, msg->string_array_arg[0], msg->string_array_arg[1]);
+		}
+		break;
+	default:
+		break;
+	}
+
+	switch (tech_pvt->ftdmchan->type) {
+	case FTDM_CHAN_TYPE_FXS:
+	case FTDM_CHAN_TYPE_EM:
+		status = channel_receive_message_fxs(session, msg);
+		break;
+	case FTDM_CHAN_TYPE_FXO:
+		status = channel_receive_message_fxo(session, msg);
+		break;
+	case FTDM_CHAN_TYPE_B:
+		status = channel_receive_message_b(session, msg);
+        break;
+	case FTDM_CHAN_TYPE_CAS:
+		status = channel_receive_message_cas(session, msg);
+        break;
+	default:
+		status = SWITCH_STATUS_FALSE;
+		break;
+	}
+
+ end:
+
+	ftdm_mutex_unlock(ftdmchan->mutex);	
+
+	return status;
+
+}
+
+switch_state_handler_table_t freetdm_state_handlers = {
+	/*.on_init */ channel_on_init,
+	/*.on_routing */ channel_on_routing,
+	/*.on_execute */ channel_on_execute,
+	/*.on_hangup */ channel_on_hangup,
+	/*.on_exchange_media */ channel_on_exchange_media,
+	/*.on_soft_execute */ channel_on_soft_execute,
+	/*.on_consume_media */ NULL,
+    /*.on_hibernate */ NULL,
+    /*.on_reset */ NULL,
+    /*.on_park*/ NULL,
+    /*.on_reporting*/ NULL,
+    /*.on_destroy*/ channel_on_destroy
+
+};
+
+switch_io_routines_t freetdm_io_routines = {
+	/*.outgoing_channel */ channel_outgoing_channel,
+	/*.read_frame */ channel_read_frame,
+	/*.write_frame */ channel_write_frame,
+	/*.kill_channel */ channel_kill_channel,
+	/*.send_dtmf */ channel_send_dtmf,
+	/*.receive_message*/ channel_receive_message
+};
+
+/* Make sure when you have 2 sessions in the same scope that you pass the appropriate one to the routines
+that allocate memory or you will have 1 channel with memory allocated from another channel's pool!
+*/
+static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *session, switch_event_t *var_event,
+													switch_caller_profile_t *outbound_profile,
+													switch_core_session_t **new_session, switch_memory_pool_t **pool,
+													switch_originate_flag_t flags, switch_call_cause_t *cancel_cause)
+{
+
+	const char *dest = NULL;
+	char *data = NULL;
+	int span_id = -1, group_id = -1,chan_id = 0;
+	ftdm_channel_t *ftdmchan = NULL;
+	switch_call_cause_t cause = SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
+	char name[128];
+	ftdm_status_t status;
+	int direction = FTDM_TOP_DOWN;
+	ftdm_caller_data_t caller_data = {{ 0 }};
+	char *span_name = NULL;
+	switch_event_header_t *h;
+	char *argv[3];
+	int argc = 0;
+	const char *var;
+	const char *dest_num = NULL, *callerid_num = NULL;
+
+	if (!outbound_profile) {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Missing caller profile\n");
+		return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
+	}
+
+	if (zstr(outbound_profile->destination_number)) {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid dial string\n");
+		return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
+	}
+
+
+	data = switch_core_strdup(outbound_profile->pool, outbound_profile->destination_number);
+
+	if (!zstr(outbound_profile->destination_number)) {
+		dest_num = switch_sanitize_number(switch_core_strdup(outbound_profile->pool, outbound_profile->destination_number));
+	}
+
+	if (!zstr(outbound_profile->caller_id_number)) {
+		callerid_num = switch_sanitize_number(switch_core_strdup(outbound_profile->pool, outbound_profile->caller_id_number));
+	}
+
+	if (!zstr(callerid_num) && !strcmp(callerid_num, "0000000000")) {
+		callerid_num = NULL;
+	}
+	
+	if ((argc = switch_separate_string(data, '/', argv, (sizeof(argv) / sizeof(argv[0])))) < 2) {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid dial string\n");
+        return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
+	}
+	
+	if (switch_is_number(argv[0])) {
+		span_id = atoi(argv[0]);
+	} else {
+		span_name = argv[0];
+	}	
+
+	if (*argv[1] == 'A') {
+		direction = FTDM_BOTTOM_UP;
+	} else if (*argv[1] == 'a') {
+		direction =  FTDM_TOP_DOWN;
+	} else {
+		chan_id = atoi(argv[1]);
+	}
+
+	if (!(dest = argv[2])) {
+		dest = "";
+	}
+
+	if (span_id == 0 && chan_id != 0) {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Span 0 is used to pick the first available span, selecting a channel is not supported (and doesn't make sense)\n");
+		return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
+	}
+
+	if (span_id == -1 && !zstr(span_name)) {
+		ftdm_span_t *span;
+		ftdm_status_t zstatus = ftdm_span_find_by_name(span_name, &span);
+		if (zstatus == FTDM_SUCCESS && span) {
+			span_id = span->span_id;
+		}
+	}
+
+	if (span_id == -1) {
+		//Look for a group
+		ftdm_group_t *group;
+		ftdm_status_t zstatus = ftdm_group_find_by_name(span_name, &group);
+		if (zstatus == FTDM_SUCCESS && group) {
+			group_id = group->group_id;
+		} else {
+			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Missing ftdm span or group: %s\n", span_name);
+			return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
+		}
+	}
+
+	if (group_id < 0 && chan_id < 0) {
+		direction = FTDM_BOTTOM_UP;
+		chan_id = 0;
+	}
+	
+	if (switch_test_flag(outbound_profile, SWITCH_CPF_SCREEN)) {
+		caller_data.screen = 1;
+	}
+
+	if (switch_test_flag(outbound_profile, SWITCH_CPF_HIDE_NUMBER)) {
+		caller_data.pres = 1;
+	}
+
+	if (!zstr(dest)) {
+		ftdm_set_string(caller_data.dnis.digits, dest);
+	}
+	
+	if ((var = switch_event_get_header(var_event, "freetdm_outbound_ton")) || (var = switch_core_get_variable("freetdm_outbound_ton"))) {
+		if (!strcasecmp(var, "national")) {
+			caller_data.dnis.type = FTDM_TON_NATIONAL;
+		} else if (!strcasecmp(var, "international")) {
+			caller_data.dnis.type = FTDM_TON_INTERNATIONAL;
+		} else if (!strcasecmp(var, "local")) {
+			caller_data.dnis.type = FTDM_TON_SUBSCRIBER_NUMBER;
+		} else if (!strcasecmp(var, "unknown")) {
+			caller_data.dnis.type = FTDM_TON_UNKNOWN;
+		}
+	} else {
+		caller_data.dnis.type = outbound_profile->destination_number_ton;
+	}
+	
+	caller_data.dnis.plan = outbound_profile->destination_number_numplan;
+
+	/* blindly copy data from outbound_profile. They will be overwritten
+	 * by calling ftdm_caller_data if needed after */
+	caller_data.cid_num.type = outbound_profile->caller_ton;
+	caller_data.cid_num.plan = outbound_profile->caller_numplan;
+	caller_data.rdnis.type = outbound_profile->rdnis_ton;
+	caller_data.rdnis.plan = outbound_profile->rdnis_numplan;
+
+	ftdm_set_string(caller_data.cid_name, outbound_profile->caller_id_name);
+	ftdm_set_string(caller_data.cid_num.digits, switch_str_nil(outbound_profile->caller_id_number));
+
+	if (group_id >= 0) {
+		status = ftdm_channel_open_by_group(group_id, direction, &caller_data, &ftdmchan);
+	} else if (chan_id) {
+		status = ftdm_channel_open(span_id, chan_id, &ftdmchan);
+	} else {
+		status = ftdm_channel_open_by_span(span_id, direction, &caller_data, &ftdmchan);
+	}
+	
+	if (status != FTDM_SUCCESS) {
+		if (caller_data.hangup_cause == SWITCH_CAUSE_NONE) {
+			caller_data.hangup_cause = SWITCH_CAUSE_NORMAL_CIRCUIT_CONGESTION;
+		}
+		return caller_data.hangup_cause;
+	}
+
+	if ((var = switch_event_get_header(var_event, "freetdm_pre_buffer_size"))) {
+		int tmp = atoi(var);
+		if (tmp > -1) {
+			ftdm_channel_command(ftdmchan, FTDM_COMMAND_SET_PRE_BUFFER_SIZE, &tmp);
+		}
+	}
+
+	ftdm_channel_clear_vars(ftdmchan);
+	for (h = var_event->headers; h; h = h->next) {
+		if (!strncasecmp(h->name, FREETDM_VAR_PREFIX, FREETDM_VAR_PREFIX_LEN)) {
+			char *v = h->name + FREETDM_VAR_PREFIX_LEN;
+			if (!zstr(v)) {
+				ftdm_channel_add_var(ftdmchan, v, h->value);
+			}
+		}
+	}
+	
+	if ((*new_session = switch_core_session_request(freetdm_endpoint_interface, SWITCH_CALL_DIRECTION_OUTBOUND, pool)) != 0) {
+		private_t *tech_pvt;
+		switch_caller_profile_t *caller_profile;
+		switch_channel_t *channel = switch_core_session_get_channel(*new_session);
+		
+		switch_core_session_add_stream(*new_session, NULL);
+		if ((tech_pvt = (private_t *) switch_core_session_alloc(*new_session, sizeof(private_t))) != 0) {
+			tech_init(tech_pvt, *new_session, ftdmchan);
+		} else {
+			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Hey where is my memory pool?\n");
+			switch_core_session_destroy(new_session);
+			cause = SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
+			goto fail;
+		}
+
+		snprintf(name, sizeof(name), "FreeTDM/%u:%u/%s", ftdmchan->span_id, ftdmchan->chan_id, dest);
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Connect outbound channel %s\n", name);
+		switch_channel_set_name(channel, name);
+		switch_channel_set_variable(channel, "freetdm_span_name", ftdmchan->span->name);
+		switch_channel_set_variable_printf(channel, "freetdm_span_number", "%d", ftdmchan->span_id);	
+		switch_channel_set_variable_printf(channel, "freetdm_chan_number", "%d", ftdmchan->chan_id);
+		ftdm_channel_set_caller_data(ftdmchan, &caller_data);
+		caller_profile = switch_caller_profile_clone(*new_session, outbound_profile);
+		caller_profile->destination_number = switch_core_strdup(caller_profile->pool, switch_str_nil(dest_num));
+		caller_profile->caller_id_number = switch_core_strdup(caller_profile->pool, switch_str_nil(callerid_num));
+		switch_channel_set_caller_profile(channel, caller_profile);
+		tech_pvt->caller_profile = caller_profile;
+		
+		
+		switch_channel_set_flag(channel, CF_OUTBOUND);
+		switch_channel_set_state(channel, CS_INIT);
+		if (ftdm_channel_add_token(ftdmchan, switch_core_session_get_uuid(*new_session), ftdmchan->token_count) != FTDM_SUCCESS) {
+			switch_core_session_destroy(new_session);
+			cause = SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
+            goto fail;
+		}
+
+
+		if (ftdm_channel_outgoing_call(ftdmchan) != FTDM_SUCCESS) {
+			if (tech_pvt->read_codec.implementation) {
+				switch_core_codec_destroy(&tech_pvt->read_codec);
+			}
+			
+			if (tech_pvt->write_codec.implementation) {
+				switch_core_codec_destroy(&tech_pvt->write_codec);
+			}
+			switch_core_session_destroy(new_session);
+            cause = SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
+            goto fail;
+		}
+
+		ftdm_channel_init(ftdmchan);
+		
+		return SWITCH_CAUSE_SUCCESS;
+	}
+
+ fail:
+
+	if (ftdmchan) {
+		ftdm_channel_done(ftdmchan);
+	}
+
+	return cause;
+
+}
+
+ftdm_status_t ftdm_channel_from_event(ftdm_sigmsg_t *sigmsg, switch_core_session_t **sp)
+{
+	switch_core_session_t *session = NULL;
+	private_t *tech_pvt = NULL;
+	switch_channel_t *channel = NULL;
+	char name[128];
+	
+	*sp = NULL;
+	
+	if (!(session = switch_core_session_request(freetdm_endpoint_interface, SWITCH_CALL_DIRECTION_INBOUND, NULL))) {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Initilization Error!\n");
+		return FTDM_FAIL;
+	}
+	
+	switch_core_session_add_stream(session, NULL);
+	
+	tech_pvt = (private_t *) switch_core_session_alloc(session, sizeof(private_t));
+	assert(tech_pvt != NULL);
+	channel = switch_core_session_get_channel(session);
+	if (tech_init(tech_pvt, session, sigmsg->channel) != SWITCH_STATUS_SUCCESS) {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Initilization Error!\n");
+		switch_core_session_destroy(&session);
+		return FTDM_FAIL;
+	}
+	
+	*sigmsg->channel->caller_data.collected = '\0';
+	
+	if (zstr(sigmsg->channel->caller_data.cid_name)) {
+		switch_set_string(sigmsg->channel->caller_data.cid_name, sigmsg->channel->chan_name);
+	}
+
+	if (zstr(sigmsg->channel->caller_data.cid_num.digits)) {
+		if (!zstr(sigmsg->channel->caller_data.ani.digits)) {
+			switch_set_string(sigmsg->channel->caller_data.cid_num.digits, sigmsg->channel->caller_data.ani.digits);
+		} else {
+			switch_set_string(sigmsg->channel->caller_data.cid_num.digits, sigmsg->channel->chan_number);
+		}
+	}
+
+	tech_pvt->caller_profile = switch_caller_profile_new(switch_core_session_get_pool(session),
+														 "FreeTDM",
+														 SPAN_CONFIG[sigmsg->channel->span_id].dialplan,
+														 sigmsg->channel->caller_data.cid_name,
+														 sigmsg->channel->caller_data.cid_num.digits,
+														 NULL,
+														 sigmsg->channel->caller_data.ani.digits,
+														 sigmsg->channel->caller_data.aniII,
+														 sigmsg->channel->caller_data.rdnis.digits,
+														 (char *) modname,
+														 SPAN_CONFIG[sigmsg->channel->span_id].context,
+														 sigmsg->channel->caller_data.dnis.digits);
+
+	assert(tech_pvt->caller_profile != NULL);
+
+	if (sigmsg->channel->caller_data.screen == 1 || sigmsg->channel->caller_data.screen == 3) {
+		switch_set_flag(tech_pvt->caller_profile, SWITCH_CPF_SCREEN);
+	}
+
+	if (sigmsg->channel->caller_data.pres) {
+		switch_set_flag(tech_pvt->caller_profile, SWITCH_CPF_HIDE_NAME | SWITCH_CPF_HIDE_NUMBER);
+	}
+	
+	snprintf(name, sizeof(name), "FreeTDM/%u:%u/%s", sigmsg->channel->span_id, sigmsg->channel->chan_id, tech_pvt->caller_profile->destination_number);
+	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Connect inbound channel %s\n", name);
+	switch_channel_set_name(channel, name);
+	switch_channel_set_caller_profile(channel, tech_pvt->caller_profile);
+
+	switch_channel_set_variable(channel, "freetdm_span_name", sigmsg->channel->span->name);
+	switch_channel_set_variable_printf(channel, "freetdm_span_number", "%d", sigmsg->channel->span_id);	
+	switch_channel_set_variable_printf(channel, "freetdm_chan_number", "%d", sigmsg->channel->chan_id);
+		
+	switch_channel_set_state(channel, CS_INIT);
+	if (switch_core_session_thread_launch(session) != SWITCH_STATUS_SUCCESS) {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Error spawning thread\n");
+		switch_core_session_destroy(&session);
+		return FTDM_FAIL;
+	}
+
+	if (ftdm_channel_add_token(sigmsg->channel, switch_core_session_get_uuid(session), 0) != FTDM_SUCCESS) {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Error adding token\n");
+		switch_core_session_destroy(&session);
+		return FTDM_FAIL;
+	}
+	*sp = session;
+
+    return FTDM_SUCCESS;
+}
+
+static FIO_SIGNAL_CB_FUNCTION(on_common_signal)
+{
+	switch_event_t *event = NULL;
+
+	switch (sigmsg->event_id) {
+
+	case FTDM_SIGEVENT_ALARM_CLEAR:
+	case FTDM_SIGEVENT_ALARM_TRAP:
+		{
+			if (ftdm_channel_get_alarms(sigmsg->channel) != FTDM_SUCCESS) {
+				ftdm_log(FTDM_LOG_ERROR, "failed to retrieve alarms\n");
+				return FTDM_FAIL;
+			}
+			if (switch_event_create(&event, SWITCH_EVENT_TRAP) != SWITCH_STATUS_SUCCESS) {
+				ftdm_log(FTDM_LOG_ERROR, "failed to create alarms events\n");
+				return FTDM_FAIL;
+			}
+			if (sigmsg->event_id == FTDM_SIGEVENT_ALARM_CLEAR) {
+				ftdm_log(FTDM_LOG_NOTICE, "Alarm cleared on channel %d:%d [%s]\n", sigmsg->channel->span_id, sigmsg->channel->chan_id);
+				switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "condition", "ftdm-alarm-clear");
+			} else {
+				ftdm_log(FTDM_LOG_NOTICE, "Alarm raised on channel %d:%d [%s]\n", sigmsg->channel->span_id, sigmsg->channel->chan_id);
+				switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "condition", "ftdm-alarm-trap");
+			}
+		}
+		break;
+	default:
+		return FTDM_SUCCESS;
+		break;
+	}
+
+	switch_event_add_header(event, SWITCH_STACK_BOTTOM, "span-name", "%s", sigmsg->channel->span->name);
+	switch_event_add_header(event, SWITCH_STACK_BOTTOM, "span-number", "%d", sigmsg->channel->span_id);
+	switch_event_add_header(event, SWITCH_STACK_BOTTOM, "chan-number", "%d", sigmsg->channel->chan_id);
+
+	if (ftdm_test_alarm_flag(sigmsg->channel, FTDM_ALARM_RECOVER)) {
+		switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "alarm", "recover");
+	}
+	if (ftdm_test_alarm_flag(sigmsg->channel, FTDM_ALARM_LOOPBACK)) {
+		switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "alarm", "loopback");
+	}
+	if (ftdm_test_alarm_flag(sigmsg->channel, FTDM_ALARM_YELLOW)) {
+		switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "alarm", "yellow");
+	}
+	if (ftdm_test_alarm_flag(sigmsg->channel, FTDM_ALARM_RED)) {
+		switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "alarm", "red");
+	}
+	if (ftdm_test_alarm_flag(sigmsg->channel, FTDM_ALARM_BLUE)) {
+		switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "alarm", "blue");
+	}
+	if (ftdm_test_alarm_flag(sigmsg->channel, FTDM_ALARM_NOTOPEN)) {
+		switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "alarm", "notopen");
+	}
+	if (ftdm_test_alarm_flag(sigmsg->channel, FTDM_ALARM_AIS)) {
+		switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "alarm", "ais");
+	}
+	if (ftdm_test_alarm_flag(sigmsg->channel, FTDM_ALARM_RAI)) {
+		switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "alarm", "rai");
+	}
+	if (ftdm_test_alarm_flag(sigmsg->channel, FTDM_ALARM_GENERAL)) {
+		switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "alarm", "general");
+	}
+	switch_event_fire(&event);
+
+	return FTDM_BREAK;
+}
+
+static FIO_SIGNAL_CB_FUNCTION(on_fxo_signal)
+{
+	switch_core_session_t *session = NULL;
+	switch_channel_t *channel = NULL;
+	ftdm_status_t status;
+
+	ftdm_log(FTDM_LOG_DEBUG, "got FXO sig %d:%d [%s]\n", sigmsg->channel->span_id, sigmsg->channel->chan_id, ftdm_signal_event2str(sigmsg->event_id));
+
+    switch(sigmsg->event_id) {
+
+    case FTDM_SIGEVENT_PROGRESS_MEDIA:
+		{
+			if ((session = ftdm_channel_get_session(sigmsg->channel, 0))) {
+				channel = switch_core_session_get_channel(session);
+				switch_channel_mark_pre_answered(channel);
+				switch_core_session_rwunlock(session);
+			}
+		}
+		break;
+    case FTDM_SIGEVENT_STOP:
+		{
+			private_t *tech_pvt = NULL;
+			while((session = ftdm_channel_get_session(sigmsg->channel, 0))) {
+				tech_pvt = switch_core_session_get_private(session);
+				switch_set_flag_locked(tech_pvt, TFLAG_DEAD);
+				ftdm_channel_clear_token(sigmsg->channel, 0);
+				channel = switch_core_session_get_channel(session);
+				switch_channel_hangup(channel, sigmsg->channel->caller_data.hangup_cause);
+				ftdm_channel_clear_token(sigmsg->channel, switch_core_session_get_uuid(session));
+				switch_core_session_rwunlock(session);
+			}
+		}
+		break;
+    case FTDM_SIGEVENT_UP:
+		{
+			if ((session = ftdm_channel_get_session(sigmsg->channel, 0))) {
+				channel = switch_core_session_get_channel(session);
+				switch_channel_mark_answered(channel);
+				switch_core_session_rwunlock(session);
+			}
+		}
+		break;
+    case FTDM_SIGEVENT_START:
+		{
+			status = ftdm_channel_from_event(sigmsg, &session);
+			if (status != FTDM_SUCCESS) {
+				ftdm_set_state_locked(sigmsg->channel, FTDM_CHANNEL_STATE_DOWN);
+			}
+		}
+		break;
+
+	default:
+		{
+			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Unhandled msg type %d for channel %d:%d\n",
+							  sigmsg->event_id, sigmsg->channel->span_id, sigmsg->channel->chan_id);
+		}
+		break;
+
+	}
+
+	return FTDM_SUCCESS;
+}
+
+static FIO_SIGNAL_CB_FUNCTION(on_fxs_signal)
+{
+	switch_core_session_t *session = NULL;
+	switch_channel_t *channel = NULL;
+	ftdm_status_t status = FTDM_SUCCESS;
+
+    ftdm_log(FTDM_LOG_DEBUG, "got FXS sig [%s]\n", ftdm_signal_event2str(sigmsg->event_id));
+
+    switch(sigmsg->event_id) {
+    case FTDM_SIGEVENT_UP:
+		{
+			if ((session = ftdm_channel_get_session(sigmsg->channel, 0))) {
+				channel = switch_core_session_get_channel(session);
+				switch_channel_mark_answered(channel);
+				switch_core_session_rwunlock(session);
+			}
+		}
+		break;
+    case FTDM_SIGEVENT_PROGRESS:
+		{
+			if ((session = ftdm_channel_get_session(sigmsg->channel, 0))) {
+				channel = switch_core_session_get_channel(session);
+				switch_channel_mark_ring_ready(channel);
+				switch_core_session_rwunlock(session);
+			}
+		}
+		break;
+    case FTDM_SIGEVENT_START:
+		{
+			ftdm_clear_flag_locked(sigmsg->channel, FTDM_CHANNEL_HOLD);
+			status = ftdm_channel_from_event(sigmsg, &session);
+			if (status != FTDM_SUCCESS) {
+				ftdm_set_state_locked(sigmsg->channel, FTDM_CHANNEL_STATE_BUSY);
+			}
+		}
+		break;
+    case FTDM_SIGEVENT_STOP:
+		{
+			private_t *tech_pvt = NULL;
+			switch_call_cause_t cause = SWITCH_CAUSE_NORMAL_CLEARING;
+			if (sigmsg->channel->token_count) {
+				switch_core_session_t *session_a, *session_b, *session_t = NULL;
+				switch_channel_t *channel_a = NULL, *channel_b = NULL;
+				int digits = !zstr(sigmsg->channel->caller_data.collected);
+				const char *br_a_uuid = NULL, *br_b_uuid = NULL;
+				private_t *tech_pvt = NULL;
+
+
+				if ((session_a = switch_core_session_locate(sigmsg->channel->tokens[0]))) {
+					channel_a = switch_core_session_get_channel(session_a);
+					br_a_uuid = switch_channel_get_variable(channel_a, SWITCH_SIGNAL_BOND_VARIABLE);
+
+					tech_pvt = switch_core_session_get_private(session_a);
+					stop_hold(session_a, switch_channel_get_variable(channel_a, SWITCH_SIGNAL_BOND_VARIABLE));
+					switch_clear_flag_locked(tech_pvt, TFLAG_HOLD);
+				}
+
+				if ((session_b = switch_core_session_locate(sigmsg->channel->tokens[1]))) {
+					channel_b = switch_core_session_get_channel(session_b);
+					br_b_uuid = switch_channel_get_variable(channel_b, SWITCH_SIGNAL_BOND_VARIABLE);
+
+					tech_pvt = switch_core_session_get_private(session_b);
+					stop_hold(session_a, switch_channel_get_variable(channel_b, SWITCH_SIGNAL_BOND_VARIABLE));
+					switch_clear_flag_locked(tech_pvt, TFLAG_HOLD);
+				}
+
+				if (channel_a && channel_b && !switch_channel_test_flag(channel_a, CF_OUTBOUND) && !switch_channel_test_flag(channel_b, CF_OUTBOUND)) {
+					cause = SWITCH_CAUSE_ATTENDED_TRANSFER;
+					if (br_a_uuid && br_b_uuid) {
+						switch_ivr_uuid_bridge(br_a_uuid, br_b_uuid);
+					} else if (br_a_uuid && digits) {
+						session_t = switch_core_session_locate(br_a_uuid);
+					} else if (br_b_uuid && digits) {
+						session_t = switch_core_session_locate(br_b_uuid);
+					}
+				}
+				
+				if (session_t) {
+					switch_ivr_session_transfer(session_t, sigmsg->channel->caller_data.collected, NULL, NULL);
+					switch_core_session_rwunlock(session_t);
+				}
+
+				if (session_a) {
+					switch_core_session_rwunlock(session_a);
+				}
+
+				if (session_b) {
+					switch_core_session_rwunlock(session_b);
+				}
+
+				
+			}
+
+			while((session = ftdm_channel_get_session(sigmsg->channel, 0))) {
+				tech_pvt = switch_core_session_get_private(session);
+				switch_set_flag_locked(tech_pvt, TFLAG_DEAD);
+				channel = switch_core_session_get_channel(session);
+				switch_channel_hangup(channel, cause);
+				ftdm_channel_clear_token(sigmsg->channel, switch_core_session_get_uuid(session));
+				switch_core_session_rwunlock(session);
+			}
+			ftdm_channel_clear_token(sigmsg->channel, NULL);
+			
+		}
+		break;
+
+    case FTDM_SIGEVENT_ADD_CALL:
+		{
+			cycle_foreground(sigmsg->channel, 1, NULL);
+		}
+		break;
+    case FTDM_SIGEVENT_FLASH:
+		{
+
+			if (ftdm_test_flag(sigmsg->channel, FTDM_CHANNEL_HOLD) && sigmsg->channel->token_count == 1) {
+				switch_core_session_t *session;
+				if ((session = ftdm_channel_get_session(sigmsg->channel, 0))) {
+					const char *buuid;
+					switch_channel_t *channel;
+					private_t *tech_pvt;
+					
+					tech_pvt = switch_core_session_get_private(session);
+					channel = switch_core_session_get_channel(session);
+					buuid = switch_channel_get_variable(channel, SWITCH_SIGNAL_BOND_VARIABLE);
+					ftdm_set_state_locked(sigmsg->channel,  FTDM_CHANNEL_STATE_UP);
+					stop_hold(session, buuid);
+					switch_clear_flag_locked(tech_pvt, TFLAG_HOLD);
+					switch_core_session_rwunlock(session);
+				}
+			} else if (sigmsg->channel->token_count == 2 && (SPAN_CONFIG[sigmsg->span_id].analog_options & ANALOG_OPTION_3WAY)) {
+				if (ftdm_test_flag(sigmsg->channel, FTDM_CHANNEL_3WAY)) {
+					ftdm_clear_flag(sigmsg->channel, FTDM_CHANNEL_3WAY);
+					if ((session = ftdm_channel_get_session(sigmsg->channel, 1))) {
+						channel = switch_core_session_get_channel(session);
+						switch_channel_hangup(channel, SWITCH_CAUSE_NORMAL_CLEARING);
+						ftdm_channel_clear_token(sigmsg->channel, switch_core_session_get_uuid(session));
+						switch_core_session_rwunlock(session);
+					}
+					cycle_foreground(sigmsg->channel, 1, NULL);
+				} else {
+					char *cmd;
+					cmd = switch_mprintf("three_way::%s", sigmsg->channel->tokens[0]);
+					ftdm_set_flag(sigmsg->channel, FTDM_CHANNEL_3WAY);
+					cycle_foreground(sigmsg->channel, 1, cmd);
+					free(cmd);
+				}
+			} else if ((SPAN_CONFIG[sigmsg->span_id].analog_options & ANALOG_OPTION_CALL_SWAP)
+					   || (SPAN_CONFIG[sigmsg->span_id].analog_options & ANALOG_OPTION_3WAY)
+					   ) { 
+				cycle_foreground(sigmsg->channel, 1, NULL);
+				if (sigmsg->channel->token_count == 1) {
+					ftdm_set_flag_locked(sigmsg->channel, FTDM_CHANNEL_HOLD);
+					ftdm_set_state_locked(sigmsg->channel, FTDM_CHANNEL_STATE_DIALTONE);
+				}
+			}
+			
+		}
+		break;
+
+    case FTDM_SIGEVENT_COLLECTED_DIGIT:
+		{
+			char *dtmf = sigmsg->raw_data;
+			char *regex = SPAN_CONFIG[sigmsg->channel->span->span_id].dial_regex;
+			char *fail_regex = SPAN_CONFIG[sigmsg->channel->span->span_id].fail_dial_regex;
+			
+			if (zstr(regex)) {
+				regex = NULL;
+			}
+
+			if (zstr(fail_regex)) {
+				fail_regex = NULL;
+			}
+
+			ftdm_log(FTDM_LOG_DEBUG, "got DTMF sig [%s]\n", dtmf);
+			switch_set_string(sigmsg->channel->caller_data.collected, dtmf);
+			
+			if ((regex || fail_regex) && !zstr(dtmf)) {
+				switch_regex_t *re = NULL;
+				int ovector[30];
+				int match = 0;
+
+				if (fail_regex) {
+					match = switch_regex_perform(dtmf, fail_regex, &re, ovector, sizeof(ovector) / sizeof(ovector[0]));
+					status = match ? FTDM_SUCCESS : FTDM_BREAK;
+					switch_regex_safe_free(re);
+				}
+
+				if (status == FTDM_SUCCESS && regex) {
+					match = switch_regex_perform(dtmf, regex, &re, ovector, sizeof(ovector) / sizeof(ovector[0]));
+					status = match ? FTDM_BREAK : FTDM_SUCCESS;
+				}
+				
+				switch_regex_safe_free(re);
+			}
+
+		}
+		break;
+
+	default:
+		{
+			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Unhandled msg type %d for channel %d:%d\n",
+							  sigmsg->event_id, sigmsg->channel->span_id, sigmsg->channel->chan_id);
+		}
+		break;
+
+	}
+
+	return status;
+}
+
+static FIO_SIGNAL_CB_FUNCTION(on_r2_signal)
+{
+	switch_core_session_t *session = NULL;
+	switch_channel_t *channel = NULL;
+	ftdm_status_t status = FTDM_SUCCESS;
+
+	ftdm_log(FTDM_LOG_DEBUG, "Got R2 channel sig [%s] in channel %d\n", ftdm_signal_event2str(sigmsg->event_id), sigmsg->channel->physical_chan_id);
+
+	if (on_common_signal(sigmsg) == FTDM_BREAK) {
+		return FTDM_SUCCESS;
+	}
+
+	switch(sigmsg->event_id) {
+		/* on_call_disconnect from the R2 side */
+		case FTDM_SIGEVENT_STOP: 
+		{	
+			private_t *tech_pvt = NULL;
+			while((session = ftdm_channel_get_session(sigmsg->channel, 0))) {
+				tech_pvt = switch_core_session_get_private(session);
+				switch_set_flag_locked(tech_pvt, TFLAG_DEAD);
+				channel = switch_core_session_get_channel(session);
+				switch_channel_hangup(channel, sigmsg->channel->caller_data.hangup_cause);
+				ftdm_channel_clear_token(sigmsg->channel, switch_core_session_get_uuid(session));
+				switch_core_session_rwunlock(session);
+			}
+		}
+		break;
+
+		/* on_call_offered from the R2 side */
+		case FTDM_SIGEVENT_START: 
+		{
+			status = ftdm_channel_from_event(sigmsg, &session);
+		}
+		break;
+
+		/* on DNIS received from the R2 forward side, return status == FTDM_BREAK to stop requesting DNIS */
+		case FTDM_SIGEVENT_COLLECTED_DIGIT: 
+		{
+			char *regex = SPAN_CONFIG[sigmsg->channel->span->span_id].dial_regex;
+			char *fail_regex = SPAN_CONFIG[sigmsg->channel->span->span_id].fail_dial_regex;
+
+			if (zstr(regex)) {
+				regex = NULL;
+			}
+
+			if (zstr(fail_regex)) {
+				fail_regex = NULL;
+			}
+
+			ftdm_log(FTDM_LOG_DEBUG, "R2 DNIS so far [%s]\n", sigmsg->channel->caller_data.dnis.digits);
+
+			if ((regex || fail_regex) && !zstr(sigmsg->channel->caller_data.dnis.digits)) {
+				switch_regex_t *re = NULL;
+				int ovector[30];
+				int match = 0;
+
+				if (fail_regex) {
+					match = switch_regex_perform(sigmsg->channel->caller_data.dnis.digits, fail_regex, &re, ovector, sizeof(ovector) / sizeof(ovector[0]));
+					status = match ? FTDM_SUCCESS : FTDM_BREAK;
+					switch_regex_safe_free(re);
+				}
+
+				if (status == FTDM_SUCCESS && regex) {
+					match = switch_regex_perform(sigmsg->channel->caller_data.dnis.digits, regex, &re, ovector, sizeof(ovector) / sizeof(ovector[0]));
+					status = match ? FTDM_BREAK : FTDM_SUCCESS;
+				}
+
+				switch_regex_safe_free(re);
+			}
+		}
+		break;
+
+		case FTDM_SIGEVENT_PROGRESS:
+		{
+			if ((session = ftdm_channel_get_session(sigmsg->channel, 0))) {
+				channel = switch_core_session_get_channel(session);
+				switch_channel_mark_ring_ready(channel);
+				switch_core_session_rwunlock(session);
+			}
+		}
+		break;
+
+		case FTDM_SIGEVENT_UP:
+		{
+			if ((session = ftdm_channel_get_session(sigmsg->channel, 0))) {
+				ftdm_tone_type_t tt = FTDM_TONE_DTMF;
+				channel = switch_core_session_get_channel(session);
+				switch_channel_mark_answered(channel);
+				if (ftdm_channel_command(sigmsg->channel, FTDM_COMMAND_ENABLE_DTMF_DETECT, &tt) != FTDM_SUCCESS) {
+					ftdm_log(FTDM_LOG_ERROR, "Failed to enable DTMF detection in R2 channel %d:%d\n", sigmsg->channel->span_id, sigmsg->channel->chan_id);
+				}
+				switch_core_session_rwunlock(session);
+			}
+		}
+		break;
+
+		default:
+		{
+			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Unhandled event %d from R2 for channel %d:%d\n",
+			sigmsg->event_id, sigmsg->channel->span_id, sigmsg->channel->chan_id);
+		}
+		break;
+	}
+
+	return status;
+}
+
+static FIO_SIGNAL_CB_FUNCTION(on_clear_channel_signal)
+{
+	switch_core_session_t *session = NULL;
+	switch_channel_t *channel = NULL;
+
+	ftdm_log(FTDM_LOG_DEBUG, "got clear channel sig [%s]\n", ftdm_signal_event2str(sigmsg->event_id));
+
+	if (on_common_signal(sigmsg) == FTDM_BREAK) {
+		return FTDM_SUCCESS;
+	}
+
+    switch(sigmsg->event_id) {
+    case FTDM_SIGEVENT_START:
+		{
+			ftdm_tone_type_t tt = FTDM_TONE_DTMF;
+
+			if (ftdm_channel_command(sigmsg->channel, FTDM_COMMAND_ENABLE_DTMF_DETECT, &tt) != FTDM_SUCCESS) {
+				ftdm_log(FTDM_LOG_ERROR, "TONE ERROR\n");
+			}
+
+			return ftdm_channel_from_event(sigmsg, &session);
+		}
+		break;
+    case FTDM_SIGEVENT_STOP:
+    case FTDM_SIGEVENT_RESTART:
+		{
+			private_t *tech_pvt = NULL;
+			while((session = ftdm_channel_get_session(sigmsg->channel, 0))) {
+				tech_pvt = switch_core_session_get_private(session);
+				switch_set_flag_locked(tech_pvt, TFLAG_DEAD);
+				channel = switch_core_session_get_channel(session);
+				switch_channel_hangup(channel, sigmsg->channel->caller_data.hangup_cause);
+				ftdm_channel_clear_token(sigmsg->channel, switch_core_session_get_uuid(session));
+				switch_core_session_rwunlock(session);
+			}
+		}
+		break;
+    case FTDM_SIGEVENT_UP:
+		{
+			if ((session = ftdm_channel_get_session(sigmsg->channel, 0))) {
+				ftdm_tone_type_t tt = FTDM_TONE_DTMF;
+				channel = switch_core_session_get_channel(session);
+				switch_channel_mark_answered(channel);
+				if (ftdm_channel_command(sigmsg->channel, FTDM_COMMAND_ENABLE_DTMF_DETECT, &tt) != FTDM_SUCCESS) {
+					ftdm_log(FTDM_LOG_ERROR, "TONE ERROR\n");
+				}
+				switch_core_session_rwunlock(session);
+			} else {
+				const char *uuid = ftdm_channel_get_uuid(sigmsg->channel, 0);
+
+				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Session for channel %d:%d not found [UUID: %s]\n",
+					sigmsg->channel->span_id, sigmsg->channel->chan_id, (uuid) ? uuid : "N/A");
+			}
+		}
+    case FTDM_SIGEVENT_PROGRESS_MEDIA:
+		{
+			if ((session = ftdm_channel_get_session(sigmsg->channel, 0))) {
+				channel = switch_core_session_get_channel(session);
+				switch_channel_mark_pre_answered(channel);
+				switch_core_session_rwunlock(session);
+			} else {
+				const char *uuid = ftdm_channel_get_uuid(sigmsg->channel, 0);
+
+				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Session for channel %d:%d not found [UUID: %s]\n",
+					sigmsg->channel->span_id, sigmsg->channel->chan_id, (uuid) ? uuid : "N/A");
+			}
+		}
+		break;
+	case FTDM_SIGEVENT_PROGRESS:
+		{
+			if ((session = ftdm_channel_get_session(sigmsg->channel, 0))) {
+				channel = switch_core_session_get_channel(session);
+				switch_channel_mark_ring_ready(channel);
+				switch_core_session_rwunlock(session);
+			} else {
+				const char *uuid = ftdm_channel_get_uuid(sigmsg->channel, 0);
+
+				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Session for channel %d:%d not found [UUID: %s]\n",
+					sigmsg->channel->span_id, sigmsg->channel->chan_id, (uuid) ? uuid : "N/A");
+			}
+		}
+	default:
+		{
+			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Unhandled msg type %d for channel %d:%d\n",
+							  sigmsg->event_id, sigmsg->channel->span_id, sigmsg->channel->chan_id);
+		}
+		break;
+	}
+
+	return FTDM_SUCCESS;
+}
+
+
+static FIO_SIGNAL_CB_FUNCTION(on_analog_signal)
+{
+	switch_status_t status = SWITCH_STATUS_FALSE;
+
+	if (on_common_signal(sigmsg) == FTDM_BREAK) {
+		return FTDM_SUCCESS;
+	}
+
+	switch (sigmsg->channel->type) {
+	case FTDM_CHAN_TYPE_FXO:
+	case FTDM_CHAN_TYPE_EM:
+		{
+			status = on_fxo_signal(sigmsg);
+		}
+		break;
+	case FTDM_CHAN_TYPE_FXS:
+		{
+			status = on_fxs_signal(sigmsg);
+		}
+		break;
+	default: 
+		{
+			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Unhandled analog channel type %d for channel %d:%d\n",
+							  sigmsg->channel->type, sigmsg->channel->span_id, sigmsg->channel->chan_id);
+		}
+		break;
+	}
+
+	return status;
+}
+
+static void ftdm_logger(const char *file, const char *func, int line, int level, const char *fmt, ...)
+{
+    char *data = NULL;
+    va_list ap;
+	
+    va_start(ap, fmt);
+
+	if (switch_vasprintf(&data, fmt, ap) != -1) {
+		switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, (char *)func, line, NULL, level, "%s", data);
+		free(data);
+	}
+	
+    va_end(ap);
+
+}
+
+static uint32_t enable_analog_option(const char *str, uint32_t current_options)
+{
+	if (!strcasecmp(str, "3-way")) {
+		current_options |= ANALOG_OPTION_3WAY;
+		current_options &= ~ANALOG_OPTION_CALL_SWAP;
+	} else if (!strcasecmp(str, "call-swap")) {
+		current_options |= ANALOG_OPTION_CALL_SWAP;
+		current_options &= ~ANALOG_OPTION_3WAY;
+	}
+	
+	return current_options;
+	
+}
+
+static switch_status_t load_config(void)
+{
+	const char *cf = "freetdm.conf";
+	switch_xml_t cfg, xml, settings, param, spans, myspan;
+	ftdm_span_t *boost_spans[FTDM_MAX_PHYSICAL_SPANS_PER_LOGICAL_SPAN];
+	ftdm_span_t *boost_span = NULL;
+	unsigned boosti = 0;
+	unsigned int i = 0;
+
+	memset(boost_spans, 0, sizeof(boost_spans));
+	memset(&globals, 0, sizeof(globals));
+	switch_mutex_init(&globals.mutex, SWITCH_MUTEX_NESTED, module_pool);
+	if (!(xml = switch_xml_open_cfg(cf, &cfg, NULL))) {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "open of %s failed\n", cf);
+		return SWITCH_STATUS_TERM;
+	}
+	
+	if ((settings = switch_xml_child(cfg, "settings"))) {
+		for (param = switch_xml_child(settings, "param"); param; param = param->next) {
+			char *var = (char *) switch_xml_attr_soft(param, "name");
+			char *val = (char *) switch_xml_attr_soft(param, "value");
+
+			if (!strcasecmp(var, "debug")) {
+				globals.debug = atoi(val);
+			} else if (!strcasecmp(var, "hold-music")) {
+				switch_set_string(globals.hold_music, val);
+			} else if (!strcasecmp(var, "enable-analog-option")) {
+				globals.analog_options = enable_analog_option(val, globals.analog_options);
+			}
+		}
+	}
+
+	if ((spans = switch_xml_child(cfg, "analog_spans"))) {
+		for (myspan = switch_xml_child(spans, "span"); myspan; myspan = myspan->next) {
+			char *id = (char *) switch_xml_attr(myspan, "id");
+			char *name = (char *) switch_xml_attr(myspan, "name");
+			ftdm_status_t zstatus = FTDM_FAIL;
+			const char *context = "default";
+			const char *dialplan = "XML";
+			const char *tonegroup = NULL;
+			char *digit_timeout = NULL;
+			char *max_digits = NULL;
+			char *hotline = NULL;
+			char *dial_regex = NULL;
+			char *hold_music = NULL;
+			char *fail_dial_regex = NULL;
+			const char *enable_callerid = "true";
+
+			uint32_t span_id = 0, to = 0, max = 0;
+			ftdm_span_t *span = NULL;
+			analog_option_t analog_options = ANALOG_OPTION_NONE;
+			
+			for (param = switch_xml_child(myspan, "param"); param; param = param->next) {
+				char *var = (char *) switch_xml_attr_soft(param, "name");
+				char *val = (char *) switch_xml_attr_soft(param, "value");
+
+				if (!strcasecmp(var, "tonegroup")) {
+					tonegroup = val;
+				} else if (!strcasecmp(var, "digit_timeout") || !strcasecmp(var, "digit-timeout")) {
+					digit_timeout = val;
+				} else if (!strcasecmp(var, "context")) {
+					context = val;
+				} else if (!strcasecmp(var, "dialplan")) {
+					dialplan = val;
+				} else if (!strcasecmp(var, "dial-regex")) {
+					dial_regex = val;
+				} else if (!strcasecmp(var, "enable-callerid")) {
+					enable_callerid = val;
+				} else if (!strcasecmp(var, "fail-dial-regex")) {
+					fail_dial_regex = val;
+				} else if (!strcasecmp(var, "hold-music")) {
+					hold_music = val;
+				} else if (!strcasecmp(var, "max_digits") || !strcasecmp(var, "max-digits")) {
+					max_digits = val;
+				} else if (!strcasecmp(var, "hotline")) {
+					hotline = val;
+				} else if (!strcasecmp(var, "enable-analog-option")) {
+					analog_options = enable_analog_option(val, analog_options);
+				}
+			}
+				
+			if (!id && !name) {
+				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "span missing required param 'id'\n");
+				continue;
+			}
+
+			
+			
+			if (!tonegroup) {
+				tonegroup = "us";
+			}
+			
+			if (digit_timeout) {
+				to = atoi(digit_timeout);
+			}
+
+			if (max_digits) {
+				max = atoi(max_digits);
+			}
+
+			if (name) {
+				zstatus = ftdm_span_find_by_name(name, &span);
+			} else {
+				if (switch_is_number(id)) {
+					span_id = atoi(id);
+					zstatus = ftdm_span_find(span_id, &span);
+				}
+
+				if (zstatus != FTDM_SUCCESS) {
+					zstatus = ftdm_span_find_by_name(id, &span);
+				}
+			}
+
+			if (zstatus != FTDM_SUCCESS) {
+				ftdm_log(FTDM_LOG_ERROR, "Error finding FreeTDM span id:%s name:%s\n", switch_str_nil(id), switch_str_nil(name));
+				continue;
+			}
+			
+			if (!span_id) {
+				span_id = span->span_id;
+			}
+
+			if (ftdm_configure_span("analog", span, on_analog_signal, 
+								   "tonemap", tonegroup, 
+								   "digit_timeout", &to,
+								   "max_dialstr", &max,
+								   "hotline", hotline,
+								   "enable_callerid", enable_callerid,
+								   TAG_END) != FTDM_SUCCESS) {
+				ftdm_log(FTDM_LOG_ERROR, "Error starting FreeTDM span %d\n", span_id);
+				continue;
+			}
+
+			SPAN_CONFIG[span->span_id].span = span;
+			switch_set_string(SPAN_CONFIG[span->span_id].context, context);
+			switch_set_string(SPAN_CONFIG[span->span_id].dialplan, dialplan);
+			SPAN_CONFIG[span->span_id].analog_options = analog_options | globals.analog_options;
+			
+			if (dial_regex) {
+				switch_set_string(SPAN_CONFIG[span->span_id].dial_regex, dial_regex);
+			}
+
+			if (fail_dial_regex) {
+				switch_set_string(SPAN_CONFIG[span->span_id].fail_dial_regex, fail_dial_regex);
+			}
+
+			if (hold_music) {
+				switch_set_string(SPAN_CONFIG[span->span_id].hold_music, hold_music);
+			}
+			switch_copy_string(SPAN_CONFIG[span->span_id].type, "analog", sizeof(SPAN_CONFIG[span->span_id].type));
+			ftdm_span_start(span);
+		}
+	}
+
+	if ((spans = switch_xml_child(cfg, "analog_em_spans"))) {
+		for (myspan = switch_xml_child(spans, "span"); myspan; myspan = myspan->next) {
+			char *id = (char *) switch_xml_attr(myspan, "id");
+			char *name = (char *) switch_xml_attr(myspan, "name");
+			ftdm_status_t zstatus = FTDM_FAIL;
+			const char *context = "default";
+			const char *dialplan = "XML";
+			const char *tonegroup = NULL;
+			char *digit_timeout = NULL;
+			char *max_digits = NULL;
+			char *dial_regex = NULL;
+			char *hold_music = NULL;
+			char *fail_dial_regex = NULL;
+			uint32_t span_id = 0, to = 0, max = 0;
+			ftdm_span_t *span = NULL;
+			analog_option_t analog_options = ANALOG_OPTION_NONE;
+
+			for (param = switch_xml_child(myspan, "param"); param; param = param->next) {
+				char *var = (char *) switch_xml_attr_soft(param, "name");
+				char *val = (char *) switch_xml_attr_soft(param, "value");
+
+				if (!strcasecmp(var, "tonegroup")) {
+					tonegroup = val;
+				} else if (!strcasecmp(var, "digit_timeout") || !strcasecmp(var, "digit-timeout")) {
+					digit_timeout = val;
+				} else if (!strcasecmp(var, "context")) {
+					context = val;
+				} else if (!strcasecmp(var, "dialplan")) {
+					dialplan = val;
+				} else if (!strcasecmp(var, "dial-regex")) {
+					dial_regex = val;
+				} else if (!strcasecmp(var, "fail-dial-regex")) {
+					fail_dial_regex = val;
+				} else if (!strcasecmp(var, "hold-music")) {
+					hold_music = val;
+				} else if (!strcasecmp(var, "max_digits") || !strcasecmp(var, "max-digits")) {
+					max_digits = val;
+				} else if (!strcasecmp(var, "enable-analog-option")) {
+					analog_options = enable_analog_option(val, analog_options);
+				}
+			}
+				
+			if (!id && !name) {
+				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "span missing required param 'id'\n");
+				continue;
+			}
+
+			
+			if (!tonegroup) {
+				tonegroup = "us";
+			}
+			
+			if (digit_timeout) {
+				to = atoi(digit_timeout);
+			}
+
+			if (max_digits) {
+				max = atoi(max_digits);
+			}
+
+
+			if (name) {
+				zstatus = ftdm_span_find_by_name(name, &span);
+			} else {
+				if (switch_is_number(id)) {
+					span_id = atoi(id);
+					zstatus = ftdm_span_find(span_id, &span);
+				}
+
+				if (zstatus != FTDM_SUCCESS) {
+					zstatus = ftdm_span_find_by_name(id, &span);
+				}
+			}
+
+			if (zstatus != FTDM_SUCCESS) {
+				ftdm_log(FTDM_LOG_ERROR, "Error finding FreeTDM span id:%s name:%s\n", switch_str_nil(id), switch_str_nil(name));
+				continue;
+			}
+			
+			if (!span_id) {
+				span_id = span->span_id;
+			}
+
+
+			if (ftdm_configure_span("analog_em", span, on_analog_signal, 
+								   "tonemap", tonegroup, 
+								   "digit_timeout", &to,
+								   "max_dialstr", &max,
+								   TAG_END) != FTDM_SUCCESS) {
+				ftdm_log(FTDM_LOG_ERROR, "Error starting FreeTDM span %d\n", span_id);
+				continue;
+			}
+
+			SPAN_CONFIG[span->span_id].span = span;
+			switch_set_string(SPAN_CONFIG[span->span_id].context, context);
+			switch_set_string(SPAN_CONFIG[span->span_id].dialplan, dialplan);
+			SPAN_CONFIG[span->span_id].analog_options = analog_options | globals.analog_options;
+			
+			if (dial_regex) {
+				switch_set_string(SPAN_CONFIG[span->span_id].dial_regex, dial_regex);
+			}
+
+			if (fail_dial_regex) {
+				switch_set_string(SPAN_CONFIG[span->span_id].fail_dial_regex, fail_dial_regex);
+			}
+
+			if (hold_music) {
+				switch_set_string(SPAN_CONFIG[span->span_id].hold_music, hold_music);
+			}
+			switch_copy_string(SPAN_CONFIG[span->span_id].type, "analog_em", sizeof(SPAN_CONFIG[span->span_id].type));
+			ftdm_span_start(span);
+		}
+	}
+
+	if ((spans = switch_xml_child(cfg, "pri_spans"))) {
+		for (myspan = switch_xml_child(spans, "span"); myspan; myspan = myspan->next) {
+			char *id = (char *) switch_xml_attr(myspan, "id");
+			char *name = (char *) switch_xml_attr(myspan, "name");
+			ftdm_status_t zstatus = FTDM_FAIL;
+			const char *context = "default";
+			const char *dialplan = "XML";
+			//Q921NetUser_t mode = Q931_TE;
+			//Q931Dialect_t dialect = Q931_Dialect_National;
+			char *mode = NULL;
+			char *dialect = NULL;
+			uint32_t span_id = 0;
+			ftdm_span_t *span = NULL;
+			const char *tonegroup = NULL;
+			char *digit_timeout = NULL;
+			const char *opts = "none";
+			uint32_t to = 0;
+			int q921loglevel = -1;
+			int q931loglevel = -1;
+			
+			// quick debug
+			//switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "ID: '%s', Name:'%s'\n",id,name);
+
+			for (param = switch_xml_child(myspan, "param"); param; param = param->next) {
+				char *var = (char *) switch_xml_attr_soft(param, "name");
+				char *val = (char *) switch_xml_attr_soft(param, "value");
+
+				if (!strcasecmp(var, "tonegroup")) {
+					tonegroup = val;
+				} else if (!strcasecmp(var, "mode")) {
+					mode = val;
+				} else if (!strcasecmp(var, "dialect")) {
+					dialect = val;
+				} else if (!strcasecmp(var, "q921loglevel")) {
+                    if ((q921loglevel = switch_log_str2level(val)) == SWITCH_LOG_INVALID) {
+                        q921loglevel = -1;
+                    }
+				} else if (!strcasecmp(var, "q931loglevel")) {
+                    if ((q931loglevel = switch_log_str2level(val)) == SWITCH_LOG_INVALID) {
+                        q931loglevel = -1;
+                    }
+				} else if (!strcasecmp(var, "context")) {
+					context = val;
+				} else if (!strcasecmp(var, "opts")) {
+					opts = val;
+				} else if (!strcasecmp(var, "dialplan")) {
+					dialplan = val;
+				} else if (!strcasecmp(var, "digit_timeout") || !strcasecmp(var, "digit-timeout")) {
+					digit_timeout = val;
+				}
+			}
+	
+			if (!id && !name) {
+				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "span missing required param 'id'\n");
+				continue;
+			}
+			
+			if (name) {
+				zstatus = ftdm_span_find_by_name(name, &span);
+			} else {
+				if (switch_is_number(id)) {
+					span_id = atoi(id);
+					zstatus = ftdm_span_find(span_id, &span);
+				}
+
+				if (zstatus != FTDM_SUCCESS) {
+					zstatus = ftdm_span_find_by_name(id, &span);
+				}
+			}
+
+			if (digit_timeout) {
+				to = atoi(digit_timeout);
+			}
+			
+			if (zstatus != FTDM_SUCCESS) {
+				ftdm_log(FTDM_LOG_ERROR, "Error finding FreeTDM span id:%s name:%s\n", switch_str_nil(id), switch_str_nil(name));
+				continue;
+			}
+
+                        if (!span_id) {
+                                span_id = span->span_id;
+                        }
+
+			if (!tonegroup) {
+				tonegroup = "us";
+			}
+			
+			if (ftdm_configure_span("isdn", span, on_clear_channel_signal, 
+								   "mode", mode,
+								   "dialect", dialect,
+								   "digit_timeout", &to,
+								   "opts", opts,
+								   "tonemap", tonegroup,
+								   "q921loglevel", q921loglevel,
+								   "q931loglevel", q931loglevel,
+								   TAG_END) != FTDM_SUCCESS) {
+				ftdm_log(FTDM_LOG_ERROR, "Error starting FreeTDM span %d mode: %s dialect: %s error: %s\n", span_id, mode, dialect, span->last_error);
+				continue;
+			}
+
+			SPAN_CONFIG[span->span_id].span = span;
+			switch_copy_string(SPAN_CONFIG[span->span_id].context, context, sizeof(SPAN_CONFIG[span->span_id].context));
+			switch_copy_string(SPAN_CONFIG[span->span_id].dialplan, dialplan, sizeof(SPAN_CONFIG[span->span_id].dialplan));
+			switch_copy_string(SPAN_CONFIG[span->span_id].type, "isdn", sizeof(SPAN_CONFIG[span->span_id].type));
+
+			ftdm_span_start(span);
+		}
+	}
+
+
+
+	if ((spans = switch_xml_child(cfg, "libpri_spans"))) {
+		for (myspan = switch_xml_child(spans, "span"); myspan; myspan = myspan->next) {
+			char *id = (char *) switch_xml_attr(myspan, "id");
+			char *name = (char *) switch_xml_attr(myspan, "name");
+			ftdm_status_t zstatus = FTDM_FAIL;
+			const char *context = "default";
+			const char *dialplan = "XML";
+			
+			const char *o_node = "cpe";
+			const char *o_switch = "dms100";
+			const char *o_dp = "unknown";
+			const char *o_l1 = "ulaw";
+			const char *o_debug = "none";
+			const char* opts = "none";	
+					
+			uint32_t span_id = 0;
+			ftdm_span_t *span = NULL;
+
+			
+			for (param = switch_xml_child(myspan, "param"); param; param = param->next) {
+				char *var = (char *) switch_xml_attr_soft(param, "name");
+				char *val = (char *) switch_xml_attr_soft(param, "value");
+
+				if (!strcasecmp(var, "node")) {
+					o_node = val;
+				} else if (!strcasecmp(var, "switch")) {
+					o_switch = val;
+				} else if (!strcasecmp(var, "dp")) {
+					o_dp = val;
+				} else if (!strcasecmp(var, "l1")) {
+					o_l1 = val;
+				} else if (!strcasecmp(var, "debug")) {
+					o_debug = val;
+				} else if (!strcasecmp(var, "context")) {
+					context = val;
+				} else if (!strcasecmp(var, "opts")) {
+					opts = val;
+				} else if (!strcasecmp(var, "dialplan")) {
+					dialplan = val;
+				}
+			}
+	
+			if (!id && !name) {
+				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "span missing required param 'id'\n");
+				continue;
+			}
+			
+			if (name) {
+				zstatus = ftdm_span_find_by_name(name, &span);
+			} else {
+				if (switch_is_number(id)) {
+					span_id = atoi(id);
+					zstatus = ftdm_span_find(span_id, &span);
+				}
+
+				if (zstatus != FTDM_SUCCESS) {
+					zstatus = ftdm_span_find_by_name(id, &span);
+				}
+			}
+
+			if (zstatus != FTDM_SUCCESS) {
+				ftdm_log(FTDM_LOG_ERROR, "Error finding FreeTDM span id:%s name:%s\n", switch_str_nil(id), switch_str_nil(name));
+				continue;
+			}
+
+			if (!span_id) {
+				span_id = span->span_id;
+			}
+			
+			
+			if (ftdm_configure_span("libpri", span, on_clear_channel_signal, 
+								   "node", o_node,
+								   "switch", o_switch,
+								   "dp", o_dp,
+								   "l1", o_l1,
+								   "debug", o_debug,
+								   "opts", opts,
+								   TAG_END) != FTDM_SUCCESS) {
+				ftdm_log(FTDM_LOG_ERROR, "Error starting FreeTDM span %d node: %s switch: %s dp: %s l1: %s debug: %s error: %s\n", 
+						span_id, switch_str_nil(o_node), switch_str_nil(o_switch), switch_str_nil(o_dp), switch_str_nil(o_l1), switch_str_nil(o_debug),
+						span->last_error);
+				continue;
+			}
+
+			SPAN_CONFIG[span->span_id].span = span;
+			switch_copy_string(SPAN_CONFIG[span->span_id].context, context, sizeof(SPAN_CONFIG[span->span_id].context));
+			switch_copy_string(SPAN_CONFIG[span->span_id].dialplan, dialplan, sizeof(SPAN_CONFIG[span->span_id].dialplan));
+			switch_copy_string(SPAN_CONFIG[span->span_id].type, "isdn", sizeof(SPAN_CONFIG[span->span_id].type));
+
+			ftdm_span_start(span);
+		}
+	}
+
+	if ((spans = switch_xml_child(cfg, "boost_spans"))) {
+		for (myspan = switch_xml_child(spans, "span"); myspan; myspan = myspan->next) {
+			char *id = (char *) switch_xml_attr(myspan, "id");
+			char *name = (char *) switch_xml_attr(myspan, "name");
+			char *sigmod = (char *) switch_xml_attr(myspan, "sigmod");
+			ftdm_status_t zstatus = FTDM_FAIL;
+			const char *context = "default";
+			const char *dialplan = "XML";
+			uint32_t span_id = 0;
+			ftdm_span_t *span = NULL;
+			const char *tonegroup = NULL;
+			ftdm_conf_parameter_t spanparameters[30];
+			unsigned paramindex = 0;
+			
+			if (!id && !name) {
+				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "boost span requires an id or name as attribute: <span id=ftid|name=ftname>\n");
+				continue;
+			}
+			memset(spanparameters, 0, sizeof(spanparameters));
+			if (sigmod) {
+				spanparameters[paramindex].var = "sigmod";
+				spanparameters[paramindex].val = sigmod;
+				paramindex++;
+			}
+
+			for (param = switch_xml_child(myspan, "param"); param; param = param->next) {
+				char *var = (char *) switch_xml_attr_soft(param, "name");
+				char *val = (char *) switch_xml_attr_soft(param, "value");
+				if (sizeof(spanparameters)/sizeof(spanparameters[0]) == paramindex) {
+					switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Too many parameters for boost span, ignoring any parameter after %s\n", var);
+					break;
+				}
+				if (!strcasecmp(var, "tonegroup")) {
+					tonegroup = val;
+				} else if (!strcasecmp(var, "context")) {
+					context = val;
+				} else if (!strcasecmp(var, "dialplan")) {
+					dialplan = val;
+				} else {
+					spanparameters[paramindex].var = var;
+					spanparameters[paramindex].val = val;
+					paramindex++;
+				}
+			}
+
+			if (!tonegroup) {
+				tonegroup = "us";
+			}
+			
+			if (name) {
+				zstatus = ftdm_span_find_by_name(name, &span);
+			} else {
+				if (switch_is_number(id)) {
+					span_id = atoi(id);
+					zstatus = ftdm_span_find(span_id, &span);
+				}
+
+				if (zstatus != FTDM_SUCCESS) {
+					zstatus = ftdm_span_find_by_name(id, &span);
+				}
+			}
+
+			if (zstatus != FTDM_SUCCESS) {
+				ftdm_log(FTDM_LOG_ERROR, "Error finding FreeTDM span id:%s name:%s\n", switch_str_nil(id), switch_str_nil(name));
+				continue;
+			}
+			
+			if (!span_id) {
+				span_id = span->span_id;
+			}
+
+			if (ftdm_configure_span_signaling("sangoma_boost", span, on_clear_channel_signal, spanparameters) != FTDM_SUCCESS) {
+				ftdm_log(FTDM_LOG_ERROR, "Error starting FreeTDM span %d error: %s\n", span_id, span->last_error);
+				continue;
+			}
+
+			SPAN_CONFIG[span->span_id].span = span;
+			switch_copy_string(SPAN_CONFIG[span->span_id].context, context, sizeof(SPAN_CONFIG[span->span_id].context));
+			switch_copy_string(SPAN_CONFIG[span->span_id].dialplan, dialplan, sizeof(SPAN_CONFIG[span->span_id].dialplan));
+
+			switch_copy_string(SPAN_CONFIG[span->span_id].type, "Sangoma (boost)", sizeof(SPAN_CONFIG[span->span_id].type));
+			boost_spans[boosti++] = span;
+		}
+	}
+
+	if ((spans = switch_xml_child(cfg, "r2_spans"))) {
+		for (myspan = switch_xml_child(spans, "span"); myspan; myspan = myspan->next) {
+			char *id = (char *) switch_xml_attr(myspan, "id");
+			char *name = (char *) switch_xml_attr(myspan, "name");
+			ftdm_status_t zstatus = FTDM_FAIL;
+
+			/* strings */
+			const char *variant = "itu";
+			const char *category = "national_subscriber";
+			const char *logdir = "/usr/local/freeswitch/log/"; /* FIXME: get PREFIX variable */
+			const char *logging = "notice,warning,error";
+			const char *advanced_protocol_file = "";
+
+			/* booleans */
+			int call_files = 0;
+			int get_ani_first = -1;
+			int immediate_accept = -1;
+			int double_answer = -1;
+			int skip_category = -1;
+			int forced_release = -1;
+			int charge_calls = -1;
+
+			/* integers */
+			int mfback_timeout = -1;
+			int metering_pulse_timeout = -1;
+			int allow_collect_calls = -1;
+			int max_ani = 10;
+			int max_dnis = 4;
+
+			/* common non r2 stuff */
+			const char *context = "default";
+			const char *dialplan = "XML";
+			char *dial_regex = NULL;
+			char *fail_dial_regex = NULL;
+			uint32_t span_id = 0;
+			ftdm_span_t *span = NULL;
+
+
+			for (param = switch_xml_child(myspan, "param"); param; param = param->next) {
+				char *var = (char *) switch_xml_attr_soft(param, "name");
+				char *val = (char *) switch_xml_attr_soft(param, "value");
+
+				/* string parameters */
+				if (!strcasecmp(var, "variant")) {
+					variant = val;
+				} else if (!strcasecmp(var, "category")) {
+					category = val;
+				} else if (!strcasecmp(var, "logdir")) {
+					logdir = val;
+				} else if (!strcasecmp(var, "logging")) {
+					logging = val;
+				} else if (!strcasecmp(var, "advanced_protocol_file")) {
+					advanced_protocol_file = val;
+
+				/* booleans */
+				} else if (!strcasecmp(var, "allow_collect_calls")) {
+					allow_collect_calls = switch_true(val);
+				} else if (!strcasecmp(var, "immediate_accept")) {
+					immediate_accept = switch_true(val);
+				} else if (!strcasecmp(var, "double_answer")) {
+					double_answer = switch_true(val);
+				} else if (!strcasecmp(var, "skip_category")) {
+					skip_category = switch_true(var);
+				} else if (!strcasecmp(var, "forced_release")) {
+					forced_release = switch_true(val);
+				} else if (!strcasecmp(var, "charge_calls")) {
+					charge_calls = switch_true(val);
+				} else if (!strcasecmp(var, "get_ani_first")) {
+					get_ani_first = switch_true(val);
+				} else if (!strcasecmp(var, "call_files")) {
+					call_files = switch_true(val);
+
+				/* integers */
+				} else if (!strcasecmp(var, "mfback_timeout")) {
+					mfback_timeout = atoi(val);
+				} else if (!strcasecmp(var, "metering_pulse_timeout")) {
+					metering_pulse_timeout = atoi(val);
+				} else if (!strcasecmp(var, "max_ani")) {
+					max_ani = atoi(val);
+				} else if (!strcasecmp(var, "max_dnis")) {
+					max_dnis = atoi(val);
+
+				/* common non r2 stuff */
+				} else if (!strcasecmp(var, "context")) {
+					context = val;
+				} else if (!strcasecmp(var, "dialplan")) {
+					dialplan = val;
+				} else if (!strcasecmp(var, "dial-regex")) {
+					dial_regex = val;
+				} else if (!strcasecmp(var, "fail-dial-regex")) {
+					fail_dial_regex = val;
+				}
+			}
+
+			if (!id && !name) {
+				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "span missing required param 'id'\n");
+				continue;
+			}
+
+			if (name) {
+				zstatus = ftdm_span_find_by_name(name, &span);
+			} else {
+				if (switch_is_number(id)) {
+					span_id = atoi(id);
+					zstatus = ftdm_span_find(span_id, &span);
+				}
+
+				if (zstatus != FTDM_SUCCESS) {
+					zstatus = ftdm_span_find_by_name(id, &span);
+				}
+			}
+
+			if (zstatus != FTDM_SUCCESS) {
+				ftdm_log(FTDM_LOG_ERROR, "Error finding FreeTDM span id:%s name:%s\n", switch_str_nil(id), switch_str_nil(name));
+				continue;
+			}
+
+			if (!span_id) {
+				span_id = span->span_id;
+			}
+
+			if (ftdm_configure_span("r2", span, on_r2_signal, 
+				"variant", variant, 
+				"max_ani", max_ani,
+				"max_dnis", max_dnis,
+				"category", category,
+				"logdir", logdir,
+				"logging", logging,
+				"advanced_protocol_file", advanced_protocol_file,
+				"allow_collect_calls", allow_collect_calls,
+				"immediate_accept", immediate_accept,
+				"double_answer", double_answer,
+				"skip_category", skip_category,
+				"forced_release", forced_release,
+				"charge_calls", charge_calls,
+				"get_ani_first", get_ani_first,
+				"call_files", call_files,
+				"mfback_timeout", mfback_timeout,
+				"metering_pulse_timeout", metering_pulse_timeout, 
+				TAG_END) != FTDM_SUCCESS) {
+				ftdm_log(FTDM_LOG_ERROR, "Error configuring R2 FreeTDM span %d, error: %s\n", 
+				span_id, span->last_error);
+				continue;
+			}
+
+			if (dial_regex) {
+				switch_set_string(SPAN_CONFIG[span->span_id].dial_regex, dial_regex);
+			}
+
+			if (fail_dial_regex) {
+				switch_set_string(SPAN_CONFIG[span->span_id].fail_dial_regex, fail_dial_regex);
+			}
+
+			SPAN_CONFIG[span->span_id].span = span;
+			switch_copy_string(SPAN_CONFIG[span->span_id].context, context, sizeof(SPAN_CONFIG[span->span_id].context));
+			switch_copy_string(SPAN_CONFIG[span->span_id].dialplan, dialplan, sizeof(SPAN_CONFIG[span->span_id].dialplan));
+			switch_copy_string(SPAN_CONFIG[span->span_id].type, "r2", sizeof(SPAN_CONFIG[span->span_id].type));
+
+			if (ftdm_span_start(span) == FTDM_FAIL) {
+				ftdm_log(FTDM_LOG_ERROR, "Error starting R2 FreeTDM span %d, error: %s\n", span_id, span->last_error);
+				continue;
+			}
+		}
+	}
+
+	/* start all boost spans now that we're done configuring. Unfortunately at this point boost modules have the limitation
+	 * of needing all spans to be configured before starting them */
+	for ( ; i < boosti; i++) {
+		boost_span = boost_spans[i];
+		ftdm_log(FTDM_LOG_DEBUG, "Starting boost span %d\n", boost_span->span_id);
+		if (ftdm_span_start(boost_span) == FTDM_FAIL) {
+				ftdm_log(FTDM_LOG_ERROR, "Error starting boost FreeTDM span %d, error: %s\n", boost_span->span_id, boost_span->last_error);
+				continue;
+		}
+	}
+
+
+	switch_xml_free(xml);
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+
+void dump_chan(ftdm_span_t *span, uint32_t chan_id, switch_stream_handle_t *stream)
+{
+	if (chan_id > span->chan_count) {
+		return;
+	}
+
+	stream->write_function(stream,
+						   "span_id: %u\n"
+						   "chan_id: %u\n"
+						   "physical_span_id: %u\n"
+						   "physical_chan_id: %u\n"
+						   "type: %s\n"
+						   "state: %s\n"
+						   "last_state: %s\n"
+						   "cid_date: %s\n"
+						   "cid_name: %s\n"
+						   "cid_num: %s\n"
+						   "ani: %s\n"
+						   "aniII: %s\n"
+						   "dnis: %s\n"
+						   "rdnis: %s\n"
+						   "cause: %s\n\n",
+						   span->channels[chan_id]->span_id,
+						   span->channels[chan_id]->chan_id,
+						   span->channels[chan_id]->physical_span_id,
+						   span->channels[chan_id]->physical_chan_id,
+						   ftdm_chan_type2str(span->channels[chan_id]->type),
+						   ftdm_channel_state2str(span->channels[chan_id]->state),
+						   ftdm_channel_state2str(span->channels[chan_id]->last_state),
+						   span->channels[chan_id]->caller_data.cid_date,
+						   span->channels[chan_id]->caller_data.cid_name,
+						   span->channels[chan_id]->caller_data.cid_num.digits,
+						   span->channels[chan_id]->caller_data.ani.digits,
+						   span->channels[chan_id]->caller_data.aniII,
+						   span->channels[chan_id]->caller_data.dnis.digits,
+						   span->channels[chan_id]->caller_data.rdnis.digits,
+						   switch_channel_cause2str(span->channels[chan_id]->caller_data.hangup_cause)
+						   );
+}
+
+void dump_chan_xml(ftdm_span_t *span, uint32_t chan_id, switch_stream_handle_t *stream)
+{
+	if (chan_id > span->chan_count) {
+		return;
+	}
+
+	stream->write_function(stream,
+						   " <channel>\n"
+						   "  <span-id>%u</span-id>\n"
+						   "  <chan-id>%u</chan-id>>\n"
+						   "  <physical-span-id>%u</physical-span-id>\n"
+						   "  <physical-chan-id>%u</physical-chan-id>\n"
+						   "  <type>%s</type>\n"
+						   "  <state>%s</state>\n"
+						   "  <last-state>%s</last-state>\n"
+						   "  <cid-date>%s</cid-date>\n"
+						   "  <cid-name>%s</cid-name>\n"
+						   "  <cid-num>%s</cid-num>\n"
+						   "  <ani>%s</ani>\n"
+						   "  <aniII>%s</aniII>\n"
+						   "  <dnis>%s</dnis>\n"
+						   "  <rdnis>%s</rdnis>\n"
+						   "  <cause>%s</cause>\n"
+						   " </channel>\n",
+						   span->channels[chan_id]->span_id,
+						   span->channels[chan_id]->chan_id,
+						   span->channels[chan_id]->physical_span_id,
+						   span->channels[chan_id]->physical_chan_id,
+						   ftdm_chan_type2str(span->channels[chan_id]->type),
+						   ftdm_channel_state2str(span->channels[chan_id]->state),
+						   ftdm_channel_state2str(span->channels[chan_id]->last_state),
+						   span->channels[chan_id]->caller_data.cid_date,
+						   span->channels[chan_id]->caller_data.cid_name,
+						   span->channels[chan_id]->caller_data.cid_num.digits,
+						   span->channels[chan_id]->caller_data.ani.digits,
+						   span->channels[chan_id]->caller_data.aniII,
+						   span->channels[chan_id]->caller_data.dnis.digits,
+						   span->channels[chan_id]->caller_data.rdnis.digits,
+						   switch_channel_cause2str(span->channels[chan_id]->caller_data.hangup_cause)
+						   );
+}
+
+#define FT_SYNTAX "list || dump <span_id> [<chan_id>] || q931_pcap <span_id> on|off [pcapfilename without suffix] || gains <span> <txgain> <rxgain>" 
+SWITCH_STANDARD_API(ft_function)
+{
+	char *mycmd = NULL, *argv[10] = { 0 };
+	int argc = 0;
+
+	if (!zstr(cmd) && (mycmd = strdup(cmd))) {
+		argc = switch_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
+	}
+
+	if (!argc) {
+		stream->write_function(stream, "%s", FT_SYNTAX);
+		goto end;
+	}
+
+	if (!strcasecmp(argv[0], "dump")) {
+		if (argc < 2) {
+			stream->write_function(stream, "-ERR Usage: ft dump <span_id> [<chan_id>]\n");
+			goto end;
+		} else {
+			uint32_t chan_id = 0;
+			ftdm_span_t *span;
+			char *as = NULL;
+			
+			ftdm_span_find_by_name(argv[1], &span);
+			
+			if (argc > 2) {
+				if (argv[3] && !strcasecmp(argv[2], "as")) {
+					as = argv[3];
+				} else {
+					chan_id = atoi(argv[2]);
+				}
+			}
+
+			if (argv[4] && !strcasecmp(argv[3], "as")) {
+				as = argv[4];
+			}
+
+			if (!zstr(as) && !strcasecmp(as, "xml")) {
+				stream->write_function(stream, "<channels>\n");
+				if (!span) {
+					stream->write_function(stream, "<error>invalid span</error>\n");
+				} else {
+					if (chan_id) {
+						if(chan_id > span->chan_count) {
+							stream->write_function(stream, "<error>invalid channel</error>\n");
+						} else {
+							dump_chan_xml(span, chan_id, stream);
+						}
+					} else {
+						uint32_t j;
+						for (j = 1; j <= span->chan_count; j++) {
+							dump_chan_xml(span, j, stream);
+						}
+						
+					}
+				}
+				stream->write_function(stream, "</channels>\n");
+			} else {
+				if (!span) {
+					stream->write_function(stream, "-ERR invalid span\n");
+				} else {
+					if (chan_id) {
+						if(chan_id > span->chan_count) {
+							stream->write_function(stream, "-ERR invalid channel\n");
+						} else {
+							dump_chan(span, chan_id, stream);
+						}
+					} else {
+						uint32_t j;
+						
+						stream->write_function(stream, "+OK\n");
+						for (j = 1; j <= span->chan_count; j++) {
+							dump_chan(span, j, stream);
+						}
+						
+					}
+				}
+			}
+		}
+	} else if (!strcasecmp(argv[0], "list")) {
+		int j;
+		for (j = 0 ; j < FTDM_MAX_SPANS_INTERFACE; j++) {
+			if (SPAN_CONFIG[j].span) {
+				const char *flags = "none";
+				ftdm_signaling_status_t sigstatus;
+
+				if (SPAN_CONFIG[j].analog_options & ANALOG_OPTION_3WAY) {
+					flags = "3way";
+				} else if (SPAN_CONFIG[j].analog_options & ANALOG_OPTION_CALL_SWAP) {
+					flags = "call swap";
+				}
+				
+				if ((FTDM_SUCCESS == ftdm_span_get_sig_status(SPAN_CONFIG[j].span, &sigstatus))) {
+					stream->write_function(stream,
+										   "+OK\n"
+										   "span: %u (%s)\n"
+										   "type: %s\n"
+										   "signaling_status: %s\n"
+										   "chan_count: %u\n"
+										   "dialplan: %s\n"
+										   "context: %s\n"
+										   "dial_regex: %s\n"
+										   "fail_dial_regex: %s\n"
+										   "hold_music: %s\n"
+										   "analog_options %s\n",
+										   j,
+										   SPAN_CONFIG[j].span->name,
+										   SPAN_CONFIG[j].type,
+										   ftdm_signaling_status2str(sigstatus),
+										   SPAN_CONFIG[j].span->chan_count,
+										   SPAN_CONFIG[j].dialplan,
+										   SPAN_CONFIG[j].context,
+										   SPAN_CONFIG[j].dial_regex,
+										   SPAN_CONFIG[j].fail_dial_regex,
+										   SPAN_CONFIG[j].hold_music,
+										   flags
+										   );
+				} else {
+					stream->write_function(stream,
+										   "+OK\n"
+										   "span: %u (%s)\n"
+										   "type: %s\n"
+										   "chan_count: %u\n"
+										   "dialplan: %s\n"
+										   "context: %s\n"
+										   "dial_regex: %s\n"
+										   "fail_dial_regex: %s\n"
+										   "hold_music: %s\n"
+										   "analog_options %s\n",
+										   j,
+										   SPAN_CONFIG[j].span->name,
+										   SPAN_CONFIG[j].type,
+										   SPAN_CONFIG[j].span->chan_count,
+										   SPAN_CONFIG[j].dialplan,
+										   SPAN_CONFIG[j].context,
+										   SPAN_CONFIG[j].dial_regex,
+										   SPAN_CONFIG[j].fail_dial_regex,
+										   SPAN_CONFIG[j].hold_music,
+										   flags
+										   );
+				}
+			}
+		}
+	} else if (!strcasecmp(argv[0], "stop") || !strcasecmp(argv[0], "start")) {
+		char *span_name = argv[1];
+		ftdm_span_t *span = NULL;
+		ftdm_status_t status;
+
+		if (span_name) {
+			ftdm_span_find_by_name(span_name, &span);
+		}
+
+		if (!span) {
+			stream->write_function(stream, "-ERR no span\n");
+			goto end;
+		}
+		
+		if (!strcasecmp(argv[0], "stop")) {
+			status = ftdm_span_stop(span);
+		} else {
+			status = ftdm_span_start(span);
+		}
+		
+		stream->write_function(stream, status == FTDM_SUCCESS ? "+OK\n" : "-ERR failure\n");
+		
+		goto end;
+
+		/*Q931ToPcap enhancement*/
+	} else if (!strcasecmp(argv[0], "q931_pcap")) {
+		int32_t span_id = 0;
+                ftdm_span_t *span;
+		const char *pcapfn = NULL;
+		char *tmp_path = NULL;
+
+                if (argc < 3) {
+                        stream->write_function(stream, "-ERR Usage: ft q931_pcap <span_id> on|off [pcapfilename without suffix]\n");
+                        goto end;
+                }
+		span_id = atoi(argv[1]);
+		if (!(span_id && (span = SPAN_CONFIG[span_id].span))) {
+                                stream->write_function(stream, "-ERR invalid span\n");
+				goto end;
+                } 
+
+		/*Look for a given file name or use default file name*/
+		if (argc > 3) {
+			if(argv[3]){
+				pcapfn=argv[3];
+			}
+		}
+		else {
+			pcapfn="q931";
+		}
+
+		/*Add log directory path to file name*/
+		tmp_path=switch_mprintf("%s%s%s.pcap", SWITCH_GLOBAL_dirs.log_dir, SWITCH_PATH_SEPARATOR, pcapfn);
+		
+		if(!strcasecmp(argv[2], "on")) {
+			if (ftdm_configure_span("isdn", span, on_clear_channel_signal, "q931topcap", 1, "pcapfilename", tmp_path, TAG_END) != FTDM_SUCCESS) {
+                                ftdm_log(FTDM_LOG_WARNING, "Error couldn't (re-)enable Q931-To-Pcap!\n");
+				goto end;
+                        } else {
+				stream->write_function(stream, "+OK\n");
+			}
+		} else if(!strcasecmp(argv[2], "off")) {
+			if (ftdm_configure_span("isdn", span, on_clear_channel_signal, "q931topcap", 0, TAG_END) != FTDM_SUCCESS) {
+                                ftdm_log(FTDM_LOG_ERROR, "Error couldn't enable Q931-To-Pcap!\n");
+                                goto end;
+			} else {
+                                stream->write_function(stream, "+OK\n");
+                        }
+                } else {
+			stream->write_function(stream, "-ERR Usage: ft q931_pcap <span_id> on|off [pcapfilename without suffix]\n");
+                        goto end;
+		}
+
+	} else if (!strcasecmp(argv[0], "gains")) {
+		unsigned int i = 0;
+		float txgain = 0.0;
+		float rxgain = 0.0;
+		uint32_t chan_id = 0;
+		ftdm_span_t *span = NULL;
+		if (argc < 4) {
+			stream->write_function(stream, "-ERR Usage: ft gains <txgain> <rxgain> <span_id> [<chan_id>]\n");
+			goto end;
+		} 
+		ftdm_span_find_by_name(argv[3], &span);
+		if (!span) {
+			stream->write_function(stream, "-ERR invalid span\n");
+			goto end;
+		}
+		if (argc > 4) {
+			chan_id = atoi(argv[4]);
+			if (chan_id > span->chan_count) {
+				stream->write_function(stream, "-ERR invalid chan\n");
+				goto end;
+			}
+		}
+		i = sscanf(argv[1], "%f", &rxgain);
+		i += sscanf(argv[2], "%f", &txgain);
+		if (i != 2) {
+			stream->write_function(stream, "-ERR invalid gains\n");
+			goto end;
+		}
+		if (chan_id) {
+			ftdm_channel_command(span->channels[chan_id], FTDM_COMMAND_SET_RX_GAIN, &rxgain);
+			ftdm_channel_command(span->channels[chan_id], FTDM_COMMAND_SET_TX_GAIN, &txgain);
+		} else {
+			for (i = 1; i < span->chan_count; i++) {
+				ftdm_channel_command(span->channels[i], FTDM_COMMAND_SET_RX_GAIN, &rxgain);
+				ftdm_channel_command(span->channels[i], FTDM_COMMAND_SET_TX_GAIN, &txgain);
+			}
+		}
+		stream->write_function(stream, "+OK gains set to Rx %f and Tx %f\n", rxgain, txgain);
+	} else {
+		char *rply = ftdm_api_execute(cmd, NULL);
+		
+		if (rply) {
+			stream->write_function(stream, "%s", rply);
+			free(rply);
+		} else {
+			stream->write_function(stream, "-ERR Usage: %s\n", FT_SYNTAX);
+		}
+	}
+	/*Q931ToPcap enhancement done*/
+
+ end:
+
+	switch_safe_free(mycmd);
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+
+SWITCH_STANDARD_APP(disable_ec_function)
+{
+	private_t *tech_pvt;
+	int x = 0;
+
+	if (!switch_core_session_check_interface(session, freetdm_endpoint_interface)) {
+		ftdm_log(FTDM_LOG_ERROR, "This application is only for FreeTDM channels.\n");
+		return;
+	}
+	
+	tech_pvt = switch_core_session_get_private(session);
+
+	if (switch_test_flag(tech_pvt, TFLAG_DEAD)) {
+        switch_channel_hangup(switch_core_session_get_channel(session), SWITCH_CAUSE_LOSE_RACE);
+        return;
+    }
+	
+	ftdm_channel_command(tech_pvt->ftdmchan, FTDM_COMMAND_DISABLE_ECHOCANCEL, &x);
+	ftdm_channel_command(tech_pvt->ftdmchan, FTDM_COMMAND_DISABLE_ECHOTRAIN, &x);
+	ftdm_log(FTDM_LOG_INFO, "Echo Canceller Disabled\n");
+}
+
+
+SWITCH_MODULE_LOAD_FUNCTION(mod_freetdm_load)
+{
+
+	switch_api_interface_t *commands_api_interface;
+	switch_application_interface_t *app_interface;
+
+	module_pool = pool;
+
+	ftdm_global_set_logger(ftdm_logger);
+	
+	if (ftdm_global_init() != FTDM_SUCCESS) {
+		ftdm_log(FTDM_LOG_ERROR, "Error loading FreeTDM\n");
+		return SWITCH_STATUS_TERM;
+	}
+
+	if (ftdm_global_configuration() != FTDM_SUCCESS) {
+		ftdm_log(FTDM_LOG_ERROR, "Error configuring FreeTDM\n");
+		return SWITCH_STATUS_TERM;
+	}
+	
+	if (load_config() != SWITCH_STATUS_SUCCESS) {
+		ftdm_global_destroy();
+		return SWITCH_STATUS_TERM;
+	}
+
+	*module_interface = switch_loadable_module_create_module_interface(pool, modname);
+	freetdm_endpoint_interface = switch_loadable_module_create_interface(*module_interface, SWITCH_ENDPOINT_INTERFACE);
+	freetdm_endpoint_interface->interface_name = "freetdm";
+	freetdm_endpoint_interface->io_routines = &freetdm_io_routines;
+	freetdm_endpoint_interface->state_handler = &freetdm_state_handlers;
+	
+	SWITCH_ADD_API(commands_api_interface, "ftdm", "FreeTDM commands", ft_function, FT_SYNTAX);
+
+	SWITCH_ADD_APP(app_interface, "disable_ec", "Disable Echo Canceller", "Disable Echo Canceller", disable_ec_function, "", SAF_NONE);
+
+	/* indicate that the module should continue to be loaded */
+	return SWITCH_STATUS_SUCCESS;
+}
+
+SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_freetdm_shutdown)
+{
+	ftdm_global_destroy();
+
+	// this breaks pika but they are MIA so *shrug*
+	//return SWITCH_STATUS_NOUNLOAD;
+	return SWITCH_STATUS_SUCCESS;
+}
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */

Added: freeswitch/trunk/libs/freetdm/mod_freetdm/mod_openzap.2005.vcproj (0 => 17141)


--- freeswitch/trunk/libs/freetdm/mod_freetdm/mod_openzap.2005.vcproj	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/mod_freetdm/mod_openzap.2005.vcproj	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,201 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="8.00"
+	Name="mod_freetdm"
+	ProjectGUID="{FE3540C5-3303-46E0-A69E-D92F775687F1}"
+	RootNamespace="mod_freetdm"
+	Keyword="Win32Proj"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="2"
+			InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+			CharacterSet="2"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				AdditionalIncludeDirectories="../../../src/include;../src/include;../src/isdn/include"
+				PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS"
+				MinimalRebuild="true"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="3"
+				UsePrecompiledHeader="0"
+				WarningLevel="4"
+				WarnAsError="true"
+				Detect64BitPortabilityProblems="false"
+				DebugInformationFormat="3"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="FreeSwitchCore.lib"
+				OutputFile="$(SolutionDir)$(OutDir)/mod/$(InputName).dll"
+				LinkIncremental="2"
+				AdditionalLibraryDirectories="&quot;../../../w32/Library/$(OutDir)&quot;"
+				GenerateDebugInformation="true"
+				ProgramDatabaseFile="$(OutDir)$(TargetName).pdb"
+				SubSystem="2"
+				ImportLibrary="$(OutDir)/mod_freetdm.lib"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="2"
+			InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+			CharacterSet="2"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalIncludeDirectories="../../../src/include;../src/include;../src/isdn/include"
+				PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS"
+				RuntimeLibrary="2"
+				UsePrecompiledHeader="0"
+				WarningLevel="4"
+				WarnAsError="true"
+				Detect64BitPortabilityProblems="false"
+				DebugInformationFormat="3"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="FreeSwitchCore.lib"
+				OutputFile="$(SolutionDir)$(OutDir)/mod/$(InputName).dll"
+				LinkIncremental="1"
+				AdditionalLibraryDirectories="&quot;../../../w32/Library/$(OutDir)&quot;"
+				GenerateDebugInformation="true"
+				ProgramDatabaseFile="$(OutDir)$(TargetName).pdb"
+				SubSystem="2"
+				OptimizeReferences="2"
+				EnableCOMDATFolding="2"
+				LinkTimeCodeGeneration="1"
+				ImportLibrary="$(OutDir)/mod_freetdm.lib"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<Filter
+			Name="Source Files"
+			Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+			>
+			<File
+				RelativePath=".\mod_freetdm.c"
+				>
+			</File>
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>

Added: freeswitch/trunk/libs/freetdm/msvc/freetdm.2008.vcproj (0 => 17141)


--- freeswitch/trunk/libs/freetdm/msvc/freetdm.2008.vcproj	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/msvc/freetdm.2008.vcproj	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,455 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="9.00"
+	Name="freetdm"
+	ProjectGUID="{93B8812C-3EC4-4F78-8970-FFBFC99E167D}"
+	RootNamespace="freetdm"
+	Keyword="Win32Proj"
+	TargetFrameworkVersion="131072"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+		<Platform
+			Name="x64"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="2"
+			CharacterSet="2"
+			BuildLogFile="$(IntDir)\BuildLog-freetdm.htm"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				AdditionalIncludeDirectories="../src/include;../src/isdn/include"
+				PreprocessorDefinitions="WIN32;_DEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;FREETDM_EXPORTS;TELETONE_EXPORTS"
+				MinimalRebuild="true"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="3"
+				DisableLanguageExtensions="false"
+				RuntimeTypeInfo="false"
+				UsePrecompiledHeader="0"
+				WarningLevel="4"
+				WarnAsError="true"
+				Detect64BitPortabilityProblems="false"
+				DebugInformationFormat="3"
+				CompileAs="1"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				GenerateDebugInformation="true"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="2"
+			CharacterSet="2"
+			WholeProgramOptimization="1"
+			BuildLogFile="$(IntDir)\BuildLog-freetdm.htm"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalIncludeDirectories="../src/include;../src/isdn/include"
+				PreprocessorDefinitions="WIN32;NDEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;FREETDM_EXPORTS;TELETONE_EXPORTS"
+				RuntimeLibrary="2"
+				DisableLanguageExtensions="false"
+				RuntimeTypeInfo="false"
+				UsePrecompiledHeader="0"
+				WarningLevel="4"
+				WarnAsError="true"
+				Detect64BitPortabilityProblems="false"
+				DebugInformationFormat="3"
+				CompileAs="1"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Debug|x64"
+			OutputDirectory="$(SolutionDir)$(PlatformName)\$(ConfigurationName)"
+			IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+			ConfigurationType="2"
+			CharacterSet="2"
+			BuildLogFile="$(IntDir)\BuildLog-freetdm.htm"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+				TargetEnvironment="3"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				AdditionalIncludeDirectories="../src/include;../src/isdn/include"
+				PreprocessorDefinitions="WIN32;_DEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;FREETDM_EXPORTS;TELETONE_EXPORTS"
+				MinimalRebuild="true"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="3"
+				DisableLanguageExtensions="false"
+				RuntimeTypeInfo="false"
+				UsePrecompiledHeader="0"
+				WarningLevel="4"
+				WarnAsError="true"
+				Detect64BitPortabilityProblems="false"
+				DebugInformationFormat="3"
+				CompileAs="1"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				GenerateDebugInformation="true"
+				TargetMachine="17"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|x64"
+			OutputDirectory="$(SolutionDir)$(PlatformName)\$(ConfigurationName)"
+			IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+			ConfigurationType="2"
+			CharacterSet="2"
+			WholeProgramOptimization="1"
+			BuildLogFile="$(IntDir)\BuildLog-freetdm.htm"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+				TargetEnvironment="3"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalIncludeDirectories="../src/include;../src/isdn/include"
+				PreprocessorDefinitions="WIN32;NDEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;FREETDM_EXPORTS;TELETONE_EXPORTS"
+				RuntimeLibrary="2"
+				DisableLanguageExtensions="false"
+				RuntimeTypeInfo="false"
+				UsePrecompiledHeader="0"
+				WarningLevel="4"
+				WarnAsError="true"
+				Detect64BitPortabilityProblems="false"
+				DebugInformationFormat="3"
+				CompileAs="1"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				TargetMachine="17"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<Filter
+			Name="Header Files"
+			Filter="h;hpp;hxx;hm;inl;inc;xsd"
+			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+			>
+			<File
+				RelativePath="..\src\include\fsk.h"
+				>
+			</File>
+			<File
+				RelativePath="..\src\include\g711.h"
+				>
+			</File>
+			<File
+				RelativePath="..\src\include\hashtable.h"
+				>
+			</File>
+			<File
+				RelativePath="..\src\include\hashtable_itr.h"
+				>
+			</File>
+			<File
+				RelativePath="..\src\include\hashtable_private.h"
+				>
+			</File>
+			<File
+				RelativePath="..\src\include\libteletone.h"
+				>
+			</File>
+			<File
+				RelativePath="..\src\include\libteletone_detect.h"
+				>
+			</File>
+			<File
+				RelativePath="..\src\include\libteletone_generate.h"
+				>
+			</File>
+			<File
+				RelativePath="..\src\include\freetdm.h"
+				>
+			</File>
+			<File
+				RelativePath="..\src\include\uart.h"
+				>
+			</File>
+			<File
+				RelativePath="..\src\include\ftdm_buffer.h"
+				>
+			</File>
+			<File
+				RelativePath="..\src\include\ftdm_config.h"
+				>
+			</File>
+			<File
+				RelativePath="..\src\include\ftdm_dso.h"
+				>
+			</File>
+			<File
+				RelativePath="..\src\include\ftdm_threadmutex.h"
+				>
+			</File>
+			<File
+				RelativePath="..\src\include\ftdm_types.h"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="Source Files"
+			Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+			>
+			<File
+				RelativePath="..\src\fsk.c"
+				>
+			</File>
+			<File
+				RelativePath="..\src\g711.c"
+				>
+			</File>
+			<File
+				RelativePath="..\src\hashtable.c"
+				>
+			</File>
+			<File
+				RelativePath="..\src\hashtable_itr.c"
+				>
+			</File>
+			<File
+				RelativePath="..\src\libteletone_detect.c"
+				>
+			</File>
+			<File
+				RelativePath="..\src\libteletone_generate.c"
+				>
+			</File>
+			<File
+				RelativePath="..\src\uart.c"
+				>
+			</File>
+			<File
+				RelativePath="..\src\ftdm_buffer.c"
+				>
+			</File>
+			<File
+				RelativePath="..\src\ftdm_callerid.c"
+				>
+			</File>
+			<File
+				RelativePath="..\src\ftdm_config.c"
+				>
+			</File>
+			<File
+				RelativePath="..\src\ftdm_dso.c"
+				>
+			</File>
+			<File
+				RelativePath="..\src\ftdm_io.c"
+				>
+			</File>
+			<File
+				RelativePath="..\src\ftdm_queue.c"
+				>
+			</File>
+			<File
+				RelativePath="..\src\ftdm_threadmutex.c"
+				>
+			</File>
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>

Added: freeswitch/trunk/libs/freetdm/msvc/openzap.2005.vcproj (0 => 17141)


--- freeswitch/trunk/libs/freetdm/msvc/openzap.2005.vcproj	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/msvc/openzap.2005.vcproj	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,301 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="8.00"
+	Name="freetdm"
+	ProjectGUID="{93B8812C-3EC4-4F78-8970-FFBFC99E167D}"
+	RootNamespace="freetdm"
+	Keyword="Win32Proj"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="2"
+			CharacterSet="2"
+			BuildLogFile="$(IntDir)\BuildLog-freetdm.htm"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				AdditionalIncludeDirectories="../src/include;../src/isdn/include"
+				PreprocessorDefinitions="WIN32;_DEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;FREETDM_EXPORTS;TELETONE_EXPORTS"
+				MinimalRebuild="true"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="3"
+				DisableLanguageExtensions="false"
+				RuntimeTypeInfo="false"
+				UsePrecompiledHeader="0"
+				WarningLevel="4"
+				WarnAsError="true"
+				Detect64BitPortabilityProblems="true"
+				DebugInformationFormat="3"
+				CompileAs="1"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="2"
+			CharacterSet="2"
+			WholeProgramOptimization="1"
+			BuildLogFile="$(IntDir)\BuildLog-freetdm.htm"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalIncludeDirectories="../src/include;../src/isdn/include"
+				PreprocessorDefinitions="WIN32;NDEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;FREETDM_EXPORTS;TELETONE_EXPORTS"
+				RuntimeLibrary="2"
+				DisableLanguageExtensions="false"
+				RuntimeTypeInfo="false"
+				UsePrecompiledHeader="0"
+				WarningLevel="4"
+				WarnAsError="true"
+				Detect64BitPortabilityProblems="true"
+				DebugInformationFormat="3"
+				CompileAs="1"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<Filter
+			Name="Source Files"
+			Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+			>
+			<File
+				RelativePath="..\src\fsk.c"
+				>
+			</File>
+			<File
+				RelativePath="..\src\g711.c"
+				>
+			</File>
+			<File
+				RelativePath="..\src\hashtable.c"
+				>
+			</File>
+			<File
+				RelativePath="..\src\hashtable_itr.c"
+				>
+			</File>
+			<File
+				RelativePath="..\src\libteletone_detect.c"
+				>
+			</File>
+			<File
+				RelativePath="..\src\libteletone_generate.c"
+				>
+			</File>
+			<File
+				RelativePath="..\src\uart.c"
+				>
+			</File>
+			<File
+				RelativePath="..\src\ftdm_buffer.c"
+				>
+			</File>
+			<File
+				RelativePath="..\src\ftdm_callerid.c"
+				>
+			</File>
+			<File
+				RelativePath="..\src\ftdm_config.c"
+				>
+			</File>
+			<File
+				RelativePath="..\src\ftdm_dso.c"
+				>
+			</File>
+			<File
+				RelativePath="..\src\ftdm_io.c"
+				>
+			</File>
+			<File
+				RelativePath="..\src\ftdm_threadmutex.c"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="Header Files"
+			Filter="h;hpp;hxx;hm;inl;inc;xsd"
+			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+			>
+			<File
+				RelativePath="..\src\include\fsk.h"
+				>
+			</File>
+			<File
+				RelativePath="..\src\include\g711.h"
+				>
+			</File>
+			<File
+				RelativePath="..\src\include\hashtable.h"
+				>
+			</File>
+			<File
+				RelativePath="..\src\include\hashtable_itr.h"
+				>
+			</File>
+			<File
+				RelativePath="..\src\include\hashtable_private.h"
+				>
+			</File>
+			<File
+				RelativePath="..\src\include\libteletone.h"
+				>
+			</File>
+			<File
+				RelativePath="..\src\include\libteletone_detect.h"
+				>
+			</File>
+			<File
+				RelativePath="..\src\include\libteletone_generate.h"
+				>
+			</File>
+			<File
+				RelativePath="..\src\include\freetdm.h"
+				>
+			</File>
+			<File
+				RelativePath="..\src\include\uart.h"
+				>
+			</File>
+			<File
+				RelativePath="..\src\include\ftdm_buffer.h"
+				>
+			</File>
+			<File
+				RelativePath="..\src\include\ftdm_config.h"
+				>
+			</File>
+			<File
+				RelativePath="..\src\include\ftdm_dso.h"
+				>
+			</File>
+			<File
+				RelativePath="..\src\include\ftdm_threadmutex.h"
+				>
+			</File>
+			<File
+				RelativePath="..\src\include\ftdm_types.h"
+				>
+			</File>
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>

Added: freeswitch/trunk/libs/freetdm/msvc/testanalog/testanalog.2005.vcproj (0 => 17141)


--- freeswitch/trunk/libs/freetdm/msvc/testanalog/testanalog.2005.vcproj	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/msvc/testanalog/testanalog.2005.vcproj	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,193 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="8.00"
+	Name="testanalog"
+	ProjectGUID="{BB833648-BAFF-4BE2-94DB-F8BB043C588C}"
+	RootNamespace="testanalog"
+	Keyword="Win32Proj"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="1"
+			CharacterSet="1"
+			BuildLogFile="$(IntDir)\BuildLog-testanalog.htm"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				AdditionalIncludeDirectories="../../src/include;../../src/isdn/include"
+				PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
+				MinimalRebuild="true"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="3"
+				UsePrecompiledHeader="0"
+				WarningLevel="4"
+				WarnAsError="true"
+				Detect64BitPortabilityProblems="true"
+				DebugInformationFormat="4"
+				DisableSpecificWarnings="4100"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				LinkIncremental="2"
+				GenerateDebugInformation="true"
+				SubSystem="1"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="1"
+			CharacterSet="1"
+			WholeProgramOptimization="1"
+			BuildLogFile="$(IntDir)\BuildLog-testanalog.htm"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalIncludeDirectories="../../src/include;../../src/isdn/include"
+				PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
+				RuntimeLibrary="2"
+				UsePrecompiledHeader="0"
+				WarningLevel="4"
+				WarnAsError="true"
+				Detect64BitPortabilityProblems="true"
+				DebugInformationFormat="3"
+				DisableSpecificWarnings="4100"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				LinkIncremental="1"
+				GenerateDebugInformation="true"
+				SubSystem="1"
+				OptimizeReferences="2"
+				EnableCOMDATFolding="2"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<Filter
+			Name="Source Files"
+			Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+			>
+			<File
+				RelativePath="..\..\src\testanalog.c"
+				>
+			</File>
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>

Added: freeswitch/trunk/libs/freetdm/msvc/testanalog/testanalog.2008.vcproj (0 => 17141)


--- freeswitch/trunk/libs/freetdm/msvc/testanalog/testanalog.2008.vcproj	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/msvc/testanalog/testanalog.2008.vcproj	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,349 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="9.00"
+	Name="testanalog"
+	ProjectGUID="{BB833648-BAFF-4BE2-94DB-F8BB043C588C}"
+	RootNamespace="testanalog"
+	Keyword="Win32Proj"
+	TargetFrameworkVersion="131072"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+		<Platform
+			Name="x64"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="1"
+			CharacterSet="1"
+			BuildLogFile="$(IntDir)\BuildLog-testanalog.htm"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				AdditionalIncludeDirectories="../../src/include;../../src/isdn/include"
+				PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
+				MinimalRebuild="true"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="3"
+				UsePrecompiledHeader="0"
+				WarningLevel="4"
+				WarnAsError="true"
+				DebugInformationFormat="4"
+				DisableSpecificWarnings="4100"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				LinkIncremental="2"
+				GenerateDebugInformation="true"
+				SubSystem="1"
+				RandomizedBaseAddress="1"
+				DataExecutionPrevention="0"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="1"
+			CharacterSet="1"
+			WholeProgramOptimization="1"
+			BuildLogFile="$(IntDir)\BuildLog-testanalog.htm"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalIncludeDirectories="../../src/include;../../src/isdn/include"
+				PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
+				RuntimeLibrary="2"
+				UsePrecompiledHeader="0"
+				WarningLevel="4"
+				WarnAsError="true"
+				DebugInformationFormat="3"
+				DisableSpecificWarnings="4100"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				LinkIncremental="1"
+				GenerateDebugInformation="true"
+				SubSystem="1"
+				OptimizeReferences="2"
+				EnableCOMDATFolding="2"
+				RandomizedBaseAddress="1"
+				DataExecutionPrevention="0"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Debug|x64"
+			OutputDirectory="$(SolutionDir)$(PlatformName)\$(ConfigurationName)"
+			IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+			ConfigurationType="1"
+			CharacterSet="1"
+			BuildLogFile="$(IntDir)\BuildLog-testanalog.htm"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+				TargetEnvironment="3"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				AdditionalIncludeDirectories="../../src/include;../../src/isdn/include"
+				PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
+				MinimalRebuild="true"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="3"
+				UsePrecompiledHeader="0"
+				WarningLevel="4"
+				WarnAsError="true"
+				DebugInformationFormat="3"
+				DisableSpecificWarnings="4100"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				LinkIncremental="2"
+				GenerateDebugInformation="true"
+				SubSystem="1"
+				RandomizedBaseAddress="1"
+				DataExecutionPrevention="0"
+				TargetMachine="17"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|x64"
+			OutputDirectory="$(SolutionDir)$(PlatformName)\$(ConfigurationName)"
+			IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+			ConfigurationType="1"
+			CharacterSet="1"
+			WholeProgramOptimization="1"
+			BuildLogFile="$(IntDir)\BuildLog-testanalog.htm"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+				TargetEnvironment="3"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalIncludeDirectories="../../src/include;../../src/isdn/include"
+				PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
+				RuntimeLibrary="2"
+				UsePrecompiledHeader="0"
+				WarningLevel="4"
+				WarnAsError="true"
+				DebugInformationFormat="3"
+				DisableSpecificWarnings="4100"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				LinkIncremental="1"
+				GenerateDebugInformation="true"
+				SubSystem="1"
+				OptimizeReferences="2"
+				EnableCOMDATFolding="2"
+				RandomizedBaseAddress="1"
+				DataExecutionPrevention="0"
+				TargetMachine="17"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<Filter
+			Name="Source Files"
+			Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+			>
+			<File
+				RelativePath="..\..\src\testanalog.c"
+				>
+			</File>
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>

Added: freeswitch/trunk/libs/freetdm/msvc/testboost/testboost.2008.vcproj (0 => 17141)


--- freeswitch/trunk/libs/freetdm/msvc/testboost/testboost.2008.vcproj	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/msvc/testboost/testboost.2008.vcproj	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,191 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="9.00"
+	Name="testboost"
+	ProjectGUID="{2B1BAF36-0241-43E7-B865-A8338AD48E2E}"
+	RootNamespace="testboost"
+	Keyword="Win32Proj"
+	TargetFrameworkVersion="131072"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="1"
+			CharacterSet="1"
+			BuildLogFile="$(IntDir)\BuildLog-testboost.htm"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				AdditionalIncludeDirectories="../../src/include"
+				PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
+				MinimalRebuild="true"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="3"
+				UsePrecompiledHeader="0"
+				WarningLevel="4"
+				WarnAsError="true"
+				DebugInformationFormat="4"
+				DisableSpecificWarnings="4100"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="..\..\debug\freetdm.lib"
+				LinkIncremental="2"
+				GenerateDebugInformation="true"
+				SubSystem="1"
+				RandomizedBaseAddress="1"
+				DataExecutionPrevention="0"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="1"
+			CharacterSet="1"
+			WholeProgramOptimization="1"
+			BuildLogFile="$(IntDir)\BuildLog-testboost.htm"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalIncludeDirectories="../../src/include"
+				PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
+				RuntimeLibrary="2"
+				UsePrecompiledHeader="0"
+				WarningLevel="4"
+				WarnAsError="true"
+				DebugInformationFormat="3"
+				DisableSpecificWarnings="4100"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				LinkIncremental="1"
+				GenerateDebugInformation="true"
+				SubSystem="1"
+				OptimizeReferences="2"
+				EnableCOMDATFolding="2"
+				RandomizedBaseAddress="1"
+				DataExecutionPrevention="0"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<Filter
+			Name="Source Files"
+			Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+			>
+			<File
+				RelativePath="..\..\src\testboost.c"
+				>
+			</File>
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>

Added: freeswitch/trunk/libs/freetdm/msvc/testboost/testsangomaboost.2008.vcproj (0 => 17141)


--- freeswitch/trunk/libs/freetdm/msvc/testboost/testsangomaboost.2008.vcproj	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/msvc/testboost/testsangomaboost.2008.vcproj	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,191 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="9.00"
+	Name="testsangomaboost"
+	ProjectGUID="{0DA69C18-4FA1-4E8C-89CE-12498637C5BE}"
+	RootNamespace="testsangomaboost"
+	Keyword="Win32Proj"
+	TargetFrameworkVersion="131072"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="1"
+			CharacterSet="1"
+			BuildLogFile="$(IntDir)\BuildLog-testsangomaboost.htm"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				AdditionalIncludeDirectories="../../src/include"
+				PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
+				MinimalRebuild="true"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="3"
+				UsePrecompiledHeader="0"
+				WarningLevel="4"
+				WarnAsError="true"
+				DebugInformationFormat="4"
+				DisableSpecificWarnings="4100"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="..\..\debug\freetdm.lib"
+				LinkIncremental="2"
+				GenerateDebugInformation="true"
+				SubSystem="1"
+				RandomizedBaseAddress="1"
+				DataExecutionPrevention="0"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="1"
+			CharacterSet="1"
+			WholeProgramOptimization="1"
+			BuildLogFile="$(IntDir)\BuildLog-testsangomaboost.htm"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalIncludeDirectories="../../src/include"
+				PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
+				RuntimeLibrary="2"
+				UsePrecompiledHeader="0"
+				WarningLevel="4"
+				WarnAsError="true"
+				DebugInformationFormat="3"
+				DisableSpecificWarnings="4100"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				LinkIncremental="1"
+				GenerateDebugInformation="true"
+				SubSystem="1"
+				OptimizeReferences="2"
+				EnableCOMDATFolding="2"
+				RandomizedBaseAddress="1"
+				DataExecutionPrevention="0"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<Filter
+			Name="Source Files"
+			Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+			>
+			<File
+				RelativePath="..\..\src\testsangomaboost.c"
+				>
+			</File>
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>

Added: freeswitch/trunk/libs/freetdm/msvc/testisdn/testisdn.2005.vcproj (0 => 17141)


--- freeswitch/trunk/libs/freetdm/msvc/testisdn/testisdn.2005.vcproj	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/msvc/testisdn/testisdn.2005.vcproj	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,193 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="8.00"
+	Name="testisdn"
+	ProjectGUID="{6DA6FD42-641D-4147-92F5-3BC4AAA6589B}"
+	RootNamespace="testisdn"
+	Keyword="Win32Proj"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="1"
+			CharacterSet="1"
+			BuildLogFile="$(IntDir)\BuildLog-testisdn.htm"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				AdditionalIncludeDirectories="../../src/include;../../src/isdn/include"
+				PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
+				MinimalRebuild="true"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="3"
+				UsePrecompiledHeader="0"
+				WarningLevel="4"
+				WarnAsError="true"
+				Detect64BitPortabilityProblems="true"
+				DebugInformationFormat="4"
+				DisableSpecificWarnings="4100"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				LinkIncremental="2"
+				GenerateDebugInformation="true"
+				SubSystem="1"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="1"
+			CharacterSet="1"
+			WholeProgramOptimization="1"
+			BuildLogFile="$(IntDir)\BuildLog-testisdn.htm"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalIncludeDirectories="../../src/include;../../src/isdn/include"
+				PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
+				RuntimeLibrary="2"
+				UsePrecompiledHeader="0"
+				WarningLevel="4"
+				WarnAsError="true"
+				Detect64BitPortabilityProblems="true"
+				DebugInformationFormat="3"
+				DisableSpecificWarnings="4100"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				LinkIncremental="1"
+				GenerateDebugInformation="true"
+				SubSystem="1"
+				OptimizeReferences="2"
+				EnableCOMDATFolding="2"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<Filter
+			Name="Source Files"
+			Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+			>
+			<File
+				RelativePath="..\..\src\testisdn.c"
+				>
+			</File>
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>

Added: freeswitch/trunk/libs/freetdm/msvc/testisdn/testisdn.2008.vcproj (0 => 17141)


--- freeswitch/trunk/libs/freetdm/msvc/testisdn/testisdn.2008.vcproj	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/msvc/testisdn/testisdn.2008.vcproj	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,349 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="9.00"
+	Name="testisdn"
+	ProjectGUID="{6DA6FD42-641D-4147-92F5-3BC4AAA6589B}"
+	RootNamespace="testisdn"
+	Keyword="Win32Proj"
+	TargetFrameworkVersion="131072"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+		<Platform
+			Name="x64"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="1"
+			CharacterSet="1"
+			BuildLogFile="$(IntDir)\BuildLog-testisdn.htm"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				AdditionalIncludeDirectories="../../src/include;../../src/isdn/include"
+				PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
+				MinimalRebuild="true"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="3"
+				UsePrecompiledHeader="0"
+				WarningLevel="4"
+				WarnAsError="true"
+				DebugInformationFormat="4"
+				DisableSpecificWarnings="4100"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				LinkIncremental="2"
+				GenerateDebugInformation="true"
+				SubSystem="1"
+				RandomizedBaseAddress="1"
+				DataExecutionPrevention="0"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="1"
+			CharacterSet="1"
+			WholeProgramOptimization="1"
+			BuildLogFile="$(IntDir)\BuildLog-testisdn.htm"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalIncludeDirectories="../../src/include;../../src/isdn/include"
+				PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
+				RuntimeLibrary="2"
+				UsePrecompiledHeader="0"
+				WarningLevel="4"
+				WarnAsError="true"
+				DebugInformationFormat="3"
+				DisableSpecificWarnings="4100"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				LinkIncremental="1"
+				GenerateDebugInformation="true"
+				SubSystem="1"
+				OptimizeReferences="2"
+				EnableCOMDATFolding="2"
+				RandomizedBaseAddress="1"
+				DataExecutionPrevention="0"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Debug|x64"
+			OutputDirectory="$(SolutionDir)$(PlatformName)\$(ConfigurationName)"
+			IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+			ConfigurationType="1"
+			CharacterSet="1"
+			BuildLogFile="$(IntDir)\BuildLog-testisdn.htm"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+				TargetEnvironment="3"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				AdditionalIncludeDirectories="../../src/include;../../src/isdn/include"
+				PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
+				MinimalRebuild="true"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="3"
+				UsePrecompiledHeader="0"
+				WarningLevel="4"
+				WarnAsError="true"
+				DebugInformationFormat="3"
+				DisableSpecificWarnings="4100"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				LinkIncremental="2"
+				GenerateDebugInformation="true"
+				SubSystem="1"
+				RandomizedBaseAddress="1"
+				DataExecutionPrevention="0"
+				TargetMachine="17"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|x64"
+			OutputDirectory="$(SolutionDir)$(PlatformName)\$(ConfigurationName)"
+			IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+			ConfigurationType="1"
+			CharacterSet="1"
+			WholeProgramOptimization="1"
+			BuildLogFile="$(IntDir)\BuildLog-testisdn.htm"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+				TargetEnvironment="3"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalIncludeDirectories="../../src/include;../../src/isdn/include"
+				PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
+				RuntimeLibrary="2"
+				UsePrecompiledHeader="0"
+				WarningLevel="4"
+				WarnAsError="true"
+				DebugInformationFormat="3"
+				DisableSpecificWarnings="4100"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				LinkIncremental="1"
+				GenerateDebugInformation="true"
+				SubSystem="1"
+				OptimizeReferences="2"
+				EnableCOMDATFolding="2"
+				RandomizedBaseAddress="1"
+				DataExecutionPrevention="0"
+				TargetMachine="17"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<Filter
+			Name="Source Files"
+			Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+			>
+			<File
+				RelativePath="..\..\src\testisdn.c"
+				>
+			</File>
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>

Added: freeswitch/trunk/libs/freetdm/openzap.2005.sln (0 => 17141)


--- freeswitch/trunk/libs/freetdm/openzap.2005.sln	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/openzap.2005.sln	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,82 @@
+
+Microsoft Visual Studio Solution File, Format Version 9.00
+# Visual Studio 2005
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "openzap", "msvc\openzap.2005.vcproj", "{93B8812C-3EC4-4F78-8970-FFBFC99E167D}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testanalog", "msvc\testanalog\testanalog.2005.vcproj", "{BB833648-BAFF-4BE2-94DB-F8BB043C588C}"
+	ProjectSection(ProjectDependencies) = postProject
+		{93B8812C-3EC4-4F78-8970-FFBFC99E167D} = {93B8812C-3EC4-4F78-8970-FFBFC99E167D}
+	EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testisdn", "msvc\testisdn\testisdn.2005.vcproj", "{6DA6FD42-641D-4147-92F5-3BC4AAA6589B}"
+	ProjectSection(ProjectDependencies) = postProject
+		{93B8812C-3EC4-4F78-8970-FFBFC99E167D} = {93B8812C-3EC4-4F78-8970-FFBFC99E167D}
+	EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_openzap", "mod_openzap\mod_openzap.2005.vcproj", "{FE3540C5-3303-46E0-A69E-D92F775687F1}"
+	ProjectSection(ProjectDependencies) = postProject
+		{93B8812C-3EC4-4F78-8970-FFBFC99E167D} = {93B8812C-3EC4-4F78-8970-FFBFC99E167D}
+	EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ozmod_analog", "src\ozmod\ozmod_analog\ozmod_analog.2005.vcproj", "{37C94798-6E33-4B4F-8EE0-C72A7DC91157}"
+	ProjectSection(ProjectDependencies) = postProject
+		{93B8812C-3EC4-4F78-8970-FFBFC99E167D} = {93B8812C-3EC4-4F78-8970-FFBFC99E167D}
+	EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ozmod_analog_em", "src\ozmod\ozmod_analog_em\ozmod_analog_em.2005.vcproj", "{C539D7C8-26A8-4A94-B938-77672165C130}"
+	ProjectSection(ProjectDependencies) = postProject
+		{93B8812C-3EC4-4F78-8970-FFBFC99E167D} = {93B8812C-3EC4-4F78-8970-FFBFC99E167D}
+	EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ozmod_isdn", "src\ozmod\ozmod_isdn\ozmod_isdn.2005.vcproj", "{729344A5-D5E9-434D-8EE8-AF8C6C795D15}"
+	ProjectSection(ProjectDependencies) = postProject
+		{93B8812C-3EC4-4F78-8970-FFBFC99E167D} = {93B8812C-3EC4-4F78-8970-FFBFC99E167D}
+	EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ozmod_wanpipe", "src\ozmod\ozmod_wanpipe\ozmod_wanpipe.2005.vcproj", "{1A145EE9-BBD8-45E5-98CD-EB4BE99E1DCD}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ozmod_pika", "src\ozmod\ozmod_pika\ozmod_pika.2005.vcproj", "{E886B4D5-AB4F-4092-B8F4-3B06E1E462EF}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Win32 = Debug|Win32
+		Release|Win32 = Release|Win32
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{93B8812C-3EC4-4F78-8970-FFBFC99E167D}.Debug|Win32.ActiveCfg = Debug|Win32
+		{93B8812C-3EC4-4F78-8970-FFBFC99E167D}.Debug|Win32.Build.0 = Debug|Win32
+		{93B8812C-3EC4-4F78-8970-FFBFC99E167D}.Release|Win32.ActiveCfg = Release|Win32
+		{93B8812C-3EC4-4F78-8970-FFBFC99E167D}.Release|Win32.Build.0 = Release|Win32
+		{BB833648-BAFF-4BE2-94DB-F8BB043C588C}.Debug|Win32.ActiveCfg = Debug|Win32
+		{BB833648-BAFF-4BE2-94DB-F8BB043C588C}.Debug|Win32.Build.0 = Debug|Win32
+		{BB833648-BAFF-4BE2-94DB-F8BB043C588C}.Release|Win32.ActiveCfg = Release|Win32
+		{BB833648-BAFF-4BE2-94DB-F8BB043C588C}.Release|Win32.Build.0 = Release|Win32
+		{6DA6FD42-641D-4147-92F5-3BC4AAA6589B}.Debug|Win32.ActiveCfg = Debug|Win32
+		{6DA6FD42-641D-4147-92F5-3BC4AAA6589B}.Debug|Win32.Build.0 = Debug|Win32
+		{6DA6FD42-641D-4147-92F5-3BC4AAA6589B}.Release|Win32.ActiveCfg = Release|Win32
+		{6DA6FD42-641D-4147-92F5-3BC4AAA6589B}.Release|Win32.Build.0 = Release|Win32
+		{FE3540C5-3303-46E0-A69E-D92F775687F1}.Debug|Win32.ActiveCfg = Debug|Win32
+		{FE3540C5-3303-46E0-A69E-D92F775687F1}.Debug|Win32.Build.0 = Debug|Win32
+		{FE3540C5-3303-46E0-A69E-D92F775687F1}.Release|Win32.ActiveCfg = Release|Win32
+		{FE3540C5-3303-46E0-A69E-D92F775687F1}.Release|Win32.Build.0 = Release|Win32
+		{37C94798-6E33-4B4F-8EE0-C72A7DC91157}.Debug|Win32.ActiveCfg = Debug|Win32
+		{37C94798-6E33-4B4F-8EE0-C72A7DC91157}.Debug|Win32.Build.0 = Debug|Win32
+		{37C94798-6E33-4B4F-8EE0-C72A7DC91157}.Release|Win32.ActiveCfg = Release|Win32
+		{37C94798-6E33-4B4F-8EE0-C72A7DC91157}.Release|Win32.Build.0 = Release|Win32
+		{C539D7C8-26A8-4A94-B938-77672165C130}.Debug|Win32.ActiveCfg = Debug|Win32
+		{C539D7C8-26A8-4A94-B938-77672165C130}.Debug|Win32.Build.0 = Debug|Win32
+		{C539D7C8-26A8-4A94-B938-77672165C130}.Release|Win32.ActiveCfg = Release|Win32
+		{C539D7C8-26A8-4A94-B938-77672165C130}.Release|Win32.Build.0 = Release|Win32
+		{729344A5-D5E9-434D-8EE8-AF8C6C795D15}.Debug|Win32.ActiveCfg = Debug|Win32
+		{729344A5-D5E9-434D-8EE8-AF8C6C795D15}.Debug|Win32.Build.0 = Debug|Win32
+		{729344A5-D5E9-434D-8EE8-AF8C6C795D15}.Release|Win32.ActiveCfg = Release|Win32
+		{729344A5-D5E9-434D-8EE8-AF8C6C795D15}.Release|Win32.Build.0 = Release|Win32
+		{1A145EE9-BBD8-45E5-98CD-EB4BE99E1DCD}.Debug|Win32.ActiveCfg = Debug|Win32
+		{1A145EE9-BBD8-45E5-98CD-EB4BE99E1DCD}.Release|Win32.ActiveCfg = Release|Win32
+		{E886B4D5-AB4F-4092-B8F4-3B06E1E462EF}.Debug|Win32.ActiveCfg = Debug|Win32
+		{E886B4D5-AB4F-4092-B8F4-3B06E1E462EF}.Release|Win32.ActiveCfg = Release|Win32
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+EndGlobal

Added: freeswitch/trunk/libs/freetdm/ozrename.sh (0 => 17141)


--- freeswitch/trunk/libs/freetdm/ozrename.sh	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/ozrename.sh	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,99 @@
+# renaming main header and build file
+copy="cp -r"
+
+$copy src/include/openzap.h src/include/freetdm.h
+svn delete src/include/openzap.h
+$copy openzap.pc.in freetdm.pc.in
+svn delete openzap.pc.in
+
+# create mod_freetdm
+mkdir mod_freetdm
+cp mod_openzap/* mod_freetdm/
+mv mod_freetdm/mod_openzap.c mod_freetdm/mod_freetdm.c
+svn delete --force mod_openzap
+
+
+##### ozmod stuff ####
+# rename anything ozmod to ftmod, including directories first
+mkdir ./src/ftmod
+for file in `find ./src/ozmod -name *ozmod_* -type d`
+do
+	$copy ${file} ${file//ozmod/ftmod}
+done
+
+#remove .svn directories in the copied ozmod dirs
+find ./src/ftmod -name *.svn -exec rm -rf {} \;
+
+# copy ozmod c files
+for file in `find ./src/ftmod -name *ozmod_*.c`
+do
+	mv $file ${file//ozmod/ftmod}
+done
+
+# copy ozmod h files
+for file in `find ./src/ftmod -name *ozmod_*.h`
+do
+	mv $file ${file//ozmod/ftmod}
+done
+
+#### end ozmod stuff ####
+
+# renaming other zap files
+for file in `find ./ -name *zap_*.c`
+do
+	mv $file ${file//zap_/ftdm_}
+done
+
+for file in `find ./ -name *zap_*.h`
+do
+	mv $file ${file//zap_/ftdm_}
+done
+
+svn revert -R src/ozmod
+svn delete --force src/ozmod
+
+# replace full openzap occurences first (handles openzap.h, libopenzap etc)
+find ./ -name *.c -exec sed -i 's,openzap,freetdm,g' {} \;
+
+find ./ -name *.h -exec sed -i 's,openzap,freetdm,g' {} \;
+
+sed -i 's,openzap,freetdm,g' Makefile.am
+
+sed -i 's,openzap,freetdm,g' configure.ac
+
+sed -i 's,openzap,freetdm,g' mod_freetdm/Makefile.in
+
+# replace inside files
+find ./ -name *.c -exec sed -i 's,oz,ft,g' {} \;
+find ./ -name *.c -exec sed -i 's,OZ,FT,g' {} \;
+find ./ -name *.c -exec sed -i 's,zap,ftdm,g' {} \;
+find ./ -name *.c -exec sed -i 's,ZAP,FTDM,g' {} \;
+find ./ -name *.c -exec sed -i 's,zchan,ftdmchan,g' {} \;
+
+find ./ -name *.h -exec sed -i 's,oz,ft,g' {} \;
+find ./ -name *.h -exec sed -i 's,OZ,FT,g' {} \;
+find ./ -name *.h -exec sed -i 's,zap,ftdm,g' {} \;
+find ./ -name *.h -exec sed -i 's,ZAP,FTDM,g' {} \;
+find ./ -name *.h -exec sed -i 's,zchan,ftdmchan,g' {} \;
+
+sed -i 's,oz,ft,g' Makefile.am 
+sed -i 's,OZ,FT,g' Makefile.am
+sed -i 's,zap,ftdm,g' Makefile.am
+sed -i 's,ZAP,FTDM,g' Makefile.am
+sed -i 's,zchan,ftdmchan,g' Makefile.am
+
+sed -i 's,oz,ft,g' configure.ac
+sed -i 's,OZ,FT,g' configure.ac
+sed -i 's,zap,ftdm,g' configure.ac
+sed -i 's,ZAP,FTDM,g' configure.ac
+sed -i 's,zchan,ftdmchan,g' configure.ac
+
+sed -i 's,oz,ft,g' mod_freetdm/Makefile.in
+sed -i 's,OZ,FT,g' mod_freetdm/Makefile.in
+sed -i 's,zap,ftdm,g' mod_freetdm/Makefile.in
+sed -i 's,ZAP,FTDM,g' mod_freetdm/Makefile.in
+sed -i 's,zchan,ftdmchan,g' mod_freetdm/Makefile.in
+
+svn add src/ftmod/
+svn add mod_freetdm/
+
Property changes on: freeswitch/trunk/libs/freetdm/ozrename.sh
___________________________________________________________________
Name: svn:executable
   + *

Added: freeswitch/trunk/libs/freetdm/ozreplace.sh (0 => 17141)


--- freeswitch/trunk/libs/freetdm/ozreplace.sh	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/ozreplace.sh	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,13 @@
+##### ozmod stuff ####
+# replace full openzap occurences first (handles openzap.h, libopenzap etc)
+sed -i 's,openzap,freetdm,g' $1
+sed -i 's,ozmod,ftmod,g' $1
+
+sed -i 's,zchan,ftdmchan,g' $1
+sed -i 's,oz,ft,g' $1
+sed -i 's,OZ,FT,g' $1
+sed -i 's,zap,ftdm,g' $1
+sed -i 's,ZAP,FTDM,g' $1
+sed -i 's,zio,fio,g' $1
+sed -i 's,ZIO,FIO,g' $1
+
Property changes on: freeswitch/trunk/libs/freetdm/ozreplace.sh
___________________________________________________________________
Name: svn:executable
   + *

Added: freeswitch/trunk/libs/freetdm/patches/oz.diff (0 => 17141)


--- freeswitch/trunk/libs/freetdm/patches/oz.diff	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/patches/oz.diff	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,134 @@
+Index: src/ozmod/ozmod_wanpipe/ozmod_wanpipe.c
+===================================================================
+--- src/ozmod/ozmod_wanpipe/ozmod_wanpipe.c	(revision 745)
++++ src/ozmod/ozmod_wanpipe/ozmod_wanpipe.c	(working copy)
+@@ -98,19 +98,21 @@
+  * so we can have one analong handler thread that will deal with all the idle analog channels for events
+  * the alternative would be for the driver to provide one socket for all of the oob events for all analog channels
+  */
+-static __inline__ int tdmv_api_wait_socket(sng_fd_t fd, int timeout, int *flags)
++static __inline__ int tdmv_api_wait_socket(zap_channel_t *zchan, int timeout, int *flags)
+ {
+ 	
+ #ifdef LIBSANGOMA_VERSION
+ 	int err;
+-	sangoma_wait_obj_t sangoma_wait_obj;
++	sangoma_wait_obj_t *sangoma_wait_obj = zchan->mod_data;
+ 
+- 	sangoma_init_wait_obj(&sangoma_wait_obj, fd, 1, 1, *flags, SANGOMA_WAIT_OBJ);
++	sangoma_init_wait_obj(sangoma_wait_obj, zchan->sockfd, 1, 1, 0, SANGOMA_WAIT_OBJ);
+ 
+-	err=sangoma_socket_waitfor_many(&sangoma_wait_obj,1 , timeout);
++	err = sangoma_socket_waitfor_many(&sangoma_wait_obj, 1, timeout);
++
+ 	if (err > 0) {
+-		*flags=sangoma_wait_obj.flags_out;
++		*flags = sangoma_wait_obj.flags_out;
+ 	}
++
+ 	return err;
+ 
+ #else
+@@ -118,7 +120,7 @@
+     int res;
+ 
+     memset(&pfds[0], 0, sizeof(pfds[0]));
+-    pfds[0].fd = fd;
++    pfds[0].fd = zchan->sockfd;
+     pfds[0].events = *flags;
+     res = poll(pfds, 1, timeout);
+ 	*flags = 0;
+@@ -200,6 +202,15 @@
+ 		
+ 		if (sockfd != WP_INVALID_SOCKET && zap_span_add_channel(span, sockfd, type, &chan) == ZAP_SUCCESS) {
+ 			wanpipe_tdm_api_t tdm_api;
++#ifdef LIBSANGOMA_VERSION
++			sangoma_wait_obj_t *sangoma_wait_obj;
++
++			sangoma_wait_obj = malloc(sizeof(*sangoma_wait_obj));
++			memset(sangoma_wait_obj, 0, sizeof(*sangoma_wait_obj));
++			sangoma_init_wait_obj(sangoma_wait_obj, sockfd, 1, 1, 0, SANGOMA_WAIT_OBJ);
++			chan->mod_data = sangoma_wait_obj;
++#endif
++
+ 			memset(&tdm_api,0,sizeof(tdm_api));
+ 			
+ 			chan->physical_span_id = spanno;
+@@ -211,7 +222,7 @@
+ 				
+ 				dtmf = "software";
+ 
+-				/* FIXME: Handle Error Conditino Check for return code */
++				/* FIXME: Handle Error Condition Check for return code */
+ 				err= sangoma_tdm_get_hw_coding(chan->sockfd, &tdm_api);
+ 
+ 				if (tdm_api.wp_tdm_cmd.hw_tdm_coding) {
+@@ -606,7 +617,7 @@
+ 		inflags |= POLLPRI;
+ 	}
+ 
+-	result = tdmv_api_wait_socket(zchan->sockfd, to, &inflags);
++	result = tdmv_api_wait_socket(zchan, to, &inflags);
+ 
+ 	*flags = ZAP_NO_FLAGS;
+ 
+@@ -643,26 +654,30 @@
+ ZIO_SPAN_POLL_EVENT_FUNCTION(wanpipe_poll_event)
+ {
+ #ifdef LIBSANGOMA_VERSION
+-	sangoma_wait_obj_t pfds[ZAP_MAX_CHANNELS_SPAN];
++	sangoma_wait_obj_t *pfds[ZAP_MAX_CHANNELS_SPAN] = { 0 };
+ #else
+ 	struct pollfd pfds[ZAP_MAX_CHANNELS_SPAN];
+ #endif
+ 
+ 	uint32_t i, j = 0, k = 0, l = 0;
+-	int objects=0;
+ 	int r;
+ 	
+ 	for(i = 1; i <= span->chan_count; i++) {
+ 		zap_channel_t *zchan = span->channels[i];
+ 
++
+ #ifdef LIBSANGOMA_VERSION
+- 		sangoma_init_wait_obj(&pfds[j], zchan->sockfd , 1, 1, POLLPRI, SANGOMA_WAIT_OBJ);
++		if (!zchan->mod_data) {
++			continue;
++		}
++		pfds[j] = zchan->mod_data;
++
+ #else
+ 		memset(&pfds[j], 0, sizeof(pfds[j]));
+ 		pfds[j].fd = span->channels[i]->sockfd;
+ 		pfds[j].events = POLLPRI;
+ #endif
+-		objects++;
++
+ 		/* The driver probably should be able to do this wink/flash/ringing by itself this is sort of a hack to make it work! */
+ 
+ 		if (zap_test_flag(zchan, ZAP_CHANNEL_WINK) || zap_test_flag(zchan, ZAP_CHANNEL_FLASH)) {
+@@ -703,7 +718,7 @@
+ 		ms = l;
+ 	}
+ #ifdef LIBSANGOMA_VERSION
+-	r = sangoma_socket_waitfor_many(pfds,objects,ms);
++	r = sangoma_socket_waitfor_many(pfds, j, ms);
+ #else
+ 	r = poll(pfds, j, ms);
+ #endif
+@@ -935,6 +950,15 @@
+  */
+ static ZIO_CHANNEL_DESTROY_FUNCTION(wanpipe_channel_destroy)
+ {
++	sangoma_wait_obj_t *sangoma_wait_obj;
++
++	if (zchan->mod_data) {
++		sangoma_wait_obj = zchan->mod_data;
++		zchan->mod_data = NULL;
++		sangoma_release_wait_obj(sangoma_wait_obj);
++		free(sangoma_wait_obj);
++	}
++
+ 	if (zchan->sockfd > -1) {
+ 		close(zchan->sockfd);
+ 		zchan->sockfd = WP_INVALID_SOCKET;

Added: freeswitch/trunk/libs/freetdm/src/detect_dtmf.c (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/detect_dtmf.c	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/detect_dtmf.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,33 @@
+//#include "freetdm.h"
+#include "libteletone_detect.h"
+
+int main(int argc, char *argv[])
+{
+	int fd, b;
+	short sln[512] = {0};
+	teletone_dtmf_detect_state_t dtmf_detect = {0};
+	char digit_str[128] = "";
+
+	if (argc < 2) {
+		fprintf(stderr, "Arg Error!\n");
+		exit(-1);
+	}
+
+	teletone_dtmf_detect_init (&dtmf_detect, 8000);
+
+	if ((fd = open(argv[1], O_RDONLY)) < 0) {
+		fprintf(stderr, "File Error! [%s]\n", strerror(errno));
+		exit(-1);
+	}
+
+	while((b = read(fd, sln, 320)) > 0) {
+		teletone_dtmf_detect(&dtmf_detect, sln, b / 2);
+		teletone_dtmf_get(&dtmf_detect, digit_str, sizeof(digit_str));
+		if (*digit_str) {
+			printf("digit: %s\n", digit_str);
+		}
+	}
+	close(fd);
+	return 0;
+}
+

Added: freeswitch/trunk/libs/freetdm/src/detect_tones.c (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/detect_tones.c	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/detect_tones.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,32 @@
+//#include "freetdm.h"
+#include "libteletone_detect.h"
+
+int main(int argc, char *argv[])
+{
+	teletone_multi_tone_t mt = {0};
+	teletone_tone_map_t map = {{0}};
+
+	int fd, b;
+	short sln[512] = {0};
+
+	if (argc < 2) {
+		fprintf(stderr, "Arg Error!\n");
+		exit(-1);
+	}
+
+	map.freqs[0] = atof("350");
+	map.freqs[1] = atof("440");
+	teletone_multi_tone_init(&mt, &map);
+
+	if ((fd = open(argv[1], O_RDONLY)) < 0) {
+		fprintf(stderr, "File Error! [%s]\n", strerror(errno));
+		exit(-1);
+	}
+
+	while((b = read(fd, sln, 320)) > 0) {
+		printf("TEST %d %d\n", b, teletone_multi_tone_detect(&mt, sln, b / 2));
+	}
+	close(fd);
+	return 0;
+}
+

Added: freeswitch/trunk/libs/freetdm/src/fsk.c (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/fsk.c	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/fsk.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,351 @@
+
+/*
+ *	bell202.c
+ *
+ *	Copyright (c) 2005 Robert Krten.  All Rights Reserved.
+ *
+ *	Redistribution and use in source and binary forms, with or without
+ *	modification, are permitted provided that the following conditions
+ *	are met:
+ *
+ *	1. Redistributions of source code must retain the above copyright
+ *	   notice, this list of conditions and the following disclaimer.
+ *	2. Redistributions in binary form must reproduce the above copyright
+ *	   notice, this list of conditions and the following disclaimer in the
+ *	   documentation and/or other materials provided with the distribution.
+ *
+ *	THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
+ *	ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ *	IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ *	ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE
+ *	FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ *	DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ *	OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ *	HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ *	LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ *	OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ *	SUCH DAMAGE.
+ *
+ *	This module contains a Bell-202 1200-baud FSK decoder, suitable for
+ *	use in a library.  The general style of the library calls is modeled
+ *	after the POSIX pthread_*() functions.
+ *
+ *	2005 03 20	R. Krten		created
+*/
+#include <freetdm.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <math.h>
+
+#include "fsk.h"
+#include "uart.h"
+
+#ifndef M_PI
+#define M_PI        3.14159265358979323846
+#endif
+
+fsk_modem_definition_t fsk_modem_definitions[] =
+{
+    { /* FSK_V23_FORWARD_MODE1	*/	1700,	1300,	600		},
+    { /* FSK_V23_FORWARD_MODE2	*/	2100,	1300,	1200	},
+    { /* FSK_V23_BACKWARD		*/	450,	390,	75		},
+    { /* FSK_BELL202			*/	2200,	1200,	1200	},
+};
+
+/*
+ *	dsp_fsk_attr_init
+ *
+ *	Initializes the attributes structure; this must be done before the
+ *	attributes structure is used.
+*/
+
+void dsp_fsk_attr_init (dsp_fsk_attr_t *attr)
+{
+	memset(attr, 0, sizeof(*attr));
+}
+
+/*
+ *	dsp_fsk_attr_get_bithandler
+ *	dsp_fsk_attr_set_bithandler
+ *	dsp_fsk_attr_get_bytehandler
+ *	dsp_fsk_attr_set_bytehandler
+ *	dsp_fsk_attr_getsamplerate
+ *	dsp_fsk_attr_setsamplerate
+ *
+ *	These functions get and set their respective elements from the
+ *	attributes structure.  If an error code is returned, it is just
+ *	zero == ok, -1 == fail.
+*/
+
+bithandler_func_t dsp_fsk_attr_get_bithandler(dsp_fsk_attr_t *attr, void **bithandler_arg)
+{
+	*bithandler_arg = attr->bithandler_arg;
+	return attr->bithandler;
+}
+
+void dsp_fsk_attr_set_bithandler(dsp_fsk_attr_t *attr, bithandler_func_t bithandler, void *bithandler_arg)
+{
+	attr->bithandler = bithandler;
+	attr->bithandler_arg = bithandler_arg;
+}
+
+bytehandler_func_t dsp_fsk_attr_get_bytehandler(dsp_fsk_attr_t *attr, void **bytehandler_arg)
+{
+	*bytehandler_arg = attr->bytehandler_arg;
+	return attr->bytehandler;
+}
+
+void dsp_fsk_attr_set_bytehandler(dsp_fsk_attr_t *attr, bytehandler_func_t bytehandler, void *bytehandler_arg)
+{
+	attr->bytehandler = bytehandler;
+	attr->bytehandler_arg = bytehandler_arg;
+}
+
+int dsp_fsk_attr_get_samplerate (dsp_fsk_attr_t *attr)
+{
+	return attr->sample_rate;
+}
+
+int dsp_fsk_attr_set_samplerate (dsp_fsk_attr_t *attr, int samplerate)
+{
+	if (samplerate <= 0) {
+		return -1;
+	}
+	attr->sample_rate = samplerate;
+	return 0;
+}
+
+/*
+ *	dsp_fsk_create
+ *
+ *	Creates a handle for subsequent use.  The handle is created to contain
+ *	a context data structure for use by the sample handler function.  The
+ *	function expects an initialized attributes structure, and returns the
+ *	handle or a NULL if there were errors.
+ *
+ *	Once created, the handle can be used until it is destroyed.
+*/
+
+dsp_fsk_handle_t *dsp_fsk_create(dsp_fsk_attr_t *attr)
+{
+	int						i;
+	double					phi_mark, phi_space;
+	dsp_fsk_handle_t	*handle;
+
+	handle = ftdm_malloc(sizeof(*handle));
+	if (!handle) {
+		return NULL;
+	}
+
+	memset(handle, 0, sizeof(*handle));
+
+	/* fill the attributes member */
+	memcpy(&handle->attr, attr, sizeof(*attr));
+
+	/* see if we can do downsampling.  We only really need 6 samples to "match" */
+	if (attr->sample_rate / fsk_modem_definitions[FSK_BELL202].freq_mark > 6) {
+		handle->downsampling_count = attr->sample_rate / fsk_modem_definitions[FSK_BELL202].freq_mark / 6;
+	} else {
+		handle->downsampling_count = 1;
+	}
+	handle->current_downsample = 1;
+
+	/* calculate the correlate size (number of samples required for slowest wave) */
+	handle->corrsize = attr->sample_rate / handle->downsampling_count / fsk_modem_definitions[FSK_BELL202].freq_mark;
+
+	/* allocate the correlation sin/cos arrays and initialize */
+	for (i = 0; i < 4; i++) {
+		handle->correlates[i] = ftdm_malloc(sizeof(double) * handle->corrsize);
+		if (handle->correlates[i] == NULL) {
+			/* some failed, back out memory allocations */
+			dsp_fsk_destroy(&handle);
+			return NULL;
+		}
+	}
+
+	/* now initialize them */
+	phi_mark = 2. * M_PI / ((double) attr->sample_rate / (double) handle->downsampling_count / (double) fsk_modem_definitions[FSK_BELL202].freq_mark);
+	phi_space = 2. * M_PI / ((double) attr->sample_rate / (double) handle->downsampling_count / (double) fsk_modem_definitions[FSK_BELL202].freq_space);
+
+	for (i = 0; i < handle->corrsize; i++) {
+		handle->correlates[0][i] = sin(phi_mark * (double) i);
+		handle->correlates[1][i] = cos(phi_mark * (double) i);
+		handle->correlates[2][i] = sin(phi_space * (double) i);
+		handle->correlates[3][i] = cos(phi_space * (double) i);
+	}
+
+	/* initialize the ring buffer */
+	handle->buffer = ftdm_malloc(sizeof(double) * handle->corrsize);
+	if (!handle->buffer) {				/* failed; back out memory allocations */
+		dsp_fsk_destroy(&handle);
+		return NULL;
+	}
+	memset(handle->buffer, 0, sizeof(double) * handle->corrsize);
+	handle->ringstart = 0;
+
+	/* initalize intra-cell position */
+	handle->cellpos = 0;
+	handle->celladj = fsk_modem_definitions[FSK_BELL202].baud_rate / (double) attr->sample_rate * (double) handle->downsampling_count;
+
+	/* if they have provided a byte handler, add a UART to the processing chain */
+	if (handle->attr.bytehandler) {
+		dsp_uart_attr_t		uart_attr;
+		dsp_uart_handle_t	*uart_handle;
+
+		dsp_uart_attr_init(&uart_attr);
+		dsp_uart_attr_set_bytehandler(&uart_attr, handle->attr.bytehandler, handle->attr.bytehandler_arg);
+		uart_handle = dsp_uart_create(&uart_attr);
+		if (uart_handle == NULL) {
+			dsp_fsk_destroy(&handle);
+			return NULL;
+		}
+		handle->attr.bithandler = dsp_uart_bit_handler;
+		handle->attr.bithandler_arg = uart_handle;
+	}
+
+	return handle;
+}
+
+/*
+ *	dsp_fsk_destroy
+ *
+ *	Destroys a handle, releasing any associated memory.  Sets handle pointer to NULL 
+ *	so A destroyed handle can not be used for anything after the destroy.
+*/
+
+void dsp_fsk_destroy(dsp_fsk_handle_t **handle)
+{
+	int		i;
+
+	/* if empty handle, just return */
+	if (*handle == NULL) {
+		return;
+	}
+
+	for (i = 0; i < 4; i++) {
+		if ((*handle)->correlates[i] != NULL) {
+			ftdm_safe_free((*handle)->correlates[i]);
+			(*handle)->correlates[i] = NULL;
+		}
+	}
+
+	if ((*handle)->buffer != NULL) {
+		ftdm_safe_free((*handle)->buffer);
+		(*handle)->buffer = NULL;
+	}
+
+	if ((*handle)->attr.bytehandler) {
+		dsp_uart_handle_t** dhandle = (void *)(&(*handle)->attr.bithandler_arg);
+		dsp_uart_destroy(dhandle);
+	}
+
+	ftdm_safe_free(*handle);
+	*handle = NULL;
+}
+
+/*
+ *	dsp_fsk_sample
+ *
+ *	This is the main processing entry point.  The function accepts a normalized
+ *	sample (i.e., one whose range is between -1 and +1).  The function performs
+ *	the Bell-202 FSK modem decode processing, and, if it detects a valid bit,
+ *	will call the bithandler associated with the attributes structure.
+ *
+ *	For the Bell-202 standard, a logical zero (space) is 2200 Hz, and a logical
+ *	one (mark) is 1200 Hz.
+*/
+
+void
+dsp_fsk_sample (dsp_fsk_handle_t *handle, double normalized_sample)
+{
+	double	val;
+	double	factors[4];
+	int		i, j;
+
+	/* if we can avoid processing samples, do so */
+	if (handle->downsampling_count != 1) {
+		if (handle->current_downsample < handle->downsampling_count) {
+			handle->current_downsample++;
+			return;												/* throw this sample out */
+		}
+		handle->current_downsample = 1;
+	}
+
+	/* store sample in buffer */
+	handle->buffer[handle->ringstart++] = normalized_sample;
+	if (handle->ringstart >= handle->corrsize) {
+		handle->ringstart = 0;
+	}
+
+	/* do the correlation calculation */
+	factors[0] = factors[1] = factors[2] = factors[3] = 0;	/* clear out intermediate sums */
+	j = handle->ringstart;
+	for (i = 0; i < handle->corrsize; i++) {
+		if (j >= handle->corrsize) {
+			j = 0;
+		}
+		val = handle->buffer[j];
+		factors[0] += handle->correlates[0][i] * val;
+		factors[1] += handle->correlates[1][i] * val;
+		factors[2] += handle->correlates[2][i] * val;
+		factors[3] += handle->correlates[3][i] * val;
+		j++;
+	}
+
+	/* store the bit (bit value is comparison of the two sets of correlate factors) */
+	handle->previous_bit = handle->current_bit;
+	handle->current_bit = (factors[0] * factors[0] + factors[1] * factors[1] > factors[2] * factors[2] + factors[3] * factors[3]);
+
+	/* if there's a transition, we can synchronize the cell position */
+	if (handle->previous_bit != handle->current_bit) {
+		handle->cellpos = 0.5;								/* adjust cell position to be in the middle of the cell */
+	}
+	handle->cellpos += handle->celladj;						/* walk the cell along */
+
+	if (handle->cellpos > 1.0) {
+		handle->cellpos -= 1.0;
+		
+		switch (handle->state) {
+		case FSK_STATE_DATA:
+			{		
+				
+				(*handle->attr.bithandler) (handle->attr.bithandler_arg, handle->current_bit);
+			}
+			break;
+		case FSK_STATE_CHANSEIZE:
+			{
+
+				if (handle->last_bit != handle->current_bit) {
+					handle->conscutive_state_bits++;
+				} else {
+					handle->conscutive_state_bits = 0;
+				}
+
+				if (handle->conscutive_state_bits > 15) {
+					handle->state = FSK_STATE_CARRIERSIG;
+					handle->conscutive_state_bits = 0;
+				}
+			}
+			break;
+		case FSK_STATE_CARRIERSIG:
+			{
+				if (handle->current_bit) {
+					handle->conscutive_state_bits++;
+				} else {
+					handle->conscutive_state_bits = 0;
+				}
+
+				if (handle->conscutive_state_bits > 15) {
+					handle->state = FSK_STATE_DATA;
+					handle->conscutive_state_bits = 0;
+				}
+			}
+			break;
+		}
+
+		handle->last_bit = handle->current_bit;
+	}
+}
+

Added: freeswitch/trunk/libs/freetdm/src/ftdm_buffer.c (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/ftdm_buffer.c	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/ftdm_buffer.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,302 @@
+/*
+ * Copyright (c) 2007, Anthony Minessale II
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "freetdm.h"
+#include "ftdm_buffer.h"
+
+static unsigned buffer_id = 0;
+
+struct ftdm_buffer {
+	unsigned char *data;
+	unsigned char *head;
+	ftdm_size_t used;
+	ftdm_size_t actually_used;
+	ftdm_size_t datalen;
+	ftdm_size_t max_len;
+	ftdm_size_t blocksize;
+	unsigned id;
+	int loops;
+};
+
+
+FT_DECLARE(ftdm_status_t) ftdm_buffer_create(ftdm_buffer_t **buffer, ftdm_size_t blocksize, ftdm_size_t start_len, ftdm_size_t max_len)
+{
+	ftdm_buffer_t *new_buffer;
+
+	new_buffer = ftdm_malloc(sizeof(*new_buffer));
+	if (new_buffer) {
+		memset(new_buffer, 0, sizeof(*new_buffer));
+
+		if (start_len) {
+			new_buffer->data = ftdm_malloc(start_len);
+			if (!new_buffer->data) {
+				ftdm_safe_free(new_buffer);
+				return FTDM_MEMERR;
+			}
+			memset(new_buffer->data, 0, start_len);
+		}
+
+		new_buffer->max_len = max_len;
+		new_buffer->datalen = start_len;
+		new_buffer->id = buffer_id++;
+		new_buffer->blocksize = blocksize;
+		new_buffer->head = new_buffer->data;
+
+		*buffer = new_buffer;
+		return FTDM_SUCCESS;
+	}
+
+	return FTDM_MEMERR;
+}
+
+FT_DECLARE(ftdm_size_t) ftdm_buffer_len(ftdm_buffer_t *buffer)
+{
+
+	assert(buffer != NULL);
+
+	return buffer->datalen;
+
+}
+
+
+FT_DECLARE(ftdm_size_t) ftdm_buffer_freespace(ftdm_buffer_t *buffer)
+{
+	assert(buffer != NULL);
+
+
+	if (buffer->max_len) {
+		return (ftdm_size_t) (buffer->max_len - buffer->used);
+	}
+	return 1000000;
+
+}
+
+FT_DECLARE(ftdm_size_t) ftdm_buffer_inuse(ftdm_buffer_t *buffer)
+{
+	assert(buffer != NULL);
+
+	return buffer->used;
+}
+
+FT_DECLARE(ftdm_size_t) ftdm_buffer_seek(ftdm_buffer_t *buffer, ftdm_size_t datalen)
+{
+	ftdm_size_t reading = 0;
+
+	assert(buffer != NULL);
+
+	if (buffer->used < 1) {
+		buffer->used = 0;
+		return 0;
+	} else if (buffer->used >= datalen) {
+		reading = datalen;
+	} else {
+		reading = buffer->used;
+	}
+
+	buffer->used = buffer->actually_used - reading;
+	buffer->head = buffer->data + reading;
+
+	return reading;
+}
+
+FT_DECLARE(ftdm_size_t) ftdm_buffer_toss(ftdm_buffer_t *buffer, ftdm_size_t datalen)
+{
+	ftdm_size_t reading = 0;
+
+	assert(buffer != NULL);
+
+	if (buffer->used < 1) {
+		buffer->used = 0;
+		return 0;
+	} else if (buffer->used >= datalen) {
+		reading = datalen;
+	} else {
+		reading = buffer->used;
+	}
+
+	buffer->used -= reading;
+	buffer->head += reading;
+
+	return buffer->used;
+}
+
+FT_DECLARE(void) ftdm_buffer_set_loops(ftdm_buffer_t *buffer, int loops)
+{
+	buffer->loops = loops;
+}
+
+FT_DECLARE(ftdm_size_t) ftdm_buffer_read_loop(ftdm_buffer_t *buffer, void *data, ftdm_size_t datalen)
+{
+	ftdm_size_t len;
+	if ((len = ftdm_buffer_read(buffer, data, datalen)) < datalen) {
+		if (buffer->loops == 0) {
+			return len;
+		}
+		buffer->head = buffer->data;
+		buffer->used = buffer->actually_used;
+		len = ftdm_buffer_read(buffer, (char*)data + len, datalen - len);
+		buffer->loops--;
+	}
+	return len;
+}
+
+FT_DECLARE(ftdm_size_t) ftdm_buffer_read(ftdm_buffer_t *buffer, void *data, ftdm_size_t datalen)
+{
+	ftdm_size_t reading = 0;
+
+	assert(buffer != NULL);
+	assert(data != NULL);
+
+
+	if (buffer->used < 1) {
+		buffer->used = 0;
+		return 0;
+	} else if (buffer->used >= datalen) {
+		reading = datalen;
+	} else {
+		reading = buffer->used;
+	}
+
+	memcpy(data, buffer->head, reading);
+	buffer->used -= reading;
+	buffer->head += reading;
+
+	/* if (buffer->id == 4) printf("%u o %d = %d\n", buffer->id, (unsigned)reading, (unsigned)buffer->used); */
+	return reading;
+}
+
+FT_DECLARE(ftdm_size_t) ftdm_buffer_write(ftdm_buffer_t *buffer, const void *data, ftdm_size_t datalen)
+{
+	ftdm_size_t freespace, actual_freespace;
+
+	assert(buffer != NULL);
+	assert(data != NULL);
+	assert(buffer->data != NULL);
+
+	if (!datalen) {
+		return buffer->used;
+	}
+
+	actual_freespace = buffer->datalen - buffer->actually_used;
+	if (actual_freespace < datalen && (!buffer->max_len || (buffer->used + datalen <= buffer->max_len))) {
+		memmove(buffer->data, buffer->head, buffer->used);
+		buffer->head = buffer->data;
+		buffer->actually_used = buffer->used;
+	}
+
+	freespace = buffer->datalen - buffer->used;
+
+	/*
+	  if (buffer->data != buffer->head) {
+	  memmove(buffer->data, buffer->head, buffer->used);
+	  buffer->head = buffer->data;
+	  }
+	*/
+	
+	if (freespace < datalen) {
+		ftdm_size_t new_size, new_block_size;
+		void *data;
+		
+		new_size = buffer->datalen + datalen;
+		new_block_size = buffer->datalen + buffer->blocksize;
+
+		if (new_block_size > new_size) {
+			new_size = new_block_size;
+		}
+		buffer->head = buffer->data;
+		data = realloc(buffer->data, new_size);
+		if (!data) {
+			return 0;
+		}
+		buffer->data = data;
+		buffer->head = buffer->data;
+		buffer->datalen = new_size;
+	}
+	
+
+	freespace = buffer->datalen - buffer->used;
+
+	if (freespace < datalen) {
+		return 0;
+	} else {
+		memcpy(buffer->head + buffer->used, data, datalen);
+		buffer->used += datalen;
+		buffer->actually_used += datalen;
+	}
+	/* if (buffer->id == 4) printf("%u i %d = %d\n", buffer->id, (unsigned)datalen, (unsigned)buffer->used); */
+
+	return buffer->used;
+}
+
+FT_DECLARE(void) ftdm_buffer_zero(ftdm_buffer_t *buffer)
+{
+	assert(buffer != NULL);
+	assert(buffer->data != NULL);
+
+	buffer->used = 0;
+	buffer->actually_used = 0;
+	buffer->head = buffer->data;
+}
+
+FT_DECLARE(ftdm_size_t) ftdm_buffer_zwrite(ftdm_buffer_t *buffer, const void *data, ftdm_size_t datalen)
+{
+	ftdm_size_t w;
+	
+	if (!(w = ftdm_buffer_write(buffer, data, datalen))) {
+		ftdm_buffer_zero(buffer);
+		return ftdm_buffer_write(buffer, data, datalen);
+	}
+
+	return w;
+}
+
+FT_DECLARE(void) ftdm_buffer_destroy(ftdm_buffer_t **buffer)
+{
+	if (*buffer) {
+		ftdm_safe_free((*buffer)->data);
+		ftdm_safe_free(*buffer);
+	}
+
+	*buffer = NULL;
+}
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */

Added: freeswitch/trunk/libs/freetdm/src/ftdm_callerid.c (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/ftdm_callerid.c	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/ftdm_callerid.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,307 @@
+#include "freetdm.h"
+#include "fsk.h"
+#include "uart.h"
+
+
+
+static void fsk_byte_handler (void *x, int data)
+{
+	ftdm_fsk_data_state_t *state = (ftdm_fsk_data_state_t *) x;
+	uint8_t byte = (uint8_t)data;
+
+ top:
+
+	if (state->init == 3) {
+		return;
+	}
+
+	if (state->dlen) {
+		goto add_byte;
+	}
+	
+	if (state->bpos == 1) {
+		state->blen = byte;
+
+		if ((uint32_t)(state->dlen = state->bpos + byte + 2) > state->bufsize) {
+			state->dlen = state->bufsize;
+		}
+		goto top;
+	}
+
+ add_byte:
+
+	if (state->bpos <= state->dlen) {
+		state->buf[state->bpos++] = byte;
+	} else {
+		state->init = 3;
+	}
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_fsk_data_init(ftdm_fsk_data_state_t *state, uint8_t *data, uint32_t datalen)
+{
+	memset(state, 0, sizeof(*state));
+	state->buf = data;
+	state->bufsize = datalen;
+	state->bpos = 2;
+
+	return FTDM_SUCCESS;
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_fsk_data_add_sdmf(ftdm_fsk_data_state_t *state, const char *date, char *number)
+{
+	size_t dlen = strlen(date);
+	size_t nlen = strlen(number);
+
+	state->buf[0] = FTDM_CID_TYPE_SDMF;
+	memcpy(&state->buf[state->bpos], date, dlen);
+	state->bpos += dlen;
+	memcpy(&state->buf[state->bpos], number, nlen);
+	state->bpos += nlen;
+
+	return FTDM_SUCCESS;
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_fsk_data_add_mdmf(ftdm_fsk_data_state_t *state, ftdm_mdmf_type_t type, const uint8_t *data, uint32_t datalen)
+{
+	state->buf[0] = FTDM_CID_TYPE_MDMF;
+	state->buf[state->bpos++] = type;
+	state->buf[state->bpos++] = (uint8_t)datalen;
+	memcpy(&state->buf[state->bpos], data, datalen);
+	state->bpos += datalen;
+	return FTDM_SUCCESS;
+}
+
+
+FT_DECLARE(ftdm_status_t) ftdm_fsk_data_add_checksum(ftdm_fsk_data_state_t *state)
+{
+	uint32_t i;
+	uint8_t check = 0;
+
+	state->buf[1] = (uint8_t)(state->bpos - 2);
+
+	for (i = 0; i < state->bpos; i++) {
+		check = check + state->buf[i];
+	}
+
+	state->checksum = state->buf[state->bpos] = (uint8_t)(256 - check);
+	state->bpos++;
+
+	state->dlen = state->bpos;
+	state->blen = state->buf[1];
+
+	return FTDM_SUCCESS;
+}
+
+
+FT_DECLARE(ftdm_status_t) ftdm_fsk_data_parse(ftdm_fsk_data_state_t *state, ftdm_size_t *type, char **data, ftdm_size_t *len)
+{
+
+	ftdm_size_t i;
+	int sum = 0;
+	
+ top:
+
+	if (state->checksum != 0 || state->ppos >= state->dlen - 1) {
+		return FTDM_FAIL;
+	}
+
+	if (!state->ppos) {
+		for(i = 0; i < state->bpos; i++) {
+			sum += state->buf[i];
+		}
+		state->checksum = sum % 256;
+		state->ppos = 2;		
+
+		if (state->buf[0] != FTDM_CID_TYPE_MDMF && state->buf[0] != FTDM_CID_TYPE_SDMF) {
+			state->checksum = -1;
+		}
+		goto top;
+	}
+
+	if (state->buf[0] == FTDM_CID_TYPE_SDMF) {
+		/* convert sdmf to mdmf so we don't need 2 parsers */
+		if (state->ppos == 2) {
+			*type = MDMF_DATETIME;
+			*len = 8;
+		} else {
+			if (state->buf[state->ppos] == 'P' || state->buf[state->ppos] == 'O') {
+				*type = MDMF_NO_NUM;
+				*len = 1;
+			} else {
+				*type = MDMF_PHONE_NUM;
+				*len = state->blen - 8;
+			}
+		}
+		*data = (char *)&state->buf[state->ppos];
+		state->ppos += *len;		
+		return FTDM_SUCCESS;
+	} else if (state->buf[0] == FTDM_CID_TYPE_MDMF) {
+		*type = state->buf[state->ppos++];
+		*len = state->buf[state->ppos++];
+		*data = (char *)&state->buf[state->ppos];
+		state->ppos += *len;
+		return FTDM_SUCCESS;
+	}
+
+	return FTDM_FAIL;
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_fsk_demod_feed(ftdm_fsk_data_state_t *state, int16_t *data, ftdm_size_t samples)
+{
+	uint32_t x;
+	int16_t *sp = data;
+
+	if (state->init == 3) {
+		return FTDM_FAIL;
+	}
+
+	for (x = 0; x < samples; x++) {
+		dsp_fsk_sample (state->fsk1200_handle, (double) *sp++ / 32767.0);
+		if (state->dlen && state->bpos >= state->dlen) {
+			state->init = 3;
+			return FTDM_FAIL;
+		}
+	}
+
+	return FTDM_SUCCESS;
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_fsk_demod_destroy(ftdm_fsk_data_state_t *state)
+{
+	dsp_fsk_destroy(&state->fsk1200_handle);
+	memset(state, 0, sizeof(*state));
+	return FTDM_SUCCESS;
+}
+
+FT_DECLARE(int) ftdm_fsk_demod_init(ftdm_fsk_data_state_t *state, int rate, uint8_t *buf, ftdm_size_t bufsize)
+{
+
+	dsp_fsk_attr_t fsk1200_attr;
+
+	if (state->fsk1200_handle) {
+		dsp_fsk_destroy(&state->fsk1200_handle);
+	}
+
+	memset(state, 0, sizeof(*state));
+	memset(buf, 0, bufsize);
+	state->buf = buf;
+	state->bufsize = bufsize;
+	
+	dsp_fsk_attr_init (&fsk1200_attr);
+	dsp_fsk_attr_set_samplerate (&fsk1200_attr, rate);
+	dsp_fsk_attr_set_bytehandler (&fsk1200_attr, fsk_byte_handler, state);
+	state->fsk1200_handle = dsp_fsk_create (&fsk1200_attr);
+
+	if (state->fsk1200_handle == NULL) {
+		return FTDM_FAIL;
+	}
+
+	return FTDM_SUCCESS;
+}
+
+FT_DECLARE(ftdm_size_t) ftdm_fsk_modulator_generate_bit(ftdm_fsk_modulator_t *fsk_trans, int8_t bit, int16_t *buf, ftdm_size_t buflen)
+{
+	ftdm_size_t i;
+		
+	for(i = 0 ; i < buflen; i++) {
+		fsk_trans->bit_accum += fsk_trans->bit_factor;
+		if (fsk_trans->bit_accum >= FTDM_FSK_MOD_FACTOR) {
+			fsk_trans->bit_accum -= (FTDM_FSK_MOD_FACTOR + fsk_trans->bit_factor);
+			break;
+		}
+
+		buf[i] = teletone_dds_state_modulate_sample(&fsk_trans->dds, bit);
+	}
+
+	return i;
+}
+
+
+FT_DECLARE(int32_t) ftdm_fsk_modulator_generate_carrier_bits(ftdm_fsk_modulator_t *fsk_trans, uint32_t bits)
+{
+	uint32_t i = 0;
+	ftdm_size_t r = 0;
+	int8_t bit = 1;
+
+	for (i = 0; i < bits; i++) {
+		if ((r = ftdm_fsk_modulator_generate_bit(fsk_trans, bit, fsk_trans->sample_buffer, sizeof(fsk_trans->sample_buffer) / 2))) {
+			if (fsk_trans->write_sample_callback(fsk_trans->sample_buffer, r, fsk_trans->user_data) != FTDM_SUCCESS) {
+				break;
+			}
+		} else {
+			break;
+		}
+	}
+
+	return i;
+}
+
+
+FT_DECLARE(void) ftdm_fsk_modulator_generate_chan_sieze(ftdm_fsk_modulator_t *fsk_trans)
+{
+	uint32_t i = 0;
+	ftdm_size_t r = 0;
+	int8_t bit = 0;
+	
+	for (i = 0; i < fsk_trans->chan_sieze_bits; i++) {
+		if ((r = ftdm_fsk_modulator_generate_bit(fsk_trans, bit, fsk_trans->sample_buffer, sizeof(fsk_trans->sample_buffer) / 2))) {
+			if (fsk_trans->write_sample_callback(fsk_trans->sample_buffer, r, fsk_trans->user_data) != FTDM_SUCCESS) {
+				break;
+			}
+		} else {
+			break;
+		}
+		bit = !bit;
+	}
+	
+
+}
+
+
+FT_DECLARE(void) ftdm_fsk_modulator_send_data(ftdm_fsk_modulator_t *fsk_trans)
+{
+	ftdm_size_t r = 0;
+	int8_t bit = 0;
+
+	while((bit = ftdm_bitstream_get_bit(&fsk_trans->bs)) > -1) {
+		if ((r = ftdm_fsk_modulator_generate_bit(fsk_trans, bit, fsk_trans->sample_buffer, sizeof(fsk_trans->sample_buffer) / 2))) {
+			if (fsk_trans->write_sample_callback(fsk_trans->sample_buffer, r, fsk_trans->user_data) != FTDM_SUCCESS) {
+				break;
+			}
+		} else {
+			break;
+		}
+	}
+}
+
+
+FT_DECLARE(ftdm_status_t) ftdm_fsk_modulator_init(ftdm_fsk_modulator_t *fsk_trans,
+									fsk_modem_types_t modem_type,
+									uint32_t sample_rate,
+									ftdm_fsk_data_state_t *fsk_data,
+									float db_level,
+									uint32_t carrier_bits_start,
+									uint32_t carrier_bits_stop,
+									uint32_t chan_sieze_bits,
+									ftdm_fsk_write_sample_t write_sample_callback,
+									void *user_data)
+{
+	memset(fsk_trans, 0, sizeof(*fsk_trans));
+	fsk_trans->modem_type = modem_type;
+	teletone_dds_state_set_tone(&fsk_trans->dds, fsk_modem_definitions[fsk_trans->modem_type].freq_space, sample_rate, 0);
+	teletone_dds_state_set_tone(&fsk_trans->dds, fsk_modem_definitions[fsk_trans->modem_type].freq_mark, sample_rate, 1);
+	fsk_trans->bit_factor = (uint32_t)((fsk_modem_definitions[fsk_trans->modem_type].baud_rate * FTDM_FSK_MOD_FACTOR) / (float)sample_rate);
+	fsk_trans->samples_per_bit = (uint32_t) (sample_rate / fsk_modem_definitions[fsk_trans->modem_type].baud_rate);
+	fsk_trans->est_bytes = (int32_t)(((fsk_data->dlen * 10) + carrier_bits_start + carrier_bits_stop + chan_sieze_bits) * ((fsk_trans->samples_per_bit + 1) * 2));
+	fsk_trans->bit_accum = 0;
+	fsk_trans->fsk_data = fsk_data;
+	teletone_dds_state_set_tx_level(&fsk_trans->dds, db_level);
+	ftdm_bitstream_init(&fsk_trans->bs, fsk_trans->fsk_data->buf, (uint32_t)fsk_trans->fsk_data->dlen, FTDM_ENDIAN_BIG, 1);
+	fsk_trans->carrier_bits_start = carrier_bits_start;
+	fsk_trans->carrier_bits_stop = carrier_bits_stop;
+	fsk_trans->chan_sieze_bits = chan_sieze_bits;
+	fsk_trans->write_sample_callback = write_sample_callback;
+	fsk_trans->user_data = user_data;
+	return FTDM_SUCCESS;
+}
+

Added: freeswitch/trunk/libs/freetdm/src/ftdm_config.c (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/ftdm_config.c	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/ftdm_config.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,251 @@
+/*
+ * Copyright (c) 2007, Anthony Minessale II
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "freetdm.h"
+#include "ftdm_config.h"
+
+int ftdm_config_open_file(ftdm_config_t *cfg, const char *file_path)
+{
+	FILE *f;
+	const char *path = NULL;
+	char path_buf[1024];
+
+	if (file_path[0] == '/') {
+		path = file_path;
+	} else {
+		snprintf(path_buf, sizeof(path_buf), "%s%s%s", FTDM_CONFIG_DIR, FTDM_PATH_SEPARATOR, file_path);
+		path = path_buf;
+	}
+
+	if (!path) {
+		return 0;
+	}
+
+	memset(cfg, 0, sizeof(*cfg));
+	cfg->lockto = -1;
+	ftdm_log(FTDM_LOG_DEBUG, "Configuration file is %s.\n", path);
+	f = fopen(path, "r");
+
+	if (!f) {
+		if (file_path[0] != '/') {
+			int last = -1;
+			char *var, *val;
+
+			snprintf(path_buf, sizeof(path_buf), "%s%sfreetdm.conf", FTDM_CONFIG_DIR, FTDM_PATH_SEPARATOR);
+			path = path_buf;
+
+			if ((f = fopen(path, "r")) == 0) {
+				return 0;
+			}
+
+			cfg->file = f;
+			ftdm_set_string(cfg->path, path);
+
+			while (ftdm_config_next_pair(cfg, &var, &val)) {
+				if ((cfg->sectno != last) && !strcmp(cfg->section, file_path)) {
+					cfg->lockto = cfg->sectno;
+					return 1;
+				}
+			}
+
+			ftdm_config_close_file(cfg);
+			memset(cfg, 0, sizeof(*cfg));
+			return 0;
+		}
+
+		return 0;
+	} else {
+		cfg->file = f;
+		ftdm_set_string(cfg->path, path);
+		return 1;
+	}
+}
+
+void ftdm_config_close_file(ftdm_config_t *cfg)
+{
+
+	if (cfg->file) {
+		fclose(cfg->file);
+	}
+
+	memset(cfg, 0, sizeof(*cfg));
+}
+
+
+
+int ftdm_config_next_pair(ftdm_config_t *cfg, char **var, char **val)
+{
+	int ret = 0;
+	char *p, *end;
+
+	*var = *val = NULL;
+
+	if (!cfg->path) {
+		return 0;
+	}
+
+	for (;;) {
+		cfg->lineno++;
+
+		if (!fgets(cfg->buf, sizeof(cfg->buf), cfg->file)) {
+			ret = 0;
+			break;
+		}
+		*var = cfg->buf;
+
+		if (**var == '[' && (end = strchr(*var, ']')) != 0) {
+			*end = '\0';
+			(*var)++;
+			if (**var == '+') {
+				(*var)++;
+				ftdm_copy_string(cfg->section, *var, sizeof(cfg->section));
+				cfg->sectno++;
+
+				if (cfg->lockto > -1 && cfg->sectno != cfg->lockto) {
+					break;
+				}
+				cfg->catno = 0;
+				cfg->lineno = 0;
+				*var = (char *) "";
+				*val = (char *) "";
+				return 1;
+			} else {
+				ftdm_copy_string(cfg->category, *var, sizeof(cfg->category));
+				cfg->catno++;
+			}
+			continue;
+		}
+
+
+
+		if (**var == '#' || **var == ';' || **var == '\n' || **var == '\r') {
+			continue;
+		}
+
+		if (!strncmp(*var, "__END__", 7)) {
+			break;
+		}
+
+
+		if ((end = strchr(*var, ';')) && *(end+1) == *end) {
+			*end = '\0';
+			end--;
+		} else if ((end = strchr(*var, '\n')) != 0) {
+			if (*(end - 1) == '\r') {
+				end--;
+			}
+			*end = '\0';
+		}
+
+		p = *var;
+		while ((*p == ' ' || *p == '\t') && p != end) {
+			*p = '\0';
+			p++;
+		}
+		*var = p;
+
+
+		if ((*val = strchr(*var, '=')) == 0) {
+			ret = -1;
+			/* log_printf(0, server.log, "Invalid syntax on %s: line %d\n", cfg->path, cfg->lineno); */
+			continue;
+		} else {
+			p = *val - 1;
+			*(*val) = '\0';
+			(*val)++;
+			if (*(*val) == '>') {
+				*(*val) = '\0';
+				(*val)++;
+			}
+
+			while ((*p == ' ' || *p == '\t') && p != *var) {
+				*p = '\0';
+				p--;
+			}
+
+			p = *val;
+			while ((*p == ' ' || *p == '\t') && p != end) {
+				*p = '\0';
+				p++;
+			}
+			*val = p;
+			ret = 1;
+			break;
+		}
+	}
+
+
+	return ret;
+
+}
+
+FT_DECLARE (int) ftdm_config_get_cas_bits(char *strvalue, unsigned char *outbits)
+{
+	char cas_bits[5];
+	unsigned char bit = 0x8;
+	int x = 0;
+	char *double_colon = strchr(strvalue, ':');
+	if (!double_colon) {
+		ftdm_log(FTDM_LOG_ERROR, "No CAS bits specified: %s, :xxxx definition expected, where x is 1 or 0\n", strvalue);
+		return -1;
+	}
+	double_colon++;
+	*outbits = 0;
+	cas_bits[4] = 0;
+	if (sscanf(double_colon, "%c%c%c%c", &cas_bits[0], &cas_bits[1], &cas_bits[2], &cas_bits[3]) != 4) {
+		ftdm_log(FTDM_LOG_ERROR, "Invalid CAS bits specified: '%s', :xxxx definition expected, where x is 1 or 0\n", double_colon);
+		return -1;
+	}
+	ftdm_log(FTDM_LOG_DEBUG, "CAS bits specification found: %s\n", cas_bits);
+	for (; cas_bits[x]; x++) {
+		if ('1' == cas_bits[x]) {
+			*outbits |= bit;
+		} else if ('0' != cas_bits[x]) {
+			ftdm_log(FTDM_LOG_ERROR, "Invalid CAS pattern specified: %s, just 0 or 1 allowed for each bit\n");
+			return -1;
+		}
+		bit >>= 1;
+	}
+	return 0;
+}
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */

Added: freeswitch/trunk/libs/freetdm/src/ftdm_dso.c (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/ftdm_dso.c	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/ftdm_dso.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,116 @@
+/* 
+ * Cross Platform dso/dll load abstraction
+ * Copyright(C) 2008 Michael Jerris
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so.
+ *
+ * This work is provided under this license on an "as is" basis, without warranty of any kind,
+ * either expressed or implied, including, without limitation, warranties that the covered code
+ * is free of defects, merchantable, fit for a particular purpose or non-infringing. The entire
+ * risk as to the quality and performance of the covered code is with you. Should any covered
+ * code prove defective in any respect, you (not the initial developer or any other contributor)
+ * assume the cost of any necessary servicing, repair or correction. This disclaimer of warranty
+ * constitutes an essential part of this license. No use of any covered code is authorized hereunder
+ * except under this disclaimer. 
+ *
+ */
+
+#include "freetdm.h"
+#include "ftdm_dso.h"
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef WIN32
+#include <windows.h>
+#include <stdio.h>
+
+
+FT_DECLARE(void) ftdm_dso_destroy(ftdm_dso_lib_t *lib) {
+	if (lib && *lib) {
+		FreeLibrary(*lib);
+		*lib = NULL;
+	}
+}
+
+FT_DECLARE(ftdm_dso_lib_t) ftdm_dso_open(const char *path, char **err) {
+    HINSTANCE lib;
+	
+	lib = LoadLibraryEx(path, NULL, 0);
+
+	if (!lib) {
+		LoadLibraryEx(path, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
+	}
+
+	if (!lib) {
+		DWORD error = GetLastError();
+		char tmp[80];
+		sprintf(tmp, "dll open error [%ul]\n", error);
+		*err = ftdm_strdup(tmp);
+	}
+
+	return lib;
+}
+
+FT_DECLARE(void*) ftdm_dso_func_sym(ftdm_dso_lib_t lib, const char *sym, char **err) {
+	FARPROC func = GetProcAddress(lib, sym);
+	if (!func) {
+		DWORD error = GetLastError();
+		char tmp[80];
+		sprintf(tmp, "dll sym error [%ul]\n", error);
+		*err = ftdm_strdup(tmp);
+	}
+	return (void *)(intptr_t)func; // this should really be addr - ftdm_dso_func_data
+}
+
+#else
+
+/*
+** {========================================================================
+** This is an implementation of loadlib based on the dlfcn interface.
+** The dlfcn interface is available in Linux, SunOS, Solaris, IRIX, FreeBSD,
+** NetBSD, AIX 4.2, HPUX 11, and  probably most other Unix flavors, at least
+** as an emulation layer on top of native functions.
+** =========================================================================
+*/
+
+
+#include <dlfcn.h>
+
+FT_DECLARE(void) ftdm_dso_destroy(ftdm_dso_lib_t *lib) {
+	if (lib && *lib) {
+		dlclose(*lib);
+		*lib = NULL;
+	}
+}
+
+FT_DECLARE(ftdm_dso_lib_t) ftdm_dso_open(const char *path, char **err) {
+	void *lib = dlopen(path, RTLD_NOW | RTLD_LOCAL);
+	if (lib == NULL) {
+		*err = ftdm_strdup(dlerror());
+	}
+	return lib;
+}
+
+FT_DECLARE(void*) ftdm_dso_func_sym(ftdm_dso_lib_t lib, const char *sym, char **err) {
+	void *func = dlsym(lib, sym);
+	if (!func) {
+		*err = ftdm_strdup(dlerror());
+	}
+	return func;
+}
+#endif
+
+/* }====================================================== */
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4
+ */

Added: freeswitch/trunk/libs/freetdm/src/ftdm_io.c (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/ftdm_io.c	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/ftdm_io.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,3927 @@
+/*
+ * Copyright (c) 2007, Anthony Minessale II
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Contributors: 
+ *
+ * Moises Silva <moy@sangoma.com>
+ * David Yat Sin <dyatsin@sangoma.com>
+ *
+ */
+
+#define _GNU_SOURCE
+#ifndef WIN32
+#endif
+#include "freetdm.h"
+#include <stdarg.h>
+#ifdef WIN32
+#include <io.h>
+#endif
+#ifdef FTDM_PIKA_SUPPORT
+#include "ftdm_pika.h"
+#endif
+
+#define SPAN_PENDING_CHANS_QUEUE_SIZE 1000
+
+static int time_is_init = 0;
+
+static void time_init(void)
+{
+#ifdef WIN32
+	timeBeginPeriod(1);
+#endif
+	time_is_init = 1;
+}
+
+static void time_end(void)
+{
+#ifdef WIN32
+	timeEndPeriod(1);
+#endif
+	time_is_init = 0;
+}
+
+FT_DECLARE(ftdm_time_t) ftdm_current_time_in_ms(void)
+{
+#ifdef WIN32
+	return timeGetTime();
+#else
+	struct timeval tv;
+	gettimeofday(&tv, NULL);
+	return ((tv.tv_sec * 1000) + (tv.tv_usec / 1000));
+#endif
+}
+
+static struct {
+	ftdm_hash_t *interface_hash;
+	ftdm_hash_t *module_hash;
+	ftdm_hash_t *span_hash;
+	ftdm_hash_t *group_hash;
+	ftdm_mutex_t *mutex;
+	ftdm_mutex_t *span_mutex;
+	ftdm_mutex_t *group_mutex;
+	uint32_t span_index;
+	uint32_t group_index;
+	uint32_t running;
+	ftdm_span_t *spans;
+	ftdm_group_t *groups;
+} globals;
+
+
+/* enum lookup funcs */
+FTDM_ENUM_NAMES(TONEMAP_NAMES, TONEMAP_STRINGS)
+FTDM_STR2ENUM(ftdm_str2ftdm_tonemap, ftdm_tonemap2str, ftdm_tonemap_t, TONEMAP_NAMES, FTDM_TONEMAP_INVALID)
+
+FTDM_ENUM_NAMES(OOB_NAMES, OOB_STRINGS)
+FTDM_STR2ENUM(ftdm_str2ftdm_oob_event, ftdm_oob_event2str, ftdm_oob_event_t, OOB_NAMES, FTDM_OOB_INVALID)
+
+FTDM_ENUM_NAMES(TRUNK_TYPE_NAMES, TRUNK_STRINGS)
+FTDM_STR2ENUM(ftdm_str2ftdm_trunk_type, ftdm_trunk_type2str, ftdm_trunk_type_t, TRUNK_TYPE_NAMES, FTDM_TRUNK_NONE)
+
+FTDM_ENUM_NAMES(START_TYPE_NAMES, START_TYPE_STRINGS)
+FTDM_STR2ENUM(ftdm_str2ftdm_analog_start_type, ftdm_analog_start_type2str, ftdm_analog_start_type_t, START_TYPE_NAMES, FTDM_ANALOG_START_NA)
+
+FTDM_ENUM_NAMES(SIGNAL_NAMES, SIGNAL_STRINGS)
+FTDM_STR2ENUM(ftdm_str2ftdm_signal_event, ftdm_signal_event2str, ftdm_signal_event_t, SIGNAL_NAMES, FTDM_SIGEVENT_INVALID)
+
+FTDM_ENUM_NAMES(CHANNEL_STATE_NAMES, CHANNEL_STATE_STRINGS)
+FTDM_STR2ENUM(ftdm_str2ftdm_channel_state, ftdm_channel_state2str, ftdm_channel_state_t, CHANNEL_STATE_NAMES, FTDM_CHANNEL_STATE_INVALID)
+
+FTDM_ENUM_NAMES(MDMF_TYPE_NAMES, MDMF_STRINGS)
+FTDM_STR2ENUM(ftdm_str2ftdm_mdmf_type, ftdm_mdmf_type2str, ftdm_mdmf_type_t, MDMF_TYPE_NAMES, MDMF_INVALID)
+
+FTDM_ENUM_NAMES(CHAN_TYPE_NAMES, CHAN_TYPE_STRINGS)
+FTDM_STR2ENUM(ftdm_str2ftdm_chan_type, ftdm_chan_type2str, ftdm_chan_type_t, CHAN_TYPE_NAMES, FTDM_CHAN_TYPE_COUNT)
+
+FTDM_ENUM_NAMES(SIGNALING_STATUS_NAMES, SIGSTATUS_STRINGS)
+FTDM_STR2ENUM(ftdm_str2ftdm_signaling_status, ftdm_signaling_status2str, ftdm_signaling_status_t, SIGNALING_STATUS_NAMES, FTDM_SIG_STATE_INVALID)
+
+static const char *cut_path(const char *in)
+{
+	const char *p, *ret = in;
+	char delims[] = "/\\";
+	char *i;
+
+	for (i = delims; *i; i++) {
+		p = in;
+		while ((p = strchr(p, *i)) != 0) {
+			ret = ++p;
+		}
+	}
+	return ret;
+}
+
+static void null_logger(const char *file, const char *func, int line, int level, const char *fmt, ...)
+{
+	if (file && func && line && level && fmt) {
+		return;
+	}
+	return;
+}
+
+
+static const char *LEVEL_NAMES[] = {
+	"EMERG",
+	"ALERT",
+	"CRIT",
+	"ERROR",
+	"WARNING",
+	"NOTICE",
+	"INFO",
+	"DEBUG",
+	NULL
+};
+
+static int ftdm_log_level = 7;
+
+static void default_logger(const char *file, const char *func, int line, int level, const char *fmt, ...)
+{
+	const char *fp;
+	char data[1024];
+	va_list ap;
+
+	if (level < 0 || level > 7) {
+		level = 7;
+	}
+	if (level > ftdm_log_level) {
+		return;
+	}
+	
+	fp = cut_path(file);
+
+	va_start(ap, fmt);
+
+	vsnprintf(data, sizeof(data), fmt, ap);
+
+
+	fprintf(stderr, "[%s] %s:%d %s() %s", LEVEL_NAMES[level], file, line, func, data);
+
+	va_end(ap);
+
+}
+
+static __inline__ void *ftdm_std_malloc(void *pool, ftdm_size_t size)
+{
+	void *ptr = malloc(size);
+	pool = NULL; /* fix warning */
+	ftdm_assert_return(ptr != NULL, NULL, "Out of memory");
+	return ptr;
+}
+
+static __inline__ void *ftdm_std_calloc(void *pool, ftdm_size_t elements, ftdm_size_t size)
+{
+	void *ptr = calloc(elements, size);
+	pool = NULL;
+	ftdm_assert_return(ptr != NULL, NULL, "Out of memory");
+	return ptr;
+}
+
+static __inline__ void ftdm_std_free(void *pool, void *ptr)
+{
+	pool = NULL;
+	ftdm_assert_return(ptr != NULL, , "Attempted to free null pointer");
+	free(ptr);
+}
+
+FT_DECLARE_DATA ftdm_memory_handler_t g_ftdm_mem_handler = 
+{
+	/*.pool =*/ NULL,
+	/*.malloc =*/ ftdm_std_malloc,
+	/*.calloc =*/ ftdm_std_calloc,
+	/*.free =*/ ftdm_std_free
+};
+
+FT_DECLARE_DATA ftdm_crash_policy_t g_ftdm_crash_policy = FTDM_CRASH_NEVER;
+
+static ftdm_status_t ftdm_set_caller_data(ftdm_span_t *span, ftdm_caller_data_t *caller_data)
+{
+	if (!caller_data) {
+		ftdm_log(FTDM_LOG_CRIT, "Error: trying to set caller data, but no caller_data!\n");
+		return FTDM_FAIL;
+	}
+
+	if (caller_data->cid_num.plan == FTDM_NPI_INVALID) {
+		caller_data->cid_num.plan = span->default_caller_data.cid_num.plan;
+	}
+
+	if (caller_data->cid_num.type == FTDM_TON_INVALID) {
+		caller_data->cid_num.type = span->default_caller_data.cid_num.type;
+	}
+
+	if (caller_data->ani.plan == FTDM_NPI_INVALID) {
+		caller_data->ani.plan = span->default_caller_data.ani.plan;
+	}
+
+	if (caller_data->ani.type == FTDM_TON_INVALID) {
+		caller_data->ani.type = span->default_caller_data.ani.type;
+	}
+
+	if (caller_data->rdnis.plan == FTDM_NPI_INVALID) {
+		caller_data->rdnis.plan = span->default_caller_data.rdnis.plan;
+	}
+
+	if (caller_data->rdnis.type == FTDM_NPI_INVALID) {
+		caller_data->rdnis.type = span->default_caller_data.rdnis.type;
+	}
+	return FTDM_SUCCESS;
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_channel_set_caller_data(ftdm_channel_t *ftdmchan, ftdm_caller_data_t *caller_data)
+{
+	ftdm_status_t err = FTDM_SUCCESS;
+	if (!ftdmchan) {
+		ftdm_log(FTDM_LOG_CRIT, "Error: trying to set caller data, but no ftdmchan!\n");
+		return FTDM_FAIL;
+	}
+	if ((err = ftdm_set_caller_data(ftdmchan->span, caller_data)) != FTDM_SUCCESS) {
+		return err; 
+	}
+	ftdmchan->caller_data = *caller_data;
+	return FTDM_SUCCESS;
+}
+
+FT_DECLARE_DATA ftdm_logger_t ftdm_log = null_logger;
+
+FT_DECLARE(void) ftdm_global_set_crash_policy(ftdm_crash_policy_t policy)
+{
+	g_ftdm_crash_policy |= policy;
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_global_set_memory_handler(ftdm_memory_handler_t *handler)
+{
+	if (!handler) {
+		return FTDM_FAIL;
+	}
+	if (!handler->malloc) {
+		return FTDM_FAIL;
+	}
+	if (!handler->calloc) {
+		return FTDM_FAIL;
+	}
+	if (!handler->free) {
+		return FTDM_FAIL;
+	}
+	memcpy(&g_ftdm_mem_handler, handler, sizeof(*handler));
+	return FTDM_SUCCESS;
+}
+
+FT_DECLARE(void) ftdm_global_set_logger(ftdm_logger_t logger)
+{
+	if (logger) {
+		ftdm_log = logger;
+	} else {
+		ftdm_log = null_logger;
+	}
+}
+
+FT_DECLARE(void) ftdm_global_set_default_logger(int level)
+{
+	if (level < 0 || level > 7) {
+		level = 7;
+	}
+
+	ftdm_log = default_logger;
+	ftdm_log_level = level;
+}
+
+FT_DECLARE_NONSTD(int) ftdm_hash_equalkeys(void *k1, void *k2)
+{
+    return strcmp((char *) k1, (char *) k2) ? 0 : 1;
+}
+
+FT_DECLARE_NONSTD(uint32_t) ftdm_hash_hashfromstring(void *ky)
+{
+	unsigned char *str = (unsigned char *) ky;
+	uint32_t hash = 0;
+    int c;
+	
+	while ((c = *str++)) {
+        hash = c + (hash << 6) + (hash << 16) - hash;
+	}
+
+    return hash;
+}
+
+static ftdm_status_t ftdm_channel_destroy(ftdm_channel_t *ftdmchan)
+{
+
+	if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_CONFIGURED)) {
+
+		while (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_INTHREAD)) {
+			ftdm_log(FTDM_LOG_INFO, "Waiting for thread to exit on channel %u:%u\n", ftdmchan->span_id, ftdmchan->chan_id);
+			ftdm_sleep(500);
+		}
+
+		ftdm_mutex_lock(ftdmchan->pre_buffer_mutex);
+		ftdm_buffer_destroy(&ftdmchan->pre_buffer);
+		ftdm_mutex_unlock(ftdmchan->pre_buffer_mutex);
+
+		ftdm_buffer_destroy(&ftdmchan->digit_buffer);
+		ftdm_buffer_destroy(&ftdmchan->gen_dtmf_buffer);
+		ftdm_buffer_destroy(&ftdmchan->dtmf_buffer);
+		ftdm_buffer_destroy(&ftdmchan->fsk_buffer);
+		ftdmchan->pre_buffer_size = 0;
+
+		hashtable_destroy(ftdmchan->variable_hash);
+
+		ftdm_safe_free(ftdmchan->dtmf_hangup_buf);
+
+		if (ftdmchan->tone_session.buffer) {
+			teletone_destroy_session(&ftdmchan->tone_session);
+			memset(&ftdmchan->tone_session, 0, sizeof(ftdmchan->tone_session));
+		}
+
+		
+		if (ftdmchan->span->fio->channel_destroy) {
+			ftdm_log(FTDM_LOG_INFO, "Closing channel %s:%u:%u fd:%d\n", ftdmchan->span->type, ftdmchan->span_id, ftdmchan->chan_id, ftdmchan->sockfd);
+			if (ftdmchan->span->fio->channel_destroy(ftdmchan) == FTDM_SUCCESS) {
+				ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_CONFIGURED);
+			} else {
+				ftdm_log(FTDM_LOG_ERROR, "Error Closing channel %u:%u fd:%d\n", ftdmchan->span_id, ftdmchan->chan_id, ftdmchan->sockfd);
+			}
+		}
+
+		ftdm_mutex_destroy(&ftdmchan->mutex);
+		ftdm_mutex_destroy(&ftdmchan->pre_buffer_mutex);
+	}
+	
+	return FTDM_SUCCESS;
+}
+
+static ftdm_status_t ftdm_span_destroy(ftdm_span_t *span)
+{
+	ftdm_status_t status = FTDM_SUCCESS;
+	unsigned j;
+
+	ftdm_mutex_lock(span->mutex);
+
+	/* stop the signaling */
+	if (span->stop) {
+		status = span->stop(span);
+	} 
+
+	/* destroy the channels */
+	ftdm_clear_flag(span, FTDM_SPAN_CONFIGURED);
+	for(j = 1; j <= span->chan_count && span->channels[j]; j++) {
+		ftdm_channel_t *cur_chan = span->channels[j];
+		if (cur_chan) {
+			if (ftdm_test_flag(cur_chan, FTDM_CHANNEL_CONFIGURED)) {
+				ftdm_channel_destroy(cur_chan);
+			}
+			ftdm_safe_free(cur_chan);
+			cur_chan = NULL;
+		}
+	}
+
+	/* destroy the I/O for the span */
+	if (span->fio && span->fio->span_destroy) {
+		ftdm_log(FTDM_LOG_INFO, "Destroying span %u type (%s)\n", span->span_id, span->type);
+		if (span->fio->span_destroy(span) != FTDM_SUCCESS) {
+			status = FTDM_FAIL;
+		}
+		ftdm_safe_free(span->type);
+		ftdm_safe_free(span->dtmf_hangup);
+	}
+
+	/* destroy final basic resources of the span data structure */
+	ftdm_queue_destroy(&span->pendingchans);
+	ftdm_mutex_unlock(span->mutex);
+	ftdm_mutex_destroy(&span->mutex);
+	ftdm_safe_free(span->signal_data);
+
+	return status;
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_channel_get_alarms(ftdm_channel_t *ftdmchan)
+{
+	ftdm_status_t status = FTDM_FAIL;
+
+	if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_CONFIGURED)) {
+		if (ftdmchan->span->fio->get_alarms) {
+			if ((status = ftdmchan->span->fio->get_alarms(ftdmchan)) == FTDM_SUCCESS) {
+				*ftdmchan->last_error = '\0';
+				if (ftdm_test_alarm_flag(ftdmchan, FTDM_ALARM_RED)) {
+					snprintf(ftdmchan->last_error + strlen(ftdmchan->last_error), sizeof(ftdmchan->last_error) - strlen(ftdmchan->last_error), "RED/");
+				}
+				if (ftdm_test_alarm_flag(ftdmchan, FTDM_ALARM_YELLOW)) {
+					snprintf(ftdmchan->last_error + strlen(ftdmchan->last_error), sizeof(ftdmchan->last_error) - strlen(ftdmchan->last_error), "YELLOW/");
+				}
+				if (ftdm_test_alarm_flag(ftdmchan, FTDM_ALARM_BLUE)) {
+					snprintf(ftdmchan->last_error + strlen(ftdmchan->last_error), sizeof(ftdmchan->last_error) - strlen(ftdmchan->last_error), "BLUE/");
+				}
+				if (ftdm_test_alarm_flag(ftdmchan, FTDM_ALARM_LOOPBACK)) {
+					snprintf(ftdmchan->last_error + strlen(ftdmchan->last_error), sizeof(ftdmchan->last_error) - strlen(ftdmchan->last_error), "LOOP/");
+				}
+				if (ftdm_test_alarm_flag(ftdmchan, FTDM_ALARM_RECOVER)) {
+					snprintf(ftdmchan->last_error + strlen(ftdmchan->last_error), sizeof(ftdmchan->last_error) - strlen(ftdmchan->last_error), "RECOVER/");
+				}
+				*(ftdmchan->last_error + strlen(ftdmchan->last_error) - 1) = '\0';
+
+			}
+		} else {
+			status = FTDM_NOTIMPL;
+		}
+	}
+	
+	return status;
+}
+
+static void ftdm_span_add(ftdm_span_t *span)
+{
+	ftdm_span_t *sp;
+	ftdm_mutex_lock(globals.span_mutex);
+	for (sp = globals.spans; sp && sp->next; sp = sp->next);
+	if (sp) {
+		sp->next = span;
+	} else {
+		globals.spans = span;
+	}
+	hashtable_insert(globals.span_hash, (void *)span->name, span, HASHTABLE_FLAG_NONE);
+	ftdm_mutex_unlock(globals.span_mutex);
+}
+
+#if 0
+static void ftdm_span_del(ftdm_span_t *span)
+{
+	ftdm_span_t *last = NULL, *sp;
+
+	ftdm_mutex_lock(globals.span_mutex);
+	for (sp = globals.spans; sp; sp = sp->next) {
+		
+		if (sp == span) {
+			if (last) {
+				last->next = sp->next;
+			} else {
+				globals.spans = sp->next;
+			}
+			hashtable_remove(globals.span_hash, (void *)sp->name);
+			break;
+		}
+
+		last = sp;
+	}
+	ftdm_mutex_unlock(globals.span_mutex);
+}
+#endif
+
+FT_DECLARE(ftdm_status_t) ftdm_span_stop(ftdm_span_t *span)
+{
+	if (span->stop) {
+		span->stop(span);
+		return FTDM_SUCCESS;
+	}
+	
+	return FTDM_FAIL;
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_span_create(ftdm_io_interface_t *fio, ftdm_span_t **span, const char *name)
+{
+	ftdm_span_t *new_span = NULL;
+	ftdm_status_t status = FTDM_FAIL;
+
+	ftdm_assert(fio != NULL, "No IO provided\n");
+
+	ftdm_mutex_lock(globals.mutex);
+
+	if (globals.span_index < FTDM_MAX_SPANS_INTERFACE) {
+		new_span = ftdm_calloc(sizeof(*new_span), 1);
+		ftdm_assert(new_span, "allocating span failed\n");
+
+		status = ftdm_mutex_create(&new_span->mutex);
+		ftdm_assert(status == FTDM_SUCCESS, "mutex creation failed\n");
+
+		status = ftdm_queue_create(&new_span->pendingchans, SPAN_PENDING_CHANS_QUEUE_SIZE);
+		ftdm_assert(status == FTDM_SUCCESS, "span chans queue creation failed\n");
+		
+		ftdm_set_flag(new_span, FTDM_SPAN_CONFIGURED);
+		new_span->span_id = ++globals.span_index;
+		new_span->fio = fio;
+		ftdm_copy_string(new_span->tone_map[FTDM_TONEMAP_DIAL], "%(1000,0,350,440)", FTDM_TONEMAP_LEN);
+		ftdm_copy_string(new_span->tone_map[FTDM_TONEMAP_RING], "%(2000,4000,440,480)", FTDM_TONEMAP_LEN);
+		ftdm_copy_string(new_span->tone_map[FTDM_TONEMAP_BUSY], "%(500,500,480,620)", FTDM_TONEMAP_LEN);
+		ftdm_copy_string(new_span->tone_map[FTDM_TONEMAP_ATTN], "%(100,100,1400,2060,2450,2600)", FTDM_TONEMAP_LEN);
+		new_span->trunk_type = FTDM_TRUNK_NONE;
+		new_span->data_type = FTDM_TYPE_SPAN;
+
+		ftdm_mutex_lock(globals.span_mutex);
+		if (!ftdm_strlen_zero(name) && hashtable_search(globals.span_hash, (void *)name)) {
+			ftdm_log(FTDM_LOG_WARNING, "name %s is already used, substituting 'span%d' as the name\n", name, new_span->span_id);
+			name = NULL;
+		}
+		ftdm_mutex_unlock(globals.span_mutex);
+		
+		if (!name) {
+			char buf[128] = "";
+			snprintf(buf, sizeof(buf), "span%d", new_span->span_id);
+			name = buf;
+		}
+		new_span->name = ftdm_strdup(name);
+		ftdm_span_add(new_span);
+		*span = new_span;
+		status = FTDM_SUCCESS;
+	}
+	ftdm_mutex_unlock(globals.mutex);
+	return status;
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_span_close_all(void)
+{
+	ftdm_span_t *span;
+	uint32_t i = 0, j;
+
+	ftdm_mutex_lock(globals.span_mutex);
+	for (span = globals.spans; span; span = span->next) {
+		if (ftdm_test_flag(span, FTDM_SPAN_CONFIGURED)) {
+			for(j = 1; j <= span->chan_count && span->channels[j]; j++) {
+				ftdm_channel_t *toclose = span->channels[j];
+				if (ftdm_test_flag(toclose, FTDM_CHANNEL_INUSE)) {
+					ftdm_channel_close(&toclose);
+				}
+				i++;
+			}
+		} 
+	}
+	ftdm_mutex_unlock(globals.span_mutex);
+
+	return i ? FTDM_SUCCESS : FTDM_FAIL;
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_span_load_tones(ftdm_span_t *span, const char *mapname)
+{
+	ftdm_config_t cfg;
+	char *var, *val;
+	int x = 0;
+
+	if (!ftdm_config_open_file(&cfg, "tones.conf")) {
+		snprintf(span->last_error, sizeof(span->last_error), "error loading tones.");
+		return FTDM_FAIL;
+	}
+	
+	while (ftdm_config_next_pair(&cfg, &var, &val)) {
+		int detect = 0;
+
+		if (!strcasecmp(cfg.category, mapname) && var && val) {
+			uint32_t index;
+			char *name = NULL;
+
+			if (!strncasecmp(var, "detect-", 7)) {
+				name = var + 7;
+				detect = 1;
+			} else if (!strncasecmp(var, "generate-", 9)) {
+				name = var + 9;
+			} else {
+				ftdm_log(FTDM_LOG_WARNING, "Unknown tone name %s\n", var);
+				continue;
+			}
+
+			index = ftdm_str2ftdm_tonemap(name);
+
+			if (index >= FTDM_TONEMAP_INVALID || index == FTDM_TONEMAP_NONE) {
+				ftdm_log(FTDM_LOG_WARNING, "Unknown tone name %s\n", name);
+			} else {
+				if (detect) {
+					char *p = val, *next;
+					int i = 0;
+					do {
+						teletone_process_t this;
+						next = strchr(p, ',');
+						this = (teletone_process_t)atof(p);
+						span->tone_detect_map[index].freqs[i++] = this;
+						if (next) {
+							p = next + 1;
+						}
+					} while (next);
+					ftdm_log(FTDM_LOG_DEBUG, "added tone detect [%s] = [%s]\n", name, val);
+				}  else {
+					ftdm_log(FTDM_LOG_DEBUG, "added tone generation [%s] = [%s]\n", name, val);
+					ftdm_copy_string(span->tone_map[index], val, sizeof(span->tone_map[index]));
+				}
+				x++;
+			}
+		}
+	}
+
+	ftdm_config_close_file(&cfg);
+	
+	if (!x) {
+		snprintf(span->last_error, sizeof(span->last_error), "error loading tones.");
+		return FTDM_FAIL;
+	}
+
+	return FTDM_SUCCESS;
+	
+}
+
+#define FTDM_SLINEAR_MAX_VALUE 32767
+#define FTDM_SLINEAR_MIN_VALUE -32767
+static void reset_gain_table(unsigned char *gain_table, float new_gain, ftdm_codec_t codec_gain)
+{
+	/* sample value */
+	unsigned char sv = 0;
+	/* linear gain factor */
+	float lingain = 0;
+	/* linear value for each table sample */
+	float linvalue = 0;
+	/* amplified (or attenuated in case of negative amplification) sample value */
+	int ampvalue = 0;
+
+	/* gain tables are only for alaw and ulaw */
+	if (codec_gain != FTDM_CODEC_ALAW && codec_gain != FTDM_CODEC_ULAW) {
+		ftdm_log(FTDM_LOG_WARNING, "Not resetting gain table because codec is not ALAW or ULAW but %d\n", codec_gain);
+		return;
+	}
+
+	if (!new_gain) {
+		/* for a 0.0db gain table, each alaw/ulaw sample value is left untouched (0 ==0, 1 == 1, 2 == 2 etc)*/
+		sv = 0;
+		while (1) {
+			gain_table[sv] = sv;
+			if (sv == (FTDM_GAINS_TABLE_SIZE-1)) {
+				break;
+			}
+			sv++;
+		}
+		return;
+	}
+
+	/* use the 20log rule to increase the gain: http://en.wikipedia.org/wiki/Gain, http:/en.wipedia.org/wiki/20_log_rule#Definitions */
+	lingain = (float)pow(10.0, new_gain/ 20.0);
+	sv = 0;
+	while (1) {
+		/* get the linear value for this alaw/ulaw sample value */
+		linvalue = codec_gain == FTDM_CODEC_ALAW ? (float)alaw_to_linear(sv) : (float)ulaw_to_linear(sv);
+
+		/* multiply the linear value and the previously calculated linear gain */
+		ampvalue = (int)(linvalue * lingain);
+
+		/* chop it if goes beyond the limits */
+		if (ampvalue > FTDM_SLINEAR_MAX_VALUE) {
+			ampvalue = FTDM_SLINEAR_MAX_VALUE;
+		}
+
+		if (ampvalue < FTDM_SLINEAR_MIN_VALUE) {
+			ampvalue = FTDM_SLINEAR_MIN_VALUE;
+		}
+		gain_table[sv] = codec_gain == FTDM_CODEC_ALAW ? linear_to_alaw(ampvalue) : linear_to_ulaw(ampvalue);
+		if (sv == (FTDM_GAINS_TABLE_SIZE-1)) {
+			break;
+		}
+		sv++;
+	}
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_span_add_channel(ftdm_span_t *span, ftdm_socket_t sockfd, ftdm_chan_type_t type, ftdm_channel_t **chan)
+{
+	unsigned char i = 0;
+	if (span->chan_count < FTDM_MAX_CHANNELS_SPAN) {
+		ftdm_channel_t *new_chan = span->channels[++span->chan_count];
+
+		if (!new_chan) {
+			if (!(new_chan = ftdm_calloc(1, sizeof(*new_chan)))) {
+				return FTDM_FAIL;
+			}
+			span->channels[span->chan_count] = new_chan;
+		}
+
+		new_chan->type = type;
+		new_chan->sockfd = sockfd;
+		new_chan->fio = span->fio;
+		new_chan->span_id = span->span_id;
+		new_chan->chan_id = span->chan_count;
+		new_chan->span = span;
+		new_chan->fds[0] = -1;
+		new_chan->fds[1] = -1;
+		new_chan->data_type = FTDM_TYPE_CHANNEL;
+		if (!new_chan->dtmf_on) {
+			new_chan->dtmf_on = FTDM_DEFAULT_DTMF_ON;
+		}
+
+		if (!new_chan->dtmf_off) {
+			new_chan->dtmf_off = FTDM_DEFAULT_DTMF_OFF;
+		}
+
+		ftdm_mutex_create(&new_chan->mutex);
+		ftdm_mutex_create(&new_chan->pre_buffer_mutex);
+
+		ftdm_buffer_create(&new_chan->digit_buffer, 128, 128, 0);
+		ftdm_buffer_create(&new_chan->gen_dtmf_buffer, 128, 128, 0);
+		new_chan->variable_hash = create_hashtable(16, ftdm_hash_hashfromstring, ftdm_hash_equalkeys);
+
+		new_chan->dtmf_hangup_buf = ftdm_calloc (span->dtmf_hangup_len + 1, sizeof (char));
+
+		/* set 0.0db gain table */
+		i = 0;
+		while (1) {
+			new_chan->txgain_table[i] = i;
+			new_chan->rxgain_table[i] = i;
+			if (i == (sizeof(new_chan->txgain_table)-1)) {
+				break;
+			}
+			i++;
+		}
+
+		ftdm_set_flag(new_chan, FTDM_CHANNEL_CONFIGURED | FTDM_CHANNEL_READY);
+		*chan = new_chan;
+		return FTDM_SUCCESS;
+	}
+
+	return FTDM_FAIL;
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_span_find_by_name(const char *name, ftdm_span_t **span)
+{
+	ftdm_status_t status = FTDM_FAIL;
+
+	ftdm_mutex_lock(globals.span_mutex);
+	if (!ftdm_strlen_zero(name)) {
+		if ((*span = hashtable_search(globals.span_hash, (void *)name))) {
+			status = FTDM_SUCCESS;
+		} else {
+			int span_id = atoi(name);
+
+			ftdm_span_find(span_id, span);
+			if (*span) {
+				status = FTDM_SUCCESS;
+			}
+		}
+	}
+	ftdm_mutex_unlock(globals.span_mutex);
+	
+	return status;
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_span_find(uint32_t id, ftdm_span_t **span)
+{
+	ftdm_span_t *fspan = NULL, *sp;
+
+	if (id > FTDM_MAX_SPANS_INTERFACE) {
+		return FTDM_FAIL;
+	}
+
+	ftdm_mutex_lock(globals.span_mutex);
+	for (sp = globals.spans; sp; sp = sp->next) {
+		if (sp->span_id == id) {
+			fspan = sp;
+			break;
+		}
+	}
+	ftdm_mutex_unlock(globals.span_mutex);
+
+	if (!fspan || !ftdm_test_flag(fspan, FTDM_SPAN_CONFIGURED)) {
+		return FTDM_FAIL;
+	}
+
+	*span = fspan;
+
+	return FTDM_SUCCESS;
+	
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_span_set_event_callback(ftdm_span_t *span, fio_event_cb_t event_callback)
+{
+	ftdm_mutex_lock(span->mutex);
+	span->event_callback = event_callback;
+	ftdm_mutex_unlock(span->mutex);
+	return FTDM_SUCCESS;
+}
+
+
+FT_DECLARE(ftdm_status_t) ftdm_span_poll_event(ftdm_span_t *span, uint32_t ms)
+{
+	assert(span->fio != NULL);
+
+	if (span->fio->poll_event) {
+		return span->fio->poll_event(span, ms);
+	} else {
+		ftdm_log(FTDM_LOG_ERROR, "poll_event method not implemented in module %s!", span->fio->name);
+	}
+
+	return FTDM_NOTIMPL;
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_span_next_event(ftdm_span_t *span, ftdm_event_t **event)
+{
+	ftdm_status_t status = FTDM_FAIL;
+	ftdm_sigmsg_t sigmsg;
+	ftdm_assert_return(span->fio != NULL, FTDM_FAIL, "No I/O module attached to this span!\n");
+
+	if (!span->fio->next_event) {
+		ftdm_log(FTDM_LOG_ERROR, "next_event method not implemented in module %s!", span->fio->name);
+		return FTDM_NOTIMPL;
+	}
+
+	status = span->fio->next_event(span, event);
+	if (status != FTDM_SUCCESS) {
+		return status;
+	}
+
+	/* before returning the event to the user we do some core operations with certain OOB events */
+	memset(&sigmsg, 0, sizeof(sigmsg));
+	sigmsg.span_id = span->span_id;
+	sigmsg.chan_id = (*event)->channel->chan_id;
+	sigmsg.channel = (*event)->channel;
+	switch ((*event)->enum_id) {
+	case FTDM_OOB_ALARM_CLEAR:
+		{
+			sigmsg.event_id = FTDM_SIGEVENT_ALARM_CLEAR;
+			ftdm_clear_flag_locked((*event)->channel, FTDM_CHANNEL_IN_ALARM);
+			ftdm_span_send_signal(span, &sigmsg);
+		}
+		break;
+	case FTDM_OOB_ALARM_TRAP:
+		{
+			sigmsg.event_id = FTDM_SIGEVENT_ALARM_TRAP;
+			ftdm_set_flag_locked((*event)->channel, FTDM_CHANNEL_IN_ALARM);
+			ftdm_span_send_signal(span, &sigmsg);
+		}
+		break;
+	default:
+		/* NOOP */
+		break;
+	}
+
+	return status;
+}
+
+static ftdm_status_t ftdmchan_fsk_write_sample(int16_t *buf, ftdm_size_t buflen, void *user_data)
+{
+	ftdm_channel_t *ftdmchan = (ftdm_channel_t *) user_data;
+	ftdm_buffer_write(ftdmchan->fsk_buffer, buf, buflen * 2);
+	return FTDM_SUCCESS;
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_channel_send_fsk_data(ftdm_channel_t *ftdmchan, ftdm_fsk_data_state_t *fsk_data, float db_level)
+{
+	struct ftdm_fsk_modulator fsk_trans;
+
+	if (!ftdmchan->fsk_buffer) {
+		ftdm_buffer_create(&ftdmchan->fsk_buffer, 128, 128, 0);
+	} else {
+		ftdm_buffer_zero(ftdmchan->fsk_buffer);
+	}
+
+	if (ftdmchan->token_count > 1) {
+		ftdm_fsk_modulator_init(&fsk_trans, FSK_BELL202, ftdmchan->rate, fsk_data, db_level, 80, 5, 0, ftdmchan_fsk_write_sample, ftdmchan);
+		ftdm_fsk_modulator_send_all((&fsk_trans));
+	} else {
+		ftdm_fsk_modulator_init(&fsk_trans, FSK_BELL202, ftdmchan->rate, fsk_data, db_level, 180, 5, 300, ftdmchan_fsk_write_sample, ftdmchan);
+		ftdm_fsk_modulator_send_all((&fsk_trans));
+		ftdmchan->buffer_delay = 3500 / ftdmchan->effective_interval;
+	}
+
+	return FTDM_SUCCESS;
+}
+
+
+FT_DECLARE(ftdm_status_t) ftdm_channel_set_event_callback(ftdm_channel_t *ftdmchan, fio_event_cb_t event_callback)
+{
+	ftdm_mutex_lock(ftdmchan->mutex);
+	ftdmchan->event_callback = event_callback;
+	ftdm_mutex_unlock(ftdmchan->mutex);
+	return FTDM_SUCCESS;
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_channel_clear_token(ftdm_channel_t *ftdmchan, const char *token)
+{
+	ftdm_status_t status = FTDM_FAIL;
+	
+	ftdm_mutex_lock(ftdmchan->mutex);
+	if (token == NULL) {
+		memset(ftdmchan->tokens, 0, sizeof(ftdmchan->tokens));
+		ftdmchan->token_count = 0;
+	} else if (*token != '\0') {
+		char tokens[FTDM_MAX_TOKENS][FTDM_TOKEN_STRLEN];
+		int32_t i, count = ftdmchan->token_count;
+		memcpy(tokens, ftdmchan->tokens, sizeof(tokens));
+		memset(ftdmchan->tokens, 0, sizeof(ftdmchan->tokens));
+		ftdmchan->token_count = 0;		
+
+		for (i = 0; i < count; i++) {
+			if (strcmp(tokens[i], token)) {
+				ftdm_copy_string(ftdmchan->tokens[ftdmchan->token_count], tokens[i], sizeof(ftdmchan->tokens[ftdmchan->token_count]));
+				ftdmchan->token_count++;
+			}
+		}
+
+		status = FTDM_SUCCESS;
+	}
+	ftdm_mutex_unlock(ftdmchan->mutex);
+
+	return status;
+}
+
+FT_DECLARE(void) ftdm_channel_rotate_tokens(ftdm_channel_t *ftdmchan)
+{
+	if (ftdmchan->token_count) {
+		memmove(ftdmchan->tokens[1], ftdmchan->tokens[0], ftdmchan->token_count * FTDM_TOKEN_STRLEN);
+		ftdm_copy_string(ftdmchan->tokens[0], ftdmchan->tokens[ftdmchan->token_count], FTDM_TOKEN_STRLEN);
+		*ftdmchan->tokens[ftdmchan->token_count] = '\0';
+	}
+}
+
+FT_DECLARE(void) ftdm_channel_replace_token(ftdm_channel_t *ftdmchan, const char *old_token, const char *new_token)
+{
+	unsigned int i;
+
+	if (ftdmchan->token_count) {
+		for(i = 0; i < ftdmchan->token_count; i++) {
+			if (!strcmp(ftdmchan->tokens[i], old_token)) {
+				ftdm_copy_string(ftdmchan->tokens[i], new_token, FTDM_TOKEN_STRLEN);
+				break;
+			}
+		}
+	}
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_channel_add_token(ftdm_channel_t *ftdmchan, char *token, int end)
+{
+	ftdm_status_t status = FTDM_FAIL;
+
+	ftdm_mutex_lock(ftdmchan->mutex);
+	if (ftdmchan->token_count < FTDM_MAX_TOKENS) {
+		if (end) {
+			ftdm_copy_string(ftdmchan->tokens[ftdmchan->token_count++], token, FTDM_TOKEN_STRLEN);
+		} else {
+			memmove(ftdmchan->tokens[1], ftdmchan->tokens[0], ftdmchan->token_count * FTDM_TOKEN_STRLEN);
+			ftdm_copy_string(ftdmchan->tokens[0], token, FTDM_TOKEN_STRLEN);
+			ftdmchan->token_count++;
+		}
+		status = FTDM_SUCCESS;
+	}
+	ftdm_mutex_unlock(ftdmchan->mutex);
+
+	return status;
+}
+
+
+FT_DECLARE(ftdm_status_t) ftdm_channel_complete_state(ftdm_channel_t *ftdmchan)
+{
+	ftdm_channel_state_t state = ftdmchan->state;
+
+	if (state == FTDM_CHANNEL_STATE_PROGRESS) {
+		ftdm_set_flag(ftdmchan, FTDM_CHANNEL_PROGRESS);
+	} else if (state == FTDM_CHANNEL_STATE_UP) {
+		ftdm_set_flag(ftdmchan, FTDM_CHANNEL_PROGRESS);
+		ftdm_set_flag(ftdmchan, FTDM_CHANNEL_MEDIA);	
+		ftdm_set_flag(ftdmchan, FTDM_CHANNEL_ANSWERED);	
+	} else if (state == FTDM_CHANNEL_STATE_PROGRESS_MEDIA) {
+		ftdm_set_flag(ftdmchan, FTDM_CHANNEL_PROGRESS);	
+		ftdm_set_flag(ftdmchan, FTDM_CHANNEL_MEDIA);	
+	}
+
+	return FTDM_SUCCESS;
+}
+
+static int ftdm_parse_state_map(ftdm_channel_t *ftdmchan, ftdm_channel_state_t state, ftdm_state_map_t *state_map)
+{
+	int x = 0, ok = 0;
+	ftdm_state_direction_t direction = ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND) ? ZSD_OUTBOUND : ZSD_INBOUND;
+
+	for(x = 0; x < FTDM_MAP_NODE_SIZE; x++) {
+		int i = 0, proceed = 0;
+		if (!state_map->nodes[x].type) {
+			break;
+		}
+
+		if (state_map->nodes[x].direction != direction) {
+			continue;
+		}
+		
+		if (state_map->nodes[x].check_states[0] == FTDM_ANY_STATE) {
+			proceed = 1;
+		} else {
+			for(i = 0; i < FTDM_MAP_MAX; i++) {
+				if (state_map->nodes[x].check_states[i] == ftdmchan->state) {
+					proceed = 1;
+					break;
+				}
+			}
+		}
+
+		if (!proceed) {
+			continue;
+		}
+		
+		for(i = 0; i < FTDM_MAP_MAX; i++) {
+			ok = (state_map->nodes[x].type == ZSM_ACCEPTABLE);
+			if (state_map->nodes[x].states[i] == FTDM_END) {
+				break;
+			}
+			if (state_map->nodes[x].states[i] == state) {
+				ok = !ok;
+				goto end;
+			}
+		}
+	}
+ end:
+	
+	return ok;
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_channel_set_state(ftdm_channel_t *ftdmchan, ftdm_channel_state_t state, int lock)
+{
+	int ok = 1;
+	
+	if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_READY)) {
+		return FTDM_FAIL;
+	}
+
+	if (ftdm_test_flag(ftdmchan->span, FTDM_SPAN_SUSPENDED)) {
+		if (state != FTDM_CHANNEL_STATE_RESTART && state != FTDM_CHANNEL_STATE_DOWN) {
+			return FTDM_FAIL;
+		}
+	}
+
+	if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE)) {
+		ftdm_log(FTDM_LOG_CRIT, "Ignored state change request from %s to %s, the previous state change has not been processed yet\n",
+				ftdm_channel_state2str(ftdmchan->state), ftdm_channel_state2str(state));
+		return FTDM_FAIL;
+	}
+
+	if (lock) {
+		ftdm_mutex_lock(ftdmchan->mutex);
+	}
+
+	if (ftdmchan->span->state_map) {
+		ok = ftdm_parse_state_map(ftdmchan, state, ftdmchan->span->state_map);
+		goto end;
+	}
+
+	switch(ftdmchan->state) {
+	case FTDM_CHANNEL_STATE_HANGUP:
+	case FTDM_CHANNEL_STATE_TERMINATING:
+		{
+			ok = 0;
+			switch(state) {
+			case FTDM_CHANNEL_STATE_DOWN:
+			case FTDM_CHANNEL_STATE_BUSY:
+			case FTDM_CHANNEL_STATE_RESTART:
+				ok = 1;
+				break;
+			default:
+				break;
+			}
+		}
+		break;
+	case FTDM_CHANNEL_STATE_UP:
+		{
+			ok = 1;
+			switch(state) {
+			case FTDM_CHANNEL_STATE_PROGRESS:
+			case FTDM_CHANNEL_STATE_PROGRESS_MEDIA:
+			case FTDM_CHANNEL_STATE_RING:
+				ok = 0;
+				break;
+			default:
+				break;
+			}
+		}
+		break;
+	case FTDM_CHANNEL_STATE_DOWN:
+		{
+			ok = 0;
+			
+			switch(state) {
+			case FTDM_CHANNEL_STATE_DIALTONE:
+			case FTDM_CHANNEL_STATE_COLLECT:
+			case FTDM_CHANNEL_STATE_DIALING:
+			case FTDM_CHANNEL_STATE_RING:
+			case FTDM_CHANNEL_STATE_PROGRESS_MEDIA:
+			case FTDM_CHANNEL_STATE_PROGRESS:				
+			case FTDM_CHANNEL_STATE_GET_CALLERID:
+			case FTDM_CHANNEL_STATE_GENRING:
+				ok = 1;
+				break;
+			default:
+				break;
+			}
+		}
+		break;
+	case FTDM_CHANNEL_STATE_BUSY:
+		{
+			switch(state) {
+			case FTDM_CHANNEL_STATE_UP:
+				ok = 0;
+				break;
+			default:
+				break;
+			}
+		}
+		break;
+	case FTDM_CHANNEL_STATE_RING:
+		{
+			switch(state) {
+			case FTDM_CHANNEL_STATE_UP:
+				ok = 1;
+				break;
+			default:
+				break;
+			}
+		}
+		break;
+	default:
+		break;
+	}
+
+ end:
+
+	if (state == ftdmchan->state) {
+		ok = 0;
+	}
+	
+
+	if (ok) {
+		ftdm_set_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE);	
+
+		ftdm_mutex_lock(ftdmchan->span->mutex);
+		ftdm_set_flag(ftdmchan->span, FTDM_SPAN_STATE_CHANGE);
+		ftdm_queue_enqueue(ftdmchan->span->pendingchans, ftdmchan);
+		ftdm_mutex_unlock(ftdmchan->span->mutex);
+
+		ftdmchan->last_state = ftdmchan->state; 
+		ftdmchan->state = state;
+	}
+
+	if (lock) {
+		ftdm_mutex_unlock(ftdmchan->mutex);
+	}
+
+	return ok ? FTDM_SUCCESS : FTDM_FAIL;
+}
+
+
+FT_DECLARE(ftdm_status_t) ftdm_group_channel_use_count(ftdm_group_t *group, uint32_t *count)
+{
+	uint32_t j;
+
+	*count = 0;
+	
+	if (!group) {
+		return FTDM_FAIL;
+	}
+	
+	for(j = 0; j < group->chan_count && group->channels[j]; j++) {
+		if (group->channels[j]) {
+			if (ftdm_test_flag(group->channels[j], FTDM_CHANNEL_INUSE)) {
+				(*count)++;
+			}
+		}
+	}
+	
+	return FTDM_SUCCESS;
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_channel_open_by_group(uint32_t group_id, ftdm_direction_t direction, ftdm_caller_data_t *caller_data, ftdm_channel_t **ftdmchan)
+{
+	ftdm_status_t status = FTDM_FAIL;
+	ftdm_channel_t *check;
+	uint32_t i, count;
+	ftdm_group_t *group = NULL;
+
+	if (group_id) {
+		ftdm_group_find(group_id, &group);
+	}
+
+	if (!group) {
+		ftdm_log(FTDM_LOG_ERROR, "Group %d not defined!\n", group_id);
+		*ftdmchan = NULL;
+		return FTDM_FAIL;
+	}
+
+	ftdm_group_channel_use_count(group, &count);
+
+	if (count >= group->chan_count) {
+		ftdm_log(FTDM_LOG_ERROR, "All circuits are busy (%d channels used out of %d available).\n", count, group->chan_count);
+		*ftdmchan = NULL;
+		return FTDM_FAIL;
+	}
+
+	
+	if (direction == FTDM_TOP_DOWN) {
+		i = 0;
+	} else {
+		i = group->chan_count-1;
+	}
+
+	ftdm_mutex_lock(group->mutex);
+	for (;;) {
+		if (direction == FTDM_TOP_DOWN) {
+			if (i >= group->chan_count) {
+				break;
+			}
+		} else {
+			if (i < 0) {
+				break;
+			}
+		}
+	
+		if (!(check = group->channels[i])) {
+			status = FTDM_FAIL;
+			break;
+		}
+
+		if (ftdm_test_flag(check, FTDM_CHANNEL_READY) && 
+			!ftdm_test_flag(check, FTDM_CHANNEL_INUSE) && 
+			!ftdm_test_flag(check, FTDM_CHANNEL_SUSPENDED) && 
+			!ftdm_test_flag(check, FTDM_CHANNEL_IN_ALARM) &&
+			check->state == FTDM_CHANNEL_STATE_DOWN && 
+			FTDM_IS_VOICE_CHANNEL(check)
+			) {
+			ftdm_span_t* span = NULL;
+			ftdm_span_find(check->span_id, &span);
+			if (span && span->channel_request) {
+				status = span->channel_request(span, check->chan_id, direction, caller_data, ftdmchan);
+				break;
+			}
+
+			status = check->fio->open(check);
+				
+			if (status == FTDM_SUCCESS) {
+				ftdm_set_flag(check, FTDM_CHANNEL_INUSE);
+				ftdm_channel_open_chan(check);
+				*ftdmchan = check;
+				break;
+			}
+		}
+		
+		if (direction == FTDM_TOP_DOWN) {
+			i++;
+		} else {
+			i--;
+		}	
+	}
+	ftdm_mutex_unlock(group->mutex);
+	return status;
+}
+
+
+FT_DECLARE(ftdm_status_t) ftdm_span_channel_use_count(ftdm_span_t *span, uint32_t *count)
+{
+	uint32_t j;
+
+	*count = 0;
+	
+	if (!span || !ftdm_test_flag(span, FTDM_SPAN_CONFIGURED)) {
+		return FTDM_FAIL;
+	}
+	
+	for(j = 1; j <= span->chan_count && span->channels[j]; j++) {
+		if (span->channels[j]) {
+			if (ftdm_test_flag(span->channels[j], FTDM_CHANNEL_INUSE)) {
+				(*count)++;
+			}
+		}
+	}
+	
+	return FTDM_SUCCESS;
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_channel_open_by_span(uint32_t span_id, ftdm_direction_t direction, ftdm_caller_data_t *caller_data, ftdm_channel_t **ftdmchan)
+{
+	ftdm_status_t status = FTDM_FAIL;
+	ftdm_channel_t *check;
+	uint32_t i, j, count;
+	ftdm_span_t *span = NULL;
+	uint32_t span_max;
+
+	if (span_id) {
+		ftdm_span_find(span_id, &span);
+
+		if (!span || !ftdm_test_flag(span, FTDM_SPAN_CONFIGURED)) {
+			ftdm_log(FTDM_LOG_CRIT, "SPAN NOT DEFINED!\n");
+			*ftdmchan = NULL;
+            		return FTDM_FAIL;
+		}
+
+		ftdm_span_channel_use_count(span, &count);
+
+		if (count >= span->chan_count) {
+			ftdm_log(FTDM_LOG_CRIT, "All circuits are busy.\n");
+			*ftdmchan = NULL;
+			return FTDM_FAIL;
+		}
+
+		if (span->channel_request && !span->suggest_chan_id) {
+			ftdm_set_caller_data(span, caller_data);
+			return span->channel_request(span, 0, direction, caller_data, ftdmchan);
+		}
+		
+		span_max = span_id;
+		j = span_id;
+	} else {
+		ftdm_log(FTDM_LOG_CRIT, "No span supplied\n");
+		*ftdmchan = NULL;
+		return FTDM_FAIL;
+	}
+	
+	ftdm_mutex_lock(span->mutex);
+	
+	if (direction == FTDM_TOP_DOWN) {
+		i = 1;
+	} else {
+		i = span->chan_count;
+	}	
+		
+	for(;;) {
+
+		if (direction == FTDM_TOP_DOWN) {
+			if (i > span->chan_count) {
+				break;
+			}
+		} else {
+			if (i == 0) {
+				break;
+			}
+		}
+			
+		if (!(check = span->channels[i])) {
+			status = FTDM_FAIL;
+			break;
+		}
+			
+		if (ftdm_test_flag(check, FTDM_CHANNEL_READY) && 
+			!ftdm_test_flag(check, FTDM_CHANNEL_INUSE) && 
+			!ftdm_test_flag(check, FTDM_CHANNEL_SUSPENDED) && 
+			!ftdm_test_flag(check, FTDM_CHANNEL_IN_ALARM) && 
+			check->state == FTDM_CHANNEL_STATE_DOWN && 
+			FTDM_IS_VOICE_CHANNEL(check)
+			) {
+
+			if (span && span->channel_request) {
+				ftdm_set_caller_data(span, caller_data);
+				status = span->channel_request(span, i, direction, caller_data, ftdmchan);
+				break;
+			}
+
+			status = check->fio->open(check);
+				
+			if (status == FTDM_SUCCESS) {
+				ftdm_set_flag(check, FTDM_CHANNEL_INUSE);
+				ftdm_channel_open_chan(check);
+				*ftdmchan = check;
+				break;
+			}
+		}
+		
+		if (direction == FTDM_TOP_DOWN) {
+			i++;
+		} else {
+			i--;
+		}
+	}
+
+	ftdm_mutex_unlock(span->mutex);
+
+	return status;
+}
+
+static ftdm_status_t ftdm_channel_reset(ftdm_channel_t *ftdmchan)
+{
+	ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_OPEN);
+	ftdmchan->event_callback = NULL;
+	ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_DTMF_DETECT);
+	ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_SUPRESS_DTMF);
+	ftdm_channel_done(ftdmchan);
+	ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_HOLD);
+
+	memset(ftdmchan->tokens, 0, sizeof(ftdmchan->tokens));
+	ftdmchan->token_count = 0;
+
+	ftdm_channel_flush_dtmf(ftdmchan);
+
+	if (ftdmchan->gen_dtmf_buffer) {
+		ftdm_buffer_zero(ftdmchan->gen_dtmf_buffer);
+	}
+
+	if (ftdmchan->digit_buffer) {
+		ftdm_buffer_zero(ftdmchan->digit_buffer);
+	}
+
+	if (!ftdmchan->dtmf_on) {
+		ftdmchan->dtmf_on = FTDM_DEFAULT_DTMF_ON;
+	}
+
+	if (!ftdmchan->dtmf_off) {
+		ftdmchan->dtmf_off = FTDM_DEFAULT_DTMF_OFF;
+	}
+	
+	memset(ftdmchan->dtmf_hangup_buf, '\0', ftdmchan->span->dtmf_hangup_len);
+
+	if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_TRANSCODE)) {
+		ftdmchan->effective_codec = ftdmchan->native_codec;
+		ftdmchan->packet_len = ftdmchan->native_interval * (ftdmchan->effective_codec == FTDM_CODEC_SLIN ? 16 : 8);
+		ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_TRANSCODE);
+	}
+
+	return FTDM_SUCCESS;
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_channel_init(ftdm_channel_t *ftdmchan)
+{
+	if (ftdmchan->init_state != FTDM_CHANNEL_STATE_DOWN) {
+		ftdm_set_state_locked(ftdmchan, ftdmchan->init_state);
+		ftdmchan->init_state = FTDM_CHANNEL_STATE_DOWN;
+	}
+
+	return FTDM_SUCCESS;
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_channel_open_chan(ftdm_channel_t *ftdmchan)
+{
+	ftdm_status_t status = FTDM_FAIL;
+
+	assert(ftdmchan != NULL);
+
+	if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_SUSPENDED)) {
+		snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "%s", "Channel is suspended\n");
+		return FTDM_FAIL;
+	}
+
+	if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_IN_ALARM)) {
+		snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "%s", "Channel is alarmed\n");
+		return FTDM_FAIL;
+	}
+	
+	if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_READY) || (status = ftdm_mutex_trylock(ftdmchan->mutex)) != FTDM_SUCCESS) {
+		snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "Channel is not ready or is in use %d %d", ftdm_test_flag(ftdmchan, FTDM_CHANNEL_READY), status);
+		return status;
+	}
+
+	status = FTDM_FAIL;
+
+	if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_READY)) {
+		status = ftdmchan->span->fio->open(ftdmchan);
+		if (status == FTDM_SUCCESS) {
+			ftdm_set_flag(ftdmchan, FTDM_CHANNEL_OPEN | FTDM_CHANNEL_INUSE);
+		}
+	} else {
+		snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "%s", "Channel is not ready");
+	}
+
+	ftdm_mutex_unlock(ftdmchan->mutex);
+	return status;
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_channel_open(uint32_t span_id, uint32_t chan_id, ftdm_channel_t **ftdmchan)
+{
+	ftdm_channel_t *check;
+	ftdm_status_t status = FTDM_FAIL;
+	ftdm_span_t *span = NULL;
+
+	ftdm_mutex_unlock(globals.mutex);
+	ftdm_span_find(span_id, &span);
+
+	if (!span || !ftdm_test_flag(span, FTDM_SPAN_CONFIGURED) || chan_id >= FTDM_MAX_CHANNELS_SPAN) {
+		ftdm_log(FTDM_LOG_CRIT, "SPAN NOT DEFINED!\n");
+		*ftdmchan = NULL;
+		goto done;
+	}
+
+	if (span->channel_request) {
+		ftdm_log(FTDM_LOG_ERROR, "Individual channel selection not implemented on this span.\n");
+		*ftdmchan = NULL;
+		goto done;
+	}
+	
+	if (!(check = span->channels[chan_id])) {
+		ftdm_log(FTDM_LOG_ERROR, "Invalid Channel %d\n", chan_id);
+		*ftdmchan = NULL;
+		goto done;
+	}
+
+	if (ftdm_test_flag(check, FTDM_CHANNEL_SUSPENDED) || ftdm_test_flag(check, FTDM_CHANNEL_IN_ALARM) ||
+		!ftdm_test_flag(check, FTDM_CHANNEL_READY) || (status = ftdm_mutex_trylock(check->mutex)) != FTDM_SUCCESS) {
+		*ftdmchan = NULL;
+		goto done;
+	}
+	
+	status = FTDM_FAIL;
+
+	if (ftdm_test_flag(check, FTDM_CHANNEL_READY) && (!ftdm_test_flag(check, FTDM_CHANNEL_INUSE) || 
+													(check->type == FTDM_CHAN_TYPE_FXS && check->token_count == 1))) {
+		if (!ftdm_test_flag(check, FTDM_CHANNEL_OPEN)) {
+			status = check->fio->open(check);
+			if (status == FTDM_SUCCESS) {
+				ftdm_set_flag(check, FTDM_CHANNEL_OPEN);
+			}
+		} else {
+			status = FTDM_SUCCESS;
+		}
+		ftdm_set_flag(check, FTDM_CHANNEL_INUSE);
+		*ftdmchan = check;
+	}
+	ftdm_mutex_unlock(check->mutex);
+
+	done:
+	ftdm_mutex_unlock(globals.mutex);
+
+	return status;
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_channel_outgoing_call(ftdm_channel_t *ftdmchan)
+{
+	ftdm_status_t status;
+
+	assert(ftdmchan != NULL);
+	
+	if (ftdmchan->span->outgoing_call) {
+		if ((status = ftdmchan->span->outgoing_call(ftdmchan)) == FTDM_SUCCESS) {
+			ftdm_set_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND);
+		}
+		return status;
+	} else {
+		ftdm_log(FTDM_LOG_ERROR, "outgoing_call method not implemented!\n");
+	}
+	
+	return FTDM_FAIL;
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_channel_set_sig_status(ftdm_channel_t *ftdmchan, ftdm_signaling_status_t sigstatus)
+{
+	ftdm_assert_return(ftdmchan != NULL, FTDM_FAIL, "Null channel\n");
+	ftdm_assert_return(ftdmchan->span != NULL, FTDM_FAIL, "Null span\n");
+	
+	if (ftdmchan->span->set_channel_sig_status) {
+		return ftdmchan->span->set_channel_sig_status(ftdmchan, sigstatus);
+	} else {
+		ftdm_log(FTDM_LOG_ERROR, "set_channel_sig_status method not implemented!\n");
+		return FTDM_FAIL;
+	}
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_channel_get_sig_status(ftdm_channel_t *ftdmchan, ftdm_signaling_status_t *sigstatus)
+{
+	ftdm_assert_return(ftdmchan != NULL, FTDM_FAIL, "Null channel\n");
+	ftdm_assert_return(ftdmchan->span != NULL, FTDM_FAIL, "Null span\n");
+	ftdm_assert_return(sigstatus != NULL, FTDM_FAIL, "Null sig status parameter\n");
+	
+	if (ftdmchan->span->get_channel_sig_status) {
+		return ftdmchan->span->get_channel_sig_status(ftdmchan, sigstatus);
+	} else {
+		ftdm_log(FTDM_LOG_ERROR, "get_channel_sig_status method not implemented!\n");
+		return FTDM_FAIL;
+	}
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_span_set_sig_status(ftdm_span_t *span, ftdm_signaling_status_t sigstatus)
+{
+	ftdm_assert_return(span != NULL, FTDM_FAIL, "Null span\n");
+	
+	if (span->set_span_sig_status) {
+		return span->set_span_sig_status(span, sigstatus);
+	} else {
+		ftdm_log(FTDM_LOG_ERROR, "set_span_sig_status method not implemented!\n");
+		return FTDM_FAIL;
+	}
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_span_get_sig_status(ftdm_span_t *span, ftdm_signaling_status_t *sigstatus)
+{
+	ftdm_assert_return(span != NULL, FTDM_FAIL, "Null span\n");
+	ftdm_assert_return(sigstatus != NULL, FTDM_FAIL, "Null sig status parameter\n");
+	
+	if (span->get_span_sig_status) {
+		return span->get_span_sig_status(span, sigstatus);
+	} else {
+		ftdm_log(FTDM_LOG_ERROR, "get_span_sig_status method not implemented!\n");
+		return FTDM_FAIL;
+	}
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_channel_done(ftdm_channel_t *ftdmchan)
+{
+	assert(ftdmchan != NULL);
+
+	ftdm_mutex_lock(ftdmchan->mutex);
+
+	memset(&ftdmchan->caller_data, 0, sizeof(ftdmchan->caller_data));
+
+	ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_INUSE);
+	ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND);
+	ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_WINK);
+	ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_FLASH);
+	ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE);
+	ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_HOLD);
+	ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_OFFHOOK);
+	ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_RINGING);
+	ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_PROGRESS_DETECT);
+	ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_CALLERID_DETECT);
+	ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_3WAY);
+	ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_PROGRESS);
+	ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_MEDIA);
+	ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_ANSWERED);
+	ftdm_mutex_lock(ftdmchan->pre_buffer_mutex);
+	ftdm_buffer_destroy(&ftdmchan->pre_buffer);
+	ftdmchan->pre_buffer_size = 0;
+	ftdm_mutex_unlock(ftdmchan->pre_buffer_mutex);
+
+	ftdmchan->init_state = FTDM_CHANNEL_STATE_DOWN;
+	ftdmchan->state = FTDM_CHANNEL_STATE_DOWN;
+
+	ftdm_log(FTDM_LOG_DEBUG, "channel done %u:%u\n", ftdmchan->span_id, ftdmchan->chan_id);
+
+	ftdm_mutex_unlock(ftdmchan->mutex);
+
+	return FTDM_SUCCESS;
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_channel_use(ftdm_channel_t *ftdmchan)
+{
+
+	assert(ftdmchan != NULL);
+
+	ftdm_set_flag_locked(ftdmchan, FTDM_CHANNEL_INUSE);
+
+	return FTDM_SUCCESS;
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_channel_close(ftdm_channel_t **ftdmchan)
+{
+	ftdm_channel_t *check;
+	ftdm_status_t status = FTDM_FAIL;
+
+	assert(ftdmchan != NULL);
+	check = *ftdmchan;
+	*ftdmchan = NULL;
+
+	if (!check) {
+		return FTDM_FAIL;
+	}
+
+	if (!ftdm_test_flag(check, FTDM_CHANNEL_INUSE)) {
+		ftdm_log(FTDM_LOG_WARNING, "Called ftdm_channel_close but never ftdm_channel_open in chan %d:%d??\n", check->span_id, check->chan_id);
+		return FTDM_FAIL;
+	}
+
+	if (ftdm_test_flag(check, FTDM_CHANNEL_CONFIGURED)) {
+		ftdm_mutex_lock(check->mutex);
+		if (ftdm_test_flag(check, FTDM_CHANNEL_OPEN)) {
+			status = check->fio->close(check);
+			if (status == FTDM_SUCCESS) {
+				ftdm_clear_flag(check, FTDM_CHANNEL_INUSE);
+				ftdm_channel_reset(check);
+				*ftdmchan = NULL;
+			}
+		}
+		check->ring_count = 0;
+		ftdm_mutex_unlock(check->mutex);
+	}
+	
+	return status;
+}
+
+
+static ftdm_status_t ftdmchan_activate_dtmf_buffer(ftdm_channel_t *ftdmchan)
+{
+
+	if (!ftdmchan->dtmf_buffer) {
+		if (ftdm_buffer_create(&ftdmchan->dtmf_buffer, 1024, 3192, 0) != FTDM_SUCCESS) {
+			ftdm_log(FTDM_LOG_ERROR, "Failed to allocate DTMF Buffer!\n");
+			snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "buffer error");
+			return FTDM_FAIL;
+		} else {
+			ftdm_log(FTDM_LOG_DEBUG, "Created DTMF Buffer!\n");
+		}
+	}
+
+	
+	if (!ftdmchan->tone_session.buffer) {
+		memset(&ftdmchan->tone_session, 0, sizeof(ftdmchan->tone_session));
+		teletone_init_session(&ftdmchan->tone_session, 0, NULL, NULL);
+	}
+
+	ftdmchan->tone_session.rate = ftdmchan->rate;
+	ftdmchan->tone_session.duration = ftdmchan->dtmf_on * (ftdmchan->tone_session.rate / 1000);
+	ftdmchan->tone_session.wait = ftdmchan->dtmf_off * (ftdmchan->tone_session.rate / 1000);
+	ftdmchan->tone_session.volume = -7;
+
+	/*
+	  ftdmchan->tone_session.debug = 1;
+	  ftdmchan->tone_session.debug_stream = stdout;
+	*/
+
+	return FTDM_SUCCESS;
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_channel_command(ftdm_channel_t *ftdmchan, ftdm_command_t command, void *obj)
+{
+	ftdm_status_t status = FTDM_FAIL;
+	
+	assert(ftdmchan != NULL);
+	assert(ftdmchan->fio != NULL);
+
+	ftdm_mutex_lock(ftdmchan->mutex);
+
+	switch(command) {
+
+	case FTDM_COMMAND_ENABLE_CALLERID_DETECT:
+		{
+			if (!ftdm_channel_test_feature(ftdmchan, FTDM_CHANNEL_FEATURE_CALLERID)) {
+				if (ftdm_fsk_demod_init(&ftdmchan->fsk, ftdmchan->rate, ftdmchan->fsk_buf, sizeof(ftdmchan->fsk_buf)) != FTDM_SUCCESS) {
+					snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "%s", strerror(errno));
+					GOTO_STATUS(done, FTDM_FAIL);
+				}
+				ftdm_set_flag_locked(ftdmchan, FTDM_CHANNEL_CALLERID_DETECT);
+			}
+		}
+		break;
+	case FTDM_COMMAND_DISABLE_CALLERID_DETECT:
+		{
+			if (!ftdm_channel_test_feature(ftdmchan, FTDM_CHANNEL_FEATURE_CALLERID)) {
+				ftdm_fsk_demod_destroy(&ftdmchan->fsk);
+				ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_CALLERID_DETECT);
+			}
+		}
+		break;
+	case FTDM_COMMAND_TRACE_INPUT:
+		{
+			char *path = (char *) obj;
+			if (ftdmchan->fds[0] > 0) {
+				close(ftdmchan->fds[0]);
+				ftdmchan->fds[0] = -1;
+			}
+			if ((ftdmchan->fds[0] = open(path, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR)) > -1) {
+				ftdm_log(FTDM_LOG_DEBUG, "Tracing channel %u:%u to [%s]\n", ftdmchan->span_id, ftdmchan->chan_id, path);	
+				GOTO_STATUS(done, FTDM_SUCCESS);
+			}
+			
+			snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "%s", strerror(errno));
+			GOTO_STATUS(done, FTDM_FAIL);
+		}
+		break;
+	case FTDM_COMMAND_TRACE_OUTPUT:
+		{
+			char *path = (char *) obj;
+			if (ftdmchan->fds[1] > 0) {
+				close(ftdmchan->fds[1]);
+				ftdmchan->fds[1] = -1;
+			}
+			if ((ftdmchan->fds[1] = open(path, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR)) > -1) {
+				ftdm_log(FTDM_LOG_DEBUG, "Tracing channel %u:%u to [%s]\n", ftdmchan->span_id, ftdmchan->chan_id, path);	
+				GOTO_STATUS(done, FTDM_SUCCESS);
+			}
+			
+			snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "%s", strerror(errno));
+			GOTO_STATUS(done, FTDM_FAIL);
+		}
+		break;
+	case FTDM_COMMAND_SET_INTERVAL:
+		{
+			if (!ftdm_channel_test_feature(ftdmchan, FTDM_CHANNEL_FEATURE_INTERVAL)) {
+				ftdmchan->effective_interval = FTDM_COMMAND_OBJ_INT;
+				if (ftdmchan->effective_interval == ftdmchan->native_interval) {
+					ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_BUFFER);
+				} else {
+					ftdm_set_flag(ftdmchan, FTDM_CHANNEL_BUFFER);
+				}
+				ftdmchan->packet_len = ftdmchan->native_interval * (ftdmchan->effective_codec == FTDM_CODEC_SLIN ? 16 : 8);
+				GOTO_STATUS(done, FTDM_SUCCESS);
+			}
+		}
+		break;
+	case FTDM_COMMAND_GET_INTERVAL:
+		{
+			if (!ftdm_channel_test_feature(ftdmchan, FTDM_CHANNEL_FEATURE_INTERVAL)) {
+				FTDM_COMMAND_OBJ_INT = ftdmchan->effective_interval;
+				GOTO_STATUS(done, FTDM_SUCCESS);
+			}
+		}
+		break;
+	case FTDM_COMMAND_SET_CODEC:
+		{
+			if (!ftdm_channel_test_feature(ftdmchan, FTDM_CHANNEL_FEATURE_CODECS)) {
+				ftdmchan->effective_codec = FTDM_COMMAND_OBJ_INT;
+				
+				if (ftdmchan->effective_codec == ftdmchan->native_codec) {
+					ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_TRANSCODE);
+				} else {
+					ftdm_set_flag(ftdmchan, FTDM_CHANNEL_TRANSCODE);
+				}
+				ftdmchan->packet_len = ftdmchan->native_interval * (ftdmchan->effective_codec == FTDM_CODEC_SLIN ? 16 : 8);
+				GOTO_STATUS(done, FTDM_SUCCESS);
+			}
+		}
+		break;
+
+	case FTDM_COMMAND_SET_NATIVE_CODEC:
+		{
+			if (!ftdm_channel_test_feature(ftdmchan, FTDM_CHANNEL_FEATURE_CODECS)) {
+				ftdmchan->effective_codec = ftdmchan->native_codec;
+				ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_TRANSCODE);
+				ftdmchan->packet_len = ftdmchan->native_interval * (ftdmchan->effective_codec == FTDM_CODEC_SLIN ? 16 : 8);
+				GOTO_STATUS(done, FTDM_SUCCESS);
+			}
+		}
+		break;
+
+	case FTDM_COMMAND_GET_CODEC: 
+		{
+			if (!ftdm_channel_test_feature(ftdmchan, FTDM_CHANNEL_FEATURE_CODECS)) {
+				FTDM_COMMAND_OBJ_INT = ftdmchan->effective_codec;
+				GOTO_STATUS(done, FTDM_SUCCESS);
+			}
+		}
+		break;
+	case FTDM_COMMAND_GET_NATIVE_CODEC: 
+		{
+			if (!ftdm_channel_test_feature(ftdmchan, FTDM_CHANNEL_FEATURE_CODECS)) {
+				FTDM_COMMAND_OBJ_INT = ftdmchan->native_codec;
+				GOTO_STATUS(done, FTDM_SUCCESS);
+			}
+		}
+		break;
+	case FTDM_COMMAND_ENABLE_PROGRESS_DETECT:
+		{
+			if (!ftdm_channel_test_feature(ftdmchan, FTDM_CHANNEL_FEATURE_PROGRESS)) {
+				/* if they don't have thier own, use ours */
+				ftdm_channel_clear_detected_tones(ftdmchan);
+				ftdm_channel_clear_needed_tones(ftdmchan);
+				teletone_multi_tone_init(&ftdmchan->span->tone_finder[FTDM_TONEMAP_DIAL], &ftdmchan->span->tone_detect_map[FTDM_TONEMAP_DIAL]);
+				teletone_multi_tone_init(&ftdmchan->span->tone_finder[FTDM_TONEMAP_RING], &ftdmchan->span->tone_detect_map[FTDM_TONEMAP_RING]);
+				teletone_multi_tone_init(&ftdmchan->span->tone_finder[FTDM_TONEMAP_BUSY], &ftdmchan->span->tone_detect_map[FTDM_TONEMAP_BUSY]);
+				ftdm_set_flag(ftdmchan, FTDM_CHANNEL_PROGRESS_DETECT);
+				GOTO_STATUS(done, FTDM_SUCCESS);
+			}
+		}
+		break;
+	case FTDM_COMMAND_DISABLE_PROGRESS_DETECT:
+		{
+			if (!ftdm_channel_test_feature(ftdmchan, FTDM_CHANNEL_FEATURE_PROGRESS)) {
+				ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_PROGRESS_DETECT);
+				ftdm_channel_clear_detected_tones(ftdmchan);
+				ftdm_channel_clear_needed_tones(ftdmchan);
+				GOTO_STATUS(done, FTDM_SUCCESS);
+			}
+		}
+		break;
+	case FTDM_COMMAND_ENABLE_DTMF_DETECT:
+		{
+			/* if they don't have thier own, use ours */
+			if (!ftdm_channel_test_feature(ftdmchan, FTDM_CHANNEL_FEATURE_DTMF_DETECT)) {
+				ftdm_tone_type_t tt = FTDM_COMMAND_OBJ_INT;
+				if (tt == FTDM_TONE_DTMF) {
+					teletone_dtmf_detect_init (&ftdmchan->dtmf_detect, ftdmchan->rate);
+					ftdm_set_flag_locked(ftdmchan, FTDM_CHANNEL_DTMF_DETECT);
+					ftdm_set_flag_locked(ftdmchan, FTDM_CHANNEL_SUPRESS_DTMF);
+					GOTO_STATUS(done, FTDM_SUCCESS);
+				} else {
+					snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "invalid command");
+					GOTO_STATUS(done, FTDM_FAIL);
+				}
+			}
+		}
+		break;
+	case FTDM_COMMAND_DISABLE_DTMF_DETECT:
+		{
+			if (!ftdm_channel_test_feature(ftdmchan, FTDM_CHANNEL_FEATURE_DTMF_DETECT)) {
+				ftdm_tone_type_t tt = FTDM_COMMAND_OBJ_INT;
+                if (tt == FTDM_TONE_DTMF) {
+                    teletone_dtmf_detect_init (&ftdmchan->dtmf_detect, ftdmchan->rate);
+                    ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_DTMF_DETECT);
+					ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_SUPRESS_DTMF);
+					GOTO_STATUS(done, FTDM_SUCCESS);
+                } else {
+                    snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "invalid command");
+					GOTO_STATUS(done, FTDM_FAIL);
+                }
+			}
+		}
+
+	case FTDM_COMMAND_SET_PRE_BUFFER_SIZE:
+		{
+			int val = FTDM_COMMAND_OBJ_INT;
+
+			if (val < 0) {
+				val = 0;
+			}
+
+			ftdmchan->pre_buffer_size = val * 8;
+
+			ftdm_mutex_lock(ftdmchan->pre_buffer_mutex);
+			if (!ftdmchan->pre_buffer_size) {
+				ftdm_buffer_destroy(&ftdmchan->pre_buffer);
+			} else if (!ftdmchan->pre_buffer) {
+				ftdm_buffer_create(&ftdmchan->pre_buffer, 1024, ftdmchan->pre_buffer_size, 0);
+			}
+			ftdm_mutex_unlock(ftdmchan->pre_buffer_mutex);
+
+			GOTO_STATUS(done, FTDM_SUCCESS);
+
+		}
+		break;
+	case FTDM_COMMAND_GET_DTMF_ON_PERIOD:
+		{
+			if (!ftdm_channel_test_feature(ftdmchan, FTDM_CHANNEL_FEATURE_DTMF_GENERATE)) {
+				FTDM_COMMAND_OBJ_INT = ftdmchan->dtmf_on;
+				GOTO_STATUS(done, FTDM_SUCCESS);
+			}
+		}
+		break;
+	case FTDM_COMMAND_GET_DTMF_OFF_PERIOD:
+		{
+			if (!ftdm_channel_test_feature(ftdmchan, FTDM_CHANNEL_FEATURE_DTMF_GENERATE)) {
+				FTDM_COMMAND_OBJ_INT = ftdmchan->dtmf_on;
+				GOTO_STATUS(done, FTDM_SUCCESS);
+			}
+		}
+		break;
+	case FTDM_COMMAND_SET_DTMF_ON_PERIOD:
+		{
+			if (!ftdm_channel_test_feature(ftdmchan, FTDM_CHANNEL_FEATURE_DTMF_GENERATE)) {
+				int val = FTDM_COMMAND_OBJ_INT;
+				if (val > 10 && val < 1000) {
+					ftdmchan->dtmf_on = val;
+					GOTO_STATUS(done, FTDM_SUCCESS);
+				} else {
+					snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "invalid value %d range 10-1000", val);
+					GOTO_STATUS(done, FTDM_FAIL);
+				}
+			}
+		}
+		break;
+	case FTDM_COMMAND_SET_DTMF_OFF_PERIOD:
+		{
+			if (!ftdm_channel_test_feature(ftdmchan, FTDM_CHANNEL_FEATURE_DTMF_GENERATE)) {
+				int val = FTDM_COMMAND_OBJ_INT;
+				if (val > 10 && val < 1000) {
+					ftdmchan->dtmf_off = val;
+					GOTO_STATUS(done, FTDM_SUCCESS);
+				} else {
+					snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "invalid value %d range 10-1000", val);
+					GOTO_STATUS(done, FTDM_FAIL);
+				}
+			}
+		}
+		break;
+	case FTDM_COMMAND_SEND_DTMF:
+		{
+			if (!ftdm_channel_test_feature(ftdmchan, FTDM_CHANNEL_FEATURE_DTMF_GENERATE)) {
+				char *digits = FTDM_COMMAND_OBJ_CHAR_P;
+				
+				if ((status = ftdmchan_activate_dtmf_buffer(ftdmchan)) != FTDM_SUCCESS) {
+					GOTO_STATUS(done, status);
+				}
+				
+				ftdm_buffer_write(ftdmchan->gen_dtmf_buffer, digits, strlen(digits));
+				
+				GOTO_STATUS(done, FTDM_SUCCESS);
+			}
+		}
+		break;
+
+	case FTDM_COMMAND_DISABLE_ECHOCANCEL:
+		{
+			ftdm_mutex_lock(ftdmchan->pre_buffer_mutex);
+			ftdm_buffer_destroy(&ftdmchan->pre_buffer);
+			ftdmchan->pre_buffer_size = 0;
+			ftdm_mutex_unlock(ftdmchan->pre_buffer_mutex);
+		}
+		break;
+
+	/* FIXME: validate user gain values */
+	case FTDM_COMMAND_SET_RX_GAIN:
+		{
+			ftdmchan->rxgain = FTDM_COMMAND_OBJ_FLOAT;
+			reset_gain_table(ftdmchan->rxgain_table, ftdmchan->rxgain, ftdmchan->native_codec);
+			if (ftdmchan->rxgain == 0.0) {
+				ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_USE_RX_GAIN);
+			} else {
+				ftdm_set_flag(ftdmchan, FTDM_CHANNEL_USE_RX_GAIN);
+			}
+		}
+		break;
+	case FTDM_COMMAND_GET_RX_GAIN:
+		{
+			FTDM_COMMAND_OBJ_FLOAT = ftdmchan->rxgain;
+		}
+		break;
+	case FTDM_COMMAND_SET_TX_GAIN:
+		{
+			ftdmchan->txgain = FTDM_COMMAND_OBJ_FLOAT;
+			reset_gain_table(ftdmchan->txgain_table, ftdmchan->txgain, ftdmchan->native_codec);
+			if (ftdmchan->txgain == 0.0) {
+				ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_USE_TX_GAIN);
+			} else {
+				ftdm_set_flag(ftdmchan, FTDM_CHANNEL_USE_TX_GAIN);
+			}
+		}
+		break;
+	case FTDM_COMMAND_GET_TX_GAIN:
+		{
+			FTDM_COMMAND_OBJ_FLOAT = ftdmchan->txgain;
+		}
+		break;
+	default:
+		break;
+	}
+
+	if (!ftdmchan->fio->command) {
+		snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "method not implemented");
+		ftdm_log(FTDM_LOG_ERROR, "no command function defined by the I/O freetdm module!\n");	
+		GOTO_STATUS(done, FTDM_FAIL);
+	}
+
+    status = ftdmchan->fio->command(ftdmchan, command, obj);
+
+	if (status == FTDM_NOTIMPL) {
+		snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "I/O command %d not implemented in backend", command);
+		ftdm_log(FTDM_LOG_ERROR, "I/O backend does not support command %d!\n", command);	
+	}
+done:
+	ftdm_mutex_unlock(ftdmchan->mutex);
+	return status;
+
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_channel_wait(ftdm_channel_t *ftdmchan, ftdm_wait_flag_t *flags, int32_t to)
+{
+	assert(ftdmchan != NULL);
+	assert(ftdmchan->fio != NULL);
+
+    if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OPEN)) {
+		snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "channel not open");
+        return FTDM_FAIL;
+    }
+
+	if (!ftdmchan->fio->wait) {
+		snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "method not implemented");
+		return FTDM_FAIL;
+	}
+
+    return ftdmchan->fio->wait(ftdmchan, flags, to);
+
+}
+
+/*******************************/
+FIO_CODEC_FUNCTION(fio_slin2ulaw)
+{
+	int16_t sln_buf[512] = {0}, *sln = sln_buf;
+	uint8_t *lp = data;
+	uint32_t i;
+	ftdm_size_t len = *datalen;
+
+	if (max > len) {
+		max = len;
+	}
+
+	memcpy(sln, data, max);
+	
+	for(i = 0; i < max; i++) {
+		*lp++ = linear_to_ulaw(*sln++);
+	}
+
+	*datalen = max / 2;
+
+	return FTDM_SUCCESS;
+
+}
+
+
+FIO_CODEC_FUNCTION(fio_ulaw2slin)
+{
+	int16_t *sln = data;
+	uint8_t law[1024] = {0}, *lp = law;
+	uint32_t i;
+	ftdm_size_t len = *datalen;
+	
+	if (max > len) {
+		max = len;
+	}
+
+	memcpy(law, data, max);
+
+	for(i = 0; i < max; i++) {
+		*sln++ = ulaw_to_linear(*lp++);
+	}
+	
+	*datalen = max * 2;
+
+	return FTDM_SUCCESS;
+}
+
+FIO_CODEC_FUNCTION(fio_slin2alaw)
+{
+	int16_t sln_buf[512] = {0}, *sln = sln_buf;
+	uint8_t *lp = data;
+	uint32_t i;
+	ftdm_size_t len = *datalen;
+
+	if (max > len) {
+		max = len;
+	}
+
+	memcpy(sln, data, max);
+	
+	for(i = 0; i < max; i++) {
+		*lp++ = linear_to_alaw(*sln++);
+	}
+
+	*datalen = max / 2;
+
+	return FTDM_SUCCESS;
+
+}
+
+
+FIO_CODEC_FUNCTION(fio_alaw2slin)
+{
+	int16_t *sln = data;
+	uint8_t law[1024] = {0}, *lp = law;
+	uint32_t i;
+	ftdm_size_t len = *datalen;
+	
+	if (max > len) {
+		max = len;
+	}
+
+	memcpy(law, data, max);
+
+	for(i = 0; i < max; i++) {
+		*sln++ = alaw_to_linear(*lp++);
+	}
+
+	*datalen = max * 2;
+
+	return FTDM_SUCCESS;
+}
+
+FIO_CODEC_FUNCTION(fio_ulaw2alaw)
+{
+	ftdm_size_t len = *datalen;
+	uint32_t i;
+	uint8_t *lp = data;
+
+	if (max > len) {
+        max = len;
+    }
+
+	for(i = 0; i < max; i++) {
+		*lp = ulaw_to_alaw(*lp);
+		lp++;
+	}
+
+	return FTDM_SUCCESS;
+}
+
+FIO_CODEC_FUNCTION(fio_alaw2ulaw)
+{
+	ftdm_size_t len = *datalen;
+	uint32_t i;
+	uint8_t *lp = data;
+
+	if (max > len) {
+        max = len;
+    }
+
+	for(i = 0; i < max; i++) {
+		*lp = alaw_to_ulaw(*lp);
+		lp++;
+	}
+
+	return FTDM_SUCCESS;
+}
+
+/******************************/
+
+FT_DECLARE(void) ftdm_channel_clear_detected_tones(ftdm_channel_t *ftdmchan)
+{
+	uint32_t i;
+
+	memset(ftdmchan->detected_tones, 0, sizeof(ftdmchan->detected_tones[0]) * FTDM_TONEMAP_INVALID);
+	
+	for (i = 1; i < FTDM_TONEMAP_INVALID; i++) {
+		ftdmchan->span->tone_finder[i].tone_count = 0;
+	}
+}
+
+FT_DECLARE(void) ftdm_channel_clear_needed_tones(ftdm_channel_t *ftdmchan)
+{
+	memset(ftdmchan->needed_tones, 0, sizeof(ftdmchan->needed_tones[0]) * FTDM_TONEMAP_INVALID);
+}
+
+FT_DECLARE(ftdm_size_t) ftdm_channel_dequeue_dtmf(ftdm_channel_t *ftdmchan, char *dtmf, ftdm_size_t len)
+{
+	ftdm_size_t bytes = 0;
+
+	assert(ftdmchan != NULL);
+
+	if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_READY)) {
+		return FTDM_FAIL;
+	}
+
+	if (ftdmchan->digit_buffer && ftdm_buffer_inuse(ftdmchan->digit_buffer)) {
+		ftdm_mutex_lock(ftdmchan->mutex);
+		if ((bytes = ftdm_buffer_read(ftdmchan->digit_buffer, dtmf, len)) > 0) {
+			*(dtmf + bytes) = '\0';
+		}
+		ftdm_mutex_unlock(ftdmchan->mutex);
+	}
+
+	return bytes;
+}
+
+FT_DECLARE(void) ftdm_channel_flush_dtmf(ftdm_channel_t *ftdmchan)
+{
+	if (ftdmchan->digit_buffer && ftdm_buffer_inuse(ftdmchan->digit_buffer)) {
+		ftdm_mutex_lock(ftdmchan->mutex);
+		ftdm_buffer_zero(ftdmchan->digit_buffer);
+		ftdm_mutex_unlock(ftdmchan->mutex);
+	}
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_channel_queue_dtmf(ftdm_channel_t *ftdmchan, const char *dtmf)
+{
+	ftdm_status_t status;
+	register ftdm_size_t len, inuse;
+	ftdm_size_t wr = 0;
+	const char *p;
+	
+	assert(ftdmchan != NULL);
+
+	if (ftdmchan->pre_buffer) {
+		ftdm_buffer_zero(ftdmchan->pre_buffer);
+	}
+
+	ftdm_mutex_lock(ftdmchan->mutex);
+
+	inuse = ftdm_buffer_inuse(ftdmchan->digit_buffer);
+	len = strlen(dtmf);
+	
+	if (len + inuse > ftdm_buffer_len(ftdmchan->digit_buffer)) {
+		ftdm_buffer_toss(ftdmchan->digit_buffer, strlen(dtmf));
+	}
+
+	if (ftdmchan->span->dtmf_hangup_len) {
+		for (p = dtmf; ftdm_is_dtmf(*p); p++) {
+			memmove (ftdmchan->dtmf_hangup_buf, ftdmchan->dtmf_hangup_buf + 1, ftdmchan->span->dtmf_hangup_len - 1);
+			ftdmchan->dtmf_hangup_buf[ftdmchan->span->dtmf_hangup_len - 1] = *p;
+			if (!strcmp(ftdmchan->dtmf_hangup_buf, ftdmchan->span->dtmf_hangup)) {
+				ftdm_log(FTDM_LOG_DEBUG, "DTMF hangup detected.\n");
+				ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP);
+				break;
+			}
+		}
+	}
+
+	p = dtmf;
+	while (wr < len && p) {
+		if (ftdm_is_dtmf(*p)) {
+			wr++;
+		} else {
+			break;
+		}
+		p++;
+	}
+
+	status = ftdm_buffer_write(ftdmchan->digit_buffer, dtmf, wr) ? FTDM_SUCCESS : FTDM_FAIL;
+	ftdm_mutex_unlock(ftdmchan->mutex);
+	
+	return status;
+}
+
+
+static ftdm_status_t handle_dtmf(ftdm_channel_t *ftdmchan, ftdm_size_t datalen)
+{
+	ftdm_buffer_t *buffer = NULL;
+	ftdm_size_t dblen = 0;
+	int wrote = 0;
+
+	if (ftdmchan->gen_dtmf_buffer && (dblen = ftdm_buffer_inuse(ftdmchan->gen_dtmf_buffer))) {
+		char digits[128] = "";
+		char *cur;
+		int x = 0;				 
+		
+		if (dblen > sizeof(digits) - 1) {
+			dblen = sizeof(digits) - 1;
+		}
+
+		if (ftdm_buffer_read(ftdmchan->gen_dtmf_buffer, digits, dblen) && !ftdm_strlen_zero_buf(digits)) {
+			ftdm_log(FTDM_LOG_DEBUG, "%d:%d GENERATE DTMF [%s]\n", ftdmchan->span_id, ftdmchan->chan_id, digits);	
+		
+			cur = digits;
+
+			if (*cur == 'F') {
+				ftdm_channel_command(ftdmchan, FTDM_COMMAND_FLASH, NULL);
+				cur++;
+			}
+
+			for (; *cur; cur++) {
+				if ((wrote = teletone_mux_tones(&ftdmchan->tone_session, &ftdmchan->tone_session.TONES[(int)*cur]))) {
+					ftdm_buffer_write(ftdmchan->dtmf_buffer, ftdmchan->tone_session.buffer, wrote * 2);
+					x++;
+				} else {
+					ftdm_log(FTDM_LOG_ERROR, "%d:%d Problem Adding DTMF SEQ [%s]\n", ftdmchan->span_id, ftdmchan->chan_id, digits);
+					return FTDM_FAIL;
+				}
+			}
+
+			if (x) {
+				ftdmchan->skip_read_frames = (wrote / (ftdmchan->effective_interval * 8)) + 4;
+			}
+		}
+	}
+	
+
+	if (!ftdmchan->buffer_delay || --ftdmchan->buffer_delay == 0) {
+		if (ftdmchan->dtmf_buffer && (dblen = ftdm_buffer_inuse(ftdmchan->dtmf_buffer))) {
+			buffer = ftdmchan->dtmf_buffer;
+		} else if (ftdmchan->fsk_buffer && (dblen = ftdm_buffer_inuse(ftdmchan->fsk_buffer))) {
+			buffer = ftdmchan->fsk_buffer;			
+		}
+	}
+
+	if (buffer) {
+		ftdm_size_t dlen = datalen;
+		uint8_t auxbuf[1024];
+		ftdm_size_t len, br, max = sizeof(auxbuf);
+		
+		if (ftdmchan->native_codec != FTDM_CODEC_SLIN) {
+			dlen *= 2;
+		}
+		
+		len = dblen > dlen ? dlen : dblen;
+
+		br = ftdm_buffer_read(buffer, auxbuf, len);		
+		if (br < dlen) {
+			memset(auxbuf + br, 0, dlen - br);
+		}
+
+		if (ftdmchan->native_codec != FTDM_CODEC_SLIN) {
+			if (ftdmchan->native_codec == FTDM_CODEC_ULAW) {
+				fio_slin2ulaw(auxbuf, max, &dlen);
+			} else if (ftdmchan->native_codec == FTDM_CODEC_ALAW) {
+				fio_slin2alaw(auxbuf, max, &dlen);
+			}
+		}
+		
+		return ftdmchan->fio->write(ftdmchan, auxbuf, &dlen);
+	} 
+
+	return FTDM_SUCCESS;
+
+}
+
+
+FT_DECLARE(void) ftdm_generate_sln_silence(int16_t *data, uint32_t samples, uint32_t divisor)
+{
+    int16_t x;
+    uint32_t i;
+    int sum_rnd = 0;
+    int16_t rnd2 = (int16_t) ftdm_current_time_in_ms() * (int16_t) (intptr_t) data;
+
+    assert(divisor);
+
+    for (i = 0; i < samples; i++, sum_rnd = 0) {
+        for (x = 0; x < 6; x++) {
+            rnd2 = rnd2 * 31821U + 13849U;
+            sum_rnd += rnd2 ;
+        }
+        //switch_normalize_to_16bit(sum_rnd);
+        *data = (int16_t) ((int16_t) sum_rnd / (int) divisor);
+
+        data++;
+    }
+}
+
+
+
+FT_DECLARE(ftdm_status_t) ftdm_channel_read(ftdm_channel_t *ftdmchan, void *data, ftdm_size_t *datalen)
+{
+	ftdm_status_t status = FTDM_FAIL;
+	fio_codec_t codec_func = NULL;
+	ftdm_size_t max = *datalen;
+	unsigned i = 0;
+
+	ftdm_assert_return(ftdmchan != NULL, FTDM_FAIL, "ftdmchan is null\n");
+	ftdm_assert_return(ftdmchan->fio != NULL, FTDM_FAIL, "No I/O module attached to ftdmchan\n");
+	
+    if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OPEN)) {
+		snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "channel not open");
+        return FTDM_FAIL;
+    }
+
+	if (!ftdmchan->fio->read) {
+		snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "method not implemented");
+		return FTDM_FAIL;
+	}
+
+    status = ftdmchan->fio->read(ftdmchan, data, datalen);
+	if (ftdmchan->fds[0] > -1) {
+		int dlen = (int) *datalen;
+		if (write(ftdmchan->fds[0], data, dlen) != dlen) {
+			snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "file write error!");
+			return FTDM_FAIL;
+		}
+	}
+
+	if (status == FTDM_SUCCESS) {
+		if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_USE_RX_GAIN) 
+			&& (ftdmchan->native_codec == FTDM_CODEC_ALAW || ftdmchan->native_codec == FTDM_CODEC_ULAW)) {
+			unsigned char *rdata = data;
+			for (i = 0; i < *datalen; i++) {
+				rdata[i] = ftdmchan->rxgain_table[rdata[i]];
+			}
+		}
+		handle_dtmf(ftdmchan, *datalen);
+	}
+
+	if (status == FTDM_SUCCESS && ftdm_test_flag(ftdmchan, FTDM_CHANNEL_TRANSCODE) && ftdmchan->effective_codec != ftdmchan->native_codec) {
+		if (ftdmchan->native_codec == FTDM_CODEC_ULAW && ftdmchan->effective_codec == FTDM_CODEC_SLIN) {
+			codec_func = fio_ulaw2slin;
+		} else if (ftdmchan->native_codec == FTDM_CODEC_ULAW && ftdmchan->effective_codec == FTDM_CODEC_ALAW) {
+			codec_func = fio_ulaw2alaw;
+		} else if (ftdmchan->native_codec == FTDM_CODEC_ALAW && ftdmchan->effective_codec == FTDM_CODEC_SLIN) {
+			codec_func = fio_alaw2slin;
+		} else if (ftdmchan->native_codec == FTDM_CODEC_ALAW && ftdmchan->effective_codec == FTDM_CODEC_ULAW) {
+			codec_func = fio_alaw2ulaw;
+		}
+
+		if (codec_func) {
+			status = codec_func(data, max, datalen);
+		} else {
+			snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "codec error!");
+			status = FTDM_FAIL;
+		}
+	}
+
+	if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_DTMF_DETECT) || ftdm_test_flag(ftdmchan, FTDM_CHANNEL_PROGRESS_DETECT) || 
+		ftdm_test_flag(ftdmchan, FTDM_CHANNEL_CALLERID_DETECT)) {
+		uint8_t sln_buf[1024] = {0};
+		int16_t *sln;
+		ftdm_size_t slen = 0;
+		char digit_str[80] = "";
+
+		if (ftdmchan->effective_codec == FTDM_CODEC_SLIN) {
+			sln = data;
+			slen = *datalen / 2;
+		} else {
+			ftdm_size_t len = *datalen;
+			uint32_t i;
+			uint8_t *lp = data;
+
+			slen = sizeof(sln_buf) / 2;
+			if (len > slen) {
+				len = slen;
+			}
+
+			sln = (int16_t *) sln_buf;
+			for(i = 0; i < len; i++) {
+				if (ftdmchan->effective_codec == FTDM_CODEC_ULAW) {
+					*sln++ = ulaw_to_linear(*lp++);
+				} else if (ftdmchan->effective_codec == FTDM_CODEC_ALAW) {
+					*sln++ = alaw_to_linear(*lp++);
+				} else {
+					snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "codec error!");
+					return FTDM_FAIL;
+				}
+			}
+			sln = (int16_t *) sln_buf;
+			slen = len;
+		}
+
+		if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_CALLERID_DETECT)) {
+			if (ftdm_fsk_demod_feed(&ftdmchan->fsk, sln, slen) != FTDM_SUCCESS) {
+				ftdm_size_t type, mlen;
+				char str[128], *sp;
+				
+				while(ftdm_fsk_data_parse(&ftdmchan->fsk, &type, &sp, &mlen) == FTDM_SUCCESS) {
+					*(str+mlen) = '\0';
+					ftdm_copy_string(str, sp, ++mlen);
+					ftdm_clean_string(str);
+					ftdm_log(FTDM_LOG_DEBUG, "FSK: TYPE %s LEN %d VAL [%s]\n", ftdm_mdmf_type2str(type), mlen-1, str);
+					
+					switch(type) {
+					case MDMF_DDN:
+					case MDMF_PHONE_NUM:
+						{
+							if (mlen > sizeof(ftdmchan->caller_data.ani)) {
+								mlen = sizeof(ftdmchan->caller_data.ani);
+							}
+							ftdm_set_string(ftdmchan->caller_data.ani.digits, str);
+							ftdm_set_string(ftdmchan->caller_data.cid_num.digits, ftdmchan->caller_data.ani.digits);
+						}
+						break;
+					case MDMF_NO_NUM:
+						{
+							ftdm_set_string(ftdmchan->caller_data.ani.digits, *str == 'P' ? "private" : "unknown");
+							ftdm_set_string(ftdmchan->caller_data.cid_name, ftdmchan->caller_data.ani.digits);
+						}
+						break;
+					case MDMF_PHONE_NAME:
+						{
+							if (mlen > sizeof(ftdmchan->caller_data.cid_name)) {
+								mlen = sizeof(ftdmchan->caller_data.cid_name);
+							}
+							ftdm_set_string(ftdmchan->caller_data.cid_name, str);
+						}
+						break;
+					case MDMF_NO_NAME:
+						{
+							ftdm_set_string(ftdmchan->caller_data.cid_name, *str == 'P' ? "private" : "unknown");
+						}
+					case MDMF_DATETIME:
+						{
+							if (mlen > sizeof(ftdmchan->caller_data.cid_date)) {
+								mlen = sizeof(ftdmchan->caller_data.cid_date);
+							}
+							ftdm_set_string(ftdmchan->caller_data.cid_date, str);
+						}
+						break;
+					}
+				}
+				ftdm_channel_command(ftdmchan, FTDM_COMMAND_DISABLE_CALLERID_DETECT, NULL);
+			}
+		}
+
+		if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_PROGRESS_DETECT) && !ftdm_channel_test_feature(ftdmchan, FTDM_CHANNEL_FEATURE_PROGRESS)) {
+			uint32_t i;
+
+			for (i = 1; i < FTDM_TONEMAP_INVALID; i++) {
+				if (ftdmchan->span->tone_finder[i].tone_count) {
+					if (ftdmchan->needed_tones[i] && teletone_multi_tone_detect(&ftdmchan->span->tone_finder[i], sln, (int)slen)) {
+						if (++ftdmchan->detected_tones[i]) {
+							ftdmchan->needed_tones[i] = 0;
+							ftdmchan->detected_tones[0]++;
+						}
+					}
+				}
+			}
+		}
+	
+		
+		if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_DTMF_DETECT) && !ftdm_channel_test_feature(ftdmchan, FTDM_CHANNEL_FEATURE_DTMF_DETECT)) {
+			teletone_dtmf_detect(&ftdmchan->dtmf_detect, sln, (int)slen);
+			teletone_dtmf_get(&ftdmchan->dtmf_detect, digit_str, sizeof(digit_str));
+
+			if(*digit_str) {
+				fio_event_cb_t event_callback = NULL;
+
+				if (ftdmchan->state == FTDM_CHANNEL_STATE_CALLWAITING && (*digit_str == 'D' || *digit_str == 'A')) {
+					ftdmchan->detected_tones[FTDM_TONEMAP_CALLWAITING_ACK]++;
+				} else {
+					ftdm_channel_queue_dtmf(ftdmchan, digit_str);
+
+					if (ftdmchan->span->event_callback) {
+						event_callback = ftdmchan->span->event_callback;
+					} else if (ftdmchan->event_callback) {
+						event_callback = ftdmchan->event_callback;
+					}
+
+					if (event_callback) {
+						ftdmchan->event_header.channel = ftdmchan;
+						ftdmchan->event_header.e_type = FTDM_EVENT_DTMF;
+						ftdmchan->event_header.data = digit_str;
+						event_callback(ftdmchan, &ftdmchan->event_header);
+						ftdmchan->event_header.e_type = FTDM_EVENT_NONE;
+						ftdmchan->event_header.data = NULL;
+					}
+					if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_SUPRESS_DTMF)) {
+						ftdmchan->skip_read_frames = 20;
+					}
+				}
+			}
+		}
+	}
+
+	if (ftdmchan->skip_read_frames > 0 || ftdm_test_flag(ftdmchan, FTDM_CHANNEL_MUTE)) {
+		
+		ftdm_mutex_lock(ftdmchan->pre_buffer_mutex);
+		if (ftdmchan->pre_buffer && ftdm_buffer_inuse(ftdmchan->pre_buffer)) {
+			ftdm_buffer_zero(ftdmchan->pre_buffer);
+		}
+		ftdm_mutex_unlock(ftdmchan->pre_buffer_mutex);
+
+
+		memset(data, 255, *datalen);
+
+		if (ftdmchan->skip_read_frames > 0) {
+			ftdmchan->skip_read_frames--;
+		}
+	}  else	{
+		ftdm_mutex_lock(ftdmchan->pre_buffer_mutex);
+		if (ftdmchan->pre_buffer_size && ftdmchan->pre_buffer) {
+			ftdm_buffer_write(ftdmchan->pre_buffer, data, *datalen);
+			if (ftdm_buffer_inuse(ftdmchan->pre_buffer) >= ftdmchan->pre_buffer_size) {
+				ftdm_buffer_read(ftdmchan->pre_buffer, data, *datalen);
+			} else {
+				memset(data, 255, *datalen);
+			}
+		}
+		ftdm_mutex_unlock(ftdmchan->pre_buffer_mutex);
+	}
+
+
+	return status;
+}
+
+
+FT_DECLARE(ftdm_status_t) ftdm_channel_write(ftdm_channel_t *ftdmchan, void *data, ftdm_size_t datasize, ftdm_size_t *datalen)
+{
+	ftdm_status_t status = FTDM_FAIL;
+	fio_codec_t codec_func = NULL;
+	ftdm_size_t max = datasize;
+	unsigned int i = 0;
+
+	assert(ftdmchan != NULL);
+	assert(ftdmchan->fio != NULL);
+
+	if (!ftdmchan->buffer_delay && 
+		((ftdmchan->dtmf_buffer && ftdm_buffer_inuse(ftdmchan->dtmf_buffer)) ||
+		 (ftdmchan->fsk_buffer && ftdm_buffer_inuse(ftdmchan->fsk_buffer)))) {
+		/* read size writing DTMF ATM */
+		return FTDM_SUCCESS;
+	}
+
+
+    if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OPEN)) {
+		snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "channel not open");
+        return FTDM_FAIL;
+    }
+
+	if (!ftdmchan->fio->write) {
+		snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "method not implemented");
+		return FTDM_FAIL;
+	}
+	
+	if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_TRANSCODE) && ftdmchan->effective_codec != ftdmchan->native_codec) {
+		if (ftdmchan->native_codec == FTDM_CODEC_ULAW && ftdmchan->effective_codec == FTDM_CODEC_SLIN) {
+			codec_func = fio_slin2ulaw;
+		} else if (ftdmchan->native_codec == FTDM_CODEC_ULAW && ftdmchan->effective_codec == FTDM_CODEC_ALAW) {
+			codec_func = fio_alaw2ulaw;
+		} else if (ftdmchan->native_codec == FTDM_CODEC_ALAW && ftdmchan->effective_codec == FTDM_CODEC_SLIN) {
+			codec_func = fio_slin2alaw;
+		} else if (ftdmchan->native_codec == FTDM_CODEC_ALAW && ftdmchan->effective_codec == FTDM_CODEC_ULAW) {
+			codec_func = fio_ulaw2alaw;
+		}
+
+		if (codec_func) {
+			status = codec_func(data, max, datalen);
+		} else {
+			snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "codec error!");
+			status = FTDM_FAIL;
+		}
+	}	
+	
+	if (ftdmchan->fds[1] > -1) {
+		int dlen = (int) *datalen;
+		if ((write(ftdmchan->fds[1], data, dlen)) != dlen) {
+			snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "file write error!");
+			return FTDM_FAIL;
+		}
+	}
+
+	if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_USE_TX_GAIN) 
+		&& (ftdmchan->native_codec == FTDM_CODEC_ALAW || ftdmchan->native_codec == FTDM_CODEC_ULAW)) {
+		unsigned char *wdata = data;
+		for (i = 0; i < *datalen; i++) {
+			wdata[i] = ftdmchan->txgain_table[wdata[i]];
+		}
+	}
+    status = ftdmchan->fio->write(ftdmchan, data, datalen);
+
+	return status;
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_channel_clear_vars(ftdm_channel_t *ftdmchan)
+{
+	if(ftdmchan->variable_hash) {
+		hashtable_destroy(ftdmchan->variable_hash);
+	}
+	ftdmchan->variable_hash = create_hashtable(16, ftdm_hash_hashfromstring, ftdm_hash_equalkeys);
+
+	if(!ftdmchan->variable_hash)
+		return FTDM_FAIL;
+	
+	return FTDM_SUCCESS;
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_channel_add_var(ftdm_channel_t *ftdmchan, const char *var_name, const char *value)
+{
+	char *t_name = 0, *t_val = 0;
+
+	if(!ftdmchan->variable_hash || !var_name || !value)
+	{
+		return FTDM_FAIL;
+	}
+
+	t_name = ftdm_strdup(var_name);
+	t_val = ftdm_strdup(value);
+
+	if(hashtable_insert(ftdmchan->variable_hash, t_name, t_val, HASHTABLE_FLAG_FREE_KEY | HASHTABLE_FLAG_FREE_VALUE)) {
+		return FTDM_SUCCESS;
+	}
+	return FTDM_FAIL;
+}
+
+FT_DECLARE(const char *) ftdm_channel_get_var(ftdm_channel_t *ftdmchan, const char *var_name)
+{
+	if(!ftdmchan->variable_hash || !var_name)
+	{
+		return NULL;
+	}
+	return (const char *) hashtable_search(ftdmchan->variable_hash, (void *)var_name);
+}
+
+static struct {
+	ftdm_io_interface_t *pika_interface;
+} interfaces;
+
+
+FT_DECLARE(char *) ftdm_api_execute(const char *type, const char *cmd)
+{
+	ftdm_io_interface_t *fio = NULL;
+	char *dup = NULL, *p;
+	char *rval = NULL;
+
+	if (type && !cmd) {
+		dup = ftdm_strdup(type);
+		if ((p = strchr(dup, ' '))) {
+			*p++ = '\0';
+			cmd = p;
+		}
+
+		type = dup;
+	}
+	
+	ftdm_mutex_lock(globals.mutex);
+	if (!(fio = (ftdm_io_interface_t *) hashtable_search(globals.interface_hash, (void *)type))) {
+		ftdm_load_module_assume(type);
+		if ((fio = (ftdm_io_interface_t *) hashtable_search(globals.interface_hash, (void *)type))) {
+			ftdm_log(FTDM_LOG_INFO, "auto-loaded '%s'\n", type);
+		}
+	}
+	ftdm_mutex_unlock(globals.mutex);
+
+	if (fio && fio->api) {
+		ftdm_stream_handle_t stream = { 0 };
+		ftdm_status_t status;
+		FTDM_STANDARD_STREAM(stream);
+		status = fio->api(&stream, cmd);
+		
+		if (status != FTDM_SUCCESS) {
+			ftdm_safe_free(stream.data);
+		} else {
+			rval = (char *) stream.data;
+		}
+	}
+
+	ftdm_safe_free(dup);
+	
+	return rval;
+}
+
+
+static ftdm_status_t ftdm_group_add_channels(const char* name, ftdm_span_t* span, int currindex);
+static ftdm_status_t load_config(void)
+{
+	char cfg_name[] = "freetdm.conf";
+	ftdm_config_t cfg;
+	char *var, *val;
+	int catno = -1;
+	int currindex = 0;
+	ftdm_span_t *span = NULL;
+	unsigned configured = 0, d = 0;
+	char name[80] = "";
+	char number[25] = "";
+	char group_name[80] = "default";
+	ftdm_io_interface_t *fio = NULL;
+	ftdm_analog_start_type_t tmp;
+	ftdm_size_t len = 0;
+
+	if (!ftdm_config_open_file(&cfg, cfg_name)) {
+		return FTDM_FAIL;
+	}
+	
+	while (ftdm_config_next_pair(&cfg, &var, &val)) {
+		if (*cfg.category == '#') {
+			if (cfg.catno != catno) {
+				ftdm_log(FTDM_LOG_DEBUG, "Skipping %s\n", cfg.category);
+				catno = cfg.catno;
+			}
+		} else if (!strncasecmp(cfg.category, "span", 4)) {
+			if (cfg.catno != catno) {
+				char *type = cfg.category + 4;
+				char *name;
+				
+				if (*type == ' ') {
+					type++;
+				}
+				
+				ftdm_log(FTDM_LOG_DEBUG, "found config for span\n");
+				catno = cfg.catno;
+				
+				if (ftdm_strlen_zero(type)) {
+					ftdm_log(FTDM_LOG_CRIT, "failure creating span, no type specified.\n");
+					span = NULL;
+					continue;
+				}
+
+				if ((name = strchr(type, ' '))) {
+					*name++ = '\0';
+				}
+
+				ftdm_mutex_lock(globals.mutex);
+				if (!(fio = (ftdm_io_interface_t *) hashtable_search(globals.interface_hash, type))) {
+					ftdm_load_module_assume(type);
+					if ((fio = (ftdm_io_interface_t *) hashtable_search(globals.interface_hash, type))) {
+						ftdm_log(FTDM_LOG_INFO, "auto-loaded '%s'\n", type);
+					}
+				}
+				ftdm_mutex_unlock(globals.mutex);
+
+				if (!fio) {
+					ftdm_log(FTDM_LOG_CRIT, "failure creating span, no such type '%s'\n", type);
+					span = NULL;
+					continue;
+				}
+
+				if (!fio->configure_span) {
+					ftdm_log(FTDM_LOG_CRIT, "failure creating span, no configure_span method for '%s'\n", type);
+					span = NULL;
+					continue;
+				}
+
+				if (ftdm_span_create(fio, &span, name) == FTDM_SUCCESS) {
+					span->type = ftdm_strdup(type);
+					d = 0;
+
+					ftdm_log(FTDM_LOG_DEBUG, "created span %d (%s) of type %s\n", span->span_id, span->name, type);
+					
+				} else {
+					ftdm_log(FTDM_LOG_CRIT, "failure creating span of type %s\n", type);
+					span = NULL;
+					continue;
+				}
+			}
+
+			if (!span) {
+				continue;
+			}
+
+			ftdm_log(FTDM_LOG_DEBUG, "span %d [%s]=[%s]\n", span->span_id, var, val);
+			
+			if (!strcasecmp(var, "trunk_type")) {
+				span->trunk_type = ftdm_str2ftdm_trunk_type(val);
+				ftdm_log(FTDM_LOG_DEBUG, "setting trunk type to '%s'\n", ftdm_trunk_type2str(span->trunk_type)); 
+			} else if (!strcasecmp(var, "name")) {
+				if (!strcasecmp(val, "undef")) {
+					*name = '\0';
+				} else {
+					ftdm_copy_string(name, val, sizeof(name));
+				}
+			} else if (!strcasecmp(var, "number")) {
+				if (!strcasecmp(val, "undef")) {
+					*number = '\0';
+				} else {
+					ftdm_copy_string(number, val, sizeof(number));
+				}
+			} else if (!strcasecmp(var, "analog-start-type")) {
+				if (span->trunk_type == FTDM_TRUNK_FXS || span->trunk_type == FTDM_TRUNK_FXO || span->trunk_type == FTDM_TRUNK_EM) {
+					if ((tmp = ftdm_str2ftdm_analog_start_type(val)) != FTDM_ANALOG_START_NA) {
+						span->start_type = tmp;
+						ftdm_log(FTDM_LOG_DEBUG, "changing start type to '%s'\n", ftdm_analog_start_type2str(span->start_type)); 
+					}
+				} else {
+					ftdm_log(FTDM_LOG_ERROR, "This option is only valid on analog trunks!\n");
+				}
+			} else if (!strcasecmp(var, "fxo-channel")) {
+				if (span->trunk_type == FTDM_TRUNK_NONE) {
+					span->trunk_type = FTDM_TRUNK_FXO;										
+					ftdm_log(FTDM_LOG_DEBUG, "setting trunk type to '%s' start(%s)\n", ftdm_trunk_type2str(span->trunk_type), 
+							ftdm_analog_start_type2str(span->start_type));
+				}
+				if (span->trunk_type == FTDM_TRUNK_FXO) {
+					currindex = span->chan_count;
+					configured += fio->configure_span(span, val, FTDM_CHAN_TYPE_FXO, name, number);
+					ftdm_group_add_channels(group_name, span, currindex);
+				} else {
+					ftdm_log(FTDM_LOG_WARNING, "Cannot add FXO channels to an FXS trunk!\n");
+				}
+			} else if (!strcasecmp(var, "fxs-channel")) {
+				if (span->trunk_type == FTDM_TRUNK_NONE) {
+					span->trunk_type = FTDM_TRUNK_FXS;
+					ftdm_log(FTDM_LOG_DEBUG, "setting trunk type to '%s' start(%s)\n", ftdm_trunk_type2str(span->trunk_type), 
+							ftdm_analog_start_type2str(span->start_type));
+				}
+				if (span->trunk_type == FTDM_TRUNK_FXS) {
+					currindex = span->chan_count;
+					configured += fio->configure_span(span, val, FTDM_CHAN_TYPE_FXS, name, number);
+					ftdm_group_add_channels(group_name, span, currindex);
+				} else {
+					ftdm_log(FTDM_LOG_WARNING, "Cannot add FXS channels to an FXO trunk!\n");
+				}
+			} else if (!strcasecmp(var, "em-channel")) {
+				if (span->trunk_type == FTDM_TRUNK_NONE) {
+					span->trunk_type = FTDM_TRUNK_EM;
+					ftdm_log(FTDM_LOG_DEBUG, "setting trunk type to '%s' start(%s)\n", ftdm_trunk_type2str(span->trunk_type), 
+							ftdm_analog_start_type2str(span->start_type));
+				}
+				if (span->trunk_type == FTDM_TRUNK_EM) {
+					currindex = span->chan_count;
+					configured += fio->configure_span(span, val, FTDM_CHAN_TYPE_EM, name, number);
+					ftdm_group_add_channels(group_name, span, currindex);
+				} else {
+					ftdm_log(FTDM_LOG_WARNING, "Cannot add EM channels to a non-EM trunk!\n");
+				}
+			} else if (!strcasecmp(var, "b-channel")) {
+				currindex = span->chan_count;
+				configured += fio->configure_span(span, val, FTDM_CHAN_TYPE_B, name, number);
+				ftdm_group_add_channels(group_name, span, currindex);
+			} else if (!strcasecmp(var, "d-channel")) {
+				if (d) {
+					ftdm_log(FTDM_LOG_WARNING, "ignoring extra d-channel\n");
+				} else {
+					ftdm_chan_type_t qtype;
+					if (!strncasecmp(val, "lapd:", 5)) {
+						qtype = FTDM_CHAN_TYPE_DQ931;
+						val += 5;
+					} else {
+						qtype = FTDM_CHAN_TYPE_DQ921;
+					}
+					configured += fio->configure_span(span, val, qtype, name, number);
+					d++;
+				}
+			} else if (!strcasecmp(var, "cas-channel")) {
+				currindex = span->chan_count;
+				configured += fio->configure_span(span, val, FTDM_CHAN_TYPE_CAS, name, number);	
+				ftdm_group_add_channels(group_name, span, currindex);
+			} else if (!strcasecmp(var, "dtmf_hangup")) {
+				span->dtmf_hangup = ftdm_strdup(val);
+				span->dtmf_hangup_len = strlen(val);
+			} else if (!strcasecmp(var, "group")) {
+				len = strlen(val);
+				if (len >= sizeof(group_name)) {
+					len = sizeof(group_name) - 1;
+					ftdm_log(FTDM_LOG_WARNING, "Truncating group name %s to %zd length\n", val, len);
+				}
+				memcpy(group_name, val, len);
+				group_name[len] = '\0';
+			} else {
+				ftdm_log(FTDM_LOG_ERROR, "unknown span variable '%s'\n", var);
+			}
+		} else {
+			ftdm_log(FTDM_LOG_ERROR, "unknown param [%s] '%s' / '%s'\n", cfg.category, var, val);
+		}
+	}
+	ftdm_config_close_file(&cfg);
+
+	ftdm_log(FTDM_LOG_INFO, "Configured %u channel(s)\n", configured);
+	
+	return configured ? FTDM_SUCCESS : FTDM_FAIL;
+}
+
+static ftdm_status_t process_module_config(ftdm_io_interface_t *fio)
+{
+	ftdm_config_t cfg;
+	char *var, *val;
+	char filename[256] = "";
+	
+	ftdm_assert_return(fio != NULL, FTDM_FAIL, "fio argument is null\n");
+
+	snprintf(filename, sizeof(filename), "%s.conf", fio->name);
+
+	if (!fio->configure) {
+		ftdm_log(FTDM_LOG_DEBUG, "Module %s does not support configuration.\n", fio->name);	
+		return FTDM_FAIL;
+	}
+
+	if (!ftdm_config_open_file(&cfg, filename)) {
+		ftdm_log(FTDM_LOG_ERROR, "Cannot open %s\n", filename);	
+		return FTDM_FAIL;
+	}
+
+	while (ftdm_config_next_pair(&cfg, &var, &val)) {
+		fio->configure(cfg.category, var, val, cfg.lineno);
+	}
+
+	ftdm_config_close_file(&cfg);	
+
+	return FTDM_SUCCESS;
+}
+
+FT_DECLARE(char *) ftdm_build_dso_path(const char *name, char *path, ftdm_size_t len)
+{
+#ifdef WIN32
+    const char *ext = ".dll";
+    //const char *EXT = ".DLL";
+#define FTDM_MOD_DIR "." //todo
+#elif defined (MACOSX) || defined (DARWIN)
+    const char *ext = ".dylib";
+    //const char *EXT = ".DYLIB";
+#else
+    const char *ext = ".so";
+    //const char *EXT = ".SO";
+#endif
+	if (*name == *FTDM_PATH_SEPARATOR) {
+		snprintf(path, len, "%s%s", name, ext);
+	} else {
+		snprintf(path, len, "%s%s%s%s", FTDM_MOD_DIR, FTDM_PATH_SEPARATOR, name, ext);
+	}
+	return path;	
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_global_add_io_interface(ftdm_io_interface_t *interface1)
+{
+	ftdm_status_t ret = FTDM_SUCCESS;
+	ftdm_mutex_lock(globals.mutex);
+	if (hashtable_search(globals.interface_hash, (void *)interface1->name)) {
+		ftdm_log(FTDM_LOG_ERROR, "Interface %s already loaded!\n", interface1->name);
+	} else {
+		hashtable_insert(globals.interface_hash, (void *)interface1->name, interface1, HASHTABLE_FLAG_NONE);
+	}
+	ftdm_mutex_unlock(globals.mutex);
+	return ret;
+}
+
+FT_DECLARE(int) ftdm_load_module(const char *name)
+{
+	ftdm_dso_lib_t lib;
+	int count = 0, x = 0;
+	char path[128] = "";
+	char *err;
+	ftdm_module_t *mod;
+
+	ftdm_build_dso_path(name, path, sizeof(path));
+
+	if (!(lib = ftdm_dso_open(path, &err))) {
+		ftdm_log(FTDM_LOG_ERROR, "Error loading %s [%s]\n", path, err);
+		ftdm_safe_free(err);
+		return 0;
+	}
+	
+	if (!(mod = (ftdm_module_t *) ftdm_dso_func_sym(lib, "ftdm_module", &err))) {
+		ftdm_log(FTDM_LOG_ERROR, "Error loading %s [%s]\n", path, err);
+		ftdm_safe_free(err);
+		return 0;
+	}
+
+	if (mod->io_load) {
+		ftdm_io_interface_t *interface1 = NULL; /* name conflict w/windows here */
+
+		if (mod->io_load(&interface1) != FTDM_SUCCESS || !interface1 || !interface1->name) {
+			ftdm_log(FTDM_LOG_ERROR, "Error loading %s\n", path);
+		} else {
+			ftdm_log(FTDM_LOG_INFO, "Loading IO from %s [%s]\n", path, interface1->name);
+			if (ftdm_global_add_io_interface(interface1) == FTDM_SUCCESS) {
+				process_module_config(interface1);
+				x++;
+			}
+		}
+	}
+
+	if (mod->sig_load) {
+		if (mod->sig_load() != FTDM_SUCCESS) {
+			ftdm_log(FTDM_LOG_ERROR, "Error loading %s\n", path);
+		} else {
+			ftdm_log(FTDM_LOG_INFO, "Loading SIG from %s\n", path);
+			x++;
+		}
+	}
+
+	if (x) {
+		char *p;
+		mod->lib = lib;
+		ftdm_set_string(mod->path, path);
+		if (mod->name[0] == '\0') {
+			if (!(p = strrchr(path, *FTDM_PATH_SEPARATOR))) {
+				p = path;
+			}
+			ftdm_set_string(mod->name, p);
+		}
+
+		ftdm_mutex_lock(globals.mutex);
+		if (hashtable_search(globals.module_hash, (void *)mod->name)) {
+			ftdm_log(FTDM_LOG_ERROR, "Module %s already loaded!\n", mod->name);
+			ftdm_dso_destroy(&lib);
+		} else {
+			hashtable_insert(globals.module_hash, (void *)mod->name, mod, HASHTABLE_FLAG_NONE);
+			count++;
+		}
+		ftdm_mutex_unlock(globals.mutex);
+	} else {
+		ftdm_log(FTDM_LOG_ERROR, "Unloading %s\n", path);
+		ftdm_dso_destroy(&lib);
+	}
+	
+	return count;
+}
+
+FT_DECLARE(int) ftdm_load_module_assume(const char *name)
+{
+	char buf[256] = "";
+
+	snprintf(buf, sizeof(buf), "ftmod_%s", name);
+	return ftdm_load_module(buf);
+}
+
+FT_DECLARE(int) ftdm_load_modules(void)
+{
+	char cfg_name[] = "modules.conf";
+	ftdm_config_t cfg;
+	char *var, *val;
+	int count = 0;
+
+	if (!ftdm_config_open_file(&cfg, cfg_name)) {
+        return FTDM_FAIL;
+    }
+
+	while (ftdm_config_next_pair(&cfg, &var, &val)) {
+        if (!strcasecmp(cfg.category, "modules")) {
+			if (!strcasecmp(var, "load")) {
+				count += ftdm_load_module(val);
+			}
+		}
+	}
+			
+	return count;
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_unload_modules(void)
+{
+	ftdm_hash_iterator_t *i = NULL;
+	ftdm_dso_lib_t lib = NULL;
+	char modpath[255] = { 0 };
+
+	/* stop signaling interfaces first as signaling depends on I/O and not the other way around */
+	for (i = hashtable_first(globals.module_hash); i; i = hashtable_next(i)) {
+		const void *key = NULL;
+		void *val = NULL;
+		ftdm_module_t *mod = NULL;
+
+		hashtable_this(i, &key, NULL, &val);
+		
+		if (!key || !val) {
+			continue;
+		}
+		
+		mod = (ftdm_module_t *) val;
+
+		if (!mod->sig_unload) {
+			continue;
+		}
+
+		ftdm_log(FTDM_LOG_INFO, "Unloading signaling interface %s\n", mod->name);
+		
+		if (mod->sig_unload() != FTDM_SUCCESS) {
+			ftdm_log(FTDM_LOG_ERROR, "Error unloading signaling interface %s\n", mod->name);
+			continue;
+		}
+
+		ftdm_log(FTDM_LOG_INFO, "Unloaded signaling interface %s\n", mod->name);
+	}
+
+	/* Now go ahead with I/O interfaces */
+	for (i = hashtable_first(globals.module_hash); i; i = hashtable_next(i)) {
+		const void *key = NULL;
+		void *val = NULL;
+		ftdm_module_t *mod = NULL;
+
+		hashtable_this(i, &key, NULL, &val);
+		
+		if (!key || !val) {
+			continue;
+		}
+		
+		mod = (ftdm_module_t *) val;
+
+		if (!mod->io_unload) {
+			continue;
+		}
+
+		ftdm_log(FTDM_LOG_INFO, "Unloading I/O interface %s\n", mod->name);
+		
+		if (mod->io_unload() != FTDM_SUCCESS) {
+			ftdm_log(FTDM_LOG_ERROR, "Error unloading I/O interface %s\n", mod->name);
+			continue;
+		}
+
+		ftdm_log(FTDM_LOG_INFO, "Unloaded I/O interface %s\n", mod->name);
+	}
+
+	/* Now unload the actual shared object/dll */
+	for (i = hashtable_first(globals.module_hash); i; i = hashtable_next(i)) {
+		ftdm_module_t *mod = NULL;
+		const void *key = NULL;
+		void *val = NULL;
+
+		hashtable_this(i, &key, NULL, &val);
+
+		if (!key || !val) {
+			continue;
+		}
+
+		mod = (ftdm_module_t *) val;
+
+		lib = mod->lib;
+		snprintf(modpath, sizeof(modpath), "%s", mod->path);
+		ftdm_log(FTDM_LOG_INFO, "Unloading module %s\n", modpath);
+		ftdm_dso_destroy(&lib);
+		ftdm_log(FTDM_LOG_INFO, "Unloaded module %s\n", modpath);
+	}
+
+	return FTDM_SUCCESS;
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_configure_span(const char *type, ftdm_span_t *span, fio_signal_cb_t sig_cb, ...)
+{
+	ftdm_module_t *mod = (ftdm_module_t *) hashtable_search(globals.module_hash, (void *)type);
+	ftdm_status_t status = FTDM_FAIL;
+
+	if (!mod) {
+		ftdm_load_module_assume(type);
+		if ((mod = (ftdm_module_t *) hashtable_search(globals.module_hash, (void *)type))) {
+			ftdm_log(FTDM_LOG_INFO, "auto-loaded '%s'\n", type);
+		}
+	}
+
+	if (mod && mod->sig_configure) {
+		va_list ap;
+		va_start(ap, sig_cb);
+		status = mod->sig_configure(span, sig_cb, ap);
+		va_end(ap);
+	} else {
+		ftdm_log(FTDM_LOG_ERROR, "can't find '%s'\n", type);
+		status = FTDM_FAIL;
+	}
+
+	return status;
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_configure_span_signaling(const char *type, ftdm_span_t *span, fio_signal_cb_t sig_cb, ftdm_conf_parameter_t *parameters) 
+{
+	ftdm_module_t *mod = (ftdm_module_t *) hashtable_search(globals.module_hash, (void *)type);
+	ftdm_status_t status = FTDM_FAIL;
+
+	ftdm_assert_return(type != NULL, FTDM_FAIL, "No signaling type");
+	ftdm_assert_return(span != NULL, FTDM_FAIL, "No span");
+	ftdm_assert_return(sig_cb != NULL, FTDM_FAIL, "No signaling callback");
+	ftdm_assert_return(parameters != NULL, FTDM_FAIL, "No parameters");
+
+	if (!mod) {
+		ftdm_load_module_assume(type);
+		if ((mod = (ftdm_module_t *) hashtable_search(globals.module_hash, (void *)type))) {
+			ftdm_log(FTDM_LOG_INFO, "auto-loaded '%s'\n", type);
+		}
+	}
+
+	if (!mod) {
+		ftdm_log(FTDM_LOG_ERROR, "Failed to load module type: %s\n", type);
+		return FTDM_FAIL;
+	}
+
+	if (mod->configure_span_signaling) {
+		status = mod->configure_span_signaling(span, sig_cb, parameters);
+	} else {
+		ftdm_log(FTDM_LOG_ERROR, "Module %s did not implement the signaling configuration method\n", type);
+	}
+
+	return status;
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_span_start(ftdm_span_t *span)
+{
+	if (span->start) {
+		return span->start(span);
+	}
+
+	return FTDM_FAIL;
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_channel_add_to_group(const char* name, ftdm_channel_t* ftdmchan)
+{
+	unsigned int i;
+	ftdm_group_t* group = NULL;
+	
+	ftdm_mutex_lock(globals.group_mutex);
+
+	ftdm_assert_return(ftdmchan != NULL, FTDM_FAIL, "Cannot add a null channel to a group\n");
+
+	if (ftdm_group_find_by_name(name, &group) != FTDM_SUCCESS) {
+		ftdm_log(FTDM_LOG_DEBUG, "Creating new group:%s\n", name);
+		ftdm_group_create(&group, name);
+	}
+
+	/*verify that group does not already include this channel first */
+	for(i = 0; i < group->chan_count; i++) {
+		if (group->channels[i]->physical_span_id == ftdmchan->physical_span_id &&
+				group->channels[i]->physical_chan_id == ftdmchan->physical_chan_id) {
+
+			ftdm_mutex_unlock(globals.group_mutex);
+			ftdm_log(FTDM_LOG_DEBUG, "Channel %d:%d is already added to group %s\n", 
+					group->channels[i]->physical_span_id,
+					group->channels[i]->physical_chan_id,
+					name);
+			return FTDM_SUCCESS;
+		}
+	}
+
+	if (group->chan_count >= FTDM_MAX_CHANNELS_GROUP) {
+		ftdm_log(FTDM_LOG_ERROR, "Max number of channels exceeded (max:%d)\n", FTDM_MAX_CHANNELS_GROUP);
+		ftdm_mutex_unlock(globals.group_mutex);
+		return FTDM_FAIL;
+	}
+
+	group->channels[group->chan_count++] = ftdmchan;
+	ftdm_mutex_unlock(globals.group_mutex);
+	return FTDM_SUCCESS;
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_channel_remove_from_group(ftdm_group_t* group, ftdm_channel_t* ftdmchan)
+{
+	unsigned int i, j;
+	//Need to test this function
+	ftdm_mutex_lock(globals.group_mutex);
+
+	for (i=0; i < group->chan_count; i++) {
+			if (group->channels[i]->physical_span_id == ftdmchan->physical_span_id &&
+					group->channels[i]->physical_chan_id == ftdmchan->physical_chan_id) {
+
+				j=i;
+				while(j < group->chan_count-1) {
+					group->channels[j] = group->channels[j+1];
+					j++;
+				}
+				group->channels[group->chan_count--] = NULL;
+				if (group->chan_count <=0) {
+					/* Delete group if it is empty */
+					hashtable_remove(globals.group_hash, (void *)group->name);
+				}
+				ftdm_mutex_unlock(globals.group_mutex);
+				return FTDM_SUCCESS;
+			}
+	}
+
+	ftdm_mutex_unlock(globals.group_mutex);
+	//Group does not contain this channel
+	return FTDM_FAIL;
+}
+
+static ftdm_status_t ftdm_group_add_channels(const char* name, ftdm_span_t* span, int currindex)
+{
+	unsigned chan_index = 0;
+
+	ftdm_assert_return(strlen(name) > 0, FTDM_FAIL, "Invalid group name provided\n");
+	ftdm_assert_return(currindex >= 0, FTDM_FAIL, "Invalid current channel index provided\n");
+
+	if (!span->chan_count) {
+		return FTDM_SUCCESS;
+	}
+
+	for (chan_index = currindex+1; chan_index <= span->chan_count; chan_index++) {
+		if (!FTDM_IS_VOICE_CHANNEL(span->channels[chan_index])) {
+			continue;
+		}
+		if (ftdm_channel_add_to_group(name, span->channels[chan_index])) {
+			ftdm_log(FTDM_LOG_ERROR, "Failed to add chan:%d to group:%s\n", chan_index, name);
+		}
+	}
+	return FTDM_SUCCESS;
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_group_find(uint32_t id, ftdm_group_t **group)
+{
+	ftdm_group_t *fgroup = NULL, *grp;
+
+	if (id > FTDM_MAX_GROUPS_INTERFACE) {
+		return FTDM_FAIL;
+	}
+
+	
+	ftdm_mutex_lock(globals.group_mutex);
+	for (grp = globals.groups; grp; grp = grp->next) {
+		if (grp->group_id == id) {
+			fgroup = grp;
+			break;
+		}
+	}
+	ftdm_mutex_unlock(globals.group_mutex);
+
+	if (!fgroup) {
+		return FTDM_FAIL;
+	}
+
+	*group = fgroup;
+
+	return FTDM_SUCCESS;
+	
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_group_find_by_name(const char *name, ftdm_group_t **group)
+{
+	ftdm_status_t status = FTDM_FAIL;
+	*group = NULL;
+	ftdm_mutex_lock(globals.group_mutex);
+	if (!ftdm_strlen_zero(name)) {
+		if ((*group = hashtable_search(globals.group_hash, (void *) name))) {
+			status = FTDM_SUCCESS;
+		}
+	}
+	ftdm_mutex_unlock(globals.group_mutex);
+	return status;
+}
+
+static void ftdm_group_add(ftdm_group_t *group)
+{
+	ftdm_group_t *grp;
+	ftdm_mutex_lock(globals.group_mutex);
+	
+	for (grp = globals.groups; grp && grp->next; grp = grp->next);
+
+	if (grp) {
+		grp->next = group;
+	} else {
+		globals.groups = group;
+	}
+	hashtable_insert(globals.group_hash, (void *)group->name, group, HASHTABLE_FLAG_NONE);
+
+	ftdm_mutex_unlock(globals.group_mutex);
+}
+
+
+FT_DECLARE(ftdm_status_t) ftdm_group_create(ftdm_group_t **group, const char *name)
+{
+	ftdm_group_t *new_group = NULL;
+	ftdm_status_t status = FTDM_FAIL;
+
+	ftdm_mutex_lock(globals.mutex);
+	if (globals.group_index < FTDM_MAX_GROUPS_INTERFACE) {
+		new_group = ftdm_calloc(1, sizeof(*new_group));
+		
+		ftdm_assert(new_group != NULL, "Failed to create new ftdm group, expect a crash\n");
+
+		status = ftdm_mutex_create(&new_group->mutex);
+
+		ftdm_assert(status == FTDM_SUCCESS, "Failed to create group mutex, expect a crash\n");
+
+		new_group->group_id = ++globals.group_index;
+		new_group->name = ftdm_strdup(name);
+		ftdm_group_add(new_group);
+		*group = new_group;
+		status = FTDM_SUCCESS;
+	} else {
+		ftdm_log(FTDM_LOG_ERROR, "Group %s was not added, we exceeded the max number of groups\n", name);
+	}
+	ftdm_mutex_unlock(globals.mutex);
+	return status;
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_span_send_signal(ftdm_span_t *span, ftdm_sigmsg_t *sigmsg)
+{
+	ftdm_status_t status = FTDM_FAIL;
+
+	if (span->signal_cb) {
+		if (sigmsg->channel) {
+			ftdm_mutex_lock(sigmsg->channel->mutex);
+		}
+
+		status = span->signal_cb(sigmsg);
+
+		if (sigmsg->channel) {
+			ftdm_mutex_unlock(sigmsg->channel->mutex);
+		}
+	}
+
+	return status;
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_global_init(void)
+{
+	memset(&globals, 0, sizeof(globals));
+
+	time_init();
+	
+	ftdm_thread_override_default_stacksize(FTDM_THREAD_STACKSIZE);
+
+	memset(&interfaces, 0, sizeof(interfaces));
+	globals.interface_hash = create_hashtable(16, ftdm_hash_hashfromstring, ftdm_hash_equalkeys);
+	globals.module_hash = create_hashtable(16, ftdm_hash_hashfromstring, ftdm_hash_equalkeys);
+	globals.span_hash = create_hashtable(16, ftdm_hash_hashfromstring, ftdm_hash_equalkeys);
+	globals.group_hash = create_hashtable(16, ftdm_hash_hashfromstring, ftdm_hash_equalkeys);
+	ftdm_mutex_create(&globals.mutex);
+	ftdm_mutex_create(&globals.span_mutex);
+	ftdm_mutex_create(&globals.group_mutex);
+	globals.running = 1;
+	return FTDM_SUCCESS;
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_global_configuration(void)
+{
+	int modcount = ftdm_load_modules();
+	ftdm_log(FTDM_LOG_NOTICE, "Modules configured: %d \n", modcount);
+
+	if (load_config() != FTDM_SUCCESS) {
+		globals.running = 0;
+		ftdm_log(FTDM_LOG_ERROR, "FreeTDM global configuration failed!\n");
+		return FTDM_FAIL;
+	}
+	return FTDM_SUCCESS;
+}
+
+FT_DECLARE(uint32_t) ftdm_running(void)
+{
+	return globals.running;
+}
+
+
+FT_DECLARE(ftdm_status_t) ftdm_global_destroy(void)
+{
+	ftdm_span_t *sp;
+
+	time_end();
+
+	globals.running = 0;	
+
+	globals.span_index = 0;
+
+	ftdm_span_close_all();
+	
+	ftdm_mutex_lock(globals.span_mutex);
+	for (sp = globals.spans; sp;) {
+		ftdm_span_t *cur_span = sp;
+		sp = sp->next;
+
+		if (cur_span) {
+			if (ftdm_test_flag(cur_span, FTDM_SPAN_CONFIGURED)) {
+				ftdm_span_destroy(cur_span);
+			}
+
+			hashtable_remove(globals.span_hash, (void *)cur_span->name);
+			ftdm_safe_free(cur_span->type);
+			ftdm_safe_free(cur_span->name);
+			ftdm_safe_free(cur_span);
+			cur_span = NULL;
+		}
+	}
+	globals.spans = NULL;
+	ftdm_mutex_unlock(globals.span_mutex);
+
+	ftdm_unload_modules();
+
+	ftdm_mutex_lock(globals.mutex);
+	hashtable_destroy(globals.interface_hash);
+	hashtable_destroy(globals.module_hash);
+	hashtable_destroy(globals.span_hash);
+	ftdm_mutex_unlock(globals.mutex);
+	ftdm_mutex_destroy(&globals.mutex);
+	ftdm_mutex_destroy(&globals.span_mutex);
+
+	memset(&globals, 0, sizeof(globals));
+	return FTDM_SUCCESS;
+}
+
+
+FT_DECLARE(uint32_t) ftdm_separate_string(char *buf, char delim, char **array, int arraylen)
+{
+	int argc;
+	char *ptr;
+	int quot = 0;
+	char qc = '\'';
+	int x;
+
+	if (!buf || !array || !arraylen) {
+		return 0;
+	}
+
+	memset(array, 0, arraylen * sizeof(*array));
+
+	ptr = buf;
+
+	for (argc = 0; *ptr && (argc < arraylen - 1); argc++) {
+		array[argc] = ptr;
+		for (; *ptr; ptr++) {
+			if (*ptr == qc) {
+				if (quot) {
+					quot--;
+				} else {
+					quot++;
+				}
+			} else if ((*ptr == delim) && !quot) {
+				*ptr++ = '\0';
+				break;
+			}
+		}
+	}
+
+	if (*ptr) {
+		array[argc++] = ptr;
+	}
+
+	/* strip quotes and leading / trailing spaces */
+	for (x = 0; x < argc; x++) {
+		char *p;
+
+		while(*(array[x]) == ' ') {
+			(array[x])++;
+		}
+		p = array[x];
+		while((p = strchr(array[x], qc))) {
+			memmove(p, p+1, strlen(p));
+			p++;
+		}
+		p = array[x] + (strlen(array[x]) - 1);
+		while(*p == ' ') {
+			*p-- = '\0';
+		}
+	}
+
+	return argc;
+}
+
+FT_DECLARE(void) ftdm_bitstream_init(ftdm_bitstream_t *bsp, uint8_t *data, uint32_t datalen, ftdm_endian_t endian, uint8_t ss)
+{
+	memset(bsp, 0, sizeof(*bsp));
+	bsp->data = data;
+	bsp->datalen = datalen;
+	bsp->endian = endian;
+	bsp->ss = ss;
+	
+	if (endian < 0) {
+		bsp->top = bsp->bit_index = 7;
+		bsp->bot = 0;
+	} else {
+		bsp->top = bsp->bit_index = 0;
+		bsp->bot = 7;
+	}
+
+}
+
+FT_DECLARE(int8_t) ftdm_bitstream_get_bit(ftdm_bitstream_t *bsp)
+{
+	int8_t bit = -1;
+	
+
+	if (bsp->byte_index >= bsp->datalen) {
+		goto done;
+	}
+
+	if (bsp->ss) {
+		if (!bsp->ssv) {
+			bsp->ssv = 1;
+			return 0;
+		} else if (bsp->ssv == 2) {
+			bsp->byte_index++;
+			bsp->ssv = 0;
+			return 1;
+		}
+	}
+
+
+
+
+	bit = (bsp->data[bsp->byte_index] >> (bsp->bit_index)) & 1;
+	
+	if (bsp->bit_index == bsp->bot) {
+		bsp->bit_index = bsp->top;
+		if (bsp->ss) {
+			bsp->ssv = 2;
+			goto done;
+		} 
+
+		if (++bsp->byte_index > bsp->datalen) {
+			bit = -1;
+			goto done;
+		}
+		
+	} else {
+		bsp->bit_index = bsp->bit_index + bsp->endian;
+	}
+
+
+ done:
+	return bit;
+}
+
+FT_DECLARE(void) print_hex_bytes(uint8_t *data, ftdm_size_t dlen, char *buf, ftdm_size_t blen)
+{
+	char *bp = buf;
+	uint8_t *byte = data;
+	uint32_t i, j = 0;
+
+	if (blen < (dlen * 3) + 2) {
+        return;
+    }
+
+	*bp++ = '[';
+	j++;
+
+	for(i = 0; i < dlen; i++) {
+		snprintf(bp, blen-j, "%02x ", *byte++);
+		bp += 3;
+		j += 3;
+	}
+
+	*--bp = ']';
+
+}
+
+FT_DECLARE(void) print_bits(uint8_t *b, int bl, char *buf, int blen, ftdm_endian_t e, uint8_t ss)
+{
+	ftdm_bitstream_t bs;
+	int j = 0, c = 0;
+	int8_t bit;
+	uint32_t last;
+
+	if (blen < (bl * 10) + 2) {
+        return;
+    }
+
+	ftdm_bitstream_init(&bs, b, bl, e, ss);
+	last = bs.byte_index;	
+	while((bit = ftdm_bitstream_get_bit(&bs)) > -1) {
+		buf[j++] = bit ? '1' : '0';
+		if (bs.byte_index != last) {
+			buf[j++] = ' ';
+			last = bs.byte_index;
+			if (++c == 8) {
+				buf[j++] = '\n';
+				c = 0;
+			}
+		}
+	}
+
+}
+
+
+
+FT_DECLARE_NONSTD(ftdm_status_t) ftdm_console_stream_raw_write(ftdm_stream_handle_t *handle, uint8_t *data, ftdm_size_t datalen)
+{
+	ftdm_size_t need = handle->data_len + datalen;
+	
+	if (need >= handle->data_size) {
+		void *new_data;
+		need += handle->alloc_chunk;
+
+		if (!(new_data = realloc(handle->data, need))) {
+			return FTDM_MEMERR;
+		}
+
+		handle->data = new_data;
+		handle->data_size = need;
+	}
+
+	memcpy((uint8_t *) (handle->data) + handle->data_len, data, datalen);
+	handle->data_len += datalen;
+	handle->end = (uint8_t *) (handle->data) + handle->data_len;
+	*(uint8_t *)handle->end = '\0';
+
+	return FTDM_SUCCESS;
+}
+
+FT_DECLARE(int) ftdm_vasprintf(char **ret, const char *fmt, va_list ap) /* code from switch_apr.c */
+{
+#ifdef HAVE_VASPRINTF
+	return vasprintf(ret, fmt, ap);
+#else
+	char *buf;
+	int len;
+	size_t buflen;
+	va_list ap2;
+	char *tmp = NULL;
+
+#ifdef _MSC_VER
+#if _MSC_VER >= 1500
+	/* hack for incorrect assumption in msvc header files for code analysis */
+	__analysis_assume(tmp);
+#endif
+	ap2 = ap;
+#else
+	va_copy(ap2, ap);
+#endif
+
+	len = vsnprintf(tmp, 0, fmt, ap2);
+
+	if (len > 0 && (buf = ftdm_malloc((buflen = (size_t) (len + 1)))) != NULL) {
+		len = vsnprintf(buf, buflen, fmt, ap);
+		*ret = buf;
+	} else {
+		*ret = NULL;
+		len = -1;
+	}
+
+	va_end(ap2);
+	return len;
+#endif
+}
+
+FT_DECLARE_NONSTD(ftdm_status_t) ftdm_console_stream_write(ftdm_stream_handle_t *handle, const char *fmt, ...)
+{
+	va_list ap;
+	char *buf = handle->data;
+	char *end = handle->end;
+	int ret = 0;
+	char *data = NULL;
+
+	if (handle->data_len >= handle->data_size) {
+		return FTDM_FAIL;
+	}
+
+	va_start(ap, fmt);
+	ret = ftdm_vasprintf(&data, fmt, ap);
+	va_end(ap);
+
+	if (data) {
+		ftdm_size_t remaining = handle->data_size - handle->data_len;
+		ftdm_size_t need = strlen(data) + 1;
+
+		if ((remaining < need) && handle->alloc_len) {
+			ftdm_size_t new_len;
+			void *new_data;
+
+			new_len = handle->data_size + need + handle->alloc_chunk;
+			if ((new_data = realloc(handle->data, new_len))) {
+				handle->data_size = handle->alloc_len = new_len;
+				handle->data = new_data;
+				buf = handle->data;
+				remaining = handle->data_size - handle->data_len;
+				handle->end = (uint8_t *) (handle->data) + handle->data_len;
+				end = handle->end;
+			} else {
+				ftdm_log(FTDM_LOG_CRIT, "Memory Error!\n");
+				ftdm_safe_free(data);
+				return FTDM_FAIL;
+			}
+		}
+
+		if (remaining < need) {
+			ret = -1;
+		} else {
+			ret = 0;
+			snprintf(end, remaining, "%s", data);
+			handle->data_len = strlen(buf);
+			handle->end = (uint8_t *) (handle->data) + handle->data_len;
+		}
+		ftdm_safe_free(data);
+	}
+
+	return ret ? FTDM_FAIL : FTDM_SUCCESS;
+}
+
+FT_DECLARE(char *) ftdm_strdup(const char *str)
+{
+	ftdm_size_t len = strlen(str) + 1;
+	void *new = ftdm_malloc(len);
+
+	if (!new) {
+		return NULL;
+	}
+
+	return (char *)memcpy(new, str, len);
+}
+
+FT_DECLARE(char *) ftdm_strndup(const char *str, ftdm_size_t inlen)
+{
+	char *new = NULL;
+	ftdm_size_t len = strlen(str) + 1;
+	if (len > (inlen+1)) {
+		len = inlen+1;
+	}
+	new = (char *)ftdm_malloc(len);
+
+	if (!new) {
+		return NULL;
+	}
+	
+	memcpy(new, str, len-1);
+	new[len-1] = 0;
+	return new;
+}
+
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */

Added: freeswitch/trunk/libs/freetdm/src/ftdm_m3ua.c (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/ftdm_m3ua.c	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/ftdm_m3ua.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,692 @@
+/*
+ *  ftdm_m3ua.c
+ *  freetdm
+ *
+ *  Created by Shane Burrell on 4/3/08.
+ *  Copyright 2008 Shane Burrell. All rights reserved.
+ *
+ * 
+ * Copyright (c) 2007, Anthony Minessale II, Nenad Corbic * 
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#include "freetdm.h"
+#include "m3ua_client.h"
+#include "ftdm_m3ua.h"
+
+#define MAX_REQ_ID MAX_PENDING_CALLS
+typedef uint16_t m3ua_request_id_t;
+
+typedef enum {
+	BST_FREE,
+	BST_WAITING,
+	BST_READY,
+	BST_FAIL
+} m3ua_request_status_t;
+
+typedef struct {
+	m3ua_request_status_t status;
+	m3uac_event_t event;
+	ftdm_span_t *span;
+	ftdm_channel_t *ftdmchan;
+} m3ua_request_t;
+
+
+struct general_config {
+	uint32_t region;
+};
+typedef struct general_config general_config_t;
+
+
+struct m3ua_channel_profile {
+	char name[80];
+	int cust_span;
+	unsigned char opc[3];
+	unsigned char dpc[3];
+	int local_ip[4];
+	int local_port;
+	int remote_ip[4];
+	int remote_port;
+	int m3ua_mode;
+};
+typedef struct m3ua_channel_profile m3ua_channel_profile_t;
+
+static struct {
+	ftdm_hash_t *profile_hash;
+	general_config_t general_config;
+} globals;
+
+struct m3ua_span_data {
+	uint32_t boardno;
+	uint32_t flags;
+};
+typedef struct m3ua_span_data m3ua_span_data_t;
+
+struct m3ua_chan_data {
+	ftdm_buffer_t *digit_buffer;
+	ftdm_mutex_t *digit_mutex;
+	ftdm_size_t dtmf_len;
+	uint32_t flags;
+	uint32_t hdlc_bytes;
+};
+typedef struct m3ua_chan_data m3ua_chan_data_t;
+
+static ftdm_mutex_t *request_mutex = NULL;
+static ftdm_mutex_t *signal_mutex = NULL;
+
+static uint8_t req_map[MAX_REQ_ID+1] = { 0 };
+
+static void release_request_id(m3ua_request_id_t r)
+{
+	ftdm_mutex_lock(request_mutex);
+	req_map[r] = 0;
+	ftdm_mutex_unlock(request_mutex);
+}
+
+/*static m3ua_request_id_t next_request_id(void)
+{
+	m3ua_request_id_t r = 0;
+	int ok = 0;
+	
+	while(!ok) {
+		ftdm_mutex_lock(request_mutex);
+		for (r = 1; r <= MAX_REQ_ID; r++) {
+			if (!req_map[r]) {
+				ok = 1;
+				req_map[r] = 1;
+				break;
+			}
+		}
+		ftdm_mutex_unlock(request_mutex);
+		if (!ok) {
+			ftdm_sleep(5);
+		}
+	}
+	return r;
+}
+*/
+
+static __inline__ void state_advance(ftdm_channel_t *ftdmchan)
+{
+
+	m3ua_data_t *m3ua_data = ftdmchan->span->signal_data;
+	m3uac_connection_t *mcon = &m3ua_data->mcon;
+	ftdm_sigmsg_t sig;
+	ftdm_status_t status;
+
+	ftdm_log(FTDM_LOG_DEBUG, "%d:%d STATE [%s]\n", ftdmchan->span_id, ftdmchan->chan_id, ftdm_channel_state2str(ftdmchan->state));
+	
+	memset(&sig, 0, sizeof(sig));
+	sig.chan_id = ftdmchan->chan_id;
+	sig.span_id = ftdmchan->span_id;
+	sig.channel = ftdmchan;
+
+	switch (ftdmchan->state) {
+	case FTDM_CHANNEL_STATE_DOWN:
+		{
+			if (ftdmchan->extra_id) {
+				release_request_id((m3ua_request_id_t)ftdmchan->extra_id);
+				ftdmchan->extra_id = 0;
+			}
+			ftdm_channel_done(ftdmchan);			
+		}
+		break;
+	case FTDM_CHANNEL_STATE_PROGRESS_MEDIA:
+	case FTDM_CHANNEL_STATE_PROGRESS:
+		{
+			if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
+				sig.event_id = FTDM_SIGEVENT_PROGRESS_MEDIA;
+				if ((status = m3ua_data->signal_cb(&sig) != FTDM_SUCCESS)) {
+					ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP);
+				}
+			} else {
+				m3uac_exec_command(mcon,
+								   ftdmchan->physical_span_id-1,
+								   ftdmchan->physical_chan_id-1,								   
+								   0,
+								   SIGBOOST_EVENT_CALL_START_ACK,
+								   0);
+			}
+		}
+		break;
+	case FTDM_CHANNEL_STATE_RING:
+		{
+			if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
+				sig.event_id = FTDM_SIGEVENT_START;
+				if ((status = m3ua_data->signal_cb(&sig) != FTDM_SUCCESS)) {
+					ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP);
+				}
+			}
+
+		}
+		break;
+	case FTDM_CHANNEL_STATE_RESTART:
+		{
+			if (ftdmchan->last_state != FTDM_CHANNEL_STATE_HANGUP && ftdmchan->last_state != FTDM_CHANNEL_STATE_DOWN) {
+				ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP);
+			} else {
+				ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
+			}
+		}
+		break;
+	case FTDM_CHANNEL_STATE_UP:
+		{
+			if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
+				sig.event_id = FTDM_SIGEVENT_UP;
+				if ((status = m3ua_data->signal_cb(&sig) != FTDM_SUCCESS)) {
+					ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP);
+				}
+			} else {
+				if (!(ftdm_test_flag(ftdmchan, FTDM_CHANNEL_PROGRESS) || ftdm_test_flag(ftdmchan, FTDM_CHANNEL_MEDIA))) {
+					m3uac_exec_command(mcon,
+									   ftdmchan->physical_span_id-1,
+									   ftdmchan->physical_chan_id-1,								   
+									   0,
+									   SIGBOOST_EVENT_CALL_START_ACK,
+									   0);
+				}
+				
+				m3uac_exec_command(mcon,
+								   ftdmchan->physical_span_id-1,
+								   ftdmchan->physical_chan_id-1,								   
+								   0,
+								   SIGBOOST_EVENT_CALL_ANSWERED,
+								   0);
+			}
+		}
+		break;
+	case FTDM_CHANNEL_STATE_DIALING:
+		{
+		}
+		break;
+	case FTDM_CHANNEL_STATE_HANGUP_COMPLETE:
+		{
+			ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
+		}
+		break;
+	case FTDM_CHANNEL_STATE_HANGUP:
+		{
+			if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_ANSWERED) || ftdm_test_flag(ftdmchan, FTDM_CHANNEL_PROGRESS) || ftdm_test_flag(ftdmchan, FTDM_CHANNEL_MEDIA)) {
+				m3uac_exec_command(mcon,
+								   ftdmchan->physical_span_id-1,
+								   ftdmchan->physical_chan_id-1,
+								   0,
+								   SIGBOOST_EVENT_CALL_STOPPED,
+								   ftdmchan->caller_data.hangup_cause);
+			} else {
+				m3uac_exec_command(mcon,
+								   ftdmchan->physical_span_id-1,
+								   ftdmchan->physical_chan_id-1,								   
+								   0,
+								   SIGBOOST_EVENT_CALL_START_NACK,
+								   ftdmchan->caller_data.hangup_cause);
+			}			
+		}
+		break;
+	case FTDM_CHANNEL_STATE_CANCEL:
+		{
+			sig.event_id = FTDM_SIGEVENT_STOP;
+			status = m3ua_data->signal_cb(&sig);
+			ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
+			m3uac_exec_command(mcon,
+							   ftdmchan->physical_span_id-1,
+							   ftdmchan->physical_chan_id-1,
+							   0,
+							   SIGBOOST_EVENT_CALL_START_NACK_ACK,
+							   0);
+		}
+		break;
+	case FTDM_CHANNEL_STATE_TERMINATING:
+		{
+			sig.event_id = FTDM_SIGEVENT_STOP;
+			status = m3ua_data->signal_cb(&sig);
+			ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
+			m3uac_exec_command(mcon,
+							   ftdmchan->physical_span_id-1,
+							   ftdmchan->physical_chan_id-1,
+							   0,
+							   SIGBOOST_EVENT_CALL_STOPPED_ACK,
+							   0);
+		}
+		break;
+	default:
+		break;
+	}
+}
+
+
+static __inline__ void check_state(ftdm_span_t *span)
+{
+    if (ftdm_test_flag(span, FTDM_SPAN_STATE_CHANGE)) {
+        uint32_t j;
+        ftdm_clear_flag_locked(span, FTDM_SPAN_STATE_CHANGE);
+        for(j = 1; j <= span->chan_count; j++) {
+            if (ftdm_test_flag((&span->channels[j]), FTDM_CHANNEL_STATE_CHANGE)) {
+                ftdm_clear_flag_locked((&span->channels[j]), FTDM_CHANNEL_STATE_CHANGE);
+                state_advance(&span->channels[j]);
+                ftdm_channel_complete_state(&span->channels[j]);
+            }
+        }
+    }
+}
+
+
+static int parse_ss7_event(ftdm_span_t *span, m3uac_connection_t *mcon, m3uac_event_t *event)
+{
+	ftdm_mutex_lock(signal_mutex);
+	
+	if (!ftdm_running()) {
+		ftdm_log(FTDM_LOG_WARNING, "System is shutting down.\n");
+		goto end;
+	}
+
+
+	if (ftdm_test_flag(span, FTDM_SPAN_SUSPENDED) && 
+		event->event_id != SIGBOOST_EVENT_SYSTEM_RESTART_ACK && event->event_id != SIGBOOST_EVENT_HEARTBEAT) {
+
+		ftdm_log(FTDM_LOG_WARNING,
+				"INVALID EVENT: %s:(%X) [w%dg%d] Rc=%i CSid=%i Seq=%i Cd=[%s] Ci=[%s]\n",
+				m3uac_event_id_name(event->event_id),
+				event->event_id,
+				event->span+1,
+				event->chan+1,
+				event->release_cause,
+				event->call_setup_id,
+				event->fseqno,
+				(event->called_number_digits_count ? (char *) event->called_number_digits : "N/A"),
+				(event->calling_number_digits_count ? (char *) event->calling_number_digits : "N/A")
+				);
+		
+		goto end;
+	}
+
+
+	ftdm_log(FTDM_LOG_DEBUG,
+			"RX EVENT: %s:(%X) [w%dg%d] Rc=%i CSid=%i Seq=%i Cd=[%s] Ci=[%s]\n",
+			   m3uac_event_id_name(event->event_id),
+			   event->event_id,
+			   event->span+1,
+			   event->chan+1,
+			   event->release_cause,
+			   event->call_setup_id,
+			   event->fseqno,
+			   (event->called_number_digits_count ? (char *) event->called_number_digits : "N/A"),
+			   (event->calling_number_digits_count ? (char *) event->calling_number_digits : "N/A")
+			   );
+
+
+	
+    switch(event->event_id) {
+
+    case SIGBOOST_EVENT_CALL_START:
+		//handle_call_start(span, mcon, event);
+		break;
+    case SIGBOOST_EVENT_CALL_STOPPED:
+		//handle_call_stop(span, mcon, event);
+		break;
+    case SIGBOOST_EVENT_CALL_START_ACK:
+		//handle_call_start_ack(mcon, event);
+		break;
+    case SIGBOOST_EVENT_CALL_START_NACK:
+		//handle_call_start_nack(span, mcon, event);
+		break;
+    case SIGBOOST_EVENT_CALL_ANSWERED:
+		//handle_call_answer(span, mcon, event);
+		break;
+    case SIGBOOST_EVENT_HEARTBEAT:
+		//handle_heartbeat(mcon, event);
+		break;
+    case SIGBOOST_EVENT_CALL_STOPPED_ACK:
+    case SIGBOOST_EVENT_CALL_START_NACK_ACK:
+		//handle_call_done(span, mcon, event);
+		break;
+    case SIGBOOST_EVENT_INSERT_CHECK_LOOP:
+		//handle_call_loop_start(event);
+		break;
+    case SIGBOOST_EVENT_REMOVE_CHECK_LOOP:
+		//handle_call_stop(event);
+		break;
+    case SIGBOOST_EVENT_SYSTEM_RESTART_ACK:
+		//handle_restart_ack(mcon, span, event);
+		break;
+    case SIGBOOST_EVENT_AUTO_CALL_GAP_ABATE:
+		//handle_gap_abate(event);
+		break;
+    default:
+		ftdm_log(FTDM_LOG_WARNING, "No handler implemented for [%s]\n", m3uac_event_id_name(event->event_id));
+		break;
+    }
+
+ end:
+
+	ftdm_mutex_unlock(signal_mutex);
+
+	return 0;
+}
+
+static FIO_CONFIGURE_FUNCTION(m3ua_configure)
+{
+	m3ua_channel_profile_t *profile = NULL;
+
+	int ok = 1;
+
+	if (!(profile = (m3ua_channel_profile_t *) hashtable_search(globals.profile_hash, (char *)category))) {
+		profile = ftdm_malloc(sizeof(*profile));
+		memset(profile, 0, sizeof(*profile));
+		ftdm_set_string(profile->name, category);
+		hashtable_insert(globals.profile_hash, (void *)profile->name, profile);
+		ftdm_log(FTDM_LOG_INFO, "creating profile [%s]\n", category);
+	}
+
+//	ftdm_set_string(m3ua_data->mcon. cfg.local_ip, local_ip);
+	if (!strcasecmp(var, "local_sctp_port")) {
+		profile->local_port = 30000 ;
+		profile->remote_port = 30000;
+		profile->cust_span++;
+	} 
+	ok = 1;
+	
+
+	if (ok) {
+		ftdm_log(FTDM_LOG_INFO, "setting param [%s]=[%s] for profile [%s]\n", var, val, category);
+	} else {
+		ftdm_log(FTDM_LOG_ERROR, "unknown param [%s]\n", var);
+	}
+
+	return FTDM_SUCCESS;
+}
+
+static FIO_CONFIGURE_SPAN_FUNCTION(m3ua_configure_span)
+{
+
+	return FTDM_FAIL;
+}
+
+static FIO_OPEN_FUNCTION(m3ua_open) 
+{
+	
+	return FTDM_FAIL;
+}
+
+static FIO_CLOSE_FUNCTION(m3ua_close)
+{
+	
+	return FTDM_FAIL;
+}
+
+/*static FIO_SET_INTERVAL_FUNCTION(m3ua_set_interval)
+{
+	
+	return 0;
+}*/
+
+static FIO_WAIT_FUNCTION(m3ua_wait)
+{
+	
+	return FTDM_FAIL;
+}
+
+static FIO_READ_FUNCTION(m3ua_read)
+{
+	
+	return FTDM_FAIL;
+}
+
+static FIO_WRITE_FUNCTION(m3ua_write)
+{
+	
+	return FTDM_FAIL;
+}
+
+static FIO_COMMAND_FUNCTION(m3ua_command)
+{
+	return FTDM_FAIL;
+}
+
+static FIO_SPAN_POLL_EVENT_FUNCTION(m3ua_poll_event)
+{
+	return FTDM_FAIL;
+}
+
+static FIO_SPAN_NEXT_EVENT_FUNCTION(m3ua_next_event)
+{
+	return FTDM_FAIL;
+}
+
+
+static FIO_SPAN_DESTROY_FUNCTION(m3ua_span_destroy)
+{
+	m3ua_span_data_t *span_data = (m3ua_span_data_t *) span->mod_data;
+	
+	if (span_data) {
+		ftdm_safe_free(span_data);
+	}
+	
+	return FTDM_SUCCESS;
+}
+static FIO_CHANNEL_DESTROY_FUNCTION(m3ua_channel_destroy)
+{
+	m3ua_chan_data_t *chan_data = (m3ua_chan_data_t *) ftdmchan->mod_data;
+	m3ua_span_data_t *span_data = (m3ua_span_data_t *) ftdmchan->span->mod_data;
+	
+	if (!chan_data) {
+		return FTDM_FAIL;
+	}
+
+	
+		
+
+
+
+	ftdm_mutex_destroy(&chan_data->digit_mutex);
+	ftdm_buffer_destroy(&chan_data->digit_buffer);
+
+
+	ftdm_safe_free(chan_data);
+	
+	if (span_data) {
+		ftdm_safe_free(span_data);
+	}
+	
+			
+	return FTDM_SUCCESS;
+}
+
+
+
+static FIO_GET_ALARMS_FUNCTION(m3ua_get_alarms)
+{
+	return FTDM_FAIL;
+}
+
+static ftdm_io_interface_t m3ua_interface;
+
+ftdm_status_t m3ua_init(ftdm_io_interface_t **zint)
+{
+	assert(zint != NULL);
+	memset(&m3ua_interface, 0, sizeof(m3ua_interface));
+
+	m3ua_interface.name = "m3ua";
+	m3ua_interface.configure =  m3ua_configure;
+	m3ua_interface.configure_span =  m3ua_configure_span;
+	m3ua_interface.open = m3ua_open;
+	m3ua_interface.close = m3ua_close;
+	m3ua_interface.wait = m3ua_wait;
+	m3ua_interface.read = m3ua_read;
+	m3ua_interface.write = m3ua_write;
+	m3ua_interface.command = m3ua_command;
+	m3ua_interface.poll_event = m3ua_poll_event;
+	m3ua_interface.next_event = m3ua_next_event;
+	m3ua_interface.channel_destroy = m3ua_channel_destroy;
+	m3ua_interface.span_destroy = m3ua_span_destroy;
+	m3ua_interface.get_alarms = m3ua_get_alarms;
+	*zint = &m3ua_interface;
+
+	return FTDM_FAIL;
+}
+
+ftdm_status_t m3ua_destroy(void)
+{
+	return FTDM_FAIL;
+}
+
+
+static void *m3ua_run(ftdm_thread_t *me, void *obj)
+{
+    ftdm_span_t *span = (ftdm_span_t *) obj;
+    m3ua_data_t *m3ua_data = span->signal_data;
+	m3uac_connection_t *mcon, *pcon;
+	uint32_t ms = 10, too_long = 60000;
+		
+
+	m3ua_data->pcon = m3ua_data->mcon;
+
+	if (m3uac_connection_open(&m3ua_data->mcon,
+							  m3ua_data->mcon.cfg.local_ip,
+							  m3ua_data->mcon.cfg.local_port,
+							  m3ua_data->mcon.cfg.remote_ip,
+							  m3ua_data->mcon.cfg.remote_port) < 0) {
+		ftdm_log(FTDM_LOG_DEBUG, "Error: Opening MCON Socket [%d] %s\n", m3ua_data->mcon.socket, strerror(errno));
+		goto end;
+    }
+
+	if (m3uac_connection_open(&m3ua_data->pcon,
+							  m3ua_data->pcon.cfg.local_ip,
+							  ++m3ua_data->pcon.cfg.local_port,
+							  m3ua_data->pcon.cfg.remote_ip,
+							  m3ua_data->pcon.cfg.remote_port) < 0) {
+		ftdm_log(FTDM_LOG_DEBUG, "Error: Opening PCON Socket [%d] %s\n", m3ua_data->pcon.socket, strerror(errno));
+		goto end;
+    }
+	
+	mcon = &m3ua_data->mcon;
+	pcon = &m3ua_data->pcon;
+
+	top:
+
+	//init_outgoing_array();		
+
+	m3uac_exec_command(mcon,
+					   0,
+					   0,
+					   -1,
+					   SIGBOOST_EVENT_SYSTEM_RESTART,
+					   0);
+	
+	while (ftdm_test_flag(m3ua_data, FTDM_M3UA_RUNNING)) {
+		fd_set rfds, efds;
+		struct timeval tv = { 0, ms * 1000 };
+		int max, activity, i = 0;
+		m3uac_event_t *event = NULL;
+		
+		if (!ftdm_running()) {
+			m3uac_exec_command(mcon,
+							   0,
+							   0,
+							   -1,
+							   SIGBOOST_EVENT_SYSTEM_RESTART,
+							   0);
+			break;
+		}
+
+		FD_ZERO(&rfds);
+		FD_ZERO(&efds);
+		FD_SET(mcon->socket, &rfds);
+		FD_SET(mcon->socket, &efds);
+		FD_SET(pcon->socket, &rfds);
+		FD_SET(pcon->socket, &efds);
+
+		max = ((pcon->socket > mcon->socket) ? pcon->socket : mcon->socket) + 1;
+		
+		if ((activity = select(max, &rfds, NULL, &efds, &tv)) < 0) {
+			goto error;
+		}
+		
+		if (activity) {
+			if (FD_ISSET(pcon->socket, &efds) || FD_ISSET(mcon->socket, &efds)) {
+				goto error;
+			}
+
+			if (FD_ISSET(pcon->socket, &rfds)) {
+				if ((event = m3uac_connection_readp(pcon, i))) {
+					parse_ss7_event(span, mcon, event);
+				} else goto top;
+			}
+
+			if (FD_ISSET(mcon->socket, &rfds)) {
+				if ((event = m3uac_connection_read(mcon, i))) {
+					parse_ss7_event(span, mcon, event);
+				} else goto top;
+			}
+		}
+		
+		check_state(span);
+		mcon->hb_elapsed += ms;
+		
+		if (mcon->hb_elapsed >= too_long && (mcon->up || !ftdm_test_flag(span, FTDM_SPAN_SUSPENDED))) {
+			ftdm_set_state_all(span, FTDM_CHANNEL_STATE_RESTART);
+			ftdm_set_flag_locked(span, FTDM_SPAN_SUSPENDED);
+			mcon->up = 0;
+			ftdm_log(FTDM_LOG_CRIT, "Lost Heartbeat!\n");
+		}
+
+	}
+
+	goto end;
+
+ error:
+	ftdm_log(FTDM_LOG_CRIT, "Socket Error!\n");
+
+ end:
+
+	m3uac_connection_close(&m3ua_data->mcon);
+	m3uac_connection_close(&m3ua_data->pcon);
+
+	ftdm_clear_flag(m3ua_data, FTDM_M3UA_RUNNING);
+
+	ftdm_log(FTDM_LOG_DEBUG, "M3UA thread ended.\n");
+	return NULL;
+}
+ftdm_status_t m3ua_start(ftdm_span_t *span)
+{
+	m3ua_data_t *m3ua_data = span->signal_data;
+	ftdm_set_flag(m3ua_data, FTDM_M3UA_RUNNING);
+	return ftdm_thread_create_detached(m3ua_run, span);
+}
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+*/

Added: freeswitch/trunk/libs/freetdm/src/ftdm_queue.c (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/ftdm_queue.c	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/ftdm_queue.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,234 @@
+/*
+ * Copyright (c) 2009, Sangoma Technologies
+ * Moises Silva <moy@sangoma.com>
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "freetdm.h"
+
+static ftdm_status_t ftdm_std_queue_create(ftdm_queue_t **outqueue, ftdm_size_t capacity);
+static ftdm_status_t ftdm_std_queue_enqueue(ftdm_queue_t *queue, void *obj);
+static void *ftdm_std_queue_dequeue(ftdm_queue_t *queue);
+static ftdm_status_t ftdm_std_queue_wait(ftdm_queue_t *queue, int ms);
+static ftdm_status_t ftdm_std_queue_get_interrupt(ftdm_queue_t *queue, ftdm_interrupt_t **interrupt);
+static ftdm_status_t ftdm_std_queue_destroy(ftdm_queue_t **inqueue);
+
+struct ftdm_queue {
+	ftdm_mutex_t *mutex;
+	ftdm_interrupt_t *interrupt;
+	ftdm_size_t capacity;
+	ftdm_size_t size;
+	unsigned rindex;
+	unsigned windex;
+	void **elements;
+};
+
+FT_DECLARE_DATA ftdm_queue_handler_t g_ftdm_queue_handler = 
+{
+	/*.create = */ ftdm_std_queue_create,
+	/*.enqueue = */ ftdm_std_queue_enqueue,
+	/*.dequeue = */ ftdm_std_queue_dequeue,
+	/*.wait = */ ftdm_std_queue_wait,
+	/*.get_interrupt = */ ftdm_std_queue_get_interrupt,
+	/*.destroy = */ ftdm_std_queue_destroy
+};
+
+FT_DECLARE(ftdm_status_t) ftdm_global_set_queue_handler(ftdm_queue_handler_t *handler)
+{
+	if (!handler ||
+		!handler->create || 
+		!handler->enqueue || 
+		!handler->dequeue || 
+		!handler->wait || 
+		!handler->get_interrupt || 
+		!handler->destroy) {
+		return FTDM_FAIL;
+	}
+	memcpy(&g_ftdm_queue_handler, handler, sizeof(*handler));
+	return FTDM_SUCCESS;
+}
+
+static ftdm_status_t ftdm_std_queue_create(ftdm_queue_t **outqueue, ftdm_size_t capacity)
+{
+	ftdm_queue_t *queue = NULL;
+	ftdm_assert_return(outqueue, FTDM_FAIL, "Queue double pointer is null\n");
+	ftdm_assert_return(capacity > 0, FTDM_FAIL, "Queue capacity is not bigger than 0\n");
+
+	*outqueue = NULL;
+	queue = ftdm_calloc(1, sizeof(*queue));
+	if (!queue) {
+		return FTDM_FAIL;
+	}
+
+	queue->elements = ftdm_calloc(1, (sizeof(void*)*capacity));
+	if (!queue->elements) {
+		goto failed;
+	}
+	queue->capacity = capacity;
+
+	if (ftdm_mutex_create(&queue->mutex) != FTDM_SUCCESS) {
+		goto failed;
+	}
+
+	if (ftdm_interrupt_create(&queue->interrupt, FTDM_INVALID_SOCKET) != FTDM_SUCCESS) {
+		goto failed;
+	}
+
+	*outqueue = queue;	
+	return FTDM_SUCCESS;
+
+failed:
+	if (queue) {
+		if (queue->interrupt) {
+			ftdm_interrupt_destroy(&queue->interrupt);
+		}
+		if (queue->mutex) {
+			ftdm_mutex_destroy(&queue->mutex);
+		}
+		ftdm_safe_free(queue->elements);
+		ftdm_safe_free(queue);
+	}
+	return FTDM_FAIL;
+}
+
+static ftdm_status_t ftdm_std_queue_enqueue(ftdm_queue_t *queue, void *obj)
+{
+	ftdm_status_t status = FTDM_FAIL;
+
+	ftdm_assert_return(queue != NULL, FTDM_FAIL, "Queue is null!");
+
+	ftdm_mutex_lock(queue->mutex);
+
+	if (queue->windex == queue->capacity) {
+		/* try to see if we can wrap around */
+		queue->windex = 0;
+	}
+
+	if (queue->size != 0 && queue->windex == queue->rindex) {
+		ftdm_log(FTDM_LOG_ERROR, "Failed to enqueue obj %p in queue %p, no more room! windex == rindex == %d!\n", obj, queue, queue->windex);
+		goto done;
+	}
+
+	queue->elements[queue->windex++] = obj;
+	queue->size++;
+	status = FTDM_SUCCESS;
+
+	/* wake up queue reader */
+	ftdm_interrupt_signal(queue->interrupt);
+
+done:
+
+	ftdm_mutex_unlock(queue->mutex);
+
+	return status;
+}
+
+static void *ftdm_std_queue_dequeue(ftdm_queue_t *queue)
+{
+	void *obj = NULL;
+
+	ftdm_assert_return(queue != NULL, NULL, "Queue is null!");
+
+	ftdm_mutex_lock(queue->mutex);
+
+	if (queue->size == 0) {
+		goto done;
+	}
+	
+	obj = queue->elements[queue->rindex];
+	queue->elements[queue->rindex++] = NULL;
+	queue->size--;
+	if (queue->rindex == queue->capacity) {
+		queue->rindex = 0;
+	}
+
+done:
+
+	ftdm_mutex_unlock(queue->mutex);
+
+	return obj;
+}
+
+static ftdm_status_t ftdm_std_queue_wait(ftdm_queue_t *queue, int ms)
+{
+	ftdm_status_t ret;
+	ftdm_assert_return(queue != NULL, FTDM_FAIL, "Queue is null!");
+	
+	ftdm_mutex_lock(queue->mutex);
+
+	/* if there is elements in the queue, no need to wait */
+	if (queue->size != 0) {
+		ftdm_mutex_unlock(queue->mutex);
+		return FTDM_SUCCESS;
+	}
+
+	/* no elements on the queue, wait for someone to write an element */
+	ret = ftdm_interrupt_wait(queue->interrupt, ms);
+
+	/* got an element or timeout, bail out */
+	ftdm_mutex_unlock(queue->mutex);
+
+	return ret;
+}
+
+static ftdm_status_t ftdm_std_queue_get_interrupt(ftdm_queue_t *queue, ftdm_interrupt_t **interrupt)
+{
+	ftdm_assert_return(queue != NULL, FTDM_FAIL, "Queue is null!\n");
+	ftdm_assert_return(interrupt != NULL, FTDM_FAIL, "Queue is null!\n");
+	*interrupt = queue->interrupt;
+	return FTDM_SUCCESS;
+}
+
+static ftdm_status_t ftdm_std_queue_destroy(ftdm_queue_t **inqueue)
+{
+	ftdm_queue_t *queue = NULL;
+	ftdm_assert_return(inqueue != NULL, FTDM_FAIL, "Queue is null!\n");
+	ftdm_assert_return(*inqueue != NULL, FTDM_FAIL, "Queue is null!\n");
+
+	queue = *inqueue;
+	ftdm_interrupt_destroy(&queue->interrupt);
+	ftdm_mutex_destroy(&queue->mutex);
+	ftdm_safe_free(queue->elements);
+	ftdm_safe_free(queue);
+	*inqueue = NULL;
+	return FTDM_SUCCESS;
+}
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */

Added: freeswitch/trunk/libs/freetdm/src/ftdm_threadmutex.c (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/ftdm_threadmutex.c	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/ftdm_threadmutex.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,457 @@
+/* 
+ * Cross Platform Thread/Mutex abstraction
+ * Copyright(C) 2007 Michael Jerris
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so.
+ *
+ * This work is provided under this license on an "as is" basis, without warranty of any kind,
+ * either expressed or implied, including, without limitation, warranties that the covered code
+ * is free of defects, merchantable, fit for a particular purpose or non-infringing. The entire
+ * risk as to the quality and performance of the covered code is with you. Should any covered
+ * code prove defective in any respect, you (not the initial developer or any other contributor)
+ * assume the cost of any necessary servicing, repair or correction. This disclaimer of warranty
+ * constitutes an essential part of this license. No use of any covered code is authorized hereunder
+ * except under this disclaimer. 
+ *
+ * Contributors: 
+ *
+ * Moises Silva <moy@sangoma.com>
+ *
+ */
+
+#ifdef WIN32
+/* required for TryEnterCriticalSection definition.  Must be defined before windows.h include */
+#define _WIN32_WINNT 0x0400
+#endif
+
+#include "freetdm.h"
+#include "ftdm_threadmutex.h"
+
+#ifdef WIN32
+#include <process.h>
+
+#define FTDM_THREAD_CALLING_CONVENTION __stdcall
+
+struct ftdm_mutex {
+	CRITICAL_SECTION mutex;
+};
+
+#else
+#include <pthread.h>
+#include <poll.h>
+
+#define FTDM_THREAD_CALLING_CONVENTION
+
+struct ftdm_mutex {
+	pthread_mutex_t mutex;
+};
+
+#endif
+
+struct ftdm_interrupt {
+	ftdm_socket_t device;
+#ifdef WIN32
+	/* for generic interruption */
+	HANDLE event;
+#else
+	/* for generic interruption */
+	int readfd;
+	int writefd;
+#endif
+};
+
+struct ftdm_thread {
+#ifdef WIN32
+	void *handle;
+#else
+	pthread_t handle;
+#endif
+	void *private_data;
+	ftdm_thread_function_t function;
+	ftdm_size_t stack_size;
+#ifndef WIN32
+	pthread_attr_t attribute;
+#endif
+};
+
+ftdm_size_t thread_default_stacksize = 0;
+
+FT_DECLARE(void) ftdm_thread_override_default_stacksize(ftdm_size_t size)
+{
+	thread_default_stacksize = size;
+}
+
+static void * FTDM_THREAD_CALLING_CONVENTION thread_launch(void *args)
+{
+	void *exit_val;
+    ftdm_thread_t *thread = (ftdm_thread_t *)args;
+	exit_val = thread->function(thread, thread->private_data);
+#ifndef WIN32
+	pthread_attr_destroy(&thread->attribute);
+#endif
+	ftdm_safe_free(thread);
+
+	return exit_val;
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_thread_create_detached(ftdm_thread_function_t func, void *data)
+{
+	return ftdm_thread_create_detached_ex(func, data, thread_default_stacksize);
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_thread_create_detached_ex(ftdm_thread_function_t func, void *data, ftdm_size_t stack_size)
+{
+	ftdm_thread_t *thread = NULL;
+	ftdm_status_t status = FTDM_FAIL;
+
+	if (!func || !(thread = (ftdm_thread_t *)ftdm_malloc(sizeof(ftdm_thread_t)))) {
+		goto done;
+	}
+
+	thread->private_data = data;
+	thread->function = func;
+	thread->stack_size = stack_size;
+
+#if defined(WIN32)
+	thread->handle = (void *)_beginthreadex(NULL, (unsigned)thread->stack_size, (unsigned int (__stdcall *)(void *))thread_launch, thread, 0, NULL);
+	if (!thread->handle) {
+		goto fail;
+	}
+	CloseHandle(thread->handle);
+
+	status = FTDM_SUCCESS;
+	goto done;
+#else
+	
+	if (pthread_attr_init(&thread->attribute) != 0)	goto fail;
+
+	if (pthread_attr_setdetachstate(&thread->attribute, PTHREAD_CREATE_DETACHED) != 0) goto failpthread;
+
+	if (thread->stack_size && pthread_attr_setstacksize(&thread->attribute, thread->stack_size) != 0) goto failpthread;
+
+	if (pthread_create(&thread->handle, &thread->attribute, thread_launch, thread) != 0) goto failpthread;
+
+	status = FTDM_SUCCESS;
+	goto done;
+ failpthread:
+	pthread_attr_destroy(&thread->attribute);
+#endif
+
+ fail:
+	if (thread) {
+		ftdm_safe_free(thread);
+	}
+ done:
+	return status;
+}
+
+
+FT_DECLARE(ftdm_status_t) ftdm_mutex_create(ftdm_mutex_t **mutex)
+{
+	ftdm_status_t status = FTDM_FAIL;
+#ifndef WIN32
+	pthread_mutexattr_t attr;
+#endif
+	ftdm_mutex_t *check = NULL;
+
+	check = (ftdm_mutex_t *)ftdm_malloc(sizeof(**mutex));
+	if (!check)
+		goto done;
+#ifdef WIN32
+	InitializeCriticalSection(&check->mutex);
+#else
+	if (pthread_mutexattr_init(&attr))
+		goto done;
+
+	if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE))
+		goto fail;
+
+	if (pthread_mutex_init(&check->mutex, &attr))
+		goto fail;
+
+	goto success;
+
+ fail:
+	pthread_mutexattr_destroy(&attr);
+	goto done;
+
+ success:
+#endif
+	*mutex = check;
+	status = FTDM_SUCCESS;
+
+ done:
+	return status;
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_mutex_destroy(ftdm_mutex_t **mutex)
+{
+	ftdm_mutex_t *mp = *mutex;
+	*mutex = NULL;
+	if (!mp) {
+		return FTDM_FAIL;
+	}
+#ifdef WIN32
+	DeleteCriticalSection(&mp->mutex);
+#else
+	if (pthread_mutex_destroy(&mp->mutex))
+		return FTDM_FAIL;
+#endif
+	ftdm_safe_free(mp);
+	return FTDM_SUCCESS;
+}
+
+FT_DECLARE(ftdm_status_t) _ftdm_mutex_lock(ftdm_mutex_t *mutex)
+{
+#ifdef WIN32
+	EnterCriticalSection(&mutex->mutex);
+#else
+	int err;
+	if ((err = pthread_mutex_lock(&mutex->mutex))) {
+		ftdm_log(FTDM_LOG_ERROR, "Failed to lock mutex %d:%s\n", err, strerror(err));
+		return FTDM_FAIL;
+	}
+#endif
+	return FTDM_SUCCESS;
+}
+
+FT_DECLARE(ftdm_status_t) _ftdm_mutex_trylock(ftdm_mutex_t *mutex)
+{
+#ifdef WIN32
+	if (!TryEnterCriticalSection(&mutex->mutex))
+		return FTDM_FAIL;
+#else
+	if (pthread_mutex_trylock(&mutex->mutex))
+		return FTDM_FAIL;
+#endif
+	return FTDM_SUCCESS;
+}
+
+FT_DECLARE(ftdm_status_t) _ftdm_mutex_unlock(ftdm_mutex_t *mutex)
+{
+#ifdef WIN32
+	LeaveCriticalSection(&mutex->mutex);
+#else
+	if (pthread_mutex_unlock(&mutex->mutex))
+		return FTDM_FAIL;
+#endif
+	return FTDM_SUCCESS;
+}
+
+
+FT_DECLARE(ftdm_status_t) ftdm_interrupt_create(ftdm_interrupt_t **ininterrupt, ftdm_socket_t device)
+{
+	ftdm_interrupt_t *interrupt = NULL;
+#ifndef WIN32
+	int fds[2];
+#endif
+
+	ftdm_assert_return(ininterrupt != NULL, FTDM_FAIL, "interrupt double pointer is null!\n");
+
+	interrupt = ftdm_calloc(1, sizeof(*interrupt));
+	if (!interrupt) {
+		ftdm_log(FTDM_LOG_ERROR, "Failed to allocate interrupt memory\n");
+		return FTDM_FAIL;
+	}
+
+	interrupt->device = device;
+#ifdef WIN32
+	interrupt->interrupt = CreateEvent(NULL, FALSE, FALSE, NULL);
+	if (!interrupt->interrupt) {
+		ftdm_log(FTDM_LOG_ERROR, "Failed to allocate interrupt event\n");
+		goto failed;
+	}
+#else
+	if (pipe(fds)) {
+		ftdm_log(FTDM_LOG_ERROR, "Failed to allocate interrupt pipe: %s\n", strerror(errno));
+		goto failed;
+	}
+	interrupt->readfd = fds[0];
+	interrupt->writefd = fds[1];
+#endif
+
+	*ininterrupt = interrupt;
+	return FTDM_SUCCESS;
+
+failed:
+	if (interrupt) {
+#ifndef WIN32
+		if (interrupt->readfd) {
+			close(interrupt->readfd);
+			close(interrupt->writefd);
+			interrupt->readfd = -1;
+			interrupt->writefd = -1;
+		}
+#endif
+		ftdm_safe_free(interrupt);
+	}
+	return FTDM_FAIL;
+}
+
+#define ONE_BILLION 1000000000
+
+FT_DECLARE(ftdm_status_t) ftdm_interrupt_wait(ftdm_interrupt_t *interrupt, int ms)
+{
+	int num = 1;
+#ifdef WIN32
+	DWORD res = 0;
+	HANDLE ints[2];
+#else
+	int res = 0;
+	struct pollfd ints[2];
+	char pipebuf[255];
+#endif
+
+	ftdm_assert_return(interrupt != NULL, FTDM_FAIL, "Condition is null!\n");
+
+
+	/* start implementation */
+#ifdef WIN32
+	ints[0] = interrupt->event;
+	if (interrupt->device != FTDM_INVALID_SOCKET) {
+		num++;
+		ints[1] = interrupt->device;
+	}
+	res = WaitForMultipleObjects(num, &ints, FALSE, ms >= 0 ? ms : INFINITE);
+	switch (res) {
+	case WAIT_TIMEOUT:
+		return FTDM_TIMEOUT;
+	case WAIT_FAILED:
+	case WAIT_ABANDONED: /* is it right to fail with abandoned? */
+		return FTDM_FAIL;
+	default:
+		if (res >= (sizeof(ints)/sizeof(ints[0]))) {
+			ftdm_log(FTDM_LOG_ERROR, "Error waiting for freetdm interrupt event (WaitForSingleObject returned %d)\n", res);
+			return FTDM_FAIL;
+		}
+		return FTDM_SUCCESS;
+	}
+#else
+	ints[0].fd = interrupt->readfd;
+	ints[0].events = POLLIN;
+	ints[0].revents = 0;
+
+	if (interrupt->device != FTDM_INVALID_SOCKET) {
+		num++;
+		ints[1].fd = interrupt->device;
+		ints[1].events = POLLIN;
+		ints[1].revents = 0;
+	}
+
+	res = poll(ints, num, ms);
+
+	if (res == -1) {
+		ftdm_log(FTDM_LOG_CRIT, "interrupt poll failed (%s)\n", strerror(errno));
+		return FTDM_FAIL;
+	}
+
+	if (res == 0) {
+		return FTDM_TIMEOUT;
+	}
+
+	if (ints[0].revents & POLLIN) {
+		res = read(ints[0].fd, pipebuf, sizeof(pipebuf));
+		if (res == -1) {
+			ftdm_log(FTDM_LOG_CRIT, "reading interrupt descriptor failed (%s)\n", strerror(errno));
+		}
+	}
+
+	return FTDM_SUCCESS;
+#endif
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_interrupt_signal(ftdm_interrupt_t *interrupt)
+{
+	ftdm_assert_return(interrupt != NULL, FTDM_FAIL, "Interrupt is null!\n");
+#ifdef WIN32
+	if (!SetEvent(interrupt->interrupt)) {
+		ftdm_log(FTDM_LOG_ERROR, "Failed to signal interrupt\n");
+		return FTDM_FAIL;
+	}
+#else
+	int err;
+	if ((err = write(interrupt->writefd, "w", 1)) != 1) {
+		ftdm_log(FTDM_LOG_ERROR, "Failed to signal interrupt: %s\n", errno, strerror(errno));
+		return FTDM_FAIL;
+	}
+#endif
+	return FTDM_SUCCESS;
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_interrupt_destroy(ftdm_interrupt_t **ininterrupt)
+{
+	ftdm_interrupt_t *interrupt = NULL;
+	ftdm_assert_return(ininterrupt != NULL, FTDM_FAIL, "Interrupt null when destroying!\n");
+	interrupt = *ininterrupt;
+#ifdef WIN32
+	CloseHandle(interrupt->interrupt);
+#else
+	close(interrupt->readfd);
+	close(interrupt->writefd);
+	interrupt->readfd = -1;
+	interrupt->writefd = -1;
+#endif
+	ftdm_safe_free(interrupt);
+	*ininterrupt = NULL;
+	return FTDM_SUCCESS;
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_interrupt_multiple_wait(ftdm_interrupt_t *interrupts[], ftdm_size_t size, int ms)
+{
+#ifndef WIN32
+	int i;
+	int res = 0;
+	int numdevices = 0;
+	char pipebuf[255];
+	struct pollfd ints[size*2];
+
+	memset(&ints, 0, sizeof(ints));
+
+	for (i = 0; i < size; i++) {
+		ints[i].events = POLLIN;
+		ints[i].revents = 0;
+		ints[i].fd = interrupts[i]->readfd;
+		if (interrupts[i]->device != FTDM_INVALID_SOCKET) {
+			ints[i+numdevices].events = POLLIN;
+			ints[i+numdevices].revents = 0;
+			ints[i+numdevices].fd = interrupts[i]->device;
+			numdevices++;
+		}
+	}
+
+	res = poll(ints, size + numdevices, ms);
+
+	if (res == -1) {
+		ftdm_log(FTDM_LOG_CRIT, "interrupt poll failed (%s)\n", strerror(errno));
+		return FTDM_FAIL;
+	}
+
+	if (res == 0) {
+		return FTDM_TIMEOUT;
+	}
+
+	for (i = 0; i < size; i++) {
+		if (ints[i].revents & POLLIN) {
+			res = read(ints[i].fd, pipebuf, sizeof(pipebuf));
+			if (res == -1) {
+				ftdm_log(FTDM_LOG_CRIT, "reading interrupt descriptor failed (%s)\n", strerror(errno));
+			}
+		}
+	}
+
+#endif
+	return FTDM_SUCCESS;
+}
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */

Added: freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_analog/ftdm_analog.h (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_analog/ftdm_analog.h	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_analog/ftdm_analog.h	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2007, Anthony Minessale II
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FTDM_ANALOG_H
+#define FTDM_ANALOG_H
+#include "freetdm.h"
+
+typedef enum {
+	FTDM_ANALOG_RUNNING = (1 << 0),
+	FTDM_ANALOG_CALLERID = (1 << 1)
+} ftdm_analog_flag_t;
+
+#define FTDM_MAX_HOTLINE_STR		20
+#define MAX_DTMF 256
+
+struct ftdm_analog_data {
+	uint32_t flags;
+	uint32_t max_dialstr;
+	uint32_t digit_timeout;
+	char hotline[FTDM_MAX_HOTLINE_STR];
+};
+
+
+
+static void *ftdm_analog_run(ftdm_thread_t *me, void *obj);
+typedef struct ftdm_analog_data ftdm_analog_data_t;
+
+#endif
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */

Added: freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_analog/ftmod_analog.2008.vcproj (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_analog/ftmod_analog.2008.vcproj	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_analog/ftmod_analog.2008.vcproj	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,353 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="9.00"
+	Name="ftmod_analog"
+	ProjectGUID="{37C94798-6E33-4B4F-8EE0-C72A7DC91157}"
+	RootNamespace="ftmod_analog"
+	Keyword="Win32Proj"
+	TargetFrameworkVersion="196613"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+		<Platform
+			Name="x64"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="2"
+			CharacterSet="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				AdditionalIncludeDirectories="..\..\include;..\..\isdn\include"
+				PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;FTMOD_ANALOG_EXPORTS"
+				MinimalRebuild="true"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="3"
+				UsePrecompiledHeader="0"
+				WarningLevel="4"
+				WarnAsError="true"
+				DebugInformationFormat="4"
+				DisableSpecificWarnings="4100"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				LinkIncremental="2"
+				GenerateDebugInformation="true"
+				SubSystem="2"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="2"
+			CharacterSet="1"
+			WholeProgramOptimization="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="2"
+				EnableIntrinsicFunctions="true"
+				AdditionalIncludeDirectories="..\..\include;..\..\isdn\include"
+				PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;FTMOD_ANALOG_EXPORTS"
+				RuntimeLibrary="2"
+				EnableFunctionLevelLinking="true"
+				UsePrecompiledHeader="0"
+				WarningLevel="4"
+				WarnAsError="true"
+				DebugInformationFormat="3"
+				DisableSpecificWarnings="4100"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				LinkIncremental="1"
+				GenerateDebugInformation="true"
+				SubSystem="2"
+				OptimizeReferences="2"
+				EnableCOMDATFolding="2"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Debug|x64"
+			OutputDirectory="$(SolutionDir)$(PlatformName)\$(ConfigurationName)"
+			IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+			ConfigurationType="2"
+			CharacterSet="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+				TargetEnvironment="3"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				AdditionalIncludeDirectories="..\..\include;..\..\isdn\include"
+				PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;FTMOD_ANALOG_EXPORTS"
+				MinimalRebuild="true"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="3"
+				UsePrecompiledHeader="0"
+				WarningLevel="4"
+				WarnAsError="false"
+				DebugInformationFormat="3"
+				DisableSpecificWarnings="4100"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				LinkIncremental="2"
+				GenerateDebugInformation="true"
+				SubSystem="2"
+				TargetMachine="17"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|x64"
+			OutputDirectory="$(SolutionDir)$(PlatformName)\$(ConfigurationName)"
+			IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+			ConfigurationType="2"
+			CharacterSet="1"
+			WholeProgramOptimization="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+				TargetEnvironment="3"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="2"
+				EnableIntrinsicFunctions="true"
+				AdditionalIncludeDirectories="..\..\include;..\..\isdn\include"
+				PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;FTMOD_ANALOG_EXPORTS"
+				RuntimeLibrary="2"
+				EnableFunctionLevelLinking="true"
+				UsePrecompiledHeader="0"
+				WarningLevel="4"
+				WarnAsError="true"
+				DebugInformationFormat="3"
+				DisableSpecificWarnings="4100"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				LinkIncremental="1"
+				GenerateDebugInformation="true"
+				SubSystem="2"
+				OptimizeReferences="2"
+				EnableCOMDATFolding="2"
+				TargetMachine="17"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<Filter
+			Name="Source Files"
+			Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+			>
+			<File
+				RelativePath="ftmod_analog.c"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="Header Files"
+			Filter="h;hpp;hxx;hm;inl;inc;xsd"
+			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+			>
+			<File
+				RelativePath="ftdm_analog.h"
+				>
+			</File>
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>

Added: freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_analog/ftmod_analog.c (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_analog/ftmod_analog.c	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_analog/ftmod_analog.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,975 @@
+/*
+ * Copyright (c) 2007, Anthony Minessale II
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "freetdm.h"
+#include "ftdm_analog.h"
+
+#ifndef localtime_r
+struct tm * localtime_r(const time_t *clock, struct tm *result);
+#endif
+
+static void *ftdm_analog_channel_run(ftdm_thread_t *me, void *obj);
+
+/**
+ * \brief Starts an FXO channel thread (outgoing call)
+ * \param ftdmchan Channel to initiate call on
+ * \return Success or failure
+ *
+ * Initialises state, starts tone progress detection and runs the channel in a new a thread.
+ */
+static FIO_CHANNEL_OUTGOING_CALL_FUNCTION(analog_fxo_outgoing_call)
+{
+	if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OFFHOOK) && !ftdm_test_flag(ftdmchan, FTDM_CHANNEL_INTHREAD)) {		
+		ftdm_channel_clear_needed_tones(ftdmchan);
+		ftdm_channel_clear_detected_tones(ftdmchan);
+
+		ftdm_channel_command(ftdmchan, FTDM_COMMAND_OFFHOOK, NULL);
+		ftdm_channel_command(ftdmchan, FTDM_COMMAND_ENABLE_PROGRESS_DETECT, NULL);
+		ftdmchan->needed_tones[FTDM_TONEMAP_DIAL] = 1;
+		ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DIALING);
+		ftdm_thread_create_detached(ftdm_analog_channel_run, ftdmchan);
+		return FTDM_SUCCESS;
+	}
+
+	return FTDM_FAIL;
+}
+
+/**
+ * \brief Starts an FXS channel thread (outgoing call)
+ * \param ftdmchan Channel to initiate call on
+ * \return Success or failure
+ *
+ * Indicates call waiting if channel is already in use, otherwise runs the channel in a new thread.
+ */
+static FIO_CHANNEL_OUTGOING_CALL_FUNCTION(analog_fxs_outgoing_call)
+{
+
+	if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_INTHREAD)) {
+		ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_CALLWAITING);
+	} else {
+		ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_GENRING);
+		ftdm_thread_create_detached(ftdm_analog_channel_run, ftdmchan);
+	}
+
+	return FTDM_SUCCESS;
+}
+
+/**
+ * \brief Starts an analog span thread (monitor)
+ * \param span Span to monitor
+ * \return Success or failure
+ */
+static ftdm_status_t ftdm_analog_start(ftdm_span_t *span)
+{
+	ftdm_analog_data_t *analog_data = span->signal_data;
+	ftdm_set_flag(analog_data, FTDM_ANALOG_RUNNING);
+	return ftdm_thread_create_detached(ftdm_analog_run, span);
+}
+
+/**
+ * \brief Initialises an analog span from configuration variables
+ * \param span Span to configure
+ * \param sig_cb Callback function for event signals
+ * \param ap List of configuration variables
+ * \return Success or failure
+ */
+static FIO_SIG_CONFIGURE_FUNCTION(ftdm_analog_configure_span)
+//ftdm_status_t ftdm_analog_configure_span(ftdm_span_t *span, char *tonemap, uint32_t digit_timeout, uint32_t max_dialstr, fio_signal_cb_t sig_cb)
+{
+	ftdm_analog_data_t *analog_data;
+	const char *tonemap = "us";
+	const char *hotline = "";
+	uint32_t digit_timeout = 10;
+	uint32_t max_dialstr = MAX_DTMF;
+	const char *var, *val;
+	int *intval;
+	uint32_t flags = FTDM_ANALOG_CALLERID;
+
+	assert(sig_cb != NULL);
+
+	if (span->signal_type) {
+		snprintf(span->last_error, sizeof(span->last_error), "Span is already configured for signalling.");
+		return FTDM_FAIL;
+	}
+	
+	analog_data = ftdm_malloc(sizeof(*analog_data));
+	assert(analog_data != NULL);
+	memset(analog_data, 0, sizeof(*analog_data));
+
+	while ((var = va_arg(ap, char *))) {
+		if (!strcasecmp(var, "tonemap")) {
+			if (!(val = va_arg(ap, char *))) {
+				break;
+			}
+			tonemap = val;
+		} else if (!strcasecmp(var, "digit_timeout")) {
+			if (!(intval = va_arg(ap, int *))) {
+				break;
+			}
+			digit_timeout = *intval;
+		} else if (!strcasecmp(var, "enable_callerid")) {
+			if (!(val = va_arg(ap, char *))) {
+                break;
+            }
+			
+			if (ftdm_true(val)) {
+				flags |= FTDM_ANALOG_CALLERID;
+			} else {
+				flags &= ~FTDM_ANALOG_CALLERID;
+			}
+		} else if (!strcasecmp(var, "max_dialstr")) {
+			if (!(intval = va_arg(ap, int *))) {
+				break;
+			}
+			max_dialstr = *intval;
+		} else if (!strcasecmp(var, "hotline")) {
+			if (!(val = va_arg(ap, char *))) {
+				break;
+			}
+			hotline = val;
+		} else {
+			snprintf(span->last_error, sizeof(span->last_error), "Unknown parameter [%s]", var);
+			return FTDM_FAIL;
+		}			
+	}
+
+
+	if (digit_timeout < 2000 || digit_timeout > 10000) {
+		digit_timeout = 2000;
+	}
+
+	if ((max_dialstr < 1 && !strlen(hotline)) || max_dialstr > MAX_DTMF) {
+		max_dialstr = MAX_DTMF;
+	}
+	
+	span->start = ftdm_analog_start;
+	analog_data->flags = flags;
+	analog_data->digit_timeout = digit_timeout;
+	analog_data->max_dialstr = max_dialstr;
+	span->signal_cb = sig_cb;
+	strncpy(analog_data->hotline, hotline, sizeof(analog_data->hotline));
+	span->signal_type = FTDM_SIGTYPE_ANALOG;
+	span->signal_data = analog_data;
+	span->outgoing_call = span->trunk_type == FTDM_TRUNK_FXS ? analog_fxs_outgoing_call : analog_fxo_outgoing_call;
+	ftdm_span_load_tones(span, tonemap);
+
+	return FTDM_SUCCESS;
+
+}
+
+/**
+ * \brief Retrieves tone generation output to be sent
+ * \param ts Teletone generator
+ * \param map Tone map
+ * \return -1 on error, 0 on success
+ */
+static int teletone_handler(teletone_generation_session_t *ts, teletone_tone_map_t *map)
+{
+	ftdm_buffer_t *dt_buffer = ts->user_data;
+	int wrote;
+
+	if (!dt_buffer) {
+		return -1;
+	}
+	wrote = teletone_mux_tones(ts, map);
+	ftdm_buffer_write(dt_buffer, ts->buffer, wrote * 2);
+	return 0;
+}
+
+/**
+ * \brief Sends caller id on an analog channel (FSK coded)
+ * \param ftdmchan Channel to send caller id on
+ */
+static void send_caller_id(ftdm_channel_t *ftdmchan)
+{
+	ftdm_fsk_data_state_t fsk_data;
+	uint8_t databuf[1024] = "";
+	char time_str[9];
+	struct tm tm;
+	time_t now;
+	ftdm_mdmf_type_t mt = MDMF_INVALID;
+
+	time(&now);
+#ifdef WIN32
+	_tzset();
+	_localtime64_s(&tm, &now);
+#else
+	localtime_r(&now, &tm);
+#endif
+	strftime(time_str, sizeof(time_str), "%m%d%H%M", &tm);
+
+	ftdm_fsk_data_init(&fsk_data, databuf, sizeof(databuf));
+	ftdm_fsk_data_add_mdmf(&fsk_data, MDMF_DATETIME, (uint8_t *) time_str, 8);
+					
+	if (ftdm_strlen_zero(ftdmchan->caller_data.cid_num.digits)) {
+		mt = MDMF_NO_NUM;
+		ftdm_set_string(ftdmchan->caller_data.cid_num.digits, "O");
+	} else if (!strcasecmp(ftdmchan->caller_data.cid_num.digits, "P") || !strcasecmp(ftdmchan->caller_data.cid_num.digits, "O")) {
+		mt = MDMF_NO_NUM;
+	} else {
+		mt = MDMF_PHONE_NUM;
+	}
+	ftdm_fsk_data_add_mdmf(&fsk_data, mt, (uint8_t *) ftdmchan->caller_data.cid_num.digits, (uint8_t)strlen(ftdmchan->caller_data.cid_num.digits));
+
+	if (ftdm_strlen_zero(ftdmchan->caller_data.cid_name)) {
+		mt = MDMF_NO_NAME;
+		ftdm_set_string(ftdmchan->caller_data.cid_name, "O");
+	} else if (!strcasecmp(ftdmchan->caller_data.cid_name, "P") || !strcasecmp(ftdmchan->caller_data.cid_name, "O")) {
+		mt = MDMF_NO_NAME;
+	} else {
+		mt = MDMF_PHONE_NAME;
+	}
+	ftdm_fsk_data_add_mdmf(&fsk_data, mt, (uint8_t *) ftdmchan->caller_data.cid_name, (uint8_t)strlen(ftdmchan->caller_data.cid_name));
+					
+	ftdm_fsk_data_add_checksum(&fsk_data);
+	ftdm_channel_send_fsk_data(ftdmchan, &fsk_data, -14);
+}
+
+/**
+ * \brief Main thread function for analog channel (outgoing call)
+ * \param me Current thread
+ * \param obj Channel to run in this thread
+ */
+static void *ftdm_analog_channel_run(ftdm_thread_t *me, void *obj)
+{
+	ftdm_channel_t *ftdmchan = (ftdm_channel_t *) obj;
+	ftdm_buffer_t *dt_buffer = NULL;
+	teletone_generation_session_t ts;
+	uint8_t frame[1024];
+	ftdm_size_t len, rlen;
+	ftdm_tone_type_t tt = FTDM_TONE_DTMF;
+	char dtmf[MAX_DTMF+1] = "";
+	ftdm_size_t dtmf_offset = 0;
+	ftdm_analog_data_t *analog_data = ftdmchan->span->signal_data;
+	ftdm_channel_t *closed_chan;
+	uint32_t state_counter = 0, elapsed = 0, collecting = 0, interval = 0, last_digit = 0, indicate = 0, dial_timeout = 30000;
+	ftdm_sigmsg_t sig;
+	ftdm_status_t status;
+	
+	ftdm_log(FTDM_LOG_DEBUG, "ANALOG CHANNEL thread starting.\n");
+
+	ts.buffer = NULL;
+
+	if (ftdm_channel_open_chan(ftdmchan) != FTDM_SUCCESS) {
+		ftdm_log(FTDM_LOG_ERROR, "OPEN ERROR [%s]\n", ftdmchan->last_error);
+		goto done;
+	}
+
+	if (ftdm_buffer_create(&dt_buffer, 1024, 3192, 0) != FTDM_SUCCESS) {
+		snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "memory error!");
+		ftdm_log(FTDM_LOG_ERROR, "MEM ERROR\n");
+		goto done;
+	}
+
+	if (ftdm_channel_command(ftdmchan, FTDM_COMMAND_ENABLE_DTMF_DETECT, &tt) != FTDM_SUCCESS) {
+		snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "error initilizing tone detector!");
+		ftdm_log(FTDM_LOG_ERROR, "TONE ERROR\n");
+		goto done;
+	}
+
+	ftdm_set_flag_locked(ftdmchan, FTDM_CHANNEL_INTHREAD);
+	teletone_init_session(&ts, 0, teletone_handler, dt_buffer);
+	ts.rate = 8000;
+#if 0
+	ts.debug = 1;
+	ts.debug_stream = stdout;
+#endif
+	ftdm_channel_command(ftdmchan, FTDM_COMMAND_GET_INTERVAL, &interval);
+	ftdm_buffer_set_loops(dt_buffer, -1);
+	
+	memset(&sig, 0, sizeof(sig));
+	sig.chan_id = ftdmchan->chan_id;
+	sig.span_id = ftdmchan->span_id;
+	sig.channel = ftdmchan;
+	
+	assert(interval != 0);
+
+	while (ftdm_running() && ftdm_test_flag(ftdmchan, FTDM_CHANNEL_INTHREAD)) {
+		ftdm_wait_flag_t flags = FTDM_READ;
+		ftdm_size_t dlen = 0;
+		
+		len = sizeof(frame);
+		
+		elapsed += interval;
+		state_counter += interval;
+		
+		if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE)) {
+			switch(ftdmchan->state) {
+			case FTDM_CHANNEL_STATE_GET_CALLERID:
+				{
+					if (state_counter > 5000 || !ftdm_test_flag(ftdmchan, FTDM_CHANNEL_CALLERID_DETECT)) {
+						ftdm_channel_command(ftdmchan, FTDM_COMMAND_DISABLE_CALLERID_DETECT, NULL);
+						ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_IDLE);
+					}
+				}
+				break;
+			case FTDM_CHANNEL_STATE_DIALING:
+				{
+					if (state_counter > dial_timeout) {
+						if (ftdmchan->needed_tones[FTDM_TONEMAP_DIAL]) {
+							ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_BUSY);
+						} else {
+							ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_UP);
+						}
+					} 
+				}
+				break;
+			case FTDM_CHANNEL_STATE_GENRING:
+				{
+					if (state_counter > 60000) {
+						ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
+					} else if (!ftdmchan->fsk_buffer || !ftdm_buffer_inuse(ftdmchan->fsk_buffer)) {
+						ftdm_sleep(interval);
+						continue;
+					}
+				}
+				break;
+			case FTDM_CHANNEL_STATE_DIALTONE:
+				{
+					if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_HOLD) && state_counter > 10000) {
+						ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_BUSY);
+					}
+				}
+				break;
+			case FTDM_CHANNEL_STATE_BUSY:
+				{
+					if (state_counter > 20000) {
+						ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_ATTN);
+					}
+				}
+				break;
+			case FTDM_CHANNEL_STATE_ATTN:
+				{
+					if (state_counter > 20000) {
+						ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
+					}
+				}
+				break;
+			case FTDM_CHANNEL_STATE_HANGUP:
+				{
+					if (state_counter > 500) {
+						if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_RINGING)) {
+							ftdm_channel_command(ftdmchan, FTDM_COMMAND_GENERATE_RING_OFF, NULL);
+						}
+						
+						if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OFFHOOK) && 
+							(ftdmchan->last_state == FTDM_CHANNEL_STATE_RING || ftdmchan->last_state == FTDM_CHANNEL_STATE_DIALTONE 
+							 || ftdmchan->last_state >= FTDM_CHANNEL_STATE_IDLE)) {
+							ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_BUSY);
+						} else {
+							ftdmchan->caller_data.hangup_cause = FTDM_CAUSE_NORMAL_CLEARING;
+							ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
+						}
+					}
+				}
+				break;
+			case FTDM_CHANNEL_STATE_CALLWAITING:
+				{
+					int done = 0;
+					
+					if (ftdmchan->detected_tones[FTDM_TONEMAP_CALLWAITING_ACK] == 1) {
+						send_caller_id(ftdmchan);
+						ftdmchan->detected_tones[FTDM_TONEMAP_CALLWAITING_ACK]++;
+					} else if (state_counter > 600 && !ftdmchan->detected_tones[FTDM_TONEMAP_CALLWAITING_ACK]) {
+						send_caller_id(ftdmchan);
+						ftdmchan->detected_tones[FTDM_TONEMAP_CALLWAITING_ACK]++;
+					} else if (state_counter > 1000 && !ftdmchan->detected_tones[FTDM_TONEMAP_CALLWAITING_ACK]) {
+						done = 1;
+					} else if (state_counter > 10000) {
+						if (ftdmchan->fsk_buffer) {
+							ftdm_buffer_zero(ftdmchan->fsk_buffer);
+						} else {
+							ftdm_buffer_create(&ftdmchan->fsk_buffer, 128, 128, 0);
+						}
+						
+						ts.user_data = ftdmchan->fsk_buffer;
+						teletone_run(&ts, ftdmchan->span->tone_map[FTDM_TONEMAP_CALLWAITING_SAS]);
+						ts.user_data = dt_buffer;
+						done = 1;
+					}
+
+					if (done) {
+						ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_UP);
+						ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_STATE_CHANGE);
+						ftdm_clear_flag_locked(ftdmchan->span, FTDM_SPAN_STATE_CHANGE);
+						ftdmchan->detected_tones[FTDM_TONEMAP_CALLWAITING_ACK] = 0;
+					}
+				}
+			case FTDM_CHANNEL_STATE_UP:
+			case FTDM_CHANNEL_STATE_IDLE:
+				{
+					ftdm_sleep(interval);
+					continue;
+				}
+				break;
+			case FTDM_CHANNEL_STATE_DOWN:
+				{
+					goto done;
+				}
+				break;
+			default:
+				break;
+			}
+		} else {
+			ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_STATE_CHANGE);
+			ftdm_clear_flag_locked(ftdmchan->span, FTDM_SPAN_STATE_CHANGE);
+			ftdm_channel_complete_state(ftdmchan);
+			indicate = 0;
+			state_counter = 0;
+
+			ftdm_log(FTDM_LOG_DEBUG, "Executing state handler on %d:%d for %s\n", 
+					ftdmchan->span_id, ftdmchan->chan_id,
+					ftdm_channel_state2str(ftdmchan->state));
+			switch(ftdmchan->state) {
+			case FTDM_CHANNEL_STATE_UP:
+				{
+					ftdm_channel_use(ftdmchan);
+					ftdm_channel_clear_needed_tones(ftdmchan);
+					ftdm_channel_flush_dtmf(ftdmchan);
+						
+					if (ftdmchan->type == FTDM_CHAN_TYPE_FXO && !ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OFFHOOK)) {
+						ftdm_channel_command(ftdmchan, FTDM_COMMAND_OFFHOOK, NULL);
+					}
+
+					if (ftdmchan->fsk_buffer && ftdm_buffer_inuse(ftdmchan->fsk_buffer)) {
+						ftdm_log(FTDM_LOG_DEBUG, "Cancel FSK transmit due to early answer.\n");
+						ftdm_buffer_zero(ftdmchan->fsk_buffer);
+					}
+
+					if (ftdmchan->type == FTDM_CHAN_TYPE_FXS && ftdm_test_flag(ftdmchan, FTDM_CHANNEL_RINGING)) {
+						ftdm_channel_command(ftdmchan, FTDM_COMMAND_GENERATE_RING_OFF, NULL);
+					}
+
+					if (ftdmchan->token_count == 1) {
+						ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_HOLD);
+					}
+
+					if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_HOLD)) {
+						ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_HOLD);
+						sig.event_id = FTDM_SIGEVENT_ADD_CALL;
+					} else {
+						sig.event_id = FTDM_SIGEVENT_UP;
+					}
+
+					ftdm_span_send_signal(ftdmchan->span, &sig);
+					continue;
+				}
+				break;
+			case FTDM_CHANNEL_STATE_DIALING:
+				{
+					ftdm_channel_use(ftdmchan);
+				}
+				break;
+			case FTDM_CHANNEL_STATE_IDLE:
+				{
+					ftdm_channel_use(ftdmchan);
+					sig.event_id = FTDM_SIGEVENT_START;
+
+					if (ftdmchan->type == FTDM_CHAN_TYPE_FXO) {
+						ftdm_set_string(ftdmchan->caller_data.dnis.digits, ftdmchan->chan_number);
+					} else {
+						ftdm_set_string(ftdmchan->caller_data.dnis.digits, dtmf);
+					}
+
+					ftdm_span_send_signal(ftdmchan->span, &sig);
+					continue;
+				}
+				break;
+			case FTDM_CHANNEL_STATE_DOWN:
+				{
+					sig.event_id = FTDM_SIGEVENT_STOP;
+					ftdm_span_send_signal(ftdmchan->span, &sig);
+					goto done;
+				}
+				break;
+			case FTDM_CHANNEL_STATE_DIALTONE:
+				{
+					memset(&ftdmchan->caller_data, 0, sizeof(ftdmchan->caller_data));
+					*dtmf = '\0';
+					dtmf_offset = 0;
+					ftdm_buffer_zero(dt_buffer);
+					teletone_run(&ts, ftdmchan->span->tone_map[FTDM_TONEMAP_DIAL]);
+					indicate = 1;
+				}
+				break;
+			case FTDM_CHANNEL_STATE_CALLWAITING:
+				{
+					ftdmchan->detected_tones[FTDM_TONEMAP_CALLWAITING_ACK] = 0;
+					if (ftdmchan->fsk_buffer) {
+						ftdm_buffer_zero(ftdmchan->fsk_buffer);
+					} else {
+						ftdm_buffer_create(&ftdmchan->fsk_buffer, 128, 128, 0);
+					}
+					
+					ts.user_data = ftdmchan->fsk_buffer;
+					teletone_run(&ts, ftdmchan->span->tone_map[FTDM_TONEMAP_CALLWAITING_SAS]);
+					teletone_run(&ts, ftdmchan->span->tone_map[FTDM_TONEMAP_CALLWAITING_CAS]);
+					ts.user_data = dt_buffer;
+				}
+				break;
+			case FTDM_CHANNEL_STATE_GENRING:
+				{
+					ftdm_sigmsg_t sig;
+
+					send_caller_id(ftdmchan);
+					ftdm_channel_command(ftdmchan, FTDM_COMMAND_GENERATE_RING_ON, NULL);
+
+					memset(&sig, 0, sizeof(sig));
+					sig.chan_id = ftdmchan->chan_id;
+					sig.span_id = ftdmchan->span_id;
+					sig.channel = ftdmchan;
+					sig.event_id = FTDM_SIGEVENT_PROGRESS;
+					ftdm_span_send_signal(ftdmchan->span, &sig);
+					
+				}
+				break;
+			case FTDM_CHANNEL_STATE_GET_CALLERID:
+				{
+					memset(&ftdmchan->caller_data, 0, sizeof(ftdmchan->caller_data));
+					ftdm_channel_command(ftdmchan, FTDM_COMMAND_ENABLE_CALLERID_DETECT, NULL);
+					continue;
+				}
+				break;
+			case FTDM_CHANNEL_STATE_RING:
+				{
+					ftdm_buffer_zero(dt_buffer);
+					teletone_run(&ts, ftdmchan->span->tone_map[FTDM_TONEMAP_RING]);
+					indicate = 1;
+					
+				}
+				break;
+			case FTDM_CHANNEL_STATE_BUSY:
+				{
+					ftdmchan->caller_data.hangup_cause = FTDM_CAUSE_NORMAL_CIRCUIT_CONGESTION;
+					if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OFFHOOK) && !ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
+						ftdm_buffer_zero(dt_buffer);
+						teletone_run(&ts, ftdmchan->span->tone_map[FTDM_TONEMAP_BUSY]);
+						indicate = 1;
+					} else {
+						ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
+					}
+				}
+				break;
+			case FTDM_CHANNEL_STATE_ATTN:
+				{
+					if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OFFHOOK) && !ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
+						ftdm_buffer_zero(dt_buffer);
+						teletone_run(&ts, ftdmchan->span->tone_map[FTDM_TONEMAP_ATTN]);
+						indicate = 1;
+					} else {
+						ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
+					}
+				}
+				break;
+			default:
+				break;
+			}
+		}
+
+
+		if (ftdmchan->state == FTDM_CHANNEL_STATE_DIALTONE || ftdmchan->state == FTDM_CHANNEL_STATE_COLLECT) {
+			if ((dlen = ftdm_channel_dequeue_dtmf(ftdmchan, dtmf + dtmf_offset, sizeof(dtmf) - strlen(dtmf)))) {
+
+				if (ftdmchan->state == FTDM_CHANNEL_STATE_DIALTONE) {
+					ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_COLLECT);
+					collecting = 1;
+				}
+				dtmf_offset = strlen(dtmf);
+				last_digit = elapsed;
+				sig.event_id = FTDM_SIGEVENT_COLLECTED_DIGIT;
+				sig.raw_data = dtmf;
+				if (ftdm_span_send_signal(ftdmchan->span, &sig) == FTDM_BREAK) {
+					collecting = 0;
+				}
+			}
+			else if(!analog_data->max_dialstr)
+			{
+				last_digit = elapsed;
+				collecting = 0;
+				strcpy(dtmf, analog_data->hotline);
+			}
+		}
+
+
+		if (last_digit && (!collecting || ((elapsed - last_digit > analog_data->digit_timeout) || strlen(dtmf) >= analog_data->max_dialstr))) {
+			ftdm_log(FTDM_LOG_DEBUG, "Number obtained [%s]\n", dtmf);
+			ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_IDLE);
+			last_digit = 0;
+			collecting = 0;
+		}
+
+		if (ftdm_channel_wait(ftdmchan, &flags, interval * 2) != FTDM_SUCCESS) {
+			continue;
+		}
+
+		if (!(flags & FTDM_READ)) {
+			continue;
+		}
+
+		if (ftdm_channel_read(ftdmchan, frame, &len) != FTDM_SUCCESS) {
+			ftdm_log(FTDM_LOG_ERROR, "READ ERROR [%s]\n", ftdmchan->last_error);
+			goto done;
+		}
+
+		if (ftdmchan->type == FTDM_CHAN_TYPE_FXO && ftdmchan->detected_tones[0]) {
+			ftdm_sigmsg_t sig;
+			int i;
+			memset(&sig, 0, sizeof(sig));
+			sig.chan_id = ftdmchan->chan_id;
+			sig.span_id = ftdmchan->span_id;
+			sig.channel = ftdmchan;
+			sig.event_id = FTDM_SIGEVENT_TONE_DETECTED;
+			
+			for (i = 1; i < FTDM_TONEMAP_INVALID; i++) {
+				if (ftdmchan->detected_tones[i]) {
+					ftdm_log(FTDM_LOG_DEBUG, "Detected tone %s on %d:%d\n", ftdm_tonemap2str(i), ftdmchan->span_id, ftdmchan->chan_id);
+					sig.raw_data = &i;
+					ftdm_span_send_signal(ftdmchan->span, &sig);
+				}
+			}
+			
+			if (ftdmchan->detected_tones[FTDM_TONEMAP_BUSY] || 
+				ftdmchan->detected_tones[FTDM_TONEMAP_FAIL1] ||
+				ftdmchan->detected_tones[FTDM_TONEMAP_FAIL2] ||
+				ftdmchan->detected_tones[FTDM_TONEMAP_FAIL3] ||
+				ftdmchan->detected_tones[FTDM_TONEMAP_ATTN]
+				) {
+				ftdm_log(FTDM_LOG_ERROR, "Failure indication detected!\n");
+				ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_BUSY);
+			} else if (ftdmchan->detected_tones[FTDM_TONEMAP_DIAL]) {
+				if (ftdm_strlen_zero(ftdmchan->caller_data.dnis.digits)) {
+					ftdm_log(FTDM_LOG_ERROR, "No Digits to send!\n");
+					ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_BUSY);
+				} else {
+					if (ftdm_channel_command(ftdmchan, FTDM_COMMAND_SEND_DTMF, ftdmchan->caller_data.dnis.digits) != FTDM_SUCCESS) {
+						ftdm_log(FTDM_LOG_ERROR, "Send Digits Failed [%s]\n", ftdmchan->last_error);
+						ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_BUSY);
+					} else {
+						state_counter = 0;
+						ftdmchan->needed_tones[FTDM_TONEMAP_RING] = 1;
+						ftdmchan->needed_tones[FTDM_TONEMAP_BUSY] = 1;
+						ftdmchan->needed_tones[FTDM_TONEMAP_FAIL1] = 1;
+						ftdmchan->needed_tones[FTDM_TONEMAP_FAIL2] = 1;
+						ftdmchan->needed_tones[FTDM_TONEMAP_FAIL3] = 1;
+						dial_timeout = ((ftdmchan->dtmf_on + ftdmchan->dtmf_off) * strlen(ftdmchan->caller_data.dnis.digits)) + 2000;
+					}
+				}
+			} else if (ftdmchan->detected_tones[FTDM_TONEMAP_RING]) {
+				ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_UP);
+			}
+			
+			ftdm_channel_clear_detected_tones(ftdmchan);
+		}
+
+		if ((ftdmchan->dtmf_buffer && ftdm_buffer_inuse(ftdmchan->dtmf_buffer)) || (ftdmchan->fsk_buffer && ftdm_buffer_inuse(ftdmchan->fsk_buffer))) {
+			//rlen = len;
+			//memset(frame, 0, len);
+			//ftdm_channel_write(ftdmchan, frame, sizeof(frame), &rlen);
+			continue;
+		}
+		
+		if (!indicate) {
+			continue;
+		}
+
+		if (ftdmchan->type == FTDM_CHAN_TYPE_FXO && !ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OFFHOOK)) {
+			ftdm_channel_command(ftdmchan, FTDM_COMMAND_OFFHOOK, NULL);
+		}
+
+		if (ftdmchan->effective_codec != FTDM_CODEC_SLIN) {
+			len *= 2;
+		}
+
+		rlen = ftdm_buffer_read_loop(dt_buffer, frame, len);					
+		
+		if (ftdmchan->effective_codec != FTDM_CODEC_SLIN) {
+			fio_codec_t codec_func = NULL;
+
+			if (ftdmchan->native_codec == FTDM_CODEC_ULAW) {
+				codec_func = fio_slin2ulaw;
+			} else if (ftdmchan->native_codec == FTDM_CODEC_ALAW) {
+				codec_func = fio_slin2alaw;
+			}
+
+			if (codec_func) {
+				status = codec_func(frame, sizeof(frame), &rlen);
+			} else {
+				snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "codec error!");
+				goto done;
+			}
+		}
+
+		ftdm_channel_write(ftdmchan, frame, sizeof(frame), &rlen);
+	}
+
+ done:
+
+
+	if (ftdmchan->type == FTDM_CHAN_TYPE_FXO && ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OFFHOOK)) {
+		ftdm_channel_command(ftdmchan, FTDM_COMMAND_ONHOOK, NULL);
+	}
+
+	if (ftdmchan->type == FTDM_CHAN_TYPE_FXS && ftdm_test_flag(ftdmchan, FTDM_CHANNEL_RINGING)) {
+		ftdm_channel_command(ftdmchan, FTDM_COMMAND_GENERATE_RING_OFF, NULL);
+	}
+
+	
+	closed_chan = ftdmchan;
+	ftdm_channel_close(&ftdmchan);
+
+	ftdm_channel_command(closed_chan, FTDM_COMMAND_SET_NATIVE_CODEC, NULL);
+
+	if (ts.buffer) {
+		teletone_destroy_session(&ts);
+	}
+
+	if (dt_buffer) {
+		ftdm_buffer_destroy(&dt_buffer);
+	}
+
+	if (closed_chan->state != FTDM_CHANNEL_STATE_DOWN) {
+		ftdm_set_state_locked(closed_chan, FTDM_CHANNEL_STATE_DOWN);
+	}
+
+	ftdm_log(FTDM_LOG_DEBUG, "ANALOG CHANNEL %d:%d thread ended.\n", closed_chan->span_id, closed_chan->chan_id);
+	ftdm_clear_flag(closed_chan, FTDM_CHANNEL_INTHREAD);
+
+	return NULL;
+}
+
+/**
+ * \brief Processes freetdm event
+ * \param span Span on which the event was fired
+ * \param event Event to be treated
+ * \return Success or failure
+ */
+static __inline__ ftdm_status_t process_event(ftdm_span_t *span, ftdm_event_t *event)
+{
+	ftdm_sigmsg_t sig;
+	ftdm_analog_data_t *analog_data = event->channel->span->signal_data;
+	int locked = 0;
+	
+	memset(&sig, 0, sizeof(sig));
+	sig.chan_id = event->channel->chan_id;
+	sig.span_id = event->channel->span_id;
+	sig.channel = event->channel;
+
+
+	ftdm_log(FTDM_LOG_DEBUG, "EVENT [%s][%d:%d] STATE [%s]\n", 
+			ftdm_oob_event2str(event->enum_id), event->channel->span_id, event->channel->chan_id, ftdm_channel_state2str(event->channel->state));
+
+	ftdm_mutex_lock(event->channel->mutex);
+	locked++;
+
+	switch(event->enum_id) {
+	case FTDM_OOB_RING_START:
+		{
+			if (event->channel->type != FTDM_CHAN_TYPE_FXO) {
+				ftdm_log(FTDM_LOG_ERROR, "Cannot get a RING_START event on a non-fxo channel, please check your config.\n");
+				ftdm_set_state_locked(event->channel, FTDM_CHANNEL_STATE_DOWN);
+				goto end;
+			}
+			if (!event->channel->ring_count && (event->channel->state == FTDM_CHANNEL_STATE_DOWN && !ftdm_test_flag(event->channel, FTDM_CHANNEL_INTHREAD))) {
+				if (ftdm_test_flag(analog_data, FTDM_ANALOG_CALLERID)) {
+					ftdm_set_state_locked(event->channel, FTDM_CHANNEL_STATE_GET_CALLERID);
+				} else {
+					ftdm_set_state_locked(event->channel, FTDM_CHANNEL_STATE_IDLE);
+				}
+				event->channel->ring_count = 1;
+				ftdm_mutex_unlock(event->channel->mutex);
+				locked = 0;
+				ftdm_thread_create_detached(ftdm_analog_channel_run, event->channel);
+			} else {
+				event->channel->ring_count++;
+			}
+		}
+		break;
+	case FTDM_OOB_ONHOOK:
+		{
+			if (ftdm_test_flag(event->channel, FTDM_CHANNEL_RINGING)) {
+				ftdm_channel_command(event->channel, FTDM_COMMAND_GENERATE_RING_OFF, NULL);
+			}
+
+			if (event->channel->state != FTDM_CHANNEL_STATE_DOWN) {
+				ftdm_set_state_locked(event->channel, FTDM_CHANNEL_STATE_DOWN);
+			}
+
+		}
+		break;
+	case FTDM_OOB_FLASH:
+		{
+			if (event->channel->state == FTDM_CHANNEL_STATE_CALLWAITING) {
+				ftdm_set_state_locked(event->channel, FTDM_CHANNEL_STATE_UP);
+				ftdm_clear_flag_locked(event->channel, FTDM_CHANNEL_STATE_CHANGE);
+				ftdm_clear_flag_locked(event->channel->span, FTDM_SPAN_STATE_CHANGE);
+				event->channel->detected_tones[FTDM_TONEMAP_CALLWAITING_ACK] = 0;
+			} 
+
+			ftdm_channel_rotate_tokens(event->channel);
+			
+			if (ftdm_test_flag(event->channel, FTDM_CHANNEL_HOLD) && event->channel->token_count != 1) {
+				ftdm_set_state_locked(event->channel,  FTDM_CHANNEL_STATE_UP);
+			} else {
+				sig.event_id = FTDM_SIGEVENT_FLASH;
+				ftdm_span_send_signal(span, &sig);
+			}
+		}
+		break;
+	case FTDM_OOB_OFFHOOK:
+		{
+			if (event->channel->type == FTDM_CHAN_TYPE_FXS) {
+				if (ftdm_test_flag(event->channel, FTDM_CHANNEL_INTHREAD)) {
+					if (ftdm_test_flag(event->channel, FTDM_CHANNEL_RINGING)) {
+						ftdm_channel_command(event->channel, FTDM_COMMAND_GENERATE_RING_OFF, NULL);
+					}
+					ftdm_set_state_locked(event->channel, FTDM_CHANNEL_STATE_UP);
+				} else {
+					if(!analog_data->max_dialstr) {
+						ftdm_set_state_locked(event->channel, FTDM_CHANNEL_STATE_COLLECT);
+					} else {
+						ftdm_set_state_locked(event->channel, FTDM_CHANNEL_STATE_DIALTONE);
+					}						
+					ftdm_mutex_unlock(event->channel->mutex);
+					locked = 0;
+					ftdm_thread_create_detached(ftdm_analog_channel_run, event->channel);
+				}
+			} else {
+				if (!ftdm_test_flag(event->channel, FTDM_CHANNEL_INTHREAD)) {
+					if (ftdm_test_flag(event->channel, FTDM_CHANNEL_OFFHOOK)) {
+						ftdm_channel_command(event->channel, FTDM_COMMAND_ONHOOK, NULL);
+					}
+				}
+				ftdm_set_state_locked(event->channel, FTDM_CHANNEL_STATE_DOWN);
+			}
+		}
+	}
+
+ end:
+
+	if (locked) {
+		ftdm_mutex_unlock(event->channel->mutex);
+	}
+	return FTDM_SUCCESS;
+}
+
+/**
+ * \brief Main thread function for analog span (monitor)
+ * \param me Current thread
+ * \param obj Span to run in this thread
+ */
+static void *ftdm_analog_run(ftdm_thread_t *me, void *obj)
+{
+	ftdm_span_t *span = (ftdm_span_t *) obj;
+	ftdm_analog_data_t *analog_data = span->signal_data;
+	int errs = 0;
+	
+	ftdm_log(FTDM_LOG_DEBUG, "ANALOG thread starting.\n");
+
+	while(ftdm_running() && ftdm_test_flag(analog_data, FTDM_ANALOG_RUNNING)) {
+		int waitms = 1000;
+		ftdm_status_t status;
+
+		if ((status = ftdm_span_poll_event(span, waitms)) != FTDM_FAIL) {
+			errs = 0;
+		}
+		
+		switch(status) {
+		case FTDM_SUCCESS:
+			{
+				ftdm_event_t *event;
+				while (ftdm_span_next_event(span, &event) == FTDM_SUCCESS) {
+					if (event->enum_id == FTDM_OOB_NOOP) {
+						continue;
+					}
+					if (process_event(span, event) != FTDM_SUCCESS) {
+						goto end;
+					}
+				}
+			}
+			break;
+		case FTDM_FAIL:
+			{
+				ftdm_log(FTDM_LOG_ERROR, "Failure Polling event! [%s]\n", span->last_error);
+				if (++errs > 300) {
+					ftdm_log(FTDM_LOG_CRIT, "Too Many Errors!\n");
+					goto end;
+				}
+			}
+			break;
+		default:
+			break;
+		}
+
+	}
+
+ end:
+
+	ftdm_clear_flag(analog_data, FTDM_ANALOG_RUNNING);
+	
+	ftdm_log(FTDM_LOG_DEBUG, "ANALOG thread ending.\n");
+
+	return NULL;
+}
+
+/**
+ * \brief FreeTDM analog signaling module initialisation
+ * \return Success
+ */
+static FIO_SIG_LOAD_FUNCTION(ftdm_analog_init)
+{
+	return FTDM_SUCCESS;
+}
+
+/**
+ * \brief FreeTDM analog signaling module definition
+ */
+EX_DECLARE_DATA ftdm_module_t ftdm_module = {
+	"analog",
+	NULL,
+	NULL,
+	ftdm_analog_init,
+	ftdm_analog_configure_span,
+	NULL
+};
+
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */

Added: freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_analog/ozmod_analog.2005.vcproj (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_analog/ozmod_analog.2005.vcproj	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_analog/ozmod_analog.2005.vcproj	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,202 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="8.00"
+	Name="ftmod_analog"
+	ProjectGUID="{37C94798-6E33-4B4F-8EE0-C72A7DC91157}"
+	RootNamespace="ftmod_analog"
+	Keyword="Win32Proj"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="2"
+			CharacterSet="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				AdditionalIncludeDirectories="..\..\include;..\..\isdn\include"
+				PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;FTMOD_ANALOG_EXPORTS"
+				MinimalRebuild="true"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="3"
+				UsePrecompiledHeader="0"
+				WarningLevel="4"
+				WarnAsError="true"
+				DebugInformationFormat="4"
+				DisableSpecificWarnings="4100"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				LinkIncremental="2"
+				GenerateDebugInformation="true"
+				SubSystem="2"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="2"
+			CharacterSet="1"
+			WholeProgramOptimization="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="2"
+				EnableIntrinsicFunctions="true"
+				AdditionalIncludeDirectories="..\..\include;..\..\isdn\include"
+				PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;FTMOD_ANALOG_EXPORTS"
+				RuntimeLibrary="2"
+				EnableFunctionLevelLinking="true"
+				UsePrecompiledHeader="0"
+				WarningLevel="4"
+				WarnAsError="true"
+				DebugInformationFormat="3"
+				DisableSpecificWarnings="4100"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				LinkIncremental="1"
+				GenerateDebugInformation="true"
+				SubSystem="2"
+				OptimizeReferences="2"
+				EnableCOMDATFolding="2"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<Filter
+			Name="Source Files"
+			Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+			>
+			<File
+				RelativePath="ftmod_analog.c"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="Header Files"
+			Filter="h;hpp;hxx;hm;inl;inc;xsd"
+			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+			>
+			<File
+				RelativePath="ftdm_analog.h"
+				>
+			</File>
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>

Added: freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_analog_em/ftdm_analog_em.h (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_analog_em/ftdm_analog_em.h	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_analog_em/ftdm_analog_em.h	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2008, Anthony Minessale II
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Contributor(s):
+ *
+ * John Wehle (john@feith.com)
+ *
+ */
+
+#ifndef FTDM_ANALOG_EM_H
+#define FTDM_ANALOG_EM_H
+#include "freetdm.h"
+
+#define MAX_DIALSTRING 256
+
+typedef enum {
+	FTDM_ANALOG_EM_RUNNING = (1 << 0)
+} ftdm_analog_em_flag_t;
+
+
+struct ftdm_analog_data {
+	uint32_t flags;
+	uint32_t max_dialstr;
+	uint32_t digit_timeout;
+};
+
+static void *ftdm_analog_em_run(ftdm_thread_t *me, void *obj);
+typedef struct ftdm_analog_data ftdm_analog_em_data_t;
+
+#endif
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */

Added: freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_analog_em/ftmod_analog_em.2008.vcproj (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_analog_em/ftmod_analog_em.2008.vcproj	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_analog_em/ftmod_analog_em.2008.vcproj	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,353 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="9.00"
+	Name="ftmod_analog_em"
+	ProjectGUID="{B3F49375-2834-4937-9D8C-4AC2EC911010}"
+	RootNamespace="ftmod_analog_em"
+	Keyword="Win32Proj"
+	TargetFrameworkVersion="196613"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+		<Platform
+			Name="x64"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="2"
+			CharacterSet="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				AdditionalIncludeDirectories="..\..\include;..\..\isdn\include"
+				PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;FTMOD_ANALOG_EM_EXPORTS"
+				MinimalRebuild="true"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="3"
+				UsePrecompiledHeader="0"
+				WarningLevel="4"
+				WarnAsError="true"
+				DebugInformationFormat="4"
+				DisableSpecificWarnings="4100"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				LinkIncremental="2"
+				GenerateDebugInformation="true"
+				SubSystem="2"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="2"
+			CharacterSet="1"
+			WholeProgramOptimization="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="2"
+				EnableIntrinsicFunctions="true"
+				AdditionalIncludeDirectories="..\..\include;..\..\isdn\include"
+				PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;FTMOD_ANALOG_EM_EXPORTS"
+				RuntimeLibrary="2"
+				EnableFunctionLevelLinking="true"
+				UsePrecompiledHeader="0"
+				WarningLevel="4"
+				WarnAsError="true"
+				DebugInformationFormat="3"
+				DisableSpecificWarnings="4100"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				LinkIncremental="1"
+				GenerateDebugInformation="true"
+				SubSystem="2"
+				OptimizeReferences="2"
+				EnableCOMDATFolding="2"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Debug|x64"
+			OutputDirectory="$(SolutionDir)$(PlatformName)\$(ConfigurationName)"
+			IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+			ConfigurationType="2"
+			CharacterSet="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+				TargetEnvironment="3"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				AdditionalIncludeDirectories="..\..\include;..\..\isdn\include"
+				PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;FTMOD_ANALOG_EM_EXPORTS"
+				MinimalRebuild="true"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="3"
+				UsePrecompiledHeader="0"
+				WarningLevel="4"
+				WarnAsError="false"
+				DebugInformationFormat="3"
+				DisableSpecificWarnings="4100"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				LinkIncremental="2"
+				GenerateDebugInformation="true"
+				SubSystem="2"
+				TargetMachine="17"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|x64"
+			OutputDirectory="$(SolutionDir)$(PlatformName)\$(ConfigurationName)"
+			IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+			ConfigurationType="2"
+			CharacterSet="1"
+			WholeProgramOptimization="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+				TargetEnvironment="3"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="2"
+				EnableIntrinsicFunctions="true"
+				AdditionalIncludeDirectories="..\..\include;..\..\isdn\include"
+				PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;FTMOD_ANALOG_EM_EXPORTS"
+				RuntimeLibrary="2"
+				EnableFunctionLevelLinking="true"
+				UsePrecompiledHeader="0"
+				WarningLevel="4"
+				WarnAsError="true"
+				DebugInformationFormat="3"
+				DisableSpecificWarnings="4100"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				LinkIncremental="1"
+				GenerateDebugInformation="true"
+				SubSystem="2"
+				OptimizeReferences="2"
+				EnableCOMDATFolding="2"
+				TargetMachine="17"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<Filter
+			Name="Source Files"
+			Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+			>
+			<File
+				RelativePath="ftmod_analog_em.c"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="Header Files"
+			Filter="h;hpp;hxx;hm;inl;inc;xsd"
+			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+			>
+			<File
+				RelativePath="ftdm_analog_em.h"
+				>
+			</File>
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>

Added: freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_analog_em/ftmod_analog_em.c (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_analog_em/ftmod_analog_em.c	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_analog_em/ftmod_analog_em.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,707 @@
+/*
+ * Copyright (c) 2008, Anthony Minessale II
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Contributor(s):
+ *
+ * John Wehle (john@feith.com)
+ *
+ */
+
+#include "freetdm.h"
+#include "ftdm_analog_em.h"
+
+#ifndef localtime_r
+struct tm * localtime_r(const time_t *clock, struct tm *result);
+#endif
+
+static void *ftdm_analog_em_channel_run(ftdm_thread_t *me, void *obj);
+
+/**
+ * \brief Starts an EM channel thread (outgoing call)
+ * \param ftdmchan Channel to initiate call on
+ * \return Success or failure
+ *
+ * Initialises state, starts tone progress detection and runs the channel in a new a thread.
+ */
+static FIO_CHANNEL_OUTGOING_CALL_FUNCTION(analog_em_outgoing_call)
+{
+	if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OFFHOOK) && !ftdm_test_flag(ftdmchan, FTDM_CHANNEL_INTHREAD)) {		
+		ftdm_channel_clear_needed_tones(ftdmchan);
+		ftdm_channel_clear_detected_tones(ftdmchan);
+
+		ftdm_set_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND);
+
+		ftdm_channel_command(ftdmchan, FTDM_COMMAND_OFFHOOK, NULL);
+		ftdm_channel_command(ftdmchan, FTDM_COMMAND_ENABLE_PROGRESS_DETECT, NULL);
+		ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DIALING);
+		ftdm_thread_create_detached(ftdm_analog_em_channel_run, ftdmchan);
+		return FTDM_SUCCESS;
+	}
+
+	return FTDM_FAIL;
+}
+
+/**
+ * \brief Starts an EM span thread (monitor)
+ * \param span Span to monitor
+ * \return Success or failure
+ */
+static ftdm_status_t ftdm_analog_em_start(ftdm_span_t *span)
+{
+	ftdm_analog_em_data_t *analog_data = span->signal_data;
+	ftdm_set_flag(analog_data, FTDM_ANALOG_EM_RUNNING);
+	return ftdm_thread_create_detached(ftdm_analog_em_run, span);
+}
+
+/**
+ * \brief Initialises an EM span from configuration variables
+ * \param span Span to configure
+ * \param sig_cb Callback function for event signals
+ * \param ap List of configuration variables
+ * \return Success or failure
+ */
+static FIO_SIG_CONFIGURE_FUNCTION(ftdm_analog_em_configure_span)
+//ftdm_status_t ftdm_analog_em_configure_span(ftdm_span_t *span, char *tonemap, uint32_t digit_timeout, uint32_t max_dialstr, fio_signal_cb_t sig_cb)
+{
+	ftdm_analog_em_data_t *analog_data;
+	const char *tonemap = "us";
+	uint32_t digit_timeout = 10;
+	uint32_t max_dialstr = 11;
+	const char *var, *val;
+	int *intval;
+
+	assert(sig_cb != NULL);
+
+	if (span->signal_type) {
+		snprintf(span->last_error, sizeof(span->last_error), "Span is already configured for signalling.");
+		return FTDM_FAIL;
+	}
+	
+	analog_data = ftdm_malloc(sizeof(*analog_data));
+	assert(analog_data != NULL);
+	memset(analog_data, 0, sizeof(*analog_data));
+
+	while((var = va_arg(ap, char *))) {
+		if (!strcasecmp(var, "tonemap")) {
+			if (!(val = va_arg(ap, char *))) {
+				break;
+			}
+			tonemap = val;
+		} else if (!strcasecmp(var, "digit_timeout")) {
+			if (!(intval = va_arg(ap, int *))) {
+				break;
+			}
+			digit_timeout = *intval;
+		} else if (!strcasecmp(var, "max_dialstr")) {
+			if (!(intval = va_arg(ap, int *))) {
+				break;
+			}
+			max_dialstr = *intval;
+		} else {
+			snprintf(span->last_error, sizeof(span->last_error), "Unknown parameter [%s]", var);
+			return FTDM_FAIL;
+		}
+	}
+
+
+	if (digit_timeout < 2000 || digit_timeout > 10000) {
+		digit_timeout = 2000;
+	}
+
+	if (max_dialstr < 2 || max_dialstr > MAX_DIALSTRING) {
+		ftdm_log(FTDM_LOG_ERROR, "Invalid max_dialstr, setting to %d\n", MAX_DIALSTRING);
+		max_dialstr = MAX_DIALSTRING;
+	}
+
+	span->start = ftdm_analog_em_start;
+	analog_data->digit_timeout = digit_timeout;
+	analog_data->max_dialstr = max_dialstr;
+	span->signal_cb = sig_cb;
+	span->signal_type = FTDM_SIGTYPE_ANALOG;
+	span->signal_data = analog_data;
+	span->outgoing_call = analog_em_outgoing_call;
+	ftdm_span_load_tones(span, tonemap);
+
+	return FTDM_SUCCESS;
+
+}
+
+/**
+ * \brief Retrieves tone generation output to be sent
+ * \param ts Teletone generator
+ * \param map Tone map
+ * \return -1 on error, 0 on success
+ */
+static int teletone_handler(teletone_generation_session_t *ts, teletone_tone_map_t *map)
+{
+	ftdm_buffer_t *dt_buffer = ts->user_data;
+	int wrote;
+
+	if (!dt_buffer) {
+		return -1;
+	}
+	wrote = teletone_mux_tones(ts, map);
+	ftdm_buffer_write(dt_buffer, ts->buffer, wrote * 2);
+	return 0;
+}
+
+/**
+ * \brief Main thread function for EM channel (outgoing call)
+ * \param me Current thread
+ * \param obj Channel to run in this thread
+ */
+static void *ftdm_analog_em_channel_run(ftdm_thread_t *me, void *obj)
+{
+	ftdm_channel_t *ftdmchan = (ftdm_channel_t *) obj;
+	ftdm_buffer_t *dt_buffer = NULL;
+	teletone_generation_session_t ts;
+	uint8_t frame[1024];
+	ftdm_size_t len, rlen;
+	ftdm_tone_type_t tt = FTDM_TONE_DTMF;
+	char dtmf[128] = "";
+	ftdm_size_t dtmf_offset = 0;
+	ftdm_analog_em_data_t *analog_data = ftdmchan->span->signal_data;
+	ftdm_channel_t *closed_chan;
+	uint32_t state_counter = 0, elapsed = 0, collecting = 0, interval = 0, last_digit = 0, indicate = 0, dial_timeout = 30000;
+	ftdm_sigmsg_t sig;
+	ftdm_status_t status;
+	
+	ftdm_log(FTDM_LOG_DEBUG, "ANALOG EM CHANNEL thread starting.\n");
+
+	ts.buffer = NULL;
+
+	if (ftdm_channel_open_chan(ftdmchan) != FTDM_SUCCESS) {
+		ftdm_log(FTDM_LOG_ERROR, "OPEN ERROR [%s]\n", ftdmchan->last_error);
+		goto done;
+	}
+
+	if (ftdm_buffer_create(&dt_buffer, 1024, 3192, 0) != FTDM_SUCCESS) {
+		snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "memory error!");
+		ftdm_log(FTDM_LOG_ERROR, "MEM ERROR\n");
+		goto done;
+	}
+
+	if (ftdm_channel_command(ftdmchan, FTDM_COMMAND_ENABLE_DTMF_DETECT, &tt) != FTDM_SUCCESS) {
+		snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "error initilizing tone detector!");
+		ftdm_log(FTDM_LOG_ERROR, "TONE ERROR\n");
+		goto done;
+	}
+
+	ftdm_set_flag_locked(ftdmchan, FTDM_CHANNEL_INTHREAD);
+	teletone_init_session(&ts, 0, teletone_handler, dt_buffer);
+	ts.rate = 8000;
+#if 0
+	ts.debug = 1;
+	ts.debug_stream = stdout;
+#endif
+	ftdm_channel_command(ftdmchan, FTDM_COMMAND_GET_INTERVAL, &interval);
+	ftdm_buffer_set_loops(dt_buffer, -1);
+	
+	memset(&sig, 0, sizeof(sig));
+	sig.chan_id = ftdmchan->chan_id;
+	sig.span_id = ftdmchan->span_id;
+	sig.channel = ftdmchan;
+	
+	assert(interval != 0);
+
+	while (ftdm_running() && ftdm_test_flag(ftdmchan, FTDM_CHANNEL_INTHREAD)) {
+		ftdm_wait_flag_t flags = FTDM_READ;
+		ftdm_size_t dlen = 0;
+		
+		len = sizeof(frame);
+		
+		elapsed += interval;
+		state_counter += interval;
+		
+		if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE)) {
+			switch(ftdmchan->state) {
+			case FTDM_CHANNEL_STATE_DIALING:
+				{
+					if (! ftdmchan->needed_tones[FTDM_TONEMAP_RING]
+						&& ftdm_test_flag(ftdmchan, FTDM_CHANNEL_WINK)) {
+						if (ftdm_strlen_zero(ftdmchan->caller_data.dnis.digits)) {
+							ftdm_log(FTDM_LOG_ERROR, "No Digits to send!\n");
+							ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_BUSY);
+						} else {
+							if (ftdm_channel_command(ftdmchan, FTDM_COMMAND_SEND_DTMF, ftdmchan->caller_data.dnis.digits) != FTDM_SUCCESS) {
+								ftdm_log(FTDM_LOG_ERROR, "Send Digits Failed [%s]\n", ftdmchan->last_error);
+								ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_BUSY);
+							} else {
+								state_counter = 0;
+								ftdmchan->needed_tones[FTDM_TONEMAP_RING] = 1;
+								ftdmchan->needed_tones[FTDM_TONEMAP_BUSY] = 1;
+								ftdmchan->needed_tones[FTDM_TONEMAP_FAIL1] = 1;
+								ftdmchan->needed_tones[FTDM_TONEMAP_FAIL2] = 1;
+								ftdmchan->needed_tones[FTDM_TONEMAP_FAIL3] = 1;
+								dial_timeout = ((ftdmchan->dtmf_on + ftdmchan->dtmf_off) * strlen(ftdmchan->caller_data.dnis.digits)) + 2000;
+							}
+						}
+						break;
+					}
+					if (state_counter > dial_timeout) {
+						if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_WINK)) {
+							ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_BUSY);
+						} else {
+							ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_UP);
+						}
+					} 
+				}
+				break;
+			case FTDM_CHANNEL_STATE_DIALTONE:
+				{
+					if (state_counter > 10000) {
+						ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_BUSY);
+					}
+				}
+				break;
+			case FTDM_CHANNEL_STATE_BUSY:
+				{
+					if (state_counter > 20000) {
+						ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_ATTN);
+					}
+				}
+				break;
+			case FTDM_CHANNEL_STATE_ATTN:
+				{
+					if (state_counter > 20000) {
+						ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
+					}
+				}
+				break;
+			case FTDM_CHANNEL_STATE_HANGUP:
+				{
+					if (state_counter > 500) {
+						if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OFFHOOK) && 
+							(ftdmchan->last_state == FTDM_CHANNEL_STATE_RING || ftdmchan->last_state == FTDM_CHANNEL_STATE_DIALTONE 
+							 || ftdmchan->last_state >= FTDM_CHANNEL_STATE_IDLE)) {
+							ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_BUSY);
+						} else {
+							ftdmchan->caller_data.hangup_cause = FTDM_CAUSE_NORMAL_CLEARING;
+							ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
+						}
+					}
+				}
+				break;
+			case FTDM_CHANNEL_STATE_UP:
+			case FTDM_CHANNEL_STATE_IDLE:
+				{
+					ftdm_sleep(interval);
+					continue;
+				}
+				break;
+			case FTDM_CHANNEL_STATE_DOWN:
+				{
+					goto done;
+				}
+				break;
+			default:
+				break;
+			}
+		} else {
+			ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_STATE_CHANGE);
+			ftdm_clear_flag_locked(ftdmchan->span, FTDM_SPAN_STATE_CHANGE);
+			ftdm_channel_complete_state(ftdmchan);
+			indicate = 0;
+			state_counter = 0;
+
+			ftdm_log(FTDM_LOG_DEBUG, "Executing state handler on %d:%d for %s\n", 
+					ftdmchan->span_id, ftdmchan->chan_id,
+					ftdm_channel_state2str(ftdmchan->state));
+			switch(ftdmchan->state) {
+			case FTDM_CHANNEL_STATE_UP:
+				{
+					ftdm_channel_use(ftdmchan);
+					ftdm_channel_clear_needed_tones(ftdmchan);
+					ftdm_channel_flush_dtmf(ftdmchan);
+
+					if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OFFHOOK)) {
+						ftdm_channel_command(ftdmchan, FTDM_COMMAND_OFFHOOK, NULL);
+					}
+
+					sig.event_id = FTDM_SIGEVENT_UP;
+
+					ftdm_span_send_signal(ftdmchan->span, &sig);
+					continue;
+				}
+				break;
+			case FTDM_CHANNEL_STATE_DIALING:
+				{
+					ftdm_channel_use(ftdmchan);
+				}
+				break;
+			case FTDM_CHANNEL_STATE_IDLE:
+				{
+					ftdm_channel_use(ftdmchan);
+
+					if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
+						ftdm_set_string(ftdmchan->caller_data.dnis.digits, ftdmchan->chan_number);
+					} else {
+						ftdm_set_string(ftdmchan->caller_data.dnis.digits, dtmf);
+					}
+
+					sig.event_id = FTDM_SIGEVENT_START;
+
+					ftdm_span_send_signal(ftdmchan->span, &sig);
+					continue;
+				}
+				break;
+			case FTDM_CHANNEL_STATE_DOWN:
+				{
+					sig.event_id = FTDM_SIGEVENT_STOP;
+					ftdm_span_send_signal(ftdmchan->span, &sig);
+					goto done;
+				}
+				break;
+			case FTDM_CHANNEL_STATE_DIALTONE:
+				{
+					memset(&ftdmchan->caller_data, 0, sizeof(ftdmchan->caller_data));
+					*dtmf = '\0';
+					dtmf_offset = 0;
+					ftdm_buffer_zero(dt_buffer);
+					teletone_run(&ts, ftdmchan->span->tone_map[FTDM_TONEMAP_DIAL]);
+					indicate = 1;
+
+					ftdm_channel_command(ftdmchan, FTDM_COMMAND_WINK, NULL);
+				}
+				break;
+			case FTDM_CHANNEL_STATE_RING:
+				{
+					ftdm_buffer_zero(dt_buffer);
+					teletone_run(&ts, ftdmchan->span->tone_map[FTDM_TONEMAP_RING]);
+					indicate = 1;
+				}
+				break;
+			case FTDM_CHANNEL_STATE_BUSY:
+				{
+					ftdmchan->caller_data.hangup_cause = FTDM_CAUSE_NORMAL_CIRCUIT_CONGESTION;
+					if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OFFHOOK) && !ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
+						ftdm_buffer_zero(dt_buffer);
+						teletone_run(&ts, ftdmchan->span->tone_map[FTDM_TONEMAP_BUSY]);
+						indicate = 1;
+					} else {
+						ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
+					}
+				}
+				break;
+			case FTDM_CHANNEL_STATE_ATTN:
+				{
+					if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OFFHOOK) && !ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
+						ftdm_buffer_zero(dt_buffer);
+						teletone_run(&ts, ftdmchan->span->tone_map[FTDM_TONEMAP_ATTN]);
+						indicate = 1;
+					} else {
+						ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
+					}
+				}
+				break;
+			default:
+				break;
+			}
+		}
+
+
+		if (ftdmchan->state == FTDM_CHANNEL_STATE_DIALTONE || ftdmchan->state == FTDM_CHANNEL_STATE_COLLECT) {
+			if ((dlen = ftdm_channel_dequeue_dtmf(ftdmchan, dtmf + dtmf_offset, sizeof(dtmf) - strlen(dtmf)))) {
+
+				if (ftdmchan->state == FTDM_CHANNEL_STATE_DIALTONE) {
+					ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_COLLECT);
+					collecting = 1;
+				}
+				dtmf_offset = strlen(dtmf);
+				last_digit = elapsed;
+				sig.event_id = FTDM_SIGEVENT_COLLECTED_DIGIT;
+				sig.raw_data = dtmf;
+				if (ftdm_span_send_signal(ftdmchan->span, &sig) == FTDM_BREAK) {
+					collecting = 0;
+				}
+			}
+		}
+
+
+		if (last_digit && (!collecting || ((elapsed - last_digit > analog_data->digit_timeout) || strlen(dtmf) > analog_data->max_dialstr))) {
+			ftdm_log(FTDM_LOG_DEBUG, "Number obtained [%s]\n", dtmf);
+			ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_IDLE);
+			last_digit = 0;
+			collecting = 0;
+		}
+
+		if (ftdm_channel_wait(ftdmchan, &flags, interval * 2) != FTDM_SUCCESS) {
+			continue;
+		}
+
+		if (!(flags & FTDM_READ)) {
+			continue;
+		}
+
+		if (ftdm_channel_read(ftdmchan, frame, &len) != FTDM_SUCCESS) {
+			ftdm_log(FTDM_LOG_ERROR, "READ ERROR [%s]\n", ftdmchan->last_error);
+			goto done;
+		}
+
+		if (ftdmchan->detected_tones[0]) {
+			ftdm_sigmsg_t sig;
+			int i;
+			memset(&sig, 0, sizeof(sig));
+			sig.chan_id = ftdmchan->chan_id;
+			sig.span_id = ftdmchan->span_id;
+			sig.channel = ftdmchan;
+			sig.event_id = FTDM_SIGEVENT_TONE_DETECTED;
+			
+			for (i = 1; i < FTDM_TONEMAP_INVALID; i++) {
+				if (ftdmchan->detected_tones[i]) {
+					ftdm_log(FTDM_LOG_DEBUG, "Detected tone %s on %d:%d\n", ftdm_tonemap2str(i), ftdmchan->span_id, ftdmchan->chan_id);
+					sig.raw_data = &i;
+					ftdm_span_send_signal(ftdmchan->span, &sig);
+				}
+			}
+			
+			if (ftdmchan->detected_tones[FTDM_TONEMAP_BUSY] || 
+				ftdmchan->detected_tones[FTDM_TONEMAP_FAIL1] ||
+				ftdmchan->detected_tones[FTDM_TONEMAP_FAIL2] ||
+				ftdmchan->detected_tones[FTDM_TONEMAP_FAIL3] ||
+				ftdmchan->detected_tones[FTDM_TONEMAP_ATTN]
+				) {
+				ftdm_log(FTDM_LOG_ERROR, "Failure indication detected!\n");
+				ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_BUSY);
+			} else if (ftdmchan->detected_tones[FTDM_TONEMAP_RING]) {
+				ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_UP);
+			}
+			
+			ftdm_channel_clear_detected_tones(ftdmchan);
+		}
+
+		if ((ftdmchan->dtmf_buffer && ftdm_buffer_inuse(ftdmchan->dtmf_buffer))) {
+			rlen = len;
+			memset(frame, 0, len);
+			ftdm_channel_write(ftdmchan, frame, sizeof(frame), &rlen);
+			continue;
+		}
+		
+		if (!indicate) {
+			continue;
+		}
+
+		if (ftdmchan->effective_codec != FTDM_CODEC_SLIN) {
+			len *= 2;
+		}
+
+		rlen = ftdm_buffer_read_loop(dt_buffer, frame, len);
+
+		if (ftdmchan->effective_codec != FTDM_CODEC_SLIN) {
+			fio_codec_t codec_func = NULL;
+
+			if (ftdmchan->native_codec == FTDM_CODEC_ULAW) {
+				codec_func = fio_slin2ulaw;
+			} else if (ftdmchan->native_codec == FTDM_CODEC_ALAW) {
+				codec_func = fio_slin2alaw;
+			}
+
+			if (codec_func) {
+				status = codec_func(frame, sizeof(frame), &rlen);
+			} else {
+				snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "codec error!");
+				goto done;
+			}
+		}
+
+		ftdm_channel_write(ftdmchan, frame, sizeof(frame), &rlen);
+	}
+
+ done:
+
+	ftdm_channel_command(ftdmchan, FTDM_COMMAND_ONHOOK, NULL);
+	
+	closed_chan = ftdmchan;
+	ftdm_channel_close(&ftdmchan);
+
+	ftdm_channel_command(closed_chan, FTDM_COMMAND_SET_NATIVE_CODEC, NULL);
+
+	if (ts.buffer) {
+		teletone_destroy_session(&ts);
+	}
+
+	if (dt_buffer) {
+		ftdm_buffer_destroy(&dt_buffer);
+	}
+
+	ftdm_clear_flag(closed_chan, FTDM_CHANNEL_INTHREAD);
+
+	ftdm_log(FTDM_LOG_DEBUG, "ANALOG EM CHANNEL thread ended.\n");
+
+	return NULL;
+}
+
+/**
+ * \brief Processes EM events coming from ftdmtel/dahdi
+ * \param span Span on which the event was fired
+ * \param event Event to be treated
+ * \return Success or failure
+ */
+static __inline__ ftdm_status_t process_event(ftdm_span_t *span, ftdm_event_t *event)
+{
+	ftdm_sigmsg_t sig;
+	int locked = 0;
+	
+	memset(&sig, 0, sizeof(sig));
+	sig.chan_id = event->channel->chan_id;
+	sig.span_id = event->channel->span_id;
+	sig.channel = event->channel;
+
+
+	ftdm_log(FTDM_LOG_DEBUG, "EVENT [%s][%d:%d] STATE [%s]\n", 
+			ftdm_oob_event2str(event->enum_id), event->channel->span_id, event->channel->chan_id, ftdm_channel_state2str(event->channel->state));
+
+	ftdm_mutex_lock(event->channel->mutex);
+	locked++;
+
+	switch(event->enum_id) {
+	case FTDM_OOB_ONHOOK:
+		{
+			if (event->channel->state != FTDM_CHANNEL_STATE_DOWN) {
+				ftdm_set_state_locked(event->channel, FTDM_CHANNEL_STATE_DOWN);
+			}
+
+		}
+		break;
+	case FTDM_OOB_OFFHOOK:
+		{
+			if (ftdm_test_flag(event->channel, FTDM_CHANNEL_INTHREAD)) {
+				ftdm_set_state_locked(event->channel, FTDM_CHANNEL_STATE_UP);
+			} else {
+				ftdm_set_state_locked(event->channel, FTDM_CHANNEL_STATE_DIALTONE);
+				ftdm_mutex_unlock(event->channel->mutex);
+				locked = 0;
+				ftdm_thread_create_detached(ftdm_analog_em_channel_run, event->channel);
+			}
+		break;
+		}
+	case FTDM_OOB_WINK:
+		{
+			if (event->channel->state != FTDM_CHANNEL_STATE_DIALING) {
+				ftdm_set_state_locked(event->channel, FTDM_CHANNEL_STATE_DOWN);
+			} else {
+				ftdm_set_flag_locked(event->channel, FTDM_CHANNEL_WINK);
+			}
+
+		}
+		break;
+	}
+	if (locked) {
+		ftdm_mutex_unlock(event->channel->mutex);
+	}
+	return FTDM_SUCCESS;
+}
+
+/**
+ * \brief Main thread function for EM span (monitor)
+ * \param me Current thread
+ * \param obj Span to run in this thread
+ */
+static void *ftdm_analog_em_run(ftdm_thread_t *me, void *obj)
+{
+	ftdm_span_t *span = (ftdm_span_t *) obj;
+	ftdm_analog_em_data_t *analog_data = span->signal_data;
+
+	ftdm_log(FTDM_LOG_DEBUG, "ANALOG EM thread starting.\n");
+
+	while(ftdm_running() && ftdm_test_flag(analog_data, FTDM_ANALOG_EM_RUNNING)) {
+		int waitms = 10;
+		ftdm_status_t status;
+
+		status = ftdm_span_poll_event(span, waitms);
+		
+		switch(status) {
+		case FTDM_SUCCESS:
+			{
+				ftdm_event_t *event;
+				while (ftdm_span_next_event(span, &event) == FTDM_SUCCESS) {
+					if (event->enum_id == FTDM_OOB_NOOP) {
+						continue;
+					}
+					if (process_event(span, event) != FTDM_SUCCESS) {
+						goto end;
+					}
+				}
+			}
+			break;
+		case FTDM_FAIL:
+			{
+				ftdm_log(FTDM_LOG_ERROR, "Failure Polling event! [%s]\n", span->last_error);
+			}
+			break;
+		default:
+			break;
+		}
+
+	}
+
+ end:
+
+	ftdm_clear_flag(analog_data, FTDM_ANALOG_EM_RUNNING);
+	
+	ftdm_log(FTDM_LOG_DEBUG, "ANALOG EM thread ending.\n");
+
+	return NULL;
+}
+
+/**
+ * \brief FreeTDM analog EM module initialisation
+ * \return Success
+ */
+static FIO_SIG_LOAD_FUNCTION(ftdm_analog_em_init)
+{
+	return FTDM_SUCCESS;
+}
+
+/**
+ * \brief FreeTDM analog EM module definition
+ */
+EX_DECLARE_DATA ftdm_module_t ftdm_module = {
+	"analog_em",
+	NULL,
+	NULL,
+	ftdm_analog_em_init,
+	ftdm_analog_em_configure_span,
+	NULL
+};
+
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */

Added: freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_analog_em/ozmod_analog_em.2005.vcproj (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_analog_em/ozmod_analog_em.2005.vcproj	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_analog_em/ozmod_analog_em.2005.vcproj	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,202 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="8.00"
+	Name="ftmod_analog_em"
+	ProjectGUID="{C539D7C8-26A8-4A94-B938-77672165C130}"
+	RootNamespace="ftmod_analog_em"
+	Keyword="Win32Proj"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="2"
+			CharacterSet="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				AdditionalIncludeDirectories="..\..\include;..\..\isdn\include"
+				PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;FTMOD_ANALOG_EM_EXPORTS"
+				MinimalRebuild="true"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="3"
+				UsePrecompiledHeader="0"
+				WarningLevel="4"
+				WarnAsError="true"
+				DebugInformationFormat="4"
+				DisableSpecificWarnings="4100"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				LinkIncremental="2"
+				GenerateDebugInformation="true"
+				SubSystem="2"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="2"
+			CharacterSet="1"
+			WholeProgramOptimization="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="2"
+				EnableIntrinsicFunctions="true"
+				AdditionalIncludeDirectories="..\..\include;..\..\isdn\include"
+				PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;FTMOD_ANALOG_EM_EXPORTS"
+				RuntimeLibrary="2"
+				EnableFunctionLevelLinking="true"
+				UsePrecompiledHeader="0"
+				WarningLevel="4"
+				WarnAsError="true"
+				DebugInformationFormat="3"
+				DisableSpecificWarnings="4100"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				LinkIncremental="1"
+				GenerateDebugInformation="true"
+				SubSystem="2"
+				OptimizeReferences="2"
+				EnableCOMDATFolding="2"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<Filter
+			Name="Source Files"
+			Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+			>
+			<File
+				RelativePath="ftmod_analog_em.c"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="Header Files"
+			Filter="h;hpp;hxx;hm;inl;inc;xsd"
+			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+			>
+			<File
+				RelativePath="ftdm_analog_em.h"
+				>
+			</File>
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>

Added: freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_isdn/ftdm_isdn.h (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_isdn/ftdm_isdn.h	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_isdn/ftdm_isdn.h	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2007, Anthony Minessale II
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FTDM_ISDN_H
+#define FTDM_ISDN_H
+#include "freetdm.h"
+
+#define DEFAULT_DIGIT_TIMEOUT	10000		/* default overlap timeout: 10 seconds */
+
+
+typedef enum {
+	FTDM_ISDN_OPT_NONE = 0,
+	FTDM_ISDN_OPT_SUGGEST_CHANNEL = (1 << 0),
+	FTDM_ISDN_OPT_OMIT_DISPLAY_IE = (1 << 1),	/*!< Do not send Caller name in outgoing SETUP message (= Display IE) */
+	FTDM_ISDN_OPT_DISABLE_TONES = (1 << 2),		/*!< Disable tone generating thread (NT mode) */
+
+	FTDM_ISDN_OPT_MAX = (2 << 0)
+} ftdm_isdn_opts_t;
+
+typedef enum {
+	FTDM_ISDN_RUNNING = (1 << 0),
+	FTDM_ISDN_TONES_RUNNING = (1 << 1),
+	FTDM_ISDN_STOP = (1 << 2)
+} ftdm_isdn_flag_t;
+
+
+struct ftdm_isdn_data {
+	Q921Data_t q921;
+	Q931_TrunkInfo_t q931;
+	ftdm_channel_t *dchan;
+	ftdm_channel_t *dchans[2];
+	struct ftdm_sigmsg sigmsg;
+	uint32_t flags;
+	int32_t mode;
+	int32_t digit_timeout;
+	ftdm_isdn_opts_t opts;
+	ftdm_caller_data_t *outbound_crv[32768];
+	ftdm_channel_t *channels_local_crv[32768];
+	ftdm_channel_t *channels_remote_crv[32768];
+};
+
+typedef struct ftdm_isdn_data ftdm_isdn_data_t;
+
+
+/* b-channel private data */
+struct ftdm_isdn_bchan_data
+{
+	L2ULONG digit_timeout;
+};
+
+typedef struct ftdm_isdn_bchan_data ftdm_isdn_bchan_data_t;
+
+
+#endif
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
+

Added: freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_isdn/ftmod_isdn.2008.vcproj (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_isdn/ftmod_isdn.2008.vcproj	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_isdn/ftmod_isdn.2008.vcproj	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,465 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="9.00"
+	Name="ftmod_isdn"
+	ProjectGUID="{729344A5-D5E9-434D-8EE8-AF8C6C795D15}"
+	RootNamespace="ftmod_isdn"
+	Keyword="Win32Proj"
+	TargetFrameworkVersion="196613"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+		<Platform
+			Name="x64"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="2"
+			CharacterSet="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				AdditionalIncludeDirectories="..\..\isdn\include;..\..\include"
+				PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;FTMOD_ISDN_EXPORTS;_CRT_SECURE_NO_WARNINGS"
+				MinimalRebuild="true"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="3"
+				UsePrecompiledHeader="0"
+				WarningLevel="4"
+				WarnAsError="true"
+				DebugInformationFormat="4"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				LinkIncremental="2"
+				GenerateDebugInformation="true"
+				SubSystem="2"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="2"
+			CharacterSet="1"
+			WholeProgramOptimization="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="2"
+				EnableIntrinsicFunctions="true"
+				AdditionalIncludeDirectories="..\..\isdn\include;..\..\include"
+				PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;FTMOD_ISDN_EXPORTS;_CRT_SECURE_NO_WARNINGS"
+				RuntimeLibrary="2"
+				EnableFunctionLevelLinking="true"
+				UsePrecompiledHeader="0"
+				WarningLevel="4"
+				WarnAsError="true"
+				DebugInformationFormat="3"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				LinkIncremental="1"
+				GenerateDebugInformation="true"
+				SubSystem="2"
+				OptimizeReferences="2"
+				EnableCOMDATFolding="2"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Debug|x64"
+			OutputDirectory="$(SolutionDir)$(PlatformName)\$(ConfigurationName)"
+			IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+			ConfigurationType="2"
+			CharacterSet="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+				TargetEnvironment="3"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				AdditionalIncludeDirectories="..\..\isdn\include;..\..\include"
+				PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;FTMOD_ISDN_EXPORTS;_CRT_SECURE_NO_WARNINGS"
+				MinimalRebuild="true"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="3"
+				UsePrecompiledHeader="0"
+				WarningLevel="4"
+				WarnAsError="true"
+				DebugInformationFormat="3"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				LinkIncremental="2"
+				GenerateDebugInformation="true"
+				SubSystem="2"
+				TargetMachine="17"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|x64"
+			OutputDirectory="$(SolutionDir)$(PlatformName)\$(ConfigurationName)"
+			IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+			ConfigurationType="2"
+			CharacterSet="1"
+			WholeProgramOptimization="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+				TargetEnvironment="3"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="2"
+				EnableIntrinsicFunctions="true"
+				AdditionalIncludeDirectories="..\..\isdn\include;..\..\include"
+				PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;FTMOD_ISDN_EXPORTS;_CRT_SECURE_NO_WARNINGS"
+				RuntimeLibrary="2"
+				EnableFunctionLevelLinking="true"
+				UsePrecompiledHeader="0"
+				WarningLevel="4"
+				WarnAsError="true"
+				DebugInformationFormat="3"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				LinkIncremental="1"
+				GenerateDebugInformation="true"
+				SubSystem="2"
+				OptimizeReferences="2"
+				EnableCOMDATFolding="2"
+				TargetMachine="17"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<Filter
+			Name="Source Files"
+			Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+			>
+			<File
+				RelativePath="..\..\isdn\5ESSmes.c"
+				>
+			</File>
+			<File
+				RelativePath="..\..\isdn\5ESSStateNT.c"
+				>
+			</File>
+			<File
+				RelativePath="..\..\isdn\5ESSStateTE.c"
+				>
+			</File>
+			<File
+				RelativePath="..\..\isdn\DMSmes.c"
+				>
+			</File>
+			<File
+				RelativePath="..\..\isdn\DMSStateNT.c"
+				>
+			</File>
+			<File
+				RelativePath="..\..\isdn\DMSStateTE.c"
+				>
+			</File>
+			<File
+				RelativePath="..\..\isdn\EuroISDNStateNT.c"
+				>
+			</File>
+			<File
+				RelativePath="..\..\isdn\EuroISDNStateTE.c"
+				>
+			</File>
+			<File
+				RelativePath="..\..\isdn\mfifo.c"
+				>
+			</File>
+			<File
+				RelativePath="..\..\isdn\nationalmes.c"
+				>
+			</File>
+			<File
+				RelativePath="..\..\isdn\nationalStateNT.c"
+				>
+			</File>
+			<File
+				RelativePath="..\..\isdn\nationalStateTE.c"
+				>
+			</File>
+			<File
+				RelativePath="ftmod_isdn.c"
+				>
+			</File>
+			<File
+				RelativePath="..\..\isdn\Q921.c"
+				>
+			</File>
+			<File
+				RelativePath="..\..\isdn\Q931.c"
+				>
+			</File>
+			<File
+				RelativePath="..\..\isdn\Q931api.c"
+				>
+			</File>
+			<File
+				RelativePath="..\..\isdn\Q931ie.c"
+				>
+			</File>
+			<File
+				RelativePath="..\..\isdn\Q931mes.c"
+				>
+			</File>
+			<File
+				RelativePath="..\..\isdn\Q931StateNT.c"
+				>
+			</File>
+			<File
+				RelativePath="..\..\isdn\Q931StateTE.c"
+				>
+			</File>
+			<File
+				RelativePath="..\..\isdn\Q932mes.c"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="Header Files"
+			Filter="h;hpp;hxx;hm;inl;inc;xsd"
+			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+			>
+			<File
+				RelativePath="..\..\isdn\include\5ESS.h"
+				>
+			</File>
+			<File
+				RelativePath="..\..\isdn\include\DMS.h"
+				>
+			</File>
+			<File
+				RelativePath="..\..\isdn\include\mfifo.h"
+				>
+			</File>
+			<File
+				RelativePath="..\..\isdn\include\national.h"
+				>
+			</File>
+			<File
+				RelativePath="..\..\isdn\include\Q921.h"
+				>
+			</File>
+			<File
+				RelativePath="..\..\isdn\include\Q921priv.h"
+				>
+			</File>
+			<File
+				RelativePath="..\..\isdn\include\Q931.h"
+				>
+			</File>
+			<File
+				RelativePath="..\..\isdn\include\Q931ie.h"
+				>
+			</File>
+			<File
+				RelativePath="..\..\isdn\include\Q932.h"
+				>
+			</File>
+			<File
+				RelativePath="ftdm_isdn.h"
+				>
+			</File>
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>

Added: freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_isdn/ftmod_isdn.c (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_isdn/ftmod_isdn.c	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_isdn/ftmod_isdn.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,2420 @@
+/*
+ * Copyright (c) 2007, Anthony Minessale II
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * Workaround for missing u_int / u_short types on solaris
+ */
+#if defined(HAVE_LIBPCAP) && defined(__SunOS)
+#define __EXTENSIONS__
+#endif
+
+#include "freetdm.h"
+#include "Q931.h"
+#include "Q921.h"
+#ifdef WIN32
+#include <windows.h>
+#else
+#include <sys/time.h>
+#endif
+
+#include "ftdm_isdn.h"
+
+#define LINE "--------------------------------------------------------------------------------"
+//#define IODEBUG
+
+/* helper macros */
+#define FTDM_SPAN_IS_BRI(x)	((x)->trunk_type == FTDM_TRUNK_BRI || (x)->trunk_type == FTDM_TRUNK_BRI_PTMP)
+#define FTDM_SPAN_IS_NT(x)	(((ftdm_isdn_data_t *)(x)->signal_data)->mode == Q921_NT)
+
+
+#ifdef HAVE_LIBPCAP
+/*-------------------------------------------------------------------------*/
+/*Q931ToPcap functions*/
+#include <pcap.h>
+#endif
+
+#define SNAPLEN 1522
+#define MAX_ETHER_PAYLOAD_SIZE 1500
+#define MIN_ETHER_PAYLOAD_SIZE 42
+#define SIZE_ETHERNET           18
+#define VLANID_OFFSET           15
+#define SIZE_IP                 20
+#define SIZE_TCP                20
+#define SIZE_TPKT               4
+#define SIZE_ETHERNET_CRC       4
+#define OVERHEAD                SIZE_ETHERNET+SIZE_IP+SIZE_TCP+SIZE_TPKT
+#define MAX_Q931_SIZE           MAX_ETHER_PAYLOAD_SIZE-SIZE_IP-SIZE_TCP-SIZE_TPKT
+#define TPKT_SIZE_OFFSET        SIZE_ETHERNET+SIZE_IP+SIZE_TCP+2
+#define IP_SIZE_OFFSET          SIZE_ETHERNET+2
+#define TCP_SEQ_OFFSET		SIZE_ETHERNET+SIZE_IP+4
+
+#ifdef HAVE_LIBPCAP
+/*Some globals*/
+unsigned long           pcapfilesize = 0;
+unsigned long		tcp_next_seq_no_send = 0;
+unsigned long           tcp_next_seq_no_rec = 0;
+pcap_dumper_t           *pcapfile    = NULL;
+struct pcap_pkthdr      pcaphdr;
+pcap_t                  *pcaphandle  = NULL;
+char 			*pcapfn      = NULL;
+int			do_q931ToPcap= 0;
+
+/*Predefined Ethernet Frame with Q931-over-IP encapsulated - From remote TDM host to FreeSWITCH*/
+L3UCHAR  recFrame[SNAPLEN]= {
+                                /*IEEE 802.3 VLAN 802.1q Ethernet Frame Header*/
+                                2,0,1,0xAA,0xAA,0xAA,2,0,1,0xBB,0xBB,0xBB,0x81,0,0xE0,0,0x08,0,
+                                /*IPv4 Header (minimal size; no options)*/
+                                0x45,0,0,44,0,0,0,0,64,6,0,0,2,2,2,2,1,1,1,1,
+                                /*TCP-Header*/
+                                0,0x66,0,0x66,0,0,0,0,0,0,0,0,0x50,0,0,1,0,0,0,0,
+                                /*TPKT-Header RFC 1006*/
+                                3,0,0,0
+                            };
+
+/*Predefined Ethernet Frame with Q931-over-IP encapsulated - Frome FreeSWITCH to remote TDM host*/
+L3UCHAR  sendFrame[SNAPLEN]= {
+                                /*IEEE 802.3 VLAN 802.1q Ethernet Frame Header*/
+                                2,0,1,0xBB,0xBB,0xBB,2,0,1,0xAA,0xAA,0xAA,0x81,0,0xE0,0,0x08,0,
+                                /*IPv4 Header (minimal size; no options)*/
+                                0x45,0,0,44,0,0,0,0,64,6,0,0,1,1,1,1,2,2,2,2,
+                                /*TCP-Header*/
+                                0,0x66,0,0x66,0,0,0,0,0,0,0,0,0x50,0,0,1,0,0,0,0,
+                                /*TPKT-Header RFC 1006*/
+                                3,0,0,0
+                             };
+
+/**
+ * \brief Opens a pcap file for capture
+ * \return Success or failure
+ */
+static ftdm_status_t openPcapFile(void)
+{
+        if(!pcaphandle)
+        {
+                pcaphandle = pcap_open_dead(DLT_EN10MB, SNAPLEN);
+                if (!pcaphandle)
+                {
+                        ftdm_log(FTDM_LOG_ERROR, "Can't open pcap session: (%s)\n", pcap_geterr(pcaphandle));
+                        return FTDM_FAIL;
+                }
+        }
+
+        if(!pcapfile){
+                /* Open the dump file */
+                if(!(pcapfile=pcap_dump_open(pcaphandle, pcapfn))){
+                        ftdm_log(FTDM_LOG_ERROR, "Error opening output file (%s)\n", pcap_geterr(pcaphandle));
+                        return FTDM_FAIL;
+                }
+        }
+        else{
+                ftdm_log(FTDM_LOG_WARNING, "Pcap file is already open!\n");
+                return FTDM_FAIL;
+        }
+
+        ftdm_log(FTDM_LOG_DEBUG, "Pcap file '%s' successfully opened!\n", pcapfn);
+
+        pcaphdr.ts.tv_sec  	= 0;
+        pcaphdr.ts.tv_usec 	= 0;
+	pcapfilesize       	= 24;	/*current pcap file header seems to be 24 bytes*/
+	tcp_next_seq_no_send    = 0;
+	tcp_next_seq_no_rec	= 0;
+
+        return FTDM_SUCCESS;
+}
+
+/**
+ * \brief Closes a pcap file
+ * \return Success
+ */
+static ftdm_status_t closePcapFile(void)
+{
+	if (pcapfile) {
+		pcap_dump_close(pcapfile);
+		if (pcaphandle) pcap_close(pcaphandle);
+
+		ftdm_log(FTDM_LOG_DEBUG, "Pcap file closed! File size is %lu bytes.\n", pcapfilesize);
+
+		pcaphdr.ts.tv_sec 	= 0;
+		pcaphdr.ts.tv_usec 	= 0;
+		pcapfile		= NULL;
+		pcaphandle 		= NULL;
+		pcapfilesize		= 0;
+		tcp_next_seq_no_send	= 0;
+		tcp_next_seq_no_rec	= 0;
+	}
+
+	/*We have allways success with this? I think so*/
+	return FTDM_SUCCESS;
+}
+
+/**
+ * \brief Writes a Q931 packet to a pcap file
+ * \return Success or failure
+ */
+static ftdm_status_t writeQ931PacketToPcap(L3UCHAR* q931buf, L3USHORT q931size, L3ULONG span_id, L3USHORT direction)
+{
+        L3UCHAR                 *frame		= NULL;
+	struct timeval		ts;
+	u_char			spanid		= (u_char)span_id;
+	unsigned long 		*tcp_next_seq_no = NULL;
+
+	spanid=span_id;
+	
+        /*The total length of the ethernet frame generated by this function has a min length of 66
+        so we don't have to care about padding :)*/
+
+
+        /*FS is sending the packet*/
+        if(direction==0){
+		frame=sendFrame;
+		tcp_next_seq_no = &tcp_next_seq_no_send;
+        } 
+	/*FS is receiving the packet*/
+	else{
+		frame=recFrame;
+		tcp_next_seq_no = &tcp_next_seq_no_rec;
+	}
+
+	/*Set spanid in VLAN-ID tag*/
+        frame[VLANID_OFFSET]    = spanid;
+
+        /*** Write sent packet ***/
+        if(q931size > MAX_Q931_SIZE)
+        {
+                /*WARNING*/
+		ftdm_log(FTDM_LOG_WARNING, "Q931 packet size is too big (%u)! Ignoring it!\n", q931size);
+                return FTDM_FAIL;
+        }
+
+	/*Copy q931 buffer into frame*/
+        memcpy(frame+OVERHEAD,q931buf,q931size);
+
+	/*Store TCP sequence number in TCP header*/
+	frame[TCP_SEQ_OFFSET]=(*tcp_next_seq_no>>24)&0xFF;
+	frame[TCP_SEQ_OFFSET+1]=(*tcp_next_seq_no>>16)&0xFF;
+	frame[TCP_SEQ_OFFSET+2]=(*tcp_next_seq_no>>8)&0xFF;
+	frame[TCP_SEQ_OFFSET+3]=*tcp_next_seq_no & 0xFF;
+
+        /*Store size of TPKT packet*/
+        q931size+=4;
+        frame[TPKT_SIZE_OFFSET]=(q931size>>8)&0xFF;
+        frame[TPKT_SIZE_OFFSET+1]=q931size&0xFF;
+
+	/*Calc next TCP sequence number*/
+	*tcp_next_seq_no+=q931size;
+
+        /*Store size of IP packet*/
+        q931size+=SIZE_IP+SIZE_TCP;
+        frame[IP_SIZE_OFFSET]=(q931size>>8)&0xFF;
+        frame[IP_SIZE_OFFSET+1]=q931size&0xFF;
+
+        pcaphdr.caplen = SIZE_ETHERNET+SIZE_ETHERNET_CRC+q931size;
+        pcaphdr.len = pcaphdr.caplen;
+
+        /* Set Timestamp */
+        /* Get Time in ms. usecs would be better ...  */
+        gettimeofday(&ts, NULL);
+        /*Write it into packet header*/
+        pcaphdr.ts.tv_sec = ts.tv_sec;
+        pcaphdr.ts.tv_usec = ts.tv_usec;
+
+	pcap_dump((u_char*)pcapfile, &pcaphdr, frame);
+        pcap_dump_flush(pcapfile);
+
+        /*Maintain pcap file size*/
+        pcapfilesize+=pcaphdr.caplen;
+        pcapfilesize+=sizeof(struct pcap_pkthdr);
+
+	ftdm_log(FTDM_LOG_DEBUG, "Added %u bytes to pcap file. File size is now %lu, \n", q931size, pcapfilesize);
+
+        return FTDM_SUCCESS;
+}
+
+#endif
+
+/**
+ * \brief Unloads pcap IO
+ * \return Success or failure
+ */
+static FIO_IO_UNLOAD_FUNCTION(close_pcap)
+{
+#ifdef HAVE_LIBPCAP
+	return closePcapFile();
+#else
+	return FTDM_SUCCESS;
+#endif
+}
+
+/*Q931ToPcap functions DONE*/
+/*-------------------------------------------------------------------------*/
+
+/**
+ * \brief Gets current time
+ * \return Current time (in ms)
+ */
+static L2ULONG ftdm_time_now(void)
+{
+	return (L2ULONG)ftdm_current_time_in_ms();
+}
+
+/**
+ * \brief Initialises an ISDN channel (outgoing call)
+ * \param ftdmchan Channel to initiate call on
+ * \return Success or failure
+ */
+static FIO_CHANNEL_OUTGOING_CALL_FUNCTION(isdn_outgoing_call)
+{
+	ftdm_status_t status = FTDM_SUCCESS;
+	ftdm_set_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND);
+	ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DIALING);
+	return status;
+}
+
+/**
+ * \brief Requests an ISDN channel on a span (outgoing call)
+ * \param span Span where to get a channel
+ * \param chan_id Specific channel to get (0 for any)
+ * \param direction Call direction (inbound, outbound)
+ * \param caller_data Caller information
+ * \param ftdmchan Channel to initialise
+ * \return Success or failure
+ */
+static FIO_CHANNEL_REQUEST_FUNCTION(isdn_channel_request)
+{
+	Q931mes_Generic *gen = (Q931mes_Generic *) caller_data->raw_data;
+	Q931ie_BearerCap BearerCap;
+	Q931ie_ChanID ChanID = { 0 };
+	Q931ie_CallingNum CallingNum;
+	Q931ie_CallingNum *ptrCallingNum;
+	Q931ie_CalledNum CalledNum;
+	Q931ie_CalledNum *ptrCalledNum;
+	Q931ie_Display Display, *ptrDisplay;
+	Q931ie_HLComp HLComp;			/* High-Layer Compatibility IE */
+	Q931ie_ProgInd Progress;		/* Progress Indicator IE */
+	ftdm_status_t status = FTDM_FAIL;
+	ftdm_isdn_data_t *isdn_data = span->signal_data;
+	int sanity = 60000;
+	int codec  = 0;
+
+	/*
+	 * get codec type
+	 */
+	ftdm_channel_command(span->channels[chan_id], FTDM_COMMAND_GET_NATIVE_CODEC, &codec);
+
+	/*
+	 * Q.931 Setup Message
+	 */
+	Q931InitMesGeneric(gen);
+	gen->MesType = Q931mes_SETUP;
+	gen->CRVFlag = 0;		/* outgoing call */
+
+	/*
+	 * Bearer Capability IE
+	 */
+	Q931InitIEBearerCap(&BearerCap);
+	BearerCap.CodStand  = Q931_CODING_ITU;		/* ITU-T = 0, ISO/IEC = 1, National = 2, Network = 3 */
+	BearerCap.ITC       = Q931_ITC_SPEECH;		/* Speech */
+	BearerCap.TransMode = 0;			/* Circuit = 0, Packet = 1 */
+	BearerCap.ITR       = Q931_ITR_64K;		/* 64k */
+	BearerCap.Layer1Ident = 1;
+	BearerCap.UIL1Prot = (codec == FTDM_CODEC_ALAW) ? Q931_UIL1P_G711A : Q931_UIL1P_G711U;	/* U-law = 2, A-law = 3 */
+	gen->BearerCap = Q931AppendIE((L3UCHAR *) gen, (L3UCHAR *) &BearerCap);
+
+	/*
+	 * Channel ID IE
+	 */
+	Q931InitIEChanID(&ChanID);
+	ChanID.IntType = FTDM_SPAN_IS_BRI(span) ? 0 : 1;		/* PRI = 1, BRI = 0 */
+
+	if(!FTDM_SPAN_IS_NT(span)) {
+		ChanID.PrefExcl = (isdn_data->opts & FTDM_ISDN_OPT_SUGGEST_CHANNEL) ? 0 : 1; /* 0 = preferred, 1 exclusive */
+	} else {
+		ChanID.PrefExcl = 1;	/* always exclusive in NT-mode */
+	}
+
+	if(ChanID.IntType) {
+		ChanID.InfoChanSel = 1;				/* None = 0, See Slot = 1, Any = 3 */
+		ChanID.ChanMapType = 3; 			/* B-Chan */
+		ChanID.ChanSlot = (unsigned char)chan_id;
+	} else {
+		ChanID.InfoChanSel = (unsigned char)chan_id & 0x03;	/* None = 0, B1 = 1, B2 = 2, Any = 3 */
+	}
+	gen->ChanID = Q931AppendIE((L3UCHAR *) gen, (L3UCHAR *) &ChanID);
+
+	/*
+	 * Progress IE
+	 */
+	Q931InitIEProgInd(&Progress);
+	Progress.CodStand = Q931_CODING_ITU;	/* 0 = ITU */
+	Progress.Location = 0;  /* 0 = User, 1 = Private Network */
+	Progress.ProgDesc = 3;	/* 1 = Not end-to-end ISDN */
+	gen->ProgInd = Q931AppendIE((L3UCHAR *)gen, (L3UCHAR *)&Progress);
+
+	/*
+	 * Display IE
+	 */
+	if (!(isdn_data->opts & FTDM_ISDN_OPT_OMIT_DISPLAY_IE)) {
+		Q931InitIEDisplay(&Display);
+		Display.Size = Display.Size + (unsigned char)strlen(caller_data->cid_name);
+		gen->Display = Q931AppendIE((L3UCHAR *) gen, (L3UCHAR *) &Display);			
+		ptrDisplay = Q931GetIEPtr(gen->Display, gen->buf);
+		ftdm_copy_string((char *)ptrDisplay->Display, caller_data->cid_name, strlen(caller_data->cid_name)+1);
+	}
+
+	/*
+	 * Calling Number IE
+	 */
+	Q931InitIECallingNum(&CallingNum);
+	CallingNum.TypNum    = Q931_TON_UNKNOWN;
+	CallingNum.NumPlanID = Q931_NUMPLAN_E164;
+	CallingNum.PresInd   = Q931_PRES_ALLOWED;
+	CallingNum.ScreenInd = Q931_SCREEN_USER_NOT_SCREENED;
+	CallingNum.Size = CallingNum.Size + (unsigned char)strlen(caller_data->cid_num.digits);
+	gen->CallingNum = Q931AppendIE((L3UCHAR *) gen, (L3UCHAR *) &CallingNum);			
+	ptrCallingNum = Q931GetIEPtr(gen->CallingNum, gen->buf);
+	ftdm_copy_string((char *)ptrCallingNum->Digit, caller_data->cid_num.digits, strlen(caller_data->cid_num.digits)+1);
+
+
+	/*
+	 * Called number IE
+	 */
+	Q931InitIECalledNum(&CalledNum);
+	CalledNum.TypNum    = Q931_TON_UNKNOWN;
+	CalledNum.NumPlanID = Q931_NUMPLAN_E164;
+	CalledNum.Size = CalledNum.Size + (unsigned char)strlen(caller_data->dnis.digits);
+	gen->CalledNum = Q931AppendIE((L3UCHAR *) gen, (L3UCHAR *) &CalledNum);
+	ptrCalledNum = Q931GetIEPtr(gen->CalledNum, gen->buf);
+	ftdm_copy_string((char *)ptrCalledNum->Digit, caller_data->dnis.digits, strlen(caller_data->dnis.digits)+1);
+
+	/*
+	 * High-Layer Compatibility IE   (Note: Required for AVM FritzBox)
+	 */
+	Q931InitIEHLComp(&HLComp);
+	HLComp.CodStand  = Q931_CODING_ITU;	/* ITU */
+	HLComp.Interpret = 4;	/* only possible value */
+	HLComp.PresMeth  = 1;   /* High-layer protocol profile */
+	HLComp.HLCharID  = 1;	/* Telephony = 1, Fax G2+3 = 4, Fax G4 = 65 (Class I)/ 68 (Class II or III) */
+	gen->HLComp = Q931AppendIE((L3UCHAR *) gen, (L3UCHAR *) &HLComp);
+
+	caller_data->call_state = FTDM_CALLER_STATE_DIALING;
+	Q931Rx43(&isdn_data->q931, (L3UCHAR *) gen, gen->Size);
+	
+	isdn_data->outbound_crv[gen->CRV] = caller_data;
+	//isdn_data->channels_local_crv[gen->CRV] = ftdmchan;
+
+	while(ftdm_running() && caller_data->call_state == FTDM_CALLER_STATE_DIALING) {
+		ftdm_sleep(1);
+		
+		if (!--sanity) {
+			caller_data->call_state = FTDM_CALLER_STATE_FAIL;
+			break;
+		}
+	}
+	isdn_data->outbound_crv[gen->CRV] = NULL;
+	
+	if (caller_data->call_state == FTDM_CALLER_STATE_SUCCESS) {
+		ftdm_channel_t *new_chan = NULL;
+		int fail = 1;
+		
+		new_chan = NULL;
+		if (caller_data->chan_id < FTDM_MAX_CHANNELS_SPAN && caller_data->chan_id <= span->chan_count) {
+			new_chan = span->channels[caller_data->chan_id];
+		}
+
+		if (new_chan && (status = ftdm_channel_open_chan(new_chan) == FTDM_SUCCESS)) {
+			if (ftdm_test_flag(new_chan, FTDM_CHANNEL_INUSE) || new_chan->state != FTDM_CHANNEL_STATE_DOWN) {
+				if (new_chan->state == FTDM_CHANNEL_STATE_DOWN || new_chan->state >= FTDM_CHANNEL_STATE_TERMINATING) {
+					int x = 0;
+					ftdm_log(FTDM_LOG_WARNING, "Channel %d:%d ~ %d:%d is already in use waiting for it to become available.\n");
+					
+					for (x = 0; x < 200; x++) {
+						if (!ftdm_test_flag(new_chan, FTDM_CHANNEL_INUSE)) {
+							break;
+						}
+						ftdm_sleep(5);
+					}
+				}
+				if (ftdm_test_flag(new_chan, FTDM_CHANNEL_INUSE)) {
+					ftdm_log(FTDM_LOG_ERROR, "Channel %d:%d ~ %d:%d is already in use.\n",
+							new_chan->span_id,
+							new_chan->chan_id,
+							new_chan->physical_span_id,
+							new_chan->physical_chan_id
+							);
+					new_chan = NULL;
+				}
+			}
+
+			if (new_chan && new_chan->state == FTDM_CHANNEL_STATE_DOWN) {
+				isdn_data->channels_local_crv[gen->CRV] = new_chan;
+				memset(&new_chan->caller_data, 0, sizeof(new_chan->caller_data));
+				ftdm_set_flag(new_chan, FTDM_CHANNEL_OUTBOUND);
+				ftdm_set_state_locked(new_chan, FTDM_CHANNEL_STATE_DIALING);
+				switch(gen->MesType) {
+				case Q931mes_ALERTING:
+					new_chan->init_state = FTDM_CHANNEL_STATE_PROGRESS_MEDIA;
+					break;
+				case Q931mes_CONNECT:
+					new_chan->init_state = FTDM_CHANNEL_STATE_UP;
+					break;
+				default:
+					new_chan->init_state = FTDM_CHANNEL_STATE_PROGRESS;
+					break;
+				}
+
+				fail = 0;
+			} 
+		}
+		
+		if (!fail) {
+			*ftdmchan = new_chan;
+			return FTDM_SUCCESS;
+		} else {
+			Q931ie_Cause cause;
+			gen->MesType = Q931mes_DISCONNECT;
+			cause.IEId = Q931ie_CAUSE;
+			cause.Size = sizeof(Q931ie_Cause);
+			cause.CodStand  = 0;
+			cause.Location = 1;
+			cause.Recom = 1;
+			//should we be casting here.. or do we need to translate value?
+			cause.Value = (unsigned char) FTDM_CAUSE_WRONG_CALL_STATE;
+			*cause.Diag = '\0';
+			gen->Cause = Q931AppendIE((L3UCHAR *) gen, (L3UCHAR *) &cause);
+			Q931Rx43(&isdn_data->q931, (L3UCHAR *) gen, gen->Size);
+
+			if (gen->CRV) {
+				Q931ReleaseCRV(&isdn_data->q931, gen->CRV);
+			}
+			
+			if (new_chan) {
+				ftdm_log(FTDM_LOG_CRIT, "Channel is busy\n");
+			} else {
+				ftdm_log(FTDM_LOG_CRIT, "Failed to open channel for new setup message\n");
+			}
+		}
+	}
+	
+	*ftdmchan = NULL;
+	return FTDM_FAIL;
+
+}
+
+/**
+ * \brief Handler for Q931 error
+ * \param pvt Private structure (span?)
+ * \param id Error number
+ * \param p1 ??
+ * \param p2 ??
+ * \return 0
+ */
+static L3INT ftdm_isdn_931_err(void *pvt, L3INT id, L3INT p1, L3INT p2)
+{
+	ftdm_log(FTDM_LOG_ERROR, "ERROR: [%s] [%d] [%d]\n", q931_error_to_name(id), p1, p2);
+	return 0;
+}
+
+/**
+ * \brief Handler for Q931 event message
+ * \param pvt Span to handle
+ * \param msg Message string
+ * \param mlen Message string length
+ * \return 0
+ */
+static L3INT ftdm_isdn_931_34(void *pvt, L2UCHAR *msg, L2INT mlen)
+{
+	ftdm_span_t *span = (ftdm_span_t *) pvt;
+	ftdm_isdn_data_t *isdn_data = span->signal_data;
+	Q931mes_Generic *gen = (Q931mes_Generic *) msg;
+	uint32_t chan_id = 0;
+	int chan_hunt = 0;
+	ftdm_channel_t *ftdmchan = NULL;
+	ftdm_caller_data_t *caller_data = NULL;
+
+	if (Q931IsIEPresent(gen->ChanID)) {
+		Q931ie_ChanID *chanid = Q931GetIEPtr(gen->ChanID, gen->buf);
+
+		if(chanid->IntType)
+			chan_id = chanid->ChanSlot;
+		else
+			chan_id = chanid->InfoChanSel;
+
+		/* "any" channel specified */
+		if(chanid->InfoChanSel == 3) {
+			chan_hunt++;
+		}
+	} else if (FTDM_SPAN_IS_NT(span)) {
+		/* no channel ie */
+		chan_hunt++;
+	}
+
+	assert(span != NULL);
+	assert(isdn_data != NULL);
+	
+	ftdm_log(FTDM_LOG_DEBUG, "Yay I got an event! Type:[%02x] Size:[%d] CRV: %d (%#hx, CTX: %s)\n", gen->MesType, gen->Size, gen->CRV, gen->CRV, gen->CRVFlag ? "Terminator" : "Originator");
+
+	if (gen->CRVFlag && (caller_data = isdn_data->outbound_crv[gen->CRV])) {
+		if (chan_id) {
+			caller_data->chan_id = chan_id;
+		}
+
+		switch(gen->MesType) {
+		case Q931mes_STATUS:
+		case Q931mes_CALL_PROCEEDING:
+			break;
+		case Q931mes_ALERTING:
+		case Q931mes_PROGRESS:
+		case Q931mes_CONNECT:
+			{
+				caller_data->call_state = FTDM_CALLER_STATE_SUCCESS;
+			}
+			break;
+		default:
+			caller_data->call_state = FTDM_CALLER_STATE_FAIL;
+			break;
+		}
+	
+		return 0;
+	}
+
+	if (gen->CRVFlag) {
+		ftdmchan = isdn_data->channels_local_crv[gen->CRV];
+	} else {
+		ftdmchan = isdn_data->channels_remote_crv[gen->CRV];
+	}
+
+	ftdm_log(FTDM_LOG_DEBUG, "ftdmchan %x (%d:%d) source isdn_data->channels_%s_crv[%#hx]\n", ftdmchan, ftdmchan ? ftdmchan->span_id : -1, ftdmchan ? ftdmchan->chan_id : -1, gen->CRVFlag ? "local" : "remote", gen->CRV);
+
+
+	if (gen->ProtDisc == 3) {
+		switch(gen->MesType) {
+		case Q931mes_SERVICE:
+			{
+				Q931ie_ChangeStatus *changestatus = Q931GetIEPtr(gen->ChangeStatus, gen->buf);
+				if (ftdmchan) {
+					switch (changestatus->NewStatus) {
+					case 0: /* change status to "in service" */
+						{
+							ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_SUSPENDED);
+							ftdm_log(FTDM_LOG_DEBUG, "Channel %d:%d in service\n", ftdmchan->span_id, ftdmchan->chan_id);
+							ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_RESTART);
+						}
+						break;
+					case 1: 
+						{ /* change status to "maintenance" */
+							ftdm_set_flag_locked(ftdmchan, FTDM_CHANNEL_SUSPENDED);
+							ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_SUSPENDED);
+						}
+						break;
+					case 2:
+						{ /* change status to "out of service" */
+							ftdm_set_flag_locked(ftdmchan, FTDM_CHANNEL_SUSPENDED);
+							ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_SUSPENDED);
+						}
+						break;
+					default: /* unknown */
+						{
+							break;
+						}
+					}
+				}
+			}
+			break;
+		default:
+			break;
+		}
+	} else {
+		switch(gen->MesType) {
+		case Q931mes_RESTART:
+			{
+				if (chan_id) {
+					ftdmchan = span->channels[chan_id];
+				}
+				if (ftdmchan) {
+					ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_RESTART);
+				} else {
+					uint32_t i;
+					for (i = 1; i < span->chan_count; i++) {
+						ftdm_set_state_locked((span->channels[i]), FTDM_CHANNEL_STATE_RESTART);
+					}
+				}
+			}
+			break;
+		case Q931mes_RELEASE:
+		case Q931mes_RELEASE_COMPLETE:
+			{
+				const char *what = gen->MesType == Q931mes_RELEASE ? "Release" : "Release Complete";
+				if (ftdmchan) {
+					if (ftdmchan->state == FTDM_CHANNEL_STATE_TERMINATING || ftdmchan->state == FTDM_CHANNEL_STATE_HANGUP) {
+						if (gen->MesType == Q931mes_RELEASE) {
+							ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP_COMPLETE);
+						} else {
+							ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
+						}
+					}
+					else if((gen->MesType == Q931mes_RELEASE && ftdmchan->state <= FTDM_CHANNEL_STATE_UP) ||
+						(gen->MesType == Q931mes_RELEASE_COMPLETE && ftdmchan->state == FTDM_CHANNEL_STATE_DIALING)) {
+
+						/*
+						 * Don't keep inbound channels open if the remote side hangs up before we answered
+						 */
+						Q931ie_Cause *cause = Q931GetIEPtr(gen->Cause, gen->buf);
+						ftdm_sigmsg_t sig;
+						ftdm_status_t status;
+
+						memset(&sig, 0, sizeof(sig));
+						sig.chan_id = ftdmchan->chan_id;
+						sig.span_id = ftdmchan->span_id;
+						sig.channel = ftdmchan;
+						sig.channel->caller_data.hangup_cause = (cause) ? cause->Value : FTDM_CAUSE_NORMAL_UNSPECIFIED;
+
+						sig.event_id = FTDM_SIGEVENT_STOP;
+						status = ftdm_span_send_signal(ftdmchan->span, &sig);
+
+						ftdm_log(FTDM_LOG_DEBUG, "Received %s in state %s, requested hangup for channel %d:%d\n", what, ftdm_channel_state2str(ftdmchan->state), ftdmchan->span_id, chan_id);
+					}
+					else {
+						ftdm_log(FTDM_LOG_DEBUG, "Ignoring %s on channel %d\n", what, chan_id);
+					}
+				} else {
+					ftdm_log(FTDM_LOG_CRIT, "Received %s with no matching channel %d\n", what, chan_id);
+				}
+			}
+			break;
+		case Q931mes_DISCONNECT:
+			{
+				if (ftdmchan) {
+					Q931ie_Cause *cause = Q931GetIEPtr(gen->Cause, gen->buf);
+					ftdmchan->caller_data.hangup_cause = cause->Value;
+					ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING);
+				} else {
+					ftdm_log(FTDM_LOG_CRIT, "Received Disconnect with no matching channel %d\n", chan_id);
+				}
+			}
+			break;
+		case Q931mes_ALERTING:
+			{
+				if (ftdmchan) {
+					ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_PROGRESS_MEDIA);
+				} else {
+					ftdm_log(FTDM_LOG_CRIT, "Received Alerting with no matching channel %d\n", chan_id);
+				}
+			}
+			break;
+		case Q931mes_PROGRESS:
+			{
+				if (ftdmchan) {
+					ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_PROGRESS);
+				} else {
+					ftdm_log(FTDM_LOG_CRIT, "Received Progress with no matching channel %d\n", chan_id);
+				}
+			}
+			break;
+		case Q931mes_CONNECT:
+			{
+				if (ftdmchan) {
+					ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_UP);
+
+					gen->MesType = Q931mes_CONNECT_ACKNOWLEDGE;
+					gen->CRVFlag = 0;	/* outbound */
+					Q931Rx43(&isdn_data->q931, (L3UCHAR *) gen, gen->Size);
+				} else {
+					ftdm_log(FTDM_LOG_CRIT, "Received Connect with no matching channel %d\n", chan_id);
+				}
+			}
+			break;
+		case Q931mes_SETUP:
+			{
+				Q931ie_CallingNum *callingnum = Q931GetIEPtr(gen->CallingNum, gen->buf);
+				Q931ie_CalledNum *callednum = Q931GetIEPtr(gen->CalledNum, gen->buf);
+				int fail = 1;
+				int fail_cause = 0;
+				int overlap_dial = 0;
+				uint32_t cplen = mlen;
+
+				if(ftdmchan && ftdmchan == isdn_data->channels_remote_crv[gen->CRV]) {
+					ftdm_log(FTDM_LOG_INFO, "Duplicate SETUP message(?) for Channel %d:%d ~ %d:%d in state %s [ignoring]\n",
+									ftdmchan->span_id,
+									ftdmchan->chan_id,
+									ftdmchan->physical_span_id,
+									ftdmchan->physical_chan_id,
+									ftdm_channel_state2str(ftdmchan->state));
+					break;
+				}
+				
+				ftdmchan = NULL;
+				/*
+				 * Channel selection for incoming calls:
+				 */
+				if (FTDM_SPAN_IS_NT(span) && chan_hunt) {
+					uint32_t x;
+
+					/*
+					 * In NT-mode with channel selection "any",
+					 * try to find a free channel
+					 */
+					for (x = 1; x <= span->chan_count; x++) {
+						ftdm_channel_t *zc = span->channels[x];
+
+						if (!ftdm_test_flag(zc, FTDM_CHANNEL_INUSE) && zc->state == FTDM_CHANNEL_STATE_DOWN) {
+							ftdmchan = zc;
+							break;
+						}
+					}
+				}
+				else if (!FTDM_SPAN_IS_NT(span) && chan_hunt) {
+					/*
+					 * In TE-mode this ("any") is invalid
+					 */
+					fail_cause = FTDM_CAUSE_CHANNEL_UNACCEPTABLE;
+
+					ftdm_log(FTDM_LOG_ERROR, "Invalid channel selection in incoming call (network side didn't specify a channel)\n");
+				}
+				else {
+					/*
+					 * Otherwise simply try to select the channel we've been told
+					 *
+					 * TODO: NT mode is abled to select a different channel if the one chosen
+					 *       by the TE side is already in use
+					 */
+					if (chan_id > 0 && chan_id < FTDM_MAX_CHANNELS_SPAN && chan_id <= span->chan_count) {
+						ftdmchan = span->channels[chan_id];
+					}
+					else {
+						/* invalid channel id */
+						fail_cause = FTDM_CAUSE_CHANNEL_UNACCEPTABLE;
+
+						ftdm_log(FTDM_LOG_ERROR, "Invalid channel selection in incoming call (none selected or out of bounds)\n");
+					}
+				}
+
+				if (!callednum || !strlen((char *)callednum->Digit)) {
+					if (FTDM_SPAN_IS_NT(span)) {
+						ftdm_log(FTDM_LOG_NOTICE, "No destination number found, assuming overlap dial\n");
+						overlap_dial++;
+					}
+					else {
+						ftdm_log(FTDM_LOG_ERROR, "No destination number found\n");
+						ftdmchan = NULL;
+					}
+				}
+
+				if (ftdmchan) {
+					if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_INUSE) || ftdmchan->state != FTDM_CHANNEL_STATE_DOWN) {
+						if (ftdmchan->state == FTDM_CHANNEL_STATE_DOWN || ftdmchan->state >= FTDM_CHANNEL_STATE_TERMINATING) {
+							int x = 0;
+							ftdm_log(FTDM_LOG_WARNING, "Channel %d:%d ~ %d:%d is already in use waiting for it to become available.\n",
+									ftdmchan->span_id,
+									ftdmchan->chan_id,
+									ftdmchan->physical_span_id,
+									ftdmchan->physical_chan_id);
+
+							for (x = 0; x < 200; x++) {
+								if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_INUSE)) {
+									break;
+								}
+								ftdm_sleep(5);
+							}
+						}
+						if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_INUSE)) {
+							ftdm_log(FTDM_LOG_ERROR, "Channel %d:%d ~ %d:%d is already in use.\n",
+									ftdmchan->span_id,
+									ftdmchan->chan_id,
+									ftdmchan->physical_span_id,
+									ftdmchan->physical_chan_id
+									);
+							ftdmchan = NULL;
+						}
+					}
+
+					if (ftdmchan && ftdmchan->state == FTDM_CHANNEL_STATE_DOWN) {
+						isdn_data->channels_remote_crv[gen->CRV] = ftdmchan;
+						memset(&ftdmchan->caller_data, 0, sizeof(ftdmchan->caller_data));
+
+						if (ftdmchan->mod_data) {
+							memset(ftdmchan->mod_data, 0, sizeof(ftdm_isdn_bchan_data_t));
+						}
+
+						ftdm_set_string(ftdmchan->caller_data.cid_num.digits, (char *)callingnum->Digit);
+						ftdm_set_string(ftdmchan->caller_data.cid_name, (char *)callingnum->Digit);
+						ftdm_set_string(ftdmchan->caller_data.ani.digits, (char *)callingnum->Digit);
+						if (!overlap_dial) {
+							ftdm_set_string(ftdmchan->caller_data.dnis.digits, (char *)callednum->Digit);
+						}
+
+						ftdmchan->caller_data.CRV = gen->CRV;
+						if (cplen > sizeof(ftdmchan->caller_data.raw_data)) {
+							cplen = sizeof(ftdmchan->caller_data.raw_data);
+						}
+						gen->CRVFlag = !(gen->CRVFlag);
+						memcpy(ftdmchan->caller_data.raw_data, msg, cplen);
+						ftdmchan->caller_data.raw_data_len = cplen;
+						fail = 0;
+					} 
+				} 
+
+				if (fail) {
+					Q931ie_Cause cause;
+					gen->MesType = Q931mes_DISCONNECT;
+					gen->CRVFlag = 1;	/* inbound call */
+					cause.IEId = Q931ie_CAUSE;
+					cause.Size = sizeof(Q931ie_Cause);
+					cause.CodStand = Q931_CODING_ITU;
+					cause.Location = 1;
+					cause.Recom = 1;
+					//should we be casting here.. or do we need to translate value?
+					cause.Value = (unsigned char)((fail_cause) ? fail_cause : FTDM_CAUSE_WRONG_CALL_STATE);
+					*cause.Diag = '\0';
+					gen->Cause = Q931AppendIE((L3UCHAR *) gen, (L3UCHAR *) &cause);
+					Q931Rx43(&isdn_data->q931, (L3UCHAR *) gen, gen->Size);
+
+					if (gen->CRV) {
+						Q931ReleaseCRV(&isdn_data->q931, gen->CRV);
+					}
+
+					if (ftdmchan) {
+						ftdm_log(FTDM_LOG_CRIT, "Channel is busy\n");
+					} else {
+						ftdm_log(FTDM_LOG_CRIT, "Failed to open channel for new setup message\n");
+					}
+					
+				} else {
+					Q931ie_ChanID ChanID;
+
+					/*
+					 * Update Channel ID IE
+					 */
+					Q931InitIEChanID(&ChanID);
+					ChanID.IntType = FTDM_SPAN_IS_BRI(ftdmchan->span) ? 0 : 1;	/* PRI = 1, BRI = 0 */
+					ChanID.PrefExcl = FTDM_SPAN_IS_NT(ftdmchan->span) ? 1 : 0;  /* Exclusive in NT-mode = 1, Preferred otherwise = 0 */
+					if(ChanID.IntType) {
+						ChanID.InfoChanSel = 1;		/* None = 0, See Slot = 1, Any = 3 */
+						ChanID.ChanMapType = 3;		/* B-Chan */
+						ChanID.ChanSlot = (unsigned char)ftdmchan->chan_id;
+					} else {
+						ChanID.InfoChanSel = (unsigned char)ftdmchan->chan_id & 0x03;	/* None = 0, B1 = 1, B2 = 2, Any = 3 */
+					}
+					gen->ChanID = Q931AppendIE((L3UCHAR *) gen, (L3UCHAR *) &ChanID);
+
+					if (overlap_dial) {
+						Q931ie_ProgInd progress;
+
+						/*
+						 * Setup Progress indicator
+						 */
+						progress.IEId = Q931ie_PROGRESS_INDICATOR;
+						progress.Size = sizeof(Q931ie_ProgInd);
+						progress.CodStand = Q931_CODING_ITU;	/* ITU */ 
+						progress.Location = 1;	/* private network serving the local user */
+						progress.ProgDesc = 8;	/* call is not end-to-end isdn = 1, in-band information available = 8 */
+						gen->ProgInd = Q931AppendIE((L3UCHAR *) gen, (L3UCHAR *) &progress);
+
+						/*
+						 * Send SETUP ACK
+						 */
+						gen->MesType = Q931mes_SETUP_ACKNOWLEDGE;
+						gen->CRVFlag = 1;	/* inbound call */
+						Q931Rx43(&isdn_data->q931, (L3UCHAR *) gen, gen->Size);
+
+						ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DIALTONE);
+					} else {
+						/*
+						 * Advance to RING state
+						 */
+						ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_RING);
+					}
+				}
+			}
+			break;
+
+		case Q931mes_CALL_PROCEEDING:
+			{
+				if (ftdmchan) {
+					ftdm_log(FTDM_LOG_CRIT, "Received CALL PROCEEDING message for channel %d\n", chan_id);
+					ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_PROGRESS);
+				} else {
+					ftdm_log(FTDM_LOG_CRIT, "Received CALL PROCEEDING with no matching channel %d\n", chan_id);
+				}
+			}
+			break;
+		case Q931mes_CONNECT_ACKNOWLEDGE:
+			{
+				if (ftdmchan) {
+					ftdm_log(FTDM_LOG_DEBUG, "Received CONNECT_ACK message for channel %d\n", chan_id);
+				} else {
+					ftdm_log(FTDM_LOG_DEBUG, "Received CONNECT_ACK with no matching channel %d\n", chan_id);
+				}
+			}
+			break;
+
+		case Q931mes_INFORMATION:
+			{
+				if (ftdmchan) {
+					ftdm_log(FTDM_LOG_CRIT, "Received INFORMATION message for channel %d\n", ftdmchan->chan_id);
+
+					if (ftdmchan->state == FTDM_CHANNEL_STATE_DIALTONE) {
+						char digit = '\0';
+
+						/*
+						 * overlap dial digit indication
+						 */
+						if (Q931IsIEPresent(gen->CalledNum)) {
+							ftdm_isdn_bchan_data_t *data = (ftdm_isdn_bchan_data_t *)ftdmchan->mod_data;
+							Q931ie_CalledNum *callednum = Q931GetIEPtr(gen->CalledNum, gen->buf);
+							int pos;
+
+							digit = callednum->Digit[strlen((char *)callednum->Digit) - 1];
+							if (digit == '#') {
+								callednum->Digit[strlen((char *)callednum->Digit) - 1] = '\0';
+							}
+
+							/* TODO: make this more safe with strncat() */
+							pos = (int)strlen(ftdmchan->caller_data.dnis.digits);
+							strcat(&ftdmchan->caller_data.dnis.digits[pos],    (char *)callednum->Digit);
+
+							/* update timer */
+							data->digit_timeout = ftdm_time_now() + isdn_data->digit_timeout;
+
+							ftdm_log(FTDM_LOG_DEBUG, "Received new overlap digit (%s), destination number: %s\n", callednum->Digit, ftdmchan->caller_data.dnis.digits);
+						}
+
+						if (Q931IsIEPresent(gen->SendComplete) || digit == '#') {
+							ftdm_log(FTDM_LOG_DEBUG, "Leaving overlap dial mode\n");
+
+							ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_RING);
+						}
+					}
+				} else {
+					ftdm_log(FTDM_LOG_CRIT, "Received INFORMATION message with no matching channel\n");
+				}
+			}
+			break;
+
+		case Q931mes_STATUS_ENQUIRY:
+			{
+				/*
+				 * !! HACK ALERT !!
+				 *
+				 * Map FreeTDM channel states to Q.931 states
+				 */
+				Q931ie_CallState state;
+				Q931ie_Cause cause;
+
+				gen->MesType = Q931mes_STATUS;
+				gen->CRVFlag = gen->CRVFlag ? 0 : 1;
+
+				state.CodStand  = Q931_CODING_ITU;	/* ITU-T */
+				state.CallState = Q931_U0;		/* Default: Null */
+
+				cause.IEId = Q931ie_CAUSE;
+				cause.Size = sizeof(Q931ie_Cause);
+				cause.CodStand = Q931_CODING_ITU;	/* ITU */
+				cause.Location = 1;	/* private network */
+				cause.Recom    = 1;	/* */
+				*cause.Diag    = '\0';
+
+				if(ftdmchan) {
+					switch(ftdmchan->state) {
+					case FTDM_CHANNEL_STATE_UP:
+						state.CallState = Q931_U10;	/* Active */
+						break;
+					case FTDM_CHANNEL_STATE_RING:
+						state.CallState = Q931_U6;	/* Call present */
+						break;
+					case FTDM_CHANNEL_STATE_DIALING:
+						state.CallState = Q931_U1;	/* Call initiated */
+						break;
+					case FTDM_CHANNEL_STATE_DIALTONE:
+						state.CallState = Q931_U25;	/* Overlap receiving */
+						break;
+
+					/* TODO: map missing states */
+
+					default:
+						state.CallState = Q931_U0;
+					}
+
+					cause.Value = 30;	/* response to STATUS ENQUIRY */
+				} else {
+					cause.Value = 98;	/* */
+				}
+
+				gen->CallState = Q931AppendIE((L3UCHAR *) gen, (L3UCHAR *) &state);
+				gen->Cause     = Q931AppendIE((L3UCHAR *) gen, (L3UCHAR *) &cause);
+				Q931Rx43(&isdn_data->q931, (L3UCHAR *) gen, gen->Size);
+			}
+			break;
+
+		default:
+			ftdm_log(FTDM_LOG_CRIT, "Received unhandled message %d (%#x)\n", (int)gen->MesType, (int)gen->MesType);
+			break;
+		}
+	}
+
+	return 0;
+}
+
+/**
+ * \brief Handler for Q921 read event
+ * \param pvt Span were message is coming from
+ * \param ind Q921 indication
+ * \param tei Terminal Endpoint Identifier
+ * \param msg Message string
+ * \param mlen Message string length
+ * \return 0 on success, 1 on failure
+ */
+static int ftdm_isdn_921_23(void *pvt, Q921DLMsg_t ind, L2UCHAR tei, L2UCHAR *msg, L2INT mlen)
+{
+	int ret, offset = (ind == Q921_DL_DATA) ? 4 : 3;
+	char bb[4096] = "";
+
+	switch(ind) {
+	case Q921_DL_DATA:
+	case Q921_DL_UNIT_DATA:
+		print_hex_bytes(msg + offset, mlen - offset, bb, sizeof(bb));
+#ifdef HAVE_LIBPCAP
+		/*Q931ToPcap*/
+                if(do_q931ToPcap==1){
+			ftdm_span_t *span = (ftdm_span_t *) pvt;
+                        if(writeQ931PacketToPcap(msg + offset, mlen - offset, span->span_id, 1) != FTDM_SUCCESS){
+                                ftdm_log(FTDM_LOG_WARNING, "Couldn't write Q931 buffer to pcap file!\n");
+                        }
+                }
+                /*Q931ToPcap done*/
+#endif
+		ftdm_log(FTDM_LOG_DEBUG, "READ %d\n%s\n%s\n\n\n", (int)mlen - offset, LINE, bb);
+	
+	default:
+		ret = Q931Rx23(pvt, ind, tei, msg, mlen);
+		if (ret != 0)
+			ftdm_log(FTDM_LOG_DEBUG, "931 parse error [%d] [%s]\n", ret, q931_error_to_name(ret));
+		break;
+	}
+
+	return ((ret >= 0) ? 1 : 0);
+}
+
+/**
+ * \brief Handler for Q921 write event
+ * \param pvt Span were message is coming from
+ * \param msg Message string
+ * \param mlen Message string length
+ * \return 0 on success, -1 on failure
+ */
+static int ftdm_isdn_921_21(void *pvt, L2UCHAR *msg, L2INT mlen)
+{
+	ftdm_span_t *span = (ftdm_span_t *) pvt;
+	ftdm_size_t len = (ftdm_size_t) mlen;
+	ftdm_isdn_data_t *isdn_data = span->signal_data;
+
+#ifdef IODEBUG
+	char bb[4096] = "";
+	print_hex_bytes(msg, len, bb, sizeof(bb));
+	print_bits(msg, (int)len, bb, sizeof(bb), FTDM_ENDIAN_LITTLE, 0);
+	ftdm_log(FTDM_LOG_DEBUG, "WRITE %d\n%s\n%s\n\n", (int)len, LINE, bb);
+
+#endif
+
+	assert(span != NULL);
+	return ftdm_channel_write(isdn_data->dchan, msg, len, &len) == FTDM_SUCCESS ? 0 : -1;
+}
+
+/**
+ * \brief Handler for channel state change
+ * \param ftdmchan Channel to handle
+ */
+static __inline__ void state_advance(ftdm_channel_t *ftdmchan)
+{
+	Q931mes_Generic *gen = (Q931mes_Generic *) ftdmchan->caller_data.raw_data;
+	ftdm_isdn_data_t *isdn_data = ftdmchan->span->signal_data;
+	ftdm_sigmsg_t sig;
+	ftdm_status_t status;
+
+	ftdm_log(FTDM_LOG_DEBUG, "%d:%d STATE [%s]\n", 
+			ftdmchan->span_id, ftdmchan->chan_id, ftdm_channel_state2str(ftdmchan->state));
+
+	memset(&sig, 0, sizeof(sig));
+	sig.chan_id = ftdmchan->chan_id;
+	sig.span_id = ftdmchan->span_id;
+	sig.channel = ftdmchan;
+
+	switch (ftdmchan->state) {
+	case FTDM_CHANNEL_STATE_DOWN:
+		{
+			if (gen->CRV) {
+				if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
+					isdn_data->channels_local_crv[gen->CRV] = NULL;
+				} else {
+					isdn_data->channels_remote_crv[gen->CRV] = NULL;
+				}
+				Q931ReleaseCRV(&isdn_data->q931, gen->CRV);
+			}
+			ftdm_channel_done(ftdmchan);
+		}
+		break;
+	case FTDM_CHANNEL_STATE_PROGRESS:
+		{
+			if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
+				sig.event_id = FTDM_SIGEVENT_PROGRESS;
+				if ((status = ftdm_span_send_signal(ftdmchan->span, &sig) != FTDM_SUCCESS)) {
+					ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP);
+				}
+			} else {
+				gen->MesType = Q931mes_CALL_PROCEEDING;
+				gen->CRVFlag = 1;	/* inbound */
+
+				if (FTDM_SPAN_IS_NT(ftdmchan->span)) {
+					Q931ie_ChanID ChanID;
+
+					/*
+					 * Set new Channel ID
+					 */
+					Q931InitIEChanID(&ChanID);
+					ChanID.IntType = FTDM_SPAN_IS_BRI(ftdmchan->span) ? 0 : 1;		/* PRI = 1, BRI = 0 */
+					ChanID.PrefExcl = 1;	/* always exclusive in NT-mode */
+
+					if(ChanID.IntType) {
+						ChanID.InfoChanSel = 1;		/* None = 0, See Slot = 1, Any = 3 */
+						ChanID.ChanMapType = 3; 	/* B-Chan */
+						ChanID.ChanSlot = (unsigned char)ftdmchan->chan_id;
+					} else {
+						ChanID.InfoChanSel = (unsigned char)ftdmchan->chan_id & 0x03;	/* None = 0, B1 = 1, B2 = 2, Any = 3 */
+					}
+					gen->ChanID = Q931AppendIE((L3UCHAR *) gen, (L3UCHAR *) &ChanID);
+				}
+
+				Q931Rx43(&isdn_data->q931, (void *)gen, gen->Size);
+			}
+		}
+		break;
+	case FTDM_CHANNEL_STATE_DIALTONE:
+		{
+			ftdm_isdn_bchan_data_t *data = (ftdm_isdn_bchan_data_t *)ftdmchan->mod_data;
+
+			if (data) {
+				data->digit_timeout = ftdm_time_now() + isdn_data->digit_timeout;
+			}
+		}
+		break;
+	case FTDM_CHANNEL_STATE_RING:
+		{
+			if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
+				sig.event_id = FTDM_SIGEVENT_START;
+				if ((status = ftdm_span_send_signal(ftdmchan->span, &sig) != FTDM_SUCCESS)) {
+					ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP);
+				}
+			}
+		}
+		break;
+	case FTDM_CHANNEL_STATE_RESTART:
+		{
+			ftdmchan->caller_data.hangup_cause = FTDM_CAUSE_NORMAL_UNSPECIFIED;
+			sig.event_id = FTDM_SIGEVENT_RESTART;
+			status = ftdm_span_send_signal(ftdmchan->span, &sig);
+			ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
+		}
+		break;
+	case FTDM_CHANNEL_STATE_PROGRESS_MEDIA:
+		{
+			if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
+				sig.event_id = FTDM_SIGEVENT_PROGRESS_MEDIA;
+				if ((status = ftdm_span_send_signal(ftdmchan->span, &sig) != FTDM_SUCCESS)) {
+					ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP);
+				}
+			} else {
+				if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OPEN)) {
+					if (ftdm_channel_open_chan(ftdmchan) != FTDM_SUCCESS) {
+						ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP);
+						return;
+					}
+				}
+				gen->MesType = Q931mes_ALERTING;
+				gen->CRVFlag = 1;	/* inbound call */
+				Q931Rx43(&isdn_data->q931, (void *)gen, gen->Size);
+			}
+		}
+		break;
+	case FTDM_CHANNEL_STATE_UP:
+		{
+			if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
+				sig.event_id = FTDM_SIGEVENT_UP;
+				if ((status = ftdm_span_send_signal(ftdmchan->span, &sig) != FTDM_SUCCESS)) {
+					ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP);
+				}
+			} else {
+				if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OPEN)) {
+					if (ftdm_channel_open_chan(ftdmchan) != FTDM_SUCCESS) {
+						ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP);
+						return;
+					}
+				}
+				gen->MesType = Q931mes_CONNECT;
+				gen->BearerCap = 0;
+				gen->CRVFlag = 1;	/* inbound call */
+				Q931Rx43(&isdn_data->q931, (void *)gen, ftdmchan->caller_data.raw_data_len);
+			}
+		}
+		break;
+	case FTDM_CHANNEL_STATE_DIALING:
+		if (!(isdn_data->opts & FTDM_ISDN_OPT_SUGGEST_CHANNEL)) {
+			Q931ie_BearerCap BearerCap;
+			Q931ie_ChanID ChanID;
+			Q931ie_CallingNum CallingNum;
+			Q931ie_CallingNum *ptrCallingNum;
+			Q931ie_CalledNum CalledNum;
+			Q931ie_CalledNum *ptrCalledNum;
+			Q931ie_Display Display, *ptrDisplay;
+			Q931ie_HLComp HLComp;			/* High-Layer Compatibility IE */
+			Q931ie_ProgInd Progress;		/* Progress Indicator IE */
+			int codec  = 0;
+
+			/*
+			 * get codec type
+			 */
+			ftdm_channel_command(ftdmchan->span->channels[ftdmchan->chan_id], FTDM_COMMAND_GET_NATIVE_CODEC, &codec);
+
+			/*
+			 * Q.931 Setup Message
+			 */ 
+			Q931InitMesGeneric(gen);
+			gen->MesType = Q931mes_SETUP;
+			gen->CRVFlag = 0;		/* outbound(?) */
+
+			/*
+			 * Bearer Capability IE
+			 */
+			Q931InitIEBearerCap(&BearerCap);
+			BearerCap.CodStand  = Q931_CODING_ITU;	/* ITU-T = 0, ISO/IEC = 1, National = 2, Network = 3 */
+			BearerCap.ITC       = Q931_ITC_SPEECH;	/* Speech */
+			BearerCap.TransMode = 0;		/* Circuit = 0, Packet = 1 */
+			BearerCap.ITR       = Q931_ITR_64K;	/* 64k = 16, Packet mode = 0 */
+			BearerCap.Layer1Ident = 1;
+			BearerCap.UIL1Prot = (codec == FTDM_CODEC_ALAW) ? 3 : 2;	/* U-law = 2, A-law = 3 */
+			gen->BearerCap = Q931AppendIE((L3UCHAR *) gen, (L3UCHAR *) &BearerCap);
+
+			/*
+			 * ChannelID IE
+			 */
+			Q931InitIEChanID(&ChanID);
+			ChanID.IntType = FTDM_SPAN_IS_BRI(ftdmchan->span) ? 0 : 1;	/* PRI = 1, BRI = 0 */
+			ChanID.PrefExcl = FTDM_SPAN_IS_NT(ftdmchan->span) ? 1 : 0;  /* Exclusive in NT-mode = 1, Preferred otherwise = 0 */
+			if(ChanID.IntType) {
+				ChanID.InfoChanSel = 1;		/* None = 0, See Slot = 1, Any = 3 */
+				ChanID.ChanMapType = 3;		/* B-Chan */
+				ChanID.ChanSlot = (unsigned char)ftdmchan->chan_id;
+			} else {
+				ChanID.InfoChanSel = (unsigned char)ftdmchan->chan_id & 0x03;	/* None = 0, B1 = 1, B2 = 2, Any = 3 */
+			}
+			gen->ChanID = Q931AppendIE((L3UCHAR *) gen, (L3UCHAR *) &ChanID);
+
+			/*
+			 * Progress IE
+			 */
+			Q931InitIEProgInd(&Progress);
+			Progress.CodStand = Q931_CODING_ITU;	/* 0 = ITU */
+			Progress.Location = 0;  /* 0 = User, 1 = Private Network */
+			Progress.ProgDesc = 3;	/* 1 = Not end-to-end ISDN */
+			gen->ProgInd = Q931AppendIE((L3UCHAR *)gen, (L3UCHAR *)&Progress);
+
+			/*
+			 * Display IE
+			 */
+			if (!(isdn_data->opts & FTDM_ISDN_OPT_OMIT_DISPLAY_IE)) {
+				Q931InitIEDisplay(&Display);
+				Display.Size = Display.Size + (unsigned char)strlen(ftdmchan->caller_data.cid_name);
+				gen->Display = Q931AppendIE((L3UCHAR *) gen, (L3UCHAR *) &Display);
+				ptrDisplay = Q931GetIEPtr(gen->Display, gen->buf);
+				ftdm_copy_string((char *)ptrDisplay->Display, ftdmchan->caller_data.cid_name, strlen(ftdmchan->caller_data.cid_name)+1);
+			}
+
+			/*
+			 * CallingNum IE
+			 */ 
+			Q931InitIECallingNum(&CallingNum);
+			CallingNum.TypNum    = ftdmchan->caller_data.ani.type;
+			CallingNum.NumPlanID = Q931_NUMPLAN_E164;
+			CallingNum.PresInd   = Q931_PRES_ALLOWED;
+			CallingNum.ScreenInd = Q931_SCREEN_USER_NOT_SCREENED;
+			CallingNum.Size = CallingNum.Size + (unsigned char)strlen(ftdmchan->caller_data.cid_num.digits);
+			gen->CallingNum = Q931AppendIE((L3UCHAR *) gen, (L3UCHAR *) &CallingNum);
+			ptrCallingNum = Q931GetIEPtr(gen->CallingNum, gen->buf);
+			ftdm_copy_string((char *)ptrCallingNum->Digit, ftdmchan->caller_data.cid_num.digits, strlen(ftdmchan->caller_data.cid_num.digits)+1);
+
+			/*
+			 * CalledNum IE
+			 */
+			Q931InitIECalledNum(&CalledNum);
+			CalledNum.TypNum    = ftdmchan->caller_data.dnis.type;
+			CalledNum.NumPlanID = Q931_NUMPLAN_E164;
+			CalledNum.Size = CalledNum.Size + (unsigned char)strlen(ftdmchan->caller_data.dnis.digits);
+			gen->CalledNum = Q931AppendIE((L3UCHAR *) gen, (L3UCHAR *) &CalledNum);
+			ptrCalledNum = Q931GetIEPtr(gen->CalledNum, gen->buf);
+			ftdm_copy_string((char *)ptrCalledNum->Digit, ftdmchan->caller_data.dnis.digits, strlen(ftdmchan->caller_data.dnis.digits)+1);
+
+			/*
+			 * High-Layer Compatibility IE   (Note: Required for AVM FritzBox)
+			 */
+			Q931InitIEHLComp(&HLComp);
+			HLComp.CodStand  = Q931_CODING_ITU;	/* ITU */
+			HLComp.Interpret = 4;	/* only possible value */
+			HLComp.PresMeth  = 1;   /* High-layer protocol profile */
+			HLComp.HLCharID  = Q931_HLCHAR_TELEPHONY;	/* Telephony = 1, Fax G2+3 = 4, Fax G4 = 65 (Class I)/ 68 (Class II or III) */   /* TODO: make accessible from user layer */
+			gen->HLComp = Q931AppendIE((L3UCHAR *) gen, (L3UCHAR *) &HLComp);
+
+			Q931Rx43(&isdn_data->q931, (L3UCHAR *) gen, gen->Size);
+			isdn_data->channels_local_crv[gen->CRV] = ftdmchan;
+		}
+		break;
+	case FTDM_CHANNEL_STATE_HANGUP_COMPLETE:
+		{
+			/* reply RELEASE with RELEASE_COMPLETE message */
+			if(ftdmchan->last_state == FTDM_CHANNEL_STATE_HANGUP) {
+				gen->MesType = Q931mes_RELEASE_COMPLETE;
+
+				Q931Rx43(&isdn_data->q931, (L3UCHAR *) gen, gen->Size);
+			}
+			ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
+		}
+		break;
+	case FTDM_CHANNEL_STATE_HANGUP:
+		{
+			Q931ie_Cause cause;
+
+			ftdm_log(FTDM_LOG_DEBUG, "Hangup: Direction %s\n", ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND) ? "Outbound" : "Inbound");
+
+			gen->CRVFlag = ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND) ? 0 : 1;
+
+			cause.IEId = Q931ie_CAUSE;
+			cause.Size = sizeof(Q931ie_Cause);
+			cause.CodStand = Q931_CODING_ITU;	/* ITU */
+			cause.Location = 1;	/* private network */
+			cause.Recom    = 1;	/* */
+
+			/*
+			 * BRI PTMP needs special handling here...
+			 * TODO: cleanup / refine (see above)
+			 */
+			if (ftdmchan->last_state == FTDM_CHANNEL_STATE_RING) {
+				/*
+				 * inbound call [was: number unknown (= not found in routing state)]
+				 * (in Q.931 spec terms: Reject request)
+				 */
+				gen->MesType = Q931mes_RELEASE_COMPLETE;
+
+				//cause.Value = (unsigned char) FTDM_CAUSE_UNALLOCATED;
+				cause.Value = (unsigned char) ftdmchan->caller_data.hangup_cause;
+				*cause.Diag = '\0';
+				gen->Cause = Q931AppendIE((L3UCHAR *) gen, (L3UCHAR *) &cause);
+				Q931Rx43(&isdn_data->q931, (L3UCHAR *) gen, gen->Size);
+
+				/* we're done, release channel */
+				//ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP_COMPLETE);
+				ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
+			}
+			else if (ftdmchan->last_state <= FTDM_CHANNEL_STATE_PROGRESS) {
+				/*
+				 * just release all unanswered calls [was: inbound call, remote side hung up before we answered]
+				 */
+				gen->MesType = Q931mes_RELEASE;
+
+				cause.Value = (unsigned char) ftdmchan->caller_data.hangup_cause;
+				*cause.Diag = '\0';
+				gen->Cause = Q931AppendIE((L3UCHAR *) gen, (L3UCHAR *) &cause);
+				Q931Rx43(&isdn_data->q931, (void *)gen, gen->Size);
+
+				/* this will be triggered by the RELEASE_COMPLETE reply */
+				/* ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP_COMPLETE); */
+			}
+			else {
+				/*
+				 * call connected, hangup
+				 */
+				gen->MesType = Q931mes_DISCONNECT;
+
+				cause.Value = (unsigned char) ftdmchan->caller_data.hangup_cause;
+				*cause.Diag = '\0';
+				gen->Cause = Q931AppendIE((L3UCHAR *) gen, (L3UCHAR *) &cause);
+				Q931Rx43(&isdn_data->q931, (L3UCHAR *) gen, gen->Size);
+			}
+		}
+		break;
+	case FTDM_CHANNEL_STATE_TERMINATING:
+		{
+			ftdm_log(FTDM_LOG_DEBUG, "Terminating: Direction %s\n", ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND) ? "Outbound" : "Inbound");
+
+			sig.event_id = FTDM_SIGEVENT_STOP;
+			status = ftdm_span_send_signal(ftdmchan->span, &sig);
+			gen->MesType = Q931mes_RELEASE;
+			gen->CRVFlag = ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND) ? 0 : 1;
+			Q931Rx43(&isdn_data->q931, (void *)gen, gen->Size);
+		}
+	default:
+		break;
+	}
+}
+
+/**
+ * \brief Checks current state on a span
+ * \param span Span to check status on
+ */
+static __inline__ void check_state(ftdm_span_t *span)
+{
+    if (ftdm_test_flag(span, FTDM_SPAN_STATE_CHANGE)) {
+        uint32_t j;
+        ftdm_clear_flag_locked(span, FTDM_SPAN_STATE_CHANGE);
+        for(j = 1; j <= span->chan_count; j++) {
+            if (ftdm_test_flag((span->channels[j]), FTDM_CHANNEL_STATE_CHANGE)) {
+				ftdm_mutex_lock(span->channels[j]->mutex);
+                ftdm_clear_flag((span->channels[j]), FTDM_CHANNEL_STATE_CHANGE);
+                state_advance(span->channels[j]);
+                ftdm_channel_complete_state(span->channels[j]);
+				ftdm_mutex_unlock(span->channels[j]->mutex);
+            }
+        }
+    }
+}
+
+/**
+ * \brief Processes FreeTDM event on a span
+ * \param span Span to process event on
+ * \param event Event to process
+ * \return Success or failure
+ */
+static __inline__ ftdm_status_t process_event(ftdm_span_t *span, ftdm_event_t *event)
+{
+	ftdm_log(FTDM_LOG_DEBUG, "EVENT [%s][%d:%d] STATE [%s]\n", 
+			ftdm_oob_event2str(event->enum_id), event->channel->span_id, event->channel->chan_id, ftdm_channel_state2str(event->channel->state));
+
+	switch(event->enum_id) {
+	case FTDM_OOB_ALARM_TRAP:
+		{
+			if (event->channel->state != FTDM_CHANNEL_STATE_DOWN) {
+				if (event->channel->type == FTDM_CHAN_TYPE_B) {
+					ftdm_set_state_locked(event->channel, FTDM_CHANNEL_STATE_RESTART);
+				}
+			}
+			
+
+			ftdm_set_flag(event->channel, FTDM_CHANNEL_SUSPENDED);
+
+			
+			ftdm_channel_get_alarms(event->channel);
+			ftdm_log(FTDM_LOG_WARNING, "channel %d:%d (%d:%d) has alarms! [%s]\n", 
+					event->channel->span_id, event->channel->chan_id, 
+					event->channel->physical_span_id, event->channel->physical_chan_id, 
+					event->channel->last_error);
+		}
+		break;
+	case FTDM_OOB_ALARM_CLEAR:
+		{
+			
+			ftdm_log(FTDM_LOG_WARNING, "channel %d:%d (%d:%d) alarms Cleared!\n", event->channel->span_id, event->channel->chan_id,
+					event->channel->physical_span_id, event->channel->physical_chan_id);
+
+			ftdm_clear_flag(event->channel, FTDM_CHANNEL_SUSPENDED);
+			ftdm_channel_get_alarms(event->channel);
+		}
+		break;
+	}
+
+	return FTDM_SUCCESS;
+}
+
+/**
+ * \brief Checks for events on a span
+ * \param span Span to check for events
+ */
+static __inline__ void check_events(ftdm_span_t *span)
+{
+	ftdm_status_t status;
+
+	status = ftdm_span_poll_event(span, 5);
+
+	switch(status) {
+	case FTDM_SUCCESS:
+		{
+			ftdm_event_t *event;
+			while (ftdm_span_next_event(span, &event) == FTDM_SUCCESS) {
+				if (event->enum_id == FTDM_OOB_NOOP) {
+					continue;
+				}
+				if (process_event(span, event) != FTDM_SUCCESS) {
+					break;
+				}
+			}
+		}
+		break;
+	case FTDM_FAIL:
+		{
+			ftdm_log(FTDM_LOG_DEBUG, "Event Failure! %d\n", ftdm_running());
+		}
+		break;
+	default:
+		break;
+	}
+}
+
+/**
+ * \brief Retrieves tone generation output to be sent
+ * \param ts Teletone generator
+ * \param map Tone map
+ * \return -1 on error, 0 on success
+ */
+static int teletone_handler(teletone_generation_session_t *ts, teletone_tone_map_t *map)
+{
+	ftdm_buffer_t *dt_buffer = ts->user_data;
+	int wrote;
+
+	if (!dt_buffer) {
+		return -1;
+	}
+	wrote = teletone_mux_tones(ts, map);
+	ftdm_buffer_write(dt_buffer, ts->buffer, wrote * 2);
+	return 0;
+}
+
+/**
+ * \brief Main thread function for tone generation on a span
+ * \param me Current thread
+ * \param obj Span to generate tones on
+ */
+static void *ftdm_isdn_tones_run(ftdm_thread_t *me, void *obj)
+{
+	ftdm_span_t *span = (ftdm_span_t *) obj;
+	ftdm_isdn_data_t *isdn_data = span->signal_data;
+	ftdm_buffer_t *dt_buffer = NULL;
+	teletone_generation_session_t ts = {{{{0}}}};
+	unsigned char frame[1024];
+	uint32_t x;
+	int interval = 0;
+	int offset = 0;
+
+	ftdm_log(FTDM_LOG_DEBUG, "ISDN tones thread starting.\n");
+	ftdm_set_flag(isdn_data, FTDM_ISDN_TONES_RUNNING);
+
+	if (ftdm_buffer_create(&dt_buffer, 1024, 1024, 0) != FTDM_SUCCESS) {
+		snprintf(isdn_data->dchan->last_error, sizeof(isdn_data->dchan->last_error), "memory error!");
+		ftdm_log(FTDM_LOG_ERROR, "MEM ERROR\n");
+		goto done;
+	}
+	ftdm_buffer_set_loops(dt_buffer, -1);
+
+	/* get a tone generation friendly interval to avoid distortions */
+	for (x = 1; x <= span->chan_count; x++) {
+		if (span->channels[x]->type != FTDM_CHAN_TYPE_DQ921) {
+			ftdm_channel_command(span->channels[x], FTDM_COMMAND_GET_INTERVAL, &interval);
+			break;
+		}
+	}
+	if (!interval) {
+		interval = 20;
+	}
+	ftdm_log(FTDM_LOG_NOTICE, "Tone generating interval %d\n", interval);
+
+	/* init teletone */
+	teletone_init_session(&ts, 0, teletone_handler, dt_buffer);
+	ts.rate     = 8000;
+	ts.duration = ts.rate;
+
+	/* main loop */
+	while(ftdm_running() && ftdm_test_flag(isdn_data, FTDM_ISDN_TONES_RUNNING) && !ftdm_test_flag(isdn_data, FTDM_ISDN_STOP)) {
+		ftdm_wait_flag_t flags;
+		ftdm_status_t status;
+		int last_chan_state = 0;
+		int gated = 0;
+		L2ULONG now = ftdm_time_now();
+
+		/*
+		 * check b-channel states and generate & send tones if neccessary
+		 */
+		for (x = 1; x <= span->chan_count; x++) {
+			ftdm_channel_t *ftdmchan = span->channels[x];
+			ftdm_size_t len = sizeof(frame), rlen;
+
+			if (ftdmchan->type == FTDM_CHAN_TYPE_DQ921) {
+				continue;
+			}
+
+			/*
+			 * Generate tones based on current bchan state
+			 * (Recycle buffer content if succeeding channels share the
+			 *  same state, this saves some cpu cycles)
+			 */
+			switch (ftdmchan->state) {
+			case FTDM_CHANNEL_STATE_DIALTONE:
+				{
+					ftdm_isdn_bchan_data_t *data = (ftdm_isdn_bchan_data_t *)ftdmchan->mod_data;
+
+					/* check overlap dial timeout first before generating tone */
+					if (data && data->digit_timeout && data->digit_timeout <= now) {
+						if (strlen(ftdmchan->caller_data.dnis.digits) > 0) {
+							ftdm_log(FTDM_LOG_DEBUG, "Overlap dial timeout, advancing to RING state\n");
+							ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_RING);
+						} else {
+							/* no digits received, hangup */
+							ftdm_log(FTDM_LOG_DEBUG, "Overlap dial timeout, no digits received, going to HANGUP state\n");
+							ftdmchan->caller_data.hangup_cause = FTDM_CAUSE_RECOVERY_ON_TIMER_EXPIRE;	/* TODO: probably wrong cause value */
+							ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP);
+						}
+						data->digit_timeout = 0;
+						continue;
+					}
+
+					if (last_chan_state != ftdmchan->state) {
+						ftdm_buffer_zero(dt_buffer);
+						teletone_run(&ts, ftdmchan->span->tone_map[FTDM_TONEMAP_DIAL]);
+						last_chan_state = ftdmchan->state;
+					}
+				}
+				break;
+
+			case FTDM_CHANNEL_STATE_RING:
+				{
+					if (last_chan_state != ftdmchan->state) {
+						ftdm_buffer_zero(dt_buffer);
+						teletone_run(&ts, ftdmchan->span->tone_map[FTDM_TONEMAP_RING]);
+						last_chan_state = ftdmchan->state;
+					}
+				}
+				break;
+
+			default:	/* Not in a tone generating state, go to next round */
+				continue;
+			}
+
+			if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OPEN)) {
+				if (ftdm_channel_open_chan(ftdmchan) != FTDM_SUCCESS) {
+					ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP);
+					continue;
+				}
+				ftdm_log(FTDM_LOG_NOTICE, "Successfully opened channel %d:%d\n", ftdmchan->span_id, ftdmchan->chan_id);
+			}
+
+			flags = FTDM_READ;
+
+			status = ftdm_channel_wait(ftdmchan, &flags, (gated) ? 0 : interval);
+			switch(status) {
+			case FTDM_FAIL:
+				continue;
+
+			case FTDM_TIMEOUT:
+				gated = 1;
+				continue;
+
+			default:
+				if (!(flags & FTDM_READ)) {
+					continue;
+				}
+			}
+			gated = 1;
+
+			status = ftdm_channel_read(ftdmchan, frame, &len);
+			if (status != FTDM_SUCCESS || len <= 0) {
+				continue;
+			}
+
+			if (ftdmchan->effective_codec != FTDM_CODEC_SLIN) {
+				len *= 2;
+			}
+
+			/* seek to current offset */
+			ftdm_buffer_seek(dt_buffer, offset);
+
+			rlen = ftdm_buffer_read_loop(dt_buffer, frame, len);
+
+			if (ftdmchan->effective_codec != FTDM_CODEC_SLIN) {
+				fio_codec_t codec_func = NULL;
+
+				if (ftdmchan->native_codec == FTDM_CODEC_ULAW) {
+					codec_func = fio_slin2ulaw;
+				} else if (ftdmchan->native_codec == FTDM_CODEC_ALAW) {
+					codec_func = fio_slin2alaw;
+				}
+
+				if (codec_func) {
+					status = codec_func(frame, sizeof(frame), &rlen);
+				} else {
+					snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "codec error!");
+					goto done;
+				}
+			}
+			ftdm_channel_write(ftdmchan, frame, sizeof(frame), &rlen);
+		}
+
+		/*
+		 * sleep a bit if there was nothing to do
+		 */
+		if (!gated) {
+			ftdm_sleep(interval);
+		}
+
+		offset += (ts.rate / (1000 / interval)) << 1;
+		if (offset >= ts.rate) {
+			offset = 0;
+		}
+	}
+
+done:
+	if (ts.buffer) {
+		teletone_destroy_session(&ts);
+	}
+
+	if (dt_buffer) {
+		ftdm_buffer_destroy(&dt_buffer);
+	}
+
+	ftdm_log(FTDM_LOG_DEBUG, "ISDN tone thread ended.\n");
+	ftdm_clear_flag(isdn_data, FTDM_ISDN_TONES_RUNNING);
+
+	return NULL;
+}
+
+/**
+ * \brief Main thread function for an ISDN span
+ * \param me Current thread
+ * \param obj Span to monitor
+ */
+static void *ftdm_isdn_run(ftdm_thread_t *me, void *obj)
+{
+	ftdm_span_t *span = (ftdm_span_t *) obj;
+	ftdm_isdn_data_t *isdn_data = span->signal_data;
+	unsigned char frame[1024];
+	ftdm_size_t len = sizeof(frame);
+	int errs = 0;
+
+#ifdef WIN32
+    timeBeginPeriod(1);
+#endif
+
+	ftdm_log(FTDM_LOG_DEBUG, "ISDN thread starting.\n");
+	ftdm_set_flag(isdn_data, FTDM_ISDN_RUNNING);
+
+	Q921Start(&isdn_data->q921);
+
+	while(ftdm_running() && ftdm_test_flag(isdn_data, FTDM_ISDN_RUNNING) && !ftdm_test_flag(isdn_data, FTDM_ISDN_STOP)) {
+		ftdm_wait_flag_t flags = FTDM_READ;
+		ftdm_status_t status = ftdm_channel_wait(isdn_data->dchan, &flags, 100);
+
+		Q921TimerTick(&isdn_data->q921);
+		Q931TimerTick(&isdn_data->q931);
+		check_state(span);
+		check_events(span);
+
+		/*
+		 *
+		 */
+		switch(status) {
+		case FTDM_FAIL:
+			{
+				ftdm_log(FTDM_LOG_ERROR, "D-Chan Read Error!\n");
+				snprintf(span->last_error, sizeof(span->last_error), "D-Chan Read Error!");
+				if (++errs == 10) {
+					isdn_data->dchan->state = FTDM_CHANNEL_STATE_UP;
+					goto done;
+				}
+			}
+			break;
+		case FTDM_TIMEOUT:
+			{
+				errs = 0;
+			}
+			break;
+		default:
+			{
+				errs = 0;
+				if (flags & FTDM_READ) {
+
+					if (ftdm_test_flag(isdn_data->dchan, FTDM_CHANNEL_SUSPENDED)) {
+						ftdm_clear_flag_all(span, FTDM_CHANNEL_SUSPENDED);
+					}
+					len = sizeof(frame);
+					if (ftdm_channel_read(isdn_data->dchan, frame, &len) == FTDM_SUCCESS) {
+#ifdef IODEBUG
+						char bb[4096] = "";
+						print_hex_bytes(frame, len, bb, sizeof(bb));
+
+						print_bits(frame, (int)len, bb, sizeof(bb), FTDM_ENDIAN_LITTLE, 0);
+						ftdm_log(FTDM_LOG_DEBUG, "READ %d\n%s\n%s\n\n", (int)len, LINE, bb);
+#endif
+
+						Q921QueueHDLCFrame(&isdn_data->q921, frame, (int)len);
+						Q921Rx12(&isdn_data->q921);
+					}
+				} else {
+					ftdm_log(FTDM_LOG_DEBUG, "No Read FLAG!\n");
+				}
+			}
+			break;
+		}
+	}
+	
+ done:
+	ftdm_channel_close(&isdn_data->dchans[0]);
+	ftdm_channel_close(&isdn_data->dchans[1]);
+	ftdm_clear_flag(isdn_data, FTDM_ISDN_RUNNING);
+
+#ifdef WIN32
+    timeEndPeriod(1);
+#endif
+
+	ftdm_log(FTDM_LOG_DEBUG, "ISDN thread ended.\n");
+	return NULL;
+}
+
+/**
+ * \brief FreeTDM ISDN signaling module initialisation
+ * \return Success
+ */
+static FIO_SIG_LOAD_FUNCTION(ftdm_isdn_init)
+{
+	Q931Initialize();
+
+	Q921SetGetTimeCB(ftdm_time_now);
+	Q931SetGetTimeCB(ftdm_time_now);
+
+	return FTDM_SUCCESS;
+}
+
+/**
+ * \brief Receives a Q931 indication message
+ * \param pvt Span were message is coming from
+ * \param ind Q931 indication
+ * \param tei Terminal Endpoint Identifier
+ * \param msg Message string
+ * \param mlen Message string length
+ * \return 0 on success
+ */
+static int q931_rx_32(void *pvt, Q921DLMsg_t ind, L3UCHAR tei, L3UCHAR *msg, L3INT mlen)
+{
+	int offset = 4;
+	char bb[4096] = "";
+
+	switch(ind) {
+	case Q921_DL_UNIT_DATA:
+		offset = 3;
+
+	case Q921_DL_DATA:
+		print_hex_bytes(msg + offset, mlen - offset, bb, sizeof(bb));
+#ifdef HAVE_LIBPCAP
+		/*Q931ToPcap*/
+		if(do_q931ToPcap==1){
+			ftdm_span_t *span = (ftdm_span_t *) pvt;
+			if(writeQ931PacketToPcap(msg + offset, mlen - offset, span->span_id, 0) != FTDM_SUCCESS){
+				ftdm_log(FTDM_LOG_WARNING, "Couldn't write Q931 buffer to pcap file!\n");	
+			}
+		}
+		/*Q931ToPcap done*/
+#endif
+		ftdm_log(FTDM_LOG_DEBUG, "WRITE %d\n%s\n%s\n\n", (int)mlen - offset, LINE, bb);
+		break;
+
+	default:
+		break;
+	}
+
+	return Q921Rx32(pvt, ind, tei, msg, mlen);
+}
+
+/**
+ * \brief Logs Q921 message
+ * \param pvt Span were message is coming from
+ * \param level Q921 log level
+ * \param msg Message string
+ * \param size Message string length
+ * \return 0
+ */
+static int ftdm_isdn_q921_log(void *pvt, Q921LogLevel_t level, char *msg, L2INT size)
+{
+	ftdm_span_t *span = (ftdm_span_t *) pvt;
+
+	ftdm_log("Span", "Q.921", span->span_id, (int)level, "%s", msg);
+	return 0;
+}
+
+/**
+ * \brief Logs Q931 message
+ * \param pvt Span were message is coming from
+ * \param level Q931 log level
+ * \param msg Message string
+ * \param size Message string length
+ * \return 0
+ */
+static L3INT ftdm_isdn_q931_log(void *pvt, Q931LogLevel_t level, char *msg, L3INT size)
+{
+	ftdm_span_t *span = (ftdm_span_t *) pvt;
+
+	ftdm_log("Span", "Q.931", span->span_id, (int)level, "%s", msg);
+	return 0;
+}
+/**
+ * \brief ISDN state map
+ */
+static ftdm_state_map_t isdn_state_map = {
+	{
+		{
+			ZSD_OUTBOUND,
+			ZSM_UNACCEPTABLE,
+			{FTDM_ANY_STATE},
+			{FTDM_CHANNEL_STATE_RESTART, FTDM_END}
+		},
+		{
+			ZSD_OUTBOUND,
+			ZSM_UNACCEPTABLE,
+			{FTDM_CHANNEL_STATE_RESTART, FTDM_END},
+			{FTDM_CHANNEL_STATE_DOWN, FTDM_END}
+		},
+		{
+			ZSD_OUTBOUND,
+			ZSM_UNACCEPTABLE,
+			{FTDM_CHANNEL_STATE_DOWN, FTDM_END},
+			{FTDM_CHANNEL_STATE_DIALING, FTDM_END}
+		},
+		{
+			ZSD_OUTBOUND,
+			ZSM_UNACCEPTABLE,
+			{FTDM_CHANNEL_STATE_DIALING, FTDM_END},
+			{FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_CHANNEL_STATE_PROGRESS, FTDM_CHANNEL_STATE_UP, FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_END}
+		},
+		{
+			ZSD_OUTBOUND,
+			ZSM_UNACCEPTABLE,
+			{FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_CHANNEL_STATE_PROGRESS, FTDM_END},
+			{FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_UP, FTDM_END}
+		},
+		{
+			ZSD_OUTBOUND,
+			ZSM_UNACCEPTABLE,
+			{FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_END},
+			{FTDM_CHANNEL_STATE_HANGUP_COMPLETE, FTDM_CHANNEL_STATE_DOWN, FTDM_END}
+		},
+		{
+			ZSD_OUTBOUND,
+			ZSM_UNACCEPTABLE,
+			{FTDM_CHANNEL_STATE_HANGUP_COMPLETE, FTDM_END},
+			{FTDM_CHANNEL_STATE_DOWN, FTDM_END},
+		},
+		{
+			ZSD_OUTBOUND,
+			ZSM_UNACCEPTABLE,
+			{FTDM_CHANNEL_STATE_UP, FTDM_END},
+			{FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_END}
+		},
+
+		/****************************************/
+		{
+			ZSD_INBOUND,
+			ZSM_UNACCEPTABLE,
+			{FTDM_ANY_STATE},
+			{FTDM_CHANNEL_STATE_RESTART, FTDM_END}
+		},
+		{
+			ZSD_INBOUND,
+			ZSM_UNACCEPTABLE,
+			{FTDM_CHANNEL_STATE_RESTART, FTDM_END},
+			{FTDM_CHANNEL_STATE_DOWN, FTDM_END}
+		},
+		{
+			ZSD_INBOUND,
+			ZSM_UNACCEPTABLE,
+			{FTDM_CHANNEL_STATE_DOWN, FTDM_END},
+			{FTDM_CHANNEL_STATE_DIALTONE, FTDM_CHANNEL_STATE_RING, FTDM_END}
+		},
+		{
+			ZSD_INBOUND,
+			ZSM_UNACCEPTABLE,
+			{FTDM_CHANNEL_STATE_DIALTONE, FTDM_END},
+			{FTDM_CHANNEL_STATE_RING, FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_END}
+		},
+		{
+			ZSD_INBOUND,
+			ZSM_UNACCEPTABLE,
+			{FTDM_CHANNEL_STATE_RING, FTDM_END},
+			{FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_PROGRESS, FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_CHANNEL_STATE_UP, FTDM_END}
+		},
+		{
+			ZSD_INBOUND,
+			ZSM_UNACCEPTABLE,
+			{FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_END},
+			{FTDM_CHANNEL_STATE_HANGUP_COMPLETE, FTDM_CHANNEL_STATE_DOWN, FTDM_END},
+		},
+		{
+			ZSD_INBOUND,
+			ZSM_UNACCEPTABLE,
+			{FTDM_CHANNEL_STATE_HANGUP_COMPLETE, FTDM_END},
+			{FTDM_CHANNEL_STATE_DOWN, FTDM_END},
+		},
+		{
+			ZSD_INBOUND,
+			ZSM_UNACCEPTABLE,
+			{FTDM_CHANNEL_STATE_PROGRESS, FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_END},
+			{FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_PROGRESS_MEDIA, 
+			 FTDM_CHANNEL_STATE_CANCEL, FTDM_CHANNEL_STATE_UP, FTDM_END},
+		},
+		{
+			ZSD_INBOUND,
+			ZSM_UNACCEPTABLE,
+			{FTDM_CHANNEL_STATE_UP, FTDM_END},
+			{FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_END},
+		},
+		
+
+	}
+};
+
+/**
+ * \brief Stops an ISDN span
+ * \param span Span to halt
+ * \return Success
+ *
+ * Sets a stop flag and waits for the threads to end
+ */
+static ftdm_status_t ftdm_isdn_stop(ftdm_span_t *span)
+{
+	ftdm_isdn_data_t *isdn_data = span->signal_data;
+
+	if (!ftdm_test_flag(isdn_data, FTDM_ISDN_RUNNING)) {
+		return FTDM_FAIL;
+	}
+		
+	ftdm_set_flag(isdn_data, FTDM_ISDN_STOP);
+	
+	while(ftdm_test_flag(isdn_data, FTDM_ISDN_RUNNING)) {
+		ftdm_sleep(100);
+	}
+
+	while(ftdm_test_flag(isdn_data, FTDM_ISDN_TONES_RUNNING)) {
+		ftdm_sleep(100);
+	}
+
+	return FTDM_SUCCESS;
+	
+}
+
+/**
+ * \brief Starts an ISDN span
+ * \param span Span to halt
+ * \return Success or failure
+ *
+ * Launches a thread to monitor the span and a thread to generate tones on the span
+ */
+static ftdm_status_t ftdm_isdn_start(ftdm_span_t *span)
+{
+	ftdm_status_t ret;
+	ftdm_isdn_data_t *isdn_data = span->signal_data;
+
+	if (ftdm_test_flag(isdn_data, FTDM_ISDN_RUNNING)) {
+		return FTDM_FAIL;
+	}
+
+	ftdm_clear_flag(isdn_data, FTDM_ISDN_STOP);
+	ret = ftdm_thread_create_detached(ftdm_isdn_run, span);
+
+	if (ret != FTDM_SUCCESS) {
+		return ret;
+	}
+
+	if (FTDM_SPAN_IS_NT(span) && !(isdn_data->opts & FTDM_ISDN_OPT_DISABLE_TONES)) {
+		ret = ftdm_thread_create_detached(ftdm_isdn_tones_run, span);
+	}
+	return ret;
+}
+
+/**
+ * \brief Parses an option string to flags
+ * \param in String to parse for configuration options
+ * \return Flags
+ */
+static uint32_t parse_opts(const char *in)
+{
+	uint32_t flags = 0;
+	
+	if (!in) {
+		return 0;
+	}
+	
+	if (strstr(in, "suggest_channel")) {
+		flags |= FTDM_ISDN_OPT_SUGGEST_CHANNEL;
+	}
+
+	if (strstr(in, "omit_display")) {
+		flags |= FTDM_ISDN_OPT_OMIT_DISPLAY_IE;
+	}
+
+	if (strstr(in, "disable_tones")) {
+		flags |= FTDM_ISDN_OPT_DISABLE_TONES;
+	}
+
+	return flags;
+}
+
+/**
+ * \brief Initialises an ISDN span from configuration variables
+ * \param span Span to configure
+ * \param sig_cb Callback function for event signals
+ * \param ap List of configuration variables
+ * \return Success or failure
+ */
+static FIO_SIG_CONFIGURE_FUNCTION(ftdm_isdn_configure_span)
+{
+	uint32_t i, x = 0;
+	ftdm_channel_t *dchans[2] = {0};
+	ftdm_isdn_data_t *isdn_data;
+	const char *tonemap = "us";
+	char *var, *val;
+	Q931Dialect_t dialect = Q931_Dialect_National;
+	int32_t digit_timeout = 0;
+	int q921loglevel = -1;
+	int q931loglevel = -1;
+#ifdef HAVE_LIBPCAP
+	int q931topcap   = -1; 	/*Q931ToPcap*/
+	int openPcap = 0; 	/*Flag: open Pcap file please*/
+#endif
+
+	if (span->signal_type) {
+#ifdef HAVE_LIBPCAP
+		/*Q931ToPcap: Get the content of the q931topcap and pcapfilename args given by mod_freetdm */
+		while((var = va_arg(ap, char *))) {
+			if (!strcasecmp(var, "q931topcap")) {
+				q931topcap = va_arg(ap, int);
+				if(q931topcap==1) {
+					/*PCAP on*/;
+					openPcap=1;
+				} else if (q931topcap==0) {
+					/*PCAP off*/
+					if (closePcapFile() != FTDM_SUCCESS) return FTDM_FAIL;
+					do_q931ToPcap=0;
+					return FTDM_SUCCESS;
+				}
+			}
+			if (!strcasecmp(var, "pcapfilename")) {
+				/*Put filename into global var*/
+				pcapfn = va_arg(ap, char*);
+			}
+		}
+		/*We know now, that user wants to enable Q931ToPcap and what file name he wants, so open it please*/
+		if(openPcap==1){
+			if(openPcapFile() != FTDM_SUCCESS) return FTDM_FAIL;
+			do_q931ToPcap=1;
+			return FTDM_SUCCESS;
+		}
+		/*Q931ToPcap done*/
+#endif
+		snprintf(span->last_error, sizeof(span->last_error), "Span is already configured for signalling [%d].", span->signal_type);
+		return FTDM_FAIL;
+	}
+
+	if (span->trunk_type >= FTDM_TRUNK_NONE) {
+		ftdm_log(FTDM_LOG_WARNING, "Invalid trunk type '%s' defaulting to T1.\n", ftdm_trunk_type2str(span->trunk_type));
+		span->trunk_type = FTDM_TRUNK_T1;
+	}
+	
+	for(i = 1; i <= span->chan_count; i++) {
+		if (span->channels[i]->type == FTDM_CHAN_TYPE_DQ921) {
+			if (x > 1) {
+				snprintf(span->last_error, sizeof(span->last_error), "Span has more than 2 D-Channels!");
+				return FTDM_FAIL;
+			} else {
+				if (ftdm_channel_open(span->span_id, i, &dchans[x]) == FTDM_SUCCESS) {
+					ftdm_log(FTDM_LOG_DEBUG, "opening d-channel #%d %d:%d\n", x, dchans[x]->span_id, dchans[x]->chan_id);
+					dchans[x]->state = FTDM_CHANNEL_STATE_UP;
+					x++;
+				}
+			}
+		}
+	}
+
+	if (!x) {
+		snprintf(span->last_error, sizeof(span->last_error), "Span has no D-Channels!");
+		return FTDM_FAIL;
+	}
+
+	isdn_data = ftdm_malloc(sizeof(*isdn_data));
+	assert(isdn_data != NULL);
+	memset(isdn_data, 0, sizeof(*isdn_data));
+	
+	isdn_data->mode = Q931_TE;
+	dialect = Q931_Dialect_National;
+	
+	while((var = va_arg(ap, char *))) {
+		if (!strcasecmp(var, "mode")) {
+			if (!(val = va_arg(ap, char *))) {
+				break;
+			}
+			isdn_data->mode = strcasecmp(val, "net") ? Q931_TE : Q931_NT;
+		} else if (!strcasecmp(var, "dialect")) {
+			if (!(val = va_arg(ap, char *))) {
+				break;
+			}
+			dialect = q931_str2Q931Dialect_type(val);
+			if (dialect == Q931_Dialect_Count) {
+				return FTDM_FAIL;
+			}
+		} else if (!strcasecmp(var, "opts")) {
+			if (!(val = va_arg(ap, char *))) {
+				break;
+			}
+			isdn_data->opts = parse_opts(val);
+		} else if (!strcasecmp(var, "tonemap")) {
+			if (!(val = va_arg(ap, char *))) {
+				break;
+			}
+			tonemap = (const char *)val;
+		} else if (!strcasecmp(var, "digit_timeout")) {
+			int *optp;
+			if (!(optp = va_arg(ap, int *))) {
+				break;
+			}
+			digit_timeout = *optp;
+		} else if (!strcasecmp(var, "q921loglevel")) {
+			q921loglevel = va_arg(ap, int);
+			if (q921loglevel < Q921_LOG_NONE) {
+				q921loglevel = Q921_LOG_NONE;
+			} else if (q921loglevel > Q921_LOG_DEBUG) {
+				q921loglevel = Q921_LOG_DEBUG;
+			}
+		} else if (!strcasecmp(var, "q931loglevel")) {
+			q931loglevel = va_arg(ap, int);
+			if (q931loglevel < Q931_LOG_NONE) {
+				q931loglevel = Q931_LOG_NONE;
+			} else if (q931loglevel > Q931_LOG_DEBUG) {
+				q931loglevel = Q931_LOG_DEBUG;
+			}
+		} else {
+			snprintf(span->last_error, sizeof(span->last_error), "Unknown parameter [%s]", var);
+			return FTDM_FAIL;
+		}
+	}
+
+
+	if (!digit_timeout) {
+		digit_timeout = DEFAULT_DIGIT_TIMEOUT;
+	}
+	else if (digit_timeout < 3000 || digit_timeout > 30000) {
+		ftdm_log(FTDM_LOG_WARNING, "Digit timeout %d ms outside of range (3000 - 30000 ms), using default (10000 ms)\n", digit_timeout);
+		digit_timeout = DEFAULT_DIGIT_TIMEOUT;
+	}
+
+	/* allocate per b-chan data */
+	if (isdn_data->mode == Q931_NT) {
+		ftdm_isdn_bchan_data_t *data;
+
+		data = ftdm_malloc((span->chan_count - 1) * sizeof(ftdm_isdn_bchan_data_t));
+		if (!data) {
+			return FTDM_FAIL;
+		}
+
+		for (i = 1; i <= span->chan_count; i++, data++) {
+			if (span->channels[i]->type == FTDM_CHAN_TYPE_B) {
+				span->channels[i]->mod_data = data;
+				memset(data, 0, sizeof(ftdm_isdn_bchan_data_t));
+			}
+		}
+	}
+					
+	span->start = ftdm_isdn_start;
+	span->stop = ftdm_isdn_stop;
+	span->signal_cb = sig_cb;
+	isdn_data->dchans[0] = dchans[0];
+	isdn_data->dchans[1] = dchans[1];
+	isdn_data->dchan = isdn_data->dchans[0];
+	isdn_data->digit_timeout = digit_timeout;
+	
+	Q921_InitTrunk(&isdn_data->q921,
+				   0,
+				   0,
+				   isdn_data->mode,
+				   span->trunk_type == FTDM_TRUNK_BRI_PTMP ? Q921_PTMP : Q921_PTP,
+				   0,
+				   ftdm_isdn_921_21,
+				   (Q921Tx23CB_t)ftdm_isdn_921_23,
+				   span,
+				   &isdn_data->q931);
+
+	Q921SetLogCB(&isdn_data->q921, &ftdm_isdn_q921_log, isdn_data);
+	Q921SetLogLevel(&isdn_data->q921, (Q921LogLevel_t)q921loglevel);
+	
+	Q931Api_InitTrunk(&isdn_data->q931,
+					  dialect,
+					  isdn_data->mode,
+					  span->trunk_type,
+					  ftdm_isdn_931_34,
+					  (Q931Tx32CB_t)q931_rx_32,
+					  ftdm_isdn_931_err,
+					  &isdn_data->q921,
+					  span);
+
+	Q931SetLogCB(&isdn_data->q931, &ftdm_isdn_q931_log, isdn_data);
+	Q931SetLogLevel(&isdn_data->q931, (Q931LogLevel_t)q931loglevel);
+
+	isdn_data->q931.autoRestartAck = 1;
+	isdn_data->q931.autoConnectAck = 0;
+	isdn_data->q931.autoServiceAck = 1;
+	span->signal_data = isdn_data;
+	span->signal_type = FTDM_SIGTYPE_ISDN;
+	span->outgoing_call = isdn_outgoing_call;
+
+	if ((isdn_data->opts & FTDM_ISDN_OPT_SUGGEST_CHANNEL)) {
+		span->channel_request = isdn_channel_request;
+		span->suggest_chan_id = 1;
+	}
+	span->state_map = &isdn_state_map;
+
+	ftdm_span_load_tones(span, tonemap);
+
+	return FTDM_SUCCESS;
+}
+
+/**
+ * \brief FreeTDM ISDN signaling module definition
+ */
+EX_DECLARE_DATA ftdm_module_t ftdm_module = {
+	"isdn",
+	NULL,
+	close_pcap,
+	ftdm_isdn_init,
+	ftdm_isdn_configure_span,
+	NULL
+};
+
+
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */

Added: freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_isdn/ozmod_isdn.2005.vcproj (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_isdn/ozmod_isdn.2005.vcproj	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_isdn/ozmod_isdn.2005.vcproj	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,316 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="8.00"
+	Name="ftmod_isdn"
+	ProjectGUID="{729344A5-D5E9-434D-8EE8-AF8C6C795D15}"
+	RootNamespace="ftmod_isdn"
+	Keyword="Win32Proj"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="2"
+			CharacterSet="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				AdditionalIncludeDirectories="..\..\isdn\include;..\..\include"
+				PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;FTMOD_ISDN_EXPORTS;_CRT_SECURE_NO_WARNINGS"
+				MinimalRebuild="true"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="3"
+				UsePrecompiledHeader="0"
+				WarningLevel="4"
+				WarnAsError="true"
+				DebugInformationFormat="4"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				LinkIncremental="2"
+				GenerateDebugInformation="true"
+				SubSystem="2"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="2"
+			CharacterSet="1"
+			WholeProgramOptimization="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="2"
+				EnableIntrinsicFunctions="true"
+				AdditionalIncludeDirectories="..\..\isdn\include;..\..\include"
+				PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;FTMOD_ISDN_EXPORTS;_CRT_SECURE_NO_WARNINGS"
+				RuntimeLibrary="2"
+				EnableFunctionLevelLinking="true"
+				UsePrecompiledHeader="0"
+				WarningLevel="4"
+				WarnAsError="true"
+				DebugInformationFormat="3"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				LinkIncremental="1"
+				GenerateDebugInformation="true"
+				SubSystem="2"
+				OptimizeReferences="2"
+				EnableCOMDATFolding="2"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<Filter
+			Name="Source Files"
+			Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+			>
+			<File
+				RelativePath="..\..\isdn\5ESSmes.c"
+				>
+			</File>
+			<File
+				RelativePath="..\..\isdn\5ESSStateNT.c"
+				>
+			</File>
+			<File
+				RelativePath="..\..\isdn\5ESSStateTE.c"
+				>
+			</File>
+			<File
+				RelativePath="..\..\isdn\DMSmes.c"
+				>
+			</File>
+			<File
+				RelativePath="..\..\isdn\DMSStateNT.c"
+				>
+			</File>
+			<File
+				RelativePath="..\..\isdn\DMSStateTE.c"
+				>
+			</File>
+			<File
+				RelativePath="..\..\isdn\EuroISDNStateNT.c"
+				>
+			</File>
+			<File
+				RelativePath="..\..\isdn\EuroISDNStateTE.c"
+				>
+			</File>
+			<File
+				RelativePath="..\..\isdn\mfifo.c"
+				>
+			</File>
+			<File
+				RelativePath="..\..\isdn\nationalmes.c"
+				>
+			</File>
+			<File
+				RelativePath="..\..\isdn\nationalStateNT.c"
+				>
+			</File>
+			<File
+				RelativePath="..\..\isdn\nationalStateTE.c"
+				>
+			</File>
+			<File
+				RelativePath="ftmod_isdn.c"
+				>
+			</File>
+			<File
+				RelativePath="..\..\isdn\Q921.c"
+				>
+			</File>
+			<File
+				RelativePath="..\..\isdn\Q931.c"
+				>
+			</File>
+			<File
+				RelativePath="..\..\isdn\Q931api.c"
+				>
+			</File>
+			<File
+				RelativePath="..\..\isdn\Q931ie.c"
+				>
+			</File>
+			<File
+				RelativePath="..\..\isdn\Q931mes.c"
+				>
+			</File>
+			<File
+				RelativePath="..\..\isdn\Q931StateNT.c"
+				>
+			</File>
+			<File
+				RelativePath="..\..\isdn\Q931StateTE.c"
+				>
+			</File>
+			<File
+				RelativePath="..\..\isdn\Q932mes.c"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="Header Files"
+			Filter="h;hpp;hxx;hm;inl;inc;xsd"
+			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+			>
+			<File
+				RelativePath="..\..\isdn\include\5ESS.h"
+				>
+			</File>
+			<File
+				RelativePath="..\..\isdn\include\DMS.h"
+				>
+			</File>
+			<File
+				RelativePath="..\..\isdn\include\mfifo.h"
+				>
+			</File>
+			<File
+				RelativePath="..\..\isdn\include\national.h"
+				>
+			</File>
+			<File
+				RelativePath="..\..\isdn\include\Q921.h"
+				>
+			</File>
+			<File
+				RelativePath="..\..\isdn\include\Q921priv.h"
+				>
+			</File>
+			<File
+				RelativePath="..\..\isdn\include\Q931.h"
+				>
+			</File>
+			<File
+				RelativePath="..\..\isdn\include\Q931ie.h"
+				>
+			</File>
+			<File
+				RelativePath="..\..\isdn\include\Q932.h"
+				>
+			</File>
+			<File
+				RelativePath="ftdm_isdn.h"
+				>
+			</File>
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>

Added: freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_libpri/ftmod_libpri.c (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_libpri/ftmod_libpri.c	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_libpri/ftmod_libpri.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,1364 @@
+/*
+ * Copyright (c) 2007, Anthony Minessale II
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "freetdm.h"
+#include "ftmod_libpri.h"
+
+/**
+ * \brief Unloads libpri IO module
+ * \return Success
+ */
+static FIO_IO_UNLOAD_FUNCTION(ftdm_libpri_unload)
+{
+	return FTDM_SUCCESS;
+}
+
+/**
+ * \brief Starts a libpri channel (outgoing call)
+ * \param ftdmchan Channel to initiate call on
+ * \return Success or failure
+ */
+static FIO_CHANNEL_OUTGOING_CALL_FUNCTION(isdn_outgoing_call)
+{
+	ftdm_status_t status = FTDM_SUCCESS;
+	ftdm_set_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND);
+	ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DIALING);
+	return status;
+}
+
+/**
+ * \brief Requests an libpri channel on a span (outgoing call)
+ * \param span Span where to get a channel (unused)
+ * \param chan_id Specific channel to get (0 for any) (unused)
+ * \param direction Call direction (unused)
+ * \param caller_data Caller information (unused)
+ * \param ftdmchan Channel to initialise (unused)
+ * \return Failure
+ */
+static FIO_CHANNEL_REQUEST_FUNCTION(isdn_channel_request)
+{
+	return FTDM_FAIL;
+}
+
+#ifdef WIN32
+/**
+ * \brief Logs a libpri error
+ * \param s Error string
+ */
+static void s_pri_error(char *s)
+#else
+/**
+ * \brief Logs a libpri error
+ * \param pri libpri structure (unused)
+ * \param s Error string
+ */
+static void s_pri_error(struct pri *pri, char *s)
+#endif
+{
+	ftdm_log(FTDM_LOG_ERROR, "%s", s);
+}
+
+#ifdef WIN32
+/**
+ * \brief Logs a libpri message
+ * \param s Message string
+ */
+static void s_pri_message(char *s)
+#else
+/**
+ * \brief Logs a libpri message
+ * \param pri libpri structure (unused)
+ * \param s Message string
+ */
+static void s_pri_message(struct pri *pri, char *s)
+#endif
+{
+		ftdm_log(FTDM_LOG_DEBUG, "%s", s);
+}
+
+/**
+ * \brief Parses an option string to flags
+ * \param in String to parse for configuration options
+ * \return Flags
+ */
+static uint32_t parse_opts(const char *in)
+{
+	uint32_t flags = 0;
+	
+	if (!in) {
+		return 0;
+	}
+	
+	if (strstr(in, "suggest_channel")) {
+		flags |= FTMOD_LIBPRI_OPT_SUGGEST_CHANNEL;
+	}
+	
+	if (strstr(in, "omit_display")) {
+		flags |= FTMOD_LIBPRI_OPT_OMIT_DISPLAY_IE;
+	}
+	
+	if (strstr(in, "omit_redirecting_number")) {
+		flags |= FTMOD_LIBPRI_OPT_OMIT_REDIRECTING_NUMBER_IE;
+	}
+
+	return flags;
+}
+
+/**
+ * \brief Parses a debug string to flags
+ * \param in Debug string to parse for
+ * \return Flags
+ */
+static int parse_debug(const char *in)
+{
+	int flags = 0;
+
+	if (!in) {
+		return 0;
+	}
+
+	if (strstr(in, "q921_raw")) {
+		flags |= PRI_DEBUG_Q921_RAW;
+	}
+
+	if (strstr(in, "q921_dump")) {
+		flags |= PRI_DEBUG_Q921_DUMP;
+	}
+
+	if (strstr(in, "q921_state")) {
+		flags |= PRI_DEBUG_Q921_STATE;
+	}
+
+	if (strstr(in, "config")) {
+		flags |= PRI_DEBUG_CONFIG;
+	}
+
+	if (strstr(in, "q931_dump")) {
+		flags |= PRI_DEBUG_Q931_DUMP;
+	}
+
+	if (strstr(in, "q931_state")) {
+		flags |= PRI_DEBUG_Q931_STATE;
+	}
+
+	if (strstr(in, "q931_anomaly")) {
+		flags |= PRI_DEBUG_Q931_ANOMALY;
+	}
+
+	if (strstr(in, "apdu")) {
+		flags |= PRI_DEBUG_APDU;
+	}
+
+	if (strstr(in, "aoc")) {
+		flags |= PRI_DEBUG_AOC;
+	}
+
+	if (strstr(in, "all")) {
+		flags |= PRI_DEBUG_ALL;
+	}
+
+	if (strstr(in, "none")) {
+		flags = 0;
+	}
+
+	return flags;
+}
+
+static ftdm_io_interface_t ftdm_libpri_interface;
+
+static ftdm_status_t ftdm_libpri_start(ftdm_span_t *span);
+
+/**
+ * \brief API function to kill or debug a libpri span
+ * \param stream API stream handler
+ * \param data String containing argurments
+ * \return Flags
+ */
+static FIO_API_FUNCTION(ftdm_libpri_api)
+{
+	char *mycmd = NULL, *argv[10] = { 0 };
+    int argc = 0;
+	
+	if (data) {
+		mycmd = ftdm_strdup(data);
+		argc = ftdm_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
+	}
+
+	if (argc == 2) {
+		if (!strcasecmp(argv[0], "kill")) {
+			int span_id = atoi(argv[1]);
+			ftdm_span_t *span = NULL;
+
+			if (ftdm_span_find_by_name(argv[1], &span) == FTDM_SUCCESS || ftdm_span_find(span_id, &span) == FTDM_SUCCESS) {
+				ftdm_libpri_data_t *isdn_data = span->signal_data;
+
+				if (span->start != ftdm_libpri_start) {
+					stream->write_function(stream, "%s: -ERR invalid span.\n", __FILE__);
+					goto done;
+				}
+
+				ftdm_clear_flag((&isdn_data->spri), LPWRAP_PRI_READY);
+				stream->write_function(stream, "%s: +OK killed.\n", __FILE__);
+				goto done;
+			} else {
+				stream->write_function(stream, "%s: -ERR invalid span.\n", __FILE__);
+				goto done;
+			}
+		}
+	}
+
+	if (argc > 2) {
+		if (!strcasecmp(argv[0], "debug")) {
+			ftdm_span_t *span = NULL;
+
+			if (ftdm_span_find_by_name(argv[1], &span) == FTDM_SUCCESS) {
+				ftdm_libpri_data_t *isdn_data = span->signal_data;
+				if (span->start != ftdm_libpri_start) {
+					stream->write_function(stream, "%s: -ERR invalid span.\n", __FILE__);
+					goto done;
+				}
+
+				pri_set_debug(isdn_data->spri.pri, parse_debug(argv[2]));				
+				stream->write_function(stream, "%s: +OK debug set.\n", __FILE__);
+				goto done;
+			} else {
+				stream->write_function(stream, "%s: -ERR invalid span.\n", __FILE__);
+				goto done;
+			}
+		}
+
+	}
+
+	stream->write_function(stream, "%s: -ERR invalid command.\n", __FILE__);
+	
+ done:
+
+	ftdm_safe_free(mycmd);
+
+	return FTDM_SUCCESS;
+}
+
+/**
+ * \brief Loads libpri IO module
+ * \param fio FreeTDM IO interface
+ * \return Success
+ */
+static FIO_IO_LOAD_FUNCTION(ftdm_libpri_io_init)
+{
+	assert(fio != NULL);
+	memset(&ftdm_libpri_interface, 0, sizeof(ftdm_libpri_interface));
+
+	ftdm_libpri_interface.name = "libpri";
+	ftdm_libpri_interface.api = ftdm_libpri_api;
+
+	*fio = &ftdm_libpri_interface;
+
+	return FTDM_SUCCESS;
+}
+
+/**
+ * \brief Loads libpri signaling module
+ * \param fio FreeTDM IO interface
+ * \return Success
+ */
+static FIO_SIG_LOAD_FUNCTION(ftdm_libpri_init)
+{
+	pri_set_error(s_pri_error);
+	pri_set_message(s_pri_message);
+	return FTDM_SUCCESS;
+}
+
+/**
+ * \brief libpri state map
+ */
+static ftdm_state_map_t isdn_state_map = {
+	{
+		{
+			ZSD_OUTBOUND,
+			ZSM_UNACCEPTABLE,
+			{FTDM_ANY_STATE},
+			{FTDM_CHANNEL_STATE_RESTART, FTDM_END}
+		},
+		{
+			ZSD_OUTBOUND,
+			ZSM_UNACCEPTABLE,
+			{FTDM_CHANNEL_STATE_RESTART, FTDM_END},
+			{FTDM_CHANNEL_STATE_DOWN, FTDM_END}
+		},
+		{
+			ZSD_OUTBOUND,
+			ZSM_UNACCEPTABLE,
+			{FTDM_CHANNEL_STATE_DOWN, FTDM_END},
+			{FTDM_CHANNEL_STATE_DIALING, FTDM_END}
+		},
+		{
+			ZSD_OUTBOUND,
+			ZSM_UNACCEPTABLE,
+			{FTDM_CHANNEL_STATE_DIALING, FTDM_END},
+			{FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_CHANNEL_STATE_PROGRESS, FTDM_CHANNEL_STATE_UP, FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_END}
+		},
+		{
+			ZSD_OUTBOUND,
+			ZSM_UNACCEPTABLE,
+			{FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_CHANNEL_STATE_PROGRESS, FTDM_END},
+			{FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_UP, FTDM_END}
+		},
+		{
+			ZSD_OUTBOUND,
+			ZSM_UNACCEPTABLE,
+			{FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_END},
+			{FTDM_CHANNEL_STATE_HANGUP_COMPLETE, FTDM_CHANNEL_STATE_DOWN, FTDM_END}
+		},
+		{
+			ZSD_OUTBOUND,
+			ZSM_UNACCEPTABLE,
+			{FTDM_CHANNEL_STATE_HANGUP_COMPLETE, FTDM_END},
+			{FTDM_CHANNEL_STATE_DOWN, FTDM_END},
+		},
+		{
+			ZSD_OUTBOUND,
+			ZSM_UNACCEPTABLE,
+			{FTDM_CHANNEL_STATE_UP, FTDM_END},
+			{FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_END}
+		},
+
+		/****************************************/
+		{
+			ZSD_INBOUND,
+			ZSM_UNACCEPTABLE,
+			{FTDM_ANY_STATE},
+			{FTDM_CHANNEL_STATE_RESTART, FTDM_END}
+		},
+		{
+			ZSD_INBOUND,
+			ZSM_UNACCEPTABLE,
+			{FTDM_CHANNEL_STATE_RESTART, FTDM_END},
+			{FTDM_CHANNEL_STATE_DOWN, FTDM_END}
+		},
+		{
+			ZSD_INBOUND,
+			ZSM_UNACCEPTABLE,
+			{FTDM_CHANNEL_STATE_DOWN, FTDM_END},
+			{FTDM_CHANNEL_STATE_DIALTONE, FTDM_CHANNEL_STATE_RING, FTDM_END}
+		},
+		{
+			ZSD_INBOUND,
+			ZSM_UNACCEPTABLE,
+			{FTDM_CHANNEL_STATE_DIALTONE, FTDM_END},
+			{FTDM_CHANNEL_STATE_RING, FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_END}
+		},
+		{
+			ZSD_INBOUND,
+			ZSM_UNACCEPTABLE,
+			{FTDM_CHANNEL_STATE_RING, FTDM_END},
+			{FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_PROGRESS, FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_CHANNEL_STATE_UP, FTDM_END}
+		},
+		{
+			ZSD_INBOUND,
+			ZSM_UNACCEPTABLE,
+			{FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_END},
+			{FTDM_CHANNEL_STATE_HANGUP_COMPLETE, FTDM_CHANNEL_STATE_DOWN, FTDM_END},
+		},
+		{
+			ZSD_INBOUND,
+			ZSM_UNACCEPTABLE,
+			{FTDM_CHANNEL_STATE_HANGUP_COMPLETE, FTDM_END},
+			{FTDM_CHANNEL_STATE_DOWN, FTDM_END},
+		},
+		{
+			ZSD_INBOUND,
+			ZSM_UNACCEPTABLE,
+			{FTDM_CHANNEL_STATE_PROGRESS, FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_END},
+			{FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_PROGRESS_MEDIA, 
+			 FTDM_CHANNEL_STATE_CANCEL, FTDM_CHANNEL_STATE_UP, FTDM_END},
+		},
+		{
+			ZSD_INBOUND,
+			ZSM_UNACCEPTABLE,
+			{FTDM_CHANNEL_STATE_UP, FTDM_END},
+			{FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_END},
+		},
+		
+
+	}
+};
+
+/**
+ * \brief Handler for channel state change
+ * \param ftdmchan Channel to handle
+ */
+static __inline__ void state_advance(ftdm_channel_t *ftdmchan)
+{
+	//Q931mes_Generic *gen = (Q931mes_Generic *) ftdmchan->caller_data.raw_data;
+	ftdm_libpri_data_t *isdn_data = ftdmchan->span->signal_data;
+	ftdm_status_t status;
+	ftdm_sigmsg_t sig;
+	q931_call *call = (q931_call *) ftdmchan->call_data;
+	
+	
+	ftdm_log(FTDM_LOG_DEBUG, "%d:%d STATE [%s]\n", 
+			ftdmchan->span_id, ftdmchan->chan_id, ftdm_channel_state2str(ftdmchan->state));
+
+
+#if 0
+	if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND) && !call) {
+		ftdm_log(FTDM_LOG_WARNING, "NO CALL!!!!\n");
+	}
+#endif
+
+	
+	memset(&sig, 0, sizeof(sig));
+	sig.chan_id = ftdmchan->chan_id;
+	sig.span_id = ftdmchan->span_id;
+	sig.channel = ftdmchan;
+
+
+	switch (ftdmchan->state) {
+	case FTDM_CHANNEL_STATE_DOWN:
+		{
+			ftdmchan->call_data = NULL;
+			ftdm_channel_done(ftdmchan);			
+		}
+		break;
+	case FTDM_CHANNEL_STATE_PROGRESS:
+		{
+			if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
+				sig.event_id = FTDM_SIGEVENT_PROGRESS;
+				if ((status = ftdm_span_send_signal(ftdmchan->span, &sig) != FTDM_SUCCESS)) {
+					ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP);
+				}
+			} else if (call) {
+				pri_progress(isdn_data->spri.pri, call, ftdmchan->chan_id, 1);
+			} else {
+				ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_RESTART);
+			}
+		}
+		break;
+	case FTDM_CHANNEL_STATE_PROGRESS_MEDIA:
+		{
+			if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
+				sig.event_id = FTDM_SIGEVENT_PROGRESS_MEDIA;
+				if ((status = ftdm_span_send_signal(ftdmchan->span, &sig) != FTDM_SUCCESS)) {
+					ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP);
+				}
+			} else if (call) {
+				pri_proceeding(isdn_data->spri.pri, call, ftdmchan->chan_id, 1);
+			} else {
+				ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_RESTART);
+			}
+		}
+		break;
+	case FTDM_CHANNEL_STATE_RING:
+		{
+			if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
+				if (call) {
+					pri_acknowledge(isdn_data->spri.pri, call, ftdmchan->chan_id, 0);
+					sig.event_id = FTDM_SIGEVENT_START;
+					if ((status = ftdm_span_send_signal(ftdmchan->span, &sig) != FTDM_SUCCESS)) {
+						ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP);
+					}
+				} else {
+					ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_RESTART);
+				}
+			}
+		}
+		break;
+	case FTDM_CHANNEL_STATE_RESTART:
+		{
+			ftdmchan->caller_data.hangup_cause = FTDM_CAUSE_NORMAL_UNSPECIFIED;
+			sig.event_id = FTDM_SIGEVENT_RESTART;
+			status = ftdm_span_send_signal(ftdmchan->span, &sig);
+			ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
+		}
+		break;
+	case FTDM_CHANNEL_STATE_UP:
+		{
+			if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
+				sig.event_id = FTDM_SIGEVENT_UP;
+				if ((status = ftdm_span_send_signal(ftdmchan->span, &sig) != FTDM_SUCCESS)) {
+					ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP);
+				}
+			} else if (call) {
+				pri_answer(isdn_data->spri.pri, call, 0, 1);
+			} else {
+				ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_RESTART);
+			}
+		}
+		break;
+	case FTDM_CHANNEL_STATE_DIALING:
+		if (isdn_data) {
+			struct pri_sr *sr;
+			int dp;
+
+			if (!(call = pri_new_call(isdn_data->spri.pri))) {
+				ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_RESTART);
+				return;
+			}
+
+			
+			dp = ftdmchan->caller_data.dnis.type;
+			switch(dp) {
+			case FTDM_TON_NATIONAL:
+				dp = PRI_NATIONAL_ISDN;
+				break;
+			case FTDM_TON_INTERNATIONAL:
+				dp = PRI_INTERNATIONAL_ISDN;
+				break;
+			case FTDM_TON_SUBSCRIBER_NUMBER:
+				dp = PRI_LOCAL_ISDN;
+				break;
+			default:
+				dp = isdn_data->dp;
+			}
+
+			ftdmchan->call_data = call;
+			sr = pri_sr_new();
+			assert(sr);
+			pri_sr_set_channel(sr, ftdmchan->chan_id, 0, 0);
+			pri_sr_set_bearer(sr, 0, isdn_data->l1);
+			pri_sr_set_called(sr, ftdmchan->caller_data.dnis.digits, dp, 1);
+			pri_sr_set_caller(sr, ftdmchan->caller_data.cid_num.digits, (isdn_data->opts & FTMOD_LIBPRI_OPT_OMIT_DISPLAY_IE ? NULL : ftdmchan->caller_data.cid_name),
+						dp, (ftdmchan->caller_data.pres != 1 ? PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN : PRES_PROHIB_USER_NUMBER_NOT_SCREENED));
+
+			if (!(isdn_data->opts & FTMOD_LIBPRI_OPT_OMIT_REDIRECTING_NUMBER_IE)) {
+				pri_sr_set_redirecting(sr, ftdmchan->caller_data.cid_num.digits, dp, PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN, PRI_REDIR_UNCONDITIONAL);
+			}
+
+			if (pri_setup(isdn_data->spri.pri, call, sr)) {
+				ftdmchan->caller_data.hangup_cause = FTDM_CAUSE_DESTINATION_OUT_OF_ORDER;				
+				ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP);
+			}
+
+			pri_sr_free(sr);
+		}
+
+		break;
+	case FTDM_CHANNEL_STATE_HANGUP:
+		{
+			if (call) {
+				pri_hangup(isdn_data->spri.pri, call, ftdmchan->caller_data.hangup_cause);
+				pri_destroycall(isdn_data->spri.pri, call);
+				ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
+			} else {
+				ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_RESTART);
+			}
+		}
+		break;
+	case FTDM_CHANNEL_STATE_HANGUP_COMPLETE:
+		break;
+	case FTDM_CHANNEL_STATE_TERMINATING:
+		{
+			sig.event_id = FTDM_SIGEVENT_STOP;
+			status = ftdm_span_send_signal(ftdmchan->span, &sig);
+			ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
+
+		}
+	default:
+		break;
+	}
+
+
+
+	return;
+}
+
+/**
+ * \brief Checks current state on a span
+ * \param span Span to check status on
+ */
+static __inline__ void check_state(ftdm_span_t *span)
+{
+    if (ftdm_test_flag(span, FTDM_SPAN_STATE_CHANGE)) {
+        uint32_t j;
+        ftdm_clear_flag_locked(span, FTDM_SPAN_STATE_CHANGE);
+        for(j = 1; j <= span->chan_count; j++) {
+            if (ftdm_test_flag((span->channels[j]), FTDM_CHANNEL_STATE_CHANGE)) {
+				ftdm_mutex_lock(span->channels[j]->mutex);
+                ftdm_clear_flag((span->channels[j]), FTDM_CHANNEL_STATE_CHANGE);
+                state_advance(span->channels[j]);
+                ftdm_channel_complete_state(span->channels[j]);
+				ftdm_mutex_unlock(span->channels[j]->mutex);
+            }
+        }
+    }
+}
+
+/**
+ * \brief Handler for libpri information event (incoming call?)
+ * \param spri Pri wrapper structure (libpri, span, dchan)
+ * \param event_type Event type (unused)
+ * \param pevent Event
+ * \return 0
+ */
+static int on_info(lpwrap_pri_t *spri, lpwrap_pri_event_t event_type, pri_event *pevent)
+{
+
+	ftdm_log(FTDM_LOG_DEBUG, "number is: %s\n", pevent->ring.callednum);
+	if (strlen(pevent->ring.callednum) > 3) {
+		ftdm_log(FTDM_LOG_DEBUG, "final number is: %s\n", pevent->ring.callednum);
+		pri_answer(spri->pri, pevent->ring.call, 0, 1);
+	}
+	return 0;
+}
+
+/**
+ * \brief Handler for libpri hangup event
+ * \param spri Pri wrapper structure (libpri, span, dchan)
+ * \param event_type Event type (unused)
+ * \param pevent Event
+ * \return 0
+ */
+static int on_hangup(lpwrap_pri_t *spri, lpwrap_pri_event_t event_type, pri_event *pevent)
+{
+	ftdm_span_t *span = spri->private_info;
+	ftdm_channel_t *ftdmchan = NULL;
+	q931_call *call = NULL;
+	ftdmchan = span->channels[pevent->hangup.channel];
+	
+	if (ftdmchan) {
+		call = (q931_call *) ftdmchan->call_data;
+		ftdm_log(FTDM_LOG_DEBUG, "-- Hangup on channel %d:%d\n", spri->span->span_id, pevent->hangup.channel);
+		ftdmchan->caller_data.hangup_cause = pevent->hangup.cause;
+		pri_release(spri->pri, call, 0);
+		pri_destroycall(spri->pri, call);
+		ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING);
+	} else {
+		ftdm_log(FTDM_LOG_DEBUG, "-- Hangup on channel %d:%d %s but it's not in use?\n", spri->span->span_id,
+				pevent->hangup.channel, ftdmchan->chan_id);
+	}
+
+	return 0;
+}
+
+/**
+ * \brief Handler for libpri answer event
+ * \param spri Pri wrapper structure (libpri, span, dchan)
+ * \param event_type Event type (unused)
+ * \param pevent Event
+ * \return 0
+ */
+static int on_answer(lpwrap_pri_t *spri, lpwrap_pri_event_t event_type, pri_event *pevent)
+{
+	ftdm_span_t *span = spri->private_info;
+	ftdm_channel_t *ftdmchan = NULL;
+
+	ftdmchan = span->channels[pevent->answer.channel];
+	
+	if (ftdmchan) {
+		ftdm_log(FTDM_LOG_DEBUG, "-- Answer on channel %d:%d\n", spri->span->span_id, pevent->answer.channel);
+		ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_UP);
+	} else {
+		ftdm_log(FTDM_LOG_DEBUG, "-- Answer on channel %d:%d %s but it's not in use?\n", spri->span->span_id, pevent->answer.channel, ftdmchan->chan_id);
+				
+	}
+
+	return 0;
+}
+
+/**
+ * \brief Handler for libpri proceed event
+ * \param spri Pri wrapper structure (libpri, span, dchan)
+ * \param event_type Event type (unused)
+ * \param pevent Event
+ * \return 0
+ */
+static int on_proceed(lpwrap_pri_t *spri, lpwrap_pri_event_t event_type, pri_event *pevent)
+{
+	ftdm_span_t *span = spri->private_info;
+	ftdm_channel_t *ftdmchan = NULL;
+	
+	ftdmchan = span->channels[pevent->proceeding.channel];
+	
+	if (ftdmchan) {
+		ftdm_log(FTDM_LOG_DEBUG, "-- Proceeding on channel %d:%d\n", spri->span->span_id, pevent->proceeding.channel);
+		ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_PROGRESS_MEDIA);
+	} else {
+		ftdm_log(FTDM_LOG_DEBUG, "-- Proceeding on channel %d:%d %s but it's not in use?\n", spri->span->span_id,
+						  pevent->proceeding.channel, ftdmchan->chan_id);
+	}
+
+	return 0;
+}
+
+/**
+ * \brief Handler for libpri ringing event
+ * \param spri Pri wrapper structure (libpri, span, dchan)
+ * \param event_type Event type (unused)
+ * \param pevent Event
+ * \return 0
+ */
+static int on_ringing(lpwrap_pri_t *spri, lpwrap_pri_event_t event_type, pri_event *pevent)
+{
+	ftdm_span_t *span = spri->private_info;
+	ftdm_channel_t *ftdmchan = NULL;
+
+	ftdmchan = span->channels[pevent->ringing.channel];
+	
+	if (ftdmchan) {
+		ftdm_log(FTDM_LOG_DEBUG, "-- Ringing on channel %d:%d\n", spri->span->span_id, pevent->ringing.channel);
+		/* we may get on_ringing even when we're already in FTDM_CHANNEL_STATE_PROGRESS_MEDIA */
+		if (ftdmchan->state == FTDM_CHANNEL_STATE_PROGRESS_MEDIA) {
+			/* dont try to move to STATE_PROGRESS to avoid annoying veto warning */
+			return 0;
+		}
+		ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_PROGRESS);
+	} else {
+		ftdm_log(FTDM_LOG_DEBUG, "-- Ringing on channel %d:%d %s but it's not in use?\n", spri->span->span_id,
+						  pevent->ringing.channel, ftdmchan->chan_id);
+	}
+
+	return 0;
+}
+
+/**
+ * \brief Handler for libpri ring event
+ * \param spri Pri wrapper structure (libpri, span, dchan)
+ * \param event_type Event type (unused)
+ * \param pevent Event
+ * \return 0 on success
+ */
+static int on_ring(lpwrap_pri_t *spri, lpwrap_pri_event_t event_type, pri_event *pevent)
+{
+	ftdm_span_t *span = spri->private_info;
+	ftdm_channel_t *ftdmchan = NULL;
+	int ret = 0;
+
+	//switch_mutex_lock(globals.channel_mutex);
+	
+	ftdmchan = span->channels[pevent->ring.channel];
+	if (!ftdmchan || ftdmchan->state != FTDM_CHANNEL_STATE_DOWN || ftdm_test_flag(ftdmchan, FTDM_CHANNEL_INUSE)) {
+		ftdm_log(FTDM_LOG_WARNING, "--Duplicate Ring on channel %d:%d (ignored)\n", spri->span->span_id, pevent->ring.channel);
+		ret = 0;
+		goto done;
+	}
+
+	if (ftdm_channel_open_chan(ftdmchan) != FTDM_SUCCESS) {
+		ftdm_log(FTDM_LOG_WARNING, "--Failure opening channel %d:%d (ignored)\n", spri->span->span_id, pevent->ring.channel);
+		ret = 0;
+		goto done;
+	}
+	
+
+	ftdm_log(FTDM_LOG_NOTICE, "-- Ring on channel %d:%d (from %s to %s)\n", spri->span->span_id, pevent->ring.channel,
+					  pevent->ring.callingnum, pevent->ring.callednum);
+	
+	memset(&ftdmchan->caller_data, 0, sizeof(ftdmchan->caller_data));
+	
+	ftdm_set_string(ftdmchan->caller_data.cid_num.digits, (char *)pevent->ring.callingnum);
+	if (!ftdm_strlen_zero((char *)pevent->ring.callingname)) {
+		ftdm_set_string(ftdmchan->caller_data.cid_name, (char *)pevent->ring.callingname);
+	} else {
+		ftdm_set_string(ftdmchan->caller_data.cid_name, (char *)pevent->ring.callingnum);
+	}
+	ftdm_set_string(ftdmchan->caller_data.ani.digits, (char *)pevent->ring.callingani);
+	ftdm_set_string(ftdmchan->caller_data.dnis.digits, (char *)pevent->ring.callednum);
+	
+	if (pevent->ring.ani2 >= 0) {
+		snprintf(ftdmchan->caller_data.aniII, 5, "%.2d", pevent->ring.ani2);
+	}
+	
+	// scary to trust this pointer, you'd think they would give you a copy of the call data so you own it......
+	ftdmchan->call_data = pevent->ring.call;
+	
+	ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_RING);
+	
+ done:
+	//switch_mutex_unlock(globals.channel_mutex);
+
+	return ret;
+}
+
+/**
+ * \brief Processes freetdm event
+ * \param span Span on which the event was fired
+ * \param event Event to be treated
+ * \return Success or failure
+ */
+static __inline__ ftdm_status_t process_event(ftdm_span_t *span, ftdm_event_t *event)
+{
+	ftdm_log(FTDM_LOG_DEBUG, "EVENT [%s][%d][%d:%d] STATE [%s]\n", 
+			ftdm_oob_event2str(event->enum_id), event->enum_id, event->channel->span_id, event->channel->chan_id, ftdm_channel_state2str(event->channel->state));
+
+	switch(event->enum_id) {
+	case FTDM_OOB_ALARM_TRAP:
+		{
+			if (event->channel->state != FTDM_CHANNEL_STATE_DOWN) {
+				if (event->channel->type == FTDM_CHAN_TYPE_B) {
+					ftdm_set_state_locked(event->channel, FTDM_CHANNEL_STATE_RESTART);
+				}
+			}
+			
+
+			ftdm_set_flag(event->channel, FTDM_CHANNEL_SUSPENDED);
+
+			
+			ftdm_channel_get_alarms(event->channel);
+			ftdm_log(FTDM_LOG_WARNING, "channel %d:%d (%d:%d) has alarms! [%s]\n", 
+					event->channel->span_id, event->channel->chan_id, 
+					event->channel->physical_span_id, event->channel->physical_chan_id, 
+					event->channel->last_error);
+		}
+		break;
+	case FTDM_OOB_ALARM_CLEAR:
+		{
+			
+			ftdm_log(FTDM_LOG_WARNING, "channel %d:%d (%d:%d) alarms Cleared!\n", event->channel->span_id, event->channel->chan_id,
+					event->channel->physical_span_id, event->channel->physical_chan_id);
+
+			ftdm_clear_flag(event->channel, FTDM_CHANNEL_SUSPENDED);
+			ftdm_channel_get_alarms(event->channel);
+		}
+		break;
+	}
+
+	return FTDM_SUCCESS;
+}
+
+/**
+ * \brief Checks for events on a span
+ * \param span Span to check for events
+ */
+static __inline__ void check_events(ftdm_span_t *span)
+{
+	ftdm_status_t status;
+
+	status = ftdm_span_poll_event(span, 5);
+
+	switch(status) {
+	case FTDM_SUCCESS:
+		{
+			ftdm_event_t *event;
+			while (ftdm_span_next_event(span, &event) == FTDM_SUCCESS) {
+				if (event->enum_id == FTDM_OOB_NOOP) {
+					continue;
+				}
+				if (process_event(span, event) != FTDM_SUCCESS) {
+					break;
+				}
+			}
+		}
+		break;
+	case FTDM_FAIL:
+		{
+			ftdm_log(FTDM_LOG_DEBUG, "Event Failure! %d\n", ftdm_running());
+			ftdm_sleep(2000);
+		}
+		break;
+	default:
+		break;
+	}
+}
+
+/**
+ * \brief Checks flags on a pri span
+ * \param spri Pri wrapper structure (libpri, span, dchan)
+ * \return 0 on success, -1 on error
+ */
+static int check_flags(lpwrap_pri_t *spri)
+{
+	ftdm_span_t *span = spri->private_info;
+
+	if (!ftdm_running() || ftdm_test_flag(span, FTDM_SPAN_STOP_THREAD)) {
+		return -1;
+	}
+
+	check_state(span);
+	check_events(span);
+
+
+	return 0;
+}
+
+/**
+ * \brief Handler for libpri restart event
+ * \param spri Pri wrapper structure (libpri, span, dchan)
+ * \param event_type Event type (unused)
+ * \param pevent Event
+ * \return 0
+ */
+static int on_restart(lpwrap_pri_t *spri, lpwrap_pri_event_t event_type, pri_event *pevent)
+{
+	ftdm_span_t *span = spri->private_info;
+	ftdm_channel_t *ftdmchan;
+
+	ftdm_log(FTDM_LOG_NOTICE, "-- Restarting %d:%d\n", spri->span->span_id, pevent->restart.channel);
+
+	ftdmchan = span->channels[pevent->restart.channel];
+
+	if (!ftdmchan) {
+		return 0;
+	}
+
+	if (pevent->restart.channel < 1) {
+		ftdm_set_state_all(ftdmchan->span, FTDM_CHANNEL_STATE_RESTART);
+	} else {
+		ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_RESTART);
+	}
+
+	return 0;
+}
+
+/**
+ * \brief Handler for libpri dchan up event
+ * \param spri Pri wrapper structure (libpri, span, dchan)
+ * \param event_type Event type (unused)
+ * \param pevent Event
+ * \return 0
+ */
+static int on_dchan_up(lpwrap_pri_t *spri, lpwrap_pri_event_t event_type, pri_event *pevent)
+{
+	
+	if (!ftdm_test_flag(spri, LPWRAP_PRI_READY)) {
+		ftdm_log(FTDM_LOG_INFO, "Span %d D-Chan UP!\n", spri->span->span_id);
+		ftdm_set_flag(spri, LPWRAP_PRI_READY);
+		ftdm_set_state_all(spri->span, FTDM_CHANNEL_STATE_RESTART);
+	}
+
+	return 0;
+}
+
+/**
+ * \brief Handler for libpri dchan down event
+ * \param spri Pri wrapper structure (libpri, span, dchan)
+ * \param event_type Event type (unused)
+ * \param pevent Event
+ * \return 0
+ */
+static int on_dchan_down(lpwrap_pri_t *spri, lpwrap_pri_event_t event_type, pri_event *pevent)
+{
+
+	if (ftdm_test_flag(spri, LPWRAP_PRI_READY)) {
+		ftdm_log(FTDM_LOG_INFO, "Span %d D-Chan DOWN!\n", spri->span->span_id);
+		ftdm_clear_flag(spri, LPWRAP_PRI_READY);
+		ftdm_set_state_all(spri->span, FTDM_CHANNEL_STATE_RESTART);
+		
+	}
+
+	return 0;
+}
+
+/**
+ * \brief Handler for any libpri event
+ * \param spri Pri wrapper structure (libpri, span, dchan)
+ * \param event_type Event type (unused)
+ * \param pevent Event
+ * \return 0
+ */
+static int on_anything(lpwrap_pri_t *spri, lpwrap_pri_event_t event_type, pri_event *pevent)
+{
+
+	ftdm_log(FTDM_LOG_DEBUG, "Caught Event span %d %u (%s)\n", spri->span->span_id, event_type, lpwrap_pri_event_str(event_type));
+	return 0;
+}
+
+/**
+ * \brief Handler for libpri io fail event
+ * \param spri Pri wrapper structure (libpri, span, dchan)
+ * \param event_type Event type (unused)
+ * \param pevent Event
+ * \return 0
+ */
+static int on_io_fail(lpwrap_pri_t *spri, lpwrap_pri_event_t event_type, pri_event *pevent)
+{
+
+	ftdm_log(FTDM_LOG_DEBUG, "Caught Event span %d %u (%s)\n", spri->span->span_id, event_type, lpwrap_pri_event_str(event_type));
+	return 0;
+}
+
+/**
+ * \brief Main thread function for libpri span (monitor)
+ * \param me Current thread
+ * \param obj Span to run in this thread
+ */
+static void *ftdm_libpri_run(ftdm_thread_t *me, void *obj)
+{
+	ftdm_span_t *span = (ftdm_span_t *) obj;
+	ftdm_libpri_data_t *isdn_data = span->signal_data;
+	int i, x = 0;
+	int down = 0;
+	int got_d = 0;
+	
+	ftdm_set_flag(span, FTDM_SPAN_IN_THREAD);
+	
+	while(ftdm_running() && !ftdm_test_flag(span, FTDM_SPAN_STOP_THREAD)) {
+		if (!got_d) {
+			for(i = 1; i <= span->chan_count; i++) {
+				if (span->channels[i]->type == FTDM_CHAN_TYPE_DQ921) {
+					if (ftdm_channel_open(span->span_id, i, &isdn_data->dchan) == FTDM_SUCCESS) {
+						ftdm_log(FTDM_LOG_DEBUG, "opening d-channel #%d %d:%d\n", x, isdn_data->dchan->span_id, isdn_data->dchan->chan_id);
+						isdn_data->dchan->state = FTDM_CHANNEL_STATE_UP;
+						got_d = 1;
+						x++;
+						break;
+					}
+				}
+			}
+		}
+		
+		
+		if (lpwrap_init_pri(&isdn_data->spri,
+								  span,  // span
+								  isdn_data->dchan, // dchan
+								  isdn_data->pswitch,
+								  isdn_data->node,
+								  isdn_data->debug) < 0) {
+			snprintf(span->last_error, sizeof(span->last_error), "PRI init FAIL!");
+		} else {
+
+			LPWRAP_MAP_PRI_EVENT(isdn_data->spri, LPWRAP_PRI_EVENT_ANY, on_anything);
+			LPWRAP_MAP_PRI_EVENT(isdn_data->spri, LPWRAP_PRI_EVENT_RING, on_ring);
+			LPWRAP_MAP_PRI_EVENT(isdn_data->spri, LPWRAP_PRI_EVENT_RINGING, on_ringing);
+			//LPWRAP_MAP_PRI_EVENT(isdn_data->spri, LPWRAP_PRI_EVENT_SETUP_ACK, on_proceed);
+			LPWRAP_MAP_PRI_EVENT(isdn_data->spri, LPWRAP_PRI_EVENT_PROCEEDING, on_proceed);
+			LPWRAP_MAP_PRI_EVENT(isdn_data->spri, LPWRAP_PRI_EVENT_ANSWER, on_answer);
+			LPWRAP_MAP_PRI_EVENT(isdn_data->spri, LPWRAP_PRI_EVENT_DCHAN_UP, on_dchan_up);
+			LPWRAP_MAP_PRI_EVENT(isdn_data->spri, LPWRAP_PRI_EVENT_DCHAN_DOWN, on_dchan_down);
+			LPWRAP_MAP_PRI_EVENT(isdn_data->spri, LPWRAP_PRI_EVENT_HANGUP_REQ, on_hangup);
+			LPWRAP_MAP_PRI_EVENT(isdn_data->spri, LPWRAP_PRI_EVENT_HANGUP, on_hangup);
+			LPWRAP_MAP_PRI_EVENT(isdn_data->spri, LPWRAP_PRI_EVENT_INFO_RECEIVED, on_info);
+			LPWRAP_MAP_PRI_EVENT(isdn_data->spri, LPWRAP_PRI_EVENT_RESTART, on_restart);
+			LPWRAP_MAP_PRI_EVENT(isdn_data->spri, LPWRAP_PRI_EVENT_IO_FAIL, on_io_fail);
+
+			if (down) {
+				ftdm_log(FTDM_LOG_INFO, "PRI back up on span %d\n", isdn_data->spri.span->span_id);
+				ftdm_set_state_all(span, FTDM_CHANNEL_STATE_RESTART);
+				down = 0;
+			}
+
+			isdn_data->spri.on_loop = check_flags;
+			isdn_data->spri.private_info = span;
+			lpwrap_run_pri(&isdn_data->spri);
+
+		}
+
+		if (!ftdm_running() || ftdm_test_flag(span, FTDM_SPAN_STOP_THREAD)) {
+			break;
+		}
+
+		ftdm_log(FTDM_LOG_CRIT, "PRI down on span %d\n", isdn_data->spri.span->span_id);
+
+		if (!down) {
+			ftdm_set_state_all(span, FTDM_CHANNEL_STATE_RESTART);
+			check_state(span);
+		}
+
+		check_state(span);
+		check_events(span);
+
+		down++;
+		ftdm_sleep(5000);
+	}
+
+	ftdm_log(FTDM_LOG_DEBUG, "PRI thread ended on span %d\n", isdn_data->spri.span->span_id);
+
+	ftdm_clear_flag(span, FTDM_SPAN_IN_THREAD);
+	ftdm_clear_flag(isdn_data, FTMOD_LIBPRI_RUNNING);
+
+	return NULL;
+}
+
+/**
+ * \brief Stops a libpri span
+ * \param span Span to halt
+ * \return Success
+ *
+ * Sets a stop flag and waits for the thread to end
+ */
+static ftdm_status_t ftdm_libpri_stop(ftdm_span_t *span)
+{
+	ftdm_libpri_data_t *isdn_data = span->signal_data;
+
+	if (!ftdm_test_flag(isdn_data, FTMOD_LIBPRI_RUNNING)) {
+		return FTDM_FAIL;
+	}
+
+	ftdm_set_state_all(span, FTDM_CHANNEL_STATE_RESTART);
+	check_state(span);
+	ftdm_set_flag(span, FTDM_SPAN_STOP_THREAD);
+	while(ftdm_test_flag(span, FTDM_SPAN_IN_THREAD)) {
+		ftdm_sleep(100);
+	}
+	check_state(span);
+
+	return FTDM_SUCCESS;
+}
+
+/**
+ * \brief Starts a libpri span
+ * \param span Span to halt
+ * \return Success or failure
+ *
+ * Launches a thread to monitor the span
+ */
+static ftdm_status_t ftdm_libpri_start(ftdm_span_t *span)
+{
+	ftdm_status_t ret;
+	ftdm_libpri_data_t *isdn_data = span->signal_data;
+
+	if (ftdm_test_flag(isdn_data, FTMOD_LIBPRI_RUNNING)) {
+		return FTDM_FAIL;
+	}
+
+	ftdm_clear_flag(span, FTDM_SPAN_STOP_THREAD);
+	ftdm_clear_flag(span, FTDM_SPAN_IN_THREAD);
+
+	ftdm_set_flag(isdn_data, FTMOD_LIBPRI_RUNNING);
+	ret = ftdm_thread_create_detached(ftdm_libpri_run, span);
+
+	if (ret != FTDM_SUCCESS) {
+		return ret;
+	}
+
+	return ret;
+}
+
+/**
+ * \brief Converts a node string to node value
+ * \param node Node string to convert
+ * \return -1 on failure, node value on success
+ */
+static int str2node(char *node)
+{
+	if (!strcasecmp(node, "cpe") || !strcasecmp(node, "user"))
+		return PRI_CPE;
+	if (!strcasecmp(node, "network") || !strcasecmp(node, "net"))
+		return PRI_NETWORK;
+	return -1;
+}
+
+/**
+ * \brief Converts a switch string to switch value
+ * \param swtype Swtype string to convert
+ * \return Switch value
+ */
+static int str2switch(char *swtype)
+{
+	if (!strcasecmp(swtype, "ni1"))
+		return PRI_SWITCH_NI1;
+	if (!strcasecmp(swtype, "ni2"))
+		return PRI_SWITCH_NI2;
+	if (!strcasecmp(swtype, "dms100"))
+		return PRI_SWITCH_DMS100;
+	if (!strcasecmp(swtype, "lucent5e") || !strcasecmp(swtype, "5ess"))
+		return PRI_SWITCH_LUCENT5E;
+	if (!strcasecmp(swtype, "att4ess") || !strcasecmp(swtype, "4ess"))
+		return PRI_SWITCH_ATT4ESS;
+	if (!strcasecmp(swtype, "euroisdn"))
+		return PRI_SWITCH_EUROISDN_E1;
+	if (!strcasecmp(swtype, "gr303eoc"))
+		return PRI_SWITCH_GR303_EOC;
+	if (!strcasecmp(swtype, "gr303tmc"))
+		return PRI_SWITCH_GR303_TMC;
+	return PRI_SWITCH_DMS100;
+}
+
+/**
+ * \brief Converts a L1 string to L1 value
+ * \param l1 L1 string to convert
+ * \return L1 value
+ */
+static int str2l1(char *l1)
+{
+	if (!strcasecmp(l1, "alaw"))
+		return PRI_LAYER_1_ALAW;
+	
+	return PRI_LAYER_1_ULAW;
+}
+
+/**
+ * \brief Converts a DP string to DP value
+ * \param dp DP string to convert
+ * \return DP value
+ */
+static int str2dp(char *dp)
+{
+	if (!strcasecmp(dp, "international"))
+		return PRI_INTERNATIONAL_ISDN;
+	if (!strcasecmp(dp, "national"))
+		return PRI_NATIONAL_ISDN;
+	if (!strcasecmp(dp, "local"))
+		return PRI_LOCAL_ISDN;
+	if (!strcasecmp(dp, "private"))
+		return PRI_PRIVATE;
+	if (!strcasecmp(dp, "unknown"))
+		return PRI_UNKNOWN;
+
+	return PRI_UNKNOWN;
+}
+
+/**
+ * \brief Initialises a libpri span from configuration variables
+ * \param span Span to configure
+ * \param sig_cb Callback function for event signals
+ * \param ap List of configuration variables
+ * \return Success or failure
+ */
+static FIO_SIG_CONFIGURE_FUNCTION(ftdm_libpri_configure_span)
+{
+	uint32_t i, x = 0;
+	//ftdm_channel_t *dchans[2] = {0};
+	ftdm_libpri_data_t *isdn_data;
+	char *var, *val;
+	char *debug = NULL;
+
+	if (span->trunk_type >= FTDM_TRUNK_NONE) {
+		ftdm_log(FTDM_LOG_WARNING, "Invalid trunk type '%s' defaulting to T1.\n", ftdm_trunk_type2str(span->trunk_type));
+		span->trunk_type = FTDM_TRUNK_T1;
+	}
+	
+	for(i = 1; i <= span->chan_count; i++) {
+		if (span->channels[i]->type == FTDM_CHAN_TYPE_DQ921) {
+			if (x > 1) {
+				snprintf(span->last_error, sizeof(span->last_error), "Span has more than 2 D-Channels!");
+				return FTDM_FAIL;
+			} else {
+#if 0
+				if (ftdm_channel_open(span->span_id, i, &dchans[x]) == FTDM_SUCCESS) {
+					ftdm_log(FTDM_LOG_DEBUG, "opening d-channel #%d %d:%d\n", x, dchans[x]->span_id, dchans[x]->chan_id);
+					dchans[x]->state = FTDM_CHANNEL_STATE_UP;
+					x++;
+				}
+#endif
+			}
+		}
+	}
+	
+#if 0
+	if (!x) {
+		snprintf(span->last_error, sizeof(span->last_error), "Span has no D-Channels!");
+		return FTDM_FAIL;
+	}
+#endif
+
+	isdn_data = ftdm_malloc(sizeof(*isdn_data));
+	assert(isdn_data != NULL);
+	memset(isdn_data, 0, sizeof(*isdn_data));
+
+    if (span->trunk_type == FTDM_TRUNK_E1) {
+        ftdm_log(FTDM_LOG_NOTICE, "Setting default Layer 1 to ALAW since this is an E1 trunk\n");
+        isdn_data->l1 = PRI_LAYER_1_ALAW;
+    } else if (span->trunk_type == FTDM_TRUNK_T1) {
+        ftdm_log(FTDM_LOG_NOTICE, "Setting default Layer 1 to ULAW since this is a T1 trunk\n");
+        isdn_data->l1 = PRI_LAYER_1_ULAW;
+    }
+	
+	while((var = va_arg(ap, char *))) {
+		if (!strcasecmp(var, "node")) {
+			int node;
+			if (!(val = va_arg(ap, char *))) {
+				break;
+			}
+			node = str2node(val);
+			if (-1 == node) {
+				ftdm_log(FTDM_LOG_ERROR, "Unknown node type %s, defaulting to CPE mode\n", val);
+				node = PRI_CPE;
+			}
+			isdn_data->node = node;
+		} else if (!strcasecmp(var, "switch")) {
+			if (!(val = va_arg(ap, char *))) {
+				break;
+			}
+			isdn_data->pswitch = str2switch(val);
+		} else if (!strcasecmp(var, "opts")) {
+			if (!(val = va_arg(ap, char *))) {
+				break;
+			}
+			isdn_data->opts = parse_opts(val);
+		} else if (!strcasecmp(var, "dp")) {
+			if (!(val = va_arg(ap, char *))) {
+				break;
+			}
+			isdn_data->dp = str2dp(val);
+		} else if (!strcasecmp(var, "l1")) {
+			if (!(val = va_arg(ap, char *))) {
+				break;
+			}
+			isdn_data->l1 = str2l1(val);
+		} else if (!strcasecmp(var, "debug")) {
+			if (!(val = va_arg(ap, char *))) {
+				break;
+			}
+			debug = val;
+		} else {
+			snprintf(span->last_error, sizeof(span->last_error), "Unknown parameter [%s]", var);
+			return FTDM_FAIL;
+		}
+	}
+    
+	span->start = ftdm_libpri_start;
+	span->stop = ftdm_libpri_stop;
+	span->signal_cb = sig_cb;
+	//isdn_data->dchans[0] = dchans[0];
+	//isdn_data->dchans[1] = dchans[1];
+	//isdn_data->dchan = isdn_data->dchans[0];
+	
+	isdn_data->debug = parse_debug(debug);
+		
+
+	span->signal_data = isdn_data;
+	span->signal_type = FTDM_SIGTYPE_ISDN;
+	span->outgoing_call = isdn_outgoing_call;
+
+	if ((isdn_data->opts & FTMOD_LIBPRI_OPT_SUGGEST_CHANNEL)) {
+		span->channel_request = isdn_channel_request;
+		span->suggest_chan_id = 1;
+	}
+
+	span->state_map = &isdn_state_map;
+
+	return FTDM_SUCCESS;
+}
+
+/**
+ * \brief FreeTDM libpri signaling and IO module definition
+ */
+ftdm_module_t ftdm_module = { 
+	"libpri",
+	ftdm_libpri_io_init,
+	ftdm_libpri_unload,
+	ftdm_libpri_init,
+	ftdm_libpri_configure_span,
+	NULL
+};
+
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */

Added: freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_libpri/ftmod_libpri.h (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_libpri/ftmod_libpri.h	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_libpri/ftmod_libpri.h	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2009, Anthony Minessale II
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#ifndef FTMOD_LIBPRI_H
+#define FTMOD_LIBPRI_H
+#include "freetdm.h"
+#include "lpwrap_pri.h"
+
+typedef enum {
+	FTMOD_LIBPRI_OPT_NONE = 0,
+	FTMOD_LIBPRI_OPT_SUGGEST_CHANNEL = (1 << 0),
+	FTMOD_LIBPRI_OPT_OMIT_DISPLAY_IE = (1 << 1),
+	FTMOD_LIBPRI_OPT_OMIT_REDIRECTING_NUMBER_IE = (1 << 2),
+		
+	FTMOD_LIBPRI_OPT_MAX = (1 << 3)
+} ftdm_isdn_opts_t;
+
+typedef enum {
+	FTMOD_LIBPRI_RUNNING = (1 << 0)
+} ftdm_isdn_flag_t;
+
+
+struct ftdm_libpri_data {
+	ftdm_channel_t *dchan;
+	ftdm_channel_t *dchans[2];
+	struct ftdm_sigmsg sigmsg;
+	uint32_t flags;
+	int32_t mode;
+	ftdm_isdn_opts_t opts;
+
+	int node;
+	int pswitch;
+	char *dialplan;
+	unsigned int l1;
+	unsigned int dp;
+
+	int debug;
+
+	lpwrap_pri_t spri;
+};
+
+typedef struct ftdm_libpri_data ftdm_libpri_data_t;
+
+
+/* b-channel private data */
+struct ftdm_isdn_bchan_data
+{
+	int32_t digit_timeout;
+};
+
+typedef struct ftdm_isdn_bchan_data ftdm_isdn_bchan_data_t;
+
+
+#endif
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
+

Added: freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_libpri/lpwrap_pri.c (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_libpri/lpwrap_pri.c	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_libpri/lpwrap_pri.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,303 @@
+/*
+ * Copyright (c) 2009, Anthony Minessale II
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+//#define IODEBUG
+
+#include "freetdm.h"
+#include "lpwrap_pri.h"
+#ifndef HAVE_GETTIMEOFDAY
+
+#ifdef WIN32
+#include <mmsystem.h>
+
+static __inline int gettimeofday(struct timeval *tp, void *nothing)
+{
+#ifdef WITHOUT_MM_LIB
+	SYSTEMTIME st;
+	time_t tt;
+	struct tm tmtm;
+	/* mktime converts local to UTC */
+	GetLocalTime (&st);
+	tmtm.tm_sec = st.wSecond;
+	tmtm.tm_min = st.wMinute;
+	tmtm.tm_hour = st.wHour;
+	tmtm.tm_mday = st.wDay;
+	tmtm.tm_mon = st.wMonth - 1;
+	tmtm.tm_year = st.wYear - 1900;  tmtm.tm_isdst = -1;
+	tt = mktime (&tmtm);
+	tp->tv_sec = tt;
+	tp->tv_usec = st.wMilliseconds * 1000;
+#else
+	/**
+	 ** The earlier time calculations using GetLocalTime
+	 ** had a time resolution of 10ms.The timeGetTime, part
+	 ** of multimedia apis offer a better time resolution
+	 ** of 1ms.Need to link against winmm.lib for this
+	 **/
+	unsigned long Ticks = 0;
+	unsigned long Sec =0;
+	unsigned long Usec = 0;
+	Ticks = timeGetTime();
+
+	Sec = Ticks/1000;
+	Usec = (Ticks - (Sec*1000))*1000;
+	tp->tv_sec = Sec;
+	tp->tv_usec = Usec;
+#endif /* WITHOUT_MM_LIB */
+	(void)nothing;
+	return 0;
+}
+#endif /* WIN32 */
+#endif /* HAVE_GETTIMEOFDAY */
+
+static struct lpwrap_pri_event_list LPWRAP_PRI_EVENT_LIST[] = {
+	{0, LPWRAP_PRI_EVENT_ANY, "ANY"},
+	{1, LPWRAP_PRI_EVENT_DCHAN_UP, "DCHAN_UP"},
+	{2, LPWRAP_PRI_EVENT_DCHAN_DOWN, "DCHAN_DOWN"},
+	{3, LPWRAP_PRI_EVENT_RESTART, "RESTART"},
+	{4, LPWRAP_PRI_EVENT_CONFIG_ERR, "CONFIG_ERR"},
+	{5, LPWRAP_PRI_EVENT_RING, "RING"},
+	{6, LPWRAP_PRI_EVENT_HANGUP, "HANGUP"},
+	{7, LPWRAP_PRI_EVENT_RINGING, "RINGING"},
+	{8, LPWRAP_PRI_EVENT_ANSWER, "ANSWER"},
+	{9, LPWRAP_PRI_EVENT_HANGUP_ACK, "HANGUP_ACK"},
+	{10, LPWRAP_PRI_EVENT_RESTART_ACK, "RESTART_ACK"},
+	{11, LPWRAP_PRI_EVENT_FACNAME, "FACNAME"},
+	{12, LPWRAP_PRI_EVENT_INFO_RECEIVED, "INFO_RECEIVED"},
+	{13, LPWRAP_PRI_EVENT_PROCEEDING, "PROCEEDING"},
+	{14, LPWRAP_PRI_EVENT_SETUP_ACK, "SETUP_ACK"},
+	{15, LPWRAP_PRI_EVENT_HANGUP_REQ, "HANGUP_REQ"},
+	{16, LPWRAP_PRI_EVENT_NOTIFY, "NOTIFY"},
+	{17, LPWRAP_PRI_EVENT_PROGRESS, "PROGRESS"},
+	{18, LPWRAP_PRI_EVENT_KEYPAD_DIGIT, "KEYPAD_DIGIT"},
+	{19, LPWRAP_PRI_EVENT_IO_FAIL, "IO_FAIL"},
+};
+
+#define LINE "--------------------------------------------------------------------------------"
+
+const char *lpwrap_pri_event_str(lpwrap_pri_event_t event_id)
+{ 
+	return LPWRAP_PRI_EVENT_LIST[event_id].name;
+}
+
+static int __pri_lpwrap_read(struct pri *pri, void *buf, int buflen)
+{
+	struct lpwrap_pri *spri = (struct lpwrap_pri *) pri_get_userdata(pri);
+	ftdm_size_t len = buflen;
+	int res;
+	ftdm_status_t zst;
+
+	if ((zst = ftdm_channel_read(spri->dchan, buf, &len)) != FTDM_SUCCESS) {
+		if (zst == FTDM_FAIL) {
+			ftdm_log(FTDM_LOG_CRIT, "span %d D-READ FAIL! [%s]\n", spri->span->span_id, spri->dchan->last_error);
+			spri->errs++;
+		} else {
+			ftdm_log(FTDM_LOG_CRIT, "span %d D-READ TIMEOUT\n", spri->span->span_id);
+		}
+		
+		ftdm_clear_flag(spri, LPWRAP_PRI_READY);
+		return -1;
+	}
+	spri->errs = 0;
+	res = (int)len;
+	memset(&((unsigned char*)buf)[res],0,2);
+	res+=2;
+
+#ifdef IODEBUG
+	{
+		char bb[2048] = { 0 };
+
+		print_hex_bytes(buf, res - 2, bb, sizeof(bb));
+		ftdm_log(FTDM_LOG_DEBUG, "READ %d\n", res-2);
+	}
+#endif
+
+	return res;
+}
+
+static int __pri_lpwrap_write(struct pri *pri, void *buf, int buflen)
+{
+	struct lpwrap_pri *spri = (struct lpwrap_pri *) pri_get_userdata(pri);
+	ftdm_size_t len = buflen -2;
+
+	if (ftdm_channel_write(spri->dchan, buf, buflen, &len) != FTDM_SUCCESS) {
+		ftdm_log(FTDM_LOG_CRIT, "span %d D-WRITE FAIL! [%s]\n", spri->span->span_id, spri->dchan->last_error);
+		ftdm_clear_flag(spri, LPWRAP_PRI_READY);
+		return -1;
+	}
+
+#ifdef IODEBUG
+	{
+		char bb[2048] = { 0 };
+
+		print_hex_bytes(buf, buflen - 2, bb, sizeof(bb));
+		ftdm_log(FTDM_LOG_DEBUG, "WRITE %d\n", (int)buflen-2);
+	}
+#endif
+
+	return (int) buflen;
+}
+
+int lpwrap_init_pri(struct lpwrap_pri *spri, ftdm_span_t *span, ftdm_channel_t *dchan, int swtype, int node, int debug)
+{
+	int ret = -1;
+
+	memset(spri, 0, sizeof(struct lpwrap_pri));
+	
+	spri->dchan = dchan;
+	spri->span = span;
+
+	if ((spri->pri = pri_new_cb(spri->dchan->sockfd, node, swtype, __pri_lpwrap_read, __pri_lpwrap_write, spri))){
+		unsigned char buf[4] = { 0 };
+		size_t buflen = sizeof(buf), len = 0;
+		pri_set_debug(spri->pri, debug);
+		ret = 0;
+		ftdm_set_flag(spri, LPWRAP_PRI_READY);
+		ftdm_channel_write(spri->dchan, buf, buflen, &len);
+	} else {
+		fprintf(stderr, "Unable to create PRI\n");
+	}
+
+	return ret;
+}
+
+
+int lpwrap_one_loop(struct lpwrap_pri *spri)
+{
+	fd_set rfds, efds;
+	struct timeval now = {0,0}, *next;
+	pri_event *event;
+	event_handler handler;
+    int sel;
+	
+	if (spri->on_loop) {
+		if ((sel = spri->on_loop(spri)) < 0) {
+			return sel;
+		}
+	}
+
+	if (spri->errs >= 2) {
+		spri->errs = 0;
+		return -1;
+	}
+
+	FD_ZERO(&rfds);
+	FD_ZERO(&efds);
+
+#ifdef _MSC_VER
+	//Windows macro for FD_SET includes a warning C4127: conditional expression is constant
+#pragma warning(push)
+#pragma warning(disable:4127)
+#endif
+
+	FD_SET(pri_fd(spri->pri), &rfds);
+	FD_SET(pri_fd(spri->pri), &efds);
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+	now.tv_sec = 0;
+	now.tv_usec = 100000;
+
+	sel = select(pri_fd(spri->pri) + 1, &rfds, NULL, &efds, &now);
+
+	event = NULL;
+
+	if (!sel) {
+		if ((next = pri_schedule_next(spri->pri))) {
+			gettimeofday(&now, NULL);
+			if (now.tv_sec >= next->tv_sec && (now.tv_usec >= next->tv_usec || next->tv_usec <= 100000)) {
+				//ftdm_log(FTDM_LOG_DEBUG, "Check event\n");
+				event = pri_schedule_run(spri->pri);
+			}
+		}
+	} else if (sel > 0) {
+		event = pri_check_event(spri->pri);
+	}
+
+	if (event) {
+		/* 0 is catchall event handler */
+		if ((handler = spri->eventmap[event->e] ? spri->eventmap[event->e] : spri->eventmap[0] ? spri->eventmap[0] : NULL)) {
+			handler(spri, event->e, event);
+		} else {
+			ftdm_log(FTDM_LOG_CRIT, "No event handler found for event %d.\n", event->e);
+		}
+	}
+
+
+	return sel;
+
+
+	if ((handler = spri->eventmap[LPWRAP_PRI_EVENT_IO_FAIL] ? spri->eventmap[LPWRAP_PRI_EVENT_IO_FAIL] : spri->eventmap[0] ? spri->eventmap[0] : NULL)) {
+		handler(spri, LPWRAP_PRI_EVENT_IO_FAIL, NULL);
+	}
+
+	return -1;
+}
+
+int lpwrap_run_pri(struct lpwrap_pri *spri)
+{
+	int ret = 0;
+	
+	for (;;){
+		ret = lpwrap_one_loop(spri);
+
+		if (ret < 0) {
+
+#ifndef WIN32 //This needs to be adressed fror WIN32 still
+			if (errno == EINTR){
+				/* Igonore an interrupted system call */
+				continue;
+			}
+#endif	
+			ftdm_log(FTDM_LOG_CRIT, "Error = %i [%s]\n", ret, strerror(errno));
+			break;
+		}
+	}
+
+	return ret;
+
+}
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
+

Added: freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_libpri/lpwrap_pri.h (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_libpri/lpwrap_pri.h	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_libpri/lpwrap_pri.h	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2009, Anthony Minessale II
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _LPWRAP_PRI_H
+#define _LPWRAP_PRI_H
+#include <libpri.h>
+#include <freetdm.h>
+
+
+#define LPWRAP_MAX_CHAN_PER_SPAN 32
+
+typedef enum {
+	LPWRAP_PRI_EVENT_ANY           = 0,
+	LPWRAP_PRI_EVENT_DCHAN_UP      = PRI_EVENT_DCHAN_UP,
+	LPWRAP_PRI_EVENT_DCHAN_DOWN    = PRI_EVENT_DCHAN_DOWN,
+	LPWRAP_PRI_EVENT_RESTART       = PRI_EVENT_RESTART,
+	LPWRAP_PRI_EVENT_CONFIG_ERR    = PRI_EVENT_CONFIG_ERR,
+	LPWRAP_PRI_EVENT_RING          = PRI_EVENT_RING,
+	LPWRAP_PRI_EVENT_HANGUP        = PRI_EVENT_HANGUP,
+	LPWRAP_PRI_EVENT_RINGING       = PRI_EVENT_RINGING,
+	LPWRAP_PRI_EVENT_ANSWER        = PRI_EVENT_ANSWER,
+	LPWRAP_PRI_EVENT_HANGUP_ACK    = PRI_EVENT_HANGUP_ACK,
+	LPWRAP_PRI_EVENT_RESTART_ACK   = PRI_EVENT_RESTART_ACK,
+	LPWRAP_PRI_EVENT_FACNAME       = PRI_EVENT_FACNAME,
+	LPWRAP_PRI_EVENT_INFO_RECEIVED = PRI_EVENT_INFO_RECEIVED,
+	LPWRAP_PRI_EVENT_PROCEEDING    = PRI_EVENT_PROCEEDING,
+	LPWRAP_PRI_EVENT_SETUP_ACK     = PRI_EVENT_SETUP_ACK,
+	LPWRAP_PRI_EVENT_HANGUP_REQ    = PRI_EVENT_HANGUP_REQ,
+	LPWRAP_PRI_EVENT_NOTIFY        = PRI_EVENT_NOTIFY,
+	LPWRAP_PRI_EVENT_PROGRESS      = PRI_EVENT_PROGRESS,
+	LPWRAP_PRI_EVENT_KEYPAD_DIGIT  = PRI_EVENT_KEYPAD_DIGIT,
+	LPWRAP_PRI_EVENT_IO_FAIL       = 19,
+
+	/* don't touch */
+	LPWRAP_PRI_EVENT_MAX
+} lpwrap_pri_event_t;
+
+typedef enum {
+	LPWRAP_PRI_NETWORK = PRI_NETWORK,
+	LPWRAP_PRI_CPE = PRI_CPE
+} lpwrap_pri_node_t;
+
+typedef enum {
+	LPWRAP_PRI_SWITCH_UNKNOWN     = PRI_SWITCH_UNKNOWN,
+	LPWRAP_PRI_SWITCH_NI2         = PRI_SWITCH_NI2,
+	LPWRAP_PRI_SWITCH_DMS100      = PRI_SWITCH_DMS100,
+	LPWRAP_PRI_SWITCH_LUCENT5E    = PRI_SWITCH_LUCENT5E,
+	LPWRAP_PRI_SWITCH_ATT4ESS     = PRI_SWITCH_ATT4ESS,
+	LPWRAP_PRI_SWITCH_EUROISDN_E1 = PRI_SWITCH_EUROISDN_E1,
+	LPWRAP_PRI_SWITCH_EUROISDN_T1 = PRI_SWITCH_EUROISDN_T1,
+	LPWRAP_PRI_SWITCH_NI1         = PRI_SWITCH_NI1,
+	LPWRAP_PRI_SWITCH_GR303_EOC   = PRI_SWITCH_GR303_EOC,
+	LPWRAP_PRI_SWITCH_GR303_TMC   = PRI_SWITCH_GR303_TMC,
+	LPWRAP_PRI_SWITCH_QSIG        = PRI_SWITCH_QSIG,
+
+	/* don't touch */
+	LPWRAP_PRI_SWITCH_MAX
+} lpwrap_pri_switch_t;
+
+typedef enum {
+	LPWRAP_PRI_READY = (1 << 0)
+} lpwrap_pri_flag_t;
+
+struct lpwrap_pri;
+typedef int (*event_handler)(struct lpwrap_pri *, lpwrap_pri_event_t, pri_event *);
+typedef int (*loop_handler)(struct lpwrap_pri *);
+
+struct lpwrap_pri {
+	struct pri *pri;
+	ftdm_span_t *span;
+	ftdm_channel_t *dchan;
+	unsigned int flags;
+	void *private_info;
+	event_handler eventmap[LPWRAP_PRI_EVENT_MAX];
+	loop_handler on_loop;
+	int errs;
+};
+
+typedef struct lpwrap_pri lpwrap_pri_t;
+
+struct lpwrap_pri_event_list {
+	int event_id;
+	int pri_event;
+	const char *name;
+};
+
+
+
+#define LPWRAP_MAP_PRI_EVENT(spri, event, func) spri.eventmap[event] = func;
+
+const char *lpwrap_pri_event_str(lpwrap_pri_event_t event_id);
+int lpwrap_one_loop(struct lpwrap_pri *spri);
+int lpwrap_init_pri(struct lpwrap_pri *spri, ftdm_span_t *span, ftdm_channel_t *dchan, int swtype, int node, int debug);
+int lpwrap_run_pri(struct lpwrap_pri *spri);
+
+#endif

Added: freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_pika/ftdm_pika.h (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_pika/ftdm_pika.h	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_pika/ftdm_pika.h	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2007, Anthony Minessale II
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FTDM_PIKA_H
+#define FTDM_PIKA_H
+#include "freetdm.h"
+#include "pikahmpapi.h"
+
+
+
+#define PIKA_STR2ENUM_P(_FUNC1, _FUNC2, _TYPE) _TYPE _FUNC1 (const char *name); const char * _FUNC2 (_TYPE type);
+#define PIKA_STR2ENUM(_FUNC1, _FUNC2, _TYPE, _STRINGS, _MAX)	\
+	_TYPE _FUNC1 (const char *name)								\
+	{														\
+		int i;												\
+		_TYPE t = _MAX ;									\
+															\
+		for (i = 0; i < _MAX ; i++) {						\
+			if (!strcasecmp(name, _STRINGS[i])) {			\
+				t = (_TYPE) i;								\
+				break;										\
+			}												\
+		}													\
+															\
+		return t;											\
+	}														\
+	const char * _FUNC2 (_TYPE type)						\
+	{														\
+		if (type > _MAX) {									\
+			type = _MAX;									\
+		}													\
+		return _STRINGS[(int)type];							\
+	}
+
+
+typedef enum {
+	PIKA_SPAN_FRAMING_T1_D4,
+	PIKA_SPAN_FRAMING_T1_ESF,
+	PIKA_SPAN_FRAMING_E1_BASIC,
+	PIKA_SPAN_FRAMING_E1_CRC4,
+	PIKA_SPAN_INVALID
+} PIKA_TSpanFraming;
+#define PIKA_SPAN_STRINGS "T1_D4", "T1_ESF", "E1_BASIC", "E1_CRC4"
+PIKA_STR2ENUM_P(pika_str2span, pika_span2str, PIKA_TSpanFraming)
+
+typedef enum {
+	PIKA_SPAN_ENCODING_T1_AMI_ZS_NONE,
+	PIKA_SPAN_ENCODING_T1_AMI_ZS_GTE,
+	PIKA_SPAN_ENCODING_T1_AMI_ZS_BELL,
+	PIKA_SPAN_ENCODING_T1_AMI_ZS_JAM8,
+	PIKA_SPAN_ENCODING_T1_B8ZS,
+	PIKA_SPAN_ENCODING_E1_AMI,
+	PIKA_SPAN_ENCODING_E1_HDB3,
+	PIKA_SPAN_ENCODING_INVALID
+} PIKA_TSpanEncoding;
+#define PIKA_SPAN_ENCODING_STRINGS "T1_AMI_ZS_NONE", "T1_AMI_ZS_GTE", "T1_AMI_ZS_BELL", "T1_AMI_ZS_JAM8", "T1_B8ZS", "E1_AMI", "E1_HDB3"
+PIKA_STR2ENUM_P(pika_str2span_encoding, pika_span_encoding2str, PIKA_TSpanEncoding)
+
+typedef enum {
+	PIKA_SPAN_LOOP_LENGTH_SHORT_HAUL,
+	PIKA_SPAN_LOOP_LENGTH_LONG_HAUL,
+	PIKA_SPAN_LOOP_INVALID
+} PIKA_TSpanLoopLength;
+#define PIKA_LL_STRINGS "SHORT_HAUL", "LONG_HAUL"
+PIKA_STR2ENUM_P(pika_str2loop_length, pika_loop_length2str, PIKA_TSpanLoopLength)
+
+typedef enum {
+	PIKA_SPAN_LBO_T1_LONG_0_DB,
+	PIKA_SPAN_LBO_T1_LONG_7_DB,
+	PIKA_SPAN_LBO_T1_LONG_15_DB,
+	PIKA_SPAN_LBO_T1_LONG_22_DB,
+	PIKA_SPAN_LBO_T1_SHORT_133_FT,
+	PIKA_SPAN_LBO_T1_SHORT_266_FT,
+	PIKA_SPAN_LBO_T1_SHORT_399_FT,
+	PIKA_SPAN_LBO_T1_SHORT_533_FT,
+	PIKA_SPAN_LBO_T1_SHORT_655_FT,
+	PIKA_SPAN_LBO_E1_WAVEFORM_120_OHM,
+	PIKA_SPAN_LBO_INVALID
+} PIKA_TSpanBuildOut;
+#define PIKA_LBO_STRINGS "T1_LONG_0_DB", "T1_LONG_7_DB", "T1_LONG_15_DB", "T1_LONG_22_DB", "T1_SHORT_133_FT", "T1_SHORT_266_FT", "T1_SHORT_399_FT", "T1_SHORT_533_FT", "T1_SHORT_655_FT", "E1_WAVEFORM_120_OHM"
+PIKA_STR2ENUM_P(pika_str2lbo, pika_lbo2str, PIKA_TSpanBuildOut)
+
+typedef enum {
+	PIKA_SPAN_COMPAND_MODE_MU_LAW = 1,
+	PIKA_SPAN_COMPAND_MODE_A_LAW,
+	PIKA_SPAN_COMPAND_MODE_INVALID
+} PIKA_TSpanCompandMode;
+#define PIKA_SPAN_COMPAND_MODE_STRINGS "MU_LAW", "A_LAW"
+PIKA_STR2ENUM_P(pika_str2compand_mode, pika_compand_mode2str, PIKA_TSpanCompandMode)
+
+#endif
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */

Added: freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_pika/ftmod_pika.2008.vcproj (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_pika/ftmod_pika.2008.vcproj	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_pika/ftmod_pika.2008.vcproj	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,197 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="9.00"
+	Name="ftmod_pika"
+	ProjectGUID="{E886B4D5-AB4F-4092-B8F4-3B06E1E462EF}"
+	RootNamespace="ftmod_pika"
+	Keyword="Win32Proj"
+	TargetFrameworkVersion="196613"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="2"
+			CharacterSet="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				AdditionalIncludeDirectories="..\..\isdn\include;..\..\include;..\..\..\pika\aoh\inc"
+				PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;FTMOD_PIKA_EXPORTS"
+				MinimalRebuild="true"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="3"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				DebugInformationFormat="4"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="pikahmpapi.lib"
+				LinkIncremental="2"
+				AdditionalLibraryDirectories="..\..\..\pika\aoh\lib"
+				GenerateDebugInformation="true"
+				SubSystem="2"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="2"
+			CharacterSet="1"
+			WholeProgramOptimization="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="2"
+				EnableIntrinsicFunctions="true"
+				AdditionalIncludeDirectories="..\..\isdn\include;..\..\include;..\..\..\pika\aoh\inc"
+				PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;FTMOD_PIKA_EXPORTS"
+				RuntimeLibrary="2"
+				EnableFunctionLevelLinking="true"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				DebugInformationFormat="3"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="pikahmpapi.lib"
+				LinkIncremental="1"
+				AdditionalLibraryDirectories="..\..\..\pika\aoh\lib"
+				GenerateDebugInformation="true"
+				SubSystem="2"
+				OptimizeReferences="2"
+				EnableCOMDATFolding="2"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<Filter
+			Name="Source Files"
+			Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+			>
+			<File
+				RelativePath=".\ftmod_pika.c"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="Header Files"
+			Filter="h;hpp;hxx;hm;inl;inc;xsd"
+			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+			>
+			<File
+				RelativePath=".\ftdm_pika.h"
+				>
+			</File>
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>

Added: freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_pika/ftmod_pika.c (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_pika/ftmod_pika.c	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_pika/ftmod_pika.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,1469 @@
+/*
+ * Copyright (c) 2007, Anthony Minessale II
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#include "freetdm.h"
+#include "ftdm_pika.h"
+
+
+#define MAX_NUMBER_OF_TRUNKS 64
+#define PIKA_BLOCK_SIZE 160
+#define PIKA_BLOCK_LEN 20
+#define PIKA_NUM_BUFFERS 8
+#define TRY_OR_DIE(__code, __status, __label) if ((status = __code ) != __status) goto __label
+#define pk_atof(__a) (PK_FLOAT) atof(__a)
+
+PK_VOID PK_CALLBACK media_out_callback(PKH_TPikaEvent *event);
+
+FTDM_ENUM_NAMES(PIKA_SPAN_NAMES, PIKA_SPAN_STRINGS)
+PIKA_STR2ENUM(pika_str2span, pika_span2str, PIKA_TSpanFraming, PIKA_SPAN_NAMES, PIKA_SPAN_INVALID)
+
+FTDM_ENUM_NAMES(PIKA_SPAN_ENCODING_NAMES, PIKA_SPAN_ENCODING_STRINGS)
+PIKA_STR2ENUM(pika_str2span_encoding, pika_span_encoding2str, PIKA_TSpanEncoding, PIKA_SPAN_ENCODING_NAMES, PIKA_SPAN_ENCODING_INVALID)
+
+FTDM_ENUM_NAMES(PIKA_LL_NAMES, PIKA_LL_STRINGS)
+PIKA_STR2ENUM(pika_str2loop_length, pika_loop_length2str, PIKA_TSpanLoopLength, PIKA_LL_NAMES, PIKA_SPAN_LOOP_INVALID)
+
+FTDM_ENUM_NAMES(PIKA_LBO_NAMES, PIKA_LBO_STRINGS)
+PIKA_STR2ENUM(pika_str2lbo, pika_lbo2str, PIKA_TSpanBuildOut, PIKA_LBO_NAMES, PIKA_SPAN_LBO_INVALID)
+
+FTDM_ENUM_NAMES(PIKA_SPAN_COMPAND_MODE_NAMES, PIKA_SPAN_COMPAND_MODE_STRINGS)
+PIKA_STR2ENUM(pika_str2compand_mode, pika_compand_mode2str, PIKA_TSpanCompandMode, PIKA_SPAN_COMPAND_MODE_NAMES, PIKA_SPAN_COMPAND_MODE_INVALID)
+
+
+typedef enum {
+	PK_FLAG_READY = (1 << 0),
+	PK_FLAG_LOCKED = (1 << 1)
+} pk_flag_t;
+
+struct general_config {
+	uint32_t region;
+};
+typedef struct general_config general_config_t;
+
+struct pika_channel_profile {
+	char name[80];
+	PKH_TRecordConfig record_config;
+	PKH_TPlayConfig play_config;
+	int ec_enabled;
+	PKH_TECConfig ec_config;
+	PKH_TSpanConfig span_config;
+	general_config_t general_config;
+	int cust_span;
+};
+typedef struct pika_channel_profile pika_channel_profile_t;
+
+static struct {
+	PKH_TSystemDeviceList board_list;
+	TPikaHandle open_boards[MAX_NUMBER_OF_TRUNKS];
+	TPikaHandle system_handle;
+	PKH_TSystemConfig system_config;
+	PKH_TRecordConfig record_config;
+	PKH_TPlayConfig play_config;
+	PKH_TECConfig ec_config;
+	PKH_TSpanConfig t1_span_config;
+	PKH_TSpanConfig e1_span_config;
+	ftdm_hash_t *profile_hash;
+	general_config_t general_config;
+} globals;
+
+
+struct pika_span_data {
+	TPikaHandle event_queue;
+	PKH_TPikaEvent last_oob_event;
+	uint32_t boardno;
+	PKH_TSpanConfig span_config;
+	TPikaHandle handle;
+	uint32_t flags;
+};
+typedef struct pika_span_data pika_span_data_t;
+
+struct pika_chan_data {
+	TPikaHandle handle;
+	TPikaHandle media_in;
+	TPikaHandle media_out;
+	TPikaHandle media_in_queue;
+	TPikaHandle media_out_queue;
+	PKH_TPikaEvent last_media_event;
+	PKH_TPikaEvent last_oob_event;
+	PKH_TRecordConfig record_config;
+	PKH_TPlayConfig play_config;
+	int ec_enabled;
+	PKH_TECConfig ec_config;
+	PKH_THDLCConfig hdlc_config;
+	ftdm_buffer_t *digit_buffer;
+	ftdm_mutex_t *digit_mutex;
+	ftdm_size_t dtmf_len;
+	uint32_t flags;
+	uint32_t hdlc_bytes;
+};
+typedef struct pika_chan_data pika_chan_data_t;
+
+static const char *pika_board_type_string(PK_UINT type)
+{
+	if (type == PKH_BOARD_TYPE_DIGITAL_GATEWAY) {
+		return "digital_gateway";
+	}
+
+	if (type == PKH_BOARD_TYPE_ANALOG_GATEWAY) {
+		return "analog_gateway";
+	}
+
+	return "unknown";
+}
+
+/**
+ * \brief Process configuration variable for a pika profile
+ * \param category Pika profile name
+ * \param var Variable name
+ * \param val Variable value
+ * \param lineno Line number from configuration file (unused)
+ * \return Success
+ */
+static FIO_CONFIGURE_FUNCTION(pika_configure)
+{
+	pika_channel_profile_t *profile = NULL;
+	int ok = 1;
+
+	if (!(profile = (pika_channel_profile_t *) hashtable_search(globals.profile_hash, (char *)category))) {
+		profile = ftdm_malloc(sizeof(*profile));
+		memset(profile, 0, sizeof(*profile));
+		ftdm_set_string(profile->name, category);
+		profile->ec_config = globals.ec_config;
+		profile->record_config = globals.record_config;
+		profile->play_config = globals.play_config;
+		hashtable_insert(globals.profile_hash, (void *)profile->name, profile, HASHTABLE_FLAG_NONE);
+		ftdm_log(FTDM_LOG_INFO, "creating profile [%s]\n", category);
+	}
+
+	if (!strcasecmp(var, "rx-gain")) {
+		profile->record_config.gain = pk_atof(val);
+	} else if (!strcasecmp(var, "rx-agc-enabled")) {
+		profile->record_config.AGC.enabled = ftdm_true(val);
+	} else if (!strcasecmp(var, "rx-agc-targetPower")) {
+		profile->record_config.AGC.targetPower = pk_atof(val);
+	} else if (!strcasecmp(var, "rx-agc-minGain")) {
+		profile->record_config.AGC.minGain = pk_atof(val);
+	} else if (!strcasecmp(var, "rx-agc-maxGain")) {
+		profile->record_config.AGC.maxGain = pk_atof(val);
+	} else if (!strcasecmp(var, "rx-agc-attackRate")) {
+		profile->record_config.AGC.attackRate = atoi(val);
+	} else if (!strcasecmp(var, "rx-agc-decayRate")) {
+		profile->record_config.AGC.decayRate = atoi(val);
+	} else if (!strcasecmp(var, "rx-agc-speechThreshold")) {
+		profile->record_config.AGC.speechThreshold = pk_atof(val);
+	} else if (!strcasecmp(var, "rx-vad-enabled")) {
+		profile->record_config.VAD.enabled = ftdm_true(val);
+	} else if (!strcasecmp(var, "rx-vad-activationThreshold")) {
+		profile->record_config.VAD.activationThreshold = pk_atof(val);
+	} else if (!strcasecmp(var, "rx-vad-activationDebounceTime")) {
+		profile->record_config.VAD.activationDebounceTime = atoi(val);
+	} else if (!strcasecmp(var, "rx-vad-deactivationThreshold")) {
+		profile->record_config.VAD.deactivationThreshold = pk_atof(val);
+	} else if (!strcasecmp(var, "rx-vad-deactivationDebounceTime")) {
+		profile->record_config.VAD.deactivationDebounceTime = atoi(val);
+	} else if (!strcasecmp(var, "rx-vad-preSpeechBufferSize")) {
+		profile->record_config.VAD.preSpeechBufferSize = atoi(val);
+	} else if (!strcasecmp(var, "tx-gain")) {
+		profile->play_config.gain = pk_atof(val);
+	} else if (!strcasecmp(var, "tx-agc-enabled")) {
+		profile->play_config.AGC.enabled = ftdm_true(val);
+	} else if (!strcasecmp(var, "tx-agc-targetPower")) {
+		profile->play_config.AGC.targetPower = pk_atof(val);
+	} else if (!strcasecmp(var, "tx-agc-minGain")) {
+		profile->play_config.AGC.minGain = pk_atof(val);
+	} else if (!strcasecmp(var, "tx-agc-maxGain")) {
+		profile->play_config.AGC.maxGain = pk_atof(val);
+	} else if (!strcasecmp(var, "tx-agc-attackRate")) {
+		profile->play_config.AGC.attackRate = atoi(val);
+	} else if (!strcasecmp(var, "tx-agc-decayRate")) {
+		profile->play_config.AGC.decayRate = atoi(val);
+	} else if (!strcasecmp(var, "tx-agc-speechThreshold")) {
+		profile->play_config.AGC.speechThreshold = pk_atof(val);
+	} else if (!strcasecmp(var, "ec-enabled")) {
+		profile->ec_enabled = ftdm_true(val);
+	} else if (!strcasecmp(var, "ec-doubleTalkerThreshold")) {
+		profile->ec_config.doubleTalkerThreshold = pk_atof(val);
+	} else if (!strcasecmp(var, "ec-speechPresentThreshold")) {
+		profile->ec_config.speechPresentThreshold = pk_atof(val);
+	} else if (!strcasecmp(var, "ec-echoSuppressionThreshold")) {
+		profile->ec_config.echoSuppressionThreshold = pk_atof(val);
+	} else if (!strcasecmp(var, "ec-echoSuppressionEnabled")) {
+		profile->ec_config.echoSuppressionEnabled = ftdm_true(val);
+	} else if (!strcasecmp(var, "ec-comfortNoiseEnabled")) {
+		profile->ec_config.comfortNoiseEnabled = ftdm_true(val);
+	} else if (!strcasecmp(var, "ec-adaptationModeEnabled")) {
+		profile->ec_config.adaptationModeEnabled = ftdm_true(val);
+	} else if (!strcasecmp(var, "framing")) {
+		profile->span_config.framing = pika_str2span(val);
+		profile->cust_span++;
+	} else if (!strcasecmp(var, "encoding")) {
+		profile->span_config.encoding = pika_str2span_encoding(val);
+		profile->cust_span++;
+	} else if (!strcasecmp(var, "loopLength")) {
+		profile->span_config.loopLength = pika_str2loop_length(val);
+		profile->cust_span++;
+	} else if (!strcasecmp(var, "buildOut")) {
+		profile->span_config.buildOut = pika_str2lbo(val);
+		profile->cust_span++;
+	} else if (!strcasecmp(var, "compandMode")) {
+		profile->span_config.compandMode = pika_str2compand_mode(val);
+		profile->cust_span++;
+	} else if (!strcasecmp(var, "region")) {
+		if (!strcasecmp(val, "eu")) {
+			profile->general_config.region = PKH_TRUNK_EU;
+		} else {
+			profile->general_config.region = PKH_TRUNK_NA;
+		}
+	} else {
+		ok = 0;
+	}
+
+	if (ok) {
+		ftdm_log(FTDM_LOG_INFO, "setting param [%s]=[%s] for profile [%s]\n", var, val, category);
+	} else {
+		ftdm_log(FTDM_LOG_ERROR, "unknown param [%s]\n", var);
+	}
+
+	return FTDM_SUCCESS;
+}
+
+/**
+ * \brief Pika event handler
+ * \param event Pika event
+ */
+PK_VOID PK_CALLBACK media_out_callback(PKH_TPikaEvent *event)
+{
+	PK_STATUS pk_status;
+	ftdm_channel_t *ftdmchan = event->userData;
+	pika_chan_data_t *chan_data = (pika_chan_data_t *) ftdmchan->mod_data;
+
+	//PK_CHAR event_text[PKH_EVENT_MAX_NAME_LENGTH];
+	//PKH_EVENT_GetText(event->id, event_text, sizeof(event_text));
+	//ftdm_log(FTDM_LOG_DEBUG, "Event: %s\n", event_text);
+	
+	switch (event->id) {
+	case PKH_EVENT_PLAY_IDLE:
+		{
+			while (ftdm_buffer_inuse(chan_data->digit_buffer)) {
+				char dtmf[128] = "";
+				ftdm_mutex_lock(chan_data->digit_mutex);
+				chan_data->dtmf_len = ftdm_buffer_read(chan_data->digit_buffer, dtmf, sizeof(dtmf));
+				pk_status = PKH_TG_PlayDTMF(chan_data->media_out, dtmf);
+				ftdm_mutex_unlock(chan_data->digit_mutex);
+			}
+		}
+		break;
+	case PKH_EVENT_TG_TONE_PLAYED:
+		{
+
+			if (!event->p1) {
+				ftdm_mutex_lock(chan_data->digit_mutex);
+				PKH_PLAY_Start(chan_data->media_out);
+				chan_data->dtmf_len = 0;
+				ftdm_mutex_unlock(chan_data->digit_mutex);
+			}
+
+				
+		}
+		break;
+	default:
+		break;
+	}
+
+}
+
+/**
+ * \brief Initialises a range of pika channels
+ * \param span FreeTDM span
+ * \param boardno Pika board number
+ * \param spanno Pika span number
+ * \param start Initial pika channel number
+ * \param end Final pika channel number
+ * \param type FreeTDM channel type
+ * \param name FreeTDM span name
+ * \param number FreeTDM span number
+ * \param profile Pika channel profile
+ * \return number of spans configured
+ */
+static unsigned pika_open_range(ftdm_span_t *span, unsigned boardno, unsigned spanno, unsigned start, unsigned end, 
+								ftdm_chan_type_t type, char *name, char *number, pika_channel_profile_t *profile)
+{
+	unsigned configured = 0, x;
+	PK_STATUS status;
+	PK_CHAR error_text[PKH_ERROR_MAX_NAME_LENGTH];
+	pika_span_data_t *span_data;
+
+	if (boardno >= globals.board_list.numberOfBoards) {
+		ftdm_log(FTDM_LOG_ERROR, "Board %u is not present!\n", boardno);
+		return 0;
+	}
+
+	if (!globals.open_boards[boardno]) {
+		status = PKH_BOARD_Open(globals.board_list.board[boardno].id,
+								NULL,
+								&globals.open_boards[boardno]);
+		if(status != PK_SUCCESS) {
+			ftdm_log(FTDM_LOG_ERROR, "Error: PKH_BOARD_Open %d failed(%s)!\n",  boardno,
+					PKH_ERROR_GetText(status, error_text, sizeof(error_text)));
+			return 0;
+		}
+
+		ftdm_log(FTDM_LOG_DEBUG, "Open board %u\n",  boardno);
+
+		//PKH_BOARD_SetDebugTrace(globals.open_boards[boardno], 1, 0);
+		
+	}
+
+	if (span->mod_data) {
+		span_data = span->mod_data;
+	} else {
+		span_data = ftdm_malloc(sizeof(*span_data));
+		assert(span_data != NULL);
+		memset(span_data, 0, sizeof(*span_data));
+		span_data->boardno = boardno;
+		
+		status = PKH_QUEUE_Create(PKH_QUEUE_TYPE_NORMAL, &span_data->event_queue);
+		
+		if (status != PK_SUCCESS) {
+			ftdm_log(FTDM_LOG_ERROR, "Error: PKH_QUEUE_Create failed(%s)!\n",
+					PKH_ERROR_GetText(status, error_text, sizeof(error_text)));
+			ftdm_safe_free(span_data);
+			return 0;
+		}
+
+		//PKH_QUEUE_Attach(span_data->event_queue, globals.open_boards[boardno], NULL);
+
+		span->mod_data = span_data;
+	}
+
+	if (type == FTDM_CHAN_TYPE_FXS || type == FTDM_CHAN_TYPE_FXO) {
+		start--;
+		end--;
+	}
+
+	for(x = start; x < end; x++) {
+		ftdm_channel_t *chan;
+		pika_chan_data_t *chan_data = NULL;
+
+		chan_data = ftdm_malloc(sizeof *chan_data);
+		assert(chan_data);
+		memset(chan_data, 0, sizeof(*chan_data));
+		ftdm_span_add_channel(span, 0, type, &chan);
+		chan->mod_data = chan_data;
+
+		if ((type == FTDM_CHAN_TYPE_B || type == FTDM_CHAN_TYPE_DQ921) && !span_data->handle) {
+			PKH_TBoardConfig boardConfig;
+			
+			TRY_OR_DIE(PKH_BOARD_GetConfig(globals.open_boards[boardno], &boardConfig), PK_SUCCESS, error);
+			if ((profile && profile->general_config.region == PKH_TRUNK_EU) || ftdm_test_flag(span_data, PK_FLAG_LOCKED)) {
+				if (span->trunk_type == FTDM_TRUNK_T1) {
+					ftdm_log(FTDM_LOG_WARNING, "Changing trunk type to E1 based on previous config.\n");
+				}
+				span->trunk_type = FTDM_TRUNK_E1;
+			}
+
+			if (span->trunk_type == FTDM_TRUNK_T1) {
+				if (ftdm_test_flag(span_data, PK_FLAG_LOCKED)) {
+					ftdm_log(FTDM_LOG_WARNING, "Already locked into E1 mode!\n");
+				}
+			} else if (span->trunk_type == FTDM_TRUNK_E1) {
+				boardConfig.specific.DigitalGateway.interfaceType = PKH_BOARD_INTERFACE_TYPE_E1;
+				if ((status = PKH_BOARD_SetConfig(globals.open_boards[boardno], &boardConfig)) != PK_SUCCESS) {
+					ftdm_log(FTDM_LOG_ERROR, "Error: [%s]\n",
+							PKH_ERROR_GetText(status, error_text, sizeof(error_text)));
+				}
+				ftdm_set_flag(span_data, PK_FLAG_LOCKED);
+			}
+			
+			TRY_OR_DIE(PKH_SPAN_Open(globals.open_boards[boardno], spanno, NULL, &span_data->handle), PK_SUCCESS, error);
+			TRY_OR_DIE(PKH_SPAN_GetConfig(span_data->handle, &span_data->span_config), PK_SUCCESS, error);
+			TRY_OR_DIE(PKH_QUEUE_Attach(span_data->event_queue, span_data->handle, (PK_VOID*) span), PK_SUCCESS, error);
+		}
+
+		if (type == FTDM_CHAN_TYPE_FXO) {
+			PKH_TTrunkConfig trunkConfig;
+			
+			TRY_OR_DIE(PKH_TRUNK_Open(globals.open_boards[boardno], x, &chan_data->handle), PK_SUCCESS, error);
+			TRY_OR_DIE(PKH_TRUNK_Seize(chan_data->handle), PK_SUCCESS, error);
+
+			if (profile && profile->general_config.region == PKH_TRUNK_EU) {
+				TRY_OR_DIE(PKH_TRUNK_GetConfig(chan_data->handle, &trunkConfig), PK_SUCCESS, error);
+				trunkConfig.internationalControl = PKH_PHONE_INTERNATIONAL_CONTROL_EU;
+				trunkConfig.audioFormat = PKH_AUDIO_ALAW;
+				trunkConfig.compandMode = PKH_PHONE_AUDIO_ALAW;
+				chan->native_codec = chan->effective_codec = FTDM_CODEC_ALAW;
+				TRY_OR_DIE(PKH_TRUNK_SetConfig(chan_data->handle, &trunkConfig), PK_SUCCESS, error);
+			} else {
+				chan->native_codec = chan->effective_codec = FTDM_CODEC_ULAW;
+			}
+
+			
+			TRY_OR_DIE(PKH_QUEUE_Attach(span_data->event_queue, chan_data->handle, (PK_VOID*) chan), PK_SUCCESS, error);
+			TRY_OR_DIE(PKH_TRUNK_GetMediaStreams(chan_data->handle, &chan_data->media_in, &chan_data->media_out), PK_SUCCESS, error);
+			TRY_OR_DIE(PKH_QUEUE_Create(PKH_QUEUE_TYPE_NORMAL, &chan_data->media_in_queue), PK_SUCCESS, error);
+			TRY_OR_DIE(PKH_QUEUE_Attach(chan_data->media_in_queue, chan_data->media_in, (PK_VOID*) chan), PK_SUCCESS, error);
+			TRY_OR_DIE(PKH_QUEUE_Create(PKH_QUEUE_TYPE_CALLBACK, &chan_data->media_out_queue), PK_SUCCESS, error);
+			TRY_OR_DIE(PKH_QUEUE_SetEventHandler(chan_data->media_out_queue, media_out_callback), PK_SUCCESS, error);
+			TRY_OR_DIE(PKH_QUEUE_Attach(chan_data->media_out_queue, chan_data->media_out, (PK_VOID*) chan), PK_SUCCESS, error);
+			TRY_OR_DIE(PKH_TRUNK_Start(chan_data->handle), PK_SUCCESS, error);
+		} else if (type == FTDM_CHAN_TYPE_FXS) {
+			PKH_TPhoneConfig phoneConfig;
+
+			if (profile && profile->general_config.region == PKH_TRUNK_EU) {
+				TRY_OR_DIE(PKH_PHONE_GetConfig(chan_data->handle, &phoneConfig), PK_SUCCESS, error);
+				phoneConfig.internationalControl = PKH_PHONE_INTERNATIONAL_CONTROL_EU;
+				phoneConfig.compandMode = PKH_PHONE_AUDIO_ALAW;
+				chan->native_codec = chan->effective_codec = FTDM_CODEC_ALAW;
+				TRY_OR_DIE(PKH_PHONE_SetConfig(chan_data->handle, &phoneConfig), PK_SUCCESS, error);
+			} else {
+				chan->native_codec = chan->effective_codec = FTDM_CODEC_ULAW;
+			}
+
+			TRY_OR_DIE(PKH_PHONE_Open(globals.open_boards[boardno], x, &chan_data->handle), PK_SUCCESS, error);
+			TRY_OR_DIE(PKH_PHONE_Seize(chan_data->handle), PK_SUCCESS, error);
+			TRY_OR_DIE(PKH_PHONE_GetMediaStreams(chan_data->handle, &chan_data->media_in, &chan_data->media_out), PK_SUCCESS, error);
+			TRY_OR_DIE(PKH_QUEUE_Attach(span_data->event_queue, chan_data->handle, (PK_VOID*) chan), PK_SUCCESS, error);
+			TRY_OR_DIE(PKH_QUEUE_Create(PKH_QUEUE_TYPE_NORMAL, &chan_data->media_in_queue), PK_SUCCESS, error);
+			TRY_OR_DIE(PKH_QUEUE_Attach(chan_data->media_in_queue, chan_data->media_in, (PK_VOID*) chan), PK_SUCCESS, error);
+			TRY_OR_DIE(PKH_QUEUE_Create(PKH_QUEUE_TYPE_CALLBACK, &chan_data->media_out_queue), PK_SUCCESS, error);
+			TRY_OR_DIE(PKH_QUEUE_SetEventHandler(chan_data->media_out_queue, media_out_callback), PK_SUCCESS, error);
+			TRY_OR_DIE(PKH_QUEUE_Attach(chan_data->media_out_queue, chan_data->media_out, (PK_VOID*) chan), PK_SUCCESS, error);
+			TRY_OR_DIE(PKH_PHONE_Start(chan_data->handle), PK_SUCCESS, error);
+		} else if (type == FTDM_CHAN_TYPE_B) {
+			TRY_OR_DIE(PKH_SPAN_SeizeChannel(span_data->handle, x), PK_SUCCESS, error);
+			TRY_OR_DIE(PKH_SPAN_GetMediaStreams(span_data->handle, x, &chan_data->media_in, &chan_data->media_out), PK_SUCCESS, error);
+			TRY_OR_DIE(PKH_QUEUE_Create(PKH_QUEUE_TYPE_NORMAL, &chan_data->media_in_queue), PK_SUCCESS, error);
+			TRY_OR_DIE(PKH_QUEUE_Attach(chan_data->media_in_queue, chan_data->media_in, (PK_VOID*) chan), PK_SUCCESS, error);
+			TRY_OR_DIE(PKH_QUEUE_Create(PKH_QUEUE_TYPE_CALLBACK, &chan_data->media_out_queue), PK_SUCCESS, error);
+			TRY_OR_DIE(PKH_QUEUE_SetEventHandler(chan_data->media_out_queue, media_out_callback), PK_SUCCESS, error);
+			TRY_OR_DIE(PKH_QUEUE_Attach(chan_data->media_out_queue, chan_data->media_out, (PK_VOID*) chan), PK_SUCCESS, error);
+		} else if (type == FTDM_CHAN_TYPE_DQ921) {
+			TRY_OR_DIE(PKH_SPAN_HDLC_Open(span_data->handle, PKH_SPAN_HDLC_MODE_NORMAL, &chan_data->handle), PK_SUCCESS, error);
+			TRY_OR_DIE(PKH_SPAN_HDLC_GetConfig(chan_data->handle, &chan_data->hdlc_config), PK_SUCCESS, error);
+			chan_data->hdlc_config.channelId = x;
+			TRY_OR_DIE(PKH_SPAN_HDLC_SetConfig(chan_data->handle, &chan_data->hdlc_config), PK_SUCCESS, error);
+			TRY_OR_DIE(PKH_QUEUE_Create(PKH_QUEUE_TYPE_NORMAL, &chan_data->media_in_queue), PK_SUCCESS, error);
+			TRY_OR_DIE(PKH_QUEUE_Attach(chan_data->media_in_queue, chan_data->handle, (PK_VOID*) chan), PK_SUCCESS, error);
+			TRY_OR_DIE(PKH_QUEUE_Attach(span_data->event_queue, chan_data->handle, (PK_VOID*) chan), PK_SUCCESS, error);
+
+			if (profile) {
+				if (profile->cust_span) {
+					span_data->span_config.framing = profile->span_config.framing;
+					span_data->span_config.encoding = profile->span_config.encoding;
+					span_data->span_config.loopLength = profile->span_config.loopLength;
+					span_data->span_config.buildOut = profile->span_config.buildOut;
+					span_data->span_config.compandMode = profile->span_config.compandMode;
+				} else {
+					if (profile->general_config.region == PKH_TRUNK_EU) {
+						span_data->span_config = globals.e1_span_config;
+					} else {
+						span_data->span_config = globals.t1_span_config;
+					}
+				}
+			} else {
+				if (span->trunk_type == FTDM_TRUNK_E1) {
+					span_data->span_config = globals.e1_span_config;
+				} else {
+					span_data->span_config = globals.t1_span_config;
+				}
+			}
+			
+			PKH_SPAN_SetConfig(span_data->handle, &span_data->span_config);
+			TRY_OR_DIE(PKH_SPAN_Start(span_data->handle), PK_SUCCESS, error);
+		}
+		
+		goto ok;
+
+	error:
+		PKH_ERROR_GetText(status, error_text, sizeof(error_text));
+		ftdm_log(FTDM_LOG_ERROR, "failure configuring device b%ds%dc%d [%s]\n", boardno, spanno, x, error_text);
+		continue;
+	ok:
+		ftdm_set_flag(chan_data, PK_FLAG_READY);
+		status = PKH_RECORD_GetConfig(chan_data->media_in, &chan_data->record_config);
+		chan_data->record_config.encoding = PKH_RECORD_ENCODING_MU_LAW;
+		chan_data->record_config.samplingRate = PKH_RECORD_SAMPLING_RATE_8KHZ;
+		chan_data->record_config.bufferSize = PIKA_BLOCK_SIZE;
+		chan_data->record_config.numberOfBuffers = PIKA_NUM_BUFFERS;
+		chan_data->record_config.VAD.enabled = PK_FALSE;
+		//chan_data->record_config.speechSegmentEventsEnabled = PK_FALSE;
+		//chan_data->record_config.gain = rxgain;
+
+		status = PKH_PLAY_GetConfig(chan_data->media_out, &chan_data->play_config);
+		chan_data->play_config.encoding = PKH_RECORD_ENCODING_MU_LAW;
+		chan_data->play_config.samplingRate = PKH_RECORD_SAMPLING_RATE_8KHZ;
+		chan_data->play_config.AGC.enabled = PK_FALSE;
+		ftdm_log(FTDM_LOG_INFO, "configuring device b%ds%dc%d as FreeTDM device %d:%d\n", boardno, spanno, x, chan->span_id, chan->chan_id);
+
+		if (profile) {
+			ftdm_log(FTDM_LOG_INFO, "applying config profile %s to device %d:%d\n", profile->name, chan->span_id, chan->chan_id);
+			chan_data->record_config.gain = profile->record_config.gain;
+			chan_data->record_config.AGC = profile->record_config.AGC;
+			chan_data->record_config.VAD = profile->record_config.VAD;
+			chan_data->play_config.gain = profile->play_config.gain;
+			chan_data->play_config.AGC = profile->play_config.AGC;
+			chan_data->ec_enabled = profile->ec_enabled;
+			chan_data->ec_config = profile->ec_config;
+		}
+		
+		if (type == FTDM_CHAN_TYPE_B) {
+			if (span_data->span_config.compandMode == PKH_SPAN_COMPAND_MODE_A_LAW) {
+				chan->native_codec = chan->effective_codec = FTDM_CODEC_ALAW;
+			} else {
+				chan->native_codec = chan->effective_codec = FTDM_CODEC_ULAW;
+			}
+		}
+
+		status = PKH_RECORD_SetConfig(chan_data->media_in, &chan_data->record_config);
+		status = PKH_PLAY_SetConfig(chan_data->media_out, &chan_data->play_config);
+
+		chan->physical_span_id = spanno;
+		chan->physical_chan_id = x;
+
+		chan->rate = 8000;
+		chan->packet_len = (uint32_t)chan_data->record_config.bufferSize;
+		chan->effective_interval = chan->native_interval = chan->packet_len / 8;
+
+		PKH_RECORD_Start(chan_data->media_in);
+		PKH_PLAY_Start(chan_data->media_out);
+		if (chan_data->ec_enabled) {
+			PKH_EC_SetConfig(chan_data->media_in, &chan_data->ec_config);
+			PKH_EC_Start(chan_data->media_in, chan_data->media_in, chan_data->media_out);
+		}
+
+		if (!ftdm_strlen_zero(name)) {
+			ftdm_copy_string(chan->chan_name, name, sizeof(chan->chan_name));
+		}
+		
+		if (!ftdm_strlen_zero(number)) {
+			ftdm_copy_string(chan->chan_number, number, sizeof(chan->chan_number));
+		}
+
+		ftdm_channel_set_feature(chan, FTDM_CHANNEL_FEATURE_DTMF_GENERATE);
+		ftdm_buffer_create(&chan_data->digit_buffer, 128, 128, 0);
+		ftdm_mutex_create(&chan_data->digit_mutex);
+
+		configured++;
+	} 
+
+	
+	return configured;
+}
+
+/**
+ * \brief Initialises an freetdm pika span from a configuration string
+ * \param span FreeTDM span
+ * \param str Configuration string
+ * \param type FreeTDM span type
+ * \param name FreeTDM span name
+ * \param number FreeTDM span number
+ * \return Success or failure
+ */
+static FIO_CONFIGURE_SPAN_FUNCTION(pika_configure_span)
+{
+	int items, i;
+    char *mydata, *item_list[10];
+	char *bd, *sp, *ch = NULL, *mx;
+	int boardno;
+	int channo;
+	int spanno;
+	int top = 0;
+	unsigned configured = 0;
+	char *profile_name = NULL;
+	pika_channel_profile_t *profile = NULL;
+
+	assert(str != NULL);
+
+	mydata = ftdm_strdup(str);
+	assert(mydata != NULL);
+
+	if ((profile_name = strchr(mydata, '@'))) {
+		*profile_name++ = '\0';
+		if (!ftdm_strlen_zero(profile_name)) {
+			profile = (pika_channel_profile_t *) hashtable_search(globals.profile_hash, (char *)profile_name);
+		}
+	}
+		
+	items = ftdm_separate_string(mydata, ',', item_list, (sizeof(item_list) / sizeof(item_list[0])));
+
+	for(i = 0; i < items; i++) {
+		bd = item_list[i];
+		if ((sp = strchr(bd, ':'))) {
+			*sp++ = '\0';
+			if ((ch = strchr(sp, ':'))) {
+				*ch++ = '\0';
+			}
+		}
+		
+		if (!(bd && sp && ch)) {
+			ftdm_log(FTDM_LOG_ERROR, "Invalid input\n");
+			continue;
+		}
+
+		boardno = atoi(bd);
+		channo = atoi(ch);
+		spanno = atoi(sp);
+
+
+		if (boardno < 0) {
+			ftdm_log(FTDM_LOG_ERROR, "Invalid board number %d\n", boardno);
+			continue;
+		}
+
+		if (channo < 0) {
+			ftdm_log(FTDM_LOG_ERROR, "Invalid channel number %d\n", channo);
+			continue;
+		}
+
+		if (spanno < 0) {
+			ftdm_log(FTDM_LOG_ERROR, "Invalid span number %d\n", channo);
+			continue;
+		}
+		
+		if ((mx = strchr(ch, '-'))) {
+			mx++;
+			top = atoi(mx) + 1;
+		} else {
+			top = channo + 1;
+		}
+		
+		
+		if (top < 0) {
+			ftdm_log(FTDM_LOG_ERROR, "Invalid range number %d\n", top);
+			continue;
+		}
+
+		configured += pika_open_range(span, boardno, spanno, channo, top, type, name, number, profile);
+
+	}
+	
+	ftdm_safe_free(mydata);
+
+	return configured;
+}
+
+/**
+ * \brief Opens Pika channel
+ * \param ftdmchan Channel to open
+ * \return Success or failure
+ */
+static FIO_OPEN_FUNCTION(pika_open) 
+{
+	pika_chan_data_t *chan_data = (pika_chan_data_t *) ftdmchan->mod_data;
+
+	if (!chan_data && !ftdm_test_flag(chan_data, PK_FLAG_READY)) {
+		return FTDM_FAIL;
+	}
+
+	if (chan_data->media_in_queue) {
+		PKH_QUEUE_Flush(chan_data->media_in_queue);
+	}
+
+	if (ftdmchan->type == FTDM_CHAN_TYPE_FXS || ftdmchan->type == FTDM_CHAN_TYPE_FXO || ftdmchan->type == FTDM_CHAN_TYPE_B) {
+		PKH_PLAY_Start(chan_data->media_out);
+	}
+	return FTDM_SUCCESS;
+}
+
+/**
+ * \brief Closes Pika channel
+ * \param ftdmchan Channel to close
+ * \return Success
+ */
+static FIO_CLOSE_FUNCTION(pika_close)
+{
+	return FTDM_SUCCESS;
+}
+
+/**
+ * \brief Waits for an event on a Pika channel
+ * \param ftdmchan Channel to open
+ * \param flags Type of event to wait for
+ * \param to Time to wait (in ms)
+ * \return Success, failure or timeout
+ */
+static FIO_WAIT_FUNCTION(pika_wait)
+{
+	pika_chan_data_t *chan_data = (pika_chan_data_t *) ftdmchan->mod_data;
+	PK_STATUS status;
+	ftdm_wait_flag_t myflags = *flags;
+	PK_CHAR event_text[PKH_EVENT_MAX_NAME_LENGTH];
+
+	*flags = FTDM_NO_FLAGS;	
+
+	if (myflags & FTDM_READ) {
+		if (chan_data->hdlc_bytes) {
+			*flags |= FTDM_READ;
+			return FTDM_SUCCESS;
+		}
+		status = PKH_QUEUE_WaitOnEvent(chan_data->media_in_queue, to, &chan_data->last_media_event);
+		
+		if (status == PK_SUCCESS) {
+			if (chan_data->last_media_event.id == PKH_EVENT_QUEUE_TIMEOUT || chan_data->last_media_event.id == PKH_EVENT_RECORD_BUFFER_OVERFLOW) {
+				return FTDM_TIMEOUT;
+			}
+			
+			*flags |= FTDM_READ;
+			return FTDM_SUCCESS;
+		}
+
+		PKH_EVENT_GetText(chan_data->last_media_event.id, event_text, sizeof(event_text));
+		ftdm_log(FTDM_LOG_DEBUG, "Event: %s\n", event_text);
+	}
+
+	return FTDM_SUCCESS;
+}
+
+/**
+ * \brief Reads data from a Pika channel
+ * \param ftdmchan Channel to read from
+ * \param data Data buffer
+ * \param datalen Size of data buffer
+ * \return Success or failure
+ */
+static FIO_READ_FUNCTION(pika_read)
+{
+	pika_chan_data_t *chan_data = (pika_chan_data_t *) ftdmchan->mod_data;
+	PK_STATUS status;
+	PK_CHAR event_text[PKH_EVENT_MAX_NAME_LENGTH];
+	uint32_t len;
+
+	if (ftdmchan->type == FTDM_CHAN_TYPE_DQ921) {
+		if ((status = PKH_SPAN_HDLC_GetMessage(chan_data->handle, data, *datalen)) == PK_SUCCESS) {
+			*datalen = chan_data->hdlc_bytes;
+			chan_data->hdlc_bytes = 0;
+			return FTDM_SUCCESS;
+		}
+		return FTDM_FAIL;
+	}
+
+	if (!(len = chan_data->last_media_event.p0)) {
+		len = ftdmchan->packet_len;
+	}
+	
+	if (len < *datalen) {
+		*datalen = len;
+	}
+
+	if ((status = PKH_RECORD_GetData(chan_data->media_in, data, *datalen)) == PK_SUCCESS) {
+		return FTDM_SUCCESS;
+	}
+
+
+	PKH_ERROR_GetText(status, event_text, sizeof(event_text));
+	ftdm_log(FTDM_LOG_DEBUG, "ERR: %s\n", event_text);
+	return FTDM_FAIL;
+}
+
+/**
+ * \brief Writes data to a Pika channel
+ * \param ftdmchan Channel to write to
+ * \param data Data buffer
+ * \param datalen Size of data buffer
+ * \return Success or failure
+ */
+static FIO_WRITE_FUNCTION(pika_write)
+{
+	pika_chan_data_t *chan_data = (pika_chan_data_t *) ftdmchan->mod_data;
+	PK_STATUS status;
+
+	if (ftdmchan->type == FTDM_CHAN_TYPE_DQ921) {
+		if ((status = PKH_SPAN_HDLC_SendMessage(chan_data->handle, data, *datalen)) == PK_SUCCESS) {
+			return FTDM_SUCCESS;
+		}
+		return FTDM_FAIL;
+	}
+
+	if (PKH_PLAY_AddData(chan_data->media_out, 0, data, *datalen) == PK_SUCCESS) {
+		return FTDM_SUCCESS;
+	}
+
+	return FTDM_FAIL;
+}
+
+/**
+ * \brief Executes an FreeTDM command on a Pika channel
+ * \param ftdmchan Channel to execute command on
+ * \param command FreeTDM command to execute
+ * \param obj Object (unused)
+ * \return Success or failure
+ */
+static FIO_COMMAND_FUNCTION(pika_command)
+{
+	pika_chan_data_t *chan_data = (pika_chan_data_t *) ftdmchan->mod_data;
+	//pika_span_data_t *span_data = (pika_span_data_t *) ftdmchan->span->mod_data;
+	PK_STATUS pk_status;
+	ftdm_status_t status = FTDM_SUCCESS;
+
+	switch(command) {
+	case FTDM_COMMAND_OFFHOOK:
+		{
+			if ((pk_status = PKH_TRUNK_SetHookSwitch(chan_data->handle, PKH_TRUNK_OFFHOOK)) != PK_SUCCESS) {
+				PKH_ERROR_GetText(pk_status, ftdmchan->last_error, sizeof(ftdmchan->last_error));
+				GOTO_STATUS(done, FTDM_FAIL);
+			} else {
+				ftdm_set_flag_locked(ftdmchan, FTDM_CHANNEL_OFFHOOK);
+			}
+		}
+		break;
+	case FTDM_COMMAND_ONHOOK:
+		{
+			if ((pk_status = PKH_TRUNK_SetHookSwitch(chan_data->handle, PKH_TRUNK_ONHOOK)) != PK_SUCCESS) {
+				PKH_ERROR_GetText(pk_status, ftdmchan->last_error, sizeof(ftdmchan->last_error));
+				GOTO_STATUS(done, FTDM_FAIL);
+			} else {
+				ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_OFFHOOK);
+			}
+		}
+		break;
+	case FTDM_COMMAND_GENERATE_RING_ON:
+		{
+			if ((pk_status = PKH_PHONE_RingStart(chan_data->handle, 0, 0)) != PK_SUCCESS) {
+				PKH_ERROR_GetText(pk_status, ftdmchan->last_error, sizeof(ftdmchan->last_error));
+				GOTO_STATUS(done, FTDM_FAIL);
+			} else {
+				ftdm_set_flag_locked(ftdmchan, FTDM_CHANNEL_RINGING);
+			}
+		}
+		break;
+	case FTDM_COMMAND_GENERATE_RING_OFF:
+		{
+			if ((pk_status = PKH_PHONE_RingStop(chan_data->handle)) != PK_SUCCESS) {
+				PKH_ERROR_GetText(pk_status, ftdmchan->last_error, sizeof(ftdmchan->last_error));
+				GOTO_STATUS(done, FTDM_FAIL);
+			} else {
+				ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_RINGING);
+			}
+		}
+		break;
+	case FTDM_COMMAND_GET_INTERVAL:
+		{
+
+			FTDM_COMMAND_OBJ_INT = ftdmchan->native_interval;
+
+		}
+		break;
+	case FTDM_COMMAND_SET_INTERVAL: 
+		{
+			int interval = FTDM_COMMAND_OBJ_INT;
+			int len = interval * 8;
+			chan_data->record_config.bufferSize = len;
+			chan_data->record_config.numberOfBuffers = (PK_UINT)chan_data->record_config.bufferSize;
+			ftdmchan->packet_len = (uint32_t)chan_data->record_config.bufferSize;
+			ftdmchan->effective_interval = ftdmchan->native_interval = ftdmchan->packet_len / 8;
+			PKH_RECORD_SetConfig(chan_data->media_in, &chan_data->record_config);
+			GOTO_STATUS(done, FTDM_SUCCESS);
+		}
+		break;
+	case FTDM_COMMAND_GET_DTMF_ON_PERIOD:
+		{
+
+			FTDM_COMMAND_OBJ_INT = ftdmchan->dtmf_on;
+			GOTO_STATUS(done, FTDM_SUCCESS);
+
+		}
+		break;
+	case FTDM_COMMAND_GET_DTMF_OFF_PERIOD:
+		{			
+				FTDM_COMMAND_OBJ_INT = ftdmchan->dtmf_on;
+				GOTO_STATUS(done, FTDM_SUCCESS);
+		}
+		break;
+	case FTDM_COMMAND_SET_DTMF_ON_PERIOD:
+		{
+			int val = FTDM_COMMAND_OBJ_INT;
+			if (val > 10 && val < 1000) {
+				ftdmchan->dtmf_on = val;
+				GOTO_STATUS(done, FTDM_SUCCESS);
+			} else {
+				snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "invalid value %d range 10-1000", val);
+				GOTO_STATUS(done, FTDM_FAIL);
+			}
+		}
+		break;
+	case FTDM_COMMAND_SET_DTMF_OFF_PERIOD:
+		{
+			int val = FTDM_COMMAND_OBJ_INT;
+			if (val > 10 && val < 1000) {
+				ftdmchan->dtmf_off = val;
+				GOTO_STATUS(done, FTDM_SUCCESS);
+			} else {
+				snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "invalid value %d range 10-1000", val);
+				GOTO_STATUS(done, FTDM_FAIL);
+			}
+		}
+		break;
+	case FTDM_COMMAND_SEND_DTMF:
+		{
+			char *digits = FTDM_COMMAND_OBJ_CHAR_P;
+			ftdm_log(FTDM_LOG_DEBUG, "Adding DTMF SEQ [%s]\n", digits);
+			ftdm_mutex_lock(chan_data->digit_mutex);
+			ftdm_buffer_write(chan_data->digit_buffer, digits, strlen(digits));
+			ftdm_mutex_unlock(chan_data->digit_mutex);
+			pk_status = PKH_PLAY_Stop(chan_data->media_out);
+			
+			if (pk_status != PK_SUCCESS) {
+				PKH_ERROR_GetText(pk_status, ftdmchan->last_error, sizeof(ftdmchan->last_error));
+				GOTO_STATUS(done, FTDM_FAIL);
+			}
+			GOTO_STATUS(done, FTDM_SUCCESS);
+		}
+		break;
+	default:
+		break;
+	};
+
+ done:
+	return status;
+}
+
+/**
+ * \brief Checks for events on a Pika span
+ * \param span Span to check for events
+ * \param ms Time to wait for event
+ * \return Success if event is waiting or failure if not
+ */
+static FIO_SPAN_POLL_EVENT_FUNCTION(pika_poll_event)
+{
+	pika_span_data_t *span_data = (pika_span_data_t *) span->mod_data;
+	PK_STATUS status;
+	PK_CHAR event_text[PKH_EVENT_MAX_NAME_LENGTH];
+
+	status = PKH_QUEUE_WaitOnEvent(span_data->event_queue, ms, &span_data->last_oob_event);
+
+	if (status == PK_SUCCESS) {
+		ftdm_channel_t *ftdmchan = NULL;
+		uint32_t *data = (uint32_t *) span_data->last_oob_event.userData;
+		ftdm_data_type_t data_type = FTDM_TYPE_NONE;
+
+		if (span_data->last_oob_event.id == PKH_EVENT_QUEUE_TIMEOUT) {
+			return FTDM_TIMEOUT;
+		}
+
+		if (data) {
+			data_type = *data;
+		}
+
+		if (data_type == FTDM_TYPE_CHANNEL) {
+			ftdmchan = span_data->last_oob_event.userData;
+		} else if (data_type == FTDM_TYPE_SPAN) {
+            ftdm_time_t last_event_time = ftdm_current_time_in_ms();
+			uint32_t event_id = 0;
+
+			switch (span_data->last_oob_event.id) {
+			case PKH_EVENT_SPAN_ALARM_T1_RED:
+			case PKH_EVENT_SPAN_ALARM_T1_YELLOW:
+			case PKH_EVENT_SPAN_ALARM_T1_AIS:
+			case PKH_EVENT_SPAN_ALARM_E1_RED:
+			case PKH_EVENT_SPAN_ALARM_E1_RAI:
+			case PKH_EVENT_SPAN_ALARM_E1_AIS:
+			case PKH_EVENT_SPAN_ALARM_E1_RMAI:
+			case PKH_EVENT_SPAN_ALARM_E1_TS16AIS:
+			case PKH_EVENT_SPAN_ALARM_E1_TS16LOS:
+			case PKH_EVENT_SPAN_OUT_OF_SYNC:
+			case PKH_EVENT_SPAN_FRAMING_ERROR:
+			case PKH_EVENT_SPAN_LOSS_OF_SIGNAL:
+			case PKH_EVENT_SPAN_OUT_OF_CRC_MF_SYNC:
+			case PKH_EVENT_SPAN_OUT_OF_CAS_MF_SYNC:
+				event_id = FTDM_OOB_ALARM_TRAP;
+				break;
+			case PKH_EVENT_SPAN_ALARM_T1_RED_CLEAR:
+			case PKH_EVENT_SPAN_ALARM_T1_YELLOW_CLEAR:
+			case PKH_EVENT_SPAN_ALARM_T1_AIS_CLEAR:
+			case PKH_EVENT_SPAN_ALARM_E1_RED_CLEAR:
+			case PKH_EVENT_SPAN_ALARM_E1_RAI_CLEAR:
+			case PKH_EVENT_SPAN_ALARM_E1_AIS_CLEAR:
+			case PKH_EVENT_SPAN_ALARM_E1_RMAI_CLEAR:
+			case PKH_EVENT_SPAN_ALARM_E1_TS16AIS_CLEAR:
+			case PKH_EVENT_SPAN_ALARM_E1_TS16LOS_CLEAR:
+			case PKH_EVENT_SPAN_IN_SYNC:
+			case PKH_EVENT_SPAN_LOSS_OF_SIGNAL_CLEAR:
+			case PKH_EVENT_SPAN_IN_CRC_MF_SYNC:
+			case PKH_EVENT_SPAN_IN_CAS_MF_SYNC:
+				event_id = FTDM_OOB_ALARM_CLEAR;
+				break;
+			case PKH_EVENT_SPAN_MESSAGE:
+			case PKH_EVENT_SPAN_ABCD_SIGNAL_CHANGE:
+				break;
+			}
+
+			if (event_id) {
+				uint32_t x = 0;
+				ftdm_channel_t *ftdmchan;
+				pika_chan_data_t *chan_data;
+				for(x = 1; x <= span->chan_count; x++) {
+					ftdmchan = span->channels[x];
+					assert(ftdmchan != NULL);
+					chan_data = (pika_chan_data_t *) ftdmchan->mod_data;
+					assert(chan_data != NULL);
+					
+
+					ftdm_set_flag(ftdmchan, FTDM_CHANNEL_EVENT);
+					ftdmchan->last_event_time = last_event_time;
+					chan_data->last_oob_event = span_data->last_oob_event;
+				}
+
+			}
+
+		}
+		
+		PKH_EVENT_GetText(span_data->last_oob_event.id, event_text, sizeof(event_text));
+		//ftdm_log(FTDM_LOG_DEBUG, "Event: %s\n", event_text);
+		
+		if (ftdmchan) {
+			pika_chan_data_t *chan_data = (pika_chan_data_t *) ftdmchan->mod_data;
+
+			assert(chan_data != NULL);
+			ftdm_set_flag(ftdmchan, FTDM_CHANNEL_EVENT);
+            ftdmchan->last_event_time = ftdm_current_time_in_ms();
+			chan_data->last_oob_event = span_data->last_oob_event;
+		}
+
+		return FTDM_SUCCESS;
+	}
+
+	return FTDM_FAIL;
+}
+
+/**
+ * \brief Retrieves an event from a Pika span
+ * \param span Span to retrieve event from
+ * \param event FreeTDM event to return
+ * \return Success or failure
+ */
+static FIO_SPAN_NEXT_EVENT_FUNCTION(pika_next_event)
+{
+	uint32_t i, event_id = 0;
+	
+	for(i = 1; i <= span->chan_count; i++) {
+		if (ftdm_test_flag(span->channels[i], FTDM_CHANNEL_EVENT)) {
+			pika_chan_data_t *chan_data = (pika_chan_data_t *) span->channels[i]->mod_data;
+			PK_CHAR event_text[PKH_EVENT_MAX_NAME_LENGTH];
+			
+			ftdm_clear_flag(span->channels[i], FTDM_CHANNEL_EVENT);
+			
+			PKH_EVENT_GetText(chan_data->last_oob_event.id, event_text, sizeof(event_text));
+
+			switch(chan_data->last_oob_event.id) {
+			case PKH_EVENT_HDLC_MESSAGE:
+				chan_data->hdlc_bytes = chan_data->last_oob_event.p2;
+				continue;
+			case PKH_EVENT_TRUNK_HOOKFLASH:
+				event_id = FTDM_OOB_FLASH;
+				break;
+			case PKH_EVENT_TRUNK_RING_OFF:
+				event_id = FTDM_OOB_RING_STOP;
+				break;
+			case PKH_EVENT_TRUNK_RING_ON:
+				event_id = FTDM_OOB_RING_START;
+				break;
+
+			case PKH_EVENT_PHONE_OFFHOOK:
+				ftdm_set_flag_locked(span->channels[i], FTDM_CHANNEL_OFFHOOK);
+				event_id = FTDM_OOB_OFFHOOK;
+				break;
+
+			case PKH_EVENT_TRUNK_BELOW_THRESHOLD:
+			case PKH_EVENT_TRUNK_ABOVE_THRESHOLD:
+			case PKH_EVENT_PHONE_ONHOOK:
+				ftdm_clear_flag_locked(span->channels[i], FTDM_CHANNEL_OFFHOOK);
+				event_id = FTDM_OOB_ONHOOK;
+				break;
+
+
+
+			case PKH_EVENT_SPAN_ALARM_T1_RED:
+				ftdm_set_alarm_flag(span->channels[i], FTDM_ALARM_RED);
+				snprintf(span->channels[i]->last_error, sizeof(span->channels[i]->last_error), "RED ALARM");
+				event_id = FTDM_OOB_ALARM_TRAP;
+				break;
+			case PKH_EVENT_SPAN_ALARM_T1_YELLOW:
+				ftdm_set_alarm_flag(span->channels[i], FTDM_ALARM_YELLOW);
+				snprintf(span->channels[i]->last_error, sizeof(span->channels[i]->last_error), "YELLOW ALARM");
+				event_id = FTDM_OOB_ALARM_TRAP;
+				break;
+			case PKH_EVENT_SPAN_ALARM_T1_AIS:
+				ftdm_set_alarm_flag(span->channels[i], FTDM_ALARM_AIS);
+				snprintf(span->channels[i]->last_error, sizeof(span->channels[i]->last_error), "AIS ALARM");
+				event_id = FTDM_OOB_ALARM_TRAP;
+				break;
+			case PKH_EVENT_SPAN_ALARM_E1_RED:
+				ftdm_set_alarm_flag(span->channels[i], FTDM_ALARM_RED);
+				snprintf(span->channels[i]->last_error, sizeof(span->channels[i]->last_error), "RED ALARM");
+				event_id = FTDM_OOB_ALARM_TRAP;
+				break;
+			case PKH_EVENT_SPAN_ALARM_E1_RAI:
+				ftdm_set_alarm_flag(span->channels[i], FTDM_ALARM_RAI);
+				snprintf(span->channels[i]->last_error, sizeof(span->channels[i]->last_error), "RAI ALARM");
+				event_id = FTDM_OOB_ALARM_TRAP;
+				break;
+			case PKH_EVENT_SPAN_ALARM_E1_AIS:
+				ftdm_set_alarm_flag(span->channels[i], FTDM_ALARM_AIS);
+				snprintf(span->channels[i]->last_error, sizeof(span->channels[i]->last_error), "AIS ALARM");
+				event_id = FTDM_OOB_ALARM_TRAP;
+				break;
+			case PKH_EVENT_SPAN_ALARM_E1_RMAI:
+			case PKH_EVENT_SPAN_ALARM_E1_TS16AIS:
+			case PKH_EVENT_SPAN_ALARM_E1_TS16LOS:
+			case PKH_EVENT_SPAN_OUT_OF_SYNC:
+			case PKH_EVENT_SPAN_FRAMING_ERROR:
+			case PKH_EVENT_SPAN_LOSS_OF_SIGNAL:
+			case PKH_EVENT_SPAN_OUT_OF_CRC_MF_SYNC:
+			case PKH_EVENT_SPAN_OUT_OF_CAS_MF_SYNC:
+				ftdm_set_alarm_flag(span->channels[i], FTDM_ALARM_GENERAL);
+				snprintf(span->channels[i]->last_error, sizeof(span->channels[i]->last_error), "GENERAL ALARM");
+				event_id = FTDM_OOB_ALARM_TRAP;
+				break;
+			case PKH_EVENT_SPAN_ALARM_T1_RED_CLEAR:
+				ftdm_set_alarm_flag(span->channels[i], FTDM_ALARM_RED);
+			case PKH_EVENT_SPAN_ALARM_T1_YELLOW_CLEAR:
+				ftdm_set_alarm_flag(span->channels[i], FTDM_ALARM_YELLOW);
+			case PKH_EVENT_SPAN_ALARM_T1_AIS_CLEAR:
+				ftdm_set_alarm_flag(span->channels[i], FTDM_ALARM_AIS);
+			case PKH_EVENT_SPAN_ALARM_E1_RED_CLEAR:
+				ftdm_set_alarm_flag(span->channels[i], FTDM_ALARM_RED);
+			case PKH_EVENT_SPAN_ALARM_E1_RAI_CLEAR:
+				ftdm_set_alarm_flag(span->channels[i], FTDM_ALARM_RAI);
+			case PKH_EVENT_SPAN_ALARM_E1_AIS_CLEAR:
+				ftdm_set_alarm_flag(span->channels[i], FTDM_ALARM_AIS);
+			case PKH_EVENT_SPAN_ALARM_E1_RMAI_CLEAR:
+			case PKH_EVENT_SPAN_ALARM_E1_TS16AIS_CLEAR:
+			case PKH_EVENT_SPAN_ALARM_E1_TS16LOS_CLEAR:
+			case PKH_EVENT_SPAN_IN_SYNC:
+			case PKH_EVENT_SPAN_LOSS_OF_SIGNAL_CLEAR:
+			case PKH_EVENT_SPAN_IN_CRC_MF_SYNC:
+			case PKH_EVENT_SPAN_IN_CAS_MF_SYNC:
+				ftdm_clear_alarm_flag(span->channels[i], FTDM_ALARM_GENERAL);
+				event_id = FTDM_OOB_ALARM_CLEAR;
+				break;
+			case PKH_EVENT_SPAN_MESSAGE:
+			case PKH_EVENT_SPAN_ABCD_SIGNAL_CHANGE:
+				break;
+
+
+
+
+			case PKH_EVENT_TRUNK_ONHOOK:
+			case PKH_EVENT_TRUNK_OFFHOOK:				
+			case PKH_EVENT_TRUNK_DIALED :
+			case PKH_EVENT_TRUNK_REVERSAL:
+			case PKH_EVENT_TRUNK_LCSO:
+			case PKH_EVENT_TRUNK_DROPOUT:
+			case PKH_EVENT_TRUNK_LOF:
+			case PKH_EVENT_TRUNK_RX_OVERLOAD:
+			default:
+				ftdm_log(FTDM_LOG_DEBUG, "Unhandled event %d on channel %d [%s]\n", chan_data->last_oob_event.id, i, event_text);
+				event_id = FTDM_OOB_INVALID;
+				break;
+			}
+
+			span->channels[i]->last_event_time = 0;
+			span->event_header.e_type = FTDM_EVENT_OOB;
+			span->event_header.enum_id = event_id;
+			span->event_header.channel = span->channels[i];
+			*event = &span->event_header;
+			return FTDM_SUCCESS;
+		}
+	}
+
+	return FTDM_FAIL;
+}
+
+/**
+ * \brief Destroys a Pika Span
+ * \param span Span to destroy
+ * \return Success
+ */
+static FIO_SPAN_DESTROY_FUNCTION(pika_span_destroy)
+{
+	pika_span_data_t *span_data = (pika_span_data_t *) span->mod_data;
+	
+	if (span_data) {
+		PKH_QUEUE_Destroy(span_data->event_queue);
+		ftdm_safe_free(span_data);
+	}
+	
+	return FTDM_SUCCESS;
+}
+
+/**
+ * \brief Destroys a Pika Channel
+ * \param ftdmchan Channel to destroy
+ * \return Success or failure
+ */
+static FIO_CHANNEL_DESTROY_FUNCTION(pika_channel_destroy)
+{
+	pika_chan_data_t *chan_data = (pika_chan_data_t *) ftdmchan->mod_data;
+	pika_span_data_t *span_data = (pika_span_data_t *) ftdmchan->span->mod_data;
+	
+	if (!chan_data) {
+		return FTDM_FAIL;
+	}
+
+	if (!ftdm_test_flag(chan_data, PK_FLAG_READY)) {
+		goto end;
+	}
+
+	PKH_RECORD_Stop(chan_data->media_in);
+	PKH_PLAY_Stop(chan_data->media_out);
+	PKH_QUEUE_Destroy(chan_data->media_in_queue);
+	PKH_QUEUE_Destroy(chan_data->media_out_queue);
+	
+	switch(ftdmchan->type) {
+	case FTDM_CHAN_TYPE_FXS:
+		PKH_QUEUE_Detach(span_data->event_queue, chan_data->handle);
+		PKH_PHONE_Close(chan_data->handle);
+		break;
+	case FTDM_CHAN_TYPE_FXO:
+		PKH_QUEUE_Detach(span_data->event_queue, chan_data->handle);
+		PKH_TRUNK_Close(chan_data->handle);
+		break;
+	case FTDM_CHAN_TYPE_DQ921:
+		PKH_SPAN_Stop(span_data->handle);
+		break;
+	default:
+		break;
+	}
+
+
+	ftdm_mutex_destroy(&chan_data->digit_mutex);
+	ftdm_buffer_destroy(&chan_data->digit_buffer);
+
+ end:
+	ftdm_safe_free(chan_data);
+	
+	return FTDM_SUCCESS;
+}
+
+/**
+ * \brief Gets alarms from a Pika Channel (does nothing)
+ * \param ftdmchan Channel to get alarms from
+ * \return Failure
+ */
+static FIO_GET_ALARMS_FUNCTION(pika_get_alarms)
+{
+	return FTDM_FAIL;
+}
+
+static ftdm_io_interface_t pika_interface;
+
+/**
+ * \brief Loads Pika IO module
+ * \param fio FreeTDM IO interface
+ * \return Success or failure
+ */
+static FIO_IO_LOAD_FUNCTION(pika_init)
+{
+
+	PK_STATUS status;
+	PK_CHAR error_text[PKH_ERROR_MAX_NAME_LENGTH];
+	uint32_t i;
+	int ok = 0;
+	PKH_TLogMasks m;
+	TPikaHandle tmpHandle;
+
+	assert(fio != NULL);
+	memset(&pika_interface, 0, sizeof(pika_interface));
+	memset(&globals, 0, sizeof(globals));
+	globals.general_config.region = PKH_TRUNK_NA;
+
+	globals.profile_hash = create_hashtable(16, ftdm_hash_hashfromstring, ftdm_hash_equalkeys);
+
+	// Open the system object, to enumerate boards configured for this system
+	if ((status = PKH_SYSTEM_Open(&globals.system_handle)) != PK_SUCCESS) {
+		ftdm_log(FTDM_LOG_ERROR, "Error: PKH_SYSTEM_Open failed(%s)!\n",
+				PKH_ERROR_GetText(status, error_text, sizeof(error_text)));
+		return FTDM_FAIL;
+	}
+
+	// Retrieves a list of all boards in this system, existing,
+	// or listed in pika.cfg
+	if ((status = PKH_SYSTEM_Detect(globals.system_handle, &globals.board_list)) != PK_SUCCESS) {
+		ftdm_log(FTDM_LOG_ERROR, "Error: PKH_SYSTEM_Detect failed(%s)!\n",
+				PKH_ERROR_GetText(status, error_text, sizeof(error_text)));
+		return FTDM_FAIL;
+	}
+	
+	PKH_SYSTEM_GetConfig(globals.system_handle, &globals.system_config);
+	globals.system_config.maxAudioProcessBlockSize = PIKA_BLOCK_LEN;
+	globals.system_config.playBufferSize = PIKA_BLOCK_SIZE;
+	globals.system_config.recordBufferSize = PIKA_BLOCK_SIZE;
+	globals.system_config.recordNumberOfBuffers = PIKA_NUM_BUFFERS;
+	PKH_SYSTEM_SetConfig(globals.system_handle, &globals.system_config);
+
+	status = PKH_MEDIA_STREAM_Create(&tmpHandle);
+	status = PKH_RECORD_GetConfig(tmpHandle, &globals.record_config);
+	status = PKH_PLAY_GetConfig(tmpHandle, &globals.play_config);
+	status = PKH_EC_GetConfig(tmpHandle, &globals.ec_config);
+	status = PKH_MEDIA_STREAM_Destroy(tmpHandle);
+
+	
+
+	ftdm_log(FTDM_LOG_DEBUG, "Found %u board%s\n", globals.board_list.numberOfBoards, globals.board_list.numberOfBoards == 1 ? "" : "s");
+	for(i = 0; i < globals.board_list.numberOfBoards; ++i) {
+		ftdm_log(FTDM_LOG_INFO, "Found PIKA board type:[%s] id:[%u] serno:[%u]\n", 
+				pika_board_type_string(globals.board_list.board[i].type), globals.board_list.board[i].id, (uint32_t)
+				globals.board_list.board[i].serialNumber);
+
+		if (globals.board_list.board[i].type == PKH_BOARD_TYPE_DIGITAL_GATEWAY) {
+			TPikaHandle board_handle, span_handle;
+			PKH_TBoardConfig boardConfig;
+			PKH_BOARD_GetConfig(board_handle, &boardConfig);
+			PKH_BOARD_Open(globals.board_list.board[i].id, NULL, &board_handle);
+			PKH_SPAN_Open(board_handle, 0, NULL, &span_handle);
+			PKH_SPAN_GetConfig(span_handle, &globals.t1_span_config);
+			PKH_SPAN_Close(span_handle);
+			boardConfig.specific.DigitalGateway.interfaceType = PKH_BOARD_INTERFACE_TYPE_E1;
+			PKH_BOARD_SetConfig(board_handle, &boardConfig);
+			PKH_SPAN_Open(board_handle, 0, NULL, &span_handle);
+			PKH_SPAN_GetConfig(span_handle, &globals.e1_span_config);
+			PKH_SPAN_Close(span_handle);
+			boardConfig.specific.DigitalGateway.interfaceType = PKH_BOARD_INTERFACE_TYPE_T1;
+			PKH_BOARD_SetConfig(board_handle, &boardConfig);
+			PKH_BOARD_Close(board_handle);
+		}
+		ok++;
+
+	}
+
+	if (!ok) {
+		return FTDM_FAIL;
+	}
+	
+	pika_interface.name = "pika";
+	pika_interface.configure =  pika_configure;
+	pika_interface.configure_span = pika_configure_span;
+	pika_interface.open = pika_open;
+	pika_interface.close = pika_close;
+	pika_interface.wait = pika_wait;
+	pika_interface.read = pika_read;
+	pika_interface.write = pika_write;
+	pika_interface.command = pika_command;
+	pika_interface.poll_event = pika_poll_event;
+	pika_interface.next_event = pika_next_event;
+	pika_interface.channel_destroy = pika_channel_destroy;
+	pika_interface.span_destroy = pika_span_destroy;
+	pika_interface.get_alarms = pika_get_alarms;
+	*fio = &pika_interface;
+
+
+	ftdm_log(FTDM_LOG_INFO, "Dumping Default configs:\n");
+	ftdm_log(FTDM_LOG_INFO, "rx-gain => %0.2f\n", (float)globals.record_config.gain);
+	ftdm_log(FTDM_LOG_INFO, "rx-agc-enabled => %s\n", globals.record_config.AGC.enabled ? "true" : "false");
+	ftdm_log(FTDM_LOG_INFO, "rx-agc-targetPower => %0.2f\n", (float)globals.record_config.AGC.targetPower);
+	ftdm_log(FTDM_LOG_INFO, "rx-agc-minGain => %0.2f\n", (float)globals.record_config.AGC.minGain);
+	ftdm_log(FTDM_LOG_INFO, "rx-agc-maxGain => %0.2f\n", (float)globals.record_config.AGC.maxGain);
+	ftdm_log(FTDM_LOG_INFO, "rx-agc-attackRate => %d\n", (int)globals.record_config.AGC.attackRate);
+	ftdm_log(FTDM_LOG_INFO, "rx-agc-decayRate => %d\n", (int)globals.record_config.AGC.decayRate);
+	ftdm_log(FTDM_LOG_INFO, "rx-agc-speechThreshold => %0.2f\n", (float)globals.record_config.AGC.speechThreshold);
+	ftdm_log(FTDM_LOG_INFO, "rx-vad-enabled => %s\n", globals.record_config.VAD.enabled ? "true" : "false");
+	ftdm_log(FTDM_LOG_INFO, "rx-vad-activationThreshold => %0.2f\n", (float)globals.record_config.VAD.activationThreshold);
+	ftdm_log(FTDM_LOG_INFO, "rx-vad-activationDebounceTime => %d\n", (int)globals.record_config.VAD.activationDebounceTime);
+	ftdm_log(FTDM_LOG_INFO, "rx-vad-deactivationThreshold => %0.2f\n", (float)globals.record_config.VAD.deactivationThreshold);
+	ftdm_log(FTDM_LOG_INFO, "rx-vad-deactivationDebounceTime => %d\n", (int)globals.record_config.VAD.deactivationDebounceTime);
+	ftdm_log(FTDM_LOG_INFO, "rx-vad-preSpeechBufferSize => %d\n", (int)globals.record_config.VAD.preSpeechBufferSize);
+	ftdm_log(FTDM_LOG_INFO, "tx-gain => %0.2f\n", (float)globals.play_config.gain);
+	ftdm_log(FTDM_LOG_INFO, "tx-agc-enabled => %s\n", globals.play_config.AGC.enabled ? "true" : "false");
+	ftdm_log(FTDM_LOG_INFO, "tx-agc-targetPower => %0.2f\n", (float)globals.play_config.AGC.targetPower);
+	ftdm_log(FTDM_LOG_INFO, "tx-agc-minGain => %0.2f\n", (float)globals.play_config.AGC.minGain);
+	ftdm_log(FTDM_LOG_INFO, "tx-agc-maxGain => %0.2f\n", (float)globals.play_config.AGC.maxGain);
+	ftdm_log(FTDM_LOG_INFO, "tx-agc-attackRate => %d\n", (int)globals.play_config.AGC.attackRate);
+	ftdm_log(FTDM_LOG_INFO, "tx-agc-decayRate => %d\n", (int)globals.play_config.AGC.decayRate);
+	ftdm_log(FTDM_LOG_INFO, "tx-agc-speechThreshold => %0.2f\n", (float)globals.play_config.AGC.speechThreshold);
+	ftdm_log(FTDM_LOG_INFO, "ec-doubleTalkerThreshold => %0.2f\n", (float)globals.ec_config.doubleTalkerThreshold);
+	ftdm_log(FTDM_LOG_INFO, "ec-speechPresentThreshold => %0.2f\n", (float)globals.ec_config.speechPresentThreshold);
+	ftdm_log(FTDM_LOG_INFO, "ec-echoSuppressionThreshold => %0.2f\n", (float)globals.ec_config.echoSuppressionThreshold);
+	ftdm_log(FTDM_LOG_INFO, "ec-echoSuppressionEnabled => %s\n", globals.ec_config.echoSuppressionEnabled ? "true" : "false");
+	ftdm_log(FTDM_LOG_INFO, "ec-comfortNoiseEnabled => %s\n", globals.ec_config.comfortNoiseEnabled ? "true" : "false");
+	ftdm_log(FTDM_LOG_INFO, "ec-adaptationModeEnabled => %s\n", globals.ec_config.adaptationModeEnabled ? "true" : "false");
+
+	
+
+	memset(&m, 0, sizeof(m));
+	//m.apiMask = 0xffffffff;
+	//PKH_LOG_SetMasks(&m);
+
+	return FTDM_SUCCESS;
+}
+
+/**
+ * \brief Unloads Pika IO module
+ * \return Success
+ */
+static FIO_IO_UNLOAD_FUNCTION(pika_destroy)
+{
+	uint32_t x;
+	PK_STATUS status;
+	PK_CHAR error_text[PKH_ERROR_MAX_NAME_LENGTH];
+
+	for (x = 0; x < MAX_NUMBER_OF_TRUNKS; x++) {
+		if (globals.open_boards[x]) {
+			ftdm_log(FTDM_LOG_INFO, "Closing board %u\n", x);
+			PKH_BOARD_Close(globals.open_boards[x]);
+		}
+	}
+
+	// The system can now be closed.
+	if ((status = PKH_SYSTEM_Close(globals.system_handle)) != PK_SUCCESS) {
+		ftdm_log(FTDM_LOG_ERROR, "Error: PKH_SYSTEM_Close failed(%s)!\n",
+				PKH_ERROR_GetText(status, error_text, sizeof(error_text)));
+	} else {
+		ftdm_log(FTDM_LOG_INFO, "Closing system handle\n");
+	}
+
+	hashtable_destroy(globals.profile_hash);
+
+	return FTDM_SUCCESS;
+}
+
+/**
+ * \brief Pika IO module definition
+ */
+EX_DECLARE_DATA ftdm_module_t ftdm_module = { 
+	"pika",
+	pika_init,
+	pika_destroy,
+};
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
+

Added: freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_pika/ozmod_pika.2005.vcproj (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_pika/ozmod_pika.2005.vcproj	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_pika/ozmod_pika.2005.vcproj	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,197 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="8.00"
+	Name="ftmod_pika"
+	ProjectGUID="{E886B4D5-AB4F-4092-B8F4-3B06E1E462EF}"
+	RootNamespace="ftmod_pika"
+	Keyword="Win32Proj"
+	TargetFrameworkVersion="196613"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="2"
+			CharacterSet="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				AdditionalIncludeDirectories="..\..\isdn\include;..\..\include;..\..\..\pika\aoh\inc"
+				PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;FTMOD_PIKA_EXPORTS"
+				MinimalRebuild="true"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="3"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				DebugInformationFormat="4"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="pikahmpapi.lib"
+				LinkIncremental="2"
+				AdditionalLibraryDirectories="..\..\..\pika\aoh\lib"
+				GenerateDebugInformation="true"
+				SubSystem="2"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="2"
+			CharacterSet="1"
+			WholeProgramOptimization="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="2"
+				EnableIntrinsicFunctions="true"
+				AdditionalIncludeDirectories="..\..\isdn\include;..\..\include;..\..\..\pika\aoh\inc"
+				PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;FTMOD_PIKA_EXPORTS"
+				RuntimeLibrary="2"
+				EnableFunctionLevelLinking="true"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				DebugInformationFormat="3"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="pikahmpapi.lib"
+				LinkIncremental="1"
+				AdditionalLibraryDirectories="..\..\..\pika\aoh\lib"
+				GenerateDebugInformation="true"
+				SubSystem="2"
+				OptimizeReferences="2"
+				EnableCOMDATFolding="2"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<Filter
+			Name="Source Files"
+			Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+			>
+			<File
+				RelativePath=".\ftmod_pika.c"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="Header Files"
+			Filter="h;hpp;hxx;hm;inl;inc;xsd"
+			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+			>
+			<File
+				RelativePath=".\ftdm_pika.h"
+				>
+			</File>
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>

Added: freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,1363 @@
+/*
+ * Copyright (c) 2009, Moises Silva <moy@sangoma.com>
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <openr2.h>
+#include "freetdm.h"
+
+/* debug thread count for r2 legs */
+static ftdm_mutex_t* g_thread_count_mutex;
+static int32_t g_thread_count = 0;
+
+/* when the users kills a span we clear this flag to kill the signaling thread */
+/* FIXME: what about the calls that are already up-and-running? */
+typedef enum {
+	FTDM_R2_RUNNING = (1 << 0),
+} ftdm_r2_flag_t;
+
+/* private call information stored in ftdmchan->call_data void* ptr */
+#define R2CALL(ftdmchan) ((ftdm_r2_call_t*)((ftdmchan)->call_data))
+typedef struct ftdm_r2_call_t {
+    openr2_chan_t *r2chan;
+	int accepted:1;
+	int answer_pending:1;
+	int state_ack_pending:1;
+	int disconnect_rcvd:1;
+	int ftdm_started:1;
+	ftdm_channel_state_t chanstate;
+	ftdm_size_t dnis_index;
+	ftdm_size_t ani_index;
+	char name[10];
+} ftdm_r2_call_t;
+
+/* this is just used as place holder in the stack when configuring the span to avoid using bunch of locals */
+typedef struct ft_r2_conf_s {
+	/* openr2 types */
+	openr2_variant_t variant;
+	openr2_calling_party_category_t category;
+	openr2_log_level_t loglevel;
+
+	/* strings */
+	char *logdir;
+	char *advanced_protocol_file;
+
+	/* ints */
+	int32_t max_ani;
+	int32_t max_dnis;
+	int32_t mfback_timeout; 
+	int32_t metering_pulse_timeout;
+
+	/* booleans */
+	int immediate_accept;
+	int skip_category;
+	int get_ani_first;
+	int call_files;
+	int double_answer;
+	int charge_calls;
+	int forced_release;
+	int allow_collect_calls;
+} ft_r2_conf_t;
+
+/* r2 configuration stored in span->signal_data */
+typedef struct ftdm_r2_data_s {
+	/* span flags */
+	ftdm_r2_flag_t flags;
+	/* openr2 handle for the R2 variant context */
+	openr2_context_t *r2context;
+	/* category to use when making calls */
+	openr2_calling_party_category_t category;
+	/* whether to use OR2_CALL_WITH_CHARGE or OR2_CALL_NO_CHARGE when accepting a call */
+	int charge_calls:1;
+	/* allow or reject collect calls */
+	int allow_collect_calls:1;
+	/* whether to use forced release when hanging up */
+	int forced_release:1;
+	/* whether accept the call when offered, or wait until the user decides to accept */
+	int accept_on_offer:1;
+} ftdm_r2_data_t;
+
+/* one element per span will be stored in g_mod_data_hash global var to keep track of them
+   and destroy them on module unload */
+typedef struct ftdm_r2_span_pvt_s {
+	openr2_context_t *r2context; /* r2 context allocated for this span */
+	ftdm_hash_t *r2calls; /* hash table of allocated call data per channel for this span */
+} ftdm_r2_span_pvt_t;
+
+/* span monitor thread */
+static void *ftdm_r2_run(ftdm_thread_t *me, void *obj);
+
+/* channel monitor thread */
+static void *ftdm_r2_channel_run(ftdm_thread_t *me, void *obj);
+
+/* hash of all the private span allocations
+   we need to keep track of them to destroy them when unloading the module 
+   since freetdm does not notify signaling modules when destroying a span
+   span -> ftdm_r2_mod_allocs_t */
+static ftdm_hash_t *g_mod_data_hash;
+
+/* IO interface for the command API */
+static ftdm_io_interface_t g_ftdm_r2_interface;
+
+static void ft_r2_clean_call(ftdm_r2_call_t *call)
+{
+    openr2_chan_t *r2chan = call->r2chan;
+    memset(call, 0, sizeof(*call));
+    call->r2chan = r2chan;
+}
+
+static void ft_r2_accept_call(ftdm_channel_t *ftdmchan)
+{
+	openr2_chan_t *r2chan = R2CALL(ftdmchan)->r2chan;
+	// FIXME: not always accept as no charge, let the user decide that
+	// also we should check the return code from openr2_chan_accept_call and handle error condition
+	// hanging up the call with protocol error as the reason, this openr2 API will fail only when there something
+	// wrong at the I/O layer or the library itself
+	openr2_chan_accept_call(r2chan, OR2_CALL_NO_CHARGE);
+	R2CALL(ftdmchan)->accepted = 1;
+}
+
+static void ft_r2_answer_call(ftdm_channel_t *ftdmchan)
+{
+	openr2_chan_t *r2chan = R2CALL(ftdmchan)->r2chan;
+	// FIXME
+	// 1. check openr2_chan_answer_call return code
+	// 2. The openr2_chan_answer_call_with_mode should be used depending on user settings
+	// openr2_chan_answer_call_with_mode(r2chan, OR2_ANSWER_SIMPLE);
+	openr2_chan_answer_call(r2chan);
+	R2CALL(ftdmchan)->answer_pending = 0;
+}
+
+static FIO_CHANNEL_OUTGOING_CALL_FUNCTION(r2_outgoing_call)
+{
+	ftdm_status_t status;
+	ftdm_mutex_lock(ftdmchan->mutex);
+
+	/* the channel may be down but the thread not quite done */
+	ftdm_wait_for_flag_cleared(ftdmchan, FTDM_CHANNEL_INTHREAD, 200);
+
+	if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_INTHREAD)) {
+		ftdm_log(FTDM_LOG_ERROR, "%d:%d Yay! R2 outgoing call in channel that is already in thread.\n", 
+				ftdmchan->span_id, ftdmchan->chan_id);
+		ftdm_mutex_unlock(ftdmchan->mutex);
+		return FTDM_FAIL;
+	}
+
+	ft_r2_clean_call(ftdmchan->call_data);
+	R2CALL(ftdmchan)->chanstate = FTDM_CHANNEL_STATE_DOWN;
+	ftdm_channel_set_state(ftdmchan, FTDM_CHANNEL_STATE_DIALING, 0);
+	ftdm_set_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND);
+	R2CALL(ftdmchan)->ftdm_started = 1;
+	ftdm_mutex_unlock(ftdmchan->mutex);
+
+	status = ftdm_thread_create_detached(ftdm_r2_channel_run, ftdmchan);
+	if (status == FTDM_FAIL) {
+		ftdm_log(FTDM_LOG_ERROR, "%d:%d Cannot handle request to start call in channel, failed to create thread!\n", 
+				ftdmchan->span_id, ftdmchan->chan_id);
+		ftdm_channel_done(ftdmchan);
+		return FTDM_FAIL;
+	}
+
+	return FTDM_SUCCESS;
+}
+
+static ftdm_status_t ftdm_r2_start(ftdm_span_t *span)
+{
+	ftdm_r2_data_t *r2_data = span->signal_data;
+	ftdm_set_flag(r2_data, FTDM_R2_RUNNING);
+	return ftdm_thread_create_detached(ftdm_r2_run, span);
+}
+
+/* always called from the monitor thread */
+static void ftdm_r2_on_call_init(openr2_chan_t *r2chan)
+{
+	ftdm_channel_t *ftdmchan = openr2_chan_get_client_data(r2chan);
+	ftdm_status_t status;
+	ftdm_log(FTDM_LOG_NOTICE, "Received request to start call on chan %d\n", openr2_chan_get_number(r2chan));
+
+	ftdm_mutex_lock(ftdmchan->mutex);
+
+	if (ftdmchan->state != FTDM_CHANNEL_STATE_DOWN) {
+		ftdm_log(FTDM_LOG_ERROR, "Cannot handle request to start call in channel %d, invalid state (%d)\n", 
+				openr2_chan_get_number(r2chan), ftdmchan->state);
+		ftdm_mutex_unlock(ftdmchan->mutex);
+		return;
+	}
+
+	/* the channel may be down but the thread not quite done */
+	ftdm_wait_for_flag_cleared(ftdmchan, FTDM_CHANNEL_INTHREAD, 200);
+
+	if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_INTHREAD)) {
+		ftdm_log(FTDM_LOG_ERROR, "Cannot handle request to start call in channel %d, already in thread!\n", 
+				openr2_chan_get_number(r2chan));
+		ftdm_mutex_unlock(ftdmchan->mutex);
+		return;
+	}
+	ft_r2_clean_call(ftdmchan->call_data);
+	R2CALL(ftdmchan)->chanstate = FTDM_CHANNEL_STATE_DOWN;
+	ftdm_channel_set_state(ftdmchan, FTDM_CHANNEL_STATE_COLLECT, 0);
+	ftdm_mutex_unlock(ftdmchan->mutex);
+
+	status = ftdm_thread_create_detached(ftdm_r2_channel_run, ftdmchan);
+	if (status == FTDM_FAIL) {
+		ftdm_log(FTDM_LOG_ERROR, "Cannot handle request to start call in channel %d, failed to create thread!\n", 
+				openr2_chan_get_number(r2chan));
+	}
+}
+
+/* only called for incoming calls when the ANI, DNIS etc is complete and the user has to decide either to accept or reject the call */
+static void ftdm_r2_on_call_offered(openr2_chan_t *r2chan, const char *ani, const char *dnis, openr2_calling_party_category_t category)
+{
+	ftdm_sigmsg_t sigev;
+	ftdm_channel_t *ftdmchan = openr2_chan_get_client_data(r2chan);
+
+	ftdm_log(FTDM_LOG_NOTICE, "Call offered on chan %d, ANI = %s, DNIS = %s, Category = %s\n", openr2_chan_get_number(r2chan), 
+			ani, dnis, openr2_proto_get_category_string(category));
+
+	/* notify the user about the new call */
+	memset(&sigev, 0, sizeof(sigev));
+	sigev.chan_id = ftdmchan->chan_id;
+	sigev.span_id = ftdmchan->span_id;
+	sigev.channel = ftdmchan;
+	sigev.event_id = FTDM_SIGEVENT_START;
+
+	if (ftdm_span_send_signal(ftdmchan->span, &sigev) != FTDM_SUCCESS) {
+		ftdm_log(FTDM_LOG_NOTICE, "Failed to handle call offered on chan %d\n", openr2_chan_get_number(r2chan));
+		openr2_chan_disconnect_call(r2chan, OR2_CAUSE_OUT_OF_ORDER);
+		ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_CANCEL);
+		return; 
+	}
+	ftdm_channel_use(ftdmchan);
+	R2CALL(ftdmchan)->ftdm_started = 1; 
+}
+
+static void ftdm_r2_on_call_accepted(openr2_chan_t *r2chan, openr2_call_mode_t mode)
+{
+	ftdm_channel_t *ftdmchan = openr2_chan_get_client_data(r2chan);
+	ftdm_log(FTDM_LOG_NOTICE, "Call accepted on chan %d\n", openr2_chan_get_number(r2chan));
+	/* at this point the MF signaling has ended and there is no point on keep reading */
+	openr2_chan_disable_read(r2chan);
+	if (OR2_DIR_BACKWARD == openr2_chan_get_direction(r2chan)) {
+		R2CALL(ftdmchan)->state_ack_pending = 1;
+		if (R2CALL(ftdmchan)->answer_pending) {
+			ftdm_log(FTDM_LOG_DEBUG, "Answer was pending on chan %d, answering now.\n", openr2_chan_get_number(r2chan));
+			ft_r2_answer_call(ftdmchan);
+			return;
+		}
+	} else {
+		ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_PROGRESS);
+	}
+}
+
+static void ftdm_r2_on_call_answered(openr2_chan_t *r2chan)
+{
+	ftdm_channel_t *ftdmchan = openr2_chan_get_client_data(r2chan);
+	ftdm_log(FTDM_LOG_NOTICE, "Call answered on chan %d\n", openr2_chan_get_number(r2chan));
+	/* notify the upper layer of progress in the outbound call */
+	if (OR2_DIR_FORWARD == openr2_chan_get_direction(r2chan)) {
+		ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_UP);
+	}
+}
+
+/* may be called in the signaling or media thread depending on whether the hangup is product of MF or CAS signaling */
+static void ftdm_r2_on_call_disconnect(openr2_chan_t *r2chan, openr2_call_disconnect_cause_t cause)
+{
+	ftdm_sigmsg_t sigev;
+	ftdm_r2_data_t *r2data;
+	ftdm_channel_t *ftdmchan = openr2_chan_get_client_data(r2chan);
+	ftdm_log(FTDM_LOG_NOTICE, "Call disconnected on chan %d\n", openr2_chan_get_number(r2chan));
+
+	ftdm_log(FTDM_LOG_DEBUG, "Got openr2 disconnection, clearing call on channel %d\n", ftdmchan->physical_chan_id);
+
+	R2CALL(ftdmchan)->disconnect_rcvd = 1;
+
+	/* acknowledge the hangup, cause will be ignored. From here to -> HANGUP once the freetdm side hangs up as well */
+	openr2_chan_disconnect_call(r2chan, OR2_CAUSE_NORMAL_CLEARING);
+
+	/* if the call has not been started yet we must go to HANGUP right here */ 
+	if (!R2CALL(ftdmchan)->ftdm_started) {
+		ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP);
+		return;
+	}
+
+	/* FIXME: use the cause received from openr2 and map it to ftdm cause  */
+	ftdmchan->caller_data.hangup_cause  = FTDM_CAUSE_NORMAL_CLEARING; 
+
+	/* notify the user of the call terminating */
+	memset(&sigev, 0, sizeof(sigev));
+	sigev.chan_id = ftdmchan->chan_id;
+	sigev.span_id = ftdmchan->span_id;
+	sigev.channel = ftdmchan;
+	sigev.event_id = FTDM_SIGEVENT_STOP;
+	r2data = ftdmchan->span->signal_data;
+
+	ftdm_span_send_signal(ftdmchan->span, &sigev);
+}
+
+static void ftdm_r2_on_call_end(openr2_chan_t *r2chan)
+{
+	ftdm_channel_t *ftdmchan = openr2_chan_get_client_data(r2chan);
+	ftdm_log(FTDM_LOG_NOTICE, "Call finished on chan %d\n", openr2_chan_get_number(r2chan));
+	/* this means the freetdm side disconnected the call, therefore we must move to DOWN here */
+	if (!R2CALL(ftdmchan)->disconnect_rcvd) {
+		ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
+		return;
+	}
+}
+
+static void ftdm_r2_on_call_read(openr2_chan_t *r2chan, const unsigned char *buf, int buflen)
+{
+	ftdm_log(FTDM_LOG_NOTICE, "Call read data on chan %d\n", openr2_chan_get_number(r2chan));
+}
+
+static void ftdm_r2_on_hardware_alarm(openr2_chan_t *r2chan, int alarm)
+{
+	ftdm_log(FTDM_LOG_NOTICE, "Alarm on chan %d (%d)\n", openr2_chan_get_number(r2chan), alarm);
+}
+
+static void ftdm_r2_on_os_error(openr2_chan_t *r2chan, int errorcode)
+{
+	ftdm_log(FTDM_LOG_ERROR, "OS error on chan %d: %s\n", openr2_chan_get_number(r2chan), strerror(errorcode));
+}
+
+static void ftdm_r2_on_protocol_error(openr2_chan_t *r2chan, openr2_protocol_error_t reason)
+{
+	ftdm_sigmsg_t sigev;
+	ftdm_r2_data_t *r2data;
+	ftdm_channel_t *ftdmchan = openr2_chan_get_client_data(r2chan);
+
+	ftdm_log(FTDM_LOG_ERROR, "Protocol error on chan %d\n", openr2_chan_get_number(r2chan));
+
+	R2CALL(ftdmchan)->disconnect_rcvd = 1;
+
+	if (!R2CALL(ftdmchan)->ftdm_started) {
+		ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP);
+		return;
+	}
+
+	ftdmchan->caller_data.hangup_cause  = FTDM_CAUSE_PROTOCOL_ERROR; 
+
+	/* notify the user of the call terminating */
+	memset(&sigev, 0, sizeof(sigev));
+	sigev.chan_id = ftdmchan->chan_id;
+	sigev.span_id = ftdmchan->span_id;
+	sigev.channel = ftdmchan;
+	sigev.event_id = FTDM_SIGEVENT_STOP;
+	r2data = ftdmchan->span->signal_data;
+
+	ftdm_span_send_signal(ftdmchan->span, &sigev);
+}
+
+static void ftdm_r2_on_line_blocked(openr2_chan_t *r2chan)
+{
+	ftdm_log(FTDM_LOG_NOTICE, "Far end blocked on chan %d\n", openr2_chan_get_number(r2chan));
+}
+
+static void ftdm_r2_on_line_idle(openr2_chan_t *r2chan)
+{
+	ftdm_log(FTDM_LOG_NOTICE, "Far end unblocked on chan %d\n", openr2_chan_get_number(r2chan));
+}
+
+static void ftdm_r2_write_log(openr2_log_level_t level, const char *message)
+{
+	switch (level) {
+		case OR2_LOG_NOTICE:
+			ftdm_log(FTDM_LOG_NOTICE, "%s", message);
+			break;
+		case OR2_LOG_WARNING:
+			ftdm_log(FTDM_LOG_WARNING, "%s", message);
+			break;
+		case OR2_LOG_ERROR:
+			ftdm_log(FTDM_LOG_ERROR, "%s", message);
+			break;
+		case OR2_LOG_STACK_TRACE:
+		case OR2_LOG_MF_TRACE:
+		case OR2_LOG_CAS_TRACE:
+		case OR2_LOG_DEBUG:
+		case OR2_LOG_EX_DEBUG:
+			ftdm_log(FTDM_LOG_DEBUG, "%s", message);
+			break;
+		default:
+			ftdm_log(FTDM_LOG_WARNING, "We should handle logging level %d here.\n", level);
+			ftdm_log(FTDM_LOG_DEBUG, "%s", message);
+			break;
+	}
+}
+
+static void ftdm_r2_on_context_log(openr2_context_t *r2context, openr2_log_level_t level, const char *fmt, va_list ap)
+{
+#define CONTEXT_TAG "Context -"
+	char logmsg[256];
+	char completemsg[sizeof(logmsg) + sizeof(CONTEXT_TAG) - 1];
+	vsnprintf(logmsg, sizeof(logmsg), fmt, ap);
+	snprintf(completemsg, sizeof(completemsg), CONTEXT_TAG "%s", logmsg);
+	ftdm_r2_write_log(level, completemsg);
+#undef CONTEXT_TAG
+}
+
+static void ftdm_r2_on_chan_log(openr2_chan_t *r2chan, openr2_log_level_t level, const char *fmt, va_list ap)
+{
+#define CHAN_TAG "Chan "
+	char logmsg[256];
+	char completemsg[sizeof(logmsg) + sizeof(CHAN_TAG) - 1];
+	vsnprintf(logmsg, sizeof(logmsg), fmt, ap);
+	snprintf(completemsg, sizeof(completemsg), CHAN_TAG "%d: %s", openr2_chan_get_number(r2chan), logmsg);
+	ftdm_r2_write_log(level, completemsg);
+#undef CHAN_TAG
+}
+
+static int ftdm_r2_on_dnis_digit_received(openr2_chan_t *r2chan, char digit)
+{
+	ftdm_sigmsg_t sigev;
+	ftdm_r2_data_t *r2data;
+	ftdm_channel_t *ftdmchan = openr2_chan_get_client_data(r2chan);
+	ftdm_size_t collected_len = R2CALL(ftdmchan)->dnis_index;
+
+	ftdm_log(FTDM_LOG_DEBUG, "DNIS digit %d received chan %d\n", digit, openr2_chan_get_number(r2chan));
+
+	/* save the digit we just received */ 
+	ftdmchan->caller_data.dnis.digits[collected_len] = digit;
+	collected_len++;
+	ftdmchan->caller_data.dnis.digits[collected_len] = '\0';
+	R2CALL(ftdmchan)->dnis_index = collected_len;
+
+	/* notify the user about the new digit and check if we should stop requesting more DNIS */
+	memset(&sigev, 0, sizeof(sigev));
+	sigev.chan_id = ftdmchan->chan_id;
+	sigev.span_id = ftdmchan->span_id;
+	sigev.channel = ftdmchan;
+	sigev.event_id = FTDM_SIGEVENT_COLLECTED_DIGIT;
+	r2data = ftdmchan->span->signal_data;
+	if (ftdm_span_send_signal(ftdmchan->span, &sigev) == FTDM_BREAK) {
+		ftdm_log(FTDM_LOG_NOTICE, "Requested to stop getting DNIS. Current DNIS = %s on chan %d\n", ftdmchan->caller_data.dnis.digits, openr2_chan_get_number(r2chan));
+		return OR2_STOP_DNIS_REQUEST; 
+	}
+
+	/* the only other reason to stop requesting DNIS is that there is no more room to save it */
+	if (collected_len == (sizeof(ftdmchan->caller_data.dnis.digits) - 1)) {
+		ftdm_log(FTDM_LOG_NOTICE, "No more room for DNIS. Current DNIS = %s on chan %d\n", ftdmchan->caller_data.dnis.digits, openr2_chan_get_number(r2chan));
+		return OR2_STOP_DNIS_REQUEST;
+	}
+
+	return OR2_CONTINUE_DNIS_REQUEST; 
+}
+
+static void ftdm_r2_on_ani_digit_received(openr2_chan_t *r2chan, char digit)
+{
+	ftdm_channel_t *ftdmchan = openr2_chan_get_client_data(r2chan);
+	ftdm_size_t collected_len = R2CALL(ftdmchan)->ani_index;
+
+	/* check if we should drop ANI */
+	if (collected_len == (sizeof(ftdmchan->caller_data.ani.digits) - 1)) {
+		ftdm_log(FTDM_LOG_NOTICE, "No more room for ANI %c on chan %d, digit dropped.\n", digit, openr2_chan_get_number(r2chan));
+		return;
+	}
+	ftdm_log(FTDM_LOG_DEBUG, "ANI digit %c received chan %d\n", digit, openr2_chan_get_number(r2chan));
+
+	/* save the digit we just received */ 
+	ftdmchan->caller_data.ani.digits[collected_len++] = digit;
+	ftdmchan->caller_data.ani.digits[collected_len] = '\0';
+}
+
+static openr2_event_interface_t ftdm_r2_event_iface = {
+	.on_call_init = ftdm_r2_on_call_init,
+	.on_call_offered = ftdm_r2_on_call_offered,
+	.on_call_accepted = ftdm_r2_on_call_accepted,
+	.on_call_answered = ftdm_r2_on_call_answered,
+	.on_call_disconnect = ftdm_r2_on_call_disconnect,
+	.on_call_end = ftdm_r2_on_call_end,
+	.on_call_read = ftdm_r2_on_call_read,
+	.on_hardware_alarm = ftdm_r2_on_hardware_alarm,
+	.on_os_error = ftdm_r2_on_os_error,
+	.on_protocol_error = ftdm_r2_on_protocol_error,
+	.on_line_blocked = ftdm_r2_on_line_blocked,
+	.on_line_idle = ftdm_r2_on_line_idle,
+	/* cast seems to be needed to get rid of the annoying warning regarding format attribute  */
+	.on_context_log = (openr2_handle_context_logging_func)ftdm_r2_on_context_log,
+	.on_dnis_digit_received = ftdm_r2_on_dnis_digit_received,
+	.on_ani_digit_received = ftdm_r2_on_ani_digit_received,
+	/* so far we do nothing with billing pulses */
+	.on_billing_pulse_received = NULL
+};
+
+static int ftdm_r2_io_set_cas(openr2_chan_t *r2chan, int cas)
+{
+	ftdm_channel_t *ftdm_chan = openr2_chan_get_fd(r2chan);
+	ftdm_status_t status = ftdm_channel_command(ftdm_chan, FTDM_COMMAND_SET_CAS_BITS, &cas);
+	if (FTDM_FAIL == status) {
+		return -1;
+	}
+	return 0;
+}
+
+static int ftdm_r2_io_get_cas(openr2_chan_t *r2chan, int *cas)
+{
+	ftdm_channel_t *ftdm_chan = openr2_chan_get_fd(r2chan);
+	ftdm_status_t status = ftdm_channel_command(ftdm_chan, FTDM_COMMAND_GET_CAS_BITS, cas);
+	if (FTDM_FAIL == status) {
+		return -1;
+	}
+	return 0;
+}
+
+static int ftdm_r2_io_flush_write_buffers(openr2_chan_t *r2chan)
+{
+	ftdm_channel_t *ftdm_chan = openr2_chan_get_fd(r2chan);
+	ftdm_status_t status = ftdm_channel_command(ftdm_chan, FTDM_COMMAND_FLUSH_TX_BUFFERS, NULL);
+	if (FTDM_FAIL == status) {
+		return -1;
+	}
+	return 0;
+}
+
+static int ftdm_r2_io_write(openr2_chan_t *r2chan, const void *buf, int size)
+{
+	ftdm_channel_t *ftdm_chan = openr2_chan_get_fd(r2chan);
+	ftdm_size_t outsize = size;
+	ftdm_status_t status = ftdm_channel_write(ftdm_chan, (void *)buf, size, &outsize);
+	if (FTDM_FAIL == status) {
+		return -1;
+	}
+	return outsize;
+}
+
+static int ftdm_r2_io_read(openr2_chan_t *r2chan, const void *buf, int size)
+{
+	ftdm_channel_t *ftdm_chan = openr2_chan_get_fd(r2chan);
+	ftdm_size_t outsize = size;
+	ftdm_status_t status = ftdm_channel_read(ftdm_chan, (void *)buf, &outsize);
+	if (FTDM_FAIL == status) {
+		return -1;
+	}
+	return outsize;
+}
+
+static int ftdm_r2_io_wait(openr2_chan_t *r2chan, int *flags, int block)
+{
+	ftdm_status_t status;
+	ftdm_wait_flag_t ftdmflags = 0;
+
+	ftdm_channel_t *ftdm_chan = openr2_chan_get_fd(r2chan);
+	int32_t timeout = block ? -1 : 0;
+
+	if (*flags & OR2_IO_READ) {
+		ftdmflags |= FTDM_READ;
+	}
+	if (*flags & OR2_IO_WRITE) {
+		ftdmflags |= FTDM_WRITE;
+	}
+	if (*flags & OR2_IO_OOB_EVENT) {
+		ftdmflags |= FTDM_EVENTS;
+	}
+
+	status = ftdm_channel_wait(ftdm_chan, &ftdmflags, timeout);
+
+	if (FTDM_SUCCESS != status) {
+		return -1;
+	}
+
+	*flags = 0;
+	if (ftdmflags & FTDM_READ) {
+		*flags |= OR2_IO_READ;
+	}
+	if (ftdmflags & FTDM_WRITE) {
+		*flags |= OR2_IO_WRITE;
+	}
+	if (ftdmflags & FTDM_EVENTS) {
+		*flags |= OR2_IO_OOB_EVENT;
+	}
+
+	return 0;
+}
+
+/* The following openr2 hooks never get called, read on for reasoning ... */
+/* since freetdm takes care of opening the file descriptor and using openr2_chan_new_from_fd, openr2 should never call this hook */
+static openr2_io_fd_t ftdm_r2_io_open(openr2_context_t *r2context, int channo)
+{
+	ftdm_log(FTDM_LOG_ERROR, "I should not be called (I/O open)!!\n");
+	return NULL;
+}
+
+/* since freetdm takes care of closing the file descriptor and uses openr2_chan_new_from_fd, openr2 should never call this hook */
+static int ftdm_r2_io_close(openr2_chan_t *r2chan)
+{
+	ftdm_log(FTDM_LOG_ERROR, "I should not be called (I/O close)!!\n");
+	return 0;
+}
+
+/* since freetdm takes care of opening the file descriptor and using openr2_chan_new_from_fd, openr2 should never call this hook */
+static int ftdm_r2_io_setup(openr2_chan_t *r2chan)
+{
+	ftdm_log(FTDM_LOG_ERROR, "I should not be called (I/O Setup)!!\n");
+	return 0;
+}
+
+/* since the signaling thread calls openr2_chan_process_cas_signaling directly, openr2 should never call this hook */
+static int ftdm_r2_io_get_oob_event(openr2_chan_t *r2chan, openr2_oob_event_t *event)
+{
+	*event = 0;
+	ftdm_log(FTDM_LOG_ERROR, "I should not be called (I/O get oob event)!!\n");
+	return 0;
+}
+
+static openr2_io_interface_t ftdm_r2_io_iface = {
+	.open = ftdm_r2_io_open, /* never called */
+	.close = ftdm_r2_io_close, /* never called */
+	.set_cas = ftdm_r2_io_set_cas,
+	.get_cas = ftdm_r2_io_get_cas,
+	.flush_write_buffers = ftdm_r2_io_flush_write_buffers,
+	.write = ftdm_r2_io_write,
+	.read = ftdm_r2_io_read,
+	.setup = ftdm_r2_io_setup, /* never called */
+	.wait = ftdm_r2_io_wait,
+	.get_oob_event = ftdm_r2_io_get_oob_event /* never called */
+};
+
+static FIO_SIG_CONFIGURE_FUNCTION(ftdm_r2_configure_span)
+	//ftdm_status_t (ftdm_span_t *span, fio_signal_cb_t sig_cb, va_list ap)
+{
+	int i = 0;
+	int conf_failure = 0;
+	char *var = NULL;
+	char *val = NULL;
+	ftdm_r2_data_t *r2data = NULL;
+	ftdm_r2_span_pvt_t *spanpvt = NULL;
+	ftdm_r2_call_t *r2call = NULL;
+	openr2_chan_t *r2chan = NULL;
+
+	assert(sig_cb != NULL);
+
+	ft_r2_conf_t r2conf = 
+	{
+		.variant = OR2_VAR_ITU,
+		.category = OR2_CALLING_PARTY_CATEGORY_NATIONAL_SUBSCRIBER,
+		.loglevel = OR2_LOG_ERROR | OR2_LOG_WARNING,
+		.max_ani = 10,
+		.max_dnis = 4,
+		.mfback_timeout = -1,
+		.metering_pulse_timeout = -1,
+		.allow_collect_calls = -1,
+		.immediate_accept = -1,
+		.skip_category = -1,
+		.forced_release = -1,
+		.charge_calls = -1,
+		.get_ani_first = -1,
+		.call_files = -1,
+		.logdir = NULL,
+		.advanced_protocol_file = NULL 
+	};
+
+
+	if (span->signal_type) {
+		snprintf(span->last_error, sizeof(span->last_error), "Span is already configured for signalling.");
+		return FTDM_FAIL;
+	}
+
+	while ((var = va_arg(ap, char *))) {
+		ftdm_log(FTDM_LOG_DEBUG, "Reading R2 parameter %s for span %d\n", var, span->span_id);
+		if (!strcasecmp(var, "variant")) {
+			if (!(val = va_arg(ap, char *))) {
+				break;
+			}
+			if (ftdm_strlen_zero_buf(val)) {
+				ftdm_log(FTDM_LOG_NOTICE, "Ignoring empty R2 variant parameter\n");
+				continue;
+			}
+			r2conf.variant = openr2_proto_get_variant(val);
+			if (r2conf.variant == OR2_VAR_UNKNOWN) {
+				ftdm_log(FTDM_LOG_ERROR, "Unknown R2 variant %s\n", val);
+				conf_failure = 1;
+				break;
+			}
+			ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %d for variant %s\n", span->span_id, val);
+		} else if (!strcasecmp(var, "category")) {
+			if (!(val = va_arg(ap, char *))) {
+				break;
+			}
+			if (ftdm_strlen_zero_buf(val)) {
+				ftdm_log(FTDM_LOG_NOTICE, "Ignoring empty R2 category parameter\n");
+				continue;
+			}
+			r2conf.category = openr2_proto_get_category(val);
+			if (r2conf.category == OR2_CALLING_PARTY_CATEGORY_UNKNOWN) {
+				ftdm_log(FTDM_LOG_ERROR, "Unknown R2 caller category %s\n", val);
+				conf_failure = 1;
+				break;
+			}
+			ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %d with default category %s\n", span->span_id, val);
+		} else if (!strcasecmp(var, "logdir")) {
+			if (!(val = va_arg(ap, char *))) {
+				break;
+			}
+			if (ftdm_strlen_zero_buf(val)) {
+				ftdm_log(FTDM_LOG_NOTICE, "Ignoring empty R2 logdir parameter\n");
+				continue;
+			}
+			r2conf.logdir = val;
+			ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %d with logdir %s\n", span->span_id, val);
+		} else if (!strcasecmp(var, "logging")) {
+			if (!(val = va_arg(ap, char *))) {
+				break;
+			}
+			if (ftdm_strlen_zero_buf(val)) {
+				ftdm_log(FTDM_LOG_NOTICE, "Ignoring empty R2 logging parameter\n");
+				continue;
+			}
+			openr2_log_level_t tmplevel;
+			char *clevel;
+			char *logval = ftdm_malloc(strlen(val)+1); /* alloca man page scared me, so better to use good ol' malloc  */
+			if (!logval) {
+				ftdm_log(FTDM_LOG_WARNING, "Ignoring R2 logging parameter: '%s', failed to alloc memory\n", val);
+				continue;
+			}
+			strcpy(logval, val);
+			while (logval) {
+				clevel = strsep(&logval, ",");
+				if (-1 == (tmplevel = openr2_log_get_level(clevel))) {
+					ftdm_log(FTDM_LOG_WARNING, "Ignoring invalid R2 logging level: '%s'\n", clevel);
+					continue;
+				}
+				r2conf.loglevel |= tmplevel;
+				ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %d with loglevel %s\n", span->span_id, clevel);
+			}
+			ftdm_safe_free(logval);
+		} else if (!strcasecmp(var, "advanced_protocol_file")) {
+			if (!(val = va_arg(ap, char *))) {
+				break;
+			}
+			if (ftdm_strlen_zero_buf(val)) {
+				ftdm_log(FTDM_LOG_NOTICE, "Ignoring empty R2 advanced_protocol_file parameter\n");
+				continue;
+			}
+			r2conf.advanced_protocol_file = val;
+			ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %d with advanced protocol file %s\n", span->span_id, val);
+		} else if (!strcasecmp(var, "allow_collect_calls")) {
+			r2conf.allow_collect_calls = va_arg(ap, int);
+			ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %d with allow collect calls max ani = %d\n", span->span_id, r2conf.allow_collect_calls);
+		} else if (!strcasecmp(var, "double_answer")) {
+			r2conf.double_answer = va_arg(ap, int);
+			ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %d with double answer = %d\n", span->span_id, r2conf.double_answer);
+		} else if (!strcasecmp(var, "immediate_accept")) {
+			r2conf.immediate_accept = va_arg(ap, int);
+			ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %d with immediate accept = %d\n", span->span_id, r2conf.immediate_accept);
+		} else if (!strcasecmp(var, "skip_category")) {
+			r2conf.skip_category = va_arg(ap, int);
+			ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %d with skip category = %d\n", span->span_id, r2conf.skip_category);
+		} else if (!strcasecmp(var, "forced_release")) {
+			r2conf.forced_release = va_arg(ap, int);
+			ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %d with forced release = %d\n", span->span_id, r2conf.forced_release);
+		} else if (!strcasecmp(var, "charge_calls")) {
+			r2conf.charge_calls = va_arg(ap, int);
+			ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %d with charge calls = %d\n", span->span_id, r2conf.charge_calls);
+		} else if (!strcasecmp(var, "get_ani_first")) {
+			r2conf.get_ani_first = va_arg(ap, int);
+			ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %d with get ani first = %d\n", span->span_id, r2conf.get_ani_first);
+		} else if (!strcasecmp(var, "call_files")) {
+			r2conf.call_files = va_arg(ap, int);
+			ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %d with call files = %d\n", span->span_id, r2conf.call_files);
+		} else if (!strcasecmp(var, "mfback_timeout")) {
+			r2conf.mfback_timeout = va_arg(ap, int);
+			ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %d with MF backward timeout = %dms\n", span->span_id, r2conf.mfback_timeout);
+		} else if (!strcasecmp(var, "metering_pulse_timeout")) {
+			r2conf.metering_pulse_timeout = va_arg(ap, int);
+			ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %d with metering pulse timeout = %dms\n", span->span_id, r2conf.metering_pulse_timeout);
+		} else if (!strcasecmp(var, "max_ani")) {
+			r2conf.max_ani = va_arg(ap, int);
+			ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %d with max ani = %d\n", span->span_id, r2conf.max_ani);
+		} else if (!strcasecmp(var, "max_dnis")) {
+			r2conf.max_dnis = va_arg(ap, int);
+			ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %d with max dnis = %d\n", span->span_id, r2conf.max_dnis);
+		} else {
+			snprintf(span->last_error, sizeof(span->last_error), "Unknown R2 parameter [%s]", var);
+			return FTDM_FAIL;
+		}
+	}
+
+	if (conf_failure) {
+		snprintf(span->last_error, sizeof(span->last_error), "R2 configuration error");
+		return FTDM_FAIL;
+	}
+
+	r2data = ftdm_malloc(sizeof(*r2data));
+	if (!r2data) {
+		snprintf(span->last_error, sizeof(span->last_error), "Failed to allocate R2 data.");
+		return FTDM_FAIL;
+	}
+	memset(r2data, 0, sizeof(*r2data));
+
+	spanpvt = ftdm_malloc(sizeof(*spanpvt));
+	if (!spanpvt) {
+		snprintf(span->last_error, sizeof(span->last_error), "Failed to allocate private span data container.");
+		goto fail;
+	}
+	memset(spanpvt, 0, sizeof(*spanpvt));
+
+	r2data->r2context = openr2_context_new(r2conf.variant, &ftdm_r2_event_iface, r2conf.max_ani, r2conf.max_dnis);
+	if (!r2data->r2context) {
+		snprintf(span->last_error, sizeof(span->last_error), "Cannot create openr2 context for span.");
+		goto fail;
+	}
+	openr2_context_set_io_type(r2data->r2context, OR2_IO_CUSTOM, &ftdm_r2_io_iface);
+	openr2_context_set_log_level(r2data->r2context, r2conf.loglevel);
+	openr2_context_set_ani_first(r2data->r2context, r2conf.get_ani_first);
+	openr2_context_set_skip_category_request(r2data->r2context, r2conf.skip_category);
+	openr2_context_set_mf_back_timeout(r2data->r2context, r2conf.mfback_timeout);
+	openr2_context_set_metering_pulse_timeout(r2data->r2context, r2conf.metering_pulse_timeout);
+	openr2_context_set_double_answer(r2data->r2context, r2conf.double_answer);
+	openr2_context_set_immediate_accept(r2data->r2context, r2conf.immediate_accept);
+	if (r2conf.logdir) {
+		openr2_context_set_log_directory(r2data->r2context, r2conf.logdir);
+	}
+	if (r2conf.advanced_protocol_file) {
+		openr2_context_configure_from_advanced_file(r2data->r2context, r2conf.advanced_protocol_file);
+	}
+
+	spanpvt->r2calls = create_hashtable(FTDM_MAX_CHANNELS_SPAN, ftdm_hash_hashfromstring, ftdm_hash_equalkeys);
+	if (!spanpvt->r2calls) {
+		snprintf(span->last_error, sizeof(span->last_error), "Cannot create channel calls hash for span.");
+		goto fail;
+	}
+
+	for (i = 1; (i <= span->chan_count) && (i <= FTDM_MAX_CHANNELS_SPAN); i++) {
+		r2chan = openr2_chan_new_from_fd(r2data->r2context, span->channels[i], span->channels[i]->physical_chan_id);
+		if (!r2chan) {
+			snprintf(span->last_error, sizeof(span->last_error), "Cannot create all openr2 channels for span.");
+			goto fail;
+		}
+		if (r2conf.call_files) {
+			openr2_chan_enable_call_files(r2chan);
+			openr2_chan_set_log_level(r2chan, r2conf.loglevel);
+		}
+
+		r2call = ftdm_malloc(sizeof(*r2call));
+		if (!r2call) {
+			snprintf(span->last_error, sizeof(span->last_error), "Cannot create all R2 call data structures for the span.");
+			ftdm_safe_free(r2chan);
+			goto fail;
+		}
+		memset(r2call, 0, sizeof(*r2call));
+		openr2_chan_set_logging_func(r2chan, ftdm_r2_on_chan_log);
+		openr2_chan_set_client_data(r2chan, span->channels[i]);
+        r2call->r2chan = r2chan;
+		span->channels[i]->call_data = r2call;
+		/* value and key are the same so just free one of them */
+		snprintf(r2call->name, sizeof(r2call->name), "chancall%d", i);
+		hashtable_insert(spanpvt->r2calls, (void *)r2call->name, r2call, HASHTABLE_FLAG_FREE_VALUE);
+
+	}
+	spanpvt->r2context = r2data->r2context;
+
+	/* just the value must be freed by the hash */
+	hashtable_insert(g_mod_data_hash, (void *)span->name, spanpvt, HASHTABLE_FLAG_FREE_VALUE);
+
+	span->start = ftdm_r2_start;
+	r2data->flags = 0;
+	span->signal_cb = sig_cb;
+	span->signal_type = FTDM_SIGTYPE_R2;
+	span->signal_data = r2data;
+	span->outgoing_call = r2_outgoing_call;
+
+	return FTDM_SUCCESS;
+
+fail:
+
+	if (r2data && r2data->r2context) {
+		openr2_context_delete(r2data->r2context);
+	}
+	if (spanpvt && spanpvt->r2calls) {
+		hashtable_destroy(spanpvt->r2calls);
+	}
+	ftdm_safe_free(r2data);
+	ftdm_safe_free(spanpvt);
+	return FTDM_FAIL;
+
+}
+
+static void *ftdm_r2_channel_run(ftdm_thread_t *me, void *obj)
+{
+	ftdm_channel_t *closed_chan;
+	uint32_t interval = 0;
+	ftdm_sigmsg_t sigev;
+	ftdm_channel_t *ftdmchan = (ftdm_channel_t *)obj;
+	openr2_chan_t *r2chan = R2CALL(ftdmchan)->r2chan;
+
+	ftdm_set_flag_locked(ftdmchan, FTDM_CHANNEL_INTHREAD);
+
+	ftdm_mutex_lock(g_thread_count_mutex);
+	g_thread_count++;
+	ftdm_mutex_unlock(g_thread_count_mutex);
+
+	ftdm_log(FTDM_LOG_DEBUG, "R2 CHANNEL thread starting on %d in state %s.\n", 
+			ftdmchan->physical_chan_id,
+			ftdm_channel_state2str(ftdmchan->state));
+
+	if (ftdm_channel_open_chan(ftdmchan) != FTDM_SUCCESS) {
+		ftdm_log(FTDM_LOG_ERROR, "OPEN ERROR [%s]\n", ftdmchan->last_error);
+		goto endthread;
+	}
+
+	ftdm_channel_command(ftdmchan, FTDM_COMMAND_GET_INTERVAL, &interval);
+
+	assert(interval != 0);
+	ftdm_log(FTDM_LOG_DEBUG, "Got %d interval for chan %d\n", interval, ftdmchan->physical_chan_id);
+
+	if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
+		/* FIXME: is this needed? */
+		memset(ftdmchan->caller_data.dnis.digits, 0, sizeof(ftdmchan->caller_data.collected));
+		memset(ftdmchan->caller_data.ani.digits, 0, sizeof(ftdmchan->caller_data.collected));
+	}
+
+	memset(&sigev, 0, sizeof(sigev));
+	sigev.chan_id = ftdmchan->chan_id;
+	sigev.span_id = ftdmchan->span_id;
+	sigev.channel = ftdmchan;
+
+	while (ftdm_running()) {
+		int32_t read_enabled = openr2_chan_get_read_enabled(r2chan);
+		ftdm_wait_flag_t flags = read_enabled ? ( FTDM_READ | FTDM_WRITE ) : 0;
+
+		if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE) && (R2CALL(ftdmchan)->chanstate != ftdmchan->state)) {
+
+			ftdm_log(FTDM_LOG_DEBUG, "Executing state handler on %d:%d for %s\n", ftdmchan->span_id, ftdmchan->chan_id, ftdm_channel_state2str(ftdmchan->state));
+			R2CALL(ftdmchan)->chanstate = ftdmchan->state;
+
+			if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND) && !R2CALL(ftdmchan)->accepted &&
+					(ftdmchan->state == FTDM_CHANNEL_STATE_PROGRESS ||
+					 ftdmchan->state == FTDM_CHANNEL_STATE_PROGRESS_MEDIA ||
+					 ftdmchan->state == FTDM_CHANNEL_STATE_UP) ) {
+				/* if an accept ack will be required we should not acknowledge the state change just yet, 
+				   it will be done below after processing the MF signals, otherwise we have a race condition between freetdm calling
+				   openr2_chan_answer_call and openr2 accepting the call first, if freetdm calls openr2_chan_answer_call before the accept cycle
+				   completes, openr2 will fail to answer the call */
+				ftdm_log(FTDM_LOG_DEBUG, "State ack in chan %d:%d for state %s will have to wait a bit\n", ftdmchan->span_id, ftdmchan->chan_id, ftdm_channel_state2str(ftdmchan->state));
+			} else if (ftdmchan->state != FTDM_CHANNEL_STATE_DOWN){
+				/* the down state will be completed in ftdm_channel_done below */
+				ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_STATE_CHANGE);
+				ftdm_channel_complete_state(ftdmchan);
+			}
+
+			switch (ftdmchan->state) {
+
+				/* starting an incoming call */
+				case FTDM_CHANNEL_STATE_COLLECT: 
+					{
+						ftdm_log(FTDM_LOG_DEBUG, "COLLECT: Starting processing of incoming call in channel %d with interval %d\n", ftdmchan->physical_chan_id, interval);
+					}
+					break;
+
+					/* starting an outgoing call */
+				case FTDM_CHANNEL_STATE_DIALING:
+					{
+						// FIXME: use user defined calling party
+						ftdm_channel_use(ftdmchan);
+						ftdm_log(FTDM_LOG_DEBUG, "DIALING: Starting processing of outgoing call in channel %d with interval %d\n", ftdmchan->physical_chan_id, interval);
+						if (openr2_chan_make_call(r2chan, ftdmchan->caller_data.cid_num.digits, ftdmchan->caller_data.dnis.digits, OR2_CALLING_PARTY_CATEGORY_NATIONAL_SUBSCRIBER)) {
+							ftdm_log(FTDM_LOG_ERROR, "%d:%d Failed to make call in R2 channel, openr2_chan_make_call failed\n", ftdmchan->span_id, ftdmchan->chan_id);
+							ftdmchan->caller_data.hangup_cause = FTDM_CAUSE_DESTINATION_OUT_OF_ORDER;
+							ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP);
+						}
+					}
+					break;
+
+					/* the call is ringing */
+				case FTDM_CHANNEL_STATE_PROGRESS:
+				case FTDM_CHANNEL_STATE_PROGRESS_MEDIA:
+					{
+						if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
+							if (!R2CALL(ftdmchan)->accepted) {
+								ftdm_log(FTDM_LOG_DEBUG, "PROGRESS: Accepting call on channel %d\n", ftdmchan->physical_chan_id);
+								ft_r2_accept_call(ftdmchan);
+							} 
+						} else {
+							ftdm_log(FTDM_LOG_DEBUG, "PROGRESS: Notifying progress in channel %d\n", ftdmchan->physical_chan_id);
+							sigev.event_id = FTDM_SIGEVENT_PROGRESS;
+							if (ftdm_span_send_signal(ftdmchan->span, &sigev) != FTDM_SUCCESS) {
+								ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP);
+							}
+						}
+					}
+					break;
+
+					/* the call was answered */
+				case FTDM_CHANNEL_STATE_UP:
+					{
+						ftdm_log(FTDM_LOG_DEBUG, "UP: Call was answered on channel %d\n", ftdmchan->physical_chan_id);
+						if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
+							if (!R2CALL(ftdmchan)->accepted) {
+								ftdm_log(FTDM_LOG_DEBUG, "UP: Call has not been accepted, need to accept first\n");
+								// the answering will be done in the on_call_accepted handler
+								ft_r2_accept_call(ftdmchan);
+								R2CALL(ftdmchan)->answer_pending = 1;
+							} else {
+								ft_r2_answer_call(ftdmchan);
+							}
+						} else {
+							ftdm_log(FTDM_LOG_DEBUG, "UP: Notifying of call answered in channel %d\n", ftdmchan->physical_chan_id);
+							sigev.event_id = FTDM_SIGEVENT_UP;
+							if (ftdm_span_send_signal(ftdmchan->span, &sigev) != FTDM_SUCCESS) {
+								ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP);
+							}
+						}
+					}
+					break;
+
+					/* just got hangup */
+				case FTDM_CHANNEL_STATE_HANGUP: 
+					{
+						/* FIXME: the cause should be retrieved from ftdmchan->caller_data.hangup_cause and translated from Q931 to R2 cause */
+						ftdm_log(FTDM_LOG_DEBUG, "HANGUP: Clearing call on channel %d\n", ftdmchan->physical_chan_id);
+						if (!R2CALL(ftdmchan)->disconnect_rcvd) {
+							/* this will disconnect the call, but need to wait for the call end before moving to DOWN */
+							openr2_chan_disconnect_call(r2chan, OR2_CAUSE_NORMAL_CLEARING);
+						} else {
+							/* at this point on_call_end possibly was already called, 
+							 * but we needed to wait for the freetdm confirmation before moving to DOWN */
+							ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
+						}
+					}
+					break;
+
+					/* just got hangup from the freetdm side due to abnormal failure */
+				case FTDM_CHANNEL_STATE_CANCEL:
+					{
+						ftdm_log(FTDM_LOG_DEBUG, "CANCEL: Unable to receive call on channel %d\n", ftdmchan->physical_chan_id);
+						openr2_chan_disconnect_call(r2chan, OR2_CAUSE_OUT_OF_ORDER);
+					}
+					break;
+
+					/* finished call for good */
+				case FTDM_CHANNEL_STATE_DOWN: 
+					{
+						ftdm_log(FTDM_LOG_DEBUG, "DOWN: Placing channel %d back to the pool of available channels\n", ftdmchan->physical_chan_id);
+						ftdm_channel_done(ftdmchan);
+						goto endthread;
+					}
+					break;
+
+				default:
+					{
+						ftdm_log(FTDM_LOG_ERROR, "%s: Unhandled channel state change in channel %d\n", ftdm_channel_state2str(ftdmchan->state), ftdmchan->physical_chan_id);
+					}
+					break;
+
+			}
+		}
+
+		if (flags) {
+			if (ftdm_channel_wait(ftdmchan, &flags, interval * 2) != FTDM_SUCCESS) {
+				ftdm_log(FTDM_LOG_DEBUG, "ftdm_channel_wait did not return FTDM_SUCCESS\n");
+				continue;
+			}
+
+			/* handle timeout events first if any */
+			openr2_chan_run_schedule(r2chan);
+
+			/* openr2 will now try to detect MF tones, make sense out of them, reply if necessary with another tone and trigger 
+			 * telephony events via the call event interface we provided when creating the R2 context.
+			 * openr2 will also call our I/O callbacks to retrieve audio from the channel and call our wait poll I/O registered callback
+			 * and will not return from this function until the I/O poll callback returns no pending events
+			 * */
+			openr2_chan_process_mf_signaling(r2chan);
+			if (R2CALL(ftdmchan)->state_ack_pending) {
+				ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_STATE_CHANGE);
+				ftdm_channel_complete_state(ftdmchan);
+				R2CALL(ftdmchan)->state_ack_pending = 0;
+			}
+		} else {
+			/* once the MF signaling has end we just loop here waiting for state changes */
+			ftdm_sleep(interval);
+		}
+
+	}
+
+endthread:
+
+	closed_chan = ftdmchan;
+	ftdm_channel_close(&closed_chan);
+	ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_INTHREAD);
+	ftdm_log(FTDM_LOG_DEBUG, "R2 channel %d thread ended.\n", ftdmchan->physical_chan_id);
+
+	ftdm_mutex_lock(g_thread_count_mutex);
+	g_thread_count--;
+	ftdm_mutex_unlock(g_thread_count_mutex);
+
+	return NULL;
+}
+
+static void *ftdm_r2_run(ftdm_thread_t *me, void *obj)
+{
+	openr2_chan_t *r2chan;
+	ftdm_status_t status;
+	ftdm_span_t *span = (ftdm_span_t *) obj;
+	ftdm_r2_data_t *r2data = span->signal_data;
+	int waitms = 1000;
+	int i;
+
+	ftdm_log(FTDM_LOG_DEBUG, "OpenR2 monitor thread started.\n");
+  r2chan = NULL;
+	for (i = 1; i <= span->chan_count; i++) {
+		r2chan = R2CALL(span->channels[i])->r2chan;
+		openr2_chan_set_idle(r2chan);
+		openr2_chan_process_cas_signaling(r2chan);
+	}
+
+	while (ftdm_running() && ftdm_test_flag(r2data, FTDM_R2_RUNNING)) {
+		status = ftdm_span_poll_event(span, waitms);
+		if (FTDM_FAIL == status) {
+			ftdm_log(FTDM_LOG_ERROR, "Failure Polling event! [%s]\n", span->last_error);
+			continue;
+		}
+		if (FTDM_SUCCESS == status) {
+			ftdm_event_t *event;
+			while (ftdm_span_next_event(span, &event) == FTDM_SUCCESS) {
+				if (event->enum_id == FTDM_OOB_CAS_BITS_CHANGE) {
+                    r2chan = R2CALL(event->channel)->r2chan;
+					ftdm_log(FTDM_LOG_DEBUG, "Handling CAS on channel %d.\n", openr2_chan_get_number(r2chan));
+					// we only expect CAS and other OOB events on this thread/loop, once a call is started
+					// the MF events (in-band signaling) are handled in the call thread
+					openr2_chan_process_cas_signaling(r2chan);
+				} else {
+					ftdm_log(FTDM_LOG_DEBUG, "Ignoring event %d on channel %d.\n", event->enum_id, openr2_chan_get_number(r2chan));
+					// XXX TODO: handle alarms here XXX
+				}
+			}
+		} else if (status != FTDM_TIMEOUT) {
+			ftdm_log(FTDM_LOG_ERROR, "ftdm_span_poll_event returned %d.\n", status);
+		} else {
+			//ftdm_log(FTDM_LOG_DEBUG, "timed out waiting for event on span %d\n", span->span_id);
+		}
+	}
+
+    /*
+    FIXME: we should set BLOCKED but at this point I/O routines of freetdm caused segfault
+	for (i = 1; i <= span->chan_count; i++) {
+		r2chan = R2CALL(span->channels[i])->r2chan;
+		openr2_chan_set_blocked(r2chan);
+	}
+    */
+
+	ftdm_clear_flag(r2data, FTDM_R2_RUNNING);
+	ftdm_log(FTDM_LOG_DEBUG, "R2 thread ending.\n");
+
+	return NULL;
+
+}
+
+static FIO_API_FUNCTION(ftdm_r2_api)
+{
+	char *mycmd = NULL, *argv[10] = { 0 };
+	int argc = 0;
+
+	if (data) {
+		mycmd = ftdm_strdup(data);
+		argc = ftdm_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
+	}
+
+	if (argc == 2) {
+		if (!strcasecmp(argv[0], "kill")) {
+			int span_id = atoi(argv[1]);
+			ftdm_span_t *span = NULL;
+
+			if (ftdm_span_find_by_name(argv[1], &span) == FTDM_SUCCESS || ftdm_span_find(span_id, &span) == FTDM_SUCCESS) {
+				ftdm_r2_data_t *r2data = span->signal_data;
+
+				if (span->start != ftdm_r2_start) {
+					stream->write_function(stream, "-ERR invalid span.\n");
+					goto done;
+				}
+
+				ftdm_clear_flag(r2data, FTDM_R2_RUNNING);
+				stream->write_function(stream, "+OK killed.\n");
+				goto done;
+			} else {
+				stream->write_function(stream, "-ERR invalid span.\n");
+				goto done;
+			}
+		}
+
+		if (!strcasecmp(argv[0], "status")) {
+			int span_id = atoi(argv[1]);
+			ftdm_r2_data_t *r2data = NULL;
+			ftdm_span_t *span = NULL;
+			openr2_chan_t *r2chan = NULL;
+			openr2_context_t *r2context = NULL;
+			int i = 0;
+
+			if (ftdm_span_find_by_name(argv[1], &span) == FTDM_SUCCESS || ftdm_span_find(span_id, &span) == FTDM_SUCCESS) {
+				if (span->start != ftdm_r2_start) {
+					stream->write_function(stream, "-ERR not an R2 span.\n");
+					goto done;
+				}
+				if (!(r2data =  span->signal_data)) {
+					stream->write_function(stream, "-ERR invalid span. No R2 singal data in span.\n");
+					goto done;
+				}
+				r2context = r2data->r2context;
+				openr2_variant_t r2variant = openr2_context_get_variant(r2context);
+				stream->write_function(stream, 
+						"Variant: %s\n"
+						"Max ANI: %d\n"
+						"Max DNIS: %d\n"
+						"ANI First: %s\n"
+						"Immediate Accept: %s\n",
+						openr2_proto_get_variant_string(r2variant),
+						openr2_context_get_max_ani(r2context),
+						openr2_context_get_max_dnis(r2context),
+						openr2_context_get_ani_first(r2context) ? "Yes" : "No",
+						openr2_context_get_immediate_accept(r2context) ? "Yes" : "No");
+				stream->write_function(stream, "\n");
+				stream->write_function(stream, "%4s %-12.12s %-12.12s\n", "Channel", "Tx CAS", "Rx CAS");
+				for (i = 1; i <= span->chan_count; i++) {
+					if (i == 16) continue;
+					r2chan = R2CALL(span->channels[i])->r2chan;
+					stream->write_function(stream, "%4d    %-12.12s %-12.12s\n", 
+							span->channels[i]->physical_chan_id,
+							openr2_chan_get_tx_cas_string(r2chan),
+							openr2_chan_get_rx_cas_string(r2chan));
+				}
+				stream->write_function(stream, "\n");
+				stream->write_function(stream, "+OK.\n");
+				goto done;
+			} else {
+				stream->write_function(stream, "-ERR invalid span.\n");
+				goto done;
+			}
+		}
+
+	}
+
+	if (argc == 1) {
+		if (!strcasecmp(argv[0], "threads")) {
+			ftdm_mutex_lock(g_thread_count_mutex);
+			stream->write_function(stream, "%d R2 channel threads up\n", g_thread_count);
+			ftdm_mutex_unlock(g_thread_count_mutex);
+			stream->write_function(stream, "+OK.\n");
+			goto done;
+		}
+
+		if (!strcasecmp(argv[0], "version")) {
+			stream->write_function(stream, "OpenR2 version: %s, revision: %s\n", openr2_get_version(), openr2_get_revision());
+			stream->write_function(stream, "+OK.\n");
+			goto done;
+		}
+
+		if (!strcasecmp(argv[0], "variants")) {
+			int32_t numvariants = 0;
+			const openr2_variant_entry_t *variants = openr2_proto_get_variant_list(&numvariants);
+			if (!variants) {
+				stream->write_function(stream, "-ERR failed to retrieve openr2 variant list.\n");
+				goto done;
+			}
+#define VARIANT_FORMAT "%4s %40s\n"
+			stream->write_function(stream, VARIANT_FORMAT, "Variant Code", "Country");
+			numvariants--;
+			for (; numvariants; numvariants--) {
+				stream->write_function(stream, VARIANT_FORMAT, variants[numvariants].name, variants[numvariants].country);
+			}
+			stream->write_function(stream, "+OK.\n");
+#undef VARIANT_FORMAT
+			goto done;
+		}
+	}
+
+	stream->write_function(stream, "-ERR invalid command.\n");
+
+done:
+
+	ftdm_safe_free(mycmd);
+
+	return FTDM_SUCCESS;
+
+}
+
+static FIO_IO_LOAD_FUNCTION(ftdm_r2_io_init)
+{
+	assert(fio != NULL);
+	memset(&g_ftdm_r2_interface, 0, sizeof(g_ftdm_r2_interface));
+
+	g_ftdm_r2_interface.name = "r2";
+	g_ftdm_r2_interface.api = ftdm_r2_api;
+
+	*fio = &g_ftdm_r2_interface;
+
+	return FTDM_SUCCESS;
+}
+
+static FIO_SIG_LOAD_FUNCTION(ftdm_r2_init)
+{
+	g_mod_data_hash = create_hashtable(10, ftdm_hash_hashfromstring, ftdm_hash_equalkeys);
+	if (!g_mod_data_hash) {
+		return FTDM_FAIL;
+	}
+	ftdm_mutex_create(&g_thread_count_mutex);
+	return FTDM_SUCCESS;
+}
+
+static FIO_SIG_UNLOAD_FUNCTION(ftdm_r2_destroy)
+{
+	ftdm_hash_iterator_t *i = NULL;
+	ftdm_r2_span_pvt_t *spanpvt = NULL;
+	const void *key = NULL;
+	void *val = NULL;
+	for (i = hashtable_first(g_mod_data_hash); i; i = hashtable_next(i)) {
+		hashtable_this(i, &key, NULL, &val);
+		if (key && val) {
+			spanpvt = val;
+			openr2_context_delete(spanpvt->r2context);
+			hashtable_destroy(spanpvt->r2calls);
+		}
+	}
+	hashtable_destroy(g_mod_data_hash);
+	ftdm_mutex_destroy(&g_thread_count_mutex);
+	return FTDM_SUCCESS;
+}
+
+ftdm_module_t ftdm_module = { 
+	"r2",
+	ftdm_r2_io_init,
+	NULL,
+	ftdm_r2_init,
+	ftdm_r2_configure_span,
+	ftdm_r2_destroy
+};
+	
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4
+ */

Added: freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_sangoma_boost/BOOST.limitations (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_sangoma_boost/BOOST.limitations	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_sangoma_boost/BOOST.limitations	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,20 @@
+== Boost sigmod current limitations ==
+- we don't support having openzap spans with physical channels
+  belonging to other physical spans. this is due to netborder sangoma abstraction, therefore
+  any openzap span using sigboost must have only channels belonging to the corresponding
+  physical span.
+
+  This is the reason we added group functionality in openzap core, furthermore, previous groups in openzap
+  were only possible through adding of b-channels to a single span, but this forces the user to create groups
+  of channels only whithin the same type of trunk among other things.
+
+- all spans must be configured and then started, cannot configure, start, configure start etc
+  this is due to netborder telesoft abstraction. that requires configuring everything and
+  then starting everything at once.
+
+- sangoma_prid and sangoma_brid on Windows had to be compiled hacking make/Makefile.platform to comment all VC runtime checks, 
+  otherwise when running in debug mode exceptions are thrown due to loss of data ie short to char conversions.
+
+== TODO ==
+- proper upper layer management of HW alarms (this must be done in mod_openzap.c)
+

Added: freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_sangoma_boost/boost-tasks.txt (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_sangoma_boost/boost-tasks.txt	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_sangoma_boost/boost-tasks.txt	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,146 @@
+== General Design ==
+
+NBE will do its current loading of spans and configuration process through Sangoma Board Manager (SBM).
+After doing SangomaBoardManager::getInstance().configure -> start. It will proceed to initalize
+the openzap stack (just as the TelesoftStack is loaded after starting SMB. The procedure will be:
+
+- create a static or malloced zap_io_interface_t
+- call zap_global_set_logger with the logging hooks.
+- call zap_global_set_memhandler() with the memory hooks.
+- call zap_global_init() to initialize the stack
+- call zap_add_io_iface() to add the I/O iface.
+- iterate over all SBM spans configured for BRI or any boost-managed signaling and:
+    * call zap_span_create(NBE I/O mod, in_ptrSpan, SMB span name)
+    * Fill in some members like: 
+      span->trunk_type = E1/T1/J1/FXO/FXS etc ...
+    * iterate over all channels in SMB span and:
+      * zap_span_add_channel(zap_span, sock, type:CAS|BCHAN|DCHAN|ETC)
+    * call zap_configure_span("sangoma_boost", span, sigmsg_callback, "param1", value1, "param2", value1 ...)
+    * zap_span_start(span);
+
+
+At this point, NBE would receive signaling msgs via sigmsg_callback registered when configuring
+and NBE would request hangup or making calls throug openzap API, like zap_set_state_* and zap_channel_outgoing_call() to place calls.
+
+When NBE wants to check for link status. 
+
+      zap_get_siglink_state() which would return 
+      ZAP_SIG_STATE_UP (D-chan UP, R2 bits in IDLE, ss7?)
+      ZAP_SIG_STATE_SUSPENDED (D-chan in power saving mode?)
+      ZAP_SIG_STATE_DOWN (D-chan down, R2 bits in blocked, ss7?)
+
+      Whenever a state in sig link changes, the sigmsg_callback will be used to notify NBE or any other user.
+
+NOTE: right now hardware alarms notification in openzap is seriously broken,
+see ozmod_libpri.c process_event ... reads an event from hardware (zap_event_t *),
+then checks the event type, if its ZAP_OOB_ALARM_TRAP prepares a zap_sigmsg_t
+(signaling event) setting its event_id to ZAP_OOB_ALARM_TRAP, which is *WRONG*
+because event_id is of type zap_signal_event_t and not zap_oob_event_t!
+this means on alarm the user will get ZAP_SIGEVENT_PROGRESS_MEDIA!! which is
+value 7 that is in conflict with ZAP_OOB_ALARM_TRAP, I think a separate
+callback should be used if the outside user wants to be notified about
+hardware events like HW DTMF or so. Currently there is alreadya  generic DTMF
+listener.
+
+== Tasks Stage 1 / OpenZAP and Boost changes (To be tested with FreeSWITCH) ==
+
+- Change malloc and other mem functions in openzap
+  to use internal hooks provided via zap_global_set_memhandler()
+  which would be called before zap_global_init(), this is
+  already done for the logger via zap_global_set_logger()
+  
+  question: should the mem routines allow for memory pool ptr?
+            this could be useful to provide a memory pool to
+            the whole module.
+
+  question: should we allow hooks for threads and locking?
+            I think we can skip this one unless needed. They already
+            use their own threading abstraction which is working for
+            Linux and Windows. If we ever need to profile threading
+            we can add profiling hooks.
+
+  question: I had to add openzap calls to the hash table and libteletone implementations, is that acceptable?
+
+- Modify zap_global_init() API
+  
+  This API must just initialize vars, mutexes etc.
+  and NOT DO ANY CONFIGURATION LOADING, PARSING, SPAN CREATION and I/O
+  configuration, which is what is currently doing. 
+  We don't want zap_global_init() to create the spans based on that configuration
+  since NBE will have its own configuration and will take care of creating
+  the needed data structures on its own.
+
+- Add new zap_std_io_config() API 
+
+  This API will parse the standard openzap.conf module and create the spans.  
+  This will be used by FS but not by NBE, which will create the openzap spans by itself.
+  The NBE flow to initialize openzap will be:
+
+- Add new API zap_global_add_io_iface(), 
+
+  This API will add a new I/O interface structure to the internal openzap hash of I/O structs. 
+  This is needed because NBE I/O structure will NOT be loaded from an openzap module (.so/.dll)
+  but rather just registered on runtime (probably from a static structure in NBE code).
+  This openzap hash is used by zap_api_execute() for example, to find the module that can 
+  handle a given API, ie (oz libpri status). This is an example of how an openzap I/O interface 
+  can decide to implement just the ->api() member to handle commands and NOTHING else,
+  so I/O interfaces not necessary are hardware-related.
+
+- Add new zap_channel_get_siglink_state(zap_channel, zap_siglink_status_t &status)
+
+- Modify mod_openzap.c to read proto= setting in boost spans, this will determine wich boost sig
+  module will handle the configuration and those channels.
+
+    <boost_spans> <span sigmod="bri|ss7|blah"> <param="proto-specific-setting" value="setting"> </span> </boost_spans>
+
+    Then as first config arg to zap_config_span() the boost proto module name would be included as "sigmod" which will be used
+    by ozmod_sangoma_boost to decide which sig module must handle that span configuration
+
+- Create minimal boost mod interface.
+ 
+   ozmod_boost_ss7 should load sig boost mods and get interface via dlsym(boost_get_interface) boost_get_interface(boost_iface);
+  The boost interface will have
+    * const char *name                  // boost sigmod name (brid,ss7d)
+    * set_write_boost_msg_cb(callback)  // tell the stack how to send us boost messages
+    * set_sig_status_cb(callback);      // tell the stack how to notify us about link status changes
+    * write_boost_msg(struct boost_msg) // send a boost msg to the stack
+    * configure_span(zap_span_t span, "configuration", value, "configuration", value) // configure a given span
+    * get_sig_status(openzap_sigstatus_t status)
+    * start(span) // to start a given openzap span
+    * stop(span) // to stop the stack on a given openzap span
+
+- Migrate current sangoma_brid sig module to openzap
+  * Make sangoma_brid a library
+  * Move from using malloc, threading, locking, logging and I/O to openzap functions. Export the boost sigmod interface and its supporting code.
+
+== State 2 Tasks == 
+
+- Create the I/O NBE interface and supporting functions. It must be possible to poll over the span
+  given that ozmod_sangoma_boost BRI module and others may need to *wait* for data. The poll()
+  function in I/O NBE interface would wait on a pthread condition or Windows event, which would
+  be triggered by some external NBE component registered with Sangoma Board Manager (SMB) for d-chan
+  data, whenever d-chan data arrives, saves the data in a buffer and triggers the condition to wakeup
+  any waiter, then the waiter (sangoma_brid or any other boost client) calls zap_channel_read which calls
+  our own I/O NBE interface read method and retrieves the data from the buffer.
+
+    Dropped alternative design:
+    Another option is to add a new API zap_span_push_incoming_data(span/chan, data); However this changes
+    the model openzap has followed and I don't think fits that well, since now we have 2 different models
+    to support in openzap. 
+
+== TODO ==
+
+- how about logging specific modules, like, just ozmod_boost, or just the BRI stack?
+  more work to be done so the BRI module uses zap_log instead of current syslog
+  then work to be done to be able to filter logs from specific openzap code? is it worth it?
+
+- remove FORCE_SEGFAULT from sprid
+
+
+=== Shortcomings ==
+
+- we had to drop smg support in the branch where we work on sangoma prid.
+  After all, most people using sangoma_prid is using freeswitch/openzap and not Sangoma Media Gateway
+  The problem is in freeswitch/openzap mode, sangoma_boost ozmod takes care of span events (POLLPRI)
+  where in SMG and Netborder POLLPRI is done typically by sangoma board manager.
+

Added: freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_sangoma_boost/ftdm_sangoma_boost.h (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_sangoma_boost/ftdm_sangoma_boost.h	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_sangoma_boost/ftdm_sangoma_boost.h	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2007, Anthony Minessale II
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FTDM_SANGOMA_BOOST_H
+#define FTDM_SANGOMA_BOOST_H
+#include "sangoma_boost_client.h"
+#include "freetdm.h"
+
+#define MAX_CHANS_PER_TRUNKGROUP 1024
+
+typedef enum {
+	FTDM_SANGOMA_BOOST_RUNNING = (1 << 0),
+	FTDM_SANGOMA_BOOST_RESTARTING = (1 << 1)
+} ftdm_sangoma_boost_flag_t;
+
+typedef struct ftdm_sangoma_boost_data {
+	sangomabc_connection_t mcon;
+	sangomabc_connection_t pcon;
+	int iteration;
+	uint32_t flags;
+	boost_sigmod_interface_t *sigmod;
+	ftdm_queue_t *boost_queue;	
+} ftdm_sangoma_boost_data_t;
+
+typedef struct ftdm_sangoma_boost_trunkgroup {
+	ftdm_mutex_t *mutex;
+	ftdm_size_t size;			/* Number of b-channels in group */	
+	unsigned int last_used_index; /* index of last b-channel used */
+	ftdm_channel_t* ftdmchans[MAX_CHANS_PER_TRUNKGROUP];
+	//DAVIDY need to merge congestion timeouts to this struct
+} ftdm_sangoma_boost_trunkgroup_t;
+#endif
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
+

Added: freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_sangoma_boost/ftmod_sangoma_boost.2008.vcproj (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_sangoma_boost/ftmod_sangoma_boost.2008.vcproj	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_sangoma_boost/ftmod_sangoma_boost.2008.vcproj	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,215 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="9.00"
+	Name="ftmod_sangoma_boost"
+	ProjectGUID="{D021EF2A-460D-4827-A0F7-41FDECF46F1B}"
+	RootNamespace="ftmod_sangoma_boost"
+	Keyword="Win32Proj"
+	TargetFrameworkVersion="196613"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="2"
+			CharacterSet="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				AdditionalIncludeDirectories="..\..\include;..\..\isdn\include"
+				PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;FTMOD_SANGOMA_BOOST_EXPORTS"
+				MinimalRebuild="true"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="3"
+				UsePrecompiledHeader="0"
+				WarningLevel="4"
+				WarnAsError="true"
+				DebugInformationFormat="4"
+				DisableSpecificWarnings="4100"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="freetdm.lib"
+				LinkIncremental="2"
+				AdditionalLibraryDirectories="&quot;$(OutDir)&quot;"
+				GenerateDebugInformation="true"
+				SubSystem="2"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="2"
+			CharacterSet="1"
+			WholeProgramOptimization="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="2"
+				EnableIntrinsicFunctions="true"
+				AdditionalIncludeDirectories="..\..\include"
+				PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;FTMOD_SANGOMA_BOOST_EXPORTS"
+				RuntimeLibrary="2"
+				EnableFunctionLevelLinking="true"
+				UsePrecompiledHeader="0"
+				WarningLevel="4"
+				WarnAsError="true"
+				DebugInformationFormat="3"
+				DisableSpecificWarnings="4100"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				LinkIncremental="1"
+				GenerateDebugInformation="true"
+				SubSystem="2"
+				OptimizeReferences="2"
+				EnableCOMDATFolding="2"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<Filter
+			Name="Source Files"
+			Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+			>
+			<File
+				RelativePath="ftmod_sangoma_boost.c"
+				>
+			</File>
+			<File
+				RelativePath="sangoma_boost_client.c"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="Header Files"
+			Filter="h;hpp;hxx;hm;inl;inc;xsd"
+			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+			>
+			<File
+				RelativePath="sangoma_boost_client.h"
+				>
+			</File>
+			<File
+				RelativePath="sangoma_boost_interface.h"
+				>
+			</File>
+			<File
+				RelativePath="sigboost.h"
+				>
+			</File>
+			<File
+				RelativePath="ftdm_sangoma_boost.h"
+				>
+			</File>
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>

Added: freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_sangoma_boost/ftmod_sangoma_boost.c (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_sangoma_boost/ftmod_sangoma_boost.c	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_sangoma_boost/ftmod_sangoma_boost.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,2273 @@
+/*
+ * Copyright (c) 2007, Anthony Minessale II
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Contributors: 
+ *
+ * Moises Silva <moy@sangoma.com>
+ * David Yat Sin <dyatsin@sangoma.com>
+ * Nenad Corbic <ncorbic@sangoma.com>
+ *
+ */
+
+/* NOTE:
+On __WINDOWS__ platform this code works with sigmod ONLY, don't try to make sense of any socket code for win
+I basically ifdef out everything that the compiler complained about
+*/
+
+#include "freetdm.h"
+#include "sangoma_boost_client.h"
+#include "ftdm_sangoma_boost.h"
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+
+/* Boost signaling modules global hash and its mutex */
+ftdm_mutex_t *g_boost_modules_mutex = NULL;
+ftdm_hash_t *g_boost_modules_hash = NULL;
+
+#define MAX_TRUNK_GROUPS 64
+//DAVIDY need to merge congestion_timeouts with ftdm_sangoma_boost_trunkgroups
+static time_t congestion_timeouts[MAX_TRUNK_GROUPS];
+
+static ftdm_sangoma_boost_trunkgroup_t *g_trunkgroups[MAX_TRUNK_GROUPS];
+
+#define BOOST_QUEUE_SIZE 500
+
+/* get freetdm span and chan depending on the span mode */
+#define BOOST_SPAN(ftdmchan) ((ftdm_sangoma_boost_data_t*)(ftdmchan)->span->signal_data)->sigmod ? ftdmchan->physical_span_id : ftdmchan->physical_span_id-1
+#define BOOST_CHAN(ftdmchan) ((ftdm_sangoma_boost_data_t*)(ftdmchan)->span->signal_data)->sigmod ? ftdmchan->physical_chan_id : ftdmchan->physical_chan_id-1
+
+/**
+ * \brief Strange flag
+ */
+typedef enum {
+	SFLAG_FREE_REQ_ID = (1 << 0),
+	SFLAG_SENT_FINAL_MSG = (1 << 1),
+	SFLAG_SENT_ACK = (1 << 2),
+	SFLAG_RECVD_ACK = (1 << 3),
+	SFLAG_HANGUP = (1 << 4),
+	SFLAG_TERMINATING = (1 << 5)
+} sflag_t;
+
+typedef uint16_t sangoma_boost_request_id_t;
+
+/**
+ * \brief SANGOMA boost request status
+ */
+typedef enum {
+	BST_FREE,
+	BST_WAITING,
+	BST_ACK,
+	BST_READY,
+	BST_FAIL
+} sangoma_boost_request_status_t;
+
+/**
+ * \brief SANGOMA boost request structure
+ */
+typedef struct {
+	sangoma_boost_request_status_t status;
+	sangomabc_short_event_t event;
+	ftdm_span_t *span;
+	ftdm_channel_t *ftdmchan;
+	int hangup_cause;
+	int flags;
+} sangoma_boost_request_t;
+
+//#define MAX_REQ_ID FTDM_MAX_PHYSICAL_SPANS_PER_LOGICAL_SPAN * FTDM_MAX_CHANNELS_PHYSICAL_SPAN
+#define MAX_REQ_ID 6000
+
+static uint16_t SETUP_GRID[FTDM_MAX_PHYSICAL_SPANS_PER_LOGICAL_SPAN+1][FTDM_MAX_CHANNELS_PHYSICAL_SPAN+1] = {{ 0 }};
+
+static sangoma_boost_request_t OUTBOUND_REQUESTS[MAX_REQ_ID+1] = {{ 0 }};
+
+static ftdm_mutex_t *request_mutex = NULL;
+
+static uint8_t req_map[MAX_REQ_ID+1] = { 0 };
+static uint8_t nack_map[MAX_REQ_ID+1] = { 0 };
+
+/**
+ * \brief Releases span and channel from setup grid
+ * \param span Span number
+ * \param chan Channel number
+ * \param func Calling function
+ * \param line Line number on request
+ * \return NULL if not found, channel otherwise
+ */
+static void __release_request_id_span_chan(int span, int chan, const char *func, int line)
+{
+	int id;
+
+	ftdm_mutex_lock(request_mutex);
+	if ((id = SETUP_GRID[span][chan])) {
+		assert(id <= MAX_REQ_ID);
+		req_map[id] = 0;
+		SETUP_GRID[span][chan] = 0;
+	}
+	ftdm_mutex_unlock(request_mutex);
+}
+#define release_request_id_span_chan(s, c) __release_request_id_span_chan(s, c, __FUNCTION__, __LINE__)
+
+/**
+ * \brief Releases request ID
+ * \param func Calling function
+ * \param line Line number on request
+ * \return NULL if not found, channel otherwise
+ */
+static void __release_request_id(sangoma_boost_request_id_t r, const char *func, int line)
+{
+	assert(r <= MAX_REQ_ID);
+	ftdm_mutex_lock(request_mutex);
+	req_map[r] = 0;
+	ftdm_mutex_unlock(request_mutex);
+}
+#define release_request_id(r) __release_request_id(r, __FUNCTION__, __LINE__)
+
+static sangoma_boost_request_id_t last_req = 0;
+
+/**
+ * \brief Gets the first available tank request ID
+ * \param func Calling function
+ * \param line Line number on request
+ * \return 0 on failure, request ID on success
+ */
+static sangoma_boost_request_id_t __next_request_id(const char *func, int line)
+{
+	sangoma_boost_request_id_t r = 0, i = 0;
+	int found=0;
+	
+	ftdm_mutex_lock(request_mutex);
+	//r = ++last_req;
+	//while(!r || req_map[r]) {
+
+	for (i=1; i<= MAX_REQ_ID; i++){
+		r = ++last_req;
+
+		if (r >= MAX_REQ_ID) {
+			r = i = last_req = 1;
+		}
+
+		if (req_map[r]) {
+			/* Busy find another */
+			continue;
+
+		}
+
+		req_map[r] = 1;
+		found=1;
+		break;
+
+	}
+
+	ftdm_mutex_unlock(request_mutex);
+
+	if (!found) {
+		return 0;
+	}
+
+	return r;
+}
+#define next_request_id() __next_request_id(__FUNCTION__, __LINE__)
+
+/**
+ * \brief Finds the channel that triggered an event
+ * \param span Span where to search the channel
+ * \param event SANGOMA event
+ * \param force Do not wait for the channel to be available if in use
+ * \return NULL if not found, channel otherwise
+ */
+static ftdm_channel_t *find_ftdmchan(ftdm_span_t *span, sangomabc_short_event_t *event, int force)
+{
+	uint32_t i;
+	ftdm_channel_t *ftdmchan = NULL;
+	ftdm_sangoma_boost_data_t *sangoma_boost_data = span->signal_data;
+	uint32_t targetspan = event->span+1;
+	uint32_t targetchan = event->chan+1;
+	if (sangoma_boost_data->sigmod) {
+		/* span is not strictly needed here since we're supposed to get only events for our span */
+		targetspan = event->span;
+		targetchan = event->chan;
+	}
+
+	for(i = 1; i <= span->chan_count; i++) {
+		if (span->channels[i]->physical_span_id == targetspan && span->channels[i]->physical_chan_id == targetchan) {
+			ftdmchan = span->channels[i];
+			if (force || (ftdmchan->state == FTDM_CHANNEL_STATE_DOWN && !ftdm_test_flag(ftdmchan, FTDM_CHANNEL_INUSE))) {
+				break;
+			} else {
+				ftdmchan = NULL;
+				ftdm_log(FTDM_LOG_DEBUG, "Channel %d:%d ~ %d:%d is already in use.\n",
+						span->channels[i]->span_id,
+						span->channels[i]->chan_id,
+						span->channels[i]->physical_span_id,
+						span->channels[i]->physical_chan_id
+						);
+				break;
+			}
+		}
+	}
+
+	return ftdmchan;
+}
+
+static int check_congestion(int trunk_group)
+{
+	if (congestion_timeouts[trunk_group]) {
+		time_t now = time(NULL);
+
+		if (now >= congestion_timeouts[trunk_group]) {
+			congestion_timeouts[trunk_group] = 0;
+		} else {
+			return 1;
+		}
+	}
+
+	return 0;
+}
+
+
+/**
+ * \brief Requests an sangoma boost channel on a span (outgoing call)
+ * \param span Span where to get a channel
+ * \param chan_id Specific channel to get (0 for any)
+ * \param direction Call direction
+ * \param caller_data Caller information
+ * \param ftdmchan Channel to initialise
+ * \return Success or failure
+ */
+static FIO_CHANNEL_REQUEST_FUNCTION(sangoma_boost_channel_request)
+{
+	ftdm_sangoma_boost_data_t *sangoma_boost_data = span->signal_data;
+	ftdm_status_t status = FTDM_FAIL;
+	sangoma_boost_request_id_t r;
+	sangomabc_event_t event = {0};
+	/* sanity has to be more than 8 seconds.
+	 * In PRI specs, timeout is 4 seconds for remote switch to respond to a SETUP,
+	 * and PRI stack will retransmit a second SETUP after the first timeout, so
+	 * we should allow for at least 8 seconds.
+	 */
+	int boost_request_timeout = 10000;
+	sangoma_boost_request_status_t st;
+	char dnis[128] = "";
+	char *gr = NULL;
+	uint32_t count = 0;
+	int tg=0;
+	
+	if (sangoma_boost_data->sigmod) {
+		ftdm_log(FTDM_LOG_CRIT, "This function should not be called when sigmod was configured in boost\n");
+		*ftdmchan = NULL;
+		return FTDM_FAIL;
+	}
+
+	if (ftdm_test_flag(span, FTDM_SPAN_SUSPENDED)) {
+		ftdm_log(FTDM_LOG_CRIT, "SPAN is not online.\n");
+		*ftdmchan = NULL;
+		return FTDM_FAIL;
+	}
+	
+	ftdm_set_string(dnis, caller_data->dnis.digits);
+
+	r = next_request_id();
+	if (r == 0) {
+		ftdm_log(FTDM_LOG_CRIT, "All tanks ids are busy.\n");
+		*ftdmchan = NULL;
+		return FTDM_FAIL;
+	}
+	sangomabc_call_init(&event, caller_data->cid_num.digits, dnis, r);
+
+	if ((gr = strchr(dnis, '@'))) {
+		*gr++ = '\0';
+	}
+
+	if (gr && *(gr+1)) {
+		tg = atoi(gr+1);
+		if (tg > 0) {
+			tg--;
+		}
+	}
+	event.trunk_group = tg;
+
+	if (check_congestion(tg)) {
+		ftdm_log(FTDM_LOG_CRIT, "All circuits are busy. Trunk Group=%i (BOOST REQUESTED BACK OFF)\n",tg+1);
+		*ftdmchan = NULL;
+		return FTDM_FAIL;
+	}
+
+	ftdm_span_channel_use_count(span, &count);
+
+	if (count >= span->chan_count) {
+		ftdm_log(FTDM_LOG_CRIT, "All circuits are busy.\n");
+		*ftdmchan = NULL;
+		return FTDM_FAIL;
+	}	
+
+	if (gr && *(gr+1)) {
+		switch(*gr) {
+				case 'g':
+						event.hunt_group = SIGBOOST_HUNTGRP_SEQ_ASC;
+						break;
+				case 'G':
+						event.hunt_group = SIGBOOST_HUNTGRP_SEQ_DESC;
+						break;
+				case 'r':
+						event.hunt_group = SIGBOOST_HUNTGRP_RR_ASC;
+						break;
+				case 'R':
+						event.hunt_group = SIGBOOST_HUNTGRP_RR_DESC;
+						break;
+				default:
+						ftdm_log(FTDM_LOG_WARNING, "Failed to determine huntgroup (%s)\n", gr);
+									event.hunt_group = SIGBOOST_HUNTGRP_SEQ_ASC;
+		}
+	}
+
+	ftdm_set_string(event.calling_name, caller_data->cid_name);
+	ftdm_set_string(event.rdnis.digits, caller_data->rdnis.digits);
+	if (strlen(caller_data->rdnis.digits)) {
+			event.rdnis.digits_count = strlen(caller_data->rdnis.digits)+1;
+			event.rdnis.ton = caller_data->rdnis.type;
+			event.rdnis.npi = caller_data->rdnis.plan;
+	}
+    
+	event.calling.screening_ind = caller_data->screen;
+	event.calling.presentation_ind = caller_data->pres;
+
+	event.calling.ton = caller_data->cid_num.type;
+	event.calling.npi = caller_data->cid_num.plan;
+
+	event.called.ton = caller_data->dnis.type;
+	event.called.npi = caller_data->dnis.plan;
+
+	OUTBOUND_REQUESTS[r].status = BST_WAITING;
+	OUTBOUND_REQUESTS[r].span = span;
+
+	if (sangomabc_connection_write(&sangoma_boost_data->mcon, &event) <= 0) {
+		ftdm_log(FTDM_LOG_CRIT, "Failed to tx boost event [%s]\n", strerror(errno));
+		status = FTDM_FAIL;
+		if (!sangoma_boost_data->sigmod) {
+			*ftdmchan = NULL;
+		}
+		goto done;
+	}
+
+	while(ftdm_running() && OUTBOUND_REQUESTS[r].status == BST_WAITING) {
+		ftdm_sleep(1);
+		if (--boost_request_timeout <= 0) {
+			status = FTDM_FAIL;
+			if (!sangoma_boost_data->sigmod) {
+				*ftdmchan = NULL;
+			}
+			ftdm_log(FTDM_LOG_CRIT, "s%dc%d: Csid:%d Timed out waiting for boost channel request response, current status: BST_WAITING\n", (*ftdmchan)->physical_span_id, (*ftdmchan)->physical_chan_id, r);
+			goto done;
+		}
+	}
+
+	if (OUTBOUND_REQUESTS[r].status == BST_READY && OUTBOUND_REQUESTS[r].ftdmchan) {
+		*ftdmchan = OUTBOUND_REQUESTS[r].ftdmchan;
+		status = FTDM_SUCCESS;
+	} else {
+		status = FTDM_FAIL;
+		if (!sangoma_boost_data->sigmod) {
+			*ftdmchan = NULL;
+		}
+	}
+
+ done:
+	
+	st = OUTBOUND_REQUESTS[r].status;
+	OUTBOUND_REQUESTS[r].status = BST_FREE;	
+
+	if (status == FTDM_FAIL) {
+		if (st == BST_FAIL) {
+			caller_data->hangup_cause = OUTBOUND_REQUESTS[r].hangup_cause;
+		} else {
+			caller_data->hangup_cause = FTDM_CAUSE_RECOVERY_ON_TIMER_EXPIRE;
+		}
+	}
+	
+	if (st == BST_FAIL) {
+		release_request_id(r);
+	} else if (st != BST_READY) {
+		ftdm_assert_return(r <= MAX_REQ_ID, FTDM_FAIL, "Invalid index\n");
+		nack_map[r] = 1;
+		if (sangoma_boost_data->sigmod) {
+			sangomabc_exec_command(&sangoma_boost_data->mcon,
+								BOOST_SPAN((*ftdmchan)),
+								BOOST_CHAN((*ftdmchan)),
+								r,
+								SIGBOOST_EVENT_CALL_START_NACK,
+								0, 0);
+		} else {
+			sangomabc_exec_command(&sangoma_boost_data->mcon,
+								0,
+								0,
+								r,
+								SIGBOOST_EVENT_CALL_START_NACK,
+								0, 0);
+		}
+	}
+
+	return status;
+}
+
+/**
+ * \brief Starts an sangoma boost channel (outgoing call)
+ * \param ftdmchan Channel to initiate call on
+ * \return Success
+ */
+static FIO_CHANNEL_OUTGOING_CALL_FUNCTION(sangoma_boost_outgoing_call)
+{
+	char dnis[128] = "";
+	sangoma_boost_request_id_t r;
+	sangomabc_event_t event = {0};
+	ftdm_sangoma_boost_data_t *sangoma_boost_data = ftdmchan->span->signal_data;
+	if (!sangoma_boost_data->sigmod) {
+		return FTDM_SUCCESS;
+	}
+	ftdm_set_string(dnis, ftdmchan->caller_data.dnis.digits);
+
+	r = next_request_id();
+	if (r == 0) {
+		ftdm_log(FTDM_LOG_CRIT, "All boost request ids are busy.\n");
+		return FTDM_FAIL;
+	}
+	
+	ftdm_set_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND);
+
+	sangomabc_call_init(&event, ftdmchan->caller_data.cid_num.digits, dnis, r);
+
+	event.span = (uint8_t)ftdmchan->physical_span_id;
+	event.chan = (uint8_t)ftdmchan->physical_chan_id;
+
+	ftdm_set_string(event.calling_name, ftdmchan->caller_data.cid_name);
+	ftdm_set_string(event.rdnis.digits, ftdmchan->caller_data.rdnis.digits);
+	if (strlen(ftdmchan->caller_data.rdnis.digits)) {
+			event.rdnis.digits_count = strlen(ftdmchan->caller_data.rdnis.digits)+1;
+			event.rdnis.ton = ftdmchan->caller_data.rdnis.type;
+			event.rdnis.npi = ftdmchan->caller_data.rdnis.plan;
+	}
+    
+	event.calling.screening_ind = ftdmchan->caller_data.screen;
+	event.calling.presentation_ind = ftdmchan->caller_data.pres;
+
+	event.calling.ton = ftdmchan->caller_data.cid_num.type;
+	event.calling.npi = ftdmchan->caller_data.cid_num.plan;
+
+	event.called.ton = ftdmchan->caller_data.dnis.type;
+	event.called.npi = ftdmchan->caller_data.dnis.plan;
+
+	OUTBOUND_REQUESTS[r].status = BST_WAITING;
+	OUTBOUND_REQUESTS[r].span = ftdmchan->span;
+	OUTBOUND_REQUESTS[r].ftdmchan = ftdmchan;
+
+	ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DIALING);
+
+	ftdm_log(FTDM_LOG_DEBUG, "Dialing number %s over boost channel with request id %d\n", event.called_number_digits, r);
+	if (sangomabc_connection_write(&sangoma_boost_data->mcon, &event) <= 0) {
+		ftdm_log(FTDM_LOG_CRIT, "Failed to tx boost event [%s]\n", strerror(errno));
+		return FTDM_FAIL;
+	}
+			
+	return FTDM_SUCCESS;
+}
+
+/**
+ * \brief Handler for call start ack no media event
+ * \param mcon sangoma boost connection
+ * \param event Event to handle
+ */
+static void handle_call_progress(ftdm_span_t *span, sangomabc_connection_t *mcon, sangomabc_short_event_t *event)
+{
+	ftdm_channel_t *ftdmchan;
+
+
+	if ((ftdmchan = find_ftdmchan(span, event, 1))) {
+		ftdm_sangoma_boost_data_t *sangoma_boost_data = ftdmchan->span->signal_data;
+		ftdm_mutex_lock(ftdmchan->mutex);
+		if (!sangoma_boost_data->sigmod && ftdmchan->state == FTDM_CHANNEL_STATE_HOLD) {
+			if ((event->flags & SIGBOOST_PROGRESS_MEDIA)) {
+				ftdmchan->init_state = FTDM_CHANNEL_STATE_PROGRESS_MEDIA;
+				ftdm_log(FTDM_LOG_DEBUG, "Channel init state updated to PROGRESS_MEDIA [Csid:%d]\n", event->call_setup_id);
+			} else if ((event->flags & SIGBOOST_PROGRESS_RING)) {
+				ftdmchan->init_state = FTDM_CHANNEL_STATE_PROGRESS;
+				ftdm_log(FTDM_LOG_DEBUG, "Channel init state updated to PROGRESS [Csid:%d]\n", event->call_setup_id);
+			} else {
+				ftdmchan->init_state = FTDM_CHANNEL_STATE_IDLE;
+				ftdm_log(FTDM_LOG_DEBUG, "Channel init state updated to IDLE [Csid:%d]\n", event->call_setup_id);
+			}			
+		} else {
+			if ((event->flags & SIGBOOST_PROGRESS_MEDIA)) {
+				ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_PROGRESS_MEDIA);
+			} else if ((event->flags & SIGBOOST_PROGRESS_RING)) {
+				ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_PROGRESS);
+			} else {
+				ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_IDLE);
+			}
+		}
+		ftdm_mutex_unlock(ftdmchan->mutex);
+	}
+}
+
+/**
+ * \brief Handler for call start ack event
+ * \param mcon sangoma boost connection
+ * \param event Event to handle
+ */
+static void handle_call_start_ack(sangomabc_connection_t *mcon, sangomabc_short_event_t *event)
+{
+	
+	ftdm_channel_t *ftdmchan = NULL;
+	uint32_t event_span = event->span+1;
+	uint32_t event_chan = event->chan+1;
+
+	if (nack_map[event->call_setup_id]) {
+		return;
+	}
+
+	if (mcon->sigmod) {
+		event_span = event->span;
+		event_chan = event->chan;
+	}
+
+	OUTBOUND_REQUESTS[event->call_setup_id].event = *event;
+	SETUP_GRID[event->span][event->chan] = event->call_setup_id;
+
+	if (mcon->sigmod) {
+		ftdmchan = OUTBOUND_REQUESTS[event->call_setup_id].ftdmchan;
+	} else {
+		ftdmchan = find_ftdmchan(OUTBOUND_REQUESTS[event->call_setup_id].span, event, 0);
+	}
+
+
+	if (ftdmchan) {
+		ftdm_sangoma_boost_data_t *sangoma_boost_data = ftdmchan->span->signal_data;
+		if (ftdm_channel_open_chan(ftdmchan) != FTDM_SUCCESS) {
+			ftdm_log(FTDM_LOG_ERROR, "Failed to open FTDM channel [%s]\n", ftdmchan->last_error);
+		} else {
+			ftdm_set_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND);
+			ftdm_set_flag_locked(ftdmchan, FTDM_CHANNEL_INUSE);
+			ftdmchan->sflags = SFLAG_RECVD_ACK;
+
+			if ((event->flags & SIGBOOST_PROGRESS_MEDIA)) {
+				if (sangoma_boost_data->sigmod) {
+					ftdm_log(FTDM_LOG_DEBUG, "Channel state changing to PROGRESS_MEDIA [Csid:%d]\n", event->call_setup_id);
+					ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_PROGRESS_MEDIA);
+				} else {
+					ftdmchan->init_state = FTDM_CHANNEL_STATE_PROGRESS_MEDIA;
+					ftdm_log(FTDM_LOG_DEBUG, "Channel init state changed to PROGRESS_MEDIA [Csid:%d]\n", event->call_setup_id);
+				}
+			} else if ((event->flags & SIGBOOST_PROGRESS_RING)) {
+				if (sangoma_boost_data->sigmod) {
+					ftdm_log(FTDM_LOG_DEBUG, "Channel state changing to PROGRESS [Csid:%d]\n", event->call_setup_id);
+					ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_PROGRESS);
+				} else {
+					ftdmchan->init_state = FTDM_CHANNEL_STATE_PROGRESS;
+					ftdm_log(FTDM_LOG_DEBUG, "Channel init state changed to PROGRESS [Csid:%d]\n", event->call_setup_id);
+				}
+			} else {
+				if (sangoma_boost_data->sigmod) {
+					/* should we set a state here? */
+				} else {
+					ftdmchan->init_state = FTDM_CHANNEL_STATE_IDLE;
+					ftdm_log(FTDM_LOG_DEBUG, "Channel init state changed to IDLE [Csid:%d]\n", event->call_setup_id);
+				}
+			}
+			if (!sangoma_boost_data->sigmod) {
+				ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HOLD);
+				ftdm_log(FTDM_LOG_DEBUG, "Assigned chan %d:%d (%d:%d) to CSid=%d\n", 
+						ftdmchan->span_id, ftdmchan->chan_id, event_span, event_chan, event->call_setup_id);
+				OUTBOUND_REQUESTS[event->call_setup_id].ftdmchan = ftdmchan;
+			}
+			OUTBOUND_REQUESTS[event->call_setup_id].flags = event->flags;
+			OUTBOUND_REQUESTS[event->call_setup_id].status = BST_READY;
+			return;
+		}
+	} 
+
+	if (!ftdmchan) {
+		ftdm_log(FTDM_LOG_CRIT, "START ACK CANT FIND A CHAN %d:%d\n", event->span+1,event->chan+1);
+	} else {
+		/* only reason to be here is failed to open channel when we we're in sigmod  */
+		ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING);
+	}
+	ftdm_set_sflag(ftdmchan, SFLAG_SENT_FINAL_MSG);
+	sangomabc_exec_command(mcon,
+					   event->span,
+					   event->chan,
+					   event->call_setup_id,
+					   SIGBOOST_EVENT_CALL_STOPPED,
+					   FTDM_CAUSE_DESTINATION_OUT_OF_ORDER, 0);
+	OUTBOUND_REQUESTS[event->call_setup_id].status = BST_FAIL;
+	OUTBOUND_REQUESTS[event->call_setup_id].hangup_cause = FTDM_CAUSE_DESTINATION_OUT_OF_ORDER;
+}
+
+/**
+ * \brief Handler for call done event
+ * \param span Span where event was fired
+ * \param mcon sangoma boost connection
+ * \param event Event to handle
+ */
+static void handle_call_done(ftdm_span_t *span, sangomabc_connection_t *mcon, sangomabc_short_event_t *event)
+{
+	ftdm_channel_t *ftdmchan;
+	int r = 0;
+	
+	if ((ftdmchan = find_ftdmchan(span, event, 1))) {
+		ftdm_sangoma_boost_data_t *sangoma_boost_data = ftdmchan->span->signal_data;
+		ftdm_mutex_lock(ftdmchan->mutex);
+
+		if (sangoma_boost_data->sigmod) {
+			/* not really completely done, but if we ever get an incoming call before moving to HANGUP_COMPLETE
+			 * handle_incoming_call() will take care of moving the state machine to release the channel */
+			sangomabc_exec_command(&sangoma_boost_data->mcon,
+								BOOST_SPAN(ftdmchan),
+								BOOST_CHAN(ftdmchan),
+								0,
+								SIGBOOST_EVENT_CALL_RELEASED,
+								0, 0);
+		}
+
+		if (ftdmchan->state == FTDM_CHANNEL_STATE_DOWN || ftdmchan->state == FTDM_CHANNEL_STATE_HANGUP_COMPLETE || ftdm_test_sflag(ftdmchan, SFLAG_TERMINATING)) {
+			goto done;
+		}
+
+		ftdm_set_state_r(ftdmchan, FTDM_CHANNEL_STATE_HANGUP_COMPLETE, 0, r);
+		if (r) {
+			ftdm_set_sflag(ftdmchan, SFLAG_FREE_REQ_ID);
+			ftdm_mutex_unlock(ftdmchan->mutex);
+			return;
+		}
+	} 
+
+ done:
+	
+	if (ftdmchan) {
+		ftdm_mutex_unlock(ftdmchan->mutex);
+	}
+
+	if (event->call_setup_id) {
+		release_request_id(event->call_setup_id);
+	} else {
+		release_request_id_span_chan(event->span, event->chan);
+	}
+}
+
+/**
+ * \brief Handler for call start nack event
+ * \param span Span where event was fired
+ * \param mcon sangoma boost connection
+ * \param event Event to handle
+ */
+static void handle_call_start_nack(ftdm_span_t *span, sangomabc_connection_t *mcon, sangomabc_short_event_t *event)
+{
+	ftdm_channel_t *ftdmchan;
+	ftdm_sangoma_boost_data_t *sangoma_boost_data = span->signal_data;
+
+	if (event->release_cause == SIGBOOST_CALL_SETUP_NACK_ALL_CKTS_BUSY) {
+		uint32_t count = 0;
+		int delay = 0;
+		int tg=event->trunk_group;
+
+		ftdm_span_channel_use_count(span, &count);
+
+		delay = (int) (count / 100) * 2;
+		
+		if (delay > 10) {
+			delay = 10;
+		} else if (delay < 1) {
+			delay = 1;
+		}
+
+		if (tg < 0 || tg >= MAX_TRUNK_GROUPS) {
+			ftdm_log(FTDM_LOG_CRIT, "Invalid All Ckt Busy trunk group number %i\n", tg);
+			tg=0;
+		}
+		
+		congestion_timeouts[tg] = time(NULL) + delay;
+		event->release_cause = 17;
+
+	} else if (event->release_cause == SIGBOOST_CALL_SETUP_CSUPID_DBL_USE) {
+		event->release_cause = 17;
+	}
+
+	if (event->call_setup_id) {
+		if (sangoma_boost_data->sigmod) {
+			ftdmchan = OUTBOUND_REQUESTS[event->call_setup_id].ftdmchan;
+			ftdmchan->call_data = (void*)(intptr_t)event->event_id;
+			ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING);
+		} else {
+			sangomabc_exec_command(mcon,
+						   0,
+						   0,
+						   event->call_setup_id,
+						   SIGBOOST_EVENT_CALL_START_NACK_ACK,
+						   0, 0);
+			OUTBOUND_REQUESTS[event->call_setup_id].event = *event;
+			OUTBOUND_REQUESTS[event->call_setup_id].status = BST_FAIL;
+			OUTBOUND_REQUESTS[event->call_setup_id].hangup_cause = event->release_cause;
+			ftdm_log(FTDM_LOG_DEBUG, "setting outbound request status %d to BST_FAIL\n", event->call_setup_id);
+		}
+		return;
+	} else {
+		if ((ftdmchan = find_ftdmchan(span, event, 1))) {
+			int r = 0;
+
+			/* if there is no call setup id this should not be an outbound channel for sure */
+			ftdm_assert(!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND), "Yay, outbound flag should not be set here!\n");
+
+			ftdmchan->call_data = (void*)(intptr_t)event->event_id;
+			ftdm_mutex_lock(ftdmchan->mutex);
+			ftdm_set_state_r(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING, 0, r);
+			if (r == FTDM_STATE_CHANGE_SUCCESS) {
+				ftdmchan->caller_data.hangup_cause = event->release_cause;
+			}
+			ftdm_mutex_unlock(ftdmchan->mutex);
+			if (r) {
+				return;
+			}
+		} 
+	}
+
+	if (ftdmchan) {
+		ftdm_set_sflag_locked(ftdmchan, SFLAG_SENT_FINAL_MSG);
+	}
+
+	/* nobody else will do it so we have to do it ourselves */
+	sangomabc_exec_command(mcon,
+					   event->span,
+					   event->chan,
+					   0,
+					   SIGBOOST_EVENT_CALL_START_NACK_ACK,
+					   0, 0);
+}
+
+static void handle_call_released(ftdm_span_t *span, sangomabc_connection_t *mcon, sangomabc_short_event_t *event)
+{
+	ftdm_channel_t *ftdmchan;
+	
+	if ((ftdmchan = find_ftdmchan(span, event, 1))) {
+		ftdm_log(FTDM_LOG_DEBUG, "Releasing completely chan s%dc%d\n", event->span, event->chan);
+		ftdm_channel_done(ftdmchan);
+	} else {
+		ftdm_log(FTDM_LOG_ERROR, "Odd, We could not find chan: s%dc%d to release the call completely!!\n", event->span, event->chan);
+	}
+}
+
+/**
+ * \brief Handler for call stop event
+ * \param span Span where event was fired
+ * \param mcon sangoma boost connection
+ * \param event Event to handle
+ */
+static void handle_call_stop(ftdm_span_t *span, sangomabc_connection_t *mcon, sangomabc_short_event_t *event)
+{
+	ftdm_channel_t *ftdmchan;
+	
+	if ((ftdmchan = find_ftdmchan(span, event, 1))) {
+		int r = 0;
+
+		ftdm_mutex_lock(ftdmchan->mutex);
+		
+		if (ftdm_test_sflag(ftdmchan, SFLAG_HANGUP)) {
+			/* racing condition where both sides initiated a hangup 
+			 * Do not change current state as channel is already clearing
+			 * itself through local initiated hangup */
+			
+			sangomabc_exec_command(mcon,
+						BOOST_SPAN(ftdmchan),
+						BOOST_CHAN(ftdmchan),
+						0,
+						SIGBOOST_EVENT_CALL_STOPPED_ACK,
+						0, 0);
+			ftdm_mutex_unlock(ftdmchan->mutex);
+			return;
+		} else if (ftdmchan->state == FTDM_CHANNEL_STATE_HOLD) {
+			ftdmchan->init_state = FTDM_CHANNEL_STATE_TERMINATING;
+			ftdm_log(FTDM_LOG_DEBUG, "Channel init state updated to TERMINATING [Csid:%d]\n", event->call_setup_id);
+			OUTBOUND_REQUESTS[event->call_setup_id].hangup_cause = event->release_cause;
+			ftdmchan->caller_data.hangup_cause = event->release_cause;
+			ftdm_mutex_unlock(ftdmchan->mutex);
+			return;
+		} else {
+			ftdm_set_state_r(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING, 0, r);
+		}
+
+		if (r == FTDM_STATE_CHANGE_SUCCESS) {
+			ftdmchan->caller_data.hangup_cause = event->release_cause;
+		}
+
+		if (r) {
+			ftdm_set_sflag(ftdmchan, SFLAG_FREE_REQ_ID);
+		}
+
+		ftdm_mutex_unlock(ftdmchan->mutex);
+
+		if (r) {
+			return;
+		}
+	} else { /* we have to do it ourselves.... */
+		ftdm_log(FTDM_LOG_ERROR, "Odd, We could not find chan: s%dc%d\n", event->span, event->chan);
+		release_request_id_span_chan(event->span, event->chan);
+	}
+}
+
+/**
+ * \brief Handler for call answer event
+ * \param span Span where event was fired
+ * \param mcon sangoma boost connection
+ * \param event Event to handle
+ */
+static void handle_call_answer(ftdm_span_t *span, sangomabc_connection_t *mcon, sangomabc_short_event_t *event)
+{
+	ftdm_channel_t *ftdmchan;
+	
+	if ((ftdmchan = find_ftdmchan(span, event, 1))) {
+		ftdm_mutex_lock(ftdmchan->mutex);
+		if (ftdmchan->state == FTDM_CHANNEL_STATE_HOLD) {
+			ftdmchan->init_state = FTDM_CHANNEL_STATE_UP;
+		} else {
+			int r = 0;
+			ftdm_set_state_r(ftdmchan, FTDM_CHANNEL_STATE_UP, 0, r);
+		}
+		ftdm_mutex_unlock(ftdmchan->mutex);
+	} else {
+		ftdm_log(FTDM_LOG_CRIT, "ANSWER CANT FIND A CHAN %d:%d\n", event->span+1,event->chan+1);
+		sangomabc_exec_command(mcon,
+							   event->span,
+							   event->chan,
+							   event->call_setup_id,
+							   SIGBOOST_EVENT_CALL_STOPPED,
+							   FTDM_CAUSE_DESTINATION_OUT_OF_ORDER, 0);
+	}
+}
+
+static __inline__ void advance_chan_states(ftdm_channel_t *ftdmchan);
+
+/**
+ * \brief Handler for call start event
+ * \param span Span where event was fired
+ * \param mcon sangoma boost connection
+ * \param event Event to handle
+ */
+static void handle_call_start(ftdm_span_t *span, sangomabc_connection_t *mcon, sangomabc_event_t *event)
+{
+	ftdm_channel_t *ftdmchan;
+
+	if (!(ftdmchan = find_ftdmchan(span, (sangomabc_short_event_t*)event, 0))) {
+		if ((ftdmchan = find_ftdmchan(span, (sangomabc_short_event_t*)event, 1))) {
+			int r;
+			if (ftdmchan->state == FTDM_CHANNEL_STATE_UP) {
+				ftdm_log(FTDM_LOG_CRIT, "ZCHAN STATE UP -> Changed to TERMINATING %d:%d\n", event->span+1,event->chan+1);
+				ftdm_set_state_r(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING, 0, r);
+			} else if (ftdm_test_sflag(ftdmchan, SFLAG_HANGUP)) { 
+				ftdm_log(FTDM_LOG_CRIT, "ZCHAN STATE HANGUP -> Changed to HANGUP COMPLETE %d:%d\n", event->span+1,event->chan+1);
+				ftdm_set_state_r(ftdmchan, FTDM_CHANNEL_STATE_HANGUP_COMPLETE, 0, r);
+			} else {
+				ftdm_log(FTDM_LOG_CRIT, "ZCHAN STATE INVALID %s on IN CALL %d:%d\n", ftdm_channel_state2str(ftdmchan->state),event->span+1,event->chan+1);
+
+			}
+			ftdm_set_sflag(ftdmchan, SFLAG_SENT_FINAL_MSG);
+			ftdmchan=NULL;
+		}
+		ftdm_log(FTDM_LOG_CRIT, "START CANT FIND CHAN %d:%d\n", event->span+1,event->chan+1);
+		goto error;
+	}
+
+	if (ftdm_channel_open_chan(ftdmchan) != FTDM_SUCCESS) {
+		ftdm_log(FTDM_LOG_CRIT, "START CANT OPEN CHAN %d:%d\n", event->span+1,event->chan+1);
+		goto error;
+	}
+	
+	ftdm_log(FTDM_LOG_DEBUG, "Got call start from s%dc%d mapped to freetdm logical s%dc%d, physical s%dc%d\n", 
+			event->span, event->chan, 
+			ftdmchan->span_id, ftdmchan->chan_id,
+			ftdmchan->physical_span_id, ftdmchan->physical_chan_id);
+
+	ftdmchan->sflags = 0;
+	ftdm_set_string(ftdmchan->caller_data.cid_num.digits, (char *)event->calling.digits);
+	ftdm_set_string(ftdmchan->caller_data.cid_name, (char *)event->calling.digits);
+	ftdm_set_string(ftdmchan->caller_data.ani.digits, (char *)event->calling.digits);
+	ftdm_set_string(ftdmchan->caller_data.dnis.digits, (char *)event->called.digits);
+	ftdm_set_string(ftdmchan->caller_data.rdnis.digits, (char *)event->rdnis.digits);
+
+	if (strlen(event->calling_name)) {
+		ftdm_set_string(ftdmchan->caller_data.cid_name, (char *)event->calling_name);
+	}
+
+	ftdmchan->caller_data.cid_num.plan = event->calling.npi;
+	ftdmchan->caller_data.cid_num.type = event->calling.ton;
+
+	ftdmchan->caller_data.ani.plan = event->calling.npi;
+	ftdmchan->caller_data.ani.type = event->calling.ton;
+
+	ftdmchan->caller_data.dnis.plan = event->called.npi;
+	ftdmchan->caller_data.dnis.type = event->called.ton;
+
+	ftdmchan->caller_data.rdnis.plan = event->rdnis.npi;
+	ftdmchan->caller_data.rdnis.type = event->rdnis.ton;
+
+	ftdmchan->caller_data.screen = event->calling.screening_ind;
+	ftdmchan->caller_data.pres = event->calling.presentation_ind;
+
+	if (event->custom_data_size) {
+		char* p = NULL;
+
+		p = strstr((char*)event->custom_data,"PRI001-ANI2-");
+		if (p!=NULL) {
+			int ani2 = 0;
+			sscanf(p, "PRI001-ANI2-%d", &ani2);
+			snprintf(ftdmchan->caller_data.aniII, 5, "%.2d", ani2);
+		}	
+	}
+
+	ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_RING);
+	return;
+
+ error:
+	sangomabc_exec_command(mcon,
+						   event->span,
+						   event->chan,
+						   0,
+						   SIGBOOST_EVENT_CALL_START_NACK,
+						   0, 0);
+		
+}
+
+static void handle_call_loop_start(ftdm_span_t *span, sangomabc_connection_t *mcon, sangomabc_short_event_t *event)
+{
+	ftdm_status_t res = FTDM_FAIL;
+	ftdm_channel_t *ftdmchan;
+
+	if (!(ftdmchan = find_ftdmchan(span, (sangomabc_short_event_t*)event, 0))) {
+		ftdm_log(FTDM_LOG_CRIT, "CANNOT START LOOP, CHAN NOT AVAILABLE %d:%d\n", event->span+1,event->chan+1);
+		return;
+	}
+
+	if (ftdm_channel_open_chan(ftdmchan) != FTDM_SUCCESS) {
+		ftdm_log(FTDM_LOG_CRIT, "CANNOT START LOOP, CANT OPEN CHAN %d:%d\n", event->span+1,event->chan+1);
+		return;
+	}
+
+	ftdm_set_state_r(ftdmchan, FTDM_CHANNEL_STATE_IN_LOOP, 0, res);
+	if (res != FTDM_SUCCESS) {
+		ftdm_log(FTDM_LOG_CRIT, "yay, could not set the state of the channel to IN_LOOP, loop will fail\n");
+		ftdm_channel_done(ftdmchan);
+		return;
+	}
+	ftdm_channel_command(ftdmchan, FTDM_COMMAND_ENABLE_LOOP, NULL);
+}
+
+static void handle_call_loop_stop(ftdm_span_t *span, sangomabc_connection_t *mcon, sangomabc_short_event_t *event)
+{
+	ftdm_channel_t *ftdmchan;
+	ftdm_status_t res = FTDM_FAIL;
+	if (!(ftdmchan = find_ftdmchan(span, (sangomabc_short_event_t*)event, 1))) {
+		ftdm_log(FTDM_LOG_CRIT, "CANNOT STOP LOOP, INVALID CHAN REQUESTED %d:%d\n", event->span+1,event->chan+1);
+		return;
+	}
+	if (ftdmchan->state != FTDM_CHANNEL_STATE_IN_LOOP) {
+		ftdm_log(FTDM_LOG_ERROR, "Got stop loop request in a channel that is not in loop, ignoring ...\n");
+		return;
+	}
+	ftdm_channel_command(ftdmchan, FTDM_COMMAND_DISABLE_LOOP, NULL);
+	/* even when we did not sent a msg we set this flag to avoid sending call stop in the DOWN state handler */
+	ftdm_set_flag(ftdmchan, SFLAG_SENT_FINAL_MSG);
+	ftdm_set_state_r(ftdmchan, FTDM_CHANNEL_STATE_DOWN, 0, res);
+}
+
+/**
+ * \brief Handler for heartbeat event
+ * \param mcon sangoma boost connection
+ * \param event Event to handle
+ */
+static void handle_heartbeat(sangomabc_connection_t *mcon, sangomabc_short_event_t *event)
+{
+	int err;
+	
+	err = sangomabc_connection_writep(mcon, (sangomabc_event_t*)event);
+	
+	if (err <= 0) {
+		ftdm_log(FTDM_LOG_CRIT, "Failed to tx on boost connection [%s]: %s\n", strerror(errno));
+	}
+    return;
+}
+
+/**
+ * \brief Handler for restart ack event
+ * \param mcon sangoma boost connection
+ * \param span Span where event was fired
+ * \param event Event to handle
+ */
+static void handle_restart_ack(sangomabc_connection_t *mcon, ftdm_span_t *span, sangomabc_short_event_t *event)
+{
+	ftdm_log(FTDM_LOG_DEBUG, "RECV RESTART ACK\n");
+}
+
+/**
+ * \brief Handler for restart event
+ * \param mcon sangoma boost connection
+ * \param span Span where event was fired
+ * \param event Event to handle
+ */
+static void handle_restart(sangomabc_connection_t *mcon, ftdm_span_t *span, sangomabc_short_event_t *event)
+{
+	ftdm_sangoma_boost_data_t *sangoma_boost_data = span->signal_data;
+
+    mcon->rxseq_reset = 0;
+	ftdm_set_flag((&sangoma_boost_data->mcon), MSU_FLAG_DOWN);
+	ftdm_set_flag_locked(span, FTDM_SPAN_SUSPENDED);
+	ftdm_set_flag(sangoma_boost_data, FTDM_SANGOMA_BOOST_RESTARTING);
+	
+}
+
+/**
+ * \brief Handler for incoming digit event
+ * \param mcon sangoma boost connection
+ * \param span Span where event was fired
+ * \param event Event to handle
+ */
+static void handle_incoming_digit(sangomabc_connection_t *mcon, ftdm_span_t *span, sangomabc_event_t *event)
+{
+	ftdm_channel_t *ftdmchan = NULL;
+	char digits[MAX_DIALED_DIGITS + 2] = "";
+	
+	if (!(ftdmchan = find_ftdmchan(span, (sangomabc_short_event_t *)event, 1))) {
+		ftdm_log(FTDM_LOG_ERROR, "Invalid channel\n");
+		return;
+	}
+	
+	if (event->called_number_digits_count == 0) {
+		ftdm_log(FTDM_LOG_WARNING, "Error Incoming digit with len %s %d [w%dg%d]\n",
+			   	event->called_number_digits,
+			   	event->called_number_digits_count,
+			   	event->span+1, event->chan+1);
+		return;
+	}
+
+	ftdm_log(FTDM_LOG_WARNING, "Incoming digit with len %s %d [w%dg%d]\n",
+			   	event->called_number_digits,
+			   	event->called_number_digits_count,
+			   	event->span+1, event->chan+1);
+
+	memcpy(digits, event->called_number_digits, event->called_number_digits_count);
+	ftdm_channel_queue_dtmf(ftdmchan, digits);
+
+	return;
+}
+
+
+/**
+ * \brief Checks if span has state changes pending and processes 
+ * \param span Span where event was fired
+ * \param event Event to handle
+ * \return The locked FTDM channel associated to the event if any, NULL otherwise
+ */
+static ftdm_channel_t* event_process_states(ftdm_span_t *span, sangomabc_short_event_t *event) 
+{
+    ftdm_channel_t *ftdmchan = NULL;
+    
+    switch (event->event_id) {
+        case SIGBOOST_EVENT_CALL_START_NACK:
+        case SIGBOOST_EVENT_CALL_START_NACK_ACK:
+            if (event->call_setup_id) {
+                return NULL;
+            } 
+            //if event->span and event->chan is valid, fall-through
+        case SIGBOOST_EVENT_CALL_START:
+        case SIGBOOST_EVENT_CALL_START_ACK:
+        case SIGBOOST_EVENT_CALL_STOPPED:
+        case SIGBOOST_EVENT_CALL_PROGRESS:
+        case SIGBOOST_EVENT_CALL_ANSWERED:
+        case SIGBOOST_EVENT_CALL_STOPPED_ACK:
+        case SIGBOOST_EVENT_DIGIT_IN:
+        case SIGBOOST_EVENT_INSERT_CHECK_LOOP:
+        case SIGBOOST_EVENT_REMOVE_CHECK_LOOP:
+        case SIGBOOST_EVENT_CALL_RELEASED:
+            if (!(ftdmchan = find_ftdmchan(span, (sangomabc_short_event_t*)event, 1))) {
+                ftdm_log(FTDM_LOG_DEBUG, "PROCESS STATES  CANT FIND CHAN %d:%d\n", event->span+1,event->chan+1);
+                return NULL;
+            }
+            break;
+        case SIGBOOST_EVENT_HEARTBEAT:
+        case SIGBOOST_EVENT_SYSTEM_RESTART_ACK:
+        case SIGBOOST_EVENT_SYSTEM_RESTART:
+        case SIGBOOST_EVENT_AUTO_CALL_GAP_ABATE:
+            return NULL;
+        default:
+            ftdm_log(FTDM_LOG_CRIT, "Unhandled event id:%d\n", event->event_id);
+            return NULL;
+    }
+
+    ftdm_mutex_lock(ftdmchan->mutex);
+    advance_chan_states(ftdmchan);
+    return ftdmchan;
+}
+
+/**
+ * \brief Handler for sangoma boost event
+ * \param span Span where event was fired
+ * \param mcon sangoma boost connection
+ * \param event Event to handle
+ */
+static int parse_sangoma_event(ftdm_span_t *span, sangomabc_connection_t *mcon, sangomabc_short_event_t *event)
+{
+    ftdm_channel_t* ftdmchan = NULL;
+	
+	if (!ftdm_running()) {
+		ftdm_log(FTDM_LOG_WARNING, "System is shutting down.\n");
+		return -1;
+	}
+
+    ftdm_assert_return(event->call_setup_id <= MAX_REQ_ID, -1, "Unexpected call setup id\n");
+
+	/* process all pending state changes for that channel before
+	 * processing the new boost event */
+	ftdmchan = event_process_states(span, event);
+
+    switch(event->event_id) {
+    case SIGBOOST_EVENT_CALL_START:
+		handle_call_start(span, mcon, (sangomabc_event_t*)event);
+		break;
+    case SIGBOOST_EVENT_CALL_STOPPED:
+		handle_call_stop(span, mcon, event);
+		break;
+    case SIGBOOST_EVENT_CALL_RELEASED:
+		handle_call_released(span, mcon, event);
+		break;
+    case SIGBOOST_EVENT_CALL_START_ACK:
+		handle_call_start_ack(mcon, event);
+		break;
+    case SIGBOOST_EVENT_CALL_PROGRESS:
+		handle_call_progress(span, mcon, event);
+		break;
+    case SIGBOOST_EVENT_CALL_START_NACK:
+		handle_call_start_nack(span, mcon, event);
+		break;
+    case SIGBOOST_EVENT_CALL_ANSWERED:
+		handle_call_answer(span, mcon, event);
+		break;
+    case SIGBOOST_EVENT_HEARTBEAT:
+		handle_heartbeat(mcon, event);
+		break;
+    case SIGBOOST_EVENT_CALL_STOPPED_ACK:
+		handle_call_done(span, mcon, event);
+		break;
+    case SIGBOOST_EVENT_CALL_START_NACK_ACK:
+		handle_call_done(span, mcon, event);
+		nack_map[event->call_setup_id] = 0;
+		break;
+    case SIGBOOST_EVENT_INSERT_CHECK_LOOP:
+		handle_call_loop_start(span, mcon, event);
+		break;
+    case SIGBOOST_EVENT_REMOVE_CHECK_LOOP:
+		handle_call_loop_stop(span, mcon, event);
+		break;
+    case SIGBOOST_EVENT_SYSTEM_RESTART_ACK:
+		handle_restart_ack(mcon, span, event);
+		break;
+	case SIGBOOST_EVENT_SYSTEM_RESTART:
+		handle_restart(mcon, span, event);
+		break;
+    case SIGBOOST_EVENT_AUTO_CALL_GAP_ABATE:
+		//handle_gap_abate(event);
+		break;
+	case SIGBOOST_EVENT_DIGIT_IN:
+		handle_incoming_digit(mcon, span, (sangomabc_event_t*)event);
+		break;
+    default:
+		ftdm_log(FTDM_LOG_WARNING, "No handler implemented for [%s]\n", sangomabc_event_id_name(event->event_id));
+		break;
+    }
+
+    if(ftdmchan != NULL) {
+        advance_chan_states(ftdmchan);
+        ftdm_mutex_unlock(ftdmchan->mutex);
+    }
+
+	return 0;
+
+}
+
+/**
+ * \brief Handler for channel state change
+ * \param ftdmchan Channel to handle
+ */
+static __inline__ void state_advance(ftdm_channel_t *ftdmchan)
+{
+
+	ftdm_sangoma_boost_data_t *sangoma_boost_data = ftdmchan->span->signal_data;
+	sangomabc_connection_t *mcon = &sangoma_boost_data->mcon;
+	ftdm_sigmsg_t sig;
+	ftdm_status_t status;
+
+	ftdm_log(FTDM_LOG_DEBUG, "%d:%d PROCESSING STATE [%s]\n", ftdmchan->span_id, ftdmchan->chan_id, ftdm_channel_state2str(ftdmchan->state));
+	
+	memset(&sig, 0, sizeof(sig));
+	sig.chan_id = ftdmchan->chan_id;
+	sig.span_id = ftdmchan->span_id;
+	sig.channel = ftdmchan;
+
+	switch (ftdmchan->state) {
+	case FTDM_CHANNEL_STATE_DOWN:
+		{
+			int call_stopped_ack_sent = 0;
+			ftdm_sangoma_boost_data_t *sangoma_boost_data = ftdmchan->span->signal_data;
+
+			if (ftdm_test_sflag(ftdmchan, SFLAG_FREE_REQ_ID)) {
+				release_request_id_span_chan(ftdmchan->physical_span_id-1, ftdmchan->physical_chan_id-1);
+			}
+
+			if (!ftdm_test_sflag(ftdmchan, SFLAG_SENT_FINAL_MSG)) {
+				ftdm_set_sflag_locked(ftdmchan, SFLAG_SENT_FINAL_MSG);
+
+				if (ftdmchan->call_data && ((uint32_t)(intptr_t)ftdmchan->call_data == SIGBOOST_EVENT_CALL_START_NACK)) {
+					sangomabc_exec_command(mcon,
+									BOOST_SPAN(ftdmchan),
+									BOOST_CHAN(ftdmchan),
+									0,
+									SIGBOOST_EVENT_CALL_START_NACK_ACK,
+									0, 0);
+					
+				} else {
+					/* we got a call stop msg, time to reply with call stopped ack  */
+					sangomabc_exec_command(mcon,
+									BOOST_SPAN(ftdmchan),
+									BOOST_CHAN(ftdmchan),
+									0,
+									SIGBOOST_EVENT_CALL_STOPPED_ACK,
+									0, 0);
+					call_stopped_ack_sent = 1;
+				}
+			}
+			ftdmchan->sflags = 0;
+			ftdmchan->call_data = NULL;
+			if (sangoma_boost_data->sigmod && call_stopped_ack_sent) {
+				/* we dont want to call ftdm_channel_done just yet until call released is received */
+				ftdm_log(FTDM_LOG_DEBUG, "Waiting for call release confirmation before declaring chan %d:%d as available \n", 
+						ftdmchan->span_id, ftdmchan->chan_id);
+			} else {
+				ftdm_channel_done(ftdmchan);
+			}
+		}
+		break;
+	case FTDM_CHANNEL_STATE_PROGRESS_MEDIA:
+		{
+			if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
+				sig.event_id = FTDM_SIGEVENT_PROGRESS_MEDIA;
+				if ((status = ftdm_span_send_signal(ftdmchan->span, &sig) != FTDM_SUCCESS)) {
+					ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP);
+				}
+			} else {
+				if (!ftdm_test_sflag(ftdmchan, SFLAG_SENT_ACK)) {
+					ftdm_set_sflag(ftdmchan, SFLAG_SENT_ACK);
+					sangomabc_exec_command(mcon,
+								BOOST_SPAN(ftdmchan),
+								BOOST_CHAN(ftdmchan),
+								0,
+								SIGBOOST_EVENT_CALL_START_ACK,
+								0, SIGBOOST_PROGRESS_MEDIA);
+				}
+			}
+		}
+		break;
+	case FTDM_CHANNEL_STATE_PROGRESS:
+		{
+			if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
+				sig.event_id = FTDM_SIGEVENT_PROGRESS;
+				if ((status = ftdm_span_send_signal(ftdmchan->span, &sig) != FTDM_SUCCESS)) {
+					ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP);
+				}
+			} else {
+				if (!ftdm_test_sflag(ftdmchan, SFLAG_SENT_ACK)) {
+					ftdm_set_sflag(ftdmchan, SFLAG_SENT_ACK);
+					sangomabc_exec_command(mcon,
+								BOOST_SPAN(ftdmchan),
+								BOOST_CHAN(ftdmchan),
+								0,
+								SIGBOOST_EVENT_CALL_START_ACK,
+								0, SIGBOOST_PROGRESS_RING);
+				}
+			}
+		}
+		break;
+	case FTDM_CHANNEL_STATE_IDLE:
+	case FTDM_CHANNEL_STATE_HOLD:
+		{
+			/* twiddle */
+		}
+		break;
+	case FTDM_CHANNEL_STATE_RING:
+		{
+			if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
+				sig.event_id = FTDM_SIGEVENT_START;
+				if ((status = ftdm_span_send_signal(ftdmchan->span, &sig) != FTDM_SUCCESS)) {
+					ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP);
+				}
+			}
+		}
+		break;
+	case FTDM_CHANNEL_STATE_RESTART:
+		{
+			sig.event_id = FTDM_SIGEVENT_RESTART;
+			status = ftdm_span_send_signal(ftdmchan->span, &sig);
+			ftdm_set_sflag_locked(ftdmchan, SFLAG_SENT_FINAL_MSG);
+			ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
+		}
+		break;
+	case FTDM_CHANNEL_STATE_UP:
+		{
+			if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
+				sig.event_id = FTDM_SIGEVENT_UP;
+				if ((status = ftdm_span_send_signal(ftdmchan->span, &sig) != FTDM_SUCCESS)) {
+					ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP);
+				}
+			} else {
+				if (!(ftdm_test_flag(ftdmchan, FTDM_CHANNEL_PROGRESS) || ftdm_test_flag(ftdmchan, FTDM_CHANNEL_MEDIA))) {
+					sangomabc_exec_command(mcon,
+									   BOOST_SPAN(ftdmchan),
+									   BOOST_CHAN(ftdmchan),								   
+									   0,
+									   SIGBOOST_EVENT_CALL_START_ACK,
+									   0, 0);
+				}
+				
+				sangomabc_exec_command(mcon,
+								   BOOST_SPAN(ftdmchan),
+								   BOOST_CHAN(ftdmchan),								   
+								   0,
+								   SIGBOOST_EVENT_CALL_ANSWERED,
+								   0, 0);
+			}
+		}
+		break;
+	case FTDM_CHANNEL_STATE_DIALING:
+		{
+		}
+		break;
+	case FTDM_CHANNEL_STATE_HANGUP_COMPLETE:
+		{
+			ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
+		}
+		break;
+	case FTDM_CHANNEL_STATE_HANGUP:
+		{
+			ftdm_set_sflag_locked(ftdmchan, SFLAG_HANGUP);
+
+			if (ftdm_test_sflag(ftdmchan, SFLAG_SENT_FINAL_MSG) || ftdm_test_sflag(ftdmchan, SFLAG_TERMINATING)) {
+				ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP_COMPLETE);
+			} else {
+				ftdm_set_sflag_locked(ftdmchan, SFLAG_SENT_FINAL_MSG);
+				if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_ANSWERED) || 
+						ftdm_test_flag(ftdmchan, FTDM_CHANNEL_PROGRESS) || 
+						ftdm_test_flag(ftdmchan, FTDM_CHANNEL_MEDIA) ||
+						ftdm_test_sflag(ftdmchan, SFLAG_RECVD_ACK)) {
+					sangomabc_exec_command(mcon,
+									   BOOST_SPAN(ftdmchan),
+									   BOOST_CHAN(ftdmchan),
+									   0,
+									   SIGBOOST_EVENT_CALL_STOPPED,
+									   ftdmchan->caller_data.hangup_cause, 0);
+				} else {
+					sangomabc_exec_command(mcon,
+									   BOOST_SPAN(ftdmchan),
+									   BOOST_CHAN(ftdmchan),								   
+									   0,
+									   SIGBOOST_EVENT_CALL_START_NACK,
+									   ftdmchan->caller_data.hangup_cause, 0);
+				}
+			}
+		}
+		break;
+	case FTDM_CHANNEL_STATE_TERMINATING:
+		{
+			ftdm_set_sflag_locked(ftdmchan, SFLAG_TERMINATING);
+			sig.event_id = FTDM_SIGEVENT_STOP;
+			status = ftdm_span_send_signal(ftdmchan->span, &sig);
+		}
+		break;
+	case FTDM_CHANNEL_STATE_IN_LOOP:
+		{
+			/* nothing to do, we sent the FTDM_COMMAND_ENABLE_LOOP command in handle_call_loop_start() right away */
+		}
+		break;
+	default:
+		break;
+	}
+}
+
+static __inline__ void advance_chan_states(ftdm_channel_t *ftdmchan)
+{
+	while (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE)) {
+		ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE);
+		state_advance(ftdmchan);
+		ftdm_channel_complete_state(ftdmchan);
+	}
+}
+
+/**
+ * \brief Initialises outgoing requests array
+ */
+static __inline__ void init_outgoing_array(void)
+{
+	memset(&OUTBOUND_REQUESTS, 0, sizeof(OUTBOUND_REQUESTS));
+
+}
+
+/**
+ * \brief Checks current state on a span
+ * \param span Span to check status on
+ */
+static __inline__ void check_state(ftdm_span_t *span)
+{
+	ftdm_channel_t *ftdmchan = NULL;
+	ftdm_sangoma_boost_data_t *sangoma_boost_data = span->signal_data;
+	int susp = ftdm_test_flag(span, FTDM_SPAN_SUSPENDED);
+	
+	if (susp && ftdm_check_state_all(span, FTDM_CHANNEL_STATE_DOWN)) {
+		susp = 0;
+	}
+
+	if (ftdm_test_flag(span, FTDM_SPAN_STATE_CHANGE) || susp) {
+		uint32_t j;
+		ftdm_clear_flag_locked(span, FTDM_SPAN_STATE_CHANGE);
+		if (susp) {
+			for (j = 0; j <= span->chan_count; j++) {
+				ftdm_mutex_lock(span->channels[j]->mutex);
+				ftdm_clear_flag((span->channels[j]), FTDM_CHANNEL_STATE_CHANGE);
+				ftdm_channel_set_state(span->channels[j], FTDM_CHANNEL_STATE_RESTART, 0);
+				state_advance(span->channels[j]);
+				ftdm_channel_complete_state(span->channels[j]);
+				ftdm_mutex_unlock(span->channels[j]->mutex);
+			}
+		} else {
+			while ((ftdmchan = ftdm_queue_dequeue(span->pendingchans))) {
+				/* it can happen that someone else processed the chan states
+				 * but without taking the chan out of the queue, so check th
+				 * flag before advancing the state */
+				ftdm_mutex_lock(ftdmchan->mutex);
+				if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE)) {
+					ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE);
+					state_advance(ftdmchan);
+					ftdm_channel_complete_state(ftdmchan);
+				}
+				ftdm_mutex_unlock(ftdmchan->mutex);
+			}
+		}
+	}
+
+	if (ftdm_test_flag(sangoma_boost_data, FTDM_SANGOMA_BOOST_RESTARTING)) {
+		if (ftdm_check_state_all(span, FTDM_CHANNEL_STATE_DOWN)) {
+			sangomabc_exec_command(&sangoma_boost_data->mcon,
+								   0,
+								   0,
+								   -1,
+								   SIGBOOST_EVENT_SYSTEM_RESTART_ACK,
+								   0, 0);	
+			ftdm_clear_flag(sangoma_boost_data, FTDM_SANGOMA_BOOST_RESTARTING);
+			ftdm_clear_flag_locked(span, FTDM_SPAN_SUSPENDED);
+			ftdm_clear_flag((&sangoma_boost_data->mcon), MSU_FLAG_DOWN);
+			init_outgoing_array();
+		}
+	}
+}
+
+
+/**
+ * \brief Checks for events on a span
+ * \param span Span to check for events
+ */
+static __inline__ ftdm_status_t check_events(ftdm_span_t *span, int ms_timeout)
+{
+	ftdm_status_t status;
+	ftdm_sangoma_boost_data_t *sangoma_boost_data = span->signal_data;
+
+	status = ftdm_span_poll_event(span, ms_timeout);
+
+	switch(status) {
+	case FTDM_SUCCESS:
+		{
+			ftdm_event_t *event;
+			while (ftdm_span_next_event(span, &event) == FTDM_SUCCESS) {
+				switch (event->enum_id) {
+				case FTDM_OOB_ALARM_TRAP:
+					if (sangoma_boost_data->sigmod) {
+						sangoma_boost_data->sigmod->on_hw_link_status_change(event->channel, FTDM_HW_LINK_DISCONNECTED);
+					}
+					break;
+				case FTDM_OOB_ALARM_CLEAR:
+					if (sangoma_boost_data->sigmod) {
+						sangoma_boost_data->sigmod->on_hw_link_status_change(event->channel, FTDM_HW_LINK_CONNECTED);
+					}
+					break;
+				}
+			}
+		}
+		break;
+	case FTDM_FAIL:
+		{
+			if (!ftdm_running()) {
+				break;
+			}
+			ftdm_log(FTDM_LOG_ERROR, "Boost Check Event Failure Failure: %s\n", span->last_error);
+			return FTDM_FAIL;
+		}
+		break;
+	default:
+		break;
+	}
+
+	return FTDM_SUCCESS;
+}
+
+/**
+ * \brief Main thread function for sangoma boost span (monitor)
+ * \param me Current thread
+ * \param obj Span to run in this thread
+ */
+static void *ftdm_sangoma_events_run(ftdm_thread_t *me, void *obj)
+{
+    ftdm_span_t *span = (ftdm_span_t *) obj;
+	ftdm_sangoma_boost_data_t *sangoma_boost_data = span->signal_data;
+	unsigned errs = 0;
+
+	while (ftdm_test_flag(sangoma_boost_data, FTDM_SANGOMA_BOOST_RUNNING) && ftdm_running()) {
+		if (check_events(span,100) != FTDM_SUCCESS) {
+			if (errs++ > 50) {
+				ftdm_log(FTDM_LOG_ERROR, "Too many event errors, quitting sangoma events thread\n");
+				return NULL;
+			}
+		}
+	}
+
+	return NULL;
+}
+
+static ftdm_status_t ftdm_boost_connection_open(ftdm_span_t *span)
+{
+	ftdm_sangoma_boost_data_t *sangoma_boost_data = span->signal_data;
+	if (sangoma_boost_data->sigmod) {
+		if (sangoma_boost_data->sigmod->start_span(span) != FTDM_SUCCESS) {
+			return FTDM_FAIL;
+		}
+		ftdm_clear_flag(sangoma_boost_data, FTDM_SANGOMA_BOOST_RESTARTING);
+		ftdm_clear_flag_locked(span, FTDM_SPAN_SUSPENDED);
+		ftdm_clear_flag((&sangoma_boost_data->mcon), MSU_FLAG_DOWN);
+	} 
+
+	sangoma_boost_data->pcon = sangoma_boost_data->mcon;
+
+	/* when sigmod is present, all arguments: local_ip etc, are ignored by sangomabc_connection_open */
+	if (sangomabc_connection_open(&sangoma_boost_data->mcon,
+								  sangoma_boost_data->mcon.cfg.local_ip,
+								  sangoma_boost_data->mcon.cfg.local_port,
+								  sangoma_boost_data->mcon.cfg.remote_ip,
+								  sangoma_boost_data->mcon.cfg.remote_port) < 0) {
+		ftdm_log(FTDM_LOG_ERROR, "Error: Opening MCON Socket [%d] %s\n", sangoma_boost_data->mcon.socket, strerror(errno));
+		return FTDM_FAIL;
+	}
+
+	if (sangomabc_connection_open(&sangoma_boost_data->pcon,
+							  sangoma_boost_data->pcon.cfg.local_ip,
+							  ++sangoma_boost_data->pcon.cfg.local_port,
+							  sangoma_boost_data->pcon.cfg.remote_ip,
+							  ++sangoma_boost_data->pcon.cfg.remote_port) < 0) {
+		ftdm_log(FTDM_LOG_ERROR, "Error: Opening PCON Socket [%d] %s\n", sangoma_boost_data->pcon.socket, strerror(errno));
+		return FTDM_FAIL;
+    }
+
+	/* try to create the boost sockets interrupt objects */
+	if (ftdm_interrupt_create(&sangoma_boost_data->pcon.sock_interrupt, sangoma_boost_data->pcon.socket) != FTDM_SUCCESS) {
+		ftdm_log(FTDM_LOG_ERROR, "Span %s could not create its boost msock interrupt!\n", span->name);
+		return FTDM_FAIL;
+	}
+
+	if (ftdm_interrupt_create(&sangoma_boost_data->mcon.sock_interrupt, sangoma_boost_data->mcon.socket) != FTDM_SUCCESS) {
+		ftdm_log(FTDM_LOG_ERROR, "Span %s could not create its boost psock interrupt!\n", span->name);
+		return FTDM_FAIL;
+	}
+
+	return FTDM_SUCCESS;
+}
+
+/*! 
+  \brief wait for a boost event 
+  \return -1 on error, 0 on timeout, 1 when there are events
+ */
+static int ftdm_boost_wait_event(ftdm_span_t *span)
+{
+		ftdm_status_t res;
+		ftdm_interrupt_t *ints[3];
+		int numints;
+		ftdm_sangoma_boost_data_t *sangoma_boost_data = span->signal_data;
+
+		ftdm_queue_get_interrupt(span->pendingchans, &ints[0]);
+		numints = 1;
+		/* if in queue mode wait for both the pendingchans queue and the boost msg queue */
+		if (sangoma_boost_data->sigmod) {
+			ftdm_queue_get_interrupt(sangoma_boost_data->boost_queue, &ints[1]);
+			numints = 2;
+		} 
+#ifndef __WINDOWS__
+		else {
+			/* socket mode ... */
+			ints[1] = sangoma_boost_data->mcon.sock_interrupt;
+			ints[2] = sangoma_boost_data->pcon.sock_interrupt;
+			numints = 3;
+			sangoma_boost_data->iteration = 0;
+		}
+#endif
+		res = ftdm_interrupt_multiple_wait(ints, numints, -1);
+		if (FTDM_SUCCESS != res) {
+			ftdm_log(FTDM_LOG_CRIT, "Unexpected return value from interrupt waiting: %d\n", res);
+			return -1;
+		}
+		return 0;
+}
+
+
+static sangomabc_event_t *ftdm_boost_read_event(ftdm_span_t *span)
+{
+	sangomabc_event_t *event = NULL;
+	sangomabc_connection_t *mcon, *pcon;
+	ftdm_sangoma_boost_data_t *sangoma_boost_data = span->signal_data;
+
+	mcon = &sangoma_boost_data->mcon;
+	pcon = &sangoma_boost_data->pcon;
+
+	event = sangomabc_connection_readp(pcon, sangoma_boost_data->iteration);
+
+	/* if there is no event and this is not a sigmod-driven span it's time to try the other connection for events */
+	if (!event && !sangoma_boost_data->sigmod) {
+		event = sangomabc_connection_read(mcon, sangoma_boost_data->iteration);
+	}
+
+	return event;
+}
+
+/**
+ * \brief Main thread function for sangoma boost span (monitor)
+ * \param me Current thread
+ * \param obj Span to run in this thread
+ */
+static void *ftdm_sangoma_boost_run(ftdm_thread_t *me, void *obj)
+{
+	ftdm_span_t *span = (ftdm_span_t *) obj;
+	sangomabc_connection_t *mcon, *pcon;
+	ftdm_sangoma_boost_data_t *sangoma_boost_data = span->signal_data;
+
+	mcon = &sangoma_boost_data->mcon;
+	pcon = &sangoma_boost_data->pcon;	
+
+	/* sigmod overrides socket functionality if not null */
+	if (sangoma_boost_data->sigmod) {
+		mcon->span = span;
+		pcon->span = span;
+		/* everything could be retrieved through span, but let's use shortcuts */
+		mcon->sigmod = sangoma_boost_data->sigmod;
+		pcon->sigmod = sangoma_boost_data->sigmod;
+		mcon->boost_queue = sangoma_boost_data->boost_queue;
+		pcon->boost_queue = sangoma_boost_data->boost_queue;
+	}
+
+	if (ftdm_boost_connection_open(span) != FTDM_SUCCESS) {
+		ftdm_log(FTDM_LOG_ERROR, "ftdm_boost_connection_open failed\n");
+		goto end;
+	}
+
+	init_outgoing_array();
+	if (!sangoma_boost_data->sigmod) {
+		sangomabc_exec_commandp(pcon,
+						   0,
+						   0,
+						   -1,
+						   SIGBOOST_EVENT_SYSTEM_RESTART,
+						   0);
+		ftdm_set_flag(mcon, MSU_FLAG_DOWN);
+	}
+
+	while (ftdm_test_flag(sangoma_boost_data, FTDM_SANGOMA_BOOST_RUNNING)) {
+		sangomabc_event_t *event = NULL;
+		
+		if (!ftdm_running()) {
+			if (!sangoma_boost_data->sigmod) {
+				sangomabc_exec_commandp(pcon,
+								   0,
+								   0,
+								   -1,
+								   SIGBOOST_EVENT_SYSTEM_RESTART,
+								   0);
+				ftdm_set_flag(mcon, MSU_FLAG_DOWN);
+			}
+			ftdm_log(FTDM_LOG_DEBUG, "ftdm is no longer running\n");
+			break;
+		}
+
+		if (ftdm_boost_wait_event(span) < 0) {
+			ftdm_log(FTDM_LOG_ERROR, "ftdm_boost_wait_event failed\n");
+			goto error;
+		}
+		
+		while ((event = ftdm_boost_read_event(span))) {
+			parse_sangoma_event(span, pcon, (sangomabc_short_event_t*)event);
+			sangoma_boost_data->iteration++;
+		}
+		
+		check_state(span);
+	}
+
+	goto end;
+
+error:
+	ftdm_log(FTDM_LOG_CRIT, "Boost event processing Error!\n");
+
+end:
+	if (!sangoma_boost_data->sigmod) {
+		sangomabc_connection_close(&sangoma_boost_data->mcon);
+		sangomabc_connection_close(&sangoma_boost_data->pcon);
+	}
+
+	ftdm_clear_flag(sangoma_boost_data, FTDM_SANGOMA_BOOST_RUNNING);
+
+	ftdm_log(FTDM_LOG_DEBUG, "Sangoma Boost thread ended.\n");
+	return NULL;
+}
+
+/**
+ * \brief Loads sangoma boost signaling module
+ * \param fio FreeTDM IO interface
+ * \return Success
+ */
+static FIO_SIG_LOAD_FUNCTION(ftdm_sangoma_boost_init)
+{
+	g_boost_modules_hash = create_hashtable(10, ftdm_hash_hashfromstring, ftdm_hash_equalkeys);
+	if (!g_boost_modules_hash) {
+		return FTDM_FAIL;
+	}
+	ftdm_mutex_create(&request_mutex);
+	ftdm_mutex_create(&g_boost_modules_mutex);
+	memset(&g_trunkgroups[0], 0, sizeof(g_trunkgroups));
+	return FTDM_SUCCESS;
+}
+
+static FIO_SIG_UNLOAD_FUNCTION(ftdm_sangoma_boost_destroy)
+{
+	ftdm_hash_iterator_t *i = NULL;
+	boost_sigmod_interface_t *sigmod = NULL;
+	const void *key = NULL;
+	void *val = NULL;
+	ftdm_dso_lib_t lib;
+
+	for (i = hashtable_first(g_boost_modules_hash); i; i = hashtable_next(i)) {
+		hashtable_this(i, &key, NULL, &val);
+		if (key && val) {
+			sigmod = val;
+			lib = sigmod->pvt;
+			ftdm_dso_destroy(&lib);
+		}
+	}
+
+	hashtable_destroy(g_boost_modules_hash);
+	ftdm_mutex_destroy(&request_mutex);
+	ftdm_mutex_destroy(&g_boost_modules_mutex);
+	return FTDM_SUCCESS;
+}
+
+static ftdm_status_t ftdm_sangoma_boost_start(ftdm_span_t *span)
+{
+	int err;
+	ftdm_sangoma_boost_data_t *sangoma_boost_data = span->signal_data;
+	ftdm_set_flag(sangoma_boost_data, FTDM_SANGOMA_BOOST_RUNNING);
+	err=ftdm_thread_create_detached(ftdm_sangoma_boost_run, span);
+	if (err) {
+		ftdm_clear_flag(sangoma_boost_data, FTDM_SANGOMA_BOOST_RUNNING);
+		return err;
+	}
+	// launch the events thread to handle HW DTMF and possibly
+	// other events in the future
+	err=ftdm_thread_create_detached(ftdm_sangoma_events_run, span);
+	if (err) {
+		ftdm_clear_flag(sangoma_boost_data, FTDM_SANGOMA_BOOST_RUNNING);
+	}
+	return err;
+}
+
+static ftdm_status_t ftdm_sangoma_boost_stop(ftdm_span_t *span)
+{
+	int cnt = 10;
+	ftdm_status_t status = FTDM_SUCCESS;
+	ftdm_sangoma_boost_data_t *sangoma_boost_data = span->signal_data;
+	if (sangoma_boost_data->sigmod) {
+
+		/* FIXME: we should make sure the span thread is stopped (use pthread_kill or freetdm thread kill function) */
+		/* I think stopping the span before destroying the queue makes sense
+		   otherwise may be boost events would still arrive when the queue is already destroyed! */
+		status = sangoma_boost_data->sigmod->stop_span(span);
+
+		ftdm_queue_enqueue(sangoma_boost_data->boost_queue, NULL);
+		while(ftdm_test_flag(sangoma_boost_data, FTDM_SANGOMA_BOOST_RUNNING) && cnt-- > 0) {
+			ftdm_log(FTDM_LOG_DEBUG, "Waiting for boost thread\n");
+			ftdm_sleep(500);
+		}
+		ftdm_queue_destroy(&sangoma_boost_data->boost_queue);
+		return status;
+	}
+	return status;
+}
+
+static ftdm_state_map_t boost_state_map = {
+	{
+		{
+			ZSD_OUTBOUND,
+			ZSM_UNACCEPTABLE,
+			{FTDM_ANY_STATE},
+			{FTDM_CHANNEL_STATE_RESTART, FTDM_END}
+		},
+		{
+			ZSD_OUTBOUND,
+			ZSM_UNACCEPTABLE,
+			{FTDM_CHANNEL_STATE_RESTART, FTDM_END},
+			{FTDM_CHANNEL_STATE_DOWN, FTDM_END}
+		},
+		{
+			ZSD_OUTBOUND,
+			ZSM_UNACCEPTABLE,
+			{FTDM_CHANNEL_STATE_DOWN, FTDM_END},
+			{FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_CHANNEL_STATE_PROGRESS, FTDM_CHANNEL_STATE_DIALING, FTDM_CHANNEL_STATE_IDLE, FTDM_CHANNEL_STATE_HOLD, FTDM_END}
+		},
+		{
+			ZSD_OUTBOUND,
+			ZSM_UNACCEPTABLE,
+			{FTDM_CHANNEL_STATE_HOLD, FTDM_END},
+			{FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_CHANNEL_STATE_PROGRESS, 
+			 FTDM_CHANNEL_STATE_IDLE, FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_UP, FTDM_END}
+		},
+		{
+			ZSD_OUTBOUND,
+			ZSM_UNACCEPTABLE,
+			{FTDM_CHANNEL_STATE_IDLE, FTDM_CHANNEL_STATE_DIALING, FTDM_END},
+			{FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_CHANNEL_STATE_PROGRESS, FTDM_END}
+		},
+		{
+			ZSD_OUTBOUND,
+			ZSM_UNACCEPTABLE,
+			{FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_CHANNEL_STATE_PROGRESS, FTDM_CHANNEL_STATE_IDLE, FTDM_CHANNEL_STATE_DIALING, FTDM_END},
+			{FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_UP, FTDM_END}
+		},
+		{
+			ZSD_OUTBOUND,
+			ZSM_UNACCEPTABLE,
+			{FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_END},
+			{FTDM_CHANNEL_STATE_HANGUP_COMPLETE, FTDM_CHANNEL_STATE_HANGUP, FTDM_END}
+		},
+		{
+			ZSD_OUTBOUND,
+			ZSM_UNACCEPTABLE,
+			{FTDM_CHANNEL_STATE_HANGUP_COMPLETE, FTDM_END},
+			{FTDM_CHANNEL_STATE_DOWN, FTDM_END},
+		},
+		{
+			ZSD_OUTBOUND,
+			ZSM_UNACCEPTABLE,
+			{FTDM_CHANNEL_STATE_UP, FTDM_END},
+			{FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_END}
+		},
+
+		/****************************************/
+		{
+			ZSD_INBOUND,
+			ZSM_UNACCEPTABLE,
+			{FTDM_ANY_STATE},
+			{FTDM_CHANNEL_STATE_RESTART, FTDM_END}
+		},
+		{
+			ZSD_INBOUND,
+			ZSM_UNACCEPTABLE,
+			{FTDM_CHANNEL_STATE_RESTART, FTDM_END},
+			{FTDM_CHANNEL_STATE_DOWN, FTDM_END}
+		},
+		{
+			ZSD_INBOUND,
+			ZSM_UNACCEPTABLE,
+			{FTDM_CHANNEL_STATE_DOWN},
+			{FTDM_CHANNEL_STATE_IN_LOOP, FTDM_END}
+		},
+		{
+			ZSD_INBOUND,
+			ZSM_UNACCEPTABLE,
+			{FTDM_CHANNEL_STATE_IN_LOOP},
+			{FTDM_CHANNEL_STATE_DOWN, FTDM_END}
+		},
+		{
+			ZSD_INBOUND,
+			ZSM_UNACCEPTABLE,
+			{FTDM_CHANNEL_STATE_DOWN, FTDM_END},
+			{FTDM_CHANNEL_STATE_RING, FTDM_END}
+		},
+		{
+			ZSD_INBOUND,
+			ZSM_UNACCEPTABLE,
+			{FTDM_CHANNEL_STATE_RING, FTDM_END},
+			{FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_PROGRESS, FTDM_CHANNEL_STATE_PROGRESS_MEDIA,FTDM_END}
+		},
+		{
+			ZSD_INBOUND,
+			ZSM_UNACCEPTABLE,
+			{FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_END},
+			{FTDM_CHANNEL_STATE_HANGUP_COMPLETE, FTDM_CHANNEL_STATE_HANGUP, FTDM_END},
+		},
+		{
+			ZSD_INBOUND,
+			ZSM_UNACCEPTABLE,
+			{FTDM_CHANNEL_STATE_HANGUP_COMPLETE, FTDM_CHANNEL_STATE_TERMINATING, FTDM_END},
+			{FTDM_CHANNEL_STATE_DOWN, FTDM_END},
+		},
+		{
+			ZSD_INBOUND,
+			ZSM_UNACCEPTABLE,
+			{FTDM_CHANNEL_STATE_PROGRESS, FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_END},
+			{FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_UP, FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_END},
+		},
+		{
+			ZSD_INBOUND,
+			ZSM_UNACCEPTABLE,
+			{FTDM_CHANNEL_STATE_UP, FTDM_END},
+			{FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_END},
+		},
+		
+
+	}
+};
+
+static BOOST_WRITE_MSG_FUNCTION(ftdm_boost_write_msg)
+{
+	sangomabc_short_event_t *shortmsg = NULL;
+	ftdm_sangoma_boost_data_t *sangoma_boost_data = NULL;
+	sangomabc_queue_element_t *element = NULL;
+
+	ftdm_assert_return(msg != NULL, FTDM_FAIL, "Boost message to write was null");
+
+	if (!span) {
+		shortmsg = msg;
+		ftdm_log(FTDM_LOG_ERROR, "Unexpected boost message %d\n", shortmsg->event_id);
+		return FTDM_FAIL;
+	}
+	/* duplicate the event and enqueue it */
+	element = ftdm_calloc(1, sizeof(*element));
+	if (!element) {
+		return FTDM_FAIL;
+	}
+	memcpy(element->boostmsg, msg, msglen);
+	element->size = msglen;
+
+	sangoma_boost_data = span->signal_data;
+	return ftdm_queue_enqueue(sangoma_boost_data->boost_queue, element);
+}
+
+static BOOST_SIG_STATUS_CB_FUNCTION(ftdm_boost_sig_status_change)
+{
+	ftdm_sigmsg_t sig;
+	ftdm_log(FTDM_LOG_NOTICE, "%d:%d Signaling link status changed to %s\n", ftdmchan->span_id, ftdmchan->chan_id, ftdm_signaling_status2str(status));
+	
+	memset(&sig, 0, sizeof(sig));
+	sig.chan_id = ftdmchan->chan_id;
+	sig.span_id = ftdmchan->span_id;
+	sig.channel = ftdmchan;
+	sig.event_id = FTDM_SIGEVENT_SIGSTATUS_CHANGED;
+	sig.raw_data = &status;
+	ftdm_span_send_signal(ftdmchan->span, &sig);
+	return;
+}
+
+static FIO_CHANNEL_SET_SIG_STATUS_FUNCTION(sangoma_boost_set_channel_sig_status)
+{
+	ftdm_sangoma_boost_data_t *sangoma_boost_data = ftdmchan->span->signal_data;
+	if (!sangoma_boost_data->sigmod) {
+		ftdm_log(FTDM_LOG_ERROR, "Cannot set signaling status in boost channel with no signaling module configured\n");
+		return FTDM_FAIL;
+	}
+	if (!sangoma_boost_data->sigmod->set_channel_sig_status) {
+		ftdm_log(FTDM_LOG_ERROR, "Cannot set signaling status in boost channel: method not implemented\n");
+		return FTDM_NOTIMPL;
+	}
+	return sangoma_boost_data->sigmod->set_channel_sig_status(ftdmchan, status);
+}
+
+static FIO_CHANNEL_GET_SIG_STATUS_FUNCTION(sangoma_boost_get_channel_sig_status)
+{
+	ftdm_sangoma_boost_data_t *sangoma_boost_data = ftdmchan->span->signal_data;
+	if (!sangoma_boost_data->sigmod) {
+		ftdm_log(FTDM_LOG_ERROR, "Cannot get signaling status in boost channel with no signaling module configured\n");
+		return FTDM_FAIL;
+	}
+	if (!sangoma_boost_data->sigmod->get_channel_sig_status) {
+		ftdm_log(FTDM_LOG_ERROR, "Cannot get signaling status in boost channel: method not implemented\n");
+		return FTDM_NOTIMPL;
+	}
+	return sangoma_boost_data->sigmod->get_channel_sig_status(ftdmchan, status);
+}
+
+static FIO_SPAN_SET_SIG_STATUS_FUNCTION(sangoma_boost_set_span_sig_status)
+{
+	ftdm_sangoma_boost_data_t *sangoma_boost_data = span->signal_data;
+	if (!sangoma_boost_data->sigmod) {
+		ftdm_log(FTDM_LOG_ERROR, "Cannot set signaling status in boost span with no signaling module configured\n");
+		return FTDM_FAIL;
+	}
+	if (!sangoma_boost_data->sigmod->set_span_sig_status) {
+		ftdm_log(FTDM_LOG_ERROR, "Cannot set signaling status in boost span: method not implemented\n");
+		return FTDM_NOTIMPL;
+	}
+	return sangoma_boost_data->sigmod->set_span_sig_status(span, status);
+}
+
+static FIO_SPAN_GET_SIG_STATUS_FUNCTION(sangoma_boost_get_span_sig_status)
+{
+	ftdm_sangoma_boost_data_t *sangoma_boost_data = span->signal_data;
+	if (!sangoma_boost_data->sigmod) {
+		ftdm_log(FTDM_LOG_ERROR, "Cannot get signaling status in boost span with no signaling module configured\n");
+		return FTDM_FAIL;
+	}
+	if (!sangoma_boost_data->sigmod->get_span_sig_status) {
+		ftdm_log(FTDM_LOG_ERROR, "Cannot get signaling status in boost span: method not implemented\n");
+		return FTDM_NOTIMPL;
+	}
+	return sangoma_boost_data->sigmod->get_span_sig_status(span, status);
+}
+
+/* TODO: move these ones to a common private header so other ISDN mods can use them */
+static void ftdm_span_set_npi(const char *npi_string, uint8_t *target)
+{
+	if (!strcasecmp(npi_string, "isdn") || !strcasecmp(npi_string, "e164")) {
+		*target = FTDM_NPI_ISDN;
+	} else if (!strcasecmp(npi_string, "data")) {
+		*target = FTDM_NPI_DATA;
+	} else if (!strcasecmp(npi_string, "telex")) {
+		*target = FTDM_NPI_TELEX;
+	} else if (!strcasecmp(npi_string, "national")) {
+		*target = FTDM_NPI_NATIONAL;
+	} else if (!strcasecmp(npi_string, "private")) {
+		*target = FTDM_NPI_PRIVATE;
+	} else if (!strcasecmp(npi_string, "reserved")) {
+		*target = FTDM_NPI_RESERVED;
+	} else if (!strcasecmp(npi_string, "unknown")) {
+		*target = FTDM_NPI_UNKNOWN;
+	} else {
+		ftdm_log(FTDM_LOG_WARNING, "Invalid NPI value (%s)\n", npi_string);
+		*target = FTDM_NPI_UNKNOWN;
+	}
+}
+
+static void ftdm_span_set_ton(const char *ton_string, uint8_t *target)
+{
+	if (!strcasecmp(ton_string, "national")) {
+		*target = FTDM_TON_NATIONAL;
+	} else if (!strcasecmp(ton_string, "international")) {
+		*target = FTDM_TON_INTERNATIONAL;
+	} else if (!strcasecmp(ton_string, "local")) {
+		*target = FTDM_TON_SUBSCRIBER_NUMBER;
+	} else if (!strcasecmp(ton_string, "unknown")) {
+		*target = FTDM_TON_UNKNOWN;
+	} else {
+		ftdm_log(FTDM_LOG_WARNING, "Invalid TON value (%s)\n", ton_string);
+		*target = FTDM_TON_UNKNOWN;
+	}
+}
+
+
+/**
+ * \brief Initialises an sangoma boost span from configuration variables
+ * \param span Span to configure
+ * \param sig_cb Callback function for event signals
+ * \param ap List of configuration variables
+ * \return Success or failure
+ */
+static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_sangoma_boost_configure_span)
+{
+#define FAIL_CONFIG_RETURN(retstatus) \
+		if (sangoma_boost_data) \
+			ftdm_safe_free(sangoma_boost_data); \
+		if (err) \
+			ftdm_safe_free(err) \
+		if (hash_locked) \
+			ftdm_mutex_unlock(g_boost_modules_mutex); \
+		if (lib) \
+			ftdm_dso_destroy(&lib); \
+		return retstatus;
+
+	boost_sigmod_interface_t *sigmod_iface = NULL;
+	ftdm_sangoma_boost_data_t *sangoma_boost_data = NULL;
+	const char *local_ip = "127.0.0.65", *remote_ip = "127.0.0.66";
+	const char *sigmod = NULL;
+	int local_port = 53000, remote_port = 53000;
+	const char *var = NULL, *val = NULL;
+	int hash_locked = 0;
+	ftdm_dso_lib_t lib = NULL;
+	char path[255] = "";
+	char *err = NULL;
+	unsigned paramindex = 0;
+	ftdm_status_t rc = FTDM_SUCCESS;
+
+	for (; ftdm_parameters[paramindex].var; paramindex++) {
+		var = ftdm_parameters[paramindex].var;
+		val = ftdm_parameters[paramindex].val;
+		if (!strcasecmp(var, "sigmod")) {
+			sigmod = val;
+		} else if (!strcasecmp(var, "local_ip")) {
+			local_ip = val;
+		} else if (!strcasecmp(var, "remote_ip")) {
+			remote_ip = val;
+		} else if (!strcasecmp(var, "local_port")) {
+			local_port = atoi(val);
+		} else if (!strcasecmp(var, "remote_port")) {
+			remote_port = atoi(val);
+		} else if (!strcasecmp(var, "outbound-called-ton")) {
+			ftdm_span_set_ton(val, &span->default_caller_data.dnis.type);
+		} else if (!strcasecmp(var, "outbound-called-npi")) {
+			ftdm_span_set_npi(val, &span->default_caller_data.dnis.plan);
+		} else if (!strcasecmp(var, "outbound-calling-ton")) {
+			ftdm_span_set_ton(val, &span->default_caller_data.cid_num.type);
+		} else if (!strcasecmp(var, "outbound-calling-npi")) {
+			ftdm_span_set_npi(val, &span->default_caller_data.cid_num.plan);
+		} else if (!strcasecmp(var, "outbound-rdnis-ton")) {
+			ftdm_span_set_ton(val, &span->default_caller_data.rdnis.type);
+		} else if (!strcasecmp(var, "outbound-rdnis-npi")) {
+			ftdm_span_set_npi(val, &span->default_caller_data.rdnis.plan);
+		} else if (!sigmod) {
+			snprintf(span->last_error, sizeof(span->last_error), "Unknown parameter [%s]", var);
+			FAIL_CONFIG_RETURN(FTDM_FAIL);
+		}
+	}
+
+	if (!sigmod) {
+		if (!local_ip && local_port && remote_ip && remote_port && sig_cb) {
+			ftdm_set_string(span->last_error, "missing Sangoma boost IP parameters");
+			FAIL_CONFIG_RETURN(FTDM_FAIL);
+		}
+	}
+
+	sangoma_boost_data = ftdm_calloc(1, sizeof(*sangoma_boost_data));
+	if (!sangoma_boost_data) {
+		FAIL_CONFIG_RETURN(FTDM_FAIL);
+	}
+
+	/* WARNING: be sure to release this mutex on errors inside this if() */
+	ftdm_mutex_lock(g_boost_modules_mutex);
+	hash_locked = 1;
+	if (sigmod && !(sigmod_iface = hashtable_search(g_boost_modules_hash, (void *)sigmod))) {
+		ftdm_build_dso_path(sigmod, path, sizeof(path));	
+		lib = ftdm_dso_open(path, &err);
+		if (!lib) {
+			ftdm_log(FTDM_LOG_ERROR, "Error loading Sangoma boost signaling module '%s': %s\n", path, err);
+			snprintf(span->last_error, sizeof(span->last_error), "Failed to load sangoma boost signaling module %s", path);
+
+			FAIL_CONFIG_RETURN(FTDM_FAIL);
+		}
+		if (!(sigmod_iface = (boost_sigmod_interface_t *)ftdm_dso_func_sym(lib, BOOST_INTERFACE_NAME_STR, &err))) {
+			ftdm_log(FTDM_LOG_ERROR, "Failed to read Sangoma boost signaling module interface '%s': %s\n", path, err);
+			snprintf(span->last_error, sizeof(span->last_error), "Failed to read Sangoma boost signaling module interface '%s': %s", path, err);
+
+			FAIL_CONFIG_RETURN(FTDM_FAIL);
+		}
+		rc = sigmod_iface->on_load();
+		if (rc != FTDM_SUCCESS) {
+			ftdm_log(FTDM_LOG_ERROR, "Failed to load Sangoma boost signaling module interface '%s': on_load method failed (%d)\n", path, rc);
+			FAIL_CONFIG_RETURN(FTDM_FAIL);
+		}
+		sigmod_iface->pvt = lib;
+		sigmod_iface->set_write_msg_cb(ftdm_boost_write_msg);
+		sigmod_iface->set_sig_status_cb(ftdm_boost_sig_status_change);
+		hashtable_insert(g_boost_modules_hash, (void *)sigmod_iface->name, sigmod_iface, HASHTABLE_FLAG_NONE);
+		lib = NULL; /* destroying the lib will be done when going down and NOT on FAIL_CONFIG_RETURN */
+	}
+	ftdm_mutex_unlock(g_boost_modules_mutex);
+	hash_locked = 0;
+
+	if (sigmod_iface) {
+		/* try to create the boost queue */
+		if (ftdm_queue_create(&sangoma_boost_data->boost_queue, BOOST_QUEUE_SIZE) != FTDM_SUCCESS) {
+			ftdm_log(FTDM_LOG_ERROR, "Span %s could not create its boost queue!\n", span->name);
+			FAIL_CONFIG_RETURN(FTDM_FAIL);
+		}
+		ftdm_log(FTDM_LOG_NOTICE, "Span %s will use Sangoma Boost Signaling Module %s\n", span->name, sigmod_iface->name);
+		sangoma_boost_data->sigmod = sigmod_iface;
+		sigmod_iface->configure_span(span, ftdm_parameters);
+	} else {
+		ftdm_log(FTDM_LOG_NOTICE, "Span %s will use boost socket mode\n", span->name);
+		ftdm_set_string(sangoma_boost_data->mcon.cfg.local_ip, local_ip);
+		sangoma_boost_data->mcon.cfg.local_port = local_port;
+		ftdm_set_string(sangoma_boost_data->mcon.cfg.remote_ip, remote_ip);
+		sangoma_boost_data->mcon.cfg.remote_port = remote_port;
+	}
+	span->signal_cb = sig_cb;
+	span->start = ftdm_sangoma_boost_start;
+	span->stop = ftdm_sangoma_boost_stop;
+	span->signal_data = sangoma_boost_data;
+	span->signal_type = FTDM_SIGTYPE_SANGOMABOOST;
+	span->outgoing_call = sangoma_boost_outgoing_call;
+	span->channel_request = sangoma_boost_channel_request;
+	span->get_channel_sig_status = sangoma_boost_get_channel_sig_status;
+	span->set_channel_sig_status = sangoma_boost_set_channel_sig_status;
+	span->get_span_sig_status = sangoma_boost_get_span_sig_status;
+	span->set_span_sig_status = sangoma_boost_set_span_sig_status;
+	span->state_map = &boost_state_map;
+	span->suggest_chan_id = 0;
+	if (sigmod_iface) {
+		/* the core will do the hunting */
+		span->channel_request = NULL;
+	} 
+	ftdm_set_flag_locked(span, FTDM_SPAN_SUSPENDED);
+	return FTDM_SUCCESS;
+}
+
+/**
+ * \brief FreeTDM sangoma boost signaling module definition
+ */
+EX_DECLARE_DATA ftdm_module_t ftdm_module = { 
+	/*.name =*/ "sangoma_boost",
+	/*.io_load =*/ NULL,
+	/*.io_unload =*/ NULL,
+	/*.sig_load = */ ftdm_sangoma_boost_init,
+	/*.sig_configure =*/ NULL,
+	/*.sig_unload = */ftdm_sangoma_boost_destroy,
+	/*.configure_span_signaling = */ ftdm_sangoma_boost_configure_span
+};
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */

Added: freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_sangoma_boost/sangoma_boost_client.c (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_sangoma_boost/sangoma_boost_client.c	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_sangoma_boost/sangoma_boost_client.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,575 @@
+/*
+ * Copyright (c) 2007, Anthony Minessale II, Nenad Corbic
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if HAVE_NETDB_H
+#include <netdb.h>
+#endif
+
+#include "freetdm.h"
+#include "sangoma_boost_client.h"
+
+#ifndef HAVE_GETHOSTBYNAME_R
+extern int gethostbyname_r (const char *__name, 
+							struct hostent *__result_buf, 
+							char *__buf, size_t __buflen, 
+							struct hostent **__result, 
+							int *__h_errnop);
+#endif
+
+struct sangomabc_map {
+	uint32_t event_id;
+	const char *name;
+};
+
+static struct sangomabc_map sangomabc_table[] = {
+	{SIGBOOST_EVENT_CALL_START, "CALL_START"},
+	{SIGBOOST_EVENT_CALL_START_ACK, "CALL_START_ACK"}, 
+	{SIGBOOST_EVENT_CALL_START_NACK, "CALL_START_NACK"},
+	{SIGBOOST_EVENT_CALL_PROGRESS, "CALL PROGRESS"},
+	{SIGBOOST_EVENT_CALL_START_NACK_ACK, "CALL_START_NACK_ACK"}, 
+	{SIGBOOST_EVENT_CALL_ANSWERED, "CALL_ANSWERED"}, 
+	{SIGBOOST_EVENT_CALL_STOPPED, "CALL_STOPPED"}, 
+	{SIGBOOST_EVENT_CALL_STOPPED_ACK, "CALL_STOPPED_ACK"}, 
+	{SIGBOOST_EVENT_CALL_RELEASED, "CALL_RELEASED"}, 
+	{SIGBOOST_EVENT_SYSTEM_RESTART, "SYSTEM_RESTART"}, 
+	{SIGBOOST_EVENT_SYSTEM_RESTART_ACK, "SYSTEM_RESTART_ACK"}, 
+	{SIGBOOST_EVENT_HEARTBEAT, "HEARTBEAT"}, 
+	{SIGBOOST_EVENT_INSERT_CHECK_LOOP, "LOOP START"}, 
+	{SIGBOOST_EVENT_REMOVE_CHECK_LOOP, "LOOP STOP"},
+	{SIGBOOST_EVENT_AUTO_CALL_GAP_ABATE, "AUTO_CALL_GAP_ABATE"},
+	{SIGBOOST_EVENT_DIGIT_IN, "DIGIT_IN"}
+}; 
+
+
+
+static void sangomabc_print_event_call(sangomabc_connection_t *mcon, sangomabc_event_t *event, int priority, int dir, const char *file, const char *func, int line)
+{
+	if (event->event_id == SIGBOOST_EVENT_HEARTBEAT)
+		return;
+
+	ftdm_log(file, func, line, FTDM_LOG_LEVEL_DEBUG, "%s EVENT (%s): %s:(%X) [w%dg%d] CSid=%i Seq=%i Cn=[%s] Cd=[%s] Ci=[%s] Rdnis=[%s]\n",
+		    dir ? "TX":"RX",
+			priority ? "P":"N",
+			sangomabc_event_id_name(event->event_id),
+			event->event_id,
+			event->span,
+			event->chan,
+			event->call_setup_id,
+			event->fseqno,
+			strlen(event->calling_name)?event->calling_name:"N/A",
+			(event->called_number_digits_count ? (char *) event->called_number_digits : "N/A"),
+			(event->calling_number_digits_count ? (char *) event->calling_number_digits : "N/A"),
+			event->isup_in_rdnis);
+
+}
+static void sangomabc_print_event_short(sangomabc_connection_t *mcon, sangomabc_short_event_t *event, int priority, int dir, const char *file, const char *func, int line)
+{
+	if (event->event_id == SIGBOOST_EVENT_HEARTBEAT)
+		return;
+	ftdm_log(file, func, line, FTDM_LOG_LEVEL_DEBUG, "%s EVENT (%s): %s:(%X) [s%dc%d] Rc=%i CSid=%i Seq=%i \n",
+			   dir ? "TX":"RX", 
+			   priority ? "P":"N",
+                           sangomabc_event_id_name(event->event_id), 
+                           event->event_id, 
+                           event->span, 
+                           event->chan, 
+                           event->release_cause, 
+                           event->call_setup_id, 
+                           event->fseqno);
+}
+
+
+static int create_conn_socket(sangomabc_connection_t *mcon, char *local_ip, int local_port, char *ip, int port)
+{
+#ifndef WIN32
+	int rc;
+	struct hostent *result, *local_result;
+	char buf[512], local_buf[512];
+	int err = 0, local_err = 0;
+
+	if (mcon->sigmod) {
+		ftdm_log(FTDM_LOG_WARNING, "I should not be called on a sigmod-managed connection!\n");
+		return 0;
+	}
+
+	memset(&mcon->remote_hp, 0, sizeof(mcon->remote_hp));
+	memset(&mcon->local_hp, 0, sizeof(mcon->local_hp));
+#ifdef HAVE_NETINET_SCTP_H
+	ftdm_log(FTDM_LOG_DEBUG, "Creating SCTP socket L=%s:%d R=%s:%d\n", 
+			local_ip, local_port, ip, port);
+	mcon->socket = socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP);
+#else
+	ftdm_log(FTDM_LOG_DEBUG, "Creating UDP socket L=%s:%d R=%s:%d\n", 
+			local_ip, local_port, ip, port);
+	mcon->socket = socket(AF_INET, SOCK_DGRAM, 0);
+#endif
+ 
+	if (mcon->socket >= 0) {
+		int flag;
+
+		flag = 1;
+#ifdef HAVE_GETHOSTBYNAME_R_FIVE
+		gethostbyname_r(ip, &mcon->remote_hp, buf, sizeof(buf), &err);
+		gethostbyname_r(local_ip, &mcon->local_hp, local_buf, sizeof(local_buf), &local_err);
+		if (!err && !local_err) {
+#else
+		gethostbyname_r(ip, &mcon->remote_hp, buf, sizeof(buf), &result, &err);
+		gethostbyname_r(local_ip, &mcon->local_hp, local_buf, sizeof(local_buf), &local_result, &local_err);
+		if (result && local_result) {
+#endif
+			mcon->remote_addr.sin_family = mcon->remote_hp.h_addrtype;
+			memcpy((char *) &mcon->remote_addr.sin_addr.s_addr, mcon->remote_hp.h_addr_list[0], mcon->remote_hp.h_length);
+			mcon->remote_addr.sin_port = htons(port);
+
+			mcon->local_addr.sin_family = mcon->local_hp.h_addrtype;
+			memcpy((char *) &mcon->local_addr.sin_addr.s_addr, mcon->local_hp.h_addr_list[0], mcon->local_hp.h_length);
+			mcon->local_addr.sin_port = htons(local_port);
+
+#ifdef HAVE_NETINET_SCTP_H
+			setsockopt(mcon->socket, IPPROTO_SCTP, SCTP_NODELAY, 
+					   (char *)&flag, sizeof(int));
+#endif
+
+			if ((rc = bind(mcon->socket, 
+						   (struct sockaddr *) &mcon->local_addr, 
+						   sizeof(mcon->local_addr))) < 0) {
+				close(mcon->socket);
+				mcon->socket = -1;
+			} else {
+#ifdef HAVE_NETINET_SCTP_H
+				rc=listen(mcon->socket, 100);
+				if (rc) {
+					close(mcon->socket);
+					mcon->socket = -1;
+				}
+#endif
+			}
+		}
+	}
+
+	return mcon->socket;
+#else
+	return 0;
+#endif // ifndef WIN32
+}
+
+int sangomabc_connection_close(sangomabc_connection_t *mcon)
+{
+#ifndef WIN32
+	if (mcon->sigmod) {
+		ftdm_log(FTDM_LOG_WARNING, "I should not be called on a sigmod-managed connection!\n");
+		return 0;
+	}
+	if (mcon->socket > -1) {
+		close(mcon->socket);
+	}
+
+	if (mcon->mutex) {
+		ftdm_mutex_lock(mcon->mutex);
+		ftdm_mutex_unlock(mcon->mutex);
+		ftdm_mutex_destroy(&mcon->mutex);
+	}
+	memset(mcon, 0, sizeof(*mcon));
+	mcon->socket = -1;
+#endif
+	return 0;
+}
+
+int sangomabc_connection_open(sangomabc_connection_t *mcon, char *local_ip, int local_port, char *ip, int port)
+{
+	ftdm_mutex_create(&mcon->mutex);
+	if (mcon->sigmod) {
+		/*value of mcon->socket will be ignored in sigmod mode */
+		return 0;
+	}
+#ifndef WIN32
+	create_conn_socket(mcon, local_ip, local_port, ip, port);
+	return mcon->socket;
+#else
+	return 0;
+#endif
+}
+
+
+int sangomabc_exec_command(sangomabc_connection_t *mcon, int span, int chan, int id, int cmd, int cause, int flags)
+{
+    sangomabc_short_event_t oevent;
+    int retry = 5;
+
+    sangomabc_event_init(&oevent, cmd, chan, span);
+    oevent.release_cause = (uint8_t)cause;
+    oevent.flags = flags;
+
+	if (cmd == SIGBOOST_EVENT_SYSTEM_RESTART || cmd == SIGBOOST_EVENT_SYSTEM_RESTART_ACK) {
+		mcon->rxseq_reset = 1;
+		mcon->txseq = 0;
+		mcon->rxseq = 0;
+		mcon->txwindow = 0;
+	}
+
+    if (id >= 0) {
+        oevent.call_setup_id = (uint16_t)id;
+    }
+
+    while (sangomabc_connection_write(mcon, (sangomabc_event_t*)&oevent) <= 0) {
+        if (--retry <= 0) {
+            ftdm_log(FTDM_LOG_CRIT, "Failed to tx on boost socket: %s\n", strerror(errno));
+            return -1;
+        } else {
+            ftdm_log(FTDM_LOG_WARNING, "Failed to tx on boost socket: %s :retry %i\n", strerror(errno), retry);
+			ftdm_sleep(1);
+        }
+    }
+
+    return 0;
+}
+
+
+int sangomabc_exec_commandp(sangomabc_connection_t *pcon, int span, int chan, int id, int cmd, int cause)
+{
+    sangomabc_short_event_t oevent;
+    int retry = 5;
+
+    sangomabc_event_init(&oevent, cmd, chan, span);
+    oevent.release_cause = (uint8_t)cause;
+
+    if (id >= 0) {
+        oevent.call_setup_id = (uint16_t)id;
+    }
+
+    while (sangomabc_connection_writep(pcon, (sangomabc_event_t*)&oevent) <= 0) {
+        if (--retry <= 0) {
+            ftdm_log(FTDM_LOG_CRIT, "Failed to tx on boost socket: %s\n", strerror(errno));
+            return -1;
+        } else {
+            ftdm_log(FTDM_LOG_WARNING, "Failed to tx on boost socket: %s :retry %i\n", strerror(errno), retry);
+			ftdm_sleep(1);
+        }
+    }
+
+    return 0;
+}
+
+sangomabc_event_t *__sangomabc_connection_read(sangomabc_connection_t *mcon, int iteration, const char *file, const char *func, int line)
+{
+#ifndef WIN32
+	unsigned int fromlen = sizeof(struct sockaddr_in);
+#endif
+	int bytes = 0;
+	int msg_ok = 0;
+	sangomabc_queue_element_t *e = NULL;
+
+	if (mcon->sigmod) {
+		e = ftdm_queue_dequeue(mcon->boost_queue);
+		if (e) {
+			bytes = e->size;
+			memcpy(&mcon->event, e->boostmsg, bytes);
+			ftdm_safe_free(e);
+		}
+	} 
+#ifndef WIN32	
+	else {
+		bytes = recvfrom(mcon->socket, &mcon->event, sizeof(mcon->event), MSG_DONTWAIT, 
+						 (struct sockaddr *) &mcon->local_addr, &fromlen);
+	}
+#endif
+	if (bytes <= 0) {
+		return NULL;
+	}
+
+	if (mcon->event.version != SIGBOOST_VERSION) {
+		ftdm_log(FTDM_LOG_CRIT, "Invalid Boost Version %i  Expecting %i\n",mcon->event.version, SIGBOOST_VERSION);
+	}   
+
+	if ((bytes >= MIN_SIZE_CALLSTART_MSG) && boost_full_event(mcon->event.event_id)) {
+		msg_ok=1;
+		
+	} else if (bytes == sizeof(sangomabc_short_event_t)) {
+		msg_ok=1;
+
+	} else {
+		msg_ok=0;
+	}
+
+	if (msg_ok) {
+		if (sangomabc_test_flag(mcon, MSU_FLAG_DOWN)) {
+			if (mcon->event.event_id != SIGBOOST_EVENT_SYSTEM_RESTART && 
+				mcon->event.event_id != SIGBOOST_EVENT_SYSTEM_RESTART_ACK && 
+				mcon->event.event_id != SIGBOOST_EVENT_HEARTBEAT) {
+				ftdm_log(file, func, line, FTDM_LOG_LEVEL_WARNING, "Not reading packets when connection is down. [%s]\n", 
+						sangomabc_event_id_name(mcon->event.event_id));
+				return NULL;
+			}
+		}
+		
+		if  (boost_full_event(mcon->event.event_id)) {
+			sangomabc_print_event_call(mcon, &mcon->event, 0, 0, file, func, line);
+		} else {
+			sangomabc_print_event_short(mcon, (sangomabc_short_event_t*)&mcon->event, 0, 0, file, func, line);
+		}
+
+#if 0
+/* NC: NOT USED ANY MORE */
+		if (mcon->rxseq_reset) {
+			//if (mcon->event.event_id == SIGBOOST_EVENT_SYSTEM_RESTART_ACK) {
+				ftdm_log(FTDM_LOG_DEBUG, "Rx sync ok\n");
+				mcon->rxseq = mcon->event.fseqno;
+				return &mcon->event;
+				//}
+			errno=EAGAIN;
+			ftdm_log(FTDM_LOG_DEBUG, "Waiting for rx sync...\n");
+			return NULL;
+		}
+#endif
+		
+		mcon->txwindow = mcon->txseq - mcon->event.bseqno;
+		mcon->rxseq++;
+
+#if 0
+		if (mcon->rxseq != mcon->event.fseqno) {
+			ftdm_log(FTDM_LOG_CRIT, "Invalid Sequence Number Expect=%i Rx=%i\n", mcon->rxseq, mcon->event.fseqno);
+			return NULL;
+		}
+#endif
+
+		return &mcon->event;
+	} else {
+		if (iteration == 0) {
+			ftdm_log(FTDM_LOG_CRIT, "NC -  Invalid Event length from boost rxlen=%i evsz=%i\n", bytes, sizeof(mcon->event));
+			return NULL;
+		}
+	}
+
+	return NULL;
+}
+
+sangomabc_event_t *__sangomabc_connection_readp(sangomabc_connection_t *mcon, int iteration, const char *file, const char *func, int line)
+{
+#ifndef WIN32
+	unsigned int fromlen = sizeof(struct sockaddr_in);
+#endif
+	int bytes = 0;
+
+	if (mcon->sigmod) {
+		/* priority stuff is handled just the same when there is a sigmod */
+		return sangomabc_connection_read(mcon, iteration);
+	} 
+#ifndef WIN32
+	else {
+		bytes = recvfrom(mcon->socket, &mcon->event, sizeof(mcon->event), MSG_DONTWAIT, (struct sockaddr *) &mcon->local_addr, &fromlen);
+	}
+#endif	
+	if (bytes <= 0) {
+		return NULL;
+	}
+
+    if (mcon->event.version != SIGBOOST_VERSION) {
+		ftdm_log(FTDM_LOG_CRIT, "Invalid Boost Version %i  Expecting %i\n",mcon->event.version, SIGBOOST_VERSION);
+    }   
+
+	if (bytes == sizeof(sangomabc_short_event_t)) {
+
+		if  (boost_full_event(mcon->event.event_id)) {
+			sangomabc_print_event_call(mcon, &mcon->event, 1, 0, file, func, line);
+		} else {
+			sangomabc_print_event_short(mcon, (sangomabc_short_event_t*)&mcon->event, 1, 0, file, func, line);
+		}
+
+		return &mcon->event;
+	} else {
+		if (iteration == 0) {
+			ftdm_log(FTDM_LOG_CRIT, "Critical Error: PQ Invalid Event lenght from boost rxlen=%i evsz=%i\n", bytes, sizeof(mcon->event));
+			return NULL;
+		}
+	}
+
+	return NULL;
+}
+
+
+int __sangomabc_connection_write(sangomabc_connection_t *mcon, sangomabc_event_t *event, const char *file, const char *func, int line)
+{
+	int err = 0;
+	int event_size=MIN_SIZE_CALLSTART_MSG+event->isup_in_rdnis_size;
+
+	ftdm_assert_return(event != NULL, -1, "No event!");
+	ftdm_assert_return(mcon->socket >= 0, -1, "No mcon->socket!");
+	ftdm_assert_return(mcon->mutex != NULL, -1, "No mcon->mutex!");
+
+	ftdm_assert_return(event->span <= FTDM_MAX_PHYSICAL_SPANS_PER_LOGICAL_SPAN, -1, "Invalid span when writing boost event\n");
+	ftdm_assert_return(event->chan <= FTDM_MAX_CHANNELS_PHYSICAL_SPAN, -1, "Invalid chan when writing boost event\n");
+
+	if (!boost_full_event(event->event_id)) {
+		event_size=sizeof(sangomabc_short_event_t);
+	}	
+
+	if (sangomabc_test_flag(mcon, MSU_FLAG_DOWN)) {
+		if (event->event_id != SIGBOOST_EVENT_SYSTEM_RESTART && 
+			event->event_id != SIGBOOST_EVENT_SYSTEM_RESTART_ACK && 
+			event->event_id != SIGBOOST_EVENT_HEARTBEAT) {
+			ftdm_log(file, func, line, FTDM_LOG_LEVEL_WARNING, "Not writing packets when connection is down. [%s]\n",
+					sangomabc_event_id_name(event->event_id));
+			return 0;
+		}
+	}
+
+	ftdm_mutex_lock(mcon->mutex);
+	if (event->event_id == SIGBOOST_EVENT_SYSTEM_RESTART_ACK) {
+		mcon->txseq=0;
+		mcon->rxseq=0;
+		event->fseqno=0;	
+	} else {
+		event->fseqno = mcon->txseq++;
+	}
+	event->bseqno = mcon->rxseq;
+    	event->version = SIGBOOST_VERSION; 
+
+	if (boost_full_event(event->event_id)) {
+		sangomabc_print_event_call(mcon, event, 0, 1, file, func, line);
+	} else {
+		sangomabc_print_event_short(mcon, (sangomabc_short_event_t*)event, 0, 1, file, func, line);
+	}
+
+	if (mcon->sigmod) {
+		mcon->sigmod->write_msg(mcon->span, event, event_size);
+		err = event_size;
+	} 
+#ifndef WIN32
+	else {
+		err = sendto(mcon->socket, event, event_size, 0, (struct sockaddr *) &mcon->remote_addr, sizeof(mcon->remote_addr));
+	}
+#endif
+
+	ftdm_mutex_unlock(mcon->mutex);
+
+	ftdm_assert_return(err == event_size, -1, "Failed to send the boost message completely!");
+
+	return err;
+}
+
+
+int __sangomabc_connection_writep(sangomabc_connection_t *mcon, sangomabc_event_t *event, const char *file, const char *func, int line)
+{
+	int err = 0;
+	int event_size=sizeof(sangomabc_event_t);
+
+	if (!mcon->sigmod) {
+		ftdm_assert_return(event != NULL, -1, "No event!");
+		ftdm_assert_return(mcon->socket >= 0, -1, "No mcon->socket!");
+		ftdm_assert_return(mcon->mutex != NULL, -1, "No mcon->mutex!");
+	}
+    
+	if (!boost_full_event(event->event_id)) {
+		event_size=sizeof(sangomabc_short_event_t);
+	}	
+
+	ftdm_mutex_lock(mcon->mutex);
+	event->version = SIGBOOST_VERSION; 
+	if (mcon->sigmod) {
+		mcon->sigmod->write_msg(mcon->span, event, event_size);
+	    err = event_size;
+
+	} 
+#ifndef WIN32
+	else {
+		err = sendto(mcon->socket, event, event_size, 0, (struct sockaddr *) &mcon->remote_addr, sizeof(mcon->remote_addr));
+	}
+#endif
+	ftdm_mutex_unlock(mcon->mutex);
+
+	ftdm_assert_return(err == event_size, -1, "Failed to send boost message completely!");
+
+	if (boost_full_event(event->event_id)) {
+		sangomabc_print_event_call(mcon, event, 1, 1, file, func, line);
+	} else {
+		sangomabc_print_event_short(mcon, (sangomabc_short_event_t*)event, 1, 1, file, func, line);
+	}
+
+	return err;
+}
+
+
+void sangomabc_call_init(sangomabc_event_t *event, const char *calling, const char *called, int setup_id)
+{
+	memset(event, 0, sizeof(sangomabc_event_t));
+	event->event_id = SIGBOOST_EVENT_CALL_START;
+
+	if (calling) {
+		strncpy((char*)event->calling_number_digits, calling, sizeof(event->calling_number_digits)-1);
+		event->calling_number_digits_count = (uint8_t)strlen(calling);
+	}
+
+	if (called) {
+		strncpy((char*)event->called_number_digits, called, sizeof(event->called_number_digits)-1);
+		event->called_number_digits_count = (uint8_t)strlen(called);
+	}
+		
+	event->call_setup_id = (uint16_t)setup_id;
+	
+}
+
+void sangomabc_event_init(sangomabc_short_event_t *event, sangomabc_event_id_t event_id, int chan, int span)
+{
+	memset(event, 0, sizeof(sangomabc_short_event_t));
+	event->event_id = event_id;
+	event->chan = (uint8_t)chan;
+	event->span = (uint8_t)span;
+}
+
+const char *sangomabc_event_id_name(uint32_t event_id)
+{
+	unsigned int x;
+	const char *ret = NULL;
+
+	for (x = 0 ; x < sizeof(sangomabc_table)/sizeof(struct sangomabc_map); x++) {
+		if (sangomabc_table[x].event_id == event_id) {
+			ret = sangomabc_table[x].name;
+			break;
+		}
+	}
+
+	return ret;
+}
+
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
+

Added: freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_sangoma_boost/sangoma_boost_client.h (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_sangoma_boost/sangoma_boost_client.h	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_sangoma_boost/sangoma_boost_client.h	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2007, Anthony Minessale II, Nenad Corbic
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _SANGOMABC_H
+#define _SANGOMABC_H
+
+#include "sangoma_boost_interface.h"
+
+#include <ctype.h>
+#include <string.h>
+#ifndef WIN32
+#include <unistd.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#ifdef HAVE_NETINET_SCTP_H
+#include <netinet/sctp.h>
+#endif
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <sys/time.h>
+#endif
+#include <stdlib.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <stdarg.h>
+#include "sigboost.h"
+
+#define sangomabc_test_flag(p,flag) ((p)->flags & (flag))
+
+#define sangomabc_set_flag(p,flag) 		do {		\
+		((p)->flags |= (flag));					\
+	} while (0)
+
+#define sangomabc_clear_flag(p,flag) 		do {	\
+		((p)->flags &= ~(flag));				\
+	} while (0)
+
+#define sangomabc_copy_flags(dest,src,flagz)	do {	\
+		(dest)->flags &= ~(flagz);					\
+		(dest)->flags |= ((src)->flags & (flagz));	\
+	} while (0)
+
+typedef  t_sigboost_callstart sangomabc_event_t;
+typedef  t_sigboost_short sangomabc_short_event_t;
+typedef uint32_t sangomabc_event_id_t;
+
+typedef struct sangomabc_ip_cfg
+{
+	char local_ip[25];
+	int local_port;
+	char remote_ip[25];
+	int remote_port;
+}sangomabc_ip_cfg_t;
+
+typedef enum {
+	MSU_FLAG_EVENT = (1 << 0),
+	MSU_FLAG_DOWN = (1 << 1)
+} sangomabc_flag_t;
+
+
+struct sangomabc_connection {
+	ftdm_socket_t socket;
+	struct sockaddr_in local_addr;
+	struct sockaddr_in remote_addr;
+	sangomabc_event_t event;
+	struct hostent remote_hp;
+	struct hostent local_hp;
+	unsigned int flags;
+	ftdm_mutex_t *mutex;
+	FILE *log;
+	unsigned int txseq;
+	unsigned int rxseq;
+	unsigned int txwindow;
+	unsigned int rxseq_reset;
+	sangomabc_ip_cfg_t cfg;
+	/* boost signaling mod interface pointer (if not working in TCP mode) */
+	boost_sigmod_interface_t *sigmod;
+	ftdm_queue_t *boost_queue;	
+	ftdm_interrupt_t *sock_interrupt;
+	ftdm_span_t *span;
+};
+
+typedef struct sangomabc_connection sangomabc_connection_t;
+
+typedef struct sangomabc_queue_element {
+	unsigned char boostmsg[sizeof(sangomabc_event_t)];
+	ftdm_size_t size;
+} sangomabc_queue_element_t;
+
+/* disable nagle's algorythm */
+static __inline__ void sctp_no_nagle(int socket)
+{
+#ifdef HAVE_NETINET_SCTP_H
+    int flag = 1;
+    setsockopt(socket, IPPROTO_SCTP, SCTP_NODELAY, (char *) &flag, sizeof(int));
+#endif
+}
+
+int sangomabc_connection_close(sangomabc_connection_t *mcon);
+int sangomabc_connection_open(sangomabc_connection_t *mcon, char *local_ip, int local_port, char *ip, int port);
+sangomabc_event_t *__sangomabc_connection_read(sangomabc_connection_t *mcon, int iteration, const char *file, const char *func, int line);
+sangomabc_event_t *__sangomabc_connection_readp(sangomabc_connection_t *mcon, int iteration, const char *file, const char *func, int line);
+int __sangomabc_connection_write(sangomabc_connection_t *mcon, sangomabc_event_t *event, const char *file, const char *func, int line);
+int __sangomabc_connection_writep(sangomabc_connection_t *mcon, sangomabc_event_t *event, const char *file, const char *func, int line);
+#define sangomabc_connection_write(_m,_e) __sangomabc_connection_write(_m, _e, __FILE__, __FUNCTION__, __LINE__)
+#define sangomabc_connection_writep(_m,_e) __sangomabc_connection_writep(_m, _e, __FILE__, __FUNCTION__, __LINE__)
+#define sangomabc_connection_read(_m,_e) __sangomabc_connection_read(_m, _e, __FILE__, __FUNCTION__, __LINE__)
+#define sangomabc_connection_readp(_m,_e) __sangomabc_connection_readp(_m, _e, __FILE__, __FUNCTION__, __LINE__)
+void sangomabc_event_init(sangomabc_short_event_t *event, sangomabc_event_id_t event_id, int chan, int span);
+void sangomabc_call_init(sangomabc_event_t *event, const char *calling, const char *called, int setup_id);
+const char *sangomabc_event_id_name(uint32_t event_id);
+int sangomabc_exec_command(sangomabc_connection_t *mcon, int span, int chan, int id, int cmd, int cause, int flags);
+int sangomabc_exec_commandp(sangomabc_connection_t *pcon, int span, int chan, int id, int cmd, int cause);
+
+#endif
+
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */

Added: freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_sangoma_boost/sangoma_boost_interface.h (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_sangoma_boost/sangoma_boost_interface.h	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_sangoma_boost/sangoma_boost_interface.h	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,244 @@
+/*
+ * Copyright (c) 2009, Sangoma Technologies
+ * Moises Silva <moy@sangoma.com>
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef SANGOMA_BOOST_INTERFACE_H
+#define SANGOMA_BOOST_INTERFACE_H
+
+#include "freetdm.h"
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*! 
+  \brief Callback used to notify signaling status changes on a channel
+  \param ftdmchan The freetdm channel where the signaling status just changed
+  \param status The new signaling status
+ */
+#define BOOST_SIG_STATUS_CB_ARGS (ftdm_channel_t *ftdmchan, ftdm_signaling_status_t status)
+typedef void (*boost_sig_status_cb_func_t) BOOST_SIG_STATUS_CB_ARGS;
+#define BOOST_SIG_STATUS_CB_FUNCTION(name) void name BOOST_SIG_STATUS_CB_ARGS
+
+/*! 
+  \brief Write a boost msg to a boost endpoint 
+  \param span The freetdm span where this msg was generated
+  \param msg The generic message pointer, owned by the caller
+  \param msglen The length of the provided structure pointed by msg
+  \return FTDM_SUCCESS or FTDM_FAIL
+
+   The msg buffer is owned by the caller and it should
+   be either t_sigboost_callstart or t_sigboost_short
+   the endpoint receiving the msg will first cast to
+   t_sigboost_short, check the event type, and if needed.
+ */
+#define BOOST_WRITE_MSG_ARGS (ftdm_span_t *span, void *msg, ftdm_size_t msglen)
+typedef ftdm_status_t (*boost_write_msg_func_t) BOOST_WRITE_MSG_ARGS;
+#define BOOST_WRITE_MSG_FUNCTION(name) ftdm_status_t name BOOST_WRITE_MSG_ARGS
+
+/*! 
+  \brief Set the callback to be used by a signaling module to write boost messages
+  \param callback The callback to be used by the signaling module
+
+   The provided callback will be used for the signaling boost module to notify the
+   user with boost messages.
+ */
+#define BOOST_SET_WRITE_MSG_CB_ARGS (boost_write_msg_func_t callback)
+typedef void (*boost_set_write_msg_cb_func_t) BOOST_SET_WRITE_MSG_CB_ARGS;
+#define BOOST_SET_WRITE_MSG_CB_FUNCTION(name) void name BOOST_SET_WRITE_MSG_CB_ARGS
+
+/*! 
+  \brief Notify hardware status change
+  \param ftdmchan The freetdm channel
+  \param status The hw status 
+  \return FTDM_SUCCESS or FTDM_FAIL 
+ */
+#define BOOST_ON_HW_LINK_STATUS_CHANGE_ARGS (ftdm_channel_t *ftdmchan, ftdm_channel_hw_link_status_t status)
+typedef void (*boost_on_hw_link_status_change_func_t) BOOST_ON_HW_LINK_STATUS_CHANGE_ARGS;
+#define BOOST_ON_HW_LINK_STATUS_CHANGE_FUNCTION(name) void name BOOST_ON_HW_LINK_STATUS_CHANGE_ARGS
+
+/*! 
+  \brief Set signaling status callback used by the signaling module to report signaling status changes
+  \param callback The callback to be used by the signaling module
+
+   The provided callback will be used for the signaling boost module to notify the
+   user with signaling link status changes.
+ */
+#define BOOST_SET_SIG_STATUS_CB_ARGS (boost_sig_status_cb_func_t callback)
+typedef void (*boost_set_sig_status_cb_func_t) BOOST_SET_SIG_STATUS_CB_ARGS;
+#define BOOST_SET_SIG_STATUS_CB_FUNCTION(name) void name BOOST_SET_SIG_STATUS_CB_ARGS
+
+/*! 
+  \brief Get the signaling status on the given channel.
+  \param ftdmchan The freetdm channel
+  \param status The status pointer where the current signaling status will be set
+ */
+#define BOOST_GET_CHANNEL_SIG_STATUS_ARGS (ftdm_channel_t *ftdmchan, ftdm_signaling_status_t *status)
+typedef ftdm_status_t (*boost_get_channel_sig_status_func_t) BOOST_GET_CHANNEL_SIG_STATUS_ARGS;
+#define BOOST_GET_CHANNEL_SIG_STATUS_FUNCTION(name) ftdm_status_t name BOOST_GET_CHANNEL_SIG_STATUS_ARGS
+
+/*! 
+  \brief Set the signaling status on the given channel.
+  \param ftdmchan The freetdm channel
+  \param status The new status for the channel
+  \return FTDM_SUCCESS or FTDM_FAIL 
+ */
+#define BOOST_SET_CHANNEL_SIG_STATUS_ARGS (ftdm_channel_t *ftdmchan, ftdm_signaling_status_t status)
+typedef ftdm_status_t (*boost_set_channel_sig_status_func_t) BOOST_SET_CHANNEL_SIG_STATUS_ARGS;
+#define BOOST_SET_CHANNEL_SIG_STATUS_FUNCTION(name) ftdm_status_t name BOOST_SET_CHANNEL_SIG_STATUS_ARGS
+
+/*! 
+  \brief Get the signaling status on the given span.
+  \param span The freetdm span 
+  \param status The status pointer where the current signaling status will be set
+ */
+#define BOOST_GET_SPAN_SIG_STATUS_ARGS (ftdm_span_t *span, ftdm_signaling_status_t *status)
+typedef ftdm_status_t (*boost_get_span_sig_status_func_t) BOOST_GET_SPAN_SIG_STATUS_ARGS;
+#define BOOST_GET_SPAN_SIG_STATUS_FUNCTION(name) ftdm_status_t name BOOST_GET_SPAN_SIG_STATUS_ARGS
+
+/*! 
+  \brief Set the signaling status on the given span.
+  \param ftdmchan The freetdm span
+  \param status The new status for the span
+  \return FTDM_SUCCESS or FTDM_FAIL 
+ */
+#define BOOST_SET_SPAN_SIG_STATUS_ARGS (ftdm_span_t *span, ftdm_signaling_status_t status)
+typedef ftdm_status_t (*boost_set_span_sig_status_func_t) BOOST_SET_SPAN_SIG_STATUS_ARGS;
+#define BOOST_SET_SPAN_SIG_STATUS_FUNCTION(name) ftdm_status_t name BOOST_SET_SPAN_SIG_STATUS_ARGS
+
+/*! 
+  \brief Configure the given span signaling
+  \param span The freetdm span
+  \param parameters The array of configuration key,value pairs (must be null terminated)
+  \return FTDM_SUCCESS or FTDM_FAIL 
+ */
+#define BOOST_CONFIGURE_SPAN_ARGS (ftdm_span_t *span, ftdm_conf_parameter_t *parameters) 
+typedef ftdm_status_t (*boost_configure_span_func_t) BOOST_CONFIGURE_SPAN_ARGS;
+#define BOOST_CONFIGURE_SPAN_FUNCTION(name) ftdm_status_t name BOOST_CONFIGURE_SPAN_ARGS
+
+/*! 
+  \brief Start the given span
+  \param span The freetdm span
+  \return FTDM_SUCCESS or FTDM_FAIL 
+ */
+#define BOOST_START_SPAN_ARGS (ftdm_span_t *span) 
+typedef ftdm_status_t (*boost_start_span_func_t) BOOST_START_SPAN_ARGS;
+#define BOOST_START_SPAN_FUNCTION(name) ftdm_status_t name BOOST_START_SPAN_ARGS
+
+/*! 
+  \brief Stop the given span
+  \param span The freetdm span
+  \return FTDM_SUCCESS or FTDM_FAIL 
+ */
+#define BOOST_STOP_SPAN_ARGS (ftdm_span_t *span) 
+typedef ftdm_status_t (*boost_stop_span_func_t) BOOST_START_SPAN_ARGS;
+#define BOOST_STOP_SPAN_FUNCTION(name) ftdm_status_t name BOOST_STOP_SPAN_ARGS
+
+/*! 
+  \brief Called when the module is being loaded BEFORE calling anything else
+  \return FTDM_SUCCESS or FTDM_FAIL
+ */
+#define BOOST_ON_LOAD_ARGS (void) 
+typedef ftdm_status_t (*boost_on_load_func_t) BOOST_ON_LOAD_ARGS;
+#define BOOST_ON_LOAD_FUNCTION(name) ftdm_status_t name BOOST_ON_LOAD_ARGS 
+
+/*! 
+  \brief Called when the module is being unloaded, last chance to stop everything!
+ */
+#define BOOST_ON_UNLOAD_ARGS (void) 
+typedef ftdm_status_t (*boost_on_unload_func_t) BOOST_ON_UNLOAD_ARGS;
+#define BOOST_ON_UNLOAD_FUNCTION(name) ftdm_status_t name BOOST_ON_UNLOAD_ARGS 
+
+/*! 
+  \brief The boost signaling module interface 
+ */
+typedef struct boost_sigmod_interface_s {
+	/*! \brief Module name */
+	const char *name;
+	/*! \brief write boost message function */
+	boost_write_msg_func_t write_msg;	
+	/*! \brief set the user write boost message function */
+	boost_set_write_msg_cb_func_t set_write_msg_cb;
+	/*! \brief set the user signaling status function */
+	boost_set_sig_status_cb_func_t set_sig_status_cb;
+	/*! \brief get channel signaling status */
+	boost_get_channel_sig_status_func_t get_channel_sig_status;
+	/*! \brief set channel signaling status */
+	boost_set_channel_sig_status_func_t set_channel_sig_status;
+	/*! \brief get span signaling status */
+	boost_get_span_sig_status_func_t get_span_sig_status;
+	/*! \brief set span signaling status */
+	boost_set_span_sig_status_func_t set_span_sig_status;
+	/*! \brief set notify hardware link status change */
+	boost_on_hw_link_status_change_func_t on_hw_link_status_change;
+	/*! \brief configure span signaling */
+	boost_configure_span_func_t configure_span;
+	/*! \brief start freetdm span */
+	boost_start_span_func_t start_span;
+	/*! \brief stop freetdm span */
+	boost_stop_span_func_t stop_span;
+	/*! \brief the module was just loaded */
+	boost_on_load_func_t on_load;
+	/*! \brief the module is about to be unloaded */
+	boost_on_unload_func_t on_unload;
+	/*! \brief private pointer for the interface user */
+	void *pvt;
+} boost_sigmod_interface_t;
+
+#ifdef __cplusplus
+} // extern C
+#endif
+
+#define BOOST_INTERFACE_NAME boost_sigmod_interface
+#define BOOST_INTERFACE_NAME_STR "boost_sigmod_interface"
+/* use this in your sig boost module to declare your interface */
+#ifndef WIN32
+#define BOOST_INTERFACE boost_sigmod_interface_t BOOST_INTERFACE_NAME
+#else
+#define BOOST_INTERFACE __declspec(dllexport) boost_sigmod_interface_t BOOST_INTERFACE_NAME
+#endif
+#endif
+
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
+

Added: freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_sangoma_boost/sigboost.h (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_sangoma_boost/sigboost.h	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_sangoma_boost/sigboost.h	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,203 @@
+/****************************************************************************
+ * sigboost.h     $Revision: 1.13 $
+ *
+ * Definitions for the sigboost interface.
+ *
+ * WARNING WARNING WARNING
+ *
+ * This file is used by sangoma_mgd and perhaps other programs. Any changes 
+ * to this file must be coordinated with other user programs,
+ *
+ * Copyright (C) 2005  Xygnada Technology, Inc.
+ * 
+****************************************************************************/
+#ifndef _SIGBOOST_H_
+#define _SIGBOOST_H_
+
+#define SIGBOOST_VERSION 103
+
+// handy to define integer types that actually work on both Lin and Win
+#include <freetdm.h>
+
+enum	e_sigboost_event_id_values
+{
+	SIGBOOST_EVENT_CALL_START			= 0x80, /*128*/
+	SIGBOOST_EVENT_CALL_START_ACK			= 0x81, /*129*/
+	SIGBOOST_EVENT_CALL_START_NACK			= 0x82, /*130*/
+	SIGBOOST_EVENT_CALL_START_NACK_ACK		= 0x83, /*131*/
+	SIGBOOST_EVENT_CALL_ANSWERED			= 0x84, /*132*/
+	SIGBOOST_EVENT_CALL_STOPPED			= 0x85, /*133*/
+	SIGBOOST_EVENT_CALL_STOPPED_ACK			= 0x86, /*134*/
+	SIGBOOST_EVENT_SYSTEM_RESTART			= 0x87, /*135*/
+	SIGBOOST_EVENT_SYSTEM_RESTART_ACK		= 0x88, /*136*/
+       /* CALL_RELEASED is aimed to fix a race condition that became obvious
+        * when the boost socket was replaced by direct function calls
+        * and the channel hunting was moved to freetdm, the problem is
+        * we can get CALL_STOPPED msg and reply with CALL_STOPPED_ACK
+        * but the signaling module will still (in PRI) send RELEASE and
+        * wait for RELEASE_COMPLETE from the isdn network before
+        * marking the channel as available, therefore freetdm should
+        * also not mark the channel as available until CALL_RELEASED
+        * is received, for socket mode we can continue working as usual
+        * with CALL_STOPPED being the last step because the hunting is
+        * done in the signaling module.
+        * */
+	SIGBOOST_EVENT_CALL_RELEASED                    = 0x51, /* 81 */
+	SIGBOOST_EVENT_CALL_PROGRESS            	= 0x50, /*decimal  80*/
+	/* Following IDs are ss7boost to sangoma_mgd only. */
+	SIGBOOST_EVENT_HEARTBEAT			= 0x89, /*137*/
+	SIGBOOST_EVENT_INSERT_CHECK_LOOP		= 0x8a, /*138*/
+	SIGBOOST_EVENT_REMOVE_CHECK_LOOP		= 0x8b, /*139*/
+	SIGBOOST_EVENT_AUTO_CALL_GAP_ABATE		= 0x8c, /*140*/
+	SIGBOOST_EVENT_DIGIT_IN					= 0x8d, /*141*/
+};
+enum	e_sigboost_release_cause_values
+{
+	SIGBOOST_RELEASE_CAUSE_UNDEFINED		= 0,
+	SIGBOOST_RELEASE_CAUSE_NORMAL			= 16,
+	/* probable elimination */
+	//SIGBOOST_RELEASE_CAUSE_BUSY			= 0x91, /* 145 */
+	//SIGBOOST_RELEASE_CAUSE_CALLED_NOT_EXIST	= 0x92, /* 146 */
+	//SIGBOOST_RELEASE_CAUSE_CIRCUIT_RESET		= 0x93, /* 147 */
+	//SIGBOOST_RELEASE_CAUSE_NOANSWER		= 0x94, /* 148 */
+};
+
+enum	e_sigboost_call_setup_ack_nack_cause_values
+{
+	//SIGBOOST_CALL_SETUP_NACK_ALL_CKTS_BUSY		= 34,  /* Q.850 value - don't use */
+	SIGBOOST_CALL_SETUP_NACK_ALL_CKTS_BUSY		= 117,  /* non Q.850 value indicates local all ckt busy 
+								   causing sangoma_mgd to perform automatic call 
+								   gapping*/
+	SIGBOOST_CALL_SETUP_NACK_TEST_CKT_BUSY		= 17,  /* Q.850 value */
+	SIGBOOST_CALL_SETUP_NACK_INVALID_NUMBER		= 28,  /* Q.850 value */
+	SIGBOOST_CALL_SETUP_CSUPID_DBL_USE		= 200, /* unused Q.850 value */
+};
+
+
+enum	e_sigboost_huntgroup_values
+{
+	SIGBOOST_HUNTGRP_SEQ_ASC	= 0x00, /* sequential with lowest available first */
+	SIGBOOST_HUNTGRP_SEQ_DESC	= 0x01, /* sequential with highest available first */
+	SIGBOOST_HUNTGRP_RR_ASC		= 0x02, /* round-robin with lowest available first */
+	SIGBOOST_HUNTGRP_RR_DESC	= 0x03, /* round-robin with highest available first */
+};
+
+enum e_sigboost_event_info_par_values
+{
+  	SIGBOOST_EVI_SPARE 				   	 	= 0x00, 
+  	SIGBOOST_EVI_ALERTING 					= 0x01, 
+  	SIGBOOST_EVI_PROGRESS 					= 0x02, 
+};
+
+enum e_sigboost_progress_flags
+{
+	SIGBOOST_PROGRESS_RING = (1 << 0),
+	SIGBOOST_PROGRESS_MEDIA = (1 << 1)
+};
+
+#define MAX_DIALED_DIGITS	31
+
+/* Next two defines are used to create the range of values for call_setup_id
+ * in the t_sigboost structure.
+ * 0..((CORE_MAX_SPANS * CORE_MAX_CHAN_PER_SPAN) - 1) */
+#define CORE_MAX_SPANS 		200
+#define CORE_MAX_CHAN_PER_SPAN 	32
+#define MAX_PENDING_CALLS 	CORE_MAX_SPANS * CORE_MAX_CHAN_PER_SPAN
+/* 0..(MAX_PENDING_CALLS-1) is range of call_setup_id below */
+
+/* Should only be used by server */
+#define MAX_CALL_SETUP_ID   0xFFFF
+
+#define SIZE_CUSTOM	900
+#define SIZE_RDNIS  SIZE_CUSTOM
+
+
+#pragma pack(1)
+
+typedef struct
+{
+	uint8_t			capability;
+	uint8_t			uil1p;
+} t_sigboost_bearer;
+
+typedef struct
+{
+	uint8_t			digits_count;
+	char			digits [MAX_DIALED_DIGITS + 1]; /* it's a null terminated string */
+	uint8_t 		npi;
+	uint8_t 		ton;
+	uint8_t			screening_ind;
+	uint8_t			presentation_ind;
+}t_sigboost_digits;
+
+typedef struct
+{
+	uint16_t		version;
+	uint32_t		event_id;
+	/* delete sequence numbers - SCTP does not need them */
+	uint32_t		fseqno;
+	uint32_t		bseqno;
+	uint16_t		call_setup_id;
+	uint32_t		trunk_group;
+	uint8_t			span;
+	uint8_t			chan;
+	uint32_t		flags;
+	/* struct timeval  	tv; */ 
+	t_sigboost_digits called;
+	t_sigboost_digits calling;
+	t_sigboost_digits rdnis;
+	/* ref. Q.931 Table 4-11 and Q.951 Section 3 */
+	char			calling_name[MAX_DIALED_DIGITS + 1];
+	t_sigboost_bearer 	bearer;
+	uint8_t			hunt_group;
+	uint16_t		custom_data_size;
+	char			custom_data[SIZE_CUSTOM]; /* it's a null terminated string */
+
+} t_sigboost_callstart;
+
+#define called_number_digits_count		called.digits_count
+#define called_number_digits			called.digits
+#define calling_number_digits_count		calling.digits_count
+#define calling_number_digits			calling.digits
+#define calling_number_screening_ind	calling.screening_ind
+#define calling_number_presentation		calling.presentation_ind
+
+#define isup_in_rdnis_size				custom_data_size
+#define isup_in_rdnis					custom_data
+
+
+#define MIN_SIZE_CALLSTART_MSG  sizeof(t_sigboost_callstart) - SIZE_CUSTOM
+
+typedef struct
+{
+	uint16_t		version;
+	uint32_t		event_id;
+	/* delete sequence numbers - SCTP does not need them */
+	uint32_t		fseqno;
+	uint32_t		bseqno;
+	uint16_t		call_setup_id;
+	uint32_t		trunk_group;
+	uint8_t			span;
+	uint8_t			chan;
+	uint32_t		flags;
+	/* struct timeval  	tv; */ 
+	uint8_t			release_cause;
+} t_sigboost_short;
+#pragma pack()
+
+
+static __inline__ int boost_full_event(int event_id)
+{
+        switch (event_id) {
+        case SIGBOOST_EVENT_CALL_START:
+        case SIGBOOST_EVENT_DIGIT_IN:
+	case SIGBOOST_EVENT_CALL_PROGRESS:
+		return 1;
+        default:
+		break;
+        }
+
+        return 0;
+}
+
+#endif

Added: freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_skel/ftmod_skel.c (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_skel/ftmod_skel.c	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_skel/ftmod_skel.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,152 @@
+/*
+ * Copyright (c) 2007, Anthony Minessale II
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#include "freetdm.h"
+//#include "ftdm_skel.h"
+
+static FIO_CONFIGURE_FUNCTION(skel_configure)
+{
+	return FTDM_FAIL;
+}
+
+static FIO_CONFIGURE_SPAN_FUNCTION(skel_configure_span)
+{
+	return FTDM_FAIL;
+}
+
+static FIO_OPEN_FUNCTION(skel_open) 
+{
+	return FTDM_FAIL;
+}
+
+static FIO_CLOSE_FUNCTION(skel_close)
+{
+	return FTDM_FAIL;
+}
+
+static FIO_WAIT_FUNCTION(skel_wait)
+{
+	return FTDM_FAIL;
+}
+
+static FIO_READ_FUNCTION(skel_read)
+{
+	return FTDM_FAIL;
+}
+
+static FIO_WRITE_FUNCTION(skel_write)
+{
+	return FTDM_FAIL;
+}
+
+static FIO_COMMAND_FUNCTION(skel_command)
+{
+	return FTDM_FAIL;
+}
+
+static FIO_SPAN_POLL_EVENT_FUNCTION(skel_poll_event)
+{
+	return FTDM_FAIL;
+}
+
+static FIO_SPAN_NEXT_EVENT_FUNCTION(skel_next_event)
+{
+	return FTDM_FAIL;
+}
+
+static FIO_CHANNEL_DESTROY_FUNCTION(skel_channel_destroy)
+{
+	return FTDM_FAIL;
+}
+
+static FIO_SPAN_DESTROY_FUNCTION(skel_span_destroy)
+{
+	return FTDM_FAIL;
+}
+
+static FIO_GET_ALARMS_FUNCTION(skel_get_alarms)
+{
+	return FTDM_FAIL;
+}
+
+static ftdm_io_interface_t skel_interface;
+
+static FIO_IO_LOAD_FUNCTION(skel_init)
+{
+	assert(fio != NULL);
+	memset(&skel_interface, 0, sizeof(skel_interface));
+
+	skel_interface.name = "skel";
+	skel_interface.configure =  skel_configure;
+	skel_interface.configure_span =  skel_configure_span;
+	skel_interface.open = skel_open;
+	skel_interface.close = skel_close;
+	skel_interface.wait = skel_wait;
+	skel_interface.read = skel_read;
+	skel_interface.write = skel_write;
+	skel_interface.command = skel_command;
+	skel_interface.poll_event = skel_poll_event;
+	skel_interface.next_event = skel_next_event;
+	skel_interface.channel_destroy = skel_channel_destroy;
+	skel_interface.span_destroy = skel_span_destroy;
+	skel_interface.get_alarms = skel_get_alarms;
+	*fio = &skel_interface;
+
+	return FTDM_SUCCESS;
+}
+
+static FIO_IO_UNLOAD_FUNCTION(skel_destroy)
+{
+	return FTDM_SUCCESS;
+}
+
+
+ftdm_module_t ftdm_module = { 
+	"skel",
+	skel_init,
+	skel_destroy,
+};
+
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
+

Added: freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.2008.vcproj (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.2008.vcproj	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.2008.vcproj	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,355 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="9.00"
+	Name="ftmod_wanpipe"
+	ProjectGUID="{1A145EE9-BBD8-45E5-98CD-EB4BE99E1DCD}"
+	RootNamespace="ftmod_wanpipe"
+	Keyword="Win32Proj"
+	TargetFrameworkVersion="131072"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+		<Platform
+			Name="x64"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="2"
+			CharacterSet="2"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				AdditionalIncludeDirectories="../../../src/include;../../../src/isdn/include;&quot;C:\Program Files\Sangoma\include&quot;"
+				PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;"
+				MinimalRebuild="true"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="3"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				Detect64BitPortabilityProblems="true"
+				DebugInformationFormat="4"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="freetdm.lib libsangoma.lib"
+				LinkIncremental="2"
+				AdditionalLibraryDirectories="&quot;$(OutDir)&quot;;&quot;C:\Program Files\Sangoma\lib&quot;"
+				GenerateDebugInformation="true"
+				SubSystem="1"
+				RandomizedBaseAddress="1"
+				DataExecutionPrevention="0"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Debug|x64"
+			OutputDirectory="$(SolutionDir)$(PlatformName)\$(ConfigurationName)"
+			IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+			ConfigurationType="2"
+			CharacterSet="2"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+				TargetEnvironment="3"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				AdditionalIncludeDirectories="../../../src/include;../../../src/isdn/include;../../../wanpipe/include"
+				PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;"
+				MinimalRebuild="true"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="3"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				Detect64BitPortabilityProblems="true"
+				DebugInformationFormat="3"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="freetdm.lib libsangoma.lib"
+				LinkIncremental="2"
+				AdditionalLibraryDirectories="&quot;$(OutDir)&quot;;../../../wanpipe/api/lib/x64"
+				GenerateDebugInformation="true"
+				SubSystem="1"
+				RandomizedBaseAddress="1"
+				DataExecutionPrevention="0"
+				TargetMachine="17"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="2"
+			CharacterSet="2"
+			WholeProgramOptimization="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalIncludeDirectories="../../../src/include;../../../src/isdn/include;../../../wanpipe/include"
+				PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
+				RuntimeLibrary="2"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				Detect64BitPortabilityProblems="true"
+				DebugInformationFormat="3"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="freetdm.lib libsangoma.lib"
+				LinkIncremental="1"
+				AdditionalLibraryDirectories="&quot;$(OutDir)&quot;;../../../wanpipe/api/lib/x86"
+				GenerateDebugInformation="true"
+				SubSystem="1"
+				OptimizeReferences="2"
+				EnableCOMDATFolding="2"
+				RandomizedBaseAddress="1"
+				DataExecutionPrevention="0"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|x64"
+			OutputDirectory="$(SolutionDir)$(PlatformName)\$(ConfigurationName)"
+			IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+			ConfigurationType="2"
+			CharacterSet="2"
+			WholeProgramOptimization="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+				TargetEnvironment="3"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalIncludeDirectories="../../../src/include;../../../src/isdn/include;../../../wanpipe/include"
+				PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
+				RuntimeLibrary="2"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				Detect64BitPortabilityProblems="true"
+				DebugInformationFormat="3"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="freetdm.lib libsangoma.lib"
+				LinkIncremental="1"
+				AdditionalLibraryDirectories="&quot;$(OutDir)&quot;;../../../wanpipe/api/lib/x64"
+				GenerateDebugInformation="true"
+				SubSystem="1"
+				OptimizeReferences="2"
+				EnableCOMDATFolding="2"
+				RandomizedBaseAddress="1"
+				DataExecutionPrevention="0"
+				TargetMachine="17"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<Filter
+			Name="Source Files"
+			Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+			>
+			<File
+				RelativePath=".\ftmod_wanpipe.c"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="Header Files"
+			Filter="h;hpp;hxx;hm;inl;inc;xsd"
+			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+			>
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>

Added: freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,1238 @@
+/*
+ * Copyright (c) 2007, Anthony Minessale II
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Contributors: 
+ *
+ * Moises Silva <moy@sangoma.com>
+ * David Yat Sin <davidy@sangoma.com>
+ * Nenad Corbic <ncorbic@sangoma.com>
+ *
+ */
+
+#ifdef __sun
+#include <unistd.h>
+#include <stropts.h>
+#endif
+#include "freetdm.h"
+#ifndef __WINDOWS__
+#include <poll.h>
+#include <sys/socket.h>
+#endif
+#include "libsangoma.h"
+
+#if defined(__WINDOWS__)
+/*! Backward compatible defines - current code is all using the old names*/ 
+#define sangoma_open_tdmapi_span_chan sangoma_open_api_span_chan
+#define sangoma_open_tdmapi_span sangoma_open_api_span
+#define sangoma_open_tdmapi_ctrl sangoma_open_api_ctrl
+#define sangoma_tdm_get_fe_status sangoma_get_fe_status
+#define sangoma_socket_close sangoma_close
+#define sangoma_tdm_get_hw_coding sangoma_get_hw_coding
+#define sangoma_tdm_set_fe_status sangoma_set_fe_status
+#define sangoma_tdm_get_link_status sangoma_get_link_status
+#define sangoma_tdm_flush_bufs sangoma_flush_bufs
+#define sangoma_tdm_cmd_exec sangoma_cmd_exec
+#define sangoma_tdm_read_event sangoma_read_event
+#define sangoma_readmsg_tdm sangoma_readmsg
+#define sangoma_readmsg_socket sangoma_readmsg
+#define sangoma_sendmsg_socket sangoma_writemsg
+#define sangoma_writemsg_tdm sangoma_writemsg
+#define sangoma_create_socket_intr sangoma_open_api_span_chan
+#endif
+
+/*! Starting with libsangoma 3 we can use the new libsangoma waitable API, the poor souls of those using a release where LIBSANGOMA version
+ * is defined but the version is not higher or equal to 3.0.0 will be forced to upgrade
+ * */
+#ifdef LIBSANGOMA_VERSION 
+#if LIBSANGOMA_VERSION_CODE < LIBSANGOMA_VERSION(3,0,0)
+#undef LIBSANGOMA_VERSION
+#endif
+#endif
+
+/**
+ * \brief Wanpipe flags
+ */
+typedef enum {
+	WP_RINGING = (1 << 0)
+} wp_flag_t;
+
+/**
+ * \brief Wanpipe globals
+ */
+static struct {
+	uint32_t codec_ms;
+	uint32_t wink_ms;
+	uint32_t flash_ms;
+	uint32_t ring_on_ms;
+	uint32_t ring_off_ms;
+} wp_globals;
+
+/* a bunch of this stuff should go into the wanpipe_tdm_api_iface.h */
+
+FIO_SPAN_POLL_EVENT_FUNCTION(wanpipe_poll_event);
+FIO_SPAN_NEXT_EVENT_FUNCTION(wanpipe_next_event);
+
+#define WP_INVALID_SOCKET -1 
+
+/**
+ * \brief Poll for event on a wanpipe socket
+ * \param fd Wanpipe socket descriptor
+ * \param timeout Time to wait for event
+ * \param flags Sangoma event flags
+ * \return -1 on failure, wanpipe event flags on success
+ *
+ * a cross platform way to poll on an actual pollset (span and/or list of spans) will probably also be needed for analog
+ * so we can have one analong handler thread that will deal with all the idle analog channels for events
+ * the alternative would be for the driver to provide one socket for all of the oob events for all analog channels
+ */
+static __inline__ int tdmv_api_wait_socket(ftdm_channel_t *ftdmchan, int timeout, int *flags)
+{
+	
+#ifdef LIBSANGOMA_VERSION
+	int err;
+    uint32_t inflags = *flags;
+    uint32_t outflags = 0;
+	sangoma_wait_obj_t *sangoma_wait_obj = ftdmchan->mod_data;
+
+	err = sangoma_waitfor(sangoma_wait_obj, inflags, &outflags, timeout);
+	*flags = 0;
+    if (err == SANG_STATUS_SUCCESS) {
+        *flags = outflags;
+        err = 1; /* ideally should be the number of file descriptors with something to read */
+    }
+    if (err == SANG_STATUS_APIPOLL_TIMEOUT) {
+        err = 0;
+    }
+    return err;
+#else
+ 	struct pollfd pfds[1];
+    int res;
+
+    memset(&pfds[0], 0, sizeof(pfds[0]));
+    pfds[0].fd = ftdmchan->sockfd;
+    pfds[0].events = *flags;
+    res = poll(pfds, 1, timeout);
+	*flags = 0;
+
+	if (pfds[0].revents & POLLERR) {
+		res = -1;
+	}
+
+	if (res > 0) {
+		*flags = pfds[0].revents;
+	}
+
+    return res;
+#endif
+	
+}
+
+/**
+ * \brief Opens a sangoma channel socket (TDM API)
+ * \param span Span number
+ * \param chan Channel number
+ * \return 0 on success, wanpipe error code on failure
+ */
+static __inline__ sng_fd_t tdmv_api_open_span_chan(int span, int chan) 
+{
+	return sangoma_open_tdmapi_span_chan(span, chan);
+}
+
+#ifdef LIBSANGOMA_VERSION
+static __inline__ sng_fd_t __tdmv_api_open_span_chan(int span, int chan) 
+{ 
+	return  __sangoma_open_tdmapi_span_chan(span, chan);
+}                        
+#endif
+
+static ftdm_io_interface_t wanpipe_interface;
+
+/**
+ * \brief Inverts bit string
+ * \param cas_bits CAS bit string
+ * \return Swapped bits
+ */
+static unsigned char wanpipe_swap_bits(unsigned char cas_bits)
+{
+	unsigned char swapped_bits = 0x0;
+	if (cas_bits & 0x8) {
+		swapped_bits |= 0x1;
+	}
+	if (cas_bits & 0x4) {
+		swapped_bits |= 0x2;
+	}
+	if (cas_bits & 0x2) {
+		swapped_bits |= 0x4;
+	}
+	if (cas_bits & 0x1) {
+		swapped_bits |= 0x8;
+	}
+	return swapped_bits;
+}
+
+/**
+ * \brief Initialises a range of wanpipe channels
+ * \param span FreeTDM span
+ * \param spanno Wanpipe span number
+ * \param start Initial wanpipe channel number
+ * \param end Final wanpipe channel number
+ * \param type FreeTDM channel type
+ * \param name FreeTDM span name
+ * \param number FreeTDM span number
+ * \param cas_bits CAS bits
+ * \return number of spans configured
+ */
+static unsigned wp_open_range(ftdm_span_t *span, unsigned spanno, unsigned start, unsigned end, ftdm_chan_type_t type, char *name, char *number, unsigned char cas_bits)
+{
+	unsigned configured = 0, x;
+#ifdef LIBSANGOMA_VERSION
+	sangoma_status_t sangstatus;
+	sangoma_wait_obj_t *sangoma_wait_obj;
+#endif
+
+	if (type == FTDM_CHAN_TYPE_CAS) {
+		ftdm_log(FTDM_LOG_DEBUG, "Configuring Wanpipe CAS channels with abcd == 0x%X\n", cas_bits);
+	}	
+	for(x = start; x < end; x++) {
+		ftdm_channel_t *chan;
+		ftdm_socket_t sockfd = WP_INVALID_SOCKET;
+		const char *dtmf = "none";
+		if (!strncasecmp(span->name, "smg_prid_nfas", 8) && span->trunk_type == FTDM_TRUNK_T1 && x == 24) {
+#ifdef LIBSANGOMA_VERSION
+			sockfd = __tdmv_api_open_span_chan(spanno, x);
+#else
+			ftdm_log(FTDM_LOG_ERROR, "span %d channel %d cannot be configured as smg_prid_nfas, you need to compile freetdm with newer libsangoma\n", spanno, x);
+#endif
+		} else {
+			sockfd = tdmv_api_open_span_chan(spanno, x);
+		}
+
+		if (sockfd == WP_INVALID_SOCKET) {
+			ftdm_log(FTDM_LOG_ERROR, "Failed to open wanpipe device span %d channel %d\n", spanno, x);
+			continue;
+		}
+		
+		if (ftdm_span_add_channel(span, sockfd, type, &chan) == FTDM_SUCCESS) {
+			wanpipe_tdm_api_t tdm_api;
+			memset(&tdm_api, 0, sizeof(tdm_api));
+#ifdef LIBSANGOMA_VERSION
+			/* we need SANGOMA_DEVICE_WAIT_OBJ_SIG and not SANGOMA_DEVICE_WAIT_OBJ alone because we need to call 
+			 * sangoma_wait_obj_sig to wake up any I/O waiters when closing the channel (typically on ftdm shutdown)
+			 * this adds an extra pair of file descriptors to the waitable object
+			 * */
+			sangstatus = sangoma_wait_obj_create(&sangoma_wait_obj, sockfd, SANGOMA_DEVICE_WAIT_OBJ_SIG);
+			if (sangstatus != SANG_STATUS_SUCCESS) {
+				ftdm_log(FTDM_LOG_ERROR, "failure create waitable object for s%dc%d\n", spanno, x);
+				continue;
+			}
+			chan->mod_data = sangoma_wait_obj;
+#endif
+			
+			chan->physical_span_id = spanno;
+			chan->physical_chan_id = x;
+			chan->rate = 8000;
+			
+			if (type == FTDM_CHAN_TYPE_FXS || type == FTDM_CHAN_TYPE_FXO || type == FTDM_CHAN_TYPE_B) {
+				int err;
+				
+				dtmf = "software";
+
+				/* FIXME: Handle Error Condition Check for return code */
+				err = sangoma_tdm_get_hw_coding(chan->sockfd, &tdm_api);
+
+				if (tdm_api.wp_tdm_cmd.hw_tdm_coding) {
+					chan->native_codec = chan->effective_codec = FTDM_CODEC_ALAW;
+				} else {
+					chan->native_codec = chan->effective_codec = FTDM_CODEC_ULAW;
+				}
+
+				//err = sangoma_tdm_get_hw_dtmf(chan->sockfd, &tdm_api);
+				//if (err > 0) {
+					err = sangoma_tdm_enable_dtmf_events(chan->sockfd, &tdm_api);
+					if (err == 0) {
+						ftdm_channel_set_feature(chan, FTDM_CHANNEL_FEATURE_DTMF_DETECT);
+						dtmf = "hardware";
+					}
+				//}
+			}
+
+#ifdef LIBSANGOMA_VERSION
+			if (type == FTDM_CHAN_TYPE_FXS) {
+				if (sangoma_tdm_disable_ring_trip_detect_events(chan->sockfd, &tdm_api)) {
+					/* we had problems of on-hook/off-hook detection due to how ring trip events were handled
+					 * if this fails, I believe we will still work ok as long as we dont handle them incorrectly */
+					ftdm_log(FTDM_LOG_WARNING, "Failed to disable ring trip events in channel s%dc%d\n", spanno, x);
+				}
+			}
+#endif
+#if 0
+            if (type == FTDM_CHAN_TYPE_FXS || type == FTDM_CHAN_TYPE_FXO) {
+                /* Enable FLASH/Wink Events */
+                int err=sangoma_set_rm_rxflashtime(chan->sockfd, &tdm_api, wp_globals.flash_ms);
+                if (err == 0) {
+			        ftdm_log(FTDM_LOG_ERROR, "flash enabled s%dc%d\n", spanno, x);
+                } else {
+			        ftdm_log(FTDM_LOG_ERROR, "flash disabled s%dc%d\n", spanno, x);
+                }
+            }
+#endif
+
+			if (type == FTDM_CHAN_TYPE_CAS || type == FTDM_CHAN_TYPE_EM) {
+#ifdef LIBSANGOMA_VERSION
+				sangoma_tdm_write_rbs(chan->sockfd,&tdm_api,chan->physical_chan_id, wanpipe_swap_bits(cas_bits));
+
+				/* this should probably be done for old libsangoma but I am not sure if the API is available and I'm lazy to check,
+				   The poll rate is hard coded to 100 per second (done in the driver, is the max rate of polling allowed by wanpipe)
+				 */
+				if (sangoma_tdm_enable_rbs_events(chan->sockfd, &tdm_api, 100)) {
+					ftdm_log(FTDM_LOG_ERROR, "Failed to enable RBS/CAS events in device %d:%d fd:%d\n", chan->span_id, chan->chan_id, sockfd);
+					continue;
+				}
+				/* probably done by the driver but lets write defensive code this time */
+				sangoma_flush_bufs(chan->sockfd, &tdm_api);
+#else
+				/* 
+				 * With wanpipe 3.4.4.2 I get failure even though the events are enabled, /var/log/messages said:
+				 * wanpipe4: WARNING: Event type 9 is already pending!
+				 * wanpipe4: Failed to add new fe event 09 ch_map=FFFFFFFF!
+				 * may be we should not send an error until that is fixed in the driver
+				 */
+				if (sangoma_tdm_enable_rbs_events(chan->sockfd, &tdm_api, 100)) {
+					ftdm_log(FTDM_LOG_ERROR, "Failed to enable RBS/CAS events in device %d:%d fd:%d\n", chan->span_id, chan->chan_id, sockfd);
+				}
+				/* probably done by the driver but lets write defensive code this time */
+				sangoma_tdm_flush_bufs(chan->sockfd, &tdm_api);
+				sangoma_tdm_write_rbs(chan->sockfd,&tdm_api, wanpipe_swap_bits(cas_bits));
+#endif
+			}
+			
+			if (!ftdm_strlen_zero(name)) {
+				ftdm_copy_string(chan->chan_name, name, sizeof(chan->chan_name));
+			}
+
+			if (!ftdm_strlen_zero(number)) {
+				ftdm_copy_string(chan->chan_number, number, sizeof(chan->chan_number));
+			}
+			configured++;
+			ftdm_log(FTDM_LOG_INFO, "configuring device s%dc%d as FreeTDM device %d:%d fd:%d DTMF: %s\n",
+				spanno, x, chan->span_id, chan->chan_id, sockfd, dtmf);
+
+		} else {
+			ftdm_log(FTDM_LOG_ERROR, "ftdm_span_add_channel failed for wanpipe span %d channel %d\n", spanno, x);
+		}
+	}
+	
+	return configured;
+}
+
+/**
+ * \brief Process configuration variable for a Wanpipe profile
+ * \param category Wanpipe profile name
+ * \param var Variable name
+ * \param val Variable value
+ * \param lineno Line number from configuration file
+ * \return Success
+ */
+static FIO_CONFIGURE_FUNCTION(wanpipe_configure)
+{
+	int num;
+
+	if (!strcasecmp(category, "defaults")) {
+		if (!strcasecmp(var, "codec_ms")) {
+			num = atoi(val);
+			if (num < 10 || num > 60) {
+				ftdm_log(FTDM_LOG_WARNING, "invalid codec ms at line %d\n", lineno);
+			} else {
+				wp_globals.codec_ms = num;
+			}
+		} else if (!strcasecmp(var, "wink_ms")) {
+			num = atoi(val);
+			if (num < 50 || num > 3000) {
+				ftdm_log(FTDM_LOG_WARNING, "invalid wink ms at line %d\n", lineno);
+			} else {
+				wp_globals.wink_ms = num;
+			}
+		} else if (!strcasecmp(var, "flash_ms")) {
+			num = atoi(val);
+			if (num < 50 || num > 3000) {
+				ftdm_log(FTDM_LOG_WARNING, "invalid flash ms at line %d\n", lineno);
+			} else {
+				wp_globals.flash_ms = num;
+			}
+		} else if (!strcasecmp(var, "ring_on_ms")) {
+			num = atoi(val);
+			if (num < 500 || num > 5000) {
+				ftdm_log(FTDM_LOG_WARNING, "invalid ring_on_ms at line %d (valid range 500 to 5000)\n", lineno);
+			} else {
+				wp_globals.ring_on_ms = num;
+			}
+		} else if (!strcasecmp(var, "ring_off_ms")) {
+			num = atoi(val);
+			if (num < 500 || num > 5000) {
+				ftdm_log(FTDM_LOG_WARNING, "invalid ring_off_ms at line %d (valid range 500 to 5000)\n", lineno);
+			} else {
+				wp_globals.ring_off_ms = num;
+			}
+		}
+	}
+
+	return FTDM_SUCCESS;
+}
+
+/**
+ * \brief Initialises an freetdm Wanpipe span from a configuration string
+ * \param span FreeTDM span
+ * \param str Configuration string
+ * \param type FreeTDM span type
+ * \param name FreeTDM span name
+ * \param number FreeTDM span number
+ * \return Success or failure
+ */
+static FIO_CONFIGURE_SPAN_FUNCTION(wanpipe_configure_span)
+{
+	int items, i;
+	char *mydata, *item_list[10];
+	char *sp, *ch, *mx;
+	unsigned char cas_bits = 0;
+	int channo;
+	int spanno;
+	int top = 0;
+	unsigned configured = 0;
+
+	assert(str != NULL);
+	
+
+	mydata = ftdm_strdup(str);
+	assert(mydata != NULL);
+
+
+	items = ftdm_separate_string(mydata, ',', item_list, (sizeof(item_list) / sizeof(item_list[0])));
+
+	for(i = 0; i < items; i++) {
+		sp = item_list[i];
+		if ((ch = strchr(sp, ':'))) {
+			*ch++ = '\0';
+		}
+
+		if (!(sp && ch)) {
+			ftdm_log(FTDM_LOG_ERROR, "No valid wanpipe span and channel was specified\n");
+			continue;
+		}
+
+		channo = atoi(ch);
+		spanno = atoi(sp);
+
+		if (channo < 0) {
+			ftdm_log(FTDM_LOG_ERROR, "Invalid channel number %d\n", channo);
+			continue;
+		}
+
+		if (spanno < 0) {
+			ftdm_log(FTDM_LOG_ERROR, "Invalid span number %d\n", channo);
+			continue;
+		}
+		
+		if ((mx = strchr(ch, '-'))) {
+			mx++;
+			top = atoi(mx) + 1;
+		} else {
+			top = channo + 1;
+		}
+		
+		
+		if (top < 0) {
+			ftdm_log(FTDM_LOG_ERROR, "Invalid range number %d\n", top);
+			continue;
+		}
+		if (FTDM_CHAN_TYPE_CAS == type && ftdm_config_get_cas_bits(ch, &cas_bits)) {
+			ftdm_log(FTDM_LOG_ERROR, "Failed to get CAS bits in CAS channel\n");
+			continue;
+		}
+		configured += wp_open_range(span, spanno, channo, top, type, name, number, cas_bits);
+
+	}
+	
+	ftdm_safe_free(mydata);
+
+	return configured;
+}
+
+/**
+ * \brief Opens Wanpipe channel
+ * \param ftdmchan Channel to open
+ * \return Success or failure
+ */
+static FIO_OPEN_FUNCTION(wanpipe_open) 
+{
+
+	wanpipe_tdm_api_t tdm_api;
+
+	memset(&tdm_api,0,sizeof(tdm_api));
+	sangoma_tdm_flush_bufs(ftdmchan->sockfd, &tdm_api);
+#ifdef LIBSANGOMA_VERSION
+	sangoma_flush_event_bufs(ftdmchan->sockfd, &tdm_api);
+#endif
+
+	if (ftdmchan->type == FTDM_CHAN_TYPE_DQ921 || ftdmchan->type == FTDM_CHAN_TYPE_DQ931) {
+		ftdmchan->native_codec = ftdmchan->effective_codec = FTDM_CODEC_NONE;
+	} else {
+		ftdmchan->effective_codec = ftdmchan->native_codec;
+		
+		sangoma_tdm_set_usr_period(ftdmchan->sockfd, &tdm_api, wp_globals.codec_ms);
+
+		ftdm_channel_set_feature(ftdmchan, FTDM_CHANNEL_FEATURE_INTERVAL);
+		ftdmchan->effective_interval = ftdmchan->native_interval = wp_globals.codec_ms;
+		ftdmchan->packet_len = ftdmchan->native_interval * 8;
+	}
+
+	return FTDM_SUCCESS;
+}
+
+/**
+ * \brief Closes Wanpipe channel
+ * \param ftdmchan Channel to close
+ * \return Success
+ */
+static FIO_CLOSE_FUNCTION(wanpipe_close)
+{
+#ifdef LIBSANGOMA_VERSION
+	sangoma_wait_obj_t *waitobj = ftdmchan->mod_data;
+	/* kick any I/O waiters */
+	sangoma_wait_obj_signal(waitobj);
+#endif
+	return FTDM_SUCCESS;
+}
+
+/**
+ * \brief Executes an FreeTDM command on a Wanpipe channel
+ * \param ftdmchan Channel to execute command on
+ * \param command FreeTDM command to execute
+ * \param obj Object (unused)
+ * \return Success or failure
+ */
+static FIO_COMMAND_FUNCTION(wanpipe_command)
+{
+	wanpipe_tdm_api_t tdm_api;
+	int err = 0;
+
+	memset(&tdm_api, 0, sizeof(tdm_api));
+
+	switch(command) {
+	case FTDM_COMMAND_OFFHOOK:
+		{
+			err=sangoma_tdm_txsig_offhook(ftdmchan->sockfd,&tdm_api);
+			if (err) {
+				snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "OFFHOOK Failed");
+				return FTDM_FAIL;
+			}
+			ftdm_set_flag_locked(ftdmchan, FTDM_CHANNEL_OFFHOOK);
+		}
+		break;
+	case FTDM_COMMAND_ONHOOK:
+		{
+			err=sangoma_tdm_txsig_onhook(ftdmchan->sockfd,&tdm_api);
+			if (err) {
+				snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "ONHOOK Failed");
+				return FTDM_FAIL;
+			}
+			ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_OFFHOOK);
+		}
+		break;
+	case FTDM_COMMAND_GENERATE_RING_ON:
+		{
+			err=sangoma_tdm_txsig_start(ftdmchan->sockfd,&tdm_api);
+			if (err) {
+				snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "Ring Failed");
+				return FTDM_FAIL;
+			}
+			ftdm_set_flag_locked(ftdmchan, FTDM_CHANNEL_RINGING);
+			ftdm_set_pflag_locked(ftdmchan, WP_RINGING);
+			ftdmchan->ring_time = ftdm_current_time_in_ms() + wp_globals.ring_on_ms;
+		}
+		break;
+	case FTDM_COMMAND_GENERATE_RING_OFF:
+		{
+			err=sangoma_tdm_txsig_offhook(ftdmchan->sockfd,&tdm_api);
+			if (err) {
+				snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "Ring-off Failed");
+				return FTDM_FAIL;
+			}
+			ftdm_clear_pflag_locked(ftdmchan, WP_RINGING);
+			ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_RINGING);
+		}
+		break;
+	case FTDM_COMMAND_GET_INTERVAL:
+		{
+			err=sangoma_tdm_get_usr_period(ftdmchan->sockfd, &tdm_api);
+			if (err > 0 ) {
+				FTDM_COMMAND_OBJ_INT = err;
+				err=0;
+			}
+		}
+		break;
+	case FTDM_COMMAND_ENABLE_ECHOCANCEL:
+		{
+			err=sangoma_tdm_enable_hwec(ftdmchan->sockfd, &tdm_api);
+			if (err) {
+             	snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "HWEC Enable Failed");
+				return FTDM_FAIL;
+			}
+		}
+		break;
+	case FTDM_COMMAND_DISABLE_ECHOCANCEL:
+		{
+			err=sangoma_tdm_disable_hwec(ftdmchan->sockfd, &tdm_api);
+			if (err) {
+             	snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "HWEC Disable Failed");
+				return FTDM_FAIL;
+			}
+		}
+		break;
+	case FTDM_COMMAND_ENABLE_LOOP:
+		{
+#ifdef WP_API_FEATURE_LOOP
+         	err=sangoma_tdm_enable_loop(ftdmchan->sockfd, &tdm_api);
+			if (err) {
+				snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "Loop Enable Failed");
+				return FTDM_FAIL;
+			}
+#endif		
+		}
+	case FTDM_COMMAND_DISABLE_LOOP:
+		{
+#ifdef WP_API_FEATURE_LOOP
+         	err=sangoma_tdm_disable_loop(ftdmchan->sockfd, &tdm_api);
+			if (err) {
+				snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "Loop Disable Failed");
+				return FTDM_FAIL;
+			}
+#endif	 
+		}
+	case FTDM_COMMAND_SET_INTERVAL: 
+		{
+			err=sangoma_tdm_set_usr_period(ftdmchan->sockfd, &tdm_api, FTDM_COMMAND_OBJ_INT);
+			ftdmchan->packet_len = ftdmchan->native_interval * (ftdmchan->effective_codec == FTDM_CODEC_SLIN ? 16 : 8);
+		}
+		break;
+	case FTDM_COMMAND_SET_CAS_BITS:
+		{
+#ifdef LIBSANGOMA_VERSION
+			err = sangoma_tdm_write_rbs(ftdmchan->sockfd,&tdm_api, ftdmchan->physical_chan_id, wanpipe_swap_bits(FTDM_COMMAND_OBJ_INT));
+#else
+			err = sangoma_tdm_write_rbs(ftdmchan->sockfd, &tdm_api, wanpipe_swap_bits(FTDM_COMMAND_OBJ_INT));
+#endif
+		}
+		break;
+	case FTDM_COMMAND_GET_CAS_BITS:
+		{
+#ifdef LIBSANGOMA_VERSION
+			unsigned char rbsbits;
+			err = sangoma_tdm_read_rbs(ftdmchan->sockfd, &tdm_api, ftdmchan->physical_chan_id, &rbsbits);
+			if (!err) {
+				FTDM_COMMAND_OBJ_INT = wanpipe_swap_bits(rbsbits);
+			}
+#else
+			// does sangoma_tdm_read_rbs is available here?
+			FTDM_COMMAND_OBJ_INT = ftdmchan->rx_cas_bits;
+#endif
+		}
+		break;
+	case FTDM_COMMAND_SET_LINK_STATUS:
+		{
+			ftdm_channel_hw_link_status_t status = FTDM_COMMAND_OBJ_INT;
+			char sangoma_status = status == FTDM_HW_LINK_CONNECTED ? FE_CONNECTED : FE_DISCONNECTED;
+			err = sangoma_tdm_set_fe_status(ftdmchan->sockfd, &tdm_api, sangoma_status);
+		}
+		break;
+	case FTDM_COMMAND_GET_LINK_STATUS:
+		{
+			unsigned char sangoma_status = 0;
+			err = sangoma_tdm_get_fe_status(ftdmchan->sockfd, &tdm_api, &sangoma_status);
+			if (!err) {
+				FTDM_COMMAND_OBJ_INT = sangoma_status == FE_CONNECTED ? FTDM_HW_LINK_CONNECTED : FTDM_HW_LINK_DISCONNECTED;
+			}
+		}
+		break;
+	default:
+		break;
+	};
+
+	if (err) {
+		snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "%s", strerror(errno));
+		return FTDM_FAIL;
+	}
+
+
+	return FTDM_SUCCESS;
+}
+
+/**
+ * \brief Reads data from a Wanpipe channel
+ * \param ftdmchan Channel to read from
+ * \param data Data buffer
+ * \param datalen Size of data buffer
+ * \return Success, failure or timeout
+ */
+static FIO_READ_FUNCTION(wanpipe_read)
+{
+	int rx_len = 0;
+	wp_tdm_api_rx_hdr_t hdrframe;
+
+	memset(&hdrframe, 0, sizeof(hdrframe));
+
+	rx_len = sangoma_readmsg_tdm(ftdmchan->sockfd, &hdrframe, (int)sizeof(hdrframe), data, (int)*datalen,0);
+	*datalen = rx_len;
+
+	if (rx_len == 0 || rx_len == -17) {
+		return FTDM_TIMEOUT;
+	}
+
+	if (rx_len < 0) {
+		snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "%s", strerror(errno));
+		return FTDM_FAIL;
+	} 
+
+
+	return FTDM_SUCCESS;
+}
+
+/**
+ * \brief Writes data to a Wanpipe channel
+ * \param ftdmchan Channel to write to
+ * \param data Data buffer
+ * \param datalen Size of data buffer
+ * \return Success or failure
+ */
+static FIO_WRITE_FUNCTION(wanpipe_write)
+{
+	int bsent;
+	wp_tdm_api_tx_hdr_t hdrframe;
+
+	/* Do we even need the headerframe here? on windows, we don't even pass it to the driver */
+	memset(&hdrframe, 0, sizeof(hdrframe));
+	if (*datalen == 0) {
+		return FTDM_SUCCESS;
+	}
+	bsent = sangoma_writemsg_tdm(ftdmchan->sockfd, &hdrframe, (int)sizeof(hdrframe), data, (unsigned short)(*datalen),0);
+
+	/* should we be checking if bsent == *datalen here? */
+	if (bsent > 0) {
+		*datalen = bsent;
+		return FTDM_SUCCESS;
+	}
+
+	return FTDM_FAIL;
+}
+
+/**
+ * \brief Waits for an event on a Wanpipe channel
+ * \param ftdmchan Channel to open
+ * \param flags Type of event to wait for
+ * \param to Time to wait (in ms)
+ * \return Success, failure or timeout
+ */
+
+static FIO_WAIT_FUNCTION(wanpipe_wait)
+{
+	int32_t inflags = 0;
+	int result;
+
+	if (*flags & FTDM_READ) {
+		inflags |= POLLIN;
+	}
+
+	if (*flags & FTDM_WRITE) {
+		inflags |= POLLOUT;
+	}
+
+	if (*flags & FTDM_EVENTS) {
+		inflags |= POLLPRI;
+	}
+
+	result = tdmv_api_wait_socket(ftdmchan, to, &inflags);
+
+	*flags = FTDM_NO_FLAGS;
+
+	if (result < 0){
+		snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "Poll failed");
+		return FTDM_FAIL;
+	}
+
+	if (result == 0) {
+		return FTDM_TIMEOUT;
+	}
+
+	if (inflags & POLLIN) {
+		*flags |= FTDM_READ;
+	}
+
+	if (inflags & POLLOUT) {
+		*flags |= FTDM_WRITE;
+	}
+
+	if (inflags & POLLPRI) {
+		*flags |= FTDM_EVENTS;
+	}
+
+	return FTDM_SUCCESS;
+}
+
+/**
+ * \brief Checks for events on a Wanpipe span
+ * \param span Span to check for events
+ * \param ms Time to wait for event
+ * \return Success if event is waiting or failure if not
+ */
+FIO_SPAN_POLL_EVENT_FUNCTION(wanpipe_poll_event)
+{
+#ifdef LIBSANGOMA_VERSION
+	sangoma_status_t sangstatus;
+	sangoma_wait_obj_t *pfds[FTDM_MAX_CHANNELS_SPAN] = { 0 };
+	uint32_t inflags[FTDM_MAX_CHANNELS_SPAN];
+	uint32_t outflags[FTDM_MAX_CHANNELS_SPAN];
+#else
+	struct pollfd pfds[FTDM_MAX_CHANNELS_SPAN];
+#endif
+	uint32_t i, j = 0, k = 0, l = 0;
+	int r;
+	
+	for(i = 1; i <= span->chan_count; i++) {
+		ftdm_channel_t *ftdmchan = span->channels[i];
+#ifdef LIBSANGOMA_VERSION
+		if (!ftdmchan->mod_data) {
+			continue; /* should never happen but happens when shutting down */
+		}
+		pfds[j] = ftdmchan->mod_data;
+		inflags[j] = POLLPRI;
+#else
+		memset(&pfds[j], 0, sizeof(pfds[j]));
+		pfds[j].fd = span->channels[i]->sockfd;
+		pfds[j].events = POLLPRI;
+#endif
+
+		/* The driver probably should be able to do this wink/flash/ringing by itself this is sort of a hack to make it work! */
+		if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_WINK) || ftdm_test_flag(ftdmchan, FTDM_CHANNEL_FLASH)) {
+			l = 5;
+		}
+
+		j++;
+
+		if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_RINGING)) {
+			l = 5;
+		}
+
+		if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_RINGING) && ftdm_current_time_in_ms() >= ftdmchan->ring_time) {
+			wanpipe_tdm_api_t tdm_api;
+			int err;
+			memset(&tdm_api, 0, sizeof(tdm_api));
+			if (ftdm_test_pflag(ftdmchan, WP_RINGING)) {
+				err = sangoma_tdm_txsig_offhook(ftdmchan->sockfd,&tdm_api);
+				if (err) {
+					snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "Ring-off Failed");
+					ftdm_log(FTDM_LOG_ERROR, "sangoma_tdm_txsig_offhook failed\n");
+					return FTDM_FAIL;
+				}
+				ftdm_clear_pflag_locked(ftdmchan, WP_RINGING);
+				ftdmchan->ring_time = ftdm_current_time_in_ms() + wp_globals.ring_off_ms;
+			} else {
+				err=sangoma_tdm_txsig_start(ftdmchan->sockfd,&tdm_api);
+				if (err) {
+					snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "Ring Failed");
+					ftdm_log(FTDM_LOG_ERROR, "sangoma_tdm_txsig_start failed\n");
+					return FTDM_FAIL;
+				}
+				ftdm_set_pflag_locked(ftdmchan, WP_RINGING);
+				ftdmchan->ring_time = ftdm_current_time_in_ms() + wp_globals.ring_on_ms;
+			}
+		}
+	}
+
+	if (l) {
+		ms = l;
+	}
+#ifdef LIBSANGOMA_VERSION
+	sangstatus = sangoma_waitfor_many(pfds, inflags, outflags, j, ms);
+	if (SANG_STATUS_APIPOLL_TIMEOUT == sangstatus) {
+		r = 0;
+	} else if (SANG_STATUS_SUCCESS == sangstatus) {
+		r = 1; /* hopefully we never need how many changed -_- */
+	} else {
+		ftdm_log(FTDM_LOG_ERROR, "sangoma_waitfor_many failed: %d, %s\n", sangstatus, strerror(errno));
+		r = -1;
+	}
+#else
+	r = poll(pfds, j, ms);
+#endif
+	
+	if (r == 0) {
+		return l ? FTDM_SUCCESS : FTDM_TIMEOUT;
+	} else if (r < 0) {
+		snprintf(span->last_error, sizeof(span->last_error), "%s", strerror(errno));
+		return FTDM_FAIL;
+	}
+	
+	for(i = 1; i <= span->chan_count; i++) {
+		ftdm_channel_t *ftdmchan = span->channels[i];
+
+#ifdef LIBSANGOMA_VERSION
+		if (outflags[i-1] & POLLPRI) {
+#else
+		if (pfds[i-1].revents & POLLPRI) {
+#endif
+			ftdm_set_flag(ftdmchan, FTDM_CHANNEL_EVENT);
+			ftdmchan->last_event_time = ftdm_current_time_in_ms();
+			k++;
+		}
+	}
+	/* when k is 0 it might be that an async wanpipe device signal was delivered */	
+	return FTDM_SUCCESS;
+}
+
+/**
+ * \brief Gets alarms from a Wanpipe Channel
+ * \param ftdmchan Channel to get alarms from
+ * \return Success or failure
+ */
+static FIO_GET_ALARMS_FUNCTION(wanpipe_get_alarms)
+{
+	wanpipe_tdm_api_t tdm_api;
+	unsigned int alarms = 0;
+	int err;
+
+	memset(&tdm_api,0,sizeof(tdm_api));
+
+#ifdef LIBSANGOMA_VERSION
+	if ((err = sangoma_tdm_get_fe_alarms(ftdmchan->sockfd, &tdm_api, &alarms))) {
+		snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "ioctl failed (%s)", strerror(errno));
+		snprintf(ftdmchan->span->last_error, sizeof(ftdmchan->span->last_error), "ioctl failed (%s)", strerror(errno));
+		return FTDM_FAIL;		
+	}
+#else
+	if ((err = sangoma_tdm_get_fe_alarms(ftdmchan->sockfd, &tdm_api)) < 0){
+		snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "ioctl failed (%s)", strerror(errno));
+		snprintf(ftdmchan->span->last_error, sizeof(ftdmchan->span->last_error), "ioctl failed (%s)", strerror(errno));
+		return FTDM_FAIL;		
+	}
+	alarms = tdm_api.wp_tdm_cmd.fe_alarms;
+#endif
+	ftdmchan->alarm_flags = FTDM_ALARM_NONE;
+
+	if (alarms & WAN_TE_BIT_ALARM_RED) {
+		ftdmchan->alarm_flags |= FTDM_ALARM_RED;
+		alarms &= ~WAN_TE_BIT_ALARM_RED;
+	}
+
+	if (alarms & WAN_TE_BIT_ALARM_AIS) {
+		ftdmchan->alarm_flags |= FTDM_ALARM_AIS;
+		ftdmchan->alarm_flags |= FTDM_ALARM_BLUE;
+		alarms &= ~WAN_TE_BIT_ALARM_AIS;
+	}
+
+	if (alarms & WAN_TE_BIT_ALARM_RAI) {
+		ftdmchan->alarm_flags |= FTDM_ALARM_RAI;
+		ftdmchan->alarm_flags |= FTDM_ALARM_YELLOW;
+		alarms &= ~WAN_TE_BIT_ALARM_RAI;
+	}
+
+	/* still missing to map:
+	 * FTDM_ALARM_RECOVER
+	 * FTDM_ALARM_LOOPBACK
+	 * FTDM_ALARM_NOTOPEN
+	 * */
+
+	/* if we still have alarms that we did not map, set the general alarm */
+	if (alarms) {
+		ftdm_log(FTDM_LOG_DEBUG, "Unmapped wanpipe alarms: %d\n", alarms);
+		ftdmchan->alarm_flags |= FTDM_ALARM_GENERAL;
+	}
+
+	return FTDM_SUCCESS;
+}
+
+/**
+ * \brief Retrieves an event from a wanpipe span
+ * \param span Span to retrieve event from
+ * \param event FreeTDM event to return
+ * \return Success or failure
+ */
+FIO_SPAN_NEXT_EVENT_FUNCTION(wanpipe_next_event)
+{
+	uint32_t i,err;
+	ftdm_oob_event_t event_id;
+	for(i = 1; i <= span->chan_count; i++) {
+		if (span->channels[i]->last_event_time && !ftdm_test_flag(span->channels[i], FTDM_CHANNEL_EVENT)) {
+			uint32_t diff = (uint32_t)(ftdm_current_time_in_ms() - span->channels[i]->last_event_time);
+			/* XX printf("%u %u %u\n", diff, (unsigned)ftdm_current_time_in_ms(), (unsigned)span->channels[i]->last_event_time); */
+			if (ftdm_test_flag(span->channels[i], FTDM_CHANNEL_WINK)) {
+				if (diff > wp_globals.wink_ms) {
+					ftdm_clear_flag_locked(span->channels[i], FTDM_CHANNEL_WINK);
+					ftdm_clear_flag_locked(span->channels[i], FTDM_CHANNEL_FLASH);
+					ftdm_set_flag_locked(span->channels[i], FTDM_CHANNEL_OFFHOOK);
+					event_id = FTDM_OOB_OFFHOOK;
+					goto event;
+				}
+			}
+
+			if (ftdm_test_flag(span->channels[i], FTDM_CHANNEL_FLASH)) {
+				if (diff > wp_globals.flash_ms) {
+					ftdm_clear_flag_locked(span->channels[i], FTDM_CHANNEL_FLASH);
+					ftdm_clear_flag_locked(span->channels[i], FTDM_CHANNEL_WINK);
+					ftdm_clear_flag_locked(span->channels[i], FTDM_CHANNEL_OFFHOOK);
+					event_id = FTDM_OOB_ONHOOK;
+
+					if (span->channels[i]->type == FTDM_CHAN_TYPE_FXO) {
+						ftdm_channel_t *ftdmchan = span->channels[i];
+						wanpipe_tdm_api_t tdm_api;
+						memset(&tdm_api, 0, sizeof(tdm_api));
+
+						sangoma_tdm_txsig_onhook(ftdmchan->sockfd,&tdm_api);
+					}
+					goto event;
+				}
+			}
+		} 
+		if (ftdm_test_flag(span->channels[i], FTDM_CHANNEL_EVENT)) {
+			wanpipe_tdm_api_t tdm_api;
+			ftdm_channel_t *ftdmchan = span->channels[i];
+			memset(&tdm_api, 0, sizeof(tdm_api));
+			ftdm_clear_flag(span->channels[i], FTDM_CHANNEL_EVENT);
+
+			err = sangoma_tdm_read_event(ftdmchan->sockfd, &tdm_api);
+			if (err != FTDM_SUCCESS) {
+				snprintf(span->last_error, sizeof(span->last_error), "%s", strerror(errno));
+				return FTDM_FAIL;
+			}
+			
+			ftdm_log(FTDM_LOG_DEBUG, "read wanpipe event %d\n", tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_type);
+			switch(tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_type) {
+
+			case WP_TDMAPI_EVENT_LINK_STATUS:
+				{
+					switch(tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_link_status) {
+					case WP_TDMAPI_EVENT_LINK_STATUS_CONNECTED:
+						event_id = FTDM_OOB_ALARM_CLEAR;
+						break;
+					default:
+						event_id = FTDM_OOB_ALARM_TRAP;
+						break;
+					};
+				}
+				break;
+
+			case WP_TDMAPI_EVENT_RXHOOK:
+				{
+					if (span->channels[i]->type == FTDM_CHAN_TYPE_FXS) {
+						event_id = tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_hook_state & WP_TDMAPI_EVENT_RXHOOK_OFF ? FTDM_OOB_OFFHOOK : FTDM_OOB_ONHOOK;
+						if (event_id == FTDM_OOB_OFFHOOK) {
+							if (ftdm_test_flag(span->channels[i], FTDM_CHANNEL_FLASH)) {
+								ftdm_clear_flag_locked(span->channels[i], FTDM_CHANNEL_FLASH);
+								ftdm_clear_flag_locked(span->channels[i], FTDM_CHANNEL_WINK);
+								event_id = FTDM_OOB_FLASH;
+								goto event;
+							} else {
+								ftdm_set_flag_locked(span->channels[i], FTDM_CHANNEL_WINK);
+							}
+						} else {
+							if (ftdm_test_flag(span->channels[i], FTDM_CHANNEL_WINK)) {
+								ftdm_clear_flag_locked(span->channels[i], FTDM_CHANNEL_WINK);
+								ftdm_clear_flag_locked(span->channels[i], FTDM_CHANNEL_FLASH);
+								event_id = FTDM_OOB_WINK;
+								goto event;
+							} else {
+								ftdm_set_flag_locked(span->channels[i], FTDM_CHANNEL_FLASH);
+							}
+						}					
+						continue;
+					} else {
+						int err;
+						ftdm_channel_t *ftdmchan = span->channels[i];
+						err=sangoma_tdm_txsig_onhook(ftdmchan->sockfd,&tdm_api);
+						if (err) {
+							snprintf(span->channels[i]->last_error, sizeof(span->channels[i]->last_error), "ONHOOK Failed");
+							return FTDM_FAIL;
+						}
+						event_id = tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_hook_state & WP_TDMAPI_EVENT_RXHOOK_OFF ? FTDM_OOB_ONHOOK : FTDM_OOB_NOOP;	
+					}
+				}
+				break;
+			case WP_TDMAPI_EVENT_RING_DETECT:
+				{
+					event_id = tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_ring_state == WP_TDMAPI_EVENT_RING_PRESENT ? FTDM_OOB_RING_START : FTDM_OOB_RING_STOP;
+				}
+				break;
+				/*
+				disabled this ones when configuring, we don't need them, do we?
+			case WP_TDMAPI_EVENT_RING_TRIP_DETECT:
+				{
+					event_id = tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_ring_state == WP_TDMAPI_EVENT_RING_PRESENT ? FTDM_OOB_ONHOOK : FTDM_OOB_OFFHOOK;
+				}
+				break;
+				*/
+			case WP_TDMAPI_EVENT_RBS:
+				{
+					event_id = FTDM_OOB_CAS_BITS_CHANGE;
+					span->channels[i]->rx_cas_bits = wanpipe_swap_bits(tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_rbs_bits);
+				}
+				break;
+			case WP_TDMAPI_EVENT_DTMF:
+				{
+					char tmp_dtmf[2] = { tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_dtmf_digit, 0 };
+					event_id = FTDM_OOB_NOOP;
+
+					if (tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_dtmf_type == WAN_EC_TONE_PRESENT) {
+						ftdm_set_flag_locked(ftdmchan, FTDM_CHANNEL_MUTE);
+					}
+
+					if (tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_dtmf_type == WAN_EC_TONE_STOP) {
+						ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_MUTE);
+						if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_INUSE)) {
+							ftdm_log(FTDM_LOG_DEBUG, "Queuing wanpipe DTMF: %c\n", tmp_dtmf[0]);
+							ftdm_channel_queue_dtmf(ftdmchan, tmp_dtmf);
+						}
+					} 
+				}
+				break;
+			case WP_TDMAPI_EVENT_ALARM:
+				{
+					ftdm_log(FTDM_LOG_DEBUG, "Got wanpipe alarms %d\n", tdm_api.wp_tdm_cmd.event.wp_api_event_alarm);
+					event_id = FTDM_OOB_ALARM_TRAP;
+				}
+				break;
+			default:
+				{
+					ftdm_log(FTDM_LOG_WARNING, "Unhandled wanpipe event %d\n", tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_type);
+					event_id = FTDM_OOB_INVALID;
+				}
+				break;
+			}
+
+		event:
+
+			span->channels[i]->last_event_time = 0;
+			span->event_header.e_type = FTDM_EVENT_OOB;
+			span->event_header.enum_id = event_id;
+			span->event_header.channel = span->channels[i];
+			*event = &span->event_header;
+			return FTDM_SUCCESS;
+		}
+	}
+
+	return FTDM_FAIL;
+	
+}
+
+/**
+ * \brief Destroys a Wanpipe Channel
+ * \param ftdmchan Channel to destroy
+ * \return Success
+ */
+static FIO_CHANNEL_DESTROY_FUNCTION(wanpipe_channel_destroy)
+{
+#ifdef LIBSANGOMA_VERSION
+	if (ftdmchan->mod_data) {
+		sangoma_wait_obj_t *sangoma_wait_obj;
+		sangoma_wait_obj = ftdmchan->mod_data;
+		ftdmchan->mod_data = NULL;
+		sangoma_wait_obj_delete(&sangoma_wait_obj);
+	}
+#endif
+
+	if (ftdmchan->sockfd > -1) {
+		close(ftdmchan->sockfd);
+		ftdmchan->sockfd = WP_INVALID_SOCKET;
+	}
+
+	return FTDM_SUCCESS;
+}
+
+/**
+ * \brief Loads wanpipe IO module
+ * \param fio FreeTDM IO interface
+ * \return Success
+ */
+static FIO_IO_LOAD_FUNCTION(wanpipe_init)
+{
+	assert(fio != NULL);
+	memset(&wanpipe_interface, 0, sizeof(wanpipe_interface));
+
+	wp_globals.codec_ms = 20;
+	wp_globals.wink_ms = 150;
+	wp_globals.flash_ms = 750;
+	wp_globals.ring_on_ms = 2000;
+	wp_globals.ring_off_ms = 4000;
+	wanpipe_interface.name = "wanpipe";
+	wanpipe_interface.configure_span = wanpipe_configure_span;
+	wanpipe_interface.configure = wanpipe_configure;
+	wanpipe_interface.open = wanpipe_open;
+	wanpipe_interface.close = wanpipe_close;
+	wanpipe_interface.command = wanpipe_command;
+	wanpipe_interface.wait = wanpipe_wait;
+	wanpipe_interface.read = wanpipe_read;
+	wanpipe_interface.write = wanpipe_write;
+	wanpipe_interface.poll_event = wanpipe_poll_event;
+	wanpipe_interface.next_event = wanpipe_next_event;
+	wanpipe_interface.channel_destroy = wanpipe_channel_destroy;
+	wanpipe_interface.get_alarms = wanpipe_get_alarms;
+	*fio = &wanpipe_interface;
+
+	return FTDM_SUCCESS;
+}
+
+/**
+ * \brief Unloads wanpipe IO module
+ * \return Success
+ */
+static FIO_IO_UNLOAD_FUNCTION(wanpipe_destroy)
+{
+	memset(&wanpipe_interface, 0, sizeof(wanpipe_interface));
+	return FTDM_SUCCESS;
+}
+
+/**
+ * \brief FreeTDM wanpipe IO module definition
+ */
+EX_DECLARE_DATA ftdm_module_t ftdm_module = { 
+	"wanpipe",
+	wanpipe_init,
+	wanpipe_destroy,
+};
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4 
+ */

Added: freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_wanpipe/ozmod_wanpipe.2005.vcproj (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_wanpipe/ozmod_wanpipe.2005.vcproj	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_wanpipe/ozmod_wanpipe.2005.vcproj	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,196 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="8.00"
+	Name="ftmod_wanpipe"
+	ProjectGUID="{1A145EE9-BBD8-45E5-98CD-EB4BE99E1DCD}"
+	RootNamespace="ftmod_wanpipe"
+	Keyword="Win32Proj"
+	TargetFrameworkVersion="131072"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="2"
+			CharacterSet="2"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				AdditionalIncludeDirectories="../../../src/include;../../../src/isdn/include;../../../wanpipe/include"
+				PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;"
+				MinimalRebuild="true"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="3"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				Detect64BitPortabilityProblems="true"
+				DebugInformationFormat="4"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="freetdm.lib libsangoma.lib"
+				LinkIncremental="2"
+				AdditionalLibraryDirectories="&quot;$(OutDir)&quot;;../../../wanpipe/api/lib/x86"
+				GenerateDebugInformation="true"
+				SubSystem="1"
+				RandomizedBaseAddress="1"
+				DataExecutionPrevention="0"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="2"
+			CharacterSet="2"
+			WholeProgramOptimization="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalIncludeDirectories="../../../src/include;../../../src/isdn/include;../../../wanpipe/include"
+				PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
+				RuntimeLibrary="2"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				Detect64BitPortabilityProblems="true"
+				DebugInformationFormat="3"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="freetdm.lib libsangoma.lib"
+				LinkIncremental="1"
+				AdditionalLibraryDirectories="&quot;$(OutDir)&quot;;../../../wanpipe/api/lib/x86"
+				GenerateDebugInformation="true"
+				SubSystem="1"
+				OptimizeReferences="2"
+				EnableCOMDATFolding="2"
+				RandomizedBaseAddress="1"
+				DataExecutionPrevention="0"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<Filter
+			Name="Source Files"
+			Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+			>
+			<File
+				RelativePath=".\ftmod_wanpipe.c"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="Header Files"
+			Filter="h;hpp;hxx;hm;inl;inc;xsd"
+			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+			>
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>

Added: freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_wanpipe/wanpipe_tdm_api_iface.h (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_wanpipe/wanpipe_tdm_api_iface.h	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_wanpipe/wanpipe_tdm_api_iface.h	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,351 @@
+/*****************************************************************************
+* wanpipe_tdm_api_iface.h 
+* 		
+* 		WANPIPE(tm) AFT TE1 Hardware Support
+*
+* Authors: 	Nenad Corbic <ncorbic@sangoma.com>
+*
+* Copyright (c) 2007 - 08, Sangoma Technologies
+* All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are met:
+*     * Redistributions of source code must retain the above copyright
+*       notice, this list of conditions and the following disclaimer.
+*     * Redistributions in binary form must reproduce the above copyright
+*       notice, this list of conditions and the following disclaimer in the
+*       documentation and/or other materials provided with the distribution.
+*     * Neither the name of the <organization> nor the
+*       names of its contributors may be used to endorse or promote products
+*       derived from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY <copyright holder> ``AS IS'' AND ANY
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+* DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
+* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+* ============================================================================
+* Oct 04, 2005	Nenad Corbic	Initial version.
+*
+* Jul 25, 2006	David Rokhvarg	<davidr@sangoma.com>	Ported to Windows.
+*****************************************************************************/
+
+#ifndef __WANPIPE_TDM_API_IFACE_H_
+#define __WANPIPE_TDM_API_IFACE_H_ 
+
+
+#if defined(__WINDOWS__)
+typedef HANDLE sng_fd_t;
+#else
+typedef int sng_fd_t;
+#endif
+
+/* Indicate to library that new features exist */
+#define WP_TDM_FEATURE_DTMF_EVENTS	1
+#define WP_TDM_FEATURE_FE_ALARM		1
+#define WP_TDM_FEATURE_EVENTS		1
+#define WP_TDM_FEATURE_LINK_STATUS	1
+
+enum wanpipe_tdm_api_cmds {
+
+	SIOC_WP_TDM_GET_USR_MTU_MRU,	/* 0x00 */
+
+	SIOC_WP_TDM_SET_USR_PERIOD,	/* 0x01 */
+	SIOC_WP_TDM_GET_USR_PERIOD,	/* 0x02 */
+	
+	SIOC_WP_TDM_SET_HW_MTU_MRU,	/* 0x03 */
+	SIOC_WP_TDM_GET_HW_MTU_MRU,	/* 0x04 */
+
+	SIOC_WP_TDM_SET_CODEC,		/* 0x05 */
+	SIOC_WP_TDM_GET_CODEC,		/* 0x06 */
+
+	SIOC_WP_TDM_SET_POWER_LEVEL,	/* 0x07 */
+	SIOC_WP_TDM_GET_POWER_LEVEL,	/* 0x08 */
+
+	SIOC_WP_TDM_TOGGLE_RX,		/* 0x09 */
+	SIOC_WP_TDM_TOGGLE_TX,		/* 0x0A */
+
+	SIOC_WP_TDM_GET_HW_CODING,	/* 0x0B */
+	SIOC_WP_TDM_SET_HW_CODING,	/* 0x0C */
+
+	SIOC_WP_TDM_GET_FULL_CFG,	/* 0x0D */
+
+	SIOC_WP_TDM_SET_EC_TAP,		/* 0x0E */
+	SIOC_WP_TDM_GET_EC_TAP,		/* 0x0F */
+	
+	SIOC_WP_TDM_ENABLE_RBS_EVENTS,	/* 0x10 */
+	SIOC_WP_TDM_DISABLE_RBS_EVENTS,	/* 0x11 */
+	SIOC_WP_TDM_WRITE_RBS_BITS,	/* 0x12 */
+	
+	SIOC_WP_TDM_GET_STATS,		/* 0x13 */
+	SIOC_WP_TDM_FLUSH_BUFFERS,	/* 0x14 */
+	
+	SIOC_WP_TDM_READ_EVENT,		/* 0x15 */
+	
+	SIOC_WP_TDM_SET_EVENT,		/* 0x16 */
+
+	SIOC_WP_TDM_SET_RX_GAINS,	/* 0x17 */
+	SIOC_WP_TDM_SET_TX_GAINS,	/* 0x18 */
+	SIOC_WP_TDM_CLEAR_RX_GAINS,	/* 0x19 */
+	SIOC_WP_TDM_CLEAR_TX_GAINS,	/* 0x1A */
+
+	SIOC_WP_TDM_GET_FE_ALARMS,	/* 0x1B */
+
+	SIOC_WP_TDM_ENABLE_HWEC,	/* 0x1C */
+	SIOC_WP_TDM_DISABLE_HWEC,	/* 0x1D */
+	
+	SIOC_WP_TDM_SET_FE_STATUS,	/* 0x1E */
+	SIOC_WP_TDM_GET_FE_STATUS,	/* 0x1F */
+
+	SIOC_WP_TDM_GET_HW_DTMF,	/* 0x20 */
+
+	SIOC_WP_TDM_NOTSUPP		/*  */
+
+};
+
+#define SIOC_WP_TDM_GET_LINK_STATUS SIOC_WP_TDM_GET_FE_STATUS
+
+enum wanpipe_tdm_api_events {
+	WP_TDMAPI_EVENT_NONE,
+	WP_TDMAPI_EVENT_RBS,
+	WP_TDMAPI_EVENT_ALARM,
+	WP_TDMAPI_EVENT_DTMF,
+	WP_TDMAPI_EVENT_RM_DTMF,
+	WP_TDMAPI_EVENT_RXHOOK,
+	WP_TDMAPI_EVENT_RING,
+	WP_TDMAPI_EVENT_RING_DETECT,
+	WP_TDMAPI_EVENT_RING_TRIP_DETECT,
+	WP_TDMAPI_EVENT_TONE,
+	WP_TDMAPI_EVENT_TXSIG_KEWL,
+	WP_TDMAPI_EVENT_TXSIG_START,
+	WP_TDMAPI_EVENT_TXSIG_OFFHOOK,
+	WP_TDMAPI_EVENT_TXSIG_ONHOOK,
+	WP_TDMAPI_EVENT_ONHOOKTRANSFER,
+	WP_TDMAPI_EVENT_SETPOLARITY,
+	WP_TDMAPI_EVENT_BRI_CHAN_LOOPBACK,
+	WP_TDMAPI_EVENT_LINK_STATUS
+};
+
+#define WP_TDMAPI_EVENT_FE_ALARM WP_TDMAPI_EVENT_ALARM
+
+
+#define WP_TDMAPI_EVENT_ENABLE		0x01
+#define WP_TDMAPI_EVENT_DISABLE		0x02
+#define WP_TDMAPI_EVENT_MODE_DECODE(mode)				\
+		((mode) == WP_TDMAPI_EVENT_ENABLE) ? "Enable" :	\
+		((mode) == WP_TDMAPI_EVENT_DISABLE) ? "Disable" :	\
+						"(Unknown mode)"
+
+#define WPTDM_A_BIT 			WAN_RBS_SIG_A
+#define WPTDM_B_BIT 			WAN_RBS_SIG_B
+#define WPTDM_C_BIT 			WAN_RBS_SIG_C
+#define WPTDM_D_BIT 			WAN_RBS_SIG_D
+ 
+#define WP_TDMAPI_EVENT_RXHOOK_OFF	0x01
+#define WP_TDMAPI_EVENT_RXHOOK_ON	0x02
+#define WP_TDMAPI_EVENT_RXHOOK_DECODE(state)				\
+		((state) == WP_TDMAPI_EVENT_RXHOOK_OFF) ? "Off-hook" :	\
+		((state) == WP_TDMAPI_EVENT_RXHOOK_ON) ? "On-hook" :	\
+						"(Unknown state)"
+
+#define WP_TDMAPI_EVENT_RING_PRESENT	0x01
+#define WP_TDMAPI_EVENT_RING_STOP	0x02
+#define WP_TDMAPI_EVENT_RING_DECODE(state)				\
+		((state) == WP_TDMAPI_EVENT_RING_PRESENT) ? "Ring Present" :	\
+		((state) == WP_TDMAPI_EVENT_RING_STOP) ? "Ring Stop" :	\
+						"(Unknown state)"
+
+#define WP_TDMAPI_EVENT_RING_TRIP_PRESENT	0x01
+#define WP_TDMAPI_EVENT_RING_TRIP_STOP	0x02
+#define WP_TDMAPI_EVENT_RING_TRIP_DECODE(state)				\
+		((state) == WP_TDMAPI_EVENT_RING_TRIP_PRESENT) ? "Ring Present" :	\
+		((state) == WP_TDMAPI_EVENT_RING_TRIP_STOP) ? "Ring Stop" :	\
+						"(Unknown state)"
+/*Link Status */
+#define WP_TDMAPI_EVENT_LINK_STATUS_CONNECTED		0x01
+#define WP_TDMAPI_EVENT_LINK_STATUS_DISCONNECTED	0x02
+#define WP_TDMAPI_EVENT_LINK_STATUS_DECODE(status)					\
+		((status) == WP_TDMAPI_EVENT_LINK_STATUS_CONNECTED) ? "Connected" :		\
+		((status) == WP_TDMAPI_EVENT_LINK_STATUS_DISCONNECTED)  ? "Disconnected" :		\
+							"Unknown"
+#define	WP_TDMAPI_EVENT_TONE_DIAL	0x01
+#define	WP_TDMAPI_EVENT_TONE_BUSY	0x02
+#define	WP_TDMAPI_EVENT_TONE_RING	0x03
+#define	WP_TDMAPI_EVENT_TONE_CONGESTION	0x04
+
+/* BRI channels list */						
+#define	WAN_BRI_BCHAN1		0x01
+#define	WAN_BRI_BCHAN2		0x02
+#define	WAN_BRI_DCHAN		0x03
+
+
+typedef struct {
+
+	u_int8_t	type;
+	u_int8_t	mode;
+	u_int32_t	time_stamp;
+	u_int8_t	channel;
+	u_int32_t	chan_map;
+	u_int8_t	span;
+	union {
+		struct {
+			u_int8_t	alarm;
+		} te1_alarm;
+		struct {
+			u_int8_t	rbs_bits;
+		} te1_rbs;
+		struct {
+			u_int8_t	state;
+			u_int8_t	sig;
+		} rm_hook;
+		struct {
+			u_int8_t	state;
+		} rm_ring;
+		struct {
+			u_int8_t	type;
+		} rm_tone;
+		struct {
+			u_int8_t	digit;	/* DTMF: digit  */
+			u_int8_t	port;	/* DTMF: SOUT/ROUT */
+			u_int8_t	type;	/* DTMF: PRESET/STOP */
+		} dtmf;
+		struct {
+			u_int16_t	polarity;
+			u_int16_t	ohttimer;
+		} rm_common;
+		struct{
+			u_int16_t status;
+		} linkstatus;
+	} wp_tdm_api_event_u;
+#define wp_tdm_api_event_type 		type
+#define wp_tdm_api_event_mode 		mode
+#define wp_tdm_api_event_alarm 		wp_tdm_api_event_u.te1_alarm.alarm
+#define wp_tdm_api_event_alarm 		wp_tdm_api_event_u.te1_alarm.alarm
+#define wp_tdm_api_event_rbs_bits 	wp_tdm_api_event_u.te1_rbs.rbs_bits
+#define wp_tdm_api_event_hook_state 	wp_tdm_api_event_u.rm_hook.state
+#define wp_tdm_api_event_hook_sig 	wp_tdm_api_event_u.rm_hook.sig
+#define wp_tdm_api_event_ring_state 	wp_tdm_api_event_u.rm_ring.state
+#define wp_tdm_api_event_tone_type 	wp_tdm_api_event_u.rm_tone.type
+#define wp_tdm_api_event_dtmf_digit 	wp_tdm_api_event_u.dtmf.digit
+#define wp_tdm_api_event_dtmf_type 	wp_tdm_api_event_u.dtmf.type
+#define wp_tdm_api_event_dtmf_port 	wp_tdm_api_event_u.dtmf.port
+#define wp_tdm_api_event_ohttimer 	wp_tdm_api_event_u.rm_common.ohttimer
+#define wp_tdm_api_event_polarity 	wp_tdm_api_event_u.rm_common.polarity
+#define wp_tdm_api_event_link_status	wp_tdm_api_event_u.linkstatus.status
+} wp_tdm_api_event_t;
+
+typedef struct {
+	union {
+		unsigned char	reserved[16];
+	}wp_rx_hdr_u;
+} wp_tdm_api_rx_hdr_t;
+
+typedef struct {
+        wp_tdm_api_rx_hdr_t	hdr;
+        unsigned char  		data[1];
+} wp_tdm_api_rx_element_t;
+
+typedef struct {
+	union {
+		struct {
+			unsigned char	_rbs_rx_bits;
+			unsigned int	_time_stamp;
+		}wp_tx;
+		unsigned char	reserved[16];
+	}wp_tx_hdr_u;
+#define wp_api_time_stamp 	wp_tx_hdr_u.wp_tx._time_stamp
+} wp_tdm_api_tx_hdr_t;
+
+typedef struct {
+        wp_tdm_api_tx_hdr_t	hdr;
+        unsigned char  		data[1];
+} wp_tdm_api_tx_element_t;
+
+
+
+typedef struct wp_tdm_chan_stats
+{
+	unsigned int	rx_packets;		/* total packets received	*/
+	unsigned int	tx_packets;		/* total packets transmitted	*/
+	unsigned int	rx_bytes;		/* total bytes received 	*/
+	unsigned int	tx_bytes;		/* total bytes transmitted	*/
+	unsigned int	rx_errors;		/* bad packets received		*/
+	unsigned int	tx_errors;		/* packet transmit problems	*/
+	unsigned int	rx_dropped;		/* no space in linux buffers	*/
+	unsigned int	tx_dropped;		/* no space available in linux	*/
+	unsigned int	multicast;		/* multicast packets received	*/
+#if !defined(__WINDOWS__)
+	unsigned int	collisions;
+#endif
+	/* detailed rx_errors: */
+	unsigned int	rx_length_errors;
+	unsigned int	rx_over_errors;		/* receiver ring buff overflow	*/
+	unsigned int	rx_crc_errors;		/* recved pkt with crc error	*/
+	unsigned int	rx_frame_errors;	/* recv'd frame alignment error */
+#if !defined(__WINDOWS__)
+	unsigned int	rx_fifo_errors;		/* recv'r fifo overrun		*/
+#endif
+	unsigned int	rx_missed_errors;	/* receiver missed packet	*/
+
+	/* detailed tx_errors */
+#if !defined(__WINDOWS__)
+	unsigned int	tx_aborted_errors;
+	unsigned int	tx_carrier_errors;
+#endif
+	unsigned int	tx_fifo_errors;
+	unsigned int	tx_heartbeat_errors;
+	unsigned int	tx_window_errors;
+	
+}wp_tdm_chan_stats_t;          
+
+
+ 
+typedef struct wanpipe_tdm_api_cmd{
+	unsigned int cmd;
+	unsigned int hw_tdm_coding;	/* Set/Get HW TDM coding: uLaw muLaw */
+	unsigned int hw_mtu_mru;	/* Set/Get HW TDM MTU/MRU */
+	unsigned int usr_period;	/* Set/Get User Period in ms */
+	unsigned int tdm_codec;		/* Set/Get TDM Codec: SLinear */
+	unsigned int power_level;	/* Set/Get Power level treshold */
+	unsigned int rx_disable;	/* Enable/Disable Rx */
+	unsigned int tx_disable;	/* Enable/Disable Tx */		
+	unsigned int usr_mtu_mru;	/* Set/Get User TDM MTU/MRU */
+	unsigned int ec_tap;		/* Echo Cancellation Tap */
+	unsigned int rbs_poll;		/* Enable/Disable RBS Polling */
+	unsigned int rbs_rx_bits;	/* Rx RBS Bits */
+	unsigned int rbs_tx_bits;	/* Tx RBS Bits */
+	unsigned int hdlc;			/* HDLC based device */
+	unsigned int idle_flag;		/* IDLE flag to Tx */
+	unsigned int fe_alarms;		/* FE Alarms detected */
+	wp_tdm_chan_stats_t stats;	/* TDM Statistics */
+	/* Do NOT add anything above this! Important for binary backward compatibility. */
+	wp_tdm_api_event_t event;	/* TDM Event */
+	unsigned int data_len;
+        void *data;	
+	unsigned char fe_status;	/* FE status - Connected or Disconnected */
+	unsigned int hw_dtmf;		/* HW DTMF enabled */
+}wanpipe_tdm_api_cmd_t;
+
+typedef struct wanpipe_tdm_api_event{
+	int (*wp_rbs_event)(sng_fd_t fd, unsigned char rbs_bits);
+	int (*wp_dtmf_event)(sng_fd_t fd, unsigned char dtmf, unsigned char type, unsigned char port);
+	int (*wp_rxhook_event)(sng_fd_t fd, unsigned char hook_state);
+	int (*wp_ring_detect_event)(sng_fd_t fd, unsigned char ring_state);
+	int (*wp_ring_trip_detect_event)(sng_fd_t fd, unsigned char ring_state);
+	int (*wp_fe_alarm_event)(sng_fd_t fd, unsigned char fe_alarm_event);
+	int (*wp_link_status_event)(sng_fd_t fd, unsigned char link_status_event);
+}wanpipe_tdm_api_event_t; 
+
+typedef struct wanpipe_tdm_api{
+	wanpipe_tdm_api_cmd_t	wp_tdm_cmd;
+	wanpipe_tdm_api_event_t wp_tdm_event;
+}wanpipe_tdm_api_t;
+
+
+#endif

Added: freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_zt/ftmod_zt.c (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_zt/ftmod_zt.c	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_zt/ftmod_zt.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,1232 @@
+/*
+ * Copyright (c) 2007, Anthony Minessale II
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#include "freetdm.h"
+#include "ftmod_zt.h"
+
+/**
+ * \brief Zaptel globals
+ */
+static struct {
+	uint32_t codec_ms;
+	uint32_t wink_ms;
+	uint32_t flash_ms;
+	uint32_t eclevel;
+	uint32_t etlevel;
+    float rxgain;
+    float txgain;
+} zt_globals;
+
+/**
+ * \brief General IOCTL codes
+ */
+struct ioctl_codes {
+    int GET_BLOCKSIZE;
+    int SET_BLOCKSIZE;
+    int FLUSH;
+    int SYNC;
+    int GET_PARAMS;
+    int SET_PARAMS;
+    int HOOK;
+    int GETEVENT;
+    int IOMUX;
+    int SPANSTAT;
+    int MAINT;
+    int GETCONF;
+    int SETCONF;
+    int CONFLINK;
+    int CONFDIAG;
+    int GETGAINS;
+    int SETGAINS;
+    int SPANCONFIG;
+    int CHANCONFIG;
+    int SET_BUFINFO;
+    int GET_BUFINFO;
+    int AUDIOMODE;
+    int ECHOCANCEL;
+    int HDLCRAWMODE;
+    int HDLCFCSMODE;
+    int SPECIFY;
+    int SETLAW;
+    int SETLINEAR;
+    int GETCONFMUTE;
+    int ECHOTRAIN;
+    int SETTXBITS;
+    int GETRXBITS;
+};
+
+/**
+ * \brief Zaptel IOCTL codes
+ */
+static struct ioctl_codes zt_ioctl_codes = {
+    .GET_BLOCKSIZE = ZT_GET_BLOCKSIZE,
+    .SET_BLOCKSIZE = ZT_SET_BLOCKSIZE,
+    .FLUSH = ZT_FLUSH,
+    .SYNC = ZT_SYNC,
+    .GET_PARAMS = ZT_GET_PARAMS,
+    .SET_PARAMS = ZT_SET_PARAMS,
+    .HOOK = ZT_HOOK,
+    .GETEVENT = ZT_GETEVENT,
+    .IOMUX = ZT_IOMUX,
+    .SPANSTAT = ZT_SPANSTAT,
+    .MAINT = ZT_MAINT,
+    .GETCONF = ZT_GETCONF,
+    .SETCONF = ZT_SETCONF,
+    .CONFLINK = ZT_CONFLINK,
+    .CONFDIAG = ZT_CONFDIAG,
+    .GETGAINS = ZT_GETGAINS,
+    .SETGAINS = ZT_SETGAINS,
+    .SPANCONFIG = ZT_SPANCONFIG,
+    .CHANCONFIG = ZT_CHANCONFIG,
+    .SET_BUFINFO = ZT_SET_BUFINFO,
+    .GET_BUFINFO = ZT_GET_BUFINFO,
+    .AUDIOMODE = ZT_AUDIOMODE,
+    .ECHOCANCEL = ZT_ECHOCANCEL,
+    .HDLCRAWMODE = ZT_HDLCRAWMODE,
+    .HDLCFCSMODE = ZT_HDLCFCSMODE,
+    .SPECIFY = ZT_SPECIFY,
+    .SETLAW = ZT_SETLAW,
+    .SETLINEAR = ZT_SETLINEAR,
+    .GETCONFMUTE = ZT_GETCONFMUTE,
+    .ECHOTRAIN = ZT_ECHOTRAIN,
+    .SETTXBITS = ZT_SETTXBITS,
+    .GETRXBITS = ZT_GETRXBITS
+};
+
+/**
+ * \brief Dahdi IOCTL codes
+ */
+static struct ioctl_codes dahdi_ioctl_codes = {
+    .GET_BLOCKSIZE = DAHDI_GET_BLOCKSIZE,
+    .SET_BLOCKSIZE = DAHDI_SET_BLOCKSIZE,
+    .FLUSH = DAHDI_FLUSH,
+    .SYNC = DAHDI_SYNC,
+    .GET_PARAMS = DAHDI_GET_PARAMS,
+    .SET_PARAMS = DAHDI_SET_PARAMS,
+    .HOOK = DAHDI_HOOK,
+    .GETEVENT = DAHDI_GETEVENT,
+    .IOMUX = DAHDI_IOMUX,
+    .SPANSTAT = DAHDI_SPANSTAT,
+    .MAINT = DAHDI_MAINT,
+    .GETCONF = DAHDI_GETCONF,
+    .SETCONF = DAHDI_SETCONF,
+    .CONFLINK = DAHDI_CONFLINK,
+    .CONFDIAG = DAHDI_CONFDIAG,
+    .GETGAINS = DAHDI_GETGAINS,
+    .SETGAINS = DAHDI_SETGAINS,
+    .SPANCONFIG = DAHDI_SPANCONFIG,
+    .CHANCONFIG = DAHDI_CHANCONFIG,
+    .SET_BUFINFO = DAHDI_SET_BUFINFO,
+    .GET_BUFINFO = DAHDI_GET_BUFINFO,
+    .AUDIOMODE = DAHDI_AUDIOMODE,
+    .ECHOCANCEL = DAHDI_ECHOCANCEL,
+    .HDLCRAWMODE = DAHDI_HDLCRAWMODE,
+    .HDLCFCSMODE = DAHDI_HDLCFCSMODE,
+    .SPECIFY = DAHDI_SPECIFY,
+    .SETLAW = DAHDI_SETLAW,
+    .SETLINEAR = DAHDI_SETLINEAR,
+    .GETCONFMUTE = DAHDI_GETCONFMUTE,
+    .ECHOTRAIN = DAHDI_ECHOTRAIN,
+    .SETTXBITS = DAHDI_SETTXBITS,
+    .GETRXBITS = DAHDI_GETRXBITS
+};
+
+#define ZT_INVALID_SOCKET -1
+static struct ioctl_codes codes;
+static const char *ctlpath = NULL;
+static const char *chanpath = NULL;
+
+static const char dahdi_ctlpath[] = "/dev/dahdi/ctl";
+static const char dahdi_chanpath[] = "/dev/dahdi/channel";
+
+static const char zt_ctlpath[] = "/dev/ftdm/ctl";
+static const char zt_chanpath[] = "/dev/ftdm/channel";
+
+static ftdm_socket_t CONTROL_FD = ZT_INVALID_SOCKET;
+
+FIO_SPAN_NEXT_EVENT_FUNCTION(zt_next_event);
+FIO_SPAN_POLL_EVENT_FUNCTION(zt_poll_event);
+
+/**
+ * \brief Initialises codec, and rx/tx gains
+ * \param g Structure for gains to be initialised
+ * \param rxgain RX gain value
+ * \param txgain TX gain value
+ * \param codec Codec
+ */
+static void zt_build_gains(struct zt_gains *g, float rxgain, float txgain, int codec)
+{
+	int j;
+	int k;
+	float linear_rxgain = pow(10.0, rxgain / 20.0);
+    float linear_txgain = pow(10.0, txgain / 20.0);
+
+	switch (codec) {
+	case FTDM_CODEC_ALAW:
+		for (j = 0; j < (sizeof(g->receive_gain) / sizeof(g->receive_gain[0])); j++) {
+			if (rxgain) {
+				k = (int) (((float) alaw_to_linear(j)) * linear_rxgain);
+				if (k > 32767) k = 32767;
+				if (k < -32767) k = -32767;
+				g->receive_gain[j] = linear_to_alaw(k);
+			} else {
+				g->receive_gain[j] = j;
+			}
+			if (txgain) {
+				k = (int) (((float) alaw_to_linear(j)) * linear_txgain);
+				if (k > 32767) k = 32767;
+				if (k < -32767) k = -32767;
+				g->transmit_gain[j] = linear_to_alaw(k);
+			} else {
+				g->transmit_gain[j] = j;
+			}
+		}
+		break;
+	case FTDM_CODEC_ULAW:
+		for (j = 0; j < (sizeof(g->receive_gain) / sizeof(g->receive_gain[0])); j++) {
+			if (rxgain) {
+				k = (int) (((float) ulaw_to_linear(j)) * linear_rxgain);
+				if (k > 32767) k = 32767;
+				if (k < -32767) k = -32767;
+				g->receive_gain[j] = linear_to_ulaw(k);
+			} else {
+				g->receive_gain[j] = j;
+			}
+			if (txgain) {
+				k = (int) (((float) ulaw_to_linear(j)) * linear_txgain);
+				if (k > 32767) k = 32767;
+				if (k < -32767) k = -32767;
+				g->transmit_gain[j] = linear_to_ulaw(k);
+			} else {
+				g->transmit_gain[j] = j;
+			}
+		}
+		break;
+	}
+}
+
+/**
+ * \brief Initialises a range of ftdmtel channels
+ * \param span FreeTDM span
+ * \param start Initial wanpipe channel number
+ * \param end Final wanpipe channel number
+ * \param type FreeTDM channel type
+ * \param name FreeTDM span name
+ * \param number FreeTDM span number
+ * \param cas_bits CAS bits
+ * \return number of spans configured
+ */
+static unsigned zt_open_range(ftdm_span_t *span, unsigned start, unsigned end, ftdm_chan_type_t type, char *name, char *number, unsigned char cas_bits)
+{
+	unsigned configured = 0, x;
+	zt_params_t ztp;
+
+	memset(&ztp, 0, sizeof(ztp));
+
+	if (type == FTDM_CHAN_TYPE_CAS) {
+		ftdm_log(FTDM_LOG_DEBUG, "Configuring CAS channels with abcd == 0x%X\n", cas_bits);
+	}	
+	for(x = start; x < end; x++) {
+		ftdm_channel_t *ftdmchan;
+		ftdm_socket_t sockfd = ZT_INVALID_SOCKET;
+		int len;
+
+		sockfd = open(chanpath, O_RDWR);
+		if (sockfd != ZT_INVALID_SOCKET && ftdm_span_add_channel(span, sockfd, type, &ftdmchan) == FTDM_SUCCESS) {
+
+			if (ioctl(sockfd, codes.SPECIFY, &x)) {
+				ftdm_log(FTDM_LOG_ERROR, "failure configuring device %s chan %d fd %d (%s)\n", chanpath, x, sockfd, strerror(errno));
+				close(sockfd);
+				continue;
+			}
+
+			if (ftdmchan->type == FTDM_CHAN_TYPE_DQ921) {
+				struct zt_bufferinfo binfo;
+				memset(&binfo, 0, sizeof(binfo));
+				binfo.txbufpolicy = 0;
+				binfo.rxbufpolicy = 0;
+				binfo.numbufs = 32;
+				binfo.bufsize = 1024;
+				if (ioctl(sockfd, codes.SET_BUFINFO, &binfo)) {
+					ftdm_log(FTDM_LOG_ERROR, "failure configuring device %s as FreeTDM device %d:%d fd:%d\n", chanpath, ftdmchan->span_id, ftdmchan->chan_id, sockfd);
+					close(sockfd);
+					continue;
+				}
+			}
+
+			if (type == FTDM_CHAN_TYPE_FXS || type == FTDM_CHAN_TYPE_FXO) {
+				struct zt_chanconfig cc;
+				memset(&cc, 0, sizeof(cc));
+				cc.chan = cc.master = x;
+				
+				switch(type) {
+				case FTDM_CHAN_TYPE_FXS:
+					{
+						switch(span->start_type) {
+						case FTDM_ANALOG_START_KEWL:
+							cc.sigtype = ZT_SIG_FXOKS;
+							break;
+						case FTDM_ANALOG_START_LOOP:
+							cc.sigtype = ZT_SIG_FXOLS;
+							break;
+						case FTDM_ANALOG_START_GROUND:
+							cc.sigtype = ZT_SIG_FXOGS;
+							break;
+						default:
+							break;
+						}
+					}
+					break;
+				case FTDM_CHAN_TYPE_FXO:
+					{
+						switch(span->start_type) {
+						case FTDM_ANALOG_START_KEWL:
+							cc.sigtype = ZT_SIG_FXSKS;
+							break;
+						case FTDM_ANALOG_START_LOOP:
+							cc.sigtype = ZT_SIG_FXSLS;
+							break;
+						case FTDM_ANALOG_START_GROUND:
+							cc.sigtype = ZT_SIG_FXSGS;
+							break;
+						default:
+							break;
+						}
+					}
+					break;
+				default:
+					break;
+				}
+				
+				if (ioctl(CONTROL_FD, codes.CHANCONFIG, &cc)) {
+					ftdm_log(FTDM_LOG_WARNING, "this ioctl fails on older ftdmtel but is harmless if you used ztcfg\n[device %s chan %d fd %d (%s)]\n", chanpath, x, CONTROL_FD, strerror(errno));
+				}
+			}
+
+			if (type == FTDM_CHAN_TYPE_CAS) {
+				struct zt_chanconfig cc;
+				memset(&cc, 0, sizeof(cc));
+				cc.chan = cc.master = x;
+				cc.sigtype = ZT_SIG_CAS;
+				cc.idlebits = cas_bits;
+				if (ioctl(CONTROL_FD, codes.CHANCONFIG, &cc)) {
+					ftdm_log(FTDM_LOG_ERROR, "failure configuring device %s as FreeTDM device %d:%d fd:%d err:%s", chanpath, ftdmchan->span_id, ftdmchan->chan_id, sockfd, strerror(errno));
+					close(sockfd);
+					continue;
+				}
+			}
+
+			if (ftdmchan->type != FTDM_CHAN_TYPE_DQ921 && ftdmchan->type != FTDM_CHAN_TYPE_DQ931) {
+				len = zt_globals.codec_ms * 8;
+				if (ioctl(ftdmchan->sockfd, codes.SET_BLOCKSIZE, &len)) {
+					ftdm_log(FTDM_LOG_ERROR, "failure configuring device %s as FreeTDM device %d:%d fd:%d err:%s\n", 
+							chanpath, ftdmchan->span_id, ftdmchan->chan_id, sockfd, strerror(errno));
+					close(sockfd);
+					continue;
+				}
+
+				ftdmchan->packet_len = len;
+				ftdmchan->effective_interval = ftdmchan->native_interval = ftdmchan->packet_len / 8;
+			
+				if (ftdmchan->effective_codec == FTDM_CODEC_SLIN) {
+					ftdmchan->packet_len *= 2;
+				}
+			}
+			
+			if (ioctl(sockfd, codes.GET_PARAMS, &ztp) < 0) {
+				ftdm_log(FTDM_LOG_ERROR, "failure configuring device %s as FreeTDM device %d:%d fd:%d\n", chanpath, ftdmchan->span_id, ftdmchan->chan_id, sockfd);
+				close(sockfd);
+				continue;
+			}
+
+			if (ftdmchan->type == FTDM_CHAN_TYPE_DQ921) {
+				if (
+					(ztp.sig_type != ZT_SIG_HDLCRAW) &&
+					(ztp.sig_type != ZT_SIG_HDLCFCS) &&
+					(ztp.sig_type != ZT_SIG_HARDHDLC)
+					) {
+					ftdm_log(FTDM_LOG_ERROR, "Failure configuring device %s as FreeTDM device %d:%d fd:%d, hardware signaling is not HDLC, fix your Zap/DAHDI configuration!\n", chanpath, ftdmchan->span_id, ftdmchan->chan_id, sockfd);
+					close(sockfd);
+					continue;
+				}
+			}
+
+			ftdm_log(FTDM_LOG_INFO, "configuring device %s channel %d as FreeTDM device %d:%d fd:%d\n", chanpath, x, ftdmchan->span_id, ftdmchan->chan_id, sockfd);
+			
+			ftdmchan->rate = 8000;
+			ftdmchan->physical_span_id = ztp.span_no;
+			ftdmchan->physical_chan_id = ztp.chan_no;
+			
+			if (type == FTDM_CHAN_TYPE_FXS || type == FTDM_CHAN_TYPE_FXO || type == FTDM_CHAN_TYPE_EM || type == FTDM_CHAN_TYPE_B) {
+				if (ztp.g711_type == ZT_G711_ALAW) {
+					ftdmchan->native_codec = ftdmchan->effective_codec = FTDM_CODEC_ALAW;
+				} else if (ztp.g711_type == ZT_G711_MULAW) {
+					ftdmchan->native_codec = ftdmchan->effective_codec = FTDM_CODEC_ULAW;
+				} else {
+					int type;
+
+					if (ftdmchan->span->trunk_type == FTDM_TRUNK_E1) {
+						type = FTDM_CODEC_ALAW;
+					} else {
+						type = FTDM_CODEC_ULAW;
+					}
+
+					ftdmchan->native_codec = ftdmchan->effective_codec = type;
+
+				}
+			}
+
+			ztp.wink_time = zt_globals.wink_ms;
+			ztp.flash_time = zt_globals.flash_ms;
+
+			if (ioctl(sockfd, codes.SET_PARAMS, &ztp) < 0) {
+				ftdm_log(FTDM_LOG_ERROR, "failure configuring device %s as FreeTDM device %d:%d fd:%d\n", chanpath, ftdmchan->span_id, ftdmchan->chan_id, sockfd);
+				close(sockfd);
+				continue;
+			}
+
+			if (!ftdm_strlen_zero(name)) {
+				ftdm_copy_string(ftdmchan->chan_name, name, sizeof(ftdmchan->chan_name));
+			}
+			if (!ftdm_strlen_zero(number)) {
+				ftdm_copy_string(ftdmchan->chan_number, number, sizeof(ftdmchan->chan_number));
+			}
+			configured++;
+		} else {
+			ftdm_log(FTDM_LOG_ERROR, "failure configuring device %s\n", chanpath);
+		}
+	}
+	
+
+
+	return configured;
+}
+
+/**
+ * \brief Initialises an freetdm ftdmtel span from a configuration string
+ * \param span FreeTDM span
+ * \param str Configuration string
+ * \param type FreeTDM span type
+ * \param name FreeTDM span name
+ * \param number FreeTDM span number
+ * \return Success or failure
+ */
+static FIO_CONFIGURE_SPAN_FUNCTION(zt_configure_span)
+{
+
+	int items, i;
+	char *mydata, *item_list[10];
+	char *ch, *mx;
+	unsigned char cas_bits = 0;
+	int channo;
+	int top = 0;
+	unsigned configured = 0;
+
+	assert(str != NULL);
+	
+
+	mydata = ftdm_strdup(str);
+	assert(mydata != NULL);
+
+
+	items = ftdm_separate_string(mydata, ',', item_list, (sizeof(item_list) / sizeof(item_list[0])));
+
+	for(i = 0; i < items; i++) {
+		ch = item_list[i];
+
+		if (!(ch)) {
+			ftdm_log(FTDM_LOG_ERROR, "Invalid input\n");
+			continue;
+		}
+
+		channo = atoi(ch);
+		
+		if (channo < 0) {
+			ftdm_log(FTDM_LOG_ERROR, "Invalid channel number %d\n", channo);
+			continue;
+		}
+
+		if ((mx = strchr(ch, '-'))) {
+			mx++;
+			top = atoi(mx) + 1;
+		} else {
+			top = channo + 1;
+		}
+		
+		
+		if (top < 0) {
+			ftdm_log(FTDM_LOG_ERROR, "Invalid range number %d\n", top);
+			continue;
+		}
+		if (FTDM_CHAN_TYPE_CAS == type && ftdm_config_get_cas_bits(ch, &cas_bits)) {
+			ftdm_log(FTDM_LOG_ERROR, "Failed to get CAS bits in CAS channel\n");
+			continue;
+		}
+		configured += zt_open_range(span, channo, top, type, name, number, cas_bits);
+
+	}
+	
+	ftdm_safe_free(mydata);
+
+	return configured;
+
+}
+
+/**
+ * \brief Process configuration variable for a ftdmtel profile
+ * \param category Wanpipe profile name
+ * \param var Variable name
+ * \param val Variable value
+ * \param lineno Line number from configuration file
+ * \return Success
+ */
+static FIO_CONFIGURE_FUNCTION(zt_configure)
+{
+
+	int num;
+    float fnum;
+
+	if (!strcasecmp(category, "defaults")) {
+		if (!strcasecmp(var, "codec_ms")) {
+			num = atoi(val);
+			if (num < 10 || num > 60) {
+				ftdm_log(FTDM_LOG_WARNING, "invalid codec ms at line %d\n", lineno);
+			} else {
+				zt_globals.codec_ms = num;
+			}
+		} else if (!strcasecmp(var, "wink_ms")) {
+			num = atoi(val);
+			if (num < 50 || num > 3000) {
+				ftdm_log(FTDM_LOG_WARNING, "invalid wink ms at line %d\n", lineno);
+			} else {
+				zt_globals.wink_ms = num;
+			}
+		} else if (!strcasecmp(var, "flash_ms")) {
+			num = atoi(val);
+			if (num < 50 || num > 3000) {
+				ftdm_log(FTDM_LOG_WARNING, "invalid flash ms at line %d\n", lineno);
+			} else {
+				zt_globals.flash_ms = num;
+			}
+		} else if (!strcasecmp(var, "echo_cancel_level")) {
+			num = atoi(val);
+			if (num < 0 || num > 256) {
+                ftdm_log(FTDM_LOG_WARNING, "invalid echo can val at line %d\n", lineno);
+            } else {
+                zt_globals.eclevel = num;
+            }
+			
+		} else if (!strcasecmp(var, "rxgain")) {
+			fnum = (float)atof(val);
+			if (fnum < -100.0 || fnum > 100.0) {
+                ftdm_log(FTDM_LOG_WARNING, "invalid rxgain val at line %d\n", lineno);
+            } else {
+                zt_globals.rxgain = fnum;
+                ftdm_log(FTDM_LOG_INFO, "Setting rxgain val to %f\n", fnum);
+            }
+			
+		} else if (!strcasecmp(var, "txgain")) {
+			fnum = (float)atof(val);
+			if (fnum < -100.0 || fnum > 100.0) {
+                ftdm_log(FTDM_LOG_WARNING, "invalid txgain val at line %d\n", lineno);
+            } else {
+                zt_globals.txgain = fnum;
+                ftdm_log(FTDM_LOG_INFO, "Setting txgain val to %f\n", fnum);
+            }
+			
+		}
+	}
+
+	return FTDM_SUCCESS;
+}
+
+/**
+ * \brief Opens a ftdmtel channel
+ * \param ftdmchan Channel to open
+ * \return Success or failure
+ */
+static FIO_OPEN_FUNCTION(zt_open) 
+{
+	ftdm_channel_set_feature(ftdmchan, FTDM_CHANNEL_FEATURE_INTERVAL);
+
+	if (ftdmchan->type == FTDM_CHAN_TYPE_DQ921 || ftdmchan->type == FTDM_CHAN_TYPE_DQ931) {
+		ftdmchan->native_codec = ftdmchan->effective_codec = FTDM_CODEC_NONE;
+	} else {
+		int blocksize = zt_globals.codec_ms * (ftdmchan->rate / 1000);
+		int err;
+		if ((err = ioctl(ftdmchan->sockfd, codes.SET_BLOCKSIZE, &blocksize))) {
+			snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "%s", strerror(errno));
+			return FTDM_FAIL;
+		} else {
+			ftdmchan->effective_interval = ftdmchan->native_interval;
+			ftdmchan->packet_len = blocksize;
+			ftdmchan->native_codec = ftdmchan->effective_codec;
+		}
+		
+		if (ftdmchan->type == FTDM_CHAN_TYPE_B) {
+			int one = 1;
+			if (ioctl(ftdmchan->sockfd, codes.AUDIOMODE, &one)) {
+				snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "%s", strerror(errno));
+				ftdm_log(FTDM_LOG_ERROR, "%s\n", ftdmchan->last_error);
+				return FTDM_FAIL;
+			}
+		} else if (ftdmchan->type == FTDM_CHAN_TYPE_FXS || ftdmchan->type == FTDM_CHAN_TYPE_FXO || ftdmchan->type == FTDM_CHAN_TYPE_EM) {
+			int len = zt_globals.eclevel;
+			if (ioctl(ftdmchan->sockfd, codes.ECHOCANCEL, &len)) {
+				ftdm_log(FTDM_LOG_WARNING, "Echo cancel not available for %d:%d\n", ftdmchan->span_id, ftdmchan->chan_id);
+				//snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "%s", strerror(errno));
+				//ftdm_log(FTDM_LOG_ERROR, "%s\n", ftdmchan->last_error);
+				//return FTDM_FAIL;
+			} else {
+				len = zt_globals.etlevel;
+				if (ioctl(ftdmchan->sockfd, codes.ECHOTRAIN, &len)) {
+					ftdm_log(FTDM_LOG_WARNING, "Echo training not available for %d:%d\n", ftdmchan->span_id, ftdmchan->chan_id);
+					//snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "%s", strerror(errno));
+					//ftdm_log(FTDM_LOG_ERROR, "%s\n", ftdmchan->last_error);
+					//return FTDM_FAIL;
+				}
+			}
+		}
+        if(zt_globals.rxgain || zt_globals.txgain) {
+            struct zt_gains gains;
+            memset(&gains, 0, sizeof(gains));
+
+            gains.chan_no = ftdmchan->physical_chan_id;
+            zt_build_gains(&gains, zt_globals.rxgain, zt_globals.txgain, ftdmchan->native_codec);
+
+            if(zt_globals.rxgain)
+                ftdm_log(FTDM_LOG_INFO, "Setting rxgain to %f on channel %d\n", zt_globals.rxgain, gains.chan_no);
+
+            if(zt_globals.txgain)
+                ftdm_log(FTDM_LOG_INFO, "Setting txgain to %f on channel %d\n", zt_globals.txgain, gains.chan_no);
+
+			if (ioctl(ftdmchan->sockfd, codes.SETGAINS, &gains) < 0) {
+				ftdm_log(FTDM_LOG_ERROR, "failure configuring device %s as FreeTDM device %d:%d fd:%d\n", chanpath, ftdmchan->span_id, ftdmchan->chan_id, ftdmchan->sockfd);
+   			}
+        }
+
+        int len = zt_globals.eclevel;
+       	ftdm_log(FTDM_LOG_INFO, "Setting echo cancel to %d taps for %d:%d\n", len, ftdmchan->span_id, ftdmchan->chan_id);
+        if (ioctl(ftdmchan->sockfd, codes.ECHOCANCEL, &len)) {
+                ftdm_log(FTDM_LOG_WARNING, "Echo cancel not available for %d:%d\n", ftdmchan->span_id, ftdmchan->chan_id);
+        } else {
+                len = zt_globals.etlevel;
+               	if (ioctl(ftdmchan->sockfd, codes.ECHOTRAIN, &len)) {
+                        ftdm_log(FTDM_LOG_WARNING, "Echo training not available for %d:%d\n", ftdmchan->span_id, ftdmchan->chan_id);
+                }
+       	}
+
+	}
+	return FTDM_SUCCESS;
+}
+
+/**
+ * \brief Closes ftdmtel channel
+ * \param ftdmchan Channel to close
+ * \return Success
+ */
+static FIO_CLOSE_FUNCTION(zt_close)
+{
+	return FTDM_SUCCESS;
+}
+
+/**
+ * \brief Executes an FreeTDM command on a ftdmtel channel
+ * \param ftdmchan Channel to execute command on
+ * \param command FreeTDM command to execute
+ * \param obj Object (unused)
+ * \return Success or failure
+ */
+static FIO_COMMAND_FUNCTION(zt_command)
+{
+	zt_params_t ztp;
+	int err = 0;
+
+	memset(&ztp, 0, sizeof(ztp));
+
+	switch(command) {
+	case FTDM_COMMAND_ENABLE_ECHOCANCEL:
+		{
+			int level = FTDM_COMMAND_OBJ_INT;
+			err = ioctl(ftdmchan->sockfd, codes.ECHOCANCEL, &level);
+			FTDM_COMMAND_OBJ_INT = level;
+		}
+	case FTDM_COMMAND_DISABLE_ECHOCANCEL:
+		{
+			int level = 0;
+			err = ioctl(ftdmchan->sockfd, codes.ECHOCANCEL, &level);
+			FTDM_COMMAND_OBJ_INT = level;
+		}
+		break;
+	case FTDM_COMMAND_ENABLE_ECHOTRAIN:
+		{
+			int level = FTDM_COMMAND_OBJ_INT;
+			err = ioctl(ftdmchan->sockfd, codes.ECHOTRAIN, &level);
+			FTDM_COMMAND_OBJ_INT = level;
+		}
+	case FTDM_COMMAND_DISABLE_ECHOTRAIN:
+		{
+			int level = 0;
+			err = ioctl(ftdmchan->sockfd, codes.ECHOTRAIN, &level);
+			FTDM_COMMAND_OBJ_INT = level;
+		}
+		break;
+	case FTDM_COMMAND_OFFHOOK:
+		{
+			int command = ZT_OFFHOOK;
+			if (ioctl(ftdmchan->sockfd, codes.HOOK, &command)) {
+				snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "OFFHOOK Failed");
+				return FTDM_FAIL;
+			}
+			ftdm_set_flag_locked(ftdmchan, FTDM_CHANNEL_OFFHOOK);
+		}
+		break;
+	case FTDM_COMMAND_ONHOOK:
+		{
+			int command = ZT_ONHOOK;
+			if (ioctl(ftdmchan->sockfd, codes.HOOK, &command)) {
+				snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "ONHOOK Failed");
+				return FTDM_FAIL;
+			}
+			ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_OFFHOOK);
+		}
+		break;
+	case FTDM_COMMAND_FLASH:
+		{
+			int command = ZT_FLASH;
+			if (ioctl(ftdmchan->sockfd, codes.HOOK, &command)) {
+				snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "FLASH Failed");
+				return FTDM_FAIL;
+			}
+		}
+		break;
+	case FTDM_COMMAND_WINK:
+		{
+			int command = ZT_WINK;
+			if (ioctl(ftdmchan->sockfd, codes.HOOK, &command)) {
+				snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "WINK Failed");
+				return FTDM_FAIL;
+			}
+		}
+		break;
+	case FTDM_COMMAND_GENERATE_RING_ON:
+		{
+			int command = ZT_RING;
+			if (ioctl(ftdmchan->sockfd, codes.HOOK, &command)) {
+				snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "Ring Failed");
+				return FTDM_FAIL;
+			}
+			ftdm_set_flag_locked(ftdmchan, FTDM_CHANNEL_RINGING);
+		}
+		break;
+	case FTDM_COMMAND_GENERATE_RING_OFF:
+		{
+			int command = ZT_RINGOFF;
+			if (ioctl(ftdmchan->sockfd, codes.HOOK, &command)) {
+				snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "Ring-off failed");
+				return FTDM_FAIL;
+			}
+			ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_RINGING);
+		}
+		break;
+	case FTDM_COMMAND_GET_INTERVAL:
+		{
+
+			if (!(err = ioctl(ftdmchan->sockfd, codes.GET_BLOCKSIZE, &ftdmchan->packet_len))) {
+				ftdmchan->native_interval = ftdmchan->packet_len / 8;
+				if (ftdmchan->effective_codec == FTDM_CODEC_SLIN) {
+					ftdmchan->packet_len *= 2;
+				}
+				FTDM_COMMAND_OBJ_INT = ftdmchan->native_interval;
+			} 			
+		}
+		break;
+	case FTDM_COMMAND_SET_INTERVAL: 
+		{
+			int interval = FTDM_COMMAND_OBJ_INT;
+			int len = interval * 8;
+
+			if (!(err = ioctl(ftdmchan->sockfd, codes.SET_BLOCKSIZE, &len))) {
+				ftdmchan->packet_len = len;
+				ftdmchan->effective_interval = ftdmchan->native_interval = ftdmchan->packet_len / 8;
+
+				if (ftdmchan->effective_codec == FTDM_CODEC_SLIN) {
+					ftdmchan->packet_len *= 2;
+				}
+			}
+		}
+		break;
+	case FTDM_COMMAND_SET_CAS_BITS:
+		{
+			int bits = FTDM_COMMAND_OBJ_INT;
+			err = ioctl(ftdmchan->sockfd, codes.SETTXBITS, &bits);
+		}
+		break;
+	case FTDM_COMMAND_GET_CAS_BITS:
+		{
+			err = ioctl(ftdmchan->sockfd, codes.GETRXBITS, &ftdmchan->rx_cas_bits);
+			if (!err) {
+				FTDM_COMMAND_OBJ_INT = ftdmchan->rx_cas_bits;
+			}
+		}
+		break;
+	case FTDM_COMMAND_FLUSH_TX_BUFFERS:
+		{
+			int flushmode = ZT_FLUSH_WRITE;
+			err = ioctl(ftdmchan->sockfd, codes.FLUSH, &flushmode);
+		}
+		break;
+	case FTDM_COMMAND_FLUSH_RX_BUFFERS:
+		{
+			int flushmode = ZT_FLUSH_READ;
+			err = ioctl(ftdmchan->sockfd, codes.FLUSH, &flushmode);
+		}
+		break;
+	case FTDM_COMMAND_FLUSH_BUFFERS:
+		{
+			int flushmode = ZT_FLUSH_BOTH;
+			err = ioctl(ftdmchan->sockfd, codes.FLUSH, &flushmode);
+		}
+		break;
+	default:
+		err = FTDM_NOTIMPL;
+		break;
+	};
+
+	if (err && err != FTDM_NOTIMPL) {
+		snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "%s", strerror(errno));
+		return FTDM_FAIL;
+	}
+
+
+	return err == 0 ? FTDM_SUCCESS : err;
+}
+
+/**
+ * \brief Gets alarms from a ftdmtel Channel
+ * \param ftdmchan Channel to get alarms from
+ * \return Success or failure
+ */
+static FIO_GET_ALARMS_FUNCTION(zt_get_alarms)
+{
+	struct zt_spaninfo info;
+
+	memset(&info, 0, sizeof(info));
+	info.span_no = ftdmchan->physical_span_id;
+
+	if (ioctl(CONTROL_FD, codes.SPANSTAT, &info)) {
+		snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "ioctl failed (%s)", strerror(errno));
+		snprintf(ftdmchan->span->last_error, sizeof(ftdmchan->span->last_error), "ioctl failed (%s)", strerror(errno));
+		return FTDM_FAIL;
+	}
+
+	ftdmchan->alarm_flags = info.alarms;
+
+	return FTDM_SUCCESS;
+}
+
+/**
+ * \brief Waits for an event on a ftdmtel channel
+ * \param ftdmchan Channel to open
+ * \param flags Type of event to wait for
+ * \param to Time to wait (in ms)
+ * \return Success, failure or timeout
+ */
+static FIO_WAIT_FUNCTION(zt_wait)
+{
+	int32_t inflags = 0;
+	int result;
+    struct pollfd pfds[1];
+
+	if (*flags & FTDM_READ) {
+		inflags |= POLLIN;
+	}
+
+	if (*flags & FTDM_WRITE) {
+		inflags |= POLLOUT;
+	}
+
+	if (*flags & FTDM_EVENTS) {
+		inflags |= POLLPRI;
+	}
+
+
+    memset(&pfds[0], 0, sizeof(pfds[0]));
+    pfds[0].fd = ftdmchan->sockfd;
+    pfds[0].events = inflags;
+    result = poll(pfds, 1, to);
+	*flags = 0;
+
+	if (pfds[0].revents & POLLERR) {
+		result = -1;
+	}
+
+	if (result > 0) {
+		inflags = pfds[0].revents;
+	}
+
+	*flags = FTDM_NO_FLAGS;
+
+	if (result < 0){
+		snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "Poll failed");
+		return FTDM_FAIL;
+	}
+
+	if (result == 0) {
+		return FTDM_TIMEOUT;
+	}
+
+	if (inflags & POLLIN) {
+		*flags |= FTDM_READ;
+	}
+
+	if (inflags & POLLOUT) {
+		*flags |= FTDM_WRITE;
+	}
+
+	if (inflags & POLLPRI) {
+		*flags |= FTDM_EVENTS;
+	}
+
+	return FTDM_SUCCESS;
+
+}
+
+/**
+ * \brief Checks for events on a ftdmtel span
+ * \param span Span to check for events
+ * \param ms Time to wait for event
+ * \return Success if event is waiting or failure if not
+ */
+FIO_SPAN_POLL_EVENT_FUNCTION(zt_poll_event)
+{
+	struct pollfd pfds[FTDM_MAX_CHANNELS_SPAN];
+	uint32_t i, j = 0, k = 0;
+	int r;
+	
+	for(i = 1; i <= span->chan_count; i++) {
+		memset(&pfds[j], 0, sizeof(pfds[j]));
+		pfds[j].fd = span->channels[i]->sockfd;
+		pfds[j].events = POLLPRI;
+		j++;
+	}
+
+    r = poll(pfds, j, ms);
+
+	if (r == 0) {
+		return FTDM_TIMEOUT;
+	} else if (r < 0 || (pfds[i-1].revents & POLLERR)) {
+		snprintf(span->last_error, sizeof(span->last_error), "%s", strerror(errno));
+		return FTDM_FAIL;
+	}
+	
+	for(i = 1; i <= span->chan_count; i++) {
+		if (pfds[i-1].revents & POLLPRI) {
+			ftdm_set_flag(span->channels[i], FTDM_CHANNEL_EVENT);
+			span->channels[i]->last_event_time = ftdm_current_time_in_ms();
+			k++;
+		}
+	}
+
+	if (!k) {
+		snprintf(span->last_error, sizeof(span->last_error), "no matching descriptor");
+	}
+
+	return k ? FTDM_SUCCESS : FTDM_FAIL;
+}
+
+/**
+ * \brief Retrieves an event from a ftdmtel span
+ * \param span Span to retrieve event from
+ * \param event FreeTDM event to return
+ * \return Success or failure
+ */
+FIO_SPAN_NEXT_EVENT_FUNCTION(zt_next_event)
+{
+	uint32_t i, event_id = 0;
+	ftdm_oob_event_t zt_event_id = 0;
+
+	for(i = 1; i <= span->chan_count; i++) {
+		if (ftdm_test_flag(span->channels[i], FTDM_CHANNEL_EVENT)) {
+			ftdm_clear_flag(span->channels[i], FTDM_CHANNEL_EVENT);
+			if (ioctl(span->channels[i]->sockfd, codes.GETEVENT, &zt_event_id) == -1) {
+				snprintf(span->last_error, sizeof(span->last_error), "%s", strerror(errno));
+				return FTDM_FAIL;
+			}
+
+			switch(zt_event_id) {
+			case ZT_EVENT_RINGEROFF:
+				{
+					return FTDM_FAIL;
+				}
+				break;
+			case ZT_EVENT_RINGERON:
+				{
+					return FTDM_FAIL;
+				}
+				break;
+			case ZT_EVENT_RINGBEGIN:
+				{
+					event_id = FTDM_OOB_RING_START;
+				}
+				break;
+			case ZT_EVENT_ONHOOK:
+				{
+					event_id = FTDM_OOB_ONHOOK;
+				}
+				break;
+			case ZT_EVENT_WINKFLASH:
+				{
+					if (span->channels[i]->state == FTDM_CHANNEL_STATE_DOWN || span->channels[i]->state == FTDM_CHANNEL_STATE_DIALING) {
+						event_id = FTDM_OOB_WINK;
+					} else {
+						event_id = FTDM_OOB_FLASH;
+					}
+				}
+				break;
+			case ZT_EVENT_RINGOFFHOOK:
+				{
+					if (span->channels[i]->type == FTDM_CHAN_TYPE_FXS || (span->channels[i]->type == FTDM_CHAN_TYPE_EM && span->channels[i]->state != FTDM_CHANNEL_STATE_UP)) {
+						ftdm_set_flag_locked(span->channels[i], FTDM_CHANNEL_OFFHOOK);
+						event_id = FTDM_OOB_OFFHOOK;
+					} else if (span->channels[i]->type == FTDM_CHAN_TYPE_FXO) {
+						event_id = FTDM_OOB_RING_START;
+					}
+				}
+				break;
+			case ZT_EVENT_ALARM:
+				{
+					event_id = FTDM_OOB_ALARM_TRAP;
+				}
+				break;
+			case ZT_EVENT_NOALARM:
+				{
+					event_id = FTDM_OOB_ALARM_CLEAR;
+				}
+				break;
+			case ZT_EVENT_BITSCHANGED:
+				{
+					event_id = FTDM_OOB_CAS_BITS_CHANGE;
+					int bits = 0;
+					int err = ioctl(span->channels[i]->sockfd, codes.GETRXBITS, &bits);
+					if (err) {
+						return FTDM_FAIL;
+					}
+					span->channels[i]->rx_cas_bits = bits;
+				}
+				break;
+			default:
+				{
+					ftdm_log(FTDM_LOG_WARNING, "Unhandled event %d for %d:%d\n", zt_event_id, span->span_id, i);
+					event_id = FTDM_OOB_INVALID;
+				}
+				break;
+			}
+
+			span->channels[i]->last_event_time = 0;
+			span->event_header.e_type = FTDM_EVENT_OOB;
+			span->event_header.enum_id = event_id;
+			span->event_header.channel = span->channels[i];
+			*event = &span->event_header;
+			return FTDM_SUCCESS;
+		}
+	}
+
+	return FTDM_FAIL;
+	
+}
+
+/**
+ * \brief Reads data from a ftdmtel channel
+ * \param ftdmchan Channel to read from
+ * \param data Data buffer
+ * \param datalen Size of data buffer
+ * \return Success, failure or timeout
+ */
+static FIO_READ_FUNCTION(zt_read)
+{
+	ftdm_ssize_t r = 0;
+	int errs = 0;
+
+	while (errs++ < 30) {
+		if ((r = read(ftdmchan->sockfd, data, *datalen)) > 0) {
+			break;
+		}
+		ftdm_sleep(10);
+		if (r == 0) {
+			errs--;
+		}
+	}
+
+	if (r > 0) {
+		*datalen = r;
+		if (ftdmchan->type == FTDM_CHAN_TYPE_DQ921) {
+			*datalen -= 2;
+		}
+		return FTDM_SUCCESS;
+	}
+
+	return r == 0 ? FTDM_TIMEOUT : FTDM_FAIL;
+}
+
+/**
+ * \brief Writes data to a ftdmtel channel
+ * \param ftdmchan Channel to write to
+ * \param data Data buffer
+ * \param datalen Size of data buffer
+ * \return Success or failure
+ */
+static FIO_WRITE_FUNCTION(zt_write)
+{
+	ftdm_ssize_t w = 0;
+	ftdm_size_t bytes = *datalen;
+
+	if (ftdmchan->type == FTDM_CHAN_TYPE_DQ921) {
+		memset(data+bytes, 0, 2);
+		bytes += 2;
+	}
+
+	w = write(ftdmchan->sockfd, data, bytes);
+	
+	if (w >= 0) {
+		*datalen = w;
+		return FTDM_SUCCESS;
+	}
+
+	return FTDM_FAIL;
+}
+
+/**
+ * \brief Destroys a ftdmtel Channel
+ * \param ftdmchan Channel to destroy
+ * \return Success
+ */
+static FIO_CHANNEL_DESTROY_FUNCTION(zt_channel_destroy)
+{
+	close(ftdmchan->sockfd);
+	ftdmchan->sockfd = ZT_INVALID_SOCKET;
+
+	return FTDM_SUCCESS;
+}
+
+/**
+ * \brief Global FreeTDM IO interface for ftdmtel
+ */
+static ftdm_io_interface_t zt_interface;
+
+/**
+ * \brief Loads ftdmtel IO module
+ * \param fio FreeTDM IO interface
+ * \return Success or failure
+ */
+static FIO_IO_LOAD_FUNCTION(zt_init)
+{
+	assert(fio != NULL);
+    struct stat statbuf;
+	memset(&zt_interface, 0, sizeof(zt_interface));
+	memset(&zt_globals, 0, sizeof(zt_globals));
+
+    if (!stat(zt_ctlpath, &statbuf)) {
+        ftdm_log(FTDM_LOG_NOTICE, "Using Zaptel control device\n");
+        ctlpath = zt_ctlpath;
+        chanpath = zt_chanpath;
+        memcpy(&codes, &zt_ioctl_codes, sizeof(codes));
+    } else if (!stat(dahdi_ctlpath, &statbuf)) {
+        ftdm_log(FTDM_LOG_NOTICE, "Using DAHDI control device\n");
+        ctlpath = dahdi_ctlpath;
+        chanpath = dahdi_chanpath;
+        memcpy(&codes, &dahdi_ioctl_codes, sizeof(codes));
+    } else {
+		ftdm_log(FTDM_LOG_ERROR, "No DAHDI or Zap control device found in /dev/\n");
+		return FTDM_FAIL;
+    }
+	if ((CONTROL_FD = open(ctlpath, O_RDWR)) < 0) {
+		ftdm_log(FTDM_LOG_ERROR, "Cannot open control device %s: %s\n", ctlpath, strerror(errno));
+		return FTDM_FAIL;
+	}
+
+	zt_globals.codec_ms = 20;
+	zt_globals.wink_ms = 150;
+	zt_globals.flash_ms = 750;
+	zt_globals.eclevel = 64;
+	zt_globals.etlevel = 0;
+	
+	zt_interface.name = "zt";
+	zt_interface.configure = zt_configure;
+	zt_interface.configure_span = zt_configure_span;
+	zt_interface.open = zt_open;
+	zt_interface.close = zt_close;
+	zt_interface.command = zt_command;
+	zt_interface.wait = zt_wait;
+	zt_interface.read = zt_read;
+	zt_interface.write = zt_write;
+	zt_interface.poll_event = zt_poll_event;
+	zt_interface.next_event = zt_next_event;
+	zt_interface.channel_destroy = zt_channel_destroy;
+	zt_interface.get_alarms = zt_get_alarms;
+	*fio = &zt_interface;
+
+	return FTDM_SUCCESS;
+}
+
+/**
+ * \brief Unloads ftdmtel IO module
+ * \return Success
+ */
+static FIO_IO_UNLOAD_FUNCTION(zt_destroy)
+{
+	close(CONTROL_FD);
+	memset(&zt_interface, 0, sizeof(zt_interface));
+	return FTDM_SUCCESS;
+}
+
+/**
+ * \brief FreeTDM ftdmtel IO module definition
+ */
+ftdm_module_t ftdm_module = { 
+	"zt",
+	zt_init,
+	zt_destroy,
+};
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */

Added: freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_zt/ftmod_zt.h (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_zt/ftmod_zt.h	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_zt/ftmod_zt.h	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,364 @@
+/*
+ * Copyright (c) 2007, Anthony Minessale II
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FTDM_ZT_H
+#define FTDM_ZT_H
+#include "freetdm.h"
+#include <sys/ioctl.h>
+#include <poll.h>
+
+#ifdef __sun
+#include <unistd.h>
+#include <sys/ioccom.h>
+#include <stropts.h>
+#endif
+
+/* Hardware interface structures and defines */
+/* Based on documentation of the structures required for the hardware interface */
+/* from http://wiki.freeswitch.org/wiki/Zapata_ftdmtel_interface */
+
+/* Structures */
+
+/* Used with ioctl: ZT_GET_PARAMS and ZT_SET_PARAMS */
+struct zt_params {
+	int chan_no;			/* Channel Number							*/
+	int span_no;			/* Span Number								*/
+	int chan_position;		/* Channel Position							*/
+	int sig_type;			/* Signal Type (read-only)					*/
+	int sig_cap;			/* Signal Cap (read-only)					*/
+	int receive_offhook;	/* Receive is offhook (read-only)			*/
+	int receive_bits;		/* Number of bits in receive (read-only)	*/
+	int transmit_bits;		/* Number of bits in transmit (read-only)	*/
+	int transmit_hook_sig;	/* Transmit Hook Signal (read-only)			*/
+	int receive_hook_sig;	/* Receive Hook Signal (read-only)			*/
+	int g711_type;			/* Member of zt_g711_t (read-only)			*/
+	int idlebits;			/* bits for the idle state (read-only)		*/
+	char chan_name[40];		/* Channel Name								*/
+	int prewink_time;
+	int preflash_time;
+	int wink_time;
+	int flash_time;
+	int start_time;
+	int receive_wink_time;
+	int receive_flash_time;
+	int debounce_time;
+	int pulse_break_time;
+	int pulse_make_time;
+	int pulse_after_time;
+    /* latest version of this struct include chan_alarms field */
+    uint32_t chan_alarms;
+};
+
+typedef struct zt_params zt_params_t;
+
+/* Used with ioctl: ZT_CONFLINK, ZT_GETCONF and ZT_SETCONF */
+struct zt_confinfo {
+	int chan_no;			/* Channel Number, 0 for current */
+	int conference_number;
+	int conference_mode;
+};
+
+/* Used with ioctl: ZT_GETGAINS and ZT_SETGAINS */
+struct zt_gains {
+	int chan_no;						/* Channel Number, 0 for current	*/
+	unsigned char receive_gain[256];	/* Receive gain table				*/
+	unsigned char transmit_gain[256];	/* Transmit gain table				*/
+};
+
+/* Used with ioctl: ZT_SPANSTAT */
+struct zt_spaninfo {
+	int span_no;						/* span number (-1 to use name)				*/
+	char name[20];						/* Name of span								*/
+	char description[40];				/* Description of span						*/
+	int alarms;							/* alarms status							*/
+	int transmit_level;					/* Transmit level							*/
+	int receive_level;					/* Receive level							*/
+	int bpv_count;						/* Current BPV count						*/
+	int crc4_count;						/* Current CRC4 error count					*/
+	int ebit_count;						/* Current E-bit error count				*/
+	int fas_count;						/* Current FAS error count					*/
+	int irq_misses;						/* Current IRQ misses						*/
+	int sync_src;						/* Span # of sync source (0 = free run)		*/
+	int configured_chan_count;			/* Count of channels configured on the span	*/
+	int channel_count;					/* Total count of channels on the span		*/
+	int span_count;						/* Total count of ftdmtel spans on the system*/
+    /* end v1 of the struct */
+    /* as long as we don't use the fields below we should be ok regardless of the ftdmtel/dahdi version */
+    int lbo;                            /* Line Build Out */
+    int lineconfig;                     /* framing/coding */
+    /* end of v2 of the struct */
+    char lboname[40];                   /* Line Build Out in text form */
+    char location[40];                  /* span's device location in system */
+    char manufacturer[40];              /* manufacturer of span's device */
+    char devicetype[40];                /* span's device type */
+    int irq;                            /* span's device IRQ */
+    int linecompat;                     /* signaling modes possible on this span */
+    char spantype[6];                   /* type of span in text form */
+};
+
+struct zt_maintinfo {
+	int span_no;						/* span number											*/
+	int command;						/* Maintenance mode to set (from zt_maintenance_mode_t)	*/
+};
+
+struct zt_lineconfig {
+/* Used in ZT_SPANCONFIG */
+	int span;							/* Which span number (0 to use name)		*/
+	char name[20];						/* Name of span to use						*/
+	int lbo;							/* line build-outs							*/
+	int lineconfig;						/* line config parameters (framing, coding) */
+	int sync;							/* what level of sync source we are			*/
+};
+
+struct zt_chanconfig {
+/* Used in ZT_CHANCONFIG */
+	int chan;							/* Channel we're applying this to (0 to use name)										*/
+	char name[40];						/* Name of channel to use																*/
+	int sigtype;						/* Signal type																			*/
+	int deflaw;							/* Default law (ZT_LAW_DEFAULT, ZT_LAW_MULAW, or ZT_LAW_ALAW							*/
+	int master;							/* Master channel if sigtype is ZT_SLAVE												*/
+	int idlebits;						/* Idle bits (if this is a CAS channel) or channel to monitor (if this is DACS channel) */
+	char netdev_name[16];				/* name for the hdlc network device														*/
+};
+
+struct zt_bufferinfo {
+/* used in ZT_SET_BUFINFO and ZT_GET_BUFINFO */
+	int txbufpolicy;					/* Policy for handling receive buffers			*/
+	int rxbufpolicy;					/* Policy for handling receive buffers			*/
+	int numbufs;						/* How many buffers to use						*/
+	int bufsize;						/* How big each buffer is						*/
+	int readbufs;						/* How many read buffers are full (read-only)	*/
+	int writebufs;						/* How many write buffers are full (read-only)	*/
+};
+
+/* Enumerations */
+
+/* Values in zt_params structure for member g711_type */
+typedef enum {
+	ZT_G711_DEFAULT		= 0,	/* Default mulaw/alaw from the span */
+	ZT_G711_MULAW		= 1,
+	ZT_G711_ALAW		= 2
+} zt_g711_t;
+
+typedef enum {
+	ZT_EVENT_NONE			= 0,
+	ZT_EVENT_ONHOOK			= 1,
+	ZT_EVENT_RINGOFFHOOK	= 2,
+	ZT_EVENT_WINKFLASH		= 3,
+	ZT_EVENT_ALARM			= 4,
+	ZT_EVENT_NOALARM		= 5,
+	ZT_EVENT_ABORT			= 6,
+	ZT_EVENT_OVERRUN		= 7,
+	ZT_EVENT_BADFCS			= 8,
+	ZT_EVENT_DIALCOMPLETE	= 9, 
+	ZT_EVENT_RINGERON		= 10,
+	ZT_EVENT_RINGEROFF		= 11,
+	ZT_EVENT_HOOKCOMPLETE	= 12,
+	ZT_EVENT_BITSCHANGED	= 13,
+	ZT_EVENT_PULSE_START	= 14,
+	ZT_EVENT_TIMER_EXPIRED	= 15,
+	ZT_EVENT_TIMER_PING		= 16,
+	ZT_EVENT_POLARITY		= 17,
+	ZT_EVENT_RINGBEGIN		= 18
+} zt_event_t;
+
+typedef enum {
+	ZT_FLUSH_READ			= 1,
+	ZT_FLUSH_WRITE			= 2,
+	ZT_FLUSH_BOTH			= (ZT_FLUSH_READ | ZT_FLUSH_WRITE),
+	ZT_FLUSH_EVENT			= 4,
+	ZT_FLUSH_ALL			= (ZT_FLUSH_READ | ZT_FLUSH_WRITE | ZT_FLUSH_EVENT)
+} zt_flush_t;
+
+typedef enum {
+	ZT_IOMUX_READ			= 1,
+	ZT_IOMUX_WRITE			= 2,
+	ZT_IOMUX_WRITEEMPTY		= 4,
+	ZT_IOMUX_SIGEVENT		= 8,
+	ZT_IOMUX_NOWAIT			= 256
+} zt_iomux_t;
+
+typedef enum {
+	ZT_ONHOOK				= 0,
+	ZT_OFFHOOK				= 1,
+	ZT_WINK					= 2,
+	ZT_FLASH				= 3,
+	ZT_START				= 4,
+	ZT_RING					= 5,
+	ZT_RINGOFF				= 6
+} zt_hookstate_t;
+
+typedef enum {
+	ZT_MAINT_NONE			= 0, /* Normal Mode				*/
+	ZT_MAINT_LOCALLOOP		= 1, /* Local Loopback			*/
+	ZT_MAINT_REMOTELOOP		= 2, /* Remote Loopback			*/
+	ZT_MAINT_LOOPUP			= 3, /* Send Loopup Code		*/
+	ZT_MAINT_LOOPDOWN		= 4, /* Send Loopdown Code		*/
+	ZT_MAINT_LOOPSTOP		= 5  /* Stop Sending Loop Codes	*/
+} zt_maintenance_mode_t;
+
+typedef enum {
+/* Signalling type */
+ZT_SIG_NONE					= 0,						/* chan not configured. */
+
+ZT_SIG_FXSLS				= ((1 << 0) | (1 << 13)),	/* FXS, Loopstart */
+ZT_SIG_FXSGS				= ((1 << 1) | (1 << 13)),	/* FXS, Groundstart */
+ZT_SIG_FXSKS				= ((1 << 2) | (1 << 13)),	/* FXS, Kewlstart */
+ZT_SIG_FXOLS				= ((1 << 3) | (1 << 12)),	/* FXO, Loopstart */
+ZT_SIG_FXOGS				= ((1 << 4) | (1 << 12)),	/* FXO, Groupstart */
+ZT_SIG_FXOKS				= ((1 << 5) | (1 << 12)),	/* FXO, Kewlstart */
+ZT_SIG_EM					= (1 << 6),					/* E&M */
+ZT_SIG_CLEAR				= (1 << 7),
+ZT_SIG_HDLCRAW				= ((1 << 8)  | ZT_SIG_CLEAR),
+ZT_SIG_HDLCFCS				= ((1 << 9)  | ZT_SIG_HDLCRAW),
+ZT_SIG_CAS                  = (1 << 15),
+ZT_SIG_HARDHDLC				= ((1 << 19) | ZT_SIG_CLEAR),
+} zt_sigtype_t;
+
+typedef enum {
+ZT_DBIT = 1,
+ZT_CBIT = 2,
+ZT_BBIT = 4,
+ZT_ABIT = 8
+} zt_cas_bit_t;
+
+/* Defines */
+
+#define		ZT_MAX_BLOCKSIZE	8192
+#define		ZT_DEFAULT_MTU_MRU	2048
+
+/* ioctl defines */
+
+#define		ZT_CODE				'J'
+#define     DAHDI_CODE          0xDA
+
+
+#define		ZT_GET_BLOCKSIZE	_IOR  (ZT_CODE, 1, int)					/* Get Transfer Block Size. */
+#define		ZT_SET_BLOCKSIZE	_IOW  (ZT_CODE, 2, int)					/* Set Transfer Block Size. */
+#define		ZT_FLUSH			_IOW  (ZT_CODE, 3, int)					/* Flush Buffer(s) and stop I/O */
+#define		ZT_SYNC				_IOW  (ZT_CODE, 4, int)					/* Wait for Write to Finish */
+#define		ZT_GET_PARAMS		_IOR  (ZT_CODE, 5, struct zt_params)	/* Get channel parameters */
+#define		ZT_SET_PARAMS		_IOW  (ZT_CODE, 6, struct zt_params)	/* Set channel parameters */
+#define		ZT_HOOK				_IOW  (ZT_CODE, 7, int)					/* Set Hookswitch Status */
+#define		ZT_GETEVENT			_IOR  (ZT_CODE, 8, int)					/* Get Signalling Event */
+#define		ZT_IOMUX			_IOWR (ZT_CODE, 9, int)					/* Wait for something to happen (IO Mux) */
+#define		ZT_SPANSTAT			_IOWR (ZT_CODE, 10, struct zt_spaninfo) /* Get Span Status */
+#define		ZT_MAINT			_IOW  (ZT_CODE, 11, struct zt_maintinfo)/* Set Maintenance Mode for a span */
+#define		ZT_GETCONF			_IOWR (ZT_CODE, 12, struct zt_confinfo)	/* Get Conference Mode */
+#define		ZT_SETCONF			_IOWR (ZT_CODE, 13, struct zt_confinfo)	/* Set Conference Mode */
+#define		ZT_CONFLINK			_IOW  (ZT_CODE, 14, struct zt_confinfo)	/* Setup or Remove Conference Link */
+#define		ZT_CONFDIAG			_IOR  (ZT_CODE, 15, int)				/* Display Conference Diagnostic Information on Console */
+
+#define		ZT_GETGAINS			_IOWR (ZT_CODE, 16, struct zt_gains)	/* Get Channel audio gains */
+#define		ZT_SETGAINS			_IOWR (ZT_CODE, 17, struct zt_gains)	/* Set Channel audio gains */
+#define		ZT_SPANCONFIG		_IOW (ZT_CODE, 18, struct zt_lineconfig)/* Set Line (T1) Configurations and start system  */
+#define		ZT_CHANCONFIG		_IOW (ZT_CODE, 19, struct zt_chanconfig)/* Set Channel Configuration  */
+#define		ZT_SET_BUFINFO		_IOW (ZT_CODE, 27, struct zt_bufferinfo)/* Set buffer policy */
+#define		ZT_GET_BUFINFO		_IOR (ZT_CODE, 28, struct zt_bufferinfo)/* Get current buffer info */
+#define		ZT_AUDIOMODE		_IOW  (ZT_CODE, 32, int)				/* Set a clear channel into audio mode */
+#define		ZT_ECHOCANCEL		_IOW  (ZT_CODE, 33, int)				/* Control Echo Canceller */
+#define		ZT_HDLCRAWMODE		_IOW  (ZT_CODE, 36, int)				/* Set a clear channel into HDLC w/out FCS checking/calculation mode */
+#define		ZT_HDLCFCSMODE		_IOW  (ZT_CODE, 37, int)				/* Set a clear channel into HDLC w/ FCS mode */
+
+/* Specify a channel on /dev/ftdm/chan -- must be done before any other ioctl's and is only valid on /dev/ftdm/chan */
+#define		ZT_SPECIFY			_IOW  (ZT_CODE, 38, int)
+
+/* Temporarily set the law on a channel to ZT_LAW_DEFAULT, ZT_LAW_ALAW, or ZT_LAW_MULAW. Is reset on close. */
+#define		ZT_SETLAW			_IOW  (ZT_CODE, 39, int)
+
+/* Temporarily set the channel to operate in linear mode when non-zero or default law if 0 */
+#define		ZT_SETLINEAR		_IOW  (ZT_CODE, 40, int)
+
+#define		ZT_GETCONFMUTE		_IOR  (ZT_CODE, 49, int)				/* Get Conference to mute mode */
+#define		ZT_ECHOTRAIN		_IOW  (ZT_CODE, 50, int)				/* Control Echo Trainer */
+
+/* Set/Get CAS bits */
+#define ZT_SETTXBITS _IOW (ZT_CODE, 43, int)
+#define ZT_GETRXBITS _IOR (ZT_CODE, 45, int)
+
+#define		DAHDI_GET_BLOCKSIZE	_IOR  (DAHDI_CODE, 1, int)					/* Get Transfer Block Size. */
+#define		DAHDI_SET_BLOCKSIZE	_IOW  (DAHDI_CODE, 1, int)					/* Set Transfer Block Size. */
+#define		DAHDI_FLUSH			_IOW  (DAHDI_CODE, 3, int)					/* Flush Buffer(s) and stop I/O */
+#define		DAHDI_SYNC			_IO   (DAHDI_CODE, 4)					/* Wait for Write to Finish */
+#define		DAHDI_GET_PARAMS	_IOR  (DAHDI_CODE, 5, struct zt_params)	/* Get channel parameters */
+#define		DAHDI_SET_PARAMS	_IOW  (DAHDI_CODE, 5, struct zt_params)	/* Set channel parameters */
+#define		DAHDI_HOOK			_IOW  (DAHDI_CODE, 7, int)					/* Set Hookswitch Status */
+#define		DAHDI_GETEVENT		_IOR  (DAHDI_CODE, 8, int)					/* Get Signalling Event */
+#define		DAHDI_IOMUX			_IOWR (DAHDI_CODE, 9, int)					/* Wait for something to happen (IO Mux) */
+#define		DAHDI_SPANSTAT		_IOWR (DAHDI_CODE, 10, struct zt_spaninfo)  /* Get Span Status */
+#define		DAHDI_MAINT			_IOW  (DAHDI_CODE, 11, struct zt_maintinfo) /* Set Maintenance Mode for a span */
+#define		DAHDI_GETCONF		_IOR  (DAHDI_CODE, 12, struct zt_confinfo)	/* Get Conference Mode */
+#define		DAHDI_SETCONF		_IOW  (DAHDI_CODE, 12, struct zt_confinfo)	/* Set Conference Mode */
+#define		DAHDI_CONFLINK		_IOW  (DAHDI_CODE, 14, struct zt_confinfo)	/* Setup or Remove Conference Link */
+#define		DAHDI_CONFDIAG		_IOR  (DAHDI_CODE, 15, int)				/* Display Conference Diagnostic Information on Console */
+
+#define		DAHDI_GETGAINS		_IOR (DAHDI_CODE, 16, struct zt_gains)	/* Get Channel audio gains */
+#define		DAHDI_SETGAINS		_IOW (DAHDI_CODE, 16, struct zt_gains)	/* Set Channel audio gains */
+#define		DAHDI_SPANCONFIG	_IOW (DAHDI_CODE, 18, struct zt_lineconfig)/* Set Line (T1) Configurations and start system  */
+#define		DAHDI_CHANCONFIG	_IOW (DAHDI_CODE, 19, struct zt_chanconfig)/* Set Channel Configuration  */
+#define		DAHDI_SET_BUFINFO	_IOW (DAHDI_CODE, 27, struct zt_bufferinfo)/* Set buffer policy */
+#define		DAHDI_GET_BUFINFO	_IOR (DAHDI_CODE, 27, struct zt_bufferinfo)/* Get current buffer info */
+#define		DAHDI_AUDIOMODE		_IOW (DAHDI_CODE, 32, int)				/* Set a clear channel into audio mode */
+#define		DAHDI_ECHOCANCEL	_IOW (DAHDI_CODE, 33, int)				/* Control Echo Canceller */
+#define		DAHDI_HDLCRAWMODE	_IOW (DAHDI_CODE, 36, int)				/* Set a clear channel into HDLC w/out FCS checking/calculation mode */
+#define		DAHDI_HDLCFCSMODE	_IOW (DAHDI_CODE, 37, int)				/* Set a clear channel into HDLC w/ FCS mode */
+
+/* Specify a channel on /dev/dahdi/chan -- must be done before any other ioctl's and is only valid on /dev/dahdi/chan */
+#define		DAHDI_SPECIFY		_IOW  (DAHDI_CODE, 38, int)
+
+/* Temporarily set the law on a channel to DAHDI_LAW_DEFAULT, DAHDI_LAW_ALAW, or DAHDI_LAW_MULAW. Is reset on close. */
+#define		DAHDI_SETLAW		_IOW  (DAHDI_CODE, 39, int)
+
+/* Temporarily set the channel to operate in linear mode when non-zero or default law if 0 */
+#define		DAHDI_SETLINEAR		_IOW  (DAHDI_CODE, 40, int)
+
+#define		DAHDI_GETCONFMUTE	_IOR  (DAHDI_CODE, 49, int)				/* Get Conference to mute mode */
+#define		DAHDI_ECHOTRAIN		_IOW  (DAHDI_CODE, 50, int)				/* Control Echo Trainer */
+
+/* Set/Get CAS bits */
+#define DAHDI_SETTXBITS _IOW (DAHDI_CODE, 43, int)
+#define DAHDI_GETRXBITS _IOR (DAHDI_CODE, 43, int)
+
+
+#endif
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */

Added: freeswitch/trunk/libs/freetdm/src/g711.c (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/g711.c	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/g711.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,104 @@
+/*
+ * SpanDSP - a series of DSP components for telephony
+ *
+ * g711.c - A-law and u-law transcoding routines
+ *
+ * Written by Steve Underwood <steveu@coppice.org>
+ *
+ * Copyright (C) 2006 Steve Underwood
+ *
+ *  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.
+ *
+ * $Id: g711.c,v 1.1 2006/06/07 15:46:39 steveu Exp $
+ */
+
+/*! \file */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#ifndef _MSC_VER
+#include <inttypes.h>
+#ifdef HAVE_TGMATH_H
+#include <tgmath.h>
+#endif
+#endif
+
+#include "g711.h"
+
+/* Copied from the CCITT G.711 specification */
+static const uint8_t ulaw_to_alaw_table[256] =
+	{
+		42,  43,  40,  41,  46,  47,  44,  45,  34,  35,  32,  33,  38,  39,  36,  37,
+		58,  59,  56,  57,  62,  63,  60,  61,  50,  51,  48,  49,  54,  55,  52,  53,
+		10,  11,   8,   9,  14,  15,  12,  13,   2,   3,   0,   1,   6,   7,   4,  26,
+		27,  24,  25,  30,  31,  28,  29,  18,  19,  16,  17,  22,  23,  20,  21, 106,
+		104, 105, 110, 111, 108, 109,  98,  99,  96,  97, 102, 103, 100, 101, 122, 120,
+		126, 127, 124, 125, 114, 115, 112, 113, 118, 119, 116, 117,  75,  73,  79,  77,
+		66,  67,  64,  65,  70,  71,  68,  69,  90,  91,  88,  89,  94,  95,  92,  93,
+		82,  82,  83,  83,  80,  80,  81,  81,  86,  86,  87,  87,  84,  84,  85,  85,
+		170, 171, 168, 169, 174, 175, 172, 173, 162, 163, 160, 161, 166, 167, 164, 165,
+		186, 187, 184, 185, 190, 191, 188, 189, 178, 179, 176, 177, 182, 183, 180, 181,
+		138, 139, 136, 137, 142, 143, 140, 141, 130, 131, 128, 129, 134, 135, 132, 154,
+		155, 152, 153, 158, 159, 156, 157, 146, 147, 144, 145, 150, 151, 148, 149, 234,
+		232, 233, 238, 239, 236, 237, 226, 227, 224, 225, 230, 231, 228, 229, 250, 248,
+		254, 255, 252, 253, 242, 243, 240, 241, 246, 247, 244, 245, 203, 201, 207, 205,
+		194, 195, 192, 193, 198, 199, 196, 197, 218, 219, 216, 217, 222, 223, 220, 221,
+		210, 210, 211, 211, 208, 208, 209, 209, 214, 214, 215, 215, 212, 212, 213, 213
+	};
+
+/* These transcoding tables are copied from the CCITT G.711 specification. To achieve
+   optimal results, do not change them. */
+
+static const uint8_t alaw_to_ulaw_table[256] =
+	{
+		42,  43,  40,  41,  46,  47,  44,  45,  34,  35,  32,  33,  38,  39,  36,  37,
+		57,  58,  55,  56,  61,  62,  59,  60,  49,  50,  47,  48,  53,  54,  51,  52,
+		10,  11,   8,   9,  14,  15,  12,  13,   2,   3,   0,   1,   6,   7,   4,   5,
+		26,  27,  24,  25,  30,  31,  28,  29,  18,  19,  16,  17,  22,  23,  20,  21,
+		98,  99,  96,  97, 102, 103, 100, 101,  93,  93,  92,  92,  95,  95,  94,  94,
+		116, 118, 112, 114, 124, 126, 120, 122, 106, 107, 104, 105, 110, 111, 108, 109,
+		72,  73,  70,  71,  76,  77,  74,  75,  64,  65,  63,  63,  68,  69,  66,  67,
+		86,  87,  84,  85,  90,  91,  88,  89,  79,  79,  78,  78,  82,  83,  80,  81,
+		170, 171, 168, 169, 174, 175, 172, 173, 162, 163, 160, 161, 166, 167, 164, 165,
+		185, 186, 183, 184, 189, 190, 187, 188, 177, 178, 175, 176, 181, 182, 179, 180,
+		138, 139, 136, 137, 142, 143, 140, 141, 130, 131, 128, 129, 134, 135, 132, 133,
+		154, 155, 152, 153, 158, 159, 156, 157, 146, 147, 144, 145, 150, 151, 148, 149,
+		226, 227, 224, 225, 230, 231, 228, 229, 221, 221, 220, 220, 223, 223, 222, 222,
+		244, 246, 240, 242, 252, 254, 248, 250, 234, 235, 232, 233, 238, 239, 236, 237,
+		200, 201, 198, 199, 204, 205, 202, 203, 192, 193, 191, 191, 196, 197, 194, 195,
+		214, 215, 212, 213, 218, 219, 216, 217, 207, 207, 206, 206, 210, 211, 208, 209
+	};
+
+uint8_t alaw_to_ulaw(uint8_t alaw)
+{
+    return alaw_to_ulaw_table[alaw];
+}
+/*- End of function --------------------------------------------------------*/
+
+uint8_t ulaw_to_alaw(uint8_t ulaw)
+{
+    return ulaw_to_alaw_table[ulaw];
+}
+/*- End of function --------------------------------------------------------*/
+/*- End of file ------------------------------------------------------------*/
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
+

Added: freeswitch/trunk/libs/freetdm/src/hashtable.c (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/hashtable.c	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/hashtable.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,340 @@
+/*
+ * Copyright (c) 2002, Christopher Clark
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "freetdm.h"
+#include "hashtable.h"
+#include "hashtable_private.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+
+/*
+  Credit for primes table: Aaron Krowne
+  http://br.endernet.org/~akrowne/
+  http://planetmath.org/encyclopedia/GoodHashTablePrimes.html
+*/
+static const unsigned int primes[] = {
+	53, 97, 193, 389,
+	769, 1543, 3079, 6151,
+	12289, 24593, 49157, 98317,
+	196613, 393241, 786433, 1572869,
+	3145739, 6291469, 12582917, 25165843,
+	50331653, 100663319, 201326611, 402653189,
+	805306457, 1610612741
+};
+const unsigned int prime_table_length = sizeof(primes)/sizeof(primes[0]);
+const float max_load_factor = 0.65f;
+
+/*****************************************************************************/
+FT_DECLARE(struct hashtable *)
+create_hashtable(unsigned int minsize,
+                 unsigned int (*hashf) (void*),
+                 int (*eqf) (void*,void*))
+{
+    struct hashtable *h;
+    unsigned int pindex, size = primes[0];
+    /* Check requested hashtable isn't too large */
+    if (minsize > (1u << 30)) return NULL;
+    /* Enforce size as prime */
+    for (pindex=0; pindex < prime_table_length; pindex++) {
+        if (primes[pindex] > minsize) { size = primes[pindex]; break; }
+    }
+    h = (struct hashtable *)ftdm_malloc(sizeof(struct hashtable));
+    if (NULL == h) return NULL; /*oom*/
+    h->table = (struct entry **)ftdm_malloc(sizeof(struct entry*) * size);
+    if (NULL == h->table) { ftdm_safe_free(h); return NULL; } /*oom*/
+    memset(h->table, 0, size * sizeof(struct entry *));
+    h->tablelength  = size;
+    h->primeindex   = pindex;
+    h->entrycount   = 0;
+    h->hashfn       = hashf;
+    h->eqfn         = eqf;
+    h->loadlimit    = (unsigned int) ceil(size * max_load_factor);
+    return h;
+}
+
+/*****************************************************************************/
+unsigned int
+hash(struct hashtable *h, void *k)
+{
+    /* Aim to protect against poor hash functions by adding logic here
+     * - logic taken from java 1.4 hashtable source */
+    unsigned int i = h->hashfn(k);
+    i += ~(i << 9);
+    i ^=  ((i >> 14) | (i << 18)); /* >>> */
+    i +=  (i << 4);
+    i ^=  ((i >> 10) | (i << 22)); /* >>> */
+    return i;
+}
+
+/*****************************************************************************/
+static int
+hashtable_expand(struct hashtable *h)
+{
+    /* Double the size of the table to accomodate more entries */
+    struct entry **newtable;
+    struct entry *e;
+    struct entry **pE;
+    unsigned int newsize, i, index;
+    /* Check we're not hitting max capacity */
+    if (h->primeindex == (prime_table_length - 1)) return 0;
+    newsize = primes[++(h->primeindex)];
+
+    newtable = (struct entry **)ftdm_malloc(sizeof(struct entry*) * newsize);
+    if (NULL != newtable)
+		{
+			memset(newtable, 0, newsize * sizeof(struct entry *));
+			/* This algorithm is not 'stable'. ie. it reverses the list
+			 * when it transfers entries between the tables */
+			for (i = 0; i < h->tablelength; i++) {
+				while (NULL != (e = h->table[i])) {
+					h->table[i] = e->next;
+					index = indexFor(newsize,e->h);
+					e->next = newtable[index];
+					newtable[index] = e;
+				}
+			}
+			ftdm_safe_free(h->table);
+			h->table = newtable;
+		}
+    /* Plan B: realloc instead */
+    else 
+		{
+			newtable = (struct entry **)
+				realloc(h->table, newsize * sizeof(struct entry *));
+			if (NULL == newtable) { (h->primeindex)--; return 0; }
+			h->table = newtable;
+			memset(newtable[h->tablelength], 0, newsize - h->tablelength);
+			for (i = 0; i < h->tablelength; i++) {
+				for (pE = &(newtable[i]), e = *pE; e != NULL; e = *pE) {
+					index = indexFor(newsize,e->h);
+					if (index == i)
+						{
+							pE = &(e->next);
+						}
+					else
+						{
+							*pE = e->next;
+							e->next = newtable[index];
+							newtable[index] = e;
+						}
+				}
+			}
+		}
+    h->tablelength = newsize;
+    h->loadlimit   = (unsigned int) ceil(newsize * max_load_factor);
+    return -1;
+}
+
+/*****************************************************************************/
+FT_DECLARE(unsigned int)
+hashtable_count(struct hashtable *h)
+{
+    return h->entrycount;
+}
+
+/*****************************************************************************/
+FT_DECLARE(int)
+hashtable_insert(struct hashtable *h, void *k, void *v, hashtable_flag_t flags)
+{
+    /* This method allows duplicate keys - but they shouldn't be used */
+    unsigned int index;
+    struct entry *e;
+    if (++(h->entrycount) > h->loadlimit)
+		{
+			/* Ignore the return value. If expand fails, we should
+			 * still try cramming just this value into the existing table
+			 * -- we may not have memory for a larger table, but one more
+			 * element may be ok. Next time we insert, we'll try expanding again.*/
+			hashtable_expand(h);
+		}
+    e = (struct entry *)ftdm_malloc(sizeof(struct entry));
+    if (NULL == e) { --(h->entrycount); return 0; } /*oom*/
+    e->h = hash(h,k);
+    index = indexFor(h->tablelength,e->h);
+    e->k = k;
+    e->v = v;
+	e->flags = flags;
+    e->next = h->table[index];
+    h->table[index] = e;
+    return -1;
+}
+
+/*****************************************************************************/
+FT_DECLARE(void *) /* returns value associated with key */
+hashtable_search(struct hashtable *h, void *k)
+{
+    struct entry *e;
+    unsigned int hashvalue, index;
+    hashvalue = hash(h,k);
+    index = indexFor(h->tablelength,hashvalue);
+    e = h->table[index];
+    while (NULL != e)
+		{
+			/* Check hash value to short circuit heavier comparison */
+			if ((hashvalue == e->h) && (h->eqfn(k, e->k))) return e->v;
+			e = e->next;
+		}
+    return NULL;
+}
+
+/*****************************************************************************/
+FT_DECLARE(void *) /* returns value associated with key */
+hashtable_remove(struct hashtable *h, void *k)
+{
+    /* TODO: consider compacting the table when the load factor drops enough,
+     *       or provide a 'compact' method. */
+
+    struct entry *e;
+    struct entry **pE;
+    void *v;
+    unsigned int hashvalue, index;
+
+    hashvalue = hash(h,k);
+    index = indexFor(h->tablelength,hash(h,k));
+    pE = &(h->table[index]);
+    e = *pE;
+    while (NULL != e)
+		{
+			/* Check hash value to short circuit heavier comparison */
+			if ((hashvalue == e->h) && (h->eqfn(k, e->k)))
+				{
+					*pE = e->next;
+					h->entrycount--;
+					v = e->v;
+					if (e->flags & HASHTABLE_FLAG_FREE_KEY) {
+						freekey(e->k);
+					}
+					ftdm_safe_free(e);
+					return v;
+				}
+			pE = &(e->next);
+			e = e->next;
+		}
+    return NULL;
+}
+
+/*****************************************************************************/
+/* destroy */
+FT_DECLARE(void)
+hashtable_destroy(struct hashtable *h)
+{
+    unsigned int i;
+    struct entry *e, *f;
+    struct entry **table = h->table;
+
+	for (i = 0; i < h->tablelength; i++)
+        {
+            e = table[i];
+            while (NULL != e)
+				{ f = e; e = e->next; if (f->flags & HASHTABLE_FLAG_FREE_KEY) freekey(f->k); if (f->flags & HASHTABLE_FLAG_FREE_VALUE) ftdm_safe_free(f->v); ftdm_safe_free(f); }
+        }
+    
+    ftdm_safe_free(h->table);
+    ftdm_safe_free(h);
+}
+
+FT_DECLARE(struct hashtable_iterator *) hashtable_next(struct hashtable_iterator *i)
+{
+
+	if (i->e) {
+		if ((i->e = i->e->next) != 0) { 
+			return i;
+		} else {
+			i->pos++;
+		}
+	}
+	
+	while(i->pos < i->h->tablelength && !i->h->table[i->pos]) {
+		i->pos++;
+	}
+	
+	if (i->pos >= i->h->tablelength) {
+		return NULL;
+	}
+	
+	if ((i->e = i->h->table[i->pos]) != 0) { 
+		return i;
+	}
+
+	return NULL;
+}
+
+FT_DECLARE(struct hashtable_iterator *) hashtable_first(struct hashtable *h)
+{
+	h->iterator.pos = 0;
+	h->iterator.e = NULL;
+	h->iterator.h = h;
+	return hashtable_next(&h->iterator);
+}
+
+
+
+FT_DECLARE(void) hashtable_this(struct hashtable_iterator *i, const void **key, int *klen, void **val)
+{
+	if (i->e) {
+		if (key) {
+			*key = i->e->k;
+		}
+		if (klen) {
+			*klen = (int)strlen(i->e->k);
+		}
+		if (val) {
+			*val = i->e->v;
+		}
+	} else {
+		if (key) {
+			*key = NULL;
+		}
+		if (klen) {
+			*klen = 0;
+		}
+		if (val) {
+			*val = NULL;
+		}
+	}
+}
+
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
+

Added: freeswitch/trunk/libs/freetdm/src/hashtable_itr.c (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/hashtable_itr.c	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/hashtable_itr.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,186 @@
+/*
+ * Copyright (c) 2002, 2004, Christopher Clark
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "freetdm.h"
+#include "hashtable.h"
+#include "hashtable_private.h"
+#include "hashtable_itr.h"
+#include <stdlib.h> /* defines NULL */
+
+/*****************************************************************************/
+/* hashtable_iterator    - iterator constructor */
+
+struct hashtable_itr *
+hashtable_iterator(struct hashtable *h)
+{
+    unsigned int i, tablelength;
+    struct hashtable_itr *itr = ftdm_malloc(sizeof(struct hashtable_itr));
+    if (NULL == itr) return NULL;
+    itr->h = h;
+    itr->e = NULL;
+    itr->parent = NULL;
+    tablelength = h->tablelength;
+    itr->index = tablelength;
+    if (0 == h->entrycount) return itr;
+
+    for (i = 0; i < tablelength; i++)
+		{
+			if (NULL != h->table[i])
+				{
+					itr->e = h->table[i];
+					itr->index = i;
+					break;
+				}
+		}
+    return itr;
+}
+
+/*****************************************************************************/
+/* advance - advance the iterator to the next element
+ *           returns zero if advanced to end of table */
+
+int
+hashtable_iterator_advance(struct hashtable_itr *itr)
+{
+    unsigned int j,tablelength;
+    struct entry **table;
+    struct entry *next;
+    if (NULL == itr->e) return 0; /* stupidity check */
+
+    next = itr->e->next;
+    if (NULL != next)
+		{
+			itr->parent = itr->e;
+			itr->e = next;
+			return -1;
+		}
+    tablelength = itr->h->tablelength;
+    itr->parent = NULL;
+    if (tablelength <= (j = ++(itr->index)))
+		{
+			itr->e = NULL;
+			return 0;
+		}
+    table = itr->h->table;
+    while (NULL == (next = table[j]))
+		{
+			if (++j >= tablelength)
+				{
+					itr->index = tablelength;
+					itr->e = NULL;
+					return 0;
+				}
+		}
+    itr->index = j;
+    itr->e = next;
+    return -1;
+}
+
+/*****************************************************************************/
+/* remove - remove the entry at the current iterator position
+ *          and advance the iterator, if there is a successive
+ *          element.
+ *          If you want the value, read it before you remove:
+ *          beware memory leaks if you don't.
+ *          Returns zero if end of iteration. */
+
+int
+hashtable_iterator_remove(struct hashtable_itr *itr)
+{
+    struct entry *remember_e, *remember_parent;
+    int ret;
+
+    /* Do the removal */
+    if (NULL == (itr->parent))
+		{
+			/* element is head of a chain */
+			itr->h->table[itr->index] = itr->e->next;
+		} else {
+        /* element is mid-chain */
+        itr->parent->next = itr->e->next;
+    }
+    /* itr->e is now outside the hashtable */
+    remember_e = itr->e;
+    itr->h->entrycount--;
+    freekey(remember_e->k);
+
+    /* Advance the iterator, correcting the parent */
+    remember_parent = itr->parent;
+    ret = hashtable_iterator_advance(itr);
+    if (itr->parent == remember_e) { itr->parent = remember_parent; }
+    ftdm_safe_free(remember_e);
+    return ret;
+}
+
+/*****************************************************************************/
+int /* returns zero if not found */
+hashtable_iterator_search(struct hashtable_itr *itr,
+                          struct hashtable *h, void *k)
+{
+    struct entry *e, *parent;
+    unsigned int hashvalue, index;
+
+    hashvalue = hash(h,k);
+    index = indexFor(h->tablelength,hashvalue);
+
+    e = h->table[index];
+    parent = NULL;
+    while (NULL != e)
+		{
+			/* Check hash value to short circuit heavier comparison */
+			if ((hashvalue == e->h) && (h->eqfn(k, e->k)))
+				{
+					itr->index = index;
+					itr->e = e;
+					itr->parent = parent;
+					itr->h = h;
+					return -1;
+				}
+			parent = e;
+			e = e->next;
+		}
+    return 0;
+}
+
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
+

Added: freeswitch/trunk/libs/freetdm/src/include/freetdm.h (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/include/freetdm.h	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/include/freetdm.h	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,968 @@
+/*
+ * Copyright (c) 2007, Anthony Minessale II
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Contributors: 
+ *
+ * Moises Silva <moy@sangoma.com>
+ *
+ */
+
+#ifndef FREETDM_H
+#define FREETDM_H
+
+
+#if !defined(_XOPEN_SOURCE) && !defined(__FreeBSD__)
+#define _XOPEN_SOURCE 600
+#endif
+
+#ifndef HAVE_STRINGS_H
+#define HAVE_STRINGS_H 1
+#endif
+#ifndef HAVE_SYS_SOCKET_H
+#define HAVE_SYS_SOCKET_H 1
+#endif
+
+#ifndef __WINDOWS__
+#if defined(WIN32) || defined(WIN64) || defined(_MSC_VER) || defined(_WIN32) || defined(_WIN64)
+#define __WINDOWS__
+#endif
+#endif
+
+#ifdef _MSC_VER
+#if defined(FT_DECLARE_STATIC)
+#define FT_DECLARE(type)			type __stdcall
+#define FT_DECLARE_NONSTD(type)		type __cdecl
+#define FT_DECLARE_DATA
+#elif defined(FREETDM_EXPORTS)
+#define FT_DECLARE(type)			__declspec(dllexport) type __stdcall
+#define FT_DECLARE_NONSTD(type)		__declspec(dllexport) type __cdecl
+#define FT_DECLARE_DATA				__declspec(dllexport)
+#else
+#define FT_DECLARE(type)			__declspec(dllimport) type __stdcall
+#define FT_DECLARE_NONSTD(type)		__declspec(dllimport) type __cdecl
+#define FT_DECLARE_DATA				__declspec(dllimport)
+#endif
+#define EX_DECLARE_DATA				__declspec(dllexport)
+#else
+#if (defined(__GNUC__) || defined(__SUNPRO_CC) || defined (__SUNPRO_C)) && defined(HAVE_VISIBILITY)
+#define FT_DECLARE(type)		__attribute__((visibility("default"))) type
+#define FT_DECLARE_NONSTD(type)	__attribute__((visibility("default"))) type
+#define FT_DECLARE_DATA		__attribute__((visibility("default")))
+#else
+#define FT_DECLARE(type)		type
+#define FT_DECLARE_NONSTD(type)	type
+#define FT_DECLARE_DATA
+#endif
+#define EX_DECLARE_DATA
+#endif
+
+#ifdef _MSC_VER
+#ifndef __inline__
+#define __inline__ __inline
+#endif
+#if (_MSC_VER >= 1400)			/* VC8+ */
+#ifndef _CRT_SECURE_NO_DEPRECATE
+#define _CRT_SECURE_NO_DEPRECATE
+#endif
+#ifndef _CRT_NONSTDC_NO_DEPRECATE
+#define _CRT_NONSTDC_NO_DEPRECATE
+#endif
+#endif
+#ifndef strcasecmp
+#define strcasecmp(s1, s2) _stricmp(s1, s2)
+#endif
+#ifndef strncasecmp
+#define strncasecmp(s1, s2, n) _strnicmp(s1, s2, n)
+#endif
+#ifndef snprintf
+#define snprintf _snprintf
+#endif
+#ifndef S_IRUSR
+#define S_IRUSR _S_IREAD
+#endif
+#ifndef S_IWUSR
+#define S_IWUSR _S_IWRITE
+#endif
+#undef HAVE_STRINGS_H
+#undef HAVE_SYS_SOCKET_H
+/* disable warning for zero length array in a struct */
+/* this will cause errors on c99 and ansi compliant compilers and will need to be fixed in the wanpipe header files */
+#pragma warning(disable:4706)
+#pragma comment(lib, "Winmm")
+#endif
+
+#define FTDM_THREAD_STACKSIZE 240 * 1024
+#define FTDM_ENUM_NAMES(_NAME, _STRINGS) static const char * _NAME [] = { _STRINGS , NULL };
+#define FTDM_STR2ENUM_P(_FUNC1, _FUNC2, _TYPE) FT_DECLARE(_TYPE) _FUNC1 (const char *name); FT_DECLARE(const char *) _FUNC2 (_TYPE type);
+#define FTDM_STR2ENUM(_FUNC1, _FUNC2, _TYPE, _STRINGS, _MAX)	\
+	FT_DECLARE(_TYPE) _FUNC1 (const char *name)							\
+	{														\
+		int i;												\
+		_TYPE t = _MAX ;									\
+															\
+		for (i = 0; i < _MAX ; i++) {						\
+			if (!strcasecmp(name, _STRINGS[i])) {			\
+				t = (_TYPE) i;								\
+				break;										\
+			}												\
+		}													\
+															\
+		return t;											\
+	}														\
+	FT_DECLARE(const char *) _FUNC2 (_TYPE type)						\
+	{														\
+		if (type > _MAX) {									\
+			type = _MAX;									\
+		}													\
+		return _STRINGS[(int)type];							\
+	}														\
+	
+#define ftdm_true(expr)							\
+	(expr && ( !strcasecmp(expr, "yes") ||		\
+			   !strcasecmp(expr, "on") ||		\
+			   !strcasecmp(expr, "true") ||		\
+			   !strcasecmp(expr, "enabled") ||	\
+			   !strcasecmp(expr, "active") ||	\
+			   atoi(expr))) ? 1 : 0
+
+
+#include <time.h>
+#ifndef __WINDOWS__
+#include <sys/time.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef HAVE_STRINGS_H
+#include <strings.h>
+#endif
+#include <assert.h>
+#include "ftdm_types.h"
+#include "hashtable.h"
+#include "ftdm_config.h"
+#include "g711.h"
+#include "libteletone.h"
+#include "ftdm_buffer.h"
+#include "ftdm_threadmutex.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __WINDOWS__
+#define ftdm_sleep(x) Sleep(x)
+#else
+#define ftdm_sleep(x) usleep(x * 1000)
+#endif
+
+#ifdef NDEBUG
+#undef assert
+#define assert(_Expression)     ((void)(_Expression))
+#endif
+
+#define FTDM_MAX_CHANNELS_PHYSICAL_SPAN 32
+#define FTDM_MAX_PHYSICAL_SPANS_PER_LOGICAL_SPAN 32
+#define FTDM_MAX_CHANNELS_SPAN FTDM_MAX_CHANNELS_PHYSICAL_SPAN * FTDM_MAX_PHYSICAL_SPANS_PER_LOGICAL_SPAN
+#define FTDM_MAX_SPANS_INTERFACE 128
+
+#define FTDM_MAX_CHANNELS_GROUP 1024
+#define FTDM_MAX_GROUPS_INTERFACE FTDM_MAX_SPANS_INTERFACE
+
+#define GOTO_STATUS(label,st) status = st; goto label ;
+
+#define ftdm_copy_string(x,y,z) strncpy(x, y, z - 1) 
+#define ftdm_set_string(x,y) strncpy(x, y, sizeof(x)-1) 
+#define ftdm_strlen_zero(s) (!s || *s == '\0')
+#define ftdm_strlen_zero_buf(s) (*s == '\0')
+
+
+#define ftdm_channel_test_feature(obj, flag) ((obj)->features & flag)
+#define ftdm_channel_set_feature(obj, flag) (obj)->features |= (flag)
+#define ftdm_channel_clear_feature(obj, flag) (obj)->features &= ~(flag)
+#define ftdm_channel_set_member_locked(obj, _m, _v) ftdm_mutex_lock(obj->mutex); obj->_m = _v; ftdm_mutex_unlock(obj->mutex)
+
+/*!
+  \brief Test for the existance of a flag on an arbitary object
+  \command obj the object to test
+  \command flag the or'd list of flags to test
+  \return true value if the object has the flags defined
+*/
+#define ftdm_test_flag(obj, flag) ((obj)->flags & flag)
+#define ftdm_test_pflag(obj, flag) ((obj)->pflags & flag)
+#define ftdm_test_sflag(obj, flag) ((obj)->sflags & flag)
+
+
+#define ftdm_set_alarm_flag(obj, flag) (obj)->alarm_flags |= (flag)
+#define ftdm_clear_alarm_flag(obj, flag) (obj)->alarm_flags &= ~(flag)
+#define ftdm_test_alarm_flag(obj, flag) ((obj)->alarm_flags & flag)
+
+/*!
+  \brief Set a flag on an arbitrary object
+  \command obj the object to set the flags on
+  \command flag the or'd list of flags to set
+*/
+#define ftdm_set_flag(obj, flag) (obj)->flags |= (flag)
+#define ftdm_set_flag_locked(obj, flag) assert(obj->mutex != NULL);	\
+	ftdm_mutex_lock(obj->mutex);										\
+	(obj)->flags |= (flag);          	   	                        \
+	ftdm_mutex_unlock(obj->mutex);
+
+#define ftdm_set_pflag(obj, flag) (obj)->pflags |= (flag)
+#define ftdm_set_pflag_locked(obj, flag) assert(obj->mutex != NULL);	\
+	ftdm_mutex_lock(obj->mutex);										\
+	(obj)->pflags |= (flag);											\
+	ftdm_mutex_unlock(obj->mutex);
+
+#define ftdm_set_sflag(obj, flag) (obj)->sflags |= (flag)
+#define ftdm_set_sflag_locked(obj, flag) assert(obj->mutex != NULL);	\
+	ftdm_mutex_lock(obj->mutex);										\
+	(obj)->sflags |= (flag);											\
+	ftdm_mutex_unlock(obj->mutex);
+
+/*!
+  \brief Clear a flag on an arbitrary object while locked
+  \command obj the object to test
+  \command flag the or'd list of flags to clear
+*/
+#define ftdm_clear_flag(obj, flag) (obj)->flags &= ~(flag)
+
+#define ftdm_clear_flag_locked(obj, flag) assert(obj->mutex != NULL); ftdm_mutex_lock(obj->mutex); (obj)->flags &= ~(flag); ftdm_mutex_unlock(obj->mutex);
+
+#define ftdm_clear_pflag(obj, flag) (obj)->pflags &= ~(flag)
+
+#define ftdm_clear_pflag_locked(obj, flag) assert(obj->mutex != NULL); ftdm_mutex_lock(obj->mutex); (obj)->pflags &= ~(flag); ftdm_mutex_unlock(obj->mutex);
+
+#define ftdm_clear_sflag(obj, flag) (obj)->sflags &= ~(flag)
+
+#define ftdm_clear_sflag_locked(obj, flag) assert(obj->mutex != NULL); ftdm_mutex_lock(obj->mutex); (obj)->sflags &= ~(flag); ftdm_mutex_unlock(obj->mutex);
+
+
+#define ftdm_set_state_locked(obj, s) if ( obj->state == s ) {			\
+		ftdm_log(FTDM_LOG_WARNING, "Why bother changing state on %d:%d from %s to %s\n", obj->span_id, obj->chan_id, ftdm_channel_state2str(obj->state), ftdm_channel_state2str(s)); \
+	} else if (ftdm_test_flag(obj, FTDM_CHANNEL_READY)) {									\
+		ftdm_channel_state_t st = obj->state;											\
+		ftdm_channel_set_state(obj, s, 1);									\
+		if (obj->state == s) ftdm_log(FTDM_LOG_DEBUG, "Changing state on %d:%d from %s to %s\n", obj->span_id, obj->chan_id, ftdm_channel_state2str(st), ftdm_channel_state2str(s)); \
+		else ftdm_log(FTDM_LOG_WARNING, "VETO Changing state on %d:%d from %s to %s\n", obj->span_id, obj->chan_id, ftdm_channel_state2str(st), ftdm_channel_state2str(s)); \
+	}
+
+#define ftdm_set_state(obj, s) if ( obj->state == s ) {			\
+		ftdm_log(FTDM_LOG_WARNING, "Why bother changing state on %d:%d from %s to %s\n", obj->span_id, obj->chan_id, ftdm_channel_state2str(obj->state), ftdm_channel_state2str(s)); \
+	} else if (ftdm_test_flag(obj, FTDM_CHANNEL_READY)) {									\
+		ftdm_channel_state_t st = obj->state;											\
+		ftdm_channel_set_state(obj, s, 0);									\
+		if (obj->state == s) ftdm_log(FTDM_LOG_DEBUG, "Changing state on %d:%d from %s to %s\n", obj->span_id, obj->chan_id, ftdm_channel_state2str(st), ftdm_channel_state2str(s)); \
+		else ftdm_log(FTDM_LOG_WARNING, "VETO Changing state on %d:%d from %s to %s\n", obj->span_id, obj->chan_id, ftdm_channel_state2str(st), ftdm_channel_state2str(s)); \
+	}
+
+#ifdef _MSC_VER
+/* The while(0) below throws a conditional expression is constant warning */
+#pragma warning(disable:4127) 
+#endif
+
+#define ftdm_set_state_locked_wait(obj, s) 						\
+	do {										\
+		int __safety = 100;							\
+		ftdm_set_state_locked(obj, s);						\
+		while(__safety-- && ftdm_test_flag(obj, FTDM_CHANNEL_STATE_CHANGE)) {	\
+			ftdm_sleep(10);							\
+		}									\
+		if(!__safety) {								\
+			ftdm_log(FTDM_LOG_CRIT, "State change not completed\n");		\
+		}									\
+	} while(0);
+
+#define ftdm_wait_for_flag_cleared(obj, flag, time) 					\
+	do {										\
+		int __safety = time;							\
+		while(__safety-- && ftdm_test_flag(obj, flag)) { 			\
+			ftdm_mutex_unlock(obj->mutex);					\
+			ftdm_sleep(10);							\
+			ftdm_mutex_lock(obj->mutex);					\
+		}									\
+		if(!__safety) {								\
+			ftdm_log(FTDM_LOG_CRIT, "flag %d was never cleared\n", flag);	\
+		}									\
+	} while(0);
+
+#define ftdm_set_state_wait(obj, s) 						\
+	do {										\
+		ftdm_channel_set_state(obj, s, 0);					\
+		ftdm_wait_for_flag_cleared(obj, FTDM_CHANNEL_STATE_CHANGE, 100);     \
+	} while(0);
+
+
+typedef enum {
+	FTDM_STATE_CHANGE_FAIL,
+	FTDM_STATE_CHANGE_SUCCESS,
+	FTDM_STATE_CHANGE_SAME,
+} ftdm_state_change_result_t;
+
+#define ftdm_set_state_r(obj, s, l, r) if ( obj->state == s ) {	\
+		if (s != FTDM_CHANNEL_STATE_HANGUP) ftdm_log(FTDM_LOG_WARNING, "Why bother changing state on %d:%d from %s to %s\n", obj->span_id, obj->chan_id, ftdm_channel_state2str(obj->state), ftdm_channel_state2str(s)); r = FTDM_STATE_CHANGE_SAME; \
+	} else if (ftdm_test_flag(obj, FTDM_CHANNEL_READY)) {					\
+		int st = obj->state;											\
+		r = (ftdm_channel_set_state(obj, s, l) == FTDM_SUCCESS) ? FTDM_STATE_CHANGE_SUCCESS : FTDM_STATE_CHANGE_FAIL; \
+		if (obj->state == s) {ftdm_log(FTDM_LOG_DEBUG, "Changing state on %d:%d from %s to %s\n", obj->span_id, obj->chan_id, ftdm_channel_state2str(st), ftdm_channel_state2str(s));} \
+		else ftdm_log(FTDM_LOG_WARNING, "VETO Changing state on %d:%d from %s to %s\n", obj->span_id, obj->chan_id, ftdm_channel_state2str(st), ftdm_channel_state2str(s)); \
+	}
+
+
+#define ftdm_is_dtmf(key)  ((key > 47 && key < 58) || (key > 64 && key < 69) || (key > 96 && key < 101) || key == 35 || key == 42 || key == 87 || key == 119)
+
+/*!
+  \brief Copy flags from one arbitrary object to another
+  \command dest the object to copy the flags to
+  \command src the object to copy the flags from
+  \command flags the flags to copy
+*/
+#define ftdm_copy_flags(dest, src, flags) (dest)->flags &= ~(flags);	(dest)->flags |= ((src)->flags & (flags))
+
+struct ftdm_stream_handle {
+	ftdm_stream_handle_write_function_t write_function;
+	ftdm_stream_handle_raw_write_function_t raw_write_function;
+	void *data;
+	void *end;
+	ftdm_size_t data_size;
+	ftdm_size_t data_len;
+	ftdm_size_t alloc_len;
+	ftdm_size_t alloc_chunk;
+};
+
+
+FT_DECLARE_NONSTD(ftdm_status_t) ftdm_console_stream_raw_write(ftdm_stream_handle_t *handle, uint8_t *data, ftdm_size_t datalen);
+FT_DECLARE_NONSTD(ftdm_status_t) ftdm_console_stream_write(ftdm_stream_handle_t *handle, const char *fmt, ...);
+
+#define FTDM_CMD_CHUNK_LEN 1024
+#define FTDM_STANDARD_STREAM(s) memset(&s, 0, sizeof(s)); s.data = malloc(FTDM_CMD_CHUNK_LEN); \
+	assert(s.data);														\
+	memset(s.data, 0, FTDM_CMD_CHUNK_LEN);								\
+	s.end = s.data;														\
+	s.data_size = FTDM_CMD_CHUNK_LEN;									\
+	s.write_function = ftdm_console_stream_write;						\
+	s.raw_write_function = ftdm_console_stream_raw_write;				\
+	s.alloc_len = FTDM_CMD_CHUNK_LEN;									\
+	s.alloc_chunk = FTDM_CMD_CHUNK_LEN
+
+struct ftdm_event {
+	ftdm_event_type_t e_type;
+	uint32_t enum_id;
+	ftdm_channel_t *channel;
+	void *data;
+};
+
+typedef struct ftdm_queue ftdm_queue_t;
+typedef ftdm_status_t (*ftdm_queue_create_func_t)(ftdm_queue_t **queue, ftdm_size_t capacity);
+typedef ftdm_status_t (*ftdm_queue_enqueue_func_t)(ftdm_queue_t *queue, void *obj);
+typedef void *(*ftdm_queue_dequeue_func_t)(ftdm_queue_t *queue);
+typedef ftdm_status_t (*ftdm_queue_wait_func_t)(ftdm_queue_t *queue, int ms);
+typedef ftdm_status_t (*ftdm_queue_get_interrupt_func_t)(ftdm_queue_t *queue, ftdm_interrupt_t **interrupt);
+typedef ftdm_status_t (*ftdm_queue_destroy_func_t)(ftdm_queue_t **queue);
+typedef struct ftdm_queue_handler {
+	ftdm_queue_create_func_t create;
+	ftdm_queue_enqueue_func_t enqueue;
+	ftdm_queue_dequeue_func_t dequeue;
+	ftdm_queue_wait_func_t wait;
+	ftdm_queue_get_interrupt_func_t get_interrupt;
+	ftdm_queue_destroy_func_t destroy;
+} ftdm_queue_handler_t;
+FT_DECLARE_DATA extern ftdm_queue_handler_t g_ftdm_queue_handler;
+
+/*! brief create a new queue */
+#define ftdm_queue_create(queue, capacity) g_ftdm_queue_handler.create(queue, capacity)
+
+/*! Enqueue an object */
+#define ftdm_queue_enqueue(queue, obj) g_ftdm_queue_handler.enqueue(queue, obj)
+
+/*! dequeue an object from the queue */
+#define ftdm_queue_dequeue(queue) g_ftdm_queue_handler.dequeue(queue)
+
+/*! wait ms milliseconds for a queue to have available objects, -1 to wait forever */
+#define ftdm_queue_wait(queue, ms) g_ftdm_queue_handler.wait(queue, ms)
+
+/*! get the internal interrupt object (to wait for elements to be added from the outside bypassing ftdm_queue_wait) */
+#define ftdm_queue_get_interrupt(queue, ms) g_ftdm_queue_handler.get_interrupt(queue, ms)
+
+/*! destroy the queue */ 
+#define ftdm_queue_destroy(queue) g_ftdm_queue_handler.destroy(queue)
+
+
+#define FTDM_TOKEN_STRLEN 128
+#define FTDM_MAX_TOKENS 10
+
+static __inline__ char *ftdm_clean_string(char *s)
+{
+	char *p;
+
+	for (p = s; p && *p; p++) {
+		uint8_t x = (uint8_t) *p;
+		if (x < 32 || x > 127) {
+			*p = ' ';
+		}
+	}
+
+	return s;
+}
+
+struct ftdm_bitstream {
+	uint8_t *data;
+	uint32_t datalen;
+	uint32_t byte_index;
+	uint8_t bit_index;
+	int8_t endian;
+	uint8_t top;
+	uint8_t bot;
+	uint8_t ss;
+	uint8_t ssv;
+};
+
+struct ftdm_fsk_data_state {
+	dsp_fsk_handle_t *fsk1200_handle;
+	uint8_t init;
+	uint8_t *buf;
+	size_t bufsize;
+	ftdm_size_t blen;
+	ftdm_size_t bpos;
+	ftdm_size_t dlen;
+	ftdm_size_t ppos;
+	int checksum;
+};
+
+struct ftdm_fsk_modulator {
+	teletone_dds_state_t dds;
+	ftdm_bitstream_t bs;
+	uint32_t carrier_bits_start;
+	uint32_t carrier_bits_stop;
+	uint32_t chan_sieze_bits;
+	uint32_t bit_factor;
+	uint32_t bit_accum;
+	uint32_t sample_counter;
+	int32_t samples_per_bit;
+	int32_t est_bytes;
+	fsk_modem_types_t modem_type;
+	ftdm_fsk_data_state_t *fsk_data;
+	ftdm_fsk_write_sample_t write_sample_callback;
+	void *user_data;
+	int16_t sample_buffer[64];
+};
+
+/**
+ * Type Of Number (TON)
+ */
+typedef enum {
+	FTDM_TON_UNKNOWN = 0,
+	FTDM_TON_INTERNATIONAL,
+	FTDM_TON_NATIONAL,
+	FTDM_TON_NETWORK_SPECIFIC,
+	FTDM_TON_SUBSCRIBER_NUMBER,
+	FTDM_TON_ABBREVIATED_NUMBER,
+	FTDM_TON_RESERVED,
+	FTDM_TON_INVALID = 255
+} ftdm_ton_t;
+
+/**
+ * Numbering Plan Identification (NPI)
+ */
+typedef enum {
+	FTDM_NPI_UNKNOWN = 0,
+	FTDM_NPI_ISDN = 1,
+	FTDM_NPI_DATA = 3,
+	FTDM_NPI_TELEX = 4,
+	FTDM_NPI_NATIONAL = 8,
+	FTDM_NPI_PRIVATE = 9,
+	FTDM_NPI_RESERVED = 10,
+	FTDM_NPI_INVALID = 255
+} ftdm_npi_t;
+
+typedef struct {
+	char digits[25];
+	uint8_t type;
+	uint8_t plan;
+} ftdm_number_t;
+
+typedef enum {
+	FTDM_CALLER_STATE_DIALING,
+	FTDM_CALLER_STATE_SUCCESS,
+	FTDM_CALLER_STATE_FAIL
+} ftdm_caller_state_t;
+
+struct ftdm_caller_data {
+	char cid_date[8];
+	char cid_name[80];
+	ftdm_number_t cid_num;
+	ftdm_number_t ani;
+	ftdm_number_t dnis;
+	ftdm_number_t rdnis;
+	char aniII[25];
+	uint8_t screen;
+	uint8_t pres;
+	char collected[25];
+	int CRV;
+	int hangup_cause;	
+	uint8_t raw_data[1024];
+	uint32_t raw_data_len;
+	uint32_t flags;
+	ftdm_caller_state_t call_state;
+	uint32_t chan_id;
+};
+
+typedef enum {
+	FTDM_TYPE_NONE,
+	FTDM_TYPE_SPAN = 0xFF,
+	FTDM_TYPE_CHANNEL
+} ftdm_data_type_t;
+
+/* 2^8 table size, one for each byte value */
+#define FTDM_GAINS_TABLE_SIZE 256
+struct ftdm_channel {
+	ftdm_data_type_t data_type;
+	uint32_t span_id;
+	uint32_t chan_id;
+	uint32_t physical_span_id;
+	uint32_t physical_chan_id;
+	uint32_t rate;
+	uint32_t extra_id;
+	ftdm_chan_type_t type;
+	ftdm_socket_t sockfd;
+	uint32_t flags;
+	uint32_t pflags;
+	uint32_t sflags;
+	ftdm_alarm_flag_t alarm_flags;
+	ftdm_channel_feature_t features;
+	ftdm_codec_t effective_codec;
+	ftdm_codec_t native_codec;
+	uint32_t effective_interval;
+	uint32_t native_interval;
+	uint32_t packet_len;
+	ftdm_channel_state_t state;
+	ftdm_channel_state_t last_state;
+	ftdm_channel_state_t init_state;
+	ftdm_mutex_t *mutex;
+	teletone_dtmf_detect_state_t dtmf_detect;
+	uint32_t buffer_delay;
+	ftdm_event_t event_header;
+	char last_error[256];
+	fio_event_cb_t event_callback;
+	uint32_t skip_read_frames;
+	ftdm_buffer_t *dtmf_buffer;
+	ftdm_buffer_t *gen_dtmf_buffer;
+	ftdm_buffer_t *pre_buffer;
+	ftdm_buffer_t *digit_buffer;
+	ftdm_buffer_t *fsk_buffer;
+	ftdm_mutex_t *pre_buffer_mutex;
+	uint32_t dtmf_on;
+	uint32_t dtmf_off;
+	char *dtmf_hangup_buf;
+	teletone_generation_session_t tone_session;
+	ftdm_time_t last_event_time;
+	ftdm_time_t ring_time;
+	char tokens[FTDM_MAX_TOKENS+1][FTDM_TOKEN_STRLEN];
+	uint8_t needed_tones[FTDM_TONEMAP_INVALID];
+	uint8_t detected_tones[FTDM_TONEMAP_INVALID];
+	ftdm_tonemap_t last_detected_tone;	
+	uint32_t token_count;
+	char chan_name[128];
+	char chan_number[32];
+	ftdm_filehandle_t fds[2];
+	ftdm_fsk_data_state_t fsk;
+	uint8_t fsk_buf[80];
+	uint32_t ring_count;
+	void *mod_data;
+	void *call_data;
+	struct ftdm_caller_data caller_data;
+	struct ftdm_span *span;
+	struct ftdm_io_interface *fio;
+	ftdm_hash_t *variable_hash;
+	unsigned char rx_cas_bits;
+	uint32_t pre_buffer_size;
+	unsigned char rxgain_table[FTDM_GAINS_TABLE_SIZE];
+	unsigned char txgain_table[FTDM_GAINS_TABLE_SIZE];
+	float rxgain;
+	float txgain;
+};
+
+
+struct ftdm_sigmsg {
+	ftdm_signal_event_t event_id;
+	uint32_t chan_id;
+	uint32_t span_id;
+	ftdm_channel_t *channel;
+	void *raw_data;
+	uint32_t raw_data_len;
+};
+
+
+struct ftdm_span {
+	ftdm_data_type_t data_type;
+	char *name;
+	uint32_t span_id;
+	uint32_t chan_count;
+	ftdm_span_flag_t flags;
+	struct ftdm_io_interface *fio;
+	fio_event_cb_t event_callback;
+	ftdm_mutex_t *mutex;
+	ftdm_trunk_type_t trunk_type;
+	ftdm_analog_start_type_t start_type;
+	ftdm_signal_type_t signal_type;
+	void *signal_data;
+	fio_signal_cb_t signal_cb;
+	ftdm_event_t event_header;
+	char last_error[256];
+	char tone_map[FTDM_TONEMAP_INVALID+1][FTDM_TONEMAP_LEN];
+	teletone_tone_map_t tone_detect_map[FTDM_TONEMAP_INVALID+1];
+	teletone_multi_tone_t tone_finder[FTDM_TONEMAP_INVALID+1];
+	ftdm_channel_t *channels[FTDM_MAX_CHANNELS_SPAN+1];
+	fio_channel_outgoing_call_t outgoing_call;
+	fio_channel_set_sig_status_t set_channel_sig_status;
+	fio_channel_get_sig_status_t get_channel_sig_status;
+	fio_span_set_sig_status_t set_span_sig_status;
+	fio_span_get_sig_status_t get_span_sig_status;
+	fio_channel_request_t channel_request;
+	ftdm_span_start_t start;
+	ftdm_span_stop_t stop;
+	void *mod_data;
+	char *type;
+	char *dtmf_hangup;
+	size_t dtmf_hangup_len;
+	int suggest_chan_id;
+	ftdm_state_map_t *state_map;
+	ftdm_caller_data_t default_caller_data;
+	ftdm_queue_t *pendingchans;
+	struct ftdm_span *next;
+};
+
+struct ftdm_group {
+	char *name;
+	uint32_t group_id;
+	uint32_t chan_count;
+	ftdm_channel_t *channels[FTDM_MAX_CHANNELS_GROUP];
+	uint32_t last_used_index;
+	ftdm_mutex_t *mutex;
+	struct ftdm_group *next;
+};
+
+FT_DECLARE_DATA extern ftdm_logger_t ftdm_log;
+
+typedef enum {
+	FTDM_CRASH_NEVER = 0,
+	FTDM_CRASH_ON_ASSERT
+} ftdm_crash_policy_t;
+
+FT_DECLARE_DATA extern ftdm_crash_policy_t g_ftdm_crash_policy;
+
+typedef void *(*ftdm_malloc_func_t)(void *pool, ftdm_size_t len);
+typedef void *(*ftdm_calloc_func_t)(void *pool, ftdm_size_t elements, ftdm_size_t len);
+typedef void (*ftdm_free_func_t)(void *pool, void *ptr);
+typedef struct ftdm_memory_handler {
+	void *pool;
+	ftdm_malloc_func_t malloc;
+	ftdm_calloc_func_t calloc;
+	ftdm_free_func_t free;
+} ftdm_memory_handler_t;
+
+FT_DECLARE_DATA extern ftdm_memory_handler_t g_ftdm_mem_handler;
+
+struct ftdm_io_interface {
+	const char *name;
+	fio_configure_span_t configure_span;
+	fio_configure_t configure;
+	fio_open_t open;
+	fio_close_t close;
+	fio_channel_destroy_t channel_destroy;
+	fio_span_destroy_t span_destroy;
+	fio_get_alarms_t get_alarms;
+	fio_command_t command;
+	fio_wait_t wait;
+	fio_read_t read;
+	fio_write_t write;
+	fio_span_poll_event_t poll_event;
+	fio_span_next_event_t next_event;
+	fio_api_t api;
+};
+
+/*! \brief Override the default queue handler */
+FT_DECLARE(ftdm_status_t) ftdm_global_set_queue_handler(ftdm_queue_handler_t *handler);
+
+/*! \brief Duplicate string */
+FT_DECLARE(char *) ftdm_strdup(const char *str);
+FT_DECLARE(char *) ftdm_strndup(const char *str, ftdm_size_t inlen);
+
+FT_DECLARE(ftdm_size_t) ftdm_fsk_modulator_generate_bit(ftdm_fsk_modulator_t *fsk_trans, int8_t bit, int16_t *buf, ftdm_size_t buflen);
+FT_DECLARE(int32_t) ftdm_fsk_modulator_generate_carrier_bits(ftdm_fsk_modulator_t *fsk_trans, uint32_t bits);
+FT_DECLARE(void) ftdm_fsk_modulator_generate_chan_sieze(ftdm_fsk_modulator_t *fsk_trans);
+FT_DECLARE(void) ftdm_fsk_modulator_send_data(ftdm_fsk_modulator_t *fsk_trans);
+#define ftdm_fsk_modulator_send_all(_it) ftdm_fsk_modulator_generate_chan_sieze(_it); \
+	ftdm_fsk_modulator_generate_carrier_bits(_it, _it->carrier_bits_start); \
+	ftdm_fsk_modulator_send_data(_it); \
+	ftdm_fsk_modulator_generate_carrier_bits(_it, _it->carrier_bits_stop)
+
+FT_DECLARE(ftdm_status_t) ftdm_fsk_modulator_init(ftdm_fsk_modulator_t *fsk_trans,
+									fsk_modem_types_t modem_type,
+									uint32_t sample_rate,
+									ftdm_fsk_data_state_t *fsk_data,
+									float db_level,
+									uint32_t carrier_bits_start,
+									uint32_t carrier_bits_stop,
+									uint32_t chan_sieze_bits,
+									ftdm_fsk_write_sample_t write_sample_callback,
+									void *user_data);
+FT_DECLARE(int8_t) ftdm_bitstream_get_bit(ftdm_bitstream_t *bsp);
+FT_DECLARE(void) ftdm_bitstream_init(ftdm_bitstream_t *bsp, uint8_t *data, uint32_t datalen, ftdm_endian_t endian, uint8_t ss);
+FT_DECLARE(ftdm_status_t) ftdm_fsk_data_parse(ftdm_fsk_data_state_t *state, ftdm_size_t *type, char **data, ftdm_size_t *len);
+FT_DECLARE(ftdm_status_t) ftdm_fsk_demod_feed(ftdm_fsk_data_state_t *state, int16_t *data, size_t samples);
+FT_DECLARE(ftdm_status_t) ftdm_fsk_demod_destroy(ftdm_fsk_data_state_t *state);
+FT_DECLARE(int) ftdm_fsk_demod_init(ftdm_fsk_data_state_t *state, int rate, uint8_t *buf, size_t bufsize);
+FT_DECLARE(ftdm_status_t) ftdm_fsk_data_init(ftdm_fsk_data_state_t *state, uint8_t *data, uint32_t datalen);
+FT_DECLARE(ftdm_status_t) ftdm_fsk_data_add_mdmf(ftdm_fsk_data_state_t *state, ftdm_mdmf_type_t type, const uint8_t *data, uint32_t datalen);
+FT_DECLARE(ftdm_status_t) ftdm_fsk_data_add_checksum(ftdm_fsk_data_state_t *state);
+FT_DECLARE(ftdm_status_t) ftdm_fsk_data_add_sdmf(ftdm_fsk_data_state_t *state, const char *date, char *number);
+FT_DECLARE(ftdm_status_t) ftdm_channel_outgoing_call(ftdm_channel_t *ftdmchan);
+FT_DECLARE(ftdm_status_t) ftdm_channel_set_sig_status(ftdm_channel_t *ftdmchan, ftdm_signaling_status_t status);
+FT_DECLARE(ftdm_status_t) ftdm_channel_get_sig_status(ftdm_channel_t *ftdmchan, ftdm_signaling_status_t *status);
+FT_DECLARE(ftdm_status_t) ftdm_span_set_sig_status(ftdm_span_t *span, ftdm_signaling_status_t status);
+FT_DECLARE(ftdm_status_t) ftdm_span_get_sig_status(ftdm_span_t *span, ftdm_signaling_status_t *status);
+FT_DECLARE(void) ftdm_channel_rotate_tokens(ftdm_channel_t *ftdmchan);
+FT_DECLARE(void) ftdm_channel_clear_detected_tones(ftdm_channel_t *ftdmchan);
+FT_DECLARE(void) ftdm_channel_clear_needed_tones(ftdm_channel_t *ftdmchan);
+FT_DECLARE(ftdm_status_t) ftdm_channel_get_alarms(ftdm_channel_t *ftdmchan);
+FT_DECLARE(ftdm_status_t) ftdm_channel_send_fsk_data(ftdm_channel_t *ftdmchan, ftdm_fsk_data_state_t *fsk_data, float db_level);
+FT_DECLARE(ftdm_status_t) ftdm_channel_clear_token(ftdm_channel_t *ftdmchan, const char *token);
+FT_DECLARE(void) ftdm_channel_replace_token(ftdm_channel_t *ftdmchan, const char *old_token, const char *new_token);
+FT_DECLARE(ftdm_status_t) ftdm_channel_add_token(ftdm_channel_t *ftdmchan, char *token, int end);
+FT_DECLARE(ftdm_status_t) ftdm_channel_set_state(ftdm_channel_t *ftdmchan, ftdm_channel_state_t state, int lock);
+FT_DECLARE(ftdm_status_t) ftdm_span_load_tones(ftdm_span_t *span, const char *mapname);
+FT_DECLARE(ftdm_size_t) ftdm_channel_dequeue_dtmf(ftdm_channel_t *ftdmchan, char *dtmf, ftdm_size_t len);
+FT_DECLARE(ftdm_status_t) ftdm_channel_queue_dtmf(ftdm_channel_t *ftdmchan, const char *dtmf);
+FT_DECLARE(void) ftdm_channel_flush_dtmf(ftdm_channel_t *ftdmchan);
+FT_DECLARE(ftdm_time_t) ftdm_current_time_in_ms(void);
+FT_DECLARE(ftdm_status_t) ftdm_span_poll_event(ftdm_span_t *span, uint32_t ms);
+FT_DECLARE(ftdm_status_t) ftdm_span_next_event(ftdm_span_t *span, ftdm_event_t **event);
+FT_DECLARE(ftdm_status_t) ftdm_span_find(uint32_t id, ftdm_span_t **span);
+FT_DECLARE(ftdm_status_t) ftdm_span_create(ftdm_io_interface_t *fio, ftdm_span_t **span, const char *name);
+FT_DECLARE(ftdm_status_t) ftdm_span_close_all(void);
+FT_DECLARE(ftdm_status_t) ftdm_span_add_channel(ftdm_span_t *span, ftdm_socket_t sockfd, ftdm_chan_type_t type, ftdm_channel_t **chan);
+FT_DECLARE(ftdm_status_t) ftdm_span_set_event_callback(ftdm_span_t *span, fio_event_cb_t event_callback);
+FT_DECLARE(ftdm_status_t) ftdm_channel_add_to_group(const char* name, ftdm_channel_t* ftdmchan);
+FT_DECLARE(ftdm_status_t) ftdm_channel_remove_from_group(ftdm_group_t* group, ftdm_channel_t* ftdmchan);
+FT_DECLARE(ftdm_status_t) ftdm_group_find(uint32_t id, ftdm_group_t **group);
+FT_DECLARE(ftdm_status_t) ftdm_group_find_by_name(const char *name, ftdm_group_t **group);
+FT_DECLARE(ftdm_status_t) ftdm_group_create(ftdm_group_t **group, const char *name);
+FT_DECLARE(ftdm_status_t) ftdm_channel_set_event_callback(ftdm_channel_t *ftdmchan, fio_event_cb_t event_callback);
+FT_DECLARE(ftdm_status_t) ftdm_channel_open(uint32_t span_id, uint32_t chan_id, ftdm_channel_t **ftdmchan);
+FT_DECLARE(ftdm_status_t) ftdm_channel_open_chan(ftdm_channel_t *ftdmchan);
+FT_DECLARE(ftdm_status_t) ftdm_span_channel_use_count(ftdm_span_t *span, uint32_t *count);
+FT_DECLARE(ftdm_status_t) ftdm_group_channel_use_count(ftdm_group_t *group, uint32_t *count);
+FT_DECLARE(ftdm_status_t) ftdm_channel_open_by_span(uint32_t span_id, ftdm_direction_t direction, ftdm_caller_data_t *caller_data, ftdm_channel_t **ftdmchan);
+FT_DECLARE(ftdm_status_t) ftdm_channel_open_by_group(uint32_t group_id, ftdm_direction_t direction, ftdm_caller_data_t *caller_data, ftdm_channel_t **ftdmchan);
+FT_DECLARE(ftdm_status_t) ftdm_channel_close(ftdm_channel_t **ftdmchan);
+FT_DECLARE(ftdm_status_t) ftdm_channel_done(ftdm_channel_t *ftdmchan);
+FT_DECLARE(ftdm_status_t) ftdm_channel_use(ftdm_channel_t *ftdmchan);
+FT_DECLARE(ftdm_status_t) ftdm_channel_command(ftdm_channel_t *ftdmchan, ftdm_command_t command, void *obj);
+FT_DECLARE(ftdm_status_t) ftdm_channel_wait(ftdm_channel_t *ftdmchan, ftdm_wait_flag_t *flags, int32_t to);
+FT_DECLARE(ftdm_status_t) ftdm_channel_read(ftdm_channel_t *ftdmchan, void *data, ftdm_size_t *datalen);
+FT_DECLARE(void) ftdm_generate_sln_silence(int16_t *data, uint32_t samples, uint32_t divisor);
+FT_DECLARE(ftdm_status_t) ftdm_channel_write(ftdm_channel_t *ftdmchan, void *data, ftdm_size_t datasize, ftdm_size_t *datalen);
+FT_DECLARE(ftdm_status_t) ftdm_channel_add_var(ftdm_channel_t *ftdmchan, const char *var_name, const char *value);
+FT_DECLARE(const char *) ftdm_channel_get_var(ftdm_channel_t *ftdmchan, const char *var_name);
+FT_DECLARE(ftdm_status_t) ftdm_channel_clear_vars(ftdm_channel_t *ftdmchan);
+FT_DECLARE(ftdm_status_t) ftdm_global_init(void);
+FT_DECLARE(ftdm_status_t) ftdm_global_configuration(void);
+FT_DECLARE(ftdm_status_t) ftdm_global_destroy(void);
+FT_DECLARE(ftdm_status_t) ftdm_global_set_memory_handler(ftdm_memory_handler_t *handler);
+FT_DECLARE(void) ftdm_global_set_crash_policy(ftdm_crash_policy_t policy);
+FT_DECLARE(void) ftdm_global_set_logger(ftdm_logger_t logger);
+FT_DECLARE(void) ftdm_global_set_default_logger(int level);
+FT_DECLARE(uint32_t) ftdm_separate_string(char *buf, char delim, char **array, int arraylen);
+FT_DECLARE(void) print_bits(uint8_t *b, int bl, char *buf, int blen, int e, uint8_t ss);
+FT_DECLARE(void) print_hex_bytes(uint8_t *data, ftdm_size_t dlen, char *buf, ftdm_size_t blen);
+FT_DECLARE_NONSTD(int) ftdm_hash_equalkeys(void *k1, void *k2);
+FT_DECLARE_NONSTD(uint32_t) ftdm_hash_hashfromstring(void *ky);
+FT_DECLARE(uint32_t) ftdm_running(void);
+FT_DECLARE(ftdm_status_t) ftdm_channel_complete_state(ftdm_channel_t *ftdmchan);
+FT_DECLARE(ftdm_status_t) ftdm_channel_init(ftdm_channel_t *ftdmchan);
+FT_DECLARE(int) ftdm_load_modules(void);
+FT_DECLARE(ftdm_status_t) ftdm_unload_modules(void);
+FT_DECLARE(ftdm_status_t) ftdm_configure_span(const char *type, ftdm_span_t *span, fio_signal_cb_t sig_cb, ...);
+FT_DECLARE(ftdm_status_t) ftdm_configure_span_signaling(const char *type, ftdm_span_t *span, fio_signal_cb_t sig_cb, ftdm_conf_parameter_t *parameters);
+FT_DECLARE(ftdm_status_t) ftdm_span_start(ftdm_span_t *span);
+FT_DECLARE(ftdm_status_t) ftdm_span_stop(ftdm_span_t *span);
+FT_DECLARE(ftdm_status_t) ftdm_span_send_signal(ftdm_span_t *span, ftdm_sigmsg_t *sigmsg);
+FT_DECLARE(char *) ftdm_build_dso_path(const char *name, char *path, ftdm_size_t len);
+FT_DECLARE(ftdm_status_t) ftdm_global_add_io_interface(ftdm_io_interface_t *io_interface);
+FT_DECLARE(int) ftdm_load_module(const char *name);
+FT_DECLARE(int) ftdm_load_module_assume(const char *name);
+FT_DECLARE(ftdm_status_t) ftdm_span_find_by_name(const char *name, ftdm_span_t **span);
+FT_DECLARE(char *) ftdm_api_execute(const char *type, const char *cmd);
+FT_DECLARE(int) ftdm_vasprintf(char **ret, const char *fmt, va_list ap);
+FT_DECLARE(ftdm_status_t) ftdm_channel_set_caller_data(ftdm_channel_t *ftdmchan, ftdm_caller_data_t *caller_data);
+
+FIO_CODEC_FUNCTION(fio_slin2ulaw);
+FIO_CODEC_FUNCTION(fio_ulaw2slin);
+FIO_CODEC_FUNCTION(fio_slin2alaw);
+FIO_CODEC_FUNCTION(fio_alaw2slin);
+FIO_CODEC_FUNCTION(fio_ulaw2alaw);
+FIO_CODEC_FUNCTION(fio_alaw2ulaw);
+
+#ifdef DEBUG_LOCKS
+#define ftdm_mutex_lock(_x) printf("++++++lock %s:%d\n", __FILE__, __LINE__) && _ftdm_mutex_lock(_x)
+#define ftdm_mutex_trylock(_x) printf("++++++try %s:%d\n", __FILE__, __LINE__) && _ftdm_mutex_trylock(_x)
+#define ftdm_mutex_unlock(_x) printf("------unlock %s:%d\n", __FILE__, __LINE__) && _ftdm_mutex_unlock(_x)
+#else 
+#define ftdm_mutex_lock(_x) _ftdm_mutex_lock(_x)
+#define ftdm_mutex_trylock(_x) _ftdm_mutex_trylock(_x)
+#define ftdm_mutex_unlock(_x) _ftdm_mutex_unlock(_x)
+#endif
+
+/*!
+  \brief Assert condition
+*/
+#define ftdm_assert(assertion, msg) \
+	if (!(assertion)) { \
+		ftdm_log(FTDM_LOG_CRIT, msg); \
+		if (g_ftdm_crash_policy & FTDM_CRASH_ON_ASSERT) { \
+			ftdm_abort();  \
+		} \
+	}
+
+/*!
+  \brief Assert condition and return
+*/
+#define ftdm_assert_return(assertion, retval, msg) \
+	if (!(assertion)) { \
+		ftdm_log(FTDM_LOG_CRIT, msg); \
+		if (g_ftdm_crash_policy & FTDM_CRASH_ON_ASSERT) { \
+			ftdm_abort();  \
+		} else { \
+			return retval; \
+		} \
+	}
+
+/*!
+  \brief Allocate uninitialized memory
+  \command chunksize the chunk size
+*/
+#define ftdm_malloc(chunksize) g_ftdm_mem_handler.malloc(g_ftdm_mem_handler.pool, chunksize)
+
+/*!
+  \brief Allocate initialized memory
+  \command chunksize the chunk size
+*/
+#define ftdm_calloc(elements, chunksize) g_ftdm_mem_handler.calloc(g_ftdm_mem_handler.pool, elements, chunksize)
+
+/*!
+  \brief Free chunk of memory
+  \command chunksize the chunk size
+*/
+#define ftdm_free(chunk) g_ftdm_mem_handler.free(g_ftdm_mem_handler.pool, chunk)
+
+/*!
+  \brief Free a pointer and set it to NULL unless it already is NULL
+  \command it the pointer
+*/
+#define ftdm_safe_free(it) if (it) { ftdm_free(it); it = NULL; }
+
+/*!
+  \brief Socket the given socket
+  \command it the socket
+*/
+#define ftdm_socket_close(it) if (it > -1) { close(it); it = -1;}
+
+#define ftdm_array_len(array) sizeof(array)/sizeof(array[0])
+
+static __inline__ void ftdm_abort(void)
+{
+#ifdef __cplusplus
+	::abort();
+#else
+	abort();
+#endif
+}
+
+static __inline__ void ftdm_set_state_all(ftdm_span_t *span, ftdm_channel_state_t state)
+{
+	uint32_t j;
+	ftdm_mutex_lock(span->mutex);
+	for(j = 1; j <= span->chan_count; j++) {
+		ftdm_set_state_locked((span->channels[j]), state);
+	}
+	ftdm_mutex_unlock(span->mutex);
+}
+
+static __inline__ int ftdm_check_state_all(ftdm_span_t *span, ftdm_channel_state_t state)
+{
+	uint32_t j;
+	for(j = 1; j <= span->chan_count; j++) {
+		if (span->channels[j]->state != state || ftdm_test_flag(span->channels[j], FTDM_CHANNEL_STATE_CHANGE)) {
+			return 0;
+		}
+	}
+
+	return 1;
+}
+
+static __inline__ void ftdm_set_flag_all(ftdm_span_t *span, uint32_t flag)
+{
+	uint32_t j;
+	ftdm_mutex_lock(span->mutex);
+	for(j = 1; j <= span->chan_count; j++) {
+		ftdm_set_flag_locked((span->channels[j]), flag);
+	}
+	ftdm_mutex_unlock(span->mutex);
+}
+
+static __inline__ void ftdm_clear_flag_all(ftdm_span_t *span, uint32_t flag)
+{
+	uint32_t j;
+	ftdm_mutex_lock(span->mutex);
+	for(j = 1; j <= span->chan_count; j++) {
+		ftdm_clear_flag_locked((span->channels[j]), flag);
+	}
+	ftdm_mutex_unlock(span->mutex);
+}
+
+#ifdef __cplusplus
+} /* extern C */
+#endif
+
+#endif
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */

Added: freeswitch/trunk/libs/freetdm/src/include/fsk.h (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/include/fsk.h	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/include/fsk.h	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,121 @@
+/*
+ *	bell202.h
+ *
+ *	Copyright (c) 2005 Robert Krten.  All Rights Reserved.
+ *
+ *	Redistribution and use in source and binary forms, with or without
+ *	modification, are permitted provided that the following conditions
+ *	are met:
+ *
+ *	1. Redistributions of source code must retain the above copyright
+ *	   notice, this list of conditions and the following disclaimer.
+ *	2. Redistributions in binary form must reproduce the above copyright
+ *	   notice, this list of conditions and the following disclaimer in the
+ *	   documentation and/or other materials provided with the distribution.
+ *
+ *	THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
+ *	ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ *	IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ *	ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE
+ *	FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ *	DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ *	OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ *	HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ *	LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ *	OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ *	SUCH DAMAGE.
+ *
+ *	This module contains the manifest constants and declarations for
+ *	the Bell-202 1200 baud FSK modem.
+ *
+ *	2005 03 20	R. Krten		created
+*/
+
+#ifndef	__FSK_H__
+#define	__FSK_H__
+#include "uart.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct {
+    int freq_space;		/* Frequency of the 0 bit				*/
+    int freq_mark;		/* Frequency of the 1 bit				*/
+    int baud_rate;		/* baud rate for the modem				*/
+} fsk_modem_definition_t;
+
+/* Must be kept in sync with fsk_modem_definitions array in fsk.c	*/
+/* V.23 definitions: http://www.itu.int/rec/recommendation.asp?type=folders&lang=e&parent=T-REC-V.23 */
+typedef enum {
+    FSK_V23_FORWARD_MODE1 = 0,	/* Maximum 600 bps for long haul	*/
+    FSK_V23_FORWARD_MODE2,		/* Standard 1200 bps V.23			*/
+    FSK_V23_BACKWARD,			/* 75 bps return path for V.23		*/
+    FSK_BELL202					/* Bell 202 half-duplex 1200 bps	*/
+} fsk_modem_types_t;
+
+typedef enum {
+	FSK_STATE_CHANSEIZE = 0,
+	FSK_STATE_CARRIERSIG,
+	FSK_STATE_DATA
+} fsk_state_t;
+
+typedef struct dsp_fsk_attr_s
+{
+	int					sample_rate;					/* sample rate in HZ */
+	bithandler_func_t	bithandler;						/* bit handler */
+	void				*bithandler_arg;				/* arbitrary ID passed to bithandler as first argument */
+	bytehandler_func_t	bytehandler;					/* byte handler */
+	void				*bytehandler_arg;				/* arbitrary ID passed to bytehandler as first argument */
+}	dsp_fsk_attr_t;
+
+typedef struct
+{
+	fsk_state_t			state;
+	dsp_fsk_attr_t		attr;							/* attributes structure */
+	double				*correlates[4];					/* one for each of sin/cos for mark/space */
+	int					corrsize;						/* correlate size (also number of samples in ring buffer) */
+	double				*buffer;						/* sample ring buffer */
+	int					ringstart;						/* ring buffer start offset */
+	double				cellpos;						/* bit cell position */
+	double				celladj;						/* bit cell adjustment for each sample */
+	int					previous_bit;					/* previous bit (for detecting a transition to sync-up cell position) */
+	int					current_bit;					/* current bit */
+	int					last_bit;
+	int					downsampling_count;				/* number of samples to skip */
+	int					current_downsample;				/* current skip count */
+	int					conscutive_state_bits;			/* number of bits in a row that matches the pattern for the current state */
+}	dsp_fsk_handle_t;
+
+/*
+ *	Function prototypes
+ *
+ *	General calling order is:
+ *		a) create the attributes structure (dsp_fsk_attr_init)
+ *		b) initialize fields in the attributes structure (dsp_fsk_attr_set_*)
+ *		c) create a Bell-202 handle (dsp_fsk_create)
+ *		d) feed samples through the handler (dsp_fsk_sample)
+*/
+
+void					dsp_fsk_attr_init(dsp_fsk_attr_t *attributes);
+
+bithandler_func_t		dsp_fsk_attr_get_bithandler(dsp_fsk_attr_t *attributes, void **bithandler_arg);
+void					dsp_fsk_attr_set_bithandler(dsp_fsk_attr_t *attributes, bithandler_func_t bithandler, void *bithandler_arg);
+bytehandler_func_t		dsp_fsk_attr_get_bytehandler(dsp_fsk_attr_t *attributes, void **bytehandler_arg);
+void					dsp_fsk_attr_set_bytehandler(dsp_fsk_attr_t *attributes, bytehandler_func_t bytehandler, void *bytehandler_arg);
+int						dsp_fsk_attr_get_samplerate(dsp_fsk_attr_t *attributes);
+int						dsp_fsk_attr_set_samplerate(dsp_fsk_attr_t *attributes, int samplerate);
+
+dsp_fsk_handle_t *	dsp_fsk_create(dsp_fsk_attr_t *attributes);
+void					dsp_fsk_destroy(dsp_fsk_handle_t **handle);
+
+void					dsp_fsk_sample(dsp_fsk_handle_t *handle, double normalized_sample);
+
+extern fsk_modem_definition_t fsk_modem_definitions[];
+
+#ifdef __cplusplus
+} /* extern C */
+#endif
+
+#endif	
+

Added: freeswitch/trunk/libs/freetdm/src/include/ftdm_buffer.h (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/include/ftdm_buffer.h	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/include/ftdm_buffer.h	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) 2007, Anthony Minessale II
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FTDM_BUFFER_H
+#define FTDM_BUFFER_H
+
+#include "freetdm.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @defgroup ftdm_buffer Buffer Routines
+ * @ingroup buffer
+ * The purpose of this module is to make a plain buffering interface that can be used for read/write buffers
+ * throughout the application.
+ * @{
+ */
+struct ftdm_buffer;
+typedef struct ftdm_buffer ftdm_buffer_t;
+
+/*! \brief Allocate a new dynamic ftdm_buffer 
+ * \param buffer returned pointer to the new buffer
+ * \param blocksize length to realloc by as data is added
+ * \param start_len ammount of memory to reserve initially
+ * \param max_len length the buffer is allowed to grow to
+ * \return status
+ */
+FT_DECLARE(ftdm_status_t) ftdm_buffer_create(ftdm_buffer_t **buffer, ftdm_size_t blocksize, ftdm_size_t start_len, ftdm_size_t max_len);
+
+/*! \brief Get the length of a ftdm_buffer_t 
+ * \param buffer any buffer of type ftdm_buffer_t
+ * \return int size of the buffer.
+ */
+FT_DECLARE(ftdm_size_t) ftdm_buffer_len(ftdm_buffer_t *buffer);
+
+/*! \brief Get the freespace of a ftdm_buffer_t 
+ * \param buffer any buffer of type ftdm_buffer_t
+ * \return int freespace in the buffer.
+ */
+FT_DECLARE(ftdm_size_t) ftdm_buffer_freespace(ftdm_buffer_t *buffer);
+
+/*! \brief Get the in use amount of a ftdm_buffer_t 
+ * \param buffer any buffer of type ftdm_buffer_t
+ * \return int ammount of buffer curently in use
+ */
+FT_DECLARE(ftdm_size_t) ftdm_buffer_inuse(ftdm_buffer_t *buffer);
+
+/*! \brief Read data from a ftdm_buffer_t up to the ammount of datalen if it is available.  Remove read data from buffer. 
+ * \param buffer any buffer of type ftdm_buffer_t
+ * \param data pointer to the read data to be returned
+ * \param datalen amount of data to be returned
+ * \return int ammount of data actually read
+ */
+FT_DECLARE(ftdm_size_t) ftdm_buffer_read(ftdm_buffer_t *buffer, void *data, ftdm_size_t datalen);
+
+/*! \brief Read data endlessly from a ftdm_buffer_t 
+ * \param buffer any buffer of type ftdm_buffer_t
+ * \param data pointer to the read data to be returned
+ * \param datalen amount of data to be returned
+ * \return int ammount of data actually read
+ * \note Once you have read all the data from the buffer it will loop around.
+ */
+FT_DECLARE(ftdm_size_t) ftdm_buffer_read_loop(ftdm_buffer_t *buffer, void *data, ftdm_size_t datalen);
+
+/*! \brief Assign a number of loops to read
+ * \param buffer any buffer of type ftdm_buffer_t
+ * \param loops the number of loops (-1 for infinite)
+ */
+FT_DECLARE(void) ftdm_buffer_set_loops(ftdm_buffer_t *buffer, int32_t loops);
+
+/*! \brief Write data into a ftdm_buffer_t up to the length of datalen
+ * \param buffer any buffer of type ftdm_buffer_t
+ * \param data pointer to the data to be written
+ * \param datalen amount of data to be written
+ * \return int amount of buffer used after the write, or 0 if no space available
+ */
+FT_DECLARE(ftdm_size_t) ftdm_buffer_write(ftdm_buffer_t *buffer, const void *data, ftdm_size_t datalen);
+
+/*! \brief Remove data from the buffer
+ * \param buffer any buffer of type ftdm_buffer_t
+ * \param datalen amount of data to be removed
+ * \return int size of buffer, or 0 if unable to toss that much data
+ */
+FT_DECLARE(ftdm_size_t) ftdm_buffer_toss(ftdm_buffer_t *buffer, ftdm_size_t datalen);
+
+/*! \brief Remove all data from the buffer
+ * \param buffer any buffer of type ftdm_buffer_t
+ */
+FT_DECLARE(void) ftdm_buffer_zero(ftdm_buffer_t *buffer);
+
+/*! \brief Destroy the buffer
+ * \param buffer buffer to destroy
+ * \note only neccessary on dynamic buffers (noop on pooled ones)
+ */
+FT_DECLARE(void) ftdm_buffer_destroy(ftdm_buffer_t **buffer);
+
+/*! \brief Seek to offset from the beginning of the buffer
+ * \param buffer buffer to seek
+ * \param datalen offset in bytes
+ * \return new position
+ */
+FT_DECLARE(ftdm_size_t) ftdm_buffer_seek(ftdm_buffer_t *buffer, ftdm_size_t datalen);
+
+/** @} */
+
+FT_DECLARE(ftdm_size_t) ftdm_buffer_zwrite(ftdm_buffer_t *buffer, const void *data, ftdm_size_t datalen);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */

Added: freeswitch/trunk/libs/freetdm/src/include/ftdm_config.h (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/include/ftdm_config.h	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/include/ftdm_config.h	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 2007, Anthony Minessale II
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @defgroup config Config File Parser
+ * @ingroup config
+ * This module implements a basic interface and file format parser
+ * 
+ * <pre>
+ *
+ * EXAMPLE 
+ * 
+ * [category1]
+ * var1 => val1
+ * var2 => val2
+ * \# lines that begin with \# are comments
+ * \#var3 => val3
+ * </pre>
+ * @{
+ */
+
+#ifndef FTDM_CONFIG_H
+#define FTDM_CONFIG_H
+
+#include "freetdm.h"
+#define FTDM_URL_SEPARATOR "://"
+
+
+#ifdef WIN32
+#define FTDM_PATH_SEPARATOR "\\"
+#ifndef FTDM_CONFIG_DIR
+#define FTDM_CONFIG_DIR "c:\\freetdm"
+#endif
+#define ftdm_is_file_path(file) (*(file +1) == ':' || *file == '/' || strstr(file, SWITCH_URL_SEPARATOR))
+#else
+#define FTDM_PATH_SEPARATOR "/"
+#ifndef FTDM_CONFIG_DIR
+#define FTDM_CONFIG_DIR "/etc/freetdm"
+#endif
+#define ftdm_is_file_path(file) ((*file == '/') || strstr(file, SWITCH_URL_SEPARATOR))
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct ftdm_config ftdm_config_t;
+
+/*! \brief A simple file handle representing an open configuration file **/
+struct ftdm_config {
+	/*! FILE stream buffer to the opened file */
+	FILE *file;
+	/*! path to the file */
+	char path[512];
+	/*! current category */
+	char category[256];
+	/*! current section */
+	char section[256];
+	/*! buffer of current line being read */
+	char buf[1024];
+	/*! current line number in file */
+	int lineno;
+	/*! current category number in file */
+	int catno;
+	/*! current section number in file */
+	int sectno;
+
+	int lockto;
+};
+
+/*!
+  \brief Open a configuration file
+  \param cfg (ftdm_config_t *) config handle to use
+  \param file_path path to the file
+  \return 1 (true) on success 0 (false) on failure
+*/
+int ftdm_config_open_file(ftdm_config_t * cfg, const char *file_path);
+
+/*!
+  \brief Close a previously opened configuration file
+  \param cfg (ftdm_config_t *) config handle to use
+*/
+void ftdm_config_close_file(ftdm_config_t * cfg);
+
+/*!
+  \brief Retrieve next name/value pair from configuration file
+  \param cfg (ftdm_config_t *) config handle to use
+  \param var pointer to aim at the new variable name
+  \param val pointer to aim at the new value
+*/
+int ftdm_config_next_pair(ftdm_config_t * cfg, char **var, char **val);
+
+/*!
+  \brief Retrieve the CAS bits from a configuration string value
+  \param strvalue pointer to the configuration string value (expected to be in format whatever:xxxx)
+  \param outbits pointer to aim at the CAS bits
+*/
+FT_DECLARE (int) ftdm_config_get_cas_bits(char *strvalue, unsigned char *outbits);
+
+#ifdef __cplusplus
+}
+#endif
+
+/** @} */
+#endif
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */

Added: freeswitch/trunk/libs/freetdm/src/include/ftdm_dso.h (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/include/ftdm_dso.h	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/include/ftdm_dso.h	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,51 @@
+/* 
+ * Cross Platform dso/dll load abstraction
+ * Copyright(C) 2008 Michael Jerris
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so.
+ *
+ * This work is provided under this license on an "as is" basis, without warranty of any kind,
+ * either expressed or implied, including, without limitation, warranties that the covered code
+ * is free of defects, merchantable, fit for a particular purpose or non-infringing. The entire
+ * risk as to the quality and performance of the covered code is with you. Should any covered
+ * code prove defective in any respect, you (not the initial developer or any other contributor)
+ * assume the cost of any necessary servicing, repair or correction. This disclaimer of warranty
+ * constitutes an essential part of this license. No use of any covered code is authorized hereunder
+ * except under this disclaimer. 
+ *
+ */
+
+
+#ifndef _FTDM_DSO_H
+#define _FTDM_DSO_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef void (*ftdm_func_ptr_t) (void);
+typedef void * ftdm_dso_lib_t;
+
+FT_DECLARE(void) ftdm_dso_destroy(ftdm_dso_lib_t *lib);
+FT_DECLARE(ftdm_dso_lib_t) ftdm_dso_open(const char *path, char **err);
+FT_DECLARE(void *) ftdm_dso_func_sym(ftdm_dso_lib_t lib, const char *sym, char **err);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4
+ */
+

Added: freeswitch/trunk/libs/freetdm/src/include/ftdm_m3ua.h (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/include/ftdm_m3ua.h	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/include/ftdm_m3ua.h	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,134 @@
+/*
+ *  ftdm_m3ua.h
+ *  freetdm
+ *
+ *  Created by Shane Burrell on 4/3/08.
+ *  Copyright 2008 Shane Burrell. All rights reserved.
+ *
+ * Copyright (c) 2007, Anthony Minessale II, Nenad Corbic
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+//#include "m3ua_client.h"
+#include "freetdm.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+enum	e_sigboost_event_id_values
+{
+	SIGBOOST_EVENT_CALL_START			= 0x80, /*128*/
+	SIGBOOST_EVENT_CALL_START_ACK			= 0x81, /*129*/
+	SIGBOOST_EVENT_CALL_START_NACK			= 0x82, /*130*/
+	SIGBOOST_EVENT_CALL_START_NACK_ACK		= 0x83, /*131*/
+	SIGBOOST_EVENT_CALL_ANSWERED			= 0x84, /*132*/
+	SIGBOOST_EVENT_CALL_STOPPED			= 0x85, /*133*/
+	SIGBOOST_EVENT_CALL_STOPPED_ACK			= 0x86, /*134*/
+	SIGBOOST_EVENT_SYSTEM_RESTART			= 0x87, /*135*/
+	SIGBOOST_EVENT_SYSTEM_RESTART_ACK		= 0x88, /*136*/
+	/* Following IDs are ss7boost to sangoma_mgd only. */
+	SIGBOOST_EVENT_HEARTBEAT			= 0x89, /*137*/
+	SIGBOOST_EVENT_INSERT_CHECK_LOOP		= 0x8a, /*138*/
+	SIGBOOST_EVENT_REMOVE_CHECK_LOOP		= 0x8b, /*139*/
+	SIGBOOST_EVENT_AUTO_CALL_GAP_ABATE		= 0x8c, /*140*/
+};
+enum	e_sigboost_release_cause_values
+{
+	SIGBOOST_RELEASE_CAUSE_UNDEFINED		= 0,
+	SIGBOOST_RELEASE_CAUSE_NORMAL			= 16,
+	SIGBOOST_RELEASE_CAUSE_BUSY			= 17,
+	/* probable elimination */
+	//SIGBOOST_RELEASE_CAUSE_BUSY			= 0x91, /* 145 */
+	//SIGBOOST_RELEASE_CAUSE_CALLED_NOT_EXIST	= 0x92, /* 146 */
+	//SIGBOOST_RELEASE_CAUSE_CIRCUIT_RESET		= 0x93, /* 147 */
+	//SIGBOOST_RELEASE_CAUSE_NOANSWER		= 0x94, /* 148 */
+};
+
+enum	e_sigboost_call_setup_ack_nack_cause_values
+{
+	SIGBOOST_CALL_SETUP_NACK_ALL_CKTS_BUSY		= 117, /* unused Q.850 value */
+	SIGBOOST_CALL_SETUP_NACK_TEST_CKT_BUSY		= 118, /* unused Q.850 value */
+	SIGBOOST_CALL_SETUP_NACK_INVALID_NUMBER		= 28,
+	/* probable elimination */
+	//SIGBOOST_CALL_SETUP_RESERVED			= 0x00,
+	//SIGBOOST_CALL_SETUP_CIRCUIT_RESET		= 0x10,
+	//SIGBOOST_CALL_SETUP_NACK_CKT_START_TIMEOUT	= 0x11,
+	//SIGBOOST_CALL_SETUP_NACK_AUTO_CALL_GAP	= 0x17,
+};
+typedef enum {
+	M3UA_SPAN_SIGNALING_M3UA,
+	M3UA_SPAN_SIGNALING_SS7BOX,
+	
+} M3UA_TSpanSignaling;
+#define M3UA_SPAN_STRINGS "M3UA", "SS7BOX"
+FTDM_STR2ENUM_P(m3ua_str2span, m3ua_span2str, M3UA_TSpanSignaling)
+
+
+
+typedef enum {
+	FTDM_M3UA_RUNNING = (1 << 0)
+} ftdm_m3uat_flag_t;
+
+/*typedef struct m3ua_data {
+	m3uac_connection_t mcon;
+	m3uac_connection_t pcon;
+	fio_signal_cb_t signal_cb;
+	uint32_t flags;
+} m3ua_data_t;
+
+*/
+/*typedef struct mu3a_link {
+	ss7bc_connection_t mcon;
+	ss7bc_connection_t pcon;
+	fio_signal_cb_t signal_cb;
+	uint32_t flags;
+} ftdm_m3ua_data_t;
+*/
+
+ftdm_status_t m3ua_init(ftdm_io_interface_t **zint);
+ftdm_status_t m3ua_destroy(void);
+ftdm_status_t m3ua_start(ftdm_span_t *span);
+
+#ifdef __cplusplus
+}
+#endif
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
+

Added: freeswitch/trunk/libs/freetdm/src/include/ftdm_threadmutex.h (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/include/ftdm_threadmutex.h	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/include/ftdm_threadmutex.h	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,68 @@
+/* 
+ * Cross Platform Thread/Mutex abstraction
+ * Copyright(C) 2007 Michael Jerris
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so.
+ *
+ * This work is provided under this license on an "as is" basis, without warranty of any kind,
+ * either expressed or implied, including, without limitation, warranties that the covered code
+ * is free of defects, merchantable, fit for a particular purpose or non-infringing. The entire
+ * risk as to the quality and performance of the covered code is with you. Should any covered
+ * code prove defective in any respect, you (not the initial developer or any other contributor)
+ * assume the cost of any necessary servicing, repair or correction. This disclaimer of warranty
+ * constitutes an essential part of this license. No use of any covered code is authorized hereunder
+ * except under this disclaimer. 
+ *
+ * Contributors: 
+ *
+ * Moises Silva <moy@sangoma.com>
+ *
+ */
+
+
+#ifndef _FTDM_THREADMUTEX_H
+#define _FTDM_THREADMUTEX_H
+
+#include "freetdm.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+typedef struct ftdm_mutex ftdm_mutex_t;
+typedef struct ftdm_thread ftdm_thread_t;
+typedef struct ftdm_interrupt ftdm_interrupt_t;
+typedef void *(*ftdm_thread_function_t) (ftdm_thread_t *, void *);
+
+FT_DECLARE(ftdm_status_t) ftdm_thread_create_detached(ftdm_thread_function_t func, void *data);
+FT_DECLARE(ftdm_status_t) ftdm_thread_create_detached_ex(ftdm_thread_function_t func, void *data, ftdm_size_t stack_size);
+FT_DECLARE(void) ftdm_thread_override_default_stacksize(ftdm_size_t size);
+FT_DECLARE(ftdm_status_t) ftdm_mutex_create(ftdm_mutex_t **mutex);
+FT_DECLARE(ftdm_status_t) ftdm_mutex_destroy(ftdm_mutex_t **mutex);
+FT_DECLARE(ftdm_status_t) _ftdm_mutex_lock(ftdm_mutex_t *mutex);
+FT_DECLARE(ftdm_status_t) _ftdm_mutex_trylock(ftdm_mutex_t *mutex);
+FT_DECLARE(ftdm_status_t) _ftdm_mutex_unlock(ftdm_mutex_t *mutex);
+FT_DECLARE(ftdm_status_t) ftdm_interrupt_create(ftdm_interrupt_t **cond, ftdm_socket_t device);
+FT_DECLARE(ftdm_status_t) ftdm_interrupt_destroy(ftdm_interrupt_t **cond);
+FT_DECLARE(ftdm_status_t) ftdm_interrupt_signal(ftdm_interrupt_t *cond);
+FT_DECLARE(ftdm_status_t) ftdm_interrupt_wait(ftdm_interrupt_t *cond, int ms);
+FT_DECLARE(ftdm_status_t) ftdm_interrupt_multiple_wait(ftdm_interrupt_t *interrupts[], ftdm_size_t size, int ms);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
+

Added: freeswitch/trunk/libs/freetdm/src/include/ftdm_types.h (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/include/ftdm_types.h	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/include/ftdm_types.h	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,708 @@
+/*
+ * Copyright (c) 2007, Anthony Minessale II
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Contributors: 
+ *
+ * Moises Silva <moy@sangoma.com>
+ *
+ */
+
+#ifndef FTDM_TYPES_H
+#define FTDM_TYPES_H
+#include "fsk.h"
+
+#define FTDM_INVALID_SOCKET -1
+#ifdef WIN32
+#include <windows.h>
+typedef HANDLE ftdm_socket_t;
+typedef unsigned __int64 uint64_t;
+typedef unsigned __int32 uint32_t;
+typedef unsigned __int16 uint16_t;
+typedef unsigned __int8 uint8_t;
+typedef __int64 int64_t;
+typedef __int32 int32_t;
+typedef __int16 int16_t;
+typedef __int8 int8_t;
+typedef intptr_t ftdm_ssize_t;
+typedef int ftdm_filehandle_t;
+#else
+#include <stdint.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <stdarg.h>
+typedef int ftdm_socket_t;
+typedef ssize_t ftdm_ssize_t;
+typedef int ftdm_filehandle_t;
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+#define TAG_END NULL
+
+typedef size_t ftdm_size_t;
+struct ftdm_io_interface;
+
+#define FTDM_COMMAND_OBJ_INT *((int *)obj)
+#define FTDM_COMMAND_OBJ_CHAR_P (char *)obj
+#define FTDM_COMMAND_OBJ_FLOAT *(float *)obj
+#define FTDM_FSK_MOD_FACTOR 0x10000
+#define FTDM_DEFAULT_DTMF_ON 250
+#define FTDM_DEFAULT_DTMF_OFF 50
+
+#define FTDM_END -1
+#define FTDM_ANY_STATE -1
+
+typedef uint64_t ftdm_time_t; 
+
+typedef enum {
+	FTDM_ENDIAN_BIG = 1,
+	FTDM_ENDIAN_LITTLE = -1
+} ftdm_endian_t;
+
+typedef enum {
+	FTDM_CID_TYPE_SDMF = 0x04,
+	FTDM_CID_TYPE_MDMF = 0x80
+} ftdm_cid_type_t;
+
+typedef enum {
+	MDMF_DATETIME = 1,
+	MDMF_PHONE_NUM = 2,
+	MDMF_DDN = 3,
+	MDMF_NO_NUM = 4,
+	MDMF_PHONE_NAME = 7,
+	MDMF_NO_NAME = 8,
+	MDMF_ALT_ROUTE = 9,
+	MDMF_INVALID = 10
+} ftdm_mdmf_type_t;
+#define MDMF_STRINGS "X", "DATETIME", "PHONE_NUM", "DDN", "NO_NUM", "X", "X", "PHONE_NAME", "NO_NAME", "ALT_ROUTE", "INVALID"
+FTDM_STR2ENUM_P(ftdm_str2ftdm_mdmf_type, ftdm_mdmf_type2str, ftdm_mdmf_type_t)
+
+#define FTDM_TONEMAP_LEN 128
+typedef enum {
+	FTDM_TONEMAP_NONE,
+	FTDM_TONEMAP_DIAL,
+	FTDM_TONEMAP_RING,
+	FTDM_TONEMAP_BUSY,
+	FTDM_TONEMAP_FAIL1,
+	FTDM_TONEMAP_FAIL2,
+	FTDM_TONEMAP_FAIL3,
+	FTDM_TONEMAP_ATTN,
+	FTDM_TONEMAP_CALLWAITING_CAS,
+	FTDM_TONEMAP_CALLWAITING_SAS,
+	FTDM_TONEMAP_CALLWAITING_ACK,
+	FTDM_TONEMAP_INVALID
+} ftdm_tonemap_t;
+#define TONEMAP_STRINGS "NONE", "DIAL", "RING", "BUSY", "FAIL1", "FAIL2", "FAIL3", "ATTN", "CALLWAITING-CAS", "CALLWAITING-SAS", "CALLWAITING-ACK", "INVALID"
+FTDM_STR2ENUM_P(ftdm_str2ftdm_tonemap, ftdm_tonemap2str, ftdm_tonemap_t)
+
+typedef enum {
+	FTDM_TRUNK_E1,
+	FTDM_TRUNK_T1,
+	FTDM_TRUNK_J1,
+	FTDM_TRUNK_BRI,
+	FTDM_TRUNK_BRI_PTMP,
+	FTDM_TRUNK_FXO,
+	FTDM_TRUNK_FXS,
+	FTDM_TRUNK_EM,
+	FTDM_TRUNK_NONE
+} ftdm_trunk_type_t;
+#define TRUNK_STRINGS "E1", "T1", "J1", "BRI", "BRI_PTMP", "FXO", "FXS", "EM", "NONE"
+FTDM_STR2ENUM_P(ftdm_str2ftdm_trunk_type, ftdm_trunk_type2str, ftdm_trunk_type_t)
+
+typedef enum {
+	FTDM_ANALOG_START_KEWL,
+	FTDM_ANALOG_START_LOOP,
+	FTDM_ANALOG_START_GROUND,
+	FTDM_ANALOG_START_WINK,
+	FTDM_ANALOG_START_NA
+} ftdm_analog_start_type_t;
+#define START_TYPE_STRINGS "KEWL", "LOOP", "GROUND", "WINK", "NA"
+FTDM_STR2ENUM_P(ftdm_str2ftdm_analog_start_type, ftdm_analog_start_type2str, ftdm_analog_start_type_t)
+
+typedef enum {
+	FTDM_OOB_ONHOOK,
+	FTDM_OOB_OFFHOOK,
+	FTDM_OOB_WINK,
+	FTDM_OOB_FLASH,
+	FTDM_OOB_RING_START,
+	FTDM_OOB_RING_STOP,
+	FTDM_OOB_ALARM_TRAP,
+	FTDM_OOB_ALARM_CLEAR,
+	FTDM_OOB_NOOP,
+	FTDM_OOB_CAS_BITS_CHANGE,
+	FTDM_OOB_INVALID
+} ftdm_oob_event_t;
+#define OOB_STRINGS "DTMF", "ONHOOK", "OFFHOOK", "WINK", "FLASH", "RING_START", "RING_STOP", "ALARM_TRAP", "ALARM_CLEAR", "NOOP", "CAS_BITS_CHANGE", "INVALID"
+FTDM_STR2ENUM_P(ftdm_str2ftdm_oob_event, ftdm_oob_event2str, ftdm_oob_event_t)
+
+typedef enum {
+	FTDM_ALARM_NONE = 0,
+	FTDM_ALARM_RECOVER = (1 << 0),
+	FTDM_ALARM_LOOPBACK = (1 << 2),
+	FTDM_ALARM_YELLOW = (1 << 3),
+	FTDM_ALARM_RED = (1 << 4),
+	FTDM_ALARM_BLUE = (1 << 5),
+	FTDM_ALARM_NOTOPEN = ( 1 << 6),
+	FTDM_ALARM_AIS = ( 1 << 7),
+	FTDM_ALARM_RAI = ( 1 << 8),
+	FTDM_ALARM_GENERAL = ( 1 << 30)
+} ftdm_alarm_flag_t;
+
+typedef enum {
+	FTDM_SIGTYPE_NONE,
+	FTDM_SIGTYPE_ISDN,
+	FTDM_SIGTYPE_RBS,
+	FTDM_SIGTYPE_ANALOG,
+	FTDM_SIGTYPE_SANGOMABOOST,
+	FTDM_SIGTYPE_M3UA,
+	FTDM_SIGTYPE_R2
+} ftdm_signal_type_t;
+
+/*!
+  \brief Signaling status on a given span or specific channel on protocols that support it
+ */
+typedef enum {
+	/* The signaling link is down (no d-chans up in the span/group, MFC-R2 bit pattern unidentified) */
+	FTDM_SIG_STATE_DOWN,
+	/* The signaling link is suspended (MFC-R2 bit pattern blocked, ss7 blocked?) */
+	FTDM_SIG_STATE_SUSPENDED,
+	/* The signaling link is ready and calls can be placed */
+	FTDM_SIG_STATE_UP,
+	/* Invalid status */
+	FTDM_SIG_STATE_INVALID
+} ftdm_signaling_status_t;
+#define SIGSTATUS_STRINGS "DOWN", "SUSPENDED", "UP", "INVALID"
+FTDM_STR2ENUM_P(ftdm_str2ftdm_signaling_status, ftdm_signaling_status2str, ftdm_signaling_status_t)
+
+typedef enum {
+	FTDM_SIGEVENT_START,
+	FTDM_SIGEVENT_STOP,
+	FTDM_SIGEVENT_TRANSFER,
+	FTDM_SIGEVENT_ANSWER,
+	FTDM_SIGEVENT_UP,
+	FTDM_SIGEVENT_FLASH,
+	FTDM_SIGEVENT_PROGRESS,
+	FTDM_SIGEVENT_PROGRESS_MEDIA,
+	FTDM_SIGEVENT_NOTIFY,
+	FTDM_SIGEVENT_TONE_DETECTED,
+	FTDM_SIGEVENT_ALARM_TRAP,
+	FTDM_SIGEVENT_ALARM_CLEAR,
+	FTDM_SIGEVENT_MISC,
+	FTDM_SIGEVENT_COLLECTED_DIGIT,
+	FTDM_SIGEVENT_ADD_CALL,
+	FTDM_SIGEVENT_RESTART,
+	/* Signaling status changed (D-chan up, down, R2 blocked etc) */
+	FTDM_SIGEVENT_SIGSTATUS_CHANGED,
+	FTDM_SIGEVENT_INVALID
+} ftdm_signal_event_t;
+#define SIGNAL_STRINGS "START", "STOP", "TRANSFER", "ANSWER", "UP", "FLASH", "PROGRESS", \
+		"PROGRESS_MEDIA", "NOTIFY", "TONE_DETECTED", "ALARM_TRAP", "ALARM_CLEAR", "MISC", \
+		"COLLECTED_DIGIT", "ADD_CALL", "RESTART", "SIGLINK_CHANGED", "HWSTATUS_CHANGED", "INVALID"
+FTDM_STR2ENUM_P(ftdm_str2ftdm_signal_event, ftdm_signal_event2str, ftdm_signal_event_t)
+
+typedef enum {
+	FTDM_EVENT_NONE,
+	FTDM_EVENT_DTMF,
+	FTDM_EVENT_OOB,
+	FTDM_EVENT_COUNT
+} ftdm_event_type_t;
+
+typedef enum {
+	FTDM_TOP_DOWN,
+	FTDM_BOTTOM_UP
+} ftdm_direction_t;
+
+typedef enum {
+	FTDM_SUCCESS,
+	FTDM_FAIL,
+	FTDM_MEMERR,
+	FTDM_TIMEOUT,
+	FTDM_NOTIMPL,
+	FTDM_CHECKSUM_ERROR,
+	FTDM_STATUS_COUNT,
+	FTDM_BREAK
+} ftdm_status_t;
+
+typedef enum {
+	FTDM_NO_FLAGS = 0,
+	FTDM_READ =  (1 << 0),
+	FTDM_WRITE = (1 << 1),
+	FTDM_EVENTS = (1 << 2)
+} ftdm_wait_flag_t;
+
+typedef enum {
+	FTDM_CODEC_ULAW = 0,
+	FTDM_CODEC_ALAW = 8,
+	FTDM_CODEC_SLIN = 10,
+	FTDM_CODEC_NONE = (1 << 30)
+} ftdm_codec_t;
+
+typedef enum {
+	FTDM_TONE_DTMF = (1 << 0)
+} ftdm_tone_type_t;
+
+typedef enum {
+	FTDM_COMMAND_NOOP,
+	FTDM_COMMAND_SET_INTERVAL,
+	FTDM_COMMAND_GET_INTERVAL,
+	FTDM_COMMAND_SET_CODEC,
+	FTDM_COMMAND_GET_CODEC,
+	FTDM_COMMAND_SET_NATIVE_CODEC,
+	FTDM_COMMAND_GET_NATIVE_CODEC,
+	FTDM_COMMAND_ENABLE_DTMF_DETECT,
+	FTDM_COMMAND_DISABLE_DTMF_DETECT,
+	FTDM_COMMAND_SEND_DTMF,
+	FTDM_COMMAND_SET_DTMF_ON_PERIOD,
+	FTDM_COMMAND_GET_DTMF_ON_PERIOD,
+	FTDM_COMMAND_SET_DTMF_OFF_PERIOD,
+	FTDM_COMMAND_GET_DTMF_OFF_PERIOD,
+	FTDM_COMMAND_GENERATE_RING_ON,
+	FTDM_COMMAND_GENERATE_RING_OFF,
+	FTDM_COMMAND_OFFHOOK,
+	FTDM_COMMAND_ONHOOK,
+	FTDM_COMMAND_FLASH,
+	FTDM_COMMAND_WINK,
+	FTDM_COMMAND_ENABLE_PROGRESS_DETECT,
+	FTDM_COMMAND_DISABLE_PROGRESS_DETECT,
+	FTDM_COMMAND_TRACE_INPUT,
+	FTDM_COMMAND_TRACE_OUTPUT,
+	FTDM_COMMAND_ENABLE_CALLERID_DETECT,
+	FTDM_COMMAND_DISABLE_CALLERID_DETECT,
+	FTDM_COMMAND_ENABLE_ECHOCANCEL,
+	FTDM_COMMAND_DISABLE_ECHOCANCEL,
+	FTDM_COMMAND_ENABLE_ECHOTRAIN,
+	FTDM_COMMAND_DISABLE_ECHOTRAIN,
+	FTDM_COMMAND_SET_CAS_BITS,
+	FTDM_COMMAND_GET_CAS_BITS,
+	FTDM_COMMAND_SET_RX_GAIN,
+	FTDM_COMMAND_GET_RX_GAIN,
+	FTDM_COMMAND_SET_TX_GAIN,
+	FTDM_COMMAND_GET_TX_GAIN,
+	FTDM_COMMAND_FLUSH_TX_BUFFERS,
+	FTDM_COMMAND_FLUSH_RX_BUFFERS,
+	FTDM_COMMAND_FLUSH_BUFFERS,
+	FTDM_COMMAND_SET_PRE_BUFFER_SIZE,
+	FTDM_COMMAND_SET_LINK_STATUS,
+	FTDM_COMMAND_GET_LINK_STATUS,
+	FTDM_COMMAND_ENABLE_LOOP,
+	FTDM_COMMAND_DISABLE_LOOP,
+	FTDM_COMMAND_COUNT
+} ftdm_command_t;
+
+typedef enum {
+	FTDM_SPAN_CONFIGURED = (1 << 0),
+	FTDM_SPAN_READY = (1 << 1),
+	FTDM_SPAN_STATE_CHANGE = (1 << 2),
+	FTDM_SPAN_SUSPENDED = (1 << 3),
+	FTDM_SPAN_IN_THREAD = (1 << 4),
+	FTDM_SPAN_STOP_THREAD = (1 << 5)
+} ftdm_span_flag_t;
+
+typedef enum {
+	FTDM_CHAN_TYPE_B,
+	FTDM_CHAN_TYPE_DQ921,
+	FTDM_CHAN_TYPE_DQ931,
+	FTDM_CHAN_TYPE_FXS,
+	FTDM_CHAN_TYPE_FXO,
+	FTDM_CHAN_TYPE_EM,
+	FTDM_CHAN_TYPE_CAS,
+	FTDM_CHAN_TYPE_COUNT
+} ftdm_chan_type_t;
+
+#define FTDM_IS_VOICE_CHANNEL(ftdm_chan) ((ftdm_chan)->type != FTDM_CHAN_TYPE_DQ921 && (ftdm_chan)->type != FTDM_CHAN_TYPE_DQ931)
+
+#define CHAN_TYPE_STRINGS "B", "DQ921", "DQ931", "FXS", "FXO", "EM", "CAS", "INVALID"
+FTDM_STR2ENUM_P(ftdm_str2ftdm_chan_type, ftdm_chan_type2str, ftdm_chan_type_t)
+
+typedef enum {
+	FTDM_CHANNEL_FEATURE_DTMF_DETECT = (1 << 0),
+	FTDM_CHANNEL_FEATURE_DTMF_GENERATE = (1 << 1),
+	FTDM_CHANNEL_FEATURE_CODECS = (1 << 2),
+	FTDM_CHANNEL_FEATURE_INTERVAL = (1 << 3),
+	FTDM_CHANNEL_FEATURE_CALLERID = (1 << 4),
+	FTDM_CHANNEL_FEATURE_PROGRESS = (1 << 5)
+} ftdm_channel_feature_t;
+
+typedef enum {
+	FTDM_CHANNEL_STATE_DOWN,
+	FTDM_CHANNEL_STATE_HOLD,
+	FTDM_CHANNEL_STATE_SUSPENDED,
+	FTDM_CHANNEL_STATE_DIALTONE,
+	FTDM_CHANNEL_STATE_COLLECT,
+	FTDM_CHANNEL_STATE_RING,
+	FTDM_CHANNEL_STATE_BUSY,
+	FTDM_CHANNEL_STATE_ATTN,
+	FTDM_CHANNEL_STATE_GENRING,
+	FTDM_CHANNEL_STATE_DIALING,
+	FTDM_CHANNEL_STATE_GET_CALLERID,
+	FTDM_CHANNEL_STATE_CALLWAITING,
+	FTDM_CHANNEL_STATE_RESTART,
+	FTDM_CHANNEL_STATE_PROGRESS,
+	FTDM_CHANNEL_STATE_PROGRESS_MEDIA,
+	FTDM_CHANNEL_STATE_UP,
+	FTDM_CHANNEL_STATE_IDLE,
+	FTDM_CHANNEL_STATE_TERMINATING,
+	FTDM_CHANNEL_STATE_CANCEL,
+	FTDM_CHANNEL_STATE_HANGUP,
+	FTDM_CHANNEL_STATE_HANGUP_COMPLETE,
+	FTDM_CHANNEL_STATE_IN_LOOP,
+	FTDM_CHANNEL_STATE_INVALID
+} ftdm_channel_state_t;
+#define CHANNEL_STATE_STRINGS "DOWN", "HOLD", "SUSPENDED", "DIALTONE", "COLLECT", \
+		"RING", "BUSY", "ATTN", "GENRING", "DIALING", "GET_CALLERID", "CALLWAITING", \
+		"RESTART", "PROGRESS", "PROGRESS_MEDIA", "UP", "IDLE", "TERMINATING", "CANCEL", "HANGUP", "HANGUP_COMPLETE", "INVALID"
+FTDM_STR2ENUM_P(ftdm_str2ftdm_channel_state, ftdm_channel_state2str, ftdm_channel_state_t)
+
+typedef enum {
+	FTDM_CHANNEL_CONFIGURED = (1 << 0),
+	FTDM_CHANNEL_READY = (1 << 1),
+	FTDM_CHANNEL_OPEN = (1 << 2),
+	FTDM_CHANNEL_DTMF_DETECT = (1 << 3),
+	FTDM_CHANNEL_SUPRESS_DTMF = (1 << 4),
+	FTDM_CHANNEL_TRANSCODE = (1 << 5),
+	FTDM_CHANNEL_BUFFER = (1 << 6),
+	FTDM_CHANNEL_EVENT = (1 << 7),
+	FTDM_CHANNEL_INTHREAD = (1 << 8),
+	FTDM_CHANNEL_WINK = (1 << 9),
+	FTDM_CHANNEL_FLASH = (1 << 10),
+	FTDM_CHANNEL_STATE_CHANGE = (1 << 11),
+	FTDM_CHANNEL_HOLD = (1 << 12),
+	FTDM_CHANNEL_INUSE = (1 << 13),
+	FTDM_CHANNEL_OFFHOOK = (1 << 14),
+	FTDM_CHANNEL_RINGING = (1 << 15),
+	FTDM_CHANNEL_PROGRESS_DETECT = (1 << 16),
+	FTDM_CHANNEL_CALLERID_DETECT = (1 << 17),
+	FTDM_CHANNEL_OUTBOUND = (1 << 18),
+	FTDM_CHANNEL_SUSPENDED = (1 << 19),
+	FTDM_CHANNEL_3WAY = (1 << 20),
+	FTDM_CHANNEL_PROGRESS = (1 << 21),
+	FTDM_CHANNEL_MEDIA = (1 << 22),
+	FTDM_CHANNEL_ANSWERED = (1 << 23),
+	FTDM_CHANNEL_MUTE = (1 << 24),
+	FTDM_CHANNEL_USE_RX_GAIN = (1 << 25),
+	FTDM_CHANNEL_USE_TX_GAIN = (1 << 26),
+	FTDM_CHANNEL_IN_ALARM = (1 << 27),
+} ftdm_channel_flag_t;
+#if defined(__cplusplus) && defined(WIN32) 
+    // fix C2676 
+__inline__ ftdm_channel_flag_t operator|=(ftdm_channel_flag_t a, int32_t b) {
+    a = (ftdm_channel_flag_t)(a | b);
+    return a;
+}
+__inline__ ftdm_channel_flag_t operator&=(ftdm_channel_flag_t a, int32_t b) {
+    a = (ftdm_channel_flag_t)(a & b);
+    return a;
+}
+#endif
+
+typedef enum {
+	ZSM_NONE,
+	ZSM_UNACCEPTABLE,
+	ZSM_ACCEPTABLE
+} ftdm_state_map_type_t;
+
+typedef enum {
+	ZSD_INBOUND,
+	ZSD_OUTBOUND,
+} ftdm_state_direction_t;
+
+#define FTDM_MAP_NODE_SIZE 512
+#define FTDM_MAP_MAX FTDM_CHANNEL_STATE_INVALID+2
+
+struct ftdm_state_map_node {
+	ftdm_state_direction_t direction;
+	ftdm_state_map_type_t type;
+	ftdm_channel_state_t check_states[FTDM_MAP_MAX];
+	ftdm_channel_state_t states[FTDM_MAP_MAX];
+};
+typedef struct ftdm_state_map_node ftdm_state_map_node_t;
+
+struct ftdm_state_map {
+	ftdm_state_map_node_t nodes[FTDM_MAP_NODE_SIZE];
+};
+typedef struct ftdm_state_map ftdm_state_map_t;
+
+typedef enum ftdm_channel_hw_link_status {
+	FTDM_HW_LINK_DISCONNECTED = 0,
+	FTDM_HW_LINK_CONNECTED
+} ftdm_channel_hw_link_status_t;
+
+typedef struct ftdm_conf_parameter_s {
+	const char *var;
+	const char *val;
+} ftdm_conf_parameter_t;
+
+typedef struct ftdm_channel ftdm_channel_t;
+typedef struct ftdm_event ftdm_event_t;
+typedef struct ftdm_sigmsg ftdm_sigmsg_t;
+typedef struct ftdm_span ftdm_span_t;
+typedef struct ftdm_group ftdm_group_t;
+typedef struct ftdm_caller_data ftdm_caller_data_t;
+typedef struct ftdm_io_interface ftdm_io_interface_t;
+
+struct ftdm_stream_handle;
+typedef struct ftdm_stream_handle ftdm_stream_handle_t;
+
+typedef ftdm_status_t (*ftdm_stream_handle_raw_write_function_t) (ftdm_stream_handle_t *handle, uint8_t *data, ftdm_size_t datalen);
+typedef ftdm_status_t (*ftdm_stream_handle_write_function_t) (ftdm_stream_handle_t *handle, const char *fmt, ...);
+
+#define FIO_CHANNEL_REQUEST_ARGS (ftdm_span_t *span, uint32_t chan_id, ftdm_direction_t direction, ftdm_caller_data_t *caller_data, ftdm_channel_t **ftdmchan)
+#define FIO_CHANNEL_OUTGOING_CALL_ARGS (ftdm_channel_t *ftdmchan)
+#define FIO_CHANNEL_SET_SIG_STATUS_ARGS (ftdm_channel_t *ftdmchan, ftdm_signaling_status_t status)
+#define FIO_CHANNEL_GET_SIG_STATUS_ARGS (ftdm_channel_t *ftdmchan, ftdm_signaling_status_t *status)
+#define FIO_SPAN_SET_SIG_STATUS_ARGS (ftdm_span_t *span, ftdm_signaling_status_t status)
+#define FIO_SPAN_GET_SIG_STATUS_ARGS (ftdm_span_t *span, ftdm_signaling_status_t *status)
+#define FIO_SPAN_POLL_EVENT_ARGS (ftdm_span_t *span, uint32_t ms)
+#define FIO_SPAN_NEXT_EVENT_ARGS (ftdm_span_t *span, ftdm_event_t **event)
+#define FIO_SIGNAL_CB_ARGS (ftdm_sigmsg_t *sigmsg)
+#define FIO_EVENT_CB_ARGS (ftdm_channel_t *ftdmchan, ftdm_event_t *event)
+#define FIO_CODEC_ARGS (void *data, ftdm_size_t max, ftdm_size_t *datalen)
+#define FIO_CONFIGURE_SPAN_ARGS (ftdm_span_t *span, const char *str, ftdm_chan_type_t type, char *name, char *number)
+#define FIO_CONFIGURE_ARGS (const char *category, const char *var, const char *val, int lineno)
+#define FIO_OPEN_ARGS (ftdm_channel_t *ftdmchan)
+#define FIO_CLOSE_ARGS (ftdm_channel_t *ftdmchan)
+#define FIO_CHANNEL_DESTROY_ARGS (ftdm_channel_t *ftdmchan)
+#define FIO_SPAN_DESTROY_ARGS (ftdm_span_t *span)
+#define FIO_COMMAND_ARGS (ftdm_channel_t *ftdmchan, ftdm_command_t command, void *obj)
+#define FIO_WAIT_ARGS (ftdm_channel_t *ftdmchan, ftdm_wait_flag_t *flags, int32_t to)
+#define FIO_GET_ALARMS_ARGS (ftdm_channel_t *ftdmchan)
+#define FIO_READ_ARGS (ftdm_channel_t *ftdmchan, void *data, ftdm_size_t *datalen)
+#define FIO_WRITE_ARGS (ftdm_channel_t *ftdmchan, void *data, ftdm_size_t *datalen)
+#define FIO_IO_LOAD_ARGS (ftdm_io_interface_t **fio)
+#define FIO_IO_UNLOAD_ARGS (void)
+#define FIO_SIG_LOAD_ARGS (void)
+#define FIO_SIG_CONFIGURE_ARGS (ftdm_span_t *span, fio_signal_cb_t sig_cb, va_list ap)
+#define FIO_CONFIGURE_SPAN_SIGNALING_ARGS (ftdm_span_t *span, fio_signal_cb_t sig_cb, ftdm_conf_parameter_t *ftdm_parameters)
+#define FIO_SIG_UNLOAD_ARGS (void)
+#define FIO_API_ARGS (ftdm_stream_handle_t *stream, const char *data)
+
+typedef ftdm_status_t (*fio_channel_request_t) FIO_CHANNEL_REQUEST_ARGS ;
+typedef ftdm_status_t (*fio_channel_outgoing_call_t) FIO_CHANNEL_OUTGOING_CALL_ARGS ;
+typedef ftdm_status_t (*fio_channel_set_sig_status_t) FIO_CHANNEL_SET_SIG_STATUS_ARGS;
+typedef ftdm_status_t (*fio_channel_get_sig_status_t) FIO_CHANNEL_GET_SIG_STATUS_ARGS;
+typedef ftdm_status_t (*fio_span_set_sig_status_t) FIO_SPAN_SET_SIG_STATUS_ARGS;
+typedef ftdm_status_t (*fio_span_get_sig_status_t) FIO_SPAN_GET_SIG_STATUS_ARGS;
+typedef ftdm_status_t (*fio_span_poll_event_t) FIO_SPAN_POLL_EVENT_ARGS ;
+typedef ftdm_status_t (*fio_span_next_event_t) FIO_SPAN_NEXT_EVENT_ARGS ;
+typedef ftdm_status_t (*fio_signal_cb_t) FIO_SIGNAL_CB_ARGS ;
+typedef ftdm_status_t (*fio_event_cb_t) FIO_EVENT_CB_ARGS ;
+typedef ftdm_status_t (*fio_codec_t) FIO_CODEC_ARGS ;
+typedef ftdm_status_t (*fio_configure_span_t) FIO_CONFIGURE_SPAN_ARGS ;
+typedef ftdm_status_t (*fio_configure_t) FIO_CONFIGURE_ARGS ;
+typedef ftdm_status_t (*fio_open_t) FIO_OPEN_ARGS ;
+typedef ftdm_status_t (*fio_close_t) FIO_CLOSE_ARGS ;
+typedef ftdm_status_t (*fio_channel_destroy_t) FIO_CHANNEL_DESTROY_ARGS ;
+typedef ftdm_status_t (*fio_span_destroy_t) FIO_SPAN_DESTROY_ARGS ;
+typedef ftdm_status_t (*fio_get_alarms_t) FIO_GET_ALARMS_ARGS ;
+typedef ftdm_status_t (*fio_command_t) FIO_COMMAND_ARGS ;
+typedef ftdm_status_t (*fio_wait_t) FIO_WAIT_ARGS ;
+typedef ftdm_status_t (*fio_read_t) FIO_READ_ARGS ;
+typedef ftdm_status_t (*fio_write_t) FIO_WRITE_ARGS ;
+typedef ftdm_status_t (*fio_io_load_t) FIO_IO_LOAD_ARGS ;
+typedef ftdm_status_t (*fio_sig_load_t) FIO_SIG_LOAD_ARGS ;
+typedef ftdm_status_t (*fio_sig_configure_t) FIO_SIG_CONFIGURE_ARGS ;
+typedef ftdm_status_t (*fio_configure_span_signaling_t) FIO_CONFIGURE_SPAN_SIGNALING_ARGS ;
+typedef ftdm_status_t (*fio_io_unload_t) FIO_IO_UNLOAD_ARGS ;
+typedef ftdm_status_t (*fio_sig_unload_t) FIO_SIG_UNLOAD_ARGS ;
+typedef ftdm_status_t (*fio_api_t) FIO_API_ARGS ;
+
+
+#define FIO_CHANNEL_REQUEST_FUNCTION(name) ftdm_status_t name FIO_CHANNEL_REQUEST_ARGS
+#define FIO_CHANNEL_OUTGOING_CALL_FUNCTION(name) ftdm_status_t name FIO_CHANNEL_OUTGOING_CALL_ARGS
+#define FIO_CHANNEL_SET_SIG_STATUS_FUNCTION(name) ftdm_status_t name FIO_CHANNEL_SET_SIG_STATUS_ARGS
+#define FIO_CHANNEL_GET_SIG_STATUS_FUNCTION(name) ftdm_status_t name FIO_CHANNEL_GET_SIG_STATUS_ARGS
+#define FIO_SPAN_SET_SIG_STATUS_FUNCTION(name) ftdm_status_t name FIO_SPAN_SET_SIG_STATUS_ARGS
+#define FIO_SPAN_GET_SIG_STATUS_FUNCTION(name) ftdm_status_t name FIO_SPAN_GET_SIG_STATUS_ARGS
+#define FIO_SPAN_POLL_EVENT_FUNCTION(name) ftdm_status_t name FIO_SPAN_POLL_EVENT_ARGS
+#define FIO_SPAN_NEXT_EVENT_FUNCTION(name) ftdm_status_t name FIO_SPAN_NEXT_EVENT_ARGS
+#define FIO_SIGNAL_CB_FUNCTION(name) ftdm_status_t name FIO_SIGNAL_CB_ARGS
+#define FIO_EVENT_CB_FUNCTION(name) ftdm_status_t name FIO_EVENT_CB_ARGS
+#define FIO_CODEC_FUNCTION(name) FT_DECLARE_NONSTD(ftdm_status_t) name FIO_CODEC_ARGS
+#define FIO_CONFIGURE_SPAN_FUNCTION(name) ftdm_status_t name FIO_CONFIGURE_SPAN_ARGS
+#define FIO_CONFIGURE_FUNCTION(name) ftdm_status_t name FIO_CONFIGURE_ARGS
+#define FIO_OPEN_FUNCTION(name) ftdm_status_t name FIO_OPEN_ARGS
+#define FIO_CLOSE_FUNCTION(name) ftdm_status_t name FIO_CLOSE_ARGS
+#define FIO_CHANNEL_DESTROY_FUNCTION(name) ftdm_status_t name FIO_CHANNEL_DESTROY_ARGS
+#define FIO_SPAN_DESTROY_FUNCTION(name) ftdm_status_t name FIO_SPAN_DESTROY_ARGS
+#define FIO_GET_ALARMS_FUNCTION(name) ftdm_status_t name FIO_GET_ALARMS_ARGS
+#define FIO_COMMAND_FUNCTION(name) ftdm_status_t name FIO_COMMAND_ARGS
+#define FIO_WAIT_FUNCTION(name) ftdm_status_t name FIO_WAIT_ARGS
+#define FIO_READ_FUNCTION(name) ftdm_status_t name FIO_READ_ARGS
+#define FIO_WRITE_FUNCTION(name) ftdm_status_t name FIO_WRITE_ARGS
+#define FIO_IO_LOAD_FUNCTION(name) ftdm_status_t name FIO_IO_LOAD_ARGS
+#define FIO_SIG_LOAD_FUNCTION(name) ftdm_status_t name FIO_SIG_LOAD_ARGS
+#define FIO_SIG_CONFIGURE_FUNCTION(name) ftdm_status_t name FIO_SIG_CONFIGURE_ARGS
+#define FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(name) ftdm_status_t name FIO_CONFIGURE_SPAN_SIGNALING_ARGS
+#define FIO_IO_UNLOAD_FUNCTION(name) ftdm_status_t name FIO_IO_UNLOAD_ARGS
+#define FIO_SIG_UNLOAD_FUNCTION(name) ftdm_status_t name FIO_SIG_UNLOAD_ARGS
+#define FIO_API_FUNCTION(name) ftdm_status_t name FIO_API_ARGS
+
+#include "ftdm_dso.h"
+
+typedef struct {
+	char name[256];
+	fio_io_load_t io_load;
+	fio_io_unload_t io_unload;
+	fio_sig_load_t sig_load;
+	fio_sig_configure_t sig_configure;
+	fio_sig_unload_t sig_unload;
+	/*! 
+	  \brief configure a given span signaling 
+	  \see sig_configure
+	  This is just like sig_configure but receives
+	  an array of paramters instead of va_list
+	  I'd like to deprecate sig_configure and move
+	  all modules to use sigparam_configure
+	 */
+	fio_configure_span_signaling_t configure_span_signaling;
+	ftdm_dso_lib_t lib;
+	char path[256];
+} ftdm_module_t;
+
+#ifndef __FUNCTION__
+#define __FUNCTION__ (const char *)__func__
+#endif
+
+#define FTDM_PRE __FILE__, __FUNCTION__, __LINE__
+#define FTDM_LOG_LEVEL_DEBUG 7
+#define FTDM_LOG_LEVEL_INFO 6
+#define FTDM_LOG_LEVEL_NOTICE 5
+#define FTDM_LOG_LEVEL_WARNING 4
+#define FTDM_LOG_LEVEL_ERROR 3
+#define FTDM_LOG_LEVEL_CRIT 2
+#define FTDM_LOG_LEVEL_ALERT 1
+#define FTDM_LOG_LEVEL_EMERG 0
+
+#define FTDM_LOG_DEBUG FTDM_PRE, FTDM_LOG_LEVEL_DEBUG
+#define FTDM_LOG_INFO FTDM_PRE, FTDM_LOG_LEVEL_INFO
+#define FTDM_LOG_NOTICE FTDM_PRE, FTDM_LOG_LEVEL_NOTICE
+#define FTDM_LOG_WARNING FTDM_PRE, FTDM_LOG_LEVEL_WARNING
+#define FTDM_LOG_ERROR FTDM_PRE, FTDM_LOG_LEVEL_ERROR
+#define FTDM_LOG_CRIT FTDM_PRE, FTDM_LOG_LEVEL_CRIT
+#define FTDM_LOG_ALERT FTDM_PRE, FTDM_LOG_LEVEL_ALERT
+#define FTDM_LOG_EMERG FTDM_PRE, FTDM_LOG_LEVEL_EMERG
+
+typedef struct ftdm_fsk_data_state ftdm_fsk_data_state_t;
+typedef int (*ftdm_fsk_data_decoder_t)(ftdm_fsk_data_state_t *state);
+typedef ftdm_status_t (*ftdm_fsk_write_sample_t)(int16_t *buf, ftdm_size_t buflen, void *user_data);
+typedef void (*ftdm_logger_t)(const char *file, const char *func, int line, int level, const char *fmt, ...);
+typedef struct hashtable ftdm_hash_t;
+typedef struct hashtable_iterator ftdm_hash_iterator_t;
+typedef struct key ftdm_hash_key_t;
+typedef struct value ftdm_hash_val_t;
+typedef struct ftdm_bitstream ftdm_bitstream_t;
+typedef struct ftdm_fsk_modulator ftdm_fsk_modulator_t;
+typedef ftdm_status_t (*ftdm_span_start_t)(ftdm_span_t *span);
+typedef ftdm_status_t (*ftdm_span_stop_t)(ftdm_span_t *span);
+
+typedef enum {
+	FTDM_CAUSE_NONE = 0,
+	FTDM_CAUSE_UNALLOCATED = 1,
+	FTDM_CAUSE_NO_ROUTE_TRANSIT_NET = 2,
+	FTDM_CAUSE_NO_ROUTE_DESTINATION = 3,
+	FTDM_CAUSE_CHANNEL_UNACCEPTABLE = 6,
+	FTDM_CAUSE_CALL_AWARDED_DELIVERED = 7,
+	FTDM_CAUSE_NORMAL_CLEARING = 16,
+	FTDM_CAUSE_USER_BUSY = 17,
+	FTDM_CAUSE_NO_USER_RESPONSE = 18,
+	FTDM_CAUSE_NO_ANSWER = 19,
+	FTDM_CAUSE_SUBSCRIBER_ABSENT = 20,
+	FTDM_CAUSE_CALL_REJECTED = 21,
+	FTDM_CAUSE_NUMBER_CHANGED = 22,
+	FTDM_CAUSE_REDIRECTION_TO_NEW_DESTINATION = 23,
+	FTDM_CAUSE_EXCHANGE_ROUTING_ERROR = 25,
+	FTDM_CAUSE_DESTINATION_OUT_OF_ORDER = 27,
+	FTDM_CAUSE_INVALID_NUMBER_FORMAT = 28,
+	FTDM_CAUSE_FACILITY_REJECTED = 29,
+	FTDM_CAUSE_RESPONSE_TO_STATUS_ENQUIRY = 30,
+	FTDM_CAUSE_NORMAL_UNSPECIFIED = 31,
+	FTDM_CAUSE_NORMAL_CIRCUIT_CONGESTION = 34,
+	FTDM_CAUSE_NETWORK_OUT_OF_ORDER = 38,
+	FTDM_CAUSE_NORMAL_TEMPORARY_FAILURE = 41,
+	FTDM_CAUSE_SWITCH_CONGESTION = 42,
+	FTDM_CAUSE_ACCESS_INFO_DISCARDED = 43,
+	FTDM_CAUSE_REQUESTED_CHAN_UNAVAIL = 44,
+	FTDM_CAUSE_PRE_EMPTED = 45,
+	FTDM_CAUSE_FACILITY_NOT_SUBSCRIBED = 50,
+	FTDM_CAUSE_OUTGOING_CALL_BARRED = 52,
+	FTDM_CAUSE_INCOMING_CALL_BARRED = 54,
+	FTDM_CAUSE_BEARERCAPABILITY_NOTAUTH = 57,
+	FTDM_CAUSE_BEARERCAPABILITY_NOTAVAIL = 58,
+	FTDM_CAUSE_SERVICE_UNAVAILABLE = 63,
+	FTDM_CAUSE_BEARERCAPABILITY_NOTIMPL = 65,
+	FTDM_CAUSE_CHAN_NOT_IMPLEMENTED = 66,
+	FTDM_CAUSE_FACILITY_NOT_IMPLEMENTED = 69,
+	FTDM_CAUSE_SERVICE_NOT_IMPLEMENTED = 79,
+	FTDM_CAUSE_INVALID_CALL_REFERENCE = 81,
+	FTDM_CAUSE_INCOMPATIBLE_DESTINATION = 88,
+	FTDM_CAUSE_INVALID_MSG_UNSPECIFIED = 95,
+	FTDM_CAUSE_MANDATORY_IE_MISSING = 96,
+	FTDM_CAUSE_MESSAGE_TYPE_NONEXIST = 97,
+	FTDM_CAUSE_WRONG_MESSAGE = 98,
+	FTDM_CAUSE_IE_NONEXIST = 99,
+	FTDM_CAUSE_INVALID_IE_CONTENTS = 100,
+	FTDM_CAUSE_WRONG_CALL_STATE = 101,
+	FTDM_CAUSE_RECOVERY_ON_TIMER_EXPIRE = 102,
+	FTDM_CAUSE_MANDATORY_IE_LENGTH_ERROR = 103,
+	FTDM_CAUSE_PROTOCOL_ERROR = 111,
+	FTDM_CAUSE_INTERWORKING = 127,
+	FTDM_CAUSE_SUCCESS = 142,
+	FTDM_CAUSE_ORIGINATOR_CANCEL = 487,
+	FTDM_CAUSE_CRASH = 500,
+	FTDM_CAUSE_SYSTEM_SHUTDOWN = 501,
+	FTDM_CAUSE_LOSE_RACE = 502,
+	FTDM_CAUSE_MANAGER_REQUEST = 503,
+	FTDM_CAUSE_BLIND_TRANSFER = 600,
+	FTDM_CAUSE_ATTENDED_TRANSFER = 601,
+	FTDM_CAUSE_ALLOTTED_TIMEOUT = 602,
+	FTDM_CAUSE_USER_CHALLENGE = 603,
+	FTDM_CAUSE_MEDIA_TIMEOUT = 604
+} ftdm_call_cause_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
+

Added: freeswitch/trunk/libs/freetdm/src/include/g711.h (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/include/g711.h	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/include/g711.h	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,395 @@
+/*
+ * SpanDSP - a series of DSP components for telephony
+ *
+ * g711.h - In line A-law and u-law conversion routines
+ *
+ * Written by Steve Underwood <steveu@coppice.org>
+ *
+ * Copyright (C) 2001 Steve Underwood
+ *
+ *  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.
+ *
+ * $Id: g711.h,v 1.1 2006/06/07 15:46:39 steveu Exp $
+ */
+
+/*! \file */
+
+/*! \page g711_page A-law and mu-law handling
+  Lookup tables for A-law and u-law look attractive, until you consider the impact
+  on the CPU cache. If it causes a substantial area of your processor cache to get
+  hit too often, cache sloshing will severely slow things down. The main reason
+  these routines are slow in C, is the lack of direct access to the CPU's "find
+  the first 1" instruction. A little in-line assembler fixes that, and the
+  conversion routines can be faster than lookup tables, in most real world usage.
+  A "find the first 1" instruction is available on most modern CPUs, and is a
+  much underused feature. 
+
+  If an assembly language method of bit searching is not available, these routines
+  revert to a method that can be a little slow, so the cache thrashing might not
+  seem so bad :(
+
+  Feel free to submit patches to add fast "find the first 1" support for your own
+  favourite processor.
+
+  Look up tables are used for transcoding between A-law and u-law, since it is
+  difficult to achieve the precise transcoding procedure laid down in the G.711
+  specification by other means.
+*/
+
+#if !defined(_G711_H_)
+#define _G711_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef _MSC_VER
+#ifndef __inline__
+#define __inline__ __inline
+#endif
+	typedef unsigned __int8 uint8_t;
+	typedef __int16 int16_t;
+	typedef __int32 int32_t;
+	typedef unsigned __int16 uint16_t;
+#else
+#include <stdint.h>
+#endif
+
+#if defined(__i386__)
+	/*! \brief Find the bit position of the highest set bit in a word
+	  \param bits The word to be searched
+	  \return The bit number of the highest set bit, or -1 if the word is zero. */
+	static __inline__ int top_bit(unsigned int bits)
+	{
+		int res;
+
+		__asm__ __volatile__(" movl $-1,%%edx;\n"
+							 " bsrl %%eax,%%edx;\n"
+							 : "=d" (res)
+							 : "a" (bits));
+		return res;
+	}
+	/*- End of function --------------------------------------------------------*/
+
+	/*! \brief Find the bit position of the lowest set bit in a word
+	  \param bits The word to be searched
+	  \return The bit number of the lowest set bit, or -1 if the word is zero. */
+	static __inline__ int bottom_bit(unsigned int bits)
+	{
+		int res;
+
+		__asm__ __volatile__(" movl $-1,%%edx;\n"
+							 " bsfl %%eax,%%edx;\n"
+							 : "=d" (res)
+							 : "a" (bits));
+		return res;
+	}
+	/*- End of function --------------------------------------------------------*/
+#elif defined(__x86_64__)
+	static __inline__ int top_bit(unsigned int bits)
+	{
+		int res;
+
+		__asm__ __volatile__(" movq $-1,%%rdx;\n"
+							 " bsrq %%rax,%%rdx;\n"
+							 : "=d" (res)
+							 : "a" (bits));
+		return res;
+	}
+	/*- End of function --------------------------------------------------------*/
+
+	static __inline__ int bottom_bit(unsigned int bits)
+	{
+		int res;
+
+		__asm__ __volatile__(" movq $-1,%%rdx;\n"
+							 " bsfq %%rax,%%rdx;\n"
+							 : "=d" (res)
+							 : "a" (bits));
+		return res;
+	}
+	/*- End of function --------------------------------------------------------*/
+#else
+	static __inline__ int top_bit(unsigned int bits)
+	{
+		int i;
+    
+		if (bits == 0)
+			return -1;
+		i = 0;
+		if (bits & 0xFFFF0000)
+			{
+				bits &= 0xFFFF0000;
+				i += 16;
+			}
+		if (bits & 0xFF00FF00)
+			{
+				bits &= 0xFF00FF00;
+				i += 8;
+			}
+		if (bits & 0xF0F0F0F0)
+			{
+				bits &= 0xF0F0F0F0;
+				i += 4;
+			}
+		if (bits & 0xCCCCCCCC)
+			{
+				bits &= 0xCCCCCCCC;
+				i += 2;
+			}
+		if (bits & 0xAAAAAAAA)
+			{
+				bits &= 0xAAAAAAAA;
+				i += 1;
+			}
+		return i;
+	}
+	/*- End of function --------------------------------------------------------*/
+
+	static __inline__ int bottom_bit(unsigned int bits)
+	{
+		int i;
+    
+		if (bits == 0)
+			return -1;
+		i = 32;
+		if (bits & 0x0000FFFF)
+			{
+				bits &= 0x0000FFFF;
+				i -= 16;
+			}
+		if (bits & 0x00FF00FF)
+			{
+				bits &= 0x00FF00FF;
+				i -= 8;
+			}
+		if (bits & 0x0F0F0F0F)
+			{
+				bits &= 0x0F0F0F0F;
+				i -= 4;
+			}
+		if (bits & 0x33333333)
+			{
+				bits &= 0x33333333;
+				i -= 2;
+			}
+		if (bits & 0x55555555)
+			{
+				bits &= 0x55555555;
+				i -= 1;
+			}
+		return i;
+	}
+	/*- End of function --------------------------------------------------------*/
+#endif
+
+	/* N.B. It is tempting to use look-up tables for A-law and u-law conversion.
+	 *      However, you should consider the cache footprint.
+	 *
+	 *      A 64K byte table for linear to x-law and a 512 byte table for x-law to
+	 *      linear sound like peanuts these days, and shouldn't an array lookup be
+	 *      real fast? No! When the cache sloshes as badly as this one will, a tight
+	 *      calculation may be better. The messiest part is normally finding the
+	 *      segment, but a little inline assembly can fix that on an i386, x86_64 and
+	 *      many other modern processors.
+	 */
+ 
+	/*
+	 * Mu-law is basically as follows:
+	 *
+	 *      Biased Linear Input Code        Compressed Code
+	 *      ------------------------        ---------------
+	 *      00000001wxyza                   000wxyz
+	 *      0000001wxyzab                   001wxyz
+	 *      000001wxyzabc                   010wxyz
+	 *      00001wxyzabcd                   011wxyz
+	 *      0001wxyzabcde                   100wxyz
+	 *      001wxyzabcdef                   101wxyz
+	 *      01wxyzabcdefg                   110wxyz
+	 *      1wxyzabcdefgh                   111wxyz
+	 *
+	 * Each biased linear code has a leading 1 which identifies the segment
+	 * number. The value of the segment number is equal to 7 minus the number
+	 * of leading 0's. The quantization interval is directly available as the
+	 * four bits wxyz.  * The trailing bits (a - h) are ignored.
+	 *
+	 * Ordinarily the complement of the resulting code word is used for
+	 * transmission, and so the code word is complemented before it is returned.
+	 *
+	 * For further information see John C. Bellamy's Digital Telephony, 1982,
+	 * John Wiley & Sons, pps 98-111 and 472-476.
+	 */
+
+	/*#define ULAW_ZEROTRAP*/                 /* turn on the trap as per the MIL-STD */
+#define ULAW_BIAS        0x84           /* Bias for linear code. */
+
+	/*! \brief Encode a linear sample to u-law
+	  \param linear The sample to encode.
+	  \return The u-law value.
+	*/
+	static __inline__ uint8_t linear_to_ulaw(int linear)
+	{
+		uint8_t u_val;
+		int mask;
+		int seg;
+
+		/* Get the sign and the magnitude of the value. */
+		if (linear < 0)
+			{
+				linear = ULAW_BIAS - linear;
+				mask = 0x7F;
+			}
+		else
+			{
+				linear = ULAW_BIAS + linear;
+				mask = 0xFF;
+			}
+
+		seg = top_bit(linear | 0xFF) - 7;
+
+		/*
+		 * Combine the sign, segment, quantization bits,
+		 * and complement the code word.
+		 */
+		if (seg >= 8)
+			u_val = (uint8_t) (0x7F ^ mask);
+		else
+			u_val = (uint8_t) (((seg << 4) | ((linear >> (seg + 3)) & 0xF)) ^ mask);
+#ifdef ULAW_ZEROTRAP
+		/* Optional ITU trap */
+		if (u_val == 0)
+			u_val = 0x02;
+#endif
+		return  u_val;
+	}
+	/*- End of function --------------------------------------------------------*/
+
+	/*! \brief Decode an u-law sample to a linear value.
+	  \param ulaw The u-law sample to decode.
+	  \return The linear value.
+	*/
+	static __inline__ int16_t ulaw_to_linear(uint8_t ulaw)
+	{
+		int t;
+    
+		/* Complement to obtain normal u-law value. */
+		ulaw = ~ulaw;
+		/*
+		 * Extract and bias the quantization bits. Then
+		 * shift up by the segment number and subtract out the bias.
+		 */
+		t = (((ulaw & 0x0F) << 3) + ULAW_BIAS) << (((int) ulaw & 0x70) >> 4);
+		return  (int16_t) ((ulaw & 0x80)  ?  (ULAW_BIAS - t)  :  (t - ULAW_BIAS));
+	}
+	/*- End of function --------------------------------------------------------*/
+
+	/*
+	 * A-law is basically as follows:
+	 *
+	 *      Linear Input Code        Compressed Code
+	 *      -----------------        ---------------
+	 *      0000000wxyza             000wxyz
+	 *      0000001wxyza             001wxyz
+	 *      000001wxyzab             010wxyz
+	 *      00001wxyzabc             011wxyz
+	 *      0001wxyzabcd             100wxyz
+	 *      001wxyzabcde             101wxyz
+	 *      01wxyzabcdef             110wxyz
+	 *      1wxyzabcdefg             111wxyz
+	 *
+	 * For further information see John C. Bellamy's Digital Telephony, 1982,
+	 * John Wiley & Sons, pps 98-111 and 472-476.
+	 */
+
+#define ALAW_AMI_MASK       0x55
+
+	/*! \brief Encode a linear sample to A-law
+	  \param linear The sample to encode.
+	  \return The A-law value.
+	*/
+	static __inline__ uint8_t linear_to_alaw(int linear)
+	{
+		int mask;
+		int seg;
+    
+		if (linear >= 0)
+			{
+				/* Sign (bit 7) bit = 1 */
+				mask = ALAW_AMI_MASK | 0x80;
+			}
+		else
+			{
+				/* Sign (bit 7) bit = 0 */
+				mask = ALAW_AMI_MASK;
+				linear = -linear - 8;
+			}
+
+		/* Convert the scaled magnitude to segment number. */
+		seg = top_bit(linear | 0xFF) - 7;
+		if (seg >= 8)
+			{
+				if (linear >= 0)
+					{
+						/* Out of range. Return maximum value. */
+						return (uint8_t) (0x7F ^ mask);
+					}
+				/* We must be just a tiny step below zero */
+				return (uint8_t) (0x00 ^ mask);
+			}
+		/* Combine the sign, segment, and quantization bits. */
+		return (uint8_t) (((seg << 4) | ((linear >> ((seg)  ?  (seg + 3)  :  4)) & 0x0F)) ^ mask);
+	}
+	/*- End of function --------------------------------------------------------*/
+
+	/*! \brief Decode an A-law sample to a linear value.
+	  \param alaw The A-law sample to decode.
+	  \return The linear value.
+	*/
+	static __inline__ int16_t alaw_to_linear(uint8_t alaw)
+	{
+		int i;
+		int seg;
+
+		alaw ^= ALAW_AMI_MASK;
+		i = ((alaw & 0x0F) << 4);
+		seg = (((int) alaw & 0x70) >> 4);
+		if (seg)
+			i = (i + 0x108) << (seg - 1);
+		else
+			i += 8;
+		return (int16_t) ((alaw & 0x80)  ?  i  :  -i);
+	}
+	/*- End of function --------------------------------------------------------*/
+
+	/*! \brief Transcode from A-law to u-law, using the procedure defined in G.711.
+	  \param alaw The A-law sample to transcode.
+	  \return The best matching u-law value.
+	*/
+	uint8_t alaw_to_ulaw(uint8_t alaw);
+
+	/*! \brief Transcode from u-law to A-law, using the procedure defined in G.711.
+	  \param alaw The u-law sample to transcode.
+	  \return The best matching A-law value.
+	*/
+	uint8_t ulaw_to_alaw(uint8_t ulaw);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+/*- End of file ------------------------------------------------------------*/
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */

Added: freeswitch/trunk/libs/freetdm/src/include/hashtable.h (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/include/hashtable.h	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/include/hashtable.h	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,235 @@
+/* Copyright (C) 2002 Christopher Clark <firstname.lastname@cl.cam.ac.uk> */
+
+#ifndef __HASHTABLE_CWC22_H__
+#define __HASHTABLE_CWC22_H__
+#ifdef _MSC_VER
+#ifndef __inline__
+#define __inline__ __inline
+#endif
+#endif
+#include "freetdm.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+struct hashtable;
+struct hashtable_iterator;
+
+/* Example of use:
+ *
+ *      struct hashtable  *h;
+ *      struct some_key   *k;
+ *      struct some_value *v;
+ *
+ *      static unsigned int         hash_from_key_fn( void *k );
+ *      static int                  keys_equal_fn ( void *key1, void *key2 );
+ *
+ *      h = create_hashtable(16, hash_from_key_fn, keys_equal_fn);
+ *      k = (struct some_key *)     malloc(sizeof(struct some_key));
+ *      v = (struct some_value *)   malloc(sizeof(struct some_value));
+ *
+ *      (initialise k and v to suitable values)
+ * 
+ *      if (! hashtable_insert(h,k,v) )
+ *      {     exit(-1);               }
+ *
+ *      if (NULL == (found = hashtable_search(h,k) ))
+ *      {    printf("not found!");                  }
+ *
+ *      if (NULL == (found = hashtable_remove(h,k) ))
+ *      {    printf("Not found\n");                 }
+ *
+ */
+
+/* Macros may be used to define type-safe(r) hashtable access functions, with
+ * methods specialized to take known key and value types as parameters.
+ * 
+ * Example:
+ *
+ * Insert this at the start of your file:
+ *
+ * DEFINE_HASHTABLE_INSERT(insert_some, struct some_key, struct some_value);
+ * DEFINE_HASHTABLE_SEARCH(search_some, struct some_key, struct some_value);
+ * DEFINE_HASHTABLE_REMOVE(remove_some, struct some_key, struct some_value);
+ *
+ * This defines the functions 'insert_some', 'search_some' and 'remove_some'.
+ * These operate just like hashtable_insert etc., with the same parameters,
+ * but their function signatures have 'struct some_key *' rather than
+ * 'void *', and hence can generate compile time errors if your program is
+ * supplying incorrect data as a key (and similarly for value).
+ *
+ * Note that the hash and key equality functions passed to create_hashtable
+ * still take 'void *' parameters instead of 'some key *'. This shouldn't be
+ * a difficult issue as they're only defined and passed once, and the other
+ * functions will ensure that only valid keys are supplied to them.
+ *
+ * The cost for this checking is increased code size and runtime overhead
+ * - if performance is important, it may be worth switching back to the
+ * unsafe methods once your program has been debugged with the safe methods.
+ * This just requires switching to some simple alternative defines - eg:
+ * #define insert_some hashtable_insert
+ *
+ */
+
+/*****************************************************************************
+ * create_hashtable
+   
+ * @name                    create_hashtable
+ * @param   minsize         minimum initial size of hashtable
+ * @param   hashfunction    function for hashing keys
+ * @param   key_eq_fn       function for determining key equality
+ * @return                  newly created hashtable or NULL on failure
+ */
+
+FT_DECLARE(struct hashtable *)
+create_hashtable(unsigned int minsize,
+                 unsigned int (*hashfunction) (void*),
+                 int (*key_eq_fn) (void*,void*));
+
+/*****************************************************************************
+ * hashtable_insert
+   
+ * @name        hashtable_insert
+ * @param   h   the hashtable to insert into
+ * @param   k   the key - hashtable claims ownership and will free on removal
+ * @param   v   the value - does not claim ownership
+ * @return      non-zero for successful insertion
+ *
+ * This function will cause the table to expand if the insertion would take
+ * the ratio of entries to table size over the maximum load factor.
+ *
+ * This function does not check for repeated insertions with a duplicate key.
+ * The value returned when using a duplicate key is undefined -- when
+ * the hashtable changes size, the order of retrieval of duplicate key
+ * entries is reversed.
+ * If in doubt, remove before insert.
+ */
+
+
+typedef enum {
+	HASHTABLE_FLAG_NONE = 0,
+	HASHTABLE_FLAG_FREE_KEY = (1 << 0),
+	HASHTABLE_FLAG_FREE_VALUE = (1 << 1)
+} hashtable_flag_t;
+
+FT_DECLARE(int)
+hashtable_insert(struct hashtable *h, void *k, void *v, hashtable_flag_t flags);
+
+#define DEFINE_HASHTABLE_INSERT(fnname, keytype, valuetype)		\
+	int fnname (struct hashtable *h, keytype *k, valuetype *v)	\
+	{															\
+		return hashtable_insert(h,k,v);							\
+	}
+
+/*****************************************************************************
+ * hashtable_search
+   
+ * @name        hashtable_search
+ * @param   h   the hashtable to search
+ * @param   k   the key to search for  - does not claim ownership
+ * @return      the value associated with the key, or NULL if none found
+ */
+
+FT_DECLARE(void *)
+hashtable_search(struct hashtable *h, void *k);
+
+#define DEFINE_HASHTABLE_SEARCH(fnname, keytype, valuetype) \
+	valuetype * fnname (struct hashtable *h, keytype *k)	\
+	{														\
+		return (valuetype *) (hashtable_search(h,k));		\
+	}
+
+/*****************************************************************************
+ * hashtable_remove
+   
+ * @name        hashtable_remove
+ * @param   h   the hashtable to remove the item from
+ * @param   k   the key to search for  - does not claim ownership
+ * @return      the value associated with the key, or NULL if none found
+ */
+
+FT_DECLARE(void *) /* returns value */
+hashtable_remove(struct hashtable *h, void *k);
+
+#define DEFINE_HASHTABLE_REMOVE(fnname, keytype, valuetype) \
+	valuetype * fnname (struct hashtable *h, keytype *k)	\
+	{														\
+		return (valuetype *) (hashtable_remove(h,k));		\
+	}
+
+
+/*****************************************************************************
+ * hashtable_count
+   
+ * @name        hashtable_count
+ * @param   h   the hashtable
+ * @return      the number of items stored in the hashtable
+ */
+FT_DECLARE(unsigned int)
+hashtable_count(struct hashtable *h);
+
+
+/*****************************************************************************
+ * hashtable_destroy
+   
+ * @name        hashtable_destroy
+ * @param   h   the hashtable
+ * @param       free_values     whether to call 'free' on the remaining values
+ */
+
+FT_DECLARE(void)
+hashtable_destroy(struct hashtable *h);
+
+FT_DECLARE(struct hashtable_iterator*) hashtable_first(struct hashtable *h);
+FT_DECLARE(struct hashtable_iterator*) hashtable_next(struct hashtable_iterator *i);
+FT_DECLARE(void) hashtable_this(struct hashtable_iterator *i, const void **key, int *klen, void **val);
+
+#ifdef __cplusplus
+} /* extern C */
+#endif
+
+#endif /* __HASHTABLE_CWC22_H__ */
+
+/*
+ * Copyright (c) 2002, Christopher Clark
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */

Added: freeswitch/trunk/libs/freetdm/src/include/hashtable_itr.h (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/include/hashtable_itr.h	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/include/hashtable_itr.h	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,134 @@
+/* Copyright (C) 2002, 2004 Christopher Clark <firstname.lastname@cl.cam.ac.uk> */
+
+#ifndef __HASHTABLE_ITR_CWC22__
+#define __HASHTABLE_ITR_CWC22__
+#include "hashtable.h"
+#include "hashtable_private.h" /* needed to enable inlining */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*****************************************************************************/
+/* This struct is only concrete here to allow the inlining of two of the
+ * accessor functions. */
+struct hashtable_itr
+{
+    struct hashtable *h;
+    struct entry *e;
+    struct entry *parent;
+    unsigned int index;
+};
+
+
+/*****************************************************************************/
+/* hashtable_iterator
+ */
+
+struct hashtable_itr *
+hashtable_iterator(struct hashtable *h);
+
+/*****************************************************************************/
+/* hashtable_iterator_key
+ * - return the value of the (key,value) pair at the current position */
+extern __inline__ void *
+hashtable_iterator_key(struct hashtable_itr *i);
+
+extern __inline__ void *
+hashtable_iterator_key(struct hashtable_itr *i)
+{
+    return i->e->k;
+}
+
+/*****************************************************************************/
+/* value - return the value of the (key,value) pair at the current position */
+
+extern __inline__ void *
+hashtable_iterator_value(struct hashtable_itr *i);
+
+extern __inline__ void *
+hashtable_iterator_value(struct hashtable_itr *i)
+{
+    return i->e->v;
+}
+
+/*****************************************************************************/
+/* advance - advance the iterator to the next element
+ *           returns zero if advanced to end of table */
+
+int
+hashtable_iterator_advance(struct hashtable_itr *itr);
+
+/*****************************************************************************/
+/* remove - remove current element and advance the iterator to the next element
+ *          NB: if you need the value to free it, read it before
+ *          removing. ie: beware memory leaks!
+ *          returns zero if advanced to end of table */
+
+int
+hashtable_iterator_remove(struct hashtable_itr *itr);
+
+/*****************************************************************************/
+/* search - overwrite the supplied iterator, to point to the entry
+ *          matching the supplied key.
+ h points to the hashtable to be searched.
+ *          returns zero if not found. */
+int
+hashtable_iterator_search(struct hashtable_itr *itr,
+                          struct hashtable *h, void *k);
+
+#define DEFINE_HASHTABLE_ITERATOR_SEARCH(fnname, keytype)				\
+	int fnname (struct hashtable_itr *i, struct hashtable *h, keytype *k) \
+	{																	\
+		return (hashtable_iterator_search(i,h,k));						\
+	}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __HASHTABLE_ITR_CWC22__*/
+
+/*
+ * Copyright (c) 2002, 2004, Christopher Clark
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
+

Added: freeswitch/trunk/libs/freetdm/src/include/hashtable_private.h (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/include/hashtable_private.h	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/include/hashtable_private.h	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,110 @@
+/* Copyright (C) 2002, 2004 Christopher Clark <firstname.lastname@cl.cam.ac.uk> */
+
+#ifndef __HASHTABLE_PRIVATE_CWC22_H__
+#define __HASHTABLE_PRIVATE_CWC22_H__
+
+#include "hashtable.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*****************************************************************************/
+
+struct entry
+{
+    void *k, *v;
+    unsigned int h;
+	hashtable_flag_t flags;
+    struct entry *next;
+};
+
+struct hashtable_iterator {
+	unsigned int pos;
+	struct entry *e;
+	struct hashtable *h;
+};
+
+struct hashtable {
+    unsigned int tablelength;
+    struct entry **table;
+    unsigned int entrycount;
+    unsigned int loadlimit;
+    unsigned int primeindex;
+    unsigned int (*hashfn) (void *k);
+    int (*eqfn) (void *k1, void *k2);
+	struct hashtable_iterator iterator;
+};
+
+/*****************************************************************************/
+unsigned int
+hash(struct hashtable *h, void *k);
+
+/*****************************************************************************/
+/* indexFor */
+static __inline__ unsigned int
+indexFor(unsigned int tablelength, unsigned int hashvalue) {
+    return (hashvalue % tablelength);
+}
+
+/* Only works if tablelength == 2^N */
+/*static inline unsigned int
+  indexFor(unsigned int tablelength, unsigned int hashvalue)
+  {
+  return (hashvalue & (tablelength - 1u));
+  }
+*/
+
+/*****************************************************************************/
+#define freekey(X) free(X)
+/*define freekey(X) ; */
+
+#ifdef __cplusplus
+}
+#endif
+
+/*****************************************************************************/
+
+#endif /* __HASHTABLE_PRIVATE_CWC22_H__*/
+
+/*
+ * Copyright (c) 2002, Christopher Clark
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */

Added: freeswitch/trunk/libs/freetdm/src/include/libteletone.h (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/include/libteletone.h	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/include/libteletone.h	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,161 @@
+/* 
+ * libteletone
+ * Copyright (C) 2005/2006, Anthony Minessale II <anthmct@yahoo.com>
+ *
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mftilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mftilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is libteletone
+ *
+ * The Initial Developer of the Original Code is
+ * Anthony Minessale II <anthmct@yahoo.com>
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * 
+ * Anthony Minessale II <anthmct@yahoo.com>
+ *
+ *
+ * libteletone.h -- Tone Generator/Detector
+ *
+ *
+ *
+ * Exception:
+ * The author hereby grants the use of this source code under the 
+ * following license if and only if the source code is distributed
+ * as part of the freetdm library.  Any use or distribution of this
+ * source code outside the scope of the freetdm library will nullify the
+ * following license and reinact the MPL 1.1 as stated above.
+ *
+ * Copyright (c) 2007, Anthony Minessale II
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef LIBTELETONE_H
+#define LIBTELETONE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <math.h>
+
+#define	TELETONE_MAX_DTMF_DIGITS 128
+#define TELETONE_MAX_TONES 18
+#define TELETONE_TONE_RANGE 127
+
+typedef double teletone_process_t;
+
+/*! \file libteletone.h
+    \brief Top level include file
+
+	This file should be included by applications using the library
+*/
+
+/*! \brief An abstraction to store a tone mapping */
+typedef struct {
+	/*! An array of tone frequencies */
+	teletone_process_t freqs[TELETONE_MAX_TONES];
+} teletone_tone_map_t;
+
+#if !defined(M_PI)
+/* C99 systems may not define M_PI */
+#define M_PI 3.14159265358979323846264338327
+#endif
+
+#ifdef _MSC_VER
+typedef __int16 int16_t;
+#endif
+
+#if (_MSC_VER >= 1400)			// VC8+
+#define teletone_assert(expr) assert(expr);__analysis_assume( expr )
+#else
+#define teletone_assert(expr) assert(expr)
+#endif
+
+#ifdef _MSC_VER
+#if defined(TT_DECLARE_STATIC)
+#define TELETONE_API(type)			type __stdcall
+#define TELETONE_API_NONSTD(type)		type __cdecl
+#define TELETONE_API_DATA
+#elif defined(TELETONE_EXPORTS)
+#define TELETONE_API(type)			__declspec(dllexport) type __stdcall
+#define TELETONE_API_NONSTD(type)		__declspec(dllexport) type __cdecl
+#define TELETONE_API_DATA				__declspec(dllexport)
+#else
+#define TELETONE_API(type)			__declspec(dllimport) type __stdcall
+#define TELETONE_API_NONSTD(type)		__declspec(dllimport) type __cdecl
+#define TELETONE_API_DATA				__declspec(dllimport)
+#endif
+#else
+#if (defined(__GNUC__) || defined(__SUNPRO_CC) || defined (__SUNPRO_C)) && defined(HAVE_VISIBILITY)
+#define TELETONE_API(type)		__attribute__((visibility("default"))) type
+#define TELETONE_API_NONSTD(type)	__attribute__((visibility("default"))) type
+#define TELETONE_API_DATA		__attribute__((visibility("default")))
+#else
+#define TELETONE_API(type)		type
+#define TELETONE_API_NONSTD(type)	type
+#define TELETONE_API_DATA
+#endif
+#endif
+
+#include <libteletone_generate.h>
+#include <libteletone_detect.h>
+
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */

Added: freeswitch/trunk/libs/freetdm/src/include/libteletone_detect.h (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/include/libteletone_detect.h	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/include/libteletone_detect.h	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,240 @@
+/* 
+ * libteletone
+ * Copyright (C) 2005/2006, Anthony Minessale II <anthmct@yahoo.com>
+ *
+ * libteletone_detect.c Tone Detection Code
+ *
+ * Exception:
+ * The author hereby grants the use of this source code under the 
+ * following license if and only if the source code is distributed
+ * as part of the freetdm library.	Any use or distribution of this
+ * source code outside the scope of the freetdm library will nullify the
+ * following license and reinact the MPL 1.1 as stated above.
+ *
+ * Copyright (c) 2007, Anthony Minessale II
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.	 IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ********************************************************************************* 
+ *
+ * Derived from tone_detect.h - General telephony tone detection, and specific
+ * detection of DTMF.
+ *
+ * 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.
+ *
+ *
+ */
+
+#ifndef LIBTELETONE_DETECT_H
+#define LIBTELETONE_DETECT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+#include <libteletone.h>
+
+	/*! \file libteletone_detect.h
+	  \brief Tone Detection Routines
+
+	  This module is responsible for tone detection specifics
+	*/
+
+#ifndef FALSE
+#define FALSE	0
+#ifndef TRUE
+#define TRUE	(!FALSE)
+#endif
+#endif
+
+	/* Basic DTMF specs:
+	 *
+	 * Minimum tone on = 40ms
+	 * Minimum tone off = 50ms
+	 * Maximum digit rate = 10 per second
+	 * Normal twist <= 8dB accepted
+	 * Reverse twist <= 4dB accepted
+	 * S/N >= 15dB will detect OK
+	 * Attenuation <= 26dB will detect OK
+	 * Frequency tolerance +- 1.5% will detect, +-3.5% will reject
+	 */
+
+#define DTMF_THRESHOLD				8.0e7
+#define DTMF_NORMAL_TWIST			6.3		/* 8dB */
+#define DTMF_REVERSE_TWIST			2.5		/* 4dB */
+#define DTMF_RELATIVE_PEAK_ROW		6.3		/* 8dB */
+#define DTMF_RELATIVE_PEAK_COL		6.3		/* 8dB */
+#define DTMF_2ND_HARMONIC_ROW		2.5		/* 4dB */
+#define DTMF_2ND_HARMONIC_COL		63.1	/* 18dB */
+#define GRID_FACTOR 4
+#define BLOCK_LEN 102
+#define M_TWO_PI 2.0*M_PI
+
+	/*! \brief A continer for the elements of a Goertzel Algorithm (The names are from his formula) */
+	typedef struct {
+		float v2;
+		float v3;
+		double fac;
+	} teletone_goertzel_state_t;
+	
+	/*! \brief A container for a DTMF detection state.*/
+	typedef struct {
+		int hit1;
+		int hit2;
+		int hit3;
+		int hit4;
+		int mhit;
+
+		teletone_goertzel_state_t row_out[GRID_FACTOR];
+		teletone_goertzel_state_t col_out[GRID_FACTOR];
+		teletone_goertzel_state_t row_out2nd[GRID_FACTOR];
+		teletone_goertzel_state_t col_out2nd[GRID_FACTOR];
+		float energy;
+	
+		int current_sample;
+		char digits[TELETONE_MAX_DTMF_DIGITS + 1];
+		int current_digits;
+		int detected_digits;
+		int lost_digits;
+		int digit_hits[16];
+	} teletone_dtmf_detect_state_t;
+
+	/*! \brief An abstraction to store the coefficient of a tone frequency */
+	typedef struct {
+		float fac;
+	} teletone_detection_descriptor_t;
+
+	/*! \brief A container for a single multi-tone detection 
+	  TELETONE_MAX_TONES dictates the maximum simultaneous tones that can be present
+	  in a multi-tone representation.
+	*/
+	typedef struct {
+		int sample_rate;
+
+		teletone_detection_descriptor_t tdd[TELETONE_MAX_TONES];
+		teletone_goertzel_state_t gs[TELETONE_MAX_TONES];
+		teletone_goertzel_state_t gs2[TELETONE_MAX_TONES];
+		int tone_count;
+
+		float energy;
+		int current_sample;
+	
+		int min_samples;
+		int total_samples;
+
+		int positives;
+		int negatives;
+		int hits;
+
+		int positive_factor;
+		int negative_factor;
+		int hit_factor;
+
+	} teletone_multi_tone_t;
+
+
+	/*! 
+	  \brief Initilize a multi-frequency tone detector
+	  \param mt the multi-frequency tone descriptor
+	  \param map a representation of the multi-frequency tone
+	*/
+TELETONE_API(void) teletone_multi_tone_init(teletone_multi_tone_t *mt, teletone_tone_map_t *map);
+
+	/*! 
+	  \brief Check a sample buffer for the presence of the mulit-frequency tone described by mt
+	  \param mt the multi-frequency tone descriptor
+	  \param sample_buffer an array aof 16 bit signed linear samples
+	  \param samples the number of samples present in sample_buffer
+	  \return true when the tone was detected or false when it is not
+	*/
+TELETONE_API(int) teletone_multi_tone_detect (teletone_multi_tone_t *mt,
+									int16_t sample_buffer[],
+									int samples);
+
+	/*! 
+	  \brief Initilize a DTMF detection state object
+	  \param dtmf_detect_state the DTMF detection state to initilize
+	  \param sample_rate the desired sample rate
+	*/
+TELETONE_API(void) teletone_dtmf_detect_init (teletone_dtmf_detect_state_t *dtmf_detect_state, int sample_rate);
+
+	/*! 
+	  \brief Check a sample buffer for the presence of DTMF digits
+	  \param dtmf_detect_state the detection state object to check
+	  \param sample_buffer an array aof 16 bit signed linear samples
+	  \param samples the number of samples present in sample_buffer
+	  \return true when DTMF was detected or false when it is not
+	*/
+TELETONE_API(int) teletone_dtmf_detect (teletone_dtmf_detect_state_t *dtmf_detect_state,
+							  int16_t sample_buffer[],
+							  int samples);
+	/*! 
+	  \brief retrieve any collected digits into a string buffer
+	  \param dtmf_detect_state the detection state object to check
+	  \param buf the string buffer to write to
+	  \param max the maximum length of buf
+	  \return the number of characters written to buf
+	*/
+TELETONE_API(int) teletone_dtmf_get (teletone_dtmf_detect_state_t *dtmf_detect_state,
+						   char *buf,
+						   int max);
+
+	/*! 
+	  \brief Step through the Goertzel Algorithm for each sample in a buffer
+	  \param goertzel_state the goertzel state to step the samples through
+	  \param sample_buffer an array aof 16 bit signed linear samples
+	  \param samples the number of samples present in sample_buffer
+	*/
+TELETONE_API(void) teletone_goertzel_update(teletone_goertzel_state_t *goertzel_state,
+								  int16_t sample_buffer[],
+								  int samples);
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */

Added: freeswitch/trunk/libs/freetdm/src/include/libteletone_generate.h (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/include/libteletone_generate.h	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/include/libteletone_generate.h	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,281 @@
+/* 
+ * libteletone
+ * Copyright (C) 2005/2006, Anthony Minessale II <anthmct@yahoo.com>
+ *
+ * Copyright (c) 2007, Anthony Minessale II
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.	 IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef LIBTELETONE_GENERATE_H
+#define LIBTELETONE_GENERATE_H
+#ifdef __cplusplus
+extern "C" {
+#ifdef _doh
+}
+#endif
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#if  defined(__SUNPRO_C) || defined(__SUNPRO_CC)
+#ifndef __inline__
+#define __inline__ inline
+#endif
+#endif
+
+#ifdef _MSC_VER
+#ifndef __inline__
+#define __inline__ __inline
+#endif
+
+typedef unsigned __int64 uint64_t;
+typedef unsigned __int32 uint32_t;
+typedef unsigned __int16 uint16_t;
+typedef unsigned __int8 uint8_t;
+typedef __int64 int64_t;
+typedef __int32 int32_t;
+typedef __int16 int16_t;
+typedef __int8 int8_t;
+#else
+#include <stdint.h>
+#endif
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <math.h>
+#if !defined(powf) && !defined(_WIN64)
+extern float powf (float, float);
+#endif
+#include <string.h>
+#include <errno.h>
+#ifndef _MSC_VER
+#include <unistd.h>
+#endif
+#include <assert.h>
+#include <stdarg.h>
+#include <libteletone.h>
+
+#define TELETONE_VOL_DB_MAX 0
+#define TELETONE_VOL_DB_MIN -63
+#define MAX_PHASE_TONES 4
+
+struct teletone_dds_state {
+	uint32_t phase_rate[MAX_PHASE_TONES];
+	uint32_t scale_factor;
+	uint32_t phase_accumulator;
+	teletone_process_t tx_level;
+};
+typedef struct teletone_dds_state teletone_dds_state_t;
+
+#define SINE_TABLE_MAX 128
+#define SINE_TABLE_LEN (SINE_TABLE_MAX - 1)
+#define MAX_PHASE_ACCUMULATOR 0x10000 * 0x10000
+/* 3.14 == the max power on ulaw (alaw is 3.17) */
+/* 3.02 represents twice the power */
+#define DBM0_MAX_POWER (3.14f + 3.02f)
+
+TELETONE_API_DATA extern int16_t TELETONE_SINES[SINE_TABLE_MAX];
+
+static __inline__ int32_t teletone_dds_phase_rate(teletone_process_t tone, uint32_t rate)
+{
+	return (int32_t) ((tone * MAX_PHASE_ACCUMULATOR) / rate);
+}
+
+static __inline__ int16_t teletone_dds_state_modulate_sample(teletone_dds_state_t *dds, uint32_t pindex)
+{
+	int32_t bitmask = dds->phase_accumulator, sine_index = (bitmask >>= 23) & SINE_TABLE_LEN;
+	int16_t sample;
+
+	if (pindex >= MAX_PHASE_TONES)	{
+		pindex = 0;
+	}
+
+	if (bitmask & SINE_TABLE_MAX) {
+		sine_index = SINE_TABLE_LEN - sine_index;
+	}
+
+	sample = TELETONE_SINES[sine_index];
+	
+	if (bitmask & (SINE_TABLE_MAX * 2)) {
+		sample *= -1;
+	}
+
+	dds->phase_accumulator += dds->phase_rate[pindex];
+	return (int16_t) (sample * dds->scale_factor >> 15);
+}
+
+static __inline__ void teletone_dds_state_set_tx_level(teletone_dds_state_t *dds, float tx_level)
+{
+	dds->scale_factor = (int) (powf(10.0f, (tx_level - DBM0_MAX_POWER) / 20.0f) * (32767.0f * 1.414214f));
+	dds->tx_level = tx_level;
+}
+
+static __inline__ void teletone_dds_state_reset_accum(teletone_dds_state_t *dds)
+{
+	dds->phase_accumulator = 0;
+}
+
+static __inline__ int teletone_dds_state_set_tone(teletone_dds_state_t *dds, teletone_process_t tone, uint32_t rate, uint32_t pindex)
+{
+	if (pindex < MAX_PHASE_TONES)  {
+		dds->phase_rate[pindex] = teletone_dds_phase_rate(tone, rate);
+		return 0;
+	}
+	
+	return -1;
+}
+
+
+
+/*! \file libteletone_generate.h
+  \brief Tone Generation Routines
+
+  This module is responsible for tone generation specifics
+*/
+
+typedef int16_t teletone_audio_t;
+struct teletone_generation_session;
+typedef int (*tone_handler)(struct teletone_generation_session *ts, teletone_tone_map_t *map);
+
+/*! \brief An abstraction to store a tone generation session */
+struct teletone_generation_session {
+	/*! An array of tone mappings to character mappings */
+	teletone_tone_map_t TONES[TELETONE_TONE_RANGE];
+	/*! The number of channels the output audio should be in */
+	int channels;
+	/*! The Rate in hz of the output audio */
+	int rate;
+	/*! The duration (in samples) of the output audio */
+	int duration;
+	/*! The duration of silence to append after the initial audio is generated */
+	int wait;
+	/*! The duration (in samples) of the output audio (takes prescedence over actual duration value) */
+	int tmp_duration;
+	/*! The duration of silence to append after the initial audio is generated (takes prescedence over actual wait value)*/
+	int tmp_wait;
+	/*! Number of loops to repeat a single instruction*/
+	int loops;
+	/*! Number of loops to repeat the entire set of instructions*/
+	int LOOPS;
+	/*! Number to mutiply total samples by to determine when to begin ascent or decent e.g. 0=beginning 4=(last 25%) */
+	float decay_factor;
+	/*! Direction to perform volume increase/decrease 1/-1*/
+	int decay_direction;
+	/*! Number of samples between increase/decrease of volume */
+	int decay_step;
+	/*! Volume factor of the tone */
+	float volume;
+	/*! Debug on/off */
+	int debug;
+	/*! FILE stream to write debug data to */
+	FILE *debug_stream;
+	/*! Extra user data to attach to the session*/
+	void *user_data;
+	/*! Buffer for storing sample data (dynamic) */
+	teletone_audio_t *buffer;
+	/*! Size of the buffer */
+	int datalen;
+	/*! In-Use size of the buffer */
+	int samples;
+	/*! Callback function called during generation */
+	int dynamic;
+	tone_handler handler;
+};
+
+typedef struct teletone_generation_session teletone_generation_session_t;
+
+
+/*! 
+  \brief Assign a set of tones to a tone_session indexed by a paticular index/character
+  \param ts the tone generation session
+  \param index the index to map the tone to
+  \param ... up to TELETONE_MAX_TONES frequencies terminated by 0.0
+  \return 0
+*/
+TELETONE_API(int) teletone_set_tone(teletone_generation_session_t *ts, int index, ...);
+
+/*! 
+  \brief Assign a set of tones to a single tone map
+  \param map the map to assign the tones to
+  \param ... up to TELETONE_MAX_TONES frequencies terminated by 0.0
+  \return 0
+*/
+TELETONE_API(int) teletone_set_map(teletone_tone_map_t *map, ...);
+
+/*! 
+  \brief Initilize a tone generation session
+  \param ts the tone generation session to initilize
+  \param buflen the size of the buffer(in samples) to dynamically allocate
+  \param handler a callback function to execute when a tone generation instruction is complete
+  \param user_data optional user data to send
+  \return 0
+*/
+TELETONE_API(int) teletone_init_session(teletone_generation_session_t *ts, int buflen, tone_handler handler, void *user_data);
+
+/*! 
+  \brief Free the buffer allocated by a tone generation session
+  \param ts the tone generation session to destroy
+  \return 0
+*/
+TELETONE_API(int) teletone_destroy_session(teletone_generation_session_t *ts);
+
+/*! 
+  \brief Execute a single tone generation instruction
+  \param ts the tone generation session to consult for parameters
+  \param map the tone mapping to use for the frequencies
+  \return 0
+*/
+TELETONE_API(int) teletone_mux_tones(teletone_generation_session_t *ts, teletone_tone_map_t *map);
+
+/*! 
+  \brief Execute a tone generation script and call callbacks after each instruction
+  \param ts the tone generation session to execute on
+  \param cmd the script to execute
+  \return 0
+*/
+TELETONE_API(int) teletone_run(teletone_generation_session_t *ts, const char *cmd);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */

Added: freeswitch/trunk/libs/freetdm/src/include/sangoma_tdm_api.h (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/include/sangoma_tdm_api.h	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/include/sangoma_tdm_api.h	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,321 @@
+/*****************************************************************************
+ * sangoma_tdm_api.h	Sangoma TDM API Portability functions
+ *
+ * Author(s):	Anthony Minessale II <anthmct@yahoo.com>
+ *              Nenad Corbic <ncorbic@sangoma.com>
+ *				Michael Jerris <mike@jerris.com>
+ *				David Rokhvarg <davidr@sangoma.com>
+ *
+ * Copyright:	(c) 2006 Nenad Corbic <ncorbic@sangoma.com>
+ *                       Anthony Minessale II
+ *				(c) 1984-2007 Sangoma Technologies Inc.
+ *
+ * ============================================================================
+ */
+
+#ifndef _SANGOMA_TDM_API_H
+#define _SANGOMA_TDM_API_H
+
+/* This entire block of defines and includes from this line, through #define FNAME_LEN probably dont belong here */
+/* most of them probably belong in wanpipe_defines.h, then each header file listed included below properly included */
+/* in the header files that depend on them, leaving only the include for wanpipe_tdm_api.h left in this file or */
+/* possibly integrating the rest of this file diretly into wanpipe_tdm_api.h */
+#ifndef __WINDOWS__
+#if defined(WIN32) || defined(WIN64) || defined(_MSC_VER) || defined(_WIN32)
+#define __WINDOWS__
+#endif /* defined(WIN32) || defined(WIN64) || defined(_MSC_VER) || defined(_WIN32) */
+#endif /* ndef __WINDOWS__ */
+
+#if defined(__WINDOWS__)
+#if defined(_MSC_VER)
+/* disable some warnings caused by wanpipe headers that will need to be fixed in those headers */
+#pragma warning(disable:4201 4214)
+
+/* sang_api.h(74) : warning C4201: nonstandard extension used : nameless struct/union */
+
+/* wanpipe_defines.h(219) : warning C4214: nonstandard extension used : bit field types other than int */
+/* wanpipe_defines.h(220) : warning C4214: nonstandard extension used : bit field types other than int */
+/* this will break for any compilers that are strict ansi or strict c99 */
+
+/* The following definition for that struct should resolve this warning and work for 32 and 64 bit */
+#if 0
+struct iphdr {
+	
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+	unsigned    ihl:4,
+		version:4;
+#elif defined (__BIG_ENDIAN_BITFIELD)
+	unsigned    version:4,
+		ihl:4;
+#else
+# error  "unknown byteorder!"
+#endif
+	unsigned    tos:8;
+	unsigned		tot_len:16;
+	unsigned		id:16;
+	unsigned		frag_off:16;
+	__u8    ttl;
+	__u8    protocol;
+	__u16   check;
+	__u32   saddr;
+	__u32   daddr;
+	/*The options start here. */
+};
+#endif /* #if 0 */
+
+#define __inline__ __inline
+#endif /* defined(_MSC_VER) */
+#include <windows.h>
+/* do we like the name WP_INVALID_SOCKET or should it be changed? */
+#define WP_INVALID_SOCKET INVALID_HANDLE_VALUE
+#else /* defined(__WINDOWS__) */ 
+#define WP_INVALID_SOCKET -1
+#include <stropts.h>
+#include <poll.h>
+#include <sys/socket.h>
+#endif
+
+#include <wanpipe_defines.h>
+#include <wanpipe_cfg.h>
+#include <wanpipe_tdm_api.h>
+#include <sdla_te1_pmc.h>
+#ifdef __WINDOWS__
+#include <sang_status_defines.h>
+#include <sang_api.h>
+#endif
+#include <sdla_aft_te1.h>
+
+#define FNAME_LEN	50
+
+
+#if defined(__WINDOWS__)
+/* This might be broken on windows, as POLL_EVENT_TELEPHONY seems to be commented out in sang_api.h.. it should be added to POLLPRI */
+#define POLLPRI (POLL_EVENT_LINK_STATE | POLL_EVENT_LINK_CONNECT | POLL_EVENT_LINK_DISCONNECT)
+#endif
+
+/* return -1 for error, 0 for timeout or 1 for success. *flags is set to the poll evetns POLLIN | POLLOUT | POLLPRI based on the result of the poll */
+/* on windows we actually have POLLPRI defined with several events, so we could theoretically poll */
+/* for specific events.  Is there any way to do this on *nix as well? */ 
+
+/* a cross platform way to poll on an actual pollset (span and/or list of spans) will probably also be needed for analog */
+/* so we can have one analong handler thread that will deal with all the idle analog channels for events */
+/* the alternative would be for the driver to provide one socket for all of the oob events for all analog channels */
+static __inline__ int tdmv_api_wait_socket(sng_fd_t fd, int timeout, int *flags)
+{
+#if defined(__WINDOWS__)
+	DWORD ln;
+	API_POLL_STRUCT	api_poll;
+
+	memset(&api_poll, 0x00, sizeof(API_POLL_STRUCT));
+	
+	api_poll.user_flags_bitmap = *flags;
+	api_poll.timeout = timeout;
+
+	if (!DeviceIoControl(
+						 fd,
+						 IoctlApiPoll,
+						 (LPVOID)NULL,
+						 0L,
+						 (LPVOID)&api_poll,
+						 sizeof(API_POLL_STRUCT),
+						 (LPDWORD)(&ln),
+						 (LPOVERLAPPED)NULL)) {
+		return -1;
+	}
+
+	*flags = 0;
+
+	switch(api_poll.operation_status)
+		{
+		case SANG_STATUS_RX_DATA_AVAILABLE:
+			break;
+
+		case SANG_STATUS_RX_DATA_TIMEOUT:
+			return 0;
+
+		default:
+			return -1;
+		}
+
+	if (api_poll.poll_events_bitmap == 0){
+		return -1;
+	}
+
+	if (api_poll.poll_events_bitmap & POLL_EVENT_TIMEOUT) {
+		return 0;
+	}
+
+	*flags = api_poll.poll_events_bitmap;
+
+	return 1;
+#else
+    struct pollfd pfds[1];
+    int res;
+
+    memset(&pfds[0], 0, sizeof(pfds[0]));
+    pfds[0].fd = fd;
+    pfds[0].events = *flags;
+    res = poll(pfds, 1, timeout);
+	*flags = 0;
+
+	if (pfds[0].revents & POLLERR) {
+		res = -1;
+	}
+
+	if (res > 0) {
+		*flags = pfds[0].revents;
+	}
+
+    return res;
+#endif
+}
+
+/* on windows right now, there is no way to specify if we want to read events here or not, we allways get them here */
+/* we need some what to select if we are reading regular tdm msgs or events */
+/* need to either have 2 functions, 1 for events, 1 for regural read, or a flag on this function to choose */
+/* 2 functions preferred.  Need implementation for the event function for both nix and windows that is threadsafe */
+static __inline__ int tdmv_api_readmsg_tdm(sng_fd_t fd, void *hdrbuf, int hdrlen, void *databuf, int datalen)
+{
+	/* What do we need to do here to avoid having to do all */
+	/* the memcpy's on windows and still maintain api compat with nix */
+	int rx_len=0;
+#if defined(__WINDOWS__)
+	static RX_DATA_STRUCT	rx_data;
+	api_header_t			*pri;
+	wp_tdm_api_rx_hdr_t		*tdm_api_rx_hdr;
+	wp_tdm_api_rx_hdr_t		*user_buf = (wp_tdm_api_rx_hdr_t*)hdrbuf;
+	DWORD ln;
+
+	if (hdrlen != sizeof(wp_tdm_api_rx_hdr_t)){
+		return -1;
+	}
+
+	if (!DeviceIoControl(
+						 fd,
+						 IoctlReadCommand,
+						 (LPVOID)NULL,
+						 0L,
+						 (LPVOID)&rx_data,
+						 sizeof(RX_DATA_STRUCT),
+						 (LPDWORD)(&ln),
+						 (LPOVERLAPPED)NULL
+						 )){
+		return -1;
+	}
+
+	pri = &rx_data.api_header;
+	tdm_api_rx_hdr = (wp_tdm_api_rx_hdr_t*)rx_data.data;
+
+	user_buf->wp_tdm_api_event_type = pri->operation_status;
+
+	switch(pri->operation_status)
+		{
+		case SANG_STATUS_RX_DATA_AVAILABLE:
+			if (pri->data_length > datalen){
+				break;
+			}
+			memcpy(databuf, rx_data.data, pri->data_length);
+			rx_len = pri->data_length;
+			break;
+
+		default:
+			break;
+		}
+
+#else
+	struct msghdr msg;
+	struct iovec iov[2];
+
+	memset(&msg,0,sizeof(struct msghdr));
+
+	iov[0].iov_len=hdrlen;
+	iov[0].iov_base=hdrbuf;
+
+	iov[1].iov_len=datalen;
+	iov[1].iov_base=databuf;
+
+	msg.msg_iovlen=2;
+	msg.msg_iov=iov;
+
+	rx_len = read(fd,&msg,datalen+hdrlen);
+
+	if (rx_len <= sizeof(wp_tdm_api_rx_hdr_t)){
+		return -EINVAL;
+	}
+
+	rx_len-=sizeof(wp_tdm_api_rx_hdr_t);
+#endif
+    return rx_len;
+}                    
+
+static __inline__ int tdmv_api_writemsg_tdm(sng_fd_t fd, void *hdrbuf, int hdrlen, void *databuf, unsigned short datalen)
+{
+	/* What do we need to do here to avoid having to do all */
+	/* the memcpy's on windows and still maintain api compat with nix */
+	int bsent = 0;
+#if defined(__WINDOWS__)
+	static TX_DATA_STRUCT	local_tx_data;
+	api_header_t			*pri;
+	DWORD ln;
+
+	/* Are these really not needed or used???  What about for nix?? */
+	(void)hdrbuf;
+	(void)hdrlen;
+
+	pri = &local_tx_data.api_header;
+
+	pri->data_length = datalen;
+	memcpy(local_tx_data.data, databuf, pri->data_length);
+
+	if (!DeviceIoControl(
+						 fd,
+						 IoctlWriteCommand,
+						 (LPVOID)&local_tx_data,
+						 (ULONG)sizeof(TX_DATA_STRUCT),
+						 (LPVOID)&local_tx_data,
+						 sizeof(TX_DATA_STRUCT),
+						 (LPDWORD)(&ln),
+						 (LPOVERLAPPED)NULL
+						 )){
+		return -1;
+	}
+
+	if (local_tx_data.api_header.operation_status == SANG_STATUS_SUCCESS) {
+		bsent = datalen;
+	}
+#else
+	struct msghdr msg;
+	struct iovec iov[2];
+
+	memset(&msg,0,sizeof(struct msghdr));
+
+	iov[0].iov_len = hdrlen;
+	iov[0].iov_base = hdrbuf;
+
+	iov[1].iov_len = datalen;
+	iov[1].iov_base = databuf;
+
+	msg.msg_iovlen = 2;
+	msg.msg_iov = iov;
+
+	bsent = write(fd, &msg, datalen + hdrlen);
+	if (bsent > 0){
+		bsent -= sizeof(wp_tdm_api_tx_hdr_t);
+	}
+#endif
+	return bsent;
+}
+
+#endif /* _SANGOMA_TDM_API_H */
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
+

Added: freeswitch/trunk/libs/freetdm/src/include/uart.h (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/include/uart.h	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/include/uart.h	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,83 @@
+/*
+ *	uart.h
+ *
+ *	Copyright (c) 2005 Robert Krten.  All Rights Reserved.
+ *
+ *	Redistribution and use in source and binary forms, with or without
+ *	modification, are permitted provided that the following conditions
+ *	are met:
+ *
+ *	1. Redistributions of source code must retain the above copyright
+ *	   notice, this list of conditions and the following disclaimer.
+ *	2. Redistributions in binary form must reproduce the above copyright
+ *	   notice, this list of conditions and the following disclaimer in the
+ *	   documentation and/or other materials provided with the distribution.
+ *
+ *	THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
+ *	ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ *	IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ *	ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE
+ *	FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ *	DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ *	OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ *	HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ *	LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ *	OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ *	SUCH DAMAGE.
+ *
+ *	This module contains the manifest constants and declarations for
+ *	the UART module.
+ *
+ *	2005 06 19	R. Krten		created
+*/
+
+#ifndef	__UART_H__
+#define	__UART_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef void (*bytehandler_func_t) (void *, int);
+typedef void (*bithandler_func_t) (void *, int);
+
+
+typedef struct dsp_uart_attr_s
+{
+	bytehandler_func_t	bytehandler;					/* byte handler */
+	void				*bytehandler_arg;				/* arbitrary ID passed to bytehandler as first argument */
+}	dsp_uart_attr_t;
+
+typedef struct
+{
+	dsp_uart_attr_t		attr;
+	int					have_start;						/* wait for start bit to show up */
+	int					data;							/* data buffer */
+	int					nbits;							/* number of bits accumulated so far */
+}	dsp_uart_handle_t;
+
+/*
+ *	Function prototypes
+ *
+ *	General calling order is:
+ *		a) create the attributes structure (dsp_uart_attr_init)
+ *		b) initialize fields in the attributes structure (dsp_uart_attr_set_*)
+ *		c) create a Bell-202 handle (dsp_uart_create)
+ *		d) feed bits through dsp_uart_bit_handler
+*/
+
+void					dsp_uart_attr_init(dsp_uart_attr_t *attributes);
+
+bytehandler_func_t		dsp_uart_attr_get_bytehandler(dsp_uart_attr_t *attributes, void **bytehandler_arg);
+void					dsp_uart_attr_set_bytehandler(dsp_uart_attr_t *attributes, bytehandler_func_t bytehandler, void *bytehandler_arg);
+
+dsp_uart_handle_t *		dsp_uart_create(dsp_uart_attr_t *attributes);
+void					dsp_uart_destroy(dsp_uart_handle_t **handle);
+
+void					dsp_uart_bit_handler(void *handle, int bit);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+

Added: freeswitch/trunk/libs/freetdm/src/isdn/5ESSStateNT.c (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/isdn/5ESSStateNT.c	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/isdn/5ESSStateNT.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,132 @@
+/*****************************************************************************
+
+  FileName:     5ESSStateNT.c
+
+  Contents:     AT&T 5ESS ISDN State Engine for NT (Network Mode).
+
+	            The controlling state engine for Q.931 is the state engine
+	            on the NT side. The state engine on the TE side is a slave 
+	            of this. The TE side maintain it's own states as described in
+	            ITU-T Q931, but will in    raise conditions be overridden by 
+	            the NT side.
+
+  License/Copyright:
+
+  Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+  email:janvb@caselaboratories.com  
+
+  Copyright (c) 2007, Michael Jerris. All rights reserved.
+  email:mike@jerris.com  
+  
+  Copyright (c) 2007, Michael S. Collins, All rights reserved.
+  email:mcollins@fcnetwork.com
+  
+  Redistribution and use in source and binary forms, with or without 
+  modification, are permitted provided that the following conditions are 
+  met:
+
+	* Redistributions of source code must retain the above copyright notice, 
+	  this list of conditions and the following disclaimer.
+	* Redistributions in binary form must reproduce the above copyright notice, 
+	  this list of conditions and the following disclaimer in the documentation 
+	  and/or other materials provided with the distribution.
+	* Neither the name of the Case Labs, Ltd nor the names of its contributors 
+	  may be used to endorse or promote products derived from this software 
+	  without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
+  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
+  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+  POSSIBILITY OF SUCH DAMAGE.
+*****************************************************************************/
+
+#include "5ESS.h"
+
+/*****************************************************************************
+  Function:     ATT5ESSCreateNT
+
+  Description:  Will create the AT&T 5ESS ISDN NT as a Dialect in the stack. The first
+	            bulk set up the message handlers, the second bulk the IE
+	            encoders/coders, and the last bulk set up the state table.
+
+  Parameters:   i       Dialect index
+*****************************************************************************/
+void ATT5ESSCreateNT(L3UCHAR i)
+{
+	Q931SetMesProc(Q931mes_ALERTING,             i, Q931ProcAlertingNT,          Q931Umes_Alerting,          Q931Pmes_Alerting);
+	Q931SetMesProc(Q931mes_CALL_PROCEEDING,      i, Q931ProcCallProceedingNT,    Q931Umes_CallProceeding,    Q931Pmes_CallProceeding);
+	Q931SetMesProc(Q931mes_CONNECT,              i, Q931ProcConnectNT,           Q931Umes_Connect,           Q931Pmes_Connect);
+	Q931SetMesProc(Q931mes_CONNECT_ACKNOWLEDGE,  i, Q931ProcConnectAckNT,        Q931Umes_ConnectAck,        Q931Pmes_ConnectAck);
+	Q931SetMesProc(Q931mes_PROGRESS,             i, Q931ProcProgressNT,          Q931Umes_Progress,          Q931Pmes_Progress);
+	Q931SetMesProc(Q931mes_SETUP,                i, Q931ProcSetupNT,             Q931Umes_Setup,             Q931Pmes_Setup);
+	Q931SetMesProc(Q931mes_SETUP_ACKNOWLEDGE,    i, Q931ProcSetupAckNT,          Q931Umes_SetupAck,          Q931Pmes_SetupAck);
+	Q931SetMesProc(Q931mes_RESUME,               i, Q931ProcResumeNT,            Q931Umes_Resume,            Q931Pmes_Resume);
+	Q931SetMesProc(Q931mes_RESUME_ACKNOWLEDGE,   i, Q931ProcResumeAckNT,         Q931Umes_ResumeAck,         Q931Pmes_ResumeAck);
+	Q931SetMesProc(Q931mes_RESUME_REJECT,        i, Q931ProcResumeRejectNT,      Q931Umes_ResumeReject,      Q931Pmes_ResumeReject);
+	Q931SetMesProc(Q931mes_SUSPEND,              i, Q931ProcSuspendNT,           Q931Umes_Suspend,           Q931Pmes_Suspend);
+	Q931SetMesProc(Q931mes_SUSPEND_ACKNOWLEDGE,  i, Q931ProcSuspendAckNT,        Q931Umes_SuspendAck,        Q931Pmes_SuspendAck);
+	Q931SetMesProc(Q931mes_SUSPEND_REJECT,       i, Q931ProcSuspendRejectNT,     Q931Umes_SuspendReject,     Q931Pmes_SuspendReject);
+	Q931SetMesProc(Q931mes_USER_INFORMATION,     i, Q931ProcUserInformationNT,   Q931Umes_UserInformation,   Q931Pmes_UserInformation);
+	Q931SetMesProc(Q931mes_DISCONNECT,           i, Q931ProcDisconnectNT,        Q931Umes_Disconnect,        Q931Pmes_Disconnect);
+	Q931SetMesProc(Q931mes_RELEASE,              i, Q931ProcReleaseNT,           Q931Umes_Release,           Q931Pmes_Release);
+	Q931SetMesProc(Q931mes_RELEASE_COMPLETE,     i, Q931ProcReleaseCompleteNT,   Q931Umes_ReleaseComplete,   Q931Pmes_ReleaseComplete);
+	Q931SetMesProc(Q931mes_RESTART,              i, Q931ProcRestartNT,           Q931Umes_Restart,           Q931Pmes_Restart);
+	Q931SetMesProc(Q931mes_RESTART_ACKNOWLEDGE,  i, Q931ProcRestartAckNT,        Q931Umes_RestartAck,        Q931Pmes_RestartAck);
+	Q931SetMesProc(Q931mes_CONGESTION_CONTROL,   i, Q931ProcCongestionControlNT, Q931Umes_CongestionControl, Q931Pmes_CongestionControl);
+	Q931SetMesProc(Q931mes_INFORMATION,          i, Q931ProcInformationNT,       Q931Umes_Information,       Q931Pmes_Information);
+	Q931SetMesProc(Q931mes_NOTIFY,               i, Q931ProcNotifyNT,            Q931Umes_Notify,            Q931Pmes_Notify);
+	Q931SetMesProc(Q931mes_STATUS,               i, Q931ProcStatusNT,            Q931Umes_Status,            Q931Pmes_Status);
+	Q931SetMesProc(Q931mes_STATUS_ENQUIRY,       i, Q931ProcStatusEnquiryNT,     Q931Umes_StatusEnquiry,     Q931Pmes_StatusEnquiry);
+	Q931SetMesProc(Q931mes_SEGMENT,              i, Q931ProcSegmentNT,           Q931Umes_Segment,           Q931Pmes_Segment);
+
+	Q931SetMesProc(Q932mes_FACILITY,             i, Q932ProcFacilityNT,          Q932Umes_Facility,          Q932Pmes_Facility);
+	Q931SetMesProc(Q932mes_HOLD,                 i, Q932ProcHoldNT,              Q932Umes_Hold,              Q932Pmes_Hold);
+	Q931SetMesProc(Q932mes_HOLD_ACKNOWLEDGE,     i, Q932ProcHoldAckNT,           Q932Umes_HoldAck,           Q932Pmes_HoldAck);
+	Q931SetMesProc(Q932mes_HOLD_REJECT,          i, Q932ProcHoldRejectNT,        Q932Umes_HoldReject,        Q932Pmes_HoldReject);
+	Q931SetMesProc(Q932mes_REGISTER,             i, Q932ProcRegisterNT,          Q932Umes_Register,          Q932Pmes_Register);
+	Q931SetMesProc(Q932mes_RETRIEVE,             i, Q932ProcRetrieveNT,          Q932Umes_Retrieve,          Q932Pmes_Retrieve);
+	Q931SetMesProc(Q932mes_RETRIEVE_ACKNOWLEDGE, i, Q932ProcRetrieveAckNT,       Q932Umes_RetrieveAck,       Q932Pmes_RetrieveAck);
+	Q931SetMesProc(Q932mes_RETRIEVE_REJECT,      i, Q932ProcRetrieveRejectNT,    Q932Umes_RetrieveReject,    Q932Pmes_RetrieveReject);
+
+	/* Set up the IE encoder/decoder handle table.*/ 
+	Q931SetIEProc(Q931ie_SEGMENTED_MESSAGE,                i, Q931Pie_Segment,           Q931Uie_Segment);
+	Q931SetIEProc(Q931ie_BEARER_CAPABILITY,                i, Q931Pie_BearerCap,         Q931Uie_BearerCap);
+	Q931SetIEProc(Q931ie_CAUSE,                            i, Q931Pie_Cause,             Q931Uie_Cause);
+	Q931SetIEProc(Q931ie_CALL_IDENTITY,                    i, Q931Pie_CallID,            Q931Uie_CallID);
+	Q931SetIEProc(Q931ie_CALL_STATE,                       i, Q931Pie_CallState,         Q931Uie_CallState);
+	Q931SetIEProc(Q931ie_CHANNEL_IDENTIFICATION,           i, Q931Pie_ChanID,            Q931Uie_ChanID);
+	Q931SetIEProc(Q931ie_PROGRESS_INDICATOR,               i, Q931Pie_ProgInd,           Q931Uie_ProgInd);
+	Q931SetIEProc(Q931ie_NETWORK_SPECIFIC_FACILITIES,      i, Q931Pie_NetFac,            Q931Uie_NetFac);
+	Q931SetIEProc(Q931ie_NOTIFICATION_INDICATOR,           i, Q931Pie_NotifInd,          Q931Uie_NotifInd);
+	Q931SetIEProc(Q931ie_DISPLAY,                          i, Q931Pie_Display,           Q931Uie_Display);
+	Q931SetIEProc(Q931ie_DATETIME,                         i, Q931Pie_DateTime,          Q931Uie_DateTime);
+	Q931SetIEProc(Q931ie_KEYPAD_FACILITY,                  i, Q931Pie_KeypadFac,         Q931Uie_KeypadFac);
+	Q931SetIEProc(Q931ie_SIGNAL,                           i, Q931Pie_Signal,            Q931Uie_Signal);
+	Q931SetIEProc(Q931ie_TRANSIT_DELAY_SELECTION_AND_IND,  i, Q931Pie_TransNetSel,       Q931Uie_TransNetSel);
+	Q931SetIEProc(Q931ie_CALLING_PARTY_NUMBER,             i, Q931Pie_CallingNum,        Q931Uie_CallingNum);
+	Q931SetIEProc(Q931ie_CALLING_PARTY_SUBADDRESS,         i, Q931Pie_CallingSub,        Q931Uie_CallingSub);
+	Q931SetIEProc(Q931ie_CALLED_PARTY_NUMBER,              i, Q931Pie_CalledNum,         Q931Uie_CalledNum);
+	Q931SetIEProc(Q931ie_CALLED_PARTY_SUBADDRESS,          i, Q931Pie_CalledSub,         Q931Uie_CalledSub);
+	Q931SetIEProc(Q931ie_TRANSIT_NETWORK_SELECTION,        i, Q931Pie_TransNetSel,       Q931Uie_TransNetSel);
+	Q931SetIEProc(Q931ie_RESTART_INDICATOR,                i, Q931Pie_RestartInd,        Q931Uie_RestartInd);
+	Q931SetIEProc(Q931ie_LOW_LAYER_COMPATIBILITY,          i, Q931Pie_LLComp,            Q931Uie_LLComp);
+	Q931SetIEProc(Q931ie_HIGH_LAYER_COMPATIBILITY,         i, Q931Pie_HLComp,            Q931Uie_HLComp);
+	Q931SetIEProc(Q931ie_USER_USER,                        i, Q931Pie_UserUser,          Q931Uie_UserUser);
+	Q931SetIEProc(Q931ie_GENERIC_DIGITS,                   i, Q931Pie_GenericDigits,     Q931Uie_GenericDigits);
+
+	Q931SetIEProc(Q931ie_CONNECTED_NUMBER, i, Q931Pie_Generic, Q931Uie_Generic);
+	Q931SetIEProc(Q931ie_FACILITY,         i, Q931Pie_Generic, Q931Uie_Generic);
+
+	/* The following define a state machine. The point is that the Message  */
+	/* procs can when search this to find out if the message/state          */
+	/* combination is legale. If not, the proc for unexpected message apply.*/
+
+	/* TODO define state table here */
+}

Added: freeswitch/trunk/libs/freetdm/src/isdn/5ESSStateTE.c (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/isdn/5ESSStateTE.c	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/isdn/5ESSStateTE.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,291 @@
+/*****************************************************************************
+
+  FileName:     5ESSStateTE.c
+
+  Contents:     AT&T 5ESS ISDN State Engine for TE (User Mode).
+
+	            The controlling state engine for Q.931 is the state engine
+	            on the NT side. The state engine on the TE side is a slave 
+	            of this. The TE side maintain it's own states as described in
+	            ITU-T Q931, but will in    raise conditions be overridden by 
+	            the NT side.
+
+	            This reference implementation uses a process per message, 
+	            meaning that each message must check call states. This
+	            is easier for dialect maintenance as each message proc
+	            can be replaced individually. A new TE variant only
+	            need to copy the Q931CreateTE and replace those procs or
+	            need to override.
+
+  License/Copyright:
+
+  Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+  email:janvb@caselaboratories.com  
+
+  Copyright (c) 2007, Michael Jerris. All rights reserved.
+  email:mike@jerris.com  
+  
+  Copyright (c) 2007, Michael S. Collins, All rights reserved.
+  email:mcollins@fcnetwork.com
+  
+  Redistribution and use in source and binary forms, with or without 
+  modification, are permitted provided that the following conditions are 
+  met:
+
+	* Redistributions of source code must retain the above copyright notice, 
+	this list of conditions and the following disclaimer.
+	* Redistributions in binary form must reproduce the above copyright notice, 
+	this list of conditions and the following disclaimer in the documentation 
+	and/or other materials provided with the distribution.
+	* Neither the name of the Case Labs, Ltd nor the names of its contributors 
+	may be used to endorse or promote products derived from this software 
+	without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
+  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
+  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+  POSSIBILITY OF SUCH DAMAGE.
+*****************************************************************************/
+
+#include "5ESS.h"
+extern L3INT Q931L4HeaderSpace;
+
+/*****************************************************************************
+  Function:     ATT5ESSCreateTE
+
+  Description:  Will create the AT&T 5ESS TE as a Dialect in the stack. The first
+	            bulk set up the message handlers, the second bulk the IE
+	            encoders/coders, and the last bulk set up the state table.
+
+  Parameters:   i       Dialect index
+*****************************************************************************/
+void ATT5ESSCreateTE(L3UCHAR i)
+{
+	Q931SetMesProc(Q931mes_ALERTING,             i, Q931ProcAlertingTE,          Q931Umes_Alerting,          Q931Pmes_Alerting);
+	Q931SetMesProc(Q931mes_CALL_PROCEEDING,      i, Q931ProcCallProceedingTE,    Q931Umes_CallProceeding,    Q931Pmes_CallProceeding);
+	Q931SetMesProc(Q931mes_CONNECT,              i, ATT5ESSProc0x07TE,           ATT5ESSUmes_0x07,           ATT5ESSPmes_0x07);
+	Q931SetMesProc(Q931mes_CONNECT_ACKNOWLEDGE,  i, ATT5ESSProc0x0fTE,           ATT5ESSUmes_0x0f,           ATT5ESSPmes_0x0f);
+	Q931SetMesProc(Q931mes_PROGRESS,             i, Q931ProcProgressTE,          Q931Umes_Progress,          Q931Pmes_Progress);
+	Q931SetMesProc(Q931mes_SETUP,                i, Q931ProcSetupTE,             ATT5ESSUmes_Setup,          ATT5ESSPmes_Setup);
+	Q931SetMesProc(Q931mes_SETUP_ACKNOWLEDGE,    i, Q931ProcSetupAckTE,          Q931Umes_SetupAck,          Q931Pmes_SetupAck);
+	Q931SetMesProc(Q931mes_RESUME,               i, Q931ProcResumeTE,            Q931Umes_Resume,            Q931Pmes_Resume);
+	Q931SetMesProc(Q931mes_RESUME_ACKNOWLEDGE,   i, Q931ProcResumeAckTE,         Q931Umes_ResumeAck,         Q931Pmes_ResumeAck);
+	Q931SetMesProc(Q931mes_RESUME_REJECT,        i, Q931ProcResumeRejectTE,      Q931Umes_ResumeReject,      Q931Pmes_ResumeReject);
+	Q931SetMesProc(Q931mes_SUSPEND,              i, Q931ProcSuspendTE,           Q931Umes_Suspend,           Q931Pmes_Suspend);
+	Q931SetMesProc(Q931mes_SUSPEND_ACKNOWLEDGE,  i, Q931ProcSuspendAckTE,        Q931Umes_SuspendAck,        Q931Pmes_SuspendAck);
+	Q931SetMesProc(Q931mes_SUSPEND_REJECT,       i, Q931ProcSuspendRejectTE,     Q931Umes_SuspendReject,     Q931Pmes_SuspendReject);
+	Q931SetMesProc(Q931mes_USER_INFORMATION,     i, Q931ProcUserInformationTE,   Q931Umes_UserInformation,   Q931Pmes_UserInformation);
+	Q931SetMesProc(Q931mes_DISCONNECT,           i, Q931ProcDisconnectTE,        Q931Umes_Disconnect,        Q931Pmes_Disconnect);
+	Q931SetMesProc(Q931mes_RELEASE,              i, Q931ProcReleaseTE,           Q931Umes_Release,           Q931Pmes_Release);
+	Q931SetMesProc(Q931mes_RELEASE_COMPLETE,     i, Q931ProcReleaseCompleteTE,   Q931Umes_ReleaseComplete,   Q931Pmes_ReleaseComplete);
+	Q931SetMesProc(Q931mes_RESTART,              i, Q931ProcRestartTE,           Q931Umes_Restart,           Q931Pmes_Restart);
+	Q931SetMesProc(Q931mes_RESTART_ACKNOWLEDGE,  i, Q931ProcRestartAckTE,        Q931Umes_RestartAck,        Q931Pmes_RestartAck);
+	Q931SetMesProc(Q931mes_CONGESTION_CONTROL,   i, Q931ProcCongestionControlTE, Q931Umes_CongestionControl, Q931Pmes_CongestionControl);
+	Q931SetMesProc(Q931mes_INFORMATION,          i, Q931ProcInformationTE,       Q931Umes_Information,       Q931Pmes_Information);
+	Q931SetMesProc(Q931mes_NOTIFY,               i, Q931ProcNotifyTE,            Q931Umes_Notify,            Q931Pmes_Notify);
+	Q931SetMesProc(Q931mes_STATUS,               i, Q931ProcStatusTE,            Q931Umes_Status,            Q931Pmes_Status);
+	Q931SetMesProc(Q931mes_STATUS_ENQUIRY,       i, Q931ProcStatusEnquiryTE,     Q931Umes_StatusEnquiry,     Q931Pmes_StatusEnquiry);
+	Q931SetMesProc(Q931mes_SEGMENT,              i, Q931ProcSegmentTE,           Q931Umes_Segment,           Q931Pmes_Segment);
+
+	Q931SetMesProc(Q932mes_FACILITY,             i, Q932ProcFacilityTE,          Q932Umes_Facility,          Q932Pmes_Facility);
+	Q931SetMesProc(Q932mes_HOLD,                 i, Q932ProcHoldTE,              Q932Umes_Hold,              Q932Pmes_Hold);
+	Q931SetMesProc(Q932mes_HOLD_ACKNOWLEDGE,     i, Q932ProcHoldAckTE,           Q932Umes_HoldAck,           Q932Pmes_HoldAck);
+	Q931SetMesProc(Q932mes_HOLD_REJECT,          i, Q932ProcHoldRejectTE,        Q932Umes_HoldReject,        Q932Pmes_HoldReject);
+	Q931SetMesProc(Q932mes_REGISTER,             i, Q932ProcRegisterTE,          Q932Umes_Register,          Q932Pmes_Register);
+	Q931SetMesProc(Q932mes_RETRIEVE,             i, Q932ProcRetrieveTE,          Q932Umes_Retrieve,          Q932Pmes_Retrieve);
+	Q931SetMesProc(Q932mes_RETRIEVE_ACKNOWLEDGE, i, Q932ProcRetrieveAckTE,       Q932Umes_RetrieveAck,       Q932Pmes_RetrieveAck);
+	Q931SetMesProc(Q932mes_RETRIEVE_REJECT,      i, Q932ProcRetrieveRejectTE,    Q932Umes_RetrieveReject,    Q932Pmes_RetrieveReject);
+
+	/* Set up the IE encoder/decoder handle table.*/ 
+	Q931SetIEProc(Q931ie_SEGMENTED_MESSAGE,                i, Q931Pie_Segment,           Q931Uie_Segment);
+	Q931SetIEProc(Q931ie_BEARER_CAPABILITY,                i, Q931Pie_BearerCap,         Q931Uie_BearerCap);
+	Q931SetIEProc(Q931ie_CAUSE,                            i, Q931Pie_Cause,             Q931Uie_Cause);
+	Q931SetIEProc(Q931ie_CALL_IDENTITY,                    i, Q931Pie_CallID,            Q931Uie_CallID);
+	Q931SetIEProc(Q931ie_CALL_STATE,                       i, Q931Pie_CallState,         Q931Uie_CallState);
+	Q931SetIEProc(Q931ie_CHANGE_STATUS,                    i, Q931Pie_ChangeStatus,      Q931Uie_ChangeStatus);
+	Q931SetIEProc(Q931ie_CHANNEL_IDENTIFICATION,           i, Q931Pie_ChanID,            Q931Uie_ChanID);
+	Q931SetIEProc(Q931ie_PROGRESS_INDICATOR,               i, Q931Pie_ProgInd,           Q931Uie_ProgInd);
+	Q931SetIEProc(Q931ie_NETWORK_SPECIFIC_FACILITIES,      i, Q931Pie_NetFac,            Q931Uie_NetFac);
+	Q931SetIEProc(Q931ie_NOTIFICATION_INDICATOR,           i, Q931Pie_NotifInd,          Q931Uie_NotifInd);
+	Q931SetIEProc(Q931ie_DISPLAY,                          i, Q931Pie_Display,           Q931Uie_Display);
+	Q931SetIEProc(Q931ie_DATETIME,                         i, Q931Pie_DateTime,          Q931Uie_DateTime);
+	Q931SetIEProc(Q931ie_KEYPAD_FACILITY,                  i, Q931Pie_KeypadFac,         Q931Uie_KeypadFac);
+	Q931SetIEProc(Q931ie_SIGNAL,                           i, Q931Pie_Signal,            Q931Uie_Signal);
+	Q931SetIEProc(Q931ie_TRANSIT_DELAY_SELECTION_AND_IND,  i, Q931Pie_TransNetSel,       Q931Uie_TransNetSel);
+	Q931SetIEProc(Q931ie_CALLING_PARTY_NUMBER,             i, Q931Pie_CallingNum,        Q931Uie_CallingNum);
+	Q931SetIEProc(Q931ie_CALLING_PARTY_SUBADDRESS,         i, Q931Pie_CallingSub,        Q931Uie_CallingSub);
+	Q931SetIEProc(Q931ie_CALLED_PARTY_NUMBER,              i, Q931Pie_CalledNum,         Q931Uie_CalledNum);
+	Q931SetIEProc(Q931ie_CALLED_PARTY_SUBADDRESS,          i, Q931Pie_CalledSub,         Q931Uie_CalledSub);
+	Q931SetIEProc(Q931ie_TRANSIT_NETWORK_SELECTION,        i, Q931Pie_TransNetSel,       Q931Uie_TransNetSel);
+	Q931SetIEProc(Q931ie_RESTART_INDICATOR,                i, Q931Pie_RestartInd,        Q931Uie_RestartInd);
+	Q931SetIEProc(Q931ie_LOW_LAYER_COMPATIBILITY,          i, Q931Pie_LLComp,            Q931Uie_LLComp);
+	Q931SetIEProc(Q931ie_HIGH_LAYER_COMPATIBILITY,         i, Q931Pie_HLComp,            Q931Uie_HLComp);
+	Q931SetIEProc(Q931ie_USER_USER,                        i, Q931Pie_UserUser,          Q931Uie_UserUser);
+	Q931SetIEProc(Q931ie_GENERIC_DIGITS,                   i, Q931Pie_GenericDigits,     Q931Uie_GenericDigits);
+
+	Q931SetIEProc(Q931ie_CONNECTED_NUMBER, i, Q931Pie_Generic, Q931Uie_Generic);
+	Q931SetIEProc(Q931ie_FACILITY,         i, Q931Pie_Generic, Q931Uie_Generic);
+
+	/* The following define a state machine. The point is that the Message  */
+	/* procs can when search this to find out if the message/state          */
+	/* combination is legale. If not, the proc for unexpected message apply.*/
+
+	/* State 0 Idle */
+	Q931AddStateEntry(i, Q931_U0,    Q931mes_RESUME,             2);
+	Q931AddStateEntry(i, Q931_U0,    Q931mes_SETUP,              4);
+	Q931AddStateEntry(i, Q931_U0,    Q931mes_SETUP,              2);
+	Q931AddStateEntry(i, Q931_U0,    Q931mes_STATUS,             4);
+	Q931AddStateEntry(i, Q931_U0,    Q931mes_RELEASE,            4);
+	Q931AddStateEntry(i, Q931_U0,    Q931mes_RELEASE_COMPLETE,   4);
+
+	/* State 1 Call Initiating */
+	Q931AddStateEntry(i, Q931_U1,    Q931mes_DISCONNECT,         2);
+	Q931AddStateEntry(i, Q931_U1,    Q931mes_SETUP_ACKNOWLEDGE,  4);
+	Q931AddStateEntry(i, Q931_U1,    Q931mes_RELEASE_COMPLETE,   4);
+	Q931AddStateEntry(i, Q931_U1,    Q931mes_CALL_PROCEEDING,    4);
+	Q931AddStateEntry(i, Q931_U1,    Q931mes_ALERTING,           4);
+	Q931AddStateEntry(i, Q931_U1,    Q931mes_CONNECT,            4);
+
+	/* State 2 Overlap Sending */
+	Q931AddStateEntry(i, Q931_U2,    Q931mes_INFORMATION,        2);
+	Q931AddStateEntry(i, Q931_U2,    Q931mes_CALL_PROCEEDING,    4);
+	Q931AddStateEntry(i, Q931_U2,    Q931mes_ALERTING,           4);
+	Q931AddStateEntry(i, Q931_U2,    Q931mes_PROGRESS,           4);
+	Q931AddStateEntry(i, Q931_U2,    Q931mes_CONNECT,            4);
+	Q931AddStateEntry(i, Q931_U2,    Q931mes_RELEASE,            2);
+
+	/* State 3 Outgoing Call Proceeding */
+	Q931AddStateEntry(i, Q931_U3,    Q931mes_PROGRESS,           4);
+	Q931AddStateEntry(i, Q931_U3,    Q931mes_ALERTING,           4);
+	Q931AddStateEntry(i, Q931_U3,    Q931mes_CONNECT,            4);
+	Q931AddStateEntry(i, Q931_U3,    Q931mes_RELEASE,            2);
+
+	/* State 4 Call Delivered */
+	Q931AddStateEntry(i, Q931_U4,    Q931mes_CONNECT,            4);
+
+	/* State 6 Call Precent */
+	Q931AddStateEntry(i, Q931_U6,    Q931mes_INFORMATION,        2);
+	Q931AddStateEntry(i, Q931_U6,    Q931mes_ALERTING,           2);
+	Q931AddStateEntry(i, Q931_U6,    Q931mes_CALL_PROCEEDING,    2);
+	Q931AddStateEntry(i, Q931_U6,    Q931mes_CONNECT,            2);
+	Q931AddStateEntry(i, Q931_U6,    Q931mes_RELEASE_COMPLETE,   2);
+	Q931AddStateEntry(i, Q931_U6,    Q931mes_RELEASE,            4);
+	Q931AddStateEntry(i, Q931_U6,    Q931mes_DISCONNECT,         4);
+
+	/* State 7 Call Received */
+	Q931AddStateEntry(i, Q931_U7,    Q931mes_CONNECT,            2);
+
+	/* State 8 Connect request */
+	Q931AddStateEntry(i, Q931_U8,    Q931mes_CONNECT_ACKNOWLEDGE, 4);
+
+	/* State 9 Incoming Call Proceeding */
+	Q931AddStateEntry(i, Q931_U9,    Q931mes_CONNECT,            2);
+	Q931AddStateEntry(i, Q931_U9,    Q931mes_ALERTING,           2);
+	Q931AddStateEntry(i, Q931_U9,    Q931mes_PROGRESS,           2);
+
+	/* State 10 Active */
+	Q931AddStateEntry(i, Q931_U10,   Q931mes_SUSPEND,            2);
+	Q931AddStateEntry(i, Q931_U10,   Q931mes_NOTIFY,             4);
+	Q931AddStateEntry(i, Q931_U10,   Q931mes_NOTIFY,             2);
+
+	/* State 11 Disconnect Request */
+	Q931AddStateEntry(i, Q931_U11,   Q931mes_RELEASE,            4);
+	Q931AddStateEntry(i, Q931_U11,   Q931mes_DISCONNECT,         4);
+	Q931AddStateEntry(i, Q931_U11,   Q931mes_NOTIFY,             4);
+
+	/* State 12 Disconnect Ind */
+	Q931AddStateEntry(i, Q931_U12,   Q931mes_RELEASE,            4);
+	Q931AddStateEntry(i, Q931_U12,   Q931mes_RELEASE,            2);
+
+	/* State 15 Suspend Request */
+	Q931AddStateEntry(i, Q931_U15,   Q931mes_SUSPEND_ACKNOWLEDGE, 4);
+	Q931AddStateEntry(i, Q931_U15,   Q931mes_SUSPEND_REJECT,      4);
+	Q931AddStateEntry(i, Q931_U15,   Q931mes_DISCONNECT,          4);
+	Q931AddStateEntry(i, Q931_U15,   Q931mes_RELEASE,             4);
+
+/* TODO
+	Q931AddStateEntry(i, Q931_U17, 
+	Q931AddStateEntry(i, Q931_U19, 
+	Q931AddStateEntry(i, Q931_U25, 
+*/
+}
+
+/*****************************************************************************
+
+  Function:		ATT5ESSProc0x0fTE
+
+*****************************************************************************/
+L3INT ATT5ESSProc0x0fTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	if (pMes->ProtDisc == 8) {
+		/* Find the call using CRV */
+		ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+		if (ret != Q931E_NO_ERROR)
+			return ret;
+
+		/* TODO chack against state table for illegal or unexpected message here*/
+
+		/* TODO - Set correct timer here */
+		Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	}
+	if (iFrom == 4) {
+		/* TODO Add proc here*/
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom ==2) {
+		/* TODO Add proc here*/
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+
+		if (pMes->ProtDisc == 3 && pTrunk->autoServiceAck) {
+			printf("autoServiceAck is on, responding to Service Req from network...\n");
+			Q931AckService(pTrunk, buf);
+		}
+	}
+	return ret;
+
+}
+
+/*****************************************************************************
+
+  Function:		ATT5ESSProc0x07TE
+
+*****************************************************************************/
+L3INT ATT5ESSProc0x07TE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	if (pMes->ProtDisc == 8) {
+		/* Find the call using CRV */
+		ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+		if (ret != Q931E_NO_ERROR)
+			return ret;
+
+		/* TODO chack against state table for illegal or unexpected message here*/
+
+		/* TODO - Set correct timer here */
+		Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	}
+	if (iFrom == 4) {
+		/* TODO Add proc here*/
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here*/
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+
+}

Added: freeswitch/trunk/libs/freetdm/src/isdn/5ESSmes.c (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/isdn/5ESSmes.c	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/isdn/5ESSmes.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,361 @@
+/*****************************************************************************
+
+  FileName:	5ESSmes.c
+
+  Contents:	Pack/Unpack functions. These functions will unpack a 5ESS ISDN
+		message from the bit packed original format into structs
+		that contains variables sized by the user. It will also pack
+		the struct back into a Q.931 message as required.
+
+		See 5ESS.h for description. 
+
+  License/Copyright:
+
+  Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+  email:janvb@caselaboratories.com  
+
+  Copyright (c) 2007, Michael Jerris. All rights reserved.
+  email:mike@jerris.com
+  
+  Copyright (c) 2007, Michael S. Collins, All rights reserved.
+  email:mcollins@fcnetwork.com
+
+  Redistribution and use in source and binary forms, with or without 
+  modification, are permitted provided that the following conditions are 
+  met:
+
+	* Redistributions of source code must retain the above copyright notice, 
+	this list of conditions and the following disclaimer.
+	* Redistributions in binary form must reproduce the above copyright notice, 
+	this list of conditions and the following disclaimer in the documentation 
+	and/or other materials provided with the distribution.
+	* Neither the name of the Case Labs, Ltd nor the names of its contributors 
+	may be used to endorse or promote products derived from this software 
+	without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
+  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
+  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+  POSSIBILITY OF SUCH DAMAGE.
+
+*****************************************************************************/
+
+#include "5ESS.h"
+
+/*****************************************************************************
+
+  Function:	 ATT5ESSUmes_Setup
+
+*****************************************************************************/
+L3INT ATT5ESSUmes_Setup(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+	L3INT ir = 0;
+	L3INT OOff = 0;
+	L3INT rc = Q931E_NO_ERROR;
+	L3UCHAR last_codeset = 0, codeset = 0;
+	L3UCHAR shift_nolock = 1;
+
+	while (IOff < Size) {
+
+		if (shift_nolock) {
+			codeset = last_codeset;
+		}
+
+		if ((IBuf[IOff] & 0xF0) == Q931ie_SHIFT) {
+			shift_nolock = (IBuf[IOff] & 0x08);
+			if (shift_nolock) {
+				last_codeset = codeset;
+			}
+			codeset = ((IBuf[IOff] & 0x07));
+			IOff++;
+		}
+
+		if (codeset == 0) {
+			switch (IBuf[IOff])
+			{
+			case Q931ie_SENDING_COMPLETE:
+			case Q931ie_BEARER_CAPABILITY:
+			case Q931ie_CHANNEL_IDENTIFICATION:
+			case Q931ie_PROGRESS_INDICATOR:
+			case Q931ie_NETWORK_SPECIFIC_FACILITIES:
+			case Q931ie_DISPLAY:
+			case Q931ie_DATETIME:
+			case Q931ie_KEYPAD_FACILITY:
+			case Q931ie_SIGNAL:
+			case Q931ie_CALLING_PARTY_NUMBER:
+			case Q931ie_CALLING_PARTY_SUBADDRESS:
+			case Q931ie_CALLED_PARTY_NUMBER:
+			case Q931ie_CALLED_PARTY_SUBADDRESS:
+			case Q931ie_TRANSIT_NETWORK_SELECTION:
+			case Q931ie_LOW_LAYER_COMPATIBILITY:
+			case Q931ie_HIGH_LAYER_COMPATIBILITY:
+			case Q931ie_FACILITY:
+				rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+				if (rc != Q931E_NO_ERROR) 
+					return rc;
+				break;
+			case Q931ie_REPEAT_INDICATOR:
+				if (ir < 2) {
+					rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+					ir++;
+				} else {
+					return Q931E_ILLEGAL_IE;
+				}
+				break;
+			default:
+				return Q931E_ILLEGAL_IE;
+				break;
+			}
+		} else if (codeset == 6) {
+			switch (IBuf[IOff])
+			{
+			case Q931ie_GENERIC_DIGITS:
+				rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+				if (rc != Q931E_NO_ERROR) 
+					return rc;
+				break;
+			default:
+				return Q931E_ILLEGAL_IE;
+				break;
+			}
+		} else if (codeset == 7) {
+			switch (IBuf[IOff])
+			{
+			case Q931ie_DISPLAY:
+				rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+				if (rc != Q931E_NO_ERROR) 
+					return rc;
+				break;
+			default:
+				return Q931E_ILLEGAL_IE;
+				break;
+			}
+		} else {
+			return Q931E_ILLEGAL_IE;
+		}
+	}
+	mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:	 ATT5ESSPmes_Setup
+
+  Decription:   Pack a Q931mes_Generic into a real Q.931 message. The user will
+				set up a SETUP message and issue this to the stack where it
+				is processed by Q931ProcSetup that processes and validates
+				it before it actually sends it out. This function is called
+				to compute the real Q.931 message.
+
+  Parameters:   IBuf[IN]	Ptr to un-packed struct
+				ISize[IN]   Size of input buffer (unpacked message).
+				OBuf[OUT]   Ptr to packed 'octet' wise message.
+				OSize[OUT]  Size of packed message.
+
+  Called By:	Q931ProcSetup
+
+*****************************************************************************/
+L3INT ATT5ESSPmes_Setup(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+	L3INT rc = Q931E_NO_ERROR;
+	Q931mes_Generic *pMes = (Q931mes_Generic *)IBuf;
+	L3INT Octet = 0;
+
+	/* Q931 Message Header */
+	Q931MesgHeader(pTrunk, pMes, OBuf, *OSize, &Octet);
+	
+	/* Sending Complete				*/
+	if (Q931IsIEPresent(pMes->SendComplete)) {
+		OBuf[Octet++]	= (L3UCHAR)(pMes->SendComplete & 0x00ff);
+	}
+
+	/* Repeat Indicator */
+	if (Q931IsIEPresent(pMes->RepeatInd)) {
+		OBuf[Octet++]	= (L3UCHAR)(pMes->RepeatInd & 0x00ff);
+	}
+
+	/* Bearer capability */
+	if (Q931IsIEPresent(pMes->BearerCap)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_BEARER_CAPABILITY](pTrunk, Q931GetIEPtr(pMes->BearerCap,pMes->buf), OBuf, &Octet))!=0)
+			return rc;
+	} else {
+		rc = Q931E_BEARERCAP;
+	}
+
+	/* Channel Identification */
+	if (Q931IsIEPresent(pMes->ChanID)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CHANNEL_IDENTIFICATION](pTrunk, Q931GetIEPtr(pMes->ChanID,pMes->buf), OBuf, &Octet))!=0)
+			return rc;
+	}
+
+	/* Progress indicator */
+	if (Q931IsIEPresent(pMes->ProgInd)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_PROGRESS_INDICATOR](pTrunk, Q931GetIEPtr(pMes->ProgInd,pMes->buf), OBuf, &Octet))!=0)
+			return rc;
+	}
+
+	/* Network specific facilities */
+	if (Q931IsIEPresent(pMes->NetFac)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_NETWORK_SPECIFIC_FACILITIES](pTrunk, Q931GetIEPtr(pMes->NetFac,pMes->buf), OBuf, &Octet))!=0)
+			return rc;
+	}
+
+	/* Display */
+	if (Q931IsIEPresent(pMes->Display)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_DISPLAY](pTrunk, Q931GetIEPtr(pMes->Display,pMes->buf), OBuf, &Octet))!=0)
+			return rc;
+	}
+
+	/* Date/Time */
+	if (Q931IsIEPresent(pMes->DateTime)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_DATETIME](pTrunk, Q931GetIEPtr(pMes->DateTime,pMes->buf), OBuf, &Octet))!=0)
+			return rc;
+	}
+
+	/* Keypad Facility */
+	if (Q931IsIEPresent(pMes->KeypadFac)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_KEYPAD_FACILITY](pTrunk, Q931GetIEPtr(pMes->KeypadFac,pMes->buf), OBuf, &Octet))!=0)
+			return rc;
+	}
+
+	/* Signal */
+	if (Q931IsIEPresent(pMes->Signal)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_SIGNAL](pTrunk, Q931GetIEPtr(pMes->Signal,pMes->buf), OBuf, &Octet))!=0)
+			return rc;
+	}
+
+	/* Calling Party Number */
+	if (Q931IsIEPresent(pMes->CallingNum)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CALLING_PARTY_NUMBER](pTrunk, Q931GetIEPtr(pMes->CallingNum,pMes->buf), OBuf, &Octet))!=0)
+			return rc;
+	}
+
+	/* Calling Party Subaddress */
+	if (Q931IsIEPresent(pMes->CallingSub)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CALLING_PARTY_SUBADDRESS](pTrunk, Q931GetIEPtr(pMes->CallingSub,pMes->buf), OBuf, &Octet))!=0)
+			return rc;
+	}
+
+	/* Called Party number */
+	if (Q931IsIEPresent(pMes->CalledNum)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CALLED_PARTY_NUMBER](pTrunk, Q931GetIEPtr(pMes->CalledNum,pMes->buf), OBuf, &Octet))!=0)
+			return rc;
+	}
+
+	/* Called party subaddress */
+	if (Q931IsIEPresent(pMes->CalledSub)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CALLED_PARTY_SUBADDRESS](pTrunk, Q931GetIEPtr(pMes->CalledSub,pMes->buf), OBuf, &Octet))!=0)
+			return rc;
+	}
+
+	/* Transit network selection */
+	if (Q931IsIEPresent(pMes->TransNetSel)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_TRANSIT_NETWORK_SELECTION](pTrunk, Q931GetIEPtr(pMes->TransNetSel,pMes->buf), OBuf, &Octet))!=0)
+			return rc;
+	}
+
+	/* Repeat Indicator */
+	if (Q931IsIEPresent(pMes->LLRepeatInd)) {
+		rc = Q931E_UNKNOWN_IE;/* TODO */
+	}
+
+	/* Low Layer Compatibility */
+	if (Q931IsIEPresent(pMes->LLComp)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_LOW_LAYER_COMPATIBILITY](pTrunk, Q931GetIEPtr(pMes->LLComp,pMes->buf), OBuf, &Octet))!=0)
+			return rc;
+	}
+
+	/* High Layer Compatibility */
+	if (Q931IsIEPresent(pMes->HLComp)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_HIGH_LAYER_COMPATIBILITY](pTrunk, Q931GetIEPtr(pMes->HLComp,pMes->buf), OBuf, &Octet))!=0)
+			return rc;
+	}
+
+	*OSize = Octet;
+	return rc;
+}
+
+
+/*****************************************************************************
+
+  Function:	 ATT5ESSUmes_0x0f
+
+*****************************************************************************/
+L3INT ATT5ESSUmes_0x0f(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+	if (mes->ProtDisc == 8) {
+		return Q931Umes_ConnectAck(pTrunk, IBuf, mes, IOff, Size);
+	}
+
+	if (mes->ProtDisc == 3) {
+		return Q931Umes_Service(pTrunk, IBuf, mes, IOff, Size);
+	}
+
+	return Q931E_UNKNOWN_MESSAGE;
+}
+
+/*****************************************************************************
+
+  Function:	 ATT5ESSPmes_0x0f
+
+*****************************************************************************/
+L3INT ATT5ESSPmes_0x0f(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+	Q931mes_Generic *mes = (Q931mes_Generic *)IBuf;
+
+	if (mes->ProtDisc == 8) {
+		return Q931Pmes_ConnectAck(pTrunk, IBuf, ISize, OBuf, OSize);
+	}
+
+	if (mes->ProtDisc == 3) {
+		return Q931Pmes_Service(pTrunk, IBuf, ISize, OBuf, OSize);
+	}
+
+	return Q931E_UNKNOWN_MESSAGE;
+}
+
+/*****************************************************************************
+
+  Function:	 ATT5ESSUmes_0x07
+
+*****************************************************************************/
+L3INT ATT5ESSUmes_0x07(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+	if (mes->ProtDisc == 8) {
+		return Q931Umes_Connect(pTrunk, IBuf, mes, IOff, Size);
+	}
+
+	if (mes->ProtDisc == 3) {
+		return Q931Umes_ServiceAck(pTrunk, IBuf, mes, IOff, Size);
+	}
+
+	return Q931E_UNKNOWN_MESSAGE;
+}
+
+/*****************************************************************************
+
+  Function:	 ATT5ESSPmes_0x07
+
+*****************************************************************************/
+L3INT ATT5ESSPmes_0x07(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+	Q931mes_Generic *mes = (Q931mes_Generic *)IBuf;
+
+	if (mes->ProtDisc == 8) {
+		return Q931Pmes_Connect(pTrunk, IBuf, ISize, OBuf, OSize);
+	}
+
+	if (mes->ProtDisc == 3) {
+		return Q931Pmes_ServiceAck(pTrunk, IBuf, ISize, OBuf, OSize);
+	}
+
+	return Q931E_UNKNOWN_MESSAGE;
+}

Added: freeswitch/trunk/libs/freetdm/src/isdn/DMSStateNT.c (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/isdn/DMSStateNT.c	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/isdn/DMSStateNT.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,126 @@
+/*****************************************************************************
+
+  FileName:		DMSStateNT.c
+
+  Contents:		DMS-100 ISDN State Engine for NT (Network Mode).
+
+				The controlling state engine for Q.931 is the state engine
+				on the NT side. The state engine on the TE side is a slave 
+				of this. The TE side maintain it's own states as described in
+				ITU-T Q931, but will in	raise conditions be overridden by 
+				the NT side.
+
+  License/Copyright:
+
+  Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+  email:janvb@caselaboratories.com  
+
+  Copyright (c) 2007, Michael Jerris. All rights reserved.
+  email:mike@jerris.com  
+
+  Redistribution and use in source and binary forms, with or without 
+  modification, are permitted provided that the following conditions are 
+  met:
+
+	* Redistributions of source code must retain the above copyright notice, 
+	  this list of conditions and the following disclaimer.
+	* Redistributions in binary form must reproduce the above copyright notice, 
+	  this list of conditions and the following disclaimer in the documentation 
+	  and/or other materials provided with the distribution.
+	* Neither the name of the Case Labs, Ltd nor the names of its contributors 
+	  may be used to endorse or promote products derived from this software 
+	  without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
+  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
+  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+  POSSIBILITY OF SUCH DAMAGE.
+*****************************************************************************/
+
+#include "DMS.h"
+
+/*****************************************************************************
+  Function:		DMSCreateNT
+
+  Description:	Will create the National ISDN NT as a Dialect in the stack. The first
+				bulk set up the message handlers, the second bulk the IE
+				encoders/coders, and the last bulk set up the state table.
+
+  Parameters:	i		Dialect index
+*****************************************************************************/
+void DMSCreateNT(L3UCHAR i)
+{
+	Q931SetMesProc(Q931mes_ALERTING,             i, Q931ProcAlertingNT,          Q931Umes_Alerting,          Q931Pmes_Alerting);
+	Q931SetMesProc(Q931mes_CALL_PROCEEDING,      i, Q931ProcCallProceedingNT,    Q931Umes_CallProceeding,    Q931Pmes_CallProceeding);
+	Q931SetMesProc(Q931mes_CONNECT,              i, Q931ProcConnectNT,           Q931Umes_Connect,           Q931Pmes_Connect);
+	Q931SetMesProc(Q931mes_CONNECT_ACKNOWLEDGE,  i, Q931ProcConnectAckNT,        Q931Umes_ConnectAck,        Q931Pmes_ConnectAck);
+	Q931SetMesProc(Q931mes_PROGRESS,             i, Q931ProcProgressNT,          Q931Umes_Progress,          Q931Pmes_Progress);
+	Q931SetMesProc(Q931mes_SETUP,                i, Q931ProcSetupNT,             DMSUmes_Setup,              DMSPmes_Setup);
+	Q931SetMesProc(Q931mes_SETUP_ACKNOWLEDGE,    i, Q931ProcSetupAckNT,          Q931Umes_SetupAck,          Q931Pmes_SetupAck);
+	Q931SetMesProc(Q931mes_RESUME,               i, Q931ProcResumeNT,            Q931Umes_Resume,            Q931Pmes_Resume);
+	Q931SetMesProc(Q931mes_RESUME_ACKNOWLEDGE,   i, Q931ProcResumeAckNT,         Q931Umes_ResumeAck,         Q931Pmes_ResumeAck);
+	Q931SetMesProc(Q931mes_RESUME_REJECT,        i, Q931ProcResumeRejectNT,      Q931Umes_ResumeReject,      Q931Pmes_ResumeReject);
+	Q931SetMesProc(Q931mes_SUSPEND,              i, Q931ProcSuspendNT,           Q931Umes_Suspend,           Q931Pmes_Suspend);
+	Q931SetMesProc(Q931mes_SUSPEND_ACKNOWLEDGE,  i, Q931ProcSuspendAckNT,        Q931Umes_SuspendAck,        Q931Pmes_SuspendAck);
+	Q931SetMesProc(Q931mes_SUSPEND_REJECT,       i, Q931ProcSuspendRejectNT,     Q931Umes_SuspendReject,     Q931Pmes_SuspendReject);
+	Q931SetMesProc(Q931mes_USER_INFORMATION,     i, Q931ProcUserInformationNT,   Q931Umes_UserInformation,   Q931Pmes_UserInformation);
+	Q931SetMesProc(Q931mes_DISCONNECT,           i, Q931ProcDisconnectNT,        Q931Umes_Disconnect,        Q931Pmes_Disconnect);
+	Q931SetMesProc(Q931mes_RELEASE,              i, Q931ProcReleaseNT,           Q931Umes_Release,           Q931Pmes_Release);
+	Q931SetMesProc(Q931mes_RELEASE_COMPLETE,     i, Q931ProcReleaseCompleteNT,   Q931Umes_ReleaseComplete,   Q931Pmes_ReleaseComplete);
+	Q931SetMesProc(Q931mes_RESTART,              i, Q931ProcRestartNT,           Q931Umes_Restart,           Q931Pmes_Restart);
+	Q931SetMesProc(Q931mes_RESTART_ACKNOWLEDGE,  i, Q931ProcRestartAckNT,        Q931Umes_RestartAck,        Q931Pmes_RestartAck);
+	Q931SetMesProc(Q931mes_CONGESTION_CONTROL,   i, Q931ProcCongestionControlNT, Q931Umes_CongestionControl, Q931Pmes_CongestionControl);
+	Q931SetMesProc(Q931mes_INFORMATION,          i, Q931ProcInformationNT,       Q931Umes_Information,       Q931Pmes_Information);
+	Q931SetMesProc(Q931mes_NOTIFY,               i, Q931ProcNotifyNT,            Q931Umes_Notify,            Q931Pmes_Notify);
+	Q931SetMesProc(Q931mes_STATUS,               i, Q931ProcStatusNT,            Q931Umes_Status,            Q931Pmes_Status);
+	Q931SetMesProc(Q931mes_STATUS_ENQUIRY,       i, Q931ProcStatusEnquiryNT,     Q931Umes_StatusEnquiry,     Q931Pmes_StatusEnquiry);
+	Q931SetMesProc(Q931mes_SEGMENT,              i, Q931ProcSegmentNT,           Q931Umes_Segment,           Q931Pmes_Segment);
+
+	Q931SetMesProc(Q932mes_FACILITY,             i, Q932ProcFacilityNT,          Q932Umes_Facility,          Q932Pmes_Facility);
+	Q931SetMesProc(Q932mes_HOLD,                 i, Q932ProcHoldNT,              Q932Umes_Hold,              Q932Pmes_Hold);
+	Q931SetMesProc(Q932mes_HOLD_ACKNOWLEDGE,     i, Q932ProcHoldAckNT,           Q932Umes_HoldAck,           Q932Pmes_HoldAck);
+	Q931SetMesProc(Q932mes_HOLD_REJECT,          i, Q932ProcHoldRejectNT,        Q932Umes_HoldReject,        Q932Pmes_HoldReject);
+	Q931SetMesProc(Q932mes_REGISTER,             i, Q932ProcRegisterNT,          Q932Umes_Register,          Q932Pmes_Register);
+	Q931SetMesProc(Q932mes_RETRIEVE,             i, Q932ProcRetrieveNT,          Q932Umes_Retrieve,          Q932Pmes_Retrieve);
+	Q931SetMesProc(Q932mes_RETRIEVE_ACKNOWLEDGE, i, Q932ProcRetrieveAckNT,       Q932Umes_RetrieveAck,       Q932Pmes_RetrieveAck);
+	Q931SetMesProc(Q932mes_RETRIEVE_REJECT,      i, Q932ProcRetrieveRejectNT,    Q932Umes_RetrieveReject,    Q932Pmes_RetrieveReject);
+
+	/* Set up the IE encoder/decoder handle table.*/ 
+	Q931SetIEProc(Q931ie_SEGMENTED_MESSAGE,                i, Q931Pie_Segment,       Q931Uie_Segment);
+	Q931SetIEProc(Q931ie_BEARER_CAPABILITY,                i, Q931Pie_BearerCap,     Q931Uie_BearerCap);
+	Q931SetIEProc(Q931ie_CAUSE,                            i, Q931Pie_Cause,         Q931Uie_Cause);
+	Q931SetIEProc(Q931ie_CALL_IDENTITY,                    i, Q931Pie_CallID,        Q931Uie_CallID);
+	Q931SetIEProc(Q931ie_CALL_STATE,                       i, Q931Pie_CallState,     Q931Uie_CallState);
+	Q931SetIEProc(Q931ie_CHANNEL_IDENTIFICATION,           i, Q931Pie_ChanID,        Q931Uie_ChanID);
+	Q931SetIEProc(Q931ie_PROGRESS_INDICATOR,               i, Q931Pie_ProgInd,       Q931Uie_ProgInd);
+	Q931SetIEProc(Q931ie_NETWORK_SPECIFIC_FACILITIES,      i, Q931Pie_NetFac,        Q931Uie_NetFac);
+	Q931SetIEProc(Q931ie_NOTIFICATION_INDICATOR,           i, Q931Pie_NotifInd,      Q931Uie_NotifInd);
+	Q931SetIEProc(Q931ie_DISPLAY,                          i, Q931Pie_Display,       Q931Uie_Display);
+	Q931SetIEProc(Q931ie_DATETIME,                         i, Q931Pie_DateTime,      Q931Uie_DateTime);
+	Q931SetIEProc(Q931ie_KEYPAD_FACILITY,                  i, Q931Pie_KeypadFac,     Q931Uie_KeypadFac);
+	Q931SetIEProc(Q931ie_SIGNAL,                           i, Q931Pie_Signal,        Q931Uie_Signal);
+	Q931SetIEProc(Q931ie_TRANSIT_DELAY_SELECTION_AND_IND,  i, Q931Pie_TransNetSel,   Q931Uie_TransNetSel);
+	Q931SetIEProc(Q931ie_CALLING_PARTY_NUMBER,             i, Q931Pie_CallingNum,    Q931Uie_CallingNum);
+	Q931SetIEProc(Q931ie_CALLING_PARTY_SUBADDRESS,         i, Q931Pie_CallingSub,    Q931Uie_CallingSub);
+	Q931SetIEProc(Q931ie_CALLED_PARTY_NUMBER,              i, Q931Pie_CalledNum,     Q931Uie_CalledNum);
+	Q931SetIEProc(Q931ie_CALLED_PARTY_SUBADDRESS,          i, Q931Pie_CalledSub,     Q931Uie_CalledSub);
+	Q931SetIEProc(Q931ie_TRANSIT_NETWORK_SELECTION,        i, Q931Pie_TransNetSel,   Q931Uie_TransNetSel);
+	Q931SetIEProc(Q931ie_RESTART_INDICATOR,                i, Q931Pie_RestartInd,    Q931Uie_RestartInd);
+	Q931SetIEProc(Q931ie_LOW_LAYER_COMPATIBILITY,          i, Q931Pie_LLComp,        Q931Uie_LLComp);
+	Q931SetIEProc(Q931ie_HIGH_LAYER_COMPATIBILITY,         i, Q931Pie_HLComp,        Q931Uie_HLComp);
+	Q931SetIEProc(Q931ie_USER_USER,                        i, Q931Pie_UserUser,      Q931Uie_UserUser);
+	Q931SetIEProc(Q931ie_GENERIC_DIGITS, 	               i, Q931Pie_GenericDigits, Q931Uie_GenericDigits);
+
+	/* The following define a state machine. The point is that the Message	*/
+	/* procs can when search this to find out if the message/state			*/
+	/* combination is legale. If not, the proc for unexpected message apply.*/
+
+	/* TODO define state table here */
+}

Added: freeswitch/trunk/libs/freetdm/src/isdn/DMSStateTE.c (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/isdn/DMSStateTE.c	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/isdn/DMSStateTE.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,284 @@
+/*****************************************************************************
+
+  FileName:		DMSStateTE.c
+
+  Contents:		DMS-100 ISDN State Engine for TE (User Mode).
+
+			The controlling state engine for Q.931 is the state engine
+			on the NT side. The state engine on the TE side is a slave 
+			of this. The TE side maintain it's own states as described in
+			ITU-T Q931, but will in	raise conditions be overridden by 
+			the NT side.
+
+			This reference implementation uses a process per message,
+			meaning that each message must check call states. This
+			is easier for dialect maintenance as each message proc
+			can be replaced individually. A new TE variant only
+			need to copy the Q931CreateTE and replace those procs or
+			need to override.
+
+  License/Copyright:
+
+  Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+  email:janvb@caselaboratories.com  
+
+  Copyright (c) 2007, Michael Jerris. All rights reserved.
+  email:mike@jerris.com  
+
+  Redistribution and use in source and binary forms, with or without 
+  modification, are permitted provided that the following conditions are 
+  met:
+
+	* Redistributions of source code must retain the above copyright notice, 
+	  this list of conditions and the following disclaimer.
+	* Redistributions in binary form must reproduce the above copyright notice, 
+	  this list of conditions and the following disclaimer in the documentation 
+	  and/or other materials provided with the distribution.
+	* Neither the name of the Case Labs, Ltd nor the names of its contributors 
+	  may be used to endorse or promote products derived from this software 
+	  without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
+  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
+  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+  POSSIBILITY OF SUCH DAMAGE.
+*****************************************************************************/
+
+#include "DMS.h"
+extern L3INT Q931L4HeaderSpace;
+
+/*****************************************************************************
+  Function:		DMSCreateTE
+
+  Description:	Will create the National TE as a Dialect in the stack. The first
+				bulk set up the message handlers, the second bulk the IE
+				encoders/coders, and the last bulk set up the state table.
+
+  Parameters:	i		Dialect index
+*****************************************************************************/
+void DMSCreateTE(L3UCHAR i)
+{
+	Q931SetMesProc(Q931mes_ALERTING,             i, Q931ProcAlertingTE,          Q931Umes_Alerting,          Q931Pmes_Alerting);
+	Q931SetMesProc(Q931mes_CALL_PROCEEDING,      i, Q931ProcCallProceedingTE,    Q931Umes_CallProceeding,    Q931Pmes_CallProceeding);
+	Q931SetMesProc(Q931mes_CONNECT,              i, DMSProc0x07TE, 	             DMSUmes_0x07,               DMSPmes_0x07);
+	Q931SetMesProc(Q931mes_CONNECT_ACKNOWLEDGE,  i, DMSProc0x0fTE, 	             DMSUmes_0x0f,               DMSPmes_0x0f);
+	Q931SetMesProc(Q931mes_PROGRESS,             i, Q931ProcProgressTE,          Q931Umes_Progress,          Q931Pmes_Progress);
+	Q931SetMesProc(Q931mes_SETUP,                i, Q931ProcSetupTE,             DMSUmes_Setup,              DMSPmes_Setup);
+	Q931SetMesProc(Q931mes_SETUP_ACKNOWLEDGE,    i, Q931ProcSetupAckTE,          Q931Umes_SetupAck,          Q931Pmes_SetupAck);
+	Q931SetMesProc(Q931mes_RESUME,               i, Q931ProcResumeTE,            Q931Umes_Resume,            Q931Pmes_Resume);
+	Q931SetMesProc(Q931mes_RESUME_ACKNOWLEDGE,   i, Q931ProcResumeAckTE,         Q931Umes_ResumeAck,         Q931Pmes_ResumeAck);
+	Q931SetMesProc(Q931mes_RESUME_REJECT,        i, Q931ProcResumeRejectTE,      Q931Umes_ResumeReject,      Q931Pmes_ResumeReject);
+	Q931SetMesProc(Q931mes_SUSPEND,              i, Q931ProcSuspendTE,           Q931Umes_Suspend,           Q931Pmes_Suspend);
+	Q931SetMesProc(Q931mes_SUSPEND_ACKNOWLEDGE,  i, Q931ProcSuspendAckTE,        Q931Umes_SuspendAck,        Q931Pmes_SuspendAck);
+	Q931SetMesProc(Q931mes_SUSPEND_REJECT,       i, Q931ProcSuspendRejectTE,     Q931Umes_SuspendReject,     Q931Pmes_SuspendReject);
+	Q931SetMesProc(Q931mes_USER_INFORMATION,     i, Q931ProcUserInformationTE,   Q931Umes_UserInformation,   Q931Pmes_UserInformation);
+	Q931SetMesProc(Q931mes_DISCONNECT,           i, Q931ProcDisconnectTE,        Q931Umes_Disconnect,        Q931Pmes_Disconnect);
+	Q931SetMesProc(Q931mes_RELEASE,              i, Q931ProcReleaseTE,           Q931Umes_Release,           Q931Pmes_Release);
+	Q931SetMesProc(Q931mes_RELEASE_COMPLETE,     i, Q931ProcReleaseCompleteTE,   Q931Umes_ReleaseComplete,   Q931Pmes_ReleaseComplete);
+	Q931SetMesProc(Q931mes_RESTART,              i, Q931ProcRestartTE,           Q931Umes_Restart,           Q931Pmes_Restart);
+	Q931SetMesProc(Q931mes_RESTART_ACKNOWLEDGE,  i, Q931ProcRestartAckTE,        Q931Umes_RestartAck,        Q931Pmes_RestartAck);
+	Q931SetMesProc(Q931mes_CONGESTION_CONTROL,   i, Q931ProcCongestionControlTE, Q931Umes_CongestionControl, Q931Pmes_CongestionControl);
+	Q931SetMesProc(Q931mes_INFORMATION,          i, Q931ProcInformationTE,       Q931Umes_Information,       Q931Pmes_Information);
+	Q931SetMesProc(Q931mes_NOTIFY,               i, Q931ProcNotifyTE,            Q931Umes_Notify,            Q931Pmes_Notify);
+	Q931SetMesProc(Q931mes_STATUS,               i, Q931ProcStatusTE,            Q931Umes_Status,            Q931Pmes_Status);
+	Q931SetMesProc(Q931mes_STATUS_ENQUIRY,       i, Q931ProcStatusEnquiryTE,     Q931Umes_StatusEnquiry,     Q931Pmes_StatusEnquiry);
+	Q931SetMesProc(Q931mes_SEGMENT,              i, Q931ProcSegmentTE,           Q931Umes_Segment,           Q931Pmes_Segment);
+
+	Q931SetMesProc(Q932mes_FACILITY,             i, Q932ProcFacilityTE,          Q932Umes_Facility,          Q932Pmes_Facility);
+	Q931SetMesProc(Q932mes_HOLD,                 i, Q932ProcHoldTE,              Q932Umes_Hold,              Q932Pmes_Hold);
+	Q931SetMesProc(Q932mes_HOLD_ACKNOWLEDGE,     i, Q932ProcHoldAckTE,           Q932Umes_HoldAck,           Q932Pmes_HoldAck);
+	Q931SetMesProc(Q932mes_HOLD_REJECT,          i, Q932ProcHoldRejectTE,        Q932Umes_HoldReject,        Q932Pmes_HoldReject);
+	Q931SetMesProc(Q932mes_REGISTER,             i, Q932ProcRegisterTE,          Q932Umes_Register,          Q932Pmes_Register);
+	Q931SetMesProc(Q932mes_RETRIEVE,             i, Q932ProcRetrieveTE,          Q932Umes_Retrieve,          Q932Pmes_Retrieve);
+	Q931SetMesProc(Q932mes_RETRIEVE_ACKNOWLEDGE, i, Q932ProcRetrieveAckTE,       Q932Umes_RetrieveAck,       Q932Pmes_RetrieveAck);
+	Q931SetMesProc(Q932mes_RETRIEVE_REJECT,      i, Q932ProcRetrieveRejectTE,    Q932Umes_RetrieveReject,    Q932Pmes_RetrieveReject);
+
+	/* Set up the IE encoder/decoder handle table.*/ 
+	Q931SetIEProc(Q931ie_SEGMENTED_MESSAGE,                i, Q931Pie_Segment,       Q931Uie_Segment);
+	Q931SetIEProc(Q931ie_BEARER_CAPABILITY,                i, Q931Pie_BearerCap,     Q931Uie_BearerCap);
+	Q931SetIEProc(Q931ie_CAUSE,                            i, Q931Pie_Cause,         Q931Uie_Cause);
+	Q931SetIEProc(Q931ie_CALL_IDENTITY,                    i, Q931Pie_CallID,        Q931Uie_CallID);
+	Q931SetIEProc(Q931ie_CALL_STATE,                       i, Q931Pie_CallState,     Q931Uie_CallState);
+	Q931SetIEProc(Q931ie_CHANGE_STATUS,                    i, Q931Pie_ChangeStatus,  Q931Uie_ChangeStatus);
+	Q931SetIEProc(Q931ie_CHANNEL_IDENTIFICATION,           i, Q931Pie_ChanID,        Q931Uie_ChanID);
+	Q931SetIEProc(Q931ie_PROGRESS_INDICATOR,               i, Q931Pie_ProgInd,       Q931Uie_ProgInd);
+	Q931SetIEProc(Q931ie_NETWORK_SPECIFIC_FACILITIES,      i, Q931Pie_NetFac,        Q931Uie_NetFac);
+	Q931SetIEProc(Q931ie_NOTIFICATION_INDICATOR,           i, Q931Pie_NotifInd,      Q931Uie_NotifInd);
+	Q931SetIEProc(Q931ie_DISPLAY,                          i, Q931Pie_Display,       Q931Uie_Display);
+	Q931SetIEProc(Q931ie_DATETIME,                         i, Q931Pie_DateTime,      Q931Uie_DateTime);
+	Q931SetIEProc(Q931ie_KEYPAD_FACILITY,                  i, Q931Pie_KeypadFac,     Q931Uie_KeypadFac);
+	Q931SetIEProc(Q931ie_SIGNAL,                           i, Q931Pie_Signal,        Q931Uie_Signal);
+	Q931SetIEProc(Q931ie_TRANSIT_DELAY_SELECTION_AND_IND,  i, Q931Pie_TransNetSel,   Q931Uie_TransNetSel);
+	Q931SetIEProc(Q931ie_CALLING_PARTY_NUMBER,             i, Q931Pie_CallingNum,    Q931Uie_CallingNum);
+	Q931SetIEProc(Q931ie_CALLING_PARTY_SUBADDRESS,         i, Q931Pie_CallingSub,    Q931Uie_CallingSub);
+	Q931SetIEProc(Q931ie_CALLED_PARTY_NUMBER,              i, Q931Pie_CalledNum,     Q931Uie_CalledNum);
+	Q931SetIEProc(Q931ie_CALLED_PARTY_SUBADDRESS,          i, Q931Pie_CalledSub,     Q931Uie_CalledSub);
+	Q931SetIEProc(Q931ie_TRANSIT_NETWORK_SELECTION,        i, Q931Pie_TransNetSel,   Q931Uie_TransNetSel);
+	Q931SetIEProc(Q931ie_RESTART_INDICATOR,                i, Q931Pie_RestartInd,    Q931Uie_RestartInd);
+	Q931SetIEProc(Q931ie_LOW_LAYER_COMPATIBILITY,          i, Q931Pie_LLComp,        Q931Uie_LLComp);
+	Q931SetIEProc(Q931ie_HIGH_LAYER_COMPATIBILITY,         i, Q931Pie_HLComp,        Q931Uie_HLComp);
+	Q931SetIEProc(Q931ie_USER_USER,                        i, Q931Pie_UserUser,      Q931Uie_UserUser);
+	Q931SetIEProc(Q931ie_GENERIC_DIGITS,                   i, Q931Pie_GenericDigits, Q931Uie_GenericDigits);
+
+	/* The following define a state machine. The point is that the Message	*/
+	/* procs can when search this to find out if the message/state			*/
+	/* combination is legale. If not, the proc for unexpected message apply.*/
+
+	/* State 0 Idle */
+	Q931AddStateEntry(i, Q931_U0, Q931mes_RESUME,           2);
+	Q931AddStateEntry(i, Q931_U0, Q931mes_SETUP,            4);
+	Q931AddStateEntry(i, Q931_U0, Q931mes_SETUP,            2);
+	Q931AddStateEntry(i, Q931_U0, Q931mes_STATUS,           4);
+	Q931AddStateEntry(i, Q931_U0, Q931mes_RELEASE,          4);
+	Q931AddStateEntry(i, Q931_U0, Q931mes_RELEASE_COMPLETE, 4);
+
+	/* State 1 Call Initiating */
+	Q931AddStateEntry(i, Q931_U1, Q931mes_DISCONNECT,        2);
+	Q931AddStateEntry(i, Q931_U1, Q931mes_SETUP_ACKNOWLEDGE, 4);
+	Q931AddStateEntry(i, Q931_U1, Q931mes_RELEASE_COMPLETE,  4);
+	Q931AddStateEntry(i, Q931_U1, Q931mes_CALL_PROCEEDING,   4);
+	Q931AddStateEntry(i, Q931_U1, Q931mes_ALERTING,          4);
+	Q931AddStateEntry(i, Q931_U1, Q931mes_CONNECT,           4);
+
+	/* State 2 Overlap Sending */
+	Q931AddStateEntry(i, Q931_U2, Q931mes_INFORMATION,     2);
+	Q931AddStateEntry(i, Q931_U2, Q931mes_CALL_PROCEEDING, 4);
+	Q931AddStateEntry(i, Q931_U2, Q931mes_ALERTING,        4);
+	Q931AddStateEntry(i, Q931_U2, Q931mes_PROGRESS,        4);
+	Q931AddStateEntry(i, Q931_U2, Q931mes_CONNECT,         4);
+	Q931AddStateEntry(i, Q931_U2, Q931mes_RELEASE,         2);
+
+	/* State 3 Outgoing Call Proceeding */
+	Q931AddStateEntry(i, Q931_U3, Q931mes_PROGRESS, 4);
+	Q931AddStateEntry(i, Q931_U3, Q931mes_ALERTING, 4);
+	Q931AddStateEntry(i, Q931_U3, Q931mes_CONNECT,  4);
+	Q931AddStateEntry(i, Q931_U3, Q931mes_RELEASE,  2);
+
+	/* State 4 Call Delivered */
+	Q931AddStateEntry(i, Q931_U4, Q931mes_CONNECT, 4);
+
+	/* State 6 Call Precent */
+	Q931AddStateEntry(i, Q931_U6, Q931mes_INFORMATION,      2);	
+	Q931AddStateEntry(i, Q931_U6, Q931mes_ALERTING,         2);	
+	Q931AddStateEntry(i, Q931_U6, Q931mes_CALL_PROCEEDING,  2);	
+	Q931AddStateEntry(i, Q931_U6, Q931mes_CONNECT,          2);	
+	Q931AddStateEntry(i, Q931_U6, Q931mes_RELEASE_COMPLETE, 2);	
+	Q931AddStateEntry(i, Q931_U6, Q931mes_RELEASE,          4);	
+	Q931AddStateEntry(i, Q931_U6, Q931mes_DISCONNECT,       4);	
+
+	/* State 7 Call Received */
+	Q931AddStateEntry(i, Q931_U7, Q931mes_CONNECT, 2);
+
+	/* State 8 Connect request */
+	Q931AddStateEntry(i, Q931_U8, Q931mes_CONNECT_ACKNOWLEDGE, 4);
+
+	/* State 9 Incoming Call Proceeding */
+	Q931AddStateEntry(i, Q931_U9, Q931mes_CONNECT,  2);
+	Q931AddStateEntry(i, Q931_U9, Q931mes_ALERTING, 2);
+	Q931AddStateEntry(i, Q931_U9, Q931mes_PROGRESS, 2);
+
+	/* State 10 Active */
+	Q931AddStateEntry(i, Q931_U10, Q931mes_SUSPEND, 2);
+	Q931AddStateEntry(i, Q931_U10, Q931mes_NOTIFY,  4);
+	Q931AddStateEntry(i, Q931_U10, Q931mes_NOTIFY,  2);
+
+	/* State 11 Disconnect Request */
+	Q931AddStateEntry(i, Q931_U11, Q931mes_RELEASE,    4);
+	Q931AddStateEntry(i, Q931_U11, Q931mes_DISCONNECT, 4);
+	Q931AddStateEntry(i, Q931_U11, Q931mes_NOTIFY,     4);
+
+	/* State 12 Disconnect Ind */
+	Q931AddStateEntry(i, Q931_U12, Q931mes_RELEASE,	4);
+	Q931AddStateEntry(i, Q931_U12, Q931mes_RELEASE, 2);
+
+	/* State 15 Suspend Request */
+	Q931AddStateEntry(i, Q931_U15, Q931mes_SUSPEND_ACKNOWLEDGE, 4);
+	Q931AddStateEntry(i, Q931_U15, Q931mes_SUSPEND_REJECT,      4);
+	Q931AddStateEntry(i, Q931_U15, Q931mes_DISCONNECT,          4);
+	Q931AddStateEntry(i, Q931_U15, Q931mes_RELEASE,             4);
+
+/* TODO
+	Q931AddStateEntry(i, Q931_U17,
+	Q931AddStateEntry(i, Q931_U19,
+	Q931AddStateEntry(i, Q931_U25,
+*/
+}
+
+/*****************************************************************************
+
+  Function:		DMSProc0x0fTE
+
+*****************************************************************************/
+L3INT DMSProc0x0fTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	if (pMes->ProtDisc == 8) {
+		/* Find the call using CRV */
+		ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+		if (ret != Q931E_NO_ERROR)
+			return ret;
+
+		/* TODO chack against state table for illegal or unexpected message here*/
+
+		/* TODO - Set correct timer here */
+		Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	}
+	if (iFrom == 4) {
+		/* TODO Add proc here*/
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here*/
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+
+		if (pMes->ProtDisc == 3 && pTrunk->autoServiceAck) {
+			Q931AckService(pTrunk, buf);
+		}
+	}
+	return ret;
+
+}
+
+/*****************************************************************************
+
+  Function:		DMSProc0x07TE
+
+*****************************************************************************/
+L3INT DMSProc0x07TE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	if (pMes->ProtDisc == 8) {
+		/* Find the call using CRV */
+		ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+		if (ret != Q931E_NO_ERROR)
+			return ret;
+
+		/* TODO chack against state table for illegal or unexpected message here*/
+
+		/* TODO - Set correct timer here */
+		Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	}
+	if (iFrom == 4) {
+		/* TODO Add proc here*/
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here*/
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+
+}

Added: freeswitch/trunk/libs/freetdm/src/isdn/DMSmes.c (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/isdn/DMSmes.c	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/isdn/DMSmes.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,344 @@
+/*****************************************************************************
+
+  FileName:	DMSmes.c
+
+  Contents:	Pack/Unpack functions. These functions will unpack a DMS-100 ISDN
+		message from the bit packed original format into structs
+		that contains variables sized by the user. It will also pack
+		the struct back into a Q.931 message as required.
+
+		See national.h for description. 
+
+  License/Copyright:
+
+  Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+  email:janvb@caselaboratories.com  
+
+  Copyright (c) 2007, Michael Jerris. All rights reserved.
+  email:mike@jerris.com  
+
+  Redistribution and use in source and binary forms, with or without 
+  modification, are permitted provided that the following conditions are 
+  met:
+
+	* Redistributions of source code must retain the above copyright notice, 
+	  this list of conditions and the following disclaimer.
+	* Redistributions in binary form must reproduce the above copyright notice, 
+	  this list of conditions and the following disclaimer in the documentation 
+	  and/or other materials provided with the distribution.
+	* Neither the name of the Case Labs, Ltd nor the names of its contributors 
+	  may be used to endorse or promote products derived from this software 
+	  without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
+  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
+  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+  POSSIBILITY OF SUCH DAMAGE.
+
+*****************************************************************************/
+
+#include "DMS.h"
+
+/*****************************************************************************
+
+  Function:	 DMSUmes_Setup
+
+*****************************************************************************/
+L3INT DMSUmes_Setup(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+	L3INT ir = 0;
+	L3INT OOff = 0;
+	L3INT rc = Q931E_NO_ERROR;
+	L3UCHAR last_codeset = 0, codeset = 0;
+	L3UCHAR shift_lock = 1;
+
+	while (IOff < Size) {
+		if (!shift_lock) {
+			codeset = last_codeset;
+		}
+
+		if ((IBuf[IOff] & 0xF0) == Q931ie_SHIFT ) {
+			shift_lock = (IBuf[IOff] & 0x08);
+			if (shift_lock) {
+				last_codeset = codeset;
+			}
+			codeset = ((IBuf[IOff] & 0x07));
+			IOff++;
+		}
+
+		if (codeset == 0) {
+			switch (IBuf[IOff]) {
+			case Q931ie_SENDING_COMPLETE:
+			case Q931ie_BEARER_CAPABILITY:
+			case Q931ie_CHANNEL_IDENTIFICATION:
+			case Q931ie_PROGRESS_INDICATOR:
+			case Q931ie_NETWORK_SPECIFIC_FACILITIES:
+			case Q931ie_DISPLAY:
+			case Q931ie_DATETIME:
+			case Q931ie_KEYPAD_FACILITY:
+			case Q931ie_SIGNAL:
+			case Q931ie_CALLING_PARTY_NUMBER:
+			case Q931ie_CALLING_PARTY_SUBADDRESS:
+			case Q931ie_CALLED_PARTY_NUMBER:
+			case Q931ie_CALLED_PARTY_SUBADDRESS:
+			case Q931ie_TRANSIT_NETWORK_SELECTION:
+			case Q931ie_LOW_LAYER_COMPATIBILITY:
+			case Q931ie_HIGH_LAYER_COMPATIBILITY:
+				rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+				if (rc != Q931E_NO_ERROR) 
+					return rc;
+				break;
+			case Q931ie_REPEAT_INDICATOR:
+				if (ir < 2) {
+					rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+					ir++;
+				} else {
+					return Q931E_ILLEGAL_IE;
+				}
+				break;
+			default:
+				return Q931E_ILLEGAL_IE;
+				break;
+			}
+		} else if (codeset == 6) {
+			switch (IBuf[IOff]) {
+			case Q931ie_GENERIC_DIGITS:
+				rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+				if (rc != Q931E_NO_ERROR) 
+					return rc;
+				break;
+			default:
+				return Q931E_ILLEGAL_IE;
+				break;
+			}
+
+		} else {
+			return Q931E_ILLEGAL_IE;
+		}
+	}
+	mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:	 DMSPmes_Setup
+
+  Decription:	Pack a Q931mes_Generic into a real Q.931 message. The user will
+				set up a SETUP message and issue this to the stack where it
+				is processed by Q931ProcSetup that processes and validates
+				it before it actually sends it out. This function is called
+				to compute the real Q.931 message.
+
+  Parameters:	IBuf[IN]	Ptr to un-packed struct
+				ISize[IN]	Size of input buffer (unpacked message).
+				OBuf[OUT]	Ptr to packed 'octet' wise message.
+				OSize[OUT]	Size of packed message.
+
+  Called By:	Q931ProcSetup
+
+*****************************************************************************/
+L3INT DMSPmes_Setup(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+	L3INT rc = Q931E_NO_ERROR;
+	Q931mes_Generic *pMes = (Q931mes_Generic *)IBuf;
+	L3INT Octet = 0;
+
+	/* Q931 Message Header */
+	Q931MesgHeader(pTrunk, pMes, OBuf, *OSize, &Octet);
+	
+	/* Sending Complete */
+	if (Q931IsIEPresent(pMes->SendComplete)) {
+		OBuf[Octet++]	= (L3UCHAR)(pMes->SendComplete & 0x00ff);
+	}
+
+	/* Repeat Indicator */
+	if (Q931IsIEPresent(pMes->RepeatInd)) {
+		OBuf[Octet++]	= (L3UCHAR)(pMes->RepeatInd & 0x00ff);		
+	}
+
+	/* Bearer capability */
+	if (Q931IsIEPresent(pMes->BearerCap)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_BEARER_CAPABILITY](pTrunk, Q931GetIEPtr(pMes->BearerCap,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	} else {
+		rc = Q931E_BEARERCAP;
+	}
+
+	/* Channel Identification */
+	if (Q931IsIEPresent(pMes->ChanID)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CHANNEL_IDENTIFICATION](pTrunk, Q931GetIEPtr(pMes->ChanID,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Progress indicator */
+	if (Q931IsIEPresent(pMes->ProgInd)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_PROGRESS_INDICATOR](pTrunk, Q931GetIEPtr(pMes->ProgInd,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Network spesific facilities */
+	if (Q931IsIEPresent(pMes->NetFac)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_NETWORK_SPECIFIC_FACILITIES](pTrunk, Q931GetIEPtr(pMes->NetFac,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Display */
+	if (Q931IsIEPresent(pMes->Display)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_DISPLAY](pTrunk, Q931GetIEPtr(pMes->Display,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Date/Time */
+	if (Q931IsIEPresent(pMes->DateTime)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_DATETIME](pTrunk, Q931GetIEPtr(pMes->DateTime,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Keypad Facility */
+	if (Q931IsIEPresent(pMes->KeypadFac)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_KEYPAD_FACILITY](pTrunk, Q931GetIEPtr(pMes->KeypadFac,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Signal */
+	if (Q931IsIEPresent(pMes->Signal)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_SIGNAL](pTrunk, Q931GetIEPtr(pMes->Signal,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Calling Party Number */
+	if (Q931IsIEPresent(pMes->CallingNum)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CALLING_PARTY_NUMBER](pTrunk, Q931GetIEPtr(pMes->CallingNum,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Calling Party Subaddress */
+	if (Q931IsIEPresent(pMes->CallingSub)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CALLING_PARTY_SUBADDRESS](pTrunk, Q931GetIEPtr(pMes->CallingSub,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Called Party number */
+	if (Q931IsIEPresent(pMes->CalledNum)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CALLED_PARTY_NUMBER](pTrunk, Q931GetIEPtr(pMes->CalledNum,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+
+	/* Called party subaddress */
+	if (Q931IsIEPresent(pMes->CalledSub)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CALLED_PARTY_SUBADDRESS](pTrunk, Q931GetIEPtr(pMes->CalledSub,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Transit network selection */
+	if (Q931IsIEPresent(pMes->TransNetSel)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_TRANSIT_NETWORK_SELECTION](pTrunk, Q931GetIEPtr(pMes->TransNetSel,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Repeat Indicator */
+	if (Q931IsIEPresent(pMes->LLRepeatInd)) {
+		rc = Q931E_UNKNOWN_IE;/* TODO */
+	}
+
+	/* Low Layer Compatibility */
+	if (Q931IsIEPresent(pMes->LLComp)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_LOW_LAYER_COMPATIBILITY](pTrunk, Q931GetIEPtr(pMes->LLComp,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* High Layer Compatibility */
+	if (Q931IsIEPresent(pMes->HLComp)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_HIGH_LAYER_COMPATIBILITY](pTrunk, Q931GetIEPtr(pMes->HLComp,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	*OSize = Octet;	
+	return rc;
+}
+
+
+/*****************************************************************************
+
+  Function:	 DMSUmes_0x0f
+
+*****************************************************************************/
+L3INT DMSUmes_0x0f(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+	if (mes->ProtDisc == 8) {
+		return Q931Umes_ConnectAck(pTrunk, IBuf, mes, IOff, Size);
+	}
+
+	if (mes->ProtDisc == 3) {
+		return Q931Umes_Service(pTrunk, IBuf, mes, IOff, Size);
+	}
+
+	return Q931E_UNKNOWN_MESSAGE;
+}
+
+/*****************************************************************************
+
+  Function:	 DMSPmes_0x0f
+
+*****************************************************************************/
+L3INT DMSPmes_0x0f(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+	Q931mes_Generic *mes = (Q931mes_Generic *)IBuf;
+
+	if (mes->ProtDisc == 8) {
+		return Q931Pmes_ConnectAck(pTrunk, IBuf, ISize, OBuf, OSize);
+	}
+
+	if (mes->ProtDisc == 3) {
+		return Q931Pmes_Service(pTrunk, IBuf, ISize, OBuf, OSize);
+	}
+
+	return Q931E_UNKNOWN_MESSAGE;
+}
+
+/*****************************************************************************
+
+  Function:	 DMSUmes_0x07
+
+*****************************************************************************/
+L3INT DMSUmes_0x07(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+	if (mes->ProtDisc == 8) {
+		return Q931Umes_Connect(pTrunk, IBuf, mes, IOff, Size);
+	}
+
+	if (mes->ProtDisc == 3) {
+		return Q931Umes_ServiceAck(pTrunk, IBuf, mes, IOff, Size);
+	}
+
+	return Q931E_UNKNOWN_MESSAGE;
+}
+
+/*****************************************************************************
+
+  Function:	 DMSPmes_0x07
+
+*****************************************************************************/
+L3INT DMSPmes_0x07(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+	Q931mes_Generic *mes = (Q931mes_Generic *)IBuf;
+
+	if (mes->ProtDisc == 8) {
+		return Q931Pmes_Connect(pTrunk, IBuf, ISize, OBuf, OSize);
+	}
+
+	if (mes->ProtDisc == 3) {
+		return Q931Pmes_ServiceAck(pTrunk, IBuf, ISize, OBuf, OSize);
+	}
+
+	return Q931E_UNKNOWN_MESSAGE;
+}

Added: freeswitch/trunk/libs/freetdm/src/isdn/EuroISDNStateNT.c (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/isdn/EuroISDNStateNT.c	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/isdn/EuroISDNStateNT.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,44 @@
+/*****************************************************************************
+
+  FileName:		EuroISDNStateNT.c
+
+  Contents:		EuroISDN State Engine for NT (Network Mode).
+
+			The controlling state engine for Q.931 is the state engine
+			on the NT side. The state engine on the TE side is a slave 
+			of this. The TE side maintain it's own states as described in
+			ITU-T Q931, but will in	raise conditions be overridden by 
+			the NT side.
+
+  License/Copyright:
+
+  Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+  email:janvb@caselaboratories.com  
+
+  Redistribution and use in source and binary forms, with or without 
+  modification, are permitted provided that the following conditions are 
+  met:
+
+	* Redistributions of source code must retain the above copyright notice, 
+	  this list of conditions and the following disclaimer.
+	* Redistributions in binary form must reproduce the above copyright notice, 
+	  this list of conditions and the following disclaimer in the documentation 
+	  and/or other materials provided with the distribution.
+	* Neither the name of the Case Labs, Ltd nor the names of its contributors 
+	  may be used to endorse or promote products derived from this software 
+	  without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
+  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
+  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+  POSSIBILITY OF SUCH DAMAGE.
+*****************************************************************************/
+
+#include "Q931.h"

Added: freeswitch/trunk/libs/freetdm/src/isdn/EuroISDNStateTE.c (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/isdn/EuroISDNStateTE.c	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/isdn/EuroISDNStateTE.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,58 @@
+/*****************************************************************************
+
+  FileName:		EuroISDNStateTE.c
+
+  Contents:		EuroISDN State Engine for TE (User Mode).
+
+			The controlling state engine for Q.931 is the state engine
+			on the NT side. The state engine on the TE side is a slave 
+			of this. The TE side maintain it's own states as described in
+			ITU-T Q931, but will in	raise conditions be overridden by 
+			the NT side.
+
+  License/Copyright:
+
+  Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+  email:janvb@caselaboratories.com  
+
+  Redistribution and use in source and binary forms, with or without 
+  modification, are permitted provided that the following conditions are 
+  met:
+
+	* Redistributions of source code must retain the above copyright notice, 
+	  this list of conditions and the following disclaimer.
+	* Redistributions in binary form must reproduce the above copyright notice, 
+	  this list of conditions and the following disclaimer in the documentation 
+	  and/or other materials provided with the distribution.
+	* Neither the name of the Case Labs, Ltd nor the names of its contributors 
+	  may be used to endorse or promote products derived from this software 
+	  without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
+  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
+  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+  POSSIBILITY OF SUCH DAMAGE.
+*****************************************************************************/
+
+#include "Q931.h"
+
+/*
+  EuroISDN is a sub-set of Q.931. Q.931 is very generic as it embrase a lot,
+  while EuroISDN is more exact and make decitions on some of the 
+  'implementation options' in the original standard. EuroISDN will 
+  however run smoothly under the generic space, so these functions are more 
+  for show 
+*/
+#if 0
+static void EuroISDNCreateTE(L3UCHAR i)
+{
+	Q931CreateTE(i);
+}
+#endif

Added: freeswitch/trunk/libs/freetdm/src/isdn/Q921.c (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/isdn/Q921.c	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/isdn/Q921.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,3518 @@
+/*****************************************************************************
+
+  FileName:     q921.c
+
+  Description:  Contains the implementation of a Q.921 protocol
+
+  Created:      27.dec.2000/JVB
+
+  License/Copyright:
+
+  Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+  email:janvb@caselaboratories.com  
+
+  Redistribution and use in source and binary forms, with or without 
+  modification, are permitted provided that the following conditions are 
+  met:
+
+    * Redistributions of source code must retain the above copyright notice, 
+	  this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright notice, 
+	  this list of conditions and the following disclaimer in the documentation 
+	  and/or other materials provided with the distribution.
+    * Neither the name of the Case Labs, Ltd nor the names of its contributors 
+	  may be used to endorse or promote products derived from this software 
+	  without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
+  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
+  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+  POSSIBILITY OF SUCH DAMAGE.
+
+*****************************************************************************/
+
+/****************************************************************************
+ * Changes:
+ *
+ * - June-August 2008: Stefan Knoblich <s.knoblich@axsentis.de>:
+ *     Add PTMP TEI management (NT + TE mode)
+ *     Add timers
+ *     Add retransmit counters
+ *     Add logging
+ *     Various cleanups
+ *     Queues, retransmission of I frames
+ *     PTMP NT mode
+ *
+ *
+ * TODO:
+ *
+ * - Cleanup queueing, test retransmission
+ *
+ * - Q921Start() /-Stop() TEI acquire + release
+ *   (move everything related into these functions)
+ *
+ * - Q.921 '97 Appendix I (and maybe III, IV)
+ *
+ * - More complete Appendix II
+ *
+ * - Test PTP mode
+ *
+ * - PTMP NT mode (in progress)
+ *
+ * - NT mode TEI management: (ab)use T202 for TEI Check Request retransmission
+ *
+ * - General cleanup (move all non-public declarations into private header file)
+ *
+ * - Statistics, per-Frame type debug message filter
+ *
+ ****************************************************************************/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+
+#include "freetdm.h"
+#include "Q921.h"
+#include "Q921priv.h"
+#include "mfifo.h"
+
+#ifdef WIN32
+#pragma warning(disable:4100 4244)
+#endif
+
+/******************************************************************************************************
+ * Actual code below this line
+ ******************************************************************************************************/
+
+
+/**
+ * Q921StateNames
+ * \brief	Static array of state name / value mappings
+ */
+static struct Q921StateName {
+	Q921State_t value;
+	const char *name;
+} Q921StateNames[10] = {
+	{ Q921_STATE_STOPPED, "Stopped" },
+	{ Q921_STATE_TEI_UNASSIGNED, "TEI Unassigned" },
+	{ Q921_STATE_TEI_AWAITING, "TEI Awaiting Assignment" },
+	{ Q921_STATE_TEI_ESTABLISH, "TEI Awaiting Establishment" },
+	{ Q921_STATE_TEI_ASSIGNED, "TEI Assigned" },
+	{ Q921_STATE_AWAITING_ESTABLISHMENT, "Awaiting Establishment" },
+	{ Q921_STATE_AWAITING_RELEASE, "Awaiting Release" },
+	{ Q921_STATE_MULTIPLE_FRAME_ESTABLISHED, "Multiple Frame Mode Established" },
+	{ Q921_STATE_TIMER_RECOVERY, "Timer Recovery" },
+	{ 0, 0 }
+};
+
+/**
+ * Q921State2Name
+ * \brief	Convert state value to name
+ * \param[in]	state	the state value
+ * \return	the state name or "Unknown"
+ *
+ * \author	Stefan Knoblich
+ */
+static const char *Q921State2Name(Q921State_t state)
+{
+	struct Q921StateName *p = Q921StateNames;
+
+	while(p->name) {
+		if(p->value == state)
+			return p->name;
+		p++;
+	}
+
+	return "Unknown";
+}
+
+
+/**
+ * Q921SendEnquiry
+ */
+static int Q921SendEnquiry(L2TRUNK trunk, L2UCHAR tei)
+{
+	struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+	/* send enquiry: begin */
+	if(Q921_CHECK_FLAG(link, Q921_FLAG_RECV_BUSY)) {
+
+		Q921SendRNR(trunk, trunk->sapi, Q921_COMMAND(trunk), tei, 1);
+	}
+	else {
+		Q921SendRR(trunk, trunk->sapi, Q921_COMMAND(trunk), tei, 1);
+	}
+
+	/* clear acknowledge pending */
+	Q921_CLEAR_FLAG(link, Q921_FLAG_ACK_PENDING);
+
+	/* "Start" T200 */
+	Q921T200TimerReset(trunk, tei);
+
+	/* send enquiry: end */
+	return 1;
+}
+
+/**
+ * Q921SendEnquiryResponse
+ */
+static int Q921SendEnquiryResponse(L2TRUNK trunk, L2UCHAR tei)
+{
+	struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+	/* send enquiry: begin */
+	if(Q921_CHECK_FLAG(link, Q921_FLAG_RECV_BUSY)) {
+
+		Q921SendRNR(trunk, trunk->sapi, Q921_RESPONSE(trunk), tei, 1);
+	}
+	else {
+		Q921SendRR(trunk, trunk->sapi, Q921_RESPONSE(trunk), tei, 1);
+
+		/* clear acknowledge pending */
+		Q921_CLEAR_FLAG(link, Q921_FLAG_ACK_PENDING);
+	}
+	/* send enquiry: end */
+	return 1;
+}
+
+/**
+ * Q921ResetExceptionConditions
+ * \brief	Reset Q.921 Exception conditions procedure
+ * \param	trunk	Q.921 data structure
+ * \param	tei	TEI
+ * \todo	Do something
+ */
+static void Q921ResetExceptionConditions(L2TRUNK trunk, L2UCHAR tei)
+{
+	struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+	/* Clear peer receiver busy */
+	Q921_CLEAR_FLAG(link, Q921_FLAG_PEER_RECV_BUSY);
+
+	/* Clear reject exception */
+	Q921_CLEAR_FLAG(link, Q921_FLAG_REJECT);
+
+	/* Clear own receiver busy */
+	Q921_CLEAR_FLAG(link, Q921_FLAG_RECV_BUSY);
+
+	/* Clear acknowledge pending */
+	Q921_CLEAR_FLAG(link, Q921_FLAG_ACK_PENDING);
+
+	return;
+}
+
+/**
+ * Q921EstablishDataLink
+ * \brief	Q.921 Establish data link procedure
+ * \param	trunk	Q.921 data structure
+ * \param	tei	TEI
+ * \return	always 1 (success)
+ */
+static int Q921EstablishDataLink(L2TRUNK trunk, L2UCHAR tei)
+{
+	struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+	/* reset exception conditions */
+	Q921ResetExceptionConditions(trunk, tei);
+
+	/* RC = 0 */
+	link->N200 = 0;
+
+	/* Send SABME */
+	Q921SendSABME(trunk, trunk->sapi, Q921_COMMAND(trunk), tei, 1);
+
+	/* Restart T200, stop T203 */
+	Q921T200TimerReset(trunk, tei);
+	Q921T203TimerStop(trunk, tei);
+
+	return 1;
+}
+
+/**
+ * Q921NrErrorRecovery
+ * \brief	NR(R) Error recovery procedure
+ * \param	trunk	Q.921 data structure
+ * \param	tei	TEI
+ * \return	always 1 (success)
+ */
+static int Q921NrErrorRecovery(L2TRUNK trunk, L2UCHAR tei)
+{
+	struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+	/* MDL Error indication (J) */
+
+	/* Establish datalink */
+	Q921EstablishDataLink(trunk, tei);
+
+	/* Clear L3 initiated */
+	Q921_CLEAR_FLAG(link, Q921_FLAG_L3_INITIATED);
+
+	return 1;
+}
+
+
+/**
+ * Q921InvokeRetransmission
+ * \brief	I Frame retransmission procedure
+ * \param	trunk	Q.921 data structure
+ * \param	tei	TEI
+ * \param	nr	N(R) for retransmission
+ * \return	always 1 (success)
+ */
+static int Q921InvokeRetransmission(L2TRUNK trunk, L2UCHAR tei, L2UCHAR nr)
+{
+	struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+	L2UCHAR *mes;
+	L2INT qpos, qnum, size = 0;
+
+	qnum = MFIFOGetMesCount(link->IFrameResendQueue);
+	qpos = qnum - 1;
+
+	/*
+	 * slightly different than what is shown in the spec
+	 * (Q.921 '97 Annex B, Figure B.9, page 104)
+	 * 
+	 * what the above mentioned figure probably means is:
+	 * "as long as V(S) != N(R), move the pointer marking
+	 *  the first frame to start resending at to the previous
+	 *  frame"
+	 *
+	 * if we actually implemented it as shown in the figure, we'd be
+	 * resending frames in the wrong order (moving backwards in time)
+	 * meaning we'd have to add an incoming queue to reorder the frames
+	 *
+	 */
+	/*
+	 * TODO: There's a "traditional" off-by-one error hidden in the original
+	 *       mfifo implementation + it's late, i'm tired and being lazy,
+	 *       so i'll probably have added another one :P
+	 *
+	 *       wow, the first while loop sucks and can be removed
+	 */
+	while(link->vs != nr && qpos > 0) {	/* ???? */
+		/* V(S) = V(S) - 1 */
+		Q921_DEC_COUNTER(link->vs);	/* huh? backwards? */
+
+		/* next frame in queue (backtrack along I queue) ??? */
+		qpos--;
+	}
+
+	/*
+	 * being lazy and trying to avoid mod 128 math this way...
+	 */
+	if(link->vs != nr && !qpos) {
+		/* fatal, we don't have enough history to resend all missing frames */
+		/* TODO: how to handle this? */
+	}
+
+	/*
+	 * resend frames in correct order (oldest missing frame first,
+	 * contrary to what the spec figure shows)
+	 */
+	while(qpos < qnum) {
+		/* Grab frame's buffer ptr and size from queue */
+		mes = MFIFOGetMesPtrOffset(link->IFrameResendQueue, &size, qpos);
+		if(mes) {
+			/* requeue frame (TODO: check queue full condition) */
+			MFIFOWriteMes(link->IFrameQueue, mes, size);
+
+			/* set I frame queued */
+		}
+
+		qpos++;
+	}
+
+	return 1;
+}
+
+
+static int Q921AcknowledgePending(L2TRUNK trunk, L2UCHAR tei)
+{
+	struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+	switch(link->state) {
+	case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
+	case Q921_STATE_TIMER_RECOVERY:
+		if(Q921_CHECK_FLAG(link, Q921_FLAG_ACK_PENDING)) {
+			/* clear acknowledge pending */
+			Q921_CLEAR_FLAG(link, Q921_FLAG_ACK_PENDING);
+
+			/* send RR */
+			Q921SendRR(trunk, trunk->sapi, Q921_COMMAND(trunk), tei, 0);
+
+			return 1;
+		}
+		break;
+
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+/*****************************************************************************
+
+  Function:     Q921_InitTrunk
+
+  Decription:   Initialize a Q.921 trunk so it is ready for use. This 
+                function MUST be called before you call any other functions.
+
+*****************************************************************************/
+int Q921_InitTrunk(L2TRUNK trunk,
+					L2UCHAR sapi,
+					L2UCHAR tei,
+					Q921NetUser_t NetUser,
+					Q921NetType_t NetType,
+					L2INT hsize,
+					Q921Tx21CB_t cb21,
+					Q921Tx23CB_t cb23,
+					void *priv21,
+					void *priv23)
+{
+	int numlinks = 0;
+
+	trunk->sapi = sapi;
+	trunk->tei = tei;
+	trunk->NetUser = NetUser;
+	trunk->NetType = NetType;
+	trunk->Q921Tx21Proc = cb21;
+	trunk->Q921Tx23Proc = cb23;
+	trunk->PrivateData21 = priv21;
+	trunk->PrivateData23 = priv23;
+	trunk->Q921HeaderSpace = hsize;
+
+	numlinks = Q921_IS_PTMP_NT(trunk) ? Q921_TEI_MAX : 1;
+
+	if (trunk->initialized != INITIALIZED_MAGIC) {
+		MFIFOCreate(trunk->HDLCInQueue, Q921MAXHDLCSPACE, 10);
+
+		/*
+		 * Allocate space for per-link context(s)
+		 */
+		trunk->context = ftdm_malloc(numlinks * sizeof(struct Q921_Link));
+		if(!trunk->context)
+			return -1;
+
+		trunk->initialized = INITIALIZED_MAGIC;
+	}
+
+	/* timeout default values */
+	trunk->T200Timeout = 1000;	/*   1 second  */
+	trunk->T203Timeout = 10000;	/*  10 seconds */
+	trunk->T202Timeout = 2000;	/*   2 seconds */
+	trunk->T201Timeout = 200000;	/* 200 seconds */
+	trunk->TM01Timeout = 10000;	/*  10 seconds */
+
+	/* octet / retransmit counter default limits */
+	trunk->N200Limit   = 3;		/*   3 retransmits */
+	trunk->N201Limit   = 260;	/* 260 octets      */
+	trunk->N202Limit   = 3;		/*   3 retransmits */
+	trunk->k           = 7;		/*   7 outstanding ACKs */
+
+	/* reset counters, timers, etc. */
+	trunk->T202 = 0;
+	trunk->N202 = 0;
+
+	/* Reset per-link contexts */
+	memset(trunk->context, 0, numlinks * sizeof(struct Q921_Link));
+
+	/* clear tei map */
+	memset(trunk->tei_map, 0, Q921_TEI_MAX + 1);
+
+	if(Q921_IS_PTMP(trunk)) {
+		/*
+		 * We're either the Network side (NT, TEI = 0)
+		 * or user-side equipment (TE) which will get it's TEI via
+		 * dynamic assignment
+		 */
+		trunk->tei = 0;
+	}
+
+	return 0;
+}
+
+
+/**
+ * Q921Tx21Proc
+ * \brief	Submit frame to layer 1 (for sending)
+ * \param[in]	trunk	Pointer to trunk struct
+ * \param[in]	mes	pointer to message buffer
+ * \param[in]	size	size of message
+ * \return	> 0 on success; <= 0 on error
+ */
+static int Q921Tx21Proc(L2TRUNK trunk, L2UCHAR *Msg, L2INT size)
+{
+	Q921LogMesg(trunk, Q921_LOG_DEBUG, 0, Msg, size, "Sending frame");
+
+	return trunk->Q921Tx21Proc(trunk->PrivateData21, Msg, size);
+}
+
+
+/**
+ * Q921Tx23Proc
+ * \brief	Submit frame to layer 3
+ * \param[in]	trunk	Pointer to trunk struct
+ * \param[in]	mes	pointer to message buffer
+ * \param[in]	size	size of message
+ * \return	> 0 on success; <= 0 on error
+ */
+static int Q921Tx23Proc(L2TRUNK trunk, Q921DLMsg_t ind, L2UCHAR tei, L2UCHAR *Msg, L2INT size)
+{
+	return trunk->Q921Tx23Proc(trunk->PrivateData23, ind, tei, Msg, size);
+}
+
+
+/**
+ * Q921LogProc
+ * \brief	Used for logging, converts to string and submits to higher level log function via callback
+ * \param[in]	trunk	Pointer to trunk struct
+ * \param[in]	level	Q921 Loglevel
+ * \param[in]	fmt	format of logmessage
+ * \return	>= 0 on success, < 0 on error
+ *
+ * \author	Stefan Knoblich
+ */
+static int Q921Log(L2TRUNK trunk, Q921LogLevel_t level, const char *fmt, ...)
+{
+	char  buf[Q921_LOGBUFSIZE];
+	L2INT len;
+	va_list ap;
+
+	if(!trunk->Q921LogProc)
+		return 0;
+
+	if(trunk->loglevel < level)
+		return 0;
+
+	va_start(ap, fmt);
+
+	len = vsnprintf(buf, sizeof(buf)-1, fmt, ap);
+	if(len <= 0) {
+		/* TODO: error handling */
+		return -1;
+	}
+	if(len >= sizeof(buf))
+		len = sizeof(buf) - 1;
+
+	buf[len] = '\0';
+
+	va_end(ap);
+
+	return trunk->Q921LogProc(trunk->PrivateDataLog, level, buf, len);
+}
+
+
+static int print_hex(char *buf, int bsize, const unsigned char *in, const int len)
+{
+	static const char hex[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
+	int offset = 0;
+	int pos    = 0;
+	int nr     = 0;
+
+	buf[pos++] = '[';
+	bsize -= 3;
+
+	while((bsize - pos) > 0 && offset < len) {
+		buf[pos++] = hex[(in[offset] & 0xF0) >> 4];
+		buf[pos++] = hex[(in[offset++]   & 0x0F)];
+
+		if(++nr == 32 && offset < len && (bsize - pos) > 3) {
+			nr = 0;
+			buf[pos++] = ']';
+			buf[pos++] = '\n';
+			buf[pos++] = '[';
+		}
+		else if(offset < len) {
+			buf[pos++] = ' ';
+		}
+	}
+
+	buf[pos++] = ']';
+	buf[pos++] = '\n';
+	buf[pos]   = '\0';
+
+	return pos;
+}
+
+#define APPEND_MSG(buf, off, lef, fmt, ...) 			\
+	len = snprintf(buf + off, lef, fmt, ##__VA_ARGS__);	\
+	if(len > 0) { 						\
+		off += len;					\
+		lef -= len;					\
+	} else {						\
+		goto out;					\
+	}
+
+/**
+ * Q921LogProcMesg
+ * \brief	Used for logging, converts to string and submits to higher level log function via callback
+ * \param[in]	trunk	Pointer to trunk struct
+ * \param[in]	level	Q921 Loglevel
+ * \param[in]	received	direction of the message (received = 1, sending = 0)
+ * \param[in]	mes	pointer to message buffer
+ * \param[in]	size	size of message
+ * \param[in]	fmt	format of logmessage
+ * \return	>= 0 on success, < 0 on error
+ *
+ * \author	Stefan Knoblich
+ */
+static int Q921LogMesg(L2TRUNK trunk, Q921LogLevel_t level, L2UCHAR received, L2UCHAR *mes, L2INT size, const char *fmt, ...)
+{
+	char  buf[Q921_LOGBUFSIZE];
+	size_t len, left;
+	va_list ap;
+
+	if(!trunk->Q921LogProc)
+		return 0;
+
+	if(trunk->loglevel < level)
+		return 0;
+
+	if(!mes)
+		return 0;
+
+	memset(buf, 0, sizeof(buf));
+
+	left = sizeof(buf) - 1;
+
+	va_start(ap, fmt);
+
+	len = vsnprintf(buf, left, fmt, ap);
+	if(len > 0)
+		left -= len;
+	else {
+		/* TODO: error handling */
+		return -1;
+	}
+
+	va_end(ap);
+
+	if(trunk->loglevel == Q921_LOG_DEBUG) {
+		char pbuf[1024];
+		size_t pleft, poffset;
+		L2UCHAR sapi, tei, cr;
+		L2UCHAR *pmes = mes + trunk->Q921HeaderSpace;
+		struct Q921_Link *link;
+
+		memset(pbuf, 0, sizeof(pbuf));
+
+		pleft   = sizeof(pbuf);
+		poffset = 0;
+
+		/*
+		 * Decode packet
+		 */
+		sapi = (pmes[0] & 0xfc) >> 2;
+		cr   = (pmes[0] & 0x02) >> 1;
+		tei  = (pmes[1] & 0xfe) >> 1;
+		link  = Q921_LINK_CONTEXT(trunk, tei);
+
+		/* make cr actually useful */
+		cr   = (received) ? Q921_IS_COMMAND(trunk, cr) : Q921_IS_RESPONSE(trunk, cr);
+
+		/* filter */
+		if((pmes[2] & 0x01) == 0x00) {
+ 			;
+		}
+		else if((pmes[2] & 0x03) == 0x01) {
+			; //return 0;
+		}
+		else if((pmes[2] & 0x03) == 0x03) {
+			;
+		}
+
+		APPEND_MSG(pbuf, poffset, pleft, "\n----------------- Q.921 Packet [%s%s] ---------------\n", received ? "Incoming" : "Outgoing",
+						(tei == link->tei || tei == Q921_TEI_BCAST) ? "" : ", Ignored" );
+
+		/* common header */
+		APPEND_MSG(pbuf, poffset, pleft, "    SAPI: %u, TEI: %u, C/R: %s (%d)\n\n", sapi, tei, (cr) ? "Command" : "Response", (mes[0] & 0x02) >> 1 );
+
+		/*
+		 * message specific
+		 */
+		if((pmes[2] & 0x01) == 0x00) {
+			/*
+			 * I frame
+			 */
+			L2UCHAR pf = pmes[3] & 0x01;	/* poll / final flag */
+			L2UCHAR nr = pmes[3] >> 1;	/* receive sequence number */
+			L2UCHAR ns = pmes[2] >> 1;	/* send sequence number */
+
+			APPEND_MSG(pbuf, poffset, pleft, "    Type: I Frame\n          P/F: %d, N(S): %d, N(R): %d  [V(A): %d, V(R): %d, V(S): %d]\n", pf, ns, nr,
+														link->va, link->vr, link->vs);
+
+			/* Dump content of I Frames for foreign TEIs */
+			if(tei != link->tei) {
+				APPEND_MSG(pbuf, poffset, pleft, "    CONTENT:\n");
+
+				len = print_hex(pbuf + poffset, (int)pleft, &pmes[4], size - (trunk->Q921HeaderSpace + 4));
+				poffset += len;
+				pleft   -= len;
+			}
+		}
+		else if((pmes[2] & 0x03) == 0x01) {
+			/*
+			 * S frame
+			 */
+			L2UCHAR sv = (pmes[2] & 0x0c) >> 2;	/* supervisory format id */
+			L2UCHAR pf =  pmes[3] & 0x01;		/* poll / final flag */
+			L2UCHAR nr =  pmes[3] >> 1;		/* receive sequence number */
+			const char *type;
+
+			switch(sv) {
+			case 0x00:	/* RR : Receive Ready */
+				type = "RR (Receive Ready)";
+				break;
+
+			case 0x02:	/* RNR : Receive Not Ready */
+				type = "RNR (Receiver Not Ready)";
+				break;
+
+			case 0x04:	/* REJ : Reject */
+				type = "REJ (Reject)";
+				break;
+
+			default:	/* Invalid / Unknown */
+				type = "Unknown";
+				break;
+			}
+
+			APPEND_MSG(pbuf, poffset, pleft, "    Type: S Frame, SV: %s\n          P/F: %d, N(R): %d  [V(A): %d, V(R): %d, V(S): %d]\n", type, pf, nr,
+														link->va, link->vr, link->vs);
+		}
+		else if((pmes[2] & 0x03) == 0x03) {
+			/*
+			 * U frame
+			 */
+			L2UCHAR m  = (pmes[2] & 0xe0) >> 3 | (pmes[2] & 0x0c) >> 2;	/* modifier function id */
+			L2UCHAR pf = (pmes[2] & 0x10) >> 4;				/* poll / final flag */
+			const char *type;
+
+			switch(m) {
+			case 0x00:
+				type = "UI (Unnumbered Information)";
+				break;
+
+			case 0x03:
+				type = "DM (Disconnected Mode)";
+				break;
+
+			case 0x08:
+				type = "DISC (Disconnect)";
+				break;
+
+			case 0x0c:
+				type = "UA (Unnumbered Acknowledgement)";
+				break;
+
+			case 0x0f:
+				type = "SABME";
+				break;
+
+			case 0x11:
+				type = "FRMR (Frame Reject)";
+				break;
+
+			case 0x17:
+				type = "XID (Exchange Identification)";
+				break;
+
+			default:
+				type = "Unknown";
+			}
+
+
+			APPEND_MSG(pbuf, poffset, pleft, "    Type: U Frame (%s)\n          P/F: %d\n", type, pf);
+
+			if(m == 0x00) {
+				switch(pmes[3]) {
+				case Q921_LAYER_ENT_ID_TEI:
+					type = "TEI Mgmt";
+					break;
+
+				case Q921_LAYER_ENT_ID_Q931:
+					type = "Q.931";
+					break;
+
+				default:
+					type = "Unknown";
+				}
+
+				if(pmes[3] == Q921_LAYER_ENT_ID_TEI) {
+					const char *command = "";
+
+					switch(pmes[6]) {
+					case Q921_TEI_ID_REQUEST:
+						command = "Request";
+						break;
+					case Q921_TEI_ID_VERIFY:
+						command = "Verify";
+						break;
+					case Q921_TEI_ID_CHECKREQ:
+						command = "Check req";
+						break;
+					case Q921_TEI_ID_CHECKRESP:
+						command = "Check resp";
+						break;
+					case Q921_TEI_ID_REMOVE:
+						command = "Remove";
+						break;
+					case Q921_TEI_ID_ASSIGNED:
+						command = "Assign";
+						break;
+					case Q921_TEI_ID_DENIED:
+						command = "Denied";
+						break;
+					}
+					APPEND_MSG(pbuf, poffset, pleft, "    ENT ID: %d (%s), COMMAND: %d (%s), RI: %#x, AI: %d\n",
+							 pmes[3], type, pmes[6], command, (int)((pmes[4] << 8) | pmes[5]), pmes[7] >> 1);
+				}
+				else {
+					APPEND_MSG(pbuf, poffset, pleft, "    ENT ID: %d (%s), MESSAGE CONTENT:\n", pmes[3], type);
+
+					len = print_hex(pbuf + poffset, (int)pleft, &pmes[3], size - (trunk->Q921HeaderSpace + 3));
+					poffset += len;
+					pleft   -= len;
+				}
+			}
+		}	
+		else {
+			/*
+			 * Unknown
+			 */
+			strncat(pbuf + poffset, "  -- unknown frame type --\n", pleft);
+
+			len = (sizeof(pbuf) - poffset) - strlen(pbuf + poffset);
+			if(len > 0) {
+				poffset += len;
+				pleft   -= len;
+			} else
+				goto out;
+		}
+
+		APPEND_MSG(pbuf, poffset, pleft, "\n    Q.921 state: \"%s\" (%d) [flags: %c%c%c%c]\n", Q921State2Name(link->state), link->state,
+											Q921_CHECK_FLAG(link, Q921_FLAG_ACK_PENDING) ? 'A' : '-',
+											Q921_CHECK_FLAG(link, Q921_FLAG_REJECT) ? 'R' : '-',
+											Q921_CHECK_FLAG(link, Q921_FLAG_PEER_RECV_BUSY) ? 'P' : '-',
+											Q921_CHECK_FLAG(link, Q921_FLAG_RECV_BUSY) ? 'B' : '-');
+
+		strncat(pbuf + poffset, "----------------------------------------------\n\n", pleft);
+
+		len = (sizeof(pbuf) - poffset) - strlen(pbuf + poffset);
+		if(len > 0) {
+			poffset += len;
+			pleft   -= len;
+		} else
+			goto out;
+
+
+		/* concat buffers together */
+		len = strlen(pbuf);
+		if(len <= left)
+			strncat(buf, pbuf, left);
+		else
+			strncat(buf, "-- packet truncated --\n", left);
+	}
+
+out:
+	buf[sizeof(buf) - 1] = '\0';
+
+	return trunk->Q921LogProc(trunk->PrivateDataLog, level, buf, (int)strlen(buf));
+}
+
+/*****************************************************************************
+
+  Function:     Q921TimeTick
+
+  Description:  Called periodically from an external source to allow the 
+                stack to process and maintain it's own timers.
+
+  Return Value: none
+
+*****************************************************************************/
+static L2ULONG (*Q921GetTimeProc) (void) = NULL; /* callback for func reading time in ms */
+static L2ULONG tLast = {0};
+
+static L2ULONG Q921GetTime(void)
+{
+	L2ULONG tNow = 0;
+
+	if(Q921GetTimeProc)
+	{
+		tNow = Q921GetTimeProc();
+		if(tNow < tLast)	/* wrapped */
+		{
+			/* TODO */
+		}
+		tLast = tNow;
+	}
+	return tNow;
+}
+
+/*
+ * T200 handling (per-TEI in PTMP NT mode, tei=0 otherwise)
+ */
+static void Q921T200TimerStart(L2TRUNK trunk, L2UCHAR tei)
+{
+	struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+	if (!link->T200) {
+		link->T200 = Q921GetTime() + trunk->T200Timeout;
+
+		Q921Log(trunk, Q921_LOG_DEBUG, "T200 (timeout: %d msecs) started for TEI %d\n", trunk->T200Timeout, tei);
+	}
+}
+
+static void Q921T200TimerStop(L2TRUNK trunk, L2UCHAR tei)
+{
+	struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+	link->T200 = 0;
+
+	Q921Log(trunk, Q921_LOG_DEBUG, "T200 stopped for TEI %d\n", tei);
+}
+
+static void Q921T200TimerReset(L2TRUNK trunk, L2UCHAR tei)
+{
+	struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+	link->T200 = Q921GetTime() + trunk->T200Timeout;
+
+	Q921Log(trunk, Q921_LOG_DEBUG, "T200 (timeout: %d msecs) restarted for TEI %d\n", trunk->T200Timeout, tei);
+}
+
+/*
+ * T203 handling (per-TEI in PTMP NT mode, tei=0 otherwise)
+ */
+static void Q921T203TimerStart(L2TRUNK trunk, L2UCHAR tei)
+{
+	struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+	if (!link->T203) {
+		link->T203 = Q921GetTime() + trunk->T203Timeout;
+
+		Q921Log(trunk, Q921_LOG_DEBUG, "T203 (timeout: %d msecs) started for TEI %d\n", trunk->T203Timeout, tei);
+	}
+}
+
+static void Q921T203TimerStop(L2TRUNK trunk, L2UCHAR tei)
+{
+	struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+	link->T203 = 0;
+
+	Q921Log(trunk, Q921_LOG_DEBUG, "T203 stopped for TEI %d\n", tei);
+}
+
+static void Q921T203TimerReset(L2TRUNK trunk, L2UCHAR tei)
+{
+	struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+	link->T203 = Q921GetTime() + trunk->T203Timeout;
+
+	Q921Log(trunk, Q921_LOG_DEBUG, "T203 (timeout: %d msecs) restarted for TEI %d\n", trunk->T203Timeout, tei);
+}
+
+/*
+ * T202 handling (TEI message timeout, TE mode only)
+ */
+static void Q921T202TimerStart(L2TRUNK trunk)
+{
+	if (!trunk->T202) {
+		trunk->T202 = Q921GetTime() + trunk->T202Timeout;
+
+		Q921Log(trunk, Q921_LOG_DEBUG, "T202 (timeout: %d msecs) started\n", trunk->T202Timeout);
+	}
+}
+
+static void Q921T202TimerStop(L2TRUNK trunk)
+{
+	trunk->T202 = 0;
+
+	Q921Log(trunk, Q921_LOG_DEBUG, "T202 stopped\n");
+}
+
+static void Q921T202TimerReset(L2TRUNK trunk)
+{
+	trunk->T202 = Q921GetTime() + trunk->T202Timeout;
+
+	Q921Log(trunk, Q921_LOG_DEBUG, "T202 (timeout: %d msecs) restarted\n", trunk->T202Timeout);
+}
+
+/*
+ * T201 handling (TEI management (NT side), per-TEI)
+ */
+static void Q921T201TimerStart(L2TRUNK trunk, L2UCHAR tei)
+{
+	struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+	if (!link->T201) {
+		link->T201 = Q921GetTime() + trunk->T201Timeout;
+
+		Q921Log(trunk, Q921_LOG_DEBUG, "T201 (timeout: %d msecs) started for TEI %d\n", trunk->T201Timeout, tei);
+	}	
+}
+
+static void Q921T201TimerStop(L2TRUNK trunk, L2UCHAR tei)
+{
+	struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+	link->T201 = 0;
+
+	Q921Log(trunk, Q921_LOG_DEBUG, "T201 stopped for TEI %d\n", tei);
+}
+
+#ifdef __UNUSED_FOR_NOW__
+static void Q921T201TimerReset(L2TRUNK trunk, L2UCHAR tei)
+{
+	struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+	link->T201 = Q921GetTime() + trunk->T201Timeout;
+
+	Q921Log(trunk, Q921_LOG_DEBUG, "T201 (timeout: %d msecs) restarted for TEI %d\n", trunk->T201Timeout, tei);
+}
+#endif
+
+/*
+ * TM01 handling (Datalink inactivity shutdown timer)
+ */
+static void Q921TM01TimerStart(L2TRUNK trunk, L2UCHAR tei)
+{
+	struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+	if (!link->TM01) {
+		link->TM01 = Q921GetTime() + trunk->TM01Timeout;
+
+		Q921Log(trunk, Q921_LOG_DEBUG, "TM01 (timeout: %d msecs) started for TEI %d\n", trunk->TM01Timeout, tei);
+	}
+}
+
+#ifdef __UNUSED_FOR_NOW__
+static void Q921TM01TimerStop(L2TRUNK trunk, L2UCHAR tei)
+{
+	struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+	link->TM01 = 0;
+
+	Q921Log(trunk, Q921_LOG_DEBUG, "TM01 stopped for TEI %d\n", tei);
+}
+#endif
+
+static void Q921TM01TimerReset(L2TRUNK trunk, L2UCHAR tei)
+{
+	struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+	link->TM01 = Q921GetTime() + trunk->TM01Timeout;
+
+	Q921Log(trunk, Q921_LOG_DEBUG, "TM01 (timeout: %d msecs) restarted for TEI %d\n", trunk->TM01Timeout, tei);
+}
+
+/*
+ * Expiry callbacks
+ */
+static void Q921T200TimerExpire(L2TRUNK trunk, L2UCHAR tei)
+{
+	struct Q921_Link *link   = Q921_LINK_CONTEXT(trunk, tei);
+	struct Q921_Link *trlink = Q921_TRUNK_CONTEXT(trunk);
+
+	Q921Log(trunk, Q921_LOG_DEBUG, "T200 expired for TEI %d (trunk TEI %d)\n", tei, trlink->tei);
+
+	/* Stop timer first */
+	Q921T200TimerStop(trunk, tei);
+
+	switch(link->state) {
+	case Q921_STATE_AWAITING_ESTABLISHMENT:
+		if(link->N200 >= trunk->N200Limit) {
+			/* Discard I queue */
+			MFIFOClear(link->IFrameQueue);
+
+			/* MDL-Error indication (G) */
+			Q921Log(trunk, Q921_LOG_ERROR, "Failed to establish Q.921 link in %d retries\n", link->N200);
+
+			/* DL-Release indication */
+			Q921Tx23Proc(trunk, Q921_DL_RELEASE, tei, NULL, 0);
+
+			/* change state (no action) */
+			Q921ChangeState(trunk, Q921_STATE_TEI_ASSIGNED, tei);
+		} else {
+			/* Increment retry counter */
+			link->N200++;
+
+			/* Send SABME */
+			Q921SendSABME(trunk,
+					trunk->sapi,
+					Q921_COMMAND(trunk),
+					tei,
+					1);
+
+			/* Start T200 */
+			Q921T200TimerStart(trunk, tei);
+		}
+		break;
+
+	case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
+		link->N200 = 0;
+
+		if(!Q921_CHECK_FLAG(link, Q921_FLAG_PEER_RECV_BUSY)) {
+			/* get last transmitted I frame */
+
+			/* V(S) = V(S) - 1 */
+			Q921_DEC_COUNTER(link->vs);
+
+			/* retransmit I frame */
+
+			/* V(S) = V(S) + 1 (done by Q921SendI() ) */
+			//Q921_INC_COUNTER(link->vs);
+
+			/* clear acknowledge pending */
+			Q921_CLEAR_FLAG(link, Q921_FLAG_ACK_PENDING);
+
+			/* Start T200 */
+			Q921T200TimerStart(trunk, tei);
+		} else {
+			/* transmit enquiry */
+			Q921SendEnquiry(trunk, tei);
+		}
+
+		/* increment counter */
+		link->N200++;
+
+		/* change state (no action) */
+		Q921ChangeState(trunk, Q921_STATE_TIMER_RECOVERY, tei);
+		break;
+
+	case Q921_STATE_TIMER_RECOVERY:
+		if(link->N200 == trunk->N200Limit) {
+			/* MDL Error indication (I) */
+
+			/* Establish data link */
+			Q921EstablishDataLink(trunk, tei);
+
+			/* Clear L3 initiated */
+			Q921_CLEAR_FLAG(link, Q921_FLAG_L3_INITIATED);
+
+			/* change state (no action) */
+			Q921ChangeState(trunk, Q921_STATE_AWAITING_ESTABLISHMENT, tei);
+		} else {
+			if(link->vs == link->va) {
+				/* transmit enquiry */
+				Q921SendEnquiry(trunk, tei);
+
+			} else if(!Q921_CHECK_FLAG(link, Q921_FLAG_PEER_RECV_BUSY)) {
+				/* get last transmitted frame */
+
+				/* V(S) = V(S) - 1 */
+				Q921_DEC_COUNTER(link->vs);
+
+				/* retrans frame */
+
+				/* V(S) = V(S) + 1 (done by Q921SendI() ) */
+				//Q921_INC_COUNTER(link->vs);
+
+				/* clear acknowledge pending */
+				Q921_CLEAR_FLAG(link, Q921_FLAG_ACK_PENDING);
+
+				/* Start T200 */
+				Q921T200TimerStart(trunk, tei);
+			}
+
+			/* increment counter */
+			link->N200++;
+
+			/* no state change */
+		}
+		break;
+
+	default:
+		break;
+	}
+}
+
+static void Q921T203TimerExpire(L2TRUNK trunk, L2UCHAR tei)
+{
+	struct Q921_Link *link   = Q921_LINK_CONTEXT(trunk, tei);
+	struct Q921_Link *trlink = Q921_TRUNK_CONTEXT(trunk);
+
+	Q921Log(trunk, Q921_LOG_DEBUG, "T203 expired for TEI %d (trunk TEI %d)\n", tei, trlink->tei);
+
+	/* Stop Timer first */
+	Q921T203TimerStop(trunk, tei);
+
+	switch(link->state) {
+	case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
+		/* Send Enquiry */
+		Q921SendEnquiry(trunk, tei);
+
+		/* RC = 0 */
+		link->N200 = 0;
+
+		/* no state change */
+		break;
+
+	default:
+		break;
+	}
+}
+
+static void Q921T202TimerExpire(L2TRUNK trunk)
+{
+	struct Q921_Link *link = Q921_TRUNK_CONTEXT(trunk);
+
+	Q921T202TimerReset(trunk);
+
+	Q921Log(trunk, Q921_LOG_DEBUG, "T202 expired for Q.921 trunk with TEI %d\n", link->tei);
+
+	/* todo: implement resend counter */
+
+	switch(link->state) {
+	case Q921_STATE_TEI_ASSIGNED:	/* Tei identity verify timeout */
+		Q921TeiSendVerifyRequest(trunk);
+		break;
+
+	default:			/* Tei assignment request timeout (TODO: refine) */
+
+		if(trunk->N202 >= trunk->N202Limit) {
+			/* Too many retransmits, reset counter, stop timer and handle case (TODO) */
+			trunk->N202 = 0;
+
+			Q921T202TimerStop(trunk);
+
+			return;
+		}
+		Q921TeiSendAssignRequest(trunk);
+
+		trunk->N202++;
+	}
+}
+
+static void Q921T201TimerExpire(L2TRUNK trunk, L2UCHAR tei)
+{
+	struct Q921_Link *link   = Q921_LINK_CONTEXT(trunk, tei);
+	struct Q921_Link *trlink = Q921_TRUNK_CONTEXT(trunk);
+
+	Q921Log(trunk, Q921_LOG_DEBUG, "T201 expired for TEI %d (trunk TEI: %d)\n", tei, trlink->tei);
+
+	Q921T201TimerStop(trunk, tei);
+
+	/* NOTE: abusing N202 for this */
+	if(link->N202 < trunk->N202Limit) {
+		/* send check request */
+		Q921TeiSendCheckRequest(trunk, tei);
+
+		/* increment counter */
+		link->N202++;
+	} else {
+		/* put context in STOPPED state */
+		Q921ChangeState(trunk, Q921_STATE_STOPPED, tei);
+
+		/* NOTE: should we clear the link too? */
+		memset(link, 0, sizeof(struct Q921_Link));
+
+		/* mark TEI free */
+		trunk->tei_map[tei] = 0;
+	}
+}
+
+#ifdef __UNUSED_FOR_NOW__
+static void Q921TM01TimerExpire(L2TRUNK trunk, L2UCHAR tei)
+{
+	struct Q921_Link *link   = Q921_LINK_CONTEXT(trunk, tei);
+	struct Q921_Link *trlink = Q921_TRUNK_CONTEXT(trunk);
+
+	Q921Log(trunk, Q921_LOG_DEBUG, "TM01 expired for TEI %d (trunk TEI: %d)\n", tei, trlink->tei);
+
+	/* Restart TM01 */
+	Q921TM01TimerReset(trunk, tei);
+
+	switch(link->state) {
+	case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
+	case Q921_STATE_TIMER_RECOVERY:
+/*
+ * NT-only, needs more support from L3
+ */
+#if 0
+		/* No activity, shutdown link */
+		Q921SendDISC(trunk, trunk->sapi, Q921_COMMAND(trunk), tei, 1);
+
+		/* clear I queue */
+		MFIFOClear(link->IFrameQueue);
+
+		/* change state */
+		Q921ChangeState(trunk, Q921_STATE_AWAITING_RELEASE, tei);
+#endif
+		break;
+
+	default:
+		break;
+	}
+}
+#endif
+
+/*
+ * Timer Tick function
+ */
+void Q921TimerTick(L2TRUNK trunk)
+{
+	struct Q921_Link *link;
+	L2ULONG tNow = Q921GetTime();
+	int numlinks = Q921_IS_PTMP_NT(trunk) ? Q921_TEI_MAX : 1;
+	int x;
+
+	for(x = 0; x <= numlinks; x++) {
+		link = Q921_LINK_CONTEXT(trunk, x);
+
+		/* TODO: check if TEI is assigned and skip check if not (speedup!) */
+		if(link->state == Q921_STATE_STOPPED)
+			continue;
+
+		if (link->T200 && tNow > link->T200) {
+			Q921T200TimerExpire(trunk, link->tei);
+		}
+		if (link->T203 && tNow > link->T203) {
+			Q921T203TimerExpire(trunk, link->tei);		
+		}
+
+		if(Q921_IS_PTMP_NT(trunk) && link->tei) {
+			if (link->T201 && tNow > link->T201) {
+				Q921T201TimerExpire(trunk, link->tei);
+			}
+		}
+
+		if(!Q921_IS_PTMP_NT(trunk)) {
+			if (trunk->T202 && tNow > trunk->T202) {
+				Q921T202TimerExpire(trunk);
+			}
+		}
+
+		/* Send enqueued I frame, if available */
+		Q921SendQueuedIFrame(trunk, link->tei);
+
+		/* Send ack if pending */
+		Q921AcknowledgePending(trunk, link->tei);
+	}
+
+}
+
+void Q921SetGetTimeCB(L2ULONG (*callback)(void))
+{
+    Q921GetTimeProc = callback;
+}
+
+/*****************************************************************************
+
+  Function:     Q921QueueHDLCFrame
+
+  Description:  Called to receive and queue an incoming HDLC frame. Will
+                queue this in Q921HDLCInQueue. The called must either call
+                Q921Rx12 directly afterwards or signal Q921Rx12 to be called
+                later. Q921Rx12 will read from the same queue and process
+                the frame.
+
+                This function assumes that the message contains header 
+                space. This is removed for internal Q921 processing, but 
+                must be keept for I frames.
+
+  Parameters:   trunk   trunk #
+                b       ptr to frame;
+                size    size of frame in bytes
+
+*****************************************************************************/
+int Q921QueueHDLCFrame(L2TRUNK trunk, L2UCHAR *b, L2INT size)
+{
+    return MFIFOWriteMes(trunk->HDLCInQueue, b, size);
+}
+
+/**
+ * Q921EnqueueI
+ * \brief	Put I frame into transmit queue
+ *
+ */
+static int Q921EnqueueI(L2TRUNK trunk, L2UCHAR Sapi, char cr, L2UCHAR Tei, char pf, L2UCHAR *mes, L2INT size)
+{
+	struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, Tei);
+
+	/* I frame header */
+	mes[trunk->Q921HeaderSpace+0] = ((Sapi << 2) & 0xfc) | ((cr << 1) & 0x02);
+	mes[trunk->Q921HeaderSpace+1] = (Tei << 1) | 0x01;
+	mes[trunk->Q921HeaderSpace+2] = 0x00;
+	mes[trunk->Q921HeaderSpace+3] = (pf & 0x01);
+
+	Q921Log(trunk, Q921_LOG_DEBUG, "Enqueueing I frame for TEI %d [%d]\n", link->tei, Tei);
+
+	/* transmit queue, (TODO: check for full condition!) */
+	MFIFOWriteMes(link->IFrameQueue, mes, size);
+
+	/* try to send queued frame */
+	Q921SendQueuedIFrame(trunk, link->tei);
+
+	return 1;
+}
+
+/**
+ * Q921SendQueuedIFrame
+ * \brief	Try to transmit queued I frame (if available)
+ */
+static int Q921SendQueuedIFrame(L2TRUNK trunk, L2UCHAR tei)
+{
+	struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+	L2INT size = 0;
+	L2UCHAR *mes;
+
+	if(MFIFOGetMesCount(link->IFrameQueue) == 0) {
+		return 0;
+	}
+
+	/* Link ready? */
+	if(link->state != Q921_STATE_MULTIPLE_FRAME_ESTABLISHED) {
+		return 0;
+	}
+
+	/* peer receiver busy? */
+	if(Q921_CHECK_FLAG(link, Q921_FLAG_PEER_RECV_BUSY)) {
+		return 0;
+	}
+
+	/* V(S) = V(A) + k? */
+	if(link->vs == ((link->va + trunk->k) % 128)) {
+		Q921Log(trunk, Q921_LOG_WARNING, "Maximum number (%d) of outstanding I frames reached for TEI %d\n", trunk->k, tei);
+		return 0;
+	}
+
+	mes = MFIFOGetMesPtr(link->IFrameQueue, &size);
+	if(mes) {
+		/* Fill in + update counter values */
+		mes[trunk->Q921HeaderSpace+2]  = link->vs << 1;
+		mes[trunk->Q921HeaderSpace+3] |= link->vr << 1;
+
+		if(MFIFOGetMesCount(link->IFrameQueue) == 0) {
+			/* clear I frame queued */
+		}
+
+		/* Send I frame */
+		Q921Tx21Proc(trunk, mes, size);
+
+		/* V(S) = V(S) + 1 */
+		Q921_INC_COUNTER(link->vs);
+
+		/* clear acknowledge pending */
+		Q921_CLEAR_FLAG(link, Q921_FLAG_ACK_PENDING);
+
+		/* T200 running? */
+		if(!link->T200) {
+			/* Stop T203, Start T200 */
+			Q921T200TimerStart(trunk, tei);
+			Q921T203TimerStop(trunk, tei);
+		}
+
+		/* put frame into resend queue */
+		MFIFOWriteMesOverwrite(link->IFrameResendQueue, mes, size);
+
+		/* dequeue frame */
+		MFIFOKillNext(link->IFrameQueue);
+
+		/* Restart TM01 */
+		if(Q921_IS_NT(trunk)) {
+			Q921TM01TimerReset(trunk, tei);
+		}
+
+		/* no state change */
+		return 1;
+	}
+
+	return 0;
+}
+
+/**
+ * Q921SendS
+ * \brief	Prepare and send S frame
+ */
+static int Q921SendS(L2TRUNK trunk, L2UCHAR Sapi, char cr, L2UCHAR Tei, char pf, L2UCHAR sv, L2UCHAR *mes, L2INT size)
+{
+	struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, Tei);
+
+	if(!Q921_IS_READY(link)) {
+		/* don't even bother trying */
+		Q921Log(trunk, Q921_LOG_DEBUG, "Link not ready, discarding S frame for TEI %d\n", Tei);
+		return 0;
+	}
+
+	/* S frame header */
+	mes[trunk->Q921HeaderSpace+0] = ((Sapi << 2) & 0xfc) | ((cr << 1) & 0x02);
+	mes[trunk->Q921HeaderSpace+1] = (Tei << 1) | 0x01;
+	mes[trunk->Q921HeaderSpace+2] = ((sv << 2) & 0x0c) | 0x01;
+	mes[trunk->Q921HeaderSpace+3] = (link->vr << 1) | (pf & 0x01);
+
+	return Q921Tx21Proc(trunk, mes, size);
+}
+
+
+/**
+ * Q921SendU
+ * \brief	Prepare and send U frame
+ */
+static int Q921SendU(L2TRUNK trunk, L2UCHAR Sapi, char cr, L2UCHAR Tei, char pf, L2UCHAR m, L2UCHAR *mes, L2INT size)
+{
+	struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, Tei);
+
+	/* U frame header */
+	mes[trunk->Q921HeaderSpace+0] = ((Sapi << 2) & 0xfc) | ((cr << 1) & 0x02);
+	mes[trunk->Q921HeaderSpace+1] = (Tei << 1) | 0x01;
+	mes[trunk->Q921HeaderSpace+2] = ((m << 3) & 0xe0) | ((pf << 4) & 0x10) | ((m << 2) & 0x0c) | 0x03;
+
+	/* link not ready? enqueue non-TEI-mgmt UI (DL-UNIT DATA) frames */
+	if(m == 0x00 && Sapi != Q921_SAPI_TEI && link->state < Q921_STATE_TEI_ASSIGNED) {
+
+		/* write frame to queue */
+		MFIFOWriteMes(link->UIFrameQueue, mes, size);
+
+		Q921Log(trunk, Q921_LOG_DEBUG, "Link not ready, UI Frame of size %d bytes queued for TEI %d\n", size, Tei);
+		return 1;
+	}
+
+	return Q921Tx21Proc(trunk, mes, size);
+}
+
+/**
+ * TODO: NT mode handling? Need a way to get Link context from Q.931
+ */
+int Q921Rx32(L2TRUNK trunk, Q921DLMsg_t ind, L2UCHAR tei, L2UCHAR * Mes, L2INT Size)
+{
+	struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);	/* TODO: need real link tei for NT mode */
+	L2INT res = 0;
+
+	Q921Log(trunk, Q921_LOG_DEBUG, "Got frame from Q.931, type: %d, tei: %d, size: %d\n", ind, tei, Size);
+
+	switch(ind) {
+	case Q921_DL_ESTABLISH:
+		/*
+		 * Hmm...
+		 */
+		switch(link->state) {
+		case Q921_STATE_TEI_ASSIGNED:
+			if(!Q921_IS_NT(trunk)) {
+				/* establish data link */
+				Q921EstablishDataLink(trunk, link->tei);
+
+				/* Set layer 3 initiated */
+				Q921_SET_FLAG(link, Q921_FLAG_L3_INITIATED);
+
+				/* change state (no action) */
+				Q921ChangeState(trunk, Q921_STATE_AWAITING_ESTABLISHMENT, link->tei);
+			}
+			break;
+
+		case Q921_STATE_AWAITING_ESTABLISHMENT:
+			if(!Q921_IS_NT(trunk)) {
+				/* Discard I queue */
+				MFIFOClear(link->IFrameQueue);
+
+				/* Set layer 3 initiated */
+				Q921_SET_FLAG(link, Q921_FLAG_L3_INITIATED);
+			}
+			break;
+
+		case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
+		case Q921_STATE_TIMER_RECOVERY:
+			if(!Q921_IS_NT(trunk)) {
+				/* Discard I queue */
+				MFIFOClear(link->IFrameQueue);
+
+				/* establish data link */
+				Q921EstablishDataLink(trunk, link->tei);
+
+				/* Set layer 3 initiated */
+				Q921_SET_FLAG(link, Q921_FLAG_L3_INITIATED);
+
+				/* change state (no action) */
+				Q921ChangeState(trunk, Q921_STATE_AWAITING_ESTABLISHMENT, link->tei);
+			}
+			break;
+
+		default:
+			break;
+		}
+		break;
+
+	case Q921_DL_RELEASE:
+		switch(link->state) {
+		case Q921_STATE_TEI_ASSIGNED:
+			/* send DL-RELEASE confirm */
+			Q921Tx23Proc(trunk, Q921_DL_RELEASE, tei, NULL, 0);
+			break;
+
+		case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
+		case Q921_STATE_TIMER_RECOVERY:
+			if(!Q921_IS_NT(trunk)) {
+				/* Discard I queue */
+				MFIFOClear(link->IFrameQueue);
+
+				/* RC = 0 */
+				link->N200 = 0;
+
+				/* send DISC command */
+				Q921SendDISC(trunk, trunk->sapi, Q921_COMMAND(trunk), link->tei, 1);
+
+				/* Stop T203, restart T200 */
+				if(link->state == Q921_STATE_MULTIPLE_FRAME_ESTABLISHED) {
+					Q921T203TimerStop(trunk, link->tei);
+				}
+				Q921T200TimerReset(trunk, link->tei);
+
+				/* change state */
+				Q921ChangeState(trunk, Q921_STATE_AWAITING_RELEASE, link->tei);
+			}
+			break;
+
+		default:
+			break;
+		}
+		break;
+
+	case Q921_DL_DATA:	/* DL-DATA request */
+		res = Q921EnqueueI(trunk, 
+				trunk->sapi, 
+				Q921_COMMAND(trunk),
+				link->tei,
+				0, 
+				Mes, 
+				Size);
+
+		if(link->state < Q921_STATE_MULTIPLE_FRAME_ESTABLISHED) {
+			/* Treat as implicit DL-ESTABLISH request */
+
+			/* establish data link */
+			Q921EstablishDataLink(trunk, link->tei);
+
+			/* Set layer 3 initiated */
+			Q921_SET_FLAG(link, Q921_FLAG_L3_INITIATED);
+
+			/* change state (no action) */
+			Q921ChangeState(trunk, Q921_STATE_AWAITING_ESTABLISHMENT, link->tei);
+		}
+		break;
+
+	case Q921_DL_UNIT_DATA:		/* DL-UNIT DATA request */
+		res = Q921SendUN(trunk,
+				trunk->sapi,
+				Q921_COMMAND(trunk),
+				Q921_TEI_BCAST,
+				0,
+				Mes,
+				Size);
+		/* NOTE: Let the other side initiate link establishment */
+		break;
+
+	default:
+		break;
+	}
+
+	return res;
+}
+/*****************************************************************************
+
+  Function:     Q921SendRR
+
+  Description:  Compose and send Receive Ready.
+
+  Parameters:   trunk       trunk #
+                Sapi        Sapi
+                cr          C/R field.
+                Tei         Tei.
+                pf          P/F fiels octet 5
+
+  Return Value: 0 if failed, 1 if Send.
+
+*****************************************************************************/
+
+static int Q921SendRR(L2TRUNK trunk, int Sapi, int cr, int Tei, int pf)
+{
+	L2UCHAR mes[25];
+
+	return Q921SendS(trunk, Sapi, cr, Tei, pf, 0x00, mes, trunk->Q921HeaderSpace+4);
+}
+
+/*****************************************************************************
+
+  Function:     Q921SendRNR
+
+  Description:  Compose and send Receive Nor Ready
+
+  Parameters:   trunk       trunk #
+                Sapi        Sapi
+                cr          C/R field.
+                Tei         Tei.
+                pf          P/F fiels octet 5
+
+  Return Value: 0 if failed, 1 if Send.
+
+*****************************************************************************/
+static int Q921SendRNR(L2TRUNK trunk, int Sapi, int cr, int Tei, int pf)
+{
+	L2UCHAR mes[25];
+
+	return Q921SendS(trunk, Sapi, cr, Tei, pf, 0x01, mes, trunk->Q921HeaderSpace+4);
+}
+
+/*****************************************************************************
+
+  Function:     Q921SendREJ
+
+  Description:  Compose and Send Reject.
+
+  Parameters:   trunk       trunk #
+                Sapi        Sapi
+                cr          C/R field.
+                Tei         Tei.
+                pf          P/F fiels octet 5
+
+  Return Value: 0 if failed, 1 if Send.
+
+*****************************************************************************/
+static int Q921SendREJ(L2TRUNK trunk, int Sapi, int cr, int Tei, int pf)
+{
+	L2UCHAR mes[25];
+
+	return Q921SendS(trunk, Sapi, cr, Tei, pf, 0x03, mes, trunk->Q921HeaderSpace+4);
+}
+
+/*****************************************************************************
+
+  Function:     Q921SendSABME
+
+  Description:  Compose and send SABME
+
+  Parameters:   trunk       trunk #
+                Sapi        Sapi
+                cr          C/R field.
+                Tei         Tei.
+                pf          P fiels octet 4
+
+  Return Value: 0 if failed, 1 if Send.
+
+*****************************************************************************/
+static int Q921SendSABME(L2TRUNK trunk, int Sapi, int cr, int Tei, int pf)
+{
+	L2UCHAR mes[25];
+
+	return Q921SendU(trunk, Sapi, cr, Tei, pf, 0x0f, mes, trunk->Q921HeaderSpace+3);
+}
+
+
+/**
+ * Q921Start
+ * \brief	Start trunk
+ * \param[in]	trunk	pointer to Q921 data struct
+ * \return	> 0 on success; <= 0 on error
+ */
+int Q921Start(L2TRUNK trunk)
+{
+	int x, numlinks = Q921_IS_PTMP_NT(trunk) ? Q921_TEI_MAX : 1;
+	struct Q921_Link *link = Q921_TRUNK_CONTEXT(trunk);
+
+	if(trunk->initialized != INITIALIZED_MAGIC)
+		return 0;
+
+	memset(trunk->context, 0, numlinks * sizeof(struct Q921_Link));
+
+	/* Common init part */
+	for(x = 0; x <= numlinks; x++) {
+		link = Q921_LINK_CONTEXT(trunk, x);
+
+		link->state = Q921_STATE_TEI_UNASSIGNED;
+		link->tei   = 0;
+
+		/* Initialize per-TEI I + UI queues */
+		MFIFOCreate(link->UIFrameQueue, Q921MAXHDLCSPACE, 10);
+		MFIFOCreate(link->IFrameQueue,  Q921MAXHDLCSPACE, 10);
+		MFIFOCreate(link->IFrameResendQueue, Q921MAXHDLCSPACE, 10);
+	}
+
+	if(Q921_IS_PTMP_TE(trunk)) {
+		link->state = Q921_STATE_TEI_UNASSIGNED;
+		link->tei   = 0;
+	}
+	else if(Q921_IS_PTMP_NT(trunk)) {
+		link = Q921_TRUNK_CONTEXT(trunk);
+
+		link->state = Q921_STATE_TEI_ASSIGNED;
+		link->tei   = trunk->tei;
+
+		/* clear tei map */
+		memset(trunk->tei_map, 0, Q921_TEI_MAX + 1);
+	}
+	else {
+		link->state = Q921_STATE_TEI_ASSIGNED;
+		link->tei   = trunk->tei;
+	}
+
+	Q921Log(trunk, Q921_LOG_DEBUG, "Starting trunk %p (sapi: %d, tei: %d, mode: %s %s)\n",
+				 trunk,
+				 trunk->sapi,
+				 link->tei,
+				 Q921_IS_PTMP(trunk) ? "PTMP" : "PTP",
+				 Q921_IS_TE(trunk) ? "TE" : "NT");
+
+	if(Q921_IS_PTP(trunk)) {
+		Q921Log(trunk, Q921_LOG_DEBUG, "Sending SABME\n");
+
+		return Q921SendSABME(trunk, 
+					trunk->sapi, 
+					Q921_COMMAND(trunk),
+					link->tei, 
+					1);
+
+	} else if(Q921_IS_PTMP_NT(trunk)) {
+
+		Q921Log(trunk, Q921_LOG_DEBUG, "Revoking all TEIs\n");
+
+		return Q921TeiSendRemoveRequest(trunk, Q921_TEI_BCAST);	/* Revoke all TEIs in use */
+	} else {
+
+		Q921Log(trunk, Q921_LOG_DEBUG, "Requesting TEI\n");
+
+		return Q921TeiSendAssignRequest(trunk);
+	}
+}
+
+
+/**
+ * Q921Stop
+ * \brief	Stop trunk
+ * \param[in]	trunk	pointer to Q921 data struct
+ * \return	> 0 on success; <= 0 on error
+ *
+ * \author	Stefan Knoblich
+ */
+int Q921Stop(L2TRUNK trunk)
+{
+	struct Q921_Link *link;
+	int x, numlinks;
+
+	if(!trunk)
+		return -1;
+
+	link = Q921_TRUNK_CONTEXT(trunk);
+	numlinks = Q921_IS_PTMP_NT(trunk) ? Q921_TEI_MAX : 1;
+
+	if(Q921_IS_STOPPED(link))
+		return 0;
+
+	/* Release TEI */
+	if(Q921_IS_PTMP_TE(trunk)) {
+		/* send verify request */
+		Q921TeiSendVerifyRequest(trunk);
+
+		/* drop TEI */
+		link->tei  = 0;
+	}
+
+	/* Stop timers, stop link, flush queues */
+	for(x = 0; x <= numlinks; x++) {
+		Q921T200TimerStop(trunk, x);
+		Q921T203TimerStop(trunk, x);
+		Q921T201TimerStop(trunk, x);
+
+		/* Change state (no action) */
+		Q921ChangeState(trunk, Q921_STATE_STOPPED, x);
+
+		/* Flush per-tei I/UI queues */
+		MFIFOClear(link->UIFrameQueue);
+		MFIFOClear(link->IFrameQueue);
+		MFIFOClear(link->IFrameResendQueue);
+	}
+	Q921T202TimerStop(trunk);
+
+	/* Flush HDLC queue */
+	MFIFOClear(trunk->HDLCInQueue);
+
+	return 0;
+}
+
+
+/*****************************************************************************
+
+  Function:     Q921SendDM
+
+  Description:  Compose and Send DM (Disconnected Mode)
+
+  Parameters:   trunk       trunk #
+                Sapi        Sapi
+                cr          C/R field.
+                Tei         Tei.
+                pf          F fiels octet 4
+
+  Return Value: 0 if failed, 1 if Send.
+
+*****************************************************************************/
+static int Q921SendDM(L2TRUNK trunk, int Sapi, int cr, int Tei, int pf)
+{
+	L2UCHAR mes[25];
+
+	return Q921SendU(trunk, Sapi, cr, Tei, pf, 0x03, mes, trunk->Q921HeaderSpace+3);
+}
+
+/*****************************************************************************
+
+  Function:     Q921SendDISC
+
+  Description:  Compose and Send Disconnect
+
+  Parameters:   trunk       trunk #
+                Sapi        Sapi
+                cr          C/R field.
+                Tei         Tei.
+                pf          P fiels octet 4
+
+  Return Value: 0 if failed, 1 if Send.
+
+*****************************************************************************/
+static int Q921SendDISC(L2TRUNK trunk, int Sapi, int cr, int Tei, int pf)
+{
+	L2UCHAR mes[25];
+
+	return Q921SendU(trunk, Sapi, cr, Tei, pf, 0x08, mes, trunk->Q921HeaderSpace+3);
+}
+
+/*****************************************************************************
+
+  Function:     Q921SendUA
+
+  Description:  Compose and Send UA
+
+  Parameters:   trunk       trunk #
+                Sapi        Sapi
+                cr          C/R field.
+                Tei         Tei.
+                pf          F fiels octet 4
+
+  Return Value: 0 if failed, 1 if Send.
+
+*****************************************************************************/
+static int Q921SendUA(L2TRUNK trunk, int Sapi, int cr, int Tei, int pf)
+{
+	L2UCHAR mes[25];
+
+	return Q921SendU(trunk, Sapi, cr, Tei, pf, 0x0c, mes, trunk->Q921HeaderSpace+3);
+}
+
+static int Q921SendUN(L2TRUNK trunk, int Sapi, int cr, int Tei, int pf, L2UCHAR *mes, L2INT size)
+{
+	return Q921SendU(trunk, Sapi, cr, Tei, pf, 0x00, mes, size+trunk->Q921HeaderSpace+3);
+}
+
+
+/**
+ * Q921ProcSABME
+ * \brief	Handle incoming SABME
+ * \param[in]	trunk	pointer to Q921 data struct
+ * \param[in]	mes	pointer to message buffer
+ * \param[in]	size	size of message
+ * \return	> 0 on success, <= 0 on error
+ */
+static int Q921ProcSABME(L2TRUNK trunk, L2UCHAR *mes, L2INT size)
+{
+	L2UCHAR pf = (mes[2] & 0x10) >> 4;				/* poll / final flag */
+	L2UCHAR tei = (mes[1] & 0xfe) >> 1;
+	struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+	switch(link->state) {
+	case Q921_STATE_TEI_ASSIGNED:
+		/* send UA */
+		Q921SendUA(trunk,
+				trunk->sapi,
+				Q921_RESPONSE(trunk),	/* or command? */
+				tei, pf);
+
+		/* clear counters */
+		link->vr=0;
+		link->vs=0;
+		link->va=0;
+
+		/* TODO: send DL-Establish indication to Q.931 */
+		Q921Tx23Proc(trunk, Q921_DL_ESTABLISH, tei, NULL, 0);
+
+		/* start T203 */
+		Q921T203TimerStart(trunk, tei);
+
+		/* change state (no action) */
+		Q921ChangeState(trunk, Q921_STATE_MULTIPLE_FRAME_ESTABLISHED, tei);
+		break;
+
+	case Q921_STATE_AWAITING_ESTABLISHMENT:
+		/* send UA */
+		Q921SendUA(trunk,
+				trunk->sapi,
+				Q921_RESPONSE(trunk),
+				tei, pf);
+
+		/* no state change */
+		break;
+
+	case Q921_STATE_AWAITING_RELEASE:
+		/* send DM */
+		Q921SendDM(trunk,
+				trunk->sapi,
+				Q921_RESPONSE(trunk),
+				tei, pf);
+
+		/* no state change */
+		break;
+
+	case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
+	case Q921_STATE_TIMER_RECOVERY:
+		/* send UA */
+		Q921SendUA(trunk,
+				trunk->sapi,
+				Q921_RESPONSE(trunk),
+				tei, pf);
+
+		/* clear exception conditions */
+		Q921ResetExceptionConditions(trunk, tei);
+
+		/* send MDL-Error indication */
+
+		/* V(S) == V(A) ? */
+		if(link->vs != link->va) {
+			/* clear I queue */
+			MFIFOClear(link->IFrameQueue);
+
+			/* DL-Establish indication */
+			Q921Tx23Proc(trunk, Q921_DL_ESTABLISH, tei, NULL, 0);
+		}
+
+		/* clear counters */
+		link->vr=0;
+		link->vs=0;
+		link->va=0;
+
+		/* Stop T200, start T203 */
+		Q921T200TimerStop(trunk, tei);
+		Q921T203TimerStart(trunk, tei);
+
+		/* state change only if in TIMER_RECOVERY state */
+		if(link->state == Q921_STATE_TIMER_RECOVERY)
+			Q921ChangeState(trunk, Q921_STATE_MULTIPLE_FRAME_ESTABLISHED, tei);
+		break;
+
+	default:
+		break;
+	}
+
+	return 1;
+}
+
+
+/**
+ * Q921ProcDM
+ * \brief	Handle incoming DM
+ * \param[in]	trunk	pointer to Q921 data struct
+ * \param[in]	mes	pointer to message buffer
+ * \param[in]	size	size of message
+ * \return	> 0 on success, <= 0 on error
+ */
+static int Q921ProcDM(L2TRUNK trunk, L2UCHAR *mes, L2INT size)
+{
+	L2UCHAR pf = (mes[2] & 0x10) >> 4;				/* poll / final flag */
+	L2UCHAR tei = (mes[1] & 0xfe) >> 1;
+	struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+	switch(link->state) {
+	case Q921_STATE_TEI_ASSIGNED:
+		if(!pf) {
+			/* to next state (no action) */
+			Q921ChangeState(trunk, Q921_STATE_AWAITING_ESTABLISHMENT, tei);
+		}
+		break;
+
+	case Q921_STATE_AWAITING_ESTABLISHMENT:
+	case Q921_STATE_AWAITING_RELEASE:
+		if(pf) {
+			if(link->state == Q921_STATE_AWAITING_ESTABLISHMENT) {
+				/* Discard I queue */
+				MFIFOClear(link->IFrameQueue);
+			}
+
+			/* Send DL-Release indication to Q.931 */
+			Q921Tx23Proc(trunk, Q921_DL_RELEASE, tei, NULL, 0);
+
+			/* Stop T200 */
+			Q921T200TimerStop(trunk, tei);
+
+			/* Change state (no action) */
+			Q921ChangeState(trunk, Q921_STATE_TEI_ASSIGNED, tei);
+		}
+		break;
+
+	case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
+		if(pf) {
+			/* MDL-Error indication (B) */
+
+			/* no state change */
+		} else {
+			/* MDL-Error indication (E) */
+
+			/* establish data link */
+			Q921EstablishDataLink(trunk, tei);
+
+			/* clear L3 initiated */
+			Q921_CLEAR_FLAG(link, Q921_FLAG_L3_INITIATED);
+
+			/* change state (no action?) */
+			Q921ChangeState(trunk, Q921_STATE_AWAITING_ESTABLISHMENT, tei);
+		}
+		break;
+
+	case Q921_STATE_TIMER_RECOVERY:
+		if(pf) {
+			/* MDL Error indication (B) */
+		} else {
+			/* MDL Error indication (E) */
+		}
+
+		/* establish data link */
+		Q921EstablishDataLink(trunk, tei);
+
+		/* clear layer 3 initiated */
+		Q921_CLEAR_FLAG(link, Q921_FLAG_L3_INITIATED);
+
+		/* change state */
+		Q921ChangeState(trunk, Q921_STATE_AWAITING_ESTABLISHMENT, tei);
+		break;
+
+	default:
+		break;
+	}
+
+	return 1;
+}
+
+/**
+ * Q921ProcUA
+ * \brief	Handle incoming UA
+ * \param[in]	trunk	pointer to Q921 data struct
+ * \param[in]	mes	pointer to message buffer
+ * \param[in]	size	size of message
+ * \return	> 0 on success, <= 0 on error
+ */
+static int Q921ProcUA(L2TRUNK trunk, L2UCHAR *mes, L2INT size)
+{
+	L2UCHAR pf = (mes[2] & 0x10) >> 4;				/* poll / final flag */
+	L2UCHAR tei = (mes[1] & 0xfe) >> 1;
+	struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+	switch(link->state) {
+	case Q921_STATE_TEI_ASSIGNED:
+	case Q921_STATE_TIMER_RECOVERY:
+		/* MDL Error indication (C, D) */
+		Q921Log(trunk, Q921_LOG_ERROR, "Received UA frame in invalid state\n");
+		break;
+
+	case Q921_STATE_AWAITING_ESTABLISHMENT:
+		if(pf) {
+			/* TODO: other fancy stuff (see docs) */
+			if(Q921_CHECK_FLAG(link, Q921_FLAG_L3_INITIATED)) {	/* layer3 initiated */
+				link->vr = 0;
+
+				/* DL-Establish confirm */
+				Q921Tx23Proc(trunk, Q921_DL_ESTABLISH_CONFIRM, tei, NULL, 0);
+
+			} else if(link->vs != link->va) {
+
+				/* discard I queue */
+				MFIFOClear(link->IFrameQueue);
+
+				/* DL-Establish indication */
+				Q921Tx23Proc(trunk, Q921_DL_ESTABLISH, tei, NULL, 0);
+			}
+
+			/* Stop T200, start T203 */
+			Q921T200TimerStop(trunk, tei);
+			Q921T203TimerStart(trunk, tei);
+
+			link->vs = 0;
+			link->va = 0;
+
+			/* change state (no action) */
+			Q921ChangeState(trunk, Q921_STATE_MULTIPLE_FRAME_ESTABLISHED, tei);
+		} else {
+			/* MDL Error indication (C, D) */
+			Q921Log(trunk, Q921_LOG_ERROR, "Received UA frame is not a response to a request\n");
+
+			/* no state change */
+		}
+		break;
+
+	case Q921_STATE_AWAITING_RELEASE:
+		if(pf) {
+			/* DL Release confirm */
+			Q921Tx23Proc(trunk, Q921_DL_RELEASE_CONFIRM, tei, NULL, 0);
+
+			/* Stop T200 */
+			Q921T200TimerStop(trunk, tei);
+
+			/* change state (no action) */
+			Q921ChangeState(trunk, Q921_STATE_TEI_ASSIGNED, tei);
+		} else {
+			/* MDL Error indication (D) */
+			Q921Log(trunk, Q921_LOG_ERROR, "Received UA frame is not a response to a request\n");
+
+			/* no state change */
+		}
+		break;
+
+	case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
+		/* MDL Error indication (C, D) */
+		Q921Log(trunk, Q921_LOG_ERROR, "Received UA frame in invalid state\n");
+
+		/* no state change */
+		break;
+
+	default:
+		break;
+	}
+
+	return 1;
+}
+
+
+/**
+ * Q921ProcDISC
+ * \brief	Handle incoming DISC
+ * \param[in]	trunk	pointer to Q921 data struct
+ * \param[in]	mes	pointer to message buffer
+ * \param[in]	size	size of message
+ * \return	> 0 on success, <= 0 on error
+ */
+static int Q921ProcDISC(L2TRUNK trunk, L2UCHAR *mes, L2INT size)
+{
+	L2UCHAR pf  = (mes[2] & 0x10) >> 4;				/* poll / final flag */
+	L2UCHAR tei = (mes[1] & 0xfe) >> 1;
+	struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+	switch(link->state) {
+	case Q921_STATE_TEI_ASSIGNED:
+	case Q921_STATE_AWAITING_ESTABLISHMENT:
+		/* Send DM */
+		Q921SendDM(trunk,
+				trunk->sapi,
+				Q921_RESPONSE(trunk),
+				tei, pf);
+
+		/* no state change */
+		break;
+
+	case Q921_STATE_AWAITING_RELEASE:
+		Q921SendUA(trunk,
+				trunk->sapi,
+				Q921_RESPONSE(trunk),
+				tei, pf);
+
+		/* no state change */
+		break;
+
+	case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
+	case Q921_STATE_TIMER_RECOVERY:
+		/* Discard I queue */
+		MFIFOClear(link->IFrameQueue);
+
+		/* send UA */
+		Q921SendUA(trunk,
+				trunk->sapi,
+				Q921_RESPONSE(trunk),
+				tei, pf);
+		
+		/* DL Release indication */
+		Q921Tx23Proc(trunk, Q921_DL_RELEASE, tei, NULL, 0);
+
+		/* Stop T200 */
+		Q921T200TimerStop(trunk, tei);
+
+		if(link->state == Q921_STATE_MULTIPLE_FRAME_ESTABLISHED) {
+			/* Stop T203 */
+			Q921T203TimerStop(trunk, tei);
+		}
+
+		/* change state (no action) */
+		Q921ChangeState(trunk, Q921_STATE_TEI_ASSIGNED, tei);
+		break;
+
+	default:
+		Q921Log(trunk, Q921_LOG_ERROR, "Invalid DISC received in state \"%s\" (%d)", Q921State2Name(link->state), link->state);
+		break;
+	}
+
+	return 1;
+}
+
+
+/**
+ * Q921ProcRR
+ * \brief	Handle incoming RR
+ * \param[in]	trunk	pointer to Q921 data struct
+ * \param[in]	mes	pointer to message buffer
+ * \param[in]	size	size of message
+ * \return	> 0 on success, <= 0 on error
+ */
+static int Q921ProcRR(L2TRUNK trunk, L2UCHAR *mes, L2INT size)
+{
+	L2UCHAR cr = (mes[0] & 0x02) >> 1;
+	L2UCHAR pf =  mes[3] & 0x01;		/* poll / final flag */
+	L2UCHAR nr = (mes[3] >> 1);
+//	L2UCHAR	sapi = (mes[0] & 0xfc) >> 2;
+	L2UCHAR	tei  = (mes[1] & 0xfe) >> 1;
+	struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+	switch(link->state) {
+	case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
+		/* clear receiver peer busy */
+		Q921_CLEAR_FLAG(link, Q921_FLAG_PEER_RECV_BUSY);
+
+		if (Q921_IS_COMMAND(trunk, cr)) { /* if this is a command */
+			if(pf) {
+				/* Enquiry response */
+				Q921SendEnquiryResponse(trunk, tei);
+			}
+		} else {
+			if(pf) {
+				/* MDL Error indication */
+			}
+		}
+
+		/* */
+		if(link->va <= nr && nr <= link->vs) {
+
+			if(nr == link->vs) {
+				/* V(A) = N(R) */
+				link->va = nr;
+
+				/* Stop T200, restart T203 */
+				Q921T200TimerStop(trunk, tei);
+				Q921T203TimerReset(trunk, tei);
+
+			} else if(nr == link->va) {
+
+				/* do nothing */
+
+			} else {
+				/* V(A) = N(R) */
+				link->va = nr;
+
+				/* Restart T200 */
+				Q921T200TimerReset(trunk, tei);
+			}
+			/* no state change */
+
+		} else {
+			/* N(R) Error recovery */
+			Q921NrErrorRecovery(trunk, tei);
+
+			/* change state (no action) */
+			Q921ChangeState(trunk, Q921_STATE_AWAITING_ESTABLISHMENT, tei);
+		}
+		break;
+
+	case Q921_STATE_TIMER_RECOVERY:
+		/* clear receiver peer busy */
+		Q921_CLEAR_FLAG(link, Q921_FLAG_PEER_RECV_BUSY);
+
+		/* command + P? */
+		if(Q921_IS_COMMAND(trunk, cr) && pf) {
+			/* Enquiry response */
+			Q921SendEnquiryResponse(trunk, tei);
+		}
+
+		/* */
+		if(link->va <= nr && nr <= link->vs) {
+			/* V(A) = N(R) */
+			link->va = nr;
+
+			if(!Q921_IS_COMMAND(trunk, cr) && pf) {
+				/* Stop T200, start T203 */
+				Q921T200TimerStop(trunk, tei);
+				Q921T203TimerStart(trunk, tei);
+
+				/* Invoke retransmission */
+				Q921InvokeRetransmission(trunk, tei, nr);
+
+				/* change state (no action) */
+				Q921ChangeState(trunk, Q921_STATE_MULTIPLE_FRAME_ESTABLISHED, tei);
+			}
+			/* no state change otherwise */
+		} else {
+			/* N(R) Error recovery */
+			Q921NrErrorRecovery(trunk, tei);
+
+			/* change state (no action) */
+			Q921ChangeState(trunk, Q921_STATE_AWAITING_ESTABLISHMENT, tei);
+		}
+		break;
+
+	default:
+		break;
+	}
+	return 1;
+}
+
+
+/**
+ * Q921ProcREJ
+ * \brief	Handle incoming REJ
+ * \param[in]	trunk	pointer to Q921 data struct
+ * \param[in]	mes	pointer to message buffer
+ * \param[in]	size	size of message
+ * \return	> 0 on success, <= 0 on error
+ */
+static int Q921ProcREJ(L2TRUNK trunk, L2UCHAR *mes, L2INT size)
+{
+	L2UCHAR cr = (mes[0] & 0x02) >> 1;
+	L2UCHAR pf =  mes[3] & 0x01;		/* poll / final flag */
+	L2UCHAR nr = (mes[3] >> 1);
+//	L2UCHAR	sapi = (mes[0] & 0xfc) >> 2;
+	L2UCHAR	tei  = (mes[1] & 0xfe) >> 1;
+	struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+	switch(link->state) {
+	case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
+		/* clear receiver peer busy */
+		Q921_CLEAR_FLAG(link, Q921_FLAG_PEER_RECV_BUSY);
+
+		/* command? */
+		if(Q921_IS_COMMAND(trunk, cr)) {
+			if(pf) {
+				/* Enquiry response */
+				Q921SendEnquiryResponse(trunk, tei);
+			}
+		} else {
+			if(pf) {
+				/* MDL Error indication (A) */
+			}
+		}
+
+		/* */
+		if(link->va <= nr && nr <= link->vs) {
+
+			/* V(A) = N(R) */
+			link->va = nr;
+
+			/* Stop T200, start T203 */
+			Q921T200TimerStop(trunk, tei);
+			Q921T203TimerStart(trunk, tei);
+
+			/* Invoke retransmission of frame >N(R)  (?) */
+			Q921InvokeRetransmission(trunk, tei, nr);
+
+			/* no state change */
+		} else {
+			/* N(R) Error recovery */
+			Q921NrErrorRecovery(trunk, tei);
+
+			/* change state (no action) */
+			Q921ChangeState(trunk, Q921_STATE_AWAITING_ESTABLISHMENT, tei);
+		}
+		break;
+
+	case Q921_STATE_TIMER_RECOVERY:
+		/* clear receiver peer busy */
+		Q921_CLEAR_FLAG(link, Q921_FLAG_PEER_RECV_BUSY);
+
+		/* command + P ? */
+		if(Q921_IS_COMMAND(trunk, cr) && pf) {
+			/* Enquiry response */
+			Q921SendEnquiryResponse(trunk, tei);
+		}
+
+		/* */
+		if(link->va <= nr && nr <= link->vs) {
+
+			/* V(A) = N(R) */
+			link->va = nr;
+
+			if(!Q921_IS_COMMAND(trunk, cr) && pf) {
+				/* Stop T200, start T203 */
+				Q921T200TimerStop(trunk, tei);
+				Q921T203TimerStart(trunk, tei);
+
+				/* Invoke retransmission */
+				Q921InvokeRetransmission(trunk, tei, nr);
+
+				/* change state (no action) */
+				Q921ChangeState(trunk, Q921_STATE_MULTIPLE_FRAME_ESTABLISHED, tei);
+			}
+			/* no state change otherwise */
+		} else {
+			/* N(R) Error recovery */
+			Q921NrErrorRecovery(trunk, tei);
+
+			/* change state (no action) */
+			Q921ChangeState(trunk, Q921_STATE_AWAITING_ESTABLISHMENT, tei);
+		}
+		break;
+
+	default:
+		break;
+	}
+
+	return 1;
+}
+
+
+/**
+ * Q921ProcRNR
+ * \brief	Handle incoming RNR
+ * \param[in]	trunk	pointer to Q921 data struct
+ * \param[in]	mes	pointer to message buffer
+ * \param[in]	size	size of message
+ * \return	> 0 on success, <= 0 on error
+ */
+static int Q921ProcRNR(L2TRUNK trunk, L2UCHAR *mes, L2INT size)
+{
+	L2UCHAR cr = (mes[0] & 0x02) >> 1;
+	L2UCHAR pf =  mes[3] & 0x01;		/* poll / final flag */
+	L2UCHAR nr = (mes[3] >> 1);
+//	L2UCHAR	sapi = (mes[0] & 0xfc) >> 2;
+	L2UCHAR	tei  = (mes[1] & 0xfe) >> 1;
+	struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+	switch(link->state) {
+	case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
+		/* set peer receiver busy */
+		Q921_SET_FLAG(link, Q921_FLAG_PEER_RECV_BUSY);
+
+		/* command? */
+		if(Q921_IS_COMMAND(trunk, cr)) {
+			if(pf) {
+				/* Enquiry response */
+				Q921SendEnquiryResponse(trunk, tei);
+			}
+		} else {
+			if(pf) {
+				/* MDL Error indication (A) */
+			}
+		}
+
+		/* */
+		if(link->va <= nr && nr <= link->vs) {
+
+			/* V(A) = N(R) */
+			link->va = nr;
+
+			/* Stop T203, restart T200 */
+			Q921T200TimerReset(trunk, tei);
+			Q921T203TimerStop(trunk, tei);
+
+			/* no state change */
+		} else {
+			/* N(R) Error recovery */
+			Q921NrErrorRecovery(trunk, tei);
+
+			/* change state (no action) */
+			Q921ChangeState(trunk, Q921_STATE_AWAITING_ESTABLISHMENT, tei);
+		}
+		break;
+
+	case Q921_STATE_TIMER_RECOVERY:
+		/* set peer receiver busy */
+		Q921_SET_FLAG(link, Q921_FLAG_PEER_RECV_BUSY);
+
+		/* command + P? */
+		if(Q921_IS_COMMAND(trunk, cr) && pf) {
+			/* Enquiry response */
+			Q921SendEnquiryResponse(trunk, tei);
+		}
+
+		/* */
+		if(link->va <= nr && nr <= link->vs) {
+
+			/* V(A) = N(R) */
+			link->va = nr;
+
+			if(!Q921_IS_COMMAND(trunk, cr) && pf) {
+				/* Restart T200 */
+				Q921T200TimerReset(trunk, tei);
+
+				/* Invoke retransmission */
+				Q921InvokeRetransmission(trunk, tei, nr);
+
+				/* change state (no action) */
+				Q921ChangeState(trunk, Q921_STATE_MULTIPLE_FRAME_ESTABLISHED, tei);
+			}
+			/* no state change otherwise */
+		} else {
+			/* N(R) Error recovery */
+			Q921NrErrorRecovery(trunk, tei);
+
+			/* change state (no action) */
+			Q921ChangeState(trunk, Q921_STATE_AWAITING_ESTABLISHMENT, tei);
+		}
+		break;
+
+	default:
+		break;
+	}
+
+	return 1;
+}
+
+#if 0
+static int Q921SetReceiverBusy(L2TRUNK trunk)
+{
+	struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+	switch(link->state) {
+	case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
+		if(!Q921_CHECK_FLAG(link, Q921_FLAG_RECV_BUSY)) {
+			/* set own receiver busy */
+			Q921_SET_FLAG(link, Q921_FLAG_RECV_BUSY);
+
+			/* send RR response */
+			Q921SendRR(trunk, trunk->sapi, Q921_RESPONSE(trunk), link->tei, 0);
+
+			/* clear ack pending */
+			Q921_CLEAR_FLAG(link, Q921_FLAG_ACK_PENDING);
+		}
+		break;
+
+	case Q921_STATE_TIMER_RECOVERY:
+		if(!Q921_CHECK_FLAG(link, Q921_FLAG_RECV_BUSY)) {
+			/* set own receiver busy */
+			Q921_SET_FLAG(link, Q921_FLAG_RECV_BUSY);
+
+			/* send RNR response */
+			Q921SendRNR(trunk, trunk->sapi, Q921_RESPONSE(trunk), link->tei, 0);
+
+			/* clear ack pending */
+			Q921_CLEAR_FLAG(link, Q921_FLAG_ACK_PENDING);
+		}
+		break;
+
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int Q921ClearReceiverBusy(L2TRUNK trunk)
+{
+	struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+	switch(link->state) {
+	case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
+	case Q921_STATE_TIMER_RECOVERY:
+		if(Q921_CHECK_FLAG(link, Q921_FLAG_RECV_BUSY)) {
+			/* clear own receiver busy */
+			Q921_CLEAR_FLAG(link, Q921_FLAG_RECV_BUSY);
+
+			/* send RNR response */
+			Q921SendRNR(trunk, trunk->sapi, Q921_RESPONSE(trunk), link->tei, 0);
+
+			/* clear ack pending */
+			Q921_CLEAR_FLAG(link, Q921_FLAG_ACK_PENDING);
+		}
+		break;
+
+	default:
+		break;
+	}
+
+	return 0;
+}
+#endif
+
+static int Q921ProcIFrame(L2TRUNK trunk, L2UCHAR *mes, L2INT size)
+{
+	/* common fields: get sapi, tei and cr */
+//	L2UCHAR sapi = (mes[0] & 0xfc) >> 2;
+//	L2UCHAR cr   = (mes[0] & 0x02) >> 1;
+	L2UCHAR tei  = (mes[1] & 0xfe) >> 1;
+	L2UCHAR pf   =  mes[3] & 0x01;		/* poll / final flag */
+	L2UCHAR nr   =  mes[3] >> 1;		/* receive sequence number */
+	L2UCHAR ns   =  mes[2] >> 1;		/* send sequence number */
+	L2UCHAR discard = 0;
+	struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+	/* Ignore I frames in earlier states */
+	if(link->state < Q921_STATE_MULTIPLE_FRAME_ESTABLISHED) {
+		Q921Log(trunk, Q921_LOG_NOTICE, "I frame in invalid state ignored\n");
+		return 0;
+	}
+
+	/* Receiver busy? */
+	if(Q921_CHECK_FLAG(link, Q921_FLAG_RECV_BUSY)) {
+		/* discard information */
+		discard = 1;
+
+		if(pf) {
+			/* send RNR Response */
+			Q921SendRNR(trunk, trunk->sapi, Q921_RESPONSE(trunk), tei, 1);
+
+			/* Clear ack pending */
+			Q921_CLEAR_FLAG(link, Q921_FLAG_ACK_PENDING);
+		}
+	}
+	else {
+		if(ns != link->vr) {
+			/* discard information */
+			discard = 1;
+
+			if(Q921_CHECK_FLAG(link, Q921_FLAG_REJECT) && pf) {
+
+				/* Send RR response */
+				Q921SendRR(trunk, trunk->sapi, Q921_RESPONSE(trunk), tei, 1);
+
+				/* clear ack pending */
+				Q921_CLEAR_FLAG(link, Q921_FLAG_ACK_PENDING);
+			}
+			else if(!Q921_CHECK_FLAG(link, Q921_FLAG_REJECT)){
+
+				/* set reject exception */
+				Q921_SET_FLAG(link, Q921_FLAG_REJECT);
+
+				/* Send REJ response */
+				Q921SendREJ(trunk, trunk->sapi, Q921_RESPONSE(trunk), tei, pf);
+
+				/* clear ack pending */
+				Q921_CLEAR_FLAG(link, Q921_FLAG_ACK_PENDING);
+			}
+		}
+		else {
+			/* V(R) = V(R) + 1 */
+			Q921_INC_COUNTER(link->vr);
+
+			/* clear reject exception */
+			Q921_CLEAR_FLAG(link, Q921_FLAG_REJECT);
+
+			/* DL-Data indication */
+			Q921Tx23Proc(trunk, Q921_DL_DATA, tei, mes, size);
+
+			if(pf) {
+				/* Send RR response */
+				Q921SendRR(trunk, trunk->sapi, Q921_RESPONSE(trunk), tei, 1);
+
+				/* clear ack pending */
+				Q921_CLEAR_FLAG(link, Q921_FLAG_ACK_PENDING);
+			}
+			else if(!Q921_CHECK_FLAG(link, Q921_FLAG_ACK_PENDING)) {
+				/* ack pending */
+
+				/* Send RR response */
+				Q921SendRR(trunk, trunk->sapi, Q921_RESPONSE(trunk), tei, 0);
+				
+				/* set ack pending*/
+				Q921_SET_FLAG(link, Q921_FLAG_ACK_PENDING);
+			}
+		}
+	}
+
+
+	switch(link->state) {
+	case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
+		if(link->va <= nr && nr <= link->vs) {
+			if(Q921_CHECK_FLAG(link, Q921_FLAG_PEER_RECV_BUSY)) {
+				link->va = nr;
+			}
+			else if(nr == link->vs) {
+				/* V(A) = N(R) */
+				link->va = nr;
+
+				/* stop t200, restart t203 */
+				Q921T200TimerStop(trunk, tei);
+				Q921T203TimerReset(trunk, tei);
+			}
+			else if(nr != link->va) {
+				/* V(A) = N(R) */
+				link->va = nr;
+
+				/* restart T200 */
+				Q921T200TimerReset(trunk, tei);
+			}
+
+			/* Restart TM01 */
+			if(Q921_IS_NT(trunk)) {
+				Q921TM01TimerReset(trunk, tei);
+			}
+		}
+		else {
+			/* N(R) error recovery */
+			Q921NrErrorRecovery(trunk, tei);
+
+			/* change state (no action) */
+			Q921ChangeState(trunk, Q921_STATE_AWAITING_ESTABLISHMENT, tei);
+		}
+		break;
+
+	case Q921_STATE_TIMER_RECOVERY:
+		if(link->va <= nr && nr <= link->vs) {
+			/* V(A) = N(R) */
+			link->va = nr;
+
+			/* Restart TM01 */
+			if(Q921_IS_NT(trunk)) {
+				Q921TM01TimerReset(trunk, tei);
+			}
+		}
+		else {
+			/* N(R) error recovery */
+			Q921NrErrorRecovery(trunk, tei);
+
+			/* change state (no action) */
+			Q921ChangeState(trunk, Q921_STATE_AWAITING_ESTABLISHMENT, tei);
+		}
+		break;
+
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+
+static int Q921ProcSFrame(L2TRUNK trunk, L2UCHAR *mes, L2INT size)
+{
+	L2UCHAR sv = (mes[2] & 0x0c) >> 2;	/* supervisory format id */
+	//L2UCHAR pf = mes[3] & 0x01;		/* poll / final flag */
+	//L2UCHAR nr = mes[3] >> 1;		/* receive sequence number */
+	L2INT res = -1;
+
+	switch(sv) {
+	case 0x00:	/* RR : Receive Ready */
+		res = Q921ProcRR(trunk, mes, size);
+		break;
+
+	case 0x02:	/* RNR : Receive Not Ready */
+		res = Q921ProcRNR(trunk, mes, size);
+		break;
+
+	case 0x04:	/* REJ : Reject */
+		res = Q921ProcREJ(trunk, mes, size);
+		break;
+
+	default:	/* Invalid / Unknown */
+		Q921Log(trunk, Q921_LOG_ERROR, "Invalid S frame type %d\n", sv);
+		break;
+	}
+
+	return res;
+}
+
+
+
+static int Q921ProcUFrame(L2TRUNK trunk, L2UCHAR *mes, L2INT size) 
+{
+	L2UCHAR m  = (mes[2] & 0xe0) >> 3 | (mes[2] & 0x0c) >> 2;	/* modifier function id */
+//	L2UCHAR pf = (mes[2] & 0x10) >> 4;				/* poll / final flag */
+	L2INT res = -1;
+
+	switch(m) {
+	case 0x00:	/* UN : Unnumbered Information */
+		if(mes[3] == Q921_LAYER_ENT_ID_TEI)
+		{
+			if(!Q921_IS_PTMP(trunk)) {
+				/* wtf? nice try */
+				return res;
+			}
+
+			switch(mes[6]) {
+			case Q921_TEI_ID_REQUEST:	/* (TE ->) NT */
+				res = Q921TeiProcAssignRequest(trunk, mes, size);
+				break;
+
+			case Q921_TEI_ID_ASSIGNED:	/* (NT ->) TE */
+			case Q921_TEI_ID_DENIED:
+				res = Q921TeiProcAssignResponse(trunk, mes, size);
+				break;
+
+			case Q921_TEI_ID_CHECKREQ:	/* (NT ->) TE */
+				res = Q921TeiProcCheckRequest(trunk, mes, size);
+				break;
+
+			case Q921_TEI_ID_CHECKRESP:	/* (TE ->) NT */
+				res = Q921TeiProcCheckResponse(trunk, mes, size);
+				break;
+
+			case Q921_TEI_ID_REMOVE:	/* (NT ->) TE */
+				res = Q921TeiProcRemoveRequest(trunk, mes, size);
+				break;
+
+			case Q921_TEI_ID_VERIFY:	/* (TE ->) NT */
+				res = Q921TeiProcVerifyRequest(trunk, mes, size);
+				break;
+
+			default:			/* Invalid / Unknown */
+				Q921Log(trunk, Q921_LOG_ERROR, "Invalid UN message from TEI management/endpoint\n");
+				break;
+			}
+		}
+		else if(mes[3] == Q921_LAYER_ENT_ID_Q931) {
+
+			Q921Log(trunk, Q921_LOG_DEBUG, "UI Frame for Layer 3 received\n");
+
+			res = Q921Tx23Proc(trunk, Q921_DL_UNIT_DATA, 0, mes, size);
+		}
+		break;
+
+	case 0x03:	/* DM : Disconnect Mode */
+		res = Q921ProcDM(trunk, mes, size);
+		break;
+
+	case 0x08:	/* DISC : Disconnect */
+		res = Q921ProcDISC(trunk, mes, size);
+		break;
+
+	case 0x0c:	/* UA : Unnumbered Acknowledgement */
+		res = Q921ProcUA(trunk, mes, size);
+		break;
+
+	case 0x0f:	/* SABME  : Set Asynchronous Balanced Mode Extend */
+		res = Q921ProcSABME(trunk, mes, size);
+		break;
+
+	case 0x11:	/* FRMR : Frame Reject */
+	case 0x17:	/* XID : Exchange Identification */
+		res = 0;
+		break;
+
+	default:	/* Unknown / Invalid */
+		Q921Log(trunk, Q921_LOG_ERROR, "Invalid U frame type: %d\n", m);
+		break;
+	}
+
+	return res;
+}
+
+
+/*****************************************************************************
+
+  Function:     Q921Rx12
+
+  Description:  Called to process a message frame from layer 1. Will 
+                identify the message and call the proper 'processor' for
+                layer 2 messages and forward I frames to the layer 3 entity.
+
+                Q921Rx12 will check the input fifo for a message, and if a 
+                message exist process one message before it exits. The caller
+                must either call Q921Rx12 polling or keep track on # 
+                messages in the queue.
+
+  Parameters:   trunk       trunk #.
+
+  Return Value: # messages processed (always 1 or 0).
+
+*****************************************************************************/
+int Q921Rx12(L2TRUNK trunk)
+{
+	L2INT size;     /* receive size & Q921 frame size*/
+	L2UCHAR *smes = MFIFOGetMesPtr(trunk->HDLCInQueue, &size);
+
+	if(smes)
+	{
+		struct Q921_Link *link;
+		L2UCHAR sapi, tei;
+		L2UCHAR *mes;
+		L2INT rs;
+
+		rs  = size - trunk->Q921HeaderSpace;
+		mes = &smes[trunk->Q921HeaderSpace];
+
+		Q921LogMesg(trunk, Q921_LOG_DEBUG, 1, mes, rs, "New packet received (%d bytes)", rs);
+
+		/* common fields: get sapi, tei and cr */
+		sapi = (mes[0] & 0xfc) >> 2;
+		tei  = (mes[1] & 0xfe) >> 1;
+		link  = Q921_LINK_CONTEXT(trunk, tei);
+
+		if(Q921_IS_PTMP_TE(trunk) && (
+			 (link->state >= Q921_STATE_TEI_ASSIGNED && tei != link->tei && tei != Q921_TEI_BCAST) ||			/* Assigned TEI: Only BCAST and directed */
+			 (link->state == Q921_STATE_TEI_UNASSIGNED && tei != Q921_TEI_BCAST)))					/* No assigned TEI: Only BCAST */
+		{
+			/* Ignore Messages with foreign TEIs */
+			goto out;
+		}
+
+		if((mes[2] & 0x01) == 0x00) {		/* I frame */
+			Q921ProcIFrame(trunk, mes, rs);
+		}
+		else if((mes[2] & 0x03) == 0x01) {	/* S frame */
+			Q921ProcSFrame(trunk, mes, rs);
+		}
+		else if((mes[2] & 0x03) == 0x03) {	/* U frame */
+			Q921ProcUFrame(trunk, mes, rs);
+		}
+		else {
+			Q921Log(trunk, Q921_LOG_ERROR, "Invalid frame type: %d\n", (int)(mes[2] & 0x03));
+			/* TODO: send FRMR or REJ */
+		}
+
+out:
+		MFIFOKillNext(trunk->HDLCInQueue);
+
+		return 1;
+	}
+
+	return 0;
+}
+
+/*
+ * Misc
+ */
+/**
+ * Q921SetLogCB
+ * \brief	Set logging callback
+ * \param[in]	trunk	pointer to Q921 data struct
+ * \param[in]	func	pointer to logging callback function
+ * \param[in]	priv	pointer to private data
+ *
+ * \author	Stefan Knoblich
+ */
+void Q921SetLogCB(L2TRUNK trunk, Q921LogCB_t func, void *priv)
+{
+	if(!trunk)
+		return;
+
+	trunk->Q921LogProc = func;
+	trunk->PrivateDataLog = priv;
+}
+
+/**
+ * Q921SetLogLevel
+ * \brief	Set loglevel of Q.921 logging functions
+ * \param[in]	trunk	pointer to Q921 data struct
+ * \param[in]	level	new loglevel
+ *
+ * \author	Stefan Knoblich
+ */
+void Q921SetLogLevel(L2TRUNK trunk, Q921LogLevel_t level)
+{
+	if(!trunk)
+		return;
+
+    if (level < Q921_LOG_NONE) {
+        level = Q921_LOG_NONE;
+    } else if (level > Q921_LOG_DEBUG) {
+        level = Q921_LOG_DEBUG;
+    }
+
+	trunk->loglevel = level;
+}
+
+
+/**
+ * Q921ChangeState
+ * \brief	Change state, invoke neccessary actions
+ * \param[in]	trunk	pointer to Q921 data struct
+ * \param[in]	state	state to change to
+ * \return	> 0 on success; <= 0 on error
+ *
+ * \author	Stefan Knoblich
+ */
+static int Q921ChangeState(L2TRUNK trunk, Q921State_t state, L2UCHAR tei)
+{
+	struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+	Q921State_t oldstate = link->state;
+	int res = 0;
+
+	Q921Log(trunk, Q921_LOG_DEBUG, "Changing state from \"%s\" (%d) to \"%s\" (%d) for TEI %d\n",
+				Q921State2Name(oldstate), oldstate,
+				Q921State2Name(state), state,
+				tei);
+
+	/*
+	 * generic actions (depending on the target state only)
+	 */
+	switch(state) {
+	case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
+		/* Start TM01 */
+		if(Q921_IS_NT(trunk)) {
+			Q921TM01TimerStart(trunk, tei);
+		}
+		break;
+
+	default:
+		break;
+	}
+
+	/*
+	 * actions that depend on type of the old -> new state transition
+	 */
+	switch(oldstate) {
+	case Q921_STATE_STOPPED:
+
+		switch(state) {
+		case Q921_STATE_TEI_UNASSIGNED:
+			if(Q921_IS_PTMP_TE(trunk)) {
+				res = Q921TeiSendAssignRequest(trunk);
+			}
+			break;
+
+		case Q921_STATE_TEI_ASSIGNED:
+			if(Q921_IS_PTMP_NT(trunk)) {
+				res = Q921TeiSendRemoveRequest(trunk, Q921_TEI_BCAST);
+			}
+			break;
+
+		default:
+			break;
+		}
+		break;
+
+	default:
+		break;
+	}
+
+	link->state = state;
+
+	Q921Log(trunk, Q921_LOG_DEBUG, "Q921ChangeState() returns %d, new state is \"%s\" (%d) for TEI %d\n", res, Q921State2Name(state), state, tei);
+
+	return res;
+}
+
+/*
+ * TEI Management functions
+ * \note	All TEI-mgmt UN frames are sent with cr = command!
+ */
+static int Q921TeiSend(L2TRUNK trunk, L2UCHAR type, L2USHORT ri, L2UCHAR ai)
+{
+	L2UCHAR mes[10];
+	L2UCHAR offset = Q921_UFRAME_DATA_OFFSET(trunk);
+
+	mes[offset++] = Q921_LAYER_ENT_ID_TEI;	/* layer management entity identifier */
+	mes[offset++] = (ri & 0xff00) >> 8;	/* reference number upper part */
+	mes[offset++] =  ri & 0xff;		/* reference number lower part */
+	mes[offset++] = type;			/* message type: Identity Request */
+	mes[offset++] = ai << 1 | 0x01;		/* action indicator: TEI */
+
+	return Q921SendU(trunk, Q921_SAPI_TEI, Q921_COMMAND(trunk), Q921_TEI_BCAST, 0, 0x00, mes, offset);
+}
+
+
+/**
+ * Q921TeiSendAssignRequest
+ * \brief	Ask for new TEI (TE mode only)
+ * \param[in]	trunk	pointer to Q921 data struct
+ * \return	> 0 on success, <= 0 on error
+ *
+ * \author	Stefan Knoblich
+ */
+static int Q921TeiSendAssignRequest(L2TRUNK trunk)
+{
+	struct Q921_Link *link = Q921_TRUNK_CONTEXT(trunk);
+	L2INT res;
+
+	if (!Q921_IS_PTMP_TE(trunk))	/* only ptmp te mode*/
+		return 0;
+
+#ifndef WIN32
+		link->ri = (L2USHORT)(random() % 0xffff);
+#else
+		link->ri = (L2USHORT)(rand() % 0xffff); //todo
+#endif
+
+	/* send TEI assign request */
+	res = Q921TeiSend(trunk, Q921_TEI_ID_REQUEST, link->ri, Q921_TEI_BCAST);
+
+	/* start T202 */
+	Q921T202TimerStart(trunk);
+
+	return res;
+}
+
+
+/**
+ * Q921TeiProcessAssignResponse
+ * \brief	Process assign response (TE mode only)
+ * \param[in]	trunk	pointer to Q921 data struct
+ * \param[in]	mes	pointer to message buffer
+ * \param[in]	size	size of message
+ * \return	> 0 on success; <= 0 on error
+ *
+ * \author	Stefan Knoblich
+ */
+static int Q921TeiProcAssignResponse(L2TRUNK trunk, L2UCHAR *mes, L2INT size)
+{
+	struct Q921_Link *link = Q921_TRUNK_CONTEXT(trunk);
+	L2UCHAR offset = Q921_UFRAME_DATA_OFFSET(trunk);
+	L2USHORT ri = 0;
+
+	if (!Q921_IS_PTMP_TE(trunk))	/* PTMP TE only */
+		return 0;
+
+	ri = (mes[offset + 1] << 8) | mes[offset + 2];
+
+	if(ri != link->ri) {
+		/* hmmm ..., not our response i guess */
+		return 0;
+	}
+
+	switch(mes[offset + 3]) {
+	case Q921_TEI_ID_ASSIGNED:
+		/* Yay, use the new TEI and change state to assigned */
+		link->tei      = mes[offset + 4] >> 1;
+
+		Q921Log(trunk, Q921_LOG_DEBUG, "Assigned TEI %d, setting state to TEI_ASSIGNED\n", link->tei);
+
+		Q921ChangeState(trunk, Q921_STATE_TEI_ASSIGNED, link->tei);
+		break;
+
+	case Q921_TEI_ID_DENIED:
+		/* oops, what to do now? */
+		if ((mes[offset + 4] >> 1) == Q921_TEI_BCAST) {
+			/* No more free TEIs? this is bad */
+
+			//Q921TeiSendVerifyRequest(trunk, Q921_TEI_BCAST); /* TODO: does this work ?? */
+		} else {
+			/* other reason, this is fatal, shutdown link */
+		}
+
+		Q921Log(trunk, Q921_LOG_DEBUG, "TEI assignment has been denied, reason: %s\n",
+			 ((mes[offset +4] >> 1) == Q921_TEI_BCAST) ? "No free TEIs available" : "Unknown");
+
+		Q921ChangeState(trunk, Q921_STATE_TEI_UNASSIGNED, link->tei);
+		break;
+
+	default:
+		return 0;
+	}
+
+	/* stop T202 */
+	Q921T202TimerStop(trunk);
+
+	return 1;
+}
+
+
+/**
+ * Q921TeiSendVerifyRequest
+ * \brief	Verify TEI (TE mode only)
+ * \param[in]	trunk	pointer to Q921 data struct
+ * \return	> 0 on success; <= 0 on error
+ *
+ * \author	Stefan Knoblich
+ */
+static int Q921TeiSendVerifyRequest(L2TRUNK trunk)
+{
+	struct Q921_Link *link = Q921_TRUNK_CONTEXT(trunk);
+	L2INT res;
+
+	if (!Q921_IS_PTMP_TE(trunk))	/* only ptmp te mode*/
+		return 0;
+
+	/* Request running? */
+	if (trunk->T202)
+		return 0;
+
+	/* Send TEI verify request */
+	res = Q921TeiSend(trunk, Q921_TEI_ID_VERIFY, link->ri, link->tei);
+
+	/* start T202 */
+	Q921T202TimerStart(trunk);
+
+	return res;
+}
+
+
+/**
+ * Q921TeiProcCheckRequest
+ * \brief	Process Check Request (TE mode only)
+ * \param[in]	trunk	pointer to Q921 data struct
+ * \param[in]	mes	pointer to message buffer
+ * \param[in]	size	size of message
+ * \return	> 0 on success; <= 0 on error
+ *
+ * \author	Stefan Knoblich
+ */
+static int Q921TeiProcCheckRequest(L2TRUNK trunk, L2UCHAR *mes, L2INT size)
+{
+	struct Q921_Link *link = Q921_TRUNK_CONTEXT(trunk);
+	L2UCHAR offset = Q921_UFRAME_DATA_OFFSET(trunk);
+	L2UCHAR tei = (mes[offset + 4] >> 1);		/* action indicator => tei */
+	L2INT res = 0;
+
+	if (!Q921_IS_PTMP_TE(trunk))	/* ptmp te mode only */
+		return 0;
+
+	Q921Log(trunk, Q921_LOG_DEBUG, "Received TEI Check request for TEI %d\n", tei);
+
+	if (tei == Q921_TEI_BCAST || tei == link->tei) {
+		/*
+		 * Broadcast TEI check or for our assigned TEI
+		 */
+
+		/* send TEI check reponse */
+		res = Q921TeiSend(trunk, Q921_TEI_ID_CHECKRESP, link->ri, link->tei);
+
+		Q921T202TimerStop(trunk);
+	}
+
+	return res;
+}
+
+
+/**
+ * Q921TeiProcRemoveRequest
+ * \brief	Process remove Request (TE mode only)
+ * \param[in]	trunk	pointer to Q921 data struct
+ * \param[in]	mes	pointer to message buffer
+ * \param[in]	size	size of message
+ * \return	> 0 on success; <= 0 on error
+ *
+ * \author	Stefan Knoblich
+ */
+static int Q921TeiProcRemoveRequest(L2TRUNK trunk, L2UCHAR *mes, L2INT size)
+{
+	struct Q921_Link *link = Q921_TRUNK_CONTEXT(trunk);
+	L2UCHAR offset = Q921_UFRAME_DATA_OFFSET(trunk);
+	L2UCHAR tei = (mes[offset + 4] >> 1);		/* action indicator => tei */
+	L2INT res = 0;
+
+	if (!Q921_IS_PTMP_TE(trunk))	/* ptmp te mode only */
+		return 0;
+
+	Q921Log(trunk, Q921_LOG_DEBUG, "Received TEI Remove request for TEI %d\n", tei);
+
+	if (tei == Q921_TEI_BCAST || tei == link->tei) {
+		/*
+		 * Broadcast TEI remove or for our assigned TEI
+		 */
+
+		/* reset tei */
+		link->tei  = 0;
+
+		/* change state (no action) */
+		Q921ChangeState(trunk, Q921_STATE_TEI_UNASSIGNED, link->tei);
+
+		/* TODO: hmm, request new one ? */
+		res = Q921TeiSendAssignRequest(trunk);
+	}
+	return res;
+}
+
+
+/**
+ * Q921TeiProcAssignRequest
+ * \brief	Process assign request from peer (NT mode only)
+ * \param[in]	trunk	pointer to Q921 data struct
+ * \param[in]	mes	pointer to message buffer
+ * \param[in]	size	size of message
+ * \return	> 0 on success; <= 0 on error
+ *
+ * \author	Stefan Knoblich
+ */
+static int Q921TeiProcAssignRequest(L2TRUNK trunk, L2UCHAR *mes, L2INT size)
+{
+	L2UCHAR offset = Q921_UFRAME_DATA_OFFSET(trunk);
+	L2USHORT ri = 0;
+	L2UCHAR tei = 0;
+
+	if (!Q921_IS_PTMP_NT(trunk))	/* PTMP NT only */
+		return 0;
+
+	ri  = (mes[offset + 1] << 8) | mes[offset + 2];
+	tei =  mes[offset + 4] >> 1;
+
+	if(tei == Q921_TEI_BCAST) {
+		int x;
+
+		/* dynamically allocate TEI */
+		for(x = Q921_TEI_DYN_MIN, tei = 0; x <= Q921_TEI_MAX; x++) {
+			if(!trunk->tei_map[x]) {
+				tei = x;
+				break;
+			}
+		}
+	}
+	else if(!(tei > 0 && tei < Q921_TEI_DYN_MIN)) {
+		/* reject TEIs that are not in the static area */
+		Q921TeiSendDenyResponse(trunk, 0, ri);
+
+		return 0;
+	}
+
+	if(!tei) {
+		/* no free TEI found */
+		Q921TeiSendDenyResponse(trunk, Q921_TEI_BCAST, ri);
+	}
+	else {
+		struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+		/* mark used */
+		trunk->tei_map[tei] = 1;
+
+		/* assign tei */
+		link->tei = tei;
+
+		/* put context in TEI ASSIGNED state */
+		Q921ChangeState(trunk, Q921_STATE_TEI_ASSIGNED, tei);
+
+		/* send assign response */
+		Q921TeiSendAssignedResponse(trunk, tei, ri);
+
+		/* Start T201 */
+		Q921T201TimerStart(trunk, tei);
+	}
+	return 0;
+}
+
+/**
+ * Q921TeiSendCheckRequest
+ * \brief	Send check request (NT mode only)
+ * \param[in]	trunk	pointer to Q921 data struct
+ * \param[in]	tei	TEI to check
+ * \return	> 0 on success; <= 0 on error
+ *
+ * \author	Stefan Knoblich
+ */
+static int Q921TeiSendCheckRequest(L2TRUNK trunk, L2UCHAR tei)
+{
+	L2INT res = 0;
+
+	if (!Q921_IS_PTMP_NT(trunk))	/* PTMP NT only */
+		return 0;
+
+	/* send TEI check request */
+	res = Q921TeiSend(trunk, Q921_TEI_ID_CHECKREQ, 0, tei);
+
+	/* (Re-)Start T201 timer */
+	Q921T201TimerStart(trunk, tei);
+
+	return res;
+}
+
+/**
+ * Q921TeiProcCheckResponse
+ * \brief	Process Check Response (NT mode only)
+ * \param[in]	trunk	pointer to Q921 data struct
+ * \param[in]	mes	pointer to message buffer
+ * \param[in]	size	size of message
+ * \return	> 0 on success; <= 0 on error
+ *
+ * \author	Stefan Knoblich
+ */
+static int Q921TeiProcCheckResponse(L2TRUNK trunk, L2UCHAR *mes, L2INT size)
+{
+	struct Q921_Link *link;
+	L2UCHAR offset = Q921_UFRAME_DATA_OFFSET(trunk);
+	L2USHORT ri = 0;
+	L2UCHAR tei = 0;
+
+	if (!Q921_IS_PTMP_NT(trunk))	/* PTMP NT mode only */
+		return 0;
+
+	ri  = (mes[offset + 1] << 8) | mes[offset + 2];
+	tei =  mes[offset + 4] >> 1;
+
+	/* restart T201 */
+	Q921T201TimerStop(trunk, tei);
+
+	/* reset counter */
+	link       = Q921_LINK_CONTEXT(trunk, tei);
+	link->N202 = 0;
+
+	if(!(tei > 0 && tei < Q921_TEI_MAX) || !trunk->tei_map[tei]) {
+		/* TODO: Should we send a DISC first? */
+
+		/* TEI not assigned? Invalid TEI? */
+		Q921TeiSendRemoveRequest(trunk, tei);
+
+		/* change state */
+		Q921ChangeState(trunk, Q921_STATE_STOPPED, tei);
+
+		/* clear */
+		memset(link, 0, sizeof(struct Q921_Link));
+	} else {
+		/* Start T201 */
+		Q921T201TimerStart(trunk, tei);
+	}
+
+	return 0;
+}
+
+
+/**
+ * Q921TeiProcVerifyRequest
+ * \brief	Process Verify Request (NT mode only)
+ * \param[in]	trunk	pointer to Q921 data struct
+ * \param[in]	mes	pointer to message buffer
+ * \param[in]	size	size of message
+ * \return	> 0 on success; <= 0 on error
+ *
+ * \author	Stefan Knoblich
+ */
+static int Q921TeiProcVerifyRequest(L2TRUNK trunk, L2UCHAR *mes, L2INT size)
+{
+	L2UCHAR resp[25];
+	L2UCHAR offset = Q921_UFRAME_DATA_OFFSET(trunk);
+	L2UCHAR tei = 0;
+
+	if (!Q921_IS_PTMP_NT(trunk))	/* PTMP NT mode only */
+		return 0;
+
+	tei = mes[offset + 4] >> 1;
+
+	/* todo: handle response... verify assigned TEI */
+	resp[offset + 0] = 0;
+
+	return 0;
+}
+
+/**
+ * Q921TeiSendDenyResponse
+ * \brief	Send Deny Response (NT mode only)
+ * \param[in]	trunk	pointer to Q921 data struct
+ * \return	> 0 on success; <= 0 on error
+ *
+ * \author	Stefan Knoblich
+ */
+static int Q921TeiSendDenyResponse(L2TRUNK trunk, L2UCHAR tei, L2USHORT ri)
+{
+	if (!Q921_IS_PTMP_NT(trunk))	/* PTMP NT only */
+		return 0;
+
+	return Q921TeiSend(trunk, Q921_TEI_ID_DENIED, ri, tei);
+}
+
+
+/**
+ * Q921TeiSendAssignedResponse
+ * \brief	Send Assigned Response (NT mode only)
+ * \param[in]	trunk	pointer to Q921 data struct
+ * \param[in]	tei	TEI to assign
+ * \param[in]	ri	RI of request
+ * \return	> 0 on success; <= 0 on error
+ *
+ * \author	Stefan Knoblich
+ */
+static int Q921TeiSendAssignedResponse(L2TRUNK trunk, L2UCHAR tei, L2USHORT ri)
+{
+	if (!Q921_IS_PTMP_NT(trunk))	/* PTMP NT only */
+		return 0;
+
+	return Q921TeiSend(trunk, Q921_TEI_ID_ASSIGNED, ri, tei);
+}
+
+/**
+ * Q921TeiSendRemoveRequest
+ * \brief	Send Remove Request (NT mode only)
+ * \param[in]	trunk	pointer to Q921 data struct
+ * \param[in]	tei	TEI to remove
+ * \return	> 0 on success; <= 0 on error
+ *
+ * \author	Stefan Knoblich
+ */
+static int Q921TeiSendRemoveRequest(L2TRUNK trunk, L2UCHAR tei)
+{
+	if (!Q921_IS_PTMP_NT(trunk))	/* PTMP NT only */
+		return 0;
+
+	return Q921TeiSend(trunk, Q921_TEI_ID_REMOVE, 0, tei);
+}

Added: freeswitch/trunk/libs/freetdm/src/isdn/Q931.c (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/isdn/Q931.c	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/isdn/Q931.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,888 @@
+/*****************************************************************************
+
+  FileName:	 Q931.c
+
+  Contents:	 Implementation of Q.931 stack main interface functions. 
+				See q931.h for description. 
+
+  License/Copyright:
+
+  Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+  email:janvb@caselaboratories.com  
+
+  Redistribution and use in source and binary forms, with or without 
+  modification, are permitted provided that the following conditions are 
+  met:
+
+	* Redistributions of source code must retain the above copyright notice, 
+	  this list of conditions and the following disclaimer.
+	* Redistributions in binary form must reproduce the above copyright notice, 
+	  this list of conditions and the following disclaimer in the documentation 
+	  and/or other materials provided with the distribution.
+	* Neither the name of the Case Labs, Ltd nor the names of its contributors 
+	  may be used to endorse or promote products derived from this software 
+	  without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
+  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
+  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+  POSSIBILITY OF SUCH DAMAGE.
+*****************************************************************************/
+
+#include "Q921.h"
+#include "Q931.h"
+#include "national.h"
+#include "DMS.h"
+#include "5ESS.h"
+
+
+/*****************************************************************************
+
+  Dialect function pointers tables.
+
+  The following function pointer arrays define pack/unpack functions and 
+  processing furnctions for the different Q.931 based dialects.
+
+  The arrays are initialized with pointers to dummy functions and later
+  overrided with pointers to actual functions as new dialects are added.
+
+  The initial Q.931 will as an example define 2 dialects as it treats User
+  and Network mode as separate ISDN dialects.
+
+  The API messages Q931AddProc, Q931AddMes, Q931AddIE are used to initialize
+  these table entries during system inititialization of a stack.
+
+*****************************************************************************/
+q931proc_func_t *Q931Proc[Q931MAXDLCT][Q931MAXMES];
+
+q931umes_func_t *Q931Umes[Q931MAXDLCT][Q931MAXMES];
+q931pmes_func_t *Q931Pmes[Q931MAXDLCT][Q931MAXMES];
+
+q931uie_func_t *Q931Uie[Q931MAXDLCT][Q931MAXIE];
+q931pie_func_t *Q931Pie[Q931MAXDLCT][Q931MAXIE];
+
+q931timeout_func_t *Q931Timeout[Q931MAXDLCT][Q931MAXTIMER];
+q931timer_t         Q931Timer[Q931MAXDLCT][Q931MAXTIMER];
+
+void (*Q931CreateDialectCB[Q931MAXDLCT])(L3UCHAR iDialect) = { NULL, NULL };
+
+Q931State Q931st[Q931MAXSTATE];
+
+/*****************************************************************************
+
+  Core system tables and variables.
+
+*****************************************************************************/
+
+L3INT Q931L4HeaderSpace = {0};	/* header space to be ignoder/inserted */
+				/* at head of each message. */
+
+L3INT Q931L2HeaderSpace = {4};	/* Q921 header space, sapi, tei etc */
+
+/*****************************************************************************
+
+  Main interface callback functions. 
+
+*****************************************************************************/
+
+Q931ErrorCB_t Q931ErrorProc;			/* callback for error messages. */
+L3ULONG (*Q931GetTimeProc) (void) = NULL;	/* callback for func reading time in ms */
+
+/*****************************************************************************
+
+  Function:	 Q931SetL4HeaderSpace
+
+  Description:  Set the # of bytes to be inserted/ignored at the head of
+		each message. Q931 will issue a message with space for header
+		and the user will use this to fill in whatever header info
+		is required to support the architecture used.
+
+*****************************************************************************/
+void Q931SetL4HeaderSpace(L3INT space)
+{
+	Q931L4HeaderSpace = space;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931SetL2HeaderSpace
+
+  Description:  Set the # of bytes to be inserted/ignored at the head of
+		each message. Q931 will issue a message with space for header
+		and the user will use this to fill in whatever header info
+		is required to support the architecture used.
+
+*****************************************************************************/
+void Q931SetL2HeaderSpace(L3INT space)
+{
+	Q931L2HeaderSpace = space;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931ProcDummy
+
+  Description:  Dummy function for message processing.
+
+*****************************************************************************/
+L3INT Q931ProcDummy(Q931_TrunkInfo_t *pTrunk, L3UCHAR * b,L3INT c)
+{
+	return Q931E_INTERNAL;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931UmesDummy
+
+  Description:  Dummy function for message processing
+
+*****************************************************************************/
+L3INT Q931UmesDummy(Q931_TrunkInfo_t *pTrunk,L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT IOff, L3INT Size)
+{
+	return Q931E_UNKNOWN_MESSAGE;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931UieDummy
+
+  Description:  Dummy function for message processing
+
+*****************************************************************************/
+L3INT Q931UieDummy(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff)
+{
+	return Q931E_UNKNOWN_IE;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931PmesDummy
+
+  Description:  Dummy function for message processing
+
+*****************************************************************************/
+L3INT Q931PmesDummy(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+	return Q931E_UNKNOWN_MESSAGE;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931PieDummy
+
+  Description:  Dummy function for message processing
+
+*****************************************************************************/
+L3INT Q931PieDummy(Q931_TrunkInfo_t *pTrunk,L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+	return Q931E_UNKNOWN_IE;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931TxDummy
+
+  Description:  Dummy function for message processing
+
+*****************************************************************************/
+L3INT Q931TxDummy(Q931_TrunkInfo_t *pTrunk, L3UCHAR * b, L3INT n)
+{
+	return Q931E_MISSING_CB;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931ErrorDummy
+
+  Description:  Dummy function for error processing
+
+*****************************************************************************/
+L3INT Q931ErrorDummy(void *priv, L3INT a, L3INT b, L3INT c)
+{
+	return 0;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Initialize
+
+  Description:  This function Initialize the stack. 
+  
+		Will set up the trunk array, channel
+		arrays and initialize Q931 function arrays before it finally
+		set up EuroISDN processing with User as dialect 0 and 
+		Network as dialect 1.
+
+  Note:		 Initialization of other stacks should be inserted after
+		the initialization of EuroISDN.
+
+*****************************************************************************/
+void Q931Initialize()
+{
+	L3INT x,y;
+
+	/* Secure the callbacks to default procs */
+	Q931ErrorProc = Q931ErrorDummy;
+
+	/* The user will only add the message handlers and IE handlers he need,
+	 * so we need to initialize every single entry to a default function
+	 * that will throw an appropriate error if they are ever called.
+	 */
+	for (x = 0; x < Q931MAXDLCT; x++) {
+		for (y = 0; y < Q931MAXMES; y++) {
+			Q931Proc[x][y] = Q931ProcDummy;
+			Q931Umes[x][y] = Q931UmesDummy;
+			Q931Pmes[x][y] = Q931PmesDummy;
+		}
+		for (y = 0; y < Q931MAXIE; y++) {
+			Q931Pie[x][y] = Q931PieDummy;
+			Q931Uie[x][y] = Q931UieDummy;
+		}
+		for (y = 0; y < Q931MAXTIMER; y++) {
+			Q931Timeout[x][y] = Q931TimeoutDummy;
+			Q931Timer[x][y]   = 0;
+		}
+	}
+
+	if (Q931CreateDialectCB[Q931_Dialect_Q931 + Q931_TE] == NULL)
+		Q931AddDialect(Q931_Dialect_Q931 + Q931_TE, Q931CreateTE);
+
+	if (Q931CreateDialectCB[Q931_Dialect_Q931 + Q931_NT] == NULL)
+		Q931AddDialect(Q931_Dialect_Q931 + Q931_NT, Q931CreateNT);
+
+	if (Q931CreateDialectCB[Q931_Dialect_National + Q931_TE] == NULL)
+		Q931AddDialect(Q931_Dialect_National + Q931_TE, nationalCreateTE);
+
+	if (Q931CreateDialectCB[Q931_Dialect_National + Q931_NT] == NULL)
+		Q931AddDialect(Q931_Dialect_National + Q931_NT, nationalCreateNT);
+
+	if (Q931CreateDialectCB[Q931_Dialect_DMS + Q931_TE] == NULL)
+		Q931AddDialect(Q931_Dialect_DMS + Q931_TE, DMSCreateTE);
+
+	if (Q931CreateDialectCB[Q931_Dialect_DMS + Q931_NT] == NULL)
+		Q931AddDialect(Q931_Dialect_DMS + Q931_NT, DMSCreateNT);
+
+	if (Q931CreateDialectCB[Q931_Dialect_5ESS + Q931_TE] == NULL)
+		Q931AddDialect(Q931_Dialect_5ESS + Q931_TE, ATT5ESSCreateTE);
+
+	if (Q931CreateDialectCB[Q931_Dialect_5ESS + Q931_NT] == NULL)
+		Q931AddDialect(Q931_Dialect_5ESS + Q931_NT, ATT5ESSCreateNT);
+
+	/* The last step we do is to call the callbacks to create the dialects  */
+	for (x = 0; x < Q931MAXDLCT; x++) {
+		if (Q931CreateDialectCB[x] != NULL) {
+			Q931CreateDialectCB[x]((L3UCHAR)x);
+		}   
+	}
+}
+
+/**
+ * Q931TimerTick
+ * \brief	Periodically called to update and check for expired timers
+ * \param	pTrunk	Q.931 trunk
+ */
+void Q931TimerTick(Q931_TrunkInfo_t *pTrunk)
+{
+	struct Q931_Call *call = NULL;
+	L3ULONG now = 0;
+	L3INT x;
+
+	/* TODO: Loop through all active calls, check timers and call timout procs
+	 * if timers are expired.
+	 * Implement a function array so each dialect can deal with their own
+	 * timeouts.
+	 */
+	now = Q931GetTime();
+
+	for (x = 0; x < Q931MAXCALLPERTRUNK; x++) {
+		call = &pTrunk->call[x];
+
+		if (!call->InUse || !call->Timer || !call->TimerID)
+			continue;
+
+		if (call->Timer <= now) {
+			/* Stop Timer */
+			Q931StopTimer(pTrunk, x, call->TimerID);
+
+			/* Invoke dialect timeout callback */
+			Q931Timeout[pTrunk->Dialect][call->TimerID](pTrunk, x);
+		}
+	}
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Rx23
+
+  Description:  Receive message from layer 2 (LAPD). Receiving a message 
+				is always done in 2 steps. First the message must be 
+				interpreted and translated to a static struct. Secondly
+				the message is processed and responded to.
+
+				The Q.931 message contains a static header that is 
+				interpreted in this function. The rest is interpreted
+				in a sub function according to mestype.
+
+  Parameters:   pTrunk  [IN]	Ptr to trunk info.
+				buf	 [IN]	Ptr to buffer containing message.
+				Size	[IN]	Size of message.
+
+  Return Value: Error Code. 0 = No Error, < 0 :error, > 0 : Warning
+				see q931errors.h for details.
+
+*****************************************************************************/
+L3INT Q931Rx23(Q931_TrunkInfo_t *pTrunk, L3INT ind, L3UCHAR tei, L3UCHAR * buf, L3INT Size)
+{
+	L3UCHAR *Mes = NULL;
+	L3INT RetCode = Q931E_NO_ERROR;
+	Q931mes_Generic *m = (Q931mes_Generic *) pTrunk->L3Buf;
+	L3INT ISize;
+	L3INT IOff = 0;
+	L3INT L2HSize = Q931L2HeaderSpace;
+
+	switch (ind) {
+	case Q921_DL_UNIT_DATA:		/* DL-UNITDATA indication (UI frame, 3 byte header) */
+		L2HSize = 3;
+
+	case Q921_DL_DATA:		/* DL-DATA indication (I frame, 4 byte header) */
+		/* Reset our decode buffer */
+		memset(pTrunk->L3Buf, 0, sizeof(pTrunk->L3Buf));
+
+		/* L2 Header Offset */
+		Mes = &buf[L2HSize];
+
+		/* Protocol Discriminator */
+		m->ProtDisc = Mes[IOff++];
+
+		/* CRV */
+		m->CRVFlag = (Mes[IOff + 1] >> 7) & 0x01;
+		m->CRV = Q931Uie_CRV(pTrunk, Mes, m->buf, &IOff, &ISize);
+
+		/* Message Type */
+		m->MesType = Mes[IOff++];
+
+		/* Store tei */
+		m->Tei = tei;
+
+		/* d'oh a little ugly but this saves us from:
+		 *	a) doing Q.921 work in the lower levels (extracting the TEI ourselves)
+		 *	b) adding a tei parameter to _all_ Proc functions
+		 */
+		if (tei) {
+			L3INT callIndex = 0;
+
+			/* Find the call using CRV */
+			RetCode = Q931FindCRV(pTrunk, m->CRV, &callIndex);
+			if (RetCode == Q931E_NO_ERROR && !pTrunk->call[callIndex].Tei) {
+				pTrunk->call[callIndex].Tei = tei;
+			}
+		}
+
+		Q931Log(pTrunk, Q931_LOG_DEBUG, "Received message from Q.921 (ind %d, tei %d, size %d)\nMesType: %d, CRVFlag %d (%s), CRV %d (Dialect: %d)\n", ind, m->Tei, Size,
+						 m->MesType, m->CRVFlag, m->CRVFlag ? "Terminator" : "Originator", m->CRV, pTrunk->Dialect);
+
+		RetCode = Q931Umes[pTrunk->Dialect][m->MesType](pTrunk, Mes, (Q931mes_Generic *)pTrunk->L3Buf, IOff, Size - L2HSize);
+		if (RetCode >= Q931E_NO_ERROR) {
+			RetCode = Q931Proc[pTrunk->Dialect][m->MesType](pTrunk, pTrunk->L3Buf, 2);
+		}
+		break;
+
+	default:
+		break;
+	}
+
+	return RetCode;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Tx34
+
+  Description:  Called from the stack to send a message to layer 4.
+
+  Parameters:   Mes[IN]	 Ptr to message buffer.
+		Size[IN]	Message size in bytes.
+
+  Return Value: Error Code. 0 = No Error, < 0 :error, > 0 : Warning
+		see q931errors.h for details.
+
+*****************************************************************************/
+L3INT Q931Tx34(Q931_TrunkInfo_t *pTrunk, L3UCHAR * Mes, L3INT Size)
+{
+	Q931Log(pTrunk, Q931_LOG_DEBUG, "Sending message to Layer4 (size: %d)\n", Size);
+
+	if (pTrunk->Q931Tx34CBProc) {
+		return pTrunk->Q931Tx34CBProc(pTrunk->PrivateData34, Mes, Size);
+	}
+	return Q931E_MISSING_CB;	
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Rx43
+
+  Description:  Receive message from Layer 4 (application).
+
+  Parameters:   pTrunk[IN]  Trunk #.
+		buf[IN]	 Message Pointer.
+		Size[IN]	Message size in bytes.
+
+  Return Value: Error Code. 0 = No Error, < 0 :error, > 0 : Warning
+		see q931errors.h for details.
+
+*****************************************************************************/
+L3INT Q931Rx43(Q931_TrunkInfo_t *pTrunk,L3UCHAR * buf, L3INT Size)
+{
+	Q931mes_Header *ptr = (Q931mes_Header*)&buf[Q931L4HeaderSpace];
+	L3INT RetCode = Q931E_NO_ERROR;
+
+	Q931Log(pTrunk, Q931_LOG_DEBUG, "Receiving message from Layer4 (size: %d, type: %d)\n", Size, ptr->MesType);
+
+	RetCode = Q931Proc[pTrunk->Dialect][ptr->MesType](pTrunk, buf, 4);
+
+	Q931Log(pTrunk, Q931_LOG_DEBUG, "Q931Rx43 return code: %d\n", RetCode);
+
+	return RetCode;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Tx32
+
+  Description:  Called from the stack to send a message to L2. The input is 
+				always a non-packed message so it will first make a proper
+				call to create a packed message before it transmits that
+				message to layer 2.
+
+  Parameters:   pTrunk[IN]  Trunk #  
+				buf[IN]	 Ptr to message buffer.
+				Size[IN]	Message size in bytes.
+
+  Return Value: Error Code. 0 = No Error, < 0 :error, > 0 : Warning
+				see q931errors.h for details.
+
+*****************************************************************************/
+L3INT Q931Tx32Data(Q931_TrunkInfo_t *pTrunk, L3UCHAR bcast, L3UCHAR * Mes, L3INT Size)
+{
+	Q931mes_Generic *ptr = (Q931mes_Generic*)Mes;
+	L3INT RetCode = Q931E_NO_ERROR;
+	L3INT iDialect = pTrunk->Dialect;
+	L3INT Offset = bcast ? (Q931L2HeaderSpace - 1) : Q931L2HeaderSpace;
+	L3INT OSize;
+
+	Q931Log(pTrunk, Q931_LOG_DEBUG, "Sending message to Q.921 (size: %d)\n", Size);
+
+	memset(pTrunk->L2Buf, 0, sizeof(pTrunk->L2Buf));
+
+	/* Call pack function through table. */
+	RetCode = Q931Pmes[iDialect][ptr->MesType](pTrunk, (Q931mes_Generic *)Mes, Size, &pTrunk->L2Buf[Offset], &OSize);
+	if (RetCode >= Q931E_NO_ERROR) {
+		L3INT callIndex;
+		L3UCHAR tei = 0;
+
+		if (ptr->CRV) {
+			/* Find the call using CRV */
+			RetCode = Q931FindCRV(pTrunk, ptr->CRV, &callIndex);
+			if (RetCode != Q931E_NO_ERROR)
+				return RetCode;
+
+			tei = pTrunk->call[callIndex].Tei;
+		}
+
+		if (pTrunk->Q931Tx32CBProc) {
+			RetCode = pTrunk->Q931Tx32CBProc(pTrunk->PrivateData32, bcast ? Q921_DL_UNIT_DATA : Q921_DL_DATA, tei, pTrunk->L2Buf, OSize + Offset);
+		} else {
+			RetCode = Q931E_MISSING_CB;
+		}
+	}
+
+	return RetCode;
+}
+
+
+/*****************************************************************************
+
+  Function:	 Q931SetError
+
+  Description:  Called from the stack to indicate an error. 
+
+  Parameters:   ErrID	   ID of ie or message causing error.
+		ErrPar1	 Error parameter 1
+		ErrPar2	 Error parameter 2.
+
+
+*****************************************************************************/
+void Q931SetError(Q931_TrunkInfo_t *pTrunk,L3INT ErrID, L3INT ErrPar1, L3INT ErrPar2)
+{
+	if (pTrunk->Q931ErrorCBProc) {
+		pTrunk->Q931ErrorCBProc(pTrunk->PrivateData34, ErrID, ErrPar1, ErrPar2);
+	} else {
+		Q931ErrorProc(pTrunk->PrivateData34, ErrID, ErrPar1, ErrPar2);
+	}
+}
+
+void Q931SetDefaultErrorCB(Q931ErrorCB_t Q931ErrorPar)
+{
+	Q931ErrorProc = Q931ErrorPar;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931CreateCRV
+
+  Description:  Create a CRV entry and return it's index. The function will 
+		locate a free entry in the call tables allocate it and 
+		allocate a unique CRV value attached to it.
+
+  Parameters:   pTrunk	  [IN]	Trunk number
+		callindex   [OUT]   return call table index.
+
+  Return Value: Error Code. 0 = No Error, < 0 :error, > 0 : Warning
+		see q931errors.h for details.
+****************************************************************************/
+L3INT Q931CreateCRV(Q931_TrunkInfo_t *pTrunk, L3INT * callIndex)
+{
+	L3INT CRV = Q931GetUniqueCRV(pTrunk);
+
+	return Q931AllocateCRV(pTrunk, CRV, callIndex);
+}
+
+
+L3INT Q931ReleaseCRV(Q931_TrunkInfo_t *pTrunk, L3INT CRV)
+{
+	int callIndex;
+	
+	if ((Q931FindCRV(pTrunk, CRV, &callIndex)) == Q931E_NO_ERROR) {
+		pTrunk->call[callIndex].InUse = 0;
+		return Q931E_NO_ERROR;
+	}
+
+	return Q931E_INVALID_CRV;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931AllocateCRV
+
+  Description:  Allocate a call table entry and assigns the given CRV value
+		to it.
+
+  Parameters:   pTrunk	  [IN]	Trunk number
+		iCRV		[IN]	Call Reference Value.
+		callindex   [OUT]   return call table index.
+
+  Return Value: Error Code. 0 = No Error, < 0 :error, > 0 : Warning
+		see q931errors.h for details.
+
+*****************************************************************************/
+L3INT Q931AllocateCRV(Q931_TrunkInfo_t *pTrunk, L3INT iCRV, L3INT * callIndex)
+{
+	L3INT x;
+	for (x = 0; x < Q931MAXCALLPERTRUNK; x++) {
+		if (!pTrunk->call[x].InUse) {
+			pTrunk->call[x].CRV     = iCRV;
+			pTrunk->call[x].BChan   = 255;
+			pTrunk->call[x].State   = 0;	/* null state - idle */
+			pTrunk->call[x].TimerID = 0;	/* no timer running */
+			pTrunk->call[x].Timer   = 0;
+			pTrunk->call[x].InUse   = 1;	/* mark as used */
+			*callIndex = x;
+			return Q931E_NO_ERROR;
+		}
+	}
+	return Q931E_TOMANYCALLS;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931GetCallState
+
+  Description:  Look up CRV and return current call state. A non existing
+				CRV is the same as state zero (0).
+
+  Parameters:   pTrunk  [IN]	Trunk number.
+				iCRV	[IN]	CRV
+
+  Return Value: Call State.
+
+*****************************************************************************/
+L3INT Q931GetCallState(Q931_TrunkInfo_t *pTrunk, L3INT iCRV)
+{
+	L3INT x;
+	for (x = 0; x < Q931MAXCALLPERTRUNK; x++) {
+		if (pTrunk->call[x].InUse) {
+			if (pTrunk->call[x].CRV == iCRV) {
+				return pTrunk->call[x].State;
+			}
+		}
+	}
+	return 0; /* assume state zero for non existing CRV's */
+}
+
+/**
+ * Q931StartTimer
+ * \brief	Start a timer
+ * \param	pTrunk		Q.931 trunk
+ * \param	callindex	Index of the call
+ * \param	iTimerID	ID of timer
+ * \return	always 0
+ */
+L3INT Q931StartTimer(Q931_TrunkInfo_t *pTrunk, L3INT callIndex, L3USHORT iTimerID)
+{
+#if 0
+	L3ULONG duration = Q931Timer[pTrunk->Dialect][iTimerID];
+
+	if (duration) {
+		pTrunk->call[callIndex].Timer   = Q931GetTime() + duration;
+		pTrunk->call[callIndex].TimerID = iTimerID;
+	}
+#endif
+	return 0;
+}
+
+/**
+ * Q931StopTimer
+ * \brief	Stop a timer
+ * \param	pTrunk		Q.931 trunk
+ * \param	callindex	Index of the call
+ * \param	iTimerID	ID of timer
+ * \return	always 0
+ */
+L3INT Q931StopTimer(Q931_TrunkInfo_t *pTrunk, L3INT callindex, L3USHORT iTimerID)
+{
+	if (pTrunk->call[callindex].TimerID == iTimerID)
+		pTrunk->call[callindex].TimerID = 0;
+
+	return 0;
+}
+
+L3INT Q931SetState(Q931_TrunkInfo_t *pTrunk, L3INT callIndex, L3INT iState)
+{
+	pTrunk->call[callIndex].State = iState;
+
+	return 0;
+}
+
+L3ULONG Q931GetTime()
+{
+	L3ULONG tNow = 0;
+	static L3ULONG tLast = 0;
+
+	if (Q931GetTimeProc != NULL) {
+		tNow = Q931GetTimeProc();
+		if (tNow < tLast) {	/* wrapped */
+			/* TODO */
+		}
+		tLast = tNow;
+	}
+	return tNow;
+}
+
+void Q931SetGetTimeCB(L3ULONG (*callback)(void))
+{
+	Q931GetTimeProc = callback;
+}
+
+L3INT Q931FindCRV(Q931_TrunkInfo_t *pTrunk, L3INT crv, L3INT *callindex)
+{
+	L3INT x;
+	for (x = 0; x < Q931MAXCALLPERTRUNK; x++) {
+		if (pTrunk->call[x].InUse) {
+			if (pTrunk->call[x].CRV == crv) {
+				*callindex = x;
+				return Q931E_NO_ERROR;
+			}
+		}
+	}
+	return Q931E_INVALID_CRV;
+}
+
+
+void Q931AddDialect(L3UCHAR i, void (*callback)(L3UCHAR iD ))
+{
+	if (i < Q931MAXDLCT) {
+		Q931CreateDialectCB[i] = callback;
+	}
+}
+
+/*****************************************************************************
+  Function:	 Q931AddStateEntry
+
+  Description:  Find an empty entry in the dialects state table and add this
+				entry.
+*****************************************************************************/
+void Q931AddStateEntry(L3UCHAR iD, L3INT iState,    L3INT iMes,    L3UCHAR cDir)
+{
+	int x;
+	for (x = 0; x < Q931MAXSTATE; x++) {
+		if (Q931st[x].Message == 0) {
+			Q931st[x].State     = iState;
+			Q931st[x].Message   = iMes;
+			Q931st[x].Direction = cDir;
+			/* TODO Sort table and use bsearch */
+			return;
+		}
+	}
+}
+
+/*****************************************************************************
+  Function:	 Q931IsEventLegal
+
+  Description:  Check state table for matching criteria to indicate if this
+				Message is legal in this state or not.
+
+  Note:		 Someone write a bsearch or invent something smart here
+				please - sequential is ok for now.
+*****************************************************************************/
+L3BOOL Q931IsEventLegal(L3UCHAR iD, L3INT iState, L3INT iMes, L3UCHAR cDir)
+{
+	int x;
+	/* TODO Sort table and use bsearch */
+	for (x = 0; x < Q931MAXSTATE; x++) {
+		if (Q931st[x].State == iState && Q931st[x].Message == iMes &&
+		    Q931st[x].Direction == cDir) {
+			return L3TRUE;
+		}
+	}
+	return L3FALSE;
+}
+
+/*****************************************************************************
+  Function:	 q931_error_to_name()
+
+  Description:  Check state table for matching criteria to indicate if this
+				Message is legal in this state or not.
+
+  Note:		 Someone write a bsearch or invent something smart here
+				please - sequential is ok for now.
+*****************************************************************************/
+static const char *q931_error_names[] = {
+	"Q931E_NO_ERROR",			/* 0 */
+
+	"Q931E_UNKNOWN_MESSAGE",		/* -3001 */
+	"Q931E_ILLEGAL_IE",			/* -3002 */
+	"Q931E_UNKNOWN_IE",			/* -3003 */
+	"Q931E_BEARERCAP",			/* -3004 */
+	"Q931E_HLCOMP",				/* -3005 */
+	"Q931E_LLCOMP",				/* -3006 */
+	"Q931E_INTERNAL",			/* -3007 */
+	"Q931E_MISSING_CB",			/* -3008 */
+	"Q931E_UNEXPECTED_MESSAGE",		/* -3009 */
+	"Q931E_ILLEGAL_MESSAGE",		/* -3010 */
+	"Q931E_TOMANYCALLS",			/* -3011 */
+	"Q931E_INVALID_CRV",			/* -3012 */
+	"Q931E_CALLID",				/* -3013 */
+	"Q931E_CALLSTATE",			/* -3014 */
+	"Q931E_CALLEDSUB",			/* -3015 */
+	"Q931E_CALLEDNUM",			/* -3016 */
+	"Q931E_CALLINGNUM",			/* -3017 */
+	"Q931E_CALLINGSUB",			/* -3018 */
+	"Q931E_CAUSE",				/* -3019 */
+	"Q931E_CHANID",				/* -3020 */
+	"Q931E_DATETIME",			/* -3021 */
+	"Q931E_DISPLAY",			/* -3022 */
+	"Q931E_KEYPADFAC",			/* -3023 */
+	"Q931E_NETFAC",				/* -3024 */
+	"Q931E_NOTIFIND",			/* -3025 */
+	"Q931E_PROGIND",			/* -3026 */
+	"Q931E_RESTARTIND",			/* -3027 */
+	"Q931E_SEGMENT",			/* -3028 */
+	"Q931E_SIGNAL",				/* -3029 */
+	"Q931E_GENERIC_DIGITS"			/* -3030 */
+
+};
+
+#define Q931_MAX_ERROR 30
+
+const char *q931_error_to_name(q931_error_t error)
+{
+	int index = 0;
+	if ((int)error < 0) {
+		index = (((int)error * -1) -3000);
+	}
+	if (index < 0 || index > Q931_MAX_ERROR) {
+		return "";
+	}
+	return q931_error_names[index];
+}
+/*
+ * Logging
+ */
+#include <stdarg.h>
+
+L3INT Q931Log(Q931_TrunkInfo_t *trunk, Q931LogLevel_t level, const char *fmt, ...)
+{
+	char buf[Q931_LOGBUFSIZE];
+	L3INT len;
+	va_list ap;
+
+	if (!trunk->Q931LogCBProc)
+		return 0;
+
+	if (trunk->loglevel < level)
+		return 0;
+
+	va_start(ap, fmt);
+
+	len = vsnprintf(buf, sizeof(buf)-1, fmt, ap);
+	if (len <= 0) {
+		/* TODO: error handling */
+		return -1;
+	}
+	if (len >= sizeof(buf))
+		len = sizeof(buf) - 1;
+
+	buf[len] = '\0';
+
+	va_end(ap);
+
+	return trunk->Q931LogCBProc(trunk->PrivateDataLog, level, buf, len);
+}
+
+/**
+ * Q921SetLogCB
+ * \brief	Set Logging callback function and private data
+ */
+void Q931SetLogCB(Q931_TrunkInfo_t *trunk, Q931LogCB_t func, void *priv)
+{
+	trunk->Q931LogCBProc  = func;
+	trunk->PrivateDataLog = priv;
+}
+
+/**
+ * Q921SetLogLevel
+ * \brief	Set Loglevel
+ */
+void Q931SetLogLevel(Q931_TrunkInfo_t *trunk, Q931LogLevel_t level)
+{
+    if(!trunk)
+        return;
+
+    if (level < Q931_LOG_NONE) {
+        level = Q931_LOG_NONE;
+    } else if (level > Q931_LOG_DEBUG) {
+        level = Q931_LOG_DEBUG;
+    }
+
+	trunk->loglevel = level;
+}
+
+/**
+ * Q931TimeoutDummy
+ * \brief	Dummy handler for timeouts
+ * \param	pTrunk		Q.931 trunk
+ * \param	callIndex	Index of call
+ */
+L3INT Q931TimeoutDummy(Q931_TrunkInfo_t *pTrunk, L3INT callIndex)
+{
+	Q931Log(pTrunk, Q931_LOG_DEBUG, "Timer %d of call %d (CRV: %d) timed out\n", pTrunk->call[callIndex].TimerID, callIndex, pTrunk->call[callIndex].CRV);
+
+	return 0;
+}

Added: freeswitch/trunk/libs/freetdm/src/isdn/Q931StateNT.c (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/isdn/Q931StateNT.c	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/isdn/Q931StateNT.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,1218 @@
+/*****************************************************************************
+
+  FileName:		q931StateNT.c
+
+  Contents:		Q.931 State Engine for NT (Network Mode).
+
+			The controlling state engine for Q.931 is the state engine
+			on the NT side. The state engine on the TE side is a slave 
+			of this. The TE side maintain it's own states as described in
+			ITU-T Q931, but will in	raise conditions be overridden by 
+			the NT side.
+
+  License/Copyright:
+
+  Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+  email:janvb@caselaboratories.com  
+
+  Redistribution and use in source and binary forms, with or without 
+  modification, are permitted provided that the following conditions are 
+  met:
+
+	* Redistributions of source code must retain the above copyright notice, 
+	  this list of conditions and the following disclaimer.
+	* Redistributions in binary form must reproduce the above copyright notice, 
+	  this list of conditions and the following disclaimer in the documentation 
+	  and/or other materials provided with the distribution.
+	* Neither the name of the Case Labs, Ltd nor the names of its contributors 
+	  may be used to endorse or promote products derived from this software 
+	  without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
+  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
+  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+  POSSIBILITY OF SUCH DAMAGE.
+*****************************************************************************/
+
+#include "Q931.h"
+
+extern L3INT Q931L4HeaderSpace;
+
+/*****************************************************************************
+  Function:		Q931CreateNT
+
+  Description:	Will create the Q931 NT as a Dialect in the stack. The first
+				bulk set up the message handlers, the second bulk the IE
+				encoders/coders, and the last bulk set up the state table.
+
+  Parameters:	i		Dialect index
+*****************************************************************************/
+void Q931CreateNT(L3UCHAR i)
+{
+	Q931SetMesProc(Q931mes_ALERTING,             i, Q931ProcAlertingNT,          Q931Umes_Alerting,          Q931Pmes_Alerting);
+	Q931SetMesProc(Q931mes_CALL_PROCEEDING,      i, Q931ProcCallProceedingNT,    Q931Umes_CallProceeding,    Q931Pmes_CallProceeding);
+	Q931SetMesProc(Q931mes_CONNECT,              i, Q931ProcConnectNT,           Q931Umes_Connect,           Q931Pmes_Connect);
+	Q931SetMesProc(Q931mes_CONNECT_ACKNOWLEDGE,  i, Q931ProcConnectAckNT,        Q931Umes_ConnectAck,        Q931Pmes_ConnectAck);
+	Q931SetMesProc(Q931mes_PROGRESS,             i, Q931ProcProgressNT,          Q931Umes_Progress,          Q931Pmes_Progress);
+	Q931SetMesProc(Q931mes_SETUP,                i, Q931ProcSetupNT,             Q931Umes_Setup,             Q931Pmes_Setup);
+	Q931SetMesProc(Q931mes_SETUP_ACKNOWLEDGE,    i, Q931ProcSetupAckNT,          Q931Umes_SetupAck,          Q931Pmes_SetupAck);
+	Q931SetMesProc(Q931mes_RESUME,               i, Q931ProcResumeNT,            Q931Umes_Resume,            Q931Pmes_Resume);
+	Q931SetMesProc(Q931mes_RESUME_ACKNOWLEDGE,   i, Q931ProcResumeAckNT,         Q931Umes_ResumeAck,         Q931Pmes_ResumeAck);
+	Q931SetMesProc(Q931mes_RESUME_REJECT,        i, Q931ProcResumeRejectNT,      Q931Umes_ResumeReject,      Q931Pmes_ResumeReject);
+	Q931SetMesProc(Q931mes_SUSPEND,              i, Q931ProcSuspendNT,           Q931Umes_Suspend,           Q931Pmes_Suspend);
+	Q931SetMesProc(Q931mes_SUSPEND_ACKNOWLEDGE,  i, Q931ProcSuspendAckNT,        Q931Umes_SuspendAck,        Q931Pmes_SuspendAck);
+	Q931SetMesProc(Q931mes_SUSPEND_REJECT,       i, Q931ProcSuspendRejectNT,     Q931Umes_SuspendReject,     Q931Pmes_SuspendReject);
+	Q931SetMesProc(Q931mes_USER_INFORMATION,     i, Q931ProcUserInformationNT,   Q931Umes_UserInformation,   Q931Pmes_UserInformation);
+	Q931SetMesProc(Q931mes_DISCONNECT,           i, Q931ProcDisconnectNT,        Q931Umes_Disconnect,        Q931Pmes_Disconnect);
+	Q931SetMesProc(Q931mes_RELEASE,              i, Q931ProcReleaseNT,           Q931Umes_Release,           Q931Pmes_Release);
+	Q931SetMesProc(Q931mes_RELEASE_COMPLETE,     i, Q931ProcReleaseCompleteNT,   Q931Umes_ReleaseComplete,   Q931Pmes_ReleaseComplete);
+	Q931SetMesProc(Q931mes_RESTART,              i, Q931ProcRestartNT,           Q931Umes_Restart,           Q931Pmes_Restart);
+	Q931SetMesProc(Q931mes_RESTART_ACKNOWLEDGE,  i, Q931ProcRestartAckNT,        Q931Umes_RestartAck,        Q931Pmes_RestartAck);
+	Q931SetMesProc(Q931mes_CONGESTION_CONTROL,   i, Q931ProcCongestionControlNT, Q931Umes_CongestionControl, Q931Pmes_CongestionControl);
+	Q931SetMesProc(Q931mes_INFORMATION,          i, Q931ProcInformationNT,       Q931Umes_Information,       Q931Pmes_Information);
+	Q931SetMesProc(Q931mes_NOTIFY,               i, Q931ProcNotifyNT,            Q931Umes_Notify,            Q931Pmes_Notify);
+	Q931SetMesProc(Q931mes_STATUS,               i, Q931ProcStatusNT,            Q931Umes_Status,            Q931Pmes_Status);
+	Q931SetMesProc(Q931mes_STATUS_ENQUIRY,       i, Q931ProcStatusEnquiryNT,     Q931Umes_StatusEnquiry,     Q931Pmes_StatusEnquiry);
+	Q931SetMesProc(Q931mes_SEGMENT,              i, Q931ProcSegmentNT,           Q931Umes_Segment,           Q931Pmes_Segment);
+
+	Q931SetMesProc(Q932mes_FACILITY,             i, Q932ProcFacilityNT,          Q932Umes_Facility,          Q932Pmes_Facility);
+	Q931SetMesProc(Q932mes_HOLD,                 i, Q932ProcHoldNT,              Q932Umes_Hold,              Q932Pmes_Hold);
+	Q931SetMesProc(Q932mes_HOLD_ACKNOWLEDGE,     i, Q932ProcHoldAckNT,           Q932Umes_HoldAck,           Q932Pmes_HoldAck);
+	Q931SetMesProc(Q932mes_HOLD_REJECT,          i, Q932ProcHoldRejectNT,        Q932Umes_HoldReject,        Q932Pmes_HoldReject);
+	Q931SetMesProc(Q932mes_REGISTER,             i, Q932ProcRegisterNT,          Q932Umes_Register,          Q932Pmes_Register);
+	Q931SetMesProc(Q932mes_RETRIEVE,             i, Q932ProcRetrieveNT,          Q932Umes_Retrieve,          Q932Pmes_Retrieve);
+	Q931SetMesProc(Q932mes_RETRIEVE_ACKNOWLEDGE, i, Q932ProcRetrieveAckNT,       Q932Umes_RetrieveAck,       Q932Pmes_RetrieveAck);
+	Q931SetMesProc(Q932mes_RETRIEVE_REJECT,      i, Q932ProcRetrieveRejectNT,    Q932Umes_RetrieveReject,    Q932Pmes_RetrieveReject);
+
+	/* Set up the IE encoder/decoder handle table.*/ 
+	Q931SetIEProc(Q931ie_SEGMENTED_MESSAGE,                i, Q931Pie_Segment,     Q931Uie_Segment);
+	Q931SetIEProc(Q931ie_BEARER_CAPABILITY,                i, Q931Pie_BearerCap,   Q931Uie_BearerCap);
+	Q931SetIEProc(Q931ie_CAUSE,                            i, Q931Pie_Cause,       Q931Uie_Cause);
+	Q931SetIEProc(Q931ie_CALL_IDENTITY,                    i, Q931Pie_CallID,      Q931Uie_CallID);
+	Q931SetIEProc(Q931ie_CALL_STATE,                       i, Q931Pie_CallState,   Q931Uie_CallState);
+	Q931SetIEProc(Q931ie_CHANNEL_IDENTIFICATION,           i, Q931Pie_ChanID,      Q931Uie_ChanID);
+	Q931SetIEProc(Q931ie_PROGRESS_INDICATOR,               i, Q931Pie_ProgInd,     Q931Uie_ProgInd);
+	Q931SetIEProc(Q931ie_NETWORK_SPECIFIC_FACILITIES,      i, Q931Pie_NetFac,      Q931Uie_NetFac);
+	Q931SetIEProc(Q931ie_NOTIFICATION_INDICATOR,           i, Q931Pie_NotifInd,    Q931Uie_NotifInd);
+	Q931SetIEProc(Q931ie_DISPLAY,                          i, Q931Pie_Display,     Q931Uie_Display);
+	Q931SetIEProc(Q931ie_DATETIME,                         i, Q931Pie_DateTime,    Q931Uie_DateTime);
+	Q931SetIEProc(Q931ie_KEYPAD_FACILITY,                  i, Q931Pie_KeypadFac,   Q931Uie_KeypadFac);
+	Q931SetIEProc(Q931ie_SIGNAL,                           i, Q931Pie_Signal,      Q931Uie_Signal);
+	Q931SetIEProc(Q931ie_TRANSIT_DELAY_SELECTION_AND_IND,  i, Q931Pie_TransNetSel, Q931Uie_TransNetSel);
+	Q931SetIEProc(Q931ie_CALLING_PARTY_NUMBER,             i, Q931Pie_CallingNum,  Q931Uie_CallingNum);
+	Q931SetIEProc(Q931ie_CALLING_PARTY_SUBADDRESS,         i, Q931Pie_CallingSub,  Q931Uie_CallingSub);
+	Q931SetIEProc(Q931ie_CALLED_PARTY_NUMBER,              i, Q931Pie_CalledNum,   Q931Uie_CalledNum);
+	Q931SetIEProc(Q931ie_CALLED_PARTY_SUBADDRESS,          i, Q931Pie_CalledSub,   Q931Uie_CalledSub);
+	Q931SetIEProc(Q931ie_TRANSIT_NETWORK_SELECTION,        i, Q931Pie_TransNetSel, Q931Uie_TransNetSel);
+	Q931SetIEProc(Q931ie_RESTART_INDICATOR,                i, Q931Pie_RestartInd,  Q931Uie_RestartInd);
+	Q931SetIEProc(Q931ie_LOW_LAYER_COMPATIBILITY,          i, Q931Pie_LLComp,      Q931Uie_LLComp);
+	Q931SetIEProc(Q931ie_HIGH_LAYER_COMPATIBILITY,         i, Q931Pie_HLComp,      Q931Uie_HLComp);
+	Q931SetIEProc(Q931ie_USER_USER,                        i, Q931Pie_UserUser,    Q931Uie_UserUser);
+
+	Q931SetIEProc(Q931ie_CONNECTED_NUMBER,   i, Q931Pie_Generic, Q931Uie_Generic);
+	Q931SetIEProc(Q931ie_FACILITY,           i, Q931Pie_Generic, Q931Uie_Generic);
+	Q931SetIEProc(Q931ie_REDIRECTING_NUMBER, i, Q931Pie_Generic, Q931Uie_Generic);
+
+	/* The following define a state machine. The point is that the Message
+	 * procs can when search this to find out if the message/state
+	 * combination is legale. If not, the proc for unexpected message apply.
+	 */
+
+	/* TODO define state table here */
+
+	/* Timer default values */
+	Q931SetTimerDefault(i, Q931_TIMER_T301, 180000);	/* T301: 180s */
+	Q931SetTimerDefault(i, Q931_TIMER_T302,  15000);	/* T302:  15s */
+	Q931SetTimerDefault(i, Q931_TIMER_T303,   4000);	/* T303:   4s */
+	Q931SetTimerDefault(i, Q931_TIMER_T304,  20000);	/* T304:  20s */
+	Q931SetTimerDefault(i, Q931_TIMER_T305,  30000);	/* T305:  30s */
+	Q931SetTimerDefault(i, Q931_TIMER_T306,  30000);	/* T306:  30s */
+	Q931SetTimerDefault(i, Q931_TIMER_T307, 180000);	/* T307: 180s */
+	Q931SetTimerDefault(i, Q931_TIMER_T308,   4000);	/* T308:   4s */
+	Q931SetTimerDefault(i, Q931_TIMER_T309,  60000);	/* T309:  60s */
+	Q931SetTimerDefault(i, Q931_TIMER_T310,  10000);	/* T310:  10s */
+	Q931SetTimerDefault(i, Q931_TIMER_T312,  12000);	/* T312:  12s */
+	Q931SetTimerDefault(i, Q931_TIMER_T314,   4000);	/* T314:   4s */
+	Q931SetTimerDefault(i, Q931_TIMER_T316, 120000);	/* T316: 120s */
+	Q931SetTimerDefault(i, Q931_TIMER_T317,  90000);	/* T317:  90s */
+	Q931SetTimerDefault(i, Q931_TIMER_T320,  30000);	/* T320:  30s */
+	Q931SetTimerDefault(i, Q931_TIMER_T321,  30000);	/* T321:  30s */
+	Q931SetTimerDefault(i, Q931_TIMER_T322,   4000);	/* T322:   4s */
+}
+
+/*****************************************************************************
+
+  Function:		Q931ProcAlertingNT
+
+*****************************************************************************/
+L3INT Q931ProcAlertingNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Find the call using CRV */
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	/* Reset 4 sec timer. */
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom == 4) {
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q931ProcCallProceedingNT
+
+*****************************************************************************/
+L3INT Q931ProcCallProceedingNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Find the call using CRV */
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	/* TODO chack against state table for illegal or unexpected message here*/
+
+	/* TODO - Set correct timer here */
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom == 4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q931ProcConnectNT
+
+*****************************************************************************/
+L3INT Q931ProcConnectNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Find the call using CRV */
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	/* TODO chack against state table for illegal or unexpected message here*/
+
+	/* TODO - Set correct timer here */
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom == 4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q931ProcConnectAckNT
+
+*****************************************************************************/
+L3INT Q931ProcConnectAckNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Find the call using CRV */
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	/* TODO chack against state table for illegal or unexpected message here*/
+
+	/* TODO - Set correct timer here */
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom == 4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q931ProcProgressNT
+
+*****************************************************************************/
+L3INT Q931ProcProgressNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Find the call using CRV */
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	/* TODO chack against state table for illegal or unexpected message here*/
+
+	/* TODO - Set correct timer here */
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom == 4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q931ProcSetupNT
+
+  Description:	Process a SETUP message.
+
+ *****************************************************************************/
+L3INT Q931ProcSetupNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Generic *pMes = (Q931mes_Generic *)&buf[Q931L4HeaderSpace];
+	L3INT rc = 0;
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Reject SETUP on existing calls */
+	if (Q931GetCallState(pTrunk, pMes->CRV) != Q931_U0) {
+		Q931Disconnect(pTrunk, iFrom, pMes->CRV, 81);
+		return Q931E_UNEXPECTED_MESSAGE;
+	}
+
+	/* outgoing call */
+	if (iFrom == 4) {
+		ret = Q931CreateCRV(pTrunk, &callIndex);
+		if (ret)
+		        return ret;
+
+		pMes->CRV = pTrunk->call[callIndex].CRV;
+
+		/*
+		 * Outgoing SETUP message will be broadcasted in PTMP mode
+		 */
+		ret = Q931Tx32Data(pTrunk, Q931_IS_PTP(pTrunk) ? 0 : 1, buf, pMes->Size);
+		if (ret)
+	        	return ret;
+
+		Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+		Q931SetState(pTrunk, callIndex, Q931_U1);
+	}
+	/* incoming call */
+	else {
+		/* Locate free CRV entry and store info */
+		ret = Q931AllocateCRV(pTrunk, pMes->CRV, &callIndex);
+		if (ret != Q931E_NO_ERROR) {
+			/* Not possible to allocate CRV entry, so must reject call */
+			Q931Disconnect(pTrunk, iFrom, pMes->CRV, 42);
+			return ret;
+		}
+
+		/* store TEI in call */
+		pTrunk->call[callIndex].Tei = pMes->Tei;
+
+		/* Send setup indication to user */
+		ret = Q931Tx34(pTrunk, (L3UCHAR*)pMes, pMes->Size);
+		if (ret != Q931E_NO_ERROR) {
+			return ret;
+		} else {
+			/* Must be full queue, meaning we can't process the call */
+			/* so we must disconnect */
+			Q931Disconnect(pTrunk, iFrom, pMes->CRV, 81);
+			return ret;
+		}
+#if 0
+		/* TODO: Unreachable code??? */
+		/* Set state U6 */
+		Q931SetState(pTrunk, callIndex, Q931_U6);
+		Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+#endif
+	}
+
+	return rc;
+}
+
+/*****************************************************************************
+
+  Function:		Q931ProcSetupAckNT
+
+  Description:	Used to acknowedge a SETUP. Usually the first initial
+				response recevide back used to buy some time.
+
+				Note that ChanID (B Channel Assignment) might come here from
+				NT side.
+
+*****************************************************************************/
+L3INT Q931ProcSetupAckNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Find the call using CRV */
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	/* TODO chack against state table for illegal or unexpected message here*/
+
+	/* TODO - Set correct timer here */
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom == 4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q931ProcResumeNT
+
+*****************************************************************************/
+L3INT Q931ProcResumeNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Find the call using CRV */
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	/* TODO chack against state table for illegal or unexpected message here */
+
+	/* TODO - Set correct timer here */
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom == 4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q931ProcResumeAckNT
+
+*****************************************************************************/
+L3INT Q931ProcResumeAckNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Find the call using CRV */
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	/* TODO chack against state table for illegal or unexpected message here*/
+
+	/* TODO - Set correct timer here */
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom == 4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q931ProcResumeRejectNT
+
+*****************************************************************************/
+L3INT Q931ProcResumeRejectNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Find the call using CRV */
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	/* TODO chack against state table for illegal or unexpected message here*/
+
+	/* TODO - Set correct timer here */
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom == 4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q931ProcSuspendNT
+
+*****************************************************************************/
+L3INT Q931ProcSuspendNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Find the call using CRV */
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	/* TODO chack against state table for illegal or unexpected message here*/
+
+	/* TODO - Set correct timer here */
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom == 4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q931ProcSuspendAckNT
+
+*****************************************************************************/
+L3INT Q931ProcSuspendAckNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Find the call using CRV */
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	/* TODO chack against state table for illegal or unexpected message here*/
+
+	/* TODO - Set correct timer here */
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom == 4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q931ProcSuspendRejectNT
+
+*****************************************************************************/
+L3INT Q931ProcSuspendRejectNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Find the call using CRV */
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	/* TODO chack against state table for illegal or unexpected message here*/
+
+	/* TODO - Set correct timer here */
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom == 4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q931ProcInformationNT
+
+*****************************************************************************/
+L3INT Q931ProcUserInformationNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Find the call using CRV */
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	/* TODO chack against state table for illegal or unexpected message here*/
+
+	/* TODO - Set correct timer here */
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom == 4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q931ProcDisconnectNT
+
+*****************************************************************************/
+L3INT Q931ProcDisconnectNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Find the call using CRV */
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	/* TODO chack against state table for illegal or unexpected message here*/
+
+	/* TODO - Set correct timer here */
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom == 4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q931ProcReleaseNT
+
+*****************************************************************************/
+L3INT Q931ProcReleaseNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Find the call using CRV */
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	/* TODO chack against state table for illegal or unexpected message here*/
+
+	/* TODO - Set correct timer here */
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom == 4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q931ProcReleaseCompleteNT
+
+*****************************************************************************/
+L3INT Q931ProcReleaseCompleteNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Find the call using CRV */
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	/* TODO chack against state table for illegal or unexpected message here*/
+
+	/* TODO - Set correct timer here */
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom == 4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q931ProcRestartNT
+
+*****************************************************************************/
+L3INT Q931ProcRestartNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Find the call using CRV */
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	/* TODO chack against state table for illegal or unexpected message here*/
+
+	/* TODO - Set correct timer here */
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom == 4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q931ProcRestartAckNT
+
+*****************************************************************************/
+L3INT Q931ProcRestartAckNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Find the call using CRV */
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	/* TODO chack against state table for illegal or unexpected message here*/
+
+	/* TODO - Set correct timer here */
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom == 4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q931ProcCongestionControlNT
+
+*****************************************************************************/
+L3INT Q931ProcCongestionControlNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Find the call using CRV */
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	/* TODO chack against state table for illegal or unexpected message here*/
+
+	/* TODO - Set correct timer here */
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom == 4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q931ProcInformationNT
+
+*****************************************************************************/
+L3INT Q931ProcInformationNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Find the call using CRV */
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	/* TODO chack against state table for illegal or unexpected message here*/
+
+	/* TODO - Set correct timer here */
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom == 4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q931ProcNotifyNT
+
+*****************************************************************************/
+L3INT Q931ProcNotifyNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Find the call using CRV */
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	/* TODO chack against state table for illegal or unexpected message here*/
+
+	/* TODO - Set correct timer here */
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom == 4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q931ProcStatusNT
+
+*****************************************************************************/
+L3INT Q931ProcStatusNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Find the call using CRV */
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	/* TODO chack against state table for illegal or unexpected message here*/
+
+	/* TODO - Set correct timer here */
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom == 4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q931ProcStatusEnquiryNT
+
+*****************************************************************************/
+L3INT Q931ProcStatusEnquiryNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Find the call using CRV */
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	/* TODO chack against state table for illegal or unexpected message here*/
+
+	/* TODO - Set correct timer here */
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom == 4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q931ProcSegmentNT
+
+*****************************************************************************/
+L3INT Q931ProcSegmentNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Find the call using CRV */
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	/* TODO chack against state table for illegal or unexpected message here*/
+
+	/* TODO - Set correct timer here */
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom == 4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+}
+
+/****************************************************************************/
+/******************* Q.932 - Supplementary Services *************************/
+/****************************************************************************/
+
+/*****************************************************************************
+
+  Function:		Q932ProcFacilityNT
+
+*****************************************************************************/
+L3INT Q932ProcFacilityNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Find the call using CRV */
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	/* TODO chack against state table for illegal or unexpected message here*/
+
+	/* TODO - Set correct timer here */
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom == 4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q932ProcHoldNT
+
+*****************************************************************************/
+L3INT Q932ProcHoldNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Find the call using CRV */
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	/* TODO chack against state table for illegal or unexpected message here*/
+
+	/* TODO - Set correct timer here */
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom == 4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q932ProcHoldAckNT
+
+*****************************************************************************/
+L3INT Q932ProcHoldAckNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Find the call using CRV */
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	/* TODO chack against state table for illegal or unexpected message here*/
+
+	/* TODO - Set correct timer here */
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom == 4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q932ProcHoldRejectNT
+
+*****************************************************************************/
+L3INT Q932ProcHoldRejectNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Find the call using CRV */
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	/* TODO chack against state table for illegal or unexpected message here*/
+
+	/* TODO - Set correct timer here */
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom == 4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q932ProcRegisterTE
+
+*****************************************************************************/
+L3INT Q932ProcRegisterNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Find the call using CRV */
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	/* TODO chack against state table for illegal or unexpected message here*/
+
+	/* TODO - Set correct timer here */
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom == 4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q932ProcRetrieveNT
+
+*****************************************************************************/
+L3INT Q932ProcRetrieveNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Find the call using CRV */
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	/* TODO chack against state table for illegal or unexpected message here*/
+
+	/* TODO - Set correct timer here */
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom == 4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q931ProcRetrieveAckNT
+
+*****************************************************************************/
+L3INT Q932ProcRetrieveAckNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Find the call using CRV */
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	/* TODO chack against state table for illegal or unexpected message here*/
+
+	/* TODO - Set correct timer here */
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom == 4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q931ProcRetrieveRejectNT
+
+*****************************************************************************/
+L3INT Q932ProcRetrieveRejectNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Find the call using CRV */
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	/* TODO chack against state table for illegal or unexpected message here*/
+
+	/* TODO - Set correct timer here */
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom == 4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+}

Added: freeswitch/trunk/libs/freetdm/src/isdn/Q931StateTE.c (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/isdn/Q931StateTE.c	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/isdn/Q931StateTE.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,1310 @@
+/*****************************************************************************
+
+  FileName:		q931StateTE.c
+
+  Contents:		Q.931 State Engine for TE (User Mode).
+
+			The controlling state engine for Q.931 is the state engine
+			on the NT side. The state engine on the TE side is a slave 
+			of this. The TE side maintain it's own states as described in
+			ITU-T Q931, but will in	raise conditions be overridden by 
+			the NT side.
+
+			This reference implementation uses a process per message,
+			meaning that each message must check call states. This
+			is easier for dialect maintenance as each message proc
+			can be replaced individually. A new TE variant only
+			need to copy the Q931CreateTE and replace those procs or
+			need to override.
+
+  License/Copyright:
+
+  Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+  email:janvb@caselaboratories.com  
+
+  Redistribution and use in source and binary forms, with or without 
+  modification, are permitted provided that the following conditions are 
+  met:
+
+	* Redistributions of source code must retain the above copyright notice, 
+	  this list of conditions and the following disclaimer.
+	* Redistributions in binary form must reproduce the above copyright notice, 
+	  this list of conditions and the following disclaimer in the documentation 
+	  and/or other materials provided with the distribution.
+	* Neither the name of the Case Labs, Ltd nor the names of its contributors 
+	  may be used to endorse or promote products derived from this software 
+	  without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
+  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
+  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+  POSSIBILITY OF SUCH DAMAGE.
+*****************************************************************************/
+
+#include "Q931.h"
+
+extern L3INT Q931L4HeaderSpace;
+
+/*****************************************************************************
+  Function:		Q931CreateTE
+
+  Description:	Will create the Q931 TE as a Dialect in the stack. The first
+				bulk set up the message handlers, the second bulk the IE
+				encoders/coders, and the last bulk set up the state table.
+
+  Parameters:	i		Dialect index
+*****************************************************************************/
+void Q931CreateTE(L3UCHAR i)
+{
+	Q931SetMesProc(Q931mes_ALERTING,             i, Q931ProcAlertingTE,          Q931Umes_Alerting,          Q931Pmes_Alerting);
+	Q931SetMesProc(Q931mes_CALL_PROCEEDING,      i, Q931ProcCallProceedingTE,    Q931Umes_CallProceeding,    Q931Pmes_CallProceeding);
+	Q931SetMesProc(Q931mes_CONNECT,              i, Q931ProcConnectTE,           Q931Umes_Connect,           Q931Pmes_Connect);
+	Q931SetMesProc(Q931mes_CONNECT_ACKNOWLEDGE,  i, Q931ProcConnectAckTE,        Q931Umes_ConnectAck,        Q931Pmes_ConnectAck);
+	Q931SetMesProc(Q931mes_PROGRESS,             i, Q931ProcProgressTE,          Q931Umes_Progress,          Q931Pmes_Progress);
+	Q931SetMesProc(Q931mes_SETUP,                i, Q931ProcSetupTE,             Q931Umes_Setup,             Q931Pmes_Setup);
+	Q931SetMesProc(Q931mes_SETUP_ACKNOWLEDGE,    i, Q931ProcSetupAckTE,          Q931Umes_SetupAck,          Q931Pmes_SetupAck);
+	Q931SetMesProc(Q931mes_RESUME,               i, Q931ProcResumeTE,            Q931Umes_Resume,            Q931Pmes_Resume);
+	Q931SetMesProc(Q931mes_RESUME_ACKNOWLEDGE,   i, Q931ProcResumeAckTE,         Q931Umes_ResumeAck,         Q931Pmes_ResumeAck);
+	Q931SetMesProc(Q931mes_RESUME_REJECT,        i, Q931ProcResumeRejectTE,      Q931Umes_ResumeReject,      Q931Pmes_ResumeReject);
+	Q931SetMesProc(Q931mes_SUSPEND,              i, Q931ProcSuspendTE,           Q931Umes_Suspend,           Q931Pmes_Suspend);
+	Q931SetMesProc(Q931mes_SUSPEND_ACKNOWLEDGE,  i, Q931ProcSuspendAckTE,        Q931Umes_SuspendAck,        Q931Pmes_SuspendAck);
+	Q931SetMesProc(Q931mes_SUSPEND_REJECT,       i, Q931ProcSuspendRejectTE,     Q931Umes_SuspendReject,     Q931Pmes_SuspendReject);
+	Q931SetMesProc(Q931mes_USER_INFORMATION,     i, Q931ProcUserInformationTE,   Q931Umes_UserInformation,   Q931Pmes_UserInformation);
+	Q931SetMesProc(Q931mes_DISCONNECT,           i, Q931ProcDisconnectTE,        Q931Umes_Disconnect,        Q931Pmes_Disconnect);
+	Q931SetMesProc(Q931mes_RELEASE,              i, Q931ProcReleaseTE,           Q931Umes_Release,           Q931Pmes_Release);
+	Q931SetMesProc(Q931mes_RELEASE_COMPLETE,     i, Q931ProcReleaseCompleteTE,   Q931Umes_ReleaseComplete,   Q931Pmes_ReleaseComplete);
+	Q931SetMesProc(Q931mes_RESTART,              i, Q931ProcRestartTE,           Q931Umes_Restart,           Q931Pmes_Restart);
+	Q931SetMesProc(Q931mes_RESTART_ACKNOWLEDGE,  i, Q931ProcRestartAckTE,        Q931Umes_RestartAck,        Q931Pmes_RestartAck);
+	Q931SetMesProc(Q931mes_CONGESTION_CONTROL,   i, Q931ProcCongestionControlTE, Q931Umes_CongestionControl, Q931Pmes_CongestionControl);
+	Q931SetMesProc(Q931mes_INFORMATION,          i, Q931ProcInformationTE,       Q931Umes_Information,       Q931Pmes_Information);
+	Q931SetMesProc(Q931mes_NOTIFY,               i, Q931ProcNotifyTE,            Q931Umes_Notify,            Q931Pmes_Notify);
+	Q931SetMesProc(Q931mes_STATUS,               i, Q931ProcStatusTE,            Q931Umes_Status,            Q931Pmes_Status);
+	Q931SetMesProc(Q931mes_STATUS_ENQUIRY,       i, Q931ProcStatusEnquiryTE,     Q931Umes_StatusEnquiry,     Q931Pmes_StatusEnquiry);
+	Q931SetMesProc(Q931mes_SEGMENT,              i, Q931ProcSegmentTE,           Q931Umes_Segment,           Q931Pmes_Segment);
+
+	Q931SetMesProc(Q932mes_FACILITY,             i, Q932ProcFacilityTE,          Q932Umes_Facility,          Q932Pmes_Facility);
+	Q931SetMesProc(Q932mes_HOLD,                 i, Q932ProcHoldTE,              Q932Umes_Hold,              Q932Pmes_Hold);
+	Q931SetMesProc(Q932mes_HOLD_ACKNOWLEDGE,     i, Q932ProcHoldAckTE,           Q932Umes_HoldAck,           Q932Pmes_HoldAck);
+	Q931SetMesProc(Q932mes_HOLD_REJECT,          i, Q932ProcHoldRejectTE,        Q932Umes_HoldReject,        Q932Pmes_HoldReject);
+	Q931SetMesProc(Q932mes_REGISTER,             i, Q932ProcRegisterTE,          Q932Umes_Register,          Q932Pmes_Register);
+	Q931SetMesProc(Q932mes_RETRIEVE,             i, Q932ProcRetrieveTE,          Q932Umes_Retrieve,          Q932Pmes_Retrieve);
+	Q931SetMesProc(Q932mes_RETRIEVE_ACKNOWLEDGE, i, Q932ProcRetrieveAckTE,       Q932Umes_RetrieveAck,       Q932Pmes_RetrieveAck);
+	Q931SetMesProc(Q932mes_RETRIEVE_REJECT,      i, Q932ProcRetrieveRejectTE,    Q932Umes_RetrieveReject,    Q932Pmes_RetrieveReject);
+
+	/* Set up the IE encoder/decoder handle table.*/ 
+	Q931SetIEProc(Q931ie_SEGMENTED_MESSAGE,                i, Q931Pie_Segment,     Q931Uie_Segment);
+	Q931SetIEProc(Q931ie_BEARER_CAPABILITY,                i, Q931Pie_BearerCap,   Q931Uie_BearerCap);
+	Q931SetIEProc(Q931ie_CAUSE,                            i, Q931Pie_Cause,       Q931Uie_Cause);
+	Q931SetIEProc(Q931ie_CALL_IDENTITY,                    i, Q931Pie_CallID,      Q931Uie_CallID);
+	Q931SetIEProc(Q931ie_CALL_STATE,                       i, Q931Pie_CallState,   Q931Uie_CallState);
+	Q931SetIEProc(Q931ie_CHANNEL_IDENTIFICATION,           i, Q931Pie_ChanID,      Q931Uie_ChanID);
+	Q931SetIEProc(Q931ie_PROGRESS_INDICATOR,               i, Q931Pie_ProgInd,     Q931Uie_ProgInd);
+	Q931SetIEProc(Q931ie_NETWORK_SPECIFIC_FACILITIES,      i, Q931Pie_NetFac,      Q931Uie_NetFac);
+	Q931SetIEProc(Q931ie_NOTIFICATION_INDICATOR,           i, Q931Pie_NotifInd,    Q931Uie_NotifInd);
+	Q931SetIEProc(Q931ie_DISPLAY,                          i, Q931Pie_Display,     Q931Uie_Display);
+	Q931SetIEProc(Q931ie_DATETIME,                         i, Q931Pie_DateTime,    Q931Uie_DateTime);
+	Q931SetIEProc(Q931ie_KEYPAD_FACILITY,                  i, Q931Pie_KeypadFac,   Q931Uie_KeypadFac);
+	Q931SetIEProc(Q931ie_SIGNAL,                           i, Q931Pie_Signal,      Q931Uie_Signal);
+	Q931SetIEProc(Q931ie_TRANSIT_DELAY_SELECTION_AND_IND,  i, Q931Pie_TransNetSel, Q931Uie_TransNetSel);
+	Q931SetIEProc(Q931ie_CALLING_PARTY_NUMBER,             i, Q931Pie_CallingNum,  Q931Uie_CallingNum);
+	Q931SetIEProc(Q931ie_CALLING_PARTY_SUBADDRESS,         i, Q931Pie_CallingSub,  Q931Uie_CallingSub);
+	Q931SetIEProc(Q931ie_CALLED_PARTY_NUMBER,              i, Q931Pie_CalledNum,   Q931Uie_CalledNum);
+	Q931SetIEProc(Q931ie_CALLED_PARTY_SUBADDRESS,          i, Q931Pie_CalledSub,   Q931Uie_CalledSub);
+	Q931SetIEProc(Q931ie_TRANSIT_NETWORK_SELECTION,        i, Q931Pie_TransNetSel, Q931Uie_TransNetSel);
+	Q931SetIEProc(Q931ie_RESTART_INDICATOR,                i, Q931Pie_RestartInd,  Q931Uie_RestartInd);
+	Q931SetIEProc(Q931ie_LOW_LAYER_COMPATIBILITY,          i, Q931Pie_LLComp,      Q931Uie_LLComp);
+	Q931SetIEProc(Q931ie_HIGH_LAYER_COMPATIBILITY,         i, Q931Pie_HLComp,      Q931Uie_HLComp);
+	Q931SetIEProc(Q931ie_USER_USER,                        i, Q931Pie_UserUser,    Q931Uie_UserUser);
+
+	Q931SetIEProc(Q931ie_CONNECTED_NUMBER,   i, Q931Pie_Generic, Q931Uie_Generic);
+	Q931SetIEProc(Q931ie_FACILITY,           i, Q931Pie_Generic, Q931Uie_Generic);
+	Q931SetIEProc(Q931ie_REDIRECTING_NUMBER, i, Q931Pie_Generic, Q931Uie_Generic);
+
+	/* The following define a state machine. The point is that the Message
+	 * procs can when search this to find out if the message/state
+	 * combination is legale. If not, the proc for unexpected message apply.
+	 */
+
+	/* State 0 Idle */
+	Q931AddStateEntry(i, Q931_U0, Q931mes_RESUME,           2);
+	Q931AddStateEntry(i, Q931_U0, Q931mes_SETUP,            4);
+	Q931AddStateEntry(i, Q931_U0, Q931mes_SETUP,            2);
+	Q931AddStateEntry(i, Q931_U0, Q931mes_STATUS,           4);
+	Q931AddStateEntry(i, Q931_U0, Q931mes_RELEASE,          4);
+	Q931AddStateEntry(i, Q931_U0, Q931mes_RELEASE_COMPLETE, 4);
+
+	/* State 1 Call Initiating */
+	Q931AddStateEntry(i, Q931_U1, Q931mes_DISCONNECT,        2);
+	Q931AddStateEntry(i, Q931_U1, Q931mes_SETUP_ACKNOWLEDGE, 4);
+	Q931AddStateEntry(i, Q931_U1, Q931mes_RELEASE_COMPLETE,  4);
+	Q931AddStateEntry(i, Q931_U1, Q931mes_CALL_PROCEEDING,   4);
+	Q931AddStateEntry(i, Q931_U1, Q931mes_ALERTING,          4);
+	Q931AddStateEntry(i, Q931_U1, Q931mes_CONNECT,           4);
+
+	/* State 2 Overlap Sending */
+	Q931AddStateEntry(i, Q931_U2, Q931mes_INFORMATION,     2);
+	Q931AddStateEntry(i, Q931_U2, Q931mes_CALL_PROCEEDING, 4);
+	Q931AddStateEntry(i, Q931_U2, Q931mes_ALERTING,        4);
+	Q931AddStateEntry(i, Q931_U2, Q931mes_PROGRESS,        4);
+	Q931AddStateEntry(i, Q931_U2, Q931mes_CONNECT,         4);
+	Q931AddStateEntry(i, Q931_U2, Q931mes_RELEASE,         2);
+
+	/* State 3 Outgoing Call Proceeding */
+	Q931AddStateEntry(i, Q931_U3, Q931mes_PROGRESS, 4);
+	Q931AddStateEntry(i, Q931_U3, Q931mes_ALERTING, 4);
+	Q931AddStateEntry(i, Q931_U3, Q931mes_CONNECT,  4);
+	Q931AddStateEntry(i, Q931_U3, Q931mes_RELEASE,  2);
+
+	/* State 4 Call Delivered */
+	Q931AddStateEntry(i, Q931_U4, Q931mes_CONNECT, 4);
+
+	/* State 6 Call Precent */
+	Q931AddStateEntry(i, Q931_U6, Q931mes_INFORMATION,      2);
+	Q931AddStateEntry(i, Q931_U6, Q931mes_ALERTING,         2);
+	Q931AddStateEntry(i, Q931_U6, Q931mes_CALL_PROCEEDING,  2);
+	Q931AddStateEntry(i, Q931_U6, Q931mes_CONNECT,          2);
+	Q931AddStateEntry(i, Q931_U6, Q931mes_RELEASE_COMPLETE, 2);
+	Q931AddStateEntry(i, Q931_U6, Q931mes_RELEASE,          4);
+	Q931AddStateEntry(i, Q931_U6, Q931mes_DISCONNECT,       4);
+
+	/* State 7 Call Received */
+	Q931AddStateEntry(i, Q931_U7, Q931mes_CONNECT, 2);
+
+	/* State 8 Connect request */
+	Q931AddStateEntry(i, Q931_U8, Q931mes_CONNECT_ACKNOWLEDGE, 4);
+
+	/* State 9 Incoming Call Proceeding */
+	Q931AddStateEntry(i, Q931_U9, Q931mes_CONNECT,  2);
+	Q931AddStateEntry(i, Q931_U9, Q931mes_ALERTING, 2);
+	Q931AddStateEntry(i, Q931_U9, Q931mes_PROGRESS, 2);
+
+	/* State 10 Active */
+	Q931AddStateEntry(i, Q931_U10, Q931mes_SUSPEND, 2);
+	Q931AddStateEntry(i, Q931_U10, Q931mes_NOTIFY,  4);
+	Q931AddStateEntry(i, Q931_U10, Q931mes_NOTIFY,  2);
+
+	/* State 11 Disconnect Request */
+	Q931AddStateEntry(i, Q931_U11, Q931mes_RELEASE,    4);
+	Q931AddStateEntry(i, Q931_U11, Q931mes_DISCONNECT, 4);
+	Q931AddStateEntry(i, Q931_U11, Q931mes_NOTIFY,     4);
+
+	/* State 12 Disconnect Ind */
+	Q931AddStateEntry(i, Q931_U12, Q931mes_RELEASE, 4);
+	Q931AddStateEntry(i, Q931_U12, Q931mes_RELEASE, 2);
+
+	/* State 15 Suspend Request */
+	Q931AddStateEntry(i, Q931_U15, Q931mes_SUSPEND_ACKNOWLEDGE, 4);
+	Q931AddStateEntry(i, Q931_U15, Q931mes_SUSPEND_REJECT,      4);
+	Q931AddStateEntry(i, Q931_U15, Q931mes_DISCONNECT,          4);
+	Q931AddStateEntry(i, Q931_U15, Q931mes_RELEASE,             4);
+
+/* TODO
+	Q931AddStateEntry(i, Q931_U17,
+	Q931AddStateEntry(i, Q931_U19,
+	Q931AddStateEntry(i, Q931_U25,
+*/
+
+	/* Timer default values */
+	Q931SetTimerDefault(i, Q931_TIMER_T301, 180000);	/* T301: 180s */
+	Q931SetTimerDefault(i, Q931_TIMER_T302,  15000);	/* T302:  15s */
+	Q931SetTimerDefault(i, Q931_TIMER_T303,   4000);	/* T303:   4s */
+	Q931SetTimerDefault(i, Q931_TIMER_T304,  30000);	/* T304:  30s */
+	Q931SetTimerDefault(i, Q931_TIMER_T305,  30000);	/* T305:  30s */
+	Q931SetTimerDefault(i, Q931_TIMER_T308,   4000);	/* T308:   4s */
+	Q931SetTimerDefault(i, Q931_TIMER_T309,  60000);	/* T309:  60s */
+	Q931SetTimerDefault(i, Q931_TIMER_T310,  60000);	/* T310:  60s */
+	Q931SetTimerDefault(i, Q931_TIMER_T313,   4000);	/* T313:   4s */
+	Q931SetTimerDefault(i, Q931_TIMER_T314,   4000);	/* T314:   4s */
+	Q931SetTimerDefault(i, Q931_TIMER_T316, 120000);	/* T316: 120s */
+	Q931SetTimerDefault(i, Q931_TIMER_T317,  90000);	/* T317:  90s */
+	Q931SetTimerDefault(i, Q931_TIMER_T318,   4000);	/* T318:   4s */
+	Q931SetTimerDefault(i, Q931_TIMER_T319,   4000);	/* T319:   4s */
+	Q931SetTimerDefault(i, Q931_TIMER_T321,  30000);	/* T321:  30s */
+	Q931SetTimerDefault(i, Q931_TIMER_T322,   4000);	/* T322:   4s */
+}
+
+/*****************************************************************************
+
+  Function:		Q931ProcAlertingTE
+
+*****************************************************************************/
+L3INT Q931ProcAlertingTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Find the call using CRV */
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	/* Reset 4 sec timer. */
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom == 4) {
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q931ProcCallProceedingTE
+
+*****************************************************************************/
+L3INT Q931ProcCallProceedingTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Find the call using CRV */
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	/* TODO chack against state table for illegal or unexpected message here */
+
+	/* TODO - Set correct timer here */
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom == 4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q931ProcConnectTE
+
+*****************************************************************************/
+L3INT Q931ProcConnectTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Find the call using CRV */
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	/* TODO chack against state table for illegal or unexpected message here */
+
+	/* TODO - Set correct timer here */
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom ==4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+		if (pTrunk->autoConnectAck) {
+			Q931AckConnect(pTrunk, buf);
+		}
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q931ProcConnectAckTE
+
+*****************************************************************************/
+L3INT Q931ProcConnectAckTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Find the call using CRV */
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	/* TODO chack against state table for illegal or unexpected message here */
+
+	/* TODO - Set correct timer here */
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom ==4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q931ProcProgressTE
+
+*****************************************************************************/
+L3INT Q931ProcProgressTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Find the call using CRV */
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	/* TODO chack against state table for illegal or unexpected message here */
+
+	/* TODO - Set correct timer here */
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom ==4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q931ProcSetupTE
+
+*****************************************************************************/
+L3INT Q931ProcSetupTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Generic *pMes = (Q931mes_Generic *)&buf[Q931L4HeaderSpace];
+	L3INT rc = 0;
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Reject SETUP on existing calls */
+	if (Q931GetCallState(pTrunk, pMes->CRV) != Q931_U0) {
+		Q931Disconnect(pTrunk, iFrom, pMes->CRV, 81);
+		return Q931E_UNEXPECTED_MESSAGE;
+	}
+
+	/* outgoing call */
+	if (iFrom == 4) {
+		ret = Q931CreateCRV(pTrunk, &callIndex);
+		if (ret)
+			return ret;
+		pMes->CRV = pTrunk->call[callIndex].CRV;
+
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+		if (ret)
+			return ret;
+
+		Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+
+		/* TODO: Add this back when we get the state stuff more filled out */
+		/*Q931SetState(pTrunk, callIndex, Q931_U1);*/
+	}
+	/* incoming call */
+	else {
+		/* Locate free CRV entry and store info */
+		ret = Q931AllocateCRV(pTrunk, pMes->CRV, &callIndex);
+		if (ret != Q931E_NO_ERROR) {
+			/* Not possible to allocate CRV entry, so must reject call */
+			Q931Disconnect(pTrunk, iFrom, pMes->CRV, 42);
+			return ret;
+		}
+
+		/* Send setup indication to user */
+		ret = Q931Tx34(pTrunk, (L3UCHAR*)pMes, pMes->Size);
+		if (ret != Q931E_NO_ERROR) {
+			if (pTrunk->autoSetupAck) {
+				Q931AckSetup(pTrunk, buf);
+			}
+			return ret;
+		} else {
+			/* Must be full queue, meaning we can't process the call */
+			/* so we must disconnect */
+			Q931Disconnect(pTrunk, iFrom, pMes->CRV, 81);
+			 return ret;
+		}
+#if 0
+		/* TODO: Unreachable code??? */
+		/* Set state U6 */
+		Q931SetState(pTrunk, callIndex, Q931_U6);
+
+		Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+#endif
+	}
+	return rc;
+}
+
+/*****************************************************************************
+
+  Function:		Q931ProcSetupAckTE
+
+  Description:	Used to acknowedge a SETUP. Usually the first initial
+				response recevide back used to buy some time. L4 sending this
+				should only be passed on. L2 sending this means that we set
+				a new timer (and pass it to L4).
+
+				Note that ChanID (B Channel Assignment) might come here from
+				NT side.
+
+*****************************************************************************/
+L3INT Q931ProcSetupAckTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom ==4) {
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q931ProcResumeTE
+
+*****************************************************************************/
+L3INT Q931ProcResumeTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Generic * pMes = (Q931mes_Generic *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	if (Q931GetCallState(pTrunk, pMes->CRV) == Q931_U0 && iFrom ==4) {
+		/* Call reference selection */
+		ret = Q931CreateCRV(pTrunk, &callIndex);
+		if (ret != Q931E_NO_ERROR)
+			return ret;
+		pMes->CRV = pTrunk->call[callIndex].CRV;
+
+		/* Send RESUME to network */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+		if (ret != Q931E_NO_ERROR)
+			return ret;
+
+		/* Start timer T318 */
+		Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T318);
+
+		/* set state U17 */
+		Q931SetState(pTrunk, callIndex, Q931_U17);
+	} else {
+		return Q931E_ILLEGAL_MESSAGE;
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q931ProcResumeAckTE
+
+*****************************************************************************/
+L3INT Q931ProcResumeAckTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Find the call using CRV */
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	/* TODO chack against state table for illegal or unexpected message here */
+
+	/* TODO - Set correct timer here */
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom ==4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q931ProcResumeRejectTE
+
+*****************************************************************************/
+L3INT Q931ProcResumeRejectTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Find the call using CRV */
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	/* TODO chack against state table for illegal or unexpected message here */
+
+	/* TODO - Set correct timer here */
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom ==4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q931ProcSuspendTE
+
+*****************************************************************************/
+L3INT Q931ProcSuspendTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Find the call using CRV */
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	/* TODO chack against state table for illegal or unexpected message here */
+
+	/* TODO - Set correct timer here */
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom ==4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q931ProcSuspendAckTE
+
+*****************************************************************************/
+L3INT Q931ProcSuspendAckTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Find the call using CRV */
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	/* TODO chack against state table for illegal or unexpected message here */
+
+	/* TODO - Set correct timer here */
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom ==4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q931ProcSuspendRejectTE
+
+*****************************************************************************/
+L3INT Q931ProcSuspendRejectTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Find the call using CRV */
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	/* TODO chack against state table for illegal or unexpected message here */
+
+	/* TODO - Set correct timer here */
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom ==4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q931ProcInformationTE
+
+*****************************************************************************/
+L3INT Q931ProcUserInformationTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Find the call using CRV */
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	/* TODO chack against state table for illegal or unexpected message here */
+
+	/* TODO - Set correct timer here */
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom ==4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q931ProcDisconnectTE
+
+*****************************************************************************/
+L3INT Q931ProcDisconnectTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	Q931Log(pTrunk, Q931_LOG_DEBUG, "Processing DISCONNECT message from %s for CRV: %d (%#hx)\n",
+						 iFrom == 4 ? "Local" : "Remote", pMes->CRV, pMes->CRV);
+
+	/* Find the call using CRV */
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	/* TODO chack against state table for illegal or unexpected message here */
+
+	/* TODO - Set correct timer here */
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom ==4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q931ProcReleaseTE
+
+*****************************************************************************/
+L3INT Q931ProcReleaseTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Generic *pMes = (Q931mes_Generic *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT state = Q931GetCallState(pTrunk, pMes->CRV);
+	L3INT ret = Q931E_NO_ERROR;
+
+	if (iFrom == 4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (state == Q931_U0 && iFrom == 2) {
+		Q931Tx34(pTrunk, buf, pMes->Size);
+		ret = Q931ReleaseComplete(pTrunk, buf);
+	} else {
+		ret = Q931ProcUnexpectedMessage(pTrunk, buf, iFrom);
+	}
+	if (pMes->CRV && iFrom == 2) {
+		/* Find the call using CRV */
+		if ((Q931FindCRV(pTrunk, pMes->CRV, &callIndex)) != Q931E_NO_ERROR)
+			return ret;
+		pTrunk->call[callIndex].InUse = 0;
+	}
+
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q931ProcReleaseCompleteTE
+
+*****************************************************************************/
+L3INT Q931ProcReleaseCompleteTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Generic *pMes = (Q931mes_Generic *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	} else {
+		if (pMes->CRV) {
+			/* Find the call using CRV */
+			ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+			if (ret != Q931E_NO_ERROR)
+				return ret;
+			pTrunk->call[callIndex].InUse = 0;
+
+			/* TODO: experimental, send RELEASE_COMPLETE message */
+		        ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+		}
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q931ProcRestartTE
+
+*****************************************************************************/
+L3INT Q931ProcRestartTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	if (pMes->CRV) {
+		/* Find the call using CRV */
+		ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+		if (ret != Q931E_NO_ERROR)
+			return ret;
+
+		/* TODO - Set correct timer here */
+		Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	}
+
+	/* TODO chack against state table for illegal or unexpected message here */
+
+	if (iFrom ==4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+
+		if (pTrunk->autoRestartAck) {
+			Q931AckRestart(pTrunk, buf);
+		}
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q931ProcRestartAckTE
+
+*****************************************************************************/
+L3INT Q931ProcRestartAckTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	if (pMes->CRV) {
+		/* Find the call using CRV */
+		ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+		if (ret != Q931E_NO_ERROR)
+			return ret;
+		/* TODO - Set correct timer here */
+		Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	}
+
+	/* TODO chack against state table for illegal or unexpected message here */
+
+	if (iFrom ==4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q931ProcCongestionControlTE
+
+*****************************************************************************/
+L3INT Q931ProcCongestionControlTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Find the call using CRV */
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	/* TODO chack against state table for illegal or unexpected message here */
+
+	/* TODO - Set correct timer here */
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom ==4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q931ProcInformationTE
+
+*****************************************************************************/
+L3INT Q931ProcInformationTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Find the call using CRV */
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	/* TODO chack against state table for illegal or unexpected message here */
+
+	/* TODO - Set correct timer here */
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom ==4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q931ProcNotifyTE
+
+*****************************************************************************/
+L3INT Q931ProcNotifyTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Find the call using CRV */
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	/* TODO chack against state table for illegal or unexpected message here */
+
+	/* TODO - Set correct timer here */
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom ==4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q931ProcStatusTE
+
+*****************************************************************************/
+L3INT Q931ProcStatusTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Find the call using CRV */
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	/* TODO chack against state table for illegal or unexpected message here */
+
+	/* TODO - Set correct timer here */
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom ==4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q931ProcStatusEnquiryTE
+
+*****************************************************************************/
+L3INT Q931ProcStatusEnquiryTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Find the call using CRV */
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	/* TODO chack against state table for illegal or unexpected message here */
+
+	/* TODO - Set correct timer here */
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom ==4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q931ProcSegmentTE
+
+*****************************************************************************/
+L3INT Q931ProcSegmentTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Find the call using CRV */
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	/* TODO chack against state table for illegal or unexpected message here */
+
+	/* TODO - Set correct timer here */
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom ==4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+}
+
+/****************************************************************************/
+/******************* Q.932 - Supplementary Services *************************/
+/****************************************************************************/
+
+/*****************************************************************************
+
+  Function:		Q932ProcRetrieveTE
+
+*****************************************************************************/
+L3INT Q932ProcFacilityTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Find the call using CRV */
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	/* TODO chack against state table for illegal or unexpected message here */
+
+	/* TODO - Set correct timer here */
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom ==4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q932ProcRetrieveTE
+
+*****************************************************************************/
+L3INT Q932ProcHoldTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Find the call using CRV */
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	/* TODO chack against state table for illegal or unexpected message here */
+
+	/* TODO - Set correct timer here */
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom ==4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q932ProcRetrieveTE
+
+*****************************************************************************/
+L3INT Q932ProcHoldAckTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Find the call using CRV */
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	/* TODO chack against state table for illegal or unexpected message here */
+
+	/* TODO - Set correct timer here */
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom ==4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q932ProcRetrieveTE
+
+*****************************************************************************/
+L3INT Q932ProcHoldRejectTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Find the call using CRV */
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	/* TODO chack against state table for illegal or unexpected message here */
+
+	/* TODO - Set correct timer here */
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom ==4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q932ProcRegisterTE
+
+*****************************************************************************/
+L3INT Q932ProcRegisterTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Find the call using CRV */
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	/* TODO chack against state table for illegal or unexpected message here */
+
+	/* TODO - Set correct timer here */
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom ==4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q932ProcRetrieveTE
+
+*****************************************************************************/
+L3INT Q932ProcRetrieveTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Find the call using CRV */
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	/* TODO chack against state table for illegal or unexpected message here */
+
+	/* TODO - Set correct timer here */
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom ==4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q931ProcRetrieveAckTE
+
+*****************************************************************************/
+L3INT Q932ProcRetrieveAckTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Find the call using CRV */
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	/* TODO chack against state table for illegal or unexpected message here */
+
+	/* TODO - Set correct timer here */
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom ==4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q931ProcRetrieveRejectTE
+
+*****************************************************************************/
+L3INT Q932ProcRetrieveRejectTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Find the call using CRV */
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	/* TODO chack against state table for illegal or unexpected message here */
+
+	/* TODO - Set correct timer here */
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom ==4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+}

Added: freeswitch/trunk/libs/freetdm/src/isdn/Q931api.c (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/isdn/Q931api.c	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/isdn/Q931api.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,598 @@
+/*****************************************************************************
+
+  FileName:		Q931api.c
+
+  Contents:		api (Application Programming Interface) functions.
+				See	q931.h for description. 
+
+  License/Copyright:
+
+  Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+  email:janvb@caselaboratories.com  
+
+  Redistribution and use in source and binary forms, with or without 
+  modification, are permitted provided that the following conditions are 
+  met:
+
+    * Redistributions of source code must retain the above copyright notice, 
+	  this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright notice, 
+	  this list of conditions and the following disclaimer in the documentation 
+	  and/or other materials provided with the distribution.
+    * Neither the name of the Case Labs, Ltd nor the names of its contributors 
+	  may be used to endorse or promote products derived from this software 
+	  without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
+  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
+  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+  POSSIBILITY OF SUCH DAMAGE.
+*****************************************************************************/
+
+#include "Q931.h"
+#include "memory.h"
+
+extern L3INT Q931L4HeaderSpace;
+
+/*
+L3INT Q931CreateMesIndex(L3INT mc)
+{
+    if(mc < 0 || mc > 127 )
+        return Q931E_INTERNAL;
+
+    if(Q931MesCount >127)
+        return Q931E_INTERNAL;
+
+    Q931MesIndex[mc] = Q931MesCount ++;
+
+    return Q931E_NO_ERROR;
+}
+*/
+/*
+L3INT Q931CreateIEIndex(L3INT iec)
+{
+    if(iec < 0 || iec > 127 )
+        return Q931E_INTERNAL;
+
+    if(Q931IECount > 127)
+        return Q931E_INTERNAL;
+
+    Q931IEIndex[iec] = Q931IECount ++;
+
+    return Q931E_NO_ERROR;
+}
+*/
+
+L3INT Q931Api_InitTrunk(Q931_TrunkInfo_t *pTrunk,
+						Q931Dialect_t Dialect,
+						Q931NetUser_t NetUser,
+						Q931_TrunkType_t TrunkType,
+						Q931Tx34CB_t Q931Tx34CBProc,
+						Q931Tx32CB_t Q931Tx32CBProc,
+						Q931ErrorCB_t Q931ErrorCBProc,
+						void *PrivateData32,
+						void *PrivateData34)
+{
+	int y, dchannel, maxchans, has_sync = 0;
+
+	switch(TrunkType)
+	{
+	case Q931_TrType_E1:
+		dchannel = 16;
+		maxchans = 31;
+		has_sync = 1;
+		break;
+
+	case Q931_TrType_T1:
+	case Q931_TrType_J1:
+		dchannel = 24;
+		maxchans = 24;
+		break;
+
+	case Q931_TrType_BRI:
+	case Q931_TrType_BRI_PTMP:
+		dchannel = 3;
+		maxchans = 3;
+		break;
+
+	default:
+		return 0;
+	}
+
+	pTrunk->Q931Tx34CBProc = Q931Tx34CBProc;
+	pTrunk->Q931Tx32CBProc = Q931Tx32CBProc;
+	pTrunk->Q931ErrorCBProc = Q931ErrorCBProc;
+	pTrunk->PrivateData32 = PrivateData32;
+	pTrunk->PrivateData34 = PrivateData34;
+
+    pTrunk->LastCRV			= 0;
+    pTrunk->Dialect			= Dialect + NetUser;       
+    pTrunk->Enabled			= 0;
+    pTrunk->TrunkType		= TrunkType;
+    pTrunk->NetUser			= NetUser;
+    pTrunk->TrunkState		= 0;
+	pTrunk->autoRestartAck	= 0;
+    for(y=0; y < Q931MAXCHPERTRUNK; y++)
+    {
+        pTrunk->ch[y].Available = 1;
+
+        if(has_sync && y == 0)
+        {
+            pTrunk->ch[y].ChanType = Q931_ChType_Sync;
+        }
+        else if(y == dchannel)
+        {
+            pTrunk->ch[y].ChanType = Q931_ChType_D;
+        }
+        else if(y > maxchans)
+        {
+            pTrunk->ch[y].ChanType = Q931_ChType_NotUsed;
+        }
+        else
+        {
+			pTrunk->ch[y].ChanType = Q931_ChType_B;
+        }
+    }
+
+    for(y=0; y < Q931MAXCALLPERTRUNK; y++)
+    {
+        pTrunk->call[y].InUse = 0;
+
+    }
+	return 1;
+}
+
+void Q931SetMesProc(L3UCHAR mes, L3UCHAR dialect, q931proc_func_t *Q931ProcFunc, q931umes_func_t *Q931UmesFunc, q931pmes_func_t *Q931PmesFunc)
+{
+    if(Q931ProcFunc != NULL)
+        Q931Proc[dialect][mes] = Q931ProcFunc;
+    if(Q931UmesFunc != NULL)
+        Q931Umes[dialect][mes] = Q931UmesFunc;
+    if(Q931PmesFunc != NULL)
+        Q931Pmes[dialect][mes] = Q931PmesFunc;
+}
+
+void Q931SetIEProc(L3UCHAR iec, L3UCHAR dialect, q931pie_func_t *Q931PieProc, q931uie_func_t *Q931UieProc)
+{
+    if(Q931PieProc != NULL)
+        Q931Pie[dialect][iec] = Q931PieProc;
+    if(Q931UieProc != NULL)
+        Q931Uie[dialect][iec] = Q931UieProc;
+}
+
+void Q931SetTimeoutProc(L3UCHAR dialect, L3UCHAR timer, q931timeout_func_t *Q931TimeoutProc)
+{
+	if(Q931Timeout != NULL)
+		Q931Timeout[dialect][timer] = Q931TimeoutProc;
+}
+
+void Q931SetTimerDefault(L3UCHAR dialect, L3UCHAR timer, q931timer_t timeout)
+{
+	Q931Timer[dialect][timer] = timeout;
+}
+
+L3INT Q931GetMesSize(Q931mes_Generic *pMes)
+{
+	
+    L3UCHAR *p = &pMes->buf[0];
+    L3INT Size = (L3INT)(p - (L3UCHAR *)pMes);
+    return Size;
+}
+
+/*****************************************************************************
+
+  Function:     q931AppendIE    
+
+  Description:  Append IE to the message.
+
+  Parameters:   pm      Ptr to message.
+                pi      Ptr to information element
+
+  Return Value  ie setting
+
+*****************************************************************************/
+
+ie Q931AppendIE( L3UCHAR *pm, L3UCHAR *pi)
+{
+	ie IE = 0;
+	Q931mes_Generic * pMes= (Q931mes_Generic *)pm;
+	Q931ie_BearerCap * pIE= (Q931ie_BearerCap *)pi;
+	L3INT iISize = pIE->Size;
+
+	L3UCHAR *pBuf = &pMes->buf[0];
+	L3INT Off = (L3INT)(pMes->Size - (pBuf - pm));
+	IE = (ie)(Off | 0x8000);
+
+	memcpy(&pm[pMes->Size], pi, iISize);
+
+	pMes->Size += iISize;
+
+	return IE;
+}
+
+/*****************************************************************************
+*****************************************************************************/
+static L3INT crv={1};
+
+L3INT Q931GetUniqueCRV(Q931_TrunkInfo_t *pTrunk)
+{
+	L3INT max = (Q931_IS_BRI(pTrunk)) ? Q931_BRI_MAX_CRV : Q931_PRI_MAX_CRV;
+
+	crv++;
+	crv = (crv <= max) ? crv : 1;
+
+	return crv;
+}
+
+L3INT Q931InitMesGeneric(Q931mes_Generic *pMes)
+{
+	memset(pMes, 0, sizeof(*pMes));
+	pMes->ProtDisc		= 0x08;
+	pMes->Size			= Q931GetMesSize(pMes);
+
+	return 0;
+}
+
+L3INT Q931InitMesResume(Q931mes_Generic * pMes)
+{
+	pMes->ProtDisc		= 0x08;
+	pMes->CRV			= 0;		/* CRV to be allocated, might be receive*/
+	pMes->MesType		= Q931mes_RESUME;
+
+	pMes->Size			= Q931GetMesSize(pMes);
+    pMes->CallID        = 0;        /* Channel Identification               */
+	return 0;
+}
+
+L3INT Q931InitMesRestartAck(Q931mes_Generic * pMes)
+{
+	pMes->ProtDisc		= 0x08;
+	pMes->CRV			= 0;		/* CRV to be allocated, might be receive*/
+	pMes->MesType		= Q931mes_RESTART_ACKNOWLEDGE;
+
+	pMes->Size			= Q931GetMesSize(pMes);
+    pMes->ChanID        = 0;        /* Channel Identification               */
+	pMes->Display		= 0;
+	pMes->RestartInd	= 0;
+	pMes->RestartWin	= 0;
+	return 0;
+}
+
+L3INT Q931InitIEBearerCap(Q931ie_BearerCap *pIE)
+{
+	pIE->IEId			= Q931ie_BEARER_CAPABILITY;
+	pIE->Size			= sizeof(Q931ie_BearerCap);
+	pIE->CodStand		= 0;
+	pIE->ITC			= 0;
+	pIE->TransMode		= 0;
+	pIE->ITR			= 0x10;
+	pIE->RateMul		= 0;
+
+	pIE->Layer1Ident	= 0;
+	pIE->UIL1Prot		= 0;        /* User Information Layer 1 Protocol    */
+	pIE->SyncAsync		= 0;        /* Sync/Async                           */
+	pIE->Negot			= 0;                
+	pIE->UserRate		= 0;
+	pIE->InterRate		= 0;        /* Intermediate Rate                    */
+	pIE->NIConTx		= 0;
+	pIE->NIConRx		= 0;
+	pIE->FlowCtlTx		= 0;        /* Flow control on Tx                   */
+	pIE->FlowCtlRx		= 0;        /* Flow control on Rx                   */
+	pIE->HDR			= 0;
+	pIE->MultiFrame		= 0;        /* Multi frame support                  */
+	pIE->Mode			= 0;
+	pIE->LLInegot		= 0;
+	pIE->Assignor		= 0;        /* Assignor/assignee                    */
+	pIE->InBandNeg		= 0;        /* In-band/out-band negot.              */
+	pIE->NumStopBits	= 0;        /* Number of stop bits                  */
+	pIE->NumDataBits	= 0;        /* Number of data bits.                 */
+	pIE->Parity			= 0;
+	pIE->DuplexMode		= 0;
+	pIE->ModemType		= 0;
+	pIE->Layer2Ident	= 0;
+	pIE->UIL2Prot		= 0;        /* User Information Layer 2 Protocol    */
+	pIE->Layer3Ident	= 0;           
+	pIE->UIL3Prot		= 0;        /* User Information Layer 3 Protocol    */
+	pIE->AL3Info1		= 0;
+	pIE->AL3Info2		= 0;
+
+	return 0;
+}
+
+L3INT Q931InitIEChanID(Q931ie_ChanID *pIE)
+{
+	pIE->IEId			= Q931ie_CHANNEL_IDENTIFICATION;
+	pIE->Size			= sizeof(Q931ie_ChanID);
+	pIE->IntIDPresent	= 0;        /* Int. id. present                     */
+	pIE->IntType		= 0;        /* Int. type                            */
+	pIE->PrefExcl		= 0;        /* Pref./Excl.                          */
+	pIE->DChanInd		= 0;        /* D-channel ind.                       */
+	pIE->InfoChanSel	= 0;        /* Info. channel selection              */
+	pIE->InterfaceID	= 0;        /* Interface identifier                 */
+	pIE->CodStand		= 0;		/* Code standard                        */
+	pIE->NumMap			= 0;        /* Number/Map                           */
+	pIE->ChanMapType	= 0;        /* Channel type/Map element type        */
+	pIE->ChanSlot		= 0;        /* Channel number/Slot map              */
+
+	return 0;
+}
+
+L3INT Q931InitIEProgInd(Q931ie_ProgInd * pIE)
+{
+	pIE->IEId			= Q931ie_PROGRESS_INDICATOR;
+	pIE->Size			= sizeof(Q931ie_ProgInd);
+	pIE->CodStand		= 0;        /* Coding standard                      */
+	pIE->Location		= 0;        /* Location                             */
+	pIE->ProgDesc		= 0;        /* Progress description                 */
+
+	return 0;
+}
+
+L3INT Q931InitIENetFac(Q931ie_NetFac * pIE)
+{
+	pIE->IEId			= Q931ie_NETWORK_SPECIFIC_FACILITIES;
+	pIE->Size			= sizeof(Q931ie_NetFac);
+	pIE->LenNetID		= 0;        /* Length of network facilities id.     */
+	pIE->TypeNetID		= 0;        /* Type of network identification       */
+	pIE->NetIDPlan		= 0;        /* Network identification plan.         */
+	pIE->NetFac			= 0;        /* Network specific facility spec.      */
+	pIE->NetID[0]		= 0;
+	return 0;
+}
+
+L3INT Q931InitIEDisplay(Q931ie_Display * pIE)
+{
+	pIE->IEId			= Q931ie_DISPLAY;
+	pIE->Size			= sizeof(Q931ie_Display);
+	pIE->Display[0]		= 0;
+	return 0;
+}
+
+L3INT Q931InitIEDateTime(Q931ie_DateTime * pIE)
+{
+	pIE->IEId			= Q931ie_DATETIME;
+	pIE->Size			= sizeof(Q931ie_DateTime);
+	pIE->Year			= 0;        /* Year                                 */
+	pIE->Month			= 0;        /* Month                                */
+	pIE->Day			= 0;        /* Day                                  */
+	pIE->Hour			= 0;        /* Hour                                 */
+	pIE->Minute			= 0;        /* Minute                               */
+	pIE->Second			= 0;        /* Second                               */
+
+	return 0;
+}
+
+L3INT Q931InitIEKeypadFac(Q931ie_KeypadFac * pIE)
+{
+	pIE->IEId			= Q931ie_KEYPAD_FACILITY;
+	pIE->Size			= sizeof(Q931ie_KeypadFac);
+	pIE->KeypadFac[0]	= 0;
+	return 0;
+}
+
+L3INT Q931InitIESignal(Q931ie_Signal * pIE)
+{
+	pIE->IEId			= Q931ie_SIGNAL;
+	pIE->Size			= sizeof(Q931ie_Signal);
+	pIE->Signal			= 0;
+	return 0;
+}
+
+L3INT Q931InitIECallingNum(Q931ie_CallingNum * pIE)
+{
+	pIE->IEId			= Q931ie_CALLING_PARTY_NUMBER;
+	pIE->Size			= sizeof(Q931ie_CallingNum);
+	pIE->TypNum			= 0;        /* Type of number                       */
+	pIE->NumPlanID		= 0;        /* Numbering plan identification        */
+	pIE->PresInd		= 0;        /* Presentation indicator               */
+	pIE->ScreenInd		= 0;        /* Screening indicator                  */
+	pIE->Digit[0]		= 0;        /* Number digits (IA5)                  */
+
+	return 0;
+}
+
+L3INT Q931InitIECallingSub(Q931ie_CallingSub * pIE)
+{
+	pIE->IEId			= Q931ie_CALLING_PARTY_SUBADDRESS;
+	pIE->Size			= sizeof(Q931ie_CallingSub);
+	pIE->TypNum			= 0;        /* Type of subaddress                   */
+	pIE->OddEvenInd		= 0;        /* Odd/Even indicator                   */
+	pIE->Digit[0]		= 0;        /* Digits                               */
+
+	return 0;
+}
+
+L3INT Q931InitIECalledNum(Q931ie_CalledNum * pIE)
+{
+	pIE->IEId			= Q931ie_CALLED_PARTY_NUMBER;
+	pIE->Size			= sizeof(Q931ie_CalledNum);
+	pIE->TypNum			= 0;        /* Type of Number                       */
+	pIE->NumPlanID		= 0;        /* Numbering plan identification        */
+	pIE->Digit[0]		= 0;        /* Digit (IA5)                          */
+
+	return 0;
+}
+
+L3INT Q931InitIECalledSub(Q931ie_CalledSub * pIE)
+{
+	pIE->IEId			= Q931ie_CALLED_PARTY_SUBADDRESS;
+	pIE->Size			= sizeof(Q931ie_CalledSub);
+	pIE->TypNum			= 0;        /* Type of subaddress                   */
+	pIE->OddEvenInd		= 0;        /* Odd/Even indicator                   */
+	pIE->Digit[0]		= 0;        /* Digits                               */
+
+	return 0;
+}
+
+L3INT Q931InitIETransNetSel(Q931ie_TransNetSel * pIE)
+{
+	pIE->IEId			= Q931ie_TRANSIT_NETWORK_SELECTION;
+	pIE->Size			= sizeof(Q931ie_TransNetSel);
+	pIE->Type			= 0;        /* Type of network identifier           */
+	pIE->NetIDPlan		= 0;        /* Network idetification plan           */
+	pIE->NetID[0]		= 0;        /* Network identification(IA5)          */
+
+	return 0;
+}
+
+L3INT Q931InitIELLComp(Q931ie_LLComp * pIE)
+{
+	pIE->IEId			= Q931ie_LOW_LAYER_COMPATIBILITY;
+	pIE->Size			= sizeof(Q931ie_LLComp);
+
+	pIE->CodStand		= 0;        /* Coding standard                      */
+	pIE->ITransCap		= 0;        /* Information transfer capability      */
+	pIE->NegotInd		= 0;        /* Negot indic.                         */
+	pIE->TransMode		= 0;        /* Transfer Mode                        */
+	pIE->InfoRate		= 0;        /* Information transfer rate            */
+	pIE->RateMul		= 0;        /* Rate multiplier                      */
+	pIE->Layer1Ident	= 0;        /* Layer 1 ident.                       */
+	pIE->UIL1Prot		= 0;        /* User information layer 1 protocol    */
+	pIE->SyncAsync		= 0;        /* Synch/asynch                         */
+	pIE->Negot			= 0;        /* Negot                                */
+	pIE->UserRate		= 0;        /* User rate                            */
+	pIE->InterRate		= 0;        /* Intermediate rate                    */
+	pIE->NIConTx		= 0;        /* NIC on Tx                            */
+	pIE->NIConRx		= 0;        /* NIC on Rx                            */
+	pIE->FlowCtlTx		= 0;        /* Flow control on Tx                   */
+	pIE->FlowCtlRx		= 0;        /* Flow control on Rx                   */
+	pIE->HDR			= 0;        /* Hdr/no hdr                           */
+	pIE->MultiFrame		= 0;        /* Multiframe                           */
+	pIE->ModeL1			= 0;		/* Mode L1								*/
+	pIE->NegotLLI		= 0;        /* Negot. LLI                           */
+	pIE->Assignor		= 0;        /* Assignor/Assignor ee                 */
+	pIE->InBandNeg		= 0;        /* In-band negot.                       */
+	pIE->NumStopBits	= 0;        /* Number of stop bits                  */
+	pIE->NumDataBits	= 0;        /* Number of data bits                  */
+	pIE->Parity			= 0;        /* Parity                               */
+	pIE->DuplexMode		= 0;        /* Duplex Mode                          */
+	pIE->ModemType		= 0;        /* Modem type                           */
+	pIE->Layer2Ident	= 0;        /* Layer 2 ident.                       */
+	pIE->UIL2Prot		= 0;        /* User information layer 2 protocol    */
+	pIE->ModeL2			= 0;        /* ModeL2                               */
+	pIE->Q933use		= 0;        /* Q.9333 use                           */
+	pIE->UsrSpcL2Prot	= 0;        /* User specified layer 2 protocol info */
+	pIE->WindowSize		= 0;        /* Window size (k)                      */
+	pIE->Layer3Ident	= 0;        /* Layer 3 ident                        */
+	pIE->OptL3Info		= 0;        /* Optional layer 3 protocol info.      */
+	pIE->ModeL3			= 0;        /* Mode of operation                    */
+#if 0
+	pIE->ModeX25op		= 0;        /* Mode of operation X.25               */
+#endif
+	pIE->DefPackSize	= 0;        /* Default packet size                  */
+	pIE->PackWinSize	= 0;        /* Packet window size                   */
+	pIE->AddL3Info		= 0;        /* Additional Layer 3 protocol info     */
+
+	return 0;
+}
+
+L3INT Q931InitIEHLComp(Q931ie_HLComp * pIE)
+{
+	pIE->IEId			= Q931ie_HIGH_LAYER_COMPATIBILITY;
+	pIE->Size			= sizeof(Q931ie_HLComp);
+
+	return 0;
+}
+
+L3INT Q931ProcUnknownMessage(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom)
+{
+	/* TODO:  Unhandled paramaters */
+	(void)pTrunk;
+	(void)b;
+	(void)iFrom;
+
+    return 0;
+}
+
+L3INT Q931ProcUnexpectedMessage(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom)
+{
+	/* TODO:  Unhandled paramaters */
+	(void)pTrunk;
+	(void)b;
+	(void)iFrom;
+
+    return 0;
+}
+
+L3INT Q931Disconnect(Q931_TrunkInfo_t *pTrunk, L3INT iTo, L3INT iCRV, L3INT iCause)
+{
+	/* TODO:  Unhandled paramaters */
+	(void)pTrunk;
+	(void)iTo;
+	(void)iCRV;
+	(void)iCause;
+
+    return 0;
+}
+
+L3INT Q931ReleaseComplete(Q931_TrunkInfo_t *pTrunk, L3UCHAR *buf)
+{
+    Q931mes_Header *ptr = (Q931mes_Header*)&buf[Q931L4HeaderSpace];
+	ptr->MesType = Q931mes_RELEASE_COMPLETE;
+	ptr->CRVFlag = !(ptr->CRVFlag);
+	return Q931Tx32Data(pTrunk,0,buf,ptr->Size);
+}
+
+L3INT Q931AckRestart(Q931_TrunkInfo_t *pTrunk, L3UCHAR *buf)
+{
+	L3INT RetCode;
+
+    Q931mes_Header *ptr = (Q931mes_Header*)&buf[Q931L4HeaderSpace];
+	ptr->MesType = Q931mes_RESTART_ACKNOWLEDGE;
+	//if (ptr->CRV) {
+		ptr->CRVFlag = !(ptr->CRVFlag);
+		//}
+
+	RetCode = Q931Proc[pTrunk->Dialect][ptr->MesType](pTrunk, buf, 4);
+
+    return RetCode;
+}
+
+L3INT Q931AckSetup(Q931_TrunkInfo_t *pTrunk, L3UCHAR *buf)
+{
+	L3INT RetCode;
+
+    Q931mes_Header *ptr = (Q931mes_Header*)&buf[Q931L4HeaderSpace];
+	ptr->MesType = Q931mes_SETUP_ACKNOWLEDGE;
+
+	RetCode = Q931Proc[pTrunk->Dialect][ptr->MesType](pTrunk, buf, 4);
+
+    return RetCode;
+}
+
+L3INT Q931AckConnect(Q931_TrunkInfo_t *pTrunk, L3UCHAR *buf)
+{
+	L3INT RetCode;
+
+    Q931mes_Header *ptr = (Q931mes_Header*)&buf[Q931L4HeaderSpace];
+	ptr->MesType = Q931mes_CONNECT_ACKNOWLEDGE;
+
+	RetCode = Q931Proc[pTrunk->Dialect][ptr->MesType](pTrunk, buf, 4);
+
+    return RetCode;
+}
+
+L3INT Q931AckService(Q931_TrunkInfo_t *pTrunk, L3UCHAR *buf)
+{
+	L3INT RetCode;
+
+    Q931mes_Header *ptr = (Q931mes_Header*)&buf[Q931L4HeaderSpace];
+	ptr->MesType = Q931mes_SERVICE_ACKNOWLEDGE;
+	if (ptr->CRV) {
+		ptr->CRVFlag = !(ptr->CRVFlag);
+	}
+
+	RetCode = Q931Proc[pTrunk->Dialect][ptr->MesType](pTrunk, buf, 4);
+
+    return RetCode;
+}
+
+Q931_ENUM_NAMES(DIALECT_TYPE_NAMES, DIALECT_STRINGS)
+Q931_STR2ENUM(q931_str2Q931Dialect_type, q931_Q931Dialect_type2str, Q931Dialect_t, DIALECT_TYPE_NAMES, Q931_Dialect_Count)

Added: freeswitch/trunk/libs/freetdm/src/isdn/Q931ie.c (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/isdn/Q931ie.c	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/isdn/Q931ie.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,3074 @@
+/*****************************************************************************
+
+  FileName:	 Q931ie.c
+
+  Contents:	 Information Element Pack/Unpack functions. 
+  
+		These functions will pack out a Q931 message from the bit 
+		packed original format into structs that are easier to process 
+		and pack the same structs back into bit fields when sending
+		messages out.
+
+		The messages contains a short for each possible IE. The MSB 
+		bit flags the precense of an IE, while the remaining bits 
+		are the offset into a buffer to find the actual IE.
+
+		Each IE are supported by 3 functions:
+
+		Q931Pie_XXX	 Pack struct into Q.931 IE
+		Q931Uie_XXX	 Unpack Q.931 IE into struct
+		Q931InitIEXXX   Initialize IE (see Q931api.c).
+
+  Dialect Note: This file will only contain standard DSS1 IE. Other IE as 
+		used in QSIG, NI2, Q.932 etc are located in separate files.
+
+		See	q931.h for description. 
+
+  License/Copyright:
+
+  Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+  email:janvb@caselaboratories.com  
+
+  Redistribution and use in source and binary forms, with or without 
+  modification, are permitted provided that the following conditions are 
+  met:
+
+	* Redistributions of source code must retain the above copyright notice, 
+	  this list of conditions and the following disclaimer.
+	* Redistributions in binary form must reproduce the above copyright notice, 
+	  this list of conditions and the following disclaimer in the documentation 
+	  and/or other materials provided with the distribution.
+	* Neither the name of the Case Labs, Ltd nor the names of its contributors 
+	  may be used to endorse or promote products derived from this software 
+	  without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
+  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
+  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+  POSSIBILITY OF SUCH DAMAGE.
+*****************************************************************************/
+
+#include "Q931.h"
+
+#ifdef _MSC_VER
+#ifndef __inline__
+#define __inline__ __inline
+#endif
+#if (_MSC_VER >= 1400)			/* VC8+ */
+#ifndef _CRT_SECURE_NO_DEPRECATE
+#define _CRT_SECURE_NO_DEPRECATE
+#endif
+#ifndef _CRT_NONSTDC_NO_DEPRECATE
+#define _CRT_NONSTDC_NO_DEPRECATE
+#endif
+#endif
+#ifndef strcasecmp
+#define strcasecmp(s1, s2) _stricmp(s1, s2)
+#endif
+#ifndef strncasecmp
+#define strncasecmp(s1, s2, n) _strnicmp(s1, s2, n)
+#endif
+#ifndef snprintf
+#define snprintf _snprintf
+#endif
+#endif
+
+/*****************************************************************************
+
+  Macro:		Q931MoreIE
+
+  Description:  Local helper macro detecting if there is more IE space left
+		based on the 3 standard parameters Octet, Off and IESpace.
+		This can be used to test if the IE is completed to avoid
+		that the header of the next IE is interpreted as a part of
+		the current IE.
+
+*****************************************************************************/
+#define Q931MoreIE() (Octet + Off - 2 < IESize)
+
+#define Q931IESizeTest(x) {\
+	if (Octet + Off - 2 != IESize) {\
+		Q931SetError(pTrunk, x, Octet, Off);\
+		return x;\
+	}\
+}
+
+/*****************************************************************************
+
+  Function:	 Q931ReadExt
+
+  Description:  Many of the octets in the standard have an MSB 'ext.1'. This
+				means that the octet usually is the latest octet, but that a
+				futhure standard may extend the octet. A stack must be able 
+				to handle such extensions by skipping the extension octets.
+
+				This function will increase the offset counter with 1 for 
+				each octet with an MSB of zero. This will allow the stack to
+				skip extensions wihout knowing anything about them.
+
+  Parameters:   IBuf	ptr to octet array.
+				Off	 Starting offset counter
+
+  Return Value: New offset value.
+
+*****************************************************************************/
+
+L3INT Q931ReadExt(L3UCHAR * IBuf, L3INT Off)
+{
+	L3INT c = 0;
+	while ((IBuf[c] & 0x80) == 0) {
+		c++;
+	}
+	return Off + c;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Uie_BearerCap
+
+  Description:  Unpack a bearer capability ie.
+
+  Parameters:   pIE[OUT]	ptr to Information Element id.
+		IBuf[IN]	ptr to a packed ie.
+		OBuf[OUT]	ptr to buffer for Unpacked ie.
+		IOff[IN\OUT]	Input buffer offset
+		OOff[IN\OUT]	Output buffer offset
+
+		Ibuf and OBuf points directly to buffers. The IOff and OOff
+		must be updated, but are otherwise not used in the ie unpack.
+
+  Return Value: Error Message
+
+*****************************************************************************/
+
+L3INT Q931Uie_BearerCap(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff) 
+{
+	Q931ie_BearerCap *pie = (Q931ie_BearerCap*)OBuf;
+	ie *pIE = &pMsg->BearerCap;
+	L3INT Off = 0;
+	L3INT Octet = 0;
+	L3INT IESize;
+	*pIE = 0;
+
+	/* Octet 1 */
+	pie->IEId = IBuf[Octet++];
+
+	/* Octet 2 */
+	IESize = IBuf[Octet++]; 
+
+	/* Octet 3 */
+	pie->CodStand = ieGetOctet((IBuf[Octet] & 0x60) >> 5);
+	pie->ITC      = ieGetOctet(IBuf[Octet] & 0x1f);
+	Off           = Q931ReadExt(&IBuf[Octet], Off);
+	Octet++;
+
+	/* Octet 4 */
+	pie->TransMode = ieGetOctet((IBuf[Octet + Off] & 0x60) >> 5);
+	pie->ITR       = ieGetOctet(IBuf[Octet + Off] & 0x1f);
+	Off            = Q931ReadExt(&IBuf[Octet + Off], Off);
+	Octet++;
+
+	/* Octet 4.1. Rate multiplier is only present if ITR = Multirate		*/
+	if (pie->ITR == 0x18) {
+		pie->RateMul = ieGetOctet(IBuf[Octet + Off] & 0x7f);
+		Off = Q931ReadExt(&IBuf[Octet + Off], Off);
+		Off ++;
+	}
+
+	/* Octet 5 */
+	if ((IBuf[Octet + Off] & 0x60) == 0x20 && Q931MoreIE()) {
+		pie->Layer1Ident = ieGetOctet((IBuf[Octet + Off] & 0x60) >> 5);
+		pie->UIL1Prot    = ieGetOctet(IBuf[Octet + Off] & 0x1f);
+		Octet++;
+
+		/* Octet 5a. The octet may be present if ITC is unrestrictd digital info
+		 * and UIL1Prot is either V.110, I.460 and X.30 or V.120. It may also
+		 * be present if ITC = 3.1 kHz audio and UIL1Prot is G.711.
+		 * Bit 8 of Octet 5 = 0 indicates that 5a is present.
+		 */
+
+		if (IsQ931Ext(IBuf[Octet + Off - 1])) {
+			if (((pie->ITC == 0x08) && (pie->UIL1Prot == 0x01 || pie->UIL1Prot == 0x08))
+			|| ((pie->ITC == 0x10) && (pie->UIL1Prot == 0x02 || pie->UIL1Prot == 0x03))) {
+				pie->SyncAsync = ieGetOctet((IBuf[Octet + Off] & 0x40) >> 6);
+				pie->Negot     = ieGetOctet((IBuf[Octet + Off] & 0x20) >> 5);
+				pie->UserRate  = ieGetOctet(IBuf[Octet + Off] & 0x1f);
+				Off ++;
+			}
+			else {
+				/* We have detected bit 8 = 0, but no setting that require the  */
+				/* additional octets ??? */
+				Q931SetError(pTrunk, Q931E_BEARERCAP, 5,Off);
+				return Q931E_BEARERCAP;
+			}
+
+			/* Octet 5b. Two different structures used. */
+			if (IsQ931Ext(IBuf[Octet + Off - 1])) {
+				if (pie->UIL1Prot == 0x01) { /* ITU V.110, I.460 and X.30 */
+					pie->InterRate = ieGetOctet((IBuf[Octet + Off] & 0x60) >> 5);
+					pie->NIConTx   = ieGetOctet((IBuf[Octet + Off] & 0x10) >> 4);
+					pie->NIConRx   = ieGetOctet((IBuf[Octet + Off] & 0x08) >> 3);
+					pie->FlowCtlTx = ieGetOctet((IBuf[Octet + Off] & 0x04) >> 2);
+					pie->FlowCtlRx = ieGetOctet((IBuf[Octet + Off] & 0x20) >> 1);
+					Off++;
+				}
+				else if (pie->UIL1Prot == 0x08) { /* ITU V.120 */
+					pie->HDR        = ieGetOctet((IBuf[Octet + Off] & 0x40) >> 6);
+					pie->MultiFrame = ieGetOctet((IBuf[Octet + Off] & 0x20) >> 5);
+					pie->Mode       = ieGetOctet((IBuf[Octet + Off] & 0x10) >> 4);
+					pie->LLInegot   = ieGetOctet((IBuf[Octet + Off] & 0x08) >> 3);
+					pie->Assignor   = ieGetOctet((IBuf[Octet + Off] & 0x04) >> 2);
+					pie->InBandNeg  = ieGetOctet((IBuf[Octet + Off] & 0x02) >> 1);
+					Off++;
+				}
+				else {
+					Q931SetError(pTrunk,Q931E_BEARERCAP, 5,Off);
+					return Q931E_BEARERCAP;
+				}
+
+				/* Octet 5c */
+				if (IsQ931Ext(IBuf[Octet + Off - 1])) {
+					pie->NumStopBits = ieGetOctet((IBuf[Octet + Off] & 0x60) >> 5);
+					pie->NumDataBits = ieGetOctet((IBuf[Octet + Off] & 0x18) >> 3);
+					pie->Parity      = ieGetOctet(IBuf[Octet + Off] & 0x07);
+					Off++;
+
+					/* Octet 5d */
+					if (IsQ931Ext(IBuf[Octet + Off - 1])) {
+						pie->DuplexMode = ieGetOctet((IBuf[Octet + Off] & 0x40) >> 6);
+						pie->ModemType  = ieGetOctet(IBuf[Octet + Off] & 0x3f);
+						Off ++;
+					}
+				}
+			}
+		}
+	}
+
+	/* Octet 6 */
+	if ((IBuf[Octet + Off] & 0x60) == 0x40 && Q931MoreIE()) {
+		pie->Layer2Ident = ieGetOctet((IBuf[Octet + Off] & 0x60) >> 5);
+		pie->UIL2Prot    = ieGetOctet(IBuf[Octet + Off] & 0x1f);
+
+		Off = Q931ReadExt(&IBuf[Octet + Off], Off);
+		Octet ++;
+	}
+
+	/* Octet 7 */
+	if ((IBuf[Octet + Off] & 0x60) == 0x60 && Q931MoreIE()) {
+		pie->Layer3Ident = ieGetOctet((IBuf[Octet + Off] & 0x60) >> 5);
+		pie->UIL3Prot    = ieGetOctet(IBuf[Octet + Off] & 0x1f);
+		Octet++;
+
+		/* Octet 7a */
+		if (IsQ931Ext(IBuf[Octet + Off - 1])) {
+			if (pie->UIL3Prot == 0x0c) {
+				pie->AL3Info1 = ieGetOctet(IBuf[Octet + Off] & 0x0f);
+				Off++;
+
+				/* Octet 7b */
+				if (IsQ931Ext(IBuf[Octet + Off])) {
+					pie->AL3Info2 = ieGetOctet(IBuf[Octet + Off] & 0x0f);
+					Off++;
+				}
+			}
+			else {
+				Q931SetError(pTrunk,Q931E_BEARERCAP, 7, Off);
+				return Q931E_BEARERCAP;
+
+			}
+		}
+	}
+
+	Q931IESizeTest(Q931E_BEARERCAP);
+	Q931SetIE(*pIE, *OOff);
+
+	*IOff = (*IOff) + Octet + Off;
+	*OOff = (*OOff) + sizeof(Q931ie_BearerCap);
+	pie->Size = sizeof(Q931ie_BearerCap);
+
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Pie_BearerCap
+
+  Description:  Packing a Q.931 Bearer Capability element from a generic 
+				struct into a packed octet structure in accordance with the
+				standard.
+
+  Parameters:   IBuf[IN]		Ptr to struct.
+				OBuf[OUT]		Ptr tp packed output buffer.
+				Octet[IN/OUT]	Offset into OBuf.
+
+  Return Value:	Error code, 0 = OK
+
+*****************************************************************************/
+
+L3INT Q931Pie_BearerCap(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+	Q931ie_BearerCap *pIE = (Q931ie_BearerCap*)IBuf;
+	L3INT rc = 0;
+	L3INT Beg = *Octet; /* remember current offset */
+	L3INT li;
+
+	Q931Log(pTrunk, Q931_LOG_DEBUG, "Encoding Bearer Capability IE\n");
+
+	OBuf[(*Octet)++] = Q931ie_BEARER_CAPABILITY ;
+	li = (*Octet)++; /* remember length position */
+
+	/* Octet 3 - Coding standard / Information transfer capability */
+	OBuf[(*Octet)++] = 0x80 | ((pIE->CodStand << 5) & 0x60) | (pIE->ITC & 0x1f);
+
+	/* Octet 4 - Transfer mode / Information transfer rate */
+	OBuf[(*Octet)++] = 0x80 | ((pIE->TransMode << 5) & 0x60) | (pIE->ITR & 0x1f);
+
+	if (pIE->ITR == 0x18) {
+		/* Octet 4.1 - Rate Multiplier */
+		OBuf[(*Octet)++] = 0x80 | (pIE->RateMul & 0x7f);
+	}
+
+	/* Octet 5 - Layer 1 Ident / User information layer 1 protocol */
+	if (pIE->Layer1Ident == 0x01) {
+		if (((pIE->ITC == 0x08) && (pIE->UIL1Prot == 0x01 || pIE->UIL1Prot == 0x08)) ||
+		   ((pIE->ITC == 0x10) && (pIE->UIL1Prot == 0x02 || pIE->UIL1Prot == 0x03))) {
+			OBuf[(*Octet)++] = 0x00 | ((pIE->Layer1Ident << 5) & 0x60) | (pIE->UIL1Prot & 0x15);
+			
+			/* Octet 5a - SyncAsync/Negot/UserRate */
+			OBuf[(*Octet)++] = 0x00 | ((pIE->SyncAsync << 6) & 0x40) | ((pIE->Negot << 5) & 0x20) | (pIE->UserRate & 0x1f);
+
+			/* Octet 5b - one of two types */
+			if (pIE->UIL1Prot == 0x01) { /* ITU V.110, I.460 and X.30	*/
+				/* Octet 5b - Intermed rate/ Nic on Tx/Nix on Rx/FlowCtlTx/FlowCtlRx */
+				OBuf[(*Octet)++] = 0x00 
+						| ((pIE->InterRate << 6) & 0x60)
+						| ((pIE->NIConTx   << 4) & 0x10)
+						| ((pIE->NIConRx   << 3) & 0x08)
+						| ((pIE->FlowCtlTx << 2) & 0x04)
+						| ((pIE->FlowCtlRx << 1) & 0x02);
+			}
+			else if (pIE->UIL1Prot == 0x08) { /* ITU V.120 */
+				/* Octet 5b - HDR/Multiframe/Mode/LLINegot/Assignor/Inbandneg*/
+				OBuf[(*Octet)++] = 0x00
+						| ((pIE->InterRate  << 6) & 0x60)
+						| ((pIE->MultiFrame << 5) & 0x20)
+						| ((pIE->Mode       << 4) & 0x10)
+						| ((pIE->LLInegot   << 3) & 0x08)
+						| ((pIE->Assignor   << 2) & 0x04)
+						| ((pIE->InBandNeg  << 1) & 0x02);
+			}
+
+			/* Octet 5c - NumStopBits/NumStartBits/Parity					*/
+			OBuf[(*Octet)++] = 0x00
+					| ((pIE->NumStopBits << 5) & 0x60)
+					| ((pIE->NumDataBits << 3) & 0x18)
+					| (pIE->Parity & 0x07);
+
+			/* Octet 5d - Duplex Mode/Modem Type */
+			OBuf[(*Octet)++] = 0x80 | ((pIE->DuplexMode << 6) & 0x40) | (pIE->ModemType & 0x3f);
+		}
+		else {
+			OBuf[(*Octet)++] = 0x80 | ((pIE->Layer1Ident << 5) & 0x60) | (pIE->UIL1Prot & 0x1f);
+		}
+	}
+
+	/* Octet 6 - Layer2Ident/User information layer 2 prtocol */
+	if (pIE->Layer2Ident == 0x02) {
+		OBuf[(*Octet)++] = 0x80 | ((pIE->Layer2Ident << 5) & 0x60) | (pIE->UIL2Prot & 0x1f);
+	}
+
+	/* Octet 7 - Layer 3 Ident/ User information layer 3 protocol */
+	if (pIE->Layer3Ident == 0x03) {
+		if (pIE->UIL3Prot == 0x0c) {
+			OBuf[(*Octet)++] = 0x00 | ((pIE->Layer3Ident << 5) & 0x60) | (pIE->UIL3Prot & 0x1f);
+
+			/* Octet 7a - Additional information layer 3 msb */
+			OBuf[(*Octet)++] = 0x00 | (pIE->AL3Info1 & 0x0f);
+
+			/* Octet 7b - Additional information layer 3 lsb */
+			OBuf[(*Octet)++] = 0x80 | (pIE->AL3Info2 & 0x0f);
+		}
+		else {
+			OBuf[(*Octet)++] = 0x80 | ((pIE->Layer3Ident << 5) & 0x60) | (pIE->UIL3Prot & 0x1f);
+		}
+	}
+
+	OBuf[li] = (L3UCHAR)((*Octet) - Beg) - 2;
+	return rc;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Uie_CallID
+
+  Parameters:   pIE[OUT]		ptr to Information Element id.
+				IBuf[IN]		ptr to a packed ie.
+				OBuf[OUT]	   ptr to buffer for Unpacked ie.
+				IOff[IN\OUT]	Input buffer offset
+				OOff[IN\OUT]	Output buffer offset
+
+
+				Ibuf and OBuf points directly to buffers. The IOff and OOff
+				must be updated, but are otherwise not used in the ie unpack.
+
+  Return Value: Error Message
+
+*****************************************************************************/
+L3INT Q931Uie_CallID(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff)
+{
+	Q931ie_CallID *pie = (Q931ie_CallID*)OBuf;
+	ie *pIE = &pMsg->CallID;
+	L3INT Off = 0;
+	L3INT Octet = 0;
+	L3INT x = 0;
+	L3INT IESize;
+
+	*pIE = 0;
+
+	/* Octet 1 */
+	pie->IEId = IBuf[Octet++];
+
+	/* Octet 2 */
+	IESize = IBuf[Octet++]; 
+
+	/* Octet 3 */
+	do {
+		pie->CallId[x] = IBuf[Octet + Off] & 0x7f;
+		Off++;
+		x++;
+	} while (Q931MoreIE());
+
+	Q931IESizeTest(Q931E_CALLID);
+	Q931SetIE(*pIE, *OOff);
+
+	*IOff = (*IOff) + Octet + Off;
+	*OOff = (*OOff) + sizeof(Q931ie_CallID) + x - 1;
+	pie->Size = (L3UCHAR)(sizeof(Q931ie_CallID) + x - 1);
+
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Pie_CallID
+
+  Parameters:   IBuf[IN]		Ptr to struct.
+				OBuf[OUT]		Ptr tp packed output buffer.
+				Octet[IN/OUT]	Offset into OBuf.
+
+  Return Value:	Error code, 0 = OK
+
+*****************************************************************************/
+
+L3INT Q931Pie_CallID(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+	Q931ie_CallID *pIE = (Q931ie_CallID*)IBuf;
+	L3INT rc = 0;
+	L3INT Beg = *Octet;/* remember current offset */
+	L3INT li;
+	L3INT sCI = pIE->Size - sizeof(Q931ie_CallID) + 1;
+	L3INT x;
+
+	OBuf[(*Octet)++] = Q931ie_CALL_IDENTITY ;
+	li = (*Octet)++; /* remember length position */
+
+	for (x = 0; x < sCI; x++) {
+		OBuf[(*Octet)++] = pIE->CallId[x];
+	}
+
+	OBuf[(*Octet) - 1] |= 0x80; /* set complete flag at last octet*/
+
+	OBuf[li] = (L3UCHAR)((*Octet) - Beg) - 2;
+	return rc;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Uie_CallState
+
+  Parameters:   pIE[OUT]		ptr to Information Element id.
+				IBuf[IN]		ptr to a packed ie.
+				OBuf[OUT]	   ptr to buffer for Unpacked ie.
+				IOff[IN\OUT]	Input buffer offset
+				OOff[IN\OUT]	Output buffer offset
+
+				Ibuf and OBuf points directly to buffers. The IOff and OOff
+				must be updated, but are otherwise not used in the ie unpack.
+
+  Return Value: Error Message
+
+*****************************************************************************/
+L3INT Q931Uie_CallState(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff)
+{
+	Q931ie_CallState *pie = (Q931ie_CallState*)OBuf;
+	ie *pIE = &pMsg->CallState;
+	L3INT Off = 0;
+	L3INT Octet = 0;
+	L3INT IESize;
+
+	*pIE = 0;
+
+	/* Octet 1 */
+	pie->IEId = IBuf[Octet++];
+
+	/* Octet 2 */
+	IESize = IBuf[Octet++];
+
+	/* Octet 3 */
+	pie->CodStand  = (IBuf[Octet + Off] >> 6) & 0x03;
+	pie->CallState =  IBuf[Octet + Off] & 0x3f;
+	Octet++;
+
+	Q931IESizeTest(Q931E_CALLSTATE);
+	Q931SetIE(*pIE, *OOff);
+
+	*IOff = (*IOff) + Octet + Off;
+	*OOff = (*OOff) + sizeof(Q931ie_CallState);
+	pie->Size = sizeof(Q931ie_CallState);
+
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Pie_CallState
+
+  Parameters:   IBuf[IN]		Ptr to struct.
+				OBuf[OUT]		Ptr tp packed output buffer.
+				Octet[IN/OUT]	Offset into OBuf.
+
+  Return Value: Error code, 0 = OK
+
+*****************************************************************************/
+L3INT Q931Pie_CallState(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+	Q931ie_CallState *pIE = (Q931ie_CallState*)IBuf;
+	L3INT rc = 0;
+	L3INT Beg = *Octet; /* remember current offset */
+	L3INT li;
+
+	OBuf[(*Octet)++] = Q931ie_CALL_STATE;
+	li = (*Octet)++; /* remember length position */
+
+	OBuf[(*Octet)++] = (pIE->CodStand << 6) | (pIE->CallState & 0x3f);
+
+	OBuf[li] = (L3UCHAR)((*Octet) - Beg) - 2;
+	return rc;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Uie_CalledSub
+
+  Parameters:   pIE[OUT]		ptr to Information Element id.
+				IBuf[IN]		ptr to a packed ie.
+				OBuf[OUT]	   ptr to buffer for Unpacked ie.
+				IOff[IN\OUT]	Input buffer offset
+				OOff[IN\OUT]	Output buffer offset
+
+				Ibuf and OBuf points directly to buffers. The IOff and OOff
+				must be updated, but are otherwise not used in the ie unpack.
+
+  Return Value: Error Message
+
+*****************************************************************************/
+L3INT Q931Uie_CalledSub(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff)
+{
+	Q931ie_CalledSub *pie = (Q931ie_CalledSub*)OBuf;
+	ie *pIE = &pMsg->CalledSub;
+	L3INT Off = 0;
+	L3INT Octet = 0;
+	L3INT x;
+	L3INT IESize;
+
+	*pIE = 0;
+
+	/* Octet 1 */
+	pie->IEId = IBuf[Octet++];
+
+	/* Octet 2 */
+	IESize = IBuf[Octet++]; 
+
+	/* Octet 3 */
+	pie->TypNum     = (IBuf[Octet + Off] >> 4) & 0x07;
+	pie->OddEvenInd = (IBuf[Octet + Off] >> 3) & 0x01;
+	Octet++;
+	
+	/* Octet 4 */
+	x = 0;
+	do {
+		pie->Digit[x] = IBuf[Octet + Off] & 0x7f;
+		Off++;
+		x++;
+	} while (Q931MoreIE() && x < 20);
+
+	Q931IESizeTest(Q931E_CALLEDSUB);
+	Q931SetIE(*pIE, *OOff);
+
+	*IOff = (*IOff) + Octet + Off;
+	*OOff = (*OOff) + sizeof(Q931ie_CalledSub) + x - 1;
+	pie->Size = (L3UCHAR)(sizeof(Q931ie_CalledSub) + x - 1);
+
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Pie_CalledSub
+
+  Parameters:   IBuf[IN]		Ptr to struct.
+				OBuf[OUT]		Ptr tp packed output buffer.
+				Octet[IN/OUT]	Offset into OBuf.
+
+  Return Value:	Error code, 0 = OK
+
+*****************************************************************************/
+L3INT Q931Pie_CalledSub(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+	Q931ie_CalledSub *pIE = (Q931ie_CalledSub*)IBuf;
+	L3INT rc = 0;
+	L3INT Beg = *Octet;
+	L3INT li;
+	L3INT sN = pIE->Size - sizeof(Q931ie_CalledSub) + 1;
+	L3INT x;
+
+	/* Octet 1 */
+	OBuf[(*Octet)++] = Q931ie_CALLED_PARTY_SUBADDRESS;
+	li = (*Octet)++;
+
+	/* Octet 3 */
+	OBuf[(*Octet)++] = 0x80 | (pIE->TypNum << 4) | (pIE->OddEvenInd << 3);
+	
+	/* Octet 4 */
+	for (x = 0; x<sN; x++) {
+		OBuf[(*Octet)++] = pIE->Digit[x];
+	}
+
+	OBuf[(*Octet) - 1] |= 0x80; /* Terminate bit */
+
+	OBuf[li] = (L3UCHAR)((*Octet) - Beg) - 2;
+	return rc;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Uie_CalledNum
+
+  Parameters:   pIE[OUT]		ptr to Information Element id.
+				IBuf[IN]		ptr to a packed ie.
+				OBuf[OUT]	   ptr to buffer for Unpacked ie.
+				IOff[IN\OUT]	Input buffer offset
+				OOff[IN\OUT]	Output buffer offset
+
+				Ibuf and OBuf points directly to buffers. The IOff and OOff
+				must be updated, but are otherwise not used in the ie unpack.
+
+  Return Value: Error Message
+
+*****************************************************************************/
+L3INT Q931Uie_CalledNum(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff)
+{
+	Q931ie_CalledNum *pie = (Q931ie_CalledNum*)OBuf;
+	ie *pIE = &pMsg->CalledNum;
+	L3INT Off = 0;
+	L3INT Octet = 0;
+	L3INT x;
+	L3INT IESize; /* # digits in this case */
+
+	*pIE = 0;
+
+	/* Octet 1 */
+	pie->IEId = IBuf[Octet++];
+
+	/* Octet 2 */
+	IESize = IBuf[Octet++]; 
+
+	/* Octet 3 */
+	pie->TypNum    = (IBuf[Octet + Off] >> 4) & 0x07;
+	pie->NumPlanID =  IBuf[Octet + Off] & 0x0f;
+	Octet++;
+
+	/* Octet 4*/
+	x = 0;
+	do {
+		pie->Digit[x] = IBuf[Octet + Off] & 0x7f;
+		Off++;
+		x++;
+	} while ((IBuf[Octet + Off]&0x80) == 0 && Q931MoreIE());
+
+	pie->Digit[x] = '\0';
+
+	Q931SetIE(*pIE, *OOff);
+
+	*IOff = (*IOff) + Octet + Off;
+	*OOff = (*OOff) + sizeof(Q931ie_CalledNum) + x;
+	pie->Size = (L3UCHAR)(sizeof(Q931ie_CalledNum) + x);
+
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Pie_CalledNum
+
+  Parameters:   IBuf[IN]		Ptr to struct.
+				OBuf[OUT]		Ptr tp packed output buffer.
+				Octet[IN/OUT]	Offset into OBuf.
+
+  Return Value:	Error code, 0 = OK
+
+*****************************************************************************/
+L3INT Q931Pie_CalledNum(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+	Q931ie_CalledNum *pIE = (Q931ie_CalledNum*)IBuf;
+	L3INT rc = 0;
+	L3INT Beg = *Octet;
+	L3INT li;
+	L3INT sN = pIE->Size - sizeof(Q931ie_CalledNum);
+	L3INT x;
+
+	/* Octet 1 */
+	OBuf[(*Octet)++] = Q931ie_CALLED_PARTY_NUMBER;
+	
+	/* Octet 2 */
+	li = (*Octet)++;
+
+	/* Octet 3 */
+	OBuf[(*Octet)++] = 0x80 | (pIE->TypNum << 4) | (pIE->NumPlanID);
+	
+	/* Octet 4 */
+	for (x = 0; x<sN; x++) {
+		OBuf[(*Octet)++] = pIE->Digit[x];
+	}
+
+	OBuf[li] = (L3UCHAR)((*Octet) - Beg) - 2;
+	return rc;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Uie_CallingNum
+
+  Parameters:   pIE[OUT]		ptr to Information Element id.
+				IBuf[IN]		ptr to a packed ie.
+				OBuf[OUT]	   ptr to buffer for Unpacked ie.
+				IOff[IN\OUT]	Input buffer offset
+				OOff[IN\OUT]	Output buffer offset
+
+				Ibuf and OBuf points directly to buffers. The IOff and OOff
+				must be updated, but are otherwise not used in the ie unpack.
+
+  Return Value: Error Message
+
+*****************************************************************************/
+L3INT Q931Uie_CallingNum(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff)
+{
+	Q931ie_CallingNum *pie = (Q931ie_CallingNum*)OBuf;
+	ie *pIE = &pMsg->CallingNum;
+	L3INT Off = 0;
+	L3INT Octet = 0;
+	L3INT x;
+	L3INT IESize;
+
+	*pIE = 0;
+
+	/* Octet 1 */
+	pie->IEId = IBuf[Octet++];
+
+	/* Octet 2 */
+	IESize = IBuf[Octet++]; 
+
+	/* Octet 3 */
+	pie->TypNum    = (IBuf[Octet + Off] >> 4) & 0x07;
+	pie->NumPlanID =  IBuf[Octet + Off] & 0x0f;
+
+	/* Octet 3a */
+	if ((IBuf[Octet + Off] & 0x80) == 0) {
+		Off++;
+		pie->PresInd   = (IBuf[Octet + Off] >> 5) & 0x03;
+		pie->ScreenInd =  IBuf[Octet + Off] & 0x03;
+	}
+	Octet++;
+
+	/* Octet 4 */
+	x = 0;
+	while (Q931MoreIE()) {
+		pie->Digit[x++] = IBuf[Octet + Off] & 0x7f;
+
+		if ((IBuf[Octet + Off] & 0x80) != 0) {
+			break;
+		}
+		Off++;
+	}
+	pie->Digit[x] = '\0';
+
+	Q931IESizeTest(Q931E_CALLINGNUM);
+	Q931SetIE(*pIE, *OOff);
+
+	*IOff = (*IOff) + Octet + Off;
+	*OOff = (*OOff) + sizeof(Q931ie_CallingNum) + x;
+	pie->Size = (L3UCHAR)(sizeof(Q931ie_CallingNum) + x);
+
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Pie_CallingNum
+
+  Parameters:   IBuf[IN]		Ptr to struct.
+				OBuf[OUT]		Ptr tp packed output buffer.
+				Octet[IN/OUT]	Offset into OBuf.
+
+  Return Value:	Error code, 0 = OK
+
+*****************************************************************************/
+L3INT Q931Pie_CallingNum(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+	Q931ie_CallingNum *pIE = (Q931ie_CallingNum*)IBuf;
+	L3INT rc = 0;
+	L3INT Beg = *Octet;
+	L3INT li;
+	L3INT sN = pIE->Size - sizeof(Q931ie_CallingNum);
+	L3INT x;
+
+	/* Octet 1 */
+	OBuf[(*Octet)++] = Q931ie_CALLING_PARTY_NUMBER;
+	
+	/* Octet 2 */
+	li = (*Octet)++;
+
+	/* Octet 3 */
+	OBuf[(*Octet)++] = 0x00 | (pIE->TypNum << 4) | (pIE->NumPlanID);
+	
+	/* Octet 4 */
+	OBuf[(*Octet)++] = 0x80;
+
+	/* Octet 5 */
+	for (x = 0; x<sN; x++) {
+		OBuf[(*Octet)++] = pIE->Digit[x];
+	}
+
+	OBuf[li] = (L3UCHAR)((*Octet) - Beg) - 2;
+	return rc;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Uie_CallingSub
+
+  Parameters:   pIE[OUT]		ptr to Information Element id.
+				IBuf[IN]		ptr to a packed ie.
+				OBuf[OUT]	   ptr to buffer for Unpacked ie.
+				IOff[IN\OUT]	Input buffer offset
+				OOff[IN\OUT]	Output buffer offset
+
+				Ibuf and OBuf points directly to buffers. The IOff and OOff
+				must be updated, but are otherwise not used in the ie unpack.
+
+  Return Value: Error Message
+
+*****************************************************************************/
+L3INT Q931Uie_CallingSub(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff)
+{
+	Q931ie_CallingSub *pie = (Q931ie_CallingSub*)OBuf;
+	ie *pIE = &pMsg->CallingSub;
+	L3INT Off = 0;
+	L3INT Octet = 0;
+	L3INT x;
+	L3INT IESize;
+
+	*pIE = 0;
+
+	/* Octet 1 */
+	pie->IEId = IBuf[Octet++];
+
+	/* Octet 2 */
+	IESize = IBuf[Octet++]; 
+
+	/* Octet 3 */
+	pie->TypNum     = (IBuf[Octet + Off] >> 4) & 0x07;
+	pie->OddEvenInd = (IBuf[Octet + Off] >> 3) & 0x01;
+	Octet++;
+	
+	/* Octet 4*/
+	x = 0;
+	do {
+		pie->Digit[x] = IBuf[Octet + Off] & 0x7f;
+		Off++;
+		x++;
+	} while (Q931MoreIE() && x < 20);
+
+	Q931IESizeTest(Q931E_CALLINGSUB);
+	Q931SetIE(*pIE, *OOff);
+
+	*IOff = (*IOff) + Octet + Off;
+	*OOff = (*OOff) + sizeof(Q931ie_CallingSub) + x -1;
+	pie->Size = (L3UCHAR)(sizeof(Q931ie_CallingSub) + x -1);
+
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Pie_CallingSub
+
+  Parameters:   IBuf[IN]		Ptr to struct.
+				OBuf[OUT]		Ptr tp packed output buffer.
+				Octet[IN/OUT]	Offset into OBuf.
+
+  Return Value:	Error code, 0 = OK
+
+*****************************************************************************/
+L3INT Q931Pie_CallingSub(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+	Q931ie_CallingSub *pIE = (Q931ie_CallingSub*)IBuf;
+	L3INT rc = 0;
+	L3INT Beg = *Octet;
+	L3INT li;
+	L3INT sN = pIE->Size - sizeof(Q931ie_CallingSub) + 1;
+	L3INT x;
+
+	/* Octet 1 */
+	OBuf[(*Octet)++] = Q931ie_CALLING_PARTY_SUBADDRESS;
+	li = (*Octet)++;
+
+	/* Octet 3 */
+	OBuf[(*Octet)++] = 0x80 | (pIE->TypNum << 4) | (pIE->OddEvenInd << 3);
+	
+	/* Octet 4 */
+	for (x = 0; x<sN; x++) {
+		OBuf[(*Octet)++] = pIE->Digit[x];
+	}
+
+	OBuf[(*Octet) - 1] |= 0x80; /* Terminate bit */
+
+	OBuf[li] = (L3UCHAR)((*Octet) - Beg) - 2;
+	return rc;
+}
+
+/*****************************************************************************
+
+  Function:		Q931Uie_Cause
+  
+  Parameters:   pIE[OUT]		ptr to Information Element id.
+				IBuf[IN]		ptr to a packed ie.
+				OBuf[OUT]	   ptr to buffer for Unpacked ie.
+				IOff[IN\OUT]	Input buffer offset
+				OOff[IN\OUT]	Output buffer offset
+
+				Ibuf and OBuf points directly to buffers. The IOff and OOff
+				must be updated, but are otherwise not used in the ie unpack.
+
+  Return Value: Error Message
+
+*****************************************************************************/
+L3INT Q931Uie_Cause(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff) 
+{
+	Q931ie_Cause *pie = (Q931ie_Cause*)OBuf;
+	ie *pIE = &pMsg->Cause;
+	L3INT Off = 0;
+	L3INT Octet = 0;
+	L3INT IESize;
+
+	*pIE = 0;
+
+	pie->IEId = IBuf[Octet++];
+
+	/* Octet 2*/
+	IESize = IBuf[Octet++]; 
+
+	/* Octet 3*/
+	pie->CodStand = (IBuf[Octet + Off]>>5) & 0x03;
+	pie->Location =  IBuf[Octet + Off] & 0x0f;
+
+	/* Octet 3a */
+	if ((IBuf[Octet + Off] & 0x80) == 0) {
+		Off++;
+		pie->Recom = IBuf[Octet + Off] & 0x7f;
+	}
+	Octet++;
+
+	/* Octet 4 */
+	pie->Value = IBuf[Octet + Off] & 0x7f;
+	Octet++;
+
+	/* Consume optional Diagnostic bytes */
+	while (Q931MoreIE()) {
+		Off++;
+	};
+
+	Q931IESizeTest(Q931E_CAUSE);
+	Q931SetIE(*pIE, *OOff);
+
+	*IOff = (*IOff) + Octet + Off;
+	*OOff = (*OOff) + sizeof(Q931ie_Cause);
+	pie->Size = sizeof(Q931ie_Cause);
+
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:		Q931Pie_Cause
+
+  Parameters:   IBuf[IN]		Ptr to struct.
+				OBuf[OUT]		Ptr tp packed output buffer.
+				Octet[IN/OUT]	Offset into OBuf.
+
+  Return Value:	Error code, 0 = OK
+
+*****************************************************************************/
+L3INT Q931Pie_Cause(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+	Q931ie_Cause *pIE = (Q931ie_Cause*)IBuf;
+	L3INT rc = 0;
+	L3INT Beg = *Octet;
+	L3INT li;
+
+	OBuf[(*Octet)++] = Q931ie_CAUSE;
+	li = (*Octet)++;
+
+	/* Octet 3 */
+	OBuf[(*Octet)++] = 0x80 | (pIE->CodStand<<5) | pIE->Location;
+
+	/* Octet 3a - currently not supported in send */
+
+	/* Octet 4 */
+	OBuf[(*Octet)++] = 0x80 | pIE->Value;
+
+	/* Octet 5 - diagnostics not supported in send */
+
+	OBuf[li] = (L3UCHAR)((*Octet) - Beg) - 2;
+	return rc;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Uie_CongLevel
+  
+  Parameters:   pIE[OUT]		ptr to Information Element id.
+				IBuf[IN]		ptr to a packed ie.
+				OBuf[OUT]	   ptr to buffer for Unpacked ie.
+				IOff[IN\OUT]	Input buffer offset
+				OOff[IN\OUT]	Output buffer offset
+
+				Ibuf and OBuf points directly to buffers. The IOff and OOff
+				must be updated, but are otherwise not used in the ie unpack.
+
+  Return Value: Error Message
+
+*****************************************************************************/
+L3INT Q931Uie_CongLevel(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff) 
+{
+	Q931ie_CongLevel *pie = (Q931ie_CongLevel*)OBuf;
+	ie *pIE = &pMsg->CongestionLevel;
+	L3INT Off = 0;
+	L3INT Octet = 0;
+
+	*pIE = 0;
+
+	pie->IEId      = IBuf[Octet] & 0xf0;
+	pie->CongLevel = IBuf[Octet] & 0x0f;
+	Octet ++;
+
+	Q931SetIE(*pIE, *OOff);
+
+	*IOff = (*IOff) + Octet + Off;
+	*OOff = (*OOff) + sizeof(Q931ie_CongLevel);
+	pie->Size = sizeof(Q931ie_CongLevel);
+
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Pie_CongLevel
+
+  Parameters:   IBuf[IN]		Ptr to struct.
+				OBuf[OUT]		Ptr tp packed output buffer.
+				Octet[IN/OUT]	Offset into OBuf.
+
+  Return Value: Error code, 0 = OK
+
+*****************************************************************************/
+L3INT Q931Pie_CongLevel(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+	Q931ie_CongLevel *pIE = (Q931ie_CongLevel*)IBuf;
+	L3INT rc = 0;
+	/* L3INT Beg = *Octet; */
+
+	OBuf[(*Octet)++] = Q931ie_CONGESTION_LEVEL | pIE->CongLevel;
+
+	return rc;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Uie_ChanID
+
+  Parameters:   IBuf[IN]		ptr to a packed ie.
+				OBuf[OUT]	   ptr to buffer for Unpacked ie.
+				IOff[IN\OUT]	Input buffer offset
+				OOff[IN\OUT]	Output buffer offset
+
+				Ibuf and OBuf points directly to buffers. The IOff and OOff
+				must be updated, but are otherwise not used in the ie unpack.
+
+  Return Value:	Error code, 0 = OK
+
+*****************************************************************************/
+L3INT Q931Uie_ChanID(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR *OBuf, L3INT *IOff, L3INT *OOff)
+{
+	Q931ie_ChanID *pie = (Q931ie_ChanID*)OBuf;
+	ie *pIE = &pMsg->ChanID;
+	L3INT Off = 0;
+	L3INT Octet = 0;
+	L3INT IESize;
+//18 04 e1 80 83 01
+	*pIE = 0;
+
+	Q931Log(pTrunk, Q931_LOG_DEBUG, "Decoding ChanID IE\n");
+
+	/* Octet 1 */
+	pie->IEId = IBuf[Octet++];
+
+	/* Octet 2 */
+	IESize    = IBuf[Octet++]; 
+
+	/* Octet 3 */
+	pie->IntIDPresent = (IBuf[Octet] >> 6) & 0x01;
+	pie->IntType      = (IBuf[Octet] >> 5) & 0x01;
+	pie->PrefExcl     = (IBuf[Octet] >> 3) & 0x01;
+	pie->DChanInd     = (IBuf[Octet] >> 2) & 0x01;
+	pie->InfoChanSel  =  IBuf[Octet] & 0x03;
+
+	Off = Q931ReadExt(&IBuf[Octet++], Off);
+
+	/* Octet 3.1 */
+	if (pie->IntIDPresent) {
+		pie->InterfaceID = IBuf[Octet + Off] & 0x7f;
+
+		/* Temp fix. Interface id can be extended using the extension bit */
+		/* this will read the octets, but do nothing with them. this is done */
+		/* because the usage of this field is a little unclear */
+		/* 30.jan.2001/JVB */
+		Off = Q931ReadExt(&IBuf[Octet + Off], Off);
+		Off++;
+	}
+
+	if ((Octet + Off - 2) != IESize) {
+		/* Octet 3.2 */
+		if (pie->IntType == 1) {        /* PRI etc */
+			pie->CodStand    = (IBuf[Octet + Off] >> 5) & 0x03;
+			pie->NumMap      = (IBuf[Octet + Off] >> 4) & 0x01;
+			pie->ChanMapType =  IBuf[Octet + Off] & 0x0f;
+			Off++;
+
+			/* Octet 3.3 */
+			/* Temp fix. Assume B channel. H channels not supported */
+			pie->ChanSlot = IBuf[Octet + Off] & 0x7f;
+
+			/* Some dialects don't follow the extension coding properly for this, but this should be safe for all */
+			if ((Octet + Off - 1) != IESize) {
+				Off = Q931ReadExt(&IBuf[Octet + Off], Off);
+			}
+			Off++;
+		}
+	}
+
+	Q931IESizeTest(Q931E_CHANID);
+	Q931SetIE(*pIE, *OOff);
+
+	*IOff = (*IOff) + Octet + Off;
+	*OOff = (*OOff) + sizeof(Q931ie_ChanID);
+	pie->Size = sizeof(Q931ie_ChanID);
+
+	if (pTrunk->loglevel == Q931_LOG_DEBUG) {
+		const char *iface;
+		char tmp[100] = "";
+
+		if (!pie->IntType) {
+			switch (pie->InfoChanSel) {
+			case 0x0:
+				iface = "None";
+				break;
+			case 0x1:
+				iface = "B1";
+				break;
+			case 0x2:
+				iface = "B2";
+				break;
+			default:
+				iface = "Any Channel";
+			}
+
+			snprintf(tmp, sizeof(tmp)-1, "InfoChanSel: %d (%s)", pie->InfoChanSel, iface);
+		}
+
+		Q931Log(pTrunk, Q931_LOG_DEBUG,
+			"\n-------------------------- Q.931 Channel ID ------------------------\n"
+			"    Pref/Excl: %s, Interface Type: %s\n"
+			"    %s\n"
+			"--------------------------------------------------------------------\n\n",
+			((pie->PrefExcl) ? "Preferred" : "Exclusive"),
+			((pie->IntType) ? "PRI/Other" : "BRI"),
+			tmp);
+	}
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Pie_ChanID
+
+  Parameters:   IBuf[IN]		Ptr to struct.
+				OBuf[OUT]		Ptr tp packed output buffer.
+				Octet[IN/OUT]	Offset into OBuf.
+
+  Return Value:	Error code, 0 = OK
+
+*****************************************************************************/
+L3INT Q931Pie_ChanID(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+	Q931ie_ChanID *pIE = (Q931ie_ChanID*)IBuf;
+	L3INT rc = Q931E_NO_ERROR;
+	L3INT Beg = *Octet;	/* remember current offset */
+	L3INT li;
+
+	OBuf[(*Octet)++] = Q931ie_CHANNEL_IDENTIFICATION;
+	li = (*Octet)++; /* remember length position */
+
+	/* Octet 3 flags & BRI chan # */
+	OBuf[(*Octet)++] = 0x80 
+			| ((pIE->IntIDPresent << 6) & 0x40)
+			| ((pIE->IntType << 5) & 0x20)
+			| ((pIE->PrefExcl << 3) & 0x08)
+			|  (pIE->InfoChanSel & 0x03);
+
+	/* Octet 3.1 - Interface Identifier */
+	if (pIE->IntIDPresent) {
+		OBuf[(*Octet)++] = 0x80 | (pIE->InterfaceID & 0x7f);
+	}
+
+	/* Octet 3.2 & 3.3 - PRI */
+	if (pIE->IntType) {
+		OBuf[(*Octet)++]  = 0x80
+			| ((pIE->CodStand << 5) & 0x60)
+			| ((pIE->NumMap << 4) & 0x10)
+			|  (pIE->ChanMapType & 0x0f);		/* TODO: support all possible channel map types */
+
+		/* Octet 3.3 Channel number */
+		switch (pIE->ChanMapType) {
+		case 0x6:	/* Slot map: H0 Channel Units */	/* unsupported, Octets 3.3.1 - 3.3.3 */
+			return Q931E_CHANID;
+
+		case 0x8:	/* Slot map: H11 Channel Units */
+		case 0x9:	/* Slot map: H12 Channel Units */
+		default:	/* Channel number */
+			OBuf[(*Octet)++] = 0x80 | (pIE->ChanSlot & 0x7f);
+			break;
+		}
+	}
+
+	OBuf[li] = (L3UCHAR)((*Octet) - Beg) - 2;
+	return rc;
+}
+
+
+/*****************************************************************************
+
+  Function:	 Q931Uie_CRV
+
+  Description:  Reading CRV. 
+
+				The CRV is currently returned in the return value that 
+				Q921Rx23 will assign to the CRV field in the unpacked
+				message. CRV is basically 2 bytes etc, but the spec allows
+				the use of longer CRV values.
+  
+  Parameters:   pIE[OUT]		ptr to Information Element id.
+				IBuf[IN]		ptr to a packed ie.
+				OBuf[OUT]	   ptr to buffer for Unpacked ie.
+				IOff[IN\OUT]	Input buffer offset
+				OOff[IN\OUT]	Output buffer offset
+
+				Ibuf and OBuf points directly to buffers. The IOff and OOff
+				must be updated, but are otherwise not used in the ie unpack.
+
+  Return Value: CRV
+
+*****************************************************************************/
+L3USHORT Q931Uie_CRV(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *IOff, L3INT *OOff)
+{
+	L3USHORT CRV = 0;
+	L3INT Octet = *IOff;
+	L3INT l = IBuf[Octet++]; 
+
+	if (l == 1) {	/* One octet CRV */
+		CRV = IBuf[Octet++] & 0x7F;
+	}
+	else if (l == 2) {	/* two octet CRV */
+		CRV  = (IBuf[Octet++] & 0x7f) << 8;
+		CRV |=  IBuf[Octet++];
+	}
+	else {
+		/* Long CRV is not used, so we skip this */
+		/* TODO: is it right to set to 0 here? */
+		CRV = 0;
+		Octet += l;
+	}
+
+	*IOff = Octet;
+	return CRV;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Uie_DateTime
+
+  Parameters:   pTrunk		[IN]		Ptr to trunk information.
+				pIE			[OUT]       ptr to Information Element id.
+				IBuf		[IN]		ptr to a packed ie.
+				OBuf		[OUT]	   ptr to buffer for Unpacked ie.
+				IOff		[IN\OUT]	Input buffer offset
+				OOff		[IN\OUT]	Output buffer offset
+
+				Ibuf and OBuf points directly to buffers. The IOff and OOff
+				must be updated, but are otherwise not used in the ie unpack.
+
+  Return Value: Error Message
+
+*****************************************************************************/
+L3INT Q931Uie_DateTime(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *IOff, L3INT *OOff)
+{
+	Q931ie_DateTime * pie = (Q931ie_DateTime*)OBuf;
+	ie *pIE = &pMsg->DateTime;
+	L3INT Off = 0;
+	L3INT Octet = 0;
+	L3INT IESize = 0;
+
+	*pIE = 0;
+
+	pie->IEId = IBuf[Octet++];
+	
+	/* Octet 2 */
+	IESize = IBuf[Octet++]; 
+
+	/* Octet 3 - Year */
+	pie->Year = IBuf[Octet++];
+
+	/* Octet 4 - Month */
+	pie->Month = IBuf[Octet++];
+
+	/* Octet 5 - Day */
+	pie->Day = IBuf[Octet++];
+
+	/*******************************************************************
+		The remaining part of the IE are optioinal, but only the length 
+		can now tell us wherever these fields are present or not
+		(always remember: IESize does not include ID and Size octet)
+	********************************************************************/
+	pie->Format = 0;
+
+	/* Octet 6 - Hour (optional)*/
+	if (IESize >= 4) {
+		pie->Format = 1;
+		pie->Hour = IBuf[Octet++];
+
+		/* Octet 7 - Minute (optional)*/
+		if (IESize >= 5) {
+			pie->Format = 2;
+			pie->Minute = IBuf[Octet++];
+
+			/* Octet 8 - Second (optional)*/
+			if (IESize >= 6) {
+				pie->Format = 3;
+				pie->Second = IBuf[Octet++];
+			}
+		}
+	}
+
+	Q931IESizeTest(Q931E_DATETIME);
+	Q931SetIE(*pIE, *OOff);
+
+	*IOff = (*IOff) + Octet + Off;
+	*OOff = (*OOff) + sizeof(Q931ie_DateTime);
+	pie->Size = sizeof(Q931ie_DateTime);
+
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Pie_DateTime
+
+  Parameters:   IBuf[IN]		Ptr to struct.
+				OBuf[OUT]		Ptr tp packed output buffer.
+				Octet[IN/OUT]	Offset into OBuf.
+
+  Return Value:	Error code, 0 = OK
+
+*****************************************************************************/
+L3INT Q931Pie_DateTime(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+	Q931ie_DateTime *pIE = (Q931ie_DateTime*)IBuf;
+	L3INT rc = 0;
+	L3INT Beg = *Octet;
+	L3INT li;
+
+	OBuf[(*Octet)++] = Q931ie_DATETIME;
+	li = (*Octet)++;
+
+	OBuf[(*Octet)++] = pIE->Year;
+	OBuf[(*Octet)++] = pIE->Month;
+	OBuf[(*Octet)++] = pIE->Day;
+	if (pIE->Format >= 1) {
+		OBuf[(*Octet)++] = pIE->Hour;
+
+		if (pIE->Format >= 2) {
+			OBuf[(*Octet)++] = pIE->Minute;
+
+			if (pIE->Format >= 3) {
+				OBuf[(*Octet)++] = pIE->Second;
+			}
+		}
+	}
+
+	OBuf[li] = (L3UCHAR)((*Octet)-Beg) - 2;
+	return rc;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Uie_Display
+
+  Parameters:   pIE[OUT]		ptr to Information Element id.
+				IBuf[IN]		ptr to a packed ie.
+				OBuf[OUT]	   ptr to buffer for Unpacked ie.
+				IOff[IN\OUT]	Input buffer offset
+				OOff[IN\OUT]	Output buffer offset
+
+				Ibuf and OBuf points directly to buffers. The IOff and OOff
+				must be updated, but are otherwise not used in the ie unpack.
+
+  Return Value: Error Message
+
+*****************************************************************************/
+L3INT Q931Uie_Display(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff)
+{
+	Q931ie_Display *pie = (Q931ie_Display*)OBuf;
+	ie *pIE = &pMsg->Display;
+	L3INT Off = 0;
+	L3INT Octet = 0;
+	L3INT IESize;
+	L3INT x;
+
+	*pIE = 0;
+
+	pie->IEId = IBuf[Octet++];
+	IESize    = IBuf[Octet++]; 
+
+	for (x = 0; x<IESize; x++) {
+		pie->Display[x] = IBuf[Octet + Off] & 0x7f;
+		Off++;
+	}
+
+	Q931IESizeTest(Q931E_DISPLAY);
+	Q931SetIE(*pIE, *OOff);
+
+	*IOff = (*IOff) + Octet + Off;
+	*OOff = (*OOff) + sizeof(Q931ie_Display) + x - 1;
+	pie->Size = (L3UCHAR)(sizeof(Q931ie_Display) + x - 1);
+
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Pie_Display
+
+  Parameters:   IBuf[IN]		Ptr to struct.
+				OBuf[OUT]		Ptr tp packed output buffer.
+				Octet[IN/OUT]	Offset into OBuf.
+
+  Return Value:	Error code, 0 = OK
+
+*****************************************************************************/
+L3INT Q931Pie_Display(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+	Q931ie_Display *pIE = (Q931ie_Display*)IBuf;
+	L3INT rc = 0;
+	L3INT Beg = *Octet;
+	L3INT li;
+	L3INT DSize;
+	L3INT x;
+
+	OBuf[(*Octet)++] = Q931ie_DISPLAY;
+	li = (*Octet)++;
+
+	DSize = pIE->Size - sizeof(Q931ie_Display);
+
+	for (x = 0; x< DSize; x++) {
+		
+		OBuf[(*Octet)++] = pIE->Display[x];
+	}
+
+	OBuf[li] = (L3UCHAR)((*Octet) - Beg) - 2;
+	return rc;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Uie_HLComp
+
+  Parameters:   pIE[OUT]		ptr to Information Element id.
+				IBuf[IN]		ptr to a packed ie.
+				OBuf[OUT]	   ptr to buffer for Unpacked ie.
+				IOff[IN\OUT]	Input buffer offset
+				OOff[IN\OUT]	Output buffer offset
+
+				Ibuf and OBuf points directly to buffers. The IOff and OOff
+				must be updated, but are otherwise not used in the ie unpack.
+
+  Return Value: Error Message
+
+*****************************************************************************/
+L3INT Q931Uie_HLComp(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff) 
+{
+	Q931ie_HLComp * pie = (Q931ie_HLComp*)OBuf;
+	ie *pIE = &pMsg->HLComp;
+	L3INT Off = 0;
+	L3INT Octet = 0;
+	L3INT IESize;
+
+	*pIE = 0;
+
+	pie->IEId = IBuf[Octet++];
+
+	/* Octet */
+	IESize = IBuf[Octet++]; 
+
+	/* Octet 3*/
+	pie->CodStand  = (IBuf[Octet + Off] >>5) & 0x03;
+	pie->Interpret = (IBuf[Octet + Off] >>2) & 0x07;
+	pie->PresMeth  =  IBuf[Octet + Off] & 0x03;
+	Octet++;
+
+	/* Octet 4 */
+	pie->HLCharID = IBuf[Octet + Off] & 0x7f;
+	Octet++;
+	
+	/* Octet 4a*/
+	if ((IBuf[Octet + Off - 1] & 0x80) == 0 && Q931MoreIE()) {
+		if (pie->HLCharID == 0x5e || pie->HLCharID == 0x5f) {
+			pie->EHLCharID = IBuf[Octet + Off] & 0x7f;
+			Off++;
+		}
+		else if ( pie->HLCharID >= 0xc3 && pie->HLCharID <= 0xcf) {
+			pie->EVideoTlfCharID = IBuf[Octet + Off] & 0x7f;
+			Off++;
+		}
+		else {
+			/* error Octet 4a indicated, but invalid value in Octet 4. */
+			Q931SetError(pTrunk,Q931E_HLCOMP, 4, Off);
+			return Q931E_HLCOMP;
+		}
+		Off = Q931ReadExt(&IBuf[Octet + Off], Off);
+	}
+
+	Q931IESizeTest(Q931E_HLCOMP);
+	Q931SetIE(*pIE, *OOff);
+
+	*IOff = (*IOff) + Octet + Off;
+	*OOff = (*OOff) + sizeof(Q931ie_HLComp);
+	pie->Size = sizeof(Q931ie_HLComp);
+
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Pie_HLComp
+
+  Parameters:   IBuf[IN]		Ptr to struct.
+				OBuf[OUT]		Ptr tp packed output buffer.
+				Octet[IN/OUT]	Offset into OBuf.
+
+  Return Value:	Error code, 0 = OK
+
+*****************************************************************************/
+L3INT Q931Pie_HLComp(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+	Q931ie_HLComp *pIE = (Q931ie_HLComp*)IBuf;
+	L3INT rc = 0;
+	L3INT Beg = *Octet;
+	L3INT li;
+
+	OBuf[(*Octet)++] = Q931ie_HIGH_LAYER_COMPATIBILITY;
+	li = (*Octet)++;
+
+	/* Octet 3 */
+	OBuf[(*Octet)++] = 0x80 | ((pIE->CodStand << 5) & 0x60) | ((pIE->Interpret << 2) & 0x1c) | (pIE->PresMeth & 0x03);
+
+	/* Octet 4 */
+	OBuf[(*Octet)++] = pIE->HLCharID;
+
+	/* Octet 4a */
+	if (pIE->HLCharID == 0x5e || pIE->HLCharID == 0x5f) {
+		OBuf[(*Octet)++] = 0x80 | (pIE->EHLCharID & 0x7f);
+	}
+	else if ( pIE->HLCharID >= 0xc3 && pIE->HLCharID <= 0xcf) {
+		OBuf[(*Octet)++] = 0x80 | (pIE->EVideoTlfCharID & 0x7f);
+	}
+	else {
+		OBuf[(*Octet) - 1] |= 0x80;
+	}
+
+	OBuf[li] = (L3UCHAR)((*Octet) - Beg) - 2;
+	return rc;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Uie_KeypadFac
+
+  Parameters:   pIE[OUT]		ptr to Information Element id.
+				IBuf[IN]		ptr to a packed ie.
+				OBuf[OUT]	   ptr to buffer for Unpacked ie.
+				IOff[IN\OUT]	Input buffer offset
+				OOff[IN\OUT]	Output buffer offset
+
+				Ibuf and OBuf points directly to buffers. The IOff and OOff
+				must be updated, but are otherwise not used in the ie unpack.
+
+  Return Value: Error Message
+
+*****************************************************************************/
+L3INT Q931Uie_KeypadFac(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff)
+{
+	Q931ie_KeypadFac *pie = (Q931ie_KeypadFac*)OBuf;
+	ie *pIE = &pMsg->KeypadFac;
+	L3INT Off = 0;
+	L3INT Octet = 0;
+	L3INT IESize;
+	L3INT x;
+
+	*pIE = 0;
+
+	pie->IEId = IBuf[Octet++];
+	IESize = IBuf[Octet++]; 
+
+	for (x = 0; x<IESize; x++) {
+		pie->KeypadFac[x] = IBuf[Octet + Off] & 0x7f;
+		Off++;
+	}
+
+	Q931IESizeTest(Q931E_KEYPADFAC);
+	Q931SetIE(*pIE, *OOff);
+
+	*IOff = (*IOff) + Octet + Off;
+	*OOff = (*OOff) + sizeof(Q931ie_KeypadFac) + x - 1;
+	pie->Size = (L3UCHAR)(sizeof(Q931ie_KeypadFac) + x - 1);
+
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Pie_KeypadFac
+
+  Parameters:   IBuf[IN]		Ptr to struct.
+				OBuf[OUT]		Ptr tp packed output buffer.
+				Octet[IN/OUT]	Offset into OBuf.
+
+  Return Value:	Error code, 0 = OK
+
+*****************************************************************************/
+L3INT Q931Pie_KeypadFac(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+	Q931ie_KeypadFac *pIE = (Q931ie_KeypadFac*)IBuf;
+	L3INT rc = 0;
+	L3INT Beg = *Octet;
+	L3INT li;
+	L3INT DSize;
+	L3INT x;
+
+	OBuf[(*Octet)++] = Q931ie_KEYPAD_FACILITY;
+	li = (*Octet)++;
+
+	DSize = pIE->Size - sizeof(Q931ie_KeypadFac) + 1;
+
+	for (x = 0; x< DSize; x++) {
+		OBuf[(*Octet)++] = pIE->KeypadFac[x];
+	}
+
+	OBuf[li] = (L3UCHAR)((*Octet) - Beg) - 2;
+	return rc;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Uie_LLComp
+
+  Parameters:   pIE[OUT]		ptr to Information Element id.
+				IBuf[IN]		ptr to a packed ie.
+				OBuf[OUT]	   ptr to buffer for Unpacked ie.
+				IOff[IN\OUT]	Input buffer offset
+				OOff[IN\OUT]	Output buffer offset
+
+				Ibuf and OBuf points directly to buffers. The IOff and OOff
+				must be updated, but are otherwise not used in the ie unpack.
+
+  Return Value: Error Message
+
+*****************************************************************************/
+L3INT Q931Uie_LLComp(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff)
+{
+	Q931ie_LLComp *pie = (Q931ie_LLComp*)OBuf;
+	ie *pIE = &pMsg->LLComp;
+	L3INT Off = 0;
+	L3INT Octet = 0;
+	L3INT IESize;
+
+	*pIE = 0;
+
+	pie->IEId = IBuf[Octet++];
+
+	/* Octet 2 */
+	IESize = IBuf[Octet++]; 
+
+	/* Octet 3 */
+	pie->CodStand  = (IBuf[Octet + Off] >> 5) & 0x03;
+	pie->ITransCap =  IBuf[Octet + Off] & 0x1f;
+	Octet++;
+
+	/* Octet 3a*/
+	if (IsQ931Ext(IBuf[Octet + Off - 1])) {
+		pie->NegotInd = (IBuf[Octet + Off] >> 6) & 0x01;
+		Off++;
+	}
+
+	/* Octet 4 */
+	pie->TransMode = (IBuf[Octet + Off] >> 5) & 0x03;
+	pie->InfoRate  =  IBuf[Octet + Off] & 0x1f;
+
+	Octet++;
+
+	/* Octet 4.1 */
+	if (pie->InfoRate == 0x14) { /* Mutirate */
+		pie->RateMul = IBuf[Octet + Off] & 0x7f;
+		Off++;
+	}
+
+	/* Octet 5 - Layer 1 Ident */
+	if ((IBuf[Octet + Off] & 0x60) == 0x20) { /* Layer 1 Ident ? */
+		pie->Layer1Ident = (IBuf[Octet + Off] >> 5) & 0x03;
+		pie->UIL1Prot    =  IBuf[Octet + Off] & 0x1f;
+		Octet++;
+
+		/* Octet 5a */
+		if (IsQ931Ext(IBuf[Octet + Off - 1])) {
+			pie->SyncAsync = (IBuf[Octet + Off] >> 6) & 0x01;
+			pie->Negot     = (IBuf[Octet + Off] >> 5) & 0x01;
+			pie->UserRate  =  IBuf[Octet + Off] & 0x1f;
+			Off++;
+
+			/* Octet 5b - 2 options */
+			if (IsQ931Ext(IBuf[Octet + Off - 1])) {
+				if (pie->UIL1Prot == 0x01) { /* V.110, I.460 and X.30*/
+					pie->InterRate = (IBuf[Octet + Off] >> 5) & 0x03;
+					pie->NIConTx   = (IBuf[Octet + Off] >> 4) & 0x01;
+					pie->NIConRx   = (IBuf[Octet + Off] >> 3) & 0x01;
+					pie->FlowCtlTx = (IBuf[Octet + Off] >> 2) & 0x01;
+					pie->FlowCtlRx = (IBuf[Octet + Off] >> 1) & 0x01;
+					Off++;
+				}
+				else if (pie->UIL1Prot == 0x80) { /* V.120 */
+					pie->HDR        = (IBuf[Octet + Off] >> 6) & 0x01;
+					pie->MultiFrame = (IBuf[Octet + Off] >> 5) & 0x01;
+					pie->ModeL1     = (IBuf[Octet + Off] >> 4) & 0x01;
+					pie->NegotLLI   = (IBuf[Octet + Off] >> 3) & 0x01;
+					pie->Assignor   = (IBuf[Octet + Off] >> 2) & 0x01;
+					pie->InBandNeg  = (IBuf[Octet + Off] >> 1) & 0x01;
+					Off++;
+				}
+				else if (pie->UIL1Prot == 0x07) { /* non standard */
+					Off = Q931ReadExt(&IBuf[Octet + Off], Off);
+					Off++;
+				}
+				else {
+					Q931SetError(pTrunk,Q931E_LLCOMP, 5,2);
+					return Q931E_LLCOMP;
+				}
+
+				/* Octet 5c */
+				if (IsQ931Ext(IBuf[Octet + Off - 1])) {
+					pie->NumStopBits = (IBuf[Octet + Off] >> 5) & 0x03;
+					pie->NumDataBits = (IBuf[Octet + Off] >> 3) & 0x03;
+					pie->Parity      =  IBuf[Octet + Off] & 0x07;
+					Off++;
+
+					/* Octet 5d */
+					if (IsQ931Ext(IBuf[Octet + Off - 1])) {
+						pie->DuplexMode	= (IBuf[Octet + Off] >> 6) & 0x01;
+						pie->ModemType  =  IBuf[Octet + Off] & 0x3f;
+						Off = Q931ReadExt(&IBuf[Octet + Off], Off);
+						Off++;
+					}
+				}
+			}
+		}
+	}
+
+	/* Octet 6 - Layer 2 Ident */
+	if ((IBuf[Octet + Off] & 0x60) == 0x40) { /* Layer 1 Ident ? */
+		pie->Layer2Ident = (IBuf[Octet + Off] >>5) & 0x03;
+		pie->UIL2Prot    =  IBuf[Octet + Off] & 0x1f;
+		Octet++;
+
+		/* Octet 6a */
+		if (IsQ931Ext(IBuf[Octet + Off - 1])) {
+			if (pie->UIL2Prot == 0x10) { /* 2nd 6a */
+				pie->UsrSpcL2Prot = IBuf[Octet + Off] & 0x7f;
+				Off++;
+			}
+			else { /* assume 1st 6a */
+				pie->ModeL2  = (IBuf[Octet + Off] >> 5) & 0x03;
+				pie->Q933use =  IBuf[Octet + Off] & 0x03;
+				Off++;
+			}
+			/* Octet 6b */
+			if (IsQ931Ext(IBuf[Octet + Off - 1])) {
+				pie->WindowSize = IBuf[Octet + Off] & 0x7f;
+				Off++;
+			}
+		}
+	}
+
+	/* Octet 7 - layer 3 Ident */
+	if ((IBuf[Octet + Off] & 0x60) == 0x60) { /* Layer 3 Ident ? */
+		pie->Layer3Ident = (IBuf[Octet + Off] >> 5) & 0x03;
+		pie->UIL3Prot    =  IBuf[Octet + Off] & 0x1f;
+		Octet++;
+
+		/* Octet 7a */
+		if (IsQ931Ext(IBuf[Octet + Off - 1])) {
+			if (pie->UIL3Prot == 0x0b) {
+				/* Octet 7a + 7b AddL3Info */
+				pie->AddL3Info = ((IBuf[Octet + Off] << 4) & 0xf0)
+								| (IBuf[Octet + Off + 1] & 0x0f);
+				Off += 2;
+			}
+			else {
+				if (pie->UIL3Prot == 0x1f) {
+					pie->ModeL3 = (IBuf[Octet + Off] >> 5) & 0x03;
+					Off++;
+				}
+				else {
+					pie->OptL3Info = IBuf[Octet + Off] & 0x7f;
+					Off++;
+				}
+
+				/* Octet 7b*/
+				if (IsQ931Ext(IBuf[Octet + Off - 1])) {
+					pie->DefPackSize = IBuf[Octet + Off] & 0x0f;
+					Off++;
+
+					/* Octet 7c */
+					if (IsQ931Ext(IBuf[Octet + Off - 1])) {
+						pie->PackWinSize= IBuf[Octet + Off] & 0x7f;
+					}
+				}
+			}
+		}
+	}
+
+	Q931IESizeTest(Q931E_LLCOMP);
+	Q931SetIE(*pIE, *OOff);
+
+	*IOff = (*IOff) + Octet + Off;
+	*OOff = (*OOff) + sizeof(Q931ie_LLComp);
+	pie->Size = sizeof(Q931ie_LLComp);
+
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Pie_LLComp
+
+  Parameters:   IBuf[IN]		Ptr to struct.
+				OBuf[OUT]		Ptr tp packed output buffer.
+				Octet[IN/OUT]	Offset into OBuf.
+
+  Return Value: Error code, 0 = OK
+
+*****************************************************************************/
+L3INT Q931Pie_LLComp(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+	Q931ie_LLComp *pIE = (Q931ie_LLComp*)IBuf;
+	L3INT rc = 0;
+	L3INT Beg = *Octet;
+	L3INT li;
+
+	OBuf[(*Octet)++] = Q931ie_LOW_LAYER_COMPATIBILITY;
+	li = (*Octet)++;
+
+	/* Octet 3 */
+	OBuf[(*Octet)++] = (pIE->CodStand << 6) | pIE->ITransCap;
+
+	/* Octet 3a */
+	OBuf[(*Octet)++] = 0x80 | (pIE->NegotInd << 6);
+
+	/* Octet 4 */
+	OBuf[(*Octet)++] = 0x80 | (pIE->TransMode << 5) | pIE->InfoRate;
+
+	/* Octet 4.1 */
+	if (pIE->InfoRate == 0x18) {
+		OBuf[(*Octet)++] = 0x80 | pIE->RateMul;
+	}
+
+	/* Octet 5 */
+	if (pIE->Layer1Ident == 0x01) {
+		OBuf[(*Octet)++] = (pIE->Layer1Ident << 5) | pIE->UIL1Prot;
+		
+		/* Octet 5a */
+		if ((pIE->ITransCap == 0x08 && (pIE->UIL1Prot == 0x01 || pIE->UIL1Prot == 0x08))
+			|| (pIE->ITransCap == 0x10 && (pIE->UIL1Prot == 0x02 || pIE->UIL1Prot == 0x03))) {
+			OBuf[(*Octet)++] = (pIE->SyncAsync<<6) | (pIE->Negot<<5) | pIE->UserRate;
+			
+			/* Octet 5b*/
+			if (pIE->UIL1Prot == 0x01) {
+				OBuf[(*Octet)++] =  (pIE->InterRate << 5)
+							| (pIE->NIConTx << 4)
+							| (pIE->NIConTx << 3)
+							| (pIE->FlowCtlTx << 2)
+							| (pIE->FlowCtlRx << 1);
+			}
+			else if (pIE->UIL1Prot == 0x08) {
+				OBuf[(*Octet)++] =  (pIE->HDR << 6)
+							| (pIE->MultiFrame << 5)
+							| (pIE->ModeL1 << 4)
+							| (pIE->NegotLLI << 3)
+							| (pIE->Assignor << 2)
+							| (pIE->InBandNeg << 1);
+			}
+			else {
+				OBuf[(*Octet) - 1] |= 0x80;
+			}
+
+			/* How to detect wherever 5c and 5d is to present is not clear
+			 * but they have been inculded as 'standard'
+			 * Octet 5c
+			 */
+			if (pIE->UIL1Prot == 0x01 || pIE->UIL1Prot == 0x08) {
+				OBuf[(*Octet)++] = (pIE->NumStopBits << 5) | (pIE->NumDataBits << 3) | pIE->Parity ;
+
+				/* Octet 5d */
+				OBuf[(*Octet)++] = 0x80 | (pIE->DuplexMode << 6) | pIE->ModemType;
+			}
+		}
+		else {
+			OBuf[(*Octet) - 1] |= 0x80;
+		}
+	}
+
+	/* Octet 6 */
+	if (pIE->Layer2Ident == 0x02) {
+		OBuf[(*Octet)++] = (pIE->Layer2Ident << 5) | pIE->UIL2Prot;
+
+		/* Octet 6a*/
+		if (pIE->UIL2Prot == 0x02 /* Q.921/I.441 */
+		|| pIE->UIL2Prot == 0x06 /* X.25 link layer */
+		|| pIE->UIL2Prot == 0x07 /* X.25 multilink */
+		|| pIE->UIL2Prot == 0x09 /* HDLC ARM */
+		|| pIE->UIL2Prot == 0x0a /* HDLC NRM */
+		|| pIE->UIL2Prot == 0x0b /* HDLC ABM */
+		|| pIE->UIL2Prot == 0x0d /* X.75 SLP */
+		|| pIE->UIL2Prot == 0x0e /* Q.922 */
+		|| pIE->UIL2Prot == 0x11) { /* ISO/ECE 7776 DTE-DCE */
+			OBuf[(*Octet)++] = (pIE->ModeL2 << 5) | pIE->Q933use;
+
+			/* Octet 6b */
+			OBuf[(*Octet)++] = 0x80 | pIE->WindowSize;
+		}
+		else if (pIE->UIL2Prot == 0x10) { /* User Specific */
+			OBuf[(*Octet)++] = 0x80 | pIE->UsrSpcL2Prot;
+		}
+		else {
+			OBuf[(*Octet) - 1] |= 0x80;
+		}
+	}
+
+	/* Octet 7 */
+	if (pIE->Layer3Ident == 0x03) {
+		OBuf[(*Octet)++] = (pIE->Layer3Ident << 5) | pIE->UIL3Prot;
+
+		/* Octet 7a - 3 different ones */
+		if (pIE->UIL3Prot == 0x10) {
+			OBuf[(*Octet++)] = 0x80 | pIE->OptL3Info;
+		}
+		else if (pIE->UIL3Prot == 0x06
+			||  pIE->UIL3Prot == 0x07
+			||  pIE->UIL3Prot == 0x08) {
+			OBuf[(*Octet)++] = pIE->ModeL3 << 5;
+
+			/* Octet 7b note 7 */
+			OBuf[(*Octet)++] = pIE->DefPackSize;
+
+			/* Octet 7c note 7 */
+			OBuf[(*Octet)++] = 0x80 | pIE->PackWinSize;
+		}
+		else if (pIE->UIL3Prot == 0x0b) {
+			OBuf[(*Octet)++] = (pIE->AddL3Info >> 4) & 0x0f;
+			OBuf[(*Octet)++] = 0x80 | (pIE->AddL3Info & 0x0f);
+		}
+		else {
+			OBuf[(*Octet) - 1] |= 0x80;
+		}
+	}
+	else {
+		Q931SetError(pTrunk,Q931E_LLCOMP, 7,0);
+		rc = Q931E_LLCOMP;
+	}
+
+	OBuf[li] = (L3UCHAR)((*Octet) - Beg) - 2;
+	return rc;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Uie_NetFac
+
+  Parameters:   pIE[OUT]		ptr to Information Element id.
+				IBuf[IN]		ptr to a packed ie.
+				OBuf[OUT]	   ptr to buffer for Unpacked ie.
+				IOff[IN\OUT]	Input buffer offset
+				OOff[IN\OUT]	Output buffer offset
+
+				Ibuf and OBuf points directly to buffers. The IOff and OOff
+				must be updated, but are otherwise not used in the ie unpack.
+
+  Return Value: Error Message
+
+*****************************************************************************/
+L3INT Q931Uie_NetFac(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff)
+{
+	Q931ie_NetFac *pie = (Q931ie_NetFac*)OBuf;
+	ie *pIE = &pMsg->NetFac;
+	L3INT Off = 0;
+	L3INT Octet = 0;
+	L3INT x = 0;
+	L3INT IESize;
+
+	*pIE = 0;
+
+	pie->IEId = IBuf[Octet++];
+
+	/* Octet 2 */
+	IESize = IBuf[Octet++]; 
+
+	pie->LenNetID = IBuf[Octet + Off]; /* full octet is used */
+	Octet++;
+
+	if (pie->LenNetID > 0) {
+		/* Octet 3.1 */
+		pie->TypeNetID = (IBuf[Octet + Off] >> 4) & 0x0f;
+		pie->NetIDPlan =  IBuf[Octet + Off] & 0x0f;
+		Off = Q931ReadExt(&IBuf[Octet], Off);
+		Off++;
+
+		/* Octet 3.2*/
+		for (x = 0; x < pie->LenNetID; x++) {
+			pie->NetID[x] = IBuf[Octet + Off] & 0x7f;
+			Off++;
+		}
+	}
+
+	/* Octet 4*/
+	pie->NetFac = IBuf[Octet + Off]; /* Full Octet is used */
+	Octet++;
+
+	Q931IESizeTest(Q931E_NETFAC);
+	Q931SetIE(*pIE, *OOff);
+
+	*IOff = (*IOff) + Octet + Off;
+	*OOff = (*OOff) + sizeof(Q931ie_NetFac) + x - 1;
+	pie->Size = (L3UCHAR)(sizeof(Q931ie_NetFac) + x - 1);
+
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Pie_NetFac
+
+  Parameters:   IBuf[IN]		Ptr to struct.
+				OBuf[OUT]		Ptr tp packed output buffer.
+				Octet[IN/OUT]	Offset into OBuf.
+
+  Return Value:	Error code, 0 = OK
+
+*****************************************************************************/
+L3INT Q931Pie_NetFac(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+	Q931ie_NetFac *pIE = (Q931ie_NetFac*)IBuf;
+	L3INT rc = Q931E_NO_ERROR;
+	L3INT Beg = *Octet;
+	L3INT li;
+	L3INT x;
+
+	OBuf[(*Octet)++] = Q931ie_NETWORK_SPECIFIC_FACILITIES;
+	li = (*Octet)++;
+
+	/* Octet 3 */
+	OBuf[(*Octet)++] = pIE->LenNetID;
+
+	if (pIE->LenNetID > 0) {
+		/* Octet 3.1 */
+		OBuf[(*Octet)++] = 0x80 | (pIE->TypeNetID << 4) | pIE->NetIDPlan;
+
+		/* Octet 3.2 */
+		for (x = 0; x <pIE->LenNetID; x++) {
+			OBuf[(*Octet)++] = pIE->NetID[x];
+		}
+	}
+
+	/* Octet 4 */
+	OBuf[(*Octet)++] = pIE->NetFac;
+
+	OBuf[li] = (L3UCHAR)((*Octet) - Beg) - 2;
+	return rc;
+}
+
+/*****************************************************************************
+
+  Function:		Q931Uie_NotifInd
+
+  Parameters:   pIE[OUT]		ptr to Information Element id.
+				IBuf[IN]		ptr to a packed ie.
+				OBuf[OUT]	   ptr to buffer for Unpacked ie.
+				IOff[IN\OUT]	Input buffer offset
+				OOff[IN\OUT]	Output buffer offset
+
+				Ibuf and OBuf points directly to buffers. The IOff and OOff
+				must be updated, but are otherwise not used in the ie unpack.
+
+  Return Value: Error Message
+
+*****************************************************************************/
+L3INT Q931Uie_NotifInd(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff)
+{
+	Q931ie_NotifInd *pie = (Q931ie_NotifInd*)OBuf;
+	ie *pIE = &pMsg->NotifInd;
+	L3INT Off = 0;
+	L3INT Octet = 0;
+	L3INT IESize;
+
+	*pIE = 0;
+
+	pie->IEId = IBuf[Octet++];
+
+	/* Octet 2*/
+	IESize = IBuf[Octet++]; 
+
+	/* Octet 3 */
+	pie->Notification = IBuf[Octet + Off] & 0x7f;
+
+	Off = Q931ReadExt(&IBuf[Octet], Off);
+	Octet++;
+
+	Q931IESizeTest(Q931E_NOTIFIND);
+	Q931SetIE(*pIE, *OOff);
+
+	*IOff = (*IOff) + Octet + Off;
+	*OOff = (*OOff) + sizeof(Q931ie_NotifInd);
+	pie->Size = sizeof(Q931ie_NotifInd);
+
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Pie_NotifInd
+
+  Parameters:   IBuf[IN]		Ptr to struct.
+				OBuf[OUT]		Ptr tp packed output buffer.
+				Octet[IN/OUT]	Offset into OBuf.
+
+  Return Value:	Error code, 0 = OK
+
+*****************************************************************************/
+L3INT Q931Pie_NotifInd(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+	Q931ie_NotifInd *pIE = (Q931ie_NotifInd*)IBuf;
+	L3INT rc = Q931E_NO_ERROR;
+	L3INT Beg = *Octet;
+	L3INT li;
+
+	OBuf[(*Octet)++] = Q931ie_NOTIFICATION_INDICATOR;
+	li = (*Octet)++;
+
+	/* Octet 3 */
+	OBuf[(*Octet)++] = pIE->Notification;
+
+	OBuf[li] = (L3UCHAR)((*Octet) - Beg) - 2;
+	return rc;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Uie_ProgInd
+
+  Parameters:   pIE[OUT]		ptr to Information Element id.
+				IBuf[IN]		ptr to a packed ie.
+				OBuf[OUT]	   ptr to buffer for Unpacked ie.
+				IOff[IN\OUT]	Input buffer offset
+				OOff[IN\OUT]	Output buffer offset
+
+				Ibuf and OBuf points directly to buffers. The IOff and OOff
+				must be updated, but are otherwise not used in the ie unpack.
+
+  Return Value: Error Message
+
+*****************************************************************************/
+L3INT Q931Uie_ProgInd(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff)
+{
+	Q931ie_ProgInd *pie = (Q931ie_ProgInd*)OBuf;
+	ie *pIE = &pMsg->ProgInd;
+	L3INT Off = 0;
+	L3INT Octet = 0;
+	L3INT IESize;
+
+	*pIE = 0;
+
+	pie->IEId = IBuf[Octet++];
+
+	/* Octet 2 */
+	IESize = IBuf[Octet++]; 
+
+	/* Octet 3 */
+	pie->CodStand = (IBuf[Octet + Off] >> 5) & 0x03;
+	pie->Location =  IBuf[Octet + Off] & 0x0f;
+
+	Off = Q931ReadExt(&IBuf[Octet], Off);
+	Octet++;
+
+	/* Octet 4 */
+	pie->ProgDesc = IBuf[Octet + Off] & 0x7f;
+	Off = Q931ReadExt(&IBuf[Octet], Off);
+	Octet++;
+
+	Q931IESizeTest(Q931E_PROGIND);
+	Q931SetIE(*pIE, *OOff);
+
+	*IOff = (*IOff) + Octet + Off;
+	*OOff = (*OOff) + sizeof(Q931ie_ProgInd);
+	pie->Size = sizeof(Q931ie_ProgInd);
+
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Pie_ProgInd
+
+  Parameters:   IBuf[IN]		Ptr to struct.
+				OBuf[OUT]	   Ptr tp packed output buffer.
+				Octet[IN/OUT]   Offset L3INTo OBuf.
+
+  Return Value: Error code, 0 = OK
+
+*****************************************************************************/
+L3INT Q931Pie_ProgInd(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+	Q931ie_ProgInd *pIE = (Q931ie_ProgInd*)IBuf;
+	L3INT rc = Q931E_NO_ERROR;
+	L3INT Beg = *Octet;
+	L3INT li;
+
+	OBuf[(*Octet)++] = Q931ie_PROGRESS_INDICATOR;
+	li = (*Octet)++;
+
+	/* Octet 3 */
+	OBuf[(*Octet)++] = 0x80 | (pIE->CodStand << 5) | pIE->Location;
+
+	/* Octet 4 */
+	OBuf[(*Octet)++] = 0x80 | pIE->ProgDesc;
+
+	OBuf[li] = (L3UCHAR)((*Octet) - Beg) - 2;
+	return rc;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Uie_RepeatInd
+
+  Parameters:   pIE[OUT]		ptr to Information Element id.
+				IBuf[IN]		ptr to a packed ie.
+				OBuf[OUT]	   ptr to buffer for Unpacked ie.
+				IOff[IN\OUT]	Input buffer offset
+				OOff[IN\OUT]	Output buffer offset
+
+				Ibuf and OBuf points directly to buffers. The IOff and OOff
+				must be updated, but are otherwise not used in the ie unpack.
+
+  Return Value: Error Message
+
+*****************************************************************************/
+L3INT Q931Uie_RepeatInd(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff)
+{
+	Q931ie_RepeatInd *pie = (Q931ie_RepeatInd*)OBuf;
+	ie *pIE = &pMsg->RepeatInd;
+	L3INT Off = 0;
+	L3INT Octet = 0;
+
+	*pIE = 0;
+
+	pie->IEId      = IBuf[Octet] & 0xf0;
+	pie->RepeatInd = IBuf[Octet] & 0x0f;
+	Octet ++;
+
+	Q931SetIE(*pIE, *OOff);
+
+	*IOff = (*IOff) + Octet + Off;
+	*OOff = (*OOff) + sizeof(Q931ie_RepeatInd);
+	pie->Size = sizeof(Q931ie_RepeatInd);
+
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Pie_RepeatInd
+
+  Parameters:   IBuf[IN]		Ptr to struct.
+				OBuf[OUT]		Ptr tp packed output buffer.
+				Octet[IN/OUT]	Offset into OBuf.
+
+  Return Value:	Error code, 0 = OK
+
+*****************************************************************************/
+L3INT Q931Pie_RepeatInd(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+	Q931ie_RepeatInd *pIE = (Q931ie_RepeatInd*)IBuf;
+	L3INT rc = 0;
+	/* L3INT Beg = *Octet; */
+
+	OBuf[(*Octet)++] = Q931ie_REPEAT_INDICATOR | pIE->RepeatInd;
+
+	return rc;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Uie_RevChargeInd
+
+  Parameters:   pIE[OUT]		ptr to Information Element id.
+				IBuf[IN]		ptr to a packed ie.
+				OBuf[OUT]	   ptr to buffer for Unpacked ie.
+				IOff[IN\OUT]	Input buffer offset
+				OOff[IN\OUT]	Output buffer offset
+
+				Ibuf and OBuf points directly to buffers. The IOff and OOff
+				must be updated, but are otherwise not used in the ie unpack.
+
+  Return Value: Error Message
+
+*****************************************************************************/
+L3INT Q931Uie_RevChargeInd(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff)
+{
+	ie iE;
+	/* ie *pIE = &pMsg->RevChargeInd; */
+	Q931SetIE(iE, *OOff);
+
+	return iE;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Pie_RevChargeInd
+
+  Parameters:   IBuf[IN]		Ptr to struct.
+				OBuf[OUT]		Ptr tp packed output buffer.
+				Octet[IN/OUT]	Offset into OBuf.
+
+  Return Value:	Error code, 0 = OK
+
+*****************************************************************************/
+L3INT Q931Pie_RevChargeInd(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+	L3BOOL RetCode = L3FALSE;
+
+	NoWarning(OBuf);
+	NoWarning(IBuf);
+
+	return RetCode;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Uie_RestartInd
+
+  Parameters:   pIE[OUT]		ptr to Information Element id.
+				IBuf[IN]		ptr to a packed ie.
+				OBuf[OUT]	   ptr to buffer for Unpacked ie.
+				IOff[IN\OUT]	Input buffer offset
+				OOff[IN\OUT]	Output buffer offset
+
+				Ibuf and OBuf points directly to buffers. The IOff and OOff
+				must be updated, but are otherwise not used in the ie unpack.
+
+  Return Value: Error Message
+
+*****************************************************************************/
+L3INT Q931Uie_RestartInd(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff)
+{
+	Q931ie_RestartInd *pie = (Q931ie_RestartInd*)OBuf;
+	ie *pIE = &pMsg->RestartInd;
+	L3INT Off = 0;
+	L3INT Octet = 0;
+	L3INT IESize;
+
+	*pIE = 0;
+
+	pie->IEId = IBuf[Octet++];
+
+	/* Octet 2 */
+	IESize = IBuf[Octet++]; 
+
+	/* Octet 3 */
+	pie->Class = IBuf[Octet + Off] & 0x07;
+	pie->Spare = IBuf[Octet + Off] & 0x78;
+
+	Off = Q931ReadExt(&IBuf[Octet], Off);
+	Octet++;
+
+	Q931IESizeTest(Q931E_RESTARTIND);
+	Q931SetIE(*pIE, *OOff);
+
+	*IOff = (*IOff) + Octet + Off;
+	*OOff = (*OOff) + sizeof(Q931ie_RestartInd);
+	pie->Size = sizeof(Q931ie_RestartInd);
+
+
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Pie_RestartInd
+
+  Parameters:   IBuf[IN]		Ptr to struct.
+				OBuf[OUT]		Ptr tp packed output buffer.
+				Octet[IN/OUT]	Offset into OBuf.
+
+  Return Value:	Error code, 0 = OK
+
+*****************************************************************************/
+L3INT Q931Pie_RestartInd(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+	Q931ie_RestartInd *pIE = (Q931ie_RestartInd*)IBuf;
+	L3INT rc = Q931E_NO_ERROR;
+	L3INT Beg = *Octet;
+	L3INT li;
+
+	OBuf[(*Octet)++] = Q931ie_RESTART_INDICATOR;
+	li = (*Octet)++;
+
+	/* Octet 3*/
+	OBuf[(*Octet)++] = 0x80 | pIE->Class ;
+
+	OBuf[li] = (L3UCHAR)((*Octet) - Beg) - 2;
+	return rc;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Uie_Segment
+
+  Parameters:   pIE[OUT]		ptr to Information Element id.
+				IBuf[IN]		ptr to a packed ie.
+				OBuf[OUT]	   ptr to buffer for Unpacked ie.
+				IOff[IN\OUT]	Input buffer offset
+				OOff[IN\OUT]	Output buffer offset
+
+				Ibuf and OBuf points directly to buffers. The IOff and OOff
+				must be updated, but are otherwise not used in the ie unpack.
+
+  Return Value: Error Message
+
+*****************************************************************************/
+L3INT Q931Uie_Segment(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff)
+{
+	Q931ie_Segment *pie = (Q931ie_Segment*)OBuf;
+	ie *pIE = &pMsg->Segment;
+	L3INT Off = 0;
+	L3INT Octet = 0;
+	L3INT IESize;
+
+	*pIE = 0;
+
+	pie->IEId = IBuf[Octet++];
+	Octet++;
+
+	/* Octet 2*/
+	IESize = IBuf[Octet++]; 
+
+	/* Octet 3 */
+	pie->FSI       = (IBuf[Octet + Off] & 0x80) >> 7;
+	pie->NumSegRem =  IBuf[Octet + Off] & 0x7f;
+	Octet++;
+
+	/* Octet 4 */
+	pie->SegType = IBuf[Octet + Off] & 0x7f;
+	Octet++;
+	
+	Q931IESizeTest(Q931E_SEGMENT);
+	Q931SetIE(*pIE, *OOff);
+
+	*IOff = (*IOff) + Octet + Off;
+	*OOff = (*OOff) + sizeof(Q931ie_Segment);
+	pie->Size = sizeof(Q931ie_Segment);
+
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Pie_Segment
+
+  Parameters:   IBuf[IN]		Ptr to struct.
+				OBuf[OUT]		Ptr tp packed output buffer.
+				Octet[IN/OUT]	Offset into OBuf.
+
+  Return Value:	Error code, 0 = OK
+
+*****************************************************************************/
+L3INT Q931Pie_Segment(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+	Q931ie_Segment *pIE = (Q931ie_Segment*)IBuf;
+	L3INT rc = Q931E_NO_ERROR;
+	L3INT Beg = *Octet;
+	L3INT li;
+
+	OBuf[(*Octet)++] = Q931ie_SEGMENTED_MESSAGE;
+	li = (*Octet)++;
+
+	/* Octet 3 */
+	OBuf[(*Octet)++] = (pIE->FSI << 7) | pIE->NumSegRem;
+
+	/* Octet 4 */
+	OBuf[(*Octet)++] = pIE->SegType;
+
+	OBuf[li] = (L3UCHAR)((*Octet) - Beg) - 2;
+	return rc;
+}
+
+/*****************************************************************************
+
+  Function:		Q931Uie_SendComplete
+
+  Parameters:   pIE[OUT]		ptr to Information Element id.
+				IBuf[IN]		ptr to a packed ie.
+				OBuf[OUT]	   ptr to buffer for Unpacked ie.
+				IOff[IN\OUT]	Input buffer offset
+				OOff[IN\OUT]	Output buffer offset
+
+				Ibuf and OBuf points directly to buffers. The IOff and OOff
+				must be updated, but are otherwise not used in the ie unpack.
+
+  Return Value: Error Message
+
+*****************************************************************************/
+L3INT Q931Uie_SendComplete(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff)
+{
+	Q931ie_SendComplete *pie = (Q931ie_SendComplete*)OBuf;
+	ie *pIE = &pMsg->SendComplete;
+	L3INT Off = 0;
+	L3INT Octet = 0;
+
+	*pIE = 0;
+	Octet++;
+
+	Q931SetIE(*pIE, *OOff);
+
+	*IOff = (*IOff) + Octet + Off;
+	*OOff = (*OOff) + sizeof(Q931ie_SendComplete);
+	pie->Size = sizeof(Q931ie_SendComplete);
+
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Pie_ProgInd
+
+  Parameters:   IBuf[IN]		Ptr to struct.
+				OBuf[OUT]	   Ptr tp packed output buffer.
+				Octet[IN/OUT]   Offset into OBuf.
+
+  Return Value: Error code, 0 = OK
+
+*****************************************************************************/
+L3INT Q931Pie_SendComplete(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+	/* Q931ie_SendComplete * pIE = (Q931ie_SendComplete*)IBuf; */
+	L3INT rc = Q931E_NO_ERROR;
+	/* L3INT Beg = *Octet; */
+
+	OBuf[(*Octet)++] = 0x80 | (L3UCHAR)Q931ie_SENDING_COMPLETE;
+
+	return rc;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Uie_Signal
+
+  Parameters:   pIE[OUT]		ptr to Information Element id.
+				IBuf[IN]		ptr to a packed ie.
+				OBuf[OUT]	   ptr to buffer for Unpacked ie.
+				IOff[IN\OUT]	Input buffer offset
+				OOff[IN\OUT]	Output buffer offset
+
+				Ibuf and OBuf points directly to buffers. The IOff and OOff
+				must be updated, but are otherwise not used in the ie unpack.
+
+  Return Value: Error Message
+
+*****************************************************************************/
+L3INT Q931Uie_Signal(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff)
+{
+	Q931ie_Signal *pie = (Q931ie_Signal*)OBuf;
+	ie *pIE = &pMsg->Signal;
+	L3INT Off = 0;
+	L3INT Octet = 0;
+	L3INT IESize;
+
+	*pIE = 0;
+
+	pie->IEId = IBuf[Octet++];
+
+	/* Octet 2 */
+	IESize = IBuf[Octet++]; 
+
+	/* Octet 3 */
+	pie->Signal = IBuf[Octet + Off];
+	Octet++;
+
+	Q931IESizeTest(Q931E_SIGNAL);
+	Q931SetIE(*pIE, *OOff);
+
+	*IOff = (*IOff) + Octet + Off;
+	*OOff = (*OOff) + sizeof(Q931ie_Signal);
+	pie->Size = sizeof(Q931ie_Signal);
+
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Pie_Signal
+
+  Parameters:   IBuf[IN]		Ptr to struct.
+				OBuf[OUT]		Ptr tp packed output buffer.
+				Octet[IN/OUT]	Offset into OBuf.
+
+  Return Value:	Error code, 0 = OK
+
+*****************************************************************************/
+L3INT Q931Pie_Signal(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+	Q931ie_Signal *pIE = (Q931ie_Signal*)IBuf;
+	L3INT rc = Q931E_NO_ERROR;
+	L3INT Beg = *Octet;
+	L3INT li;
+
+	OBuf[(*Octet)++] = Q931ie_SIGNAL;
+	li = (*Octet)++;
+
+	/* Octet 3 */
+	OBuf[(*Octet)++] = pIE->Signal;
+
+	OBuf[li] = (L3UCHAR)((*Octet) - Beg) - 2;
+	return rc;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Uie_TransNetSel
+
+  Parameters:   pIE[OUT]		ptr to Information Element id.
+				IBuf[IN]		ptr to a packed ie.
+				OBuf[OUT]	   ptr to buffer for Unpacked ie.
+				IOff[IN\OUT]	Input buffer offset
+				OOff[IN\OUT]	Output buffer offset
+
+				Ibuf and OBuf points directly to buffers. The IOff and OOff
+				must be updated, but are otherwise not used in the ie unpack.
+
+  Return Value: Error Message
+
+*****************************************************************************/
+L3INT Q931Uie_TransNetSel(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff)
+{
+	Q931ie_TransNetSel *pie = (Q931ie_TransNetSel*)OBuf;
+	ie *pIE = &pMsg->TransNetSel;
+	L3INT Off = 0;
+	L3INT Octet = 0;
+	L3INT x = 0;
+	L3INT l;
+
+	*pIE = 0;
+
+	pie->IEId = IBuf[Octet++];
+
+	/* Octet 2 */
+	l = IBuf[Octet++] - 3; 
+
+	/* Octet 3 */
+	pie->Type = (IBuf[Octet + Off] >> 4) & 0x07;
+
+	Off = Q931ReadExt(&IBuf[Octet], Off);
+	Octet++;
+
+	for (x = 0; x < l; x++) {
+		pie->NetID[x] = IBuf[Octet + Off] & 0x7f;
+		Off++;
+	}
+
+	Q931SetIE(*pIE, *OOff);
+
+	*IOff = (*IOff) + Octet + Off;
+	*OOff = (*OOff) + sizeof(Q931ie_TransNetSel) + x - 1;
+	pie->Size = (L3UCHAR)(sizeof(Q931ie_TransNetSel) + x - 1);
+
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Pie_TransNetSel
+
+  Parameters:   IBuf[IN]		Ptr to struct.
+				OBuf[OUT]		Ptr tp packed output buffer.
+				Octet[IN/OUT]	Offset into OBuf.
+
+  Return Value:	Error code, 0 = OK
+
+*****************************************************************************/
+L3INT Q931Pie_TransNetSel(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+	Q931ie_TransNetSel *pIE = (Q931ie_TransNetSel*)IBuf;
+	L3INT rc = Q931E_NO_ERROR;
+	L3INT Beg = *Octet;
+	L3INT li;
+	L3INT x;
+	L3INT l;
+
+	OBuf[(*Octet)++] = Q931ie_TRANSIT_NETWORK_SELECTION;
+	li = (*Octet)++;
+
+	/* Octet 3 */
+	OBuf[(*Octet)++] = 0x80 | (pIE->Type << 4) | pIE->NetIDPlan;
+
+	/* Octet 4 */
+	l = pIE->Size - sizeof(Q931ie_TransNetSel) + 1;
+	for (x = 0; x < l; x++) {
+		OBuf[(*Octet)++] = pIE->NetID[x];
+	}
+
+	OBuf[li] = (L3UCHAR)((*Octet) - Beg) - 2;
+	return rc;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Uie_UserUser
+
+  Parameters:   pIE[OUT]		ptr to Information Element id.
+				IBuf[IN]		ptr to a packed ie.
+				OBuf[OUT]	   ptr to buffer for Unpacked ie.
+				IOff[IN\OUT]	Input buffer offset
+				OOff[IN\OUT]	Output buffer offset
+
+				Ibuf and OBuf points directly to buffers. The IOff and OOff
+				must be updated, but are otherwise not used in the ie unpack.
+
+  Return Value: Error Message
+
+*****************************************************************************/
+L3INT Q931Uie_UserUser(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff)
+{
+	Q931ie_UserUser *pie = (Q931ie_UserUser*)OBuf;
+	ie *pIE = &pMsg->UserUser;
+	L3INT Off = 0;
+	L3INT Octet = 0;
+	L3INT l;
+
+	*pIE = 0;
+
+	pie->IEId = IBuf[Octet++];
+
+	/* Octet 2 */
+	l = IBuf[Octet++] - 1;
+
+	/* Octet 3 */
+	pie->ProtDisc = IBuf[Octet++];
+
+	for (Off = 0; Off < l; Off++) {
+		pie->User[Off] = IBuf[Octet + Off];
+	}
+
+	Q931SetIE(*pIE, *OOff);
+
+	*IOff = (*IOff) + Octet + Off;
+	*OOff = (*OOff) + sizeof(Q931ie_UserUser) + Off - 1;
+	pie->Size = (L3UCHAR)(sizeof(Q931ie_UserUser) + Off - 1);
+
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Pie_UserUser
+
+  Parameters:   IBuf[IN]		Ptr to struct.
+				OBuf[OUT]		Ptr tp packed output buffer.
+				Octet[IN/OUT]	Offset into OBuf.
+
+  Return Value:	Error code, 0 = OK
+
+*****************************************************************************/
+L3INT Q931Pie_UserUser(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+	Q931ie_UserUser *pIE = (Q931ie_UserUser*)IBuf;
+	L3INT rc = Q931E_NO_ERROR;
+	L3INT Beg = *Octet;
+	L3INT li;
+	L3INT x;
+	L3INT l;
+
+	OBuf[(*Octet)++] = Q931ie_USER_USER;
+	li = (*Octet)++;
+
+	/* Octet 3 */
+	OBuf[(*Octet)++] = pIE->ProtDisc;
+
+	/* Octet 4 */
+	l = pIE->Size - sizeof(Q931ie_UserUser) + 1;
+	for (x = 0; x < l; x++) {
+		OBuf[(*Octet)++] = pIE->User[x];
+	}
+
+	OBuf[li] = (L3UCHAR)((*Octet) - Beg) - 2;
+	return rc;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Uie_GenericDigits
+
+  Parameters:   pIE[OUT]		ptr to Information Element id.
+				IBuf[IN]		ptr to a packed ie.
+				OBuf[OUT]	   ptr to buffer for Unpacked ie.
+				IOff[IN\OUT]	Input buffer offset
+				OOff[IN\OUT]	Output buffer offset
+
+
+				Ibuf and OBuf points directly to buffers. The IOff and OOff
+				must be updated, but are otherwise not used in the ie unpack.
+
+  Return Value: Error Message
+
+*****************************************************************************/
+L3INT Q931Uie_GenericDigits(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff)
+{
+	Q931ie_GenericDigits *pie = (Q931ie_GenericDigits*)OBuf;
+	ie *pIE = &pMsg->GenericDigits;
+	L3INT Off = 0;
+	L3INT Octet = 0;
+	L3INT x;
+	L3INT IESize;
+
+	*pIE = 0;
+
+	/* Octet 1 */
+	pie->IEId = IBuf[Octet++];
+
+	/* Octet 2 */
+	IESize = IBuf[Octet++]; 
+
+	/* Octet 3 */
+	pie->Type     = (IBuf[Octet]) & 0x1F;
+	pie->Encoding = (IBuf[Octet] >> 5) & 0x07;
+	Octet++;
+	
+	/* Octet 4*/
+	if (pie->Encoding == 0) { /* BCD Even */
+		x = 0;
+		do {
+			pie->Digit[x++] =  IBuf[Octet + Off] & 0x0f;
+			pie->Digit[x++] = (IBuf[Octet + Off] >> 4) & 0x0f;
+			Off++;
+		} while (Q931MoreIE());
+	} else if (pie->Encoding == 1) { /* BCD Odd */
+		x = 0;
+		do {
+			pie->Digit[x++] = IBuf[Octet + Off] & 0x0f;
+			if (Q931MoreIE()) {
+				pie->Digit[x] = (IBuf[Octet + Off] >> 4) & 0x0f;
+			}
+			x++;
+			Off++;
+		} while (Q931MoreIE());
+	} else if (pie->Encoding == 2) { /* IA5 */
+		x = 0;
+		do {
+			pie->Digit[x++] = IBuf[Octet + Off] & 0x7f;
+			Off++;
+		} while (Q931MoreIE());
+	} else {
+		/* Binary encoding type unkown */
+		Q931SetError(pTrunk, Q931E_GENERIC_DIGITS, Octet, Off);
+		return Q931E_GENERIC_DIGITS;
+	}
+
+	Q931IESizeTest(Q931E_GENERIC_DIGITS);
+	Q931SetIE(*pIE, *OOff);
+
+	*IOff = (*IOff) + Octet + Off;
+	*OOff = (*OOff) + sizeof(Q931ie_CallingSub) + x - 1;
+	pie->Size = (L3UCHAR)(sizeof(Q931ie_CallingSub) + x - 1);
+
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Pie_GenericDigits
+
+  Parameters:   IBuf[IN]		Ptr to struct.
+				OBuf[OUT]		Ptr tp packed output buffer.
+				Octet[IN/OUT]	Offset into OBuf.
+
+  Return Value:	Error code, 0 = OK
+
+*****************************************************************************/
+
+L3INT Q931Pie_GenericDigits(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+	OBuf[(*Octet)++] = (Q931ie_GENERIC_DIGITS & 0xFF);
+	OBuf[(*Octet)++] = 0;
+
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Uie_ChangeStatus
+
+  Parameters:   pIE[OUT]		ptr to Information Element id.
+				IBuf[IN]		ptr to a packed ie.
+				OBuf[OUT]	   ptr to buffer for Unpacked ie.
+				IOff[IN\OUT]	Input buffer offset
+				OOff[IN\OUT]	Output buffer offset
+
+				Ibuf and OBuf points directly to buffers. The IOff and OOff
+				must be updated, but are otherwise not used in the ie unpack.
+
+  Return Value: Error Message
+
+*****************************************************************************/
+L3INT Q931Uie_ChangeStatus(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff)
+{
+	Q931ie_ChangeStatus *pie = (Q931ie_ChangeStatus*)OBuf;
+	ie *pIE = &pMsg->ChangeStatus;
+	L3INT Off = 0;
+	L3INT Octet = 0;
+	L3INT IESize;
+
+	*pIE = 0;
+
+	pie->IEId = IBuf[Octet++];
+
+	/* Octet 2 */
+	IESize = IBuf[Octet++]; 
+
+	/* Octet 3 */
+	pie->Preference = (IBuf[Octet + Off] >> 6) & 0x01;
+	pie->Spare      =  IBuf[Octet + Off] & 0x38;
+	pie->NewStatus  =  IBuf[Octet + Off] & 0x07;
+	Octet++;
+
+	Q931SetIE(*pIE, *OOff);
+
+	*IOff = (*IOff) + Octet + Off;
+	*OOff = (*OOff) + sizeof(Q931ie_ChangeStatus);
+	pie->Size = sizeof(Q931ie_ChangeStatus);
+
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Pie_ChangeStatus
+
+  Parameters:   IBuf[IN]		Ptr to struct.
+				OBuf[OUT]		Ptr tp packed output buffer.
+				Octet[IN/OUT]	Offset into OBuf.
+
+  Return Value:	Error code, 0 = OK
+
+*****************************************************************************/
+L3INT Q931Pie_ChangeStatus(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+	Q931ie_ChangeStatus *pIE = (Q931ie_ChangeStatus*)IBuf;
+	L3INT rc = Q931E_NO_ERROR;
+	L3INT Beg = *Octet;
+	L3INT li;
+
+	OBuf[(*Octet)++] = Q931ie_CHANGE_STATUS;
+	li = (*Octet)++;
+
+	/* Octet 3 */
+	OBuf[(*Octet)++] = 0x80 | pIE->NewStatus | ((pIE->Preference & 0x01) << 6);
+
+	OBuf[li] = (L3UCHAR)((*Octet) - Beg) - 2;
+	return rc;
+}
+
+
+
+L3INT Q931Uie_Generic(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *IOff, L3INT *OOff)
+{
+	L3INT Octet = 0;
+	L3UCHAR id = 0;
+
+	/* id */
+	id = IBuf[Octet++];
+
+	/* Length */
+	Octet += IBuf[Octet];
+	Octet++;
+
+	Q931Log(pTrunk, Q931_LOG_DEBUG, "Discarding IE %#hhx with length %d\n", id, Octet - 2);
+
+	*IOff += Octet;
+	return Q931E_NO_ERROR;
+}
+
+L3INT Q931Pie_Generic(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+	/* do nothing */
+	return Q931E_NO_ERROR;
+}

Added: freeswitch/trunk/libs/freetdm/src/isdn/Q931mes.c (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/isdn/Q931mes.c	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/isdn/Q931mes.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,1870 @@
+/*****************************************************************************
+
+  FileName:	Q931mes.c
+
+  Contents:	Pack/Unpack functions. These functions will unpack a Q931 
+		message from the bit packed original format into structs
+		that contains variables sized by the user. It will also pack
+		the struct back into a Q.931 message as required.
+
+		See q931.h for description. 
+
+  License/Copyright:
+
+  Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+  email:janvb@caselaboratories.com  
+
+  Redistribution and use in source and binary forms, with or without 
+  modification, are permitted provided that the following conditions are 
+  met:
+
+	* Redistributions of source code must retain the above copyright notice, 
+	  this list of conditions and the following disclaimer.
+	* Redistributions in binary form must reproduce the above copyright notice, 
+	  this list of conditions and the following disclaimer in the documentation 
+	  and/or other materials provided with the distribution.
+	* Neither the name of the Case Labs, Ltd nor the names of its contributors 
+	  may be used to endorse or promote products derived from this software 
+	  without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
+  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
+  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+  POSSIBILITY OF SUCH DAMAGE.
+
+*****************************************************************************/
+
+#include "Q931.h"
+
+/**
+ * Q931MesgHeader
+ * \brief	Create Q.931 Message header
+ */
+L3INT Q931MesgHeader(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *mes, L3UCHAR *OBuf, L3INT Size, L3INT *IOff)
+{
+	L3INT Octet = *IOff;
+
+	Q931Log(pTrunk, Q931_LOG_DEBUG, "Creating Q.931 Message Header:\n    ProtDisc %d (%#x), CRV %d (%#x), CRVflag: %d (%#x), MesType: %d (%#x)\n",
+			 mes->ProtDisc, mes->ProtDisc, mes->CRV, mes->CRV, mes->CRVFlag, mes->CRVFlag, mes->MesType, mes->MesType);
+
+	OBuf[Octet++] = mes->ProtDisc;				/* Protocol discriminator */
+	if (!Q931_IS_BRI(pTrunk)) {
+		OBuf[Octet++] = 2;									/* length is 2 octets */
+		OBuf[Octet++] = (L3UCHAR)((mes->CRV >> 8) & 0x7f) | ((mes->CRVFlag << 7) & 0x80);	/* msb */
+		OBuf[Octet++] = (L3UCHAR) (mes->CRV & 0xff);						/* lsb */
+	} else {
+		OBuf[Octet++] = 1;									/* length is 1 octet */
+		OBuf[Octet++] = (L3UCHAR) (mes->CRV & 0x7f) | ((mes->CRVFlag << 7) & 0x80);		/* CRV & flag */
+	}
+	OBuf[Octet++] = mes->MesType;				/* message header */
+
+	*IOff = Octet;
+	return 0;
+}
+
+
+/*****************************************************************************
+
+  Function:	 Q931Umes_Alerting
+
+*****************************************************************************/
+
+L3INT Q931Umes_Alerting(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+	L3INT OOff = 0;
+	L3INT rc = Q931E_NO_ERROR;
+
+	while (IOff < Size) {
+		switch (IBuf[IOff]) {
+		case Q931ie_BEARER_CAPABILITY: 
+		case Q931ie_CHANNEL_IDENTIFICATION:
+		case Q931ie_PROGRESS_INDICATOR:
+		case Q931ie_DISPLAY:
+		case Q931ie_SIGNAL:
+		case Q931ie_HIGH_LAYER_COMPATIBILITY:
+		case Q931ie_USER_USER:
+			rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+			if (rc != Q931E_NO_ERROR) 
+				return rc;
+			break;
+		default:
+			return Q931E_ILLEGAL_IE;
+			break;
+		}
+	}
+
+	mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Pmes_Alerting
+
+*****************************************************************************/
+L3INT Q931Pmes_Alerting(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+	Q931mes_Generic *pMes = (Q931mes_Generic *)IBuf;
+	L3INT rc = Q931E_NO_ERROR;
+	L3INT Octet = 0;
+
+	/* Q931 Message Header */
+	Q931MesgHeader(pTrunk, pMes, OBuf, *OSize, &Octet);
+	
+	/* Bearer capability */
+	if (Q931IsIEPresent(pMes->BearerCap)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_BEARER_CAPABILITY](pTrunk, Q931GetIEPtr(pMes->BearerCap,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Channel Identification */
+	if (Q931IsIEPresent(pMes->ChanID)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CHANNEL_IDENTIFICATION](pTrunk, Q931GetIEPtr(pMes->ChanID,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Progress indicator */
+	if (Q931IsIEPresent(pMes->ProgInd)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_PROGRESS_INDICATOR](pTrunk, Q931GetIEPtr(pMes->ProgInd,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Display */
+	if (Q931IsIEPresent(pMes->Display)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_DISPLAY](pTrunk, Q931GetIEPtr(pMes->Display,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Signal */
+	if (Q931IsIEPresent(pMes->Signal)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_SIGNAL](pTrunk, Q931GetIEPtr(pMes->Signal,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* High Layer Compatibility */
+	if (Q931IsIEPresent(pMes->HLComp)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_HIGH_LAYER_COMPATIBILITY](pTrunk, Q931GetIEPtr(pMes->HLComp,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	*OSize = Octet;	
+	return rc;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Umes_CallProceeding
+
+*****************************************************************************/
+L3INT Q931Umes_CallProceeding(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+	L3INT OOff = 0;
+	L3INT rc = Q931E_NO_ERROR;
+
+	while (IOff < Size) {
+		switch (IBuf[IOff]) {
+		case Q931ie_BEARER_CAPABILITY:
+		case Q931ie_CHANNEL_IDENTIFICATION:
+		case Q931ie_PROGRESS_INDICATOR:
+		case Q931ie_DISPLAY:
+		case Q931ie_HIGH_LAYER_COMPATIBILITY:
+			rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+			if (rc != Q931E_NO_ERROR) 
+				return rc;
+			break;
+		default:
+			return Q931E_ILLEGAL_IE;
+			break;
+		}
+	}
+
+	mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Pmes_CallProceeding
+
+*****************************************************************************/
+L3INT Q931Pmes_CallProceeding(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+	Q931mes_Generic *pMes = (Q931mes_Generic *)IBuf;
+	L3INT rc = Q931E_NO_ERROR;
+	L3INT Octet = 0;
+
+	/* Q931 Message Header */
+	Q931MesgHeader(pTrunk, pMes, OBuf, *OSize, &Octet);
+	
+	/* Bearer capability */
+	if (Q931IsIEPresent(pMes->BearerCap)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_BEARER_CAPABILITY](pTrunk, Q931GetIEPtr(pMes->BearerCap,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Channel Identification */
+	if (Q931IsIEPresent(pMes->ChanID)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CHANNEL_IDENTIFICATION](pTrunk, Q931GetIEPtr(pMes->ChanID,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+	
+	/* Progress indicator */
+	if (Q931IsIEPresent(pMes->ProgInd)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_PROGRESS_INDICATOR](pTrunk, Q931GetIEPtr(pMes->ProgInd,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Display */
+	if (Q931IsIEPresent(pMes->Display)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_DISPLAY](pTrunk, Q931GetIEPtr(pMes->Display,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* High Layer Compatibility */
+	if (Q931IsIEPresent(pMes->HLComp)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_HIGH_LAYER_COMPATIBILITY](pTrunk, Q931GetIEPtr(pMes->HLComp,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	*OSize = Octet;	
+	return rc;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Umes_CongestionControl
+
+*****************************************************************************/
+L3INT Q931Umes_CongestionControl(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+	L3BOOL RetCode = L3FALSE;
+
+	NoWarning(mes);
+	NoWarning(IBuf);
+
+	return RetCode;
+}
+
+
+/*****************************************************************************
+
+  Function:	 Q931Pmes_CongestionControl
+
+*****************************************************************************/
+L3INT Q931Pmes_CongestionControl(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+	L3BOOL RetCode = L3FALSE;
+
+	NoWarning(OBuf);
+	NoWarning(IBuf);
+
+	*OSize = 0;	
+	return RetCode;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Umes_Connect
+
+*****************************************************************************/
+L3INT Q931Umes_Connect(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+	L3INT OOff = 0;
+	L3INT rc = Q931E_NO_ERROR;
+
+	while (IOff < Size) {
+		switch (IBuf[IOff]) {
+		case Q931ie_BEARER_CAPABILITY:
+		case Q931ie_CHANNEL_IDENTIFICATION:
+		case Q931ie_PROGRESS_INDICATOR:
+		case Q931ie_DISPLAY:
+		case Q931ie_DATETIME:
+		case Q931ie_SIGNAL:
+		case Q931ie_LOW_LAYER_COMPATIBILITY:
+		case Q931ie_HIGH_LAYER_COMPATIBILITY:
+		case Q931ie_CONNECTED_NUMBER:		/* not actually used, seen while testing BRI PTMP TE */
+		case Q931ie_USER_USER:
+			rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+			if (rc != Q931E_NO_ERROR) 
+				return rc;
+			break;
+
+		default:
+			Q931Log(pTrunk, Q931_LOG_ERROR, "Illegal IE %#hhx in Connect Message\n", IBuf[IOff]);
+
+			return Q931E_ILLEGAL_IE;
+			break;
+		}
+	}
+
+	mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Pmes_Connect
+
+*****************************************************************************/
+L3INT Q931Pmes_Connect(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+	Q931mes_Generic *pMes = (Q931mes_Generic *)IBuf;
+	L3INT rc = Q931E_NO_ERROR;
+	L3INT Octet = 0;
+
+	/* Q931 Message Header */
+	Q931MesgHeader(pTrunk, pMes, OBuf, *OSize, &Octet);
+	
+	/* Bearer capability */
+	if (Q931IsIEPresent(pMes->BearerCap)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_BEARER_CAPABILITY](pTrunk, Q931GetIEPtr(pMes->BearerCap,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Channel Identification */
+	if (Q931IsIEPresent(pMes->ChanID)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CHANNEL_IDENTIFICATION](pTrunk, Q931GetIEPtr(pMes->ChanID,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Progress indicator */
+	if (Q931IsIEPresent(pMes->ProgInd)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_PROGRESS_INDICATOR](pTrunk, Q931GetIEPtr(pMes->ProgInd,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Display */
+	if (Q931IsIEPresent(pMes->Display)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_DISPLAY](pTrunk, Q931GetIEPtr(pMes->Display,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Date/Time */
+	if (Q931IsIEPresent(pMes->DateTime)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_DATETIME](pTrunk, Q931GetIEPtr(pMes->DateTime,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Signal */
+	if (Q931IsIEPresent(pMes->Signal)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_SIGNAL](pTrunk, Q931GetIEPtr(pMes->Signal,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Low Layer Compatibility */
+	if (Q931IsIEPresent(pMes->LLComp)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_LOW_LAYER_COMPATIBILITY](pTrunk, Q931GetIEPtr(pMes->LLComp,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* High Layer Compatibility */
+	if (Q931IsIEPresent(pMes->HLComp)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_HIGH_LAYER_COMPATIBILITY](pTrunk, Q931GetIEPtr(pMes->HLComp,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	*OSize = Octet;	
+	return rc;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Umes_ConnectAck
+
+*****************************************************************************/
+L3INT Q931Umes_ConnectAck(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+	L3INT OOff = 0;
+	L3INT rc = Q931E_NO_ERROR;
+
+	while (IOff < Size) {
+		switch (IBuf[IOff]) {
+		case Q931ie_DISPLAY:
+		case Q931ie_SIGNAL:
+			rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+			if (rc != Q931E_NO_ERROR) 
+				return rc;
+			break;
+		default:
+			return Q931E_ILLEGAL_IE;
+			break;
+		}
+	}
+
+	mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+	return Q931E_NO_ERROR;
+}
+
+
+/*****************************************************************************
+
+  Function:	 Q931Pmes_ConnectAck
+
+*****************************************************************************/
+L3INT Q931Pmes_ConnectAck(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+	Q931mes_Generic *pMes = (Q931mes_Generic *)IBuf;
+	L3INT rc = Q931E_NO_ERROR;
+	L3INT Octet = 0;
+
+	/* Q931 Message Header */
+	Q931MesgHeader(pTrunk, pMes, OBuf, *OSize, &Octet);
+	
+	/* Display */
+	if (Q931IsIEPresent(pMes->Display)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_DISPLAY](pTrunk, Q931GetIEPtr(pMes->Display,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Signal */
+	if (Q931IsIEPresent(pMes->Signal)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_SIGNAL](pTrunk, Q931GetIEPtr(pMes->Signal,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	*OSize = Octet;	
+	return rc;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Umes_Disconnect
+
+*****************************************************************************/
+L3INT Q931Umes_Disconnect(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+	L3INT OOff = 0;
+	L3INT rc = Q931E_NO_ERROR;
+
+	while (IOff < Size) {
+		switch (IBuf[IOff]) {
+		case Q931ie_CAUSE:
+		case Q931ie_PROGRESS_INDICATOR:
+		case Q931ie_DISPLAY:
+		case Q931ie_SIGNAL:
+		case Q931ie_FACILITY:
+		case Q931ie_USER_USER:
+			rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+			if (rc != Q931E_NO_ERROR) 
+				return rc;
+			break;
+		default:
+			return Q931E_ILLEGAL_IE;
+			break;
+		}
+	}
+
+	mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Pmes_Disconnect
+
+*****************************************************************************/
+L3INT Q931Pmes_Disconnect(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+	Q931mes_Generic *pMes = (Q931mes_Generic *)IBuf;
+	L3INT rc = Q931E_NO_ERROR;
+	L3INT Octet = 0;
+
+	/* Q931 Message Header */
+	Q931MesgHeader(pTrunk, pMes, OBuf, *OSize, &Octet);
+	
+	/* Cause */
+	if (Q931IsIEPresent(pMes->Cause)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CAUSE](pTrunk, Q931GetIEPtr(pMes->Cause,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+	
+	/* Progress indicator */
+	if (Q931IsIEPresent(pMes->ProgInd)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_PROGRESS_INDICATOR](pTrunk, Q931GetIEPtr(pMes->ProgInd,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Display */
+	if (Q931IsIEPresent(pMes->Display)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_DISPLAY](pTrunk, Q931GetIEPtr(pMes->Display,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Signal */
+	if (Q931IsIEPresent(pMes->Signal)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_SIGNAL](pTrunk, Q931GetIEPtr(pMes->Signal,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	*OSize = Octet;	
+	return rc;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Umes_Information
+
+*****************************************************************************/
+L3INT Q931Umes_Information(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+	L3INT OOff = 0;
+	L3INT rc = Q931E_NO_ERROR;
+
+	while (IOff < Size) {
+		switch (IBuf[IOff]) {
+		case Q931ie_SENDING_COMPLETE:
+		case Q931ie_DISPLAY:
+		case Q931ie_KEYPAD_FACILITY:
+		case Q931ie_CALLED_PARTY_NUMBER:
+			rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+			if (rc != Q931E_NO_ERROR) 
+				return rc;
+			break;
+		default:
+			return Q931E_ILLEGAL_IE;
+			break;
+		}
+	}
+
+	mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Pmes_Information
+
+*****************************************************************************/
+L3INT Q931Pmes_Information(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+	Q931mes_Generic *pMes = (Q931mes_Generic *)IBuf;
+	L3INT rc = Q931E_NO_ERROR;
+	L3INT Octet = 0;
+
+	/* Q931 Message Header */
+	Q931MesgHeader(pTrunk, pMes, OBuf, *OSize, &Octet);
+
+	/* Sending Complete */
+	if (Q931IsIEPresent(pMes->SendComplete)) {
+		OBuf[Octet++]	= (L3UCHAR)(pMes->SendComplete & 0x00ff);
+	}
+
+	/* Display */
+	if (Q931IsIEPresent(pMes->Display)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_DISPLAY](pTrunk, Q931GetIEPtr(pMes->Display,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Keypad Facility */
+	if (Q931IsIEPresent(pMes->KeypadFac)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_KEYPAD_FACILITY](pTrunk, Q931GetIEPtr(pMes->KeypadFac,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Signal */
+	if (Q931IsIEPresent(pMes->Signal)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_SIGNAL](pTrunk, Q931GetIEPtr(pMes->Signal,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Called Party number */
+	if (Q931IsIEPresent(pMes->CalledNum)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CALLED_PARTY_NUMBER](pTrunk, Q931GetIEPtr(pMes->CalledNum,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	*OSize = Octet;	
+	return rc;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Umes_Notify
+
+*****************************************************************************/
+L3INT Q931Umes_Notify(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+	L3INT OOff = 0;
+	L3INT rc = Q931E_NO_ERROR;
+
+	while (IOff < Size) {
+		switch (IBuf[IOff]) {
+		case Q931ie_BEARER_CAPABILITY:
+		case Q931ie_NOTIFICATION_INDICATOR:
+		case Q931ie_DISPLAY:
+			rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+			if (rc != Q931E_NO_ERROR) 
+				return rc;
+			break;
+		default:
+			return Q931E_ILLEGAL_IE;
+			break;
+		}
+	}
+
+	mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Pmes_Notify
+
+*****************************************************************************/
+L3INT Q931Pmes_Notify(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+	Q931mes_Generic *pMes = (Q931mes_Generic *)IBuf;
+	L3INT rc = Q931E_NO_ERROR;
+	L3INT Octet = 0;
+
+	/* Q931 Message Header */
+	Q931MesgHeader(pTrunk, pMes, OBuf, *OSize, &Octet);
+	
+	/* Bearer capability */
+	if (Q931IsIEPresent(pMes->BearerCap)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_BEARER_CAPABILITY](pTrunk, Q931GetIEPtr(pMes->BearerCap,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Display */
+	if (Q931IsIEPresent(pMes->Display)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_DISPLAY](pTrunk, Q931GetIEPtr(pMes->Display,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	*OSize = Octet;	
+	return rc;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Umes_Progress
+
+*****************************************************************************/
+L3INT Q931Umes_Progress(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+	L3INT OOff = 0;
+	L3INT rc = Q931E_NO_ERROR;
+
+	while (IOff < Size) {
+		switch (IBuf[IOff]) {
+		case Q931ie_BEARER_CAPABILITY:
+		case Q931ie_CAUSE:
+		case Q931ie_PROGRESS_INDICATOR:
+		case Q931ie_DISPLAY:
+		case Q931ie_HIGH_LAYER_COMPATIBILITY:
+			rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+			if (rc != Q931E_NO_ERROR) 
+				return rc;
+			break;
+		default:
+			return Q931E_ILLEGAL_IE;
+			break;
+		}
+	}
+
+	mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Pmes_Progress
+
+*****************************************************************************/
+L3INT Q931Pmes_Progress(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+	Q931mes_Generic *pMes = (Q931mes_Generic *)IBuf;
+	L3INT rc = Q931E_NO_ERROR;
+	L3INT Octet = 0;
+
+	/* Q931 Message Header */
+	Q931MesgHeader(pTrunk, pMes, OBuf, *OSize, &Octet);
+	
+	/* Bearer capability */
+	if (Q931IsIEPresent(pMes->BearerCap)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_BEARER_CAPABILITY](pTrunk, Q931GetIEPtr(pMes->BearerCap,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Cause */
+	if (Q931IsIEPresent(pMes->Cause)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CAUSE](pTrunk, Q931GetIEPtr(pMes->Cause,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Progress indicator */
+	if (Q931IsIEPresent(pMes->ProgInd)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_PROGRESS_INDICATOR](pTrunk, Q931GetIEPtr(pMes->ProgInd,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Display */
+	if (Q931IsIEPresent(pMes->Display)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_DISPLAY](pTrunk, Q931GetIEPtr(pMes->Display,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* High Layer Compatibility */
+	if (Q931IsIEPresent(pMes->HLComp)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_HIGH_LAYER_COMPATIBILITY](pTrunk, Q931GetIEPtr(pMes->HLComp,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	*OSize = Octet;	
+	return rc;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Umes_Release
+
+*****************************************************************************/
+L3INT Q931Umes_Release(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+	L3INT OOff = 0;
+	L3INT rc = Q931E_NO_ERROR;
+
+	while (IOff < Size) {
+		switch (IBuf[IOff]) {
+		case Q931ie_CAUSE:
+		case Q931ie_DISPLAY:
+		case Q931ie_SIGNAL:
+		case Q931ie_USER_USER:
+			rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+			if (rc != Q931E_NO_ERROR) 
+				return rc;
+			break;
+		default:
+			return Q931E_ILLEGAL_IE;
+			break;
+		}
+	}
+
+	mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Pmes_Release
+
+*****************************************************************************/
+L3INT Q931Pmes_Release(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+	Q931mes_Generic *pMes = (Q931mes_Generic *)IBuf;
+	L3INT rc = Q931E_NO_ERROR;
+	L3INT Octet = 0;
+
+	/* Q931 Message Header */
+	Q931MesgHeader(pTrunk, pMes, OBuf, *OSize, &Octet);
+	
+	/* Cause */
+	if (Q931IsIEPresent(pMes->Cause)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CAUSE](pTrunk, Q931GetIEPtr(pMes->Cause,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Display */
+	if (Q931IsIEPresent(pMes->Display)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_DISPLAY](pTrunk, Q931GetIEPtr(pMes->Display,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Signal */
+	if (Q931IsIEPresent(pMes->Signal)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_SIGNAL](pTrunk, Q931GetIEPtr(pMes->Signal,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	*OSize = Octet;	
+	return rc;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Umes_ReleaseComplete
+
+*****************************************************************************/
+L3INT Q931Umes_ReleaseComplete(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+	L3INT OOff = 0;
+	L3INT rc = Q931E_NO_ERROR;
+
+	while (IOff < Size) {
+		switch (IBuf[IOff]) {
+		case Q931ie_CAUSE:
+		case Q931ie_DISPLAY:
+		case Q931ie_SIGNAL:
+		case Q931ie_USER_USER:
+			rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+			if (rc != Q931E_NO_ERROR) 
+				return rc;
+			break;
+		default:
+			return Q931E_ILLEGAL_IE;
+			break;
+		}
+	}
+
+	mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Pmes_ReleaseComplete
+
+*****************************************************************************/
+L3INT Q931Pmes_ReleaseComplete(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+	Q931mes_Generic *pMes = (Q931mes_Generic *)IBuf;
+	L3INT rc = Q931E_NO_ERROR;
+	L3INT Octet = 0;
+
+	/* Q931 Message Header */
+	Q931MesgHeader(pTrunk, pMes, OBuf, *OSize, &Octet);
+	
+	/* Cause */
+	if (Q931IsIEPresent(pMes->Cause)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CAUSE](pTrunk, Q931GetIEPtr(pMes->Cause,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Display */
+	if (Q931IsIEPresent(pMes->Display)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_DISPLAY](pTrunk, Q931GetIEPtr(pMes->Display,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Signal */
+	if (Q931IsIEPresent(pMes->Signal)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_SIGNAL](pTrunk, Q931GetIEPtr(pMes->Signal,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	*OSize = Octet;	
+	return rc;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Umes_Restart
+
+*****************************************************************************/
+L3INT Q931Umes_Restart(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+	L3INT OOff = 0;
+	L3INT rc = Q931E_NO_ERROR;
+
+	while (IOff < Size) {
+		switch (IBuf[IOff]) {
+		case Q931ie_CHANNEL_IDENTIFICATION:
+		case Q931ie_DISPLAY:
+		case Q931ie_RESTART_INDICATOR:
+			rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+			if (rc != Q931E_NO_ERROR) 
+				return rc;
+			break;
+		default:
+			return Q931E_ILLEGAL_IE;
+			break;
+		}
+	}
+
+	mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Pmes_Restart
+
+*****************************************************************************/
+L3INT Q931Pmes_Restart(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+	Q931mes_Generic *pMes = (Q931mes_Generic *)IBuf;
+	L3INT rc = Q931E_NO_ERROR;
+	L3INT Octet = 0;
+
+	/* Q931 Message Header */
+	Q931MesgHeader(pTrunk, pMes, OBuf, *OSize, &Octet);
+   
+	/* ChanID */
+	if (Q931IsIEPresent(pMes->ChanID)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CHANNEL_IDENTIFICATION](pTrunk, Q931GetIEPtr(pMes->ChanID,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Display */
+	if (Q931IsIEPresent(pMes->Display)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_DISPLAY](pTrunk, Q931GetIEPtr(pMes->Display,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* RestartInd */
+	if (Q931IsIEPresent(pMes->RestartInd)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_RESTART_INDICATOR](pTrunk, Q931GetIEPtr(pMes->RestartInd,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	*OSize = Octet;	
+	return rc;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Umes_RestartAck
+
+*****************************************************************************/
+L3INT Q931Umes_RestartAck(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT IOff, L3INT Size)
+{
+	Q931mes_Generic *mes = (Q931mes_Generic*)OBuf;
+	L3INT OOff = 0;
+	L3INT rc = Q931E_NO_ERROR;
+
+	while (IOff < Size) {
+		switch (IBuf[IOff]) {
+		case Q931ie_CHANNEL_IDENTIFICATION:
+		case Q931ie_DISPLAY:
+		case Q931ie_RESTART_INDICATOR:
+			rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+			if (rc != Q931E_NO_ERROR) 
+				return rc;
+			break;
+		default:
+			return Q931E_ILLEGAL_IE;
+			break;
+		}
+	}
+
+	mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Pmes_RestartAck
+
+*****************************************************************************/
+L3INT Q931Pmes_RestartAck(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+	Q931mes_Generic *pMes = (Q931mes_Generic *)IBuf;
+	L3INT rc = Q931E_NO_ERROR;
+	L3INT Octet = 0;
+
+	/* Q931 Message Header */
+	Q931MesgHeader(pTrunk, pMes, OBuf, *OSize, &Octet);
+	
+	/* ChanID */
+	if (Q931IsIEPresent(pMes->ChanID)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CHANNEL_IDENTIFICATION](pTrunk, Q931GetIEPtr(pMes->ChanID,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Display */
+	if (Q931IsIEPresent(pMes->Display)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_DISPLAY](pTrunk, Q931GetIEPtr(pMes->Display,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* RestartInd */
+	if (Q931IsIEPresent(pMes->RestartInd)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_RESTART_INDICATOR](pTrunk, Q931GetIEPtr(pMes->RestartInd,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	*OSize = Octet;	
+	return rc;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Umes_Resume
+
+*****************************************************************************/
+L3INT Q931Umes_Resume(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+	L3INT OOff = 0;
+	L3INT rc = Q931E_NO_ERROR;
+
+	while (IOff < Size) {
+		switch (IBuf[IOff]) {
+		case Q931ie_CALL_IDENTITY:
+			rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+			if (rc != Q931E_NO_ERROR) 
+				return rc;
+			break;
+		default:
+			return Q931E_ILLEGAL_IE;
+			break;
+		}
+	}
+
+	mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Pmes_Resume
+
+*****************************************************************************/
+L3INT Q931Pmes_Resume(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+	Q931mes_Generic *pMes = (Q931mes_Generic *)IBuf;
+	L3INT rc = Q931E_NO_ERROR;
+	L3INT Octet = 0;
+
+	/* Q931 Message Header */
+	Q931MesgHeader(pTrunk, pMes, OBuf, *OSize, &Octet);
+
+	/* Call Identity */
+	if (Q931IsIEPresent(pMes->CallID)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CALL_IDENTITY](pTrunk, Q931GetIEPtr(pMes->CallID,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	*OSize = Octet;	
+	return rc;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Umes_ResumeAck
+
+*****************************************************************************/
+L3INT Q931Umes_ResumeAck(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+	L3INT OOff = 0;
+	L3INT rc = Q931E_NO_ERROR;
+
+	while (IOff < Size) {
+		switch (IBuf[IOff]) {
+		case Q931ie_CHANNEL_IDENTIFICATION:
+		case Q931ie_DISPLAY:
+			rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+			if (rc != Q931E_NO_ERROR) 
+				return rc;
+			break;
+		default:
+			return Q931E_ILLEGAL_IE;
+			break;
+		}
+	}
+
+	mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+	return Q931E_NO_ERROR;
+}
+
+
+/*****************************************************************************
+
+  Function:	 Q931Pmes_ResumeAck
+
+*****************************************************************************/
+L3INT Q931Pmes_ResumeAck(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+	Q931mes_Generic *pMes = (Q931mes_Generic *)IBuf;
+	L3INT rc = Q931E_NO_ERROR;
+	L3INT Octet = 0;
+
+	/* Q931 Message Header */
+	Q931MesgHeader(pTrunk, pMes, OBuf, *OSize, &Octet);
+	
+	/* Channel Identification */
+	if (Q931IsIEPresent(pMes->ChanID)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CHANNEL_IDENTIFICATION](pTrunk, Q931GetIEPtr(pMes->ChanID,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Display */
+	if (Q931IsIEPresent(pMes->Display)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_DISPLAY](pTrunk, Q931GetIEPtr(pMes->Display,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	*OSize = Octet;	
+	return rc;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Umes_ResumeReject
+
+*****************************************************************************/
+L3INT Q931Umes_ResumeReject(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+	L3INT OOff = 0;
+	L3INT rc = Q931E_NO_ERROR;
+
+	while (IOff < Size) {
+		switch (IBuf[IOff]) {
+		case Q931ie_CAUSE:
+		case Q931ie_DISPLAY:
+			rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+			if (rc != Q931E_NO_ERROR) 
+				return rc;
+			break;
+		default:
+			return Q931E_ILLEGAL_IE;
+			break;
+		}
+	}
+
+	mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+	return Q931E_NO_ERROR;
+}
+
+
+/*****************************************************************************
+
+  Function:	 Q931Pmes_ResumeReject
+
+*****************************************************************************/
+L3INT Q931Pmes_ResumeReject(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+	Q931mes_Generic *pMes = (Q931mes_Generic *)IBuf;
+	L3INT rc = Q931E_NO_ERROR;
+	L3INT Octet = 0;
+
+	/* Q931 Message Header	*/
+	Q931MesgHeader(pTrunk, pMes, OBuf, *OSize, &Octet);
+
+	/* Cause */
+	if (Q931IsIEPresent(pMes->Cause)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CAUSE](pTrunk, Q931GetIEPtr(pMes->Cause,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Display */
+	if (Q931IsIEPresent(pMes->Display)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_DISPLAY](pTrunk, Q931GetIEPtr(pMes->Display,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	*OSize = Octet;	
+	return rc;
+}
+
+L3INT Q931Umes_Segment(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT OOff)
+{
+	L3INT i = IOff;
+
+	return IOff - i;
+}
+
+L3INT Q931Pmes_Segment(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+	L3BOOL RetCode = L3FALSE;
+
+	*OSize = 0;	
+	return RetCode;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Umes_Setup
+
+*****************************************************************************/
+L3INT Q931Umes_Setup(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+	L3INT ir = 0;
+	L3INT OOff = 0;
+	L3INT rc = Q931E_NO_ERROR;
+
+	while (IOff < Size) {
+		switch (IBuf[IOff]) {
+		case Q931ie_SENDING_COMPLETE:
+			IOff++;
+			break;
+
+		case Q931ie_BEARER_CAPABILITY:
+		case Q931ie_CHANNEL_IDENTIFICATION:
+		case Q931ie_PROGRESS_INDICATOR:
+		case Q931ie_NETWORK_SPECIFIC_FACILITIES:
+		case Q931ie_DISPLAY:
+		case Q931ie_DATETIME:
+		case Q931ie_KEYPAD_FACILITY:
+		case Q931ie_SIGNAL:
+		case Q931ie_CALLING_PARTY_NUMBER:
+		case Q931ie_CALLING_PARTY_SUBADDRESS:
+		case Q931ie_CALLED_PARTY_NUMBER:
+		case Q931ie_CALLED_PARTY_SUBADDRESS:
+		case Q931ie_TRANSIT_NETWORK_SELECTION:
+		case Q931ie_LOW_LAYER_COMPATIBILITY:
+		case Q931ie_HIGH_LAYER_COMPATIBILITY:
+		case Q931ie_FACILITY:
+		case Q931ie_USER_USER:
+		case Q931ie_REDIRECTING_NUMBER:
+			rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+			if (rc != Q931E_NO_ERROR) 
+				return rc;
+			break;
+
+		case Q931ie_REPEAT_INDICATOR:
+			if (ir < 2) {
+				rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+				ir++;
+			} else {
+				return Q931E_ILLEGAL_IE;
+			}
+			break;
+
+		default:
+			return Q931E_ILLEGAL_IE;
+			break;
+		}
+	}
+
+	mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Pmes_Setup
+
+  Decription:	Pack a Q931mes_Generic into a real Q.931 message. The user will
+				set up a SETUP message and issue this to the stack where it
+				is processed by Q931ProcSetup that processes and validates
+				it before it actually sends it out. This function is called
+				to compute the real Q.931 message.
+
+  Parameters:	IBuf[IN]	Ptr to un-packed struct
+				ISize[IN]	Size of input buffer (unpacked message).
+				OBuf[OUT]	Ptr to packed 'octet' wise message.
+				OSize[OUT]	Size of packed message.
+
+  Called By:	Q931ProcSetup
+
+*****************************************************************************/
+L3INT Q931Pmes_Setup(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+	Q931mes_Generic *pMes = (Q931mes_Generic *)IBuf;
+	L3INT rc = Q931E_NO_ERROR;
+	L3INT Octet = 0;
+
+	/* Q931 Message Header */
+	Q931MesgHeader(pTrunk, pMes, OBuf, *OSize, &Octet);
+
+	/* Sending Complete */
+	if (Q931IsIEPresent(pMes->SendComplete)) {
+		OBuf[Octet++] = (L3UCHAR)Q931ie_SENDING_COMPLETE & 0xff;
+	}
+
+	/* Repeat Indicator */
+	if (Q931IsIEPresent(pMes->RepeatInd)) {
+		OBuf[Octet++] = (L3UCHAR)Q931ie_REPEAT_INDICATOR & 0xff;		
+	}
+
+	/* Bearer capability */
+	if (Q931IsIEPresent(pMes->BearerCap)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_BEARER_CAPABILITY](pTrunk, Q931GetIEPtr(pMes->BearerCap,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	} else {
+		rc = Q931E_BEARERCAP;
+	}
+
+	/* Channel Identification */
+	if (Q931IsIEPresent(pMes->ChanID)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CHANNEL_IDENTIFICATION](pTrunk, Q931GetIEPtr(pMes->ChanID,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Progress indicator */
+	if (Q931IsIEPresent(pMes->ProgInd)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_PROGRESS_INDICATOR](pTrunk, Q931GetIEPtr(pMes->ProgInd,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Network spesific facilities */
+	if (Q931IsIEPresent(pMes->NetFac)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_NETWORK_SPECIFIC_FACILITIES](pTrunk, Q931GetIEPtr(pMes->NetFac,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Display */
+	if (Q931IsIEPresent(pMes->Display)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_DISPLAY](pTrunk, Q931GetIEPtr(pMes->Display,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Date/Time */
+	if (Q931IsIEPresent(pMes->DateTime)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_DATETIME](pTrunk, Q931GetIEPtr(pMes->DateTime,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Keypad Facility */
+	if (Q931IsIEPresent(pMes->KeypadFac)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_KEYPAD_FACILITY](pTrunk, Q931GetIEPtr(pMes->KeypadFac,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Signal */
+	if (Q931IsIEPresent(pMes->Signal)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_SIGNAL](pTrunk, Q931GetIEPtr(pMes->Signal,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Calling Party Number */
+	if (Q931IsIEPresent(pMes->CallingNum)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CALLING_PARTY_NUMBER](pTrunk, Q931GetIEPtr(pMes->CallingNum,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Calling Party Subaddress */
+	if (Q931IsIEPresent(pMes->CallingSub)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CALLING_PARTY_SUBADDRESS](pTrunk, Q931GetIEPtr(pMes->CallingSub,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Called Party number */
+	if (Q931IsIEPresent(pMes->CalledNum)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CALLED_PARTY_NUMBER](pTrunk, Q931GetIEPtr(pMes->CalledNum,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Called party subaddress */
+	if (Q931IsIEPresent(pMes->CalledSub)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CALLED_PARTY_SUBADDRESS](pTrunk, Q931GetIEPtr(pMes->CalledSub,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Transit network selection */
+	if (Q931IsIEPresent(pMes->TransNetSel)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_TRANSIT_NETWORK_SELECTION](pTrunk, Q931GetIEPtr(pMes->TransNetSel,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Repeat Indicator */
+	if (Q931IsIEPresent(pMes->LLRepeatInd)) {
+		rc = Q931E_UNKNOWN_IE;/* TODO */
+	}
+
+	/* Low Layer Compatibility */
+	if (Q931IsIEPresent(pMes->LLComp)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_LOW_LAYER_COMPATIBILITY](pTrunk, Q931GetIEPtr(pMes->LLComp,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* High Layer Compatibility */
+	if (Q931IsIEPresent(pMes->HLComp)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_HIGH_LAYER_COMPATIBILITY](pTrunk, Q931GetIEPtr(pMes->HLComp,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	*OSize = Octet;	
+	return rc;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Umes_SetupAck
+
+*****************************************************************************/
+L3INT Q931Umes_SetupAck(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+	L3INT OOff = 0;
+	L3INT rc = Q931E_NO_ERROR;
+
+	while (IOff < Size) {
+		switch (IBuf[IOff]) {
+		case Q931ie_CHANNEL_IDENTIFICATION:
+		case Q931ie_PROGRESS_INDICATOR:
+		case Q931ie_DISPLAY:
+		case Q931ie_SIGNAL:
+			rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+			if (rc != Q931E_NO_ERROR) 
+				return rc;
+			break;
+		default:
+			return Q931E_ILLEGAL_IE;
+			break;
+		}
+	}
+
+	mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Pmes_SetupAck
+
+*****************************************************************************/
+L3INT Q931Pmes_SetupAck(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+	Q931mes_Generic *pMes = (Q931mes_Generic *)IBuf;
+	L3INT rc = Q931E_NO_ERROR;
+	L3INT Octet = 0;
+
+	/* Q931 Message Header */
+	Q931MesgHeader(pTrunk, pMes, OBuf, *OSize, &Octet);
+	
+	/* Channel Identification */
+	if (Q931IsIEPresent(pMes->ChanID)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CHANNEL_IDENTIFICATION](pTrunk, Q931GetIEPtr(pMes->ChanID,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Progress indicator */
+	if (Q931IsIEPresent(pMes->ProgInd)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_PROGRESS_INDICATOR](pTrunk, Q931GetIEPtr(pMes->ProgInd,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Display */
+	if (Q931IsIEPresent(pMes->Display)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_DISPLAY](pTrunk, Q931GetIEPtr(pMes->Display,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Signal */
+	if (Q931IsIEPresent(pMes->Signal)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_SIGNAL](pTrunk, Q931GetIEPtr(pMes->Signal,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	*OSize = Octet;	
+	return rc;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Umes_Status
+
+*****************************************************************************/
+L3INT Q931Umes_Status(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+	L3INT OOff = 0;
+	L3INT rc = Q931E_NO_ERROR;
+
+	while (IOff < Size) {
+		switch (IBuf[IOff]) {
+		case Q931ie_CAUSE:
+		case Q931ie_CALL_STATE:
+		case Q931ie_DISPLAY:
+			rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+			if (rc != Q931E_NO_ERROR) 
+				return rc;
+			break;
+		default:
+			return Q931E_ILLEGAL_IE;
+			break;
+		}
+	}
+
+	mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+	return Q931E_NO_ERROR;
+}
+
+
+/*****************************************************************************
+
+  Function:	 Q931Pmes_Status
+
+*****************************************************************************/
+L3INT Q931Pmes_Status(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+	Q931mes_Generic *pMes = (Q931mes_Generic *)IBuf;
+	L3INT rc = Q931E_NO_ERROR;
+	L3INT Octet = 0;
+
+	/* Q931 Message Header */
+	Q931MesgHeader(pTrunk, pMes, OBuf, *OSize, &Octet);
+	
+	/* Cause */
+	if (Q931IsIEPresent(pMes->Cause)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CAUSE](pTrunk, Q931GetIEPtr(pMes->Cause,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Call State */
+	if (Q931IsIEPresent(pMes->CallState)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CALL_STATE](pTrunk, Q931GetIEPtr(pMes->CallState,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Display */
+	if (Q931IsIEPresent(pMes->Display)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_DISPLAY](pTrunk, Q931GetIEPtr(pMes->Display,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	*OSize = Octet;	
+	return rc;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Umes_StatusEnquiry
+
+*****************************************************************************/
+L3INT Q931Umes_StatusEnquiry(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+	L3INT OOff = 0;
+	L3INT rc = Q931E_NO_ERROR;
+
+	while (IOff < Size) {
+		switch (IBuf[IOff]) {
+		case Q931ie_DISPLAY:
+			rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+			if (rc != Q931E_NO_ERROR) 
+				return rc;
+			break;
+		default:
+			return Q931E_ILLEGAL_IE;
+			break;
+		}
+	}
+
+	mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Pmes_StatusEnquiry
+
+*****************************************************************************/
+L3INT Q931Pmes_StatusEnquiry(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+	Q931mes_Generic *pMes = (Q931mes_Generic *)IBuf;
+	L3INT rc = Q931E_NO_ERROR;
+	L3INT Octet = 0;
+
+	/* Q931 Message Header */
+	Q931MesgHeader(pTrunk, pMes, OBuf, *OSize, &Octet);
+	
+	/* Display */
+	if (Q931IsIEPresent(pMes->Display)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_DISPLAY](pTrunk, Q931GetIEPtr(pMes->Display,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	*OSize = Octet;	
+
+	return rc;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Umes_Suspend
+
+*****************************************************************************/
+L3INT Q931Umes_Suspend(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+	L3INT OOff = 0;
+	L3INT rc = Q931E_NO_ERROR;
+
+	while (IOff < Size) {
+		switch (IBuf[IOff]) {
+		case Q931ie_CALL_IDENTITY:
+			rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+			if (rc != Q931E_NO_ERROR) 
+				return rc;
+			break;
+		default:
+			return Q931E_ILLEGAL_IE;
+			break;
+		}
+	}
+
+	mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Pmes_Suspend
+
+*****************************************************************************/
+L3INT Q931Pmes_Suspend(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+	Q931mes_Generic *pMes = (Q931mes_Generic *)IBuf;
+	L3INT rc = Q931E_NO_ERROR;
+	L3INT Octet = 0;
+
+	/* Q931 Message Header */
+	Q931MesgHeader(pTrunk, pMes, OBuf, *OSize, &Octet);
+	
+	/* Call Identity */
+	if (Q931IsIEPresent(pMes->CallID)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CALL_IDENTITY](pTrunk, Q931GetIEPtr(pMes->CallID,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	*OSize = Octet;	
+	return rc;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Umes_SuspendAck
+
+*****************************************************************************/
+L3INT Q931Umes_SuspendAck(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+	L3INT OOff = 0;
+	L3INT rc = Q931E_NO_ERROR;
+
+	while (IOff < Size) {
+		switch (IBuf[IOff]) {
+		case Q931ie_DISPLAY:
+			rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+			if (rc != Q931E_NO_ERROR) 
+				return rc;
+			break;
+		default:
+			return Q931E_ILLEGAL_IE;
+			break;
+		}
+	}
+
+	mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Pmes_SuspendAck
+
+*****************************************************************************/
+L3INT Q931Pmes_SuspendAck(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+	Q931mes_Generic *pMes = (Q931mes_Generic *)IBuf;
+	L3INT rc = Q931E_NO_ERROR;
+	L3INT Octet = 0;
+
+	/* Q931 Message Header */
+	Q931MesgHeader(pTrunk, pMes, OBuf, *OSize, &Octet);
+	
+	/* Display */
+	if (Q931IsIEPresent(pMes->Display)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_DISPLAY](pTrunk, Q931GetIEPtr(pMes->Display,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	*OSize = Octet;	
+	return rc;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Umes_SuspendReject
+
+*****************************************************************************/
+L3INT Q931Umes_SuspendReject(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+	L3INT OOff = 0;
+	L3INT rc = Q931E_NO_ERROR;
+
+	while (IOff < Size) {
+		switch (IBuf[IOff]) {
+		case Q931ie_CAUSE:
+		case Q931ie_DISPLAY:
+			rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+			if (rc != Q931E_NO_ERROR) 
+				return rc;
+			break;
+		default:
+			return Q931E_ILLEGAL_IE;
+			break;
+		}
+	}
+
+	mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Pmes_SuspendReject
+
+*****************************************************************************/
+L3INT Q931Pmes_SuspendReject(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+	Q931mes_Generic *pMes = (Q931mes_Generic *)IBuf;
+	L3INT rc = Q931E_NO_ERROR;
+	L3INT Octet = 0;
+
+	/* Q931 Message Header */
+	Q931MesgHeader(pTrunk, pMes, OBuf, *OSize, &Octet);
+	
+	/* Cause */
+	if (Q931IsIEPresent(pMes->Cause)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CAUSE](pTrunk, Q931GetIEPtr(pMes->Cause,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Display */
+	if (Q931IsIEPresent(pMes->Display)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_DISPLAY](pTrunk, Q931GetIEPtr(pMes->Display,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	*OSize = Octet;	
+	return rc;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Umes_UserInformation
+
+*****************************************************************************/
+L3INT Q931Umes_UserInformation(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT I, L3INT O)
+{
+	L3BOOL RetCode = L3FALSE;
+
+	NoWarning(mes);
+	NoWarning(IBuf);
+
+	return RetCode;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Pmes_UserInformation
+
+*****************************************************************************/
+L3INT Q931Pmes_UserInformation(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+	L3BOOL RetCode = L3FALSE;
+
+	NoWarning(OBuf);
+	NoWarning(IBuf);
+
+	*OSize = 0;	
+
+	return RetCode;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Umes_Service
+
+*****************************************************************************/
+L3INT Q931Umes_Service(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+	L3INT OOff = 0;
+	L3INT rc = Q931E_NO_ERROR;
+
+	while (IOff < Size) {
+		switch (IBuf[IOff]) {
+		case Q931ie_CHANNEL_IDENTIFICATION:
+			rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+			if (rc != Q931E_NO_ERROR) 
+				return rc;
+			break;
+		case Q931ie_CHANGE_STATUS:
+			rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+			if (rc != Q931E_NO_ERROR) 
+				return rc;
+			break;
+		default:
+			return Q931E_ILLEGAL_IE;
+			break;
+		}
+	}
+
+	mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Pmes_Service
+
+*****************************************************************************/
+L3INT Q931Pmes_Service(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+	Q931mes_Generic *pMes = (Q931mes_Generic *)IBuf;
+	L3INT rc = Q931E_NO_ERROR;
+	L3INT Octet = 0;
+
+	/* Q931 Message Header */
+	Q931MesgHeader(pTrunk, pMes, OBuf, *OSize, &Octet);
+	
+	/* Display */
+	if (Q931IsIEPresent(pMes->ChanID)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CHANNEL_IDENTIFICATION](pTrunk, Q931GetIEPtr(pMes->ChanID,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	if (Q931IsIEPresent(pMes->ChangeStatus)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CHANGE_STATUS](pTrunk, Q931GetIEPtr(pMes->ChangeStatus,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	*OSize = Octet;	
+	return rc;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Umes_ServiceAck
+
+*****************************************************************************/
+L3INT Q931Umes_ServiceAck(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+	L3INT OOff = 0;
+	L3INT rc = Q931E_NO_ERROR;
+
+	while (IOff < Size) {
+		switch (IBuf[IOff]) {
+		case Q931ie_CHANNEL_IDENTIFICATION:
+			rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+			if (rc != Q931E_NO_ERROR) 
+				return rc;
+			break;
+		case Q931ie_CHANGE_STATUS:
+			rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+			if (rc != Q931E_NO_ERROR) 
+				return rc;
+			break;
+		default:
+			return Q931E_ILLEGAL_IE;
+			break;
+		}
+	}
+
+	mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Pmes_ServiceAck
+
+*****************************************************************************/
+L3INT Q931Pmes_ServiceAck(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+	Q931mes_Generic *pMes = (Q931mes_Generic *)IBuf;
+	L3INT rc = Q931E_NO_ERROR;
+	L3INT Octet = 0;
+
+	/* Q931 Message Header */
+	Q931MesgHeader(pTrunk, pMes, OBuf, *OSize, &Octet);
+	
+	if (Q931IsIEPresent(pMes->ChangeStatus)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CHANGE_STATUS](pTrunk, Q931GetIEPtr(pMes->ChangeStatus,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	if (Q931IsIEPresent(pMes->ChanID)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CHANNEL_IDENTIFICATION](pTrunk, Q931GetIEPtr(pMes->ChanID,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	*OSize = Octet;	
+	return rc;
+}

Added: freeswitch/trunk/libs/freetdm/src/isdn/Q932mes.c (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/isdn/Q932mes.c	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/isdn/Q932mes.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,286 @@
+/*****************************************************************************
+
+  FileName:		Q932mes.c
+
+  Contents:		Q.932 Message Encoders/Decoders
+
+  License/Copyright:
+
+  Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+  email:janvb@caselaboratories.com  
+
+  Redistribution and use in source and binary forms, with or without 
+  modification, are permitted provided that the following conditions are 
+  met:
+
+	* Redistributions of source code must retain the above copyright notice, 
+	  this list of conditions and the following disclaimer.
+	* Redistributions in binary form must reproduce the above copyright notice, 
+	  this list of conditions and the following disclaimer in the documentation 
+	  and/or other materials provided with the distribution.
+	* Neither the name of the Case Labs, Ltd nor the names of its contributors 
+	  may be used to endorse or promote products derived from this software 
+	  without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
+  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
+  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+  POSSIBILITY OF SUCH DAMAGE.
+*****************************************************************************/
+
+#include "Q931.h"
+
+/*****************************************************************************
+
+  Function:	 Q932Umes_Facility
+
+*****************************************************************************/
+
+L3INT Q932Umes_Facility(Q931_TrunkInfo_t *pTrunk,L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+	L3INT OOff = 0;
+
+	/* TODO */
+
+	mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Pmes_Facility
+
+*****************************************************************************/
+L3INT Q932Pmes_Facility(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+	L3BOOL RetCode = L3FALSE;
+
+	NoWarning(OBuf);
+	NoWarning(IBuf);
+
+	return RetCode;
+}
+
+/*****************************************************************************
+
+  Function:	 Q932Umes_Hold
+
+*****************************************************************************/
+
+L3INT Q932Umes_Hold(Q931_TrunkInfo_t *pTrunk,L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+	L3INT OOff = 0;
+
+	/* TODO */
+
+	mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Pmes_Hold
+
+*****************************************************************************/
+L3INT Q932Pmes_Hold(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+	L3BOOL RetCode = L3FALSE;
+
+	NoWarning(OBuf);
+	NoWarning(IBuf);
+
+	return RetCode;
+}
+
+/*****************************************************************************
+
+  Function:	 Q932Umes_HoldAck
+
+*****************************************************************************/
+
+L3INT Q932Umes_HoldAck(Q931_TrunkInfo_t *pTrunk,L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+	L3INT OOff = 0;
+
+	/* TODO */
+
+	mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Pmes_HoldAck
+
+*****************************************************************************/
+L3INT Q932Pmes_HoldAck(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+	L3BOOL RetCode = L3FALSE;
+
+	NoWarning(OBuf);
+	NoWarning(IBuf);
+
+	return RetCode;
+}
+
+/*****************************************************************************
+
+  Function:	 Q932Umes_HoldReject
+
+*****************************************************************************/
+
+L3INT Q932Umes_HoldReject(Q931_TrunkInfo_t *pTrunk,L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+	L3INT OOff = 0;
+
+	/* TODO */
+
+	mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Pmes_HoldReject
+
+*****************************************************************************/
+L3INT Q932Pmes_HoldReject(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+	L3BOOL RetCode = L3FALSE;
+
+	NoWarning(OBuf);
+	NoWarning(IBuf);
+
+	return RetCode;
+}
+
+/*****************************************************************************
+
+  Function:	 Q932Umes_Register
+
+*****************************************************************************/
+
+L3INT Q932Umes_Register(Q931_TrunkInfo_t *pTrunk,L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+	L3INT OOff = 0;
+
+	/* TODO */
+
+	mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Pmes_Register
+
+*****************************************************************************/
+L3INT Q932Pmes_Register(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+	L3BOOL RetCode = L3FALSE;
+
+	NoWarning(OBuf);
+	NoWarning(IBuf);
+
+	return RetCode;
+}
+
+/*****************************************************************************
+
+  Function:	 Q932Umes_Retrieve
+
+*****************************************************************************/
+
+L3INT Q932Umes_Retrieve(Q931_TrunkInfo_t *pTrunk,L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+	L3INT OOff = 0;
+
+	/* TODO */
+
+	mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Pmes_Retrieve
+
+*****************************************************************************/
+L3INT Q932Pmes_Retrieve(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+	L3BOOL RetCode = L3FALSE;
+
+	NoWarning(OBuf);
+	NoWarning(IBuf);
+
+	return RetCode;
+}
+
+/*****************************************************************************
+
+  Function:	 Q932Umes_RetrieveAck
+
+*****************************************************************************/
+
+L3INT Q932Umes_RetrieveAck(Q931_TrunkInfo_t *pTrunk,L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+	L3INT OOff = 0;
+
+	/* TODO */
+
+	mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Pmes_RetrieveAck
+
+*****************************************************************************/
+L3INT Q932Pmes_RetrieveAck(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+	L3BOOL RetCode = L3FALSE;
+
+	NoWarning(OBuf);
+	NoWarning(IBuf);
+
+	return RetCode;
+}
+
+/*****************************************************************************
+
+  Function:	 Q932Umes_RetrieveReject
+
+*****************************************************************************/
+
+L3INT Q932Umes_RetrieveReject(Q931_TrunkInfo_t *pTrunk,L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+	L3INT OOff = 0;
+
+	/* TODO */
+
+	mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Pmes_RetrieveReject
+
+*****************************************************************************/
+L3INT Q932Pmes_RetrieveReject(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+	L3BOOL RetCode = L3FALSE;
+
+	NoWarning(OBuf);
+	NoWarning(IBuf);
+
+	return RetCode;
+}

Added: freeswitch/trunk/libs/freetdm/src/isdn/include/5ESS.h (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/isdn/include/5ESS.h	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/isdn/include/5ESS.h	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,103 @@
+/******************************************************************************
+
+  FileName:         5ESS.h
+
+  Contents:         Header and definition for the AT&T 5ESS ISDN dialect. The 
+                    header contains the following parts:
+
+                    - Definition of codes
+                    - Definition of information elements (5ESSie_).
+                    - Definition of messages (5ESSmes_).
+                    - Function prototypes.
+
+  Description:      The AT&T 5ESS ISDN dialect here covers ????
+
+  Related Files:    5ESS.h              AT&T 5ESS ISDN Definitions
+                    5ESSie.c            AT&T 5ESS ISDN IE encoders/coders (not extant yet)
+                                        See Q931ie.c for IE encoders/coders
+                    5ESSStateTE.c       AT&T 5ESS ISDN TE State Engine
+                    5ESSStateNT.c       AT&T 5ESS ISDN NT State Engine
+
+  License/Copyright:
+
+  Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+  email:janvb@caselaboratories.com  
+
+  Copyright (c) 2007, Michael Jerris. All rights reserved.
+  email:mike@jerris.com  
+  
+  Copyright (c) 2007, Michael S. Collins, All rights reserved.
+  email:mcollins@fcnetwork.com
+
+  Redistribution and use in source and binary forms, with or without 
+  modification, are permitted provided that the following conditions are 
+  met:
+
+    * Redistributions of source code must retain the above copyright notice, 
+    this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright notice, 
+    this list of conditions and the following disclaimer in the documentation 
+    and/or other materials provided with the distribution.
+    * Neither the name of the Case Labs, Ltd nor the names of its contributors 
+    may be used to endorse or promote products derived from this software 
+    without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
+  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
+  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+  POSSIBILITY OF SUCH DAMAGE.
+******************************************************************************/
+
+#ifndef _5ESS_NL
+#define _5ESS_NL
+
+#include "Q931.h"
+
+/*****************************************************************************
+
+  Q.931 Message codes
+  Only 5ESS specific message and ie types 
+  here the rest are inherited from Q931.h
+  
+*****************************************************************************/
+
+
+/*****************************************************************************
+
+  Q.931 Message Pack/Unpack functions. Implemented in 5ESSmes.c
+  Note: Because C variables may not begin with numeric digit, all identifiers
+        are prefixed with "ATT5ESS" instead of a bare "5ESS"
+
+*****************************************************************************/
+L3INT ATT5ESSUmes_Setup(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT IOff, L3INT Size);
+L3INT ATT5ESSPmes_Setup(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT ATT5ESSUmes_SetupAck(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT IOff, L3INT Size);
+L3INT ATT5ESSPmes_SetupAck(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+
+L3INT ATT5ESSUmes_0x07(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size);
+L3INT ATT5ESSPmes_0x07(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT ATT5ESSUmes_0x0f(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size);
+L3INT ATT5ESSPmes_0x0f(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+
+
+
+/*****************************************************************************
+
+  Q.931 Process Function Prototyping. Implemented in 5ESSStateTE.c
+
+*****************************************************************************/
+L3INT ATT5ESSProc0x0fTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom);
+L3INT ATT5ESSProc0x07TE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom);
+
+
+void ATT5ESSCreateTE(L3UCHAR i);
+void ATT5ESSCreateNT(L3UCHAR i);
+
+#endif /* _5ESS_NL */

Added: freeswitch/trunk/libs/freetdm/src/isdn/include/DMS.h (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/isdn/include/DMS.h	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/isdn/include/DMS.h	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,91 @@
+/******************************************************************************
+
+  FileName:         national.h
+
+  Contents:         Header and definition for the National ISDN dialect. The 
+										header contents the following parts:
+                    - Definition of codes
+                    - Definition of information elements (nationalie_).
+                    - Definition of messages (nationalmes_).
+                    - Function prototypes.
+
+  Description:		The National ISDN dialect here covers ????
+
+  Related Files:	national.h			National ISDN Definitions
+			nationalie.c			National ISDN IE encoders/coders
+			nationalStateTE.c		National ISDN TE State Engine
+			nationalStateNT.c		National ISDN NT State Engine
+
+  License/Copyright:
+
+  Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+  email:janvb@caselaboratories.com  
+
+  Copyright (c) 2007, Michael Jerris. All rights reserved.
+  email:mike@jerris.com  
+
+  Redistribution and use in source and binary forms, with or without 
+  modification, are permitted provided that the following conditions are 
+  met:
+
+    * Redistributions of source code must retain the above copyright notice, 
+	  this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright notice, 
+	  this list of conditions and the following disclaimer in the documentation 
+	  and/or other materials provided with the distribution.
+    * Neither the name of the Case Labs, Ltd nor the names of its contributors 
+	  may be used to endorse or promote products derived from this software 
+	  without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
+  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
+  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+  POSSIBILITY OF SUCH DAMAGE.
+******************************************************************************/
+
+#ifndef _DMS_NL
+#define _DMS_NL
+
+#include "Q931.h"
+
+/*****************************************************************************
+
+  Q.931 Message codes
+  Only National specific message and ie types 
+  here the rest are inherited from national.h
+  
+*****************************************************************************/
+
+
+/*****************************************************************************
+
+  Q.931 Message Pack/Unpack functions. Implemented in nationalmes.c
+
+*****************************************************************************/
+L3INT DMSUmes_Setup(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT IOff, L3INT Size);
+L3INT DMSPmes_Setup(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT DMSUmes_0x07(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size);
+L3INT DMSPmes_0x07(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT DMSUmes_0x0f(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size);
+L3INT DMSPmes_0x0f(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+
+/*****************************************************************************
+
+  Q.931 Process Function Prototyping. Implemented in nationalStateTE.c
+
+*****************************************************************************/
+
+L3INT DMSProc0x0fTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom);
+L3INT DMSProc0x07TE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom);
+
+void DMSCreateTE(L3UCHAR i);
+void DMSCreateNT(L3UCHAR i);
+
+#endif /* _DMS_NL */

Added: freeswitch/trunk/libs/freetdm/src/isdn/include/Q921.h (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/isdn/include/Q921.h	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/isdn/include/Q921.h	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,227 @@
+/*****************************************************************************
+
+  FileName:     q921.h
+
+  Description:  Contains headers of a Q.921 protocol.
+
+  Note:         This header file is the only include file that should be 
+                acessed by users of the Q.921 stack.
+
+  Interface:    The Q.921 stack contains 2 layers. 
+
+                -   One interface layer.
+                -   One driver layer.
+
+                The interface layer contains the interface functions required 
+                for a layer 2 stack to be able to send and receive messages.
+
+                The driver layer will simply feed bytes into the ship as
+                required and queue messages received out from the ship.
+
+                Q921TimeTick        The Q.921 like any other blackbox 
+                                    modules contains no thread by it's own
+                                    and must therefore be called regularly 
+                                    by an external 'thread' to do maintenance
+                                    etc.
+
+                Q921Rx32            Receive message from layer 3. Called by
+                                    the layer 3 stack to send a message.
+
+
+				NOTE: The following are not yet implemented
+
+                OnQ921Error         Function called every if an error is 
+                                    detected.
+
+                OnQ921Log           Function called if logging is active.
+
+
+                <TODO> Maintenance/Configuration interface
+				<TODO> Logging
+				<TODO> DL_ message passing to layer 3
+				<TODO> Timers
+				<TODO> Api commands to tell 921 to stop and start for a trunk
+
+  Created:      27.dec.2000/JVB
+
+  License/Copyright:
+
+  Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+  email:janvb@caselaboratories.com  
+
+  Redistribution and use in source and binary forms, with or without 
+  modification, are permitted provided that the following conditions are 
+  met:
+
+    * Redistributions of source code must retain the above copyright notice, 
+	  this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright notice, 
+	  this list of conditions and the following disclaimer in the documentation 
+	  and/or other materials provided with the distribution.
+    * Neither the name of the Case Labs, Ltd nor the names of its contributors 
+	  may be used to endorse or promote products derived from this software 
+	  without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
+  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
+  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+  POSSIBILITY OF SUCH DAMAGE.
+
+*****************************************************************************/
+
+/****************************************************************************
+ * Changes:
+ *
+ * - June,July 2008: Stefan Knoblich <s.knoblich@axsentis.de>:
+ *     Add PTMP TEI management
+ *     Add timers
+ *     Add retransmit counters
+ *     Add logging
+ *     Various cleanups
+ *
+ ****************************************************************************/
+
+#ifndef _Q921
+#define _Q921
+
+#define Q921MAXHDLCSPACE 3000
+#define L2UCHAR		unsigned char		/* Min 8 bit			*/
+#define L2USHORT	unsigned short		/* 16 bit			*/
+#define L2INT		int			/* Min 16 bit signed		*/
+#define L2ULONG		unsigned long		/* Min 32 bit			*/
+#define L2TRUNK		Q921Data_t *
+
+#define Q921_TEI_BCAST		127
+#define Q921_TEI_MAX		Q921_TEI_BCAST
+
+#define Q921_TEI_DYN_MIN	64
+#define Q921_TEI_DYN_MAX	126
+
+
+typedef enum			/* Network/User Mode		*/
+{
+	Q921_TE=0,		/*  0 : User Mode		*/
+	Q921_NT=1		/*  1 : Network Mode		*/
+} Q921NetUser_t;
+
+typedef enum			/* Type of connection		*/
+{
+	Q921_PTP=0,		/* 0 : Point-To-Point		*/
+	Q921_PTMP=1		/* 1 : Point-To-Multipoint	*/
+} Q921NetType_t;
+
+typedef enum
+{
+	Q921_LOG_NONE = -1,
+	Q921_LOG_EMERG = 0,
+	Q921_LOG_ALERT,
+	Q921_LOG_CRIT,
+	Q921_LOG_ERROR,
+	Q921_LOG_WARNING,
+	Q921_LOG_NOTICE,
+	Q921_LOG_INFO,
+	Q921_LOG_DEBUG
+} Q921LogLevel_t;
+
+
+/*
+ * Messages for L2 <-> L3 communication
+ */
+typedef enum {
+	Q921_DL_ESTABLISH = 0,
+	Q921_DL_ESTABLISH_CONFIRM,
+	Q921_DL_RELEASE,
+	Q921_DL_RELEASE_CONFIRM,
+	Q921_DL_DATA,
+	Q921_DL_UNIT_DATA
+} Q921DLMsg_t;
+
+typedef int (*Q921Tx21CB_t) (void *, L2UCHAR *, L2INT);
+typedef int (*Q921Tx23CB_t) (void *, Q921DLMsg_t ind, L2UCHAR tei, L2UCHAR *, L2INT);
+typedef int (*Q921LogCB_t) (void *, Q921LogLevel_t, char *, L2INT);
+
+struct Q921_Link;
+
+typedef struct Q921Data
+{
+	L2INT initialized;
+
+	L2UCHAR sapi;			/*!< User assigned SAPI */
+	L2UCHAR tei;			/*!< User assigned TEI value */
+
+	L2INT Q921HeaderSpace;
+	Q921NetUser_t NetUser;
+	Q921NetType_t NetType;
+
+	struct Q921_Link *context;	/*!< per-TEI / link context space */
+
+	/* timers */
+	L2ULONG T202;			/*!< PTMP TE mode TEI retransmit timer */
+	L2ULONG T200Timeout;
+	L2ULONG T201Timeout;
+	L2ULONG T202Timeout;
+	L2ULONG T203Timeout;
+
+	L2ULONG TM01Timeout;
+
+	/* counters */
+	L2ULONG N200Limit;		/*!< max retransmit */
+
+	L2ULONG N202;			/*!< PTMP TE mode retransmit counter */
+	L2ULONG N202Limit;		/*!< PTMP TE mode max retransmit */
+
+	L2ULONG N201Limit;		/*!< max number of octets */
+	L2ULONG k;			/*!< max number of unacknowledged I frames */
+
+	/* callbacks and callback data pointers */
+	Q921Tx21CB_t Q921Tx21Proc;
+	Q921Tx23CB_t Q921Tx23Proc;
+	void *PrivateData21;
+	void *PrivateData23;
+
+	/* logging */
+	Q921LogLevel_t	loglevel;	/*!< trunk loglevel */
+	Q921LogCB_t	Q921LogProc;	/*!< log callback procedure */
+	void *PrivateDataLog;		/*!< private data pointer for log proc */
+
+	/* tei mgmt */
+	L2UCHAR tei_map[Q921_TEI_MAX];	/*!< */
+
+	L2UCHAR HDLCInQueue[Q921MAXHDLCSPACE];	/*!< HDLC input queue */
+} Q921Data_t;
+
+/*
+ * Public functions
+ */
+int Q921_InitTrunk(L2TRUNK trunk,
+					L2UCHAR sapi,
+					L2UCHAR tei,
+					Q921NetUser_t NetUser,
+					Q921NetType_t NetType,
+					L2INT hsize,
+					Q921Tx21CB_t cb21,
+					Q921Tx23CB_t cb23,
+					void *priv21,
+					void *priv23);
+int Q921Start(L2TRUNK trunk);
+int Q921Stop(L2TRUNK trunk);
+
+void Q921SetLogCB(L2TRUNK trunk, Q921LogCB_t func, void *priv);
+void Q921SetLogLevel(L2TRUNK trunk, Q921LogLevel_t level);
+
+int Q921Rx12(L2TRUNK trunk);
+int Q921Rx32(L2TRUNK trunk, Q921DLMsg_t ind, L2UCHAR tei, L2UCHAR * Mes, L2INT Size);
+
+int Q921QueueHDLCFrame(L2TRUNK trunk, L2UCHAR *b, L2INT size);
+
+void Q921SetGetTimeCB(L2ULONG (*callback)(void));
+void Q921TimerTick(L2TRUNK trunk);
+
+#endif

Added: freeswitch/trunk/libs/freetdm/src/isdn/include/Q921priv.h (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/isdn/include/Q921priv.h	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/isdn/include/Q921priv.h	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,321 @@
+/*****************************************************************************
+
+  FileName:     Q921priv.h
+
+  Description:  Private declarations
+
+  Created:      08.Aug.2008/STKN
+
+  License/Copyright:
+
+  Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+  email:janvb@caselaboratories.com  
+
+  Copyright (c) 2008, Stefan Knoblich, axsentis GmbH. All rights reserved.
+  email:s.knoblich@axsentis.de  
+
+  Redistribution and use in source and binary forms, with or without 
+  modification, are permitted provided that the following conditions are 
+  met:
+
+    * Redistributions of source code must retain the above copyright notice, 
+	  this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright notice, 
+	  this list of conditions and the following disclaimer in the documentation 
+	  and/or other materials provided with the distribution.
+    * Neither the name of the Case Labs, Ltd nor the names of its contributors 
+	  may be used to endorse or promote products derived from this software 
+	  without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
+  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
+  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+  POSSIBILITY OF SUCH DAMAGE.
+
+*****************************************************************************/
+#ifndef _Q921_PRIV_H_
+#define _Q921_PRIV_H_
+
+#ifdef _MSC_VER
+#ifndef __inline__
+#define __inline__ __inline
+#endif
+#if (_MSC_VER >= 1400)			/* VC8+ */
+#ifndef _CRT_SECURE_NO_DEPRECATE
+#define _CRT_SECURE_NO_DEPRECATE
+#endif
+#ifndef _CRT_NONSTDC_NO_DEPRECATE
+#define _CRT_NONSTDC_NO_DEPRECATE
+#endif
+#endif
+#ifndef strcasecmp
+#define strcasecmp(s1, s2) _stricmp(s1, s2)
+#endif
+#ifndef strncasecmp
+#define strncasecmp(s1, s2, n) _strnicmp(s1, s2, n)
+#endif
+#ifndef snprintf
+#define snprintf _snprintf
+#endif
+#endif
+
+typedef enum			/* Q.921 States */
+{
+	Q921_STATE_STOPPED = 0,			/* Trunk stopped */
+	Q921_STATE_TEI_UNASSIGNED = 1,		/* TEI unassigned */
+	Q921_STATE_TEI_AWAITING,		/* Assign awaiting TEI */
+	Q921_STATE_TEI_ESTABLISH,		/* Establish awaiting TEI */
+	Q921_STATE_TEI_ASSIGNED,		/* TEI assigned */
+	Q921_STATE_AWAITING_ESTABLISHMENT,	/* Awaiting establishment */
+	Q921_STATE_AWAITING_RELEASE,		/* Awaiting release */
+	Q921_STATE_MULTIPLE_FRAME_ESTABLISHED,	/* Multiple frame established */
+	Q921_STATE_TIMER_RECOVERY		/* Timer recovery */
+} Q921State_t;
+
+/*
+ * Flags
+ */
+enum Q921_Flags {
+	Q921_FLAG_L3_INITIATED = (1 << 0),
+
+	Q921_FLAG_UI_FRAME_QUEUED = (1 << 1),
+	Q921_FLAG_I_FRAME_QUEUED  = (1 << 2),
+
+	Q921_FLAG_ACK_PENDING = (1 << 3),
+	Q921_FLAG_REJECT      = (1 << 4),
+
+	Q921_FLAG_RECV_BUSY      = (1 << 5),
+	Q921_FLAG_PEER_RECV_BUSY = (1 << 6)
+};
+
+#define Q921_SET_FLAG(x, f)	((x)->flags |= f)
+#define Q921_CHECK_FLAG(x, f)	((x)->flags & f)
+#define Q921_CLEAR_FLAG(x, f)	((x)->flags &= ~f)
+
+
+/*
+ * dynamic TEI handling
+ */
+#define Q921_SAPI_TEI		63	/* SAPI for all TEI Messages */
+#define Q921_LAYER_ENT_ID_TEI	0x0f	/* UN Layer Management Entity ID for TEI Mgmt */
+#define Q921_LAYER_ENT_ID_Q931	0x08	/* Q.931 Layer Management Entity ID */
+
+
+typedef enum {
+	Q921_TEI_ID_REQUEST = 1,
+	Q921_TEI_ID_ASSIGNED,
+	Q921_TEI_ID_DENIED,
+	Q921_TEI_ID_CHECKREQ,
+	Q921_TEI_ID_CHECKRESP,
+	Q921_TEI_ID_REMOVE,
+	Q921_TEI_ID_VERIFY
+} Q921TeiMessageType_t;
+
+
+/**
+ * Per-Datalink context
+ */
+struct Q921_Link {
+	L2UCHAR tei;		/*!< This endpoint's TEI */
+
+	L2UCHAR va;
+	L2UCHAR vs;
+	L2UCHAR vr;
+
+	L2INT flags;
+	Q921State_t state;
+
+	L2ULONG N202;		/*!< PTMP TE mode retransmit counter */
+	L2ULONG N200;		/*!< retransmit counter (per-TEI in PTMP NT mode) */
+
+	L2ULONG TM01;		/*!< Datalink inactivity disconnect timer */
+
+	L2ULONG T200;
+	L2ULONG T201;		/*!< PTMP NT mode timer */
+	L2ULONG T203;
+
+	L2USHORT ri;		/*!< random id for TEI request mgmt */
+
+	/* I + UI Frame queue */
+	L2UCHAR UIFrameQueue[Q921MAXHDLCSPACE];
+	L2UCHAR  IFrameQueue[Q921MAXHDLCSPACE];
+	L2UCHAR  IFrameResendQueue[Q921MAXHDLCSPACE];
+};
+
+
+#define Q921_LINK_CONTEXT(tr, tei) \
+	(Q921_IS_PTMP_NT(tr) && tei != Q921_TEI_BCAST) ? ((struct Q921_Link *)&(tr)->context[tei]) : (tr)->context
+
+#define Q921_TRUNK_CONTEXT(tr) \
+	(tr)->context
+
+#define Q921_LOGBUFSIZE		2000
+#define INITIALIZED_MAGIC	42
+
+/*
+ * Helper macros
+ */
+#define Q921_INC_COUNTER(x)		(x = (x + 1) % 128)
+#define Q921_DEC_COUNTER(x)		(x = (x) ? (x - 1) : 127)
+
+#define Q921_UFRAME_HEADER_SIZE		3
+#define Q921_UFRAME_DATA_OFFSET(tr)	((tr)->Q921HeaderSpace + Q921_UFRAME_HEADER_SIZE)
+
+#define Q921_SFRAME_HEADER_SIZE		4
+#define Q921_SFRAME_DATA_OFFSET(tr)	((tr)->Q921HeaderSpace + Q921_SFRAME_HEADER_SIZE)
+
+#define Q921_IFRAME_HEADER_SIZE		4
+#define Q921_IFRAME_DATA_OFFSET(tr)	((tr)->Q921HeaderSpace + Q921_IFRAME_HEADER_SIZE)
+
+#define Q921_IS_TE(x)			((x)->NetUser == Q921_TE)
+#define Q921_IS_NT(x)			((x)->NetUser == Q921_NT)
+
+#define Q921_IS_STOPPED(tr)		((tr)->state == Q921_STATE_STOPPED)
+
+/* TODO: rework this one */
+#define Q921_IS_READY(tr)		((tr)->state >= Q921_STATE_TEI_ASSIGNED)
+
+#define Q921_IS_PTMP(x)			((x)->NetType == Q921_PTMP)
+#define Q921_IS_PTMP_TE(x)		((x)->NetType == Q921_PTMP && (x)->NetUser == Q921_TE)
+#define Q921_IS_PTMP_NT(x)		((x)->NetType == Q921_PTMP && (x)->NetUser == Q921_NT)
+
+#define Q921_IS_PTP(x)			((x)->NetType == Q921_PTP)
+#define Q921_IS_PTP_TE(x)		((x)->NetType == Q921_PTP && (x)->NetUser == Q921_TE)
+#define Q921_IS_PTP_NT(x)		((x)->NetType == Q921_PTP && (x)->NetUser == Q921_NT)
+
+/* Make life a little easier */
+#define Q921_COMMAND(x)			((x)->NetUser == Q921_TE ? 0 : 1)
+#define Q921_RESPONSE(x)		((x)->NetUser == Q921_TE ? 1 : 0)
+
+#define Q921_IS_COMMAND(tr, x)		((x) == (Q921_IS_TE(tr) ? 1 : 0))
+#define Q921_IS_RESPONSE(tr, x)		((x) == (Q921_IS_TE(tr) ? 0 : 1))
+
+
+/*******************************************************************************
+ * Private functions
+ *******************************************************************************/
+
+/*
+ * L1 / L2 Interface
+ */
+static int Q921Tx21Proc(L2TRUNK trunk, L2UCHAR *Msg, L2INT size);
+static int Q921Tx23Proc(L2TRUNK trunk, Q921DLMsg_t ind, L2UCHAR tei, L2UCHAR *Msg, L2INT size);
+
+
+/*
+ * Timers
+ */
+static L2ULONG Q921GetTime(void);
+
+static void Q921T200TimerStart(L2TRUNK trunk, L2UCHAR tei);
+static void Q921T200TimerStop(L2TRUNK trunk, L2UCHAR tei);
+static void Q921T200TimerReset(L2TRUNK trunk, L2UCHAR tei);
+static void Q921T200TimerExpire(L2TRUNK trunk, L2UCHAR tei);
+
+static void Q921T201TimerStart(L2TRUNK trunk, L2UCHAR tei);
+static void Q921T201TimerStop(L2TRUNK trunk, L2UCHAR tei);
+/* static void Q921T201TimerReset(L2TRUNK trunk, L2UCHAR tei); - Unused for now */
+static void Q921T201TimerExpire(L2TRUNK trunk, L2UCHAR tei);
+
+static void Q921T202TimerStart(L2TRUNK trunk);
+static void Q921T202TimerStop(L2TRUNK trunk);
+static void Q921T202TimerReset(L2TRUNK trunk);
+static void Q921T202TimerExpire(L2TRUNK trunk);
+
+static void Q921T203TimerStart(L2TRUNK trunk, L2UCHAR tei);
+static void Q921T203TimerStop(L2TRUNK trunk, L2UCHAR tei);
+static void Q921T203TimerReset(L2TRUNK trunk, L2UCHAR tei);
+static void Q921T203TimerExpire(L2TRUNK trunk, L2UCHAR tei);
+
+static void Q921TM01TimerStart(L2TRUNK trunk, L2UCHAR tei);
+/* static void Q921TM01TimerStop(L2TRUNK trunk, L2UCHAR tei); - Unused for now */
+static void Q921TM01TimerReset(L2TRUNK trunk, L2UCHAR tei);
+/* static void Q921TM01TimerExpire(L2TRUNK trunk, L2UCHAR tei); - Unused for now */
+
+/*
+ * Frame encoding
+ */
+static int Q921SendS(L2TRUNK trunk, L2UCHAR Sapi, char cr, L2UCHAR Tei, char pf, L2UCHAR sv, L2UCHAR *mes, L2INT size);
+static int Q921SendU(L2TRUNK trunk, L2UCHAR Sapi, char cr, L2UCHAR Tei, char pf, L2UCHAR m, L2UCHAR *mes, L2INT size);
+
+static int Q921SendRNR(L2TRUNK trunk, int Sapi, int cr, int Tei, int pf);
+static int Q921SendREJ(L2TRUNK trunk, int Sapi, int cr, int Tei, int pf);
+static int Q921SendSABME(L2TRUNK trunk, int Sapi, int cr, int Tei, int pf);
+static int Q921SendDM(L2TRUNK trunk, int Sapi, int cr, int Tei, int pf);
+static int Q921SendDISC(L2TRUNK trunk, int Sapi, int cr, int Tei, int pf);
+static int Q921SendUA(L2TRUNK trunk, int Sapi, int cr, int Tei, int pf);
+static int Q921SendUN(L2TRUNK trunk, int Sapi, int cr, int Tei, int pf, L2UCHAR *mes, L2INT size);
+static int Q921SendRR(L2TRUNK trunk, int Sapi, int cr, int Tei, int pf);
+
+/*
+ * Frame decoding
+ */
+static int Q921ProcIFrame(L2TRUNK trunk, L2UCHAR *mes, L2INT size);
+static int Q921ProcSFrame(L2TRUNK trunk, L2UCHAR *mes, L2INT size);
+static int Q921ProcUFrame(L2TRUNK trunk, L2UCHAR *mes, L2INT size);
+
+static int Q921ProcSABME(L2TRUNK trunk, L2UCHAR *mes, L2INT size);
+static int Q921ProcDM(L2TRUNK trunk, L2UCHAR *mes, L2INT size);
+static int Q921ProcUA(L2TRUNK trunk, L2UCHAR *mes, L2INT size);
+static int Q921ProcDISC(L2TRUNK trunk, L2UCHAR *mes, L2INT size);
+static int Q921ProcRR(L2TRUNK trunk, L2UCHAR *mes, L2INT size);
+static int Q921ProcRNR(L2TRUNK trunk, L2UCHAR *mes, L2INT size);
+static int Q921ProcREJ(L2TRUNK trunk, L2UCHAR *mes, L2INT size);
+
+
+/*
+ * (Common) procedures defined in the Q.921 SDL
+ */
+static int Q921SendEnquiry(L2TRUNK trunk, L2UCHAR tei);
+static int Q921SendEnquiryResponse(L2TRUNK trunk, L2UCHAR tei);
+static void Q921ResetExceptionConditions(L2TRUNK trunk, L2UCHAR tei);
+static int Q921EstablishDataLink(L2TRUNK trunk, L2UCHAR tei);
+static int Q921NrErrorRecovery(L2TRUNK trunk, L2UCHAR tei);
+static int Q921InvokeRetransmission(L2TRUNK trunk, L2UCHAR tei, L2UCHAR nr);
+static int Q921AcknowledgePending(L2TRUNK trunk, L2UCHAR tei);
+/*
+static int Q921SetReceiverBusy(L2TRUNK trunk);
+static int Q921ClearReceiverBusy(L2TRUNK trunk);
+*/
+
+/*
+ * Queueing
+ */
+static int Q921SendQueuedIFrame(L2TRUNK trunk, L2UCHAR tei);
+static int Q921EnqueueI(L2TRUNK trunk, L2UCHAR Sapi, char cr, L2UCHAR Tei, char pf, L2UCHAR *mes, L2INT size);
+
+/*
+ * TEI management
+ */
+static int Q921TeiSendAssignRequest(L2TRUNK trunk);
+static int Q921TeiProcAssignResponse(L2TRUNK trunk, L2UCHAR *mes, L2INT size);
+static int Q921TeiSendVerifyRequest(L2TRUNK trunk);
+static int Q921TeiProcCheckRequest(L2TRUNK trunk, L2UCHAR *mes, L2INT size);
+static int Q921TeiProcRemoveRequest(L2TRUNK trunk, L2UCHAR *mes, L2INT size);
+static int Q921TeiProcAssignRequest(L2TRUNK trunk, L2UCHAR *mes, L2INT size);
+static int Q921TeiProcCheckResponse(L2TRUNK trunk, L2UCHAR *mes, L2INT size);
+static int Q921TeiProcVerifyRequest(L2TRUNK trunk, L2UCHAR *mes, L2INT size);
+static int Q921TeiSendRemoveRequest(L2TRUNK trunk, L2UCHAR tei);
+static int Q921TeiSendDenyResponse(L2TRUNK trunk, L2UCHAR tei, L2USHORT ri);
+static int Q921TeiSendAssignedResponse(L2TRUNK trunk, L2UCHAR tei, L2USHORT ri);
+static int Q921TeiSendCheckRequest(L2TRUNK trunk, L2UCHAR tei);
+
+/*
+ * Logging
+ */
+static int Q921Log(L2TRUNK trunk, Q921LogLevel_t level, const char *fmt, ...);
+static int Q921LogMesg(L2TRUNK trunk, Q921LogLevel_t level, L2UCHAR received, L2UCHAR *mes, L2INT size, const char *fmt, ...);
+
+/*
+ * State handling
+ */
+static int Q921ChangeState(L2TRUNK trunk, Q921State_t state, L2UCHAR tei);
+
+#endif

Added: freeswitch/trunk/libs/freetdm/src/isdn/include/Q931.h (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/isdn/include/Q931.h	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/isdn/include/Q931.h	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,1175 @@
+/******************************************************************************
+
+  FileName:         Q931.h
+
+  Contents:         Header and definition for the ITU-T Q.931 stack. The 
+                    header contents the following parts:
+
+                    - Definition of codes
+                    - Definition of information elements (Q931ie_).
+                    - Definition of messages (Q931mes_).
+                    - Definitian of variables (var_).
+                    - Function prototypes.
+
+  Description:		The Q.931 stack provided here covers ITU-T Q.931 w/Q.932
+                    supplementary services for both PRI, BRI and variants. 
+                    The stack is generic and designed to deal with variants as
+                    needed.
+
+                    The stack uses the following interface functions:
+
+                    - Q931Initialize	Initialize the Q.931 stack.
+                    - Q931Rx23			Receive a message from layer 2
+                    - Q931Tx32			Send a message to layer 2
+                    - Q931Rx43			Receive a message from layer 4 or above.
+                    - Q931Tx34			Send a message to layer 4 or above.
+                    - Q931TimeTick		Periodical timer processing.
+                    - Q931ErrorProc		Callback for stack error message.
+
+                    The protocol is a module with no external dependencies and
+                    can easely be ported to any operating system like Windows,
+                    Linux, rtos and others.
+
+  Related Files:	Q931.h				Q.931 Definitions
+                    Q931.c				Q.931 Interface Functions.
+                    Q931api.c			Low level L4 API functions.
+
+                    Q932.h				Q.932 Suplementary Services
+                    Q932mes.c			Q.932 encoders/coders
+
+                    Q931mes.c			Q.931 Message encoders/coders
+                    Q931ie.c			Q.931 IE encoders/coders
+                    Q931StateTE.c		Generic Q.931 TE State Engine
+                    Q931StateNT.c		Generic Q.931 NT State Engine
+
+  Design Note 1:	For each variant please add separate files starting with 
+                    the	variant short-name as follows:
+
+                    <variant>.h			Spesific headers needed.
+                    <variant>mes.c		Message encoders/decores.
+                    <variant>ie.c		IE encoders/decoders.
+                    <variant>StateTE.c	TE side state engine.
+                    <variant>StateNT.c	NT side state engine.
+
+  Design Note 2:	The stack is deliberatly made non-threading. Use 1 
+                    thread per Trunk, but lock access from the timertick
+                    and rx, tx functions. And make sure the callbacks only
+                    dump messages to a queue, no time-consuming processing
+                    inside stack processing. 
+
+                    All stack processing is async 'fire and forget', meaning
+                    that there are not, and should not be any time-consuming
+                    processing within the stack-time. The best way to thread 
+                    a stack is to use one single thread that signal 5 queues.
+                    
+                    - Incoming L2 queue.
+                    - Incoming L4 queue.
+                    - Outgoing L2 queue.
+                    - Outgoing L4 queue.
+                    - Error/Trace queue.
+
+  Design Note 3:	DSP optimization. The L3 (Rx23) can be called directly
+                    from a HDLC receiver without usage of queues for optimized 
+                    processing. But keep in mind that Q.931 calls Tx34 or Tx32 
+                    as part	of receiving a message from Layer 2.
+
+  License/Copyright:
+
+  Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+  email:janvb@caselaboratories.com  
+
+  Redistribution and use in source and binary forms, with or without 
+  modification, are permitted provided that the following conditions are 
+  met:
+
+    * Redistributions of source code must retain the above copyright notice, 
+	  this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright notice, 
+	  this list of conditions and the following disclaimer in the documentation 
+	  and/or other materials provided with the distribution.
+    * Neither the name of the Case Labs, Ltd nor the names of its contributors 
+	  may be used to endorse or promote products derived from this software 
+	  without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
+  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
+  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+  POSSIBILITY OF SUCH DAMAGE.
+******************************************************************************/
+
+#ifndef _Q931_NL
+#define _Q931_NL
+
+/* uncomment the #define below to add x.25 support to the Q.931				*/
+/* #define Q931_X25_SUPPORT */
+
+#include "stdio.h"
+
+#ifdef _MSC_VER
+#pragma warning(disable:4100)
+#ifndef strcasecmp
+#define strcasecmp(s1, s2) _stricmp(s1, s2)
+#endif
+#endif
+#include <string.h>
+
+
+/*****************************************************************************
+
+  Enum helper macros  <Need description of these macros>
+
+*****************************************************************************/
+#define Q931_ENUM_NAMES(_NAME, _STRINGS) static const char * _NAME [] = { _STRINGS , NULL };
+#define Q931_STR2ENUM_P(_FUNC1, _FUNC2, _TYPE) _TYPE _FUNC1 (const char *name); const char * _FUNC2 (_TYPE type);
+#define Q931_STR2ENUM(_FUNC1, _FUNC2, _TYPE, _STRINGS, _MAX)	\
+	_TYPE _FUNC1 (const char *name)								\
+	{														\
+		int i;												\
+		_TYPE t = _MAX ;									\
+															\
+		for (i = 0; i < _MAX ; i++) {						\
+			if (!strcasecmp(name, _STRINGS[i])) {			\
+				t = (_TYPE) i;								\
+				break;										\
+			}												\
+		}													\
+															\
+		return t;											\
+	}														\
+	const char * _FUNC2 (_TYPE type)						\
+	{														\
+		if (type > _MAX) {									\
+			type = _MAX;									\
+		}													\
+		return _STRINGS[(int)type];							\
+	}														\
+
+/*****************************************************************************
+
+  Error Codes
+
+*****************************************************************************/
+typedef enum {
+	Q931E_NO_ERROR				=	0,
+
+	Q931E_UNKNOWN_MESSAGE		=	-3001,
+	Q931E_ILLEGAL_IE			=	-3002,
+	Q931E_UNKNOWN_IE			=	-3003,
+	Q931E_BEARERCAP				=	-3004,
+	Q931E_HLCOMP				=	-3005,
+	Q931E_LLCOMP				=	-3006,
+	Q931E_INTERNAL              =	-3007,
+	Q931E_MISSING_CB            =	-3008,
+	Q931E_UNEXPECTED_MESSAGE    =	-3009,
+	Q931E_ILLEGAL_MESSAGE		=	-3010,
+	Q931E_TOMANYCALLS           =	-3011,
+	Q931E_INVALID_CRV           =	-3012,
+	Q931E_CALLID                =	-3013,
+	Q931E_CALLSTATE             =	-3014,
+	Q931E_CALLEDSUB             =	-3015,
+	Q931E_CALLEDNUM             =	-3016,
+	Q931E_CALLINGNUM            =	-3017,
+	Q931E_CALLINGSUB            =	-3018,
+	Q931E_CAUSE                 =	-3019,
+	Q931E_CHANID                =	-3020,
+	Q931E_DATETIME              =	-3021,
+	Q931E_DISPLAY               =	-3022,
+	Q931E_KEYPADFAC             =	-3023,
+	Q931E_NETFAC                =	-3024,
+	Q931E_NOTIFIND              =	-3025,
+	Q931E_PROGIND               =	-3026,
+	Q931E_RESTARTIND            =	-3027,
+	Q931E_SEGMENT               =	-3028,
+	Q931E_SIGNAL                =	-3029,
+	Q931E_GENERIC_DIGITS		=	-3030
+} q931_error_t;
+
+/* The q931_error_t enum should be kept in sync with the q931_error_names array in Q931.c */ 
+
+const char *q931_error_to_name(q931_error_t error);
+
+/*****************************************************************************
+
+	Some speed optimization can be achieved by changing all variables to the 
+	word size of your processor. A 32 bit processor has to do a lot of extra 
+	work to read a packed 8 bit integer. Changing all fields to 32 bit integer 
+	will result in usage of some extra space, but will speed up the stack.
+
+	The stack has been designed to allow L3UCHAR etc. to be any size of 8 bit
+	or larger.
+
+*****************************************************************************/
+
+#define L3UCHAR		unsigned char		/* Min 8 bit						*/
+#define L3USHORT	unsigned short		/* Min 16 bit unsigned				*/
+#define L3UINT		unsigned int		/* Min 16 bit unsigned	            */
+#define L3INT       int                 /* Min 16 bit signed                */
+#define L3ULONG		unsigned long		/* Min 32 bit						*/
+#define L3BOOL      char				/* Min 1 bit, valuse 0 & 1 only		*/
+
+#define L3TRUE      1
+#define L3FALSE     0 
+
+/*****************************************************************************
+
+  Global defines.
+
+*****************************************************************************/
+
+typedef L3USHORT ie;                /* Special data type to hold a dynamic  */
+                                    /* or optional information element as   */
+                                    /* part of a message struct. MSB = 1    */
+                                    /* indicate that the ie is present, the */
+                                    /* last 15 bits is an offset ( or the   */
+                                    /* value for single octet ) to the      */
+                                    /* struct holding the ie. Offset = 0    */
+                                    /* is buf[1] etc.                       */
+                                    /* ie == 0xffff indicates error         */
+
+/*****************************************************************************
+	
+	MAXTRUNKS sets how many physical trunks this system might have. This 
+	number should be keept at a minimum since it will use global space.
+
+	It is recommended that you leave MAXCHPERTRUNK as is
+
+*****************************************************************************/
+
+#define	Q931_LOGBUFSIZE	1024		/* size of logging buffer		*/
+
+#define Q931L4BUF	1000		/* size of message buffer		*/
+
+#define Q931L2BUF	300		/* size of message buffer		*/
+
+#define Q931MAXTRUNKS	4		/* Total number of trunks that will be	*/
+					/* processed by this instance of the	*/
+					/* stack				*/
+
+#define Q931MAXCHPERTRUNK	32	/* Number of channels per trunk. The	*/
+					/* stack uses a static set of 32	*/
+					/* channels regardless if it is E1, T1	*/
+					/* or BRI that actually is used.	*/
+
+#define Q931MAXCALLPERTRUNK	(Q931MAXCHPERTRUNK * 2)
+					/* Number of max active CRV per trunk.  */
+					/* Q.931 can have more calls than there */
+					/* are channels.			*/
+
+
+#define Q931_IS_BRI(x)		((x)->TrunkType == Q931_TrType_BRI || (x)->TrunkType == Q931_TrType_BRI_PTMP)
+#define Q931_IS_PRI(x)		(!Q931_IS_BRI(x))
+
+#define Q931_IS_PTP(x)		((x)->TrunkType != Q931_TrType_BRI_PTMP)
+#define Q931_IS_PTMP(X)		((x)->TrunkType == Q931_TrType_BRI_PTMP)
+
+#define Q931_BRI_MAX_CRV	127
+#define Q931_PRI_MAX_CRV	32767
+
+/*****************************************************************************
+
+  The following defines control the dialect switch tables and should only be
+  changed when a new dialect needs to be inserted into the stack.   
+
+  This stack uses an array of functions to know which function to call as   
+  it receives a SETUP message etc. A new dialect can when choose to use
+  the proc etc. for standard Q.931 or insert a modified proc.
+
+  This technique has also been used to distinguish between user and network
+  mode to make the code as easy to read and maintainable as possible.
+
+  A message and IE index have been used to save space. These indexes allowes
+  the message or IE code to be used directly and will give back a new index
+  into the table.
+
+*****************************************************************************/
+
+/* WARNING! Initialize Q931CreateDialectCB[] will NULL when increasing the */
+/* Q931MAXDLCT value to avoid Q931Initialize from crashing if one entry is */
+/* not used.								   */
+#define Q931MAXDLCT	8	/* Max dialects included in this        */
+				/* compile. User and Network count as   */
+				/* one dialect each.                    */
+
+#define Q931MAXMES	128		/* Number of messages				*/
+#define Q931MAXIE	255		/* Number of IE					*/
+#define Q931MAXUSEDIE	50		/* Maximum number of ie types per Dialect	*/
+#define Q931MAXCODESETS	7		/* Maximum number of codests (by spec, 0-7)	*/
+#define Q931MAXSTATE	100		/* Size of state tables			        */
+#define Q931MAXTIMER	25		/* Maximum number of timers 			*/
+
+/*****************************************************************************
+
+  Call States for ITU-T Q.931 TE (User Mode)
+
+*****************************************************************************/
+
+#define Q931_U0     0
+#define Q931_U1     1
+#define Q931_U2     2
+#define Q931_U3     3
+#define Q931_U4     4
+#define Q931_U6     6
+#define Q931_U7     7
+#define Q931_U8     8
+#define Q931_U9     9
+#define Q931_U10    10
+#define Q931_U11    11
+#define Q931_U12    12
+#define Q931_U15    15
+#define Q931_U17    17
+#define Q931_U19    19
+#define Q931_U25    25
+
+/*****************************************************************************
+
+  Call States for ITU-T Q.931 NT (Network Mode)
+
+*****************************************************************************/
+#define Q931_N0     (0x0100 | 0)
+#define Q931_N1     (0x0100 | 1)
+#define Q931_N2     (0x0100 | 2)
+#define Q931_N3     (0x0100 | 3)
+#define Q931_N4     (0x0100 | 4)
+#define Q931_N6     (0x0100 | 6)
+#define Q931_N7     (0x0100 | 7)
+#define Q931_N8     (0x0100 | 8)
+#define Q931_N9     (0x0100 | 9)
+#define Q931_N10    (0x0100 | 11)
+#define Q931_N11    (0x0100 | 11)
+#define Q931_N12    (0x0100 | 12)
+#define Q931_N15    (0x0100 | 15)
+#define Q931_N17    (0x0100 | 17)
+#define Q931_N19    (0x0100 | 19)
+#define Q931_N22    (0x0100 | 22)
+#define Q931_N25    (0x0100 | 25)
+
+/*****************************************************************************
+
+  Q.931 Message codes
+  
+*****************************************************************************/
+
+#define Q931mes_ALERTING             0x01 /* 0000 0001                   */        
+#define Q931mes_CALL_PROCEEDING      0x02 /* 0000 0010                   */
+#define Q931mes_CONNECT              0x07 /* 0000 0111                   */
+#define Q931mes_CONNECT_ACKNOWLEDGE  0x0f /* 0000 1111                   */
+#define Q931mes_PROGRESS             0x03 /* 0000 0011                   */
+#define Q931mes_SETUP                0x05 /* 0000 0101                   */
+#define Q931mes_SETUP_ACKNOWLEDGE    0x0d /* 0000 1101                   */
+#define Q931mes_RESUME               0x26 /* 0010 0110                   */
+#define Q931mes_RESUME_ACKNOWLEDGE   0x2e /* 0010 1110                   */
+#define Q931mes_RESUME_REJECT        0x22 /* 0010 0010                   */
+#define Q931mes_SUSPEND              0x25 /* 0010 0101                   */
+#define Q931mes_SUSPEND_ACKNOWLEDGE  0x2d /* 0010 1101                   */
+#define Q931mes_SUSPEND_REJECT       0x21 /* 0010 0001                   */
+#define Q931mes_USER_INFORMATION     0x20 /* 0010 0000                   */
+#define Q931mes_DISCONNECT           0x45 /* 0100 0101                   */
+#define Q931mes_RELEASE              0x4d /* 0100 1101                   */
+#define Q931mes_RELEASE_COMPLETE     0x5a /* 0101 1010                   */
+#define Q931mes_RESTART              0x46 /* 0100 0110                   */
+#define Q931mes_RESTART_ACKNOWLEDGE  0x4e /* 0100 1110                   */
+#define Q931mes_CONGESTION_CONTROL   0x79 /* 0111 1001                   */
+#define Q931mes_INFORMATION          0x7b /* 0111 1011                   */
+#define Q931mes_NOTIFY               0x6e /* 0110 1110                   */
+#define Q931mes_STATUS               0x7d /* 0111 1101                   */
+#define Q931mes_STATUS_ENQUIRY       0x75 /* 0111 0101                   */
+#define Q931mes_SEGMENT              0x60 /* 0110 0000                   */
+
+#define Q931mes_SERVICE              0x0f /* 0000 1111                   */
+#define Q931mes_SERVICE_ACKNOWLEDGE  0x07 /* 0000 0111                   */
+
+
+/**
+ * Generic Q.931 Timers
+ */
+enum {
+	Q931_TIMER_T300	= 1,		/* */
+	Q931_TIMER_T301,
+	Q931_TIMER_T302,
+	Q931_TIMER_T303,
+	Q931_TIMER_T304,
+	Q931_TIMER_T305,
+	Q931_TIMER_T306,
+	Q931_TIMER_T307,
+	Q931_TIMER_T308,
+	Q931_TIMER_T309,
+	Q931_TIMER_T310,
+	Q931_TIMER_T311,
+	Q931_TIMER_T312,
+	Q931_TIMER_T313,
+	Q931_TIMER_T314,
+	Q931_TIMER_T315,
+	Q931_TIMER_T316,
+	Q931_TIMER_T317,
+	Q931_TIMER_T318,
+	Q931_TIMER_T319,
+	Q931_TIMER_T320,
+	Q931_TIMER_T321,
+	Q931_TIMER_T322,
+};
+
+/**
+ * Q.931 ToN
+ */
+enum {
+	Q931_TON_UNKNOWN		= 0x00,
+	Q931_TON_INTERNATIONAL		= 0x01,
+	Q931_TON_NATIONAL		= 0x02,
+	Q931_TON_NETWORK_SPECIFIC	= 0x03,
+	Q931_TON_SUBSCRIBER_NUMBER	= 0x04,
+	Q931_TON_ABBREVIATED_NUMBER	= 0x06,
+	Q931_TON_RESERVED		= 0x07
+};
+
+/**
+ * Q.931 Numbering Plan
+ */
+enum {
+	Q931_NUMPLAN_UNKNOWN		= 0x00,
+	Q931_NUMPLAN_E164		= 0x01,
+	Q931_NUMPLAN_X121		= 0x03,
+	Q931_NUMPLAN_F69		= 0x04,
+	Q931_NUMPLAN_NATIONAL		= 0x08,
+	Q931_NUMPLAN_PRIVATE		= 0x09,
+	Q931_NUMPLAN_RESERVED		= 0x0e
+};
+
+/**
+ * Q.931 Presentation Indicator
+ */
+enum {
+	Q931_PRES_ALLOWED		= 0x00,
+	Q931_PRES_RESTRICTED		= 0x01,
+	Q931_PRES_NOT_AVAILABLE		= 0x02,
+	Q931_PRES_RESERVED		= 0x03
+};
+
+/**
+ * Q.931 Screening Indicator
+ */
+enum {
+	Q931_SCREEN_USER_NOT_SCREENED		= 0x00,
+	Q931_SCREEN_USER_VERIFIED_PASSED	= 0x01,
+	Q931_SCREEN_USER_VERIFIED_FAILED	= 0x02,
+	Q931_SCREEN_NETWORK			= 0x03
+};
+
+/**
+ * Q.931 Coding Standard
+ */
+enum {
+	Q931_CODING_ITU		= 0x00,
+	Q931_CODING_ISO		= 0x01,
+	Q931_CODING_NATIONAL	= 0x02,
+	Q931_CODING_NETWORK	= 0x03
+};
+
+/**
+ * Q.931 High layer characteristik id
+ */
+enum {
+	Q931_HLCHAR_TELEPHONY	= 0x01,
+	Q931_HLCHAR_FAX_G23	= 0x04,
+	Q931_HLCHAR_FAX_G4	= 0x21,
+	Q931_HLCHAR_FAX_G4II	= 0x24,
+	Q931_HLCHAR_T102	= 0x32,
+	Q931_HLCHAR_T101	= 0x33,
+	Q931_HLCHAR_F60		= 0x35,
+	Q931_HLCHAR_X400	= 0x38,
+	Q931_HLCHAR_X200	= 0x41
+};
+
+/**
+ * Q.931 User information layer 1 protocol
+ */
+enum {
+	Q931_UIL1P_V110		= 0x01,
+	Q931_UIL1P_I460		= 0x01,
+	Q931_UIL1P_X30		= 0x01,
+
+	Q931_UIL1P_G711U	= 0x02,
+	Q931_UIL1P_G711A	= 0x03,
+	Q931_UIL1P_G721		= 0x04,
+
+	Q931_UIL1P_H221		= 0x05,
+	Q931_UIL1P_H242		= 0x05,
+
+	Q931_UIL1P_H223		= 0x06,
+	Q931_UIL1P_H245		= 0x06,
+
+	Q931_UIL1P_RATE_ADAP	= 0x07,
+
+	Q931_UIL1P_V120		= 0x08,
+	Q931_UIL1P_X31		= 0x09
+};
+
+/**
+ * Q.931 Information Transfer Capability
+ */
+enum {
+	Q931_ITC_SPEECH			= 0x00,
+	Q931_ITC_UNRESTRICTED		= 0x08,
+	Q931_ITC_RESTRICTED		= 0x09,
+	Q931_ITC_3K1_AUDIO		= 0x10,
+	Q931_ITC_UNRESTRICTED_TONES	= 0x11,
+	Q931_ITC_VIDEO			= 0x18
+};
+
+/**
+ * Q.931 Information transfer rate
+ */
+enum {
+	Q931_ITR_PACKET	= 0x00,
+	Q931_ITR_64K	= 0x10,
+	Q931_ITR_128K	= 0x11,
+	Q931_ITR_384K	= 0x13,
+	Q931_ITR_1536K	= 0x15,
+	Q931_ITR_1920K	= 0x17,
+	Q931_ITR_MULTI	= 0x18
+};
+
+/*****************************************************************************
+
+  Struct:       Q931mes_Header
+
+  Description:  Used to read the header & message code.
+
+*****************************************************************************/
+typedef struct {
+	L3UINT	Size;           /* Size of message in bytes             */
+	L3UCHAR	ProtDisc;       /* Protocol Discriminator               */
+	L3UCHAR	MesType;        /* Message type                         */
+	L3UCHAR	CRVFlag;        /* Call reference value flag            */
+	L3INT	CRV;            /* Call reference value                 */
+
+} Q931mes_Header;
+
+/*****************************************************************************
+
+  Struct:       Q931mes_Generic
+
+  Description:  Generic header containing all IE's. This is not used, but is
+				provided in case a proprietary variant needs it.
+
+*****************************************************************************/
+typedef struct {
+	L3UINT		Size;           /* Size of message in bytes             */
+	L3UCHAR		ProtDisc;       /* Protocol Discriminator               */
+	L3UCHAR		MesType;        /* Message type                         */
+	L3UCHAR		CRVFlag;        /* Call reference value flag            */
+	L3INT		CRV;            /* Call reference value                 */
+
+	/* WARNING: don't touch anything above this line (TODO: use Q931mes_Header directly to make sure it's the same) */
+
+	L3UCHAR		Tei;            /* TEI                                  */
+
+	ie		Shift;
+	ie		MoreData;
+	ie		SendComplete;
+	ie		CongestionLevel;
+	ie		RepeatInd;
+
+	ie		Segment;        /* Segmented message                    */
+	ie		BearerCap;      /* Bearer Capability                    */
+	ie		Cause;          /* Cause                                */
+	ie		CallState;      /* Call State                           */
+	ie		CallID;			/* Call Identity                        */
+	ie		ChanID;         /* Channel Identification               */
+	ie		ChangeStatus;   /* Change Staus                         */
+	ie		ProgInd;        /* Progress Indicator                   */
+	ie		NetFac;         /* Network Spesific Facilities          */
+	ie		NotifInd;       /* Notification Indicator               */
+	ie		Display;        /* Display                              */
+	ie		DateTime;       /* Date/Time                            */
+	ie		KeypadFac;      /* Keypad Facility                      */
+	ie		Signal;         /* Signal                               */
+	ie		InfoRate;       /* Information rate                     */
+	ie		EndEndTxDelay;  /* End to End Transmit Delay            */
+	ie		TransDelSelInd; /* Transmit Delay Sel. and Ind.         */
+	ie		PackParam;      /* Packed Layer Binary parameters       */
+	ie		PackWinSize;    /* Packet Layer Window Size             */
+	ie		PackSize;       /* Packed Size                          */
+	ie		ClosedUserGrp;  /* Closed User Group                    */
+	ie		RevChargeInd;   /* Reverse Charging Indicator           */
+	ie		CalledNum;      /* Called Party Number                  */
+	ie		CalledSub;      /* Called Party subaddress              */
+	ie		CallingNum;     /* Calling Party Number                 */
+	ie		CallingSub;     /* Calling Party Subaddress             */
+	ie		RedirNum;       /* Redirection Number                   */
+	ie		TransNetSel;    /* Transmit Network Selection           */
+	ie		LLRepeatInd;    /* Repeat Indicator 2 LLComp            */
+	ie		RestartWin;     /* Restart Window                       */
+	ie		RestartInd;     /* Restart Indicator                    */
+	ie		LLComp;         /* Low Layer Compatibility              */
+	ie		HLComp;         /* High Layer Compatibility             */
+	ie		UserUser;       /* User-user                            */
+	ie		Escape;         /* Escape for extension                 */
+	ie		Switchhook;
+	ie		FeatAct;
+	ie		FeatInd;
+	ie		GenericDigits;
+
+	L3UCHAR		buf[1];			/* Buffer for IE's						*/
+
+} Q931mes_Generic;
+
+
+/*****************************************************************************
+
+  Struct:       Q931_TrunkInfo
+
+  Description:  TrunkInfo is the struct entry used to store Q.931 related 
+                information and state for E1/T1/J1 trunks and associated 
+                channels in the system. 
+
+				The user should store this information outside this stack
+				and needs to feed the interface functions with a pointer to
+				the TrunkInfo entry.
+
+*****************************************************************************/
+typedef struct Q931_TrunkInfo Q931_TrunkInfo_t;
+
+typedef enum {
+    Q931_LOG_NONE = -1,
+    Q931_LOG_EMERG,
+    Q931_LOG_ALERT,
+    Q931_LOG_CRIT,
+    Q931_LOG_ERROR,
+    Q931_LOG_WARNING,
+    Q931_LOG_NOTICE,
+    Q931_LOG_INFO,
+    Q931_LOG_DEBUG
+} Q931LogLevel_t;
+
+typedef L3INT (*Q931Tx34CB_t) (void *,L3UCHAR *, L3INT);
+typedef L3INT (*Q931Tx32CB_t) (void *, L3INT, L3UCHAR, L3UCHAR *, L3INT);
+typedef L3INT (*Q931ErrorCB_t) (void *,L3INT,L3INT,L3INT);
+typedef L3INT (*Q931LogCB_t) (void *, Q931LogLevel_t, char *, L3INT);
+
+typedef enum {					/* Network/User Mode.			*/
+	Q931_TE=0,				/*  0 : User Mode			*/
+	Q931_NT=1				/*  1 : Network Mode			*/
+} Q931NetUser_t;
+
+typedef enum {					/* Dialect enum                         */
+	Q931_Dialect_Q931     = 0,
+	Q931_Dialect_National = 2,
+	Q931_Dialect_DMS      = 4,
+	Q931_Dialect_5ESS     = 6,		/* Coming soon to a PRI stack near you! */
+
+	Q931_Dialect_Count
+} Q931Dialect_t;
+#define DIALECT_STRINGS "q931", "", "national", "", "dms", "", "5ess", ""
+Q931_STR2ENUM_P(q931_str2Q931Dialect_type, q931_Q931Dialect_type2str, Q931Dialect_t)
+
+typedef enum {					/* Trunk Line Type.			*/
+	Q931_TrType_E1 = 0,			/*  0 : E1 Trunk			*/
+	Q931_TrType_T1 = 1,			/*  1 : T1 Trunk			*/
+	Q931_TrType_J1 = 2,			/*  2 : J1 Trunk			*/
+	Q931_TrType_BRI	= 3,			/*  3 : BRI Trunk			*/
+	Q931_TrType_BRI_PTMP = 4		/*  4 : BRI PTMP Trunk			*/
+} Q931_TrunkType_t;
+
+typedef enum {					/* Trunk State			*/
+	Q931_TrState_NoAlignment=0,		/* Trunk not aligned		*/
+	Q931_TrState_Aligning=1,		/* Aligning in progress		*/
+	Q931_TrState_Aligned=2			/* Trunk Aligned		*/
+} Q931_TrunkState_t;
+
+typedef enum {
+	Q931_ChType_NotUsed=0,			/* Unused Channel						*/
+	Q931_ChType_B=1,			/* B Channel (Voice)					*/
+	Q931_ChType_D=2,			/* D Channel (Signalling)				*/
+	Q931_ChType_Sync=3			/* Sync Channel							*/
+} Q931_ChanType_t;
+
+struct Q931_Call
+{
+	L3UCHAR InUse;			/* Indicate if entry is in use.         */
+					/*  0 = Not in Use                      */
+					/*  1 = Active Call.                    */
+
+	L3UCHAR Tei;			/* Associated TEI 			*/
+
+	L3UCHAR BChan;			/* Associated B Channel.                */
+					/* 0 - 31 valid B chan			*/
+					/* 255 = Not allocated			*/
+
+	L3INT   CRV;			/* Associated CRV.                      */
+
+	L3UINT  State;			/* Call State.                          */
+					/*  0 is Idle, but other values are	*/
+					/*  defined per dialect.		*/
+					/*  Default usage is 1-99 for TE and    */
+					/*  101 - 199 for NT.			*/
+        
+	L3ULONG Timer;			/* Timer in ms. The TimeTick will check		*/
+					/* if this has exceeded the timeout, and	*/
+					/* if so call the timers timeout proc.		*/
+
+	L3USHORT TimerID;		/* Timer Identification/State           */
+					/* actual values defined by dialect	*/
+					/*  0 : No timer running                */
+					/*  ITU-T Q.931:301 - 322 Timer running */
+};
+
+struct Q931_TrunkInfo
+{
+	Q931NetUser_t    NetUser;		/* Network/User Mode.                   */
+	Q931_TrunkType_t TrunkType;		/* Trunk Line Type.                     */
+	Q931Dialect_t    Dialect;		/* Q.931 Based dialect index.           */
+
+	Q931Tx34CB_t     Q931Tx34CBProc;
+	Q931Tx32CB_t     Q931Tx32CBProc;
+	Q931ErrorCB_t    Q931ErrorCBProc;
+	Q931LogCB_t      Q931LogCBProc;
+	void *PrivateData32;
+	void *PrivateData34;
+	void *PrivateDataLog;
+
+	Q931LogLevel_t   loglevel;
+
+	L3UCHAR     Enabled;            /* Enabled/Disabled                     */
+                                    /*  0 = Disabled                        */
+                                    /*  1 = Enabled                         */
+
+	Q931_TrunkState_t TrunkState;
+
+    L3INT       LastCRV;            /* Last used crv for the trunk.         */
+
+    L3UCHAR L3Buf[Q931L4BUF];		/* message buffer for messages to be    */
+                                    /* send from Q.931 L4.                  */
+
+    L3UCHAR L2Buf[Q931L2BUF];		/* buffer for messages send to L2.      */
+
+	/* The auto flags below switch on/off automatic Ack messages. SETUP ACK */
+	/* as an example can be sent by the stack in response to SETUP to buy   */
+	/* time in processing on L4. Setting this to true will cause the stack  */
+	/* to automatically send this.											*/
+
+	L3BOOL	autoSetupAck;			/* Indicate if the stack should send    */
+									/* SETUP ACK or not. 0=No, 1 = Yes.		*/
+
+	L3BOOL  autoConnectAck;			/* Indicate if the stack should send    */
+									/* CONNECT ACT or not. 0=No, 1=Yes.		*/
+
+	L3BOOL  autoRestartAck;			/* Indicate if the stack should send    */
+									/* RESTART ACK or not. 0=No, 1=Yes.		*/
+
+	L3BOOL  autoServiceAck;			/* Indicate if the stack should send    */
+									/* SERVICE ACK or not. 0=No, 1=Yes.		*/
+
+	/* channel array holding info per channel. Usually defined to 32		*/
+	/* channels to fit an E1 since T1/J1 and BRI will fit inside a E1.		*/
+    struct _charray
+    {
+		Q931_ChanType_t ChanType;	/* Unused, B, D, Sync */
+
+        L3UCHAR Available;          /* Channel Available Flag               */
+                                    /*  0 : Avaiabled                       */
+                                    /*  1 : Used                            */
+
+        L3INT   CRV;                /* Associated CRV                       */
+
+    } ch[Q931MAXCHPERTRUNK];
+
+	/* Active Call information indentified by CRV. See Q931AllocateCRV for  */
+	/* initialization of call table.					*/
+	struct Q931_Call	call[Q931MAXCALLPERTRUNK];
+};
+
+/*****************************************************************************
+  
+  Struct:		Q931State
+
+  Description:	Define a Q931 State, legal events and next state for each
+				event. Used to simplify the state engine logic. Each state
+				engine defines its own state table and the logic need only
+				call a helper function to check if the message is legal
+				at this stage.
+
+*****************************************************************************/
+typedef struct
+{
+	L3INT		State;
+	L3INT		Message;
+	L3UCHAR		Direction;
+} Q931State;
+
+/*****************************************************************************
+
+  Proc table external references. 
+
+  The proc tables are defined in Q931.c and initialized in Q931Initialize.
+
+*****************************************************************************/
+typedef L3INT (q931proc_func_t) (Q931_TrunkInfo_t *pTrunk, L3UCHAR *, L3INT);
+
+typedef L3INT (q931umes_func_t) (Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT IOff, L3INT Size);
+typedef L3INT (q931pmes_func_t) (Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+
+typedef L3INT (q931uie_func_t) (Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff);
+typedef L3INT (q931pie_func_t) (Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet);
+
+typedef L3INT (q931timeout_func_t) (Q931_TrunkInfo_t *pTrunk, L3INT callIndex);
+typedef L3ULONG q931timer_t;
+
+extern q931proc_func_t *Q931Proc[Q931MAXDLCT][Q931MAXMES];
+
+extern q931umes_func_t *Q931Umes[Q931MAXDLCT][Q931MAXMES];
+extern q931pmes_func_t *Q931Pmes[Q931MAXDLCT][Q931MAXMES];
+
+extern q931uie_func_t *Q931Uie[Q931MAXDLCT][Q931MAXIE];
+extern q931pie_func_t *Q931Pie[Q931MAXDLCT][Q931MAXIE];
+
+extern q931timeout_func_t *Q931Timeout[Q931MAXDLCT][Q931MAXTIMER];
+extern q931timer_t         Q931Timer[Q931MAXDLCT][Q931MAXTIMER];
+
+
+/*****************************************************************************
+    
+  Macro:        GetIETotoSize
+
+  Syntax:       L3INT GetIETotSize(InfoElem ie);
+
+  Description:  Compute the total size in bytes of an info element including 
+                size of 'header'.    
+
+*****************************************************************************/
+#define Q931GetIETotSize(ie) (((ie.InfoID & 0x80) != 0) ? 1 : ie.LenIE) + 2)
+
+/*****************************************************************************
+
+  Macro:        IsIEPresent
+
+  Syntax:       BOOL IsIEPresent(ie InfoElement);
+
+  Description:  Return TRUE if the Information Element is included.
+
+*****************************************************************************/
+#define Q931IsIEPresent(x) ((x & 0x8000) != 0)
+
+/*****************************************************************************
+
+  Macro:        GetIEOffset and GetIEValue
+    
+  Syntax:       L3INT GetIEOffset(ie InfoElement)
+                L3INT GetIEValue(ie InfoElement)
+
+  Description:  Returns the offset (or the value )to the Information Element.
+
+  Note:         GetIEValue assumes that the 15 lsb bit is the value of a 
+                single octet information element. This macro can not be used
+                on a variable information element.
+
+*****************************************************************************/
+#define Q931GetIEOffset(x) (x & 0x7fff)
+#define Q931GetIEValue(x)  (x & 0x7fff)
+
+/*****************************************************************************
+
+  Macro:        Q931GetIEPtr
+
+  Syntax:       void * Q931GetIEPtr(ie InfoElement, L3UCHAR * Buf);
+
+  Description:  Compute a Ptr to the information element.
+
+*****************************************************************************/
+#define Q931GetIEPtr(ie,buf) ((void *)&buf[Q931GetIEOffset(ie)])
+
+/*****************************************************************************
+
+  Macro:        SetIE
+
+  Syntax:       void SetIE(ie InfoElement, L3INT Offset);
+
+  Description:  Set an information element.
+
+*****************************************************************************/
+#define Q931SetIE(x,o) { x = (ie)(o) | 0x8000; }
+
+/*****************************************************************************
+
+  Macro:        IsQ931Ext
+
+  Syntax        BOOL IsQ931Ext(L3UCHAR c)
+
+  Description:  Return true Check if the msb (bit 8) is 0. This indicate
+                that the octet is extended.
+
+*****************************************************************************/
+#define IsQ931Ext(x) ((x & 0x80) == 0)
+
+/*****************************************************************************
+
+  Macro:        ieGetOctet
+
+  Syntax:       unsigned L3UCHAR ieGetOctet(L3INT e)
+
+  Description:  Macro to fetch one byte from an integer. Mostly used to 
+                avoid warnings.
+
+*****************************************************************************/
+#define ieGetOctet(x) ((L3UCHAR)(x))
+
+/*****************************************************************************
+
+  Macro:        NoWarning
+
+  Syntax:       void NoWarning(x)
+
+  Description:  Macro to suppress unreferenced formal parameter warnings
+
+                Used during creation of the stack since the stack is 
+                developed for Warning Level 4 and this creates a lot of 
+                warning for the initial empty functions.
+
+*****************************************************************************/
+#define NoWarning(x) (x = x)
+
+/*****************************************************************************
+
+  External references. See Q931.c for details.
+
+*****************************************************************************/
+
+#include "Q931ie.h"
+
+#include "Q932.h"
+
+/*****************************************************************************
+
+  Q.931 Message Pack/Unpack functions. Implemented in Q931mes.c
+
+*****************************************************************************/
+L3INT Q931Pmes_Alerting(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q931Pmes_CallProceeding(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q931Pmes_Connect(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q931Pmes_ConnectAck(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q931Pmes_Progress(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q931Pmes_Setup(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q931Pmes_SetupAck(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q931Pmes_Resume(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q931Pmes_ResumeAck(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q931Pmes_ResumeReject(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q931Pmes_Suspend(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q931Pmes_SuspendAck(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q931Pmes_SuspendReject(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q931Pmes_UserInformation(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q931Pmes_Disconnect(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q931Pmes_Release(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q931Pmes_ReleaseComplete(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q931Pmes_Restart(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q931Pmes_RestartAck(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q931Pmes_CongestionControl(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q931Pmes_Information(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q931Pmes_Notify(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q931Pmes_Segment(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q931Pmes_Status(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q931Pmes_StatusEnquiry(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q931Pmes_Service(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q931Pmes_ServiceAck(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+
+
+L3INT Q931Umes_Alerting(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT I, L3INT O);
+L3INT Q931Umes_CallProceeding(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT I, L3INT O);
+L3INT Q931Umes_Connect(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT I, L3INT O);
+L3INT Q931Umes_ConnectAck(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT I, L3INT O);
+L3INT Q931Umes_Progress(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT I, L3INT O);
+L3INT Q931Umes_Setup(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT I, L3INT O);
+L3INT Q931Umes_SetupAck(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT I, L3INT O);
+L3INT Q931Umes_Resume(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT I, L3INT O);
+L3INT Q931Umes_ResumeAck(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT I, L3INT O);
+L3INT Q931Umes_ResumeReject(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT I, L3INT O);
+L3INT Q931Umes_Suspend(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT I, L3INT O);
+L3INT Q931Umes_SuspendAck(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT I, L3INT O);
+L3INT Q931Umes_SuspendReject(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT I, L3INT O);
+L3INT Q931Umes_UserInformation(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT I, L3INT O);
+L3INT Q931Umes_Disconnect(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT I, L3INT O);
+L3INT Q931Umes_Release(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT I, L3INT O);
+L3INT Q931Umes_ReleaseComplete(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT I, L3INT O);
+L3INT Q931Umes_Restart(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT I, L3INT O);
+L3INT Q931Umes_RestartAck(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT I, L3INT O);
+L3INT Q931Umes_CongestionControl(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT I, L3INT O);
+L3INT Q931Umes_Information(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT I, L3INT O);
+L3INT Q931Umes_Notify(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT I, L3INT O);
+L3INT Q931Umes_Segment(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT I, L3INT O);
+L3INT Q931Umes_Status(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT I, L3INT O);
+L3INT Q931Umes_StatusEnquiry(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT I, L3INT O);
+L3INT Q931Umes_Service(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size);
+L3INT Q931Umes_ServiceAck(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size);
+
+
+/*****************************************************************************
+
+  Q.931 Process Function Prototyping. Implemented in Q931StateTE.c
+
+*****************************************************************************/
+L3INT Q931ProcAlertingTE(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcCallProceedingTE(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcConnectTE(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcConnectAckTE(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcProgressTE(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcSetupTE(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcSetupAckTE(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcResumeTE(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcResumeAckTE(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcResumeRejectTE(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcSuspendTE(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcSuspendAckTE(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcSuspendRejectTE(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcUserInformationTE(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcDisconnectTE(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcReleaseTE(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcReleaseCompleteTE(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcRestartTE(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcRestartAckTE(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcCongestionControlTE(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcInformationTE(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcNotifyTE(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcStatusTE(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcStatusEnquiryTE(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcSegmentTE(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+
+L3INT Q931ProcAlertingNT(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcCallProceedingNT(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcConnectNT(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcConnectAckNT(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcProgressNT(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcSetupNT(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcSetupAckNT(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcResumeNT(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcResumeAckNT(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcResumeRejectNT(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcSuspendNT(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcSuspendAckNT(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcSuspendRejectNT(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcUserInformationNT(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcDisconnectNT(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcReleaseNT(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcReleaseCompleteNT(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcRestartNT(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcRestartAckNT(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcCongestionControlNT(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcInformationNT(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcNotifyNT(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcStatusNT(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcStatusEnquiryNT(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcSegmentNT(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+
+L3INT Q931ProcUnknownMessage(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcUnexpectedMessage(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+
+/*****************************************************************************
+
+  Interface Function Prototypes. Implemented in Q931.c
+
+*****************************************************************************/
+void    Q931TimerTick(Q931_TrunkInfo_t *pTrunk);
+L3INT   Q931Rx23(Q931_TrunkInfo_t *pTrunk, L3INT ind, L3UCHAR tei, L3UCHAR * Mes, L3INT Size);
+L3INT   Q931Tx32Data(Q931_TrunkInfo_t *pTrunk, L3UCHAR bcast, L3UCHAR * Mes, L3INT Size);
+L3INT   Q931Rx43(Q931_TrunkInfo_t *pTrunk, L3UCHAR * Mes, L3INT Size);
+L3INT   Q931Tx34(Q931_TrunkInfo_t *pTrunk, L3UCHAR * Mes, L3INT Size);
+void    Q931SetError(Q931_TrunkInfo_t *pTrunk,L3INT ErrID, L3INT ErrPar1, L3INT ErrPar2);
+
+void	Q931SetDefaultErrorCB(Q931ErrorCB_t Q931ErrorPar);
+
+void    Q931CreateTE(L3UCHAR i);
+void    Q931CreateNT(L3UCHAR i);
+void    Q931SetMesCreateCB(L3INT (*callback)(void));
+void    Q931SetDialectCreateCB(L3INT (*callback)(L3INT));
+void    Q931SetHeaderSpace(L3INT space);
+
+void Q931SetMesProc(L3UCHAR mes, L3UCHAR dialect, q931proc_func_t *Q931ProcFunc, q931umes_func_t *Q931UmesFunc, q931pmes_func_t *Q931PmesFunc);
+void Q931SetIEProc(L3UCHAR iec, L3UCHAR dialect, q931pie_func_t *Q931PieProc, q931uie_func_t *Q931UieProc);
+void Q931SetTimeoutProc(L3UCHAR dialect, L3UCHAR timer, q931timeout_func_t *Q931TimeoutProc);
+void Q931SetTimerDefault(L3UCHAR dialect, L3UCHAR timer, q931timer_t timeout);
+
+void Q931Initialize(void);
+void Q931AddDialect(L3UCHAR iDialect, void (*Q931CreateDialectCB)(L3UCHAR iDialect));
+L3INT Q931InitMesSetup(Q931mes_Generic *p);
+L3INT Q931InitMesRestartAck(Q931mes_Generic * pMes);
+L3INT Q931InitMesGeneric(Q931mes_Generic *pMes);
+
+L3INT	Q931CreateCRV(Q931_TrunkInfo_t *pTrunk, L3INT * callIndex);
+L3INT	Q931ReleaseCRV(Q931_TrunkInfo_t *pTrunk, L3INT CRV);
+L3INT	Q931AllocateCRV(Q931_TrunkInfo_t *pTrunk, L3INT iCRV, L3INT * callIndex);
+L3INT   Q931FindCRV(Q931_TrunkInfo_t *pTrunk, L3INT crv, L3INT *callindex);
+L3INT	Q931GetCallState(Q931_TrunkInfo_t *pTrunk, L3INT iCRV);
+L3INT	Q931StartTimer(Q931_TrunkInfo_t *pTrunk, L3INT callIndex, L3USHORT iTimer);
+L3INT	Q931StopTimer(Q931_TrunkInfo_t *pTrunk, L3INT callindex, L3USHORT iTimer);
+L3INT	Q931SetState(Q931_TrunkInfo_t *pTrunk, L3INT callIndex, L3INT iState);
+L3ULONG Q931GetTime(void);
+void    Q931SetGetTimeCB(L3ULONG (*callback)(void));
+void	Q931AddStateEntry(L3UCHAR iD, L3INT iState, L3INT iMes, L3UCHAR cDir);
+L3BOOL	Q931IsEventLegal(L3UCHAR iD, L3INT iState, L3INT iMes, L3UCHAR cDir);
+
+/*****************************************************************************
+
+  Q.931 Low Level API Function Prototyping. Implemented in Q931API.c
+
+*****************************************************************************/
+ie Q931AppendIE(L3UCHAR *pm, L3UCHAR *pi);
+L3INT Q931GetUniqueCRV(Q931_TrunkInfo_t *pTrunk);
+
+L3INT Q931InitIEBearerCap(Q931ie_BearerCap *p);
+L3INT Q931InitIEChanID(Q931ie_ChanID *p);
+L3INT Q931InitIEProgInd(Q931ie_ProgInd *p);
+L3INT Q931InitIENetFac(Q931ie_NetFac * pIE);
+L3INT Q931InitIEDisplay(Q931ie_Display * pIE);
+L3INT Q931InitIEDateTime(Q931ie_DateTime * pIE);
+L3INT Q931InitIEKeypadFac(Q931ie_KeypadFac * pIE);
+L3INT Q931InitIESignal(Q931ie_Signal * pIE);
+L3INT Q931InitIECallingNum(Q931ie_CallingNum * pIE);
+L3INT Q931InitIECallingSub(Q931ie_CallingSub * pIE);
+L3INT Q931InitIECalledNum(Q931ie_CalledNum * pIE);
+L3INT Q931InitIECalledSub(Q931ie_CalledSub * pIE);
+L3INT Q931InitIETransNetSel(Q931ie_TransNetSel * pIE);
+L3INT Q931InitIELLComp(Q931ie_LLComp * pIE);
+L3INT Q931InitIEHLComp(Q931ie_HLComp * pIE);
+
+L3INT Q931Disconnect(Q931_TrunkInfo_t *pTrunk, L3INT iTo, L3INT iCRV, L3INT iCause);
+L3INT Q931ReleaseComplete(Q931_TrunkInfo_t *pTrunk, L3UCHAR *buf);
+L3INT Q931AckRestart(Q931_TrunkInfo_t *pTrunk, L3UCHAR *buf);
+L3INT Q931AckConnect(Q931_TrunkInfo_t *pTrunk, L3UCHAR *buf);
+L3INT Q931AckSetup(Q931_TrunkInfo_t *pTrunk, L3UCHAR *buf);
+L3INT Q931AckService(Q931_TrunkInfo_t *pTrunk, L3UCHAR *buf);
+
+L3INT Q931Api_InitTrunk(Q931_TrunkInfo_t *pTrunk,
+						Q931Dialect_t Dialect,
+						Q931NetUser_t NetUser,
+						Q931_TrunkType_t TrunkType,
+						Q931Tx34CB_t Q931Tx34CBProc,
+						Q931Tx32CB_t Q931Tx32CBProc,
+						Q931ErrorCB_t Q931ErrorCBProc,
+						void *PrivateData32,
+						void *PrivateData34);
+
+L3INT Q931GetMesSize(Q931mes_Generic *pMes);
+L3INT Q931InitMesResume(Q931mes_Generic * pMes);
+
+L3INT Q931Log(Q931_TrunkInfo_t *trunk, Q931LogLevel_t level, const char *fmt, ...);
+void Q931SetLogCB(Q931_TrunkInfo_t *trunk, Q931LogCB_t func, void *priv);
+void Q931SetLogLevel(Q931_TrunkInfo_t *trunk, Q931LogLevel_t level);
+
+void Q931SetL4HeaderSpace(L3INT space);
+void Q931SetL2HeaderSpace(L3INT space);
+L3INT Q931ProcDummy(Q931_TrunkInfo_t *pTrunk, L3UCHAR * b,L3INT c);
+L3INT Q931UmesDummy(Q931_TrunkInfo_t *pTrunk,L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT IOff, L3INT Size);
+L3INT Q931UieDummy(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff);
+L3INT Q931PmesDummy(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q931PieDummy(Q931_TrunkInfo_t *pTrunk,L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet);
+L3INT Q931TxDummy(Q931_TrunkInfo_t *pTrunk, L3UCHAR * b, L3INT n);
+L3INT Q931ErrorDummy(void *priv, L3INT a, L3INT b, L3INT c);
+L3INT Q931TimeoutDummy(Q931_TrunkInfo_t *pTrunk, L3INT callIndex);
+
+L3INT Q931MesgHeader(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *mes, L3UCHAR *OBuf, L3INT Size, L3INT *IOff);
+
+#endif /* _Q931_NL */

Added: freeswitch/trunk/libs/freetdm/src/isdn/include/Q931ie.h (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/isdn/include/Q931ie.h	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/isdn/include/Q931ie.h	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,1205 @@
+/******************************************************************************
+
+  FileName:         Q931ie.h
+
+  Contents:         Header and definition for the ITU-T Q.931 ie
+					structures and functions
+
+  License/Copyright:
+
+  Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+  email:janvb@caselaboratories.com  
+
+  Redistribution and use in source and binary forms, with or without 
+  modification, are permitted provided that the following conditions are 
+  met:
+
+    * Redistributions of source code must retain the above copyright notice, 
+	  this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright notice, 
+	  this list of conditions and the following disclaimer in the documentation 
+	  and/or other materials provided with the distribution.
+    * Neither the name of the Case Labs, Ltd nor the names of its contributors 
+	  may be used to endorse or promote products derived from this software 
+	  without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
+  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
+  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+  POSSIBILITY OF SUCH DAMAGE.
+******************************************************************************/
+
+#ifndef _Q931IE_NL
+#define _Q931IE_NL
+
+/* Codesets */
+
+typedef enum {
+
+	Q931_CODESET_0			= ( 0 ),
+	Q931_CODESET_1			= ( 1 << 8 ),
+	Q931_CODESET_2			= ( 2 << 8 ),
+	Q931_CODESET_3			= ( 3 << 8 ),
+	Q931_CODESET_4			= ( 4 << 8 ),
+	Q931_CODESET_5			= ( 5 << 8 ),
+	Q931_CODESET_6			= ( 6 << 8 ),
+	Q931_CODESET_7			= ( 7 << 8 )
+
+} q931_codeset_t;
+
+/* Single octet information elements */
+#define Q931ie_SHIFT                            0x90 /* 1001 ----       */
+#define Q931ie_MORE_DATA                        0xa0 /* 1010 ----       */
+#define Q931ie_SENDING_COMPLETE                 0xa1 /* 1010 0001       */
+#define Q931ie_CONGESTION_LEVEL                 0xb0 /* 1011 ----       */
+#define Q931ie_REPEAT_INDICATOR                 0xd0 /* 1101 ----       */
+
+/* Variable Length Information Elements */
+#define Q931ie_SEGMENTED_MESSAGE                0x00 /* 0000 0000       */
+#define Q931ie_CHANGE_STATUS                    0x01 /* 0000 0001       */
+#define Q931ie_BEARER_CAPABILITY                0x04 /* 0000 0100       */
+#define Q931ie_CAUSE                            0x08 /* 0000 1000       */
+#define Q931ie_CALL_IDENTITY                    0x10 /* 0001 0000       */
+#define Q931ie_CALL_STATE                       0x14 /* 0001 0100       */
+#define Q931ie_CHANNEL_IDENTIFICATION           0x18 /* 0001 1000       */
+#define Q931ie_PROGRESS_INDICATOR               0x1e /* 0001 1110       */
+#define Q931ie_NETWORK_SPECIFIC_FACILITIES      0x20 /* 0010 0000       */
+#define Q931ie_NOTIFICATION_INDICATOR           0x27 /* 0010 0111       */
+#define Q931ie_DISPLAY                          0x28 /* 0010 1000       */
+#define Q931ie_DATETIME                         0x29 /* 0010 1001       */
+#define Q931ie_KEYPAD_FACILITY                  0x2c /* 0010 1100       */
+#define Q931ie_SIGNAL                           0x34 /* 0011 0100       */
+#define Q931ie_SWITCHOOK                        0x36 /* 0011 0110       */
+#define Q931ie_FEATURE_ACTIVATION               0x38 /* 0011 1000       */
+#define Q931ie_FEATURE_INDICATION               0x39 /* 0011 1001       */
+#define Q931ie_INFORMATION_RATE                 0x40 /* 0100 0000       */
+#define Q931ie_END_TO_END_TRANSIT_DELAY         0x42 /* 0100 0010       */
+#define Q931ie_TRANSIT_DELAY_SELECTION_AND_IND  0x43 /* 0100 0011       */
+#define Q931ie_PACKED_LAYER_BIMARY_PARAMETERS   0x44 /* 0100 0100       */
+#define Q931ie_PACKED_LAYER_WINDOW_SIZE         0x45 /* 0100 0101       */
+#define Q931ie_PACKED_SIZE                      0x46 /* 0100 0110       */
+#define Q931ie_CALLING_PARTY_NUMBER             0x6c /* 0110 1100       */
+#define Q931ie_CALLING_PARTY_SUBADDRESS         0x6d /* 0110 1101       */
+#define Q931ie_CALLED_PARTY_NUMBER              0x70 /* 0111 0000       */
+#define Q931ie_CALLED_PARTY_SUBADDRESS          0x71 /* 0111 0001       */
+#define Q931ie_REDIRECTING_NUMBER               0x74 /* 0111 0100       */
+#define Q931ie_TRANSIT_NETWORK_SELECTION        0x78 /* 0111 1000       */
+#define Q931ie_RESTART_INDICATOR                0x79 /* 0111 1001       */
+#define Q931ie_LOW_LAYER_COMPATIBILITY          0x7c /* 0111 1100       */
+#define Q931ie_HIGH_LAYER_COMPATIBILITY         0x7d /* 0111 1101       */
+#define Q931ie_USER_USER                        0x7e /* 0111 1110       */
+#define Q931ie_ESCAPE_FOR_EX                    0x7f /* 0111 1111       */
+
+/* Variable Length Codeset 6 Information Elements */
+#define Q931ie_GENERIC_DIGITS                   0x37 /* 0011 0111       */
+
+/* Variable Length Information Element to shut up BRI testing */
+#define Q931ie_CONNECTED_NUMBER                 0x4c /* 0100 1101 */
+#define Q931ie_FACILITY                         0x1c /* 0001 1101 */
+
+
+/*****************************************************************************
+
+  Struct:        Q931ie_BearerCap
+
+  Description:   Bearer Capability Information Element.
+
+*****************************************************************************/
+
+typedef struct {
+
+    L3UCHAR IEId;                   /* 00000100 for Bearer Capability       */
+    L3UCHAR Size;                   /* Length of Information Element        */
+
+    L3UCHAR CodStand;               /* Coding Standard.                     */
+                                    /*  00 - ITU-T                          */
+                                    /*  01 - ISO/IEC                        */
+                                    /*  10 - National standard              */
+                                    /*  11 - Network side spesific          */
+
+    L3UCHAR ITC;                    /* Information Transfer Capability      */
+                                    /*  00000 - Speech                      */
+                                    /*  01000 - Unrestricted digital info   */
+                                    /*  01001 - Restricted digital info     */
+                                    /*  10000 - 3.1 kHz audio               */
+                                    /*  10001 - Unrestricted with tones     */
+                                    /*  11000 - Video                       */
+
+    L3UCHAR TransMode;              /* Transfer Mode.                       */
+                                    /*  00 - Circuit mode                   */
+                                    /*  10 - Packet mode                    */
+
+    L3UCHAR ITR;                    /* Information Transfer Rate.           */
+                                    /*  00000 - Packed mode                 */
+                                    /*  10000 - 64 kbit/s                   */
+                                    /*  10001 - 2 x 64 kbit/s               */
+                                    /*  10011 - 384 kbit/s                  */
+                                    /*  10101 - 1536 kbit/s                 */
+                                    /*  10111 - 1920 kbit/s                 */
+                                    /*  11000 - Multirat (64 kbit/s base)   */
+
+    L3UCHAR RateMul;                /* Rate Multiplier                      */
+
+    L3UCHAR Layer1Ident;			/* Layer 1 Ident.						*/
+
+    L3UCHAR UIL1Prot;               /* User Information Layer 1 Protocol    */
+									/*	00001 : ITU-T V.110, I.460 and X.30 */
+									/*  00010 : G.711 my-law				*/
+									/*  00011 : G.711 A-law					*/
+									/*  00100 : G.721						*/
+                                    /*  00101 : H.221 and H.242				*/
+									/*  00110 : H.223 and H.245				*/
+									/*  00111 : Non ITU-T Standard			*/
+									/*  01000 : ITU-T V.120					*/
+									/*  01001 : ITU-T X.31 HDLC flag stuff.	*/
+
+    L3UCHAR SyncAsync;              /* Sync/Async                           */
+									/*	0 : Syncronous data					*/
+									/*	1 : Asyncronous data				*/
+
+    L3UCHAR Negot;					/* Negotiation							*/
+									/*	0 : In-band negotiation not possib.	*/
+									/*  1 : In-band negotiation possible	*/
+
+    L3UCHAR UserRate;				/* User rate							*/
+									/*	00000 : I.460, V.110, X,30			*/
+									/*  00001 : 0.6 kbit/s x.1				*/
+									/*  00010 : 1.2 kbit/s					*/
+									/*  00011 : 2.4 kbit/s					*/
+									/*  00100 : 3.6 kbit/s					*/
+									/*  00101 : 4.8 kbit/s					*/
+									/*  00110 : 7.2 kbit/s					*/
+									/*  00111 : 8 kbit/s I.460				*/
+									/*  01000 : 9.6 kbit/s					*/
+									/*  01001 : 14.4 kbit/s					*/
+									/*  01010 : 16 kbit/s					*/
+									/*  01011 :	19.2 kbit/s					*/
+									/*  01100 : 32 kbit/s					*/
+									/*  01101 : 38.4 kbit/s					*/
+									/*  01110 : 48 kbit/s					*/
+									/*  01111 : 56 kbit/s					*/
+									/*  10000 : 57.6 kbit/s					*/
+									/*  10010 : 28.8 kbit/s					*/
+									/*  10100 : 24 kbit/s					*/
+									/*  10101 : 0.1345 kbit/s				*/
+									/*  10110 : 0.100 kbit/s				*/
+									/*  10111 : 0.075/1.2 kbit/s			*/
+									/*  11000 : 1.2/0.075/kbit/s			*/
+									/*  11001 : 0.050 kbit/s				*/
+									/*  11010 : 0.075 kbit/s				*/
+									/*  11011 : 0.110 kbit/s				*/
+									/*  11100 : 0.150 kbit/s				*/
+									/*  11101 : 0.200 kbit/s				*/
+									/*  11110 : 0.300 kbit/s				*/
+									/*  11111 : 12 kbit/s					*/
+
+    L3UCHAR InterRate;              /* Intermediate Rate                    */
+									/*	00 : Not used						*/
+									/*  01 : 8 kbit/s						*/
+									/*  10 : 16 kbit/s						*/
+									/*  11 : 32 kbit/s						*/
+
+    L3UCHAR NIConTx;				/* Network Indepentend Clock on transmit*/
+									/*	0 : Not required to send data  clc  */
+									/*  1 : Send data w/NIC clc				*/
+
+    L3UCHAR NIConRx;				/* NIC on Rx							*/
+									/*	0 : Cannot accept indep. clc		*/
+									/*  1 : data with indep. clc accepted	*/
+
+    L3UCHAR FlowCtlTx;              /* Flow control on Tx                   */
+									/*  0 : Send Flow ctrl not required		*/
+									/*  1 : Send flow ctrl required			*/
+
+    L3UCHAR FlowCtlRx;              /* Flow control on Rx                   */
+									/*  0 : cannot use receive flow ctrl	*/
+									/*  1 : Receive flow ctrl accepted		*/
+    L3UCHAR HDR;					/* HDR/No HDR							*/
+    L3UCHAR MultiFrame;             /* Multi frame support                  */
+									/*  0 : multiframe not supported		*/
+									/*  1 : multiframe supported			*/
+
+    L3UCHAR Mode;					/* Mode of operation					*/
+									/*	0 : bit transparent mode of operat.	*/
+									/*	1 : protocol sesitive mode of op.	*/
+
+    L3UCHAR LLInegot;				/* Logical link id negotiation (oct. 5b)*/
+									/*  0 : default LLI=256 only			*/
+									/*  1 : Full protocol negotiation		*/
+
+    L3UCHAR Assignor;               /* Assignor/assignee                    */
+									/*  0 : Default Asignee					*/
+									/*  1 : Assignor only					*/
+
+    L3UCHAR InBandNeg;              /* In-band/out-band negot.              */
+									/*  0 : negot done w/ USER INFO mes		*/
+									/*  1 : negot done in-band w/link zero	*/
+
+    L3UCHAR NumStopBits;            /* Number of stop bits					*/
+									/*  00 : Not used						*/
+									/*  01 : 1 bit							*/
+									/*  10 : 1.5 bits						*/
+									/*  11 : 2 bits							*/
+
+    L3UCHAR NumDataBits;            /* Number of data bits.                 */
+									/*  00 : not used						*/
+									/*  01 : 5 bits							*/
+									/*  10 : 7 bits							*/
+									/*  11 : 8 bits							*/
+
+    L3UCHAR Parity;					/* Parity Information					*/
+									/*	000 : Odd							*/
+									/*  010 : Even							*/
+									/*  011 : None							*/
+									/*  100 : Forced to 0					*/
+									/*  101 : Forced to 1					*/
+
+    L3UCHAR DuplexMode;				/* Mode duplex							*/
+									/*  0 : Half duplex						*/
+									/*  1 : Full duplex						*/
+
+    L3UCHAR ModemType;				/* Modem type, see Q.931 p 64			*/
+
+    L3UCHAR Layer2Ident;			/* Layer 2 Ident						*/
+
+    L3UCHAR UIL2Prot;               /* User Information Layer 2 Protocol    */
+									/*	00010 : Q.921/I.441					*/
+									/*  00110 : X.25						*/
+									/*  01100 : LAN logical link			*/
+
+    L3UCHAR Layer3Ident;            /* Layer 3 ident.						*/
+
+    L3UCHAR UIL3Prot;               /* User Information Layer 3 Protocol    */
+									/*	00010 : Q.931						*/
+									/*  00110 : X.25						*/
+									/*  01011 : ISO/IEC TR 9577				*/
+
+    L3UCHAR AL3Info1;				/* additional layer 3 info 1			*/
+
+    L3UCHAR AL3Info2;				/* additional layer 3 info 2			*/
+
+} Q931ie_BearerCap;
+
+/*****************************************************************************
+
+  Struct:       Q931ie_CallID
+
+
+*****************************************************************************/
+
+typedef struct {
+
+    L3UCHAR IEId;                   /* 00010000                             */
+    L3UCHAR Size;                   /* Length of Information Element        */
+    L3UCHAR CallId[1];				/* Call identity                        */
+
+} Q931ie_CallID;
+
+/*****************************************************************************
+
+  Struct:       Q931ie_CallState
+
+
+*****************************************************************************/
+
+typedef struct {
+
+    L3UCHAR IEId;                   /* 00010100                             */
+    L3UCHAR Size;                   /* Length of Information Element        */
+    L3UCHAR CodStand;               /* Coding Standard                      */
+    L3UCHAR CallState;              /* Call State Value                     */
+
+} Q931ie_CallState;
+
+/*****************************************************************************
+
+  Struct:		Q931ie_Cause
+
+  Description:	Cause IE as described in Q.850
+
+*****************************************************************************/
+typedef struct {
+
+    L3UCHAR IEId;                   /* 00010100                             */
+    L3UCHAR Size;                   /* Length of Information Element        */
+    L3UCHAR CodStand;               /* Coding Standard                      */
+	L3UCHAR Location;				/* Location								*/
+	L3UCHAR Recom;					/* Recommendation						*/
+	L3UCHAR Value;					/* Cause Value							*/
+	L3UCHAR	Diag[1];				/* Optional Diagnostics Field			*/
+
+} Q931ie_Cause;
+
+/*****************************************************************************
+
+  Struct:        Q931ie_CalledNum
+
+*****************************************************************************/
+typedef struct {
+
+    L3UCHAR IEId;                   /* 01110000                             */
+    L3UCHAR Size;                   /* Length of Information Element        */
+    L3UCHAR TypNum;                 /* Type of Number                       */
+    L3UCHAR NumPlanID;              /* Numbering plan identification        */
+    L3UCHAR Digit[1];				/* Digit (IA5)                          */
+
+} Q931ie_CalledNum;
+
+/*****************************************************************************
+
+  Struct:       Q931ie_CalledSub
+
+  Description:  Called party subaddress
+
+*****************************************************************************/
+
+typedef struct {
+
+    L3UCHAR IEId;                   /* 01110001                             */
+    L3UCHAR Size;                   /* Length of Information Element        */
+    L3UCHAR TypNum;                 /* Type of subaddress                   */
+    L3UCHAR OddEvenInd;             /* Odd/Even indicator                   */
+    L3UCHAR Digit[1];				/* digits                               */
+
+} Q931ie_CalledSub;
+
+/*****************************************************************************
+
+  Struct:       Q931ie_CallingNum
+
+  Description:  Calling party number
+
+*****************************************************************************/
+
+typedef struct {
+
+    L3UCHAR IEId;                   /* 01101100                             */
+    L3UCHAR Size;                   /* Length of Information Element        */
+    L3UCHAR TypNum;                 /* Type of number                       */
+    L3UCHAR NumPlanID;              /* Numbering plan identification        */
+    L3UCHAR PresInd;                /* Presentation indicator               */
+    L3UCHAR ScreenInd;              /* Screening indicator                  */
+    L3UCHAR Digit[1];				/* Number digits (IA5)                  */
+
+} Q931ie_CallingNum;
+
+/*****************************************************************************
+
+  Struct:        Q931ie_CallingSub
+
+  Description:   Calling party subaddress
+
+*****************************************************************************/
+
+typedef struct {
+
+    L3UCHAR IEId;                   /* 01101101                             */
+    L3UCHAR Size;                   /* Length of Information Element        */
+    L3UCHAR TypNum;                 /* Type of subaddress                   */
+    L3UCHAR OddEvenInd;             /* Odd/Even indicator                   */
+    L3UCHAR Digit[1];				/* digits                               */
+
+} Q931ie_CallingSub;
+
+/*****************************************************************************
+
+  Struct:       Q931ie_ChanID
+
+  Description:  Channel identification
+
+				Channel Identificationis one of the IE elements that differ
+				between BRI and PRI. IntType = 1 = BRI and ChanSlot is used
+				for channel number, while InfoChanSel is used for BRI.
+
+				ChanID is one of the most important IE as it is passed	
+				either though SETUP or CALL PROCEEDING to select the channel
+				to be used.
+
+*****************************************************************************/
+
+typedef struct {
+
+    L3UCHAR IEId;                   /* 00011000                             */
+    L3UCHAR Size;                   /* Length of Information Element        */
+    L3UCHAR IntIDPresent;           /* Int. id. present                     */
+    L3UCHAR IntType;                /* Interface Type                       */
+									/*	0 : Basic Interface	(BRI)			*/
+									/*  1 : Other interfaces, PRI etc.		*/
+
+    L3UCHAR PrefExcl;               /* Pref./Excl.                          */
+									/*	0 : Indicated channel is preffered	*/
+									/*  1 : Exclusive, no other accepted	*/
+
+    L3UCHAR DChanInd;               /* D-channel ind.                       */
+									/*  0 : chan is NOT D chan.				*/
+									/*  1 : chan is D chan					*/
+
+    L3UCHAR InfoChanSel;            /* Info. channel selection              */
+									/*  00 : No channel						*/
+									/*  01 : B1 channel						*/
+									/*  10 : B2 channel						*/
+									/*  11 : Any channel					*/
+
+    L3UCHAR InterfaceID;            /* Interface identifier                 */
+
+    L3UCHAR CodStand;		        /* Code standard                        */
+									/*  00 : ITU-T standardization coding	*/
+									/*  01 : ISO/IEC Standard				*/
+									/*  10 : National Standard				*/
+									/*  11 : Standard def. by network.		*/
+
+    L3UCHAR NumMap;                 /* Number/Map                           */
+									/*  0 : chan is in following octet		*/
+									/*  1 : chan is indicated by slot map	*/
+
+    L3UCHAR ChanMapType;            /* Channel type/Map element type        */
+									/*  0011 : B Channel units				*/
+									/*  0110 : H0 channel units				*/
+									/*  1000 : H11 channel units			*/
+									/*  1001 : H12 channel units			*/
+
+    L3UCHAR ChanSlot;               /* Channel number						*/
+
+} Q931ie_ChanID;
+
+/*****************************************************************************
+
+  Struct:       Q931ie_DateTime
+
+  Description:  Date/time
+
+*****************************************************************************/
+
+typedef struct {
+
+    L3UCHAR IEId;                   /* 00101001                             */
+    L3UCHAR Size;                   /* Length of Information Element        */
+    L3UCHAR Year;                   /* Year                                 */
+    L3UCHAR Month;                  /* Month                                */
+    L3UCHAR Day;                    /* Day                                  */
+    L3UCHAR Hour;                   /* Hour                                 */
+    L3UCHAR Minute;                 /* Minute                               */
+    L3UCHAR Second;                 /* Second                               */
+	L3UCHAR Format;					/* Indicate presense of Hour, Min & sec */
+									/*	0 : Only Date						*/
+									/*  1 : Hour present					*/
+									/*  2 : Hour and Minute present			*/
+									/*  3 : Hour, Minute and Second present	*/
+} Q931ie_DateTime;
+
+/*****************************************************************************
+
+  Struct:       Q931ie_Display
+
+  Description:  Display
+
+*****************************************************************************/
+
+typedef struct {
+
+    L3UCHAR IEId;                   /* 00101000                             */
+    L3UCHAR Size;                   /* Length of Information Element        */
+    L3UCHAR Display[1];             /* Display information (IA5)            */
+
+} Q931ie_Display;
+
+/*****************************************************************************
+
+  Struct:       Q931ie_HLComp
+
+  Description:  High layer compatibility
+
+*****************************************************************************/
+
+typedef struct {
+
+    L3UCHAR IEId;                   /* 01111101                             */
+    L3UCHAR Size;                   /* Length of Information Element        */
+    L3UCHAR CodStand;               /* Coding standard                      */
+    L3UCHAR Interpret;              /* Interpretation                       */
+    L3UCHAR PresMeth;               /* Presentation methor of prot. profile */
+    L3UCHAR HLCharID;               /* High layer characteristics id.       */
+    L3UCHAR EHLCharID;              /* Extended high layer character. id.   */
+    L3UCHAR EVideoTlfCharID;        /* Ext. videotelephony char. id.        */
+
+} Q931ie_HLComp;
+
+/*****************************************************************************
+
+  Struct:       Q931ie_KeypadFac
+
+  Description:  Keypad facility
+
+*****************************************************************************/
+
+typedef struct {
+    L3UCHAR IEId;                   /* 00101100                             */
+    L3UCHAR Size;                   /* Length of Information Element        */
+    L3UCHAR KeypadFac[1];           /* dynamic buffer                       */
+
+} Q931ie_KeypadFac;
+
+/*****************************************************************************
+
+  Struct:       Q931ie_LLComp
+
+  Description:  Low layer compatibility
+
+*****************************************************************************/
+
+typedef struct {
+
+    L3UCHAR IEId;                   /* 01111100                             */
+    L3UCHAR Size;                   /* Length of Information Element        */
+    L3UCHAR CodStand;               /* Coding standard                      */
+                                    /*  00 - ITU-T                          */
+                                    /*  01 - ISO/IEC                        */
+                                    /*  10 - National standard              */
+                                    /*  11 - Network side spesific          */
+
+    L3UCHAR ITransCap;              /* Information transfer capability      */
+                                    /*  00000 - Speech                      */
+                                    /*  01000 - Unrestricted digital info   */
+                                    /*  01001 - Restricted digital info     */
+                                    /*  10000 - 3.1 kHz audio               */
+                                    /*  10001 - Unrestricted with tones     */
+                                    /*  11000 - Video                       */
+
+    L3UCHAR NegotInd;               /* Negot indic.                         */
+									/*	0 : Out-band neg. not possib.       */
+									/*  1 : Out-band neg. possible	        */
+
+    L3UCHAR TransMode;              /* Transfer Mode                        */
+                                    /*  00 : Circuit Mode                   */
+                                    /*  10 : Packed Mode                    */
+
+    L3UCHAR InfoRate;               /* Information transfer rate            */
+                                    /*  00000 - Packed mode                 */
+                                    /*  10000 - 64 kbit/s                   */
+                                    /*  10001 - 2 x 64 kbit/s               */
+                                    /*  10011 - 384 kbit/s                  */
+                                    /*  10101 - 1536 kbit/s                 */
+                                    /*  10111 - 1920 kbit/s                 */
+                                    /*  11000 - Multirat (64 kbit/s base)   */
+
+    L3UCHAR RateMul;                /* Rate multiplier                      */
+    L3UCHAR Layer1Ident;            /* Layer 1 ident.                       */
+    L3UCHAR UIL1Prot;               /* User information layer 1 protocol    */
+									/*	00001 : ITU-T V.110, I.460 and X.30 */
+									/*  00010 : G.711 my-law				*/
+									/*  00011 : G.711 A-law					*/
+									/*  00100 : G.721						*/
+                                    /*  00101 : H.221 and H.242				*/
+									/*  00110 : H.223 and H.245				*/
+									/*  00111 : Non ITU-T Standard			*/
+									/*  01000 : ITU-T V.120					*/
+									/*  01001 : ITU-T X.31 HDLC flag stuff.	*/
+
+    L3UCHAR SyncAsync;              /* Synch/asynch                         */
+									/*	0 : Syncronous data					*/
+									/*	1 : Asyncronous data				*/
+
+    L3UCHAR Negot;                  /* Negot                                */
+									/*	0 : In-band negotiation not possib.	*/
+									/*  1 : In-band negotiation possible	*/
+
+    L3UCHAR UserRate;               /* User rate                            */
+									/*	00000 : I.460, V.110, X,30			*/
+									/*  00001 : 0.6 kbit/s x.1				*/
+									/*  00010 : 1.2 kbit/s					*/
+									/*  00011 : 2.4 kbit/s					*/
+									/*  00100 : 3.6 kbit/s					*/
+									/*  00101 : 4.8 kbit/s					*/
+									/*  00110 : 7.2 kbit/s					*/
+									/*  00111 : 8 kbit/s I.460				*/
+									/*  01000 : 9.6 kbit/s					*/
+									/*  01001 : 14.4 kbit/s					*/
+									/*  01010 : 16 kbit/s					*/
+									/*  01011 :	19.2 kbit/s					*/
+									/*  01100 : 32 kbit/s					*/
+									/*  01101 : 38.4 kbit/s					*/
+									/*  01110 : 48 kbit/s					*/
+									/*  01111 : 56 kbit/s					*/
+									/*  10000 : 57.6 kbit/s					*/
+									/*  10010 : 28.8 kbit/s					*/
+									/*  10100 : 24 kbit/s					*/
+									/*  10101 : 0.1345 kbit/s				*/
+									/*  10110 : 0.100 kbit/s				*/
+									/*  10111 : 0.075/1.2 kbit/s			*/
+									/*  11000 : 1.2/0.075/kbit/s			*/
+									/*  11001 : 0.050 kbit/s				*/
+									/*  11010 : 0.075 kbit/s				*/
+									/*  11011 : 0.110 kbit/s				*/
+									/*  11100 : 0.150 kbit/s				*/
+									/*  11101 : 0.200 kbit/s				*/
+									/*  11110 : 0.300 kbit/s				*/
+									/*  11111 : 12 kbit/s					*/
+
+    L3UCHAR InterRate;              /* Intermediate rate                    */
+									/*	00 : Not used						*/
+									/*  01 : 8 kbit/s						*/
+									/*  10 : 16 kbit/s						*/
+									/*  11 : 32 kbit/s						*/
+
+    L3UCHAR NIConTx;				/* Network Indepentend Clock on transmit*/
+									/*	0 : Not required to send data  clc  */
+									/*  1 : Send data w/NIC clc				*/
+
+    L3UCHAR NIConRx;				/* NIC on Rx							*/
+									/*	0 : Cannot accept indep. clc		*/
+									/*  1 : data with indep. clc accepted	*/
+
+    L3UCHAR FlowCtlTx;              /* Flow control on Tx                   */
+									/*  0 : Send Flow ctrl not required		*/
+									/*  1 : Send flow ctrl required			*/
+
+    L3UCHAR FlowCtlRx;              /* Flow control on Rx                   */
+									/*  0 : cannot use receive flow ctrl	*/
+									/*  1 : Receive flow ctrl accepted		*/
+    L3UCHAR HDR;					/* HDR/No HDR							*/
+    L3UCHAR MultiFrame;             /* Multi frame support                  */
+									/*  0 : multiframe not supported		*/
+									/*  1 : multiframe supported			*/
+
+	L3UCHAR ModeL1;					/* Mode L1								*/
+									/*	0 : bit transparent mode of operat.	*/
+									/*	1 : protocol sesitive mode of op.	*/
+
+    L3UCHAR NegotLLI;               /* Negot. LLI                           */
+									/*  0 : default LLI=256 only			*/
+									/*  1 : Full protocol negotiation		*/
+
+    L3UCHAR Assignor;               /* Assignor/Assignor ee                 */
+									/*  0 : Default Asignee					*/
+									/*  1 : Assignor only					*/
+
+    L3UCHAR InBandNeg;              /* In-band negot.                       */
+									/*  0 : negot done w/ USER INFO mes		*/
+									/*  1 : negot done in-band w/link zero	*/
+
+    L3UCHAR NumStopBits;            /* Number of stop bits					*/
+									/*  00 : Not used						*/
+									/*  01 : 1 bit							*/
+									/*  10 : 1.5 bits						*/
+									/*  11 : 2 bits							*/
+
+    L3UCHAR NumDataBits;            /* Number of data bits.                 */
+									/*  00 : not used						*/
+									/*  01 : 5 bits							*/
+									/*  10 : 7 bits							*/
+									/*  11 : 8 bits							*/
+
+    L3UCHAR Parity;					/* Parity Information					*/
+									/*	000 : Odd							*/
+									/*  010 : Even							*/
+									/*  011 : None							*/
+									/*  100 : Forced to 0					*/
+									/*  101 : Forced to 1					*/
+
+    L3UCHAR DuplexMode;				/* Mode duplex							*/
+									/*  0 : Half duplex						*/
+									/*  1 : Full duplex						*/
+
+    L3UCHAR ModemType;				/* Modem type, see Q.931 p 89			*/
+
+    L3UCHAR Layer2Ident;            /* Layer 2 ident.                       */
+
+    L3UCHAR UIL2Prot;               /* User information layer 2 protocol    */
+                                    /*  00001 : Basic mode ISO 1745         */
+									/*	00010 : Q.921/I.441					*/
+									/*  00110 : X.25 single link			*/
+                                    /*  00111 : X.25 multilink              */
+                                    /*  01000 : Extended LAPB T.71          */
+                                    /*  01001 : HDLC ARM                    */
+                                    /*  01010 : HDLC NRM                    */
+                                    /*  01011 : HDLC ABM                    */
+									/*  01100 : LAN logical link			*/
+                                    /*  01101 : X.75 SLP                    */
+                                    /*  01110 : Q.922                       */
+                                    /*  01111 : Q.922 core aspect           */
+                                    /*  10000 : User specified              */
+                                    /*  10001 : ISO/IEC 7776 DTE-DCE        */
+
+    L3UCHAR ModeL2;                 /* Mode                                 */
+									/*	01 : Normal Mode of operation    	*/
+									/*	10 : Extended mode of operation  	*/
+
+    L3UCHAR Q933use;                /* Q.9333 use                           */
+
+    L3UCHAR UsrSpcL2Prot;           /* User specified layer 2 protocol info */
+
+    L3UCHAR WindowSize;             /* Window size (k)                      */
+
+    L3UCHAR Layer3Ident;            /* Layer 3 ident                        */
+
+    L3UCHAR UIL3Prot;				/* User Information Layer 3 protocol	*/
+									/*	00010 : Q.931						*/
+									/*  00110 : X.25						*/
+                                    /*  00111 : 8208                        */
+                                    /*  01000 : X.233 ...                   */
+                                    /*  01001 : 6473                        */
+                                    /*  01010 : T.70                        */
+									/*  01011 : ISO/IEC TR 9577				*/
+                                    /*  10000 : User specified              */
+    L3UCHAR OptL3Info;              /* Optional Leyer 3 info                */
+
+    L3UCHAR ModeL3;                 /* Mode of operation                    */
+                                    /*  01 : Normal packed seq. numbering   */
+                                    /*  10 : Extended packed seq. numbering */
+
+    L3UCHAR DefPackSize;            /* Default packet size                  */
+
+    L3UCHAR PackWinSize;            /* Packet window size                   */
+
+    L3UCHAR AddL3Info;              /* Additional Layer 3 protocol info     */
+
+} Q931ie_LLComp;
+
+/*****************************************************************************
+
+  Struct:       Q931ie_NetFac;
+
+  Description:  Network-specific facilities
+
+*****************************************************************************/
+
+typedef struct {
+
+    L3UCHAR IEId;                   /* 00100000                             */
+    L3UCHAR Size;                   /* Length of Information Element        */
+    L3UCHAR LenNetID;               /* Length of network facilities id.     */
+    L3UCHAR TypeNetID;              /* Type of network identification       */
+    L3UCHAR NetIDPlan;              /* Network identification plan.         */
+    L3UCHAR NetFac;                 /* Network specific facility spec.      */
+    L3UCHAR NetID[1];               /* Network id. (IA5)                    */
+
+} Q931ie_NetFac;
+
+/*****************************************************************************
+
+  Struct:       Q931ie_NotifInd;
+
+  Description:  Notification Indicator
+
+*****************************************************************************/
+
+typedef struct {
+
+    L3UCHAR IEId;                   /* 00100000                             */
+    L3UCHAR Size;                   /* Length of Information Element        */
+	L3UCHAR Notification;			/* Notification descriptor				*/
+
+} Q931ie_NotifInd;
+
+/*****************************************************************************
+
+  Struct:       Q931ie_ProgInd
+
+  Description:  Progress indicator
+
+*****************************************************************************/
+
+typedef struct {
+
+    L3UCHAR IEId;                   /* 00011110                             */
+    L3UCHAR Size;                   /* Length of Information Element        */
+    L3UCHAR CodStand;               /* Coding standard                      */
+    L3UCHAR Location;               /* Location                             */
+    L3UCHAR ProgDesc;               /* Progress description                 */
+
+} Q931ie_ProgInd;
+
+/*****************************************************************************
+
+  Struct;       Q931ie_Segment
+
+  Description:  Segmented message
+
+*****************************************************************************/
+
+typedef struct {
+
+    L3UCHAR IEId;                   /* 00000000                             */
+    L3UCHAR Size;                   /* Length of Information Element        */
+    L3UCHAR FSI;                    /* First segment indicator              */
+    L3UCHAR NumSegRem;              /* Number of segments remaining         */
+    L3UCHAR SegType;                /* Segment message type                 */
+
+} Q931ie_Segment;
+
+
+typedef struct {
+
+    L3UCHAR IEId;                   /* 00000000                             */
+    L3UCHAR Size;                   /* Length of Information Element        */
+
+} Q931ie_SendComplete;
+
+/*****************************************************************************
+
+  Struct:       Q931ie_Signal
+
+  Description:  Signal
+
+*****************************************************************************/
+
+typedef struct {
+
+    L3UCHAR IEId;                   /* 00000000                             */
+    L3UCHAR Size;                   /* Length of Information Element        */
+    L3UCHAR Signal;                 /* Signal value                         */
+                                    /*  00000000    Dial tone on            */
+                                    /*  00000001    Ring back tone on       */
+                                    /*  00000010    Intercept tone on       */
+                                    /*  00000011    Network congestion on   */
+                                    /*  00000100    Busy tone on            */
+                                    /*  00000101    Confirm tone on         */
+                                    /*  00000110    Answer tone on          */
+                                    /*  00000111    Call waiting tone       */
+                                    /*  00001000    Off-hook warning tone   */
+                                    /*  00001001    Pre-emption tone on     */
+                                    /*  00111111    Tones off               */
+                                    /*  01000000    Alerting on - pattern 0 */
+                                    /*  01000001    Alerting on - pattern 1 */
+                                    /*  01000010    Alerting on - pattern 2 */
+                                    /*  01000011    Alerting on - pattern 3 */
+                                    /*  01000100    Alerting on - pattern 4 */
+                                    /*  01000101    Alerting on - pattern 5 */
+                                    /*  01000110    Alerting on - pattern 6 */
+                                    /*  01000111    Alerting on - pattern 7 */
+                                    /*  01001111    Alerting off            */
+} Q931ie_Signal;
+
+/*****************************************************************************
+
+  Struct:       Q931ie_TransDelSelInd
+
+  description:  Transit delay selection and indication
+
+*****************************************************************************/
+#ifdef Q931_X25_SUPPORT
+typedef struct {
+
+    L3UCHAR IEId;                   /* 00000000                             */
+    L3UCHAR Size;                   /* Length of Information Element        */
+    L3ULONG TxDSIValue;             /* Trans. delay sel. & ind. value       */ 
+
+} Q931ie_TransDelSelInd;
+#endif
+
+/*****************************************************************************
+
+  Struct:       Q931ie_TransNetSel
+
+  Description:  Transit network selection
+
+*****************************************************************************/
+
+typedef struct {
+
+    L3UCHAR IEId;                   /* 01111000                             */
+    L3UCHAR Size;                   /* Length of Information Element        */
+    L3UCHAR Type;                   /* Type of network identifier           */
+    L3UCHAR NetIDPlan;              /* Network idetification plan           */
+    L3UCHAR NetID[1];               /* Network identification(IA5)          */
+
+} Q931ie_TransNetSel;
+
+/*****************************************************************************
+
+  Struct:       Q931ie_UserUser
+
+  Description:  User-user
+
+*****************************************************************************/
+
+typedef struct {
+
+    L3UCHAR IEId;                   /* 01111110                             */
+    L3UCHAR Size;                   /* Length of Information Element        */
+    L3UCHAR ProtDisc;               /* Protocol discriminator               */
+    L3UCHAR User[1];                /* User information                     */
+
+} Q931ie_UserUser;
+
+/*****************************************************************************
+
+  Struct:       Q931ie_ClosedUserGrp
+
+  Description:  Closed user group
+
+*****************************************************************************/
+#ifdef Q931_X25_SUPPORT
+typedef struct {
+
+    L3UCHAR IEId;                   /* 01000111                             */
+    L3UCHAR Size;                   /* Length of Information Element        */
+    L3UCHAR CUGInd;                 /* CUG indication                       */
+    L3UCHAR CUG[1];                 /* CUG index code (IA5)                 */
+
+} Q931ie_ClosedUserGrp;
+#endif
+
+/*****************************************************************************
+
+  Struct:		Q931ie_CongLevel
+
+  Description:	Congestion Level
+
+*****************************************************************************/
+typedef struct {
+
+    L3UCHAR IEId;                   /* 01000111                             */
+    L3UCHAR Size;                   /* Length of Information Element        */
+	L3UCHAR CongLevel;				/* Conguestion Level					*/
+
+} Q931ie_CongLevel;
+
+/*****************************************************************************
+
+  Struct:       Q931ie_EndEndTxDelay
+
+  Description:  End to end transit delay
+
+*****************************************************************************/
+#ifdef Q931_X25_SUPPORT
+typedef struct {
+
+    L3UCHAR IEId;                   /* 01000010                             */
+    L3UCHAR Size;                   /* Length of Information Element        */
+    L3ULONG CumTxDelay;             /* Cumulative transit delay value       */
+    L3ULONG ReqTxDelay;             /* Requested end to end transit delay   */
+    L3ULONG MaxTxDelay;             /* Maximum transit delay                */
+
+} Q931ie_EndEndTxDelay;
+#endif
+
+/*****************************************************************************
+
+  Struct:       Q931ie_InfoRate
+
+  Description:  Information Rate
+
+*****************************************************************************/
+#ifdef Q931_X25_SUPPORT
+typedef struct {
+
+    L3UCHAR IEId;                   /* 01100000                             */
+    L3UCHAR Size;                   /* Length of Information Element        */
+    L3UCHAR InInfoRate;             /* Incoming information rate            */
+    L3UCHAR OutInfoRate;            /* Outgoing information rate            */
+    L3UCHAR MinInInfoRate;          /* Minimum incoming information rate    */
+    L3UCHAR MinOutInfoRate;         /* Minimum outgoing information rate    */
+
+} Q931ie_InfoRate;
+#endif
+
+/*****************************************************************************
+
+  Struct:       Q931ie_PackParam
+
+  Description:  Packed layer binary parameters
+
+*****************************************************************************/
+#ifdef Q931_X25_SUPPORT
+typedef struct {
+
+    L3UCHAR IEId;                   /* 01000100                             */
+    L3UCHAR Size;                   /* Length of Information Element        */
+    L3UCHAR FastSel;                /* Fast selected                        */
+    L3UCHAR ExpData;                /* Exp. data                            */
+    L3UCHAR DelConf;                /* Delivery conf                        */
+    L3UCHAR Modulus;                /* Modulus                              */
+
+} Q931ie_PackParam;
+#endif
+
+/*****************************************************************************
+
+  Struct:       Q931ie_PackWinSize
+
+  Description:  Packed window size
+
+*****************************************************************************/
+#ifdef Q931_X25_SUPPORT
+typedef struct {
+
+    L3UCHAR IEId;                   /* 01000101                             */
+    L3UCHAR Size;                   /* Length of Information Element        */
+    L3UCHAR ForwardValue;           /* Forward value                        */
+    L3UCHAR BackwardValue;          /* Backward value                       */
+
+} Q931ie_PackWinSize;
+#endif
+
+/*****************************************************************************
+
+  Struct:       Q931ie_PackSize
+
+  Description:  Packet size
+
+*****************************************************************************/
+#ifdef Q931_X25_SUPPORT
+typedef struct {
+
+    L3UCHAR IEId;                   /* 01000110                             */
+    L3UCHAR Size;                   /* Length of Information Element        */
+    L3UCHAR ForwardValue;           /* Forward value                        */
+    L3UCHAR BackwardValue;          /* Backward value                       */
+
+} Q931ie_PackSize;
+#endif
+
+/*****************************************************************************
+
+  Struct:       Q931ie_RedirNum
+
+  Description:  Redirecting number
+
+*****************************************************************************/
+#ifdef Q931_X25_SUPPORT
+typedef struct {
+
+    L3UCHAR IEId;                   /* 01110100                             */
+    L3UCHAR Size;                   /* Length of Information Element        */
+    L3UCHAR TypeNum;                /* Type of number                       */
+    L3UCHAR NumPlanID;              /* Number plan identification           */
+    L3UCHAR PresInd;                /* Presentation indicator               */
+    L3UCHAR ScreenInd;              /* Screening indicator                  */
+    L3UCHAR Reason;                 /* Reason for redirection               */
+    L3UCHAR Digit[1];               /* Number digits (IA5)                  */
+
+} Q931ie_RedirNum;
+#endif
+
+typedef struct {
+
+    L3UCHAR IEId;                   /* 01110100                             */
+    L3UCHAR Size;                   /* Length of Information Element        */
+    L3UCHAR RepeatInd;              /* 0010 Prioritized list for selecting  */
+                                    /* one possible.                        */
+} Q931ie_RepeatInd;
+
+typedef struct {
+
+    L3UCHAR IEId;                   /* 01110100                             */
+    L3UCHAR Size;                   /* Length of Information Element        */
+    L3UCHAR Spare;                  /* Spare                                */
+    L3UCHAR Class;                  /* Class                                */
+                                    /*  000 Indicate channels               */
+                                    /*  110 Single interface                */
+                                    /*  111 All interfaces                  */
+} Q931ie_RestartInd;
+
+typedef struct {
+
+    L3UCHAR IEId;                   /* 01110100                             */
+    L3UCHAR Size;                   /* Length of Information Element        */
+	L3UCHAR Preference;             /* Preference 0 = reserved, 1 = channel */
+	L3UCHAR Spare;                  /* Spare                                */
+    L3UCHAR NewStatus;              /* NewStatus                            */
+                                    /*  000 In service                      */
+                                    /*  001 Maintenance                     */
+                                    /*  010 Out of service                  */
+} Q931ie_ChangeStatus;
+
+/*****************************************************************************
+
+  Struct:       Q931ie_GenericDigits
+
+
+*****************************************************************************/
+
+typedef struct {
+
+    L3UCHAR IEId;                   /* 00110111                             */
+    L3UCHAR Size;                   /* Length of Information Element        */
+    L3UCHAR Type;					/* Type of number                       */
+    L3UCHAR Encoding;				/* Encoding of number                   */
+    L3UCHAR Digit[1];				/* Number digits (IA5)                  */
+
+} Q931ie_GenericDigits;
+
+
+/*****************************************************************************
+
+  Q.931 Information Element Pack/Unpack functions. Implemented in Q931ie.c
+
+*****************************************************************************/
+q931pie_func_t Q931Pie_ChangeStatus;
+q931pie_func_t Q931Pie_BearerCap;
+q931pie_func_t Q931Pie_ChanID;
+q931pie_func_t Q931Pie_ProgInd;
+q931pie_func_t Q931Pie_Display;
+q931pie_func_t Q931Pie_Signal;
+q931pie_func_t Q931Pie_HLComp;
+q931pie_func_t Q931Pie_Segment;
+q931pie_func_t Q931Pie_DateTime;
+q931pie_func_t Q931Pie_Cause;
+q931pie_func_t Q931Pie_SendComplete;
+q931pie_func_t Q931Pie_KeypadFac;
+q931pie_func_t Q931Pie_NotifInd;
+q931pie_func_t Q931Pie_CallID;
+q931pie_func_t Q931Pie_RepeatInd;
+q931pie_func_t Q931Pie_NetFac;
+q931pie_func_t Q931Pie_CallingNum;
+q931pie_func_t Q931Pie_CallingSub;
+q931pie_func_t Q931Pie_CalledNum;
+q931pie_func_t Q931Pie_CalledSub;
+q931pie_func_t Q931Pie_CalledNum;
+q931pie_func_t Q931Pie_TransNetSel;
+q931pie_func_t Q931Pie_LLComp;
+q931pie_func_t Q931Pie_CallState;
+q931pie_func_t Q931Pie_RestartInd;
+q931pie_func_t Q931Pie_UserUser;
+
+q931pie_func_t Q931Pie_GenericDigits;
+
+L3USHORT Q931Uie_CRV(Q931_TrunkInfo_t *pTrunk,L3UCHAR * IBuf, L3UCHAR *OBuf, L3INT *IOff, L3INT *OOff);
+
+q931uie_func_t Q931Uie_ChangeStatus;
+q931uie_func_t Q931Uie_BearerCap;
+q931uie_func_t Q931Uie_ChanID;
+q931uie_func_t Q931Uie_ProgInd;
+q931uie_func_t Q931Uie_Display;
+q931uie_func_t Q931Uie_Signal;
+q931uie_func_t Q931Uie_HLComp;
+q931uie_func_t Q931Uie_Segment;
+q931uie_func_t Q931Uie_DateTime;
+q931uie_func_t Q931Uie_Cause;
+q931uie_func_t Q931Uie_SendComplete;
+q931uie_func_t Q931Uie_KeypadFac;
+q931uie_func_t Q931Uie_NotifInd;
+q931uie_func_t Q931Uie_CallID;
+q931uie_func_t Q931Uie_RepeatInd;
+q931uie_func_t Q931Uie_NetFac;
+q931uie_func_t Q931Uie_CallingNum;
+q931uie_func_t Q931Uie_CallingSub;
+q931uie_func_t Q931Uie_CalledNum;
+q931uie_func_t Q931Uie_CalledSub;
+q931uie_func_t Q931Uie_TransNetSel;
+q931uie_func_t Q931Uie_LLComp;
+q931uie_func_t Q931Uie_CallState;
+q931uie_func_t Q931Uie_RestartInd;
+q931uie_func_t Q931Uie_UserUser;
+
+q931uie_func_t Q931Uie_GenericDigits;
+
+
+L3INT Q931ReadExt(L3UCHAR * IBuf, L3INT Off);
+L3INT Q931Uie_CongLevel(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff);
+L3INT Q931Pie_CongLevel(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet);
+L3INT Q931Uie_RevChargeInd(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff);
+L3INT Q931Pie_RevChargeInd(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet);
+
+L3INT Q931Uie_Generic(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *IOff, L3INT *OOff);
+L3INT Q931Pie_Generic(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet);
+
+#endif /* _Q931IE_NL */

Added: freeswitch/trunk/libs/freetdm/src/isdn/include/Q932.h (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/isdn/include/Q932.h	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/isdn/include/Q932.h	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,95 @@
+/*****************************************************************************
+
+  FileName:		Q932.h
+
+  Contents:		Header w/structs for Q932 Suplementary Services.
+
+  NB:			Do NOT include this header directly, include Q931.h
+
+  License/Copyright:
+
+  Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+  email:janvb@caselaboratories.com  
+
+  Redistribution and use in source and binary forms, with or without 
+  modification, are permitted provided that the following conditions are 
+  met:
+
+    * Redistributions of source code must retain the above copyright notice, 
+	  this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright notice, 
+	  this list of conditions and the following disclaimer in the documentation 
+	  and/or other materials provided with the distribution.
+    * Neither the name of the Case Labs, Ltd nor the names of its contributors 
+	  may be used to endorse or promote products derived from this software 
+	  without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
+  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
+  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+  POSSIBILITY OF SUCH DAMAGE.
+*****************************************************************************/
+
+/*****************************************************************************
+  Q.932 Additional Message codes
+*****************************************************************************/
+
+#define Q932mes_HOLD                 0x24 /* 0010 0100                      */
+#define Q932mes_HOLD_ACKNOWLEDGE     0x28 /* 0010 1000                      */
+#define Q932mes_HOLD_REJECT          0x30 /* 0011 0000                      */
+#define Q932mes_RETRIEVE             0x31 /* 0011 0001                      */
+#define Q932mes_RETRIEVE_ACKNOWLEDGE 0x33 /* 0011 0011                      */
+#define Q932mes_RETRIEVE_REJECT      0x37 /* 0011 0111                      */
+#define Q932mes_FACILITY             0x62 /* 0110 0010                      */
+#define Q932mes_REGISTER             0x64 /* 0110 0100                      */
+
+/*****************************************************************************
+  Q.932 Additional EI Codes
+*****************************************************************************/
+#define Q932ie_FACILITY              0x1c /* 0001 1100                      */
+
+/*****************************************************************************
+  Function Prototypes.
+*****************************************************************************/
+L3INT Q932ProcFacilityTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * b, L3INT iFrom);
+L3INT Q932ProcHoldTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * b, L3INT iFrom);
+L3INT Q932ProcHoldAckTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * b, L3INT iFrom);
+L3INT Q932ProcHoldRejectTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * b, L3INT iFrom);
+L3INT Q932ProcRegisterTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * b, L3INT iFrom);
+L3INT Q932ProcRetrieveTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * b, L3INT iFrom);
+L3INT Q932ProcRetrieveAckTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * b, L3INT iFrom);
+L3INT Q932ProcRetrieveRejectTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * b, L3INT iFrom);
+
+L3INT Q932ProcFacilityNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * b, L3INT iFrom);
+L3INT Q932ProcHoldNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * b, L3INT iFrom);
+L3INT Q932ProcHoldAckNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * b, L3INT iFrom);
+L3INT Q932ProcHoldRejectNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * b, L3INT iFrom);
+L3INT Q932ProcRegisterNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * b, L3INT iFrom);
+L3INT Q932ProcRetrieveNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * b, L3INT iFrom);
+L3INT Q932ProcRetrieveAckNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * b, L3INT iFrom);
+L3INT Q932ProcRetrieveRejectNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * b, L3INT iFrom);
+
+L3INT Q932Pmes_Facility(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q932Pmes_Hold(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q932Pmes_HoldAck(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q932Pmes_HoldReject(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q932Pmes_Register(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q932Pmes_Retrieve(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q932Pmes_RetrieveAck(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q932Pmes_RetrieveReject(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+
+L3INT Q932Umes_Facility(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic * OBuf, L3INT I, L3INT O);
+L3INT Q932Umes_Hold(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic * OBuf, L3INT I, L3INT O);
+L3INT Q932Umes_HoldAck(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic * OBuf, L3INT I, L3INT O);
+L3INT Q932Umes_HoldReject(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic * OBuf, L3INT I, L3INT O);
+L3INT Q932Umes_Register(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic * OBuf, L3INT I, L3INT O);
+L3INT Q932Umes_Retrieve(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic * OBuf, L3INT I, L3INT O);
+L3INT Q932Umes_RetrieveAck(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic * OBuf, L3INT I, L3INT O);
+L3INT Q932Umes_RetrieveReject(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic * OBuf, L3INT I, L3INT O);

Added: freeswitch/trunk/libs/freetdm/src/isdn/include/mfifo.h (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/isdn/include/mfifo.h	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/isdn/include/mfifo.h	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,85 @@
+/*****************************************************************************
+
+  Filename:     mfifo.h
+
+  Contents:     header for MFIFO
+
+  License/Copyright:
+
+  Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+  email:janvb@caselaboratories.com  
+
+  Redistribution and use in source and binary forms, with or without 
+  modification, are permitted provided that the following conditions are 
+  met:
+
+    * Redistributions of source code must retain the above copyright notice, 
+	  this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright notice, 
+	  this list of conditions and the following disclaimer in the documentation 
+	  and/or other materials provided with the distribution.
+    * Neither the name of the Case Labs, Ltd nor the names of its contributors 
+	  may be used to endorse or promote products derived from this software 
+	  without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
+  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
+  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+  POSSIBILITY OF SUCH DAMAGE.
+*****************************************************************************/
+#ifndef _MFIFO
+#define _MFIFO
+
+/*****************************************************************************
+
+  Struct:		MINDEX
+
+  Description:	Message Index used to index a dynamic size Message FIFO.
+
+*****************************************************************************/
+typedef struct _mindex {
+    int offset;                     /* offset to message in buf             */
+    int size;                       /* size of message in bytes             */
+} MINDEX;
+
+/*****************************************************************************
+
+  Struct:		MFIFO
+
+  Description:	Message FIFO. Provides a dynamic sized message based FIFO
+				queue.
+
+*****************************************************************************/
+typedef struct {
+	int first;                      /* first out                            */
+	int last;                       /* last in + 1                          */
+	int bsize;                      /* buffer size                          */
+	unsigned char *buf;             /* ptr to start of buffer               */
+	int ixsize;                     /* index size                           */
+	MINDEX ix[1];                   /* message index                        */
+} MFIFO;
+
+/*****************************************************************************
+  Function prototypes.
+*****************************************************************************/
+int MFIFOCreate(unsigned char *buf, int size, int index);
+void MFIFOClear(unsigned char * buf);
+int MFIFOGetLBOffset(unsigned char *buf);
+int MFIFOGetFBOffset(unsigned char *buf);
+void MFIFOWriteIX(unsigned char *buf, unsigned char *mes, int size, int ix, int off);
+int MFIFOWriteMes(unsigned char *buf, unsigned char *mes, int size);
+unsigned char * MFIFOGetMesPtr(unsigned char *buf, int *size);
+void MFIFOKillNext(unsigned char *buf);
+
+unsigned char * MFIFOGetMesPtrOffset(unsigned char *buf, int *size, const int pos);
+int MFIFOGetMesCount(unsigned char *buf);
+int MFIFOWriteMesOverwrite(unsigned char *buf, unsigned char *mes, int size);
+
+#endif

Added: freeswitch/trunk/libs/freetdm/src/isdn/include/national.h (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/isdn/include/national.h	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/isdn/include/national.h	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,86 @@
+/******************************************************************************
+
+  FileName:         national.h
+
+  Contents:         Header and definition for the National ISDN dialect. The 
+                    header contents the following parts:
+                    - Definition of codes
+                    - Definition of information elements (nationalie_).
+                    - Definition of messages (nationalmes_).
+                    - Function prototypes.
+
+  Description:      The National ISDN dialect here covers ????
+
+  Related Files:	national.h			National ISDN Definitions
+			nationalie.c			National ISDN IE encoders/coders
+			nationalStateTE.c		National ISDN TE State Engine
+			nationalStateNT.c		National ISDN NT State Engine
+
+  License/Copyright:
+
+  Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+  email:janvb@caselaboratories.com  
+
+  Copyright (c) 2007, Michael Jerris. All rights reserved.
+  email:mike@jerris.com  
+
+  Redistribution and use in source and binary forms, with or without 
+  modification, are permitted provided that the following conditions are 
+  met:
+
+    * Redistributions of source code must retain the above copyright notice, 
+	  this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright notice, 
+	  this list of conditions and the following disclaimer in the documentation 
+	  and/or other materials provided with the distribution.
+    * Neither the name of the Case Labs, Ltd nor the names of its contributors 
+	  may be used to endorse or promote products derived from this software 
+	  without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
+  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
+  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+  POSSIBILITY OF SUCH DAMAGE.
+******************************************************************************/
+
+#ifndef _national_NATIONAL_NL
+#define _national_NATIONAL_NL
+
+#include "Q931.h"
+
+/*****************************************************************************
+
+  Q.931 Message codes
+  Only National specific message and ie types 
+  here the rest are inherited from national.h
+  
+*****************************************************************************/
+
+
+/*****************************************************************************
+
+  Q.931 Message Pack/Unpack functions. Implemented in nationalmes.c
+
+*****************************************************************************/
+L3INT nationalUmes_Setup(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT IOff, L3INT Size);
+L3INT nationalPmes_Setup(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+
+#include "DMS.h"
+
+/*****************************************************************************
+
+  Q.931 Process Function Prototyping. Implemented in nationalStateTE.c
+
+*****************************************************************************/
+
+void nationalCreateTE(L3UCHAR i);
+void nationalCreateNT(L3UCHAR i);
+
+#endif /* _national_NATIONAL_NL */

Added: freeswitch/trunk/libs/freetdm/src/isdn/mfifo.c (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/isdn/mfifo.c	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/isdn/mfifo.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,399 @@
+/*****************************************************************************
+
+  Filename:	 mfifo.c
+
+  Description:  mfifo is a message orriented fifo system with support of
+				both message and byte per byte retriaval of messages.
+
+				The fifo has been designed with two usages in mind:
+
+				-   Queueing of frames for hdlc and feeding out byte per byte
+					with the possibility of re-sending of frames etc. 
+
+				- fifo for messages of dynamic size.
+
+				The fifo is allocated on top of any buffer and creates an
+				index of message in the queue. The user can write/read
+				messages or write messages and read the message one byte
+				at the time.
+
+  Interface:	
+				MFIFOCreate		 Create/reset/initialize fifo.
+				MFIFOClear		  Clear FIFO.
+				MFIFOWriteMes	   Write message into fifo
+				* MFIFOReadMes		Read message from fifo.
+				MFIFOGetMesPtr	  Get ptr to next message.
+				MFIFOKillNext	   Kill next message.
+
+				* currently not implemented.
+
+  Note:		 The message will always be saved continuously. If there is not
+				sufficient space at the end of the buffer, the fifo will skip
+				the last bytes and save the message at the top of the buffer.
+
+				This is required to allow direct ptr access to messages 
+				stored in the queue.
+
+  License/Copyright:
+
+  Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+  email:janvb@caselaboratories.com  
+
+  Redistribution and use in source and binary forms, with or without 
+  modification, are permitted provided that the following conditions are 
+  met:
+
+	* Redistributions of source code must retain the above copyright notice, 
+	  this list of conditions and the following disclaimer.
+	* Redistributions in binary form must reproduce the above copyright notice, 
+	  this list of conditions and the following disclaimer in the documentation 
+	  and/or other materials provided with the distribution.
+	* Neither the name of the Case Labs, Ltd nor the names of its contributors 
+	  may be used to endorse or promote products derived from this software 
+	  without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
+  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
+  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+  POSSIBILITY OF SUCH DAMAGE.
+*****************************************************************************/
+
+#include "mfifo.h"
+#include <memory.h>
+#include <stdlib.h>
+
+/*****************************************************************************
+
+  Function:	 MFIFOCreate
+
+  Description:  Creates a fifo on top of an existing buffer.
+
+  Parameters:   buf	 ptr to buffer.
+				size	size of buffer in bytes.
+				index   size of index entries (max no messages).
+
+  Return value: 0 if failure, 1 if ok.
+
+*****************************************************************************/
+int MFIFOCreate(unsigned char *buf, int size, int index)
+{
+	MFIFO *mf = (MFIFO *)buf;
+	
+	mf->first = mf->last = 0;
+	mf->ixsize = index;
+	mf->buf = &buf[sizeof(MFIFO) + (sizeof(MINDEX) * index)];
+
+	if (mf->buf > &buf[size])
+		return 0;
+
+	mf->bsize = size - sizeof(MFIFO) - (sizeof(MINDEX) * index);
+
+	return 1;
+}
+
+/*****************************************************************************
+
+  Function:	 MFIFOClear
+
+  Description:  Clear the FIFO
+
+  Paremeters:   buf	 ptr to fifo
+
+  Return Value: none
+
+*****************************************************************************/
+void MFIFOClear(unsigned char * buf)
+{
+	MFIFO *mf = (MFIFO *)buf;
+
+	mf->first = mf->last = 0;
+}
+
+/*****************************************************************************
+
+  Function:	 MFIFOGetLBOffset
+
+  Description:  Helper function caclulating offset to the 'first out' byte.
+
+  Paremeters:   buf	 ptr to fifo
+
+  Return Value: offset.
+
+*****************************************************************************/
+int MFIFOGetLBOffset(unsigned char *buf)
+{
+	MFIFO *mf = (MFIFO *)buf;
+
+	if (mf->last != mf->first)
+		return mf->ix[mf->last].offset;
+	
+	return 0;
+}
+
+/*****************************************************************************
+
+  Function:	 MFIFOGetFBOffset
+
+  Description:  Helper function calculating the offset to the 'first in' 
+				byte in the buffer. This is the position the next byte
+				entering the fifo will occupy.
+
+  Paremeters:   buf	 ptr to fifo
+
+  Return Value: offset
+
+*****************************************************************************/
+int MFIFOGetFBOffset(unsigned char *buf)
+{
+	MFIFO *mf = (MFIFO *)buf;
+	int x;
+
+	if (mf->last == mf->first)
+		return 0;
+
+	x = mf->first - 1;
+
+	if (x < 0)
+		x = mf->ixsize - 1;
+
+	return mf->ix[x].offset + mf->ix[x].size;
+}
+
+/*****************************************************************************
+
+  Function:	 MFIFOWriteIX
+
+  Description:  Helper function writing a calculated entry. The function
+				will perform a memcpy to move the message and set the index
+				values as well as increase the 'first in' index.
+
+  Paremeters:   buf	 ptr to fifo
+				mes	 ptr to message
+				size	size of message in bytes.
+				ix	  index to index entry.
+				off	 offset to position to receive the message
+
+  Return Value: none
+
+*****************************************************************************/
+void MFIFOWriteIX(unsigned char *buf, unsigned char *mes, int size, int ix, int off)
+{
+	MFIFO *mf = (MFIFO *)buf;
+	int x;
+
+	memcpy(&mf->buf[off], mes, size);
+	mf->ix[ix].offset = off;
+	mf->ix[ix].size = size;
+
+	x = mf->first + 1;
+
+	if (x >= mf->ixsize)
+		x = 0;
+
+	mf->first = x;
+}
+
+/*****************************************************************************
+
+  Function:	 MFIFOWriteMes
+
+  Description:  
+
+  Paremeters:
+
+  Return Value:
+
+*****************************************************************************/
+int MFIFOWriteMes(unsigned char *buf, unsigned char *mes, int size)
+{
+	MFIFO *mf = (MFIFO *)buf;
+	int of, ol, x;
+
+	x = mf->first + 1;
+
+	if (x >= mf->ixsize)
+		x = 0;
+
+	if (x == mf->last)
+		return 0; /* full queue */
+
+	of = MFIFOGetFBOffset(buf);
+	ol = MFIFOGetLBOffset(buf);
+	if (mf->last == mf->first) { /* empty queue */
+		mf->first = mf->last = 0; /* optimize */
+
+		MFIFOWriteIX(buf, mes, size, mf->first, 0);
+		return 1;
+	}
+	else if (of > ol) {
+		if (mf->bsize - of >= size) {
+			MFIFOWriteIX(buf, mes, size, mf->first, of);
+			return 1;
+		}
+		else if (ol > size) {
+			MFIFOWriteIX(buf, mes, size, mf->first, ol);
+			return 1;
+		}
+	}
+	else if (ol - of > size) {
+			MFIFOWriteIX(buf, mes, size, mf->first, of);
+			return 1;
+	}
+
+	return 0;
+}
+
+/*****************************************************************************
+
+  Function:	 MFIFOGetMesPtr
+
+  Description:  
+
+  Paremeters:
+
+  Return Value:
+
+*****************************************************************************/
+unsigned char * MFIFOGetMesPtr(unsigned char *buf, int *size)
+{
+	MFIFO *mf = (MFIFO *)buf;
+
+	if (mf->first == mf->last) {
+		return NULL;
+	}
+
+	*size = mf->ix[mf->last].size;
+	return &mf->buf[mf->ix[mf->last].offset];
+}
+
+/*****************************************************************************
+
+  Function:	 MFIFOKillNext
+
+  Description:  
+
+  Paremeters:
+
+  Return Value:
+
+*****************************************************************************/
+void MFIFOKillNext(unsigned char *buf)
+{
+	MFIFO *mf = (MFIFO *)buf;
+	int x;
+
+	if (mf->first != mf->last) {
+		x = mf->last + 1;
+		if (x >= mf->ixsize) {
+			x = 0;
+		}
+
+		mf->last = x;
+	}
+}
+
+
+/*
+ * Queue-style accessor functions
+ */
+
+/**
+ * MFIFOGetMesPtrOffset
+ * \brief	Get pointer to and size of message at position x
+ */
+unsigned char * MFIFOGetMesPtrOffset(unsigned char *buf, int *size, const int pos)
+{
+	MFIFO *mf = (MFIFO *)buf;
+	int x;
+
+	if (mf->first == mf->last) {
+		return NULL;
+	}
+
+	if (pos < 0 || pos >= mf->ixsize) {
+		return NULL;
+	}
+
+	x = pos - mf->last;
+	if (x < 0) {
+		x += (mf->ixsize - 1);
+	}
+
+	*size = mf->ix[x].size;
+	return &mf->buf[mf->ix[x].offset];
+}
+
+
+/**
+ * MFIFOGetMesCount
+ * \brief	How many messages are currently in the buffer?
+ */
+int MFIFOGetMesCount(unsigned char *buf)
+{
+	MFIFO *mf = (MFIFO *)buf;
+
+	if (mf->first == mf->last) {
+		return 0;
+	}
+	else if (mf->first > mf->last) {
+		return mf->first - mf->last;
+	}
+	else {
+		return (mf->ixsize - mf->last) + mf->first;
+	}
+}
+
+/**
+ * MFIFOWriteMesOverwrite
+ * \brief	Same as MFIFOWriteMes but old frames will be overwritten if the fifo is full
+ */
+int MFIFOWriteMesOverwrite(unsigned char *buf, unsigned char *mes, int size)
+{
+	MFIFO *mf = (MFIFO *)buf;
+	int of, ol, x;
+
+	x = mf->first + 1;
+
+	if (x >= mf->ixsize)
+		x = 0;
+
+	if (x == mf->last) {
+		/* advance last pointer */
+		mf->last++;
+
+		if (mf->last >= mf->ixsize)
+			mf->last = 0;
+	}
+
+	of = MFIFOGetFBOffset(buf);
+	ol = MFIFOGetLBOffset(buf);
+
+	if (mf->last == mf->first) {	/* empty queue */
+		mf->first = mf->last = 0;	/* optimize */
+
+		MFIFOWriteIX(buf, mes, size, mf->first, 0);
+		return 1;
+	}
+	else if (of > ol) {
+		if (mf->bsize - of >= size) {
+			MFIFOWriteIX(buf, mes, size, mf->first, of);
+			return 1;
+		}
+		else if (ol > size) {
+			MFIFOWriteIX(buf, mes, size, mf->first, ol);
+			return 1;
+		}
+	}
+	else if (ol - of > size) {
+		MFIFOWriteIX(buf, mes, size, mf->first, of);
+		return 1;
+	}
+	return 0;
+}

Added: freeswitch/trunk/libs/freetdm/src/isdn/nationalStateNT.c (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/isdn/nationalStateNT.c	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/isdn/nationalStateNT.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,130 @@
+/*****************************************************************************
+
+  FileName:		nationalStateNT.c
+
+  Contents:		National ISDN State Engine for NT (Network Mode).
+
+			The controlling state engine for Q.931 is the state engine
+			on the NT side. The state engine on the TE side is a slave 
+			of this. The TE side maintain it's own states as described in
+			ITU-T Q931, but will in	raise conditions be overridden by 
+			the NT side.
+
+  License/Copyright:
+
+  Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+  email:janvb@caselaboratories.com  
+
+  Copyright (c) 2007, Michael Jerris. All rights reserved.
+  email:mike@jerris.com  
+
+  Redistribution and use in source and binary forms, with or without 
+  modification, are permitted provided that the following conditions are 
+  met:
+
+	* Redistributions of source code must retain the above copyright notice, 
+	  this list of conditions and the following disclaimer.
+	* Redistributions in binary form must reproduce the above copyright notice, 
+	  this list of conditions and the following disclaimer in the documentation 
+	  and/or other materials provided with the distribution.
+	* Neither the name of the Case Labs, Ltd nor the names of its contributors 
+	  may be used to endorse or promote products derived from this software 
+	  without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
+  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
+  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+  POSSIBILITY OF SUCH DAMAGE.
+*****************************************************************************/
+
+#include "national.h"
+
+/*****************************************************************************
+  Function:		nationalCreateNT
+
+  Description:	Will create the National ISDN NT as a Dialect in the stack. The first
+				bulk set up the message handlers, the second bulk the IE
+				encoders/coders, and the last bulk set up the state table.
+
+  Parameters:	i		Dialect index
+*****************************************************************************/
+void nationalCreateNT(L3UCHAR i)
+{
+	Q931SetMesProc(Q931mes_ALERTING,             i, Q931ProcAlertingNT,          Q931Umes_Alerting,          Q931Pmes_Alerting);
+	Q931SetMesProc(Q931mes_CALL_PROCEEDING,      i, Q931ProcCallProceedingNT,    Q931Umes_CallProceeding,    Q931Pmes_CallProceeding);
+	Q931SetMesProc(Q931mes_CONNECT,              i, Q931ProcConnectNT,           Q931Umes_Connect,           Q931Pmes_Connect);
+	Q931SetMesProc(Q931mes_CONNECT_ACKNOWLEDGE,  i, Q931ProcConnectAckNT,        Q931Umes_ConnectAck,        Q931Pmes_ConnectAck);
+	Q931SetMesProc(Q931mes_PROGRESS,             i, Q931ProcProgressNT,          Q931Umes_Progress,          Q931Pmes_Progress);
+	Q931SetMesProc(Q931mes_SETUP,                i, Q931ProcSetupNT,             nationalUmes_Setup,         nationalPmes_Setup);
+	Q931SetMesProc(Q931mes_SETUP_ACKNOWLEDGE,    i, Q931ProcSetupAckNT,          Q931Umes_SetupAck,          Q931Pmes_SetupAck);
+	Q931SetMesProc(Q931mes_RESUME,               i, Q931ProcResumeNT,            Q931Umes_Resume,            Q931Pmes_Resume);
+	Q931SetMesProc(Q931mes_RESUME_ACKNOWLEDGE,   i, Q931ProcResumeAckNT,         Q931Umes_ResumeAck,         Q931Pmes_ResumeAck);
+	Q931SetMesProc(Q931mes_RESUME_REJECT,        i, Q931ProcResumeRejectNT,      Q931Umes_ResumeReject,      Q931Pmes_ResumeReject);
+	Q931SetMesProc(Q931mes_SUSPEND,              i, Q931ProcSuspendNT,           Q931Umes_Suspend,           Q931Pmes_Suspend);
+	Q931SetMesProc(Q931mes_SUSPEND_ACKNOWLEDGE,  i, Q931ProcSuspendAckNT,        Q931Umes_SuspendAck,        Q931Pmes_SuspendAck);
+	Q931SetMesProc(Q931mes_SUSPEND_REJECT,       i, Q931ProcSuspendRejectNT,     Q931Umes_SuspendReject,     Q931Pmes_SuspendReject);
+	Q931SetMesProc(Q931mes_USER_INFORMATION,     i, Q931ProcUserInformationNT,   Q931Umes_UserInformation,   Q931Pmes_UserInformation);
+	Q931SetMesProc(Q931mes_DISCONNECT,           i, Q931ProcDisconnectNT,        Q931Umes_Disconnect,        Q931Pmes_Disconnect);
+	Q931SetMesProc(Q931mes_RELEASE,              i, Q931ProcReleaseNT,           Q931Umes_Release,           Q931Pmes_Release);
+	Q931SetMesProc(Q931mes_RELEASE_COMPLETE,     i, Q931ProcReleaseCompleteNT,   Q931Umes_ReleaseComplete,   Q931Pmes_ReleaseComplete);
+	Q931SetMesProc(Q931mes_RESTART,              i, Q931ProcRestartNT,           Q931Umes_Restart,           Q931Pmes_Restart);
+	Q931SetMesProc(Q931mes_RESTART_ACKNOWLEDGE,  i, Q931ProcRestartAckNT,        Q931Umes_RestartAck,        Q931Pmes_RestartAck);
+	Q931SetMesProc(Q931mes_CONGESTION_CONTROL,   i, Q931ProcCongestionControlNT, Q931Umes_CongestionControl, Q931Pmes_CongestionControl);
+	Q931SetMesProc(Q931mes_INFORMATION,          i, Q931ProcInformationNT,       Q931Umes_Information,       Q931Pmes_Information);
+	Q931SetMesProc(Q931mes_NOTIFY,               i, Q931ProcNotifyNT,            Q931Umes_Notify,            Q931Pmes_Notify);
+	Q931SetMesProc(Q931mes_STATUS,               i, Q931ProcStatusNT,            Q931Umes_Status,            Q931Pmes_Status);
+	Q931SetMesProc(Q931mes_STATUS_ENQUIRY,       i, Q931ProcStatusEnquiryNT,     Q931Umes_StatusEnquiry,     Q931Pmes_StatusEnquiry);
+	Q931SetMesProc(Q931mes_SEGMENT,              i, Q931ProcSegmentNT,           Q931Umes_Segment,           Q931Pmes_Segment);
+
+	Q931SetMesProc(Q932mes_FACILITY,             i, Q932ProcFacilityNT,          Q932Umes_Facility,          Q932Pmes_Facility);
+	Q931SetMesProc(Q932mes_HOLD,                 i, Q932ProcHoldNT,              Q932Umes_Hold,              Q932Pmes_Hold);
+	Q931SetMesProc(Q932mes_HOLD_ACKNOWLEDGE,     i, Q932ProcHoldAckNT,           Q932Umes_HoldAck,           Q932Pmes_HoldAck);
+	Q931SetMesProc(Q932mes_HOLD_REJECT,          i, Q932ProcHoldRejectNT,        Q932Umes_HoldReject,        Q932Pmes_HoldReject);
+	Q931SetMesProc(Q932mes_REGISTER,             i, Q932ProcRegisterNT,          Q932Umes_Register,          Q932Pmes_Register);
+	Q931SetMesProc(Q932mes_RETRIEVE,             i, Q932ProcRetrieveNT,          Q932Umes_Retrieve,          Q932Pmes_Retrieve);
+	Q931SetMesProc(Q932mes_RETRIEVE_ACKNOWLEDGE, i, Q932ProcRetrieveAckNT,       Q932Umes_RetrieveAck,       Q932Pmes_RetrieveAck);
+	Q931SetMesProc(Q932mes_RETRIEVE_REJECT,      i, Q932ProcRetrieveRejectNT,    Q932Umes_RetrieveReject,    Q932Pmes_RetrieveReject);
+
+	/* Set up the IE encoder/decoder handle table.*/ 
+	Q931SetIEProc(Q931ie_SEGMENTED_MESSAGE,                i, Q931Pie_Segment,       Q931Uie_Segment);
+	Q931SetIEProc(Q931ie_BEARER_CAPABILITY,                i, Q931Pie_BearerCap,     Q931Uie_BearerCap);
+	Q931SetIEProc(Q931ie_CAUSE,                            i, Q931Pie_Cause,         Q931Uie_Cause);
+	Q931SetIEProc(Q931ie_CALL_IDENTITY,                    i, Q931Pie_CallID,        Q931Uie_CallID);
+	Q931SetIEProc(Q931ie_CALL_STATE,                       i, Q931Pie_CallState,     Q931Uie_CallState);
+	Q931SetIEProc(Q931ie_CHANNEL_IDENTIFICATION,           i, Q931Pie_ChanID,        Q931Uie_ChanID);
+	Q931SetIEProc(Q931ie_PROGRESS_INDICATOR,               i, Q931Pie_ProgInd,       Q931Uie_ProgInd);
+	Q931SetIEProc(Q931ie_NETWORK_SPECIFIC_FACILITIES,      i, Q931Pie_NetFac,        Q931Uie_NetFac);
+	Q931SetIEProc(Q931ie_NOTIFICATION_INDICATOR,           i, Q931Pie_NotifInd,      Q931Uie_NotifInd);
+	Q931SetIEProc(Q931ie_DISPLAY,                          i, Q931Pie_Display,       Q931Uie_Display);
+	Q931SetIEProc(Q931ie_DATETIME,                         i, Q931Pie_DateTime,      Q931Uie_DateTime);
+	Q931SetIEProc(Q931ie_KEYPAD_FACILITY,                  i, Q931Pie_KeypadFac,     Q931Uie_KeypadFac);
+	Q931SetIEProc(Q931ie_SIGNAL,                           i, Q931Pie_Signal,        Q931Uie_Signal);
+	Q931SetIEProc(Q931ie_TRANSIT_DELAY_SELECTION_AND_IND,  i, Q931Pie_TransNetSel,   Q931Uie_TransNetSel);
+	Q931SetIEProc(Q931ie_CALLING_PARTY_NUMBER,             i, Q931Pie_CallingNum,    Q931Uie_CallingNum);
+	Q931SetIEProc(Q931ie_CALLING_PARTY_SUBADDRESS,         i, Q931Pie_CallingSub,    Q931Uie_CallingSub);
+	Q931SetIEProc(Q931ie_CALLED_PARTY_NUMBER,              i, Q931Pie_CalledNum,     Q931Uie_CalledNum);
+	Q931SetIEProc(Q931ie_CALLED_PARTY_SUBADDRESS,          i, Q931Pie_CalledSub,     Q931Uie_CalledSub);
+	Q931SetIEProc(Q931ie_TRANSIT_NETWORK_SELECTION,        i, Q931Pie_TransNetSel,   Q931Uie_TransNetSel);
+	Q931SetIEProc(Q931ie_RESTART_INDICATOR,                i, Q931Pie_RestartInd,    Q931Uie_RestartInd);
+	Q931SetIEProc(Q931ie_LOW_LAYER_COMPATIBILITY,          i, Q931Pie_LLComp,        Q931Uie_LLComp);
+	Q931SetIEProc(Q931ie_HIGH_LAYER_COMPATIBILITY,         i, Q931Pie_HLComp,        Q931Uie_HLComp);
+	Q931SetIEProc(Q931ie_USER_USER,                        i, Q931Pie_UserUser,      Q931Uie_UserUser);
+	Q931SetIEProc(Q931ie_GENERIC_DIGITS,                   i, Q931Pie_GenericDigits, Q931Uie_GenericDigits);
+
+	Q931SetIEProc(Q931ie_CONNECTED_NUMBER, i, Q931Pie_Generic, Q931Uie_Generic);
+	Q931SetIEProc(Q931ie_FACILITY,         i, Q931Pie_Generic, Q931Uie_Generic);
+	Q931SetIEProc(Q931ie_REDIRECTING_NUMBER, i, Q931Pie_Generic, Q931Uie_Generic);
+
+	/* The following define a state machine. The point is that the Message	*/
+	/* procs can when search this to find out if the message/state			*/
+	/* combination is legale. If not, the proc for unexpected message apply.*/
+
+	/* TODO define state table here */
+}

Added: freeswitch/trunk/libs/freetdm/src/isdn/nationalStateTE.c (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/isdn/nationalStateTE.c	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/isdn/nationalStateTE.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,217 @@
+/*****************************************************************************
+
+  FileName:		nationalStateTE.c
+
+  Contents:		National ISDN State Engine for TE (User Mode).
+
+			The controlling state engine for Q.931 is the state engine
+			on the NT side. The state engine on the TE side is a slave 
+			of this. The TE side maintain it's own states as described in
+			ITU-T Q931, but will in	raise conditions be overridden by 
+			the NT side.
+
+			This reference implementation uses a process per message,
+			meaning that each message must check call states. This
+			is easier for dialect maintenance as each message proc
+			can be replaced individually. A new TE variant only
+			need to copy the Q931CreateTE and replace those procs or
+			need to override.
+
+  License/Copyright:
+
+  Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+  email:janvb@caselaboratories.com  
+
+  Copyright (c) 2007, Michael Jerris. All rights reserved.
+  email:mike@jerris.com  
+
+  Redistribution and use in source and binary forms, with or without 
+  modification, are permitted provided that the following conditions are 
+  met:
+
+	* Redistributions of source code must retain the above copyright notice, 
+	  this list of conditions and the following disclaimer.
+	* Redistributions in binary form must reproduce the above copyright notice, 
+	  this list of conditions and the following disclaimer in the documentation 
+	  and/or other materials provided with the distribution.
+	* Neither the name of the Case Labs, Ltd nor the names of its contributors 
+	  may be used to endorse or promote products derived from this software 
+	  without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
+  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
+  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+  POSSIBILITY OF SUCH DAMAGE.
+*****************************************************************************/
+
+#include "national.h"
+extern L3INT Q931L4HeaderSpace;
+
+/*****************************************************************************
+  Function:		nationalCreateTE
+
+  Description:	Will create the National TE as a Dialect in the stack. The first
+				bulk set up the message handlers, the second bulk the IE
+				encoders/coders, and the last bulk set up the state table.
+
+  Parameters:	i		Dialect index
+*****************************************************************************/
+void nationalCreateTE(L3UCHAR i)
+{
+	Q931SetMesProc(Q931mes_ALERTING,             i, Q931ProcAlertingTE,          Q931Umes_Alerting,          Q931Pmes_Alerting);
+	Q931SetMesProc(Q931mes_CALL_PROCEEDING,      i, Q931ProcCallProceedingTE,    Q931Umes_CallProceeding,    Q931Pmes_CallProceeding);
+	Q931SetMesProc(Q931mes_CONNECT,              i, DMSProc0x07TE,               DMSUmes_0x07,               DMSPmes_0x07);
+	Q931SetMesProc(Q931mes_CONNECT_ACKNOWLEDGE,  i, DMSProc0x0fTE,               DMSUmes_0x0f,               DMSPmes_0x0f);
+	Q931SetMesProc(Q931mes_PROGRESS,             i, Q931ProcProgressTE,          Q931Umes_Progress,          Q931Pmes_Progress);
+	Q931SetMesProc(Q931mes_SETUP,                i, Q931ProcSetupTE,             nationalUmes_Setup,         nationalPmes_Setup);
+	Q931SetMesProc(Q931mes_SETUP_ACKNOWLEDGE,    i, Q931ProcSetupAckTE,          Q931Umes_SetupAck,          Q931Pmes_SetupAck);
+	Q931SetMesProc(Q931mes_RESUME,               i, Q931ProcResumeTE,            Q931Umes_Resume,            Q931Pmes_Resume);
+	Q931SetMesProc(Q931mes_RESUME_ACKNOWLEDGE,   i, Q931ProcResumeAckTE,         Q931Umes_ResumeAck,         Q931Pmes_ResumeAck);
+	Q931SetMesProc(Q931mes_RESUME_REJECT,        i, Q931ProcResumeRejectTE,      Q931Umes_ResumeReject,      Q931Pmes_ResumeReject);
+	Q931SetMesProc(Q931mes_SUSPEND,              i, Q931ProcSuspendTE,           Q931Umes_Suspend,           Q931Pmes_Suspend);
+	Q931SetMesProc(Q931mes_SUSPEND_ACKNOWLEDGE,  i, Q931ProcSuspendAckTE,        Q931Umes_SuspendAck,        Q931Pmes_SuspendAck);
+	Q931SetMesProc(Q931mes_SUSPEND_REJECT,       i, Q931ProcSuspendRejectTE,     Q931Umes_SuspendReject,     Q931Pmes_SuspendReject);
+	Q931SetMesProc(Q931mes_USER_INFORMATION,     i, Q931ProcUserInformationTE,   Q931Umes_UserInformation,   Q931Pmes_UserInformation);
+	Q931SetMesProc(Q931mes_DISCONNECT,           i, Q931ProcDisconnectTE,        Q931Umes_Disconnect,        Q931Pmes_Disconnect);
+	Q931SetMesProc(Q931mes_RELEASE,              i, Q931ProcReleaseTE,           Q931Umes_Release,           Q931Pmes_Release);
+	Q931SetMesProc(Q931mes_RELEASE_COMPLETE,     i, Q931ProcReleaseCompleteTE,   Q931Umes_ReleaseComplete,   Q931Pmes_ReleaseComplete);
+	Q931SetMesProc(Q931mes_RESTART,              i, Q931ProcRestartTE,           Q931Umes_Restart,           Q931Pmes_Restart);
+	Q931SetMesProc(Q931mes_RESTART_ACKNOWLEDGE,  i, Q931ProcRestartAckTE,        Q931Umes_RestartAck,        Q931Pmes_RestartAck);
+	Q931SetMesProc(Q931mes_CONGESTION_CONTROL,   i, Q931ProcCongestionControlTE, Q931Umes_CongestionControl, Q931Pmes_CongestionControl);
+	Q931SetMesProc(Q931mes_INFORMATION,          i, Q931ProcInformationTE,       Q931Umes_Information,       Q931Pmes_Information);
+	Q931SetMesProc(Q931mes_NOTIFY,               i, Q931ProcNotifyTE,            Q931Umes_Notify,            Q931Pmes_Notify);
+	Q931SetMesProc(Q931mes_STATUS,               i, Q931ProcStatusTE,            Q931Umes_Status,            Q931Pmes_Status);
+	Q931SetMesProc(Q931mes_STATUS_ENQUIRY,       i, Q931ProcStatusEnquiryTE,     Q931Umes_StatusEnquiry,     Q931Pmes_StatusEnquiry);
+	Q931SetMesProc(Q931mes_SEGMENT,              i, Q931ProcSegmentTE,           Q931Umes_Segment,           Q931Pmes_Segment);
+
+	Q931SetMesProc(Q932mes_FACILITY,             i, Q932ProcFacilityTE,          Q932Umes_Facility,          Q932Pmes_Facility);
+	Q931SetMesProc(Q932mes_HOLD,                 i, Q932ProcHoldTE,              Q932Umes_Hold,              Q932Pmes_Hold);
+	Q931SetMesProc(Q932mes_HOLD_ACKNOWLEDGE,     i, Q932ProcHoldAckTE,           Q932Umes_HoldAck,           Q932Pmes_HoldAck);
+	Q931SetMesProc(Q932mes_HOLD_REJECT,          i, Q932ProcHoldRejectTE,        Q932Umes_HoldReject,        Q932Pmes_HoldReject);
+	Q931SetMesProc(Q932mes_REGISTER,             i, Q932ProcRegisterTE,          Q932Umes_Register,          Q932Pmes_Register);
+	Q931SetMesProc(Q932mes_RETRIEVE,             i, Q932ProcRetrieveTE,          Q932Umes_Retrieve,          Q932Pmes_Retrieve);
+	Q931SetMesProc(Q932mes_RETRIEVE_ACKNOWLEDGE, i, Q932ProcRetrieveAckTE,       Q932Umes_RetrieveAck,       Q932Pmes_RetrieveAck);
+	Q931SetMesProc(Q932mes_RETRIEVE_REJECT,      i, Q932ProcRetrieveRejectTE,    Q932Umes_RetrieveReject,    Q932Pmes_RetrieveReject);
+
+	/* Set up the IE encoder/decoder handle table.*/ 
+	Q931SetIEProc(Q931ie_SEGMENTED_MESSAGE,                i, Q931Pie_Segment,       Q931Uie_Segment);
+	Q931SetIEProc(Q931ie_BEARER_CAPABILITY,                i, Q931Pie_BearerCap,     Q931Uie_BearerCap);
+	Q931SetIEProc(Q931ie_CAUSE,                            i, Q931Pie_Cause,         Q931Uie_Cause);
+	Q931SetIEProc(Q931ie_CALL_IDENTITY,                    i, Q931Pie_CallID,        Q931Uie_CallID);
+	Q931SetIEProc(Q931ie_CALL_STATE,                       i, Q931Pie_CallState,     Q931Uie_CallState);
+	Q931SetIEProc(Q931ie_CHANGE_STATUS,                    i, Q931Pie_ChangeStatus,  Q931Uie_ChangeStatus);
+	Q931SetIEProc(Q931ie_CHANNEL_IDENTIFICATION,           i, Q931Pie_ChanID,        Q931Uie_ChanID);
+	Q931SetIEProc(Q931ie_PROGRESS_INDICATOR,               i, Q931Pie_ProgInd,       Q931Uie_ProgInd);
+	Q931SetIEProc(Q931ie_NETWORK_SPECIFIC_FACILITIES,      i, Q931Pie_NetFac,        Q931Uie_NetFac);
+	Q931SetIEProc(Q931ie_NOTIFICATION_INDICATOR,           i, Q931Pie_NotifInd,      Q931Uie_NotifInd);
+	Q931SetIEProc(Q931ie_DISPLAY,                          i, Q931Pie_Display,       Q931Uie_Display);
+	Q931SetIEProc(Q931ie_DATETIME,                         i, Q931Pie_DateTime,      Q931Uie_DateTime);
+	Q931SetIEProc(Q931ie_KEYPAD_FACILITY,                  i, Q931Pie_KeypadFac,     Q931Uie_KeypadFac);
+	Q931SetIEProc(Q931ie_SIGNAL,                           i, Q931Pie_Signal,        Q931Uie_Signal);
+	Q931SetIEProc(Q931ie_TRANSIT_DELAY_SELECTION_AND_IND,  i, Q931Pie_TransNetSel,   Q931Uie_TransNetSel);
+	Q931SetIEProc(Q931ie_CALLING_PARTY_NUMBER,             i, Q931Pie_CallingNum,    Q931Uie_CallingNum);
+	Q931SetIEProc(Q931ie_CALLING_PARTY_SUBADDRESS,         i, Q931Pie_CallingSub,    Q931Uie_CallingSub);
+	Q931SetIEProc(Q931ie_CALLED_PARTY_NUMBER,              i, Q931Pie_CalledNum,     Q931Uie_CalledNum);
+	Q931SetIEProc(Q931ie_CALLED_PARTY_SUBADDRESS,          i, Q931Pie_CalledSub,     Q931Uie_CalledSub);
+	Q931SetIEProc(Q931ie_TRANSIT_NETWORK_SELECTION,        i, Q931Pie_TransNetSel,   Q931Uie_TransNetSel);
+	Q931SetIEProc(Q931ie_RESTART_INDICATOR,                i, Q931Pie_RestartInd,    Q931Uie_RestartInd);
+	Q931SetIEProc(Q931ie_LOW_LAYER_COMPATIBILITY,          i, Q931Pie_LLComp,        Q931Uie_LLComp);
+	Q931SetIEProc(Q931ie_HIGH_LAYER_COMPATIBILITY,         i, Q931Pie_HLComp,        Q931Uie_HLComp);
+	Q931SetIEProc(Q931ie_USER_USER,                        i, Q931Pie_UserUser,      Q931Uie_UserUser);
+	Q931SetIEProc(Q931ie_GENERIC_DIGITS,                   i, Q931Pie_GenericDigits, Q931Uie_GenericDigits);
+
+	Q931SetIEProc(Q931ie_CONNECTED_NUMBER, i, Q931Pie_Generic, Q931Uie_Generic);
+	Q931SetIEProc(Q931ie_FACILITY,         i, Q931Pie_Generic, Q931Uie_Generic);
+	Q931SetIEProc(Q931ie_REDIRECTING_NUMBER, i, Q931Pie_Generic, Q931Uie_Generic);
+
+	/* The following define a state machine. The point is that the Message
+	 * procs can when search this to find out if the message/state
+	 * combination is legale. If not, the proc for unexpected message apply.
+	 */
+
+	/* State 0 Idle */
+	Q931AddStateEntry(i, Q931_U0, Q931mes_RESUME,           2);
+	Q931AddStateEntry(i, Q931_U0, Q931mes_SETUP,            4);
+	Q931AddStateEntry(i, Q931_U0, Q931mes_SETUP,            2);
+	Q931AddStateEntry(i, Q931_U0, Q931mes_STATUS,           4);
+	Q931AddStateEntry(i, Q931_U0, Q931mes_RELEASE,          4);
+	Q931AddStateEntry(i, Q931_U0, Q931mes_RELEASE_COMPLETE, 4);
+
+	/* State 1 Call Initiating */
+	Q931AddStateEntry(i, Q931_U1, Q931mes_DISCONNECT,        2);
+	Q931AddStateEntry(i, Q931_U1, Q931mes_SETUP_ACKNOWLEDGE, 4);
+	Q931AddStateEntry(i, Q931_U1, Q931mes_RELEASE_COMPLETE,  4);
+	Q931AddStateEntry(i, Q931_U1, Q931mes_CALL_PROCEEDING,   4);
+	Q931AddStateEntry(i, Q931_U1, Q931mes_ALERTING,          4);
+	Q931AddStateEntry(i, Q931_U1, Q931mes_CONNECT,           4);
+
+	/* State 2 Overlap Sending */
+	Q931AddStateEntry(i, Q931_U2, Q931mes_INFORMATION,     2);
+	Q931AddStateEntry(i, Q931_U2, Q931mes_CALL_PROCEEDING, 4);
+	Q931AddStateEntry(i, Q931_U2, Q931mes_ALERTING,        4);
+	Q931AddStateEntry(i, Q931_U2, Q931mes_PROGRESS,        4);
+	Q931AddStateEntry(i, Q931_U2, Q931mes_CONNECT,         4);
+	Q931AddStateEntry(i, Q931_U2, Q931mes_RELEASE,         2);
+
+	/* State 3 Outgoing Call Proceeding */
+	Q931AddStateEntry(i, Q931_U3, Q931mes_PROGRESS, 4);
+	Q931AddStateEntry(i, Q931_U3, Q931mes_ALERTING, 4);
+	Q931AddStateEntry(i, Q931_U3, Q931mes_CONNECT,  4);
+	Q931AddStateEntry(i, Q931_U3, Q931mes_RELEASE,  2);
+
+	/* State 4 Call Delivered */
+	Q931AddStateEntry(i, Q931_U4, Q931mes_CONNECT, 4);
+
+	/* State 6 Call Precent */
+	Q931AddStateEntry(i, Q931_U6, Q931mes_INFORMATION,      2);	
+	Q931AddStateEntry(i, Q931_U6, Q931mes_ALERTING,         2);	
+	Q931AddStateEntry(i, Q931_U6, Q931mes_CALL_PROCEEDING,  2);	
+	Q931AddStateEntry(i, Q931_U6, Q931mes_CONNECT,          2);	
+	Q931AddStateEntry(i, Q931_U6, Q931mes_RELEASE_COMPLETE, 2);	
+	Q931AddStateEntry(i, Q931_U6, Q931mes_RELEASE,          4);	
+	Q931AddStateEntry(i, Q931_U6, Q931mes_DISCONNECT,       4);	
+
+	/* State 7 Call Received */
+	Q931AddStateEntry(i, Q931_U7, Q931mes_CONNECT, 2);
+
+	/* State 8 Connect request */
+	Q931AddStateEntry(i, Q931_U8, Q931mes_CONNECT_ACKNOWLEDGE, 4);
+
+	/* State 9 Incoming Call Proceeding */
+	Q931AddStateEntry(i, Q931_U9, Q931mes_CONNECT,  2);
+	Q931AddStateEntry(i, Q931_U9, Q931mes_ALERTING, 2);
+	Q931AddStateEntry(i, Q931_U9, Q931mes_PROGRESS, 2);
+
+	/* State 10 Active */
+	Q931AddStateEntry(i, Q931_U10, Q931mes_SUSPEND, 2);
+	Q931AddStateEntry(i, Q931_U10, Q931mes_NOTIFY,  4);
+	Q931AddStateEntry(i, Q931_U10, Q931mes_NOTIFY,  2);
+
+	/* State 11 Disconnect Request */
+	Q931AddStateEntry(i, Q931_U11, Q931mes_RELEASE,    4);
+	Q931AddStateEntry(i, Q931_U11, Q931mes_DISCONNECT, 4);
+	Q931AddStateEntry(i, Q931_U11, Q931mes_NOTIFY,     4);
+
+	/* State 12 Disconnect Ind */
+	Q931AddStateEntry(i, Q931_U12, Q931mes_RELEASE, 4);
+	Q931AddStateEntry(i, Q931_U12, Q931mes_RELEASE, 2);
+
+	/* State 15 Suspend Request */
+	Q931AddStateEntry(i, Q931_U15, Q931mes_SUSPEND_ACKNOWLEDGE, 4);
+	Q931AddStateEntry(i, Q931_U15, Q931mes_SUSPEND_REJECT,      4);
+	Q931AddStateEntry(i, Q931_U15, Q931mes_DISCONNECT,          4);
+	Q931AddStateEntry(i, Q931_U15, Q931mes_RELEASE,             4);
+
+/* TODO
+	Q931AddStateEntry(i, Q931_U17,
+	Q931AddStateEntry(i, Q931_U19,
+	Q931AddStateEntry(i, Q931_U25,
+*/
+}

Added: freeswitch/trunk/libs/freetdm/src/isdn/nationalmes.c (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/isdn/nationalmes.c	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/isdn/nationalmes.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,269 @@
+/*****************************************************************************
+
+  FileName:	nationalmes.c
+
+  Contents:	Pack/Unpack functions. These functions will unpack a National ISDN
+		message from the bit packed original format into structs
+		that contains variables sized by the user. It will also pack
+		the struct back into a Q.931 message as required.
+
+		See national.h for description. 
+
+  License/Copyright:
+
+  Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+  email:janvb@caselaboratories.com  
+
+  Copyright (c) 2007, Michael Jerris. All rights reserved.
+  email:mike@jerris.com  
+
+  Redistribution and use in source and binary forms, with or without 
+  modification, are permitted provided that the following conditions are 
+  met:
+
+	* Redistributions of source code must retain the above copyright notice, 
+	  this list of conditions and the following disclaimer.
+	* Redistributions in binary form must reproduce the above copyright notice, 
+	  this list of conditions and the following disclaimer in the documentation 
+	  and/or other materials provided with the distribution.
+	* Neither the name of the Case Labs, Ltd nor the names of its contributors 
+	  may be used to endorse or promote products derived from this software 
+	  without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
+  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
+  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+  POSSIBILITY OF SUCH DAMAGE.
+
+*****************************************************************************/
+
+#include "national.h"
+
+/*****************************************************************************
+
+  Function:	 nationalUmes_Setup
+
+*****************************************************************************/
+L3INT nationalUmes_Setup(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+	L3INT ir = 0;
+	L3INT OOff = 0;
+	L3INT rc = Q931E_NO_ERROR;
+	L3UCHAR last_codeset = 0, codeset = 0;
+	L3UCHAR shift_lock = 1;
+
+	while (IOff < Size) {
+		if (!shift_lock) {
+			codeset = last_codeset;
+		}
+
+		if ((IBuf[IOff] & 0xF0) == Q931ie_SHIFT ) {
+			shift_lock = (IBuf[IOff] & 0x08);
+			if (shift_lock) {
+				last_codeset = codeset;
+			}
+			codeset = ((IBuf[IOff] & 0x07));
+			IOff++;
+		}
+
+		if (codeset == 0) {
+			switch (IBuf[IOff]) {
+			case Q931ie_SENDING_COMPLETE:
+			case Q931ie_BEARER_CAPABILITY:
+			case Q931ie_CHANNEL_IDENTIFICATION:
+			case Q931ie_PROGRESS_INDICATOR:
+			case Q931ie_NETWORK_SPECIFIC_FACILITIES:
+			case Q931ie_DISPLAY:
+			case Q931ie_DATETIME:
+			case Q931ie_KEYPAD_FACILITY:
+			case Q931ie_SIGNAL:
+			case Q931ie_CALLING_PARTY_NUMBER:
+			case Q931ie_CALLING_PARTY_SUBADDRESS:
+			case Q931ie_CALLED_PARTY_NUMBER:
+			case Q931ie_CALLED_PARTY_SUBADDRESS:
+			case Q931ie_TRANSIT_NETWORK_SELECTION:
+			case Q931ie_LOW_LAYER_COMPATIBILITY:
+			case Q931ie_HIGH_LAYER_COMPATIBILITY:
+			case Q931ie_FACILITY:
+			case Q931ie_REDIRECTING_NUMBER:
+				rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+				if (rc != Q931E_NO_ERROR)
+					return rc;
+				break;
+			case Q931ie_REPEAT_INDICATOR:
+				if (ir < 2) {
+					rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+					ir++;
+				} else {
+					return Q931E_ILLEGAL_IE;
+				}
+				break;
+			default:
+				return Q931E_ILLEGAL_IE;
+				break;
+			}
+		} else if (codeset == 6) {
+			switch (IBuf[IOff]) {
+			case Q931ie_GENERIC_DIGITS:
+				rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+				if (rc != Q931E_NO_ERROR) 
+					return rc;
+				break;
+			default:
+				return Q931E_ILLEGAL_IE;
+				break;
+			}
+
+		} else {
+			return Q931E_ILLEGAL_IE;
+		}
+	}
+	mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:	 nationalPmes_Setup
+
+  Decription:	Pack a Q931mes_Generic into a real Q.931 message. The user will
+				set up a SETUP message and issue this to the stack where it
+				is processed by Q931ProcSetup that processes and validates
+				it before it actually sends it out. This function is called
+				to compute the real Q.931 message.
+
+  Parameters:	IBuf[IN]	Ptr to un-packed struct
+				ISize[IN]	Size of input buffer (unpacked message).
+				OBuf[OUT]	Ptr to packed 'octet' wise message.
+				OSize[OUT]	Size of packed message.
+
+  Called By:	Q931ProcSetup
+
+*****************************************************************************/
+L3INT nationalPmes_Setup(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+	L3INT rc = Q931E_NO_ERROR;
+	Q931mes_Generic *pMes = (Q931mes_Generic *)IBuf;
+	L3INT Octet = 0;
+
+	/* Q931 Message Header */
+	Q931MesgHeader(pTrunk, pMes, OBuf, *OSize, &Octet);
+
+	/* Sending Complete */
+	if (Q931IsIEPresent(pMes->SendComplete)) {
+		OBuf[Octet++]	= (L3UCHAR)(pMes->SendComplete & 0x00ff);
+	}
+
+	/* Repeat Indicator */
+	if (Q931IsIEPresent(pMes->RepeatInd)) {
+		OBuf[Octet++]	= (L3UCHAR)(pMes->RepeatInd & 0x00ff);		
+	}
+
+	/* Bearer capability */
+	if (Q931IsIEPresent(pMes->BearerCap)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_BEARER_CAPABILITY](pTrunk, Q931GetIEPtr(pMes->BearerCap,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+	else {
+		rc = Q931E_BEARERCAP;
+	}
+
+	/* Channel Identification */
+	if (Q931IsIEPresent(pMes->ChanID)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CHANNEL_IDENTIFICATION](pTrunk, Q931GetIEPtr(pMes->ChanID,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Progress indicator */
+	if (Q931IsIEPresent(pMes->ProgInd)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_PROGRESS_INDICATOR](pTrunk, Q931GetIEPtr(pMes->ProgInd,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Network spesific facilities */
+	if (Q931IsIEPresent(pMes->NetFac)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_NETWORK_SPECIFIC_FACILITIES](pTrunk, Q931GetIEPtr(pMes->NetFac,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Display */
+	if (Q931IsIEPresent(pMes->Display)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_DISPLAY](pTrunk, Q931GetIEPtr(pMes->Display,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Date/Time */
+	if (Q931IsIEPresent(pMes->DateTime)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_DATETIME](pTrunk, Q931GetIEPtr(pMes->DateTime,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Keypad Facility */
+	if (Q931IsIEPresent(pMes->KeypadFac)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_KEYPAD_FACILITY](pTrunk, Q931GetIEPtr(pMes->KeypadFac,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Signal */
+	if (Q931IsIEPresent(pMes->Signal)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_SIGNAL](pTrunk, Q931GetIEPtr(pMes->Signal,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Calling Party Number */
+	if (Q931IsIEPresent(pMes->CallingNum)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CALLING_PARTY_NUMBER](pTrunk, Q931GetIEPtr(pMes->CallingNum,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Calling Party Subaddress */
+	if (Q931IsIEPresent(pMes->CallingSub)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CALLING_PARTY_SUBADDRESS](pTrunk, Q931GetIEPtr(pMes->CallingSub,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Called Party number */
+	if (Q931IsIEPresent(pMes->CalledNum)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CALLED_PARTY_NUMBER](pTrunk, Q931GetIEPtr(pMes->CalledNum,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Called party subaddress */
+	if (Q931IsIEPresent(pMes->CalledSub)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CALLED_PARTY_SUBADDRESS](pTrunk, Q931GetIEPtr(pMes->CalledSub,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Transit network selection */
+	if (Q931IsIEPresent(pMes->TransNetSel)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_TRANSIT_NETWORK_SELECTION](pTrunk, Q931GetIEPtr(pMes->TransNetSel,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Repeat Indicator */
+	if (Q931IsIEPresent(pMes->LLRepeatInd)) {
+		rc = Q931E_UNKNOWN_IE;/* TODO */
+	}
+
+	/* Low Layer Compatibility */
+	if (Q931IsIEPresent(pMes->LLComp)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_LOW_LAYER_COMPATIBILITY](pTrunk, Q931GetIEPtr(pMes->LLComp,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* High Layer Compatibility */
+	if (Q931IsIEPresent(pMes->HLComp)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_HIGH_LAYER_COMPATIBILITY](pTrunk, Q931GetIEPtr(pMes->HLComp,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	*OSize = Octet;	
+	return rc;
+}

Added: freeswitch/trunk/libs/freetdm/src/libteletone_detect.c (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/libteletone_detect.c	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/libteletone_detect.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,427 @@
+/* 
+ * libteletone
+ * Copyright (C) 2005/2006, Anthony Minessale II <anthmct@yahoo.com>
+ *
+ * Much less efficient expansion interface was added to allow for the detection of 
+ * a single arbitrary tone combination which may also exceed 2 simultaneous tones.
+ * (controlled by compile time constant TELETONE_MAX_TONES)
+ *
+ * Copyright (C) 2006 Anthony Minessale II <anthmct@yahoo.com>
+ *
+ * libteletone_detect.c Tone Detection Code
+ *
+ * Copyright (c) 2007, Anthony Minessale II
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.	 IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ********************************************************************************* 
+ *
+ * Derived from tone_detect.c - General telephony tone detection, and specific
+ * detection of DTMF.
+ *
+ * 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.
+ *
+ *
+ *
+ */
+
+#include <libteletone_detect.h>
+
+#ifndef _MSC_VER
+#include <stdint.h>
+#endif
+#include <string.h>
+#include <stdio.h>
+#include <time.h>
+#include <fcntl.h>
+
+
+static teletone_detection_descriptor_t dtmf_detect_row[GRID_FACTOR];
+static teletone_detection_descriptor_t dtmf_detect_col[GRID_FACTOR];
+static teletone_detection_descriptor_t dtmf_detect_row_2nd[GRID_FACTOR];
+static teletone_detection_descriptor_t dtmf_detect_col_2nd[GRID_FACTOR];
+
+static float dtmf_row[] = {697.0f,	770.0f,	 852.0f,  941.0f};
+static float dtmf_col[] = {1209.0f, 1336.0f, 1477.0f, 1633.0f};
+
+static char dtmf_positions[] = "123A" "456B" "789C" "*0#D";
+
+static void goertzel_init(teletone_goertzel_state_t *goertzel_state, teletone_detection_descriptor_t *tdesc) {
+	goertzel_state->v2 = goertzel_state->v3 = 0.0;
+	goertzel_state->fac = tdesc->fac;
+}
+
+TELETONE_API(void) teletone_goertzel_update(teletone_goertzel_state_t *goertzel_state,
+							  int16_t sample_buffer[],
+							  int samples)
+{
+	int i;
+	float v1;
+	
+	for (i = 0;	 i < samples;  i++) {
+		v1 = goertzel_state->v2;
+		goertzel_state->v2 = goertzel_state->v3;
+		goertzel_state->v3 = (float)(goertzel_state->fac*goertzel_state->v2 - v1 + sample_buffer[i]);
+	}
+}
+#ifdef _MSC_VER
+#pragma warning(disable:4244)
+#endif
+
+#define teletone_goertzel_result(gs) (double)(((gs)->v3 * (gs)->v3 + (gs)->v2 * (gs)->v2 - (gs)->v2 * (gs)->v3 * (gs)->fac))
+
+TELETONE_API(void) teletone_dtmf_detect_init (teletone_dtmf_detect_state_t *dtmf_detect_state, int sample_rate)
+{
+	int i;
+	float theta;
+
+	dtmf_detect_state->hit1 = dtmf_detect_state->hit2 = 0;
+
+	for (i = 0;	 i < GRID_FACTOR;  i++) {
+		theta = (float)(M_TWO_PI*(dtmf_row[i]/(float)sample_rate));
+		dtmf_detect_row[i].fac = (float)(2.0*cos(theta));
+
+		theta = (float)(M_TWO_PI*(dtmf_col[i]/(float)sample_rate));
+		dtmf_detect_col[i].fac = (float)(2.0*cos(theta));
+	
+		theta = (float)(M_TWO_PI*(dtmf_row[i]*2.0/(float)sample_rate));
+		dtmf_detect_row_2nd[i].fac = (float)(2.0*cos(theta));
+
+		theta = (float)(M_TWO_PI*(dtmf_col[i]*2.0/(float)sample_rate));
+		dtmf_detect_col_2nd[i].fac = (float)(2.0*cos(theta));
+	
+		goertzel_init (&dtmf_detect_state->row_out[i], &dtmf_detect_row[i]);
+		goertzel_init (&dtmf_detect_state->col_out[i], &dtmf_detect_col[i]);
+		goertzel_init (&dtmf_detect_state->row_out2nd[i], &dtmf_detect_row_2nd[i]);
+		goertzel_init (&dtmf_detect_state->col_out2nd[i], &dtmf_detect_col_2nd[i]);
+	
+		dtmf_detect_state->energy = 0.0;
+	}
+	dtmf_detect_state->current_sample = 0;
+	dtmf_detect_state->detected_digits = 0;
+	dtmf_detect_state->lost_digits = 0;
+	dtmf_detect_state->digits[0] = '\0';
+	dtmf_detect_state->mhit = 0;
+}
+
+TELETONE_API(void) teletone_multi_tone_init(teletone_multi_tone_t *mt, teletone_tone_map_t *map)
+{
+	float theta = 0;
+	int x = 0;
+
+	if (!mt->sample_rate) {
+		mt->sample_rate = 8000;
+	}
+
+	if (!mt->min_samples) {
+		mt->min_samples = 102;
+	}
+
+	mt->min_samples *= (mt->sample_rate / 8000);
+
+	if (!mt->positive_factor) {
+		mt->positive_factor = 2;
+	}
+
+	if(!mt->negative_factor) {
+		mt->negative_factor = 10;
+	}
+
+	if (!mt->hit_factor) {
+		mt->hit_factor = 2;
+	}
+
+	for(x = 0; x < TELETONE_MAX_TONES; x++) {
+		if ((int) map->freqs[x] == 0) {
+			break;
+		}
+		mt->tone_count++;
+		theta = (float)(M_TWO_PI*(map->freqs[x]/(float)mt->sample_rate));
+		mt->tdd[x].fac = (float)(2.0 * cos(theta));
+		goertzel_init (&mt->gs[x], &mt->tdd[x]);
+		goertzel_init (&mt->gs2[x], &mt->tdd[x]);
+	}
+
+}
+
+TELETONE_API(int) teletone_multi_tone_detect (teletone_multi_tone_t *mt,
+								int16_t sample_buffer[],
+								int samples)
+{
+	int sample, limit = 0, j, x = 0;
+	float v1, famp;
+	float eng_sum = 0, eng_all[TELETONE_MAX_TONES] = {0.0};
+	int gtest = 0, see_hit = 0;
+
+	for (sample = 0;  sample >= 0 && sample < samples; sample = limit) {
+		mt->total_samples++;
+
+		if ((samples - sample) >= (mt->min_samples - mt->current_sample)) {
+			limit = sample + (mt->min_samples - mt->current_sample);
+		} else {
+			limit = samples;
+		}
+		if (limit < 0 || limit > samples) {
+			limit = samples;
+		}
+
+		for (j = sample;  j < limit;  j++) {
+			famp = sample_buffer[j];
+			
+			mt->energy += famp*famp;
+
+			for(x = 0; x < TELETONE_MAX_TONES && x < mt->tone_count; x++) {
+				v1 = mt->gs[x].v2;
+				mt->gs[x].v2 = mt->gs[x].v3;
+				mt->gs[x].v3 = (float)(mt->gs[x].fac * mt->gs[x].v2 - v1 + famp);
+	
+				v1 = mt->gs2[x].v2;
+				mt->gs2[x].v2 = mt->gs2[x].v3;
+				mt->gs2[x].v3 = (float)(mt->gs2[x].fac*mt->gs2[x].v2 - v1 + famp);
+			}
+		}
+
+		mt->current_sample += (limit - sample);
+		if (mt->current_sample < mt->min_samples) {
+			continue;
+		}
+
+		eng_sum = 0;
+		for(x = 0; x < TELETONE_MAX_TONES && x < mt->tone_count; x++) {
+			eng_all[x] = (float)(teletone_goertzel_result (&mt->gs[x]));
+			eng_sum += eng_all[x];
+		}
+
+		gtest = 0;
+		for(x = 0; x < TELETONE_MAX_TONES && x < mt->tone_count; x++) {
+			gtest += teletone_goertzel_result (&mt->gs2[x]) < eng_all[x] ? 1 : 0;
+		}
+
+		if ((gtest >= 2 || gtest == mt->tone_count) && eng_sum > 42.0 * mt->energy) {
+			if(mt->negatives) {
+				mt->negatives--;
+			}
+			mt->positives++;
+
+			if(mt->positives >= mt->positive_factor) {
+				mt->hits++;
+			}
+			if (mt->hits >= mt->hit_factor) {
+				see_hit++;
+				mt->positives = mt->negatives = mt->hits = 0;
+			}
+		} else {
+			mt->negatives++;
+			if(mt->positives) {
+				mt->positives--;
+			}
+			if(mt->negatives > mt->negative_factor) {
+				mt->positives = mt->hits = 0;
+			}
+		}
+
+		/* Reinitialise the detector for the next block */
+		for(x = 0; x < TELETONE_MAX_TONES && x < mt->tone_count; x++) {
+			goertzel_init (&mt->gs[x], &mt->tdd[x]);
+			goertzel_init (&mt->gs2[x], &mt->tdd[x]);
+		}
+
+		mt->energy = 0.0;
+		mt->current_sample = 0;
+	}
+
+	return see_hit;
+}
+
+
+TELETONE_API(int) teletone_dtmf_detect (teletone_dtmf_detect_state_t *dtmf_detect_state,
+						  int16_t sample_buffer[],
+						  int samples)
+{
+	float row_energy[GRID_FACTOR];
+	float col_energy[GRID_FACTOR];
+	float famp;
+	float v1;
+	int i;
+	int j;
+	int sample;
+	int best_row;
+	int best_col;
+	char hit;
+	int limit;
+
+	hit = 0;
+	for (sample = 0;  sample < samples;	 sample = limit) {
+		/* BLOCK_LEN is optimised to meet the DTMF specs. */
+		if ((samples - sample) >= (BLOCK_LEN - dtmf_detect_state->current_sample)) {
+			limit = sample + (BLOCK_LEN - dtmf_detect_state->current_sample);
+		} else {
+			limit = samples;
+		}
+
+		for (j = sample;  j < limit;  j++) {
+			int x = 0;
+			famp = sample_buffer[j];
+			
+			dtmf_detect_state->energy += famp*famp;
+
+			for(x = 0; x < GRID_FACTOR; x++) {
+				v1 = dtmf_detect_state->row_out[x].v2;
+				dtmf_detect_state->row_out[x].v2 = dtmf_detect_state->row_out[x].v3;
+				dtmf_detect_state->row_out[x].v3 = (float)(dtmf_detect_state->row_out[x].fac*dtmf_detect_state->row_out[x].v2 - v1 + famp);
+	
+				v1 = dtmf_detect_state->col_out[x].v2;
+				dtmf_detect_state->col_out[x].v2 = dtmf_detect_state->col_out[x].v3;
+				dtmf_detect_state->col_out[x].v3 = (float)(dtmf_detect_state->col_out[x].fac*dtmf_detect_state->col_out[x].v2 - v1 + famp);
+
+				v1 = dtmf_detect_state->col_out2nd[x].v2;
+				dtmf_detect_state->col_out2nd[x].v2 = dtmf_detect_state->col_out2nd[x].v3;
+				dtmf_detect_state->col_out2nd[x].v3 = (float)(dtmf_detect_state->col_out2nd[x].fac*dtmf_detect_state->col_out2nd[x].v2 - v1 + famp);
+		
+				v1 = dtmf_detect_state->row_out2nd[x].v2;
+				dtmf_detect_state->row_out2nd[x].v2 = dtmf_detect_state->row_out2nd[x].v3;
+				dtmf_detect_state->row_out2nd[x].v3 = (float)(dtmf_detect_state->row_out2nd[x].fac*dtmf_detect_state->row_out2nd[x].v2 - v1 + famp);
+			}
+
+		}
+
+		dtmf_detect_state->current_sample += (limit - sample);
+		if (dtmf_detect_state->current_sample < BLOCK_LEN) {
+			continue;
+		}
+		/* We are at the end of a DTMF detection block */
+		/* Find the peak row and the peak column */
+		row_energy[0] = teletone_goertzel_result (&dtmf_detect_state->row_out[0]);
+		col_energy[0] = teletone_goertzel_result (&dtmf_detect_state->col_out[0]);
+
+		for (best_row = best_col = 0, i = 1;  i < GRID_FACTOR;	i++) {
+			row_energy[i] = teletone_goertzel_result (&dtmf_detect_state->row_out[i]);
+			if (row_energy[i] > row_energy[best_row]) {
+				best_row = i;
+			}
+			col_energy[i] = teletone_goertzel_result (&dtmf_detect_state->col_out[i]);
+			if (col_energy[i] > col_energy[best_col]) {
+				best_col = i;
+			}
+		}
+		hit = 0;
+		/* Basic signal level test and the twist test */
+		if (row_energy[best_row] >= DTMF_THRESHOLD &&
+			col_energy[best_col] >= DTMF_THRESHOLD &&
+			col_energy[best_col] < row_energy[best_row]*DTMF_REVERSE_TWIST &&
+			col_energy[best_col]*DTMF_NORMAL_TWIST > row_energy[best_row]) {
+			/* Relative peak test */
+			for (i = 0;	 i < GRID_FACTOR;  i++) {
+				if ((i != best_col	&&	col_energy[i]*DTMF_RELATIVE_PEAK_COL > col_energy[best_col]) ||
+					(i != best_row	&&	row_energy[i]*DTMF_RELATIVE_PEAK_ROW > row_energy[best_row])) {
+					break;
+				}
+			}
+			/* ... and second harmonic test */
+			if (i >= GRID_FACTOR && (row_energy[best_row] + col_energy[best_col]) > 42.0*dtmf_detect_state->energy &&
+				teletone_goertzel_result (&dtmf_detect_state->col_out2nd[best_col])*DTMF_2ND_HARMONIC_COL < col_energy[best_col] &&
+				teletone_goertzel_result (&dtmf_detect_state->row_out2nd[best_row])*DTMF_2ND_HARMONIC_ROW < row_energy[best_row]) {
+				hit = dtmf_positions[(best_row << 2) + best_col];
+				/* 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 == dtmf_detect_state->hit3	&&	dtmf_detect_state->hit3 != dtmf_detect_state->hit2) {
+					dtmf_detect_state->mhit = hit;
+					dtmf_detect_state->digit_hits[(best_row << 2) + best_col]++;
+					dtmf_detect_state->detected_digits++;
+					if (dtmf_detect_state->current_digits < TELETONE_MAX_DTMF_DIGITS) {
+						dtmf_detect_state->digits[dtmf_detect_state->current_digits++] = hit;
+						dtmf_detect_state->digits[dtmf_detect_state->current_digits] = '\0';
+					}
+					else
+						{
+							dtmf_detect_state->lost_digits++;
+						}
+				}
+			}
+		}
+		dtmf_detect_state->hit1 = dtmf_detect_state->hit2;
+		dtmf_detect_state->hit2 = dtmf_detect_state->hit3;
+		dtmf_detect_state->hit3 = hit;
+		/* Reinitialise the detector for the next block */
+		for (i = 0;	 i < GRID_FACTOR;  i++) {
+			goertzel_init (&dtmf_detect_state->row_out[i], &dtmf_detect_row[i]);
+			goertzel_init (&dtmf_detect_state->col_out[i], &dtmf_detect_col[i]);
+			goertzel_init (&dtmf_detect_state->row_out2nd[i], &dtmf_detect_row_2nd[i]);
+			goertzel_init (&dtmf_detect_state->col_out2nd[i], &dtmf_detect_col_2nd[i]);
+		}
+		dtmf_detect_state->energy = 0.0;
+		dtmf_detect_state->current_sample = 0;
+	}
+	if ((!dtmf_detect_state->mhit) || (dtmf_detect_state->mhit != hit)) {
+		dtmf_detect_state->mhit = 0;
+		return(0);
+	}
+	return (hit);
+}
+
+
+TELETONE_API(int) teletone_dtmf_get (teletone_dtmf_detect_state_t *dtmf_detect_state,
+					   char *buf,
+					   int max)
+{
+	teletone_assert(dtmf_detect_state->current_digits <= TELETONE_MAX_DTMF_DIGITS);
+
+	if (max > dtmf_detect_state->current_digits) {
+		max = dtmf_detect_state->current_digits;
+	}
+	if (max > 0) {
+		memcpy (buf, dtmf_detect_state->digits, max);
+		memmove (dtmf_detect_state->digits, dtmf_detect_state->digits + max, dtmf_detect_state->current_digits - max);
+		dtmf_detect_state->current_digits -= max;
+	}
+	buf[max] = '\0';
+	return	max;
+}
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */

Added: freeswitch/trunk/libs/freetdm/src/libteletone_generate.c (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/libteletone_generate.c	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/libteletone_generate.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,452 @@
+/* 
+ * libteletone_generate.c -- Tone Generator
+ *
+ * Copyright (c) 2007, Anthony Minessale II
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.	 IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <libteletone.h>
+#include "freetdm.h"
+
+#define SMAX 32767
+#define SMIN -32768
+#define normalize_to_16bit(n) if (n > SMAX) n = SMAX; else if (n < SMIN) n = SMIN;
+
+#ifdef _MSC_VER
+#pragma warning(disable:4706)
+#endif
+
+TELETONE_API_DATA int16_t TELETONE_SINES[SINE_TABLE_MAX] = {
+	0x00c9, 0x025b, 0x03ed, 0x057f, 0x0711, 0x08a2, 0x0a33, 0x0bc4,
+	0x0d54, 0x0ee4, 0x1073, 0x1201, 0x138f, 0x151c, 0x16a8, 0x1833,
+	0x19be, 0x1b47, 0x1cd0, 0x1e57, 0x1fdd, 0x2162, 0x22e5, 0x2467,
+	0x25e8, 0x2768, 0x28e5, 0x2a62, 0x2bdc, 0x2d55, 0x2ecc, 0x3042,
+	0x31b5, 0x3327, 0x3497, 0x3604, 0x3770, 0x38d9, 0x3a40, 0x3ba5,
+	0x3d08, 0x3e68, 0x3fc6, 0x4121, 0x427a, 0x43d1, 0x4524, 0x4675,
+	0x47c4, 0x490f, 0x4a58, 0x4b9e, 0x4ce1, 0x4e21, 0x4f5e, 0x5098,
+	0x51cf, 0x5303, 0x5433, 0x5560, 0x568a, 0x57b1, 0x58d4, 0x59f4,
+	0x5b10, 0x5c29, 0x5d3e, 0x5e50, 0x5f5e, 0x6068, 0x616f, 0x6272,
+	0x6371, 0x646c, 0x6564, 0x6657, 0x6747, 0x6832, 0x691a, 0x69fd,
+	0x6add, 0x6bb8, 0x6c8f, 0x6d62, 0x6e31, 0x6efb, 0x6fc2, 0x7083,
+	0x7141, 0x71fa, 0x72af, 0x735f, 0x740b, 0x74b3, 0x7556, 0x75f4,
+	0x768e, 0x7723, 0x77b4, 0x7840, 0x78c8, 0x794a, 0x79c9, 0x7a42,
+	0x7ab7, 0x7b27, 0x7b92, 0x7bf9, 0x7c5a, 0x7cb7, 0x7d0f, 0x7d63,
+	0x7db1, 0x7dfb, 0x7e3f, 0x7e7f, 0x7eba, 0x7ef0, 0x7f22, 0x7f4e,
+	0x7f75, 0x7f98, 0x7fb5, 0x7fce, 0x7fe2, 0x7ff1, 0x7ffa, 0x7fff
+};
+
+
+TELETONE_API(int) teletone_set_tone(teletone_generation_session_t *ts, int index, ...)
+{
+	va_list ap;
+	int i = 0;
+	teletone_process_t x = 0;
+
+	va_start(ap, index);
+	while (i < TELETONE_MAX_TONES && (x = va_arg(ap, teletone_process_t))) {
+		ts->TONES[index].freqs[i++] = x;
+	}
+	va_end(ap);
+
+	return (i > TELETONE_MAX_TONES) ? -1 : 0;
+	
+}
+
+TELETONE_API(int) teletone_set_map(teletone_tone_map_t *map, ...)
+{
+	va_list ap;
+	int i = 0;
+	teletone_process_t x = 0;
+
+	va_start(ap, map);
+	while (i < TELETONE_MAX_TONES && (x = va_arg(ap, teletone_process_t))) {
+		map->freqs[i++] = x;
+	}
+	va_end(ap);
+
+	return (i > TELETONE_MAX_TONES) ? -1 : 0;
+	
+}
+
+TELETONE_API(int) teletone_init_session(teletone_generation_session_t *ts, int buflen, tone_handler handler, void *user_data)
+{
+	memset(ts, 0, sizeof(*ts));
+	ts->rate = 8000;
+	ts->channels = 1;
+	ts->duration = 2000;
+	ts->wait = 500;
+	ts->tmp_duration = -1;
+	ts->tmp_wait = -1;
+	ts->handler = handler;
+	ts->user_data = user_data;
+	ts->volume = -7;
+	ts->decay_step = 0;
+	ts->decay_factor = 1;
+	if (buflen) {
+		if ((ts->buffer = ftdm_calloc(buflen, sizeof(teletone_audio_t))) == 0) {
+			return -1;
+		}
+		ts->datalen = buflen;
+	} else {
+		ts->dynamic = 1024;
+	}
+	/* Add Standard DTMF Tones */
+	teletone_set_tone(ts, '1', 697.0, 1209.0, 0.0);
+	teletone_set_tone(ts, '2', 697.0, 1336.0, 0.0);
+	teletone_set_tone(ts, '3', 697.0, 1477.0, 0.0);
+	teletone_set_tone(ts, 'A', 697.0, 1633.0, 0.0);
+	teletone_set_tone(ts, '4', 770.0, 1209.0, 0.0);
+	teletone_set_tone(ts, '5', 770.0, 1336.0, 0.0);
+	teletone_set_tone(ts, '6', 770.0, 1477.0, 0.0);
+	teletone_set_tone(ts, 'B', 770.0, 1633.0, 0.0);
+	teletone_set_tone(ts, '7', 859.0, 1209.0, 0.0);
+	teletone_set_tone(ts, '8', 859.0, 1336.0, 0.0);
+	teletone_set_tone(ts, '9', 859.0, 1477.0, 0.0);
+	teletone_set_tone(ts, 'C', 859.0, 1633.0, 0.0);
+	teletone_set_tone(ts, '*', 941.0, 1209.0, 0.0);
+	teletone_set_tone(ts, '0', 941.0, 1336.0, 0.0);
+	teletone_set_tone(ts, '#', 941.0, 1477.0, 0.0);
+	teletone_set_tone(ts, 'D', 941.0, 1633.0, 0.0);
+	
+	return 0;
+}
+
+TELETONE_API(int) teletone_destroy_session(teletone_generation_session_t *ts)
+{
+	if (ts->buffer) {
+		ftdm_safe_free(ts->buffer);
+		ts->buffer = NULL;
+		ts->samples = 0;
+	}
+	return 0;
+}
+
+static int ensure_buffer(teletone_generation_session_t *ts, int need)
+{
+	need += ts->samples;
+	need *= sizeof(teletone_audio_t);
+	need *= ts->channels;
+
+	if (need > ts->datalen) {
+		teletone_audio_t *tmp;
+		ts->datalen = need + ts->dynamic;
+		tmp = realloc(ts->buffer, ts->datalen);
+		if (!tmp) {
+			return -1;
+		}
+		ts->buffer = tmp;
+	}
+
+	return 0;
+}
+
+TELETONE_API(int) teletone_mux_tones(teletone_generation_session_t *ts, teletone_tone_map_t *map)
+{
+	/*teletone_process_t period = (1.0 / ts->rate) / ts->channels;*/
+	int i, c;
+	int freqlen = 0;
+	teletone_dds_state_t tones[TELETONE_MAX_TONES+1];
+	//int decay = 0;
+	int duration;
+	int wait = 0;
+	int32_t sample;
+	int32_t dc = 0;
+	float vol = ts->volume;
+	ts->samples = 0;
+	memset(tones, 0, sizeof(tones[0]) * TELETONE_MAX_TONES);
+	duration = (ts->tmp_duration > -1) ? ts->tmp_duration : ts->duration;
+	wait = (ts->tmp_wait > -1) ? ts->tmp_wait : ts->wait;
+
+	if (map->freqs[0] > 0) {
+		for (freqlen = 0; freqlen < TELETONE_MAX_TONES && map->freqs[freqlen]; freqlen++) {
+			teletone_dds_state_set_tone(&tones[freqlen], map->freqs[freqlen], ts->rate, 0);
+			teletone_dds_state_set_tx_level(&tones[freqlen], vol);
+		}
+	
+		if (ts->channels > 1) {
+			duration *= ts->channels;
+		}
+
+		if (ts->dynamic) {
+			if (ensure_buffer(ts, duration)) {
+				return -1;
+			}
+		}
+
+		for (ts->samples = 0; ts->samples < ts->datalen && ts->samples < duration; ts->samples++) {
+			if (ts->decay_direction && ++dc >= ts->decay_step) {
+				float nvol = vol + ts->decay_direction * ts->decay_factor;
+				int j;
+
+				if (nvol <= TELETONE_VOL_DB_MAX && nvol >= TELETONE_VOL_DB_MIN) {
+					vol = nvol;
+					for (j = 0; j < TELETONE_MAX_TONES && map->freqs[j]; j++) {					
+						teletone_dds_state_set_tx_level(&tones[j], vol);
+					}
+					dc = 0;
+				}
+			}
+
+			sample = 128;
+
+			for (i = 0; i < freqlen; i++) {
+				int32_t s = teletone_dds_state_modulate_sample(&tones[i], 0);
+				sample += s;
+			}
+			sample /= freqlen;
+			ts->buffer[ts->samples] = (teletone_audio_t)sample;
+			
+			for (c = 1; c < ts->channels; c++) {
+				ts->buffer[ts->samples+1] = ts->buffer[ts->samples];
+				ts->samples++;
+			}
+			
+		}
+	}
+	if (ts->dynamic) {
+		if (ensure_buffer(ts, wait)) {
+			return -1;
+		}
+	}
+	for (c = 0; c < ts->channels; c++) {
+		for (i = 0; i < wait && ts->samples < ts->datalen; i++) {
+			ts->buffer[ts->samples++] = 0;
+		}
+	}
+
+	if (ts->debug && ts->debug_stream) {
+		if (map->freqs[0] <= 0) {
+			fprintf(ts->debug_stream, "wait %d (%dms)\n", wait, wait / (ts->rate / 1000));
+		} else {
+			fprintf(ts->debug_stream, "Generate: (");
+
+			for (i = 0; i < TELETONE_MAX_TONES && map->freqs[i]; i++) {
+				fprintf(ts->debug_stream, "%s%0.2f", i == 0 ? "" : "+",map->freqs[i]);
+			}
+			 
+			fprintf(ts->debug_stream, 
+					") [volume %0.2fdB; samples %d(%dms) x %d channel%s; wait %d(%dms); decay_factor %0.2fdB; decay_step %d(%dms); wrote %d bytes]\n",
+					ts->volume,
+					duration,
+					duration / (ts->rate / 1000), 
+					ts->channels,
+					ts->channels == 1 ? "" : "s",
+					wait,
+					wait / (ts->rate / 1000),
+					ts->decay_factor,
+					ts->decay_step,
+					ts->decay_step / (ts->rate / 1000),					
+					ts->samples * 2);
+		}
+	}	
+	return ts->samples;
+}
+
+TELETONE_API(int) teletone_run(teletone_generation_session_t *ts, const char *cmd)
+{
+	char *data = NULL, *cur = NULL, *end = NULL;
+	int var = 0, LOOPING = 0;
+	
+	if (!cmd) {
+		return -1;
+	}
+
+	do {
+		if (!(data = ftdm_strdup(cmd))) {
+			return -1;
+		}
+
+		cur = data;
+
+		while (*cur) {
+			var = 0;
+			if (*cur == ' ' || *cur == '\r' || *cur == '\n') {
+				cur++;
+				continue;
+			}
+
+			if ((end = strchr(cur, ';')) != 0) {
+				*end++ = '\0';
+			}
+			
+			if (*(cur + 1) == '=') {
+				var = 1;
+				switch(*cur) {
+				case 'c':
+					ts->channels = atoi(cur + 2);
+					break;
+				case 'r':
+					ts->rate = atoi(cur + 2);
+					break;
+				case 'd':
+					ts->duration = atoi(cur + 2) * (ts->rate / 1000);
+					break;
+				case 'v':
+					{
+						float vol = (float)atof(cur + 2);
+						if (vol <= TELETONE_VOL_DB_MAX && vol >= TELETONE_VOL_DB_MIN) {
+							ts->volume = vol;
+						}
+					}
+					break;
+				case '>':
+					ts->decay_step = atoi(cur + 2) * (ts->rate / 1000);
+					ts->decay_direction = -1;
+					break;
+				case '<':
+					ts->decay_step = atoi(cur + 2) * (ts->rate / 1000);
+					ts->decay_direction = 1;
+					break;
+				case '+':
+					ts->decay_factor = (float)atof(cur + 2);
+					break;
+				case 'w':
+					ts->wait = atoi(cur + 2) * (ts->rate / 1000);
+					break;
+				case 'l':
+					ts->loops = atoi(cur + 2); 
+					break;
+				case 'L':
+					if (!LOOPING) {
+						ts->LOOPS = atoi(cur + 2); 
+					}
+					LOOPING++;
+					break;
+				}
+			} else {
+				while (*cur) {
+					char *p = NULL, *e = NULL;
+					teletone_tone_map_t mymap, *mapp = NULL;
+
+					if (*cur == ' ' || *cur == '\r' || *cur == '\n') {
+						cur++;
+						continue;
+					}
+					
+					ts->tmp_duration = -1;
+					ts->tmp_wait = -1;
+
+					memset(&mymap, 0, sizeof(mymap));
+
+					if (*(cur + 1) == '(') {
+						p = cur + 2;
+						if (*cur) {
+							char *next;
+							int i = 0;
+							if ((e = strchr(p, ')')) != 0) {
+								*e++ = '\0';
+							}
+							do {
+								if ((next = strchr(p, ',')) != 0) {
+									*next++ = '\0';
+								}
+								if (i == 0) {
+									ts->tmp_duration = atoi(p) * (ts->rate / 1000);
+									i++;
+								} else if (i == 1) {
+									ts->tmp_wait = atoi(p) * (ts->rate / 1000);
+									i++;
+								} else {
+									mymap.freqs[i++ - 2] = atof(p);
+								}
+								p = next;
+
+							} while (next && (i-2) < TELETONE_MAX_TONES);
+							if (i > 2 && *cur == '%') {
+								mapp = &mymap;
+							} else if ((i != 2 || *cur == '%')) { 
+								if (ts->debug && ts->debug_stream) {
+									fprintf(ts->debug_stream, "Syntax Error!\n");
+								}
+								goto bottom;
+							}
+						} 
+					}
+
+					if (*cur && !mapp) {
+						if (*cur > 0 && *cur < TELETONE_TONE_RANGE) { 
+							mapp = &ts->TONES[(int)*cur];
+						} else if (ts->debug && ts->debug_stream) {
+							fprintf(ts->debug_stream, "Map [%c] Out Of Range!\n", *cur);
+						}
+					}
+
+					if (mapp) {
+						if (mapp->freqs[0]) {
+							if (ts->handler) {
+								do {
+									ts->handler(ts, mapp);
+									if (ts->loops > 0) {
+										ts->loops--;
+									}
+								} while (ts->loops);
+							}
+						} else if (ts->debug && ts->debug_stream) {
+							fprintf(ts->debug_stream, "Ignoring Empty Map [%c]!\n", *cur);
+						}
+					}
+					
+					if (e) {
+						cur = e;
+					} else {
+						cur++;
+					}
+				}
+			}
+
+			if (end) {
+				cur = end;
+			} else if (*cur){
+				cur++;
+			}
+		}
+	bottom:
+		ftdm_safe_free(data);
+		data = NULL;
+		if (ts->LOOPS > 0) {
+			ts->LOOPS--;
+		}
+
+	} while (ts->LOOPS);
+
+	return 0;
+}
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */

Added: freeswitch/trunk/libs/freetdm/src/m3ua/mstm3ua.c (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/m3ua/mstm3ua.c	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/m3ua/mstm3ua.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,62 @@
+/* WARNING WORK IN PROGRESS
+ *  mstm3ua.c
+ *  mstss7d port
+ *
+ *  Created by Shane Burrell on 2/2/08.
+ *  Copyright 2008 Shane Burrell. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "mstm3ua.h"
+
+
+
+
+
+int build_m3ua_hdr(unsigned char len,unsigned char *bytemsg)
+
+{
+   
+	*bytemsg++ = M_VERSION_REL1;  // 1 Verison
+	//bytemsg[1] = 0x00;  // 2 RESERVED
+	//bytemsg[2] = M_CLASS_XFER;  // 3 Msg Class
+    //SS7 BOX Kludge
+	*bytemsg++ = 0x01;  // 2 RESERVED
+	*bytemsg++ = 0x00;  // 2 RESERVED				
+	
+	*bytemsg++ = M_TYPE_DATA	;  // 4 Msg Type
+
+	*bytemsg++ = len;  // 5 Msg LENGTH  81  32bit field
+	*bytemsg++ = 0x00;  // 6
+	*bytemsg++ = 0x00;  // 7
+	*bytemsg++ = 0x00;  // 8
+	return(0);
+
+};
\ No newline at end of file

Added: freeswitch/trunk/libs/freetdm/src/m3ua/mstm3ua.h (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/m3ua/mstm3ua.h	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/m3ua/mstm3ua.h	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,96 @@
+/*
+ *  mstm3ua.h
+ *  mstss7d
+ *
+ *  Created by Shane Burrell on 3/2/08.
+ *  Copyright 2008 Shane Burrell. All rights reserved.
+ *
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+typedef unsigned long m3ua_ulong;
+typedef unsigned short m3ua_ushort;
+typedef unsigned char m3ua_uchar;
+
+typedef unsigned char u8;
+typedef unsigned short u16;	/* Note: multi-byte values are little-endian */
+typedef unsigned long u32;
+
+
+
+
+#define M_TAG_NETWORK_APPEARANCE	1
+#define	M_TAG_PROTOCOL_DATA		3
+#define M_TAG_INFO_STRING		4
+#define M_TAG_AFFECTED_DPC		5
+#define M_TAG_ROUTING_CONTEXT		6
+#define M_TAG_DIAGNOSTIC_INFORMATION	7
+#define M_TAG_HEARTBEAT_DATA		8
+#define M_TAG_UNAVAILABILITY_CAUSE	9
+#define M_TAG_REASON			10
+#define	M_TAG_TRAFFIC_MODE_TYPE		11
+#define M_TAG_ERROR_CODE		12
+#define	M_TAG_STATUS_TYPE		13
+#define M_TAG_CONGESTED_INDICATIONS	14
+
+#define M_VERSION_REL1   1
+
+#define M_CLASS_MGMT	0x00
+#define M_CLASS_XFER	0x01
+#define	M_CLASS_SSNM	0x02
+#define M_CLASS_ASPSM	0x03
+#define M_CLASS_ASPTM	0x04
+#define M_CLASS_RKM		0x09
+
+#define M_TYPE_ERR		(0|M_CLASS_MGMT
+
+#define M_TYPE_NTFY		(1|M_CLASS_XFER)
+#define M_TYPE_DATA		(1|M_CLASS_XFER)
+
+#define M_TYPE_DUNA		(1|M_CLASS_SSNM)
+#define M_TYPE_DAVA		(2|M_CLASS_SSNM)
+#define M_TYPE_DUAD		(3|M_CLASS_SSNM)
+#define M_TYPE_SCON		(4|M_CLASS_SSNM)
+#define M_TYPE_DUPU		(5|M_CLASS_SSNM)
+
+#define	M_TYPE_UP		(1|M_CLASS_ASPSM)
+#define	M_TYPE_DOWN		(2|M_CLASS_ASPSM)
+#define	M_TYPE_BEAT		(3|M_CLASS_ASPSM)
+#define	M_TYPE_UP_ACK		(4|M_CLASS_ASPSM)
+#define	M_TYPE_DOWN_ACK		(5|M_CLASS_ASPSM)
+#define	M_TYPE_BEAT_ACK		(6|M_CLASS_ASPSM)
+
+#define M_TYPE_ACTIVE		(1|M_CLASS_ASPTM)
+#define M_TYPE_INACTIVE		(2|M_CLASS_ASPTM)
+#define M_TYPE_ACTIVE_ACK	(3|M_CLASS_ASPTM)
+#define M_TYPE_INACTIVE_ACK	(4|M_CLASS_ASPTM)
+
+#define M_CLASS_MASK	0xff00
+#define	M_TYPE_MASK	0x00ff
+

Added: freeswitch/trunk/libs/freetdm/src/m3ua_client.c (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/m3ua_client.c	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/m3ua_client.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,333 @@
+/*
+ *  m3ua_client.c
+ *  freetdm
+ *
+ *  Created by Shane Burrell on 4/3/08.
+ *  Copyright 2008 Shane Burrell. All rights reserved.
+ *
+ * 
+  * Copyright (c) 2007, Anthony Minessale II, Nenad Corbic
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if HAVE_NETDB_H
+#include <netdb.h>
+#endif
+
+#include "freetdm.h"
+#include <m3ua_client.h>
+
+
+#ifndef HAVE_GETHOSTBYNAME_R
+extern int gethostbyname_r (const char *__name,
+							struct hostent *__result_buf,
+							char *__buf, size_t __buflen,
+							struct hostent **__result,
+							int *__h_errnop);
+#endif
+
+struct m3uac_map {
+	uint32_t event_id;
+	const char *name;
+};
+
+static struct m3uac_map m3uac_table[] = {
+	{M3UA_EVENT_CALL_START, "CALL_START"},
+	{M3UA_EVENT_CALL_START_ACK, "CALL_START_ACK"},
+	{M3UA_EVENT_CALL_START_NACK, "CALL_START_NACK"},
+	{M3UA_EVENT_CALL_START_NACK_ACK, "CALL_START_NACK_ACK"},
+	{M3UA_EVENT_CALL_ANSWERED, "CALL_ANSWERED"},
+	{M3UA_EVENT_CALL_STOPPED, "CALL_STOPPED"},
+	{M3UA_EVENT_CALL_STOPPED_ACK, "CALL_STOPPED_ACK"},
+	{M3UA_EVENT_SYSTEM_RESTART, "SYSTEM_RESTART"},
+	{M3UA_EVENT_SYSTEM_RESTART_ACK, "SYSTEM_RESTART_ACK"},
+	{M3UA_EVENT_HEARTBEAT, "HEARTBEAT"},
+	{M3UA_EVENT_INSERT_CHECK_LOOP, "LOOP START"},
+	{M3UA_EVENT_REMOVE_CHECK_LOOP, "LOOP STOP"} 
+}; 
+
+
+
+static int create_conn_socket(m3uac_connection_t *mcon, char *local_ip, int local_port, char *ip, int port)
+{
+	int rc;
+	struct hostent *result, *local_result;
+	char buf[512], local_buf[512];
+	int err = 0;
+
+	memset(&mcon->remote_hp, 0, sizeof(mcon->remote_hp));
+	memset(&mcon->local_hp, 0, sizeof(mcon->local_hp));
+	mcon->socket = socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP);
+ 
+	ftdm_log(FTDM_LOG_DEBUG, "Creating L=%s:%d R=%s:%d\n",
+			local_ip,local_port,ip,port);
+
+	if (mcon->socket >= 0) {
+		int flag;
+
+		flag = 1;
+		gethostbyname_r(ip, &mcon->remote_hp, buf, sizeof(buf), &result, &err);
+		gethostbyname_r(local_ip, &mcon->local_hp, local_buf, sizeof(local_buf), &local_result, &err);
+		if (result && local_result) {
+			mcon->remote_addr.sin_family = mcon->remote_hp.h_addrtype;
+			memcpy((char *) &mcon->remote_addr.sin_addr.s_addr, mcon->remote_hp.h_addr_list[0], mcon->remote_hp.h_length);
+			mcon->remote_addr.sin_port = htons(port);
+
+			mcon->local_addr.sin_family = mcon->local_hp.h_addrtype;
+			memcpy((char *) &mcon->local_addr.sin_addr.s_addr, mcon->local_hp.h_addr_list[0], mcon->local_hp.h_length);
+			mcon->local_addr.sin_port = htons(local_port);
+
+
+			setsockopt(mcon->socket, IPPROTO_SCTP, SCTP_NODELAY, (char *)&flag, sizeof(int));
+
+			rc=listen(mcon->socket,100);
+			if (rc) {
+			close(mcon->socket);
+			mcon->socket = -1;
+			
+			}
+		}
+	}
+
+	ftdm_mutex_create(&mcon->mutex);
+
+	return mcon->socket;
+}
+
+int m3uac_connection_close(m3uac_connection_t *mcon)
+{
+	if (mcon->socket > -1) {
+		close(mcon->socket);
+	}
+
+	ftdm_mutex_lock(mcon->mutex);
+	ftdm_mutex_unlock(mcon->mutex);
+	ftdm_mutex_destroy(&mcon->mutex);
+	memset(mcon, 0, sizeof(*mcon));
+	mcon->socket = -1;
+
+	return 0;
+}
+
+int m3uac_connection_open(m3uac_connection_t *mcon, char *local_ip, int local_port, char *ip, int port)
+{
+	create_conn_socket(mcon, local_ip, local_port, ip, port);
+	return mcon->socket;
+}
+
+
+int m3uac_exec_command(m3uac_connection_t *mcon, int span, int chan, int id, int cmd, int cause)
+{
+    m3uac_event_t oevent;
+    int retry = 5;
+
+    m3uac_event_init(&oevent, cmd, chan, span);
+    oevent.release_cause = cause;
+
+	if (cmd == SIGBOOST_EVENT_SYSTEM_RESTART) {
+		mcon->rxseq_reset = 1;
+		mcon->txseq = 0;
+		mcon->rxseq = 0;
+		mcon->txwindow = 0;
+	}
+
+    if (id >= 0) {
+        oevent.call_setup_id = id;
+    }
+
+    while (m3uac_connection_write(mcon, &oevent) <= 0) {
+        if (--retry <= 0) {
+            ftdm_log(FTDM_LOG_CRIT, "Failed to tx on M3UA socket: %s\n", strerror(errno));
+            return -1;
+        } else {
+            ftdm_log(FTDM_LOG_WARNING, "Failed to tx on M3UA socket: %s :retry %i\n", strerror(errno), retry);
+			ftdm_sleep(1);
+        }
+    }
+
+    return 0;
+}
+
+
+
+m3uac_event_t *m3uac_connection_read(m3uac_connection_t *mcon, int iteration)
+{
+	unsigned int fromlen = sizeof(struct sockaddr_in);
+	int bytes = 0;
+
+	bytes = recvfrom(mcon->socket, &mcon->event, sizeof(mcon->event), MSG_DONTWAIT, 
+					 (struct sockaddr *) &mcon->local_addr, &fromlen);
+
+	if (bytes == sizeof(mcon->event) || bytes == (sizeof(mcon->event)-sizeof(uint32_t))) {
+
+		if (mcon->rxseq_reset) {
+			if (mcon->event.event_id == SIGBOOST_EVENT_SYSTEM_RESTART_ACK) {
+				ftdm_log(FTDM_LOG_DEBUG, "Rx sync ok\n");
+				mcon->rxseq = mcon->event.fseqno;
+				return &mcon->event;
+			}
+			errno=EAGAIN;
+			ftdm_log(FTDM_LOG_DEBUG, "Waiting for rx sync...\n");
+			return NULL;
+		}
+		
+		mcon->txwindow = mcon->txseq - mcon->event.bseqno;
+		mcon->rxseq++;
+
+		if (mcon->rxseq != mcon->event.fseqno) {
+			ftdm_log(FTDM_LOG_CRIT, "Invalid Sequence Number Expect=%i Rx=%i\n", mcon->rxseq, mcon->event.fseqno);
+			return NULL;
+		}
+
+		return &mcon->event;
+	} else {
+		if (iteration == 0) {
+			ftdm_log(FTDM_LOG_CRIT, "Invalid Event length from boost rxlen=%i evsz=%i\n", bytes, sizeof(mcon->event));
+			return NULL;
+		}
+	}
+
+	return NULL;
+}
+
+m3uac_event_t *m3uac_connection_readp(m3uac_connection_t *mcon, int iteration)
+{
+	unsigned int fromlen = sizeof(struct sockaddr_in);
+	int bytes = 0;
+
+	bytes = recvfrom(mcon->socket, &mcon->event, sizeof(mcon->event), MSG_DONTWAIT, (struct sockaddr *) &mcon->local_addr, &fromlen);
+
+	if (bytes == sizeof(mcon->event) || bytes == (sizeof(mcon->event)-sizeof(uint32_t))) {
+		return &mcon->event;
+	} else {
+		if (iteration == 0) {
+			ftdm_log(FTDM_LOG_CRIT, "Critical Error: PQ Invalid Event lenght from boost rxlen=%i evsz=%i\n", bytes, sizeof(mcon->event));
+			return NULL;
+		}
+	}
+
+	return NULL;
+}
+
+
+int m3uac_connection_write(m3uac_connection_t *mcon, ss7bc_event_t *event)
+{
+	int err;
+
+	if (!event || mcon->socket < 0 || !mcon->mutex) {
+		ftdm_log(FTDM_LOG_DEBUG,  "Critical Error: No Event Device\n");
+		return -EINVAL;
+	}
+
+	if (event->span > 16 || event->chan > 31) {
+		ftdm_log(FTDM_LOG_CRIT, "Critical Error: TX Cmd=%s Invalid Span=%i Chan=%i\n", m3uac_event_id_name(event->event_id), event->span,event->chan);
+		return -1;
+	}
+
+	gettimeofday(&event->tv,NULL);
+	
+	ftdm_mutex_lock(mcon->mutex);
+	event->fseqno = mcon->txseq++;
+	event->bseqno = mcon->rxseq;
+	err = sendto(mcon->socket, event, sizeof(m3uac_event_t), 0, (struct sockaddr *) &mcon->remote_addr, sizeof(mcon->remote_addr));
+	ftdm_mutex_unlock(mcon->mutex);
+
+	if (err != sizeof(m3uac_event_t)) {
+		err = -1;
+	}
+	
+ 	ftdm_log(FTDM_LOG_DEBUG, "TX EVENT: %s:(%X) [w%dg%d] Rc=%i CSid=%i Seq=%i Cd=[%s] Ci=[%s]\n",
+			m3uac_event_id_name(event->event_id),
+			event->event_id,
+			event->span+1,
+			event->chan+1,
+			event->release_cause,
+			event->call_setup_id,
+			event->fseqno,
+			(event->called_number_digits_count ? (char *) event->called_number_digits : "N/A"),
+			(event->calling_number_digits_count ? (char *) event->calling_number_digits : "N/A")
+			);
+
+	return err;
+}
+
+void m3uac_call_init(m3uac_event_t *event, const char *calling, const char *called, int setup_id)
+{
+	memset(event, 0, sizeof(m3uac_event_t));
+	event->event_id = M3UA_EVENT_CALL_START;
+
+	if (calling) {
+		strncpy((char*)event->calling_number_digits, calling, sizeof(event->calling_number_digits)-1);
+		event->calling_number_digits_count = strlen(calling);
+	}
+
+	if (called) {
+		strncpy((char*)event->called_number_digits, called, sizeof(event->called_number_digits)-1);
+		event->called_number_digits_count = strlen(called);
+	}
+		
+	event->call_setup_id = setup_id;
+	
+}
+
+void m3uac_event_init(m3uac_event_t *event, m3uac_event_id_t event_id, int chan, int span) 
+{
+	memset(event, 0, sizeof(ss7bc_event_t));
+	event->event_id = event_id;
+	event->chan = chan;
+	event->span = span;
+}
+
+const char *m3uac_event_id_name(uint32_t event_id)
+{
+	unsigned int x;
+	const char *ret = NULL;
+
+	for (x = 0 ; x < sizeof(m3uac_table)/sizeof(struct m3uac_map); x++) {
+		if (m3uac_table[x].event_id == event_id) {
+			ret = m3uac_table[x].name;
+			break;
+		}
+	}
+
+	return ret;
+}
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
+
+

Added: freeswitch/trunk/libs/freetdm/src/m3ua_client.h (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/m3ua_client.h	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/m3ua_client.h	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,164 @@
+/*
+ *  m3ua_client.h
+ *  freetdm
+ *
+ *  Created by Shane Burrell on 4/3/08.
+ *  Copyright 2008 Shane Burrell. All rights reserved.
+ *
+ * Copyright (c) 2007, Anthony Minessale II, Nenad Corbic
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <ctype.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+// Fix this for portability
+#include <sctp.h>
+//#include <netinet/sctp.h>
+#include <arpa/inet.h>
+#include <stdarg.h>
+#include <netdb.h>
+//#include <sigboost.h>
+#include <sys/time.h>
+
+#define MAX_DIALED_DIGITS	31
+#define MAX_CALLING_NAME	31
+
+/* Next two defines are used to create the range of values for call_setup_id
+ * in the t_sigboost structure.
+ * 0..((CORE_MAX_SPANS * CORE_MAX_CHAN_PER_SPAN) - 1) */
+#define CORE_MAX_SPANS 		200
+#define CORE_MAX_CHAN_PER_SPAN 	30
+#define MAX_PENDING_CALLS 	CORE_MAX_SPANS * CORE_MAX_CHAN_PER_SPAN
+/* 0..(MAX_PENDING_CALLS-1) is range of call_setup_id below */
+#define SIZE_RDNIS		80
+
+//#undef MSGWINDOW
+#define MSGWINDOW
+
+
+typedef struct
+{
+	uint32_t	event_id;
+	uint32_t	fseqno;
+#ifdef MSGWINDOW
+	uint32_t	bseqno;
+#endif
+	uint16_t	call_setup_id;
+	uint32_t	trunk_group;
+	uint32_t	span;
+	uint32_t	chan;
+	uint8_t		called_number_digits_count;
+	char		called_number_digits [MAX_DIALED_DIGITS + 1]; /* it's a null terminated string */
+	uint8_t		calling_number_digits_count; /* it's an array */
+	char		calling_number_digits [MAX_DIALED_DIGITS + 1]; /* it's a null terminated string */
+	uint8_t		release_cause;
+	struct timeval  tv;
+	/* ref. Q.931 Table 4-11 and Q.951 Section 3 */
+	uint8_t		calling_number_screening_ind;
+	uint8_t		calling_number_presentation;
+	char		redirection_string [SIZE_RDNIS]; /* it's a null terminated string */
+	
+} t_m3ua;
+
+typedef t_m3ua m3uac_event_t;
+typedef uint32_t m3uac_event_id_t;
+
+
+typedef struct m3uac_ip_cfg
+{
+	char local_ip[25];
+	int local_port;
+	char remote_ip[25];
+	int remote_port;
+}m3uac_ip_cfg_t;
+
+struct m3uac_connection {
+	ftdm_socket_t socket;
+	struct sockaddr_in local_addr;
+	struct sockaddr_in remote_addr;
+	m3uac_event_t event;
+	struct hostent remote_hp;
+	struct hostent local_hp;
+	unsigned int flags;
+	ftdm_mutex_t *mutex;
+	FILE *log;
+	unsigned int txseq;
+	unsigned int rxseq;
+	unsigned int txwindow;
+	unsigned int rxseq_reset;
+	m3uac_ip_cfg_t cfg;
+	uint32_t hb_elapsed;
+	int up;
+};
+
+typedef enum {
+	MSU_FLAG_EVENT = (1 << 0)
+} m3uac_flag_t;
+
+typedef struct m3uac_connection m3uac_connection_t;
+
+static inline void sctp_no_nagle(int socket)
+{
+    //int flag = 1;
+    //setsockopt(socket, IPPROTO_SCTP, SCTP_NODELAY, (char *) &flag, sizeof(int));
+}
+
+int m3uac_connection_close(m3uac_connection_t *mcon);
+int m3uac_connection_open(m3uac_connection_t *mcon, char *local_ip, int local_port, char *ip, int port);
+m3uac_event_t *m3uac_connection_read(m3uac_connection_t *mcon, int iteration);
+m3uac_event_t *m3uac_connection_readp(m3uac_connection_t *mcon, int iteration);
+int m3uac_connection_write(m3uac_connection_t *mcon, m3uac_event_t *event);
+void m3uac_event_init(m3uac_event_t *event, m3uac_event_id_t event_id, int chan, int span);
+void m3uac_call_init(m3uac_event_t *event, const char *calling, const char *called, int setup_id);
+const char *m3uac_event_id_name(uint32_t event_id);
+int m3uac_exec_command(m3uac_connection_t *mcon, int span, int chan, int id, int cmd, int cause);
+
+
+
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */

Added: freeswitch/trunk/libs/freetdm/src/priserver.c (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/priserver.c	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/priserver.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,328 @@
+/*****************************************************************************
+ * priserver.c Refactoring of pritest.c
+ *
+ * Author(s):   Anthony Minessale II <anthmct@yahoo.com>
+ *              Nenad Corbic <ncorbic@sangoma.com>
+ *
+ * Copyright:   (c) 2005 Anthony Minessale II
+ *
+ *      This program is free software; you can redistribute it and/or
+ *      modify it under the terms of the GNU General Public License
+ *      as published by the Free Software Foundation; either version
+ *      2 of the License, or (at your option) any later version.
+ * ============================================================================
+ */
+
+#include "freetdm.h"
+#include <sangoma_pri.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/wait.h>
+
+typedef struct {
+	int pid;
+	q931_call call;
+	void *pri;
+	int ready;
+}call_info_t;
+
+
+#define SANGOMA_MAX_CHAN_PER_SPAN 32
+
+static call_info_t pidmap[SANGOMA_MAX_CHAN_PER_SPAN];
+
+FIO_EVENT_CB_FUNCTION(my_ftdm_event_handler)
+{
+	if (event->e_type = FTDM_EVENT_DTMF) {
+		char *dtmf = event->data;
+		printf("DTMF %s\n", dtmf);
+	}
+}
+
+/* Stupid runtime process to play a file to a b channel*/
+#define BYTES 320
+#define MAX_BYTES 1000
+
+static int ready = 1;
+
+static void handle_SIGINT(int sig)
+{
+	if (sig) {
+		ready = 0;
+	}
+
+	return;
+}
+
+static void launch_channel(struct sangoma_pri *spri, int channo)
+{
+	pid_t pid;
+	int fd = 0, file = 0, inlen = 0, outlen = 0;
+	unsigned char inframe[MAX_BYTES], outframe[MAX_BYTES];
+	fd_set readfds;
+	int mtu_mru=BYTES / 2;
+	int err;
+	ftdm_channel_t *chan;
+	ftdm_codec_t codec = FTDM_CODEC_SLIN;
+	unsigned ms = 20;
+	unsigned int lead = 50;
+	int ifd = -1;
+	ftdm_tone_type_t tt = FTDM_TONE_DTMF;
+	char dtmf[] = "1234567890";
+	int loops = 0;
+
+	pid = fork();
+	
+	if (pid) {
+		pidmap[channo-1].pid = pid;
+		printf("-- Launching process %d to handle channel %d\n", pid, channo);
+		return;
+	}
+
+	signal(SIGINT, handle_SIGINT);
+
+	//ifd = open("/nfs/sounds/ptest.raw", O_WRONLY|O_CREAT|O_TRUNC, 777);
+	
+	memset(inframe, 0, MAX_BYTES);
+	memset(outframe, 0, MAX_BYTES);
+		
+	if (ftdm_channel_open(spri->span, channo, &chan) != FTDM_SUCCESS) {
+		printf("DEBUG cant open fd!\n");
+	}
+	
+
+
+#if 1
+	if (ftdm_channel_command(chan, FTDM_COMMAND_SET_CODEC, &codec) != FTDM_SUCCESS) {
+		printf("Critical Error: Failed to set driver codec!\n");
+		ftdm_channel_close(&chan);
+		exit(-1);
+	}
+#endif
+	
+#if 1
+	if (ftdm_channel_command(chan, FTDM_COMMAND_ENABLE_DTMF_DETECT, &tt) != FTDM_SUCCESS) {
+		printf("Critical Error: Failed to set dtmf detect!\n");
+		ftdm_channel_close(&chan);
+		exit(-1);
+	}
+	ftdm_channel_set_event_callback(chan, my_ftdm_event_handler);
+#endif
+
+
+	if (ftdm_channel_command(chan, FTDM_COMMAND_SET_INTERVAL, &ms) != FTDM_SUCCESS) {
+		printf("Critical Error: Failed to set codec interval!\n");
+		ftdm_channel_close(&chan);
+		exit(-1);
+	}
+		
+	file = open("sound.raw", O_RDONLY);
+	if (file < 0){
+		printf("Critical Error: Failed to open sound file!\n");
+		ftdm_channel_close(&chan);
+		exit(-1);
+	}
+
+
+	while(ready) {
+		ftdm_wait_flag_t flags = FTDM_READ;
+		ftdm_size_t len;
+		loops++;
+
+		if (lead) {
+			lead--;
+		}
+
+		if (!lead && loops == 300) {
+#if 1
+			if (ftdm_channel_command(chan, FTDM_COMMAND_SEND_DTMF, dtmf) != FTDM_SUCCESS) {
+				printf("Critical Error: Failed to send dtmf\n");
+				ftdm_channel_close(&chan);
+				exit(-1);
+			}
+#endif
+
+		}
+
+		if (ftdm_channel_wait(chan, &flags, 2000) != FTDM_SUCCESS) {
+			printf("wait FAIL! [%s]\n", chan->last_error);
+			break;
+		}
+	
+		if (flags & FTDM_READ) {
+			len = MAX_BYTES;
+			if (ftdm_channel_read(chan, inframe, &len) == FTDM_SUCCESS) {
+				//printf("READ: %d\n", len);
+				//write(ifd, inframe, len);
+				if(!lead && (outlen = read(file, outframe, len)) <= 0) {
+					break;
+				}
+
+			} else {
+				printf("READ FAIL! %d [%s]\n", len, chan->last_error);
+				break;
+			}
+			if (lead) {
+				continue;
+			} 
+			ftdm_channel_write(chan, outframe, sizeof(outframe), &len);
+		} else {
+			printf("BREAK");
+			break;
+		}
+	}
+
+	printf("loop done\n");
+
+	//sangoma_get_full_cfg(fd, &tdm_api);
+	close(file);
+	//close(ifd);
+
+	pri_hangup(spri->pri, channo, 16);
+	if (ftdm_channel_close(&chan) != FTDM_SUCCESS) {
+		printf("Critical Error: Failed to close channel [%s]\n", chan->last_error);
+	}
+
+	printf("Call Handler: Process Finished\n");
+	exit(0);
+}
+
+
+/* Event Handlers */
+
+static int on_info(struct sangoma_pri *spri, sangoma_pri_event_t event_type, pri_event *event) 
+{
+	printf( "number is: %s\n", event->ring.callednum);
+	if(strlen(event->ring.callednum) > 3) {
+		printf( "final number is: %s\n", event->ring.callednum);
+		pri_answer(spri->pri, event->ring.call, 0, 1);
+	}
+	return 0;
+}
+
+static int on_hangup(struct sangoma_pri *spri, sangoma_pri_event_t event_type, pri_event *event) 
+{
+	//pri_hangup(spri->pri, event->hangup.call, event->hangup.cause);
+	printf("-- Hanging up channel %d\n", event->hangup.channel);
+	if(pidmap[event->hangup.channel-1].pid) {
+		pri_hangup(spri->pri, event->hangup.call, 16);
+		pri_destroycall(spri->pri, event->hangup.call);
+		kill(pidmap[event->hangup.channel-1].pid, SIGINT);
+		pidmap[event->hangup.channel-1].pid = 0;
+	}
+	return 0;
+}
+
+static int on_ring(struct sangoma_pri *spri, sangoma_pri_event_t event_type, pri_event *event) 
+{
+	printf("-- Ring on channel %d (from %s to %s), answering...\n", event->ring.channel, event->ring.callingnum, event->ring.callednum);
+	pri_answer(spri->pri, event->ring.call, event->ring.channel, 1);
+	memcpy(&pidmap[event->ring.channel-1].call, event->ring.call, sizeof(q931_call));
+	pidmap[event->ring.channel-1].pri=spri->pri;
+	pidmap[event->ring.channel-1].call = *event->ring.call;
+	launch_channel(spri, event->ring.channel);
+	return 0;
+}
+
+static int on_restart(struct sangoma_pri *spri, sangoma_pri_event_t event_type, pri_event *event)
+{
+	printf("-- Restarting channel %d\n", event->restart.channel);
+	return 0;
+}
+
+static int on_anything(struct sangoma_pri *spri, sangoma_pri_event_t event_type, pri_event *event) 
+{
+	printf("%s: Caught Event %d (%s)\n", __FUNCTION__, event_type, sangoma_pri_event_str(event_type));
+	return 0;
+}
+
+/* Generic Reaper */
+static void chan_ended(int sig)
+{
+	int status;
+	int x;
+	struct rusage rusage;
+	pid_t pid;
+	pid = wait4(-1, &status, WNOHANG, &rusage);
+
+	printf("-- PID %d ended\n", pid);
+
+	for (x=0;x<SANGOMA_MAX_CHAN_PER_SPAN;x++) {
+		if (pid == pidmap[x].pid) {
+			pidmap[x].pid = 0;
+			if (pidmap[x].pri){
+				int err=pri_hangup(pidmap[x].pri, &pidmap[x].call, 16);
+				//pri_destroycall(pidmap[x].pri, &pidmap[x].call);
+				printf("Hanging up on PID %i Err=%i\n",pid,err);
+			}
+
+			pidmap[x].pri=NULL;
+			signal(SIGCHLD, chan_ended);
+			return;
+		}
+	}
+
+	if (pid > -1) {
+		fprintf(stderr, "--!! Unknown PID %d exited\n", pid);
+		signal(SIGCHLD, chan_ended);
+		return;
+	}
+}
+
+/* Our Program */
+int main(int argc, char *argv[])
+{
+	struct sangoma_pri spri;
+	int debug = 0;
+	if (argv[1]) {
+		debug = atoi(argv[1]);
+	}
+
+	ftdm_global_set_default_logger(FTDM_LOG_LEVEL_DEBUG);
+	if (ftdm_global_init() != FTDM_SUCCESS) {
+        fprintf(stderr, "Error loading FreeTDM\n");
+        exit(-1);
+    }
+
+    printf("FreeTDM loaded\n");
+
+
+	debug = PRI_DEBUG_Q931_DUMP | PRI_DEBUG_Q931_STATE;
+	printf("WTF %d\n", debug);
+
+	if (sangoma_init_pri(&spri,
+						 1,  // span
+						 24, // dchan
+						 SANGOMA_PRI_SWITCH_DMS100,
+						 SANGOMA_PRI_CPE,
+						 debug) < 0) {
+		return -1;
+	}
+	//spri.pri->debug = (PRI_DEBUG_Q931_DUMP | PRI_DEBUG_Q921_DUMP | PRI_DEBUG_Q921_RAW | PRI_DEBUG_Q921_STATE);
+
+	//pri_set_debug(&spri.pri, (PRI_DEBUG_Q931_DUMP | PRI_DEBUG_Q921_DUMP | PRI_DEBUG_Q921_RAW | PRI_DEBUG_Q921_STATE));
+
+	SANGOMA_MAP_PRI_EVENT(spri, SANGOMA_PRI_EVENT_ANY, on_anything);
+	SANGOMA_MAP_PRI_EVENT(spri, SANGOMA_PRI_EVENT_RING, on_ring);
+	SANGOMA_MAP_PRI_EVENT(spri, SANGOMA_PRI_EVENT_HANGUP, on_hangup);
+	SANGOMA_MAP_PRI_EVENT(spri, SANGOMA_PRI_EVENT_HANGUP_REQ, on_hangup);
+	SANGOMA_MAP_PRI_EVENT(spri, SANGOMA_PRI_EVENT_INFO_RECEIVED, on_info);
+	SANGOMA_MAP_PRI_EVENT(spri, SANGOMA_PRI_EVENT_RESTART, on_restart);
+
+	signal(SIGCHLD, chan_ended);
+	sangoma_run_pri(&spri);
+	return 0;
+}
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */

Added: freeswitch/trunk/libs/freetdm/src/sangoma_pri.c (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/sangoma_pri.c	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/sangoma_pri.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,251 @@
+/*****************************************************************************
+ * sangoma_pri.c libpri Sangoma integration
+ *
+ * Author(s):	Anthony Minessale II <anthmct@yahoo.com>
+ *              Nenad Corbic <ncorbic@sangoma.com>
+ *
+ * Copyright:	(c) 2005 Anthony Minessale II
+ *
+ *		This program is free software; you can redistribute it and/or
+ *		modify it under the terms of the GNU General Public License
+ *		as published by the Free Software Foundation; either version
+ *		2 of the License, or (at your option) any later version.
+ * ============================================================================
+ */
+
+#include "freetdm.h"
+#include <sangoma_pri.h>
+#ifndef HAVE_GETTIMEOFDAY
+
+#ifdef WIN32
+#include <mmsystem.h>
+
+static __inline int gettimeofday(struct timeval *tp, void *nothing)
+{
+#ifdef WITHOUT_MM_LIB
+	SYSTEMTIME st;
+	time_t tt;
+	struct tm tmtm;
+	/* mktime converts local to UTC */
+	GetLocalTime (&st);
+	tmtm.tm_sec = st.wSecond;
+	tmtm.tm_min = st.wMinute;
+	tmtm.tm_hour = st.wHour;
+	tmtm.tm_mday = st.wDay;
+	tmtm.tm_mon = st.wMonth - 1;
+	tmtm.tm_year = st.wYear - 1900;  tmtm.tm_isdst = -1;
+	tt = mktime (&tmtm);
+	tp->tv_sec = tt;
+	tp->tv_usec = st.wMilliseconds * 1000;
+#else
+	/**
+	 ** The earlier time calculations using GetLocalTime
+	 ** had a time resolution of 10ms.The timeGetTime, part
+	 ** of multimedia apis offer a better time resolution
+	 ** of 1ms.Need to link against winmm.lib for this
+	 **/
+	unsigned long Ticks = 0;
+	unsigned long Sec =0;
+	unsigned long Usec = 0;
+	Ticks = timeGetTime();
+
+	Sec = Ticks/1000;
+	Usec = (Ticks - (Sec*1000))*1000;
+	tp->tv_sec = Sec;
+	tp->tv_usec = Usec;
+#endif /* WITHOUT_MM_LIB */
+	(void)nothing;
+	return 0;
+}
+#endif /* WIN32 */
+#endif /* HAVE_GETTIMEOFDAY */
+
+static struct sangoma_pri_event_list SANGOMA_PRI_EVENT_LIST[] = {
+	{0, SANGOMA_PRI_EVENT_ANY, "ANY"},
+	{1, SANGOMA_PRI_EVENT_DCHAN_UP, "DCHAN_UP"},
+	{2, SANGOMA_PRI_EVENT_DCHAN_DOWN, "DCHAN_DOWN"},
+	{3, SANGOMA_PRI_EVENT_RESTART, "RESTART"},
+	{4, SANGOMA_PRI_EVENT_CONFIG_ERR, "CONFIG_ERR"},
+	{5, SANGOMA_PRI_EVENT_RING, "RING"},
+	{6, SANGOMA_PRI_EVENT_HANGUP, "HANGUP"},
+	{7, SANGOMA_PRI_EVENT_RINGING, "RINGING"},
+	{8, SANGOMA_PRI_EVENT_ANSWER, "ANSWER"},
+	{9, SANGOMA_PRI_EVENT_HANGUP_ACK, "HANGUP_ACK"},
+	{10, SANGOMA_PRI_EVENT_RESTART_ACK, "RESTART_ACK"},
+	{11, SANGOMA_PRI_EVENT_FACNAME, "FACNAME"},
+	{12, SANGOMA_PRI_EVENT_INFO_RECEIVED, "INFO_RECEIVED"},
+	{13, SANGOMA_PRI_EVENT_PROCEEDING, "PROCEEDING"},
+	{14, SANGOMA_PRI_EVENT_SETUP_ACK, "SETUP_ACK"},
+	{15, SANGOMA_PRI_EVENT_HANGUP_REQ, "HANGUP_REQ"},
+	{16, SANGOMA_PRI_EVENT_NOTIFY, "NOTIFY"},
+	{17, SANGOMA_PRI_EVENT_PROGRESS, "PROGRESS"},
+	{18, SANGOMA_PRI_EVENT_KEYPAD_DIGIT, "KEYPAD_DIGIT"}
+};
+
+#define LINE "--------------------------------------------------------------------------------"
+
+char *sangoma_pri_event_str(sangoma_pri_event_t event_id)
+{ 
+	return SANGOMA_PRI_EVENT_LIST[event_id].name;
+}
+
+static int __pri_sangoma_read(struct pri *pri, void *buf, int buflen)
+{
+	struct sangoma_pri *spri = (struct sangoma_pri *) pri->userdata;
+	ftdm_size_t len = buflen;
+	int res;
+	char bb[4096] = "";
+
+
+	if (ftdm_channel_read(spri->zdchan, buf, &len) != FTDM_SUCCESS) {
+		printf("D-READ FAIL! [%s]\n", spri->zdchan->last_error);
+		return 0;
+	}
+	res = (int)len;
+	memset(&((unsigned char*)buf)[res],0,2);
+	res+=2;
+
+	//print_bits(buf, res-2, bb, sizeof(bb), 1, 0);
+	//ftdm_log(FTDM_LOG_DEBUG, "READ %d\n%s\n%s\n\n", res-2, LINE, bb);
+
+	return res;
+}
+
+static int __pri_sangoma_write(struct pri *pri, void *buf, int buflen)
+{
+	struct sangoma_pri *spri = (struct sangoma_pri *) pri->userdata;
+	int res;
+	ftdm_size_t len = buflen -2;
+	char bb[4096] = "";
+
+	if (ftdm_channel_write(spri->zdchan, buf, buflen, &len) != FTDM_SUCCESS) {
+		printf("D-WRITE FAIL! [%s]\n", spri->zdchan->last_error);
+        return 0;
+	}
+	
+	//print_bits(buf, (int)buflen-2, bb, sizeof(bb), 1, 0);
+	//ftdm_log(FTDM_LOG_DEBUG, "WRITE %d\n%s\n%s\n\n", (int)buflen-2, LINE, bb);
+
+	return (int) buflen;
+}
+
+int sangoma_init_pri(struct sangoma_pri *spri, int span, int dchan, int swtype, int node, int debug)
+{
+	int ret = -1;
+	ftdm_socket_t dfd = 0;
+
+	memset(spri, 0, sizeof(struct sangoma_pri));
+
+	if (ftdm_channel_open(span, dchan, &spri->zdchan) != FTDM_SUCCESS) {
+		fprintf(stderr, "Unable to open DCHAN %d for span %d (%s)\n", dchan, span, strerror(errno));
+	} else {
+		if ((spri->pri = pri_new_cb(spri->zdchan->sockfd, node, swtype, __pri_sangoma_read, __pri_sangoma_write, spri))){
+			spri->span = span;
+			pri_set_debug(spri->pri, debug);
+			ret = 0;
+		} else {
+			fprintf(stderr, "Unable to create PRI\n");
+		}
+	}
+	return ret;
+}
+
+
+int sangoma_one_loop(struct sangoma_pri *spri)
+{
+	fd_set rfds, efds;
+	struct timeval now = {0,0}, *next;
+	pri_event *event;
+    int sel;
+	
+	if (spri->on_loop) {
+		spri->on_loop(spri);
+	}
+
+	FD_ZERO(&rfds);
+	FD_ZERO(&efds);
+
+#ifdef _MSC_VER
+	//Windows macro for FD_SET includes a warning C4127: conditional expression is constant
+#pragma warning(push)
+#pragma warning(disable:4127)
+#endif
+
+	FD_SET(spri->pri->fd, &rfds);
+	FD_SET(spri->pri->fd, &efds);
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+	if ((next = pri_schedule_next(spri->pri))) {
+		gettimeofday(&now, NULL);
+		now.tv_sec = next->tv_sec - now.tv_sec;
+		now.tv_usec = next->tv_usec - now.tv_usec;
+		if (now.tv_usec < 0) {
+			now.tv_usec += 1000000;
+			now.tv_sec -= 1;
+		}
+		if (now.tv_sec < 0) {
+			now.tv_sec = 0;
+			now.tv_usec = 0;
+		}
+	}
+
+	sel = select(spri->pri->fd + 1, &rfds, NULL, &efds, next ? &now : NULL);
+	event = NULL;
+
+	if (!sel) {
+		event = pri_schedule_run(spri->pri);
+	} else if (sel > 0) {
+		event = pri_check_event(spri->pri);
+	}
+
+	if (event) {
+		event_handler handler;
+		/* 0 is catchall event handler */
+		if ((handler = spri->eventmap[event->e] ? spri->eventmap[event->e] : spri->eventmap[0] ? spri->eventmap[0] : NULL)) {
+			handler(spri, event->e, event);
+		} else {
+			fprintf(stderr,"No event handler found for event %d.\n", event->e);
+		}
+	}
+
+	return sel;
+}
+
+int sangoma_run_pri(struct sangoma_pri *spri)
+{
+	int ret = 0;
+
+	for (;;){
+		ret=sangoma_one_loop(spri);
+		if (ret < 0){
+
+#ifndef WIN32 //This needs to be adressed fror WIN32 still
+			if (errno == EINTR){
+				/* Igonore an interrupted system call */
+				continue;
+			}
+#endif	
+			printf("Error = %i\n",ret);
+			perror("Sangoma Run Pri: ");
+			break;		
+		}
+	}
+
+	return ret;
+
+}
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
+

Added: freeswitch/trunk/libs/freetdm/src/sangoma_pri.h (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/sangoma_pri.h	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/sangoma_pri.h	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,100 @@
+/*****************************************************************************
+ * libsangoma.c	AFT T1/E1: HDLC API Code Library
+ *
+ * Author(s):	Anthony Minessale II <anthmct@yahoo.com>
+ *              Nenad Corbic <ncorbic@sangoma.com>
+ *
+ * Copyright:	(c) 2005 Anthony Minessale II
+ *
+ *		This program is free software; you can redistribute it and/or
+ *		modify it under the terms of the GNU General Public License
+ *		as published by the Free Software Foundation; either version
+ *		2 of the License, or (at your option) any later version.
+ * ============================================================================
+ */
+
+#ifndef _SANGOMA_PRI_H
+#define _SANGOMA_PRI_H
+#include <libpri.h>
+#include <pri_internal.h>
+
+
+#define SANGOMA_MAX_CHAN_PER_SPAN 32
+
+typedef enum {
+	SANGOMA_PRI_EVENT_ANY = 0,
+	SANGOMA_PRI_EVENT_DCHAN_UP = PRI_EVENT_DCHAN_UP,
+	SANGOMA_PRI_EVENT_DCHAN_DOWN = PRI_EVENT_DCHAN_DOWN,
+	SANGOMA_PRI_EVENT_RESTART = PRI_EVENT_RESTART,
+	SANGOMA_PRI_EVENT_CONFIG_ERR = PRI_EVENT_CONFIG_ERR,
+	SANGOMA_PRI_EVENT_RING = PRI_EVENT_RING,
+	SANGOMA_PRI_EVENT_HANGUP = PRI_EVENT_HANGUP,
+	SANGOMA_PRI_EVENT_RINGING = PRI_EVENT_RINGING,
+	SANGOMA_PRI_EVENT_ANSWER = PRI_EVENT_ANSWER,
+	SANGOMA_PRI_EVENT_HANGUP_ACK = PRI_EVENT_HANGUP_ACK,
+	SANGOMA_PRI_EVENT_RESTART_ACK = PRI_EVENT_RESTART_ACK,
+	SANGOMA_PRI_EVENT_FACNAME = PRI_EVENT_FACNAME,
+	SANGOMA_PRI_EVENT_INFO_RECEIVED = PRI_EVENT_INFO_RECEIVED,
+	SANGOMA_PRI_EVENT_PROCEEDING = PRI_EVENT_PROCEEDING,
+	SANGOMA_PRI_EVENT_SETUP_ACK = PRI_EVENT_SETUP_ACK,
+	SANGOMA_PRI_EVENT_HANGUP_REQ = PRI_EVENT_HANGUP_REQ,
+	SANGOMA_PRI_EVENT_NOTIFY = PRI_EVENT_NOTIFY,
+	SANGOMA_PRI_EVENT_PROGRESS = PRI_EVENT_PROGRESS,
+	SANGOMA_PRI_EVENT_KEYPAD_DIGIT = PRI_EVENT_KEYPAD_DIGIT
+} sangoma_pri_event_t;
+
+typedef enum {
+	SANGOMA_PRI_NETWORK = PRI_NETWORK,
+	SANGOMA_PRI_CPE = PRI_CPE
+} sangoma_pri_node_t;
+
+typedef enum {
+	SANGOMA_PRI_SWITCH_UNKNOWN = PRI_SWITCH_UNKNOWN,
+	SANGOMA_PRI_SWITCH_NI2 = PRI_SWITCH_NI2,	   		
+	SANGOMA_PRI_SWITCH_DMS100 = PRI_SWITCH_DMS100,
+	SANGOMA_PRI_SWITCH_LUCENT5E = PRI_SWITCH_LUCENT5E,
+	SANGOMA_PRI_SWITCH_ATT4ESS = PRI_SWITCH_ATT4ESS,
+	SANGOMA_PRI_SWITCH_EUROISDN_E1 = PRI_SWITCH_EUROISDN_E1,
+	SANGOMA_PRI_SWITCH_EUROISDN_T1 = PRI_SWITCH_EUROISDN_T1,
+	SANGOMA_PRI_SWITCH_NI1 = PRI_SWITCH_NI1,
+	SANGOMA_PRI_SWITCH_GR303_EOC = PRI_SWITCH_GR303_EOC,
+	SANGOMA_PRI_SWITCH_GR303_TMC = PRI_SWITCH_GR303_TMC,
+	SANGOMA_PRI_SWITCH_QSIG = PRI_SWITCH_QSIG
+} sangoma_pri_switch_t;
+
+typedef enum {
+	SANGOMA_PRI_READY = (1 << 0)
+} sangoma_pri_flag_t;
+
+struct sangoma_pri;
+typedef int (*event_handler)(struct sangoma_pri *, sangoma_pri_event_t, pri_event *);
+typedef int (*loop_handler)(struct sangoma_pri *);
+#define MAX_EVENT 18
+
+struct sangoma_pri {
+	struct pri *pri;
+	int span;
+	int dchan;
+	unsigned int flags;
+	void *private_info;
+	event_handler eventmap[MAX_EVENT+1];
+	loop_handler on_loop;
+	ftdm_channel_t *zdchan;
+};
+
+struct sangoma_pri_event_list {
+	int event_id;
+	int pri_event;
+	char *name;
+};
+
+
+
+#define SANGOMA_MAP_PRI_EVENT(spri, event, func) spri.eventmap[event] = func;
+
+char *sangoma_pri_event_str(sangoma_pri_event_t event_id);
+int sangoma_one_loop(struct sangoma_pri *spri);
+int sangoma_init_pri(struct sangoma_pri *spri, int span, int dchan, int swtype, int node, int debug);
+int sangoma_run_pri(struct sangoma_pri *spri);
+
+#endif

Added: freeswitch/trunk/libs/freetdm/src/ss7/README (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/ss7/README	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/ss7/README	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,3 @@
+SS7 Coming soon
+
+-Shane Burrell-

Added: freeswitch/trunk/libs/freetdm/src/testanalog.c (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/testanalog.c	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/testanalog.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,133 @@
+#include "freetdm.h"
+
+
+static void *test_call(ftdm_thread_t *me, void *obj)
+{
+	ftdm_channel_t *chan = (ftdm_channel_t *) obj;
+	uint8_t frame[1024];
+	ftdm_size_t len;
+	char *number = strdup("5551212");
+
+	ftdm_sleep(10 * 1000);
+	
+	ftdm_log(FTDM_LOG_DEBUG, "answer call and start echo test\n");
+
+	ftdm_set_state_locked(chan, FTDM_CHANNEL_STATE_UP);
+	ftdm_channel_command(chan, FTDM_COMMAND_SEND_DTMF, number);
+
+	while (chan->state == FTDM_CHANNEL_STATE_UP) {
+		ftdm_wait_flag_t flags = FTDM_READ;
+		
+		if (ftdm_channel_wait(chan, &flags, -1) == FTDM_FAIL) {
+			break;
+		}
+		len = sizeof(frame);
+		if (flags & FTDM_READ) {
+			if (ftdm_channel_read(chan, frame, &len) == FTDM_SUCCESS) {
+				//ftdm_log(FTDM_LOG_DEBUG, "WRITE %d\n", len);
+				ftdm_channel_write(chan, frame, sizeof(frame), &len);
+			} else {
+				break;
+			}
+		}
+	}
+	
+	if (chan->state == FTDM_CHANNEL_STATE_UP) {
+		ftdm_set_state_locked(chan, FTDM_CHANNEL_STATE_BUSY);
+	}
+
+	ftdm_log(FTDM_LOG_DEBUG, "call over\n");
+	free(number);
+	return NULL;
+}
+
+static FIO_SIGNAL_CB_FUNCTION(on_signal)
+{
+	ftdm_log(FTDM_LOG_DEBUG, "got sig [%s]\n", ftdm_signal_event2str(sigmsg->event_id));
+
+	switch(sigmsg->event_id) {
+	case FTDM_SIGEVENT_START:
+		ftdm_set_state_locked(sigmsg->channel, FTDM_CHANNEL_STATE_RING);
+		ftdm_log(FTDM_LOG_DEBUG, "launching thread and indicating ring\n");
+		ftdm_thread_create_detached(test_call, sigmsg->channel);
+		break;
+	default:
+		break;
+	}
+
+	return FTDM_SUCCESS;
+}
+
+static int R = 0;
+#if 0
+static void handle_SIGINT(int sig)
+{
+	if (sig);
+	R = 0;
+	return;
+}
+#endif
+
+int main(int argc, char *argv[])
+{
+	ftdm_span_t *span;
+	int span_id;
+	int digit_timeout = 2000;
+	int max_dialstr = 11;
+
+	if (argc < 2) {
+		printf("usage %s <spanno>\n", argv[0]);
+		exit(-1);
+	}
+
+	span_id = atoi(argv[1]);
+
+	ftdm_global_set_default_logger(FTDM_LOG_LEVEL_DEBUG);
+
+	if (ftdm_global_init() != FTDM_SUCCESS) {
+		ftdm_log(FTDM_LOG_ERROR, "Error loading FreeTDM\n");
+		exit(-1);
+	}
+
+	ftdm_log(FTDM_LOG_DEBUG, "FreeTDM loaded\n");
+
+	if (ftdm_span_find(span_id, &span) != FTDM_SUCCESS) {
+		ftdm_log(FTDM_LOG_ERROR, "Error finding FreeTDM span\n");
+		goto done;
+	}
+	
+
+	if (ftdm_configure_span("analog", span, on_signal, 
+						   "tonemap", "us", 
+						   "digit_timeout", &digit_timeout,
+						   "max_dialstr", &max_dialstr,
+						   TAG_END
+						   ) != FTDM_SUCCESS) {
+		ftdm_log(FTDM_LOG_ERROR, "Error configuring FreeTDM span\n");
+		goto done;
+	}
+	ftdm_span_start(span);
+	
+	R = 1;
+
+	while(ftdm_running() && R) {
+		ftdm_sleep(1 * 1000);
+	}
+
+done:
+
+	ftdm_global_destroy();
+	return 0;
+}
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
+

Added: freeswitch/trunk/libs/freetdm/src/testapp.c (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/testapp.c	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/testapp.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,83 @@
+#include "freetdm.h"
+
+int main(int argc, char *argv[])
+{
+	ftdm_global_set_default_logger(FTDM_LOG_LEVEL_DEBUG);
+	ftdm_channel_t *chan;
+	unsigned ms = 20;
+	ftdm_codec_t codec = FTDM_CODEC_SLIN;
+	unsigned runs = 1;
+
+
+	if (ftdm_global_init() != FTDM_SUCCESS) {
+		fprintf(stderr, "Error loading FreeTDM\n");
+		exit(-1);
+	}
+
+	printf("FreeTDM loaded\n");
+
+ top:
+	//if (ftdm_channel_open_any("wanpipe", 0, FTDM_TOP_DOWN, &chan) == FTDM_SUCCESS) {
+	if (ftdm_channel_open(1, 1, &chan) == FTDM_SUCCESS) {
+		int x = 0;
+		printf("opened channel %d:%d\n", chan->span_id, chan->chan_id);
+
+#if 1
+		if (ftdm_channel_command(chan, FTDM_COMMAND_SET_INTERVAL, &ms) == FTDM_SUCCESS) {
+			ms = 0;
+			ftdm_channel_command(chan, FTDM_COMMAND_GET_INTERVAL, &ms);
+			printf("interval set to %u\n", ms);
+		} else {
+			printf("set interval failed [%s]\n", chan->last_error);
+		}
+#endif
+		if (ftdm_channel_command(chan, FTDM_COMMAND_SET_CODEC, &codec) == FTDM_SUCCESS) {
+			codec = 1;
+			ftdm_channel_command(chan, FTDM_COMMAND_GET_CODEC, &codec);
+			printf("codec set to %u\n", codec);
+		} else {
+			printf("set codec failed [%s]\n", chan->last_error);
+		}
+
+		for(x = 0; x < 25; x++) {
+			unsigned char buf[2048];
+			ftdm_size_t len = sizeof(buf);
+			ftdm_wait_flag_t flags = FTDM_READ;
+
+			if (ftdm_channel_wait(chan, &flags, -1) == FTDM_FAIL) {
+				printf("wait FAIL! %u [%s]\n", (unsigned)len, chan->last_error);
+			}
+			if (flags & FTDM_READ) {
+				if (ftdm_channel_read(chan, buf, &len) == FTDM_SUCCESS) {
+					printf("READ: %u\n", (unsigned)len); 
+				} else {
+					printf("READ FAIL! %u [%s]\n", (unsigned)len, chan->last_error);
+					break;
+				}
+			} else {
+				printf("wait fail [%s]\n", chan->last_error);
+			}
+		}
+		ftdm_channel_close(&chan);
+	} else {
+		printf("open fail [%s]\n", chan->last_error);
+	}
+
+	if(--runs) {
+		goto top;
+	}
+
+	ftdm_global_destroy();
+	return 0;
+}
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */

Added: freeswitch/trunk/libs/freetdm/src/testboost.c (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/testboost.c	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/testboost.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,82 @@
+#include "freetdm.h"
+
+static FIO_SIGNAL_CB_FUNCTION(on_signal)
+{
+	return FTDM_FAIL;
+}
+
+static int R = 0;
+#if 0
+static void handle_SIGINT(int sig)
+{
+	if (sig);
+	R = 0;
+	return;
+}
+#endif
+int main(int argc, char *argv[])
+{
+	ftdm_conf_parameter_t parameters[20];
+	ftdm_span_t *span;
+	int local_port, remote_port;
+
+	local_port = remote_port = 53000;
+
+	ftdm_global_set_default_logger(FTDM_LOG_LEVEL_DEBUG);
+#if 0
+	if (argc < 2) {
+		printf("invalid arguments\n");
+		exit(-1);
+	}
+#endif
+
+	if (ftdm_global_init() != FTDM_SUCCESS) {
+		fprintf(stderr, "Error loading FreeTDM\n");
+		exit(-1);
+	}
+	if (ftdm_global_configuration() != FTDM_SUCCESS) {
+		fprintf(stderr, "Error configuring FreeTDM\n");
+		exit(-1);
+	}
+
+	printf("FreeTDM loaded\n");
+
+	if (ftdm_span_find_by_name("wp1", &span) != FTDM_SUCCESS) {
+		fprintf(stderr, "Error finding FreeTDM span %s\n", argv[1]);
+		goto done;
+	}
+	parameters[0].var = "sigmod";	
+	parameters[0].val = "sangoma_prid";	
+	parameters[1].var = "switchtype";	
+	parameters[1].val = "euroisdn";	
+	parameters[1].var = "signalling";	
+	parameters[1].val = "pri_cpe";	
+	parameters[2].var = NULL;
+	if (ftdm_configure_span_signaling("sangoma_boost", span, on_signal, parameters) == FTDM_SUCCESS) {
+		ftdm_span_start(span);
+	} else {
+		fprintf(stderr, "Error starting SS7_BOOST\n");
+		goto done;
+	}
+
+	while(ftdm_running() && R) {
+		ftdm_sleep(1 * 1000);
+	}
+
+ done:
+
+	ftdm_global_destroy();
+
+	return 0;
+}
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */

Added: freeswitch/trunk/libs/freetdm/src/testcid.c (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/testcid.c	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/testcid.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,108 @@
+#include "freetdm.h"
+ftdm_status_t my_write_sample(int16_t *buf, ftdm_size_t buflen, void *user_data);
+
+struct helper {
+	int fd;
+	int wrote;
+};
+
+ftdm_status_t my_write_sample(int16_t *buf, ftdm_size_t buflen, void *user_data)
+{
+	struct helper *foo = (struct helper *) user_data;
+        size_t len;
+	len = write(foo->fd, buf, buflen * 2);
+        if (!len) return FTDM_FAIL;
+	foo->wrote += buflen * 2;
+	return FTDM_SUCCESS;
+}
+
+int main(int argc, char *argv[])
+{
+	struct ftdm_fsk_modulator fsk_trans;
+	ftdm_fsk_data_state_t fsk_data = {0};
+	int fd = -1;
+	int16_t buf[160] = {0};
+	ssize_t len = 0;
+	size_t type, mlen;
+	char *sp;
+	char str[128] = "";
+	char fbuf[256];
+	uint8_t databuf[1024] = "";
+	struct helper foo = {0};
+	//	int x, bytes, start_bits = 180, stop_bits = 5, sbits = 300;
+	char time_str[9];
+	struct tm tm;
+	time_t now;
+	
+	if (argc < 2) {
+		int x;
+		const char *url = "sip:cool@rad.com";
+
+		if ((fd = open("tone.raw", O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR)) < 0) {
+			fprintf(stderr, "File Error! [%s]\n", strerror(errno));
+			exit(-1);
+		}
+
+
+		time(&now);
+		localtime_r(&now, &tm);
+		strftime(time_str, sizeof(time_str), "%m%d%H%M", &tm);
+
+		ftdm_fsk_data_init(&fsk_data, databuf, sizeof(databuf));
+#if 1
+		
+		ftdm_fsk_data_add_mdmf(&fsk_data, MDMF_DATETIME, (uint8_t *)time_str, strlen(time_str));
+		//ftdm_fsk_data_add_mdmf(&fsk_data, MDMF_DATETIME, "06091213", 8);
+		ftdm_fsk_data_add_mdmf(&fsk_data, MDMF_PHONE_NUM, (uint8_t *)"14149361212", 7);
+		ftdm_fsk_data_add_mdmf(&fsk_data, MDMF_PHONE_NAME, (uint8_t *)"Fred Smith", 10);
+		for(x = 0; x < 0; x++)
+			ftdm_fsk_data_add_mdmf(&fsk_data, MDMF_ALT_ROUTE, (uint8_t *)url, strlen(url));
+#else
+		ftdm_fsk_data_add_sdmf(&fsk_data, "06061234", "0");
+		//ftdm_fsk_data_add_sdmf(&state, "06061234", "5551212");
+#endif
+		ftdm_fsk_data_add_checksum(&fsk_data);
+
+		foo.fd = fd;
+
+
+		ftdm_fsk_modulator_init(&fsk_trans, FSK_BELL202, 8000, &fsk_data, -14, 180, 5, 300, my_write_sample, &foo);
+		ftdm_fsk_modulator_send_all((&fsk_trans));
+
+		printf("%u %d %d\n", (unsigned) fsk_data.dlen, foo.wrote, fsk_trans.est_bytes);
+
+		if (fd > -1) {
+			close (fd);
+		}
+
+		return 0;
+	}
+
+	if (ftdm_fsk_demod_init(&fsk_data, 8000, (uint8_t *)fbuf, sizeof(fbuf))) {
+		printf("wtf\n");
+		return 0;
+	}
+
+	if ((fd = open(argv[1], O_RDONLY)) < 0) {
+		fprintf(stderr, "cant open file %s\n", argv[1]);
+		exit (-1);
+	}
+
+	while((len = read(fd, buf, sizeof(buf))) > 0) {
+		if (ftdm_fsk_demod_feed(&fsk_data, buf, len / 2) != FTDM_SUCCESS) {
+			break;
+		}
+	}
+
+	while(ftdm_fsk_data_parse(&fsk_data, &type, &sp, &mlen) == FTDM_SUCCESS) {
+		ftdm_copy_string(str, sp, mlen+1);
+		*(str+mlen) = '\0';
+		ftdm_clean_string(str);
+		printf("TYPE %u (%s) LEN %u VAL [%s]\n", (unsigned)type, ftdm_mdmf_type2str(type), (unsigned)mlen, str);
+	}
+
+	ftdm_fsk_demod_destroy(&fsk_data);
+
+	close(fd);
+	return 0;
+}

Added: freeswitch/trunk/libs/freetdm/src/testisdn.c (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/testisdn.c	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/testisdn.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,74 @@
+#include "freetdm.h"
+#include <signal.h>
+
+
+static FIO_SIGNAL_CB_FUNCTION(on_signal)
+{
+	return FTDM_FAIL;
+}
+
+static int R = 0;
+static void handle_SIGINT(int sig)
+{
+	if (sig);
+	R = 0;
+	return;
+}
+
+int main(int argc, char *argv[])
+{
+	ftdm_span_t *span;
+	
+	ftdm_global_set_default_logger(FTDM_LOG_LEVEL_DEBUG);
+
+	if (argc < 2) {
+		printf("umm no\n");
+		exit(-1);
+	}
+
+	if (ftdm_global_init() != FTDM_SUCCESS) {
+		fprintf(stderr, "Error loading FreeTDM\n");
+		exit(-1);
+	}
+
+	printf("FreeTDM loaded\n");
+
+	if (ftdm_span_find(atoi(argv[1]), &span) != FTDM_SUCCESS) {
+		fprintf(stderr, "Error finding FreeTDM span\n");
+		goto done;
+	}
+	
+	if (ftdm_configure_span("isdn", span, on_signal, 
+						   "mode", "te", 
+						   "dialect", "national",
+						   TAG_END) == FTDM_SUCCESS) {
+		ftdm_span_start(span);
+	} else {
+		fprintf(stderr, "Error starting ISDN D-Channel\n");
+		goto done;
+	}
+
+	signal(SIGINT, handle_SIGINT);
+	R = 1;
+	while(R) {
+		ftdm_sleep(1 * 1000);
+	}
+
+ done:
+
+	ftdm_global_destroy();
+
+	return 1;
+
+}
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */

Added: freeswitch/trunk/libs/freetdm/src/testm3ua.c (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/testm3ua.c	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/testm3ua.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,60 @@
+/*
+ *  testm3ua.c
+ *  freetdm
+ *
+ *  Created by Shane Burrell on 4/8/08.
+ *  Copyright 2008 __MyCompanyName__. All rights reserved.
+ *
+ */
+
+#include "testm3ua.h"
+#include "freetdm.h"
+#include "ftdm_m3ua.h"
+
+static FIO_SIGNAL_CB_FUNCTION(on_signal)
+{
+	return FTDM_FAIL;
+}
+
+int main(int argc, char *argv[])
+{
+	ftdm_span_t *span;
+	//m3ua_data_t *data;
+
+	ftdm_global_set_default_logger(FTDM_LOG_LEVEL_DEBUG);
+
+	if (argc < 5) {
+		printf("more args needed\n");
+		exit(-1);
+	}
+
+	if (ftdm_global_init() != FTDM_SUCCESS) {
+		fprintf(stderr, "Error loading FreeTDM\n");
+		exit(-1);
+	}
+
+	printf("FreeTDM loaded\n");
+
+	if (ftdm_span_find(atoi(argv[1]), &span) != FTDM_SUCCESS) {
+		fprintf(stderr, "Error finding FreeTDM span\n");
+		goto done;
+	}
+	
+
+	if (ftdm_m3ua_configure_span(span) == FTDM_SUCCESS) {
+		//data = span->signal_data;
+		ftdm_m3ua_start(span);
+	} else {
+		fprintf(stderr, "Error starting M3UA\n");
+		goto done;
+	}
+
+	//while(ftdm_test_flag(data, FTDM_M3UA_RUNNING)) {
+	//	ftdm_sleep(1 * 1000);
+	//}
+
+ done:
+
+	ftdm_global_destroy();
+
+}

Added: freeswitch/trunk/libs/freetdm/src/testpri.c (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/testpri.c	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/testpri.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,162 @@
+#include "freetdm.h"
+#include <signal.h>
+
+static int THREADS[4][31] = { {0} };
+static int R = 0;
+static int T = 0;
+static ftdm_mutex_t *mutex = NULL;
+
+
+static void *channel_run(ftdm_thread_t *me, void *obj)
+{
+	ftdm_channel_t *ftdmchan = obj;
+	int fd = -1;
+	short buf[160];
+
+	ftdm_mutex_lock(mutex);
+	T++;
+	ftdm_mutex_unlock(mutex);
+
+	ftdm_set_state_locked_wait(ftdmchan, FTDM_CHANNEL_STATE_UP);
+
+	if ((fd = open("test.raw", O_RDONLY, 0)) < 0) {
+		goto end;
+	}
+
+	while(R == 1 && THREADS[ftdmchan->span_id][ftdmchan->chan_id] == 1) {
+		ssize_t bytes = read(fd, buf, sizeof(buf));
+		size_t bbytes;
+
+		if (bytes <= 0) {
+			break;
+		}
+
+		bbytes = (size_t) bytes;
+
+		fio_slin2alaw(buf, sizeof(buf), &bbytes);
+
+		if (ftdm_channel_write(ftdmchan, buf, sizeof(buf), &bbytes) != FTDM_SUCCESS) {
+			break;
+		}
+	}
+
+	close(fd);
+
+ end:
+
+	ftdm_set_state_locked_wait(ftdmchan, FTDM_CHANNEL_STATE_HANGUP);
+
+	THREADS[ftdmchan->span_id][ftdmchan->chan_id] = 0;
+
+	ftdm_mutex_lock(mutex);
+	T = 0;
+	ftdm_mutex_unlock(mutex);
+	
+	return NULL;
+}
+
+static FIO_SIGNAL_CB_FUNCTION(on_signal)
+{
+	ftdm_log(FTDM_LOG_DEBUG, "got sig %d:%d [%s]\n", sigmsg->channel->span_id, sigmsg->channel->chan_id, ftdm_signal_event2str(sigmsg->event_id));
+
+    switch(sigmsg->event_id) {
+
+	case FTDM_SIGEVENT_STOP:
+		THREADS[sigmsg->channel->span_id][sigmsg->channel->chan_id] = -1;
+		break;
+
+	case FTDM_SIGEVENT_START:
+		if (!THREADS[sigmsg->channel->span_id][sigmsg->channel->chan_id]) {
+			THREADS[sigmsg->channel->span_id][sigmsg->channel->chan_id] = 1;
+			ftdm_thread_create_detached(channel_run, sigmsg->channel);
+		}
+		
+		break;
+	default:
+		break;
+	}
+	
+	return FTDM_SUCCESS;
+}
+
+
+static void handle_SIGINT(int sig)
+{
+	if (sig);
+
+	ftdm_mutex_lock(mutex);
+	R = 0;
+	ftdm_mutex_unlock(mutex);
+
+	return;
+}
+
+int main(int argc, char *argv[])
+{
+	ftdm_span_t *span;
+	ftdm_mutex_create(&mutex);
+
+	ftdm_global_set_default_logger(FTDM_LOG_LEVEL_DEBUG);
+
+	if (argc < 2) {
+		printf("umm no\n");
+		exit(-1);
+	}
+
+	if (ftdm_global_init() != FTDM_SUCCESS) {
+		fprintf(stderr, "Error loading FreeTDM\n");
+		exit(-1);
+	}
+
+	printf("FreeTDM loaded\n");
+
+	if (ftdm_span_find(atoi(argv[1]), &span) != FTDM_SUCCESS) {
+		fprintf(stderr, "Error finding FreeTDM span\n");
+		goto done;
+	}
+	
+
+
+	if (ftdm_configure_span(
+						   "libpri", span, on_signal,
+						   "node", "cpe",
+						   "switch", "euroisdn",
+						   "dp", "unknown",
+						   "l1", "alaw",
+						   "debug", NULL,
+						   "opts", 0,
+						   TAG_END) == FTDM_SUCCESS) {
+						   
+
+		ftdm_span_start(span);
+	} else {
+		fprintf(stderr, "Error starting ISDN D-Channel\n");
+		goto done;
+	}
+
+	signal(SIGINT, handle_SIGINT);
+	ftdm_mutex_lock(mutex);
+	R = 1;
+	ftdm_mutex_unlock(mutex);
+	while(R || T) {
+		ftdm_sleep(1 * 1000);
+	}
+
+ done:
+
+	ftdm_global_destroy();
+
+	return 1;
+
+}
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */

Added: freeswitch/trunk/libs/freetdm/src/testr2.c (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/testr2.c	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/testr2.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,86 @@
+#include "freetdm.h"
+#include <signal.h>
+
+static int R = 0;
+static ftdm_mutex_t *mutex = NULL;
+
+static FIO_SIGNAL_CB_FUNCTION(on_r2_signal)
+{
+    ftdm_log(FTDM_LOG_DEBUG, "Got R2 channel sig [%s] in channel\n", ftdm_signal_event2str(sigmsg->event_id), sigmsg->channel->physical_chan_id);
+    return FTDM_SUCCESS;
+}
+
+static void handle_SIGINT(int sig)
+{
+	ftdm_mutex_lock(mutex);
+	R = 0;
+	ftdm_mutex_unlock(mutex);
+	return;
+}
+
+int main(int argc, char *argv[])
+{
+	ftdm_span_t *span;
+	ftdm_mutex_create(&mutex);
+
+	ftdm_global_set_default_logger(FTDM_LOG_LEVEL_DEBUG);
+
+	if (argc < 2) {
+		printf("umm no\n");
+		exit(-1);
+	}
+
+	if (ftdm_global_init() != FTDM_SUCCESS) {
+		fprintf(stderr, "Error loading FreeTDM\n");
+		exit(-1);
+	}
+
+	printf("FreeTDM loaded\n");
+
+	if (ftdm_span_find(atoi(argv[1]), &span) != FTDM_SUCCESS) {
+		fprintf(stderr, "Error finding FreeTDM span\n");
+		goto done;
+	}
+	
+
+
+	if (ftdm_configure_span("r2", span, on_r2_signal,
+						   "variant", "mx",
+						   "max_ani", 10,
+						   "max_dnis", 4,
+						   "logging", "all",
+						   TAG_END) == FTDM_SUCCESS) {
+						   
+
+		ftdm_span_start(span);
+	} else {
+		fprintf(stderr, "Error starting R2 span\n");
+		goto done;
+	}
+
+	signal(SIGINT, handle_SIGINT);
+	ftdm_mutex_lock(mutex);
+	R = 1;
+	ftdm_mutex_unlock(mutex);
+	while(R) {
+		ftdm_sleep(1 * 1000);
+	}
+
+ done:
+
+	ftdm_global_destroy();
+
+	return 1;
+
+}
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */

Added: freeswitch/trunk/libs/freetdm/src/testsangomaboost.c (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/testsangomaboost.c	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/testsangomaboost.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,378 @@
+/*
+ * Copyright (c) 2010, Sangoma Technologies
+ * Moises Silva <moy@sangoma.com>
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * Sample program for the boost signaling absraction.
+ * Usage: boostsample <span name>
+ * The span name must be a valid span defined in freetdm.conf
+ * compile this program linking to the freetdm library (ie -lfreetdm)
+ **/
+
+#ifndef __linux__
+#define _CRT_SECURE_NO_WARNINGS 1
+#endif
+
+#include <signal.h>
+
+#include "freetdm.h"
+
+
+/* arbitrary limit for max calls in this sample program */
+#define MAX_CALLS 255
+
+/* some timers (in seconds) to fake responses in incoming calls */
+#define PROGRESS_TIMER 1
+#define ANSWER_TIMER 5
+#define HANGUP_TIMER 15
+
+/* simple variable used to stop the application */
+static int app_running = 0;
+
+typedef void (*expired_function_t)(ftdm_channel_t *channel);
+typedef struct dummy_timer_s {
+	int time;
+	ftdm_channel_t *channel;
+	expired_function_t expired;
+} dummy_timer_t;
+
+/* dummy second resolution timers */
+static dummy_timer_t g_timers[MAX_CALLS];
+
+/* mutex to protect the timers (both, the test thread and the signaling thread may modify them) */
+static ftdm_mutex_t *g_schedule_mutex;
+
+/* unique outgoing channel */
+static ftdm_channel_t *g_outgoing_channel = NULL;
+
+static void interrupt_requested(int signal)
+{
+	app_running = 0;
+}
+
+static void schedule_timer(ftdm_channel_t *channel, int sec, expired_function_t expired)
+{
+	int i;
+	ftdm_mutex_lock(g_schedule_mutex);
+	for (i = 0; i < sizeof(g_timers)/sizeof(g_timers[0]); i++) {
+		/* check the timer slot is free to use */
+		if (!g_timers[i].time) {
+			g_timers[i].time = sec;
+			g_timers[i].channel = channel;
+			g_timers[i].expired = expired;
+			ftdm_mutex_unlock(g_schedule_mutex);
+			return;
+		}
+	}
+	ftdm_log(FTDM_LOG_ERROR, "Failed to schedule timer\n");
+	ftdm_mutex_unlock(g_schedule_mutex);
+}
+
+static void run_timers(void)
+{
+	int i;
+	void *channel;
+	expired_function_t expired_func = NULL;
+	ftdm_mutex_lock(g_schedule_mutex);
+	for (i = 0; i < sizeof(g_timers)/sizeof(g_timers[0]); i++) {
+		/* if there's time left, decrement */
+		if (g_timers[i].time) {
+			g_timers[i].time--;
+		}
+
+		/* if time expired and we have an expired function, call it */
+		if (!g_timers[i].time && g_timers[i].expired) {
+			expired_func = g_timers[i].expired;
+			channel = g_timers[i].channel;
+			memset(&g_timers[i], 0, sizeof(g_timers[i]));
+			expired_func(channel);
+		}
+	}
+	ftdm_mutex_unlock(g_schedule_mutex);
+}
+
+static void release_timers(ftdm_channel_t *channel)
+{
+	int i;
+	ftdm_mutex_lock(g_schedule_mutex);
+	for (i = 0; i < sizeof(g_timers)/sizeof(g_timers[0]); i++) {
+		/* clear any timer belonging to the given channel */
+		if (g_timers[i].channel == channel) {
+			memset(&g_timers[i], 0, sizeof(g_timers[i]));
+		}
+	}
+	ftdm_mutex_unlock(g_schedule_mutex);
+}
+
+/*  hangup the call */ 
+static void send_hangup(ftdm_channel_t *channel)
+{
+	ftdm_log(FTDM_LOG_NOTICE, "-- Requesting hangup in channel %d:%d\n", channel->span_id, channel->chan_id);
+	ftdm_set_state_locked(channel, FTDM_CHANNEL_STATE_HANGUP);
+}
+
+/*  send answer for an incoming call */ 
+static void send_answer(ftdm_channel_t *channel)
+{
+	 /* we move the channel signaling state machine to UP (answered) */
+	ftdm_log(FTDM_LOG_NOTICE, "-- Requesting answer in channel %d:%d\n", channel->span_id, channel->chan_id);
+	ftdm_set_state_locked(channel, FTDM_CHANNEL_STATE_UP);
+	schedule_timer(channel, HANGUP_TIMER, send_hangup);
+}
+
+/* send progress for an incoming */
+static void send_progress(ftdm_channel_t *channel)
+{
+	 /* we move the channel signaling state machine to UP (answered) */
+	ftdm_log(FTDM_LOG_NOTICE, "-- Requesting progress\n", channel->span_id, channel->chan_id);
+	ftdm_set_state_locked(channel, FTDM_CHANNEL_STATE_PROGRESS);
+	schedule_timer(channel, ANSWER_TIMER, send_answer);
+}
+
+/* This function will be called in an undetermined signaling thread, you must not do 
+ * any blocking operations here or the signaling stack may delay other call event processing 
+ * The arguments for this function are defined in FIO_SIGNAL_CB_FUNCTION prototype, I just
+ * name them here for your convenience:
+ * ftdm_sigmsg_t *sigmsg
+ * - The sigmsg structure contains the ftdm_channel structure that represents the channel where
+ * the event occurred and the event_id of the signaling event that just occurred.
+ * */
+static FIO_SIGNAL_CB_FUNCTION(on_signaling_event)
+{
+	switch (sigmsg->event_id) {
+	/* This event signals the start of an incoming call */
+	case FTDM_SIGEVENT_START:
+		ftdm_log(FTDM_LOG_NOTICE, "Incoming call received in channel %d:%d\n", sigmsg->span_id, sigmsg->chan_id);
+		schedule_timer(sigmsg->channel, PROGRESS_TIMER, send_progress);
+		break;
+	/* This event signals progress on an outgoing call */
+	case FTDM_SIGEVENT_PROGRESS_MEDIA:
+		ftdm_log(FTDM_LOG_NOTICE, "Progress message received in channel %d:%d\n", sigmsg->span_id, sigmsg->chan_id);
+		break;
+	/* This event signals answer in an outgoing call */
+	case FTDM_SIGEVENT_UP:
+		ftdm_log(FTDM_LOG_NOTICE, "Answer received in channel %d:%d\n", sigmsg->span_id, sigmsg->chan_id);
+		/* now the channel is answered and we can use 
+		 * ftdm_channel_wait() to wait for input/output in a channel (equivalent to poll() or select())
+		 * ftdm_channel_read() to read available data in a channel
+		 * ftdm_channel_write() to write to the channel */
+		break;
+	/* This event signals hangup from the other end */
+	case FTDM_SIGEVENT_STOP:
+		ftdm_log(FTDM_LOG_NOTICE, "Hangup received in channel %d:%d\n", sigmsg->span_id, sigmsg->chan_id);
+		if (g_outgoing_channel == sigmsg->channel) {
+			g_outgoing_channel = NULL;
+		}
+		/* release any timer for this channel */
+		release_timers(sigmsg->channel);
+		/* acknowledge the hangup */
+		ftdm_set_state_locked(sigmsg->channel, FTDM_CHANNEL_STATE_HANGUP);
+		break;
+	default:
+		ftdm_log(FTDM_LOG_WARNING, "Unhandled event %s in channel %d:%d\n", ftdm_signal_event2str(sigmsg->event_id), 
+				sigmsg->span_id, sigmsg->chan_id);
+		break;
+	}
+	return FTDM_SUCCESS;
+}
+
+static void place_call(const ftdm_span_t *span, const char *number)
+{
+	ftdm_channel_t *ftdmchan = NULL;
+	ftdm_caller_data_t caller_data = {{ 0 }};
+	ftdm_status_t status = FTDM_FAIL;
+
+	/* set destiny number */
+	ftdm_set_string(caller_data.dnis.digits, number);
+
+	/* set callerid */
+	ftdm_set_string(caller_data.cid_name, "testsangomaboost");
+	ftdm_set_string(caller_data.cid_num.digits, "1234");
+
+	/* request to search for an outgoing channel top down with the given caller data.
+	 * it is also an option to use ftdm_channel_open_by_group to let freetdm hunt
+	 * an available channel in a given group instead of per span
+	 * */
+	status = ftdm_channel_open_by_span(span->span_id, FTDM_TOP_DOWN, &caller_data, &ftdmchan);
+	if (status != FTDM_SUCCESS) {
+		ftdm_log(FTDM_LOG_ERROR, "Failed to originate call\n");
+		return;
+	}
+
+	g_outgoing_channel = ftdmchan;
+
+	/* set the caller data for the outgoing channel */
+	memcpy(&ftdmchan->caller_data, &caller_data, sizeof(caller_data));
+
+	status = ftdm_channel_outgoing_call(ftdmchan);
+	if (status != FTDM_SUCCESS) {
+		ftdm_log(FTDM_LOG_ERROR, "Failed to originate call\n");
+		return;
+	}
+
+	/* this is required to initialize the outgoing channel */
+	ftdm_channel_init(ftdmchan);
+}
+
+int main(int argc, char *argv[])
+{
+	ftdm_conf_parameter_t parameters[20];
+	ftdm_span_t *span;
+	char *todial = NULL;
+	int32_t ticks = 0;
+
+	if (argc < 2) {
+		fprintf(stderr, "Usage: %s <span name> [number to dial if any]\n", argv[0]);
+		exit(-1);
+	}
+
+	/* register a handler to shutdown things properly */
+	if (signal(SIGINT, interrupt_requested) == SIG_ERR) {
+		fprintf(stderr, "Could not set the SIGINT signal handler: %s\n", strerror(errno));
+		exit(-1);
+	}
+
+	if (argc >= 3) {
+		todial = argv[2];
+		if (!strlen(todial)) {
+			todial = NULL;
+		}
+	}
+
+	/* clear any outstanding timers */
+	memset(&g_timers, 0, sizeof(g_timers));
+
+	/* set the logging level to use */
+	ftdm_global_set_default_logger(FTDM_LOG_LEVEL_DEBUG);
+
+	/* Initialize the FTDM library */
+	if (ftdm_global_init() != FTDM_SUCCESS) {
+		fprintf(stderr, "Error loading FreeTDM\n");
+		exit(-1);
+	}
+
+	/* create the schedule mutex */
+	ftdm_mutex_create(&g_schedule_mutex);
+
+	/* Load the FreeTDM configuration */
+	if (ftdm_global_configuration() != FTDM_SUCCESS) {
+		fprintf(stderr, "Error configuring FreeTDM\n");
+		exit(-1);
+	}
+
+	/* At this point FreeTDM is ready to be used, the spans defined in freetdm.conf have the basic I/O board configuration
+	 * but no telephony signaling configuration at all. */
+	printf("FreeTDM loaded ...\n");
+
+	/* Retrieve a span by name (according to freetdm.conf) */
+	if (ftdm_span_find_by_name(argv[1], &span) != FTDM_SUCCESS) {
+		fprintf(stderr, "Error finding FreeTDM span %s\n", argv[1]);
+		goto done;
+	}
+
+	/* prepare the configuration parameters that will be sent down to the signaling stack, the array of paramters must be terminated by an 
+	 * array element with a null .var member */
+
+	/* for sangoma_boost signaling (abstraction signaling used by Sangoma for PRI, BRI and SS7) the first parameter you must send
+	 * is sigmod, which must be either sangoma_prid, if you have the PRI stack available, or sangoma_brid for the BRI stack */
+	parameters[0].var = "sigmod";	
+	parameters[0].val = "sangoma_prid";	
+
+	/* following parameters are signaling stack specific, this ones are for PRI */
+	parameters[1].var = "switchtype";
+	parameters[1].val = "national";
+
+	parameters[2].var = "signalling";
+	parameters[2].val = "pri_cpe";
+
+	/*
+	 * parameters[3].var = "nfas_primary";
+	 * parameters[3].val = "4"; //span number
+	 *
+	 * parameters[4].var = "nfas_secondary";
+	 * parameters[4].val = "2"; //span number
+	 *
+	 * parameters[5].var = "nfas_group";
+	 * parameters[5].val = "1";
+	 * */
+
+	/* the last parameter .var member must be NULL! */
+	parameters[3].var = NULL;
+
+	/* send the configuration values down to the stack */
+	if (ftdm_configure_span_signaling("sangoma_boost", span, on_signaling_event, parameters) != FTDM_SUCCESS) {
+		fprintf(stderr, "Error configuring sangoma_boost signaling abstraction in span %s\n", span->name);
+		goto done;
+	}
+
+	/* configuration succeeded, we can proceed now to start the span
+	 * This step will launch at least 1 background (may be more, depending on the signaling stack used)
+	 * to handle *ALL* signaling events for this span, your on_signaling_event callback will be called always
+	 * in one of those infraestructure threads and you MUST NOT block in that handler to avoid delays and errors 
+	 * in the signaling processing for any call.
+	 * */
+	ftdm_span_start(span);
+
+	app_running = 1;
+
+	/* The application thread can go on and do anything else, like waiting for a shutdown signal */
+	while(ftdm_running() && app_running) {
+		ftdm_sleep(1000);
+		run_timers();
+		ticks++;
+		if (!(ticks % 10) && todial && !g_outgoing_channel) {
+			ftdm_log(FTDM_LOG_NOTICE, "Originating call to number %s\n", todial);
+			place_call(span, todial);
+		}
+	}
+	printf("Shutting down FreeTDM ...\n");
+ done:
+
+	ftdm_mutex_destroy(&g_schedule_mutex);
+
+	/* whenever you're done, this function will shutdown the signaling threads in any span that was started */
+	ftdm_global_destroy();
+
+	return 0;
+}
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */

Added: freeswitch/trunk/libs/freetdm/src/testtones.c (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/testtones.c	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/testtones.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,76 @@
+#include "freetdm.h"
+
+struct ttmp {
+	int fd;
+};
+
+static int teletone_handler(teletone_generation_session_t *ts, teletone_tone_map_t *map)
+{
+	struct ttmp *tmp = ts->user_data;
+	int wrote;
+	size_t len;
+
+	wrote = teletone_mux_tones(ts, map);
+	len = write(tmp->fd, ts->buffer, wrote * 2);
+	
+	if (!len) return -1;
+
+	return 0;
+}
+
+#if 1
+int main(int argc, char *argv[])
+{
+	teletone_generation_session_t ts;
+	struct ttmp tmp;
+
+	if (argc < 3) {
+		fprintf(stderr, "Arg Error! <file> <tones>\n");
+		exit(-1);
+	}
+
+	if ((tmp.fd = open(argv[1], O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR)) < 0) {
+		fprintf(stderr, "File Error! [%s]\n", strerror(errno));
+		exit(-1);
+	}
+
+	teletone_init_session(&ts, 0, teletone_handler, &tmp);
+	ts.rate = 8000;
+	ts.debug = 1;
+	ts.debug_stream = stdout;
+	teletone_run(&ts, argv[2]);
+	close(tmp.fd);
+
+	return 0;
+}
+#else 
+int32_t main(int argc, char *argv[])
+{
+	int32_t j, i, fd = -1;
+	int32_t rate = 8000;
+	/* SIT tones and durations */
+	float tones[] = { 913.8, 1370.6, 1776.7, 0 };
+	int32_t durations[] = {274, 274, 380, 0};
+	teletone_dds_state_t dds = {0};
+	int16_t sample;
+	size_t len = 1;
+
+	if (argc < 2 || (fd = open(argv[1], O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR)) < 0) {
+		fprintf(stderr, "File Error!\n", strerror(errno));
+		exit(-1);
+	}
+
+	for (j = 0; tones[j] && durations[j]; j++) {
+
+		teletone_dds_state_set_tone(&dds, tones[j], rate, -50);
+		
+		for(i = 0; (i < durations[j] * rate / 1000) && len != 0; i++) {
+			sample = teletone_dds_modulate_sample(&dds) * 20;
+			len = write(fd, &sample, sizeof(sample));
+		}
+
+	}
+	
+	close(fd);
+}
+#endif

Added: freeswitch/trunk/libs/freetdm/src/uart.c (0 => 17141)


--- freeswitch/trunk/libs/freetdm/src/uart.c	                        (rev 0)
+++ freeswitch/trunk/libs/freetdm/src/uart.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,125 @@
+
+/*
+ *	uart.c
+ *
+ *	Copyright (c) 2005 Robert Krten.  All Rights Reserved.
+ *
+ *	Redistribution and use in source and binary forms, with or without
+ *	modification, are permitted provided that the following conditions
+ *	are met:
+ *
+ *	1. Redistributions of source code must retain the above copyright
+ *	   notice, this list of conditions and the following disclaimer.
+ *	2. Redistributions in binary form must reproduce the above copyright
+ *	   notice, this list of conditions and the following disclaimer in the
+ *	   documentation and/or other materials provided with the distribution.
+ *
+ *	THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
+ *	ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ *	IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ *	ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE
+ *	FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ *	DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ *	OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ *	HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ *	LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ *	OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ *	SUCH DAMAGE.
+ *
+ *	This module contains a simple 8-bit UART, which performs a callback
+ *	with the decoded byte value.
+ *
+ *	2005 06 11	R. Krten		created
+*/
+
+#include <freetdm.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include "uart.h"
+
+/*
+ *	dsp_uart_attr_init
+ *
+ *	Initializes the attributes structure; this must be done before the
+ *	attributes structure is used.
+*/
+
+void dsp_uart_attr_init (dsp_uart_attr_t *attr)
+{
+	memset (attr, 0, sizeof (*attr));
+}
+
+/*
+ *	dsp_uart_attr_get_bytehandler
+ *	dsp_uart_attr_set_bytehandler
+ *
+ *	These functions get and set their respective elements from the
+ *	attributes structure.  If an error code is returned, it is just
+ *	zero == ok, -1 == fail.
+*/
+
+bytehandler_func_t dsp_uart_attr_get_bytehandler(dsp_uart_attr_t *attr, void **bytehandler_arg)
+{
+	*bytehandler_arg = attr->bytehandler_arg;
+	return attr->bytehandler;
+}
+
+void dsp_uart_attr_set_bytehandler(dsp_uart_attr_t *attr, bytehandler_func_t bytehandler, void *bytehandler_arg)
+{
+	attr->bytehandler = bytehandler;
+	attr->bytehandler_arg = bytehandler_arg;
+}
+
+dsp_uart_handle_t *dsp_uart_create(dsp_uart_attr_t *attr)
+{
+	dsp_uart_handle_t *handle;
+
+	handle = ftdm_malloc(sizeof (*handle));
+	if (handle) {
+		memset(handle, 0, sizeof (*handle));
+
+		/* fill the attributes member */
+		memcpy(&handle->attr, attr, sizeof (*attr));
+	}
+	return handle;
+}
+
+void dsp_uart_destroy(dsp_uart_handle_t **handle)
+{
+	if (*handle) {
+		ftdm_safe_free(*handle);
+		*handle = NULL;
+	}
+}
+
+
+void dsp_uart_bit_handler(void *x, int bit)
+{
+	dsp_uart_handle_t *handle = (dsp_uart_handle_t *) x;
+
+	if (!handle->have_start) {
+		if (bit) {
+			return;		/* waiting for start bit (0) */
+		}
+		handle->have_start = 1;
+		handle->data = 0;
+		handle->nbits = 0;
+		return;
+	}
+
+	handle->data >>= 1;
+	handle->data |= 0x80 * !!bit;
+	handle->nbits++;
+
+	if (handle->nbits == 8) {
+		handle->attr.bytehandler(handle->attr.bytehandler_arg, handle->data);
+		handle->nbits = 0;
+		handle->data = 0;
+		handle->have_start = 0;
+	}
+/* might consider handling errors in the future... */
+}
+

Added: freeswitch/trunk/libs/openzap/.gitignore (0 => 17141)


--- freeswitch/trunk/libs/openzap/.gitignore	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/.gitignore	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,13 @@
+*.o
+*.lo
+*.so
+*.a
+*.orig
+*.rej
+*.log
+
+Makefile
+config.*
+configure
+libtool
+aclocal.m4

Added: freeswitch/trunk/libs/openzap/.update (0 => 17141)


--- freeswitch/trunk/libs/openzap/.update	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/.update	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1 @@
+Fri Oct  3 17:54:41 EDT 2008

Added: freeswitch/trunk/libs/openzap/AUTHORS ( => )



Added: freeswitch/trunk/libs/openzap/ChangeLog
===================================================================

Added: freeswitch/trunk/libs/openzap/Makefile.am (0 => 17141)


--- freeswitch/trunk/libs/openzap/Makefile.am	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/Makefile.am	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,272 @@
+# Copyright (c) 2007, Anthony Minessale II
+# All rights reserved.
+# 
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 
+# * Neither the name of the original author; nor the names of any contributors
+# may be used to endorse or promote products derived from this software
+# without specific prior written permission.
+# 
+# 
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+# OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+PREFIX = $(prefix)
+SRC    = src
+
+moddir = @modinstdir@
+libdir = @libdir@
+library_includedir = $(PREFIX)/include
+
+INCS      = -I$(OZ_SRCDIR)/$(SRC)/include -I$(OZ_SRCDIR)/$(SRC)/isdn/include
+if HAVE_SCTP
+INCS +=  -I$(OZ_SRCDIR)/$(SRC)/ozmod/ozmod_sangoma_boost 
+endif
+MY_CFLAGS = $(INCS) $(ZAP_CFLAGS) -DZAP_CONFIG_DIR=\"@confdir@\" -DZAP_MOD_DIR=\"$(moddir)\" @COMP_VENDOR_CFLAGS@ @DEFS@
+COMPILE   = $(CC) $(MY_CFLAGS) $(INCS)
+LTCOMPILE = $(LIBTOOL) --mode=compile --tag=CC $(COMPILE)
+LINK      = $(LIBTOOL) --mode=link --tag=CC $(CC) $(MY_CFLAGS) $(LDFLAGS) -o $@
+
+
+#
+# GNU pkgconfig file
+#
+EXTRA_DIST = openzap.pc.in
+
+pkgconfigdir   = $(libdir)/pkgconfig
+pkgconfig_DATA = openzap.pc
+
+
+#
+# libopenzap
+#
+libopenzap_la_SOURCES = \
+$(SRC)/hashtable.c \
+$(SRC)/hashtable_itr.c \
+$(SRC)/zap_io.c \
+$(SRC)/zap_config.c \
+$(SRC)/zap_callerid.c \
+$(SRC)/fsk.c \
+$(SRC)/uart.c \
+$(SRC)/g711.c \
+$(SRC)/libteletone_detect.c \
+$(SRC)/libteletone_generate.c \
+$(SRC)/zap_buffer.c \
+$(SRC)/zap_threadmutex.c \
+$(SRC)/zap_dso.c \
+$(SRC)/zap_cpu_monitor.c
+
+library_include_HEADERS = \
+$(SRC)/include/fsk.h \
+$(SRC)/include/g711.h \
+$(SRC)/include/hashtable.h \
+$(SRC)/include/hashtable_itr.h \
+$(SRC)/include/hashtable_private.h \
+$(SRC)/include/libteletone_detect.h \
+$(SRC)/include/libteletone_generate.h \
+$(SRC)/include/libteletone.h \
+$(SRC)/include/openzap.h \
+$(SRC)/include/sangoma_tdm_api.h \
+$(SRC)/include/uart.h \
+$(SRC)/include/zap_buffer.h \
+$(SRC)/include/zap_config.h \
+$(SRC)/include/zap_threadmutex.h \
+$(SRC)/include/zap_dso.h \
+$(SRC)/include/zap_types.h \
+$(SRC)/include/zap_cpu_monitor.h
+
+lib_LTLIBRARIES	       = libopenzap.la
+libopenzap_la_CFLAGS   = $(AM_CFLAGS) $(MY_CFLAGS)
+libopenzap_la_LDFLAGS  = -version-info 1:0:0 $(AM_LDFLAGS)
+libopenzap_la_LIBADD   = $(LIBS)
+
+MYLIB = libopenzap.la
+
+core: libopenzap.la 
+core-install: install-libLTLIBRARIES
+
+#
+# tools & test programs
+#
+noinst_PROGRAMS = testtones detect_tones detect_dtmf testisdn testpri testr2 testanalog testapp testcid
+if HAVE_SCTP
+noinst_PROGRAMS += testboost
+endif
+
+testapp_SOURCES = $(SRC)/testapp.c
+testapp_LDADD   = libopenzap.la
+testapp_CFLAGS  = $(AM_CFLAGS) $(MY_CFLAGS)
+
+testcid_SOURCES = $(SRC)/testcid.c
+testcid_LDADD   = libopenzap.la
+testcid_CFLAGS  = $(AM_CFLAGS) $(MY_CFLAGS)
+
+testtones_SOURCES = $(SRC)/testtones.c
+testtones_LDADD   = libopenzap.la
+testtones_CFLAGS  = $(AM_CFLAGS) $(MY_CFLAGS)
+
+detect_tones_SOURCES = $(SRC)/detect_tones.c
+detect_tones_LDADD   = libopenzap.la
+detect_tones_CFLAGS  = $(AM_CFLAGS) $(MY_CFLAGS)
+
+detect_dtmf_SOURCES = $(SRC)/detect_dtmf.c
+detect_dtmf_LDADD   = libopenzap.la
+detect_dtmf_CFLAGS  = $(AM_CFLAGS) $(MY_CFLAGS)
+
+testisdn_SOURCES = $(SRC)/testisdn.c
+testisdn_LDADD   = libopenzap.la
+testisdn_CFLAGS  = $(AM_CFLAGS) $(MY_CFLAGS)
+
+testpri_SOURCES = $(SRC)/testpri.c
+testpri_LDADD   = libopenzap.la
+testpri_CFLAGS  = $(AM_CFLAGS) $(MY_CFLAGS)
+
+testr2_SOURCES = $(SRC)/testr2.c
+testr2_LDADD   = libopenzap.la
+testr2_CFLAGS  = $(AM_CFLAGS) $(MY_CFLAGS)
+
+if HAVE_SCTP
+testboost_SOURCES = $(SRC)/testboost.c
+testboost_LDADD   = libopenzap.la
+testboost_CFLAGS  = $(AM_CFLAGS) $(MY_CFLAGS)
+endif
+
+testanalog_SOURCES = $(SRC)/testanalog.c
+testanalog_LDADD   = libopenzap.la
+testanalog_CFLAGS  = $(AM_CFLAGS) $(MY_CFLAGS)
+
+#
+# ozmod modules
+#
+mod_LTLIBRARIES = ozmod_zt.la ozmod_skel.la ozmod_isdn.la ozmod_analog.la ozmod_analog_em.la 
+
+
+if HAVE_SCTP 
+mod_LTLIBRARIES += ozmod_sangoma_boost.la
+endif
+
+if LIBSANGOMA
+mod_LTLIBRARIES += ozmod_wanpipe.la
+endif
+
+if LIBPRI
+mod_LTLIBRARIES += ozmod_libpri.la
+endif
+
+if OPENR2
+mod_LTLIBRARIES += ozmod_r2.la
+endif
+
+ozmod_zt_la_SOURCES = $(SRC)/ozmod/ozmod_zt/ozmod_zt.c
+ozmod_zt_la_CFLAGS  = $(AM_CFLAGS) $(MY_CFLAGS)
+ozmod_zt_la_LDFLAGS = -module -avoid-version
+ozmod_zt_la_LIBADD  = $(MYLIB)
+
+ozmod_skel_la_SOURCES = $(SRC)/ozmod/ozmod_skel/ozmod_skel.c
+ozmod_skel_la_CFLAGS  = $(AM_CFLAGS) $(MY_CFLAGS)
+ozmod_skel_la_LDFLAGS = -module -avoid-version
+ozmod_skel_la_LIBADD  = $(MYLIB)
+
+if LIBSANGOMA
+ozmod_wanpipe_la_SOURCES = $(SRC)/ozmod/ozmod_wanpipe/ozmod_wanpipe.c
+ozmod_wanpipe_la_CFLAGS  = $(AM_CFLAGS) $(MY_CFLAGS) -D__LINUX__ -I/usr/include/wanpipe
+ozmod_wanpipe_la_LDFLAGS = -module -avoid-version -lsangoma
+ozmod_wanpipe_la_LIBADD  = $(MYLIB)
+endif
+
+ozmod_isdn_la_SOURCES = \
+$(SRC)/isdn/EuroISDNStateNT.c \
+$(SRC)/isdn/EuroISDNStateTE.c \
+$(SRC)/isdn/mfifo.c \
+$(SRC)/isdn/Q921.c \
+$(SRC)/isdn/Q931api.c \
+$(SRC)/isdn/Q931.c \
+$(SRC)/isdn/Q931ie.c \
+$(SRC)/isdn/Q931mes.c \
+$(SRC)/isdn/Q931StateNT.c \
+$(SRC)/isdn/Q931StateTE.c \
+$(SRC)/isdn/nationalmes.c \
+$(SRC)/isdn/nationalStateNT.c \
+$(SRC)/isdn/nationalStateTE.c \
+$(SRC)/isdn/DMSmes.c \
+$(SRC)/isdn/DMSStateNT.c \
+$(SRC)/isdn/DMSStateTE.c \
+$(SRC)/isdn/5ESSmes.c \
+$(SRC)/isdn/5ESSStateNT.c \
+$(SRC)/isdn/5ESSStateTE.c \
+$(SRC)/isdn/Q932mes.c \
+$(SRC)/ozmod/ozmod_isdn/ozmod_isdn.c
+
+ozmod_isdn_la_CFLAGS  = $(AM_CFLAGS) $(MY_CFLAGS) -D_GNU_SOURCE
+ozmod_isdn_la_LDFLAGS = $(PCAP_LIB_FLAGS) -module -avoid-version
+ozmod_isdn_la_LIBADD  = $(MYLIB)
+
+ozmod_analog_la_SOURCES = $(SRC)/ozmod/ozmod_analog/ozmod_analog.c
+ozmod_analog_la_CFLAGS  = $(AM_CFLAGS) $(MY_CFLAGS)
+ozmod_analog_la_LDFLAGS = -module -avoid-version
+ozmod_analog_la_LIBADD  = $(MYLIB)
+
+ozmod_analog_em_la_SOURCES = $(SRC)/ozmod/ozmod_analog_em/ozmod_analog_em.c
+ozmod_analog_em_la_CFLAGS  = $(AM_CFLAGS) $(MY_CFLAGS)
+ozmod_analog_em_la_LDFLAGS = -module -avoid-version
+ozmod_analog_em_la_LIBADD  = $(MYLIB)
+
+if HAVE_SCTP
+ozmod_sangoma_boost_la_SOURCES = $(SRC)/ozmod/ozmod_sangoma_boost/sangoma_boost_client.c $(SRC)/ozmod/ozmod_sangoma_boost/ozmod_sangoma_boost.c
+ozmod_sangoma_boost_la_CFLAGS  = $(AM_CFLAGS) $(MY_CFLAGS)
+ozmod_sangoma_boost_la_LDFLAGS = -module -avoid-version
+ozmod_sangoma_boost_la_LIBADD  = $(MYLIB)
+endif
+
+if LIBPRI
+ozmod_libpri_la_SOURCES = $(SRC)/ozmod/ozmod_libpri/ozmod_libpri.c $(SRC)/ozmod/ozmod_libpri/lpwrap_pri.c
+ozmod_libpri_la_CFLAGS  = $(AM_CFLAGS) $(MY_CFLAGS)
+ozmod_libpri_la_LDFLAGS = -module  -avoid-version -lpri
+ozmod_libpri_la_LIBADD  = $(MYLIB)
+endif
+
+if OPENR2
+ozmod_r2_la_SOURCES = $(SRC)/ozmod/ozmod_r2/ozmod_r2.c 
+ozmod_r2_la_CFLAGS  = $(AM_CFLAGS) $(MY_CFLAGS)
+ozmod_r2_la_LDFLAGS = -module  -avoid-version -lopenr2
+ozmod_r2_la_LIBADD  = $(MYLIB)
+endif
+
+
+dox doxygen:
+	cd docs && doxygen $(OZ_SRCDIR)/docs/Doxygen.conf
+
+mod_openzap/mod_openzap.$(DYNAMIC_LIB_EXTEN): $(MYLIB) mod_openzap/mod_openzap.c
+	cd mod_openzap && make
+
+mod_openzap: mod_openzap/mod_openzap.$(DYNAMIC_LIB_EXTEN)
+
+mod_openzap-install: mod_openzap
+	cd mod_openzap && make install
+
+mod_openzap-clean:
+	@if [ -f mod_openzap/mod_openzap.$(DYNAMIC_LIB_EXTEN) ] ; then cd mod_openzap && make clean ; fi
+
+install-data-local:
+	$(mkinstalldirs) $(DESTDIR)$(PREFIX)
+	$(mkinstalldirs) $(DESTDIR)@confdir@
+	@[ -f "$(DESTDIR)@confdir@/openzap.conf" ] || ( cp conf/*.conf $(DESTDIR)@confdir@)
+	@echo OpenZAP Installed

Added: freeswitch/trunk/libs/openzap/NEWS ( => )



Added: freeswitch/trunk/libs/openzap/README
===================================================================
--- freeswitch/trunk/libs/openzap/README	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/README	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,3 @@
+OPENZAP (WORK IN PROGRESS)
+
+*shrug*

Added: freeswitch/trunk/libs/openzap/acinclude.m4 (0 => 17141)


--- freeswitch/trunk/libs/openzap/acinclude.m4	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/acinclude.m4	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1 @@
+m4_include([build/libpcap.m4])

Added: freeswitch/trunk/libs/openzap/bootstrap (0 => 17141)


--- freeswitch/trunk/libs/openzap/bootstrap	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/bootstrap	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,6 @@
+#!/bin/bash
+autoheader
+libtoolize --force --copy
+aclocal
+automake -f --copy --add-missing
+autoconf
Property changes on: freeswitch/trunk/libs/openzap/bootstrap
___________________________________________________________________
Name: svn:executable
   + *

Added: freeswitch/trunk/libs/openzap/build/libpcap.m4 (0 => 17141)


--- freeswitch/trunk/libs/openzap/build/libpcap.m4	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/build/libpcap.m4	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,144 @@
+dnl libpcap.m4--PCAP libraries and includes
+dnl Derrick Brashear
+dnl from KTH krb and Arla
+dnl $Id: libpcap.m4,v 1.4 2006/01/20 20:21:09 snsimon Exp $
+
+AC_DEFUN([PCAP_INC_WHERE1], [
+ac_cv_found_pcap_inc=no
+if test -f "$1/pcap.h" ; then
+  ac_cv_found_pcap_inc=yes
+fi
+])
+
+AC_DEFUN([PCAP_INC_WHERE], [
+   for i in $1; do
+      AC_MSG_CHECKING(for pcap header in $i)
+      PCAP_INC_WHERE1($i)
+      if test "$ac_cv_found_pcap_inc" = "yes"; then
+        ac_cv_pcap_where_inc=$i
+        AC_MSG_RESULT(found)
+        break
+      else
+        AC_MSG_RESULT(no found)
+      fi
+    done
+])
+
+AC_DEFUN([PCAP_LIB_WHERE1], [
+saved_LIBS=$LIBS
+LIBS="$saved_LIBS -L$1 -lpcap"
+AC_TRY_LINK(,
+[pcap_lookupdev("");],
+[ac_cv_found_pcap_lib=yes],
+ac_cv_found_pcap_lib=no)
+LIBS=$saved_LIBS
+])
+
+AC_DEFUN([TEST_LIBPATH], [
+changequote(<<, >>)
+define(<<AC_CV_FOUND>>, translit(ac_cv_found_$2_lib, <<- *>>, <<__p>>))
+changequote([, ])
+if test "$AC_CV_FOUND" = "yes"; then
+  if test \! -r "$1/lib$2.a" -a \! -r "$1/lib$2.so" -a \! -r "$1/lib$2.sl" -a \! -r "$1/lib$2.dylib"; then
+    AC_CV_FOUND=no
+  fi
+fi
+])
+
+
+AC_DEFUN([PCAP_LIB_WHERE], [
+   for i in $1; do
+      AC_MSG_CHECKING(for pcap library in $i)
+      PCAP_LIB_WHERE1($i)
+      TEST_LIBPATH($i, pcap)
+      if test "$ac_cv_found_pcap_lib" = "yes" ; then
+        ac_cv_pcap_where_lib=$i
+        AC_MSG_RESULT(found)
+        break
+      else
+        AC_MSG_RESULT(no found)
+      fi
+    done
+])
+
+AC_DEFUN([FIND_LIB_SUBDIR],
+[dnl
+AC_ARG_WITH([lib-subdir], AC_HELP_STRING([--with-lib-subdir=DIR],[Find libraries in DIR instead of lib]))
+AC_CHECK_SIZEOF(long)
+AC_CACHE_CHECK([what directory libraries are found in], [ac_cv_cmu_lib_subdir],
+[test "X$with_lib_subdir" = "Xyes" && with_lib_subdir=
+test "X$with_lib_subdir" = "Xno" && with_lib_subdir=
+ if test "X$with_lib_subdir" = "X" ; then
+   ac_cv_cmu_lib_subdir=lib
+   if test $ac_cv_sizeof_long -eq 4 ; then
+     test -d /usr/lib32 && ac_cv_cmu_lib_subdir=lib32
+     test -r /usr/lib/libpcap.so && ac_cv_cmu_lib_subdir=lib
+   fi
+   if test $ac_cv_sizeof_long -eq 8 ; then
+     test -d /usr/lib64 && ac_cv_cmu_lib_subdir=lib64
+   fi
+ else
+   ac_cv_cmu_lib_subdir=$with_lib_subdir
+ fi])
+ AC_SUBST(LIB_SUBDIR, $ac_cv_cmu_lib_subdir)
+ ])
+ 
+
+AC_DEFUN([AX_LIB_PCAP], [
+AC_REQUIRE([FIND_LIB_SUBDIR])
+AC_ARG_WITH(pcap,
+	[  --with-pcap=PREFIX      Compile with PCAP support],
+	[if test "X$with_pcap" = "X"; then
+		with_pcap=yes
+	fi])
+AC_ARG_WITH(pcap-lib,
+	[  --with-pcap-lib=dir     use pcap libraries in dir],
+	[if test "$withval" = "yes" -o "$withval" = "no"; then
+		AC_MSG_ERROR([No argument for --with-pcap-lib])
+	fi])
+AC_ARG_WITH(pcap-include,
+	[  --with-pcap-include=dir use pcap headers in dir],
+	[if test "$withval" = "yes" -o "$withval" = "no"; then
+		AC_MSG_ERROR([No argument for --with-pcap-include])
+	fi])
+
+	if test "X$with_pcap" != "X"; then
+	  if test "$with_pcap" != "yes"; then
+	    ac_cv_pcap_where_lib=$with_pcap
+	    ac_cv_pcap_where_inc=$with_pcap/include
+	  fi
+	fi
+
+	if test "X$with_pcap_lib" != "X"; then
+	  ac_cv_pcap_where_lib=$with_pcap_lib
+	fi
+	if test "X$ac_cv_pcap_where_lib" = "X"; then
+	  PCAP_LIB_WHERE(/usr/$LIB_SUBDIR /usr/local/$LIB_SUBDIR)
+	fi
+
+	if test "X$with_pcap_include" != "X"; then
+	  ac_cv_pcap_where_inc=$with_pcap_include
+	fi
+	if test "X$ac_cv_pcap_where_inc" = "X"; then
+	  PCAP_INC_WHERE(/usr/ng/include /usr/include /usr/local/include)
+	fi
+
+	AC_MSG_CHECKING(whether to include pcap)
+	if test "X$ac_cv_pcap_where_lib" != "X" -a "X$ac_cv_pcap_where_inc" != "X"; then
+	  ac_cv_found_pcap=yes
+	  AC_MSG_RESULT(yes)
+	  PCAP_INC_DIR=$ac_cv_pcap_where_inc
+	  PCAP_LIB_DIR=$ac_cv_pcap_where_lib
+	  PCAP_INC_FLAGS="-I${PCAP_INC_DIR}"
+	  PCAP_LIB_FLAGS="-L${PCAP_LIB_DIR} -lpcap"
+	  AC_SUBST(PCAP_INC_DIR)
+	  AC_SUBST(PCAP_LIB_DIR)
+	  AC_SUBST(PCAP_INC_FLAGS)
+	  AC_SUBST(PCAP_LIB_FLAGS)
+	  AC_DEFINE([HAVE_LIBPCAP],[1],[libpcap])
+        else
+	  ac_cv_found_pcap=no
+	  AC_MSG_RESULT(no)
+	fi
+	])
+

Added: freeswitch/trunk/libs/openzap/conf/m3ua.conf (0 => 17141)


--- freeswitch/trunk/libs/openzap/conf/m3ua.conf	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/conf/m3ua.conf	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,38 @@
+;M3UA SS7 Links Config
+;
+;ss7box-m3ua_mode => true
+;local_sctp_ip => localhost
+;local sctp_port => 30000
+;remote_sctp_ip => localhost
+;remote_sctp_port => 30001
+;opc => 0-0-0
+;dpc => 0-0-0
+
+
+; AP Specific Stuff.  This will likely move later.
+
+; CNAM Gateways
+cnam1_dpc => 0-0-0
+cnam1_ssn => 253
+cnam2_dpc => 0-0-0
+cnam2_ssn => 253
+cnam3_dpc => 0-0-0
+cnam3_ssn => 253
+
+;LNP Gateways
+lnp1_dpc => 0-0-0
+lnp1_ssn => 253
+lnp2_dpc => 0-0-0
+lnp2_ssn => 253
+lnp3_dpc => 0-0-0
+lnp3_ssn => 253
+
+;LNP Gateways
+sms8001_dpc => 0-0-0
+sms8001_ssn => 253
+sms8002_dpc => 0-0-0
+sms8002_ssn => 253
+sms8003_dpc => 0-0-0
+sms8003_ssn => 253
+
+

Added: freeswitch/trunk/libs/openzap/conf/openzap.conf (0 => 17141)


--- freeswitch/trunk/libs/openzap/conf/openzap.conf	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/conf/openzap.conf	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,19 @@
+[span wanpipe]
+name => OpenZAP
+number => 1
+fxs-channel => 1:3-4
+
+[span wanpipe]
+fxo-channel => 1:1-2
+
+[span zt]
+name => OpenZAP
+number => 2
+fxs-channel => 1
+
+[span zt]
+name => OpenZAP
+number => 2
+fxo-channel => 3
+
+

Added: freeswitch/trunk/libs/openzap/conf/openzap.conf.xml (0 => 17141)


--- freeswitch/trunk/libs/openzap/conf/openzap.conf.xml	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/conf/openzap.conf.xml	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,45 @@
+<configuration name="openzap.conf" description="OpenZAP Configuration">
+  <settings>
+    <param name="debug" value="0"/>
+    <!--<param name="hold-music" value="$${moh_uri}"/>-->
+    <!--<param name="enable-analog-option" value="call-swap"/>-->
+    <!--<param name="enable-analog-option" value="3-way"/>-->
+  </settings>
+   <pri_spans>
+     <span name="PRI_1">
+       <!-- Log Levels: none, alert, crit, err, warning, notice, info, debug -->
+       <param name="q921loglevel" value="alert"/>
+       <param name="q931loglevel" value="alert"/>
+       <param name="mode" value="user"/>
+       <param name="dialect" value="5ess"/>
+       <param name="dialplan" value="XML"/>
+       <param name="context" value="default"/>
+     </span>
+     <span name="PRI_2">
+       <param name="q921loglevel" value="alert"/>
+       <param name="q931loglevel" value="alert"/>
+       <param name="mode" value="user"/>
+       <param name="dialect" value="5ess"/>
+       <param name="dialplan" value="XML"/>
+       <param name="context" value="default"/>
+     </span>
+   </pri_spans>
+  <!-- one entry here per openzap span -->
+  <analog_spans>
+    <span id="1">
+      <!--<param name="hold-music" value="$${moh_uri}"/>-->
+      <!--<param name="enable-analog-option" value="call-swap"/>-->
+      <!--<param name="enable-analog-option" value="3-way"/>-->
+      <param name="tonegroup" value="us"/>
+      <param name="digit-timeout" value="2000"/>
+      <param name="max-digits" value="11"/>
+      <param name="dialplan" value="XML"/>
+      <param name="context" value="default"/>
+      <param name="enable-callerid" value="true"/>
+      <!-- regex to stop dialing when it matches -->
+      <!--<param name="dial-regex" value="5555"/>-->
+      <!-- regex to stop dialing when it does not match -->
+      <!--<param name="fail-dial-regex" value="^5"/>-->
+    </span>
+  </analog_spans>
+</configuration>

Added: freeswitch/trunk/libs/openzap/conf/pika.conf (0 => 17141)


--- freeswitch/trunk/libs/openzap/conf/pika.conf	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/conf/pika.conf	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,41 @@
+; each category is a config profile
+; to apply the profile append it to a channel def in
+; openzap.conf with @<profile_name>
+; e.g.
+; [span pika]
+; name => pika
+; number => pika
+; fxs-channel => 1:0:1-12@default
+
+[default]
+; region is na or eu
+;region => na
+;rx-gain => 0.00
+;rx-agc-enabled => false
+;rx-agc-targetPower => -15.00
+;rx-agc-minGain => -6.00
+;rx-agc-maxGain => 18.00
+;rx-agc-attackRate => 170
+;rx-agc-decayRate => 750
+;rx-agc-speechThreshold => -36.00
+;rx-vad-enabled => false
+;rx-vad-activationThreshold => -40.00
+;rx-vad-activationDebounceTime => 72
+;rx-vad-deactivationThreshold => -40.00
+;rx-vad-deactivationDebounceTime => 984
+;rx-vad-preSpeechBufferSize => 240
+;tx-gain => 0.00
+;tx-agc-enabled => true
+;tx-agc-targetPower => -15.00
+;tx-agc-minGain => -6.00
+;tx-agc-maxGain => 18.00
+;tx-agc-attackRate => 170
+;tx-agc-decayRate => 750
+;tx-agc-speechThreshold => -36.00
+;ec-enabled => false
+;ec-doubleTalkerThreshold => -6.00
+;ec-speechPresentThreshold => -40.00
+;ec-echoSuppressionThreshold => -18.00
+;ec-echoSuppressionEnabled => true
+;ec-comfortNoiseEnabled => true
+;ec-adaptationModeEnabled => true

Added: freeswitch/trunk/libs/openzap/conf/tones.conf (0 => 17141)


--- freeswitch/trunk/libs/openzap/conf/tones.conf	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/conf/tones.conf	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,63 @@
+[us]
+generate-dial => v=-7;%(1000,0,350,440)
+detect-dial => 350,440
+
+generate-ring => v=-7;%(2000,4000,440,480)
+detect-ring => 440,480
+
+generate-busy => v=-7;%(500,500,480,620)
+detect-busy => 480,620
+
+generate-attn => v=0;%(100,100,1400,2060,2450,2600)
+detect-attn => 1400,2060,2450,2600
+
+generate-callwaiting-sas => v=0;%(300,0,440)
+detect-callwaiting-sas => 440
+
+generate-callwaiting-cas => v=0;%(80,0,2750,2130)
+detect-callwaiting-cas => 2750,2130
+
+detect-fail1 => 913.8
+detect-fail2 => 1370.6
+detect-fail3 => 1776.7
+
+
+[sg]
+generate-dial => v=-7;%(1000,0,425)
+detect-dial => 425
+
+generate-ring => v=-7;%(2000,4000,425)
+detect-ring => 425
+
+generate-busy => v=-7;%(750,750,425)
+detect-busy => 425
+
+generate-attn => v=0;%(100,100,1400,2060,2450,2600)
+detect-attn => 1400,2060,2450,2600
+
+generate-callwaiting-sas => v=0;%(300,0,440)
+detect-callwaiting-sas => 440
+
+generate-callwaiting-cas => v=0;%(80,0,2750,2130)
+detect-callwaiting-cas => 2750,2130
+
+detect-fail1 => 913.8
+detect-fail2 => 1370.6
+detect-fail3 => 1776.7
+
+[ru]
+generate-dial => v=-7;%(1000,425)
+detect-dial => 0
+generate-ring => v=-7;%(800,5000,425,0)
+detect-ring => 425,0
+generate-busy => v=-7;%(350,350,425,0)
+detect-busy => 425,0
+generate-attn => v=0;%(100,100,1400,2060,2450,2600)
+detect-attn => 1400,2060,2450,2600
+generate-callwaiting-sas => v=0;%(300,0,440)
+detect-callwaiting-sas => 440,480
+generate-callwaiting-cas => v=0;%(80,0,2750,2130)
+detect-callwaiting-cas => 2750,2130
+detect-fail1 => 913.8
+detect-fail2 => 1370.6
+detect-fail3 => 1776.7

Added: freeswitch/trunk/libs/openzap/conf/wanpipe.conf (0 => 17141)


--- freeswitch/trunk/libs/openzap/conf/wanpipe.conf	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/conf/wanpipe.conf	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,4 @@
+[defaults]
+codec_ms => 20
+wink_ms => 150
+flash_ms => 750

Added: freeswitch/trunk/libs/openzap/conf/zt.conf (0 => 17141)


--- freeswitch/trunk/libs/openzap/conf/zt.conf	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/conf/zt.conf	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,8 @@
+[defaults]
+codec_ms => 20
+wink_ms => 150
+flash_ms => 750
+echo_cancel_level => 64
+rxgain => 0.0
+txgain => 0.0
+

Added: freeswitch/trunk/libs/openzap/configure.ac (0 => 17141)


--- freeswitch/trunk/libs/openzap/configure.ac	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/configure.ac	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,181 @@
+#                                               -*- Autoconf -*-
+# Process this file with autoconf to produce a configure script.
+
+AC_PREREQ(2.59)
+AC_INIT([openzap],[pre-alpha],[bugs@freeswitch.org])
+AC_CONFIG_SRCDIR([src/zap_io.c])
+
+AC_CONFIG_AUX_DIR(build)
+AM_INIT_AUTOMAKE(libopenzap,0.1)
+
+# Checks for programs.
+AC_PROG_CC
+AC_PROG_MAKE_SET
+AM_PROG_CC_C_O
+
+AC_PREFIX_DEFAULT(/usr/local/openzap)
+# AC_PREFIX_DEFAULT does not get expanded until too late so we need to do this to use prefix in this script                                                     
+if test "x$prefix" = "xNONE" ; then
+    prefix='/usr/local/openzap'
+fi
+
+# Absolute source/build directory
+OZ_SRCDIR=`(cd $srcdir && pwd)`
+oz_builddir=`pwd`
+AC_SUBST(OZ_SRCDIR)
+AC_SUBST(oz_builddir)
+
+if test "$sysconfdir" = "\${prefix}/etc" ; then
+    confdir="$prefix/conf"
+else
+    confdir="$sysconfdir"
+fi
+
+AC_SUBST(confdir)
+
+#override some default libtool behavior and invoke AC_PROG_LIBTOOL (see http://lists.gnu.org/archive/html/libtool/2007-03/msg00000.html)
+m4_defun([_LT_AC_LANG_F77_CONFIG], [:])
+m4_defun([_LT_AC_LANG_GCJ_CONFIG], [:])
+m4_defun([_LT_AC_LANG_RC_CONFIG], [:])
+#AM_PROG_CC_C_O
+AC_PROG_LIBTOOL
+AC_PROG_INSTALL
+
+# Check for com;iler type
+AC_DEFUN([AX_COMPILER_VENDOR],
+[
+AC_CACHE_CHECK([for _AC_LANG compiler vendor], ax_cv_[]_AC_LANG_ABBREV[]_compiler_vendor,
+ [ax_cv_[]_AC_LANG_ABBREV[]_compiler_vendor=unknown
+  # note: don't check for GCC first, since some other compilers define __GNUC__
+  for ventest in intel:__ICC,__ECC,__INTEL_COMPILER ibm:__xlc__,__xlC__,__IBMC__,__IBMCPP__ gnu:__GNUC__ sun:__SUNPRO_C,__SUNPRO_CC hp:__HP_cc,__HP_aCC dec:__DECC,__DECCXX,__DECC_VER,__DECCXX_VER borland:__BORLANDC__,__TURBOC__ comeau:__COMO__ cray:_CRAYC kai:__KCC lcc:__LCC__ metrowerks:__MWERKS__ sgi:__sgi,sgi microsoft:_MSC_VER watcom:__WATCOMC__ portland:__PGI; do
+	vencpp="defined("`echo $ventest | cut -d: -f2 | sed 's/,/) || defined(/g'`")"
+    AC_COMPILE_IFELSE([AC_LANG_PROGRAM(,[
+#if !($vencpp)
+      thisisanerror;
+#endif
+])], [ax_cv_]_AC_LANG_ABBREV[_compiler_vendor=`echo $ventest | cut -d: -f1`; break])
+  done
+ ])
+])
+AC_ARG_ENABLE([enable_64], [AS_HELP_STRING([--enable-64], [Enable 64bit compilation])], [enable_64="$enableval"], [enable_64="no"])
+
+AX_COMPILER_VENDOR
+
+case "${ax_cv_c_compiler_vendor}" in
+gnu)
+    COMP_VENDOR_CFLAGS="-ffast-math -Wall -Werror -Wunused-variable -Wwrite-strings -Wstrict-prototypes -Wmissing-prototypes -O0"
+    ;;
+sun)
+    COMP_VENDOR_CFLAGS="-xc99=all -mt -xCC -D__FUNCTION__=__func__ -xvpara"
+    if test "$enable_64" = "yes" ; then
+        COMP_VENDOR_CFLAGS="-m64 $COMP_VENDOR_CFLAGS"
+    fi
+    ;;
+*)
+    COMP_VENDOR_CFLAGS="-std=c99 -Wall -Wunused-variable -Wwrite-strings -Wstrict-prototypes -Wmissing-prototypes"
+    ;;
+esac
+
+
+#set SOLINK variable based on compiler and host
+if test "x${ax_cv_c_compiler_vendor}"  =  "xsun" ; then
+    SOLINK="-Bdynamic -dy -G"
+elif test "x${ax_cv_c_compiler_vendor}" = "xgnu" ; then
+    case "$host" in
+        *darwin*)
+            SOLINK="-dynamic -bundle -force-flat-namespace"
+        ;;
+        *-solaris2*)
+            SOLINK="-shared -Xlinker"
+        ;;
+        *)
+            SOLINK="-shared -Xlinker -x"
+        ;;
+    esac
+else
+    AC_ERROR([Please update configure.in with SOLINK values for your compiler])
+fi
+
+# set DYNAMIC_LIB_EXTEN
+# we should really be using libtool so we don't need to do this
+case "$host" in
+    *cygwin* | *mingw*)
+        DYNAMIC_LIB_EXTEN="dll"
+    ;;
+    *)
+        DYNAMIC_LIB_EXTEN="so"
+    ;;
+esac
+
+AC_SUBST(SOLINK)
+AC_SUBST(DYNAMIC_LIB_EXTEN)
+
+AC_CHECK_LIB([dl], [dlopen])
+AC_CHECK_LIB([pthread], [pthread_create])
+AC_CHECK_LIB([m], [cos])
+AX_LIB_PCAP
+
+AC_CHECK_HEADERS([netinet/sctp.h netdb.h sys/select.h])
+AM_CONDITIONAL([HAVE_SCTP],[test "${ac_cv_header_netinet_sctp_h}" = "yes"])
+
+AC_CHECK_FUNC([gethostbyname_r],
+	[], [AC_CHECK_LIB([nsl], [gethostbyname_r])]
+)
+if test "$ac_cv_func_gethostbyname_r" = "yes" -o "$ac_cv_lib_nsl_gethostbyname_r" = "yes" ; then
+
+AC_MSG_CHECKING([whether gethostbyname_r requires five arguments])
+
+ac_cv_func_gethostbyname_r_five_args="no"
+
+AC_TRY_COMPILE([#include <netdb.h>],
+	[char *name;
+	 struct hostent *he, *res;
+	 char buffer[2048];
+	 int buflen = 2048;
+	 (void)gethostbyname_r(name, he, buffer, buflen, &res)],
+	[ac_cv_func_gethostbyname_r_five_args="yes"
+         AC_DEFINE([HAVE_GETHOSTBYNAME_R_FIVE], [1], [gethostbyname_r has five arguments])]
+)
+
+    AC_MSG_RESULT([$ac_cv_func_gethostbyname_r_five_args])
+    AC_DEFINE([HAVE_GETHOSTBYNAME_R],[1],[threadsafe gethostbyname])
+fi
+
+#  Enable debugging
+AC_ARG_ENABLE(debug,
+[AC_HELP_STRING([--enable-debug],[build with debug information])],[enable_debug="$enableval"],[enable_debug="yes"])
+
+if test "${enable_debug}" = "yes"; then
+        AC_DEFINE([DEBUG],[],[Enable extra debugging.])
+
+	if test "x${ax_cv_c_compiler_vendor}" = "xgnu" ; then
+	   COMP_VENDOR_CFLAGS="$COMP_VENDOR_CFLAGS -g -ggdb"
+	fi
+fi
+
+# Where to install the modules
+AC_ARG_WITH([modinstdir],
+ [AS_HELP_STRING([--with-modinstdir=DIR], [Install modules into this location (default: $prefix/mod)])], [modinstdir="$withval"], [modinstdir="${prefix}/mod"])
+
+AC_SUBST(modinstdir)
+
+
+# libpri?
+AC_ARG_WITH([libpri],
+ [AS_HELP_STRING([--with-libpri], [Install ozmod_libpri])], [enable_libpri="yes"], [enable_libpri="no"])
+AC_SUBST(enable_libpri)
+
+AC_CHECK_LIB([sangoma], [sangoma_span_chan_toif], [have_libsangoma="yes"])
+AM_CONDITIONAL([LIBSANGOMA],[test "${have_libsangoma}" = "yes"])
+
+AM_CONDITIONAL([LIBPRI],[test "${enable_libpri}" = "yes"])
+
+AC_CHECK_LIB([openr2], [openr2_context_set_io_type], [have_openr2="yes"])
+AM_CONDITIONAL([OPENR2],[test "${have_openr2}" = "yes"])
+
+COMP_VENDOR_CFLAGS="$COMP_VENDOR_CFLAGS"
+AC_SUBST(COMP_VENDOR_CFLAGS)
+AC_CONFIG_FILES([Makefile
+		openzap.pc
+		mod_openzap/Makefile])
+AC_OUTPUT

Added: freeswitch/trunk/libs/openzap/configure.gnu (0 => 17141)


--- freeswitch/trunk/libs/openzap/configure.gnu	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/configure.gnu	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,4 @@
+#! /bin/sh
+srcpath=$(dirname $0 2>/dev/null )  || srcpath="." 
+$srcpath/configure "$@" --with-pic
+

Added: freeswitch/trunk/libs/openzap/docs/Doxygen.conf (0 => 17141)


--- freeswitch/trunk/libs/openzap/docs/Doxygen.conf	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/docs/Doxygen.conf	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,277 @@
+# Doxyfile 1.4.6
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+PROJECT_NAME           = OpenZAP
+PROJECT_NUMBER         = 
+OUTPUT_DIRECTORY       = .
+CREATE_SUBDIRS         = NO
+OUTPUT_LANGUAGE        = English
+USE_WINDOWS_ENCODING   = YES
+BRIEF_MEMBER_DESC      = YES
+REPEAT_BRIEF           = YES
+ABBREVIATE_BRIEF       = "The $name class" \
+                         "The $name widget" \
+                         "The $name file" \
+                         is \
+                         provides \
+                         specifies \
+                         contains \
+                         represents \
+                         a \
+                         an \
+                         the
+ALWAYS_DETAILED_SEC    = NO
+INLINE_INHERITED_MEMB  = NO
+FULL_PATH_NAMES        = NO
+STRIP_FROM_PATH        = 
+STRIP_FROM_INC_PATH    = 
+SHORT_NAMES            = NO
+JAVADOC_AUTOBRIEF      = NO
+MULTILINE_CPP_IS_BRIEF = NO
+DETAILS_AT_TOP         = NO
+INHERIT_DOCS           = YES
+SEPARATE_MEMBER_PAGES  = NO
+TAB_SIZE               = 8
+ALIASES                = 
+OPTIMIZE_OUTPUT_FOR_C  = YES
+OPTIMIZE_OUTPUT_JAVA   = NO
+DISTRIBUTE_GROUP_DOC   = NO
+SUBGROUPING            = YES
+IGNORE_PREFIX          = zap_ ZAP_ Q921 Q931
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+EXTRACT_ALL            = YES
+EXTRACT_PRIVATE        = YES 
+EXTRACT_STATIC         = YES
+EXTRACT_LOCAL_CLASSES  = YES
+EXTRACT_LOCAL_METHODS  = YES
+HIDE_UNDOC_MEMBERS     = YES
+HIDE_UNDOC_CLASSES     = YES
+HIDE_FRIEND_COMPOUNDS  = NO
+HIDE_IN_BODY_DOCS      = NO
+INTERNAL_DOCS          = NO
+CASE_SENSE_NAMES       = NO
+HIDE_SCOPE_NAMES       = NO
+SHOW_INCLUDE_FILES     = YES
+INLINE_INFO            = YES
+SORT_MEMBER_DOCS       = YES
+SORT_BRIEF_DOCS        = NO
+SORT_BY_SCOPE_NAME     = NO
+GENERATE_TODOLIST      = YES
+GENERATE_TESTLIST      = YES
+GENERATE_BUGLIST       = YES
+GENERATE_DEPRECATEDLIST= YES
+ENABLED_SECTIONS       = 
+MAX_INITIALIZER_LINES  = 30
+SHOW_USED_FILES        = YES
+SHOW_DIRECTORIES       = YES
+FILE_VERSION_FILTER    = 
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+QUIET                  = NO
+WARNINGS               = YES
+WARN_IF_UNDOCUMENTED   = YES
+WARN_IF_DOC_ERROR      = YES
+WARN_NO_PARAMDOC       = NO
+WARN_FORMAT            = "$file:$line: $text"
+WARN_LOGFILE           = 
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+INPUT                  = ../src ../src/include \
+                         ../src/isdn ../src/isdn/include \
+                         ../mod_openzap ../ \
+                         ../src/ozmod \
+                         ../src/ozmod/ozmod_analog \
+                         ../src/ozmod/ozmod_analog_em \
+                         ../src/ozmod/ozmod_isdn \
+                         ../src/ozmod/ozmod_pika \
+                         ../src/ozmod/ozmod_skel \
+                         ../src/ozmod/ozmod_ss7_boost \
+                         ../src/ozmod/ozmod_wanpipe \
+                         ../src/ozmod/ozmod_zt
+
+FILE_PATTERNS          = *.c \
+                         *.cc \
+                         *.cxx \
+                         *.cpp \
+                         *.c++ \
+                         *.d \
+                         *.java \
+                         *.ii \
+                         *.ixx \
+                         *.ipp \
+                         *.i++ \
+                         *.inl \
+                         *.h \
+                         *.hh \
+                         *.hxx \
+                         *.hpp \
+                         *.h++ \
+                         *.idl \
+                         *.odl \
+                         *.cs \
+                         *.php \
+                         *.php3 \
+                         *.inc \
+                         *.m \
+                         *.mm \
+                         *.dox \
+                         *.py
+RECURSIVE              = NO
+EXCLUDE                = 
+EXCLUDE_SYMLINKS       = NO
+EXCLUDE_PATTERNS       = 
+EXAMPLE_PATH           = 
+EXAMPLE_PATTERNS       = 
+EXAMPLE_RECURSIVE      = NO
+IMAGE_PATH             = 
+INPUT_FILTER           = 
+FILTER_PATTERNS        = 
+FILTER_SOURCE_FILES    = NO
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+SOURCE_BROWSER         = NO
+INLINE_SOURCES         = YES
+STRIP_CODE_COMMENTS    = YES
+REFERENCED_BY_RELATION = YES
+REFERENCES_RELATION    = YES
+USE_HTAGS              = YES
+VERBATIM_HEADERS       = NO
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+ALPHABETICAL_INDEX     = YES
+COLS_IN_ALPHA_INDEX    = 1
+IGNORE_PREFIX          = zap_
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+GENERATE_HTML          = YES
+HTML_OUTPUT            = html
+HTML_FILE_EXTENSION    = .html
+HTML_HEADER            = 
+HTML_FOOTER            = 
+HTML_STYLESHEET        = 
+HTML_ALIGN_MEMBERS     = YES
+GENERATE_HTMLHELP      = NO
+CHM_FILE               = freeswitch.chm
+HHC_LOCATION           = 
+GENERATE_CHI           = YES
+BINARY_TOC             = NO
+TOC_EXPAND             = NO
+DISABLE_INDEX          = NO
+ENUM_VALUES_PER_LINE   = 4
+GENERATE_TREEVIEW      = YES
+TREEVIEW_WIDTH         = 250
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+GENERATE_LATEX         = NO
+LATEX_OUTPUT           = latex
+LATEX_CMD_NAME         = latex
+MAKEINDEX_CMD_NAME     = makeindex
+COMPACT_LATEX          = NO
+PAPER_TYPE             = a4wide
+EXTRA_PACKAGES         = 
+LATEX_HEADER           = 
+PDF_HYPERLINKS         = NO
+USE_PDFLATEX           = NO
+LATEX_BATCHMODE        = NO
+LATEX_HIDE_INDICES     = NO
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+GENERATE_RTF           = NO
+RTF_OUTPUT             = rtf
+COMPACT_RTF            = NO
+RTF_HYPERLINKS         = NO
+RTF_STYLESHEET_FILE    = 
+RTF_EXTENSIONS_FILE    = 
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+GENERATE_MAN           = NO
+MAN_OUTPUT             = man
+MAN_EXTENSION          = .3
+MAN_LINKS              = NO
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+GENERATE_XML           = NO
+XML_OUTPUT             = xml
+XML_SCHEMA             = 
+XML_DTD                = 
+XML_PROGRAMLISTING     = YES
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+GENERATE_AUTOGEN_DEF   = NO
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+GENERATE_PERLMOD       = NO
+PERLMOD_LATEX          = NO
+PERLMOD_PRETTY         = YES
+PERLMOD_MAKEVAR_PREFIX = 
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor   
+#---------------------------------------------------------------------------
+ENABLE_PREPROCESSING   = YES
+MACRO_EXPANSION        = YES
+EXPAND_ONLY_PREDEF     = NO
+SEARCH_INCLUDES        = NO
+INCLUDE_PATH           = 
+INCLUDE_FILE_PATTERNS  = *.h
+PREDEFINED             = ZAP_DECLARE(x)=x \
+					APR_DECLARE(x)=x \
+					ZAP_MOD_DECLARE(x)=x \
+					DoxyDefine(x)=x
+					
+EXPAND_AS_DEFINED      = NO
+SKIP_FUNCTION_MACROS   = NO
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references   
+#---------------------------------------------------------------------------
+TAGFILES               = 
+GENERATE_TAGFILE       = 
+ALLEXTERNALS           = NO
+EXTERNAL_GROUPS        = YES
+PERL_PATH              = /usr/bin/perl
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool   
+#---------------------------------------------------------------------------
+CLASS_DIAGRAMS         = YES
+HIDE_UNDOC_RELATIONS   = YES
+HAVE_DOT               = YES
+CLASS_GRAPH            = YES
+COLLABORATION_GRAPH    = YES
+GROUP_GRAPHS           = YES
+UML_LOOK               = YES
+TEMPLATE_RELATIONS     = YES
+INCLUDE_GRAPH          = YES
+INCLUDED_BY_GRAPH      = YES
+CALL_GRAPH             = YES
+GRAPHICAL_HIERARCHY    = YES
+DIRECTORY_GRAPH        = YES
+DOT_IMAGE_FORMAT       = jpg
+DOT_PATH               = 
+DOTFILE_DIRS           = 
+MAX_DOT_GRAPH_WIDTH    = 1024
+MAX_DOT_GRAPH_HEIGHT   = 1024
+MAX_DOT_GRAPH_DEPTH    = 1000
+DOT_TRANSPARENT        = NO
+DOT_MULTI_TARGETS      = NO
+GENERATE_LEGEND        = YES
+DOT_CLEANUP            = YES
+#---------------------------------------------------------------------------
+# Configuration::additions related to the search engine   
+#---------------------------------------------------------------------------
+SEARCHENGINE           = NO

Added: freeswitch/trunk/libs/openzap/mod_openzap/Makefile.in (0 => 17141)


--- freeswitch/trunk/libs/openzap/mod_openzap/Makefile.in	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/mod_openzap/Makefile.in	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,23 @@
+OZ_CFLAGS=@CFLAGS@ @COMP_VENDOR_CFLAGS@ @DEFS@
+
+BASE=../../..
+OZ_DIR=..
+VERBOSE=1
+OZLA=$(OZ_DIR)/libopenzap.la
+LOCAL_CFLAGS=-I$(OZ_DIR)/src/include -I$(OZ_DIR)/src/isdn/include $(OZ_CFLAGS)
+LOCAL_LDFLAGS=-L$(OZ_DIR) -lopenzap 
+include $(BASE)/build/modmake.rules
+
+local_depend: $(OZLA)
+
+$(OZLA): $(OZ_DIR)/.update
+	cd $(OZ_DIR) && $(MAKE)
+
+local_install:
+	cd $(OZ_DIR) && $(MAKE) install
+	[ -f $(DESTDIR)@confdir@/autoload_configs/openzap.conf.xml ] || cp -f $(OZ_DIR)/conf/openzap.conf.xml  $(DESTDIR)@confdir@/autoload_configs
+
+local_clean:
+	cd $(OZ_DIR) && $(MAKE) clean
+
+

Added: freeswitch/trunk/libs/openzap/mod_openzap/mod_openzap.2005.vcproj (0 => 17141)


--- freeswitch/trunk/libs/openzap/mod_openzap/mod_openzap.2005.vcproj	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/mod_openzap/mod_openzap.2005.vcproj	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,201 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="8.00"
+	Name="mod_openzap"
+	ProjectGUID="{FE3540C5-3303-46E0-A69E-D92F775687F1}"
+	RootNamespace="mod_openzap"
+	Keyword="Win32Proj"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="2"
+			InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+			CharacterSet="2"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				AdditionalIncludeDirectories="../../../src/include;../src/include;../src/isdn/include"
+				PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS"
+				MinimalRebuild="true"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="3"
+				UsePrecompiledHeader="0"
+				WarningLevel="4"
+				WarnAsError="true"
+				Detect64BitPortabilityProblems="false"
+				DebugInformationFormat="3"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="FreeSwitchCore.lib"
+				OutputFile="$(SolutionDir)$(OutDir)/mod/$(InputName).dll"
+				LinkIncremental="2"
+				AdditionalLibraryDirectories="&quot;../../../w32/Library/$(OutDir)&quot;"
+				GenerateDebugInformation="true"
+				ProgramDatabaseFile="$(OutDir)$(TargetName).pdb"
+				SubSystem="2"
+				ImportLibrary="$(OutDir)/mod_openzap.lib"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="2"
+			InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+			CharacterSet="2"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalIncludeDirectories="../../../src/include;../src/include;../src/isdn/include"
+				PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS"
+				RuntimeLibrary="2"
+				UsePrecompiledHeader="0"
+				WarningLevel="4"
+				WarnAsError="true"
+				Detect64BitPortabilityProblems="false"
+				DebugInformationFormat="3"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="FreeSwitchCore.lib"
+				OutputFile="$(SolutionDir)$(OutDir)/mod/$(InputName).dll"
+				LinkIncremental="1"
+				AdditionalLibraryDirectories="&quot;../../../w32/Library/$(OutDir)&quot;"
+				GenerateDebugInformation="true"
+				ProgramDatabaseFile="$(OutDir)$(TargetName).pdb"
+				SubSystem="2"
+				OptimizeReferences="2"
+				EnableCOMDATFolding="2"
+				LinkTimeCodeGeneration="1"
+				ImportLibrary="$(OutDir)/mod_openzap.lib"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<Filter
+			Name="Source Files"
+			Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+			>
+			<File
+				RelativePath=".\mod_openzap.c"
+				>
+			</File>
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>

Added: freeswitch/trunk/libs/openzap/mod_openzap/mod_openzap.2008.vcproj (0 => 17141)


--- freeswitch/trunk/libs/openzap/mod_openzap/mod_openzap.2008.vcproj	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/mod_openzap/mod_openzap.2008.vcproj	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,369 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="9.00"
+	Name="mod_openzap"
+	ProjectGUID="{FE3540C5-3303-46E0-A69E-D92F775687F1}"
+	RootNamespace="mod_openzap"
+	Keyword="Win32Proj"
+	TargetFrameworkVersion="131072"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+		<Platform
+			Name="x64"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="2"
+			InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+			CharacterSet="2"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				AdditionalIncludeDirectories="../../../src/include;../src/include;../src/isdn/include"
+				PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS"
+				MinimalRebuild="true"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="3"
+				UsePrecompiledHeader="0"
+				WarningLevel="4"
+				WarnAsError="true"
+				Detect64BitPortabilityProblems="false"
+				DebugInformationFormat="3"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="FreeSwitchCore.lib"
+				OutputFile="$(SolutionDir)$(OutDir)/mod/mod_openzap.dll"
+				LinkIncremental="2"
+				AdditionalLibraryDirectories="&quot;../../../w32/Library/$(OutDir)&quot;"
+				GenerateDebugInformation="true"
+				ProgramDatabaseFile="$(OutDir)$(TargetName).pdb"
+				SubSystem="2"
+				RandomizedBaseAddress="1"
+				DataExecutionPrevention="0"
+				ImportLibrary="$(OutDir)/mod_openzap.lib"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="2"
+			InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+			CharacterSet="2"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalIncludeDirectories="../../../src/include;../src/include;../src/isdn/include"
+				PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS"
+				RuntimeLibrary="2"
+				UsePrecompiledHeader="0"
+				WarningLevel="4"
+				WarnAsError="true"
+				Detect64BitPortabilityProblems="false"
+				DebugInformationFormat="3"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="FreeSwitchCore.lib"
+				OutputFile="$(SolutionDir)$(OutDir)/mod/mod_openzap.dll"
+				LinkIncremental="1"
+				AdditionalLibraryDirectories="&quot;../../../w32/Library/$(OutDir)&quot;"
+				GenerateDebugInformation="true"
+				ProgramDatabaseFile="$(OutDir)$(TargetName).pdb"
+				SubSystem="2"
+				OptimizeReferences="2"
+				EnableCOMDATFolding="2"
+				LinkTimeCodeGeneration="1"
+				RandomizedBaseAddress="1"
+				DataExecutionPrevention="0"
+				ImportLibrary="$(OutDir)/mod_openzap.lib"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Debug|x64"
+			OutputDirectory="$(PlatformName)\$(ConfigurationName)"
+			IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+			ConfigurationType="2"
+			InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+			CharacterSet="2"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+				TargetEnvironment="3"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				AdditionalIncludeDirectories="../../../src/include;../src/include;../src/isdn/include"
+				PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS"
+				MinimalRebuild="true"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="3"
+				UsePrecompiledHeader="0"
+				WarningLevel="4"
+				WarnAsError="true"
+				Detect64BitPortabilityProblems="false"
+				DebugInformationFormat="3"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="FreeSwitchCore.lib"
+				OutputFile="$(SolutionDir)$(OutDir)/mod/mod_openzap.dll"
+				LinkIncremental="2"
+				AdditionalLibraryDirectories="&quot;../../../w32/Library/$(OutDir)&quot;"
+				GenerateDebugInformation="true"
+				ProgramDatabaseFile="$(OutDir)$(TargetName).pdb"
+				SubSystem="2"
+				RandomizedBaseAddress="1"
+				DataExecutionPrevention="0"
+				ImportLibrary="$(OutDir)/mod_openzap.lib"
+				TargetMachine="17"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|x64"
+			OutputDirectory="$(PlatformName)\$(ConfigurationName)"
+			IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+			ConfigurationType="2"
+			InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+			CharacterSet="2"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+				TargetEnvironment="3"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalIncludeDirectories="../../../src/include;../src/include;../src/isdn/include"
+				PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS"
+				RuntimeLibrary="2"
+				UsePrecompiledHeader="0"
+				WarningLevel="4"
+				WarnAsError="true"
+				Detect64BitPortabilityProblems="false"
+				DebugInformationFormat="3"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="FreeSwitchCore.lib"
+				OutputFile="$(SolutionDir)$(OutDir)/mod/mod_openzap.dll"
+				LinkIncremental="1"
+				AdditionalLibraryDirectories="&quot;../../../w32/Library/$(OutDir)&quot;"
+				GenerateDebugInformation="true"
+				ProgramDatabaseFile="$(OutDir)$(TargetName).pdb"
+				SubSystem="2"
+				OptimizeReferences="2"
+				EnableCOMDATFolding="2"
+				LinkTimeCodeGeneration="1"
+				RandomizedBaseAddress="1"
+				DataExecutionPrevention="0"
+				ImportLibrary="$(OutDir)/mod_openzap.lib"
+				TargetMachine="17"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<Filter
+			Name="Source Files"
+			Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+			>
+			<File
+				RelativePath=".\mod_openzap.c"
+				>
+			</File>
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>

Added: freeswitch/trunk/libs/openzap/mod_openzap/mod_openzap.c (0 => 17141)


--- freeswitch/trunk/libs/openzap/mod_openzap/mod_openzap.c	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/mod_openzap/mod_openzap.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,3221 @@
+/* 
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ * Copyright (C) 2005/2006, Anthony Minessale II <anthmct@yahoo.com>
+ *
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ *
+ * The Initial Developer of the Original Code is
+ * Anthony Minessale II <anthmct@yahoo.com>
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * 
+ * Anthony Minessale II <anthmct@yahoo.com>
+ * Moises Silva <moy@sangoma.com>
+ *
+ *
+ * mod_openzap.c -- OPENZAP Endpoint Module
+ *
+ */
+#include <switch.h>
+#include "openzap.h"
+
+#ifndef __FUNCTION__
+#define __FUNCTION__ __SWITCH_FUNC__
+#endif
+
+#define OPENZAP_VAR_PREFIX "openzap_"
+#define OPENZAP_VAR_PREFIX_LEN 8
+
+SWITCH_MODULE_LOAD_FUNCTION(mod_openzap_load);
+SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_openzap_shutdown);
+SWITCH_MODULE_DEFINITION(mod_openzap, mod_openzap_load, mod_openzap_shutdown, NULL);
+
+switch_endpoint_interface_t *openzap_endpoint_interface;
+
+static switch_memory_pool_t *module_pool = NULL;
+
+typedef enum {
+	ANALOG_OPTION_NONE = 0,
+	ANALOG_OPTION_3WAY = (1 << 0),
+	ANALOG_OPTION_CALL_SWAP = (1 << 1)
+} analog_option_t;
+
+struct span_config {
+	zap_span_t *span;
+	char dialplan[80];
+	char context[80];
+	char dial_regex[256];
+	char fail_dial_regex[256];
+	char hold_music[256];
+	char type[256];	
+	analog_option_t analog_options;
+};
+
+static struct span_config SPAN_CONFIG[ZAP_MAX_SPANS_INTERFACE] = {{0}};
+
+typedef enum {
+	TFLAG_IO = (1 << 0),
+	TFLAG_DTMF = (1 << 1),
+	TFLAG_CODEC = (1 << 2),
+	TFLAG_BREAK = (1 << 3),
+	TFLAG_HOLD = (1 << 4),
+	TFLAG_DEAD = (1 << 5)
+} TFLAGS;
+
+static struct {
+	int debug;
+	char *dialplan;
+	char *codec_string;
+	char *codec_order[SWITCH_MAX_CODECS];
+	int codec_order_last;
+	char *codec_rates_string;
+	char *codec_rates[SWITCH_MAX_CODECS];
+	int codec_rates_last;
+	unsigned int flags;
+	int fd;
+	int calls;
+	char hold_music[256];
+	switch_mutex_t *mutex;
+	analog_option_t analog_options;
+} globals;
+
+struct private_object {
+	unsigned int flags;
+	switch_codec_t read_codec;
+	switch_codec_t write_codec;
+	switch_frame_t read_frame;
+	unsigned char databuf[SWITCH_RECOMMENDED_BUFFER_SIZE];
+	switch_frame_t cng_frame;
+	unsigned char cng_databuf[SWITCH_RECOMMENDED_BUFFER_SIZE];
+	switch_core_session_t *session;
+	switch_caller_profile_t *caller_profile;
+	unsigned int codec;
+	unsigned int codecs;
+	unsigned short samprate;
+	switch_mutex_t *mutex;
+	switch_mutex_t *flag_mutex;
+	zap_channel_t *zchan;
+	uint32_t wr_error;
+};
+
+typedef struct private_object private_t;
+
+
+static switch_status_t channel_on_init(switch_core_session_t *session);
+static switch_status_t channel_on_hangup(switch_core_session_t *session);
+static switch_status_t channel_on_destroy(switch_core_session_t *session);
+static switch_status_t channel_on_routing(switch_core_session_t *session);
+static switch_status_t channel_on_exchange_media(switch_core_session_t *session);
+static switch_status_t channel_on_soft_execute(switch_core_session_t *session);
+static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *session, switch_event_t *var_event,
+													switch_caller_profile_t *outbound_profile,
+													switch_core_session_t **new_session, 
+													switch_memory_pool_t **pool,
+													switch_originate_flag_t flags, switch_call_cause_t *cancel_cause);
+static switch_status_t channel_read_frame(switch_core_session_t *session, switch_frame_t **frame, switch_io_flag_t flags, int stream_id);
+static switch_status_t channel_write_frame(switch_core_session_t *session, switch_frame_t *frame, switch_io_flag_t flags, int stream_id);
+static switch_status_t channel_kill_channel(switch_core_session_t *session, int sig);
+zap_status_t zap_channel_from_event(zap_sigmsg_t *sigmsg, switch_core_session_t **sp);
+void dump_chan(zap_span_t *span, uint32_t chan_id, switch_stream_handle_t *stream);
+void dump_chan_xml(zap_span_t *span, uint32_t chan_id, switch_stream_handle_t *stream);
+
+static void zap_set_npi(const char *npi_string, uint8_t *target)
+{
+	if (!strcasecmp(npi_string, "isdn") || !strcasecmp(npi_string, "e164")) {
+		*target = ZAP_NPI_ISDN;
+	} else if (!strcasecmp(npi_string, "data")) {
+		*target = ZAP_NPI_DATA;
+	} else if (!strcasecmp(npi_string, "telex")) {
+		*target = ZAP_NPI_TELEX;
+	} else if (!strcasecmp(npi_string, "national")) {
+		*target = ZAP_NPI_NATIONAL;
+	} else if (!strcasecmp(npi_string, "private")) {
+		*target = ZAP_NPI_PRIVATE;
+	} else if (!strcasecmp(npi_string, "reserved")) {
+		*target = ZAP_NPI_RESERVED;
+	} else if (!strcasecmp(npi_string, "unknown")) {
+		*target = ZAP_NPI_UNKNOWN;
+	} else {
+		zap_log(ZAP_LOG_WARNING, "Invalid NPI value (%s)\n", npi_string);
+		*target = ZAP_NPI_UNKNOWN;
+	}
+}
+
+static void zap_set_ton(const char *ton_string, uint8_t *target)
+{
+	if (!strcasecmp(ton_string, "national")) {
+		*target = ZAP_TON_NATIONAL;
+	} else if (!strcasecmp(ton_string, "international")) {
+		*target = ZAP_TON_INTERNATIONAL;
+	} else if (!strcasecmp(ton_string, "local")) {
+		*target = ZAP_TON_SUBSCRIBER_NUMBER;
+	} else if (!strcasecmp(ton_string, "unknown")) {
+		*target = ZAP_TON_UNKNOWN;
+	} else {
+		zap_log(ZAP_LOG_WARNING, "Invalid TON value (%s)\n", ton_string);
+		*target = ZAP_TON_UNKNOWN;
+	}
+}
+
+static switch_core_session_t *zap_channel_get_session(zap_channel_t *channel, int32_t id)
+{
+	switch_core_session_t *session = NULL;
+
+	if (id > ZAP_MAX_TOKENS) {
+		return NULL;
+	}
+
+	if (!zstr(channel->tokens[id])) {
+		if (!(session = switch_core_session_locate(channel->tokens[id]))) {
+			zap_channel_clear_token(channel, channel->tokens[id]);
+		}
+	}
+
+	return session;
+}
+
+static const char *zap_channel_get_uuid(zap_channel_t *channel, int32_t id)
+{
+	if (id > ZAP_MAX_TOKENS) {
+		return NULL;
+	}
+
+	if (!zstr(channel->tokens[id])) {
+		return channel->tokens[id];
+	}
+	return NULL;
+}
+
+static void stop_hold(switch_core_session_t *session_a, const char *uuid)
+{
+	switch_core_session_t *session;
+	switch_channel_t *channel, *channel_a;
+	;
+
+	if (!uuid) {
+		return;
+	}
+
+	if ((session = switch_core_session_locate(uuid))) {
+		channel = switch_core_session_get_channel(session);
+
+		if (switch_channel_test_flag(channel, CF_HOLD)) {
+			channel_a = switch_core_session_get_channel(session_a);
+			switch_ivr_unhold(session);
+			switch_channel_clear_flag(channel_a, CF_SUSPEND);
+			switch_channel_clear_flag(channel_a, CF_HOLD);
+		} else {
+			switch_channel_stop_broadcast(channel);
+			switch_channel_wait_for_flag(channel, CF_BROADCAST, SWITCH_FALSE, 2000, NULL);
+		}
+
+		switch_core_session_rwunlock(session);
+	}
+}
+
+static void start_hold(zap_channel_t *zchan, switch_core_session_t *session_a, const char *uuid, const char *stream)
+{
+	switch_core_session_t *session;
+	switch_channel_t *channel, *channel_a;
+
+	if (!uuid) {
+		return;
+	}
+	
+	
+	if ((session = switch_core_session_locate(uuid))) {
+		channel = switch_core_session_get_channel(session);
+		if (zstr(stream)) {
+			if (!strcasecmp(globals.hold_music, "indicate_hold")) {
+				stream = "indicate_hold";
+			}
+			if (!strcasecmp(SPAN_CONFIG[zchan->span->span_id].hold_music, "indicate_hold")) {
+				stream = "indicate_hold";
+			}
+		}
+
+		if (zstr(stream)) {
+			stream = switch_channel_get_variable(channel, SWITCH_HOLD_MUSIC_VARIABLE);
+		}
+
+		if (zstr(stream)) {
+			stream = SPAN_CONFIG[zchan->span->span_id].hold_music;
+		}
+
+		if (zstr(stream)) {
+			stream = globals.hold_music;
+		}
+		
+		
+		if (zstr(stream) && !(stream = switch_channel_get_variable(channel, SWITCH_HOLD_MUSIC_VARIABLE))) {
+			stream = globals.hold_music;
+		}
+
+		if (!zstr(stream)) {
+			if (!strcasecmp(stream, "indicate_hold")) {
+				channel_a = switch_core_session_get_channel(session_a);
+				switch_ivr_hold_uuid(uuid, NULL, 0);
+				switch_channel_set_flag(channel_a, CF_SUSPEND);
+				switch_channel_set_flag(channel_a, CF_HOLD);
+			} else {
+				switch_ivr_broadcast(switch_core_session_get_uuid(session), stream, SMF_ECHO_ALEG | SMF_LOOP);
+			}
+		}
+
+		switch_core_session_rwunlock(session);
+	}
+}
+
+
+static void cycle_foreground(zap_channel_t *zchan, int flash, const char *bcast) {
+	uint32_t i = 0;
+	switch_core_session_t *session;
+	switch_channel_t *channel;
+	private_t *tech_pvt;
+	
+
+	for (i = 0; i < zchan->token_count; i++) {
+		if ((session = zap_channel_get_session(zchan, i))) {
+			const char *buuid;
+			tech_pvt = switch_core_session_get_private(session);
+			channel = switch_core_session_get_channel(session);
+			buuid = switch_channel_get_variable(channel, SWITCH_SIGNAL_BOND_VARIABLE);
+
+			
+			if (zchan->token_count == 1 && flash) {
+				if (switch_test_flag(tech_pvt, TFLAG_HOLD)) {
+					stop_hold(session, buuid);
+					switch_clear_flag_locked(tech_pvt, TFLAG_HOLD);
+				} else {
+					start_hold(zchan, session, buuid, bcast);
+					switch_set_flag_locked(tech_pvt, TFLAG_HOLD);
+				}
+			} else if (i) {
+				start_hold(zchan, session, buuid, bcast);
+				switch_set_flag_locked(tech_pvt, TFLAG_HOLD);
+			} else {
+				stop_hold(session, buuid);
+				switch_clear_flag_locked(tech_pvt, TFLAG_HOLD);
+				if (!switch_channel_test_flag(channel, CF_ANSWERED)) {
+					switch_channel_mark_answered(channel);
+				}
+			}
+			switch_core_session_rwunlock(session);
+		}
+	}
+}
+
+
+
+
+static switch_status_t tech_init(private_t *tech_pvt, switch_core_session_t *session, zap_channel_t *zchan)
+{
+	const char *dname = NULL;
+	uint32_t interval = 0, srate = 8000;
+	zap_codec_t codec;
+
+	tech_pvt->zchan = zchan;
+	tech_pvt->read_frame.data = tech_pvt->databuf;
+	tech_pvt->read_frame.buflen = sizeof(tech_pvt->databuf);
+	tech_pvt->cng_frame.data = tech_pvt->cng_databuf;
+	tech_pvt->cng_frame.buflen = sizeof(tech_pvt->cng_databuf);
+	tech_pvt->cng_frame.flags = SFF_CNG;
+	tech_pvt->cng_frame.codec = &tech_pvt->read_codec;
+	memset(tech_pvt->cng_frame.data, 255, tech_pvt->cng_frame.buflen);
+	switch_mutex_init(&tech_pvt->mutex, SWITCH_MUTEX_NESTED, switch_core_session_get_pool(session));
+	switch_mutex_init(&tech_pvt->flag_mutex, SWITCH_MUTEX_NESTED, switch_core_session_get_pool(session));
+	switch_core_session_set_private(session, tech_pvt);
+	tech_pvt->session = session;
+
+	if (ZAP_SUCCESS != zap_channel_command(zchan, ZAP_COMMAND_GET_INTERVAL, &interval)) {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to retrieve channel interval.\n");
+		return SWITCH_STATUS_GENERR;
+	}
+
+	if (ZAP_SUCCESS != zap_channel_command(zchan, ZAP_COMMAND_GET_CODEC, &codec)) {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to retrieve channel codec.\n");
+		return SWITCH_STATUS_GENERR;
+	}
+
+	switch(codec) {
+	case ZAP_CODEC_ULAW:
+		{
+			dname = "PCMU";
+		}
+		break;
+	case ZAP_CODEC_ALAW:
+		{
+			dname = "PCMA";
+		}
+		break;
+	case ZAP_CODEC_SLIN:
+		{
+			dname = "L16";
+		}
+		break;
+	default:
+		{
+			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid codec value retrieved from channel, codec value: %d\n", codec);
+			return SWITCH_STATUS_GENERR;
+		}
+	}
+
+
+	if (switch_core_codec_init(&tech_pvt->read_codec,
+							   dname,
+							   NULL,
+							   srate,
+							   interval,
+							   1,
+							   SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE,
+							   NULL, switch_core_session_get_pool(tech_pvt->session)) != SWITCH_STATUS_SUCCESS) {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't load codec?\n");
+		return SWITCH_STATUS_GENERR;
+	} else {
+		if (switch_core_codec_init(&tech_pvt->write_codec,
+								   dname,
+								   NULL,
+								   srate,
+								   interval,
+								   1,
+								   SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE,
+								   NULL, switch_core_session_get_pool(tech_pvt->session)) != SWITCH_STATUS_SUCCESS) {
+			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't load codec?\n");
+			switch_core_codec_destroy(&tech_pvt->read_codec);
+			return SWITCH_STATUS_GENERR;
+		}
+	}
+
+	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Set codec %s %dms\n", dname, interval);
+	switch_core_session_set_read_codec(tech_pvt->session, &tech_pvt->read_codec);
+	switch_core_session_set_write_codec(tech_pvt->session, &tech_pvt->write_codec);
+	switch_set_flag_locked(tech_pvt, TFLAG_CODEC);
+	tech_pvt->read_frame.codec = &tech_pvt->read_codec;
+	switch_set_flag_locked(tech_pvt, TFLAG_IO);
+
+	return SWITCH_STATUS_SUCCESS;
+	
+}
+
+static switch_status_t channel_on_init(switch_core_session_t *session)
+{
+	switch_channel_t *channel;
+	private_t *tech_pvt = NULL;
+
+	tech_pvt = switch_core_session_get_private(session);
+	assert(tech_pvt != NULL);
+
+	channel = switch_core_session_get_channel(session);
+	assert(channel != NULL);
+
+	if (switch_test_flag(tech_pvt, TFLAG_DEAD)) {
+		switch_channel_hangup(channel, SWITCH_CAUSE_LOSE_RACE);
+		return SWITCH_STATUS_SUCCESS;
+	} 
+	
+	/* Move channel's state machine to ROUTING */
+	switch_channel_set_state(channel, CS_ROUTING);
+	switch_mutex_lock(globals.mutex);
+	globals.calls++;
+	switch_mutex_unlock(globals.mutex);
+
+	zap_channel_init(tech_pvt->zchan);
+
+	//switch_channel_set_flag(channel, CF_ACCEPT_CNG);
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t channel_on_routing(switch_core_session_t *session)
+{
+	switch_channel_t *channel = NULL;
+	private_t *tech_pvt = NULL;
+
+	channel = switch_core_session_get_channel(session);
+	assert(channel != NULL);
+
+	tech_pvt = switch_core_session_get_private(session);
+	assert(tech_pvt != NULL);
+
+	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s CHANNEL ROUTING\n", switch_channel_get_name(channel));
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t channel_on_execute(switch_core_session_t *session)
+{
+
+	switch_channel_t *channel = NULL;
+	private_t *tech_pvt = NULL;
+
+	channel = switch_core_session_get_channel(session);
+	assert(channel != NULL);
+
+	tech_pvt = switch_core_session_get_private(session);
+	assert(tech_pvt != NULL);
+
+	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s CHANNEL EXECUTE\n", switch_channel_get_name(channel));
+
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t channel_on_destroy(switch_core_session_t *session)
+{
+	private_t *tech_pvt = NULL;
+	
+	if ((tech_pvt = switch_core_session_get_private(session))) {
+
+		if (tech_pvt->read_codec.implementation) {
+			switch_core_codec_destroy(&tech_pvt->read_codec);
+		}
+		
+		if (tech_pvt->write_codec.implementation) {
+			switch_core_codec_destroy(&tech_pvt->write_codec);
+		}
+	}
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t channel_on_hangup(switch_core_session_t *session)
+{
+	switch_channel_t *channel = NULL;
+	private_t *tech_pvt = NULL;
+
+	channel = switch_core_session_get_channel(session);
+	assert(channel != NULL);
+
+	tech_pvt = switch_core_session_get_private(session);
+	assert(tech_pvt != NULL);
+
+	if (!tech_pvt->zchan) {
+		goto end;
+	} 
+
+	zap_channel_clear_token(tech_pvt->zchan, switch_core_session_get_uuid(session));
+	
+	switch (tech_pvt->zchan->type) {
+	case ZAP_CHAN_TYPE_FXO:
+	case ZAP_CHAN_TYPE_EM:
+	case ZAP_CHAN_TYPE_CAS:
+		{
+			zap_set_state_locked(tech_pvt->zchan, ZAP_CHANNEL_STATE_HANGUP);
+		}
+		break;
+	case ZAP_CHAN_TYPE_FXS:
+		{
+			if (tech_pvt->zchan->state != ZAP_CHANNEL_STATE_BUSY && tech_pvt->zchan->state != ZAP_CHANNEL_STATE_DOWN) {
+				if (tech_pvt->zchan->token_count) {
+					cycle_foreground(tech_pvt->zchan, 0, NULL);
+				} else {
+					zap_set_state_locked(tech_pvt->zchan, ZAP_CHANNEL_STATE_HANGUP);
+				}
+			}
+		}
+		break;
+	case ZAP_CHAN_TYPE_B:
+		{
+			if (tech_pvt->zchan->state != ZAP_CHANNEL_STATE_DOWN) {
+				if (tech_pvt->zchan->state != ZAP_CHANNEL_STATE_TERMINATING) {
+					tech_pvt->zchan->caller_data.hangup_cause = switch_channel_get_cause_q850(channel);
+					if (tech_pvt->zchan->caller_data.hangup_cause < 1 || tech_pvt->zchan->caller_data.hangup_cause > 127) {
+						tech_pvt->zchan->caller_data.hangup_cause = ZAP_CAUSE_DESTINATION_OUT_OF_ORDER;
+					}
+				}
+				zap_set_state_locked(tech_pvt->zchan, ZAP_CHANNEL_STATE_HANGUP);
+			}
+		}
+		break;
+	default: 
+		{
+			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Unhandled channel type %d for channel %s\n", tech_pvt->zchan->type,
+                    switch_channel_get_name(channel));
+		}
+		break;
+	}
+
+ end:
+
+	switch_clear_flag_locked(tech_pvt, TFLAG_IO);
+	
+	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s CHANNEL HANGUP\n", switch_channel_get_name(channel));
+	switch_mutex_lock(globals.mutex);
+	globals.calls--;
+	if (globals.calls < 0) {
+		globals.calls = 0;
+	}
+	switch_mutex_unlock(globals.mutex);
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t channel_kill_channel(switch_core_session_t *session, int sig)
+{
+	switch_channel_t *channel = NULL;
+	private_t *tech_pvt = NULL;
+
+	channel = switch_core_session_get_channel(session);
+	assert(channel != NULL);
+
+	tech_pvt = switch_core_session_get_private(session);
+	assert(tech_pvt != NULL);
+
+	switch (sig) {
+	case SWITCH_SIG_KILL:
+		switch_clear_flag_locked(tech_pvt, TFLAG_IO);
+		switch_set_flag_locked(tech_pvt, TFLAG_DEAD);
+		break;
+	case SWITCH_SIG_BREAK:
+		switch_set_flag_locked(tech_pvt, TFLAG_BREAK);
+		break;
+	default:
+		break;
+	}
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t channel_on_exchange_media(switch_core_session_t *session)
+{
+	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "CHANNEL EXCHANGE_MEDIA\n");
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t channel_on_soft_execute(switch_core_session_t *session)
+{
+	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "CHANNEL SOFT_EXECUTE\n");
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t channel_send_dtmf(switch_core_session_t *session, const switch_dtmf_t *dtmf)
+{
+	private_t *tech_pvt = NULL;
+	char tmp[2] = "";
+
+	tech_pvt = switch_core_session_get_private(session);
+	assert(tech_pvt != NULL);
+
+	if (switch_test_flag(tech_pvt, TFLAG_DEAD)) {
+		switch_channel_hangup(switch_core_session_get_channel(session), SWITCH_CAUSE_LOSE_RACE);
+		return SWITCH_STATUS_FALSE;
+	} 
+
+	tmp[0] = dtmf->digit;
+	zap_channel_command(tech_pvt->zchan, ZAP_COMMAND_SEND_DTMF, tmp);
+		
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t channel_read_frame(switch_core_session_t *session, switch_frame_t **frame, switch_io_flag_t flags, int stream_id)
+{
+	switch_channel_t *channel = NULL;
+	private_t *tech_pvt = NULL;
+	zap_size_t len;
+	zap_wait_flag_t wflags = ZAP_READ;
+	char dtmf[128] = "";
+	zap_status_t status;
+	int total_to;
+	int chunk, do_break = 0;
+
+
+	channel = switch_core_session_get_channel(session);
+	assert(channel != NULL);
+	
+	
+	tech_pvt = switch_core_session_get_private(session);
+	assert(tech_pvt != NULL);
+
+	if (switch_test_flag(tech_pvt, TFLAG_DEAD)) {
+		return SWITCH_STATUS_FALSE;
+	} 
+
+	/* Digium Cards sometimes timeout several times in a row here. 
+	   Yes, we support digium cards, ain't we nice.......
+	   6 double length intervals should compensate */
+	chunk = tech_pvt->zchan->effective_interval * 2;
+	total_to = chunk * 6;
+
+ top:
+
+	if (switch_channel_test_flag(channel, CF_SUSPEND)) {
+		do_break = 1;
+	}
+
+	if (switch_test_flag(tech_pvt, TFLAG_BREAK)) {
+		switch_clear_flag_locked(tech_pvt, TFLAG_BREAK);
+		do_break = 1;
+	}
+
+	if (switch_test_flag(tech_pvt, TFLAG_HOLD) || do_break) {
+		switch_yield(tech_pvt->zchan->effective_interval * 1000);
+		tech_pvt->cng_frame.datalen = tech_pvt->zchan->packet_len;
+		tech_pvt->cng_frame.samples = tech_pvt->cng_frame.datalen;
+		tech_pvt->cng_frame.flags = SFF_CNG;
+		*frame = &tech_pvt->cng_frame;
+		if (tech_pvt->zchan->effective_codec == ZAP_CODEC_SLIN) {
+			tech_pvt->cng_frame.samples /= 2;
+		}
+		return SWITCH_STATUS_SUCCESS;
+	}
+	
+	if (!switch_test_flag(tech_pvt, TFLAG_IO)) {
+		goto fail;
+	}
+
+	wflags = ZAP_READ;	
+	status = zap_channel_wait(tech_pvt->zchan, &wflags, chunk);
+	
+	if (status == ZAP_FAIL) {
+		goto fail;
+	}
+	
+	if (status == ZAP_TIMEOUT) {
+		if (!switch_test_flag(tech_pvt, TFLAG_HOLD)) {
+			total_to -= chunk;
+			if (total_to <= 0) {
+				goto fail;
+			}
+		}
+
+		goto top;
+	}
+
+	if (!(wflags & ZAP_READ)) {
+		goto fail;
+	}
+
+	len = tech_pvt->read_frame.buflen;
+	if (zap_channel_read(tech_pvt->zchan, tech_pvt->read_frame.data, &len) != ZAP_SUCCESS) {
+		goto fail;
+	}
+
+	*frame = &tech_pvt->read_frame;
+	tech_pvt->read_frame.datalen = (uint32_t)len;
+	tech_pvt->read_frame.samples = tech_pvt->read_frame.datalen;
+
+	if (tech_pvt->zchan->effective_codec == ZAP_CODEC_SLIN) {
+		tech_pvt->read_frame.samples /= 2;
+	}
+
+	while (zap_channel_dequeue_dtmf(tech_pvt->zchan, dtmf, sizeof(dtmf))) {
+		switch_dtmf_t _dtmf = { 0, SWITCH_DEFAULT_DTMF_DURATION };
+		char *p;
+		for (p = dtmf; p && *p; p++) {
+			if (is_dtmf(*p)) {
+				_dtmf.digit = *p;
+				zap_log(ZAP_LOG_DEBUG, "queue DTMF [%c]\n", *p);
+				switch_channel_queue_dtmf(channel, &_dtmf);
+			}
+		}
+	}
+	return SWITCH_STATUS_SUCCESS;
+
+ fail:
+	switch_clear_flag_locked(tech_pvt, TFLAG_IO);
+	return SWITCH_STATUS_GENERR;
+	
+
+}
+
+static switch_status_t channel_write_frame(switch_core_session_t *session, switch_frame_t *frame, switch_io_flag_t flags, int stream_id)
+{
+	switch_channel_t *channel = NULL;
+	private_t *tech_pvt = NULL;
+	zap_size_t len;
+	unsigned char data[SWITCH_RECOMMENDED_BUFFER_SIZE] = {0};
+	zap_wait_flag_t wflags = ZAP_WRITE;
+	zap_status_t status;
+
+	channel = switch_core_session_get_channel(session);
+	assert(channel != NULL);
+
+	tech_pvt = switch_core_session_get_private(session);
+	assert(tech_pvt != NULL);
+
+	if (!tech_pvt->zchan) {
+		return SWITCH_STATUS_FALSE;
+	} 
+
+	if (switch_test_flag(tech_pvt, TFLAG_DEAD)) {
+		return SWITCH_STATUS_FALSE;
+	}
+
+	if (switch_test_flag(tech_pvt, TFLAG_HOLD)) {
+		return SWITCH_STATUS_SUCCESS;
+	}
+
+	if (!switch_test_flag(tech_pvt, TFLAG_IO)) {
+		goto fail;
+	}
+	
+	if (switch_test_flag(frame, SFF_CNG)) {
+		frame->data = data;
+		frame->buflen = sizeof(data);
+		if ((frame->datalen = tech_pvt->write_codec.implementation->encoded_bytes_per_packet) > frame->buflen) {
+			goto fail;
+		}
+		memset(data, 255, frame->datalen);
+	}
+
+
+	wflags = ZAP_WRITE;	
+	status = zap_channel_wait(tech_pvt->zchan, &wflags, tech_pvt->zchan->effective_interval * 10);
+	
+	if (!(wflags & ZAP_WRITE)) {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Dropping frame! (write not ready)\n");
+		return SWITCH_STATUS_SUCCESS;
+	}
+
+	len = frame->datalen;
+	if (zap_channel_write(tech_pvt->zchan, frame->data, frame->buflen, &len) != ZAP_SUCCESS) {
+		if (++tech_pvt->wr_error > 10) {
+			goto fail;
+		}
+	} else {
+		tech_pvt->wr_error = 0;
+	}
+
+	return SWITCH_STATUS_SUCCESS;
+
+ fail:
+	
+	switch_clear_flag_locked(tech_pvt, TFLAG_IO);
+	return SWITCH_STATUS_GENERR;
+
+}
+
+static switch_status_t channel_receive_message_cas(switch_core_session_t *session, switch_core_session_message_t *msg)
+{
+	switch_channel_t *channel;
+	private_t *tech_pvt;
+
+	channel = switch_core_session_get_channel(session);
+	assert(channel != NULL);
+			
+	tech_pvt = (private_t *) switch_core_session_get_private(session);
+	assert(tech_pvt != NULL);
+	
+	if (switch_test_flag(tech_pvt, TFLAG_DEAD)) {
+        switch_channel_hangup(channel, SWITCH_CAUSE_LOSE_RACE);
+        return SWITCH_STATUS_FALSE;
+    }
+	
+	zap_log(ZAP_LOG_DEBUG, "Got Freeswitch message in R2 channel %d [%d]\n", tech_pvt->zchan->physical_chan_id, 
+            msg->message_id);
+
+	switch (msg->message_id) {
+	case SWITCH_MESSAGE_INDICATE_RINGING:
+		{
+			if (switch_channel_test_flag(channel, CF_OUTBOUND)) {
+				zap_set_flag_locked(tech_pvt->zchan, ZAP_CHANNEL_PROGRESS);
+			} else {
+				zap_set_state_locked_wait(tech_pvt->zchan, ZAP_CHANNEL_STATE_PROGRESS);
+			}
+		}
+		break;
+	case SWITCH_MESSAGE_INDICATE_PROGRESS:
+		{
+			if (switch_channel_test_flag(channel, CF_OUTBOUND)) {
+				zap_set_flag_locked(tech_pvt->zchan, ZAP_CHANNEL_PROGRESS);
+				zap_set_flag_locked(tech_pvt->zchan, ZAP_CHANNEL_MEDIA);
+			} else {
+				zap_set_state_locked_wait(tech_pvt->zchan, ZAP_CHANNEL_STATE_PROGRESS);
+				zap_set_state_locked_wait(tech_pvt->zchan, ZAP_CHANNEL_STATE_PROGRESS_MEDIA);
+			}
+		}
+		break;
+	case SWITCH_MESSAGE_INDICATE_ANSWER:
+		{
+			if (switch_channel_test_flag(channel, CF_OUTBOUND)) {
+				zap_set_flag_locked(tech_pvt->zchan, ZAP_CHANNEL_ANSWERED);
+			} else {
+				/* lets make the ozmod_r2 module life easier by moving thru each
+                 * state waiting for completion, clumsy, but does the job
+				 */
+				if (tech_pvt->zchan->state < ZAP_CHANNEL_STATE_PROGRESS) {
+					zap_set_state_locked_wait(tech_pvt->zchan, ZAP_CHANNEL_STATE_PROGRESS);
+				}
+				if (tech_pvt->zchan->state < ZAP_CHANNEL_STATE_PROGRESS_MEDIA) {
+					zap_set_state_locked_wait(tech_pvt->zchan, ZAP_CHANNEL_STATE_PROGRESS_MEDIA);
+				}
+				zap_set_state_locked_wait(tech_pvt->zchan, ZAP_CHANNEL_STATE_UP);
+			}
+		}
+		break;
+	default:
+		break;
+	}
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t channel_receive_message_b(switch_core_session_t *session, switch_core_session_message_t *msg)
+{
+	switch_channel_t *channel;
+	private_t *tech_pvt;
+
+	channel = switch_core_session_get_channel(session);
+	assert(channel != NULL);
+			
+	tech_pvt = (private_t *) switch_core_session_get_private(session);
+	assert(tech_pvt != NULL);
+
+	if (switch_test_flag(tech_pvt, TFLAG_DEAD)) {
+        switch_channel_hangup(channel, SWITCH_CAUSE_LOSE_RACE);
+        return SWITCH_STATUS_FALSE;
+    }
+
+	if (tech_pvt->zchan->state == ZAP_CHANNEL_STATE_TERMINATING) {
+		zap_mutex_unlock(tech_pvt->zchan->mutex);	
+		return SWITCH_STATUS_SUCCESS;
+	}
+
+	switch (msg->message_id) {
+	case SWITCH_MESSAGE_INDICATE_RINGING:
+		{
+			if (switch_channel_test_flag(channel, CF_OUTBOUND)) {
+				zap_set_flag(tech_pvt->zchan, ZAP_CHANNEL_PROGRESS);
+			} else {
+				zap_set_state_wait(tech_pvt->zchan, ZAP_CHANNEL_STATE_PROGRESS);
+			}
+		}
+		break;
+	case SWITCH_MESSAGE_INDICATE_PROGRESS:
+		{
+			if (switch_channel_test_flag(channel, CF_OUTBOUND)) {
+				zap_set_flag(tech_pvt->zchan, ZAP_CHANNEL_PROGRESS);
+				zap_set_flag(tech_pvt->zchan, ZAP_CHANNEL_MEDIA);
+			} else {
+				/* Don't skip messages in the ISDN call setup
+				 * TODO: make the isdn stack smart enough to handle that itself
+				 *       until then, this is here for safety...
+				 */
+				if (tech_pvt->zchan->state < ZAP_CHANNEL_STATE_PROGRESS) {
+					zap_set_state_wait(tech_pvt->zchan, ZAP_CHANNEL_STATE_PROGRESS);
+				}
+				zap_set_state_wait(tech_pvt->zchan, ZAP_CHANNEL_STATE_PROGRESS_MEDIA);
+			}
+		}
+		break;
+	case SWITCH_MESSAGE_INDICATE_ANSWER:
+		{
+			if (switch_channel_test_flag(channel, CF_OUTBOUND)) {
+				zap_set_flag(tech_pvt->zchan, ZAP_CHANNEL_ANSWERED);
+			} else {
+				/* Don't skip messages in the ISDN call setup
+				 * TODO: make the isdn stack smart enough to handle that itself
+				 *       until then, this is here for safety...
+				 */
+				if (tech_pvt->zchan->state < ZAP_CHANNEL_STATE_PROGRESS) {
+					zap_set_state_wait(tech_pvt->zchan, ZAP_CHANNEL_STATE_PROGRESS);
+				}
+				if (tech_pvt->zchan->state < ZAP_CHANNEL_STATE_PROGRESS_MEDIA) {
+					zap_set_state_wait(tech_pvt->zchan, ZAP_CHANNEL_STATE_PROGRESS_MEDIA);
+				}
+				zap_set_state_wait(tech_pvt->zchan, ZAP_CHANNEL_STATE_UP);
+			}
+		}
+		break;
+	default:
+		break;
+	}
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t channel_receive_message_fxo(switch_core_session_t *session, switch_core_session_message_t *msg)
+{
+	switch_channel_t *channel;
+	private_t *tech_pvt;
+
+	channel = switch_core_session_get_channel(session);
+	assert(channel != NULL);
+			
+	tech_pvt = (private_t *) switch_core_session_get_private(session);
+	assert(tech_pvt != NULL);
+
+	if (switch_test_flag(tech_pvt, TFLAG_DEAD)) {
+        switch_channel_hangup(channel, SWITCH_CAUSE_LOSE_RACE);
+        return SWITCH_STATUS_FALSE;
+    }
+	
+	switch (msg->message_id) {
+	case SWITCH_MESSAGE_INDICATE_PROGRESS:
+	case SWITCH_MESSAGE_INDICATE_ANSWER:
+		if (switch_channel_test_flag(channel, CF_OUTBOUND)) {
+			zap_set_flag_locked(tech_pvt->zchan, ZAP_CHANNEL_ANSWERED);
+			zap_set_flag_locked(tech_pvt->zchan, ZAP_CHANNEL_PROGRESS);
+			zap_set_flag_locked(tech_pvt->zchan, ZAP_CHANNEL_MEDIA);
+		} else {
+			zap_set_state_locked(tech_pvt->zchan, ZAP_CHANNEL_STATE_UP);
+		}
+		break;
+	default:
+		break;
+	}
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t channel_receive_message_fxs(switch_core_session_t *session, switch_core_session_message_t *msg)
+{
+	switch_channel_t *channel;
+	private_t *tech_pvt;
+
+	channel = switch_core_session_get_channel(session);
+	assert(channel != NULL);
+			
+	tech_pvt = (private_t *) switch_core_session_get_private(session);
+	assert(tech_pvt != NULL);
+
+	if (switch_test_flag(tech_pvt, TFLAG_DEAD)) {
+        switch_channel_hangup(channel, SWITCH_CAUSE_LOSE_RACE);
+        return SWITCH_STATUS_FALSE;
+    }
+	
+	switch (msg->message_id) {
+	case SWITCH_MESSAGE_INDICATE_PROGRESS:
+	case SWITCH_MESSAGE_INDICATE_ANSWER:
+		if (!switch_channel_test_flag(channel, CF_OUTBOUND)) {
+			zap_set_flag_locked(tech_pvt->zchan, ZAP_CHANNEL_ANSWERED);
+			zap_set_flag_locked(tech_pvt->zchan, ZAP_CHANNEL_PROGRESS);
+			zap_set_flag_locked(tech_pvt->zchan, ZAP_CHANNEL_MEDIA);
+			zap_set_state_locked(tech_pvt->zchan, ZAP_CHANNEL_STATE_UP);
+			switch_channel_mark_answered(channel);
+		}
+		break;
+	case SWITCH_MESSAGE_INDICATE_RINGING:
+		if (!switch_channel_test_flag(channel, CF_OUTBOUND)) {
+			
+			if (!switch_channel_test_flag(channel, CF_ANSWERED) && 
+				!switch_channel_test_flag(channel, CF_EARLY_MEDIA) &&
+				!switch_channel_test_flag(channel, CF_RING_READY)
+				) {
+				zap_set_state_locked(tech_pvt->zchan, ZAP_CHANNEL_STATE_RING);
+				switch_channel_mark_ring_ready(channel);
+			}
+		}
+		break;
+	default:
+		break;
+	}
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t channel_receive_message(switch_core_session_t *session, switch_core_session_message_t *msg)
+{
+	private_t *tech_pvt;
+	switch_status_t status;
+	switch_channel_t *channel;
+	const char *var;
+	zap_channel_t *zchan = NULL;
+
+	tech_pvt = (private_t *) switch_core_session_get_private(session);
+	assert(tech_pvt != NULL);
+
+	channel = switch_core_session_get_channel(session);
+
+	if (switch_test_flag(tech_pvt, TFLAG_DEAD)) {
+        switch_channel_hangup(channel, SWITCH_CAUSE_LOSE_RACE);
+        return SWITCH_STATUS_FALSE;
+	}
+
+	if (!(zchan = tech_pvt->zchan)) {
+        switch_channel_hangup(channel, SWITCH_CAUSE_LOSE_RACE);
+        return SWITCH_STATUS_FALSE;
+    }
+
+	zap_mutex_lock(zchan->mutex);	
+
+	if (!tech_pvt->zchan) {
+		switch_channel_hangup(channel, SWITCH_CAUSE_LOSE_RACE);
+		status = SWITCH_STATUS_FALSE;
+		goto end;
+	}
+
+	switch (msg->message_id) {
+	case SWITCH_MESSAGE_INDICATE_PROGRESS:
+	case SWITCH_MESSAGE_INDICATE_ANSWER:
+		if (!switch_channel_test_flag(channel, CF_OUTBOUND)) {
+			if ((var = switch_channel_get_variable(channel, "openzap_pre_buffer_size"))) {
+				int tmp = atoi(var);
+				if (tmp > -1) {
+					zap_channel_command(tech_pvt->zchan, ZAP_COMMAND_SET_PRE_BUFFER_SIZE, &tmp);
+				}
+			}
+		}
+		break;
+	case SWITCH_MESSAGE_INDICATE_UUID_CHANGE:
+		{
+			zap_channel_replace_token(tech_pvt->zchan, msg->string_array_arg[0], msg->string_array_arg[1]);
+		}
+		break;
+	default:
+		break;
+	}
+
+	switch (tech_pvt->zchan->type) {
+	case ZAP_CHAN_TYPE_FXS:
+	case ZAP_CHAN_TYPE_EM:
+		status = channel_receive_message_fxs(session, msg);
+		break;
+	case ZAP_CHAN_TYPE_FXO:
+		status = channel_receive_message_fxo(session, msg);
+		break;
+	case ZAP_CHAN_TYPE_B:
+		status = channel_receive_message_b(session, msg);
+        break;
+	case ZAP_CHAN_TYPE_CAS:
+		status = channel_receive_message_cas(session, msg);
+        break;
+	default:
+		status = SWITCH_STATUS_FALSE;
+		break;
+	}
+
+ end:
+
+	zap_mutex_unlock(zchan->mutex);	
+
+	return status;
+
+}
+
+switch_state_handler_table_t openzap_state_handlers = {
+	/*.on_init */ channel_on_init,
+	/*.on_routing */ channel_on_routing,
+	/*.on_execute */ channel_on_execute,
+	/*.on_hangup */ channel_on_hangup,
+	/*.on_exchange_media */ channel_on_exchange_media,
+	/*.on_soft_execute */ channel_on_soft_execute,
+	/*.on_consume_media */ NULL,
+    /*.on_hibernate */ NULL,
+    /*.on_reset */ NULL,
+    /*.on_park*/ NULL,
+    /*.on_reporting*/ NULL,
+    /*.on_destroy*/ channel_on_destroy
+
+};
+
+switch_io_routines_t openzap_io_routines = {
+	/*.outgoing_channel */ channel_outgoing_channel,
+	/*.read_frame */ channel_read_frame,
+	/*.write_frame */ channel_write_frame,
+	/*.kill_channel */ channel_kill_channel,
+	/*.send_dtmf */ channel_send_dtmf,
+	/*.receive_message*/ channel_receive_message
+};
+
+/* Make sure when you have 2 sessions in the same scope that you pass the appropriate one to the routines
+that allocate memory or you will have 1 channel with memory allocated from another channel's pool!
+*/
+static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *session, switch_event_t *var_event,
+													switch_caller_profile_t *outbound_profile,
+													switch_core_session_t **new_session, switch_memory_pool_t **pool,
+													switch_originate_flag_t flags, switch_call_cause_t *cancel_cause)
+{
+
+	const char *dest = NULL;
+	char *data = NULL;
+	int span_id = -1, chan_id = 0;
+	zap_channel_t *zchan = NULL;
+	switch_call_cause_t cause = SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
+	char name[128];
+	zap_status_t status;
+	int direction = ZAP_TOP_DOWN;
+	zap_caller_data_t caller_data = {{ 0 }};
+	char *span_name = NULL;
+	switch_event_header_t *h;
+	char *argv[3];
+	int argc = 0;
+	const char *var;
+	const char *dest_num = NULL, *callerid_num = NULL;
+
+	if (!outbound_profile) {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Missing caller profile\n");
+		return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
+	}
+
+	if (zstr(outbound_profile->destination_number)) {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid dial string\n");
+		return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
+	}
+
+
+	data = switch_core_strdup(outbound_profile->pool, outbound_profile->destination_number);
+
+	if (!zstr(outbound_profile->destination_number)) {
+		dest_num = switch_sanitize_number(switch_core_strdup(outbound_profile->pool, outbound_profile->destination_number));
+	}
+
+	if (!zstr(outbound_profile->caller_id_number)) {
+		callerid_num = switch_sanitize_number(switch_core_strdup(outbound_profile->pool, outbound_profile->caller_id_number));
+	}
+
+	if (!zstr(callerid_num) && !strcmp(callerid_num, "0000000000")) {
+		callerid_num = NULL;
+	}
+	
+	if ((argc = switch_separate_string(data, '/', argv, (sizeof(argv) / sizeof(argv[0])))) < 2) {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid dial string\n");
+        return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
+	}
+	
+	if (switch_is_number(argv[0])) {
+		span_id = atoi(argv[0]);
+	} else {
+		span_name = argv[0];
+	}	
+
+	if (*argv[1] == 'A') {
+		direction = ZAP_BOTTOM_UP;
+	} else if (*argv[1] == 'a') {
+		direction =  ZAP_TOP_DOWN;
+	} else {
+		chan_id = atoi(argv[1]);
+	}
+
+	if (!(dest = argv[2])) {
+		dest = "";
+	}
+
+	if (span_id == 0 && chan_id != 0) {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Span 0 is used to pick the first available span, selecting a channel is not supported (and doesn't make sense)\n");
+        return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
+	}
+
+	if (span_id == -1 && !zstr(span_name)) {
+		zap_span_t *span;
+		zap_status_t zstatus = zap_span_find_by_name(span_name, &span);
+		if (zstatus == ZAP_SUCCESS && span) {
+			span_id = span->span_id;
+		}
+	}
+
+	if (span_id == -1) {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Missing span\n");
+		return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
+	}
+
+	if (chan_id < 0) {
+		direction = ZAP_BOTTOM_UP;
+		chan_id = 0;
+	}
+	
+	if (switch_test_flag(outbound_profile, SWITCH_CPF_SCREEN)) {
+		caller_data.screen = 1;
+	}
+
+	if (switch_test_flag(outbound_profile, SWITCH_CPF_HIDE_NUMBER)) {
+		caller_data.pres = 1;
+	}
+
+	if (!zstr(dest)) {
+		zap_set_string(caller_data.ani.digits, dest);
+	}
+	
+	if ((var = switch_event_get_header(var_event, "openzap_outbound_ton")) || (var = switch_core_get_variable("openzap_outbound_ton"))) {
+		if (!strcasecmp(var, "national")) {
+			caller_data.ani.type = ZAP_TON_NATIONAL;
+		} else if (!strcasecmp(var, "international")) {
+			caller_data.ani.type = ZAP_TON_INTERNATIONAL;
+		} else if (!strcasecmp(var, "local")) {
+			caller_data.ani.type = ZAP_TON_SUBSCRIBER_NUMBER;
+		} else if (!strcasecmp(var, "unknown")) {
+			caller_data.ani.type = ZAP_TON_UNKNOWN;
+		}
+	} else {
+		caller_data.ani.type = outbound_profile->destination_number_ton;
+	}
+
+	caller_data.ani.plan = outbound_profile->destination_number_numplan;
+
+	/* blindly copy data from outbound_profile. They will be overwritten 
+	 * by calling zap_caller_data if needed after */
+	caller_data.cid_num.type = outbound_profile->caller_ton;
+	caller_data.cid_num.plan = outbound_profile->caller_numplan;
+
+	caller_data.rdnis.type = outbound_profile->rdnis_ton;
+	caller_data.rdnis.plan = outbound_profile->rdnis_numplan;
+	
+#if 0
+	if (!zstr(outbound_profile->rdnis)) {
+		zap_set_string(caller_data.rdnis.digits, outbound_profile->rdnis);
+	}
+#endif
+
+	zap_set_string(caller_data.cid_name, outbound_profile->caller_id_name);
+	zap_set_string(caller_data.cid_num.digits, switch_str_nil(callerid_num));
+	
+	if (chan_id) {
+		status = zap_channel_open(span_id, chan_id, &zchan);
+	} else {
+		status = zap_channel_open_any(span_id, direction, &caller_data, &zchan);
+	}
+	
+	if (status != ZAP_SUCCESS) {
+		if (caller_data.hangup_cause == SWITCH_CAUSE_NONE) {
+			caller_data.hangup_cause = SWITCH_CAUSE_NORMAL_CIRCUIT_CONGESTION;
+		}
+		return caller_data.hangup_cause;
+	}
+
+	if ((var = switch_event_get_header(var_event, "openzap_pre_buffer_size"))) {
+		int tmp = atoi(var);
+		if (tmp > -1) {
+			zap_channel_command(zchan, ZAP_COMMAND_SET_PRE_BUFFER_SIZE, &tmp);
+		}
+	}
+
+	zap_channel_clear_vars(zchan);
+	for (h = var_event->headers; h; h = h->next) {
+		if (!strncasecmp(h->name, OPENZAP_VAR_PREFIX, OPENZAP_VAR_PREFIX_LEN)) {
+			char *v = h->name + OPENZAP_VAR_PREFIX_LEN;
+			if (!zstr(v)) {
+				zap_channel_add_var(zchan, v, h->value);
+			}
+		}
+	}
+	
+	if ((*new_session = switch_core_session_request(openzap_endpoint_interface, SWITCH_CALL_DIRECTION_OUTBOUND, pool)) != 0) {
+		private_t *tech_pvt;
+		switch_caller_profile_t *caller_profile;
+		switch_channel_t *channel = switch_core_session_get_channel(*new_session);
+		
+		switch_core_session_add_stream(*new_session, NULL);
+		if ((tech_pvt = (private_t *) switch_core_session_alloc(*new_session, sizeof(private_t))) != 0) {
+			tech_init(tech_pvt, *new_session, zchan);
+		} else {
+			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Hey where is my memory pool?\n");
+			switch_core_session_destroy(new_session);
+			cause = SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
+			goto fail;
+		}
+
+		snprintf(name, sizeof(name), "OpenZAP/%u:%u/%s", zchan->span_id, zchan->chan_id, dest);
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Connect outbound channel %s\n", name);
+		switch_channel_set_name(channel, name);
+		switch_channel_set_variable(channel, "openzap_span_name", zchan->span->name);
+		switch_channel_set_variable_printf(channel, "openzap_span_number", "%d", zchan->span_id);	
+		switch_channel_set_variable_printf(channel, "openzap_chan_number", "%d", zchan->chan_id);
+		zap_channel_set_caller_data(zchan, &caller_data);
+		caller_profile = switch_caller_profile_clone(*new_session, outbound_profile);
+		caller_profile->destination_number = switch_core_strdup(caller_profile->pool, switch_str_nil(dest_num));
+		caller_profile->caller_id_number = switch_core_strdup(caller_profile->pool, switch_str_nil(callerid_num));
+		switch_channel_set_caller_profile(channel, caller_profile);
+		tech_pvt->caller_profile = caller_profile;
+		
+		
+		switch_channel_set_flag(channel, CF_OUTBOUND);
+		switch_channel_set_state(channel, CS_INIT);
+		if (zap_channel_add_token(zchan, switch_core_session_get_uuid(*new_session), zchan->token_count) != ZAP_SUCCESS) {
+			switch_core_session_destroy(new_session);
+			cause = SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
+            goto fail;
+		}
+
+
+		if (zap_channel_outgoing_call(zchan) != ZAP_SUCCESS) {
+			if (tech_pvt->read_codec.implementation) {
+				switch_core_codec_destroy(&tech_pvt->read_codec);
+			}
+			
+			if (tech_pvt->write_codec.implementation) {
+				switch_core_codec_destroy(&tech_pvt->write_codec);
+			}
+			switch_core_session_destroy(new_session);
+            cause = SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
+            goto fail;
+		}
+
+		zap_channel_init(zchan);
+		
+		return SWITCH_CAUSE_SUCCESS;
+	}
+
+ fail:
+
+	if (zchan) {
+		zap_channel_done(zchan);
+	}
+
+	return cause;
+
+}
+
+zap_status_t zap_channel_from_event(zap_sigmsg_t *sigmsg, switch_core_session_t **sp)
+{
+	switch_core_session_t *session = NULL;
+	private_t *tech_pvt = NULL;
+	switch_channel_t *channel = NULL;
+	char name[128];
+	
+	*sp = NULL;
+	
+	if (!(session = switch_core_session_request(openzap_endpoint_interface, SWITCH_CALL_DIRECTION_INBOUND, NULL))) {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Initilization Error!\n");
+		return ZAP_FAIL;
+	}
+	
+	switch_core_session_add_stream(session, NULL);
+	
+	tech_pvt = (private_t *) switch_core_session_alloc(session, sizeof(private_t));
+	assert(tech_pvt != NULL);
+	channel = switch_core_session_get_channel(session);
+	if (tech_init(tech_pvt, session, sigmsg->channel) != SWITCH_STATUS_SUCCESS) {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Initilization Error!\n");
+		switch_core_session_destroy(&session);
+		return ZAP_FAIL;
+	}
+	
+	*sigmsg->channel->caller_data.collected = '\0';
+	
+	if (zstr(sigmsg->channel->caller_data.cid_name)) {
+		switch_set_string(sigmsg->channel->caller_data.cid_name, sigmsg->channel->chan_name);
+	}
+
+	if (zstr(sigmsg->channel->caller_data.cid_num.digits)) {
+		if (!zstr(sigmsg->channel->caller_data.ani.digits)) {
+			switch_set_string(sigmsg->channel->caller_data.cid_num.digits, sigmsg->channel->caller_data.ani.digits);
+		} else {
+			switch_set_string(sigmsg->channel->caller_data.cid_num.digits, sigmsg->channel->chan_number);
+		}
+	}
+
+	tech_pvt->caller_profile = switch_caller_profile_new(switch_core_session_get_pool(session),
+														 "OpenZAP",
+														 SPAN_CONFIG[sigmsg->channel->span_id].dialplan,
+														 sigmsg->channel->caller_data.cid_name,
+														 sigmsg->channel->caller_data.cid_num.digits,
+														 NULL,
+														 sigmsg->channel->caller_data.ani.digits,
+														 sigmsg->channel->caller_data.aniII,
+														 sigmsg->channel->caller_data.rdnis.digits,
+														 (char *) modname,
+														 SPAN_CONFIG[sigmsg->channel->span_id].context,
+														 sigmsg->channel->caller_data.dnis.digits);
+
+	assert(tech_pvt->caller_profile != NULL);
+
+	if (sigmsg->channel->caller_data.screen == 1 || sigmsg->channel->caller_data.screen == 3) {
+		switch_set_flag(tech_pvt->caller_profile, SWITCH_CPF_SCREEN);
+	}
+
+	tech_pvt->caller_profile->caller_ton = sigmsg->channel->caller_data.cid_num.type;
+	tech_pvt->caller_profile->caller_numplan = sigmsg->channel->caller_data.cid_num.plan;
+	tech_pvt->caller_profile->ani_ton = sigmsg->channel->caller_data.ani.type;
+	tech_pvt->caller_profile->ani_numplan = sigmsg->channel->caller_data.ani.plan;
+	tech_pvt->caller_profile->destination_number_ton = sigmsg->channel->caller_data.dnis.type;
+	tech_pvt->caller_profile->destination_number_numplan = sigmsg->channel->caller_data.dnis.plan;
+	tech_pvt->caller_profile->rdnis_ton = sigmsg->channel->caller_data.rdnis.type;
+	tech_pvt->caller_profile->rdnis_numplan = sigmsg->channel->caller_data.rdnis.plan;
+
+	if (sigmsg->channel->caller_data.pres) {
+		switch_set_flag(tech_pvt->caller_profile, SWITCH_CPF_HIDE_NAME | SWITCH_CPF_HIDE_NUMBER);
+	}
+	
+	snprintf(name, sizeof(name), "OpenZAP/%u:%u/%s", sigmsg->channel->span_id, sigmsg->channel->chan_id, tech_pvt->caller_profile->destination_number);
+	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Connect inbound channel %s\n", name);
+	switch_channel_set_name(channel, name);
+	switch_channel_set_caller_profile(channel, tech_pvt->caller_profile);
+
+	switch_channel_set_variable(channel, "openzap_span_name", sigmsg->channel->span->name);
+	switch_channel_set_variable_printf(channel, "openzap_span_number", "%d", sigmsg->channel->span_id);	
+	switch_channel_set_variable_printf(channel, "openzap_chan_number", "%d", sigmsg->channel->chan_id);
+		
+	switch_channel_set_state(channel, CS_INIT);
+	if (switch_core_session_thread_launch(session) != SWITCH_STATUS_SUCCESS) {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Error spawning thread\n");
+		switch_core_session_destroy(&session);
+		return ZAP_FAIL;
+	}
+
+	if (zap_channel_add_token(sigmsg->channel, switch_core_session_get_uuid(session), 0) != ZAP_SUCCESS) {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Error adding token\n");
+		switch_core_session_destroy(&session);
+		return ZAP_FAIL;
+	}
+	*sp = session;
+
+    return ZAP_SUCCESS;
+}
+
+static ZIO_SIGNAL_CB_FUNCTION(on_common_signal)
+{
+	switch_event_t *event = NULL;
+
+	switch (sigmsg->event_id) {
+
+	case ZAP_SIGEVENT_ALARM_CLEAR:
+	case ZAP_SIGEVENT_ALARM_TRAP:
+		{
+			if (zap_channel_get_alarms(sigmsg->channel) != ZAP_SUCCESS) {
+				zap_log(ZAP_LOG_ERROR, "failed to retrieve alarms\n");
+				return ZAP_FAIL;
+			}
+			if (switch_event_create(&event, SWITCH_EVENT_TRAP) != SWITCH_STATUS_SUCCESS) {
+				zap_log(ZAP_LOG_ERROR, "failed to create alarms events\n");
+				return ZAP_FAIL;
+			}
+			if (sigmsg->event_id == ZAP_SIGEVENT_ALARM_CLEAR) {
+				switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "condition", "zap-alarm-clear");
+			} else {
+				switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "condition", "zap-alarm-trap");
+			}
+		}
+		break;
+	default:
+		return ZAP_SUCCESS;
+		break;
+	}
+
+	switch_event_add_header(event, SWITCH_STACK_BOTTOM, "span-name", "%s", sigmsg->channel->span->name);
+	switch_event_add_header(event, SWITCH_STACK_BOTTOM, "span-number", "%d", sigmsg->channel->span_id);
+	switch_event_add_header(event, SWITCH_STACK_BOTTOM, "chan-number", "%d", sigmsg->channel->chan_id);
+
+	if (zap_test_alarm_flag(sigmsg->channel, ZAP_ALARM_RECOVER)) {
+		switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "alarm", "recover");
+	}
+	if (zap_test_alarm_flag(sigmsg->channel, ZAP_ALARM_LOOPBACK)) {
+		switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "alarm", "loopback");
+	}
+	if (zap_test_alarm_flag(sigmsg->channel, ZAP_ALARM_YELLOW)) {
+		switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "alarm", "yellow");
+	}
+	if (zap_test_alarm_flag(sigmsg->channel, ZAP_ALARM_RED)) {
+		switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "alarm", "red");
+	}
+	if (zap_test_alarm_flag(sigmsg->channel, ZAP_ALARM_BLUE)) {
+		switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "alarm", "blue");
+	}
+	if (zap_test_alarm_flag(sigmsg->channel, ZAP_ALARM_NOTOPEN)) {
+		switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "alarm", "notopen");
+	}
+	if (zap_test_alarm_flag(sigmsg->channel, ZAP_ALARM_AIS)) {
+		switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "alarm", "ais");
+	}
+	if (zap_test_alarm_flag(sigmsg->channel, ZAP_ALARM_RAI)) {
+		switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "alarm", "rai");
+	}
+	if (zap_test_alarm_flag(sigmsg->channel, ZAP_ALARM_GENERAL)) {
+		switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "alarm", "general");
+	}
+	switch_event_fire(&event);
+
+	return ZAP_BREAK;
+}
+
+static ZIO_SIGNAL_CB_FUNCTION(on_fxo_signal)
+{
+	switch_core_session_t *session = NULL;
+	switch_channel_t *channel = NULL;
+	zap_status_t status;
+
+	zap_log(ZAP_LOG_DEBUG, "got FXO sig %d:%d [%s]\n", sigmsg->channel->span_id, sigmsg->channel->chan_id, zap_signal_event2str(sigmsg->event_id));
+
+    switch(sigmsg->event_id) {
+
+    case ZAP_SIGEVENT_PROGRESS_MEDIA:
+		{
+			if ((session = zap_channel_get_session(sigmsg->channel, 0))) {
+				channel = switch_core_session_get_channel(session);
+				switch_channel_mark_pre_answered(channel);
+				switch_core_session_rwunlock(session);
+			}
+		}
+		break;
+    case ZAP_SIGEVENT_STOP:
+		{
+			private_t *tech_pvt = NULL;
+			while((session = zap_channel_get_session(sigmsg->channel, 0))) {
+				tech_pvt = switch_core_session_get_private(session);
+				switch_set_flag_locked(tech_pvt, TFLAG_DEAD);
+				zap_channel_clear_token(sigmsg->channel, 0);
+				channel = switch_core_session_get_channel(session);
+				switch_channel_hangup(channel, sigmsg->channel->caller_data.hangup_cause);
+				zap_channel_clear_token(sigmsg->channel, switch_core_session_get_uuid(session));
+				switch_core_session_rwunlock(session);
+			}
+		}
+		break;
+    case ZAP_SIGEVENT_UP:
+		{
+			if ((session = zap_channel_get_session(sigmsg->channel, 0))) {
+				channel = switch_core_session_get_channel(session);
+				switch_channel_mark_answered(channel);
+				switch_core_session_rwunlock(session);
+			}
+		}
+		break;
+    case ZAP_SIGEVENT_START:
+		{
+			status = zap_channel_from_event(sigmsg, &session);
+			if (status != ZAP_SUCCESS) {
+				zap_set_state_locked(sigmsg->channel, ZAP_CHANNEL_STATE_DOWN);
+			}
+		}
+		break;
+
+	default:
+		{
+			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Unhandled msg type %d for channel %d:%d\n",
+							  sigmsg->event_id, sigmsg->channel->span_id, sigmsg->channel->chan_id);
+		}
+		break;
+
+	}
+
+	return ZAP_SUCCESS;
+}
+
+static ZIO_SIGNAL_CB_FUNCTION(on_fxs_signal)
+{
+	switch_core_session_t *session = NULL;
+	switch_channel_t *channel = NULL;
+	zap_status_t status = ZAP_SUCCESS;
+
+    zap_log(ZAP_LOG_DEBUG, "got FXS sig [%s]\n", zap_signal_event2str(sigmsg->event_id));
+
+    switch(sigmsg->event_id) {
+    case ZAP_SIGEVENT_UP:
+		{
+			if ((session = zap_channel_get_session(sigmsg->channel, 0))) {
+				channel = switch_core_session_get_channel(session);
+				switch_channel_mark_answered(channel);
+				switch_core_session_rwunlock(session);
+			}
+		}
+		break;
+    case ZAP_SIGEVENT_PROGRESS:
+		{
+			if ((session = zap_channel_get_session(sigmsg->channel, 0))) {
+				channel = switch_core_session_get_channel(session);
+				switch_channel_mark_ring_ready(channel);
+				switch_core_session_rwunlock(session);
+			}
+		}
+		break;
+    case ZAP_SIGEVENT_START:
+		{
+			zap_clear_flag_locked(sigmsg->channel, ZAP_CHANNEL_HOLD);
+			status = zap_channel_from_event(sigmsg, &session);
+			if (status != ZAP_SUCCESS) {
+				zap_set_state_locked(sigmsg->channel, ZAP_CHANNEL_STATE_BUSY);
+			}
+		}
+		break;
+    case ZAP_SIGEVENT_STOP:
+		{
+			private_t *tech_pvt = NULL;
+			switch_call_cause_t cause = SWITCH_CAUSE_NORMAL_CLEARING;
+			if (sigmsg->channel->token_count) {
+				switch_core_session_t *session_a, *session_b, *session_t = NULL;
+				switch_channel_t *channel_a = NULL, *channel_b = NULL;
+				int digits = !zstr(sigmsg->channel->caller_data.collected);
+				const char *br_a_uuid = NULL, *br_b_uuid = NULL;
+				private_t *tech_pvt = NULL;
+
+
+				if ((session_a = switch_core_session_locate(sigmsg->channel->tokens[0]))) {
+					channel_a = switch_core_session_get_channel(session_a);
+					br_a_uuid = switch_channel_get_variable(channel_a, SWITCH_SIGNAL_BOND_VARIABLE);
+
+					tech_pvt = switch_core_session_get_private(session_a);
+					stop_hold(session_a, switch_channel_get_variable(channel_a, SWITCH_SIGNAL_BOND_VARIABLE));
+					switch_clear_flag_locked(tech_pvt, TFLAG_HOLD);
+				}
+
+				if ((session_b = switch_core_session_locate(sigmsg->channel->tokens[1]))) {
+					channel_b = switch_core_session_get_channel(session_b);
+					br_b_uuid = switch_channel_get_variable(channel_b, SWITCH_SIGNAL_BOND_VARIABLE);
+
+					tech_pvt = switch_core_session_get_private(session_b);
+					stop_hold(session_a, switch_channel_get_variable(channel_b, SWITCH_SIGNAL_BOND_VARIABLE));
+					switch_clear_flag_locked(tech_pvt, TFLAG_HOLD);
+				}
+
+				if (channel_a && channel_b && !switch_channel_test_flag(channel_a, CF_OUTBOUND) && !switch_channel_test_flag(channel_b, CF_OUTBOUND)) {
+					cause = SWITCH_CAUSE_ATTENDED_TRANSFER;
+					if (br_a_uuid && br_b_uuid) {
+						switch_ivr_uuid_bridge(br_a_uuid, br_b_uuid);
+					} else if (br_a_uuid && digits) {
+						session_t = switch_core_session_locate(br_a_uuid);
+					} else if (br_b_uuid && digits) {
+						session_t = switch_core_session_locate(br_b_uuid);
+					}
+				}
+				
+				if (session_t) {
+					switch_ivr_session_transfer(session_t, sigmsg->channel->caller_data.collected, NULL, NULL);
+					switch_core_session_rwunlock(session_t);
+				}
+
+				if (session_a) {
+					switch_core_session_rwunlock(session_a);
+				}
+
+				if (session_b) {
+					switch_core_session_rwunlock(session_b);
+				}
+
+				
+			}
+
+			while((session = zap_channel_get_session(sigmsg->channel, 0))) {
+				tech_pvt = switch_core_session_get_private(session);
+				switch_set_flag_locked(tech_pvt, TFLAG_DEAD);
+				channel = switch_core_session_get_channel(session);
+				switch_channel_hangup(channel, cause);
+				zap_channel_clear_token(sigmsg->channel, switch_core_session_get_uuid(session));
+				switch_core_session_rwunlock(session);
+			}
+			zap_channel_clear_token(sigmsg->channel, NULL);
+			
+		}
+		break;
+
+    case ZAP_SIGEVENT_ADD_CALL:
+		{
+			cycle_foreground(sigmsg->channel, 1, NULL);
+		}
+		break;
+    case ZAP_SIGEVENT_FLASH:
+		{
+
+			if (zap_test_flag(sigmsg->channel, ZAP_CHANNEL_HOLD) && sigmsg->channel->token_count == 1) {
+				switch_core_session_t *session;
+				if ((session = zap_channel_get_session(sigmsg->channel, 0))) {
+					const char *buuid;
+					switch_channel_t *channel;
+					private_t *tech_pvt;
+					
+					tech_pvt = switch_core_session_get_private(session);
+					channel = switch_core_session_get_channel(session);
+					buuid = switch_channel_get_variable(channel, SWITCH_SIGNAL_BOND_VARIABLE);
+					zap_set_state_locked(sigmsg->channel,  ZAP_CHANNEL_STATE_UP);
+					stop_hold(session, buuid);
+					switch_clear_flag_locked(tech_pvt, TFLAG_HOLD);
+					switch_core_session_rwunlock(session);
+				}
+			} else if (sigmsg->channel->token_count == 2 && (SPAN_CONFIG[sigmsg->span_id].analog_options & ANALOG_OPTION_3WAY)) {
+				if (zap_test_flag(sigmsg->channel, ZAP_CHANNEL_3WAY)) {
+					zap_clear_flag(sigmsg->channel, ZAP_CHANNEL_3WAY);
+					if ((session = zap_channel_get_session(sigmsg->channel, 1))) {
+						channel = switch_core_session_get_channel(session);
+						switch_channel_hangup(channel, SWITCH_CAUSE_NORMAL_CLEARING);
+						zap_channel_clear_token(sigmsg->channel, switch_core_session_get_uuid(session));
+						switch_core_session_rwunlock(session);
+					}
+					cycle_foreground(sigmsg->channel, 1, NULL);
+				} else {
+					char *cmd;
+					cmd = switch_mprintf("three_way::%s", sigmsg->channel->tokens[0]);
+					zap_set_flag(sigmsg->channel, ZAP_CHANNEL_3WAY);
+					cycle_foreground(sigmsg->channel, 1, cmd);
+					free(cmd);
+				}
+			} else if ((SPAN_CONFIG[sigmsg->span_id].analog_options & ANALOG_OPTION_CALL_SWAP)
+					   || (SPAN_CONFIG[sigmsg->span_id].analog_options & ANALOG_OPTION_3WAY)
+					   ) { 
+				cycle_foreground(sigmsg->channel, 1, NULL);
+				if (sigmsg->channel->token_count == 1) {
+					zap_set_flag_locked(sigmsg->channel, ZAP_CHANNEL_HOLD);
+					zap_set_state_locked(sigmsg->channel, ZAP_CHANNEL_STATE_DIALTONE);
+				}
+			}
+			
+		}
+		break;
+
+    case ZAP_SIGEVENT_COLLECTED_DIGIT:
+		{
+			char *dtmf = sigmsg->raw_data;
+			char *regex = SPAN_CONFIG[sigmsg->channel->span->span_id].dial_regex;
+			char *fail_regex = SPAN_CONFIG[sigmsg->channel->span->span_id].fail_dial_regex;
+			
+			if (zstr(regex)) {
+				regex = NULL;
+			}
+
+			if (zstr(fail_regex)) {
+				fail_regex = NULL;
+			}
+
+			zap_log(ZAP_LOG_DEBUG, "got DTMF sig [%s]\n", dtmf);
+			switch_set_string(sigmsg->channel->caller_data.collected, dtmf);
+			
+			if ((regex || fail_regex) && !zstr(dtmf)) {
+				switch_regex_t *re = NULL;
+				int ovector[30];
+				int match = 0;
+
+				if (fail_regex) {
+					match = switch_regex_perform(dtmf, fail_regex, &re, ovector, sizeof(ovector) / sizeof(ovector[0]));
+					status = match ? ZAP_SUCCESS : ZAP_BREAK;
+					switch_regex_safe_free(re);
+				}
+
+				if (status == ZAP_SUCCESS && regex) {
+					match = switch_regex_perform(dtmf, regex, &re, ovector, sizeof(ovector) / sizeof(ovector[0]));
+					status = match ? ZAP_BREAK : ZAP_SUCCESS;
+				}
+				
+				switch_regex_safe_free(re);
+			}
+
+		}
+		break;
+
+	default:
+		{
+			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Unhandled msg type %d for channel %d:%d\n",
+							  sigmsg->event_id, sigmsg->channel->span_id, sigmsg->channel->chan_id);
+		}
+		break;
+
+	}
+
+	return status;
+}
+
+static ZIO_SIGNAL_CB_FUNCTION(on_r2_signal)
+{
+	switch_core_session_t *session = NULL;
+	switch_channel_t *channel = NULL;
+	zap_status_t status = ZAP_SUCCESS;
+
+	zap_log(ZAP_LOG_DEBUG, "Got R2 channel sig [%s] in channel %d\n", zap_signal_event2str(sigmsg->event_id), sigmsg->channel->physical_chan_id);
+
+	if (on_common_signal(sigmsg) == ZAP_BREAK) {
+		return ZAP_SUCCESS;
+	}
+
+	switch(sigmsg->event_id) {
+		/* on_call_disconnect from the R2 side */
+		case ZAP_SIGEVENT_STOP: 
+		{	
+			private_t *tech_pvt = NULL;
+			while((session = zap_channel_get_session(sigmsg->channel, 0))) {
+				tech_pvt = switch_core_session_get_private(session);
+				switch_set_flag_locked(tech_pvt, TFLAG_DEAD);
+				channel = switch_core_session_get_channel(session);
+				switch_channel_hangup(channel, sigmsg->channel->caller_data.hangup_cause);
+				zap_channel_clear_token(sigmsg->channel, switch_core_session_get_uuid(session));
+				switch_core_session_rwunlock(session);
+			}
+		}
+		break;
+
+		/* on_call_offered from the R2 side */
+		case ZAP_SIGEVENT_START: 
+		{
+			status = zap_channel_from_event(sigmsg, &session);
+		}
+		break;
+
+		/* on DNIS received from the R2 forward side, return status == ZAP_BREAK to stop requesting DNIS */
+		case ZAP_SIGEVENT_COLLECTED_DIGIT: 
+		{
+			char *regex = SPAN_CONFIG[sigmsg->channel->span->span_id].dial_regex;
+			char *fail_regex = SPAN_CONFIG[sigmsg->channel->span->span_id].fail_dial_regex;
+
+			if (zstr(regex)) {
+				regex = NULL;
+			}
+
+			if (zstr(fail_regex)) {
+				fail_regex = NULL;
+			}
+
+			zap_log(ZAP_LOG_DEBUG, "R2 DNIS so far [%s]\n", sigmsg->channel->caller_data.dnis.digits);
+
+			if ((regex || fail_regex) && !zstr(sigmsg->channel->caller_data.dnis.digits)) {
+				switch_regex_t *re = NULL;
+				int ovector[30];
+				int match = 0;
+
+				if (fail_regex) {
+					match = switch_regex_perform(sigmsg->channel->caller_data.dnis.digits, fail_regex, &re, ovector, sizeof(ovector) / sizeof(ovector[0]));
+					status = match ? ZAP_SUCCESS : ZAP_BREAK;
+					switch_regex_safe_free(re);
+				}
+
+				if (status == ZAP_SUCCESS && regex) {
+					match = switch_regex_perform(sigmsg->channel->caller_data.dnis.digits, regex, &re, ovector, sizeof(ovector) / sizeof(ovector[0]));
+					status = match ? ZAP_BREAK : ZAP_SUCCESS;
+				}
+
+				switch_regex_safe_free(re);
+			}
+		}
+		break;
+
+		case ZAP_SIGEVENT_PROGRESS:
+		{
+			if ((session = zap_channel_get_session(sigmsg->channel, 0))) {
+				channel = switch_core_session_get_channel(session);
+				switch_channel_mark_ring_ready(channel);
+				switch_core_session_rwunlock(session);
+			}
+		}
+		break;
+
+		case ZAP_SIGEVENT_UP:
+		{
+			if ((session = zap_channel_get_session(sigmsg->channel, 0))) {
+				zap_tone_type_t tt = ZAP_TONE_DTMF;
+				channel = switch_core_session_get_channel(session);
+				switch_channel_mark_answered(channel);
+				if (zap_channel_command(sigmsg->channel, ZAP_COMMAND_ENABLE_DTMF_DETECT, &tt) != ZAP_SUCCESS) {
+					zap_log(ZAP_LOG_ERROR, "Failed to enable DTMF detection in R2 channel %d:%d\n", sigmsg->channel->span_id, sigmsg->channel->chan_id);
+				}
+				switch_core_session_rwunlock(session);
+			}
+		}
+		break;
+
+		default:
+		{
+			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Unhandled event %d from R2 for channel %d:%d\n",
+			sigmsg->event_id, sigmsg->channel->span_id, sigmsg->channel->chan_id);
+		}
+		break;
+	}
+
+	return status;
+}
+
+static ZIO_SIGNAL_CB_FUNCTION(on_clear_channel_signal)
+{
+	switch_core_session_t *session = NULL;
+	switch_channel_t *channel = NULL;
+
+	zap_log(ZAP_LOG_DEBUG, "got clear channel sig [%s]\n", zap_signal_event2str(sigmsg->event_id));
+
+	if (on_common_signal(sigmsg) == ZAP_BREAK) {
+		return ZAP_SUCCESS;
+	}
+
+    switch(sigmsg->event_id) {
+    case ZAP_SIGEVENT_START:
+		{
+			zap_tone_type_t tt = ZAP_TONE_DTMF;
+
+			if (zap_channel_command(sigmsg->channel, ZAP_COMMAND_ENABLE_DTMF_DETECT, &tt) != ZAP_SUCCESS) {
+				zap_log(ZAP_LOG_ERROR, "TONE ERROR\n");
+			}
+
+			return zap_channel_from_event(sigmsg, &session);
+		}
+		break;
+    case ZAP_SIGEVENT_STOP:
+    case ZAP_SIGEVENT_RESTART:
+		{
+			private_t *tech_pvt = NULL;
+			while((session = zap_channel_get_session(sigmsg->channel, 0))) {
+				tech_pvt = switch_core_session_get_private(session);
+				switch_set_flag_locked(tech_pvt, TFLAG_DEAD);
+				channel = switch_core_session_get_channel(session);
+				switch_channel_hangup(channel, sigmsg->channel->caller_data.hangup_cause);
+				zap_channel_clear_token(sigmsg->channel, switch_core_session_get_uuid(session));
+				switch_core_session_rwunlock(session);
+			}
+		}
+		break;
+    case ZAP_SIGEVENT_UP:
+		{
+			if ((session = zap_channel_get_session(sigmsg->channel, 0))) {
+				zap_tone_type_t tt = ZAP_TONE_DTMF;
+				channel = switch_core_session_get_channel(session);
+				switch_channel_mark_answered(channel);
+				if (zap_channel_command(sigmsg->channel, ZAP_COMMAND_ENABLE_DTMF_DETECT, &tt) != ZAP_SUCCESS) {
+					zap_log(ZAP_LOG_ERROR, "TONE ERROR\n");
+				}
+				switch_core_session_rwunlock(session);
+			} else {
+				const char *uuid = zap_channel_get_uuid(sigmsg->channel, 0);
+
+				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Session for channel %d:%d not found [UUID: %s]\n",
+					sigmsg->channel->span_id, sigmsg->channel->chan_id, (uuid) ? uuid : "N/A");
+			}
+		}
+    case ZAP_SIGEVENT_PROGRESS_MEDIA:
+		{
+			if ((session = zap_channel_get_session(sigmsg->channel, 0))) {
+				channel = switch_core_session_get_channel(session);
+				switch_channel_mark_pre_answered(channel);
+				switch_core_session_rwunlock(session);
+			} else {
+				const char *uuid = zap_channel_get_uuid(sigmsg->channel, 0);
+
+				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Session for channel %d:%d not found [UUID: %s]\n",
+					sigmsg->channel->span_id, sigmsg->channel->chan_id, (uuid) ? uuid : "N/A");
+			}
+		}
+		break;
+    case ZAP_SIGEVENT_PROGRESS:
+		{
+			if ((session = zap_channel_get_session(sigmsg->channel, 0))) {
+				channel = switch_core_session_get_channel(session);
+				switch_channel_mark_ring_ready(channel);
+				switch_core_session_rwunlock(session);
+			} else {
+				const char *uuid = zap_channel_get_uuid(sigmsg->channel, 0);
+
+				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Session for channel %d:%d not found [UUID: %s]\n",
+					sigmsg->channel->span_id, sigmsg->channel->chan_id, (uuid) ? uuid : "N/A");
+			}
+		}
+		break;
+
+	default:
+		{
+			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Unhandled msg type %d for channel %d:%d\n",
+							  sigmsg->event_id, sigmsg->channel->span_id, sigmsg->channel->chan_id);
+		}
+		break;
+	}
+
+	return ZAP_SUCCESS;
+}
+
+
+static ZIO_SIGNAL_CB_FUNCTION(on_analog_signal)
+{
+	switch_status_t status = SWITCH_STATUS_FALSE;
+
+	if (on_common_signal(sigmsg) == ZAP_BREAK) {
+		return ZAP_SUCCESS;
+	}
+
+	switch (sigmsg->channel->type) {
+	case ZAP_CHAN_TYPE_FXO:
+	case ZAP_CHAN_TYPE_EM:
+		{
+			status = on_fxo_signal(sigmsg);
+		}
+		break;
+	case ZAP_CHAN_TYPE_FXS:
+		{
+			status = on_fxs_signal(sigmsg);
+		}
+		break;
+	default: 
+		{
+			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Unhandled analog channel type %d for channel %d:%d\n",
+							  sigmsg->channel->type, sigmsg->channel->span_id, sigmsg->channel->chan_id);
+		}
+		break;
+	}
+
+	return status;
+}
+
+static void zap_logger(const char *file, const char *func, int line, int level, const char *fmt, ...)
+{
+    char *data = NULL;
+    va_list ap;
+	
+    va_start(ap, fmt);
+
+	if (switch_vasprintf(&data, fmt, ap) != -1) {
+		switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, (char *)func, line, NULL, level, "%s", data);
+		free(data);
+	}
+	
+    va_end(ap);
+
+}
+
+static uint32_t enable_analog_option(const char *str, uint32_t current_options)
+{
+	if (!strcasecmp(str, "3-way")) {
+		current_options |= ANALOG_OPTION_3WAY;
+		current_options &= ~ANALOG_OPTION_CALL_SWAP;
+	} else if (!strcasecmp(str, "call-swap")) {
+		current_options |= ANALOG_OPTION_CALL_SWAP;
+		current_options &= ~ANALOG_OPTION_3WAY;
+	}
+	
+	return current_options;
+	
+}
+
+static switch_status_t load_config(void)
+{
+	const char *cf = "openzap.conf";
+	switch_xml_t cfg, xml, settings, param, spans, myspan;
+
+	memset(&globals, 0, sizeof(globals));
+	switch_mutex_init(&globals.mutex, SWITCH_MUTEX_NESTED, module_pool);
+	if (!(xml = switch_xml_open_cfg(cf, &cfg, NULL))) {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "open of %s failed\n", cf);
+		return SWITCH_STATUS_TERM;
+	}
+	
+	if ((settings = switch_xml_child(cfg, "settings"))) {
+		for (param = switch_xml_child(settings, "param"); param; param = param->next) {
+			char *var = (char *) switch_xml_attr_soft(param, "name");
+			char *val = (char *) switch_xml_attr_soft(param, "value");
+
+			if (!strcasecmp(var, "debug")) {
+				globals.debug = atoi(val);
+			} else if (!strcasecmp(var, "hold-music")) {
+				switch_set_string(globals.hold_music, val);
+			} else if (!strcasecmp(var, "enable-analog-option")) {
+				globals.analog_options = enable_analog_option(val, globals.analog_options);
+			}
+		}
+	}
+
+	if ((spans = switch_xml_child(cfg, "analog_spans"))) {
+		for (myspan = switch_xml_child(spans, "span"); myspan; myspan = myspan->next) {
+			char *id = (char *) switch_xml_attr(myspan, "id");
+			char *name = (char *) switch_xml_attr(myspan, "name");
+			zap_status_t zstatus = ZAP_FAIL;
+			const char *context = "default";
+			const char *dialplan = "XML";
+			const char *tonegroup = NULL;
+			char *digit_timeout = NULL;
+			char *max_digits = NULL;
+			char *hotline = NULL;
+			char *dial_regex = NULL;
+			char *hold_music = NULL;
+			char *fail_dial_regex = NULL;
+			const char *enable_callerid = "true";
+
+			uint32_t span_id = 0, to = 0, max = 0;
+			zap_span_t *span = NULL;
+			analog_option_t analog_options = ANALOG_OPTION_NONE;
+			
+			for (param = switch_xml_child(myspan, "param"); param; param = param->next) {
+				char *var = (char *) switch_xml_attr_soft(param, "name");
+				char *val = (char *) switch_xml_attr_soft(param, "value");
+
+				if (!strcasecmp(var, "tonegroup")) {
+					tonegroup = val;
+				} else if (!strcasecmp(var, "digit_timeout") || !strcasecmp(var, "digit-timeout")) {
+					digit_timeout = val;
+				} else if (!strcasecmp(var, "context")) {
+					context = val;
+				} else if (!strcasecmp(var, "dialplan")) {
+					dialplan = val;
+				} else if (!strcasecmp(var, "dial-regex")) {
+					dial_regex = val;
+				} else if (!strcasecmp(var, "enable-callerid")) {
+					enable_callerid = val;
+				} else if (!strcasecmp(var, "fail-dial-regex")) {
+					fail_dial_regex = val;
+				} else if (!strcasecmp(var, "hold-music")) {
+					hold_music = val;
+				} else if (!strcasecmp(var, "max_digits") || !strcasecmp(var, "max-digits")) {
+					max_digits = val;
+				} else if (!strcasecmp(var, "hotline")) {
+					hotline = val;
+				} else if (!strcasecmp(var, "enable-analog-option")) {
+					analog_options = enable_analog_option(val, analog_options);
+				}
+			}
+				
+			if (!id && !name) {
+				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "span missing required param 'id'\n");
+				continue;
+			}
+
+			
+			
+			if (!tonegroup) {
+				tonegroup = "us";
+			}
+			
+			if (digit_timeout) {
+				to = atoi(digit_timeout);
+			}
+
+			if (max_digits) {
+				max = atoi(max_digits);
+			}
+
+			if (name) {
+				zstatus = zap_span_find_by_name(name, &span);
+			} else {
+				if (switch_is_number(id)) {
+					span_id = atoi(id);
+					zstatus = zap_span_find(span_id, &span);
+				}
+
+				if (zstatus != ZAP_SUCCESS) {
+					zstatus = zap_span_find_by_name(id, &span);
+				}
+			}
+
+			if (zstatus != ZAP_SUCCESS) {
+				zap_log(ZAP_LOG_ERROR, "Error finding OpenZAP span id:%s name:%s\n", switch_str_nil(id), switch_str_nil(name));
+				continue;
+			}
+			
+			if (!span_id) {
+				span_id = span->span_id;
+			}
+
+			if (zap_configure_span("analog", span, on_analog_signal, 
+								   "tonemap", tonegroup, 
+								   "digit_timeout", &to,
+								   "max_dialstr", &max,
+								   "hotline", hotline,
+								   "enable_callerid", enable_callerid,
+								   TAG_END) != ZAP_SUCCESS) {
+				zap_log(ZAP_LOG_ERROR, "Error starting OpenZAP span %d\n", span_id);
+				continue;
+			}
+
+			SPAN_CONFIG[span->span_id].span = span;
+			switch_set_string(SPAN_CONFIG[span->span_id].context, context);
+			switch_set_string(SPAN_CONFIG[span->span_id].dialplan, dialplan);
+			SPAN_CONFIG[span->span_id].analog_options = analog_options | globals.analog_options;
+			
+			if (dial_regex) {
+				switch_set_string(SPAN_CONFIG[span->span_id].dial_regex, dial_regex);
+			}
+
+			if (fail_dial_regex) {
+				switch_set_string(SPAN_CONFIG[span->span_id].fail_dial_regex, fail_dial_regex);
+			}
+
+			if (hold_music) {
+				switch_set_string(SPAN_CONFIG[span->span_id].hold_music, hold_music);
+			}
+			switch_copy_string(SPAN_CONFIG[span->span_id].type, "analog", sizeof(SPAN_CONFIG[span->span_id].type));
+			zap_span_start(span);
+		}
+	}
+
+	if ((spans = switch_xml_child(cfg, "analog_em_spans"))) {
+		for (myspan = switch_xml_child(spans, "span"); myspan; myspan = myspan->next) {
+			char *id = (char *) switch_xml_attr(myspan, "id");
+			char *name = (char *) switch_xml_attr(myspan, "name");
+			zap_status_t zstatus = ZAP_FAIL;
+			const char *context = "default";
+			const char *dialplan = "XML";
+			const char *tonegroup = NULL;
+			char *digit_timeout = NULL;
+			char *max_digits = NULL;
+			char *dial_regex = NULL;
+			char *hold_music = NULL;
+			char *fail_dial_regex = NULL;
+			uint32_t span_id = 0, to = 0, max = 0;
+			zap_span_t *span = NULL;
+			analog_option_t analog_options = ANALOG_OPTION_NONE;
+
+			for (param = switch_xml_child(myspan, "param"); param; param = param->next) {
+				char *var = (char *) switch_xml_attr_soft(param, "name");
+				char *val = (char *) switch_xml_attr_soft(param, "value");
+
+				if (!strcasecmp(var, "tonegroup")) {
+					tonegroup = val;
+				} else if (!strcasecmp(var, "digit_timeout") || !strcasecmp(var, "digit-timeout")) {
+					digit_timeout = val;
+				} else if (!strcasecmp(var, "context")) {
+					context = val;
+				} else if (!strcasecmp(var, "dialplan")) {
+					dialplan = val;
+				} else if (!strcasecmp(var, "dial-regex")) {
+					dial_regex = val;
+				} else if (!strcasecmp(var, "fail-dial-regex")) {
+					fail_dial_regex = val;
+				} else if (!strcasecmp(var, "hold-music")) {
+					hold_music = val;
+				} else if (!strcasecmp(var, "max_digits") || !strcasecmp(var, "max-digits")) {
+					max_digits = val;
+				} else if (!strcasecmp(var, "enable-analog-option")) {
+					analog_options = enable_analog_option(val, analog_options);
+				}
+			}
+				
+			if (!id && !name) {
+				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "span missing required param 'id'\n");
+				continue;
+			}
+
+			
+			if (!tonegroup) {
+				tonegroup = "us";
+			}
+			
+			if (digit_timeout) {
+				to = atoi(digit_timeout);
+			}
+
+			if (max_digits) {
+				max = atoi(max_digits);
+			}
+
+
+			if (name) {
+				zstatus = zap_span_find_by_name(name, &span);
+			} else {
+				if (switch_is_number(id)) {
+					span_id = atoi(id);
+					zstatus = zap_span_find(span_id, &span);
+				}
+
+				if (zstatus != ZAP_SUCCESS) {
+					zstatus = zap_span_find_by_name(id, &span);
+				}
+			}
+
+			if (zstatus != ZAP_SUCCESS) {
+				zap_log(ZAP_LOG_ERROR, "Error finding OpenZAP span id:%s name:%s\n", switch_str_nil(id), switch_str_nil(name));
+				continue;
+			}
+			
+			if (!span_id) {
+				span_id = span->span_id;
+			}
+
+
+			if (zap_configure_span("analog_em", span, on_analog_signal, 
+								   "tonemap", tonegroup, 
+								   "digit_timeout", &to,
+								   "max_dialstr", &max,
+								   TAG_END) != ZAP_SUCCESS) {
+				zap_log(ZAP_LOG_ERROR, "Error starting OpenZAP span %d\n", span_id);
+				continue;
+			}
+
+			SPAN_CONFIG[span->span_id].span = span;
+			switch_set_string(SPAN_CONFIG[span->span_id].context, context);
+			switch_set_string(SPAN_CONFIG[span->span_id].dialplan, dialplan);
+			SPAN_CONFIG[span->span_id].analog_options = analog_options | globals.analog_options;
+			
+			if (dial_regex) {
+				switch_set_string(SPAN_CONFIG[span->span_id].dial_regex, dial_regex);
+			}
+
+			if (fail_dial_regex) {
+				switch_set_string(SPAN_CONFIG[span->span_id].fail_dial_regex, fail_dial_regex);
+			}
+
+			if (hold_music) {
+				switch_set_string(SPAN_CONFIG[span->span_id].hold_music, hold_music);
+			}
+			switch_copy_string(SPAN_CONFIG[span->span_id].type, "analog_em", sizeof(SPAN_CONFIG[span->span_id].type));
+			zap_span_start(span);
+		}
+	}
+
+	if ((spans = switch_xml_child(cfg, "pri_spans"))) {
+		for (myspan = switch_xml_child(spans, "span"); myspan; myspan = myspan->next) {
+			char *id = (char *) switch_xml_attr(myspan, "id");
+			char *name = (char *) switch_xml_attr(myspan, "name");
+			zap_status_t zstatus = ZAP_FAIL;
+			const char *context = "default";
+			const char *dialplan = "XML";
+			//Q921NetUser_t mode = Q931_TE;
+			//Q931Dialect_t dialect = Q931_Dialect_National;
+			char *mode = NULL;
+			char *dialect = NULL;
+			uint32_t span_id = 0;
+			zap_span_t *span = NULL;
+			const char *tonegroup = NULL;
+			char *digit_timeout = NULL;
+			const char *opts = "none";
+			uint32_t to = 0;
+			int q921loglevel = -1;
+			int q931loglevel = -1;
+			
+			// quick debug
+			//switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "ID: '%s', Name:'%s'\n",id,name);
+
+			for (param = switch_xml_child(myspan, "param"); param; param = param->next) {
+				char *var = (char *) switch_xml_attr_soft(param, "name");
+				char *val = (char *) switch_xml_attr_soft(param, "value");
+
+				if (!strcasecmp(var, "tonegroup")) {
+					tonegroup = val;
+				} else if (!strcasecmp(var, "mode")) {
+					mode = val;
+				} else if (!strcasecmp(var, "dialect")) {
+					dialect = val;
+				} else if (!strcasecmp(var, "q921loglevel")) {
+                    if ((q921loglevel = switch_log_str2level(val)) == SWITCH_LOG_INVALID) {
+                        q921loglevel = -1;
+                    }
+				} else if (!strcasecmp(var, "q931loglevel")) {
+                    if ((q931loglevel = switch_log_str2level(val)) == SWITCH_LOG_INVALID) {
+                        q931loglevel = -1;
+                    }
+				} else if (!strcasecmp(var, "context")) {
+					context = val;
+				} else if (!strcasecmp(var, "opts")) {
+					opts = val;
+				} else if (!strcasecmp(var, "dialplan")) {
+					dialplan = val;
+				} else if (!strcasecmp(var, "digit_timeout") || !strcasecmp(var, "digit-timeout")) {
+					digit_timeout = val;
+				}
+			}
+	
+			if (!id && !name) {
+				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "span missing required param 'id'\n");
+				continue;
+			}
+			
+			if (name) {
+				zstatus = zap_span_find_by_name(name, &span);
+			} else {
+				if (switch_is_number(id)) {
+					span_id = atoi(id);
+					zstatus = zap_span_find(span_id, &span);
+				}
+
+				if (zstatus != ZAP_SUCCESS) {
+					zstatus = zap_span_find_by_name(id, &span);
+				}
+			}
+
+			if (digit_timeout) {
+				to = atoi(digit_timeout);
+			}
+			
+			if (zstatus != ZAP_SUCCESS) {
+				zap_log(ZAP_LOG_ERROR, "Error finding OpenZAP span id:%s name:%s\n", switch_str_nil(id), switch_str_nil(name));
+				continue;
+			}
+
+                        if (!span_id) {
+                                span_id = span->span_id;
+                        }
+
+			if (!tonegroup) {
+				tonegroup = "us";
+			}
+			
+			if (zap_configure_span("isdn", span, on_clear_channel_signal, 
+								   "mode", mode,
+								   "dialect", dialect,
+								   "digit_timeout", &to,
+								   "opts", opts,
+								   "tonemap", tonegroup,
+								   "q921loglevel", q921loglevel,
+								   "q931loglevel", q931loglevel,
+								   TAG_END) != ZAP_SUCCESS) {
+				zap_log(ZAP_LOG_ERROR, "Error starting OpenZAP span %d mode: %s dialect: %s error: %s\n", span_id, mode, dialect, span->last_error);
+				continue;
+			}
+
+			SPAN_CONFIG[span->span_id].span = span;
+			switch_copy_string(SPAN_CONFIG[span->span_id].context, context, sizeof(SPAN_CONFIG[span->span_id].context));
+			switch_copy_string(SPAN_CONFIG[span->span_id].dialplan, dialplan, sizeof(SPAN_CONFIG[span->span_id].dialplan));
+			switch_copy_string(SPAN_CONFIG[span->span_id].type, "isdn", sizeof(SPAN_CONFIG[span->span_id].type));
+
+			zap_span_start(span);
+		}
+	}
+
+
+
+	if ((spans = switch_xml_child(cfg, "libpri_spans"))) {
+		for (myspan = switch_xml_child(spans, "span"); myspan; myspan = myspan->next) {
+			char *id = (char *) switch_xml_attr(myspan, "id");
+			char *name = (char *) switch_xml_attr(myspan, "name");
+			zap_status_t zstatus = ZAP_FAIL;
+			const char *context = "default";
+			const char *dialplan = "XML";
+			
+			const char *o_node = "cpe";
+			const char *o_switch = "dms100";
+			const char *o_dp = "unknown";
+			const char *o_l1 = "ulaw";
+			const char *o_debug = "none";
+			const char* opts = "none";	
+					
+			uint32_t span_id = 0;
+			zap_span_t *span = NULL;
+
+			
+			for (param = switch_xml_child(myspan, "param"); param; param = param->next) {
+				char *var = (char *) switch_xml_attr_soft(param, "name");
+				char *val = (char *) switch_xml_attr_soft(param, "value");
+
+				if (!strcasecmp(var, "node")) {
+					o_node = val;
+				} else if (!strcasecmp(var, "switch")) {
+					o_switch = val;
+				} else if (!strcasecmp(var, "dp")) {
+					o_dp = val;
+				} else if (!strcasecmp(var, "l1")) {
+					o_l1 = val;
+				} else if (!strcasecmp(var, "debug")) {
+					o_debug = val;
+				} else if (!strcasecmp(var, "context")) {
+					context = val;
+				} else if (!strcasecmp(var, "opts")) {
+					opts = val;
+				} else if (!strcasecmp(var, "dialplan")) {
+					dialplan = val;
+				}
+			}
+	
+			if (!id && !name) {
+				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "span missing required param 'id'\n");
+				continue;
+			}
+			
+			if (name) {
+				zstatus = zap_span_find_by_name(name, &span);
+			} else {
+				if (switch_is_number(id)) {
+					span_id = atoi(id);
+					zstatus = zap_span_find(span_id, &span);
+				}
+
+				if (zstatus != ZAP_SUCCESS) {
+					zstatus = zap_span_find_by_name(id, &span);
+				}
+			}
+
+			if (zstatus != ZAP_SUCCESS) {
+				zap_log(ZAP_LOG_ERROR, "Error finding OpenZAP span id:%s name:%s\n", switch_str_nil(id), switch_str_nil(name));
+				continue;
+			}
+
+			if (!span_id) {
+				span_id = span->span_id;
+			}
+			
+			
+			if (zap_configure_span("libpri", span, on_clear_channel_signal, 
+								   "node", o_node,
+								   "switch", o_switch,
+								   "dp", o_dp,
+								   "l1", o_l1,
+								   "debug", o_debug,
+								   "opts", opts,
+								   TAG_END) != ZAP_SUCCESS) {
+				zap_log(ZAP_LOG_ERROR, "Error starting OpenZAP span %d node: %s switch: %s dp: %s l1: %s debug: %s error: %s\n", 
+						span_id, switch_str_nil(o_node), switch_str_nil(o_switch), switch_str_nil(o_dp), switch_str_nil(o_l1), switch_str_nil(o_debug),
+						span->last_error);
+				continue;
+			}
+
+			SPAN_CONFIG[span->span_id].span = span;
+			switch_copy_string(SPAN_CONFIG[span->span_id].context, context, sizeof(SPAN_CONFIG[span->span_id].context));
+			switch_copy_string(SPAN_CONFIG[span->span_id].dialplan, dialplan, sizeof(SPAN_CONFIG[span->span_id].dialplan));
+			switch_copy_string(SPAN_CONFIG[span->span_id].type, "isdn", sizeof(SPAN_CONFIG[span->span_id].type));
+
+			zap_span_start(span);
+		}
+	}
+
+	if ((spans = switch_xml_child(cfg, "boost_spans"))) {
+		for (myspan = switch_xml_child(spans, "span"); myspan; myspan = myspan->next) {
+			char *id = (char *) switch_xml_attr(myspan, "id");
+			char *name = (char *) switch_xml_attr(myspan, "name");
+			zap_status_t zstatus = ZAP_FAIL;
+			const char *context = "default";
+			const char *dialplan = "XML";
+			const char *outbound_called_ton = "national";
+			const char *outbound_called_npi = "isdn";
+			const char *outbound_calling_ton = "national";
+			const char *outbound_calling_npi = "isdn";
+			const char *outbound_rdnis_ton = "national";
+			const char *outbound_rdnis_npi = "isdn";
+			uint32_t span_id = 0;
+			zap_span_t *span = NULL;
+			const char *tonegroup = NULL;
+			char *local_ip = NULL;
+			int local_port = 0;
+			char *remote_ip = NULL;
+			int remote_port = 0;
+
+			for (param = switch_xml_child(myspan, "param"); param; param = param->next) {
+				char *var = (char *) switch_xml_attr_soft(param, "name");
+				char *val = (char *) switch_xml_attr_soft(param, "value");
+
+				if (!strcasecmp(var, "tonegroup")) {
+					tonegroup = val;
+				} else if (!strcasecmp(var, "local-ip")) {
+					local_ip = val;
+				} else if (!strcasecmp(var, "local-port")) {
+					local_port = atoi(val);
+				} else if (!strcasecmp(var, "remote-ip")) {
+					remote_ip = val;
+				} else if (!strcasecmp(var, "remote-port")) {
+					remote_port = atoi(val);
+				} else if (!strcasecmp(var, "context")) {
+					context = val;
+				} else if (!strcasecmp(var, "outbound-called-ton")) {
+					outbound_called_ton = val;
+				} else if (!strcasecmp(var, "outbound-called-npi")) {
+					outbound_called_npi = val;
+				} else if (!strcasecmp(var, "outbound-calling-ton")) {
+					outbound_calling_ton = val;
+				} else if (!strcasecmp(var, "outbound-calling-npi")) {
+					outbound_calling_npi = val;
+				} else if (!strcasecmp(var, "outbound-rdnis-ton")) {
+					outbound_rdnis_ton = val;
+				} else if (!strcasecmp(var, "outbound-rdnis-npi")) {
+					outbound_rdnis_npi = val;
+				} 
+			}
+				
+			if (!id && !name) {
+				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "span missing required param\n");
+				continue;
+			}
+
+			if (!tonegroup) {
+				tonegroup = "us";
+			}
+			
+			if (name) {
+				zstatus = zap_span_find_by_name(name, &span);
+			} else {
+				if (switch_is_number(id)) {
+					span_id = atoi(id);
+					zstatus = zap_span_find(span_id, &span);
+				}
+
+				if (zstatus != ZAP_SUCCESS) {
+					zstatus = zap_span_find_by_name(id, &span);
+				}
+			}
+
+			if (zstatus != ZAP_SUCCESS) {
+				zap_log(ZAP_LOG_ERROR, "Error finding OpenZAP span id:%s name:%s\n", switch_str_nil(id), switch_str_nil(name));
+				continue;
+			}
+			
+			if (!span_id) {
+				span_id = span->span_id;
+			}
+
+			zap_set_npi(outbound_called_npi, &span->default_caller_data.ani.plan);
+			zap_set_npi(outbound_calling_npi, &span->default_caller_data.cid_num.plan);
+			zap_set_npi(outbound_rdnis_npi, &span->default_caller_data.rdnis.plan);
+
+			zap_set_ton(outbound_called_ton, &span->default_caller_data.ani.type);
+			zap_set_ton(outbound_calling_ton, &span->default_caller_data.cid_num.type);
+			zap_set_ton(outbound_rdnis_ton, &span->default_caller_data.rdnis.type);
+
+			if (zap_configure_span("sangoma_boost", span, on_clear_channel_signal, 
+								   "local_ip", local_ip,
+								   "local_port", &local_port,
+								   "remote_ip", remote_ip,
+								   "remote_port", &remote_port,
+								   TAG_END) != ZAP_SUCCESS) {
+				zap_log(ZAP_LOG_ERROR, "Error starting OpenZAP span %d error: %s\n", span_id, span->last_error);
+				continue;
+			}
+
+			SPAN_CONFIG[span->span_id].span = span;
+			switch_copy_string(SPAN_CONFIG[span->span_id].context, context, sizeof(SPAN_CONFIG[span->span_id].context));
+			switch_copy_string(SPAN_CONFIG[span->span_id].dialplan, dialplan, sizeof(SPAN_CONFIG[span->span_id].dialplan));
+
+			zap_span_start(span);
+			switch_copy_string(SPAN_CONFIG[span->span_id].type, "Sangoma (boost)", sizeof(SPAN_CONFIG[span->span_id].type));
+		}
+	}
+
+	if ((spans = switch_xml_child(cfg, "r2_spans"))) {
+		for (myspan = switch_xml_child(spans, "span"); myspan; myspan = myspan->next) {
+			char *id = (char *) switch_xml_attr(myspan, "id");
+			char *name = (char *) switch_xml_attr(myspan, "name");
+			zap_status_t zstatus = ZAP_FAIL;
+
+			/* strings */
+			const char *variant = "itu";
+			const char *category = "national_subscriber";
+			const char *logdir = "/usr/local/freeswitch/log/"; /* FIXME: get PREFIX variable */
+			const char *logging = "notice,warning,error";
+			const char *advanced_protocol_file = "";
+
+			/* booleans */
+			int call_files = 0;
+			int get_ani_first = -1;
+			int immediate_accept = -1;
+			int double_answer = -1;
+			int skip_category = -1;
+			int forced_release = -1;
+			int charge_calls = -1;
+
+			/* integers */
+			int mfback_timeout = -1;
+			int metering_pulse_timeout = -1;
+			int allow_collect_calls = -1;
+			int max_ani = 10;
+			int max_dnis = 4;
+
+			/* common non r2 stuff */
+			const char *context = "default";
+			const char *dialplan = "XML";
+			char *dial_regex = NULL;
+			char *fail_dial_regex = NULL;
+			uint32_t span_id = 0;
+			zap_span_t *span = NULL;
+
+
+			for (param = switch_xml_child(myspan, "param"); param; param = param->next) {
+				char *var = (char *) switch_xml_attr_soft(param, "name");
+				char *val = (char *) switch_xml_attr_soft(param, "value");
+
+				/* string parameters */
+				if (!strcasecmp(var, "variant")) {
+					variant = val;
+				} else if (!strcasecmp(var, "category")) {
+					category = val;
+				} else if (!strcasecmp(var, "logdir")) {
+					logdir = val;
+				} else if (!strcasecmp(var, "logging")) {
+					logging = val;
+				} else if (!strcasecmp(var, "advanced_protocol_file")) {
+					advanced_protocol_file = val;
+
+				/* booleans */
+				} else if (!strcasecmp(var, "allow_collect_calls")) {
+					allow_collect_calls = switch_true(val);
+				} else if (!strcasecmp(var, "immediate_accept")) {
+					immediate_accept = switch_true(val);
+				} else if (!strcasecmp(var, "double_answer")) {
+					double_answer = switch_true(val);
+				} else if (!strcasecmp(var, "skip_category")) {
+					skip_category = switch_true(var);
+				} else if (!strcasecmp(var, "forced_release")) {
+					forced_release = switch_true(val);
+				} else if (!strcasecmp(var, "charge_calls")) {
+					charge_calls = switch_true(val);
+				} else if (!strcasecmp(var, "get_ani_first")) {
+					get_ani_first = switch_true(val);
+				} else if (!strcasecmp(var, "call_files")) {
+					call_files = switch_true(val);
+
+				/* integers */
+				} else if (!strcasecmp(var, "mfback_timeout")) {
+					mfback_timeout = atoi(val);
+				} else if (!strcasecmp(var, "metering_pulse_timeout")) {
+					metering_pulse_timeout = atoi(val);
+				} else if (!strcasecmp(var, "max_ani")) {
+					max_ani = atoi(val);
+				} else if (!strcasecmp(var, "max_dnis")) {
+					max_dnis = atoi(val);
+
+				/* common non r2 stuff */
+				} else if (!strcasecmp(var, "context")) {
+					context = val;
+				} else if (!strcasecmp(var, "dialplan")) {
+					dialplan = val;
+				} else if (!strcasecmp(var, "dial-regex")) {
+					dial_regex = val;
+				} else if (!strcasecmp(var, "fail-dial-regex")) {
+					fail_dial_regex = val;
+				}
+			}
+
+			if (!id && !name) {
+				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "span missing required param 'id'\n");
+				continue;
+			}
+
+			if (name) {
+				zstatus = zap_span_find_by_name(name, &span);
+			} else {
+				if (switch_is_number(id)) {
+					span_id = atoi(id);
+					zstatus = zap_span_find(span_id, &span);
+				}
+
+				if (zstatus != ZAP_SUCCESS) {
+					zstatus = zap_span_find_by_name(id, &span);
+				}
+			}
+
+			if (zstatus != ZAP_SUCCESS) {
+				zap_log(ZAP_LOG_ERROR, "Error finding OpenZAP span id:%s name:%s\n", switch_str_nil(id), switch_str_nil(name));
+				continue;
+			}
+
+			if (!span_id) {
+				span_id = span->span_id;
+			}
+
+			if (zap_configure_span("r2", span, on_r2_signal, 
+				"variant", variant, 
+				"max_ani", max_ani,
+				"max_dnis", max_dnis,
+				"category", category,
+				"logdir", logdir,
+				"logging", logging,
+				"advanced_protocol_file", advanced_protocol_file,
+				"allow_collect_calls", allow_collect_calls,
+				"immediate_accept", immediate_accept,
+				"double_answer", double_answer,
+				"skip_category", skip_category,
+				"forced_release", forced_release,
+				"charge_calls", charge_calls,
+				"get_ani_first", get_ani_first,
+				"call_files", call_files,
+				"mfback_timeout", mfback_timeout,
+				"metering_pulse_timeout", metering_pulse_timeout, 
+				TAG_END) != ZAP_SUCCESS) {
+				zap_log(ZAP_LOG_ERROR, "Error configuring R2 OpenZAP span %d, error: %s\n", 
+				span_id, span->last_error);
+				continue;
+			}
+
+			if (dial_regex) {
+				switch_set_string(SPAN_CONFIG[span->span_id].dial_regex, dial_regex);
+			}
+
+			if (fail_dial_regex) {
+				switch_set_string(SPAN_CONFIG[span->span_id].fail_dial_regex, fail_dial_regex);
+			}
+
+			SPAN_CONFIG[span->span_id].span = span;
+			switch_copy_string(SPAN_CONFIG[span->span_id].context, context, sizeof(SPAN_CONFIG[span->span_id].context));
+			switch_copy_string(SPAN_CONFIG[span->span_id].dialplan, dialplan, sizeof(SPAN_CONFIG[span->span_id].dialplan));
+			switch_copy_string(SPAN_CONFIG[span->span_id].type, "r2", sizeof(SPAN_CONFIG[span->span_id].type));
+
+			if (zap_span_start(span) == ZAP_FAIL) {
+				zap_log(ZAP_LOG_ERROR, "Error starting R2 OpenZAP span %d, error: %s\n", span_id, span->last_error);
+				continue;
+			}
+		}
+	}
+
+	switch_xml_free(xml);
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+
+void dump_chan(zap_span_t *span, uint32_t chan_id, switch_stream_handle_t *stream)
+{
+	if (chan_id > span->chan_count) {
+		return;
+	}
+
+	stream->write_function(stream,
+						   "span_id: %u\n"
+						   "chan_id: %u\n"
+						   "physical_span_id: %u\n"
+						   "physical_chan_id: %u\n"
+						   "type: %s\n"
+						   "state: %s\n"
+						   "last_state: %s\n"
+						   "txgain: %3.2f\n"
+						   "rxgain: %3.2f\n"
+						   "cid_date: %s\n"
+						   "cid_name: %s\n"
+						   "cid_num: %s\n"
+						   "ani: %s\n"
+						   "aniII: %s\n"
+						   "dnis: %s\n"
+						   "rdnis: %s\n"
+						   "cause: %s\n\n",
+						   span->channels[chan_id]->span_id,
+						   span->channels[chan_id]->chan_id,
+						   span->channels[chan_id]->physical_span_id,
+						   span->channels[chan_id]->physical_chan_id,
+						   zap_chan_type2str(span->channels[chan_id]->type),
+						   zap_channel_state2str(span->channels[chan_id]->state),
+						   zap_channel_state2str(span->channels[chan_id]->last_state),
+						   span->channels[chan_id]->txgain,
+						   span->channels[chan_id]->rxgain,
+						   span->channels[chan_id]->caller_data.cid_date,
+						   span->channels[chan_id]->caller_data.cid_name,
+						   span->channels[chan_id]->caller_data.cid_num.digits,
+						   span->channels[chan_id]->caller_data.ani.digits,
+						   span->channels[chan_id]->caller_data.aniII,
+						   span->channels[chan_id]->caller_data.dnis.digits,
+						   span->channels[chan_id]->caller_data.rdnis.digits,
+						   switch_channel_cause2str(span->channels[chan_id]->caller_data.hangup_cause)
+						   );
+}
+
+void dump_chan_xml(zap_span_t *span, uint32_t chan_id, switch_stream_handle_t *stream)
+{
+	if (chan_id > span->chan_count) {
+		return;
+	}
+
+	stream->write_function(stream,
+						   " <channel>\n"
+						   "  <span-id>%u</span-id>\n"
+						   "  <chan-id>%u</chan-id>>\n"
+						   "  <physical-span-id>%u</physical-span-id>\n"
+						   "  <physical-chan-id>%u</physical-chan-id>\n"
+						   "  <type>%s</type>\n"
+						   "  <state>%s</state>\n"
+						   "  <last-state>%s</last-state>\n"
+						   "  <txgain>%3.2f</txgain>\n"
+						   "  <rxgain>%3.2f</rxgain>\n"
+						   "  <cid-date>%s</cid-date>\n"
+						   "  <cid-name>%s</cid-name>\n"
+						   "  <cid-num>%s</cid-num>\n"
+						   "  <ani>%s</ani>\n"
+						   "  <aniII>%s</aniII>\n"
+						   "  <dnis>%s</dnis>\n"
+						   "  <rdnis>%s</rdnis>\n"
+						   "  <cause>%s</cause>\n"
+						   " </channel>\n",
+						   span->channels[chan_id]->span_id,
+						   span->channels[chan_id]->chan_id,
+						   span->channels[chan_id]->physical_span_id,
+						   span->channels[chan_id]->physical_chan_id,
+						   zap_chan_type2str(span->channels[chan_id]->type),
+						   zap_channel_state2str(span->channels[chan_id]->state),
+						   zap_channel_state2str(span->channels[chan_id]->last_state),
+						   span->channels[chan_id]->txgain,
+						   span->channels[chan_id]->rxgain,
+						   span->channels[chan_id]->caller_data.cid_date,
+						   span->channels[chan_id]->caller_data.cid_name,
+						   span->channels[chan_id]->caller_data.cid_num.digits,
+						   span->channels[chan_id]->caller_data.ani.digits,
+						   span->channels[chan_id]->caller_data.aniII,
+						   span->channels[chan_id]->caller_data.dnis.digits,
+						   span->channels[chan_id]->caller_data.rdnis.digits,
+						   switch_channel_cause2str(span->channels[chan_id]->caller_data.hangup_cause)
+						   );
+}
+
+#define OZ_SYNTAX "list || dump <span_id> [<chan_id>] || q931_pcap <span_id> on|off [pcapfilename without suffix] || gains <txgain> <rxgain> <span_id> [<chan_id>]" 
+SWITCH_STANDARD_API(oz_function)
+{
+	char *mycmd = NULL, *argv[10] = { 0 };
+	int argc = 0;
+
+	if (!zstr(cmd) && (mycmd = strdup(cmd))) {
+		argc = switch_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
+	}
+
+	if (!argc) {
+		stream->write_function(stream, "%s", OZ_SYNTAX);
+		goto end;
+	}
+
+	if (!strcasecmp(argv[0], "dump")) {
+		if (argc < 2) {
+			stream->write_function(stream, "-ERR Usage: oz dump <span_id> [<chan_id>]\n");
+			goto end;
+		} else {
+			uint32_t chan_id = 0;
+			zap_span_t *span;
+			char *as = NULL;
+			
+			zap_span_find_by_name(argv[1], &span);
+			
+			if (argc > 2) {
+				if (argv[3] && !strcasecmp(argv[2], "as")) {
+					as = argv[3];
+				} else {
+					chan_id = atoi(argv[2]);
+				}
+			}
+
+			if (argv[4] && !strcasecmp(argv[3], "as")) {
+				as = argv[4];
+			}
+
+			if (!zstr(as) && !strcasecmp(as, "xml")) {
+				stream->write_function(stream, "<channels>\n");
+				if (!span) {
+					stream->write_function(stream, "<error>invalid span</error>\n");
+				} else {
+					if (chan_id) {
+						if(chan_id > span->chan_count) {
+							stream->write_function(stream, "<error>invalid channel</error>\n");
+						} else {
+							dump_chan_xml(span, chan_id, stream);
+						}
+					} else {
+						uint32_t j;
+						for (j = 1; j <= span->chan_count; j++) {
+							dump_chan_xml(span, j, stream);
+						}
+						
+					}
+				}
+				stream->write_function(stream, "</channels>\n");
+			} else {
+				if (!span) {
+					stream->write_function(stream, "-ERR invalid span\n");
+				} else {
+					if (chan_id) {
+						if(chan_id > span->chan_count) {
+							stream->write_function(stream, "-ERR invalid channel\n");
+						} else {
+							dump_chan(span, chan_id, stream);
+						}
+					} else {
+						uint32_t j;
+						
+						stream->write_function(stream, "+OK\n");
+						for (j = 1; j <= span->chan_count; j++) {
+							dump_chan(span, j, stream);
+						}
+						
+					}
+				}
+			}
+		}
+	} else if (!strcasecmp(argv[0], "list")) {
+		int j;
+		for (j = 0 ; j < ZAP_MAX_SPANS_INTERFACE; j++) {
+			if (SPAN_CONFIG[j].span) {
+				const char *flags = "none";
+
+				if (SPAN_CONFIG[j].analog_options & ANALOG_OPTION_3WAY) {
+					flags = "3way";
+				} else if (SPAN_CONFIG[j].analog_options & ANALOG_OPTION_CALL_SWAP) {
+					flags = "call swap";
+				}
+
+				stream->write_function(stream,
+									   "+OK\n"
+									   "span: %u (%s)\n"
+									   "type: %s\n"
+									   "chan_count: %u\n"
+									   "dialplan: %s\n"
+									   "context: %s\n"
+									   "dial_regex: %s\n"
+									   "fail_dial_regex: %s\n"
+									   "hold_music: %s\n"
+									   "analog_options %s\n",
+									   j,
+									   SPAN_CONFIG[j].span->name,
+									   SPAN_CONFIG[j].type,
+									   SPAN_CONFIG[j].span->chan_count,
+									   SPAN_CONFIG[j].dialplan,
+									   SPAN_CONFIG[j].context,
+									   SPAN_CONFIG[j].dial_regex,
+									   SPAN_CONFIG[j].fail_dial_regex,
+									   SPAN_CONFIG[j].hold_music,
+									   flags
+									   );
+			}
+		}
+	} else if (!strcasecmp(argv[0], "stop") || !strcasecmp(argv[0], "start")) {
+		char *span_name = argv[1];
+		zap_span_t *span = NULL;
+		zap_status_t status;
+
+		if (span_name) {
+			zap_span_find_by_name(span_name, &span);
+		}
+
+		if (!span) {
+			stream->write_function(stream, "-ERR no span\n");
+			goto end;
+		}
+		
+		if (!strcasecmp(argv[0], "stop")) {
+			status = zap_span_stop(span);
+		} else {
+			status = zap_span_start(span);
+		}
+		
+		stream->write_function(stream, status == ZAP_SUCCESS ? "+OK\n" : "-ERR failure\n");
+		
+		goto end;
+
+		/*Q931ToPcap enhancement*/
+	} else if (!strcasecmp(argv[0], "q931_pcap")) {
+		int32_t span_id = 0;
+                zap_span_t *span;
+		const char *pcapfn = NULL;
+		char *tmp_path = NULL;
+
+                if (argc < 3) {
+                        stream->write_function(stream, "-ERR Usage: oz q931_pcap <span_id> on|off [pcapfilename without suffix]\n");
+                        goto end;
+                }
+		span_id = atoi(argv[1]);
+		if (!(span_id && (span = SPAN_CONFIG[span_id].span))) {
+                                stream->write_function(stream, "-ERR invalid span\n");
+				goto end;
+                } 
+
+		/*Look for a given file name or use default file name*/
+		if (argc > 3) {
+			if(argv[3]){
+				pcapfn=argv[3];
+			}
+		}
+		else {
+			pcapfn="q931";
+		}
+
+		/*Add log directory path to file name*/
+		tmp_path=switch_mprintf("%s%s%s.pcap", SWITCH_GLOBAL_dirs.log_dir, SWITCH_PATH_SEPARATOR, pcapfn);
+		
+		if(!strcasecmp(argv[2], "on")) {
+			if (zap_configure_span("isdn", span, on_clear_channel_signal, "q931topcap", 1, "pcapfilename", tmp_path, TAG_END) != ZAP_SUCCESS) {
+                                zap_log(ZAP_LOG_WARNING, "Error couldn't (re-)enable Q931-To-Pcap!\n");
+				goto end;
+                        } else {
+				stream->write_function(stream, "+OK\n");
+			}
+		} else if(!strcasecmp(argv[2], "off")) {
+			if (zap_configure_span("isdn", span, on_clear_channel_signal, "q931topcap", 0, TAG_END) != ZAP_SUCCESS) {
+                                zap_log(ZAP_LOG_ERROR, "Error couldn't enable Q931-To-Pcap!\n");
+                                goto end;
+			} else {
+                                stream->write_function(stream, "+OK\n");
+                        }
+                } else {
+			stream->write_function(stream, "-ERR Usage: oz q931_pcap <span_id> on|off [pcapfilename without suffix]\n");
+                        goto end;
+		}
+
+	} else if (!strcasecmp(argv[0], "gains")) {
+		int i = 0;
+		float txgain = 0.0;
+		float rxgain = 0.0;
+		uint32_t chan_id = 0;
+		zap_span_t *span = NULL;
+		if (argc < 4) {
+			stream->write_function(stream, "-ERR Usage: oz gains <txgain> <rxgain> <span_id> [<chan_id>]\n");
+			goto end;
+		} 
+		zap_span_find_by_name(argv[3], &span);
+		if (!span) {
+			stream->write_function(stream, "-ERR invalid span\n");
+			goto end;
+		}
+		if (argc > 4) {
+			chan_id = atoi(argv[4]);
+			if (chan_id > span->chan_count) {
+				stream->write_function(stream, "-ERR invalid chan\n");
+				goto end;
+			}
+		}
+		i = sscanf(argv[1], "%f", &rxgain);
+		i += sscanf(argv[2], "%f", &txgain);
+		if (i != 2) {
+			stream->write_function(stream, "-ERR invalid gains\n");
+			goto end;
+		}
+		if (chan_id) {
+			zap_channel_command(span->channels[chan_id], ZAP_COMMAND_SET_RX_GAIN, &rxgain);
+			zap_channel_command(span->channels[chan_id], ZAP_COMMAND_SET_TX_GAIN, &txgain);
+		} else {
+			for (i = 1; i < (int)span->chan_count; i++) {
+				zap_channel_command(span->channels[i], ZAP_COMMAND_SET_RX_GAIN, &rxgain);
+				zap_channel_command(span->channels[i], ZAP_COMMAND_SET_TX_GAIN, &txgain);
+			}
+		}
+		stream->write_function(stream, "+OK gains set to Rx %f and Tx %f\n", rxgain, txgain);
+	} else {
+		char *rply = zap_api_execute(cmd, NULL);
+		
+		if (rply) {
+			stream->write_function(stream, "%s", rply);
+			free(rply);
+		} else {
+			stream->write_function(stream, "-ERR Usage: %s\n", OZ_SYNTAX);
+		}
+	}
+	/*Q931ToPcap enhancement done*/
+
+ end:
+
+	switch_safe_free(mycmd);
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+
+SWITCH_STANDARD_APP(disable_ec_function)
+{
+	private_t *tech_pvt;
+	int x = 0;
+
+	if (!switch_core_session_check_interface(session, openzap_endpoint_interface)) {
+		zap_log(ZAP_LOG_ERROR, "This application is only for OpenZAP channels.\n");
+		return;
+	}
+	
+	tech_pvt = switch_core_session_get_private(session);
+
+	if (switch_test_flag(tech_pvt, TFLAG_DEAD)) {
+        switch_channel_hangup(switch_core_session_get_channel(session), SWITCH_CAUSE_LOSE_RACE);
+        return;
+    }
+	
+	zap_channel_command(tech_pvt->zchan, ZAP_COMMAND_DISABLE_ECHOCANCEL, &x);
+	zap_channel_command(tech_pvt->zchan, ZAP_COMMAND_DISABLE_ECHOTRAIN, &x);
+	zap_log(ZAP_LOG_INFO, "Echo Canceller Disabled\n");
+}
+
+
+SWITCH_MODULE_LOAD_FUNCTION(mod_openzap_load)
+{
+
+	switch_api_interface_t *commands_api_interface;
+	switch_application_interface_t *app_interface;
+
+	module_pool = pool;
+
+	zap_global_set_logger(zap_logger);
+	zap_cpu_monitor_disable();
+
+	if (zap_global_init() != ZAP_SUCCESS) {
+		zap_log(ZAP_LOG_ERROR, "Error loading OpenZAP\n");
+		return SWITCH_STATUS_TERM;
+	}
+
+	if (load_config() != SWITCH_STATUS_SUCCESS) {
+		zap_global_destroy();
+		return SWITCH_STATUS_TERM;
+	}
+
+	*module_interface = switch_loadable_module_create_module_interface(pool, modname);
+	openzap_endpoint_interface = switch_loadable_module_create_interface(*module_interface, SWITCH_ENDPOINT_INTERFACE);
+	openzap_endpoint_interface->interface_name = "openzap";
+	openzap_endpoint_interface->io_routines = &openzap_io_routines;
+	openzap_endpoint_interface->state_handler = &openzap_state_handlers;
+	
+	SWITCH_ADD_API(commands_api_interface, "oz", "OpenZAP commands", oz_function, OZ_SYNTAX);
+
+	SWITCH_ADD_APP(app_interface, "disable_ec", "Disable Echo Canceller", "Disable Echo Canceller", disable_ec_function, "", SAF_NONE);
+
+	/* indicate that the module should continue to be loaded */
+	return SWITCH_STATUS_SUCCESS;
+}
+
+SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_openzap_shutdown)
+{
+	zap_global_destroy();
+
+	// this breaks pika but they are MIA so *shrug*
+	//return SWITCH_STATUS_NOUNLOAD;
+	return SWITCH_STATUS_SUCCESS;
+}
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */

Added: freeswitch/trunk/libs/openzap/msvc/openzap.2005.vcproj (0 => 17141)


--- freeswitch/trunk/libs/openzap/msvc/openzap.2005.vcproj	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/msvc/openzap.2005.vcproj	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,301 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="8.00"
+	Name="openzap"
+	ProjectGUID="{93B8812C-3EC4-4F78-8970-FFBFC99E167D}"
+	RootNamespace="openzap"
+	Keyword="Win32Proj"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="2"
+			CharacterSet="2"
+			BuildLogFile="$(IntDir)\BuildLog-openzap.htm"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				AdditionalIncludeDirectories="../src/include;../src/isdn/include"
+				PreprocessorDefinitions="WIN32;_DEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;OPENZAP_EXPORTS;TELETONE_EXPORTS"
+				MinimalRebuild="true"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="3"
+				DisableLanguageExtensions="false"
+				RuntimeTypeInfo="false"
+				UsePrecompiledHeader="0"
+				WarningLevel="4"
+				WarnAsError="true"
+				Detect64BitPortabilityProblems="true"
+				DebugInformationFormat="3"
+				CompileAs="1"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="2"
+			CharacterSet="2"
+			WholeProgramOptimization="1"
+			BuildLogFile="$(IntDir)\BuildLog-openzap.htm"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalIncludeDirectories="../src/include;../src/isdn/include"
+				PreprocessorDefinitions="WIN32;NDEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;OPENZAP_EXPORTS;TELETONE_EXPORTS"
+				RuntimeLibrary="2"
+				DisableLanguageExtensions="false"
+				RuntimeTypeInfo="false"
+				UsePrecompiledHeader="0"
+				WarningLevel="4"
+				WarnAsError="true"
+				Detect64BitPortabilityProblems="true"
+				DebugInformationFormat="3"
+				CompileAs="1"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<Filter
+			Name="Source Files"
+			Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+			>
+			<File
+				RelativePath="..\src\fsk.c"
+				>
+			</File>
+			<File
+				RelativePath="..\src\g711.c"
+				>
+			</File>
+			<File
+				RelativePath="..\src\hashtable.c"
+				>
+			</File>
+			<File
+				RelativePath="..\src\hashtable_itr.c"
+				>
+			</File>
+			<File
+				RelativePath="..\src\libteletone_detect.c"
+				>
+			</File>
+			<File
+				RelativePath="..\src\libteletone_generate.c"
+				>
+			</File>
+			<File
+				RelativePath="..\src\uart.c"
+				>
+			</File>
+			<File
+				RelativePath="..\src\zap_buffer.c"
+				>
+			</File>
+			<File
+				RelativePath="..\src\zap_callerid.c"
+				>
+			</File>
+			<File
+				RelativePath="..\src\zap_config.c"
+				>
+			</File>
+			<File
+				RelativePath="..\src\zap_dso.c"
+				>
+			</File>
+			<File
+				RelativePath="..\src\zap_io.c"
+				>
+			</File>
+			<File
+				RelativePath="..\src\zap_threadmutex.c"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="Header Files"
+			Filter="h;hpp;hxx;hm;inl;inc;xsd"
+			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+			>
+			<File
+				RelativePath="..\src\include\fsk.h"
+				>
+			</File>
+			<File
+				RelativePath="..\src\include\g711.h"
+				>
+			</File>
+			<File
+				RelativePath="..\src\include\hashtable.h"
+				>
+			</File>
+			<File
+				RelativePath="..\src\include\hashtable_itr.h"
+				>
+			</File>
+			<File
+				RelativePath="..\src\include\hashtable_private.h"
+				>
+			</File>
+			<File
+				RelativePath="..\src\include\libteletone.h"
+				>
+			</File>
+			<File
+				RelativePath="..\src\include\libteletone_detect.h"
+				>
+			</File>
+			<File
+				RelativePath="..\src\include\libteletone_generate.h"
+				>
+			</File>
+			<File
+				RelativePath="..\src\include\openzap.h"
+				>
+			</File>
+			<File
+				RelativePath="..\src\include\uart.h"
+				>
+			</File>
+			<File
+				RelativePath="..\src\include\zap_buffer.h"
+				>
+			</File>
+			<File
+				RelativePath="..\src\include\zap_config.h"
+				>
+			</File>
+			<File
+				RelativePath="..\src\include\zap_dso.h"
+				>
+			</File>
+			<File
+				RelativePath="..\src\include\zap_threadmutex.h"
+				>
+			</File>
+			<File
+				RelativePath="..\src\include\zap_types.h"
+				>
+			</File>
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>

Added: freeswitch/trunk/libs/openzap/msvc/openzap.2008.vcproj (0 => 17141)


--- freeswitch/trunk/libs/openzap/msvc/openzap.2008.vcproj	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/msvc/openzap.2008.vcproj	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,451 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="9.00"
+	Name="openzap"
+	ProjectGUID="{93B8812C-3EC4-4F78-8970-FFBFC99E167D}"
+	RootNamespace="openzap"
+	Keyword="Win32Proj"
+	TargetFrameworkVersion="131072"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+		<Platform
+			Name="x64"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="2"
+			CharacterSet="2"
+			BuildLogFile="$(IntDir)\BuildLog-openzap.htm"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				AdditionalIncludeDirectories="../src/include;../src/isdn/include"
+				PreprocessorDefinitions="WIN32;_DEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;OPENZAP_EXPORTS;TELETONE_EXPORTS"
+				MinimalRebuild="true"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="3"
+				DisableLanguageExtensions="false"
+				RuntimeTypeInfo="false"
+				UsePrecompiledHeader="0"
+				WarningLevel="4"
+				WarnAsError="true"
+				Detect64BitPortabilityProblems="false"
+				DebugInformationFormat="3"
+				CompileAs="1"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				GenerateDebugInformation="true"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="2"
+			CharacterSet="2"
+			WholeProgramOptimization="1"
+			BuildLogFile="$(IntDir)\BuildLog-openzap.htm"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalIncludeDirectories="../src/include;../src/isdn/include"
+				PreprocessorDefinitions="WIN32;NDEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;OPENZAP_EXPORTS;TELETONE_EXPORTS"
+				RuntimeLibrary="2"
+				DisableLanguageExtensions="false"
+				RuntimeTypeInfo="false"
+				UsePrecompiledHeader="0"
+				WarningLevel="4"
+				WarnAsError="true"
+				Detect64BitPortabilityProblems="false"
+				DebugInformationFormat="3"
+				CompileAs="1"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Debug|x64"
+			OutputDirectory="$(SolutionDir)$(PlatformName)\$(ConfigurationName)"
+			IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+			ConfigurationType="2"
+			CharacterSet="2"
+			BuildLogFile="$(IntDir)\BuildLog-openzap.htm"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+				TargetEnvironment="3"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				AdditionalIncludeDirectories="../src/include;../src/isdn/include"
+				PreprocessorDefinitions="WIN32;_DEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;OPENZAP_EXPORTS;TELETONE_EXPORTS"
+				MinimalRebuild="true"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="3"
+				DisableLanguageExtensions="false"
+				RuntimeTypeInfo="false"
+				UsePrecompiledHeader="0"
+				WarningLevel="4"
+				WarnAsError="true"
+				Detect64BitPortabilityProblems="false"
+				DebugInformationFormat="3"
+				CompileAs="1"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				GenerateDebugInformation="true"
+				TargetMachine="17"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|x64"
+			OutputDirectory="$(SolutionDir)$(PlatformName)\$(ConfigurationName)"
+			IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+			ConfigurationType="2"
+			CharacterSet="2"
+			WholeProgramOptimization="1"
+			BuildLogFile="$(IntDir)\BuildLog-openzap.htm"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+				TargetEnvironment="3"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalIncludeDirectories="../src/include;../src/isdn/include"
+				PreprocessorDefinitions="WIN32;NDEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;OPENZAP_EXPORTS;TELETONE_EXPORTS"
+				RuntimeLibrary="2"
+				DisableLanguageExtensions="false"
+				RuntimeTypeInfo="false"
+				UsePrecompiledHeader="0"
+				WarningLevel="4"
+				WarnAsError="true"
+				Detect64BitPortabilityProblems="false"
+				DebugInformationFormat="3"
+				CompileAs="1"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				TargetMachine="17"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<Filter
+			Name="Header Files"
+			Filter="h;hpp;hxx;hm;inl;inc;xsd"
+			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+			>
+			<File
+				RelativePath="..\src\include\fsk.h"
+				>
+			</File>
+			<File
+				RelativePath="..\src\include\g711.h"
+				>
+			</File>
+			<File
+				RelativePath="..\src\include\hashtable.h"
+				>
+			</File>
+			<File
+				RelativePath="..\src\include\hashtable_itr.h"
+				>
+			</File>
+			<File
+				RelativePath="..\src\include\hashtable_private.h"
+				>
+			</File>
+			<File
+				RelativePath="..\src\include\libteletone.h"
+				>
+			</File>
+			<File
+				RelativePath="..\src\include\libteletone_detect.h"
+				>
+			</File>
+			<File
+				RelativePath="..\src\include\libteletone_generate.h"
+				>
+			</File>
+			<File
+				RelativePath="..\src\include\openzap.h"
+				>
+			</File>
+			<File
+				RelativePath="..\src\include\uart.h"
+				>
+			</File>
+			<File
+				RelativePath="..\src\include\zap_buffer.h"
+				>
+			</File>
+			<File
+				RelativePath="..\src\include\zap_config.h"
+				>
+			</File>
+			<File
+				RelativePath="..\src\include\zap_dso.h"
+				>
+			</File>
+			<File
+				RelativePath="..\src\include\zap_threadmutex.h"
+				>
+			</File>
+			<File
+				RelativePath="..\src\include\zap_types.h"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="Source Files"
+			Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+			>
+			<File
+				RelativePath="..\src\fsk.c"
+				>
+			</File>
+			<File
+				RelativePath="..\src\g711.c"
+				>
+			</File>
+			<File
+				RelativePath="..\src\hashtable.c"
+				>
+			</File>
+			<File
+				RelativePath="..\src\hashtable_itr.c"
+				>
+			</File>
+			<File
+				RelativePath="..\src\libteletone_detect.c"
+				>
+			</File>
+			<File
+				RelativePath="..\src\libteletone_generate.c"
+				>
+			</File>
+			<File
+				RelativePath="..\src\uart.c"
+				>
+			</File>
+			<File
+				RelativePath="..\src\zap_buffer.c"
+				>
+			</File>
+			<File
+				RelativePath="..\src\zap_callerid.c"
+				>
+			</File>
+			<File
+				RelativePath="..\src\zap_config.c"
+				>
+			</File>
+			<File
+				RelativePath="..\src\zap_dso.c"
+				>
+			</File>
+			<File
+				RelativePath="..\src\zap_io.c"
+				>
+			</File>
+			<File
+				RelativePath="..\src\zap_threadmutex.c"
+				>
+			</File>
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>

Added: freeswitch/trunk/libs/openzap/msvc/testanalog/testanalog.2005.vcproj (0 => 17141)


--- freeswitch/trunk/libs/openzap/msvc/testanalog/testanalog.2005.vcproj	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/msvc/testanalog/testanalog.2005.vcproj	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,193 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="8.00"
+	Name="testanalog"
+	ProjectGUID="{BB833648-BAFF-4BE2-94DB-F8BB043C588C}"
+	RootNamespace="testanalog"
+	Keyword="Win32Proj"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="1"
+			CharacterSet="1"
+			BuildLogFile="$(IntDir)\BuildLog-testanalog.htm"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				AdditionalIncludeDirectories="../../src/include;../../src/isdn/include"
+				PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
+				MinimalRebuild="true"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="3"
+				UsePrecompiledHeader="0"
+				WarningLevel="4"
+				WarnAsError="true"
+				Detect64BitPortabilityProblems="true"
+				DebugInformationFormat="4"
+				DisableSpecificWarnings="4100"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				LinkIncremental="2"
+				GenerateDebugInformation="true"
+				SubSystem="1"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="1"
+			CharacterSet="1"
+			WholeProgramOptimization="1"
+			BuildLogFile="$(IntDir)\BuildLog-testanalog.htm"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalIncludeDirectories="../../src/include;../../src/isdn/include"
+				PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
+				RuntimeLibrary="2"
+				UsePrecompiledHeader="0"
+				WarningLevel="4"
+				WarnAsError="true"
+				Detect64BitPortabilityProblems="true"
+				DebugInformationFormat="3"
+				DisableSpecificWarnings="4100"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				LinkIncremental="1"
+				GenerateDebugInformation="true"
+				SubSystem="1"
+				OptimizeReferences="2"
+				EnableCOMDATFolding="2"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<Filter
+			Name="Source Files"
+			Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+			>
+			<File
+				RelativePath="..\..\src\testanalog.c"
+				>
+			</File>
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>

Added: freeswitch/trunk/libs/openzap/msvc/testanalog/testanalog.2008.vcproj (0 => 17141)


--- freeswitch/trunk/libs/openzap/msvc/testanalog/testanalog.2008.vcproj	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/msvc/testanalog/testanalog.2008.vcproj	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,349 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="9.00"
+	Name="testanalog"
+	ProjectGUID="{BB833648-BAFF-4BE2-94DB-F8BB043C588C}"
+	RootNamespace="testanalog"
+	Keyword="Win32Proj"
+	TargetFrameworkVersion="131072"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+		<Platform
+			Name="x64"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="1"
+			CharacterSet="1"
+			BuildLogFile="$(IntDir)\BuildLog-testanalog.htm"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				AdditionalIncludeDirectories="../../src/include;../../src/isdn/include"
+				PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
+				MinimalRebuild="true"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="3"
+				UsePrecompiledHeader="0"
+				WarningLevel="4"
+				WarnAsError="true"
+				DebugInformationFormat="4"
+				DisableSpecificWarnings="4100"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				LinkIncremental="2"
+				GenerateDebugInformation="true"
+				SubSystem="1"
+				RandomizedBaseAddress="1"
+				DataExecutionPrevention="0"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="1"
+			CharacterSet="1"
+			WholeProgramOptimization="1"
+			BuildLogFile="$(IntDir)\BuildLog-testanalog.htm"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalIncludeDirectories="../../src/include;../../src/isdn/include"
+				PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
+				RuntimeLibrary="2"
+				UsePrecompiledHeader="0"
+				WarningLevel="4"
+				WarnAsError="true"
+				DebugInformationFormat="3"
+				DisableSpecificWarnings="4100"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				LinkIncremental="1"
+				GenerateDebugInformation="true"
+				SubSystem="1"
+				OptimizeReferences="2"
+				EnableCOMDATFolding="2"
+				RandomizedBaseAddress="1"
+				DataExecutionPrevention="0"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Debug|x64"
+			OutputDirectory="$(SolutionDir)$(PlatformName)\$(ConfigurationName)"
+			IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+			ConfigurationType="1"
+			CharacterSet="1"
+			BuildLogFile="$(IntDir)\BuildLog-testanalog.htm"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+				TargetEnvironment="3"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				AdditionalIncludeDirectories="../../src/include;../../src/isdn/include"
+				PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
+				MinimalRebuild="true"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="3"
+				UsePrecompiledHeader="0"
+				WarningLevel="4"
+				WarnAsError="true"
+				DebugInformationFormat="3"
+				DisableSpecificWarnings="4100"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				LinkIncremental="2"
+				GenerateDebugInformation="true"
+				SubSystem="1"
+				RandomizedBaseAddress="1"
+				DataExecutionPrevention="0"
+				TargetMachine="17"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|x64"
+			OutputDirectory="$(SolutionDir)$(PlatformName)\$(ConfigurationName)"
+			IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+			ConfigurationType="1"
+			CharacterSet="1"
+			WholeProgramOptimization="1"
+			BuildLogFile="$(IntDir)\BuildLog-testanalog.htm"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+				TargetEnvironment="3"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalIncludeDirectories="../../src/include;../../src/isdn/include"
+				PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
+				RuntimeLibrary="2"
+				UsePrecompiledHeader="0"
+				WarningLevel="4"
+				WarnAsError="true"
+				DebugInformationFormat="3"
+				DisableSpecificWarnings="4100"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				LinkIncremental="1"
+				GenerateDebugInformation="true"
+				SubSystem="1"
+				OptimizeReferences="2"
+				EnableCOMDATFolding="2"
+				RandomizedBaseAddress="1"
+				DataExecutionPrevention="0"
+				TargetMachine="17"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<Filter
+			Name="Source Files"
+			Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+			>
+			<File
+				RelativePath="..\..\src\testanalog.c"
+				>
+			</File>
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>

Added: freeswitch/trunk/libs/openzap/msvc/testisdn/testisdn.2005.vcproj (0 => 17141)


--- freeswitch/trunk/libs/openzap/msvc/testisdn/testisdn.2005.vcproj	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/msvc/testisdn/testisdn.2005.vcproj	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,193 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="8.00"
+	Name="testisdn"
+	ProjectGUID="{6DA6FD42-641D-4147-92F5-3BC4AAA6589B}"
+	RootNamespace="testisdn"
+	Keyword="Win32Proj"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="1"
+			CharacterSet="1"
+			BuildLogFile="$(IntDir)\BuildLog-testisdn.htm"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				AdditionalIncludeDirectories="../../src/include;../../src/isdn/include"
+				PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
+				MinimalRebuild="true"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="3"
+				UsePrecompiledHeader="0"
+				WarningLevel="4"
+				WarnAsError="true"
+				Detect64BitPortabilityProblems="true"
+				DebugInformationFormat="4"
+				DisableSpecificWarnings="4100"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				LinkIncremental="2"
+				GenerateDebugInformation="true"
+				SubSystem="1"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="1"
+			CharacterSet="1"
+			WholeProgramOptimization="1"
+			BuildLogFile="$(IntDir)\BuildLog-testisdn.htm"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalIncludeDirectories="../../src/include;../../src/isdn/include"
+				PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
+				RuntimeLibrary="2"
+				UsePrecompiledHeader="0"
+				WarningLevel="4"
+				WarnAsError="true"
+				Detect64BitPortabilityProblems="true"
+				DebugInformationFormat="3"
+				DisableSpecificWarnings="4100"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				LinkIncremental="1"
+				GenerateDebugInformation="true"
+				SubSystem="1"
+				OptimizeReferences="2"
+				EnableCOMDATFolding="2"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<Filter
+			Name="Source Files"
+			Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+			>
+			<File
+				RelativePath="..\..\src\testisdn.c"
+				>
+			</File>
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>

Added: freeswitch/trunk/libs/openzap/msvc/testisdn/testisdn.2008.vcproj (0 => 17141)


--- freeswitch/trunk/libs/openzap/msvc/testisdn/testisdn.2008.vcproj	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/msvc/testisdn/testisdn.2008.vcproj	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,349 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="9.00"
+	Name="testisdn"
+	ProjectGUID="{6DA6FD42-641D-4147-92F5-3BC4AAA6589B}"
+	RootNamespace="testisdn"
+	Keyword="Win32Proj"
+	TargetFrameworkVersion="131072"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+		<Platform
+			Name="x64"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="1"
+			CharacterSet="1"
+			BuildLogFile="$(IntDir)\BuildLog-testisdn.htm"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				AdditionalIncludeDirectories="../../src/include;../../src/isdn/include"
+				PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
+				MinimalRebuild="true"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="3"
+				UsePrecompiledHeader="0"
+				WarningLevel="4"
+				WarnAsError="true"
+				DebugInformationFormat="4"
+				DisableSpecificWarnings="4100"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				LinkIncremental="2"
+				GenerateDebugInformation="true"
+				SubSystem="1"
+				RandomizedBaseAddress="1"
+				DataExecutionPrevention="0"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="1"
+			CharacterSet="1"
+			WholeProgramOptimization="1"
+			BuildLogFile="$(IntDir)\BuildLog-testisdn.htm"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalIncludeDirectories="../../src/include;../../src/isdn/include"
+				PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
+				RuntimeLibrary="2"
+				UsePrecompiledHeader="0"
+				WarningLevel="4"
+				WarnAsError="true"
+				DebugInformationFormat="3"
+				DisableSpecificWarnings="4100"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				LinkIncremental="1"
+				GenerateDebugInformation="true"
+				SubSystem="1"
+				OptimizeReferences="2"
+				EnableCOMDATFolding="2"
+				RandomizedBaseAddress="1"
+				DataExecutionPrevention="0"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Debug|x64"
+			OutputDirectory="$(SolutionDir)$(PlatformName)\$(ConfigurationName)"
+			IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+			ConfigurationType="1"
+			CharacterSet="1"
+			BuildLogFile="$(IntDir)\BuildLog-testisdn.htm"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+				TargetEnvironment="3"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				AdditionalIncludeDirectories="../../src/include;../../src/isdn/include"
+				PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
+				MinimalRebuild="true"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="3"
+				UsePrecompiledHeader="0"
+				WarningLevel="4"
+				WarnAsError="true"
+				DebugInformationFormat="3"
+				DisableSpecificWarnings="4100"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				LinkIncremental="2"
+				GenerateDebugInformation="true"
+				SubSystem="1"
+				RandomizedBaseAddress="1"
+				DataExecutionPrevention="0"
+				TargetMachine="17"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|x64"
+			OutputDirectory="$(SolutionDir)$(PlatformName)\$(ConfigurationName)"
+			IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+			ConfigurationType="1"
+			CharacterSet="1"
+			WholeProgramOptimization="1"
+			BuildLogFile="$(IntDir)\BuildLog-testisdn.htm"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+				TargetEnvironment="3"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalIncludeDirectories="../../src/include;../../src/isdn/include"
+				PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
+				RuntimeLibrary="2"
+				UsePrecompiledHeader="0"
+				WarningLevel="4"
+				WarnAsError="true"
+				DebugInformationFormat="3"
+				DisableSpecificWarnings="4100"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				LinkIncremental="1"
+				GenerateDebugInformation="true"
+				SubSystem="1"
+				OptimizeReferences="2"
+				EnableCOMDATFolding="2"
+				RandomizedBaseAddress="1"
+				DataExecutionPrevention="0"
+				TargetMachine="17"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<Filter
+			Name="Source Files"
+			Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+			>
+			<File
+				RelativePath="..\..\src\testisdn.c"
+				>
+			</File>
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>

Added: freeswitch/trunk/libs/openzap/openzap.2005.sln (0 => 17141)


--- freeswitch/trunk/libs/openzap/openzap.2005.sln	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/openzap.2005.sln	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,82 @@
+
+Microsoft Visual Studio Solution File, Format Version 9.00
+# Visual Studio 2005
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "openzap", "msvc\openzap.2005.vcproj", "{93B8812C-3EC4-4F78-8970-FFBFC99E167D}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testanalog", "msvc\testanalog\testanalog.2005.vcproj", "{BB833648-BAFF-4BE2-94DB-F8BB043C588C}"
+	ProjectSection(ProjectDependencies) = postProject
+		{93B8812C-3EC4-4F78-8970-FFBFC99E167D} = {93B8812C-3EC4-4F78-8970-FFBFC99E167D}
+	EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testisdn", "msvc\testisdn\testisdn.2005.vcproj", "{6DA6FD42-641D-4147-92F5-3BC4AAA6589B}"
+	ProjectSection(ProjectDependencies) = postProject
+		{93B8812C-3EC4-4F78-8970-FFBFC99E167D} = {93B8812C-3EC4-4F78-8970-FFBFC99E167D}
+	EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_openzap", "mod_openzap\mod_openzap.2005.vcproj", "{FE3540C5-3303-46E0-A69E-D92F775687F1}"
+	ProjectSection(ProjectDependencies) = postProject
+		{93B8812C-3EC4-4F78-8970-FFBFC99E167D} = {93B8812C-3EC4-4F78-8970-FFBFC99E167D}
+	EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ozmod_analog", "src\ozmod\ozmod_analog\ozmod_analog.2005.vcproj", "{37C94798-6E33-4B4F-8EE0-C72A7DC91157}"
+	ProjectSection(ProjectDependencies) = postProject
+		{93B8812C-3EC4-4F78-8970-FFBFC99E167D} = {93B8812C-3EC4-4F78-8970-FFBFC99E167D}
+	EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ozmod_analog_em", "src\ozmod\ozmod_analog_em\ozmod_analog_em.2005.vcproj", "{C539D7C8-26A8-4A94-B938-77672165C130}"
+	ProjectSection(ProjectDependencies) = postProject
+		{93B8812C-3EC4-4F78-8970-FFBFC99E167D} = {93B8812C-3EC4-4F78-8970-FFBFC99E167D}
+	EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ozmod_isdn", "src\ozmod\ozmod_isdn\ozmod_isdn.2005.vcproj", "{729344A5-D5E9-434D-8EE8-AF8C6C795D15}"
+	ProjectSection(ProjectDependencies) = postProject
+		{93B8812C-3EC4-4F78-8970-FFBFC99E167D} = {93B8812C-3EC4-4F78-8970-FFBFC99E167D}
+	EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ozmod_wanpipe", "src\ozmod\ozmod_wanpipe\ozmod_wanpipe.2005.vcproj", "{1A145EE9-BBD8-45E5-98CD-EB4BE99E1DCD}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ozmod_pika", "src\ozmod\ozmod_pika\ozmod_pika.2005.vcproj", "{E886B4D5-AB4F-4092-B8F4-3B06E1E462EF}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Win32 = Debug|Win32
+		Release|Win32 = Release|Win32
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{93B8812C-3EC4-4F78-8970-FFBFC99E167D}.Debug|Win32.ActiveCfg = Debug|Win32
+		{93B8812C-3EC4-4F78-8970-FFBFC99E167D}.Debug|Win32.Build.0 = Debug|Win32
+		{93B8812C-3EC4-4F78-8970-FFBFC99E167D}.Release|Win32.ActiveCfg = Release|Win32
+		{93B8812C-3EC4-4F78-8970-FFBFC99E167D}.Release|Win32.Build.0 = Release|Win32
+		{BB833648-BAFF-4BE2-94DB-F8BB043C588C}.Debug|Win32.ActiveCfg = Debug|Win32
+		{BB833648-BAFF-4BE2-94DB-F8BB043C588C}.Debug|Win32.Build.0 = Debug|Win32
+		{BB833648-BAFF-4BE2-94DB-F8BB043C588C}.Release|Win32.ActiveCfg = Release|Win32
+		{BB833648-BAFF-4BE2-94DB-F8BB043C588C}.Release|Win32.Build.0 = Release|Win32
+		{6DA6FD42-641D-4147-92F5-3BC4AAA6589B}.Debug|Win32.ActiveCfg = Debug|Win32
+		{6DA6FD42-641D-4147-92F5-3BC4AAA6589B}.Debug|Win32.Build.0 = Debug|Win32
+		{6DA6FD42-641D-4147-92F5-3BC4AAA6589B}.Release|Win32.ActiveCfg = Release|Win32
+		{6DA6FD42-641D-4147-92F5-3BC4AAA6589B}.Release|Win32.Build.0 = Release|Win32
+		{FE3540C5-3303-46E0-A69E-D92F775687F1}.Debug|Win32.ActiveCfg = Debug|Win32
+		{FE3540C5-3303-46E0-A69E-D92F775687F1}.Debug|Win32.Build.0 = Debug|Win32
+		{FE3540C5-3303-46E0-A69E-D92F775687F1}.Release|Win32.ActiveCfg = Release|Win32
+		{FE3540C5-3303-46E0-A69E-D92F775687F1}.Release|Win32.Build.0 = Release|Win32
+		{37C94798-6E33-4B4F-8EE0-C72A7DC91157}.Debug|Win32.ActiveCfg = Debug|Win32
+		{37C94798-6E33-4B4F-8EE0-C72A7DC91157}.Debug|Win32.Build.0 = Debug|Win32
+		{37C94798-6E33-4B4F-8EE0-C72A7DC91157}.Release|Win32.ActiveCfg = Release|Win32
+		{37C94798-6E33-4B4F-8EE0-C72A7DC91157}.Release|Win32.Build.0 = Release|Win32
+		{C539D7C8-26A8-4A94-B938-77672165C130}.Debug|Win32.ActiveCfg = Debug|Win32
+		{C539D7C8-26A8-4A94-B938-77672165C130}.Debug|Win32.Build.0 = Debug|Win32
+		{C539D7C8-26A8-4A94-B938-77672165C130}.Release|Win32.ActiveCfg = Release|Win32
+		{C539D7C8-26A8-4A94-B938-77672165C130}.Release|Win32.Build.0 = Release|Win32
+		{729344A5-D5E9-434D-8EE8-AF8C6C795D15}.Debug|Win32.ActiveCfg = Debug|Win32
+		{729344A5-D5E9-434D-8EE8-AF8C6C795D15}.Debug|Win32.Build.0 = Debug|Win32
+		{729344A5-D5E9-434D-8EE8-AF8C6C795D15}.Release|Win32.ActiveCfg = Release|Win32
+		{729344A5-D5E9-434D-8EE8-AF8C6C795D15}.Release|Win32.Build.0 = Release|Win32
+		{1A145EE9-BBD8-45E5-98CD-EB4BE99E1DCD}.Debug|Win32.ActiveCfg = Debug|Win32
+		{1A145EE9-BBD8-45E5-98CD-EB4BE99E1DCD}.Release|Win32.ActiveCfg = Release|Win32
+		{E886B4D5-AB4F-4092-B8F4-3B06E1E462EF}.Debug|Win32.ActiveCfg = Debug|Win32
+		{E886B4D5-AB4F-4092-B8F4-3B06E1E462EF}.Release|Win32.ActiveCfg = Release|Win32
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+EndGlobal

Added: freeswitch/trunk/libs/openzap/openzap.2008.sln (0 => 17141)


--- freeswitch/trunk/libs/openzap/openzap.2008.sln	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/openzap.2008.sln	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,119 @@
+
+Microsoft Visual Studio Solution File, Format Version 10.00
+# Visual Studio 2008
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "openzap", "msvc\openzap.2008.vcproj", "{93B8812C-3EC4-4F78-8970-FFBFC99E167D}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testanalog", "msvc\testanalog\testanalog.2008.vcproj", "{BB833648-BAFF-4BE2-94DB-F8BB043C588C}"
+	ProjectSection(ProjectDependencies) = postProject
+		{93B8812C-3EC4-4F78-8970-FFBFC99E167D} = {93B8812C-3EC4-4F78-8970-FFBFC99E167D}
+	EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testisdn", "msvc\testisdn\testisdn.2008.vcproj", "{6DA6FD42-641D-4147-92F5-3BC4AAA6589B}"
+	ProjectSection(ProjectDependencies) = postProject
+		{93B8812C-3EC4-4F78-8970-FFBFC99E167D} = {93B8812C-3EC4-4F78-8970-FFBFC99E167D}
+	EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_openzap", "mod_openzap\mod_openzap.2008.vcproj", "{FE3540C5-3303-46E0-A69E-D92F775687F1}"
+	ProjectSection(ProjectDependencies) = postProject
+		{93B8812C-3EC4-4F78-8970-FFBFC99E167D} = {93B8812C-3EC4-4F78-8970-FFBFC99E167D}
+	EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ozmod_analog", "src\ozmod\ozmod_analog\ozmod_analog.2008.vcproj", "{37C94798-6E33-4B4F-8EE0-C72A7DC91157}"
+	ProjectSection(ProjectDependencies) = postProject
+		{93B8812C-3EC4-4F78-8970-FFBFC99E167D} = {93B8812C-3EC4-4F78-8970-FFBFC99E167D}
+	EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ozmod_analog_em", "src\ozmod\ozmod_analog_em\ozmod_analog_em.2008.vcproj", "{B3F49375-2834-4937-9D8C-4AC2EC911010}"
+	ProjectSection(ProjectDependencies) = postProject
+		{93B8812C-3EC4-4F78-8970-FFBFC99E167D} = {93B8812C-3EC4-4F78-8970-FFBFC99E167D}
+	EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ozmod_isdn", "src\ozmod\ozmod_isdn\ozmod_isdn.2008.vcproj", "{729344A5-D5E9-434D-8EE8-AF8C6C795D15}"
+	ProjectSection(ProjectDependencies) = postProject
+		{93B8812C-3EC4-4F78-8970-FFBFC99E167D} = {93B8812C-3EC4-4F78-8970-FFBFC99E167D}
+	EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ozmod_pika", "src\ozmod\ozmod_pika\ozmod_pika.2008.vcproj", "{E886B4D5-AB4F-4092-B8F4-3B06E1E462EF}"
+	ProjectSection(ProjectDependencies) = postProject
+		{93B8812C-3EC4-4F78-8970-FFBFC99E167D} = {93B8812C-3EC4-4F78-8970-FFBFC99E167D}
+	EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ozmod_wanpipe", "src\ozmod\ozmod_wanpipe\ozmod_wanpipe.2008.vcproj", "{1A145EE9-BBD8-45E5-98CD-EB4BE99E1DCD}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Win32 = Debug|Win32
+		Debug|x64 = Debug|x64
+		Release|Win32 = Release|Win32
+		Release|x64 = Release|x64
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{93B8812C-3EC4-4F78-8970-FFBFC99E167D}.Debug|Win32.ActiveCfg = Debug|Win32
+		{93B8812C-3EC4-4F78-8970-FFBFC99E167D}.Debug|Win32.Build.0 = Debug|Win32
+		{93B8812C-3EC4-4F78-8970-FFBFC99E167D}.Debug|x64.ActiveCfg = Debug|x64
+		{93B8812C-3EC4-4F78-8970-FFBFC99E167D}.Debug|x64.Build.0 = Debug|x64
+		{93B8812C-3EC4-4F78-8970-FFBFC99E167D}.Release|Win32.ActiveCfg = Release|Win32
+		{93B8812C-3EC4-4F78-8970-FFBFC99E167D}.Release|Win32.Build.0 = Release|Win32
+		{93B8812C-3EC4-4F78-8970-FFBFC99E167D}.Release|x64.ActiveCfg = Release|x64
+		{93B8812C-3EC4-4F78-8970-FFBFC99E167D}.Release|x64.Build.0 = Release|x64
+		{BB833648-BAFF-4BE2-94DB-F8BB043C588C}.Debug|Win32.ActiveCfg = Debug|Win32
+		{BB833648-BAFF-4BE2-94DB-F8BB043C588C}.Debug|Win32.Build.0 = Debug|Win32
+		{BB833648-BAFF-4BE2-94DB-F8BB043C588C}.Debug|x64.ActiveCfg = Debug|x64
+		{BB833648-BAFF-4BE2-94DB-F8BB043C588C}.Debug|x64.Build.0 = Debug|x64
+		{BB833648-BAFF-4BE2-94DB-F8BB043C588C}.Release|Win32.ActiveCfg = Release|Win32
+		{BB833648-BAFF-4BE2-94DB-F8BB043C588C}.Release|Win32.Build.0 = Release|Win32
+		{BB833648-BAFF-4BE2-94DB-F8BB043C588C}.Release|x64.ActiveCfg = Release|x64
+		{BB833648-BAFF-4BE2-94DB-F8BB043C588C}.Release|x64.Build.0 = Release|x64
+		{6DA6FD42-641D-4147-92F5-3BC4AAA6589B}.Debug|Win32.ActiveCfg = Debug|Win32
+		{6DA6FD42-641D-4147-92F5-3BC4AAA6589B}.Debug|Win32.Build.0 = Debug|Win32
+		{6DA6FD42-641D-4147-92F5-3BC4AAA6589B}.Debug|x64.ActiveCfg = Debug|x64
+		{6DA6FD42-641D-4147-92F5-3BC4AAA6589B}.Debug|x64.Build.0 = Debug|x64
+		{6DA6FD42-641D-4147-92F5-3BC4AAA6589B}.Release|Win32.ActiveCfg = Release|Win32
+		{6DA6FD42-641D-4147-92F5-3BC4AAA6589B}.Release|Win32.Build.0 = Release|Win32
+		{6DA6FD42-641D-4147-92F5-3BC4AAA6589B}.Release|x64.ActiveCfg = Release|x64
+		{6DA6FD42-641D-4147-92F5-3BC4AAA6589B}.Release|x64.Build.0 = Release|x64
+		{FE3540C5-3303-46E0-A69E-D92F775687F1}.Debug|Win32.ActiveCfg = Debug|Win32
+		{FE3540C5-3303-46E0-A69E-D92F775687F1}.Debug|Win32.Build.0 = Debug|Win32
+		{FE3540C5-3303-46E0-A69E-D92F775687F1}.Debug|x64.ActiveCfg = Debug|x64
+		{FE3540C5-3303-46E0-A69E-D92F775687F1}.Debug|x64.Build.0 = Debug|x64
+		{FE3540C5-3303-46E0-A69E-D92F775687F1}.Release|Win32.ActiveCfg = Release|Win32
+		{FE3540C5-3303-46E0-A69E-D92F775687F1}.Release|Win32.Build.0 = Release|Win32
+		{FE3540C5-3303-46E0-A69E-D92F775687F1}.Release|x64.ActiveCfg = Release|x64
+		{FE3540C5-3303-46E0-A69E-D92F775687F1}.Release|x64.Build.0 = Release|x64
+		{37C94798-6E33-4B4F-8EE0-C72A7DC91157}.Debug|Win32.ActiveCfg = Debug|Win32
+		{37C94798-6E33-4B4F-8EE0-C72A7DC91157}.Debug|Win32.Build.0 = Debug|Win32
+		{37C94798-6E33-4B4F-8EE0-C72A7DC91157}.Debug|x64.ActiveCfg = Debug|x64
+		{37C94798-6E33-4B4F-8EE0-C72A7DC91157}.Debug|x64.Build.0 = Debug|x64
+		{37C94798-6E33-4B4F-8EE0-C72A7DC91157}.Release|Win32.ActiveCfg = Release|Win32
+		{37C94798-6E33-4B4F-8EE0-C72A7DC91157}.Release|Win32.Build.0 = Release|Win32
+		{37C94798-6E33-4B4F-8EE0-C72A7DC91157}.Release|x64.ActiveCfg = Release|x64
+		{37C94798-6E33-4B4F-8EE0-C72A7DC91157}.Release|x64.Build.0 = Release|x64
+		{B3F49375-2834-4937-9D8C-4AC2EC911010}.Debug|Win32.ActiveCfg = Debug|Win32
+		{B3F49375-2834-4937-9D8C-4AC2EC911010}.Debug|Win32.Build.0 = Debug|Win32
+		{B3F49375-2834-4937-9D8C-4AC2EC911010}.Debug|x64.ActiveCfg = Debug|x64
+		{B3F49375-2834-4937-9D8C-4AC2EC911010}.Debug|x64.Build.0 = Debug|x64
+		{B3F49375-2834-4937-9D8C-4AC2EC911010}.Release|Win32.ActiveCfg = Release|Win32
+		{B3F49375-2834-4937-9D8C-4AC2EC911010}.Release|Win32.Build.0 = Release|Win32
+		{B3F49375-2834-4937-9D8C-4AC2EC911010}.Release|x64.ActiveCfg = Release|x64
+		{B3F49375-2834-4937-9D8C-4AC2EC911010}.Release|x64.Build.0 = Release|x64
+		{729344A5-D5E9-434D-8EE8-AF8C6C795D15}.Debug|Win32.ActiveCfg = Debug|Win32
+		{729344A5-D5E9-434D-8EE8-AF8C6C795D15}.Debug|Win32.Build.0 = Debug|Win32
+		{729344A5-D5E9-434D-8EE8-AF8C6C795D15}.Debug|x64.ActiveCfg = Debug|x64
+		{729344A5-D5E9-434D-8EE8-AF8C6C795D15}.Debug|x64.Build.0 = Debug|x64
+		{729344A5-D5E9-434D-8EE8-AF8C6C795D15}.Release|Win32.ActiveCfg = Release|Win32
+		{729344A5-D5E9-434D-8EE8-AF8C6C795D15}.Release|Win32.Build.0 = Release|Win32
+		{729344A5-D5E9-434D-8EE8-AF8C6C795D15}.Release|x64.ActiveCfg = Release|x64
+		{729344A5-D5E9-434D-8EE8-AF8C6C795D15}.Release|x64.Build.0 = Release|x64
+		{E886B4D5-AB4F-4092-B8F4-3B06E1E462EF}.Debug|Win32.ActiveCfg = Debug|Win32
+		{E886B4D5-AB4F-4092-B8F4-3B06E1E462EF}.Debug|x64.ActiveCfg = Debug|Win32
+		{E886B4D5-AB4F-4092-B8F4-3B06E1E462EF}.Release|Win32.ActiveCfg = Release|Win32
+		{E886B4D5-AB4F-4092-B8F4-3B06E1E462EF}.Release|x64.ActiveCfg = Release|Win32
+		{1A145EE9-BBD8-45E5-98CD-EB4BE99E1DCD}.Debug|Win32.ActiveCfg = Debug|Win32
+		{1A145EE9-BBD8-45E5-98CD-EB4BE99E1DCD}.Debug|x64.ActiveCfg = Debug|x64
+		{1A145EE9-BBD8-45E5-98CD-EB4BE99E1DCD}.Release|Win32.ActiveCfg = Release|Win32
+		{1A145EE9-BBD8-45E5-98CD-EB4BE99E1DCD}.Release|x64.ActiveCfg = Release|x64
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+EndGlobal

Added: freeswitch/trunk/libs/openzap/openzap.pc.in (0 => 17141)


--- freeswitch/trunk/libs/openzap/openzap.pc.in	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/openzap.pc.in	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,17 @@
+#
+# OpenZAP pkg-config file
+#
+prefix=@prefix@
+exec_prefix=${prefix}
+libdir=${exec_prefix}/lib
+includedir=${prefix}/include
+
+Name: OpenZAP
+Description:
+Version: @PACKAGE_VERSION@
+URL: http://www.openzap.org/
+Requires:
+Conflicts:
+Libs: -L${libdir} -lopenzap
+Libs.private: -lm
+Cflags: -I${includedir}

Added: freeswitch/trunk/libs/openzap/patches/oz.diff (0 => 17141)


--- freeswitch/trunk/libs/openzap/patches/oz.diff	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/patches/oz.diff	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,134 @@
+Index: src/ozmod/ozmod_wanpipe/ozmod_wanpipe.c
+===================================================================
+--- src/ozmod/ozmod_wanpipe/ozmod_wanpipe.c	(revision 745)
++++ src/ozmod/ozmod_wanpipe/ozmod_wanpipe.c	(working copy)
+@@ -98,19 +98,21 @@
+  * so we can have one analong handler thread that will deal with all the idle analog channels for events
+  * the alternative would be for the driver to provide one socket for all of the oob events for all analog channels
+  */
+-static __inline__ int tdmv_api_wait_socket(sng_fd_t fd, int timeout, int *flags)
++static __inline__ int tdmv_api_wait_socket(zap_channel_t *zchan, int timeout, int *flags)
+ {
+ 	
+ #ifdef LIBSANGOMA_VERSION
+ 	int err;
+-	sangoma_wait_obj_t sangoma_wait_obj;
++	sangoma_wait_obj_t *sangoma_wait_obj = zchan->mod_data;
+ 
+- 	sangoma_init_wait_obj(&sangoma_wait_obj, fd, 1, 1, *flags, SANGOMA_WAIT_OBJ);
++	sangoma_init_wait_obj(sangoma_wait_obj, zchan->sockfd, 1, 1, 0, SANGOMA_WAIT_OBJ);
+ 
+-	err=sangoma_socket_waitfor_many(&sangoma_wait_obj,1 , timeout);
++	err = sangoma_socket_waitfor_many(&sangoma_wait_obj, 1, timeout);
++
+ 	if (err > 0) {
+-		*flags=sangoma_wait_obj.flags_out;
++		*flags = sangoma_wait_obj.flags_out;
+ 	}
++
+ 	return err;
+ 
+ #else
+@@ -118,7 +120,7 @@
+     int res;
+ 
+     memset(&pfds[0], 0, sizeof(pfds[0]));
+-    pfds[0].fd = fd;
++    pfds[0].fd = zchan->sockfd;
+     pfds[0].events = *flags;
+     res = poll(pfds, 1, timeout);
+ 	*flags = 0;
+@@ -200,6 +202,15 @@
+ 		
+ 		if (sockfd != WP_INVALID_SOCKET && zap_span_add_channel(span, sockfd, type, &chan) == ZAP_SUCCESS) {
+ 			wanpipe_tdm_api_t tdm_api;
++#ifdef LIBSANGOMA_VERSION
++			sangoma_wait_obj_t *sangoma_wait_obj;
++
++			sangoma_wait_obj = malloc(sizeof(*sangoma_wait_obj));
++			memset(sangoma_wait_obj, 0, sizeof(*sangoma_wait_obj));
++			sangoma_init_wait_obj(sangoma_wait_obj, sockfd, 1, 1, 0, SANGOMA_WAIT_OBJ);
++			chan->mod_data = sangoma_wait_obj;
++#endif
++
+ 			memset(&tdm_api,0,sizeof(tdm_api));
+ 			
+ 			chan->physical_span_id = spanno;
+@@ -211,7 +222,7 @@
+ 				
+ 				dtmf = "software";
+ 
+-				/* FIXME: Handle Error Conditino Check for return code */
++				/* FIXME: Handle Error Condition Check for return code */
+ 				err= sangoma_tdm_get_hw_coding(chan->sockfd, &tdm_api);
+ 
+ 				if (tdm_api.wp_tdm_cmd.hw_tdm_coding) {
+@@ -606,7 +617,7 @@
+ 		inflags |= POLLPRI;
+ 	}
+ 
+-	result = tdmv_api_wait_socket(zchan->sockfd, to, &inflags);
++	result = tdmv_api_wait_socket(zchan, to, &inflags);
+ 
+ 	*flags = ZAP_NO_FLAGS;
+ 
+@@ -643,26 +654,30 @@
+ ZIO_SPAN_POLL_EVENT_FUNCTION(wanpipe_poll_event)
+ {
+ #ifdef LIBSANGOMA_VERSION
+-	sangoma_wait_obj_t pfds[ZAP_MAX_CHANNELS_SPAN];
++	sangoma_wait_obj_t *pfds[ZAP_MAX_CHANNELS_SPAN] = { 0 };
+ #else
+ 	struct pollfd pfds[ZAP_MAX_CHANNELS_SPAN];
+ #endif
+ 
+ 	uint32_t i, j = 0, k = 0, l = 0;
+-	int objects=0;
+ 	int r;
+ 	
+ 	for(i = 1; i <= span->chan_count; i++) {
+ 		zap_channel_t *zchan = span->channels[i];
+ 
++
+ #ifdef LIBSANGOMA_VERSION
+- 		sangoma_init_wait_obj(&pfds[j], zchan->sockfd , 1, 1, POLLPRI, SANGOMA_WAIT_OBJ);
++		if (!zchan->mod_data) {
++			continue;
++		}
++		pfds[j] = zchan->mod_data;
++
+ #else
+ 		memset(&pfds[j], 0, sizeof(pfds[j]));
+ 		pfds[j].fd = span->channels[i]->sockfd;
+ 		pfds[j].events = POLLPRI;
+ #endif
+-		objects++;
++
+ 		/* The driver probably should be able to do this wink/flash/ringing by itself this is sort of a hack to make it work! */
+ 
+ 		if (zap_test_flag(zchan, ZAP_CHANNEL_WINK) || zap_test_flag(zchan, ZAP_CHANNEL_FLASH)) {
+@@ -703,7 +718,7 @@
+ 		ms = l;
+ 	}
+ #ifdef LIBSANGOMA_VERSION
+-	r = sangoma_socket_waitfor_many(pfds,objects,ms);
++	r = sangoma_socket_waitfor_many(pfds, j, ms);
+ #else
+ 	r = poll(pfds, j, ms);
+ #endif
+@@ -935,6 +950,15 @@
+  */
+ static ZIO_CHANNEL_DESTROY_FUNCTION(wanpipe_channel_destroy)
+ {
++	sangoma_wait_obj_t *sangoma_wait_obj;
++
++	if (zchan->mod_data) {
++		sangoma_wait_obj = zchan->mod_data;
++		zchan->mod_data = NULL;
++		sangoma_release_wait_obj(sangoma_wait_obj);
++		free(sangoma_wait_obj);
++	}
++
+ 	if (zchan->sockfd > -1) {
+ 		close(zchan->sockfd);
+ 		zchan->sockfd = WP_INVALID_SOCKET;

Added: freeswitch/trunk/libs/openzap/src/detect_dtmf.c (0 => 17141)


--- freeswitch/trunk/libs/openzap/src/detect_dtmf.c	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/src/detect_dtmf.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,33 @@
+//#include "openzap.h"
+#include "libteletone_detect.h"
+
+int main(int argc, char *argv[])
+{
+	int fd, b;
+	short sln[512] = {0};
+	teletone_dtmf_detect_state_t dtmf_detect = {0};
+	char digit_str[128] = "";
+
+	if (argc < 2) {
+		fprintf(stderr, "Arg Error!\n");
+		exit(-1);
+	}
+
+	teletone_dtmf_detect_init (&dtmf_detect, 8000);
+
+	if ((fd = open(argv[1], O_RDONLY)) < 0) {
+		fprintf(stderr, "File Error! [%s]\n", strerror(errno));
+		exit(-1);
+	}
+
+	while((b = read(fd, sln, 320)) > 0) {
+		teletone_dtmf_detect(&dtmf_detect, sln, b / 2);
+		teletone_dtmf_get(&dtmf_detect, digit_str, sizeof(digit_str));
+		if (*digit_str) {
+			printf("digit: %s\n", digit_str);
+		}
+	}
+	close(fd);
+	return 0;
+}
+

Added: freeswitch/trunk/libs/openzap/src/detect_tones.c (0 => 17141)


--- freeswitch/trunk/libs/openzap/src/detect_tones.c	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/src/detect_tones.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,32 @@
+//#include "openzap.h"
+#include "libteletone_detect.h"
+
+int main(int argc, char *argv[])
+{
+	teletone_multi_tone_t mt = {0};
+	teletone_tone_map_t map = {{0}};
+
+	int fd, b;
+	short sln[512] = {0};
+
+	if (argc < 2) {
+		fprintf(stderr, "Arg Error!\n");
+		exit(-1);
+	}
+
+	map.freqs[0] = atof("350");
+	map.freqs[1] = atof("440");
+	teletone_multi_tone_init(&mt, &map);
+
+	if ((fd = open(argv[1], O_RDONLY)) < 0) {
+		fprintf(stderr, "File Error! [%s]\n", strerror(errno));
+		exit(-1);
+	}
+
+	while((b = read(fd, sln, 320)) > 0) {
+		printf("TEST %d %d\n", b, teletone_multi_tone_detect(&mt, sln, b / 2));
+	}
+	close(fd);
+	return 0;
+}
+

Added: freeswitch/trunk/libs/openzap/src/fsk.c (0 => 17141)


--- freeswitch/trunk/libs/openzap/src/fsk.c	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/src/fsk.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,351 @@
+
+/*
+ *	bell202.c
+ *
+ *	Copyright (c) 2005 Robert Krten.  All Rights Reserved.
+ *
+ *	Redistribution and use in source and binary forms, with or without
+ *	modification, are permitted provided that the following conditions
+ *	are met:
+ *
+ *	1. Redistributions of source code must retain the above copyright
+ *	   notice, this list of conditions and the following disclaimer.
+ *	2. Redistributions in binary form must reproduce the above copyright
+ *	   notice, this list of conditions and the following disclaimer in the
+ *	   documentation and/or other materials provided with the distribution.
+ *
+ *	THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
+ *	ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ *	IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ *	ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE
+ *	FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ *	DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ *	OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ *	HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ *	LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ *	OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ *	SUCH DAMAGE.
+ *
+ *	This module contains a Bell-202 1200-baud FSK decoder, suitable for
+ *	use in a library.  The general style of the library calls is modeled
+ *	after the POSIX pthread_*() functions.
+ *
+ *	2005 03 20	R. Krten		created
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <math.h>
+
+#include "fsk.h"
+#include "uart.h"
+
+#ifndef M_PI
+#define M_PI        3.14159265358979323846
+#endif
+
+fsk_modem_definition_t fsk_modem_definitions[] =
+{
+    { /* FSK_V23_FORWARD_MODE1	*/	1700,	1300,	600		},
+    { /* FSK_V23_FORWARD_MODE2	*/	2100,	1300,	1200	},
+    { /* FSK_V23_BACKWARD		*/	450,	390,	75		},
+    { /* FSK_BELL202			*/	2200,	1200,	1200	},
+};
+
+/*
+ *	dsp_fsk_attr_init
+ *
+ *	Initializes the attributes structure; this must be done before the
+ *	attributes structure is used.
+*/
+
+void dsp_fsk_attr_init (dsp_fsk_attr_t *attr)
+{
+	memset(attr, 0, sizeof(*attr));
+}
+
+/*
+ *	dsp_fsk_attr_get_bithandler
+ *	dsp_fsk_attr_set_bithandler
+ *	dsp_fsk_attr_get_bytehandler
+ *	dsp_fsk_attr_set_bytehandler
+ *	dsp_fsk_attr_getsamplerate
+ *	dsp_fsk_attr_setsamplerate
+ *
+ *	These functions get and set their respective elements from the
+ *	attributes structure.  If an error code is returned, it is just
+ *	zero == ok, -1 == fail.
+*/
+
+bithandler_func_t dsp_fsk_attr_get_bithandler(dsp_fsk_attr_t *attr, void **bithandler_arg)
+{
+	*bithandler_arg = attr->bithandler_arg;
+	return attr->bithandler;
+}
+
+void dsp_fsk_attr_set_bithandler(dsp_fsk_attr_t *attr, bithandler_func_t bithandler, void *bithandler_arg)
+{
+	attr->bithandler = bithandler;
+	attr->bithandler_arg = bithandler_arg;
+}
+
+bytehandler_func_t dsp_fsk_attr_get_bytehandler(dsp_fsk_attr_t *attr, void **bytehandler_arg)
+{
+	*bytehandler_arg = attr->bytehandler_arg;
+	return attr->bytehandler;
+}
+
+void dsp_fsk_attr_set_bytehandler(dsp_fsk_attr_t *attr, bytehandler_func_t bytehandler, void *bytehandler_arg)
+{
+	attr->bytehandler = bytehandler;
+	attr->bytehandler_arg = bytehandler_arg;
+}
+
+int dsp_fsk_attr_get_samplerate (dsp_fsk_attr_t *attr)
+{
+	return attr->sample_rate;
+}
+
+int dsp_fsk_attr_set_samplerate (dsp_fsk_attr_t *attr, int samplerate)
+{
+	if (samplerate <= 0) {
+		return -1;
+	}
+	attr->sample_rate = samplerate;
+	return 0;
+}
+
+/*
+ *	dsp_fsk_create
+ *
+ *	Creates a handle for subsequent use.  The handle is created to contain
+ *	a context data structure for use by the sample handler function.  The
+ *	function expects an initialized attributes structure, and returns the
+ *	handle or a NULL if there were errors.
+ *
+ *	Once created, the handle can be used until it is destroyed.
+*/
+
+dsp_fsk_handle_t *dsp_fsk_create(dsp_fsk_attr_t *attr)
+{
+	int						i;
+	double					phi_mark, phi_space;
+	dsp_fsk_handle_t	*handle;
+
+	handle = malloc(sizeof(*handle));
+	if (!handle) {
+		return NULL;
+	}
+
+	memset(handle, 0, sizeof(*handle));
+
+	/* fill the attributes member */
+	memcpy(&handle->attr, attr, sizeof(*attr));
+
+	/* see if we can do downsampling.  We only really need 6 samples to "match" */
+	if (attr->sample_rate / fsk_modem_definitions[FSK_BELL202].freq_mark > 6) {
+		handle->downsampling_count = attr->sample_rate / fsk_modem_definitions[FSK_BELL202].freq_mark / 6;
+	} else {
+		handle->downsampling_count = 1;
+	}
+	handle->current_downsample = 1;
+
+	/* calculate the correlate size (number of samples required for slowest wave) */
+	handle->corrsize = attr->sample_rate / handle->downsampling_count / fsk_modem_definitions[FSK_BELL202].freq_mark;
+
+	/* allocate the correlation sin/cos arrays and initialize */
+	for (i = 0; i < 4; i++) {
+		handle->correlates[i] = malloc(sizeof(double) * handle->corrsize);
+		if (handle->correlates[i] == NULL) {
+			/* some failed, back out memory allocations */
+			dsp_fsk_destroy(&handle);
+			return NULL;
+		}
+	}
+
+	/* now initialize them */
+	phi_mark = 2. * M_PI / ((double) attr->sample_rate / (double) handle->downsampling_count / (double) fsk_modem_definitions[FSK_BELL202].freq_mark);
+	phi_space = 2. * M_PI / ((double) attr->sample_rate / (double) handle->downsampling_count / (double) fsk_modem_definitions[FSK_BELL202].freq_space);
+
+	for (i = 0; i < handle->corrsize; i++) {
+		handle->correlates[0][i] = sin(phi_mark * (double) i);
+		handle->correlates[1][i] = cos(phi_mark * (double) i);
+		handle->correlates[2][i] = sin(phi_space * (double) i);
+		handle->correlates[3][i] = cos(phi_space * (double) i);
+	}
+
+	/* initialize the ring buffer */
+	handle->buffer = malloc(sizeof(double) * handle->corrsize);
+	if (!handle->buffer) {				/* failed; back out memory allocations */
+		dsp_fsk_destroy(&handle);
+		return NULL;
+	}
+	memset(handle->buffer, 0, sizeof(double) * handle->corrsize);
+	handle->ringstart = 0;
+
+	/* initalize intra-cell position */
+	handle->cellpos = 0;
+	handle->celladj = fsk_modem_definitions[FSK_BELL202].baud_rate / (double) attr->sample_rate * (double) handle->downsampling_count;
+
+	/* if they have provided a byte handler, add a UART to the processing chain */
+	if (handle->attr.bytehandler) {
+		dsp_uart_attr_t		uart_attr;
+		dsp_uart_handle_t	*uart_handle;
+
+		dsp_uart_attr_init(&uart_attr);
+		dsp_uart_attr_set_bytehandler(&uart_attr, handle->attr.bytehandler, handle->attr.bytehandler_arg);
+		uart_handle = dsp_uart_create(&uart_attr);
+		if (uart_handle == NULL) {
+			dsp_fsk_destroy(&handle);
+			return NULL;
+		}
+		handle->attr.bithandler = dsp_uart_bit_handler;
+		handle->attr.bithandler_arg = uart_handle;
+	}
+
+	return handle;
+}
+
+/*
+ *	dsp_fsk_destroy
+ *
+ *	Destroys a handle, releasing any associated memory.  Sets handle pointer to NULL 
+ *	so A destroyed handle can not be used for anything after the destroy.
+*/
+
+void dsp_fsk_destroy(dsp_fsk_handle_t **handle)
+{
+	int		i;
+
+	/* if empty handle, just return */
+	if (*handle == NULL) {
+		return;
+	}
+
+	for (i = 0; i < 4; i++) {
+		if ((*handle)->correlates[i] != NULL) {
+			free((*handle)->correlates[i]);
+			(*handle)->correlates[i] = NULL;
+		}
+	}
+
+	if ((*handle)->buffer != NULL) {
+		free((*handle)->buffer);
+		(*handle)->buffer = NULL;
+	}
+
+	if ((*handle)->attr.bytehandler) {
+		dsp_uart_handle_t** dhandle = (void *)(&(*handle)->attr.bithandler_arg);
+		dsp_uart_destroy(dhandle);
+	}
+
+	free(*handle);
+	*handle = NULL;
+}
+
+/*
+ *	dsp_fsk_sample
+ *
+ *	This is the main processing entry point.  The function accepts a normalized
+ *	sample (i.e., one whose range is between -1 and +1).  The function performs
+ *	the Bell-202 FSK modem decode processing, and, if it detects a valid bit,
+ *	will call the bithandler associated with the attributes structure.
+ *
+ *	For the Bell-202 standard, a logical zero (space) is 2200 Hz, and a logical
+ *	one (mark) is 1200 Hz.
+*/
+
+void
+dsp_fsk_sample (dsp_fsk_handle_t *handle, double normalized_sample)
+{
+	double	val;
+	double	factors[4];
+	int		i, j;
+
+	/* if we can avoid processing samples, do so */
+	if (handle->downsampling_count != 1) {
+		if (handle->current_downsample < handle->downsampling_count) {
+			handle->current_downsample++;
+			return;												/* throw this sample out */
+		}
+		handle->current_downsample = 1;
+	}
+
+	/* store sample in buffer */
+	handle->buffer[handle->ringstart++] = normalized_sample;
+	if (handle->ringstart >= handle->corrsize) {
+		handle->ringstart = 0;
+	}
+
+	/* do the correlation calculation */
+	factors[0] = factors[1] = factors[2] = factors[3] = 0;	/* clear out intermediate sums */
+	j = handle->ringstart;
+	for (i = 0; i < handle->corrsize; i++) {
+		if (j >= handle->corrsize) {
+			j = 0;
+		}
+		val = handle->buffer[j];
+		factors[0] += handle->correlates[0][i] * val;
+		factors[1] += handle->correlates[1][i] * val;
+		factors[2] += handle->correlates[2][i] * val;
+		factors[3] += handle->correlates[3][i] * val;
+		j++;
+	}
+
+	/* store the bit (bit value is comparison of the two sets of correlate factors) */
+	handle->previous_bit = handle->current_bit;
+	handle->current_bit = (factors[0] * factors[0] + factors[1] * factors[1] > factors[2] * factors[2] + factors[3] * factors[3]);
+
+	/* if there's a transition, we can synchronize the cell position */
+	if (handle->previous_bit != handle->current_bit) {
+		handle->cellpos = 0.5;								/* adjust cell position to be in the middle of the cell */
+	}
+	handle->cellpos += handle->celladj;						/* walk the cell along */
+
+	if (handle->cellpos > 1.0) {
+		handle->cellpos -= 1.0;
+		
+		switch (handle->state) {
+		case FSK_STATE_DATA:
+			{		
+				
+				(*handle->attr.bithandler) (handle->attr.bithandler_arg, handle->current_bit);
+			}
+			break;
+		case FSK_STATE_CHANSEIZE:
+			{
+
+				if (handle->last_bit != handle->current_bit) {
+					handle->conscutive_state_bits++;
+				} else {
+					handle->conscutive_state_bits = 0;
+				}
+
+				if (handle->conscutive_state_bits > 15) {
+					handle->state = FSK_STATE_CARRIERSIG;
+					handle->conscutive_state_bits = 0;
+				}
+			}
+			break;
+		case FSK_STATE_CARRIERSIG:
+			{
+				if (handle->current_bit) {
+					handle->conscutive_state_bits++;
+				} else {
+					handle->conscutive_state_bits = 0;
+				}
+
+				if (handle->conscutive_state_bits > 15) {
+					handle->state = FSK_STATE_DATA;
+					handle->conscutive_state_bits = 0;
+				}
+			}
+			break;
+		}
+
+		handle->last_bit = handle->current_bit;
+	}
+}
+

Added: freeswitch/trunk/libs/openzap/src/g711.c (0 => 17141)


--- freeswitch/trunk/libs/openzap/src/g711.c	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/src/g711.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,104 @@
+/*
+ * SpanDSP - a series of DSP components for telephony
+ *
+ * g711.c - A-law and u-law transcoding routines
+ *
+ * Written by Steve Underwood <steveu@coppice.org>
+ *
+ * Copyright (C) 2006 Steve Underwood
+ *
+ *  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.
+ *
+ * $Id: g711.c,v 1.1 2006/06/07 15:46:39 steveu Exp $
+ */
+
+/*! \file */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#ifndef _MSC_VER
+#include <inttypes.h>
+#ifdef HAVE_TGMATH_H
+#include <tgmath.h>
+#endif
+#endif
+
+#include "g711.h"
+
+/* Copied from the CCITT G.711 specification */
+static const uint8_t ulaw_to_alaw_table[256] =
+	{
+		42,  43,  40,  41,  46,  47,  44,  45,  34,  35,  32,  33,  38,  39,  36,  37,
+		58,  59,  56,  57,  62,  63,  60,  61,  50,  51,  48,  49,  54,  55,  52,  53,
+		10,  11,   8,   9,  14,  15,  12,  13,   2,   3,   0,   1,   6,   7,   4,  26,
+		27,  24,  25,  30,  31,  28,  29,  18,  19,  16,  17,  22,  23,  20,  21, 106,
+		104, 105, 110, 111, 108, 109,  98,  99,  96,  97, 102, 103, 100, 101, 122, 120,
+		126, 127, 124, 125, 114, 115, 112, 113, 118, 119, 116, 117,  75,  73,  79,  77,
+		66,  67,  64,  65,  70,  71,  68,  69,  90,  91,  88,  89,  94,  95,  92,  93,
+		82,  82,  83,  83,  80,  80,  81,  81,  86,  86,  87,  87,  84,  84,  85,  85,
+		170, 171, 168, 169, 174, 175, 172, 173, 162, 163, 160, 161, 166, 167, 164, 165,
+		186, 187, 184, 185, 190, 191, 188, 189, 178, 179, 176, 177, 182, 183, 180, 181,
+		138, 139, 136, 137, 142, 143, 140, 141, 130, 131, 128, 129, 134, 135, 132, 154,
+		155, 152, 153, 158, 159, 156, 157, 146, 147, 144, 145, 150, 151, 148, 149, 234,
+		232, 233, 238, 239, 236, 237, 226, 227, 224, 225, 230, 231, 228, 229, 250, 248,
+		254, 255, 252, 253, 242, 243, 240, 241, 246, 247, 244, 245, 203, 201, 207, 205,
+		194, 195, 192, 193, 198, 199, 196, 197, 218, 219, 216, 217, 222, 223, 220, 221,
+		210, 210, 211, 211, 208, 208, 209, 209, 214, 214, 215, 215, 212, 212, 213, 213
+	};
+
+/* These transcoding tables are copied from the CCITT G.711 specification. To achieve
+   optimal results, do not change them. */
+
+static const uint8_t alaw_to_ulaw_table[256] =
+	{
+		42,  43,  40,  41,  46,  47,  44,  45,  34,  35,  32,  33,  38,  39,  36,  37,
+		57,  58,  55,  56,  61,  62,  59,  60,  49,  50,  47,  48,  53,  54,  51,  52,
+		10,  11,   8,   9,  14,  15,  12,  13,   2,   3,   0,   1,   6,   7,   4,   5,
+		26,  27,  24,  25,  30,  31,  28,  29,  18,  19,  16,  17,  22,  23,  20,  21,
+		98,  99,  96,  97, 102, 103, 100, 101,  93,  93,  92,  92,  95,  95,  94,  94,
+		116, 118, 112, 114, 124, 126, 120, 122, 106, 107, 104, 105, 110, 111, 108, 109,
+		72,  73,  70,  71,  76,  77,  74,  75,  64,  65,  63,  63,  68,  69,  66,  67,
+		86,  87,  84,  85,  90,  91,  88,  89,  79,  79,  78,  78,  82,  83,  80,  81,
+		170, 171, 168, 169, 174, 175, 172, 173, 162, 163, 160, 161, 166, 167, 164, 165,
+		185, 186, 183, 184, 189, 190, 187, 188, 177, 178, 175, 176, 181, 182, 179, 180,
+		138, 139, 136, 137, 142, 143, 140, 141, 130, 131, 128, 129, 134, 135, 132, 133,
+		154, 155, 152, 153, 158, 159, 156, 157, 146, 147, 144, 145, 150, 151, 148, 149,
+		226, 227, 224, 225, 230, 231, 228, 229, 221, 221, 220, 220, 223, 223, 222, 222,
+		244, 246, 240, 242, 252, 254, 248, 250, 234, 235, 232, 233, 238, 239, 236, 237,
+		200, 201, 198, 199, 204, 205, 202, 203, 192, 193, 191, 191, 196, 197, 194, 195,
+		214, 215, 212, 213, 218, 219, 216, 217, 207, 207, 206, 206, 210, 211, 208, 209
+	};
+
+uint8_t alaw_to_ulaw(uint8_t alaw)
+{
+    return alaw_to_ulaw_table[alaw];
+}
+/*- End of function --------------------------------------------------------*/
+
+uint8_t ulaw_to_alaw(uint8_t ulaw)
+{
+    return ulaw_to_alaw_table[ulaw];
+}
+/*- End of function --------------------------------------------------------*/
+/*- End of file ------------------------------------------------------------*/
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
+

Added: freeswitch/trunk/libs/openzap/src/hashtable.c (0 => 17141)


--- freeswitch/trunk/libs/openzap/src/hashtable.c	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/src/hashtable.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,339 @@
+/*
+ * Copyright (c) 2002, Christopher Clark
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "hashtable.h"
+#include "hashtable_private.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+
+/*
+  Credit for primes table: Aaron Krowne
+  http://br.endernet.org/~akrowne/
+  http://planetmath.org/encyclopedia/GoodHashTablePrimes.html
+*/
+static const unsigned int primes[] = {
+	53, 97, 193, 389,
+	769, 1543, 3079, 6151,
+	12289, 24593, 49157, 98317,
+	196613, 393241, 786433, 1572869,
+	3145739, 6291469, 12582917, 25165843,
+	50331653, 100663319, 201326611, 402653189,
+	805306457, 1610612741
+};
+const unsigned int prime_table_length = sizeof(primes)/sizeof(primes[0]);
+const float max_load_factor = 0.65f;
+
+/*****************************************************************************/
+OZ_DECLARE(struct hashtable *)
+create_hashtable(unsigned int minsize,
+                 unsigned int (*hashf) (void*),
+                 int (*eqf) (void*,void*))
+{
+    struct hashtable *h;
+    unsigned int pindex, size = primes[0];
+    /* Check requested hashtable isn't too large */
+    if (minsize > (1u << 30)) return NULL;
+    /* Enforce size as prime */
+    for (pindex=0; pindex < prime_table_length; pindex++) {
+        if (primes[pindex] > minsize) { size = primes[pindex]; break; }
+    }
+    h = (struct hashtable *)malloc(sizeof(struct hashtable));
+    if (NULL == h) return NULL; /*oom*/
+    h->table = (struct entry **)malloc(sizeof(struct entry*) * size);
+    if (NULL == h->table) { free(h); return NULL; } /*oom*/
+    memset(h->table, 0, size * sizeof(struct entry *));
+    h->tablelength  = size;
+    h->primeindex   = pindex;
+    h->entrycount   = 0;
+    h->hashfn       = hashf;
+    h->eqfn         = eqf;
+    h->loadlimit    = (unsigned int) ceil(size * max_load_factor);
+    return h;
+}
+
+/*****************************************************************************/
+unsigned int
+hash(struct hashtable *h, void *k)
+{
+    /* Aim to protect against poor hash functions by adding logic here
+     * - logic taken from java 1.4 hashtable source */
+    unsigned int i = h->hashfn(k);
+    i += ~(i << 9);
+    i ^=  ((i >> 14) | (i << 18)); /* >>> */
+    i +=  (i << 4);
+    i ^=  ((i >> 10) | (i << 22)); /* >>> */
+    return i;
+}
+
+/*****************************************************************************/
+static int
+hashtable_expand(struct hashtable *h)
+{
+    /* Double the size of the table to accomodate more entries */
+    struct entry **newtable;
+    struct entry *e;
+    struct entry **pE;
+    unsigned int newsize, i, index;
+    /* Check we're not hitting max capacity */
+    if (h->primeindex == (prime_table_length - 1)) return 0;
+    newsize = primes[++(h->primeindex)];
+
+    newtable = (struct entry **)malloc(sizeof(struct entry*) * newsize);
+    if (NULL != newtable)
+		{
+			memset(newtable, 0, newsize * sizeof(struct entry *));
+			/* This algorithm is not 'stable'. ie. it reverses the list
+			 * when it transfers entries between the tables */
+			for (i = 0; i < h->tablelength; i++) {
+				while (NULL != (e = h->table[i])) {
+					h->table[i] = e->next;
+					index = indexFor(newsize,e->h);
+					e->next = newtable[index];
+					newtable[index] = e;
+				}
+			}
+			free(h->table);
+			h->table = newtable;
+		}
+    /* Plan B: realloc instead */
+    else 
+		{
+			newtable = (struct entry **)
+				realloc(h->table, newsize * sizeof(struct entry *));
+			if (NULL == newtable) { (h->primeindex)--; return 0; }
+			h->table = newtable;
+			memset(newtable[h->tablelength], 0, newsize - h->tablelength);
+			for (i = 0; i < h->tablelength; i++) {
+				for (pE = &(newtable[i]), e = *pE; e != NULL; e = *pE) {
+					index = indexFor(newsize,e->h);
+					if (index == i)
+						{
+							pE = &(e->next);
+						}
+					else
+						{
+							*pE = e->next;
+							e->next = newtable[index];
+							newtable[index] = e;
+						}
+				}
+			}
+		}
+    h->tablelength = newsize;
+    h->loadlimit   = (unsigned int) ceil(newsize * max_load_factor);
+    return -1;
+}
+
+/*****************************************************************************/
+OZ_DECLARE(unsigned int)
+hashtable_count(struct hashtable *h)
+{
+    return h->entrycount;
+}
+
+/*****************************************************************************/
+OZ_DECLARE(int)
+hashtable_insert(struct hashtable *h, void *k, void *v, hashtable_flag_t flags)
+{
+    /* This method allows duplicate keys - but they shouldn't be used */
+    unsigned int index;
+    struct entry *e;
+    if (++(h->entrycount) > h->loadlimit)
+		{
+			/* Ignore the return value. If expand fails, we should
+			 * still try cramming just this value into the existing table
+			 * -- we may not have memory for a larger table, but one more
+			 * element may be ok. Next time we insert, we'll try expanding again.*/
+			hashtable_expand(h);
+		}
+    e = (struct entry *)malloc(sizeof(struct entry));
+    if (NULL == e) { --(h->entrycount); return 0; } /*oom*/
+    e->h = hash(h,k);
+    index = indexFor(h->tablelength,e->h);
+    e->k = k;
+    e->v = v;
+	e->flags = flags;
+    e->next = h->table[index];
+    h->table[index] = e;
+    return -1;
+}
+
+/*****************************************************************************/
+OZ_DECLARE(void *) /* returns value associated with key */
+hashtable_search(struct hashtable *h, void *k)
+{
+    struct entry *e;
+    unsigned int hashvalue, index;
+    hashvalue = hash(h,k);
+    index = indexFor(h->tablelength,hashvalue);
+    e = h->table[index];
+    while (NULL != e)
+		{
+			/* Check hash value to short circuit heavier comparison */
+			if ((hashvalue == e->h) && (h->eqfn(k, e->k))) return e->v;
+			e = e->next;
+		}
+    return NULL;
+}
+
+/*****************************************************************************/
+OZ_DECLARE(void *) /* returns value associated with key */
+hashtable_remove(struct hashtable *h, void *k)
+{
+    /* TODO: consider compacting the table when the load factor drops enough,
+     *       or provide a 'compact' method. */
+
+    struct entry *e;
+    struct entry **pE;
+    void *v;
+    unsigned int hashvalue, index;
+
+    hashvalue = hash(h,k);
+    index = indexFor(h->tablelength,hash(h,k));
+    pE = &(h->table[index]);
+    e = *pE;
+    while (NULL != e)
+		{
+			/* Check hash value to short circuit heavier comparison */
+			if ((hashvalue == e->h) && (h->eqfn(k, e->k)))
+				{
+					*pE = e->next;
+					h->entrycount--;
+					v = e->v;
+					if (e->flags & HASHTABLE_FLAG_FREE_KEY) {
+						freekey(e->k);
+					}
+					free(e);
+					return v;
+				}
+			pE = &(e->next);
+			e = e->next;
+		}
+    return NULL;
+}
+
+/*****************************************************************************/
+/* destroy */
+OZ_DECLARE(void)
+hashtable_destroy(struct hashtable *h)
+{
+    unsigned int i;
+    struct entry *e, *f;
+    struct entry **table = h->table;
+
+	for (i = 0; i < h->tablelength; i++)
+        {
+            e = table[i];
+            while (NULL != e)
+				{ f = e; e = e->next; if (f->flags & HASHTABLE_FLAG_FREE_KEY) freekey(f->k); if (f->flags & HASHTABLE_FLAG_FREE_VALUE) free(f->v); free(f); }
+        }
+    
+    free(h->table);
+    free(h);
+}
+
+OZ_DECLARE(struct hashtable_iterator *) hashtable_next(struct hashtable_iterator *i)
+{
+
+	if (i->e) {
+		if ((i->e = i->e->next) != 0) { 
+			return i;
+		} else {
+			i->pos++;
+		}
+	}
+	
+	while(i->pos < i->h->tablelength && !i->h->table[i->pos]) {
+		i->pos++;
+	}
+	
+	if (i->pos >= i->h->tablelength) {
+		return NULL;
+	}
+	
+	if ((i->e = i->h->table[i->pos]) != 0) { 
+		return i;
+	}
+
+	return NULL;
+}
+
+OZ_DECLARE(struct hashtable_iterator *) hashtable_first(struct hashtable *h)
+{
+	h->iterator.pos = 0;
+	h->iterator.e = NULL;
+	h->iterator.h = h;
+	return hashtable_next(&h->iterator);
+}
+
+
+
+OZ_DECLARE(void) hashtable_this(struct hashtable_iterator *i, const void **key, int *klen, void **val)
+{
+	if (i->e) {
+		if (key) {
+			*key = i->e->k;
+		}
+		if (klen) {
+			*klen = (int)strlen(i->e->k);
+		}
+		if (val) {
+			*val = i->e->v;
+		}
+	} else {
+		if (key) {
+			*key = NULL;
+		}
+		if (klen) {
+			*klen = 0;
+		}
+		if (val) {
+			*val = NULL;
+		}
+	}
+}
+
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
+

Added: freeswitch/trunk/libs/openzap/src/hashtable_itr.c (0 => 17141)


--- freeswitch/trunk/libs/openzap/src/hashtable_itr.c	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/src/hashtable_itr.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,186 @@
+/*
+ * Copyright (c) 2002, 2004, Christopher Clark
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "hashtable.h"
+#include "hashtable_private.h"
+#include "hashtable_itr.h"
+#include <stdlib.h> /* defines NULL */
+
+/*****************************************************************************/
+/* hashtable_iterator    - iterator constructor */
+
+struct hashtable_itr *
+hashtable_iterator(struct hashtable *h)
+{
+    unsigned int i, tablelength;
+    struct hashtable_itr *itr = (struct hashtable_itr *)
+        malloc(sizeof(struct hashtable_itr));
+    if (NULL == itr) return NULL;
+    itr->h = h;
+    itr->e = NULL;
+    itr->parent = NULL;
+    tablelength = h->tablelength;
+    itr->index = tablelength;
+    if (0 == h->entrycount) return itr;
+
+    for (i = 0; i < tablelength; i++)
+		{
+			if (NULL != h->table[i])
+				{
+					itr->e = h->table[i];
+					itr->index = i;
+					break;
+				}
+		}
+    return itr;
+}
+
+/*****************************************************************************/
+/* advance - advance the iterator to the next element
+ *           returns zero if advanced to end of table */
+
+int
+hashtable_iterator_advance(struct hashtable_itr *itr)
+{
+    unsigned int j,tablelength;
+    struct entry **table;
+    struct entry *next;
+    if (NULL == itr->e) return 0; /* stupidity check */
+
+    next = itr->e->next;
+    if (NULL != next)
+		{
+			itr->parent = itr->e;
+			itr->e = next;
+			return -1;
+		}
+    tablelength = itr->h->tablelength;
+    itr->parent = NULL;
+    if (tablelength <= (j = ++(itr->index)))
+		{
+			itr->e = NULL;
+			return 0;
+		}
+    table = itr->h->table;
+    while (NULL == (next = table[j]))
+		{
+			if (++j >= tablelength)
+				{
+					itr->index = tablelength;
+					itr->e = NULL;
+					return 0;
+				}
+		}
+    itr->index = j;
+    itr->e = next;
+    return -1;
+}
+
+/*****************************************************************************/
+/* remove - remove the entry at the current iterator position
+ *          and advance the iterator, if there is a successive
+ *          element.
+ *          If you want the value, read it before you remove:
+ *          beware memory leaks if you don't.
+ *          Returns zero if end of iteration. */
+
+int
+hashtable_iterator_remove(struct hashtable_itr *itr)
+{
+    struct entry *remember_e, *remember_parent;
+    int ret;
+
+    /* Do the removal */
+    if (NULL == (itr->parent))
+		{
+			/* element is head of a chain */
+			itr->h->table[itr->index] = itr->e->next;
+		} else {
+        /* element is mid-chain */
+        itr->parent->next = itr->e->next;
+    }
+    /* itr->e is now outside the hashtable */
+    remember_e = itr->e;
+    itr->h->entrycount--;
+    freekey(remember_e->k);
+
+    /* Advance the iterator, correcting the parent */
+    remember_parent = itr->parent;
+    ret = hashtable_iterator_advance(itr);
+    if (itr->parent == remember_e) { itr->parent = remember_parent; }
+    free(remember_e);
+    return ret;
+}
+
+/*****************************************************************************/
+int /* returns zero if not found */
+hashtable_iterator_search(struct hashtable_itr *itr,
+                          struct hashtable *h, void *k)
+{
+    struct entry *e, *parent;
+    unsigned int hashvalue, index;
+
+    hashvalue = hash(h,k);
+    index = indexFor(h->tablelength,hashvalue);
+
+    e = h->table[index];
+    parent = NULL;
+    while (NULL != e)
+		{
+			/* Check hash value to short circuit heavier comparison */
+			if ((hashvalue == e->h) && (h->eqfn(k, e->k)))
+				{
+					itr->index = index;
+					itr->e = e;
+					itr->parent = parent;
+					itr->h = h;
+					return -1;
+				}
+			parent = e;
+			e = e->next;
+		}
+    return 0;
+}
+
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
+

Added: freeswitch/trunk/libs/openzap/src/include/fsk.h (0 => 17141)


--- freeswitch/trunk/libs/openzap/src/include/fsk.h	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/src/include/fsk.h	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,113 @@
+/*
+ *	bell202.h
+ *
+ *	Copyright (c) 2005 Robert Krten.  All Rights Reserved.
+ *
+ *	Redistribution and use in source and binary forms, with or without
+ *	modification, are permitted provided that the following conditions
+ *	are met:
+ *
+ *	1. Redistributions of source code must retain the above copyright
+ *	   notice, this list of conditions and the following disclaimer.
+ *	2. Redistributions in binary form must reproduce the above copyright
+ *	   notice, this list of conditions and the following disclaimer in the
+ *	   documentation and/or other materials provided with the distribution.
+ *
+ *	THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
+ *	ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ *	IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ *	ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE
+ *	FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ *	DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ *	OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ *	HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ *	LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ *	OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ *	SUCH DAMAGE.
+ *
+ *	This module contains the manifest constants and declarations for
+ *	the Bell-202 1200 baud FSK modem.
+ *
+ *	2005 03 20	R. Krten		created
+*/
+
+#ifndef	__FSK_H__
+#define	__FSK_H__
+#include "uart.h"
+
+typedef struct {
+    int freq_space;		/* Frequency of the 0 bit				*/
+    int freq_mark;		/* Frequency of the 1 bit				*/
+    int baud_rate;		/* baud rate for the modem				*/
+} fsk_modem_definition_t;
+
+/* Must be kept in sync with fsk_modem_definitions array in fsk.c	*/
+/* V.23 definitions: http://www.itu.int/rec/recommendation.asp?type=folders&lang=e&parent=T-REC-V.23 */
+typedef enum {
+    FSK_V23_FORWARD_MODE1 = 0,	/* Maximum 600 bps for long haul	*/
+    FSK_V23_FORWARD_MODE2,		/* Standard 1200 bps V.23			*/
+    FSK_V23_BACKWARD,			/* 75 bps return path for V.23		*/
+    FSK_BELL202					/* Bell 202 half-duplex 1200 bps	*/
+} fsk_modem_types_t;
+
+typedef enum {
+	FSK_STATE_CHANSEIZE = 0,
+	FSK_STATE_CARRIERSIG,
+	FSK_STATE_DATA
+} fsk_state_t;
+
+typedef struct dsp_fsk_attr_s
+{
+	int					sample_rate;					/* sample rate in HZ */
+	bithandler_func_t	bithandler;						/* bit handler */
+	void				*bithandler_arg;				/* arbitrary ID passed to bithandler as first argument */
+	bytehandler_func_t	bytehandler;					/* byte handler */
+	void				*bytehandler_arg;				/* arbitrary ID passed to bytehandler as first argument */
+}	dsp_fsk_attr_t;
+
+typedef struct
+{
+	fsk_state_t			state;
+	dsp_fsk_attr_t		attr;							/* attributes structure */
+	double				*correlates[4];					/* one for each of sin/cos for mark/space */
+	int					corrsize;						/* correlate size (also number of samples in ring buffer) */
+	double				*buffer;						/* sample ring buffer */
+	int					ringstart;						/* ring buffer start offset */
+	double				cellpos;						/* bit cell position */
+	double				celladj;						/* bit cell adjustment for each sample */
+	int					previous_bit;					/* previous bit (for detecting a transition to sync-up cell position) */
+	int					current_bit;					/* current bit */
+	int					last_bit;
+	int					downsampling_count;				/* number of samples to skip */
+	int					current_downsample;				/* current skip count */
+	int					conscutive_state_bits;			/* number of bits in a row that matches the pattern for the current state */
+}	dsp_fsk_handle_t;
+
+/*
+ *	Function prototypes
+ *
+ *	General calling order is:
+ *		a) create the attributes structure (dsp_fsk_attr_init)
+ *		b) initialize fields in the attributes structure (dsp_fsk_attr_set_*)
+ *		c) create a Bell-202 handle (dsp_fsk_create)
+ *		d) feed samples through the handler (dsp_fsk_sample)
+*/
+
+void					dsp_fsk_attr_init(dsp_fsk_attr_t *attributes);
+
+bithandler_func_t		dsp_fsk_attr_get_bithandler(dsp_fsk_attr_t *attributes, void **bithandler_arg);
+void					dsp_fsk_attr_set_bithandler(dsp_fsk_attr_t *attributes, bithandler_func_t bithandler, void *bithandler_arg);
+bytehandler_func_t		dsp_fsk_attr_get_bytehandler(dsp_fsk_attr_t *attributes, void **bytehandler_arg);
+void					dsp_fsk_attr_set_bytehandler(dsp_fsk_attr_t *attributes, bytehandler_func_t bytehandler, void *bytehandler_arg);
+int						dsp_fsk_attr_get_samplerate(dsp_fsk_attr_t *attributes);
+int						dsp_fsk_attr_set_samplerate(dsp_fsk_attr_t *attributes, int samplerate);
+
+dsp_fsk_handle_t *	dsp_fsk_create(dsp_fsk_attr_t *attributes);
+void					dsp_fsk_destroy(dsp_fsk_handle_t **handle);
+
+void					dsp_fsk_sample(dsp_fsk_handle_t *handle, double normalized_sample);
+
+extern fsk_modem_definition_t fsk_modem_definitions[];
+
+#endif	
+

Added: freeswitch/trunk/libs/openzap/src/include/g711.h (0 => 17141)


--- freeswitch/trunk/libs/openzap/src/include/g711.h	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/src/include/g711.h	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,395 @@
+/*
+ * SpanDSP - a series of DSP components for telephony
+ *
+ * g711.h - In line A-law and u-law conversion routines
+ *
+ * Written by Steve Underwood <steveu@coppice.org>
+ *
+ * Copyright (C) 2001 Steve Underwood
+ *
+ *  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.
+ *
+ * $Id: g711.h,v 1.1 2006/06/07 15:46:39 steveu Exp $
+ */
+
+/*! \file */
+
+/*! \page g711_page A-law and mu-law handling
+  Lookup tables for A-law and u-law look attractive, until you consider the impact
+  on the CPU cache. If it causes a substantial area of your processor cache to get
+  hit too often, cache sloshing will severely slow things down. The main reason
+  these routines are slow in C, is the lack of direct access to the CPU's "find
+  the first 1" instruction. A little in-line assembler fixes that, and the
+  conversion routines can be faster than lookup tables, in most real world usage.
+  A "find the first 1" instruction is available on most modern CPUs, and is a
+  much underused feature. 
+
+  If an assembly language method of bit searching is not available, these routines
+  revert to a method that can be a little slow, so the cache thrashing might not
+  seem so bad :(
+
+  Feel free to submit patches to add fast "find the first 1" support for your own
+  favourite processor.
+
+  Look up tables are used for transcoding between A-law and u-law, since it is
+  difficult to achieve the precise transcoding procedure laid down in the G.711
+  specification by other means.
+*/
+
+#if !defined(_G711_H_)
+#define _G711_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef _MSC_VER
+#ifndef __inline__
+#define __inline__ __inline
+#endif
+	typedef unsigned __int8 uint8_t;
+	typedef __int16 int16_t;
+	typedef __int32 int32_t;
+	typedef unsigned __int16 uint16_t;
+#else
+#include <stdint.h>
+#endif
+
+#if defined(__i386__)
+	/*! \brief Find the bit position of the highest set bit in a word
+	  \param bits The word to be searched
+	  \return The bit number of the highest set bit, or -1 if the word is zero. */
+	static __inline__ int top_bit(unsigned int bits)
+	{
+		int res;
+
+		__asm__ __volatile__(" movl $-1,%%edx;\n"
+							 " bsrl %%eax,%%edx;\n"
+							 : "=d" (res)
+							 : "a" (bits));
+		return res;
+	}
+	/*- End of function --------------------------------------------------------*/
+
+	/*! \brief Find the bit position of the lowest set bit in a word
+	  \param bits The word to be searched
+	  \return The bit number of the lowest set bit, or -1 if the word is zero. */
+	static __inline__ int bottom_bit(unsigned int bits)
+	{
+		int res;
+
+		__asm__ __volatile__(" movl $-1,%%edx;\n"
+							 " bsfl %%eax,%%edx;\n"
+							 : "=d" (res)
+							 : "a" (bits));
+		return res;
+	}
+	/*- End of function --------------------------------------------------------*/
+#elif defined(__x86_64__)
+	static __inline__ int top_bit(unsigned int bits)
+	{
+		int res;
+
+		__asm__ __volatile__(" movq $-1,%%rdx;\n"
+							 " bsrq %%rax,%%rdx;\n"
+							 : "=d" (res)
+							 : "a" (bits));
+		return res;
+	}
+	/*- End of function --------------------------------------------------------*/
+
+	static __inline__ int bottom_bit(unsigned int bits)
+	{
+		int res;
+
+		__asm__ __volatile__(" movq $-1,%%rdx;\n"
+							 " bsfq %%rax,%%rdx;\n"
+							 : "=d" (res)
+							 : "a" (bits));
+		return res;
+	}
+	/*- End of function --------------------------------------------------------*/
+#else
+	static __inline__ int top_bit(unsigned int bits)
+	{
+		int i;
+    
+		if (bits == 0)
+			return -1;
+		i = 0;
+		if (bits & 0xFFFF0000)
+			{
+				bits &= 0xFFFF0000;
+				i += 16;
+			}
+		if (bits & 0xFF00FF00)
+			{
+				bits &= 0xFF00FF00;
+				i += 8;
+			}
+		if (bits & 0xF0F0F0F0)
+			{
+				bits &= 0xF0F0F0F0;
+				i += 4;
+			}
+		if (bits & 0xCCCCCCCC)
+			{
+				bits &= 0xCCCCCCCC;
+				i += 2;
+			}
+		if (bits & 0xAAAAAAAA)
+			{
+				bits &= 0xAAAAAAAA;
+				i += 1;
+			}
+		return i;
+	}
+	/*- End of function --------------------------------------------------------*/
+
+	static __inline__ int bottom_bit(unsigned int bits)
+	{
+		int i;
+    
+		if (bits == 0)
+			return -1;
+		i = 32;
+		if (bits & 0x0000FFFF)
+			{
+				bits &= 0x0000FFFF;
+				i -= 16;
+			}
+		if (bits & 0x00FF00FF)
+			{
+				bits &= 0x00FF00FF;
+				i -= 8;
+			}
+		if (bits & 0x0F0F0F0F)
+			{
+				bits &= 0x0F0F0F0F;
+				i -= 4;
+			}
+		if (bits & 0x33333333)
+			{
+				bits &= 0x33333333;
+				i -= 2;
+			}
+		if (bits & 0x55555555)
+			{
+				bits &= 0x55555555;
+				i -= 1;
+			}
+		return i;
+	}
+	/*- End of function --------------------------------------------------------*/
+#endif
+
+	/* N.B. It is tempting to use look-up tables for A-law and u-law conversion.
+	 *      However, you should consider the cache footprint.
+	 *
+	 *      A 64K byte table for linear to x-law and a 512 byte table for x-law to
+	 *      linear sound like peanuts these days, and shouldn't an array lookup be
+	 *      real fast? No! When the cache sloshes as badly as this one will, a tight
+	 *      calculation may be better. The messiest part is normally finding the
+	 *      segment, but a little inline assembly can fix that on an i386, x86_64 and
+	 *      many other modern processors.
+	 */
+ 
+	/*
+	 * Mu-law is basically as follows:
+	 *
+	 *      Biased Linear Input Code        Compressed Code
+	 *      ------------------------        ---------------
+	 *      00000001wxyza                   000wxyz
+	 *      0000001wxyzab                   001wxyz
+	 *      000001wxyzabc                   010wxyz
+	 *      00001wxyzabcd                   011wxyz
+	 *      0001wxyzabcde                   100wxyz
+	 *      001wxyzabcdef                   101wxyz
+	 *      01wxyzabcdefg                   110wxyz
+	 *      1wxyzabcdefgh                   111wxyz
+	 *
+	 * Each biased linear code has a leading 1 which identifies the segment
+	 * number. The value of the segment number is equal to 7 minus the number
+	 * of leading 0's. The quantization interval is directly available as the
+	 * four bits wxyz.  * The trailing bits (a - h) are ignored.
+	 *
+	 * Ordinarily the complement of the resulting code word is used for
+	 * transmission, and so the code word is complemented before it is returned.
+	 *
+	 * For further information see John C. Bellamy's Digital Telephony, 1982,
+	 * John Wiley & Sons, pps 98-111 and 472-476.
+	 */
+
+	/*#define ULAW_ZEROTRAP*/                 /* turn on the trap as per the MIL-STD */
+#define ULAW_BIAS        0x84           /* Bias for linear code. */
+
+	/*! \brief Encode a linear sample to u-law
+	  \param linear The sample to encode.
+	  \return The u-law value.
+	*/
+	static __inline__ uint8_t linear_to_ulaw(int linear)
+	{
+		uint8_t u_val;
+		int mask;
+		int seg;
+
+		/* Get the sign and the magnitude of the value. */
+		if (linear < 0)
+			{
+				linear = ULAW_BIAS - linear;
+				mask = 0x7F;
+			}
+		else
+			{
+				linear = ULAW_BIAS + linear;
+				mask = 0xFF;
+			}
+
+		seg = top_bit(linear | 0xFF) - 7;
+
+		/*
+		 * Combine the sign, segment, quantization bits,
+		 * and complement the code word.
+		 */
+		if (seg >= 8)
+			u_val = (uint8_t) (0x7F ^ mask);
+		else
+			u_val = (uint8_t) (((seg << 4) | ((linear >> (seg + 3)) & 0xF)) ^ mask);
+#ifdef ULAW_ZEROTRAP
+		/* Optional ITU trap */
+		if (u_val == 0)
+			u_val = 0x02;
+#endif
+		return  u_val;
+	}
+	/*- End of function --------------------------------------------------------*/
+
+	/*! \brief Decode an u-law sample to a linear value.
+	  \param ulaw The u-law sample to decode.
+	  \return The linear value.
+	*/
+	static __inline__ int16_t ulaw_to_linear(uint8_t ulaw)
+	{
+		int t;
+    
+		/* Complement to obtain normal u-law value. */
+		ulaw = ~ulaw;
+		/*
+		 * Extract and bias the quantization bits. Then
+		 * shift up by the segment number and subtract out the bias.
+		 */
+		t = (((ulaw & 0x0F) << 3) + ULAW_BIAS) << (((int) ulaw & 0x70) >> 4);
+		return  (int16_t) ((ulaw & 0x80)  ?  (ULAW_BIAS - t)  :  (t - ULAW_BIAS));
+	}
+	/*- End of function --------------------------------------------------------*/
+
+	/*
+	 * A-law is basically as follows:
+	 *
+	 *      Linear Input Code        Compressed Code
+	 *      -----------------        ---------------
+	 *      0000000wxyza             000wxyz
+	 *      0000001wxyza             001wxyz
+	 *      000001wxyzab             010wxyz
+	 *      00001wxyzabc             011wxyz
+	 *      0001wxyzabcd             100wxyz
+	 *      001wxyzabcde             101wxyz
+	 *      01wxyzabcdef             110wxyz
+	 *      1wxyzabcdefg             111wxyz
+	 *
+	 * For further information see John C. Bellamy's Digital Telephony, 1982,
+	 * John Wiley & Sons, pps 98-111 and 472-476.
+	 */
+
+#define ALAW_AMI_MASK       0x55
+
+	/*! \brief Encode a linear sample to A-law
+	  \param linear The sample to encode.
+	  \return The A-law value.
+	*/
+	static __inline__ uint8_t linear_to_alaw(int linear)
+	{
+		int mask;
+		int seg;
+    
+		if (linear >= 0)
+			{
+				/* Sign (bit 7) bit = 1 */
+				mask = ALAW_AMI_MASK | 0x80;
+			}
+		else
+			{
+				/* Sign (bit 7) bit = 0 */
+				mask = ALAW_AMI_MASK;
+				linear = -linear - 8;
+			}
+
+		/* Convert the scaled magnitude to segment number. */
+		seg = top_bit(linear | 0xFF) - 7;
+		if (seg >= 8)
+			{
+				if (linear >= 0)
+					{
+						/* Out of range. Return maximum value. */
+						return (uint8_t) (0x7F ^ mask);
+					}
+				/* We must be just a tiny step below zero */
+				return (uint8_t) (0x00 ^ mask);
+			}
+		/* Combine the sign, segment, and quantization bits. */
+		return (uint8_t) (((seg << 4) | ((linear >> ((seg)  ?  (seg + 3)  :  4)) & 0x0F)) ^ mask);
+	}
+	/*- End of function --------------------------------------------------------*/
+
+	/*! \brief Decode an A-law sample to a linear value.
+	  \param alaw The A-law sample to decode.
+	  \return The linear value.
+	*/
+	static __inline__ int16_t alaw_to_linear(uint8_t alaw)
+	{
+		int i;
+		int seg;
+
+		alaw ^= ALAW_AMI_MASK;
+		i = ((alaw & 0x0F) << 4);
+		seg = (((int) alaw & 0x70) >> 4);
+		if (seg)
+			i = (i + 0x108) << (seg - 1);
+		else
+			i += 8;
+		return (int16_t) ((alaw & 0x80)  ?  i  :  -i);
+	}
+	/*- End of function --------------------------------------------------------*/
+
+	/*! \brief Transcode from A-law to u-law, using the procedure defined in G.711.
+	  \param alaw The A-law sample to transcode.
+	  \return The best matching u-law value.
+	*/
+	uint8_t alaw_to_ulaw(uint8_t alaw);
+
+	/*! \brief Transcode from u-law to A-law, using the procedure defined in G.711.
+	  \param alaw The u-law sample to transcode.
+	  \return The best matching A-law value.
+	*/
+	uint8_t ulaw_to_alaw(uint8_t ulaw);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+/*- End of file ------------------------------------------------------------*/
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */

Added: freeswitch/trunk/libs/openzap/src/include/hashtable.h (0 => 17141)


--- freeswitch/trunk/libs/openzap/src/include/hashtable.h	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/src/include/hashtable.h	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,228 @@
+/* Copyright (C) 2002 Christopher Clark <firstname.lastname@cl.cam.ac.uk> */
+
+#ifndef __HASHTABLE_CWC22_H__
+#define __HASHTABLE_CWC22_H__
+#ifdef _MSC_VER
+#ifndef __inline__
+#define __inline__ __inline
+#endif
+#endif
+#include "openzap.h"
+
+struct hashtable;
+struct hashtable_iterator;
+
+/* Example of use:
+ *
+ *      struct hashtable  *h;
+ *      struct some_key   *k;
+ *      struct some_value *v;
+ *
+ *      static unsigned int         hash_from_key_fn( void *k );
+ *      static int                  keys_equal_fn ( void *key1, void *key2 );
+ *
+ *      h = create_hashtable(16, hash_from_key_fn, keys_equal_fn);
+ *      k = (struct some_key *)     malloc(sizeof(struct some_key));
+ *      v = (struct some_value *)   malloc(sizeof(struct some_value));
+ *
+ *      (initialise k and v to suitable values)
+ * 
+ *      if (! hashtable_insert(h,k,v) )
+ *      {     exit(-1);               }
+ *
+ *      if (NULL == (found = hashtable_search(h,k) ))
+ *      {    printf("not found!");                  }
+ *
+ *      if (NULL == (found = hashtable_remove(h,k) ))
+ *      {    printf("Not found\n");                 }
+ *
+ */
+
+/* Macros may be used to define type-safe(r) hashtable access functions, with
+ * methods specialized to take known key and value types as parameters.
+ * 
+ * Example:
+ *
+ * Insert this at the start of your file:
+ *
+ * DEFINE_HASHTABLE_INSERT(insert_some, struct some_key, struct some_value);
+ * DEFINE_HASHTABLE_SEARCH(search_some, struct some_key, struct some_value);
+ * DEFINE_HASHTABLE_REMOVE(remove_some, struct some_key, struct some_value);
+ *
+ * This defines the functions 'insert_some', 'search_some' and 'remove_some'.
+ * These operate just like hashtable_insert etc., with the same parameters,
+ * but their function signatures have 'struct some_key *' rather than
+ * 'void *', and hence can generate compile time errors if your program is
+ * supplying incorrect data as a key (and similarly for value).
+ *
+ * Note that the hash and key equality functions passed to create_hashtable
+ * still take 'void *' parameters instead of 'some key *'. This shouldn't be
+ * a difficult issue as they're only defined and passed once, and the other
+ * functions will ensure that only valid keys are supplied to them.
+ *
+ * The cost for this checking is increased code size and runtime overhead
+ * - if performance is important, it may be worth switching back to the
+ * unsafe methods once your program has been debugged with the safe methods.
+ * This just requires switching to some simple alternative defines - eg:
+ * #define insert_some hashtable_insert
+ *
+ */
+
+/*****************************************************************************
+ * create_hashtable
+   
+ * @name                    create_hashtable
+ * @param   minsize         minimum initial size of hashtable
+ * @param   hashfunction    function for hashing keys
+ * @param   key_eq_fn       function for determining key equality
+ * @return                  newly created hashtable or NULL on failure
+ */
+
+OZ_DECLARE(struct hashtable *)
+create_hashtable(unsigned int minsize,
+                 unsigned int (*hashfunction) (void*),
+                 int (*key_eq_fn) (void*,void*));
+
+/*****************************************************************************
+ * hashtable_insert
+   
+ * @name        hashtable_insert
+ * @param   h   the hashtable to insert into
+ * @param   k   the key - hashtable claims ownership and will free on removal
+ * @param   v   the value - does not claim ownership
+ * @return      non-zero for successful insertion
+ *
+ * This function will cause the table to expand if the insertion would take
+ * the ratio of entries to table size over the maximum load factor.
+ *
+ * This function does not check for repeated insertions with a duplicate key.
+ * The value returned when using a duplicate key is undefined -- when
+ * the hashtable changes size, the order of retrieval of duplicate key
+ * entries is reversed.
+ * If in doubt, remove before insert.
+ */
+
+
+typedef enum {
+	HASHTABLE_FLAG_NONE = 0,
+	HASHTABLE_FLAG_FREE_KEY = (1 << 0),
+	HASHTABLE_FLAG_FREE_VALUE = (1 << 1)
+} hashtable_flag_t;
+
+OZ_DECLARE(int)
+hashtable_insert(struct hashtable *h, void *k, void *v, hashtable_flag_t flags);
+
+#define DEFINE_HASHTABLE_INSERT(fnname, keytype, valuetype)		\
+	int fnname (struct hashtable *h, keytype *k, valuetype *v)	\
+	{															\
+		return hashtable_insert(h,k,v);							\
+	}
+
+/*****************************************************************************
+ * hashtable_search
+   
+ * @name        hashtable_search
+ * @param   h   the hashtable to search
+ * @param   k   the key to search for  - does not claim ownership
+ * @return      the value associated with the key, or NULL if none found
+ */
+
+OZ_DECLARE(void *)
+hashtable_search(struct hashtable *h, void *k);
+
+#define DEFINE_HASHTABLE_SEARCH(fnname, keytype, valuetype) \
+	valuetype * fnname (struct hashtable *h, keytype *k)	\
+	{														\
+		return (valuetype *) (hashtable_search(h,k));		\
+	}
+
+/*****************************************************************************
+ * hashtable_remove
+   
+ * @name        hashtable_remove
+ * @param   h   the hashtable to remove the item from
+ * @param   k   the key to search for  - does not claim ownership
+ * @return      the value associated with the key, or NULL if none found
+ */
+
+OZ_DECLARE(void *) /* returns value */
+hashtable_remove(struct hashtable *h, void *k);
+
+#define DEFINE_HASHTABLE_REMOVE(fnname, keytype, valuetype) \
+	valuetype * fnname (struct hashtable *h, keytype *k)	\
+	{														\
+		return (valuetype *) (hashtable_remove(h,k));		\
+	}
+
+
+/*****************************************************************************
+ * hashtable_count
+   
+ * @name        hashtable_count
+ * @param   h   the hashtable
+ * @return      the number of items stored in the hashtable
+ */
+OZ_DECLARE(unsigned int)
+hashtable_count(struct hashtable *h);
+
+
+/*****************************************************************************
+ * hashtable_destroy
+   
+ * @name        hashtable_destroy
+ * @param   h   the hashtable
+ * @param       free_values     whether to call 'free' on the remaining values
+ */
+
+OZ_DECLARE(void)
+hashtable_destroy(struct hashtable *h);
+
+OZ_DECLARE(struct hashtable_iterator*) hashtable_first(struct hashtable *h);
+OZ_DECLARE(struct hashtable_iterator*) hashtable_next(struct hashtable_iterator *i);
+OZ_DECLARE(void) hashtable_this(struct hashtable_iterator *i, const void **key, int *klen, void **val);
+
+#endif /* __HASHTABLE_CWC22_H__ */
+
+/*
+ * Copyright (c) 2002, Christopher Clark
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */

Added: freeswitch/trunk/libs/openzap/src/include/hashtable_itr.h (0 => 17141)


--- freeswitch/trunk/libs/openzap/src/include/hashtable_itr.h	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/src/include/hashtable_itr.h	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,129 @@
+/* Copyright (C) 2002, 2004 Christopher Clark <firstname.lastname@cl.cam.ac.uk> */
+
+#ifndef __HASHTABLE_ITR_CWC22__
+#define __HASHTABLE_ITR_CWC22__
+#include "hashtable.h"
+#include "hashtable_private.h" /* needed to enable inlining */
+
+/*****************************************************************************/
+/* This struct is only concrete here to allow the inlining of two of the
+ * accessor functions. */
+struct hashtable_itr
+{
+    struct hashtable *h;
+    struct entry *e;
+    struct entry *parent;
+    unsigned int index;
+};
+
+
+/*****************************************************************************/
+/* hashtable_iterator
+ */
+
+struct hashtable_itr *
+hashtable_iterator(struct hashtable *h);
+
+/*****************************************************************************/
+/* hashtable_iterator_key
+ * - return the value of the (key,value) pair at the current position */
+extern __inline__ void *
+hashtable_iterator_key(struct hashtable_itr *i);
+
+extern __inline__ void *
+hashtable_iterator_key(struct hashtable_itr *i)
+{
+    return i->e->k;
+}
+
+/*****************************************************************************/
+/* value - return the value of the (key,value) pair at the current position */
+
+extern __inline__ void *
+hashtable_iterator_value(struct hashtable_itr *i);
+
+extern __inline__ void *
+hashtable_iterator_value(struct hashtable_itr *i)
+{
+    return i->e->v;
+}
+
+/*****************************************************************************/
+/* advance - advance the iterator to the next element
+ *           returns zero if advanced to end of table */
+
+int
+hashtable_iterator_advance(struct hashtable_itr *itr);
+
+/*****************************************************************************/
+/* remove - remove current element and advance the iterator to the next element
+ *          NB: if you need the value to free it, read it before
+ *          removing. ie: beware memory leaks!
+ *          returns zero if advanced to end of table */
+
+int
+hashtable_iterator_remove(struct hashtable_itr *itr);
+
+/*****************************************************************************/
+/* search - overwrite the supplied iterator, to point to the entry
+ *          matching the supplied key.
+ h points to the hashtable to be searched.
+ *          returns zero if not found. */
+int
+hashtable_iterator_search(struct hashtable_itr *itr,
+                          struct hashtable *h, void *k);
+
+#define DEFINE_HASHTABLE_ITERATOR_SEARCH(fnname, keytype)				\
+	int fnname (struct hashtable_itr *i, struct hashtable *h, keytype *k) \
+	{																	\
+		return (hashtable_iterator_search(i,h,k));						\
+	}
+
+
+
+#endif /* __HASHTABLE_ITR_CWC22__*/
+
+/*
+ * Copyright (c) 2002, 2004, Christopher Clark
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
+

Added: freeswitch/trunk/libs/openzap/src/include/hashtable_private.h (0 => 17141)


--- freeswitch/trunk/libs/openzap/src/include/hashtable_private.h	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/src/include/hashtable_private.h	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,105 @@
+/* Copyright (C) 2002, 2004 Christopher Clark <firstname.lastname@cl.cam.ac.uk> */
+
+#ifndef __HASHTABLE_PRIVATE_CWC22_H__
+#define __HASHTABLE_PRIVATE_CWC22_H__
+
+#include "hashtable.h"
+
+
+/*****************************************************************************/
+
+struct entry
+{
+    void *k, *v;
+    unsigned int h;
+	hashtable_flag_t flags;
+    struct entry *next;
+};
+
+struct hashtable_iterator {
+	unsigned int pos;
+	struct entry *e;
+	struct hashtable *h;
+};
+
+struct hashtable {
+    unsigned int tablelength;
+    struct entry **table;
+    unsigned int entrycount;
+    unsigned int loadlimit;
+    unsigned int primeindex;
+    unsigned int (*hashfn) (void *k);
+    int (*eqfn) (void *k1, void *k2);
+	struct hashtable_iterator iterator;
+};
+
+/*****************************************************************************/
+unsigned int
+hash(struct hashtable *h, void *k);
+
+/*****************************************************************************/
+/* indexFor */
+static __inline__ unsigned int
+indexFor(unsigned int tablelength, unsigned int hashvalue) {
+    return (hashvalue % tablelength);
+}
+
+/* Only works if tablelength == 2^N */
+/*static inline unsigned int
+  indexFor(unsigned int tablelength, unsigned int hashvalue)
+  {
+  return (hashvalue & (tablelength - 1u));
+  }
+*/
+
+/*****************************************************************************/
+#define freekey(X) free(X)
+/*define freekey(X) ; */
+
+
+/*****************************************************************************/
+
+#endif /* __HASHTABLE_PRIVATE_CWC22_H__*/
+
+/*
+ * Copyright (c) 2002, Christopher Clark
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */

Added: freeswitch/trunk/libs/openzap/src/include/libteletone.h (0 => 17141)


--- freeswitch/trunk/libs/openzap/src/include/libteletone.h	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/src/include/libteletone.h	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,161 @@
+/* 
+ * libteletone
+ * Copyright (C) 2005/2006, Anthony Minessale II <anthmct@yahoo.com>
+ *
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is libteletone
+ *
+ * The Initial Developer of the Original Code is
+ * Anthony Minessale II <anthmct@yahoo.com>
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * 
+ * Anthony Minessale II <anthmct@yahoo.com>
+ *
+ *
+ * libteletone.h -- Tone Generator/Detector
+ *
+ *
+ *
+ * Exception:
+ * The author hereby grants the use of this source code under the 
+ * following license if and only if the source code is distributed
+ * as part of the openzap library.  Any use or distribution of this
+ * source code outside the scope of the openzap library will nullify the
+ * following license and reinact the MPL 1.1 as stated above.
+ *
+ * Copyright (c) 2007, Anthony Minessale II
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef LIBTELETONE_H
+#define LIBTELETONE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <math.h>
+
+#define	TELETONE_MAX_DTMF_DIGITS 128
+#define TELETONE_MAX_TONES 18
+#define TELETONE_TONE_RANGE 127
+
+typedef double teletone_process_t;
+
+/*! \file libteletone.h
+    \brief Top level include file
+
+	This file should be included by applications using the library
+*/
+
+/*! \brief An abstraction to store a tone mapping */
+typedef struct {
+	/*! An array of tone frequencies */
+	teletone_process_t freqs[TELETONE_MAX_TONES];
+} teletone_tone_map_t;
+
+#if !defined(M_PI)
+/* C99 systems may not define M_PI */
+#define M_PI 3.14159265358979323846264338327
+#endif
+
+#ifdef _MSC_VER
+typedef __int16 int16_t;
+#endif
+
+#if (_MSC_VER >= 1400)			// VC8+
+#define teletone_assert(expr) assert(expr);__analysis_assume( expr )
+#else
+#define teletone_assert(expr) assert(expr)
+#endif
+
+#ifdef _MSC_VER
+#if defined(TT_DECLARE_STATIC)
+#define TELETONE_API(type)			type __stdcall
+#define TELETONE_API_NONSTD(type)		type __cdecl
+#define TELETONE_API_DATA
+#elif defined(TELETONE_EXPORTS)
+#define TELETONE_API(type)			__declspec(dllexport) type __stdcall
+#define TELETONE_API_NONSTD(type)		__declspec(dllexport) type __cdecl
+#define TELETONE_API_DATA				__declspec(dllexport)
+#else
+#define TELETONE_API(type)			__declspec(dllimport) type __stdcall
+#define TELETONE_API_NONSTD(type)		__declspec(dllimport) type __cdecl
+#define TELETONE_API_DATA				__declspec(dllimport)
+#endif
+#else
+#if (defined(__GNUC__) || defined(__SUNPRO_CC) || defined (__SUNPRO_C)) && defined(HAVE_VISIBILITY)
+#define TELETONE_API(type)		__attribute__((visibility("default"))) type
+#define TELETONE_API_NONSTD(type)	__attribute__((visibility("default"))) type
+#define TELETONE_API_DATA		__attribute__((visibility("default")))
+#else
+#define TELETONE_API(type)		type
+#define TELETONE_API_NONSTD(type)	type
+#define TELETONE_API_DATA
+#endif
+#endif
+
+#include <libteletone_generate.h>
+#include <libteletone_detect.h>
+
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */

Added: freeswitch/trunk/libs/openzap/src/include/libteletone_detect.h (0 => 17141)


--- freeswitch/trunk/libs/openzap/src/include/libteletone_detect.h	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/src/include/libteletone_detect.h	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,240 @@
+/* 
+ * libteletone
+ * Copyright (C) 2005/2006, Anthony Minessale II <anthmct@yahoo.com>
+ *
+ * libteletone_detect.c Tone Detection Code
+ *
+ * Exception:
+ * The author hereby grants the use of this source code under the 
+ * following license if and only if the source code is distributed
+ * as part of the openzap library.	Any use or distribution of this
+ * source code outside the scope of the openzap library will nullify the
+ * following license and reinact the MPL 1.1 as stated above.
+ *
+ * Copyright (c) 2007, Anthony Minessale II
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.	 IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ********************************************************************************* 
+ *
+ * Derived from tone_detect.h - General telephony tone detection, and specific
+ * detection of DTMF.
+ *
+ * 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.
+ *
+ *
+ */
+
+#ifndef LIBTELETONE_DETECT_H
+#define LIBTELETONE_DETECT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+#include <libteletone.h>
+
+	/*! \file libteletone_detect.h
+	  \brief Tone Detection Routines
+
+	  This module is responsible for tone detection specifics
+	*/
+
+#ifndef FALSE
+#define FALSE	0
+#ifndef TRUE
+#define TRUE	(!FALSE)
+#endif
+#endif
+
+	/* Basic DTMF specs:
+	 *
+	 * Minimum tone on = 40ms
+	 * Minimum tone off = 50ms
+	 * Maximum digit rate = 10 per second
+	 * Normal twist <= 8dB accepted
+	 * Reverse twist <= 4dB accepted
+	 * S/N >= 15dB will detect OK
+	 * Attenuation <= 26dB will detect OK
+	 * Frequency tolerance +- 1.5% will detect, +-3.5% will reject
+	 */
+
+#define DTMF_THRESHOLD				8.0e7
+#define DTMF_NORMAL_TWIST			6.3		/* 8dB */
+#define DTMF_REVERSE_TWIST			2.5		/* 4dB */
+#define DTMF_RELATIVE_PEAK_ROW		6.3		/* 8dB */
+#define DTMF_RELATIVE_PEAK_COL		6.3		/* 8dB */
+#define DTMF_2ND_HARMONIC_ROW		2.5		/* 4dB */
+#define DTMF_2ND_HARMONIC_COL		63.1	/* 18dB */
+#define GRID_FACTOR 4
+#define BLOCK_LEN 102
+#define M_TWO_PI 2.0*M_PI
+
+	/*! \brief A continer for the elements of a Goertzel Algorithm (The names are from his formula) */
+	typedef struct {
+		float v2;
+		float v3;
+		double fac;
+	} teletone_goertzel_state_t;
+	
+	/*! \brief A container for a DTMF detection state.*/
+	typedef struct {
+		int hit1;
+		int hit2;
+		int hit3;
+		int hit4;
+		int mhit;
+
+		teletone_goertzel_state_t row_out[GRID_FACTOR];
+		teletone_goertzel_state_t col_out[GRID_FACTOR];
+		teletone_goertzel_state_t row_out2nd[GRID_FACTOR];
+		teletone_goertzel_state_t col_out2nd[GRID_FACTOR];
+		float energy;
+	
+		int current_sample;
+		char digits[TELETONE_MAX_DTMF_DIGITS + 1];
+		int current_digits;
+		int detected_digits;
+		int lost_digits;
+		int digit_hits[16];
+	} teletone_dtmf_detect_state_t;
+
+	/*! \brief An abstraction to store the coefficient of a tone frequency */
+	typedef struct {
+		float fac;
+	} teletone_detection_descriptor_t;
+
+	/*! \brief A container for a single multi-tone detection 
+	  TELETONE_MAX_TONES dictates the maximum simultaneous tones that can be present
+	  in a multi-tone representation.
+	*/
+	typedef struct {
+		int sample_rate;
+
+		teletone_detection_descriptor_t tdd[TELETONE_MAX_TONES];
+		teletone_goertzel_state_t gs[TELETONE_MAX_TONES];
+		teletone_goertzel_state_t gs2[TELETONE_MAX_TONES];
+		int tone_count;
+
+		float energy;
+		int current_sample;
+	
+		int min_samples;
+		int total_samples;
+
+		int positives;
+		int negatives;
+		int hits;
+
+		int positive_factor;
+		int negative_factor;
+		int hit_factor;
+
+	} teletone_multi_tone_t;
+
+
+	/*! 
+	  \brief Initilize a multi-frequency tone detector
+	  \param mt the multi-frequency tone descriptor
+	  \param map a representation of the multi-frequency tone
+	*/
+TELETONE_API(void) teletone_multi_tone_init(teletone_multi_tone_t *mt, teletone_tone_map_t *map);
+
+	/*! 
+	  \brief Check a sample buffer for the presence of the mulit-frequency tone described by mt
+	  \param mt the multi-frequency tone descriptor
+	  \param sample_buffer an array aof 16 bit signed linear samples
+	  \param samples the number of samples present in sample_buffer
+	  \return true when the tone was detected or false when it is not
+	*/
+TELETONE_API(int) teletone_multi_tone_detect (teletone_multi_tone_t *mt,
+									int16_t sample_buffer[],
+									int samples);
+
+	/*! 
+	  \brief Initilize a DTMF detection state object
+	  \param dtmf_detect_state the DTMF detection state to initilize
+	  \param sample_rate the desired sample rate
+	*/
+TELETONE_API(void) teletone_dtmf_detect_init (teletone_dtmf_detect_state_t *dtmf_detect_state, int sample_rate);
+
+	/*! 
+	  \brief Check a sample buffer for the presence of DTMF digits
+	  \param dtmf_detect_state the detection state object to check
+	  \param sample_buffer an array aof 16 bit signed linear samples
+	  \param samples the number of samples present in sample_buffer
+	  \return true when DTMF was detected or false when it is not
+	*/
+TELETONE_API(int) teletone_dtmf_detect (teletone_dtmf_detect_state_t *dtmf_detect_state,
+							  int16_t sample_buffer[],
+							  int samples);
+	/*! 
+	  \brief retrieve any collected digits into a string buffer
+	  \param dtmf_detect_state the detection state object to check
+	  \param buf the string buffer to write to
+	  \param max the maximum length of buf
+	  \return the number of characters written to buf
+	*/
+TELETONE_API(int) teletone_dtmf_get (teletone_dtmf_detect_state_t *dtmf_detect_state,
+						   char *buf,
+						   int max);
+
+	/*! 
+	  \brief Step through the Goertzel Algorithm for each sample in a buffer
+	  \param goertzel_state the goertzel state to step the samples through
+	  \param sample_buffer an array aof 16 bit signed linear samples
+	  \param samples the number of samples present in sample_buffer
+	*/
+TELETONE_API(void) teletone_goertzel_update(teletone_goertzel_state_t *goertzel_state,
+								  int16_t sample_buffer[],
+								  int samples);
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */

Added: freeswitch/trunk/libs/openzap/src/include/libteletone_generate.h (0 => 17141)


--- freeswitch/trunk/libs/openzap/src/include/libteletone_generate.h	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/src/include/libteletone_generate.h	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,281 @@
+/* 
+ * libteletone
+ * Copyright (C) 2005/2006, Anthony Minessale II <anthmct@yahoo.com>
+ *
+ * Copyright (c) 2007, Anthony Minessale II
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.	 IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef LIBTELETONE_GENERATE_H
+#define LIBTELETONE_GENERATE_H
+#ifdef __cplusplus
+extern "C" {
+#ifdef _doh
+}
+#endif
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#if  defined(__SUNPRO_C) || defined(__SUNPRO_CC)
+#ifndef __inline__
+#define __inline__ inline
+#endif
+#endif
+
+#ifdef _MSC_VER
+#ifndef __inline__
+#define __inline__ __inline
+#endif
+
+typedef unsigned __int64 uint64_t;
+typedef unsigned __int32 uint32_t;
+typedef unsigned __int16 uint16_t;
+typedef unsigned __int8 uint8_t;
+typedef __int64 int64_t;
+typedef __int32 int32_t;
+typedef __int16 int16_t;
+typedef __int8 int8_t;
+#else
+#include <stdint.h>
+#endif
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <math.h>
+#if !defined(powf) && !defined(_WIN64)
+extern float powf (float, float);
+#endif
+#include <string.h>
+#include <errno.h>
+#ifndef _MSC_VER
+#include <unistd.h>
+#endif
+#include <assert.h>
+#include <stdarg.h>
+#include <libteletone.h>
+
+#define TELETONE_VOL_DB_MAX 0
+#define TELETONE_VOL_DB_MIN -63
+#define MAX_PHASE_TONES 4
+
+struct teletone_dds_state {
+	uint32_t phase_rate[MAX_PHASE_TONES];
+	uint32_t scale_factor;
+	uint32_t phase_accumulator;
+	teletone_process_t tx_level;
+};
+typedef struct teletone_dds_state teletone_dds_state_t;
+
+#define SINE_TABLE_MAX 128
+#define SINE_TABLE_LEN (SINE_TABLE_MAX - 1)
+#define MAX_PHASE_ACCUMULATOR 0x10000 * 0x10000
+/* 3.14 == the max power on ulaw (alaw is 3.17) */
+/* 3.02 represents twice the power */
+#define DBM0_MAX_POWER (3.14f + 3.02f)
+
+TELETONE_API_DATA extern int16_t TELETONE_SINES[SINE_TABLE_MAX];
+
+static __inline__ int32_t teletone_dds_phase_rate(teletone_process_t tone, uint32_t rate)
+{
+	return (int32_t) ((tone * MAX_PHASE_ACCUMULATOR) / rate);
+}
+
+static __inline__ int16_t teletone_dds_state_modulate_sample(teletone_dds_state_t *dds, uint32_t pindex)
+{
+	int32_t bitmask = dds->phase_accumulator, sine_index = (bitmask >>= 23) & SINE_TABLE_LEN;
+	int16_t sample;
+
+	if (pindex >= MAX_PHASE_TONES)	{
+		pindex = 0;
+	}
+
+	if (bitmask & SINE_TABLE_MAX) {
+		sine_index = SINE_TABLE_LEN - sine_index;
+	}
+
+	sample = TELETONE_SINES[sine_index];
+	
+	if (bitmask & (SINE_TABLE_MAX * 2)) {
+		sample *= -1;
+	}
+
+	dds->phase_accumulator += dds->phase_rate[pindex];
+	return (int16_t) (sample * dds->scale_factor >> 15);
+}
+
+static __inline__ void teletone_dds_state_set_tx_level(teletone_dds_state_t *dds, float tx_level)
+{
+	dds->scale_factor = (int) (powf(10.0f, (tx_level - DBM0_MAX_POWER) / 20.0f) * (32767.0f * 1.414214f));
+	dds->tx_level = tx_level;
+}
+
+static __inline__ void teletone_dds_state_reset_accum(teletone_dds_state_t *dds)
+{
+	dds->phase_accumulator = 0;
+}
+
+static __inline__ int teletone_dds_state_set_tone(teletone_dds_state_t *dds, teletone_process_t tone, uint32_t rate, uint32_t pindex)
+{
+	if (pindex < MAX_PHASE_TONES)  {
+		dds->phase_rate[pindex] = teletone_dds_phase_rate(tone, rate);
+		return 0;
+	}
+	
+	return -1;
+}
+
+
+
+/*! \file libteletone_generate.h
+  \brief Tone Generation Routines
+
+  This module is responsible for tone generation specifics
+*/
+
+typedef int16_t teletone_audio_t;
+struct teletone_generation_session;
+typedef int (*tone_handler)(struct teletone_generation_session *ts, teletone_tone_map_t *map);
+
+/*! \brief An abstraction to store a tone generation session */
+struct teletone_generation_session {
+	/*! An array of tone mappings to character mappings */
+	teletone_tone_map_t TONES[TELETONE_TONE_RANGE];
+	/*! The number of channels the output audio should be in */
+	int channels;
+	/*! The Rate in hz of the output audio */
+	int rate;
+	/*! The duration (in samples) of the output audio */
+	int duration;
+	/*! The duration of silence to append after the initial audio is generated */
+	int wait;
+	/*! The duration (in samples) of the output audio (takes prescedence over actual duration value) */
+	int tmp_duration;
+	/*! The duration of silence to append after the initial audio is generated (takes prescedence over actual wait value)*/
+	int tmp_wait;
+	/*! Number of loops to repeat a single instruction*/
+	int loops;
+	/*! Number of loops to repeat the entire set of instructions*/
+	int LOOPS;
+	/*! Number to mutiply total samples by to determine when to begin ascent or decent e.g. 0=beginning 4=(last 25%) */
+	float decay_factor;
+	/*! Direction to perform volume increase/decrease 1/-1*/
+	int decay_direction;
+	/*! Number of samples between increase/decrease of volume */
+	int decay_step;
+	/*! Volume factor of the tone */
+	float volume;
+	/*! Debug on/off */
+	int debug;
+	/*! FILE stream to write debug data to */
+	FILE *debug_stream;
+	/*! Extra user data to attach to the session*/
+	void *user_data;
+	/*! Buffer for storing sample data (dynamic) */
+	teletone_audio_t *buffer;
+	/*! Size of the buffer */
+	int datalen;
+	/*! In-Use size of the buffer */
+	int samples;
+	/*! Callback function called during generation */
+	int dynamic;
+	tone_handler handler;
+};
+
+typedef struct teletone_generation_session teletone_generation_session_t;
+
+
+/*! 
+  \brief Assign a set of tones to a tone_session indexed by a paticular index/character
+  \param ts the tone generation session
+  \param index the index to map the tone to
+  \param ... up to TELETONE_MAX_TONES frequencies terminated by 0.0
+  \return 0
+*/
+TELETONE_API(int) teletone_set_tone(teletone_generation_session_t *ts, int index, ...);
+
+/*! 
+  \brief Assign a set of tones to a single tone map
+  \param map the map to assign the tones to
+  \param ... up to TELETONE_MAX_TONES frequencies terminated by 0.0
+  \return 0
+*/
+TELETONE_API(int) teletone_set_map(teletone_tone_map_t *map, ...);
+
+/*! 
+  \brief Initilize a tone generation session
+  \param ts the tone generation session to initilize
+  \param buflen the size of the buffer(in samples) to dynamically allocate
+  \param handler a callback function to execute when a tone generation instruction is complete
+  \param user_data optional user data to send
+  \return 0
+*/
+TELETONE_API(int) teletone_init_session(teletone_generation_session_t *ts, int buflen, tone_handler handler, void *user_data);
+
+/*! 
+  \brief Free the buffer allocated by a tone generation session
+  \param ts the tone generation session to destroy
+  \return 0
+*/
+TELETONE_API(int) teletone_destroy_session(teletone_generation_session_t *ts);
+
+/*! 
+  \brief Execute a single tone generation instruction
+  \param ts the tone generation session to consult for parameters
+  \param map the tone mapping to use for the frequencies
+  \return 0
+*/
+TELETONE_API(int) teletone_mux_tones(teletone_generation_session_t *ts, teletone_tone_map_t *map);
+
+/*! 
+  \brief Execute a tone generation script and call callbacks after each instruction
+  \param ts the tone generation session to execute on
+  \param cmd the script to execute
+  \return 0
+*/
+TELETONE_API(int) teletone_run(teletone_generation_session_t *ts, const char *cmd);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */

Added: freeswitch/trunk/libs/openzap/src/include/openzap.h (0 => 17141)


--- freeswitch/trunk/libs/openzap/src/include/openzap.h	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/src/include/openzap.h	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,797 @@
+/*
+ * Copyright (c) 2007, Anthony Minessale II
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef OPENZAP_H
+#define OPENZAP_H
+
+
+#if !defined(_XOPEN_SOURCE) && !defined(__FreeBSD__)
+#define _XOPEN_SOURCE 600
+#endif
+
+#ifndef HAVE_STRINGS_H
+#define HAVE_STRINGS_H 1
+#endif
+#ifndef HAVE_SYS_SOCKET_H
+#define HAVE_SYS_SOCKET_H 1
+#endif
+
+#ifndef __WINDOWS__
+#if defined(WIN32) || defined(WIN64) || defined(_MSC_VER) || defined(_WIN32) || defined(_WIN64)
+#define __WINDOWS__
+#endif
+#endif
+
+#ifdef _MSC_VER
+#if defined(OZ_DECLARE_STATIC)
+#define OZ_DECLARE(type)			type __stdcall
+#define OZ_DECLARE_NONSTD(type)		type __cdecl
+#define OZ_DECLARE_DATA
+#elif defined(OPENZAP_EXPORTS)
+#define OZ_DECLARE(type)			__declspec(dllexport) type __stdcall
+#define OZ_DECLARE_NONSTD(type)		__declspec(dllexport) type __cdecl
+#define OZ_DECLARE_DATA				__declspec(dllexport)
+#else
+#define OZ_DECLARE(type)			__declspec(dllimport) type __stdcall
+#define OZ_DECLARE_NONSTD(type)		__declspec(dllimport) type __cdecl
+#define OZ_DECLARE_DATA				__declspec(dllimport)
+#endif
+#define EX_DECLARE_DATA				__declspec(dllexport)
+#else
+#if (defined(__GNUC__) || defined(__SUNPRO_CC) || defined (__SUNPRO_C)) && defined(HAVE_VISIBILITY)
+#define OZ_DECLARE(type)		__attribute__((visibility("default"))) type
+#define OZ_DECLARE_NONSTD(type)	__attribute__((visibility("default"))) type
+#define OZ_DECLARE_DATA		__attribute__((visibility("default")))
+#else
+#define OZ_DECLARE(type)		type
+#define OZ_DECLARE_NONSTD(type)	type
+#define OZ_DECLARE_DATA
+#endif
+#define EX_DECLARE_DATA
+#endif
+
+#ifdef _MSC_VER
+#ifndef __inline__
+#define __inline__ __inline
+#endif
+#if (_MSC_VER >= 1400)			/* VC8+ */
+#ifndef _CRT_SECURE_NO_DEPRECATE
+#define _CRT_SECURE_NO_DEPRECATE
+#endif
+#ifndef _CRT_NONSTDC_NO_DEPRECATE
+#define _CRT_NONSTDC_NO_DEPRECATE
+#endif
+#endif
+#ifndef strcasecmp
+#define strcasecmp(s1, s2) _stricmp(s1, s2)
+#endif
+#ifndef strncasecmp
+#define strncasecmp(s1, s2, n) _strnicmp(s1, s2, n)
+#endif
+#ifndef snprintf
+#define snprintf _snprintf
+#endif
+#ifndef S_IRUSR
+#define S_IRUSR _S_IREAD
+#endif
+#ifndef S_IWUSR
+#define S_IWUSR _S_IWRITE
+#endif
+#undef HAVE_STRINGS_H
+#undef HAVE_SYS_SOCKET_H
+/* disable warning for zero length array in a struct */
+/* this will cause errors on c99 and ansi compliant compilers and will need to be fixed in the wanpipe header files */
+#pragma warning(disable:4706)
+#pragma comment(lib, "Winmm")
+#endif
+
+#define ZAP_THREAD_STACKSIZE 240 * 1024
+#define ZAP_ENUM_NAMES(_NAME, _STRINGS) static const char * _NAME [] = { _STRINGS , NULL };
+#define ZAP_STR2ENUM_P(_FUNC1, _FUNC2, _TYPE) OZ_DECLARE(_TYPE) _FUNC1 (const char *name); OZ_DECLARE(const char *) _FUNC2 (_TYPE type);
+#define ZAP_STR2ENUM(_FUNC1, _FUNC2, _TYPE, _STRINGS, _MAX)	\
+	OZ_DECLARE(_TYPE) _FUNC1 (const char *name)							\
+	{														\
+		int i;												\
+		_TYPE t = _MAX ;									\
+															\
+		for (i = 0; i < _MAX ; i++) {						\
+			if (!strcasecmp(name, _STRINGS[i])) {			\
+				t = (_TYPE) i;								\
+				break;										\
+			}												\
+		}													\
+															\
+		return t;											\
+	}														\
+	OZ_DECLARE(const char *) _FUNC2 (_TYPE type)						\
+	{														\
+		if (type > _MAX) {									\
+			type = _MAX;									\
+		}													\
+		return _STRINGS[(int)type];							\
+	}														\
+	
+#define zap_true(expr)							\
+	(expr && ( !strcasecmp(expr, "yes") ||		\
+			   !strcasecmp(expr, "on") ||		\
+			   !strcasecmp(expr, "true") ||		\
+			   !strcasecmp(expr, "enabled") ||	\
+			   !strcasecmp(expr, "active") ||	\
+			   atoi(expr))) ? 1 : 0
+
+
+#include <time.h>
+#ifndef __WINDOWS__
+#include <sys/time.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef HAVE_STRINGS_H
+#include <strings.h>
+#endif
+#include <assert.h>
+#include "zap_types.h"
+#include "hashtable.h"
+#include "zap_config.h"
+#include "g711.h"
+#include "libteletone.h"
+#include "zap_buffer.h"
+#include "zap_threadmutex.h"
+
+#ifdef __WINDOWS__
+#define zap_sleep(x) Sleep(x)
+#else
+#define zap_sleep(x) usleep(x * 1000)
+#endif
+
+#ifdef NDEBUG
+#undef assert
+#define assert(_Expression)     ((void)(_Expression))
+#endif
+
+#define ZAP_MAX_CHANNELS_PHYSICAL_SPAN 32
+#define ZAP_MAX_PHYSICAL_SPANS_PER_LOGICAL_SPAN 32
+#define ZAP_MAX_CHANNELS_SPAN ZAP_MAX_CHANNELS_PHYSICAL_SPAN * ZAP_MAX_PHYSICAL_SPANS_PER_LOGICAL_SPAN
+#define ZAP_MAX_SPANS_INTERFACE 128
+
+#define GOTO_STATUS(label,st) status = st; goto label ;
+
+#define zap_copy_string(x,y,z) strncpy(x, y, z - 1) 
+#define zap_set_string(x,y) strncpy(x, y, sizeof(x)-1) 
+#define zap_strlen_zero(s) (!s || *s == '\0')
+#define zap_strlen_zero_buf(s) (*s == '\0')
+
+
+#define zap_channel_test_feature(obj, flag) ((obj)->features & flag)
+#define zap_channel_set_feature(obj, flag) (obj)->features |= (flag)
+#define zap_channel_clear_feature(obj, flag) (obj)->features &= ~(flag)
+#define zap_channel_set_member_locked(obj, _m, _v) zap_mutex_lock(obj->mutex); obj->_m = _v; zap_mutex_unlock(obj->mutex)
+
+/*!
+  \brief Test for the existance of a flag on an arbitary object
+  \command obj the object to test
+  \command flag the or'd list of flags to test
+  \return true value if the object has the flags defined
+*/
+#define zap_test_flag(obj, flag) ((obj)->flags & flag)
+#define zap_test_pflag(obj, flag) ((obj)->pflags & flag)
+#define zap_test_sflag(obj, flag) ((obj)->sflags & flag)
+
+
+#define zap_set_alarm_flag(obj, flag) (obj)->alarm_flags |= (flag)
+#define zap_clear_alarm_flag(obj, flag) (obj)->alarm_flags &= ~(flag)
+#define zap_test_alarm_flag(obj, flag) ((obj)->alarm_flags & flag)
+
+/*!
+  \brief Set a flag on an arbitrary object
+  \command obj the object to set the flags on
+  \command flag the or'd list of flags to set
+*/
+#define zap_set_flag(obj, flag) (obj)->flags |= (flag)
+#define zap_set_flag_locked(obj, flag) assert(obj->mutex != NULL);	\
+	zap_mutex_lock(obj->mutex);										\
+	(obj)->flags |= (flag);											\
+	zap_mutex_unlock(obj->mutex);
+
+#define zap_set_pflag(obj, flag) (obj)->pflags |= (flag)
+#define zap_set_pflag_locked(obj, flag) assert(obj->mutex != NULL);	\
+	zap_mutex_lock(obj->mutex);										\
+	(obj)->pflags |= (flag);											\
+	zap_mutex_unlock(obj->mutex);
+
+#define zap_set_sflag(obj, flag) (obj)->sflags |= (flag)
+#define zap_set_sflag_locked(obj, flag) assert(obj->mutex != NULL);	\
+	zap_mutex_lock(obj->mutex);										\
+	(obj)->sflags |= (flag);											\
+	zap_mutex_unlock(obj->mutex);
+
+/*!
+  \brief Clear a flag on an arbitrary object while locked
+  \command obj the object to test
+  \command flag the or'd list of flags to clear
+*/
+#define zap_clear_flag(obj, flag) (obj)->flags &= ~(flag)
+
+#define zap_clear_flag_locked(obj, flag) assert(obj->mutex != NULL); zap_mutex_lock(obj->mutex); (obj)->flags &= ~(flag); zap_mutex_unlock(obj->mutex);
+
+#define zap_clear_pflag(obj, flag) (obj)->pflags &= ~(flag)
+
+#define zap_clear_pflag_locked(obj, flag) assert(obj->mutex != NULL); zap_mutex_lock(obj->mutex); (obj)->pflags &= ~(flag); zap_mutex_unlock(obj->mutex);
+
+#define zap_clear_sflag(obj, flag) (obj)->sflags &= ~(flag)
+
+#define zap_clear_sflag_locked(obj, flag) assert(obj->mutex != NULL); zap_mutex_lock(obj->mutex); (obj)->sflags &= ~(flag); zap_mutex_unlock(obj->mutex);
+
+
+#define zap_set_state_locked(obj, s) if ( obj->state == s ) {			\
+		if (s != ZAP_CHANNEL_STATE_HANGUP) zap_log(ZAP_LOG_WARNING, "Why bother changing state on %d:%d from %s to %s\n", obj->span_id, obj->chan_id, zap_channel_state2str(obj->state), zap_channel_state2str(s)); \
+	} else if (zap_test_flag(obj, ZAP_CHANNEL_READY)) {									\
+		int st = obj->state;											\
+		zap_channel_set_state(obj, s, 1);									\
+		if (obj->state == s) zap_log(ZAP_LOG_DEBUG, "Changing state on %d:%d from %s to %s\n", obj->span_id, obj->chan_id, zap_channel_state2str(st), zap_channel_state2str(s)); \
+		else if (!((obj->state == ZAP_CHANNEL_STATE_HANGUP && s == ZAP_CHANNEL_STATE_TERMINATING) || (obj->state == ZAP_CHANNEL_STATE_HANGUP_COMPLETE && s == ZAP_CHANNEL_STATE_HANGUP) || (obj->state == ZAP_CHANNEL_STATE_TERMINATING && s == ZAP_CHANNEL_STATE_HANGUP))) zap_log(ZAP_LOG_WARNING, "VETO Changing state on %d:%d from %s to %s\n", obj->span_id, obj->chan_id, zap_channel_state2str(st), zap_channel_state2str(s)); \
+	}
+
+#ifdef _MSC_VER
+/* The while(0) below throws a conditional expression is constant warning */
+#pragma warning(disable:4127) 
+#endif
+
+#define zap_set_state_locked_wait(obj, s) 						\
+	do {										\
+		int __safety = 100;							\
+		zap_set_state_locked(obj, s);						\
+		while(__safety-- && zap_test_flag(obj, ZAP_CHANNEL_STATE_CHANGE)) {	\
+			zap_sleep(10);							\
+		}									\
+		if(!__safety) {								\
+			zap_log(ZAP_LOG_CRIT, "State change not completed\n");		\
+		}									\
+	} while(0);
+
+#define zap_wait_for_flag_cleared(obj, flag, time) 					\
+	do {										\
+		int __safety = time;							\
+		while(__safety-- && zap_test_flag(obj, flag)) { 			\
+			zap_mutex_unlock(obj->mutex);					\
+			zap_sleep(10);							\
+			zap_mutex_lock(obj->mutex);					\
+		}									\
+		if(!__safety) {								\
+			zap_log(ZAP_LOG_CRIT, "flag %d was never cleared\n", flag);	\
+		}									\
+	} while(0);
+
+#define zap_set_state_wait(obj, s) 						\
+	do {										\
+		zap_channel_set_state(obj, s, 0);					\
+		zap_wait_for_flag_cleared(obj, ZAP_CHANNEL_STATE_CHANGE, 100);     \
+	} while(0);
+
+
+typedef enum {
+	ZAP_STATE_CHANGE_FAIL,
+	ZAP_STATE_CHANGE_SUCCESS,
+	ZAP_STATE_CHANGE_SAME,
+} zap_state_change_result_t;
+
+#define zap_set_state_r(obj, s, l, r) if ( obj->state == s ) {	\
+		if (s != ZAP_CHANNEL_STATE_HANGUP) zap_log(ZAP_LOG_WARNING, "Why bother changing state on %d:%d from %s to %s\n", obj->span_id, obj->chan_id, zap_channel_state2str(obj->state), zap_channel_state2str(s)); r = ZAP_STATE_CHANGE_SAME; \
+	} else if (zap_test_flag(obj, ZAP_CHANNEL_READY)) {					\
+		int st = obj->state;											\
+		r = (zap_channel_set_state(obj, s, l) == ZAP_SUCCESS) ? ZAP_STATE_CHANGE_SUCCESS : ZAP_STATE_CHANGE_FAIL; \
+		if (obj->state == s) {zap_log(ZAP_LOG_DEBUG, "Changing state on %d:%d from %s to %s\n", obj->span_id, obj->chan_id, zap_channel_state2str(st), zap_channel_state2str(s));} \
+		else { if (!((obj->state == ZAP_CHANNEL_STATE_HANGUP && s == ZAP_CHANNEL_STATE_TERMINATING) || (obj->state == ZAP_CHANNEL_STATE_HANGUP_COMPLETE && s == ZAP_CHANNEL_STATE_HANGUP) || (obj->state == ZAP_CHANNEL_STATE_TERMINATING && s == ZAP_CHANNEL_STATE_HANGUP))) zap_log(ZAP_LOG_WARNING, "VETO Changing state on %d:%d from %s to %s\n", obj->span_id, obj->chan_id, zap_channel_state2str(st), zap_channel_state2str(s)); } \
+	}
+
+
+#define zap_is_dtmf(key)  ((key > 47 && key < 58) || (key > 64 && key < 69) || (key > 96 && key < 101) || key == 35 || key == 42 || key == 87 || key == 119)
+
+/*!
+  \brief Copy flags from one arbitrary object to another
+  \command dest the object to copy the flags to
+  \command src the object to copy the flags from
+  \command flags the flags to copy
+*/
+#define zap_copy_flags(dest, src, flags) (dest)->flags &= ~(flags);	(dest)->flags |= ((src)->flags & (flags))
+
+/*!
+  \brief Free a pointer and set it to NULL unless it already is NULL
+  \command it the pointer
+*/
+#define zap_safe_free(it) if (it) {free(it);it=NULL;}
+
+#define zap_socket_close(it) if (it > -1) { close(it); it = -1;}
+
+
+struct zap_stream_handle {
+	zap_stream_handle_write_function_t write_function;
+	zap_stream_handle_raw_write_function_t raw_write_function;
+	void *data;
+	void *end;
+	zap_size_t data_size;
+	zap_size_t data_len;
+	zap_size_t alloc_len;
+	zap_size_t alloc_chunk;
+};
+
+
+OZ_DECLARE_NONSTD(zap_status_t) zap_console_stream_raw_write(zap_stream_handle_t *handle, uint8_t *data, zap_size_t datalen);
+OZ_DECLARE_NONSTD(zap_status_t) zap_console_stream_write(zap_stream_handle_t *handle, const char *fmt, ...);
+
+#define ZAP_CMD_CHUNK_LEN 1024
+#define ZAP_STANDARD_STREAM(s) memset(&s, 0, sizeof(s)); s.data = malloc(ZAP_CMD_CHUNK_LEN); \
+	assert(s.data);														\
+	memset(s.data, 0, ZAP_CMD_CHUNK_LEN);								\
+	s.end = s.data;														\
+	s.data_size = ZAP_CMD_CHUNK_LEN;									\
+	s.write_function = zap_console_stream_write;						\
+	s.raw_write_function = zap_console_stream_raw_write;				\
+	s.alloc_len = ZAP_CMD_CHUNK_LEN;									\
+	s.alloc_chunk = ZAP_CMD_CHUNK_LEN
+
+struct zap_event {
+	zap_event_type_t e_type;
+	uint32_t enum_id;
+	zap_channel_t *channel;
+	void *data;
+};
+
+#define ZAP_TOKEN_STRLEN 128
+#define ZAP_MAX_TOKENS 10
+
+static __inline__ char *zap_clean_string(char *s)
+{
+	char *p;
+
+	for (p = s; p && *p; p++) {
+		uint8_t x = (uint8_t) *p;
+		if (x < 32 || x > 127) {
+			*p = ' ';
+		}
+	}
+
+	return s;
+}
+
+struct zap_bitstream {
+	uint8_t *data;
+	uint32_t datalen;
+	uint32_t byte_index;
+	uint8_t bit_index;
+	int8_t endian;
+	uint8_t top;
+	uint8_t bot;
+	uint8_t ss;
+	uint8_t ssv;
+};
+
+struct zap_fsk_data_state {
+	dsp_fsk_handle_t *fsk1200_handle;
+	uint8_t init;
+	uint8_t *buf;
+	size_t bufsize;
+	zap_size_t blen;
+	zap_size_t bpos;
+	zap_size_t dlen;
+	zap_size_t ppos;
+	int checksum;
+};
+
+struct zap_fsk_modulator {
+	teletone_dds_state_t dds;
+	zap_bitstream_t bs;
+	uint32_t carrier_bits_start;
+	uint32_t carrier_bits_stop;
+	uint32_t chan_sieze_bits;
+	uint32_t bit_factor;
+	uint32_t bit_accum;
+	uint32_t sample_counter;
+	int32_t samples_per_bit;
+	int32_t est_bytes;
+	fsk_modem_types_t modem_type;
+	zap_fsk_data_state_t *fsk_data;
+	zap_fsk_write_sample_t write_sample_callback;
+	void *user_data;
+	int16_t sample_buffer[64];
+};
+
+/**
+ * Type Of Number (TON)
+ */
+typedef enum {
+	ZAP_TON_UNKNOWN = 0,
+	ZAP_TON_INTERNATIONAL,
+	ZAP_TON_NATIONAL,
+	ZAP_TON_NETWORK_SPECIFIC,
+	ZAP_TON_SUBSCRIBER_NUMBER,
+	ZAP_TON_ABBREVIATED_NUMBER,
+	ZAP_TON_RESERVED,
+	ZAP_TON_INVALID = 255
+} zap_ton_t;
+
+/**
+ * Numbering Plan Identification (NPI)
+ */
+typedef enum {
+	ZAP_NPI_UNKNOWN = 0,
+	ZAP_NPI_ISDN = 1,
+	ZAP_NPI_DATA = 3,
+	ZAP_NPI_TELEX = 4,
+	ZAP_NPI_NATIONAL = 8,
+	ZAP_NPI_PRIVATE = 9,
+	ZAP_NPI_RESERVED = 10,
+	ZAP_NPI_INVALID = 255
+} zap_npi_t;
+
+typedef struct {
+	char digits[25];
+	uint8_t type;
+	uint8_t plan;
+} zap_number_t;
+
+typedef enum {
+	ZAP_CALLER_STATE_DIALING,
+	ZAP_CALLER_STATE_SUCCESS,
+	ZAP_CALLER_STATE_FAIL
+} zap_caller_state_t;
+
+struct zap_caller_data {
+	char cid_date[8];
+	char cid_name[80];
+	zap_number_t cid_num;
+	zap_number_t ani;
+	zap_number_t dnis;
+	zap_number_t rdnis;
+	char aniII[25];
+	uint8_t screen;
+	uint8_t pres;
+	char collected[25];
+	int CRV;
+	int hangup_cause;	
+	uint8_t raw_data[1024];
+	uint32_t raw_data_len;
+	uint32_t flags;
+	zap_caller_state_t call_state;
+	uint32_t chan_id;
+};
+
+typedef enum {
+	ZAP_TYPE_NONE,
+	ZAP_TYPE_SPAN = 0xFF,
+	ZAP_TYPE_CHANNEL
+} zap_data_type_t;
+
+/* 2^8 table size, one for each byte value */
+#define ZAP_GAINS_TABLE_SIZE 256
+struct zap_channel {
+	zap_data_type_t data_type;
+	uint32_t span_id;
+	uint32_t chan_id;
+	uint32_t physical_span_id;
+	uint32_t physical_chan_id;
+	uint32_t rate;
+	uint32_t extra_id;
+	zap_chan_type_t type;
+	zap_socket_t sockfd;
+	zap_channel_flag_t flags;
+	uint32_t pflags;
+	uint32_t sflags;
+	zap_alarm_flag_t alarm_flags;
+	zap_channel_feature_t features;
+	zap_codec_t effective_codec;
+	zap_codec_t native_codec;
+	uint32_t effective_interval;
+	uint32_t native_interval;
+	uint32_t packet_len;
+	zap_channel_state_t state;
+	zap_channel_state_t last_state;
+	zap_channel_state_t init_state;
+	zap_mutex_t *mutex;
+	teletone_dtmf_detect_state_t dtmf_detect;
+	uint32_t buffer_delay;
+	zap_event_t event_header;
+	char last_error[256];
+	zio_event_cb_t event_callback;
+	uint32_t skip_read_frames;
+	zap_buffer_t *dtmf_buffer;
+	zap_buffer_t *gen_dtmf_buffer;
+	zap_buffer_t *pre_buffer;
+	zap_buffer_t *digit_buffer;
+	zap_buffer_t *fsk_buffer;
+	zap_mutex_t *pre_buffer_mutex;
+	uint32_t dtmf_on;
+	uint32_t dtmf_off;
+	char *dtmf_hangup_buf;
+	teletone_generation_session_t tone_session;
+	zap_time_t last_event_time;
+	zap_time_t ring_time;
+	char tokens[ZAP_MAX_TOKENS+1][ZAP_TOKEN_STRLEN];
+	uint8_t needed_tones[ZAP_TONEMAP_INVALID];
+	uint8_t detected_tones[ZAP_TONEMAP_INVALID];
+	zap_tonemap_t last_detected_tone;	
+	uint32_t token_count;
+	char chan_name[128];
+	char chan_number[32];
+	zap_filehandle_t fds[2];
+	zap_fsk_data_state_t fsk;
+	uint8_t fsk_buf[80];
+	uint32_t ring_count;
+	void *mod_data;
+	void *call_data;
+	struct zap_caller_data caller_data;
+	struct zap_span *span;
+	struct zap_io_interface *zio;
+	zap_hash_t *variable_hash;
+	unsigned char rx_cas_bits;
+	uint32_t pre_buffer_size;
+	unsigned char rxgain_table[ZAP_GAINS_TABLE_SIZE];
+	unsigned char txgain_table[ZAP_GAINS_TABLE_SIZE];
+	float rxgain;
+	float txgain;
+};
+
+
+struct zap_sigmsg {
+	zap_signal_event_t event_id;
+	uint32_t chan_id;
+	uint32_t span_id;
+	zap_channel_t *channel;
+	void *raw_data;
+	uint32_t raw_data_len;
+};
+
+
+struct zap_span {
+	zap_data_type_t data_type;
+	char *name;
+	uint32_t span_id;
+	uint32_t chan_count;
+	zap_span_flag_t flags;
+	struct zap_io_interface *zio;
+	zio_event_cb_t event_callback;
+	zap_mutex_t *mutex;
+	zap_trunk_type_t trunk_type;
+	zap_analog_start_type_t start_type;
+	zap_signal_type_t signal_type;
+	void *signal_data;
+	zio_signal_cb_t signal_cb;
+	zap_event_t event_header;
+	char last_error[256];
+	char tone_map[ZAP_TONEMAP_INVALID+1][ZAP_TONEMAP_LEN];
+	teletone_tone_map_t tone_detect_map[ZAP_TONEMAP_INVALID+1];
+	teletone_multi_tone_t tone_finder[ZAP_TONEMAP_INVALID+1];
+	zap_channel_t *channels[ZAP_MAX_CHANNELS_SPAN+1];
+	zio_channel_outgoing_call_t outgoing_call;
+	zio_channel_request_t channel_request;
+	zap_span_start_t start;
+	zap_span_stop_t stop;
+	void *mod_data;
+	char *type;
+	char *dtmf_hangup;
+	size_t dtmf_hangup_len;
+	int suggest_chan_id;
+	zap_state_map_t *state_map;
+	zap_caller_data_t default_caller_data;
+	struct zap_span *next;
+};
+
+
+OZ_DECLARE_DATA extern zap_logger_t zap_log;
+
+struct zap_io_interface {
+	const char *name;
+	zio_configure_span_t configure_span;
+	zio_configure_t configure;
+	zio_open_t open;
+	zio_close_t close;
+	zio_channel_destroy_t channel_destroy;
+	zio_span_destroy_t span_destroy;
+	zio_get_alarms_t get_alarms;
+	zio_command_t command;
+	zio_wait_t wait;
+	zio_read_t read;
+	zio_write_t write;
+	zio_span_poll_event_t poll_event;
+	zio_span_next_event_t next_event;
+	zio_api_t api;
+};
+
+
+OZ_DECLARE(zap_size_t) zap_fsk_modulator_generate_bit(zap_fsk_modulator_t *fsk_trans, int8_t bit, int16_t *buf, zap_size_t buflen);
+OZ_DECLARE(int32_t) zap_fsk_modulator_generate_carrier_bits(zap_fsk_modulator_t *fsk_trans, uint32_t bits);
+OZ_DECLARE(void) zap_fsk_modulator_generate_chan_sieze(zap_fsk_modulator_t *fsk_trans);
+OZ_DECLARE(void) zap_fsk_modulator_send_data(zap_fsk_modulator_t *fsk_trans);
+#define zap_fsk_modulator_send_all(_it) zap_fsk_modulator_generate_chan_sieze(_it); \
+	zap_fsk_modulator_generate_carrier_bits(_it, _it->carrier_bits_start); \
+	zap_fsk_modulator_send_data(_it); \
+	zap_fsk_modulator_generate_carrier_bits(_it, _it->carrier_bits_stop)
+
+OZ_DECLARE(zap_status_t) zap_fsk_modulator_init(zap_fsk_modulator_t *fsk_trans,
+									fsk_modem_types_t modem_type,
+									uint32_t sample_rate,
+									zap_fsk_data_state_t *fsk_data,
+									float db_level,
+									uint32_t carrier_bits_start,
+									uint32_t carrier_bits_stop,
+									uint32_t chan_sieze_bits,
+									zap_fsk_write_sample_t write_sample_callback,
+									void *user_data);
+OZ_DECLARE(int8_t) zap_bitstream_get_bit(zap_bitstream_t *bsp);
+OZ_DECLARE(void) zap_bitstream_init(zap_bitstream_t *bsp, uint8_t *data, uint32_t datalen, zap_endian_t endian, uint8_t ss);
+OZ_DECLARE(zap_status_t) zap_fsk_data_parse(zap_fsk_data_state_t *state, zap_size_t *type, char **data, zap_size_t *len);
+OZ_DECLARE(zap_status_t) zap_fsk_demod_feed(zap_fsk_data_state_t *state, int16_t *data, size_t samples);
+OZ_DECLARE(zap_status_t) zap_fsk_demod_destroy(zap_fsk_data_state_t *state);
+OZ_DECLARE(int) zap_fsk_demod_init(zap_fsk_data_state_t *state, int rate, uint8_t *buf, size_t bufsize);
+OZ_DECLARE(zap_status_t) zap_fsk_data_init(zap_fsk_data_state_t *state, uint8_t *data, uint32_t datalen);
+OZ_DECLARE(zap_status_t) zap_fsk_data_add_mdmf(zap_fsk_data_state_t *state, zap_mdmf_type_t type, const uint8_t *data, uint32_t datalen);
+OZ_DECLARE(zap_status_t) zap_fsk_data_add_checksum(zap_fsk_data_state_t *state);
+OZ_DECLARE(zap_status_t) zap_fsk_data_add_sdmf(zap_fsk_data_state_t *state, const char *date, char *number);
+OZ_DECLARE(zap_status_t) zap_channel_outgoing_call(zap_channel_t *zchan);
+OZ_DECLARE(void) zap_channel_rotate_tokens(zap_channel_t *zchan);
+OZ_DECLARE(void) zap_channel_clear_detected_tones(zap_channel_t *zchan);
+OZ_DECLARE(void) zap_channel_clear_needed_tones(zap_channel_t *zchan);
+OZ_DECLARE(zap_status_t) zap_channel_get_alarms(zap_channel_t *zchan);
+OZ_DECLARE(zap_status_t) zap_channel_send_fsk_data(zap_channel_t *zchan, zap_fsk_data_state_t *fsk_data, float db_level);
+OZ_DECLARE(zap_status_t) zap_channel_clear_token(zap_channel_t *zchan, const char *token);
+OZ_DECLARE(void) zap_channel_replace_token(zap_channel_t *zchan, const char *old_token, const char *new_token);
+OZ_DECLARE(zap_status_t) zap_channel_add_token(zap_channel_t *zchan, char *token, int end);
+OZ_DECLARE(zap_status_t) zap_channel_set_state(zap_channel_t *zchan, zap_channel_state_t state, int lock);
+OZ_DECLARE(zap_status_t) zap_span_load_tones(zap_span_t *span, const char *mapname);
+OZ_DECLARE(zap_size_t) zap_channel_dequeue_dtmf(zap_channel_t *zchan, char *dtmf, zap_size_t len);
+OZ_DECLARE(zap_status_t) zap_channel_queue_dtmf(zap_channel_t *zchan, const char *dtmf);
+OZ_DECLARE(void) zap_channel_flush_dtmf(zap_channel_t *zchan);
+OZ_DECLARE(zap_time_t) zap_current_time_in_ms(void);
+OZ_DECLARE(zap_status_t) zap_span_poll_event(zap_span_t *span, uint32_t ms);
+OZ_DECLARE(zap_status_t) zap_span_next_event(zap_span_t *span, zap_event_t **event);
+OZ_DECLARE(zap_status_t) zap_span_find(uint32_t id, zap_span_t **span);
+OZ_DECLARE(zap_status_t) zap_span_create(zap_io_interface_t *zio, zap_span_t **span, const char *name);
+OZ_DECLARE(zap_status_t) zap_span_close_all(void);
+OZ_DECLARE(zap_status_t) zap_span_add_channel(zap_span_t *span, zap_socket_t sockfd, zap_chan_type_t type, zap_channel_t **chan);
+OZ_DECLARE(zap_status_t) zap_span_set_event_callback(zap_span_t *span, zio_event_cb_t event_callback);
+OZ_DECLARE(zap_status_t) zap_channel_set_event_callback(zap_channel_t *zchan, zio_event_cb_t event_callback);
+OZ_DECLARE(zap_status_t) zap_channel_open(uint32_t span_id, uint32_t chan_id, zap_channel_t **zchan);
+OZ_DECLARE(zap_status_t) zap_channel_open_chan(zap_channel_t *zchan);
+OZ_DECLARE(zap_status_t) zap_span_channel_use_count(zap_span_t *span, uint32_t *count);
+OZ_DECLARE(zap_status_t) zap_channel_open_any(uint32_t span_id, zap_direction_t direction, zap_caller_data_t *caller_data, zap_channel_t **zchan);
+OZ_DECLARE(zap_status_t) zap_channel_close(zap_channel_t **zchan);
+OZ_DECLARE(zap_status_t) zap_channel_done(zap_channel_t *zchan);
+OZ_DECLARE(zap_status_t) zap_channel_use(zap_channel_t *zchan);
+OZ_DECLARE(zap_status_t) zap_channel_command(zap_channel_t *zchan, zap_command_t command, void *obj);
+OZ_DECLARE(zap_status_t) zap_channel_wait(zap_channel_t *zchan, zap_wait_flag_t *flags, int32_t to);
+OZ_DECLARE(zap_status_t) zap_channel_read(zap_channel_t *zchan, void *data, zap_size_t *datalen);
+OZ_DECLARE(void) zap_generate_sln_silence(int16_t *data, uint32_t samples, uint32_t divisor);
+OZ_DECLARE(zap_status_t) zap_channel_write(zap_channel_t *zchan, void *data, zap_size_t datasize, zap_size_t *datalen);
+OZ_DECLARE(zap_status_t) zap_channel_add_var(zap_channel_t *zchan, const char *var_name, const char *value);
+OZ_DECLARE(const char *) zap_channel_get_var(zap_channel_t *zchan, const char *var_name);
+OZ_DECLARE(zap_status_t) zap_channel_clear_vars(zap_channel_t *zchan);
+OZ_DECLARE(zap_status_t) zap_global_init(void);
+OZ_DECLARE(zap_status_t) zap_global_destroy(void);
+OZ_DECLARE(void) zap_global_set_logger(zap_logger_t logger);
+OZ_DECLARE(void) zap_global_set_default_logger(int level);
+OZ_DECLARE(uint32_t) zap_separate_string(char *buf, char delim, char **array, int arraylen);
+OZ_DECLARE(void) print_bits(uint8_t *b, int bl, char *buf, int blen, int e, uint8_t ss);
+OZ_DECLARE(void) print_hex_bytes(uint8_t *data, zap_size_t dlen, char *buf, zap_size_t blen);
+OZ_DECLARE_NONSTD(int) zap_hash_equalkeys(void *k1, void *k2);
+OZ_DECLARE_NONSTD(uint32_t) zap_hash_hashfromstring(void *ky);
+OZ_DECLARE(uint32_t) zap_running(void);
+OZ_DECLARE(zap_status_t) zap_channel_complete_state(zap_channel_t *zchan);
+OZ_DECLARE(zap_status_t) zap_channel_init(zap_channel_t *zchan);
+OZ_DECLARE(int) zap_load_modules(void);
+OZ_DECLARE(zap_status_t) zap_unload_modules(void);
+OZ_DECLARE(zap_status_t) zap_configure_span(const char *type, zap_span_t *span, zio_signal_cb_t sig_cb, ...);
+OZ_DECLARE(zap_status_t) zap_span_start(zap_span_t *span);
+OZ_DECLARE(zap_status_t) zap_span_stop(zap_span_t *span);
+OZ_DECLARE(zap_status_t) zap_span_send_signal(zap_span_t *span, zap_sigmsg_t *sigmsg);
+OZ_DECLARE(int) zap_load_module(const char *name);
+OZ_DECLARE(int) zap_load_module_assume(const char *name);
+OZ_DECLARE(zap_status_t) zap_span_find_by_name(const char *name, zap_span_t **span);
+OZ_DECLARE(char *) zap_api_execute(const char *type, const char *cmd);
+OZ_DECLARE(int) zap_vasprintf(char **ret, const char *fmt, va_list ap);
+OZ_DECLARE(zap_status_t) zap_channel_set_caller_data(zap_channel_t *zchan, zap_caller_data_t *caller_data);
+OZ_DECLARE(void) zap_cpu_monitor_disable(void);
+
+ZIO_CODEC_FUNCTION(zio_slin2ulaw);
+ZIO_CODEC_FUNCTION(zio_ulaw2slin);
+ZIO_CODEC_FUNCTION(zio_slin2alaw);
+ZIO_CODEC_FUNCTION(zio_alaw2slin);
+ZIO_CODEC_FUNCTION(zio_ulaw2alaw);
+ZIO_CODEC_FUNCTION(zio_alaw2ulaw);
+
+#ifdef DEBUG_LOCKS
+#define zap_mutex_lock(_x) printf("++++++lock %s:%d\n", __FILE__, __LINE__) && _zap_mutex_lock(_x)
+#define zap_mutex_trylock(_x) printf("++++++try %s:%d\n", __FILE__, __LINE__) && _zap_mutex_trylock(_x)
+#define zap_mutex_unlock(_x) printf("------unlock %s:%d\n", __FILE__, __LINE__) && _zap_mutex_unlock(_x)
+#else 
+#define zap_mutex_lock(_x) _zap_mutex_lock(_x)
+#define zap_mutex_trylock(_x) _zap_mutex_trylock(_x)
+#define zap_mutex_unlock(_x) _zap_mutex_unlock(_x)
+#endif
+
+
+static __inline__ void zap_set_state_all(zap_span_t *span, zap_channel_state_t state)
+{
+	uint32_t j;
+	zap_mutex_lock(span->mutex);
+	for(j = 1; j <= span->chan_count; j++) {
+		zap_set_state_locked((span->channels[j]), state);
+	}
+	zap_mutex_unlock(span->mutex);
+}
+
+static __inline__ int zap_check_state_all(zap_span_t *span, zap_channel_state_t state)
+{
+	uint32_t j;
+	for(j = 1; j <= span->chan_count; j++) {
+		if (span->channels[j]->state != state || zap_test_flag(span->channels[j], ZAP_CHANNEL_STATE_CHANGE)) {
+			return 0;
+		}
+	}
+
+	return 1;
+}
+
+static __inline__ void zap_set_flag_all(zap_span_t *span, uint32_t flag)
+{
+	uint32_t j;
+	zap_mutex_lock(span->mutex);
+	for(j = 1; j <= span->chan_count; j++) {
+		zap_set_flag_locked((span->channels[j]), flag);
+	}
+	zap_mutex_unlock(span->mutex);
+}
+
+static __inline__ void zap_clear_flag_all(zap_span_t *span, uint32_t flag)
+{
+	uint32_t j;
+	zap_mutex_lock(span->mutex);
+	for(j = 1; j <= span->chan_count; j++) {
+		zap_clear_flag_locked((span->channels[j]), flag);
+	}
+	zap_mutex_unlock(span->mutex);
+}
+
+#endif
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */

Added: freeswitch/trunk/libs/openzap/src/include/sangoma_tdm_api.h (0 => 17141)


--- freeswitch/trunk/libs/openzap/src/include/sangoma_tdm_api.h	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/src/include/sangoma_tdm_api.h	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,321 @@
+/*****************************************************************************
+ * sangoma_tdm_api.h	Sangoma TDM API Portability functions
+ *
+ * Author(s):	Anthony Minessale II <anthmct@yahoo.com>
+ *              Nenad Corbic <ncorbic@sangoma.com>
+ *				Michael Jerris <mike@jerris.com>
+ *				David Rokhvarg <davidr@sangoma.com>
+ *
+ * Copyright:	(c) 2006 Nenad Corbic <ncorbic@sangoma.com>
+ *                       Anthony Minessale II
+ *				(c) 1984-2007 Sangoma Technologies Inc.
+ *
+ * ============================================================================
+ */
+
+#ifndef _SANGOMA_TDM_API_H
+#define _SANGOMA_TDM_API_H
+
+/* This entire block of defines and includes from this line, through #define FNAME_LEN probably dont belong here */
+/* most of them probably belong in wanpipe_defines.h, then each header file listed included below properly included */
+/* in the header files that depend on them, leaving only the include for wanpipe_tdm_api.h left in this file or */
+/* possibly integrating the rest of this file diretly into wanpipe_tdm_api.h */
+#ifndef __WINDOWS__
+#if defined(WIN32) || defined(WIN64) || defined(_MSC_VER) || defined(_WIN32)
+#define __WINDOWS__
+#endif /* defined(WIN32) || defined(WIN64) || defined(_MSC_VER) || defined(_WIN32) */
+#endif /* ndef __WINDOWS__ */
+
+#if defined(__WINDOWS__)
+#if defined(_MSC_VER)
+/* disable some warnings caused by wanpipe headers that will need to be fixed in those headers */
+#pragma warning(disable:4201 4214)
+
+/* sang_api.h(74) : warning C4201: nonstandard extension used : nameless struct/union */
+
+/* wanpipe_defines.h(219) : warning C4214: nonstandard extension used : bit field types other than int */
+/* wanpipe_defines.h(220) : warning C4214: nonstandard extension used : bit field types other than int */
+/* this will break for any compilers that are strict ansi or strict c99 */
+
+/* The following definition for that struct should resolve this warning and work for 32 and 64 bit */
+#if 0
+struct iphdr {
+	
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+	unsigned    ihl:4,
+		version:4;
+#elif defined (__BIG_ENDIAN_BITFIELD)
+	unsigned    version:4,
+		ihl:4;
+#else
+# error  "unknown byteorder!"
+#endif
+	unsigned    tos:8;
+	unsigned		tot_len:16;
+	unsigned		id:16;
+	unsigned		frag_off:16;
+	__u8    ttl;
+	__u8    protocol;
+	__u16   check;
+	__u32   saddr;
+	__u32   daddr;
+	/*The options start here. */
+};
+#endif /* #if 0 */
+
+#define __inline__ __inline
+#endif /* defined(_MSC_VER) */
+#include <windows.h>
+/* do we like the name WP_INVALID_SOCKET or should it be changed? */
+#define WP_INVALID_SOCKET INVALID_HANDLE_VALUE
+#else /* defined(__WINDOWS__) */ 
+#define WP_INVALID_SOCKET -1
+#include <stropts.h>
+#include <poll.h>
+#include <sys/socket.h>
+#endif
+
+#include <wanpipe_defines.h>
+#include <wanpipe_cfg.h>
+#include <wanpipe_tdm_api.h>
+#include <sdla_te1_pmc.h>
+#ifdef __WINDOWS__
+#include <sang_status_defines.h>
+#include <sang_api.h>
+#endif
+#include <sdla_aft_te1.h>
+
+#define FNAME_LEN	50
+
+
+#if defined(__WINDOWS__)
+/* This might be broken on windows, as POLL_EVENT_TELEPHONY seems to be commented out in sang_api.h.. it should be added to POLLPRI */
+#define POLLPRI (POLL_EVENT_LINK_STATE | POLL_EVENT_LINK_CONNECT | POLL_EVENT_LINK_DISCONNECT)
+#endif
+
+/* return -1 for error, 0 for timeout or 1 for success. *flags is set to the poll evetns POLLIN | POLLOUT | POLLPRI based on the result of the poll */
+/* on windows we actually have POLLPRI defined with several events, so we could theoretically poll */
+/* for specific events.  Is there any way to do this on *nix as well? */ 
+
+/* a cross platform way to poll on an actual pollset (span and/or list of spans) will probably also be needed for analog */
+/* so we can have one analong handler thread that will deal with all the idle analog channels for events */
+/* the alternative would be for the driver to provide one socket for all of the oob events for all analog channels */
+static __inline__ int tdmv_api_wait_socket(sng_fd_t fd, int timeout, int *flags)
+{
+#if defined(__WINDOWS__)
+	DWORD ln;
+	API_POLL_STRUCT	api_poll;
+
+	memset(&api_poll, 0x00, sizeof(API_POLL_STRUCT));
+	
+	api_poll.user_flags_bitmap = *flags;
+	api_poll.timeout = timeout;
+
+	if (!DeviceIoControl(
+						 fd,
+						 IoctlApiPoll,
+						 (LPVOID)NULL,
+						 0L,
+						 (LPVOID)&api_poll,
+						 sizeof(API_POLL_STRUCT),
+						 (LPDWORD)(&ln),
+						 (LPOVERLAPPED)NULL)) {
+		return -1;
+	}
+
+	*flags = 0;
+
+	switch(api_poll.operation_status)
+		{
+		case SANG_STATUS_RX_DATA_AVAILABLE:
+			break;
+
+		case SANG_STATUS_RX_DATA_TIMEOUT:
+			return 0;
+
+		default:
+			return -1;
+		}
+
+	if (api_poll.poll_events_bitmap == 0){
+		return -1;
+	}
+
+	if (api_poll.poll_events_bitmap & POLL_EVENT_TIMEOUT) {
+		return 0;
+	}
+
+	*flags = api_poll.poll_events_bitmap;
+
+	return 1;
+#else
+    struct pollfd pfds[1];
+    int res;
+
+    memset(&pfds[0], 0, sizeof(pfds[0]));
+    pfds[0].fd = fd;
+    pfds[0].events = *flags;
+    res = poll(pfds, 1, timeout);
+	*flags = 0;
+
+	if (pfds[0].revents & POLLERR) {
+		res = -1;
+	}
+
+	if (res > 0) {
+		*flags = pfds[0].revents;
+	}
+
+    return res;
+#endif
+}
+
+/* on windows right now, there is no way to specify if we want to read events here or not, we allways get them here */
+/* we need some what to select if we are reading regular tdm msgs or events */
+/* need to either have 2 functions, 1 for events, 1 for regural read, or a flag on this function to choose */
+/* 2 functions preferred.  Need implementation for the event function for both nix and windows that is threadsafe */
+static __inline__ int tdmv_api_readmsg_tdm(sng_fd_t fd, void *hdrbuf, int hdrlen, void *databuf, int datalen)
+{
+	/* What do we need to do here to avoid having to do all */
+	/* the memcpy's on windows and still maintain api compat with nix */
+	int rx_len=0;
+#if defined(__WINDOWS__)
+	static RX_DATA_STRUCT	rx_data;
+	api_header_t			*pri;
+	wp_tdm_api_rx_hdr_t		*tdm_api_rx_hdr;
+	wp_tdm_api_rx_hdr_t		*user_buf = (wp_tdm_api_rx_hdr_t*)hdrbuf;
+	DWORD ln;
+
+	if (hdrlen != sizeof(wp_tdm_api_rx_hdr_t)){
+		return -1;
+	}
+
+	if (!DeviceIoControl(
+						 fd,
+						 IoctlReadCommand,
+						 (LPVOID)NULL,
+						 0L,
+						 (LPVOID)&rx_data,
+						 sizeof(RX_DATA_STRUCT),
+						 (LPDWORD)(&ln),
+						 (LPOVERLAPPED)NULL
+						 )){
+		return -1;
+	}
+
+	pri = &rx_data.api_header;
+	tdm_api_rx_hdr = (wp_tdm_api_rx_hdr_t*)rx_data.data;
+
+	user_buf->wp_tdm_api_event_type = pri->operation_status;
+
+	switch(pri->operation_status)
+		{
+		case SANG_STATUS_RX_DATA_AVAILABLE:
+			if (pri->data_length > datalen){
+				break;
+			}
+			memcpy(databuf, rx_data.data, pri->data_length);
+			rx_len = pri->data_length;
+			break;
+
+		default:
+			break;
+		}
+
+#else
+	struct msghdr msg;
+	struct iovec iov[2];
+
+	memset(&msg,0,sizeof(struct msghdr));
+
+	iov[0].iov_len=hdrlen;
+	iov[0].iov_base=hdrbuf;
+
+	iov[1].iov_len=datalen;
+	iov[1].iov_base=databuf;
+
+	msg.msg_iovlen=2;
+	msg.msg_iov=iov;
+
+	rx_len = read(fd,&msg,datalen+hdrlen);
+
+	if (rx_len <= sizeof(wp_tdm_api_rx_hdr_t)){
+		return -EINVAL;
+	}
+
+	rx_len-=sizeof(wp_tdm_api_rx_hdr_t);
+#endif
+    return rx_len;
+}                    
+
+static __inline__ int tdmv_api_writemsg_tdm(sng_fd_t fd, void *hdrbuf, int hdrlen, void *databuf, unsigned short datalen)
+{
+	/* What do we need to do here to avoid having to do all */
+	/* the memcpy's on windows and still maintain api compat with nix */
+	int bsent = 0;
+#if defined(__WINDOWS__)
+	static TX_DATA_STRUCT	local_tx_data;
+	api_header_t			*pri;
+	DWORD ln;
+
+	/* Are these really not needed or used???  What about for nix?? */
+	(void)hdrbuf;
+	(void)hdrlen;
+
+	pri = &local_tx_data.api_header;
+
+	pri->data_length = datalen;
+	memcpy(local_tx_data.data, databuf, pri->data_length);
+
+	if (!DeviceIoControl(
+						 fd,
+						 IoctlWriteCommand,
+						 (LPVOID)&local_tx_data,
+						 (ULONG)sizeof(TX_DATA_STRUCT),
+						 (LPVOID)&local_tx_data,
+						 sizeof(TX_DATA_STRUCT),
+						 (LPDWORD)(&ln),
+						 (LPOVERLAPPED)NULL
+						 )){
+		return -1;
+	}
+
+	if (local_tx_data.api_header.operation_status == SANG_STATUS_SUCCESS) {
+		bsent = datalen;
+	}
+#else
+	struct msghdr msg;
+	struct iovec iov[2];
+
+	memset(&msg,0,sizeof(struct msghdr));
+
+	iov[0].iov_len = hdrlen;
+	iov[0].iov_base = hdrbuf;
+
+	iov[1].iov_len = datalen;
+	iov[1].iov_base = databuf;
+
+	msg.msg_iovlen = 2;
+	msg.msg_iov = iov;
+
+	bsent = write(fd, &msg, datalen + hdrlen);
+	if (bsent > 0){
+		bsent -= sizeof(wp_tdm_api_tx_hdr_t);
+	}
+#endif
+	return bsent;
+}
+
+#endif /* _SANGOMA_TDM_API_H */
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
+

Added: freeswitch/trunk/libs/openzap/src/include/uart.h (0 => 17141)


--- freeswitch/trunk/libs/openzap/src/include/uart.h	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/src/include/uart.h	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,76 @@
+/*
+ *	uart.h
+ *
+ *	Copyright (c) 2005 Robert Krten.  All Rights Reserved.
+ *
+ *	Redistribution and use in source and binary forms, with or without
+ *	modification, are permitted provided that the following conditions
+ *	are met:
+ *
+ *	1. Redistributions of source code must retain the above copyright
+ *	   notice, this list of conditions and the following disclaimer.
+ *	2. Redistributions in binary form must reproduce the above copyright
+ *	   notice, this list of conditions and the following disclaimer in the
+ *	   documentation and/or other materials provided with the distribution.
+ *
+ *	THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
+ *	ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ *	IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ *	ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE
+ *	FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ *	DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ *	OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ *	HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ *	LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ *	OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ *	SUCH DAMAGE.
+ *
+ *	This module contains the manifest constants and declarations for
+ *	the UART module.
+ *
+ *	2005 06 19	R. Krten		created
+*/
+
+#ifndef	__UART_H__
+#define	__UART_H__
+
+typedef void (*bytehandler_func_t) (void *, int);
+typedef void (*bithandler_func_t) (void *, int);
+
+
+typedef struct dsp_uart_attr_s
+{
+	bytehandler_func_t	bytehandler;					/* byte handler */
+	void				*bytehandler_arg;				/* arbitrary ID passed to bytehandler as first argument */
+}	dsp_uart_attr_t;
+
+typedef struct
+{
+	dsp_uart_attr_t		attr;
+	int					have_start;						/* wait for start bit to show up */
+	int					data;							/* data buffer */
+	int					nbits;							/* number of bits accumulated so far */
+}	dsp_uart_handle_t;
+
+/*
+ *	Function prototypes
+ *
+ *	General calling order is:
+ *		a) create the attributes structure (dsp_uart_attr_init)
+ *		b) initialize fields in the attributes structure (dsp_uart_attr_set_*)
+ *		c) create a Bell-202 handle (dsp_uart_create)
+ *		d) feed bits through dsp_uart_bit_handler
+*/
+
+void					dsp_uart_attr_init(dsp_uart_attr_t *attributes);
+
+bytehandler_func_t		dsp_uart_attr_get_bytehandler(dsp_uart_attr_t *attributes, void **bytehandler_arg);
+void					dsp_uart_attr_set_bytehandler(dsp_uart_attr_t *attributes, bytehandler_func_t bytehandler, void *bytehandler_arg);
+
+dsp_uart_handle_t *		dsp_uart_create(dsp_uart_attr_t *attributes);
+void					dsp_uart_destroy(dsp_uart_handle_t **handle);
+
+void					dsp_uart_bit_handler(void *handle, int bit);
+
+#endif
+

Added: freeswitch/trunk/libs/openzap/src/include/zap_buffer.h (0 => 17141)


--- freeswitch/trunk/libs/openzap/src/include/zap_buffer.h	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/src/include/zap_buffer.h	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 2007, Anthony Minessale II
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ZAP_BUFFER_H
+#define ZAP_BUFFER_H
+
+#include "openzap.h"
+
+/**
+ * @defgroup zap_buffer Buffer Routines
+ * @ingroup buffer
+ * The purpose of this module is to make a plain buffering interface that can be used for read/write buffers
+ * throughout the application.
+ * @{
+ */
+struct zap_buffer;
+typedef struct zap_buffer zap_buffer_t;
+
+/*! \brief Allocate a new dynamic zap_buffer 
+ * \param buffer returned pointer to the new buffer
+ * \param blocksize length to realloc by as data is added
+ * \param start_len ammount of memory to reserve initially
+ * \param max_len length the buffer is allowed to grow to
+ * \return status
+ */
+OZ_DECLARE(zap_status_t) zap_buffer_create(zap_buffer_t **buffer, zap_size_t blocksize, zap_size_t start_len, zap_size_t max_len);
+
+/*! \brief Get the length of a zap_buffer_t 
+ * \param buffer any buffer of type zap_buffer_t
+ * \return int size of the buffer.
+ */
+OZ_DECLARE(zap_size_t) zap_buffer_len(zap_buffer_t *buffer);
+
+/*! \brief Get the freespace of a zap_buffer_t 
+ * \param buffer any buffer of type zap_buffer_t
+ * \return int freespace in the buffer.
+ */
+OZ_DECLARE(zap_size_t) zap_buffer_freespace(zap_buffer_t *buffer);
+
+/*! \brief Get the in use amount of a zap_buffer_t 
+ * \param buffer any buffer of type zap_buffer_t
+ * \return int ammount of buffer curently in use
+ */
+OZ_DECLARE(zap_size_t) zap_buffer_inuse(zap_buffer_t *buffer);
+
+/*! \brief Read data from a zap_buffer_t up to the ammount of datalen if it is available.  Remove read data from buffer. 
+ * \param buffer any buffer of type zap_buffer_t
+ * \param data pointer to the read data to be returned
+ * \param datalen amount of data to be returned
+ * \return int ammount of data actually read
+ */
+OZ_DECLARE(zap_size_t) zap_buffer_read(zap_buffer_t *buffer, void *data, zap_size_t datalen);
+
+/*! \brief Read data endlessly from a zap_buffer_t 
+ * \param buffer any buffer of type zap_buffer_t
+ * \param data pointer to the read data to be returned
+ * \param datalen amount of data to be returned
+ * \return int ammount of data actually read
+ * \note Once you have read all the data from the buffer it will loop around.
+ */
+OZ_DECLARE(zap_size_t) zap_buffer_read_loop(zap_buffer_t *buffer, void *data, zap_size_t datalen);
+
+/*! \brief Assign a number of loops to read
+ * \param buffer any buffer of type zap_buffer_t
+ * \param loops the number of loops (-1 for infinite)
+ */
+OZ_DECLARE(void) zap_buffer_set_loops(zap_buffer_t *buffer, int32_t loops);
+
+/*! \brief Write data into a zap_buffer_t up to the length of datalen
+ * \param buffer any buffer of type zap_buffer_t
+ * \param data pointer to the data to be written
+ * \param datalen amount of data to be written
+ * \return int amount of buffer used after the write, or 0 if no space available
+ */
+OZ_DECLARE(zap_size_t) zap_buffer_write(zap_buffer_t *buffer, const void *data, zap_size_t datalen);
+
+/*! \brief Remove data from the buffer
+ * \param buffer any buffer of type zap_buffer_t
+ * \param datalen amount of data to be removed
+ * \return int size of buffer, or 0 if unable to toss that much data
+ */
+OZ_DECLARE(zap_size_t) zap_buffer_toss(zap_buffer_t *buffer, zap_size_t datalen);
+
+/*! \brief Remove all data from the buffer
+ * \param buffer any buffer of type zap_buffer_t
+ */
+OZ_DECLARE(void) zap_buffer_zero(zap_buffer_t *buffer);
+
+/*! \brief Destroy the buffer
+ * \param buffer buffer to destroy
+ * \note only neccessary on dynamic buffers (noop on pooled ones)
+ */
+OZ_DECLARE(void) zap_buffer_destroy(zap_buffer_t **buffer);
+
+/*! \brief Seek to offset from the beginning of the buffer
+ * \param buffer buffer to seek
+ * \param datalen offset in bytes
+ * \return new position
+ */
+OZ_DECLARE(zap_size_t) zap_buffer_seek(zap_buffer_t *buffer, zap_size_t datalen);
+
+/** @} */
+
+OZ_DECLARE(zap_size_t) zap_buffer_zwrite(zap_buffer_t *buffer, const void *data, zap_size_t datalen);
+
+#endif
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */

Added: freeswitch/trunk/libs/openzap/src/include/zap_config.h (0 => 17141)


--- freeswitch/trunk/libs/openzap/src/include/zap_config.h	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/src/include/zap_config.h	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2007, Anthony Minessale II
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @defgroup config Config File Parser
+ * @ingroup config
+ * This module implements a basic interface and file format parser
+ * 
+ * <pre>
+ *
+ * EXAMPLE 
+ * 
+ * [category1]
+ * var1 => val1
+ * var2 => val2
+ * \# lines that begin with \# are comments
+ * \#var3 => val3
+ * </pre>
+ * @{
+ */
+
+#ifndef ZAP_CONFIG_H
+#define ZAP_CONFIG_H
+
+#include "openzap.h"
+#define ZAP_URL_SEPARATOR "://"
+
+
+#ifdef WIN32
+#define ZAP_PATH_SEPARATOR "\\"
+#ifndef ZAP_CONFIG_DIR
+#define ZAP_CONFIG_DIR "c:\\openzap"
+#endif
+#define zap_is_file_path(file) (*(file +1) == ':' || *file == '/' || strstr(file, SWITCH_URL_SEPARATOR))
+#else
+#define ZAP_PATH_SEPARATOR "/"
+#ifndef ZAP_CONFIG_DIR
+#define ZAP_CONFIG_DIR "/etc/openzap"
+#endif
+#define zap_is_file_path(file) ((*file == '/') || strstr(file, SWITCH_URL_SEPARATOR))
+#endif
+
+typedef struct zap_config zap_config_t;
+
+/*! \brief A simple file handle representing an open configuration file **/
+struct zap_config {
+	/*! FILE stream buffer to the opened file */
+	FILE *file;
+	/*! path to the file */
+	char path[512];
+	/*! current category */
+	char category[256];
+	/*! current section */
+	char section[256];
+	/*! buffer of current line being read */
+	char buf[1024];
+	/*! current line number in file */
+	int lineno;
+	/*! current category number in file */
+	int catno;
+	/*! current section number in file */
+	int sectno;
+
+	int lockto;
+};
+
+/*!
+  \brief Open a configuration file
+  \param cfg (zap_config_t *) config handle to use
+  \param file_path path to the file
+  \return 1 (true) on success 0 (false) on failure
+*/
+int zap_config_open_file(zap_config_t * cfg, const char *file_path);
+
+/*!
+  \brief Close a previously opened configuration file
+  \param cfg (zap_config_t *) config handle to use
+*/
+void zap_config_close_file(zap_config_t * cfg);
+
+/*!
+  \brief Retrieve next name/value pair from configuration file
+  \param cfg (zap_config_t *) config handle to use
+  \param var pointer to aim at the new variable name
+  \param val pointer to aim at the new value
+*/
+int zap_config_next_pair(zap_config_t * cfg, char **var, char **val);
+
+/*!
+  \brief Retrieve the CAS bits from a configuration string value
+  \param strvalue pointer to the configuration string value (expected to be in format whatever:xxxx)
+  \param outbits pointer to aim at the CAS bits
+*/
+OZ_DECLARE (int) zap_config_get_cas_bits(char *strvalue, unsigned char *outbits);
+
+
+/** @} */
+#endif
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */

Added: freeswitch/trunk/libs/openzap/src/include/zap_cpu_monitor.h (0 => 17141)


--- freeswitch/trunk/libs/openzap/src/include/zap_cpu_monitor.h	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/src/include/zap_cpu_monitor.h	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,74 @@
+/* * Copyright (c) 2009, Sangoma Technologies
+ * Moises Silva <moy@sangoma.com>
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 
+ * 
+ * Contributors:
+ * David Yat Sin <dyatsin@sangoma.com>
+ * 
+ */
+
+/*! \brief opaque cpu stats structure */
+struct zap_cpu_monitor_stats;
+
+/*! 
+ * \brief create a new cpu monitor
+ * \return profile timer structure previously created with new_profile_timer, NULL on error
+ */
+OZ_DECLARE(struct zap_cpu_monitor_stats*) zap_new_cpu_monitor(void);
+
+/*! 
+ * \brief Deletes cpu_monitor
+ */
+OZ_DECLARE(void) zap_delete_cpu_monitor(struct zap_cpu_monitor_stats *p);
+
+/*! 
+ * \brief provides the percentage of idle system time
+ * \param p cpu_stats structure previously created with zap_new_cpu_monitor
+ * \param pointer to store the percentage of idle time
+ * \return -1 on error 0 for success
+ */
+OZ_DECLARE(zap_status_t) zap_cpu_get_system_idle_time (struct zap_cpu_monitor_stats *p, double *idle_percentage);
+
+
+
+
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */

Added: freeswitch/trunk/libs/openzap/src/include/zap_dso.h (0 => 17141)


--- freeswitch/trunk/libs/openzap/src/include/zap_dso.h	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/src/include/zap_dso.h	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,44 @@
+/* 
+ * Cross Platform dso/dll load abstraction
+ * Copyright(C) 2008 Michael Jerris
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so.
+ *
+ * This work is provided under this license on an "as is" basis, without warranty of any kind,
+ * either expressed or implied, including, without limitation, warranties that the covered code
+ * is free of defects, merchantable, fit for a particular purpose or non-infringing. The entire
+ * risk as to the quality and performance of the covered code is with you. Should any covered
+ * code prove defective in any respect, you (not the initial developer or any other contributor)
+ * assume the cost of any necessary servicing, repair or correction. This disclaimer of warranty
+ * constitutes an essential part of this license. No use of any covered code is authorized hereunder
+ * except under this disclaimer. 
+ *
+ */
+
+
+#ifndef _ZAP_DSO_H
+#define _ZAP_DSO_H
+
+typedef void (*zap_func_ptr_t) (void);
+typedef void * zap_dso_lib_t;
+
+void zap_dso_destroy(zap_dso_lib_t *lib);
+zap_dso_lib_t zap_dso_open(const char *path, char **err);
+void *zap_dso_func_sym(zap_dso_lib_t lib, const char *sym, char **err);
+
+
+#endif
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4
+ */
+

Added: freeswitch/trunk/libs/openzap/src/include/zap_m3ua.h (0 => 17141)


--- freeswitch/trunk/libs/openzap/src/include/zap_m3ua.h	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/src/include/zap_m3ua.h	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,128 @@
+/*
+ *  zap_m3ua.h
+ *  openzap
+ *
+ *  Created by Shane Burrell on 4/3/08.
+ *  Copyright 2008 Shane Burrell. All rights reserved.
+ *
+ * Copyright (c) 2007, Anthony Minessale II, Nenad Corbic
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+//#include "m3ua_client.h"
+#include "openzap.h"
+enum	e_sigboost_event_id_values
+{
+	SIGBOOST_EVENT_CALL_START			= 0x80, /*128*/
+	SIGBOOST_EVENT_CALL_START_ACK			= 0x81, /*129*/
+	SIGBOOST_EVENT_CALL_START_NACK			= 0x82, /*130*/
+	SIGBOOST_EVENT_CALL_START_NACK_ACK		= 0x83, /*131*/
+	SIGBOOST_EVENT_CALL_ANSWERED			= 0x84, /*132*/
+	SIGBOOST_EVENT_CALL_STOPPED			= 0x85, /*133*/
+	SIGBOOST_EVENT_CALL_STOPPED_ACK			= 0x86, /*134*/
+	SIGBOOST_EVENT_SYSTEM_RESTART			= 0x87, /*135*/
+	SIGBOOST_EVENT_SYSTEM_RESTART_ACK		= 0x88, /*136*/
+	/* Following IDs are ss7boost to sangoma_mgd only. */
+	SIGBOOST_EVENT_HEARTBEAT			= 0x89, /*137*/
+	SIGBOOST_EVENT_INSERT_CHECK_LOOP		= 0x8a, /*138*/
+	SIGBOOST_EVENT_REMOVE_CHECK_LOOP		= 0x8b, /*139*/
+	SIGBOOST_EVENT_AUTO_CALL_GAP_ABATE		= 0x8c, /*140*/
+};
+enum	e_sigboost_release_cause_values
+{
+	SIGBOOST_RELEASE_CAUSE_UNDEFINED		= 0,
+	SIGBOOST_RELEASE_CAUSE_NORMAL			= 16,
+	SIGBOOST_RELEASE_CAUSE_BUSY			= 17,
+	/* probable elimination */
+	//SIGBOOST_RELEASE_CAUSE_BUSY			= 0x91, /* 145 */
+	//SIGBOOST_RELEASE_CAUSE_CALLED_NOT_EXIST	= 0x92, /* 146 */
+	//SIGBOOST_RELEASE_CAUSE_CIRCUIT_RESET		= 0x93, /* 147 */
+	//SIGBOOST_RELEASE_CAUSE_NOANSWER		= 0x94, /* 148 */
+};
+
+enum	e_sigboost_call_setup_ack_nack_cause_values
+{
+	SIGBOOST_CALL_SETUP_NACK_ALL_CKTS_BUSY		= 117, /* unused Q.850 value */
+	SIGBOOST_CALL_SETUP_NACK_TEST_CKT_BUSY		= 118, /* unused Q.850 value */
+	SIGBOOST_CALL_SETUP_NACK_INVALID_NUMBER		= 28,
+	/* probable elimination */
+	//SIGBOOST_CALL_SETUP_RESERVED			= 0x00,
+	//SIGBOOST_CALL_SETUP_CIRCUIT_RESET		= 0x10,
+	//SIGBOOST_CALL_SETUP_NACK_CKT_START_TIMEOUT	= 0x11,
+	//SIGBOOST_CALL_SETUP_NACK_AUTO_CALL_GAP	= 0x17,
+};
+typedef enum {
+	M3UA_SPAN_SIGNALING_M3UA,
+	M3UA_SPAN_SIGNALING_SS7BOX,
+	
+} M3UA_TSpanSignaling;
+#define M3UA_SPAN_STRINGS "M3UA", "SS7BOX"
+ZAP_STR2ENUM_P(m3ua_str2span, m3ua_span2str, M3UA_TSpanSignaling)
+
+
+
+typedef enum {
+	ZAP_M3UA_RUNNING = (1 << 0)
+} zap_m3uat_flag_t;
+
+/*typedef struct m3ua_data {
+	m3uac_connection_t mcon;
+	m3uac_connection_t pcon;
+	zio_signal_cb_t signal_cb;
+	uint32_t flags;
+} m3ua_data_t;
+
+*/
+/*typedef struct mu3a_link {
+	ss7bc_connection_t mcon;
+	ss7bc_connection_t pcon;
+	zio_signal_cb_t signal_cb;
+	uint32_t flags;
+} zap_m3ua_data_t;
+*/
+
+zap_status_t m3ua_init(zap_io_interface_t **zint);
+zap_status_t m3ua_destroy(void);
+zap_status_t m3ua_start(zap_span_t *span);
+
+
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
+

Added: freeswitch/trunk/libs/openzap/src/include/zap_threadmutex.h (0 => 17141)


--- freeswitch/trunk/libs/openzap/src/include/zap_threadmutex.h	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/src/include/zap_threadmutex.h	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,56 @@
+/* 
+ * Cross Platform Thread/Mutex abstraction
+ * Copyright(C) 2007 Michael Jerris
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so.
+ *
+ * This work is provided under this license on an "as is" basis, without warranty of any kind,
+ * either expressed or implied, including, without limitation, warranties that the covered code
+ * is free of defects, merchantable, fit for a particular purpose or non-infringing. The entire
+ * risk as to the quality and performance of the covered code is with you. Should any covered
+ * code prove defective in any respect, you (not the initial developer or any other contributor)
+ * assume the cost of any necessary servicing, repair or correction. This disclaimer of warranty
+ * constitutes an essential part of this license. No use of any covered code is authorized hereunder
+ * except under this disclaimer. 
+ *
+ */
+
+
+#ifndef _ZAP_THREADMUTEX_H
+#define _ZAP_THREADMUTEX_H
+
+#include "openzap.h"
+
+typedef struct zap_mutex zap_mutex_t;
+typedef struct zap_thread zap_thread_t;
+typedef void *(*zap_thread_function_t) (zap_thread_t *, void *);
+
+OZ_DECLARE(zap_status_t) zap_thread_create_detached(zap_thread_function_t func, void *data);
+OZ_DECLARE(zap_status_t) zap_thread_create_detached_ex(zap_thread_function_t func, void *data, zap_size_t stack_size);
+OZ_DECLARE(void) zap_thread_override_default_stacksize(zap_size_t size);
+OZ_DECLARE(zap_status_t) zap_mutex_create(zap_mutex_t **mutex);
+OZ_DECLARE(zap_status_t) zap_mutex_destroy(zap_mutex_t **mutex);
+OZ_DECLARE(zap_status_t) _zap_mutex_lock(zap_mutex_t *mutex);
+OZ_DECLARE(zap_status_t) _zap_mutex_trylock(zap_mutex_t *mutex);
+OZ_DECLARE(zap_status_t) _zap_mutex_unlock(zap_mutex_t *mutex);
+
+OZ_DECLARE(zap_status_t) zap_interrupt_create(zap_interrupt_t **ininterrupt, zap_socket_t device);
+OZ_DECLARE(zap_status_t) zap_interrupt_wait(zap_interrupt_t *interrupt, int ms);
+OZ_DECLARE(zap_status_t) zap_interrupt_signal(zap_interrupt_t *interrupt);
+OZ_DECLARE(zap_status_t) zap_interrupt_destroy(zap_interrupt_t **ininterrupt);
+OZ_DECLARE(zap_status_t) zap_interrupt_multiple_wait(zap_interrupt_t *interrupts[], zap_size_t size, int ms);
+#endif
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
+

Added: freeswitch/trunk/libs/openzap/src/include/zap_types.h (0 => 17141)


--- freeswitch/trunk/libs/openzap/src/include/zap_types.h	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/src/include/zap_types.h	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,639 @@
+/*
+ * Copyright (c) 2007, Anthony Minessale II
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ZAP_TYPES_H
+#define ZAP_TYPES_H
+#include "fsk.h"
+
+#ifdef WIN32
+#define ZAP_INVALID_SOCKET INVALID_HANDLE_VALUE
+#else
+#define ZAP_INVALID_SOCKET -1
+#endif
+#define zap_array_len(obj) sizeof(obj)/sizeof(obj[0])
+
+#ifdef WIN32
+#include <windows.h>
+typedef HANDLE zap_socket_t;
+typedef unsigned __int64 uint64_t;
+typedef unsigned __int32 uint32_t;
+typedef unsigned __int16 uint16_t;
+typedef unsigned __int8 uint8_t;
+typedef __int64 int64_t;
+typedef __int32 int32_t;
+typedef __int16 int16_t;
+typedef __int8 int8_t;
+typedef intptr_t zap_ssize_t;
+typedef int zap_filehandle_t;
+#else
+#include <stdint.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <stdarg.h>
+typedef int zap_socket_t;
+typedef ssize_t zap_ssize_t;
+typedef int zap_filehandle_t;
+#endif
+
+#define TAG_END NULL
+
+typedef size_t zap_size_t;
+struct zap_io_interface;
+typedef struct zap_interrupt zap_interrupt_t;
+
+#define ZAP_COMMAND_OBJ_INT *((int *)obj)
+#define ZAP_COMMAND_OBJ_CHAR_P (char *)obj
+#define ZAP_COMMAND_OBJ_FLOAT *((float *)obj)
+#define ZAP_FSK_MOD_FACTOR 0x10000
+#define ZAP_DEFAULT_DTMF_ON 250
+#define ZAP_DEFAULT_DTMF_OFF 50
+
+#define ZAP_END -1
+#define ZAP_ANY_STATE -1
+
+typedef uint64_t zap_time_t; 
+
+typedef enum {
+	ZAP_ENDIAN_BIG = 1,
+	ZAP_ENDIAN_LITTLE = -1
+} zap_endian_t;
+
+typedef enum {
+	ZAP_CID_TYPE_SDMF = 0x04,
+	ZAP_CID_TYPE_MDMF = 0x80
+} zap_cid_type_t;
+
+typedef enum {
+	MDMF_DATETIME = 1,
+	MDMF_PHONE_NUM = 2,
+	MDMF_DDN = 3,
+	MDMF_NO_NUM = 4,
+	MDMF_PHONE_NAME = 7,
+	MDMF_NO_NAME = 8,
+	MDMF_ALT_ROUTE = 9,
+	MDMF_INVALID = 10
+} zap_mdmf_type_t;
+#define MDMF_STRINGS "X", "DATETIME", "PHONE_NUM", "DDN", "NO_NUM", "X", "X", "PHONE_NAME", "NO_NAME", "ALT_ROUTE", "INVALID"
+ZAP_STR2ENUM_P(zap_str2zap_mdmf_type, zap_mdmf_type2str, zap_mdmf_type_t)
+
+#define ZAP_TONEMAP_LEN 128
+typedef enum {
+	ZAP_TONEMAP_NONE,
+	ZAP_TONEMAP_DIAL,
+	ZAP_TONEMAP_RING,
+	ZAP_TONEMAP_BUSY,
+	ZAP_TONEMAP_FAIL1,
+	ZAP_TONEMAP_FAIL2,
+	ZAP_TONEMAP_FAIL3,
+	ZAP_TONEMAP_ATTN,
+	ZAP_TONEMAP_CALLWAITING_CAS,
+	ZAP_TONEMAP_CALLWAITING_SAS,
+	ZAP_TONEMAP_CALLWAITING_ACK,
+	ZAP_TONEMAP_INVALID
+} zap_tonemap_t;
+#define TONEMAP_STRINGS "NONE", "DIAL", "RING", "BUSY", "FAIL1", "FAIL2", "FAIL3", "ATTN", "CALLWAITING-CAS", "CALLWAITING-SAS", "CALLWAITING-ACK", "INVALID"
+ZAP_STR2ENUM_P(zap_str2zap_tonemap, zap_tonemap2str, zap_tonemap_t)
+
+typedef enum {
+	ZAP_TRUNK_E1,
+	ZAP_TRUNK_T1,
+	ZAP_TRUNK_J1,
+	ZAP_TRUNK_BRI,
+	ZAP_TRUNK_BRI_PTMP,
+	ZAP_TRUNK_FXO,
+	ZAP_TRUNK_FXS,
+	ZAP_TRUNK_EM,
+	ZAP_TRUNK_NONE
+} zap_trunk_type_t;
+#define TRUNK_STRINGS "E1", "T1", "J1", "BRI", "BRI_PTMP", "FXO", "FXS", "EM", "NONE"
+ZAP_STR2ENUM_P(zap_str2zap_trunk_type, zap_trunk_type2str, zap_trunk_type_t)
+
+typedef enum {
+	ZAP_ANALOG_START_KEWL,
+	ZAP_ANALOG_START_LOOP,
+	ZAP_ANALOG_START_GROUND,
+	ZAP_ANALOG_START_WINK,
+	ZAP_ANALOG_START_NA
+} zap_analog_start_type_t;
+#define START_TYPE_STRINGS "KEWL", "LOOP", "GROUND", "WINK", "NA"
+ZAP_STR2ENUM_P(zap_str2zap_analog_start_type, zap_analog_start_type2str, zap_analog_start_type_t)
+
+typedef enum {
+	ZAP_OOB_DTMF, 
+	ZAP_OOB_ONHOOK,
+	ZAP_OOB_OFFHOOK,
+	ZAP_OOB_WINK,
+	ZAP_OOB_FLASH,
+	ZAP_OOB_RING_START,
+	ZAP_OOB_RING_STOP,
+	ZAP_OOB_ALARM_TRAP,
+	ZAP_OOB_ALARM_CLEAR,
+	ZAP_OOB_NOOP,
+	ZAP_OOB_CAS_BITS_CHANGE,
+	ZAP_OOB_INVALID
+} zap_oob_event_t;
+#define OOB_STRINGS "DTMF", "ONHOOK", "OFFHOOK", "WINK", "FLASH", "RING_START", "RING_STOP", "ALARM_TRAP", "ALARM_CLEAR", "NOOP", "CAS_BITS_CHANGE", "INVALID"
+ZAP_STR2ENUM_P(zap_str2zap_oob_event, zap_oob_event2str, zap_oob_event_t)
+
+typedef enum {
+	ZAP_ALARM_NONE = 0,
+	ZAP_ALARM_RECOVER = (1 << 0),
+	ZAP_ALARM_LOOPBACK = (1 << 2),
+	ZAP_ALARM_YELLOW = (1 << 3),
+	ZAP_ALARM_RED = (1 << 4),
+	ZAP_ALARM_BLUE = (1 << 5),
+	ZAP_ALARM_NOTOPEN = ( 1 << 6),
+	ZAP_ALARM_AIS = ( 1 << 7),
+	ZAP_ALARM_RAI = ( 1 << 8),
+	ZAP_ALARM_GENERAL = ( 1 << 30)
+} zap_alarm_flag_t;
+
+typedef enum {
+	ZAP_SIGTYPE_NONE,
+	ZAP_SIGTYPE_ISDN,
+	ZAP_SIGTYPE_RBS,
+	ZAP_SIGTYPE_ANALOG,
+	ZAP_SIGTYPE_SANGOMABOOST,
+	ZAP_SIGTYPE_M3UA,
+	ZAP_SIGTYPE_R2
+} zap_signal_type_t;
+
+typedef enum {
+	ZAP_SIGEVENT_START,
+	ZAP_SIGEVENT_STOP,
+	ZAP_SIGEVENT_TRANSFER,
+	ZAP_SIGEVENT_ANSWER,
+	ZAP_SIGEVENT_UP,
+	ZAP_SIGEVENT_FLASH,
+	ZAP_SIGEVENT_PROGRESS,
+	ZAP_SIGEVENT_PROGRESS_MEDIA,
+	ZAP_SIGEVENT_NOTIFY,
+	ZAP_SIGEVENT_TONE_DETECTED,
+	ZAP_SIGEVENT_ALARM_TRAP,
+	ZAP_SIGEVENT_ALARM_CLEAR,
+	ZAP_SIGEVENT_MISC,
+	ZAP_SIGEVENT_COLLECTED_DIGIT,
+	ZAP_SIGEVENT_ADD_CALL,
+	ZAP_SIGEVENT_RESTART,
+	ZAP_SIGEVENT_INVALID
+} zap_signal_event_t;
+#define SIGNAL_STRINGS "START", "STOP", "TRANSFER", "ANSWER", "UP", "FLASH", "PROGRESS", \
+		"PROGRESS_MEDIA", "NOTIFY", "TONE_DETECTED", "ALARM_TRAP", "ALARM_CLEAR", "MISC", "COLLECTED_DIGIT", "ADD_CALL", "RESTART", "INVALID"
+ZAP_STR2ENUM_P(zap_str2zap_signal_event, zap_signal_event2str, zap_signal_event_t)
+
+typedef enum {
+	ZAP_EVENT_NONE,
+	ZAP_EVENT_DTMF,
+	ZAP_EVENT_OOB,
+	ZAP_EVENT_COUNT
+} zap_event_type_t;
+
+typedef enum {
+	ZAP_TOP_DOWN,
+	ZAP_BOTTOM_UP
+} zap_direction_t;
+
+typedef enum {
+	ZAP_SUCCESS,
+	ZAP_FAIL,
+	ZAP_MEMERR,
+	ZAP_TIMEOUT,
+	ZAP_NOTIMPL,
+	ZAP_CHECKSUM_ERROR,
+	ZAP_STATUS_COUNT,
+	ZAP_BREAK
+} zap_status_t;
+
+typedef enum {
+	ZAP_NO_FLAGS = 0,
+	ZAP_READ =  (1 << 0),
+	ZAP_WRITE = (1 << 1),
+	ZAP_EVENTS = (1 << 2)
+} zap_wait_flag_t;
+
+typedef enum {
+	ZAP_CODEC_ULAW = 0,
+	ZAP_CODEC_ALAW = 8,
+	ZAP_CODEC_SLIN = 10,
+	ZAP_CODEC_NONE = (1 << 30)
+} zap_codec_t;
+
+typedef enum {
+	ZAP_TONE_DTMF = (1 << 0)
+} zap_tone_type_t;
+
+typedef enum {
+	ZAP_COMMAND_NOOP,
+	ZAP_COMMAND_SET_INTERVAL,
+	ZAP_COMMAND_GET_INTERVAL,
+	ZAP_COMMAND_SET_CODEC,
+	ZAP_COMMAND_GET_CODEC,
+	ZAP_COMMAND_SET_NATIVE_CODEC,
+	ZAP_COMMAND_GET_NATIVE_CODEC,
+	ZAP_COMMAND_ENABLE_DTMF_DETECT,
+	ZAP_COMMAND_DISABLE_DTMF_DETECT,
+	ZAP_COMMAND_SEND_DTMF,
+	ZAP_COMMAND_SET_DTMF_ON_PERIOD,
+	ZAP_COMMAND_GET_DTMF_ON_PERIOD,
+	ZAP_COMMAND_SET_DTMF_OFF_PERIOD,
+	ZAP_COMMAND_GET_DTMF_OFF_PERIOD,
+	ZAP_COMMAND_GENERATE_RING_ON,
+	ZAP_COMMAND_GENERATE_RING_OFF,
+	ZAP_COMMAND_OFFHOOK,
+	ZAP_COMMAND_ONHOOK,
+	ZAP_COMMAND_FLASH,
+	ZAP_COMMAND_WINK,
+	ZAP_COMMAND_ENABLE_PROGRESS_DETECT,
+	ZAP_COMMAND_DISABLE_PROGRESS_DETECT,
+	ZAP_COMMAND_TRACE_INPUT,
+	ZAP_COMMAND_TRACE_OUTPUT,
+	ZAP_COMMAND_ENABLE_CALLERID_DETECT,
+	ZAP_COMMAND_DISABLE_CALLERID_DETECT,
+	ZAP_COMMAND_ENABLE_ECHOCANCEL,
+	ZAP_COMMAND_DISABLE_ECHOCANCEL,
+	ZAP_COMMAND_ENABLE_ECHOTRAIN,
+	ZAP_COMMAND_DISABLE_ECHOTRAIN,
+	ZAP_COMMAND_SET_CAS_BITS,
+	ZAP_COMMAND_GET_CAS_BITS,
+	ZAP_COMMAND_SET_RX_GAIN,
+	ZAP_COMMAND_GET_RX_GAIN,
+	ZAP_COMMAND_SET_TX_GAIN,
+	ZAP_COMMAND_GET_TX_GAIN,
+	ZAP_COMMAND_FLUSH_TX_BUFFERS,
+	ZAP_COMMAND_FLUSH_RX_BUFFERS,
+	ZAP_COMMAND_FLUSH_BUFFERS,
+	ZAP_COMMAND_SET_PRE_BUFFER_SIZE,
+	ZAP_COMMAND_ENABLE_LOOP,
+	ZAP_COMMAND_DISABLE_LOOP,
+	ZAP_COMMAND_COUNT
+} zap_command_t;
+
+typedef enum {
+	ZAP_SPAN_CONFIGURED = (1 << 0),
+	ZAP_SPAN_READY = (1 << 1),
+	ZAP_SPAN_STATE_CHANGE = (1 << 2),
+	ZAP_SPAN_SUSPENDED = (1 << 3),
+	ZAP_SPAN_IN_THREAD = (1 << 4),
+	ZAP_SPAN_STOP_THREAD = (1 << 5)
+} zap_span_flag_t;
+
+typedef enum {
+	ZAP_CHAN_TYPE_B,
+	ZAP_CHAN_TYPE_DQ921,
+	ZAP_CHAN_TYPE_DQ931,
+	ZAP_CHAN_TYPE_FXS,
+	ZAP_CHAN_TYPE_FXO,
+	ZAP_CHAN_TYPE_EM,
+	ZAP_CHAN_TYPE_CAS,
+	ZAP_CHAN_TYPE_COUNT
+} zap_chan_type_t;
+
+#define CHAN_TYPE_STRINGS "B", "DQ921", "DQ931", "FXS", "FXO", "EM", "CAS", "INVALID"
+ZAP_STR2ENUM_P(zap_str2zap_chan_type, zap_chan_type2str, zap_chan_type_t)
+
+#define ZAP_IS_VOICE_CHANNEL(zap_chan) ((zap_chan)->type != ZAP_CHAN_TYPE_DQ921 && (zap_chan)->type != ZAP_CHAN_TYPE_DQ931)
+
+typedef enum {
+	ZAP_CHANNEL_FEATURE_DTMF_DETECT = (1 << 0),
+	ZAP_CHANNEL_FEATURE_DTMF_GENERATE = (1 << 1),
+	ZAP_CHANNEL_FEATURE_CODECS = (1 << 2),
+	ZAP_CHANNEL_FEATURE_INTERVAL = (1 << 3),
+	ZAP_CHANNEL_FEATURE_CALLERID = (1 << 4),
+	ZAP_CHANNEL_FEATURE_PROGRESS = (1 << 5)
+} zap_channel_feature_t;
+
+typedef enum {
+	ZAP_CHANNEL_STATE_DOWN,
+	ZAP_CHANNEL_STATE_HOLD,
+	ZAP_CHANNEL_STATE_SUSPENDED,
+	ZAP_CHANNEL_STATE_DIALTONE,
+	ZAP_CHANNEL_STATE_COLLECT,
+	ZAP_CHANNEL_STATE_RING,
+	ZAP_CHANNEL_STATE_BUSY,
+	ZAP_CHANNEL_STATE_ATTN,
+	ZAP_CHANNEL_STATE_GENRING,
+	ZAP_CHANNEL_STATE_DIALING,
+	ZAP_CHANNEL_STATE_GET_CALLERID,
+	ZAP_CHANNEL_STATE_CALLWAITING,
+	ZAP_CHANNEL_STATE_RESTART,
+	ZAP_CHANNEL_STATE_PROGRESS,
+	ZAP_CHANNEL_STATE_PROGRESS_MEDIA,
+	ZAP_CHANNEL_STATE_UP,
+	ZAP_CHANNEL_STATE_IDLE,
+	ZAP_CHANNEL_STATE_TERMINATING,
+	ZAP_CHANNEL_STATE_CANCEL,
+	ZAP_CHANNEL_STATE_HANGUP,
+	ZAP_CHANNEL_STATE_HANGUP_COMPLETE,
+	ZAP_CHANNEL_STATE_IN_LOOP,
+	ZAP_CHANNEL_STATE_INVALID
+} zap_channel_state_t;
+#define CHANNEL_STATE_STRINGS "DOWN", "HOLD", "SUSPENDED", "DIALTONE", "COLLECT", \
+		"RING", "BUSY", "ATTN", "GENRING", "DIALING", "GET_CALLERID", "CALLWAITING", \
+		"RESTART", "PROGRESS", "PROGRESS_MEDIA", "UP", "IDLE", "TERMINATING", "CANCEL", "HANGUP", "HANGUP_COMPLETE", "INVALID"
+ZAP_STR2ENUM_P(zap_str2zap_channel_state, zap_channel_state2str, zap_channel_state_t)
+
+typedef enum {
+	ZAP_CHANNEL_CONFIGURED = (1 << 0),
+	ZAP_CHANNEL_READY = (1 << 1),
+	ZAP_CHANNEL_OPEN = (1 << 2),
+	ZAP_CHANNEL_DTMF_DETECT = (1 << 3),
+	ZAP_CHANNEL_SUPRESS_DTMF = (1 << 4),
+	ZAP_CHANNEL_TRANSCODE = (1 << 5),
+	ZAP_CHANNEL_BUFFER = (1 << 6),
+	ZAP_CHANNEL_EVENT = (1 << 7),
+	ZAP_CHANNEL_INTHREAD = (1 << 8),
+	ZAP_CHANNEL_WINK = (1 << 9),
+	ZAP_CHANNEL_FLASH = (1 << 10),
+	ZAP_CHANNEL_STATE_CHANGE = (1 << 11),
+	ZAP_CHANNEL_HOLD = (1 << 12),
+	ZAP_CHANNEL_INUSE = (1 << 13),
+	ZAP_CHANNEL_OFFHOOK = (1 << 14),
+	ZAP_CHANNEL_RINGING = (1 << 15),
+	ZAP_CHANNEL_PROGRESS_DETECT = (1 << 16),
+	ZAP_CHANNEL_CALLERID_DETECT = (1 << 17),
+	ZAP_CHANNEL_OUTBOUND = (1 << 18),
+	ZAP_CHANNEL_SUSPENDED = (1 << 19),
+	ZAP_CHANNEL_3WAY = (1 << 20),
+	ZAP_CHANNEL_PROGRESS = (1 << 21),
+	ZAP_CHANNEL_MEDIA = (1 << 22),
+	ZAP_CHANNEL_ANSWERED = (1 << 23),
+	ZAP_CHANNEL_MUTE = (1 << 24),
+	ZAP_CHANNEL_USE_RX_GAIN = (1 << 25),
+	ZAP_CHANNEL_USE_TX_GAIN = (1 << 26),
+} zap_channel_flag_t;
+
+typedef enum {
+	ZSM_NONE,
+	ZSM_UNACCEPTABLE,
+	ZSM_ACCEPTABLE
+} zap_state_map_type_t;
+
+typedef enum {
+	ZSD_INBOUND,
+	ZSD_OUTBOUND,
+} zap_state_direction_t;
+
+#define ZAP_MAP_NODE_SIZE 512
+#define ZAP_MAP_MAX ZAP_CHANNEL_STATE_INVALID+2
+
+struct zap_state_map_node {
+	zap_state_direction_t direction;
+	zap_state_map_type_t type;
+	zap_channel_state_t check_states[ZAP_MAP_MAX];
+	zap_channel_state_t states[ZAP_MAP_MAX];
+};
+typedef struct zap_state_map_node zap_state_map_node_t;
+
+struct zap_state_map {
+	zap_state_map_node_t nodes[ZAP_MAP_NODE_SIZE];
+};
+typedef struct zap_state_map zap_state_map_t;
+
+typedef struct zap_channel zap_channel_t;
+typedef struct zap_event zap_event_t;
+typedef struct zap_sigmsg zap_sigmsg_t;
+typedef struct zap_span zap_span_t;
+typedef struct zap_caller_data zap_caller_data_t;
+typedef struct zap_io_interface zap_io_interface_t;
+
+struct zap_stream_handle;
+typedef struct zap_stream_handle zap_stream_handle_t;
+
+typedef zap_status_t (*zap_stream_handle_raw_write_function_t) (zap_stream_handle_t *handle, uint8_t *data, zap_size_t datalen);
+typedef zap_status_t (*zap_stream_handle_write_function_t) (zap_stream_handle_t *handle, const char *fmt, ...);
+
+#define ZIO_CHANNEL_REQUEST_ARGS (zap_span_t *span, uint32_t chan_id, zap_direction_t direction, zap_caller_data_t *caller_data, zap_channel_t **zchan)
+#define ZIO_CHANNEL_OUTGOING_CALL_ARGS (zap_channel_t *zchan)
+#define ZIO_SPAN_POLL_EVENT_ARGS (zap_span_t *span, uint32_t ms)
+#define ZIO_SPAN_NEXT_EVENT_ARGS (zap_span_t *span, zap_event_t **event)
+#define ZIO_SIGNAL_CB_ARGS (zap_sigmsg_t *sigmsg)
+#define ZIO_EVENT_CB_ARGS (zap_channel_t *zchan, zap_event_t *event)
+#define ZIO_CODEC_ARGS (void *data, zap_size_t max, zap_size_t *datalen)
+#define ZIO_CONFIGURE_SPAN_ARGS (zap_span_t *span, const char *str, zap_chan_type_t type, char *name, char *number)
+#define ZIO_CONFIGURE_ARGS (const char *category, const char *var, const char *val, int lineno)
+#define ZIO_OPEN_ARGS (zap_channel_t *zchan)
+#define ZIO_CLOSE_ARGS (zap_channel_t *zchan)
+#define ZIO_CHANNEL_DESTROY_ARGS (zap_channel_t *zchan)
+#define ZIO_SPAN_DESTROY_ARGS (zap_span_t *span)
+#define ZIO_COMMAND_ARGS (zap_channel_t *zchan, zap_command_t command, void *obj)
+#define ZIO_WAIT_ARGS (zap_channel_t *zchan, zap_wait_flag_t *flags, int32_t to)
+#define ZIO_GET_ALARMS_ARGS (zap_channel_t *zchan)
+#define ZIO_READ_ARGS (zap_channel_t *zchan, void *data, zap_size_t *datalen)
+#define ZIO_WRITE_ARGS (zap_channel_t *zchan, void *data, zap_size_t *datalen)
+#define ZIO_IO_LOAD_ARGS (zap_io_interface_t **zio)
+#define ZIO_IO_UNLOAD_ARGS (void)
+#define ZIO_SIG_LOAD_ARGS (void)
+#define ZIO_SIG_CONFIGURE_ARGS (zap_span_t *span, zio_signal_cb_t sig_cb, va_list ap)
+#define ZIO_SIG_UNLOAD_ARGS (void)
+#define ZIO_API_ARGS (zap_stream_handle_t *stream, const char *data)
+
+typedef zap_status_t (*zio_channel_request_t) ZIO_CHANNEL_REQUEST_ARGS ;
+typedef zap_status_t (*zio_channel_outgoing_call_t) ZIO_CHANNEL_OUTGOING_CALL_ARGS ;
+typedef zap_status_t (*zio_span_poll_event_t) ZIO_SPAN_POLL_EVENT_ARGS ;
+typedef zap_status_t (*zio_span_next_event_t) ZIO_SPAN_NEXT_EVENT_ARGS ;
+typedef zap_status_t (*zio_signal_cb_t) ZIO_SIGNAL_CB_ARGS ;
+typedef zap_status_t (*zio_event_cb_t) ZIO_EVENT_CB_ARGS ;
+typedef zap_status_t (*zio_codec_t) ZIO_CODEC_ARGS ;
+typedef zap_status_t (*zio_configure_span_t) ZIO_CONFIGURE_SPAN_ARGS ;
+typedef zap_status_t (*zio_configure_t) ZIO_CONFIGURE_ARGS ;
+typedef zap_status_t (*zio_open_t) ZIO_OPEN_ARGS ;
+typedef zap_status_t (*zio_close_t) ZIO_CLOSE_ARGS ;
+typedef zap_status_t (*zio_channel_destroy_t) ZIO_CHANNEL_DESTROY_ARGS ;
+typedef zap_status_t (*zio_span_destroy_t) ZIO_SPAN_DESTROY_ARGS ;
+typedef zap_status_t (*zio_get_alarms_t) ZIO_GET_ALARMS_ARGS ;
+typedef zap_status_t (*zio_command_t) ZIO_COMMAND_ARGS ;
+typedef zap_status_t (*zio_wait_t) ZIO_WAIT_ARGS ;
+typedef zap_status_t (*zio_read_t) ZIO_READ_ARGS ;
+typedef zap_status_t (*zio_write_t) ZIO_WRITE_ARGS ;
+typedef zap_status_t (*zio_io_load_t) ZIO_IO_LOAD_ARGS ;
+typedef zap_status_t (*zio_sig_load_t) ZIO_SIG_LOAD_ARGS ;
+typedef zap_status_t (*zio_sig_configure_t) ZIO_SIG_CONFIGURE_ARGS ;
+typedef zap_status_t (*zio_io_unload_t) ZIO_IO_UNLOAD_ARGS ;
+typedef zap_status_t (*zio_sig_unload_t) ZIO_SIG_UNLOAD_ARGS ;
+typedef zap_status_t (*zio_api_t) ZIO_API_ARGS ;
+
+
+#define ZIO_CHANNEL_REQUEST_FUNCTION(name) zap_status_t name ZIO_CHANNEL_REQUEST_ARGS
+#define ZIO_CHANNEL_OUTGOING_CALL_FUNCTION(name) zap_status_t name ZIO_CHANNEL_OUTGOING_CALL_ARGS
+#define ZIO_SPAN_POLL_EVENT_FUNCTION(name) zap_status_t name ZIO_SPAN_POLL_EVENT_ARGS
+#define ZIO_SPAN_NEXT_EVENT_FUNCTION(name) zap_status_t name ZIO_SPAN_NEXT_EVENT_ARGS
+#define ZIO_SIGNAL_CB_FUNCTION(name) zap_status_t name ZIO_SIGNAL_CB_ARGS
+#define ZIO_EVENT_CB_FUNCTION(name) zap_status_t name ZIO_EVENT_CB_ARGS
+#define ZIO_CODEC_FUNCTION(name) OZ_DECLARE_NONSTD(zap_status_t) name ZIO_CODEC_ARGS
+#define ZIO_CONFIGURE_SPAN_FUNCTION(name) zap_status_t name ZIO_CONFIGURE_SPAN_ARGS
+#define ZIO_CONFIGURE_FUNCTION(name) zap_status_t name ZIO_CONFIGURE_ARGS
+#define ZIO_OPEN_FUNCTION(name) zap_status_t name ZIO_OPEN_ARGS
+#define ZIO_CLOSE_FUNCTION(name) zap_status_t name ZIO_CLOSE_ARGS
+#define ZIO_CHANNEL_DESTROY_FUNCTION(name) zap_status_t name ZIO_CHANNEL_DESTROY_ARGS
+#define ZIO_SPAN_DESTROY_FUNCTION(name) zap_status_t name ZIO_SPAN_DESTROY_ARGS
+#define ZIO_GET_ALARMS_FUNCTION(name) zap_status_t name ZIO_GET_ALARMS_ARGS
+#define ZIO_COMMAND_FUNCTION(name) zap_status_t name ZIO_COMMAND_ARGS
+#define ZIO_WAIT_FUNCTION(name) zap_status_t name ZIO_WAIT_ARGS
+#define ZIO_READ_FUNCTION(name) zap_status_t name ZIO_READ_ARGS
+#define ZIO_WRITE_FUNCTION(name) zap_status_t name ZIO_WRITE_ARGS
+#define ZIO_IO_LOAD_FUNCTION(name) zap_status_t name ZIO_IO_LOAD_ARGS
+#define ZIO_SIG_LOAD_FUNCTION(name) zap_status_t name ZIO_SIG_LOAD_ARGS
+#define ZIO_SIG_CONFIGURE_FUNCTION(name) zap_status_t name ZIO_SIG_CONFIGURE_ARGS
+#define ZIO_IO_UNLOAD_FUNCTION(name) zap_status_t name ZIO_IO_UNLOAD_ARGS
+#define ZIO_SIG_UNLOAD_FUNCTION(name) zap_status_t name ZIO_SIG_UNLOAD_ARGS
+#define ZIO_API_FUNCTION(name) zap_status_t name ZIO_API_ARGS
+
+#include "zap_dso.h"
+
+
+
+typedef struct {
+	char name[256];
+	zio_io_load_t io_load;
+	zio_io_unload_t io_unload;
+	zio_sig_load_t sig_load;
+	zio_sig_configure_t sig_configure;
+	zio_sig_unload_t sig_unload;
+	zap_dso_lib_t lib;
+	char path[256];
+} zap_module_t;
+
+#ifndef __FUNCTION__
+#define __FUNCTION__ (const char *)__func__
+#endif
+
+#define ZAP_PRE __FILE__, __FUNCTION__, __LINE__
+#define ZAP_LOG_LEVEL_DEBUG 7
+#define ZAP_LOG_LEVEL_INFO 6
+#define ZAP_LOG_LEVEL_NOTICE 5
+#define ZAP_LOG_LEVEL_WARNING 4
+#define ZAP_LOG_LEVEL_ERROR 3
+#define ZAP_LOG_LEVEL_CRIT 2
+#define ZAP_LOG_LEVEL_ALERT 1
+#define ZAP_LOG_LEVEL_EMERG 0
+
+#define ZAP_LOG_DEBUG ZAP_PRE, ZAP_LOG_LEVEL_DEBUG
+#define ZAP_LOG_INFO ZAP_PRE, ZAP_LOG_LEVEL_INFO
+#define ZAP_LOG_NOTICE ZAP_PRE, ZAP_LOG_LEVEL_NOTICE
+#define ZAP_LOG_WARNING ZAP_PRE, ZAP_LOG_LEVEL_WARNING
+#define ZAP_LOG_ERROR ZAP_PRE, ZAP_LOG_LEVEL_ERROR
+#define ZAP_LOG_CRIT ZAP_PRE, ZAP_LOG_LEVEL_CRIT
+#define ZAP_LOG_ALERT ZAP_PRE, ZAP_LOG_LEVEL_ALERT
+#define ZAP_LOG_EMERG ZAP_PRE, ZAP_LOG_LEVEL_EMERG
+
+typedef struct zap_fsk_data_state zap_fsk_data_state_t;
+typedef int (*zap_fsk_data_decoder_t)(zap_fsk_data_state_t *state);
+typedef zap_status_t (*zap_fsk_write_sample_t)(int16_t *buf, zap_size_t buflen, void *user_data);
+typedef void (*zap_logger_t)(const char *file, const char *func, int line, int level, const char *fmt, ...);
+typedef struct hashtable zap_hash_t;
+typedef struct hashtable_iterator zap_hash_iterator_t;
+typedef struct key zap_hash_key_t;
+typedef struct value zap_hash_val_t;
+typedef struct zap_bitstream zap_bitstream_t;
+typedef struct zap_fsk_modulator zap_fsk_modulator_t;
+typedef zap_status_t (*zap_span_start_t)(zap_span_t *span);
+typedef zap_status_t (*zap_span_stop_t)(zap_span_t *span);
+
+typedef enum {
+	ZAP_CAUSE_NONE = 0,
+	ZAP_CAUSE_UNALLOCATED = 1,
+	ZAP_CAUSE_NO_ROUTE_TRANSIT_NET = 2,
+	ZAP_CAUSE_NO_ROUTE_DESTINATION = 3,
+	ZAP_CAUSE_CHANNEL_UNACCEPTABLE = 6,
+	ZAP_CAUSE_CALL_AWARDED_DELIVERED = 7,
+	ZAP_CAUSE_NORMAL_CLEARING = 16,
+	ZAP_CAUSE_USER_BUSY = 17,
+	ZAP_CAUSE_NO_USER_RESPONSE = 18,
+	ZAP_CAUSE_NO_ANSWER = 19,
+	ZAP_CAUSE_SUBSCRIBER_ABSENT = 20,
+	ZAP_CAUSE_CALL_REJECTED = 21,
+	ZAP_CAUSE_NUMBER_CHANGED = 22,
+	ZAP_CAUSE_REDIRECTION_TO_NEW_DESTINATION = 23,
+	ZAP_CAUSE_EXCHANGE_ROUTING_ERROR = 25,
+	ZAP_CAUSE_DESTINATION_OUT_OF_ORDER = 27,
+	ZAP_CAUSE_INVALID_NUMBER_FORMAT = 28,
+	ZAP_CAUSE_FACILITY_REJECTED = 29,
+	ZAP_CAUSE_RESPONSE_TO_STATUS_ENQUIRY = 30,
+	ZAP_CAUSE_NORMAL_UNSPECIFIED = 31,
+	ZAP_CAUSE_NORMAL_CIRCUIT_CONGESTION = 34,
+	ZAP_CAUSE_NETWORK_OUT_OF_ORDER = 38,
+	ZAP_CAUSE_NORMAL_TEMPORARY_FAILURE = 41,
+	ZAP_CAUSE_SWITCH_CONGESTION = 42,
+	ZAP_CAUSE_ACCESS_INFO_DISCARDED = 43,
+	ZAP_CAUSE_REQUESTED_CHAN_UNAVAIL = 44,
+	ZAP_CAUSE_PRE_EMPTED = 45,
+	ZAP_CAUSE_FACILITY_NOT_SUBSCRIBED = 50,
+	ZAP_CAUSE_OUTGOING_CALL_BARRED = 52,
+	ZAP_CAUSE_INCOMING_CALL_BARRED = 54,
+	ZAP_CAUSE_BEARERCAPABILITY_NOTAUTH = 57,
+	ZAP_CAUSE_BEARERCAPABILITY_NOTAVAIL = 58,
+	ZAP_CAUSE_SERVICE_UNAVAILABLE = 63,
+	ZAP_CAUSE_BEARERCAPABILITY_NOTIMPL = 65,
+	ZAP_CAUSE_CHAN_NOT_IMPLEMENTED = 66,
+	ZAP_CAUSE_FACILITY_NOT_IMPLEMENTED = 69,
+	ZAP_CAUSE_SERVICE_NOT_IMPLEMENTED = 79,
+	ZAP_CAUSE_INVALID_CALL_REFERENCE = 81,
+	ZAP_CAUSE_INCOMPATIBLE_DESTINATION = 88,
+	ZAP_CAUSE_INVALID_MSG_UNSPECIFIED = 95,
+	ZAP_CAUSE_MANDATORY_IE_MISSING = 96,
+	ZAP_CAUSE_MESSAGE_TYPE_NONEXIST = 97,
+	ZAP_CAUSE_WRONG_MESSAGE = 98,
+	ZAP_CAUSE_IE_NONEXIST = 99,
+	ZAP_CAUSE_INVALID_IE_CONTENTS = 100,
+	ZAP_CAUSE_WRONG_CALL_STATE = 101,
+	ZAP_CAUSE_RECOVERY_ON_TIMER_EXPIRE = 102,
+	ZAP_CAUSE_MANDATORY_IE_LENGTH_ERROR = 103,
+	ZAP_CAUSE_PROTOCOL_ERROR = 111,
+	ZAP_CAUSE_INTERWORKING = 127,
+	ZAP_CAUSE_SUCCESS = 142,
+	ZAP_CAUSE_ORIGINATOR_CANCEL = 487,
+	ZAP_CAUSE_CRASH = 500,
+	ZAP_CAUSE_SYSTEM_SHUTDOWN = 501,
+	ZAP_CAUSE_LOSE_RACE = 502,
+	ZAP_CAUSE_MANAGER_REQUEST = 503,
+	ZAP_CAUSE_BLIND_TRANSFER = 600,
+	ZAP_CAUSE_ATTENDED_TRANSFER = 601,
+	ZAP_CAUSE_ALLOTTED_TIMEOUT = 602,
+	ZAP_CAUSE_USER_CHALLENGE = 603,
+	ZAP_CAUSE_MEDIA_TIMEOUT = 604
+} zap_call_cause_t;
+
+
+#endif
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
+

Added: freeswitch/trunk/libs/openzap/src/isdn/5ESSStateNT.c (0 => 17141)


--- freeswitch/trunk/libs/openzap/src/isdn/5ESSStateNT.c	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/src/isdn/5ESSStateNT.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,132 @@
+/*****************************************************************************
+
+  FileName:     5ESSStateNT.c
+
+  Contents:     AT&T 5ESS ISDN State Engine for NT (Network Mode).
+
+	            The controlling state engine for Q.931 is the state engine
+	            on the NT side. The state engine on the TE side is a slave 
+	            of this. The TE side maintain it's own states as described in
+	            ITU-T Q931, but will in    raise conditions be overridden by 
+	            the NT side.
+
+  License/Copyright:
+
+  Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+  email:janvb@caselaboratories.com  
+
+  Copyright (c) 2007, Michael Jerris. All rights reserved.
+  email:mike@jerris.com  
+  
+  Copyright (c) 2007, Michael S. Collins, All rights reserved.
+  email:mcollins@fcnetwork.com
+  
+  Redistribution and use in source and binary forms, with or without 
+  modification, are permitted provided that the following conditions are 
+  met:
+
+	* Redistributions of source code must retain the above copyright notice, 
+	  this list of conditions and the following disclaimer.
+	* Redistributions in binary form must reproduce the above copyright notice, 
+	  this list of conditions and the following disclaimer in the documentation 
+	  and/or other materials provided with the distribution.
+	* Neither the name of the Case Labs, Ltd nor the names of its contributors 
+	  may be used to endorse or promote products derived from this software 
+	  without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
+  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
+  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+  POSSIBILITY OF SUCH DAMAGE.
+*****************************************************************************/
+
+#include "5ESS.h"
+
+/*****************************************************************************
+  Function:     ATT5ESSCreateNT
+
+  Description:  Will create the AT&T 5ESS ISDN NT as a Dialect in the stack. The first
+	            bulk set up the message handlers, the second bulk the IE
+	            encoders/coders, and the last bulk set up the state table.
+
+  Parameters:   i       Dialect index
+*****************************************************************************/
+void ATT5ESSCreateNT(L3UCHAR i)
+{
+	Q931SetMesProc(Q931mes_ALERTING,             i, Q931ProcAlertingNT,          Q931Umes_Alerting,          Q931Pmes_Alerting);
+	Q931SetMesProc(Q931mes_CALL_PROCEEDING,      i, Q931ProcCallProceedingNT,    Q931Umes_CallProceeding,    Q931Pmes_CallProceeding);
+	Q931SetMesProc(Q931mes_CONNECT,              i, Q931ProcConnectNT,           Q931Umes_Connect,           Q931Pmes_Connect);
+	Q931SetMesProc(Q931mes_CONNECT_ACKNOWLEDGE,  i, Q931ProcConnectAckNT,        Q931Umes_ConnectAck,        Q931Pmes_ConnectAck);
+	Q931SetMesProc(Q931mes_PROGRESS,             i, Q931ProcProgressNT,          Q931Umes_Progress,          Q931Pmes_Progress);
+	Q931SetMesProc(Q931mes_SETUP,                i, Q931ProcSetupNT,             Q931Umes_Setup,             Q931Pmes_Setup);
+	Q931SetMesProc(Q931mes_SETUP_ACKNOWLEDGE,    i, Q931ProcSetupAckNT,          Q931Umes_SetupAck,          Q931Pmes_SetupAck);
+	Q931SetMesProc(Q931mes_RESUME,               i, Q931ProcResumeNT,            Q931Umes_Resume,            Q931Pmes_Resume);
+	Q931SetMesProc(Q931mes_RESUME_ACKNOWLEDGE,   i, Q931ProcResumeAckNT,         Q931Umes_ResumeAck,         Q931Pmes_ResumeAck);
+	Q931SetMesProc(Q931mes_RESUME_REJECT,        i, Q931ProcResumeRejectNT,      Q931Umes_ResumeReject,      Q931Pmes_ResumeReject);
+	Q931SetMesProc(Q931mes_SUSPEND,              i, Q931ProcSuspendNT,           Q931Umes_Suspend,           Q931Pmes_Suspend);
+	Q931SetMesProc(Q931mes_SUSPEND_ACKNOWLEDGE,  i, Q931ProcSuspendAckNT,        Q931Umes_SuspendAck,        Q931Pmes_SuspendAck);
+	Q931SetMesProc(Q931mes_SUSPEND_REJECT,       i, Q931ProcSuspendRejectNT,     Q931Umes_SuspendReject,     Q931Pmes_SuspendReject);
+	Q931SetMesProc(Q931mes_USER_INFORMATION,     i, Q931ProcUserInformationNT,   Q931Umes_UserInformation,   Q931Pmes_UserInformation);
+	Q931SetMesProc(Q931mes_DISCONNECT,           i, Q931ProcDisconnectNT,        Q931Umes_Disconnect,        Q931Pmes_Disconnect);
+	Q931SetMesProc(Q931mes_RELEASE,              i, Q931ProcReleaseNT,           Q931Umes_Release,           Q931Pmes_Release);
+	Q931SetMesProc(Q931mes_RELEASE_COMPLETE,     i, Q931ProcReleaseCompleteNT,   Q931Umes_ReleaseComplete,   Q931Pmes_ReleaseComplete);
+	Q931SetMesProc(Q931mes_RESTART,              i, Q931ProcRestartNT,           Q931Umes_Restart,           Q931Pmes_Restart);
+	Q931SetMesProc(Q931mes_RESTART_ACKNOWLEDGE,  i, Q931ProcRestartAckNT,        Q931Umes_RestartAck,        Q931Pmes_RestartAck);
+	Q931SetMesProc(Q931mes_CONGESTION_CONTROL,   i, Q931ProcCongestionControlNT, Q931Umes_CongestionControl, Q931Pmes_CongestionControl);
+	Q931SetMesProc(Q931mes_INFORMATION,          i, Q931ProcInformationNT,       Q931Umes_Information,       Q931Pmes_Information);
+	Q931SetMesProc(Q931mes_NOTIFY,               i, Q931ProcNotifyNT,            Q931Umes_Notify,            Q931Pmes_Notify);
+	Q931SetMesProc(Q931mes_STATUS,               i, Q931ProcStatusNT,            Q931Umes_Status,            Q931Pmes_Status);
+	Q931SetMesProc(Q931mes_STATUS_ENQUIRY,       i, Q931ProcStatusEnquiryNT,     Q931Umes_StatusEnquiry,     Q931Pmes_StatusEnquiry);
+	Q931SetMesProc(Q931mes_SEGMENT,              i, Q931ProcSegmentNT,           Q931Umes_Segment,           Q931Pmes_Segment);
+
+	Q931SetMesProc(Q932mes_FACILITY,             i, Q932ProcFacilityNT,          Q932Umes_Facility,          Q932Pmes_Facility);
+	Q931SetMesProc(Q932mes_HOLD,                 i, Q932ProcHoldNT,              Q932Umes_Hold,              Q932Pmes_Hold);
+	Q931SetMesProc(Q932mes_HOLD_ACKNOWLEDGE,     i, Q932ProcHoldAckNT,           Q932Umes_HoldAck,           Q932Pmes_HoldAck);
+	Q931SetMesProc(Q932mes_HOLD_REJECT,          i, Q932ProcHoldRejectNT,        Q932Umes_HoldReject,        Q932Pmes_HoldReject);
+	Q931SetMesProc(Q932mes_REGISTER,             i, Q932ProcRegisterNT,          Q932Umes_Register,          Q932Pmes_Register);
+	Q931SetMesProc(Q932mes_RETRIEVE,             i, Q932ProcRetrieveNT,          Q932Umes_Retrieve,          Q932Pmes_Retrieve);
+	Q931SetMesProc(Q932mes_RETRIEVE_ACKNOWLEDGE, i, Q932ProcRetrieveAckNT,       Q932Umes_RetrieveAck,       Q932Pmes_RetrieveAck);
+	Q931SetMesProc(Q932mes_RETRIEVE_REJECT,      i, Q932ProcRetrieveRejectNT,    Q932Umes_RetrieveReject,    Q932Pmes_RetrieveReject);
+
+	/* Set up the IE encoder/decoder handle table.*/ 
+	Q931SetIEProc(Q931ie_SEGMENTED_MESSAGE,                i, Q931Pie_Segment,           Q931Uie_Segment);
+	Q931SetIEProc(Q931ie_BEARER_CAPABILITY,                i, Q931Pie_BearerCap,         Q931Uie_BearerCap);
+	Q931SetIEProc(Q931ie_CAUSE,                            i, Q931Pie_Cause,             Q931Uie_Cause);
+	Q931SetIEProc(Q931ie_CALL_IDENTITY,                    i, Q931Pie_CallID,            Q931Uie_CallID);
+	Q931SetIEProc(Q931ie_CALL_STATE,                       i, Q931Pie_CallState,         Q931Uie_CallState);
+	Q931SetIEProc(Q931ie_CHANNEL_IDENTIFICATION,           i, Q931Pie_ChanID,            Q931Uie_ChanID);
+	Q931SetIEProc(Q931ie_PROGRESS_INDICATOR,               i, Q931Pie_ProgInd,           Q931Uie_ProgInd);
+	Q931SetIEProc(Q931ie_NETWORK_SPECIFIC_FACILITIES,      i, Q931Pie_NetFac,            Q931Uie_NetFac);
+	Q931SetIEProc(Q931ie_NOTIFICATION_INDICATOR,           i, Q931Pie_NotifInd,          Q931Uie_NotifInd);
+	Q931SetIEProc(Q931ie_DISPLAY,                          i, Q931Pie_Display,           Q931Uie_Display);
+	Q931SetIEProc(Q931ie_DATETIME,                         i, Q931Pie_DateTime,          Q931Uie_DateTime);
+	Q931SetIEProc(Q931ie_KEYPAD_FACILITY,                  i, Q931Pie_KeypadFac,         Q931Uie_KeypadFac);
+	Q931SetIEProc(Q931ie_SIGNAL,                           i, Q931Pie_Signal,            Q931Uie_Signal);
+	Q931SetIEProc(Q931ie_TRANSIT_DELAY_SELECTION_AND_IND,  i, Q931Pie_TransNetSel,       Q931Uie_TransNetSel);
+	Q931SetIEProc(Q931ie_CALLING_PARTY_NUMBER,             i, Q931Pie_CallingNum,        Q931Uie_CallingNum);
+	Q931SetIEProc(Q931ie_CALLING_PARTY_SUBADDRESS,         i, Q931Pie_CallingSub,        Q931Uie_CallingSub);
+	Q931SetIEProc(Q931ie_CALLED_PARTY_NUMBER,              i, Q931Pie_CalledNum,         Q931Uie_CalledNum);
+	Q931SetIEProc(Q931ie_CALLED_PARTY_SUBADDRESS,          i, Q931Pie_CalledSub,         Q931Uie_CalledSub);
+	Q931SetIEProc(Q931ie_TRANSIT_NETWORK_SELECTION,        i, Q931Pie_TransNetSel,       Q931Uie_TransNetSel);
+	Q931SetIEProc(Q931ie_RESTART_INDICATOR,                i, Q931Pie_RestartInd,        Q931Uie_RestartInd);
+	Q931SetIEProc(Q931ie_LOW_LAYER_COMPATIBILITY,          i, Q931Pie_LLComp,            Q931Uie_LLComp);
+	Q931SetIEProc(Q931ie_HIGH_LAYER_COMPATIBILITY,         i, Q931Pie_HLComp,            Q931Uie_HLComp);
+	Q931SetIEProc(Q931ie_USER_USER,                        i, Q931Pie_UserUser,          Q931Uie_UserUser);
+	Q931SetIEProc(Q931ie_GENERIC_DIGITS,                   i, Q931Pie_GenericDigits,     Q931Uie_GenericDigits);
+
+	Q931SetIEProc(Q931ie_CONNECTED_NUMBER, i, Q931Pie_Generic, Q931Uie_Generic);
+	Q931SetIEProc(Q931ie_FACILITY,         i, Q931Pie_Generic, Q931Uie_Generic);
+
+	/* The following define a state machine. The point is that the Message  */
+	/* procs can when search this to find out if the message/state          */
+	/* combination is legale. If not, the proc for unexpected message apply.*/
+
+	/* TODO define state table here */
+}

Added: freeswitch/trunk/libs/openzap/src/isdn/5ESSStateTE.c (0 => 17141)


--- freeswitch/trunk/libs/openzap/src/isdn/5ESSStateTE.c	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/src/isdn/5ESSStateTE.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,291 @@
+/*****************************************************************************
+
+  FileName:     5ESSStateTE.c
+
+  Contents:     AT&T 5ESS ISDN State Engine for TE (User Mode).
+
+	            The controlling state engine for Q.931 is the state engine
+	            on the NT side. The state engine on the TE side is a slave 
+	            of this. The TE side maintain it's own states as described in
+	            ITU-T Q931, but will in    raise conditions be overridden by 
+	            the NT side.
+
+	            This reference implementation uses a process per message, 
+	            meaning that each message must check call states. This
+	            is easier for dialect maintenance as each message proc
+	            can be replaced individually. A new TE variant only
+	            need to copy the Q931CreateTE and replace those procs or
+	            need to override.
+
+  License/Copyright:
+
+  Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+  email:janvb@caselaboratories.com  
+
+  Copyright (c) 2007, Michael Jerris. All rights reserved.
+  email:mike@jerris.com  
+  
+  Copyright (c) 2007, Michael S. Collins, All rights reserved.
+  email:mcollins@fcnetwork.com
+  
+  Redistribution and use in source and binary forms, with or without 
+  modification, are permitted provided that the following conditions are 
+  met:
+
+	* Redistributions of source code must retain the above copyright notice, 
+	this list of conditions and the following disclaimer.
+	* Redistributions in binary form must reproduce the above copyright notice, 
+	this list of conditions and the following disclaimer in the documentation 
+	and/or other materials provided with the distribution.
+	* Neither the name of the Case Labs, Ltd nor the names of its contributors 
+	may be used to endorse or promote products derived from this software 
+	without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
+  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
+  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+  POSSIBILITY OF SUCH DAMAGE.
+*****************************************************************************/
+
+#include "5ESS.h"
+extern L3INT Q931L4HeaderSpace;
+
+/*****************************************************************************
+  Function:     ATT5ESSCreateTE
+
+  Description:  Will create the AT&T 5ESS TE as a Dialect in the stack. The first
+	            bulk set up the message handlers, the second bulk the IE
+	            encoders/coders, and the last bulk set up the state table.
+
+  Parameters:   i       Dialect index
+*****************************************************************************/
+void ATT5ESSCreateTE(L3UCHAR i)
+{
+	Q931SetMesProc(Q931mes_ALERTING,             i, Q931ProcAlertingTE,          Q931Umes_Alerting,          Q931Pmes_Alerting);
+	Q931SetMesProc(Q931mes_CALL_PROCEEDING,      i, Q931ProcCallProceedingTE,    Q931Umes_CallProceeding,    Q931Pmes_CallProceeding);
+	Q931SetMesProc(Q931mes_CONNECT,              i, ATT5ESSProc0x07TE,           ATT5ESSUmes_0x07,           ATT5ESSPmes_0x07);
+	Q931SetMesProc(Q931mes_CONNECT_ACKNOWLEDGE,  i, ATT5ESSProc0x0fTE,           ATT5ESSUmes_0x0f,           ATT5ESSPmes_0x0f);
+	Q931SetMesProc(Q931mes_PROGRESS,             i, Q931ProcProgressTE,          Q931Umes_Progress,          Q931Pmes_Progress);
+	Q931SetMesProc(Q931mes_SETUP,                i, Q931ProcSetupTE,             ATT5ESSUmes_Setup,          ATT5ESSPmes_Setup);
+	Q931SetMesProc(Q931mes_SETUP_ACKNOWLEDGE,    i, Q931ProcSetupAckTE,          Q931Umes_SetupAck,          Q931Pmes_SetupAck);
+	Q931SetMesProc(Q931mes_RESUME,               i, Q931ProcResumeTE,            Q931Umes_Resume,            Q931Pmes_Resume);
+	Q931SetMesProc(Q931mes_RESUME_ACKNOWLEDGE,   i, Q931ProcResumeAckTE,         Q931Umes_ResumeAck,         Q931Pmes_ResumeAck);
+	Q931SetMesProc(Q931mes_RESUME_REJECT,        i, Q931ProcResumeRejectTE,      Q931Umes_ResumeReject,      Q931Pmes_ResumeReject);
+	Q931SetMesProc(Q931mes_SUSPEND,              i, Q931ProcSuspendTE,           Q931Umes_Suspend,           Q931Pmes_Suspend);
+	Q931SetMesProc(Q931mes_SUSPEND_ACKNOWLEDGE,  i, Q931ProcSuspendAckTE,        Q931Umes_SuspendAck,        Q931Pmes_SuspendAck);
+	Q931SetMesProc(Q931mes_SUSPEND_REJECT,       i, Q931ProcSuspendRejectTE,     Q931Umes_SuspendReject,     Q931Pmes_SuspendReject);
+	Q931SetMesProc(Q931mes_USER_INFORMATION,     i, Q931ProcUserInformationTE,   Q931Umes_UserInformation,   Q931Pmes_UserInformation);
+	Q931SetMesProc(Q931mes_DISCONNECT,           i, Q931ProcDisconnectTE,        Q931Umes_Disconnect,        Q931Pmes_Disconnect);
+	Q931SetMesProc(Q931mes_RELEASE,              i, Q931ProcReleaseTE,           Q931Umes_Release,           Q931Pmes_Release);
+	Q931SetMesProc(Q931mes_RELEASE_COMPLETE,     i, Q931ProcReleaseCompleteTE,   Q931Umes_ReleaseComplete,   Q931Pmes_ReleaseComplete);
+	Q931SetMesProc(Q931mes_RESTART,              i, Q931ProcRestartTE,           Q931Umes_Restart,           Q931Pmes_Restart);
+	Q931SetMesProc(Q931mes_RESTART_ACKNOWLEDGE,  i, Q931ProcRestartAckTE,        Q931Umes_RestartAck,        Q931Pmes_RestartAck);
+	Q931SetMesProc(Q931mes_CONGESTION_CONTROL,   i, Q931ProcCongestionControlTE, Q931Umes_CongestionControl, Q931Pmes_CongestionControl);
+	Q931SetMesProc(Q931mes_INFORMATION,          i, Q931ProcInformationTE,       Q931Umes_Information,       Q931Pmes_Information);
+	Q931SetMesProc(Q931mes_NOTIFY,               i, Q931ProcNotifyTE,            Q931Umes_Notify,            Q931Pmes_Notify);
+	Q931SetMesProc(Q931mes_STATUS,               i, Q931ProcStatusTE,            Q931Umes_Status,            Q931Pmes_Status);
+	Q931SetMesProc(Q931mes_STATUS_ENQUIRY,       i, Q931ProcStatusEnquiryTE,     Q931Umes_StatusEnquiry,     Q931Pmes_StatusEnquiry);
+	Q931SetMesProc(Q931mes_SEGMENT,              i, Q931ProcSegmentTE,           Q931Umes_Segment,           Q931Pmes_Segment);
+
+	Q931SetMesProc(Q932mes_FACILITY,             i, Q932ProcFacilityTE,          Q932Umes_Facility,          Q932Pmes_Facility);
+	Q931SetMesProc(Q932mes_HOLD,                 i, Q932ProcHoldTE,              Q932Umes_Hold,              Q932Pmes_Hold);
+	Q931SetMesProc(Q932mes_HOLD_ACKNOWLEDGE,     i, Q932ProcHoldAckTE,           Q932Umes_HoldAck,           Q932Pmes_HoldAck);
+	Q931SetMesProc(Q932mes_HOLD_REJECT,          i, Q932ProcHoldRejectTE,        Q932Umes_HoldReject,        Q932Pmes_HoldReject);
+	Q931SetMesProc(Q932mes_REGISTER,             i, Q932ProcRegisterTE,          Q932Umes_Register,          Q932Pmes_Register);
+	Q931SetMesProc(Q932mes_RETRIEVE,             i, Q932ProcRetrieveTE,          Q932Umes_Retrieve,          Q932Pmes_Retrieve);
+	Q931SetMesProc(Q932mes_RETRIEVE_ACKNOWLEDGE, i, Q932ProcRetrieveAckTE,       Q932Umes_RetrieveAck,       Q932Pmes_RetrieveAck);
+	Q931SetMesProc(Q932mes_RETRIEVE_REJECT,      i, Q932ProcRetrieveRejectTE,    Q932Umes_RetrieveReject,    Q932Pmes_RetrieveReject);
+
+	/* Set up the IE encoder/decoder handle table.*/ 
+	Q931SetIEProc(Q931ie_SEGMENTED_MESSAGE,                i, Q931Pie_Segment,           Q931Uie_Segment);
+	Q931SetIEProc(Q931ie_BEARER_CAPABILITY,                i, Q931Pie_BearerCap,         Q931Uie_BearerCap);
+	Q931SetIEProc(Q931ie_CAUSE,                            i, Q931Pie_Cause,             Q931Uie_Cause);
+	Q931SetIEProc(Q931ie_CALL_IDENTITY,                    i, Q931Pie_CallID,            Q931Uie_CallID);
+	Q931SetIEProc(Q931ie_CALL_STATE,                       i, Q931Pie_CallState,         Q931Uie_CallState);
+	Q931SetIEProc(Q931ie_CHANGE_STATUS,                    i, Q931Pie_ChangeStatus,      Q931Uie_ChangeStatus);
+	Q931SetIEProc(Q931ie_CHANNEL_IDENTIFICATION,           i, Q931Pie_ChanID,            Q931Uie_ChanID);
+	Q931SetIEProc(Q931ie_PROGRESS_INDICATOR,               i, Q931Pie_ProgInd,           Q931Uie_ProgInd);
+	Q931SetIEProc(Q931ie_NETWORK_SPECIFIC_FACILITIES,      i, Q931Pie_NetFac,            Q931Uie_NetFac);
+	Q931SetIEProc(Q931ie_NOTIFICATION_INDICATOR,           i, Q931Pie_NotifInd,          Q931Uie_NotifInd);
+	Q931SetIEProc(Q931ie_DISPLAY,                          i, Q931Pie_Display,           Q931Uie_Display);
+	Q931SetIEProc(Q931ie_DATETIME,                         i, Q931Pie_DateTime,          Q931Uie_DateTime);
+	Q931SetIEProc(Q931ie_KEYPAD_FACILITY,                  i, Q931Pie_KeypadFac,         Q931Uie_KeypadFac);
+	Q931SetIEProc(Q931ie_SIGNAL,                           i, Q931Pie_Signal,            Q931Uie_Signal);
+	Q931SetIEProc(Q931ie_TRANSIT_DELAY_SELECTION_AND_IND,  i, Q931Pie_TransNetSel,       Q931Uie_TransNetSel);
+	Q931SetIEProc(Q931ie_CALLING_PARTY_NUMBER,             i, Q931Pie_CallingNum,        Q931Uie_CallingNum);
+	Q931SetIEProc(Q931ie_CALLING_PARTY_SUBADDRESS,         i, Q931Pie_CallingSub,        Q931Uie_CallingSub);
+	Q931SetIEProc(Q931ie_CALLED_PARTY_NUMBER,              i, Q931Pie_CalledNum,         Q931Uie_CalledNum);
+	Q931SetIEProc(Q931ie_CALLED_PARTY_SUBADDRESS,          i, Q931Pie_CalledSub,         Q931Uie_CalledSub);
+	Q931SetIEProc(Q931ie_TRANSIT_NETWORK_SELECTION,        i, Q931Pie_TransNetSel,       Q931Uie_TransNetSel);
+	Q931SetIEProc(Q931ie_RESTART_INDICATOR,                i, Q931Pie_RestartInd,        Q931Uie_RestartInd);
+	Q931SetIEProc(Q931ie_LOW_LAYER_COMPATIBILITY,          i, Q931Pie_LLComp,            Q931Uie_LLComp);
+	Q931SetIEProc(Q931ie_HIGH_LAYER_COMPATIBILITY,         i, Q931Pie_HLComp,            Q931Uie_HLComp);
+	Q931SetIEProc(Q931ie_USER_USER,                        i, Q931Pie_UserUser,          Q931Uie_UserUser);
+	Q931SetIEProc(Q931ie_GENERIC_DIGITS,                   i, Q931Pie_GenericDigits,     Q931Uie_GenericDigits);
+
+	Q931SetIEProc(Q931ie_CONNECTED_NUMBER, i, Q931Pie_Generic, Q931Uie_Generic);
+	Q931SetIEProc(Q931ie_FACILITY,         i, Q931Pie_Generic, Q931Uie_Generic);
+
+	/* The following define a state machine. The point is that the Message  */
+	/* procs can when search this to find out if the message/state          */
+	/* combination is legale. If not, the proc for unexpected message apply.*/
+
+	/* State 0 Idle */
+	Q931AddStateEntry(i, Q931_U0,    Q931mes_RESUME,             2);
+	Q931AddStateEntry(i, Q931_U0,    Q931mes_SETUP,              4);
+	Q931AddStateEntry(i, Q931_U0,    Q931mes_SETUP,              2);
+	Q931AddStateEntry(i, Q931_U0,    Q931mes_STATUS,             4);
+	Q931AddStateEntry(i, Q931_U0,    Q931mes_RELEASE,            4);
+	Q931AddStateEntry(i, Q931_U0,    Q931mes_RELEASE_COMPLETE,   4);
+
+	/* State 1 Call Initiating */
+	Q931AddStateEntry(i, Q931_U1,    Q931mes_DISCONNECT,         2);
+	Q931AddStateEntry(i, Q931_U1,    Q931mes_SETUP_ACKNOWLEDGE,  4);
+	Q931AddStateEntry(i, Q931_U1,    Q931mes_RELEASE_COMPLETE,   4);
+	Q931AddStateEntry(i, Q931_U1,    Q931mes_CALL_PROCEEDING,    4);
+	Q931AddStateEntry(i, Q931_U1,    Q931mes_ALERTING,           4);
+	Q931AddStateEntry(i, Q931_U1,    Q931mes_CONNECT,            4);
+
+	/* State 2 Overlap Sending */
+	Q931AddStateEntry(i, Q931_U2,    Q931mes_INFORMATION,        2);
+	Q931AddStateEntry(i, Q931_U2,    Q931mes_CALL_PROCEEDING,    4);
+	Q931AddStateEntry(i, Q931_U2,    Q931mes_ALERTING,           4);
+	Q931AddStateEntry(i, Q931_U2,    Q931mes_PROGRESS,           4);
+	Q931AddStateEntry(i, Q931_U2,    Q931mes_CONNECT,            4);
+	Q931AddStateEntry(i, Q931_U2,    Q931mes_RELEASE,            2);
+
+	/* State 3 Outgoing Call Proceeding */
+	Q931AddStateEntry(i, Q931_U3,    Q931mes_PROGRESS,           4);
+	Q931AddStateEntry(i, Q931_U3,    Q931mes_ALERTING,           4);
+	Q931AddStateEntry(i, Q931_U3,    Q931mes_CONNECT,            4);
+	Q931AddStateEntry(i, Q931_U3,    Q931mes_RELEASE,            2);
+
+	/* State 4 Call Delivered */
+	Q931AddStateEntry(i, Q931_U4,    Q931mes_CONNECT,            4);
+
+	/* State 6 Call Precent */
+	Q931AddStateEntry(i, Q931_U6,    Q931mes_INFORMATION,        2);
+	Q931AddStateEntry(i, Q931_U6,    Q931mes_ALERTING,           2);
+	Q931AddStateEntry(i, Q931_U6,    Q931mes_CALL_PROCEEDING,    2);
+	Q931AddStateEntry(i, Q931_U6,    Q931mes_CONNECT,            2);
+	Q931AddStateEntry(i, Q931_U6,    Q931mes_RELEASE_COMPLETE,   2);
+	Q931AddStateEntry(i, Q931_U6,    Q931mes_RELEASE,            4);
+	Q931AddStateEntry(i, Q931_U6,    Q931mes_DISCONNECT,         4);
+
+	/* State 7 Call Received */
+	Q931AddStateEntry(i, Q931_U7,    Q931mes_CONNECT,            2);
+
+	/* State 8 Connect request */
+	Q931AddStateEntry(i, Q931_U8,    Q931mes_CONNECT_ACKNOWLEDGE, 4);
+
+	/* State 9 Incoming Call Proceeding */
+	Q931AddStateEntry(i, Q931_U9,    Q931mes_CONNECT,            2);
+	Q931AddStateEntry(i, Q931_U9,    Q931mes_ALERTING,           2);
+	Q931AddStateEntry(i, Q931_U9,    Q931mes_PROGRESS,           2);
+
+	/* State 10 Active */
+	Q931AddStateEntry(i, Q931_U10,   Q931mes_SUSPEND,            2);
+	Q931AddStateEntry(i, Q931_U10,   Q931mes_NOTIFY,             4);
+	Q931AddStateEntry(i, Q931_U10,   Q931mes_NOTIFY,             2);
+
+	/* State 11 Disconnect Request */
+	Q931AddStateEntry(i, Q931_U11,   Q931mes_RELEASE,            4);
+	Q931AddStateEntry(i, Q931_U11,   Q931mes_DISCONNECT,         4);
+	Q931AddStateEntry(i, Q931_U11,   Q931mes_NOTIFY,             4);
+
+	/* State 12 Disconnect Ind */
+	Q931AddStateEntry(i, Q931_U12,   Q931mes_RELEASE,            4);
+	Q931AddStateEntry(i, Q931_U12,   Q931mes_RELEASE,            2);
+
+	/* State 15 Suspend Request */
+	Q931AddStateEntry(i, Q931_U15,   Q931mes_SUSPEND_ACKNOWLEDGE, 4);
+	Q931AddStateEntry(i, Q931_U15,   Q931mes_SUSPEND_REJECT,      4);
+	Q931AddStateEntry(i, Q931_U15,   Q931mes_DISCONNECT,          4);
+	Q931AddStateEntry(i, Q931_U15,   Q931mes_RELEASE,             4);
+
+/* TODO
+	Q931AddStateEntry(i, Q931_U17, 
+	Q931AddStateEntry(i, Q931_U19, 
+	Q931AddStateEntry(i, Q931_U25, 
+*/
+}
+
+/*****************************************************************************
+
+  Function:		ATT5ESSProc0x0fTE
+
+*****************************************************************************/
+L3INT ATT5ESSProc0x0fTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	if (pMes->ProtDisc == 8) {
+		/* Find the call using CRV */
+		ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+		if (ret != Q931E_NO_ERROR)
+			return ret;
+
+		/* TODO chack against state table for illegal or unexpected message here*/
+
+		/* TODO - Set correct timer here */
+		Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	}
+	if (iFrom == 4) {
+		/* TODO Add proc here*/
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom ==2) {
+		/* TODO Add proc here*/
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+
+		if (pMes->ProtDisc == 3 && pTrunk->autoServiceAck) {
+			printf("autoServiceAck is on, responding to Service Req from network...\n");
+			Q931AckService(pTrunk, buf);
+		}
+	}
+	return ret;
+
+}
+
+/*****************************************************************************
+
+  Function:		ATT5ESSProc0x07TE
+
+*****************************************************************************/
+L3INT ATT5ESSProc0x07TE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	if (pMes->ProtDisc == 8) {
+		/* Find the call using CRV */
+		ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+		if (ret != Q931E_NO_ERROR)
+			return ret;
+
+		/* TODO chack against state table for illegal or unexpected message here*/
+
+		/* TODO - Set correct timer here */
+		Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	}
+	if (iFrom == 4) {
+		/* TODO Add proc here*/
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here*/
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+
+}

Added: freeswitch/trunk/libs/openzap/src/isdn/5ESSmes.c (0 => 17141)


--- freeswitch/trunk/libs/openzap/src/isdn/5ESSmes.c	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/src/isdn/5ESSmes.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,361 @@
+/*****************************************************************************
+
+  FileName:	5ESSmes.c
+
+  Contents:	Pack/Unpack functions. These functions will unpack a 5ESS ISDN
+		message from the bit packed original format into structs
+		that contains variables sized by the user. It will also pack
+		the struct back into a Q.931 message as required.
+
+		See 5ESS.h for description. 
+
+  License/Copyright:
+
+  Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+  email:janvb@caselaboratories.com  
+
+  Copyright (c) 2007, Michael Jerris. All rights reserved.
+  email:mike@jerris.com
+  
+  Copyright (c) 2007, Michael S. Collins, All rights reserved.
+  email:mcollins@fcnetwork.com
+
+  Redistribution and use in source and binary forms, with or without 
+  modification, are permitted provided that the following conditions are 
+  met:
+
+	* Redistributions of source code must retain the above copyright notice, 
+	this list of conditions and the following disclaimer.
+	* Redistributions in binary form must reproduce the above copyright notice, 
+	this list of conditions and the following disclaimer in the documentation 
+	and/or other materials provided with the distribution.
+	* Neither the name of the Case Labs, Ltd nor the names of its contributors 
+	may be used to endorse or promote products derived from this software 
+	without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
+  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
+  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+  POSSIBILITY OF SUCH DAMAGE.
+
+*****************************************************************************/
+
+#include "5ESS.h"
+
+/*****************************************************************************
+
+  Function:	 ATT5ESSUmes_Setup
+
+*****************************************************************************/
+L3INT ATT5ESSUmes_Setup(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+	L3INT ir = 0;
+	L3INT OOff = 0;
+	L3INT rc = Q931E_NO_ERROR;
+	L3UCHAR last_codeset = 0, codeset = 0;
+	L3UCHAR shift_nolock = 1;
+
+	while (IOff < Size) {
+
+		if (shift_nolock) {
+			codeset = last_codeset;
+		}
+
+		if ((IBuf[IOff] & 0xF0) == Q931ie_SHIFT) {
+			shift_nolock = (IBuf[IOff] & 0x08);
+			if (shift_nolock) {
+				last_codeset = codeset;
+			}
+			codeset = ((IBuf[IOff] & 0x07));
+			IOff++;
+		}
+
+		if (codeset == 0) {
+			switch (IBuf[IOff])
+			{
+			case Q931ie_SENDING_COMPLETE:
+			case Q931ie_BEARER_CAPABILITY:
+			case Q931ie_CHANNEL_IDENTIFICATION:
+			case Q931ie_PROGRESS_INDICATOR:
+			case Q931ie_NETWORK_SPECIFIC_FACILITIES:
+			case Q931ie_DISPLAY:
+			case Q931ie_DATETIME:
+			case Q931ie_KEYPAD_FACILITY:
+			case Q931ie_SIGNAL:
+			case Q931ie_CALLING_PARTY_NUMBER:
+			case Q931ie_CALLING_PARTY_SUBADDRESS:
+			case Q931ie_CALLED_PARTY_NUMBER:
+			case Q931ie_CALLED_PARTY_SUBADDRESS:
+			case Q931ie_TRANSIT_NETWORK_SELECTION:
+			case Q931ie_LOW_LAYER_COMPATIBILITY:
+			case Q931ie_HIGH_LAYER_COMPATIBILITY:
+			case Q931ie_FACILITY:
+				rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+				if (rc != Q931E_NO_ERROR) 
+					return rc;
+				break;
+			case Q931ie_REPEAT_INDICATOR:
+				if (ir < 2) {
+					rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+					ir++;
+				} else {
+					return Q931E_ILLEGAL_IE;
+				}
+				break;
+			default:
+				return Q931E_ILLEGAL_IE;
+				break;
+			}
+		} else if (codeset == 6) {
+			switch (IBuf[IOff])
+			{
+			case Q931ie_GENERIC_DIGITS:
+				rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+				if (rc != Q931E_NO_ERROR) 
+					return rc;
+				break;
+			default:
+				return Q931E_ILLEGAL_IE;
+				break;
+			}
+		} else if (codeset == 7) {
+			switch (IBuf[IOff])
+			{
+			case Q931ie_DISPLAY:
+				rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+				if (rc != Q931E_NO_ERROR) 
+					return rc;
+				break;
+			default:
+				return Q931E_ILLEGAL_IE;
+				break;
+			}
+		} else {
+			return Q931E_ILLEGAL_IE;
+		}
+	}
+	mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:	 ATT5ESSPmes_Setup
+
+  Decription:   Pack a Q931mes_Generic into a real Q.931 message. The user will
+				set up a SETUP message and issue this to the stack where it
+				is processed by Q931ProcSetup that processes and validates
+				it before it actually sends it out. This function is called
+				to compute the real Q.931 message.
+
+  Parameters:   IBuf[IN]	Ptr to un-packed struct
+				ISize[IN]   Size of input buffer (unpacked message).
+				OBuf[OUT]   Ptr to packed 'octet' wise message.
+				OSize[OUT]  Size of packed message.
+
+  Called By:	Q931ProcSetup
+
+*****************************************************************************/
+L3INT ATT5ESSPmes_Setup(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+	L3INT rc = Q931E_NO_ERROR;
+	Q931mes_Generic *pMes = (Q931mes_Generic *)IBuf;
+	L3INT Octet = 0;
+
+	/* Q931 Message Header */
+	Q931MesgHeader(pTrunk, pMes, OBuf, *OSize, &Octet);
+	
+	/* Sending Complete				*/
+	if (Q931IsIEPresent(pMes->SendComplete)) {
+		OBuf[Octet++]	= (L3UCHAR)(pMes->SendComplete & 0x00ff);
+	}
+
+	/* Repeat Indicator */
+	if (Q931IsIEPresent(pMes->RepeatInd)) {
+		OBuf[Octet++]	= (L3UCHAR)(pMes->RepeatInd & 0x00ff);
+	}
+
+	/* Bearer capability */
+	if (Q931IsIEPresent(pMes->BearerCap)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_BEARER_CAPABILITY](pTrunk, Q931GetIEPtr(pMes->BearerCap,pMes->buf), OBuf, &Octet))!=0)
+			return rc;
+	} else {
+		rc = Q931E_BEARERCAP;
+	}
+
+	/* Channel Identification */
+	if (Q931IsIEPresent(pMes->ChanID)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CHANNEL_IDENTIFICATION](pTrunk, Q931GetIEPtr(pMes->ChanID,pMes->buf), OBuf, &Octet))!=0)
+			return rc;
+	}
+
+	/* Progress indicator */
+	if (Q931IsIEPresent(pMes->ProgInd)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_PROGRESS_INDICATOR](pTrunk, Q931GetIEPtr(pMes->ProgInd,pMes->buf), OBuf, &Octet))!=0)
+			return rc;
+	}
+
+	/* Network specific facilities */
+	if (Q931IsIEPresent(pMes->NetFac)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_NETWORK_SPECIFIC_FACILITIES](pTrunk, Q931GetIEPtr(pMes->NetFac,pMes->buf), OBuf, &Octet))!=0)
+			return rc;
+	}
+
+	/* Display */
+	if (Q931IsIEPresent(pMes->Display)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_DISPLAY](pTrunk, Q931GetIEPtr(pMes->Display,pMes->buf), OBuf, &Octet))!=0)
+			return rc;
+	}
+
+	/* Date/Time */
+	if (Q931IsIEPresent(pMes->DateTime)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_DATETIME](pTrunk, Q931GetIEPtr(pMes->DateTime,pMes->buf), OBuf, &Octet))!=0)
+			return rc;
+	}
+
+	/* Keypad Facility */
+	if (Q931IsIEPresent(pMes->KeypadFac)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_KEYPAD_FACILITY](pTrunk, Q931GetIEPtr(pMes->KeypadFac,pMes->buf), OBuf, &Octet))!=0)
+			return rc;
+	}
+
+	/* Signal */
+	if (Q931IsIEPresent(pMes->Signal)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_SIGNAL](pTrunk, Q931GetIEPtr(pMes->Signal,pMes->buf), OBuf, &Octet))!=0)
+			return rc;
+	}
+
+	/* Calling Party Number */
+	if (Q931IsIEPresent(pMes->CallingNum)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CALLING_PARTY_NUMBER](pTrunk, Q931GetIEPtr(pMes->CallingNum,pMes->buf), OBuf, &Octet))!=0)
+			return rc;
+	}
+
+	/* Calling Party Subaddress */
+	if (Q931IsIEPresent(pMes->CallingSub)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CALLING_PARTY_SUBADDRESS](pTrunk, Q931GetIEPtr(pMes->CallingSub,pMes->buf), OBuf, &Octet))!=0)
+			return rc;
+	}
+
+	/* Called Party number */
+	if (Q931IsIEPresent(pMes->CalledNum)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CALLED_PARTY_NUMBER](pTrunk, Q931GetIEPtr(pMes->CalledNum,pMes->buf), OBuf, &Octet))!=0)
+			return rc;
+	}
+
+	/* Called party subaddress */
+	if (Q931IsIEPresent(pMes->CalledSub)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CALLED_PARTY_SUBADDRESS](pTrunk, Q931GetIEPtr(pMes->CalledSub,pMes->buf), OBuf, &Octet))!=0)
+			return rc;
+	}
+
+	/* Transit network selection */
+	if (Q931IsIEPresent(pMes->TransNetSel)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_TRANSIT_NETWORK_SELECTION](pTrunk, Q931GetIEPtr(pMes->TransNetSel,pMes->buf), OBuf, &Octet))!=0)
+			return rc;
+	}
+
+	/* Repeat Indicator */
+	if (Q931IsIEPresent(pMes->LLRepeatInd)) {
+		rc = Q931E_UNKNOWN_IE;/* TODO */
+	}
+
+	/* Low Layer Compatibility */
+	if (Q931IsIEPresent(pMes->LLComp)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_LOW_LAYER_COMPATIBILITY](pTrunk, Q931GetIEPtr(pMes->LLComp,pMes->buf), OBuf, &Octet))!=0)
+			return rc;
+	}
+
+	/* High Layer Compatibility */
+	if (Q931IsIEPresent(pMes->HLComp)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_HIGH_LAYER_COMPATIBILITY](pTrunk, Q931GetIEPtr(pMes->HLComp,pMes->buf), OBuf, &Octet))!=0)
+			return rc;
+	}
+
+	*OSize = Octet;
+	return rc;
+}
+
+
+/*****************************************************************************
+
+  Function:	 ATT5ESSUmes_0x0f
+
+*****************************************************************************/
+L3INT ATT5ESSUmes_0x0f(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+	if (mes->ProtDisc == 8) {
+		return Q931Umes_ConnectAck(pTrunk, IBuf, mes, IOff, Size);
+	}
+
+	if (mes->ProtDisc == 3) {
+		return Q931Umes_Service(pTrunk, IBuf, mes, IOff, Size);
+	}
+
+	return Q931E_UNKNOWN_MESSAGE;
+}
+
+/*****************************************************************************
+
+  Function:	 ATT5ESSPmes_0x0f
+
+*****************************************************************************/
+L3INT ATT5ESSPmes_0x0f(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+	Q931mes_Generic *mes = (Q931mes_Generic *)IBuf;
+
+	if (mes->ProtDisc == 8) {
+		return Q931Pmes_ConnectAck(pTrunk, IBuf, ISize, OBuf, OSize);
+	}
+
+	if (mes->ProtDisc == 3) {
+		return Q931Pmes_Service(pTrunk, IBuf, ISize, OBuf, OSize);
+	}
+
+	return Q931E_UNKNOWN_MESSAGE;
+}
+
+/*****************************************************************************
+
+  Function:	 ATT5ESSUmes_0x07
+
+*****************************************************************************/
+L3INT ATT5ESSUmes_0x07(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+	if (mes->ProtDisc == 8) {
+		return Q931Umes_Connect(pTrunk, IBuf, mes, IOff, Size);
+	}
+
+	if (mes->ProtDisc == 3) {
+		return Q931Umes_ServiceAck(pTrunk, IBuf, mes, IOff, Size);
+	}
+
+	return Q931E_UNKNOWN_MESSAGE;
+}
+
+/*****************************************************************************
+
+  Function:	 ATT5ESSPmes_0x07
+
+*****************************************************************************/
+L3INT ATT5ESSPmes_0x07(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+	Q931mes_Generic *mes = (Q931mes_Generic *)IBuf;
+
+	if (mes->ProtDisc == 8) {
+		return Q931Pmes_Connect(pTrunk, IBuf, ISize, OBuf, OSize);
+	}
+
+	if (mes->ProtDisc == 3) {
+		return Q931Pmes_ServiceAck(pTrunk, IBuf, ISize, OBuf, OSize);
+	}
+
+	return Q931E_UNKNOWN_MESSAGE;
+}

Added: freeswitch/trunk/libs/openzap/src/isdn/DMSStateNT.c (0 => 17141)


--- freeswitch/trunk/libs/openzap/src/isdn/DMSStateNT.c	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/src/isdn/DMSStateNT.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,126 @@
+/*****************************************************************************
+
+  FileName:		DMSStateNT.c
+
+  Contents:		DMS-100 ISDN State Engine for NT (Network Mode).
+
+				The controlling state engine for Q.931 is the state engine
+				on the NT side. The state engine on the TE side is a slave 
+				of this. The TE side maintain it's own states as described in
+				ITU-T Q931, but will in	raise conditions be overridden by 
+				the NT side.
+
+  License/Copyright:
+
+  Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+  email:janvb@caselaboratories.com  
+
+  Copyright (c) 2007, Michael Jerris. All rights reserved.
+  email:mike@jerris.com  
+
+  Redistribution and use in source and binary forms, with or without 
+  modification, are permitted provided that the following conditions are 
+  met:
+
+	* Redistributions of source code must retain the above copyright notice, 
+	  this list of conditions and the following disclaimer.
+	* Redistributions in binary form must reproduce the above copyright notice, 
+	  this list of conditions and the following disclaimer in the documentation 
+	  and/or other materials provided with the distribution.
+	* Neither the name of the Case Labs, Ltd nor the names of its contributors 
+	  may be used to endorse or promote products derived from this software 
+	  without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
+  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
+  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+  POSSIBILITY OF SUCH DAMAGE.
+*****************************************************************************/
+
+#include "DMS.h"
+
+/*****************************************************************************
+  Function:		DMSCreateNT
+
+  Description:	Will create the National ISDN NT as a Dialect in the stack. The first
+				bulk set up the message handlers, the second bulk the IE
+				encoders/coders, and the last bulk set up the state table.
+
+  Parameters:	i		Dialect index
+*****************************************************************************/
+void DMSCreateNT(L3UCHAR i)
+{
+	Q931SetMesProc(Q931mes_ALERTING,             i, Q931ProcAlertingNT,          Q931Umes_Alerting,          Q931Pmes_Alerting);
+	Q931SetMesProc(Q931mes_CALL_PROCEEDING,      i, Q931ProcCallProceedingNT,    Q931Umes_CallProceeding,    Q931Pmes_CallProceeding);
+	Q931SetMesProc(Q931mes_CONNECT,              i, Q931ProcConnectNT,           Q931Umes_Connect,           Q931Pmes_Connect);
+	Q931SetMesProc(Q931mes_CONNECT_ACKNOWLEDGE,  i, Q931ProcConnectAckNT,        Q931Umes_ConnectAck,        Q931Pmes_ConnectAck);
+	Q931SetMesProc(Q931mes_PROGRESS,             i, Q931ProcProgressNT,          Q931Umes_Progress,          Q931Pmes_Progress);
+	Q931SetMesProc(Q931mes_SETUP,                i, Q931ProcSetupNT,             DMSUmes_Setup,              DMSPmes_Setup);
+	Q931SetMesProc(Q931mes_SETUP_ACKNOWLEDGE,    i, Q931ProcSetupAckNT,          Q931Umes_SetupAck,          Q931Pmes_SetupAck);
+	Q931SetMesProc(Q931mes_RESUME,               i, Q931ProcResumeNT,            Q931Umes_Resume,            Q931Pmes_Resume);
+	Q931SetMesProc(Q931mes_RESUME_ACKNOWLEDGE,   i, Q931ProcResumeAckNT,         Q931Umes_ResumeAck,         Q931Pmes_ResumeAck);
+	Q931SetMesProc(Q931mes_RESUME_REJECT,        i, Q931ProcResumeRejectNT,      Q931Umes_ResumeReject,      Q931Pmes_ResumeReject);
+	Q931SetMesProc(Q931mes_SUSPEND,              i, Q931ProcSuspendNT,           Q931Umes_Suspend,           Q931Pmes_Suspend);
+	Q931SetMesProc(Q931mes_SUSPEND_ACKNOWLEDGE,  i, Q931ProcSuspendAckNT,        Q931Umes_SuspendAck,        Q931Pmes_SuspendAck);
+	Q931SetMesProc(Q931mes_SUSPEND_REJECT,       i, Q931ProcSuspendRejectNT,     Q931Umes_SuspendReject,     Q931Pmes_SuspendReject);
+	Q931SetMesProc(Q931mes_USER_INFORMATION,     i, Q931ProcUserInformationNT,   Q931Umes_UserInformation,   Q931Pmes_UserInformation);
+	Q931SetMesProc(Q931mes_DISCONNECT,           i, Q931ProcDisconnectNT,        Q931Umes_Disconnect,        Q931Pmes_Disconnect);
+	Q931SetMesProc(Q931mes_RELEASE,              i, Q931ProcReleaseNT,           Q931Umes_Release,           Q931Pmes_Release);
+	Q931SetMesProc(Q931mes_RELEASE_COMPLETE,     i, Q931ProcReleaseCompleteNT,   Q931Umes_ReleaseComplete,   Q931Pmes_ReleaseComplete);
+	Q931SetMesProc(Q931mes_RESTART,              i, Q931ProcRestartNT,           Q931Umes_Restart,           Q931Pmes_Restart);
+	Q931SetMesProc(Q931mes_RESTART_ACKNOWLEDGE,  i, Q931ProcRestartAckNT,        Q931Umes_RestartAck,        Q931Pmes_RestartAck);
+	Q931SetMesProc(Q931mes_CONGESTION_CONTROL,   i, Q931ProcCongestionControlNT, Q931Umes_CongestionControl, Q931Pmes_CongestionControl);
+	Q931SetMesProc(Q931mes_INFORMATION,          i, Q931ProcInformationNT,       Q931Umes_Information,       Q931Pmes_Information);
+	Q931SetMesProc(Q931mes_NOTIFY,               i, Q931ProcNotifyNT,            Q931Umes_Notify,            Q931Pmes_Notify);
+	Q931SetMesProc(Q931mes_STATUS,               i, Q931ProcStatusNT,            Q931Umes_Status,            Q931Pmes_Status);
+	Q931SetMesProc(Q931mes_STATUS_ENQUIRY,       i, Q931ProcStatusEnquiryNT,     Q931Umes_StatusEnquiry,     Q931Pmes_StatusEnquiry);
+	Q931SetMesProc(Q931mes_SEGMENT,              i, Q931ProcSegmentNT,           Q931Umes_Segment,           Q931Pmes_Segment);
+
+	Q931SetMesProc(Q932mes_FACILITY,             i, Q932ProcFacilityNT,          Q932Umes_Facility,          Q932Pmes_Facility);
+	Q931SetMesProc(Q932mes_HOLD,                 i, Q932ProcHoldNT,              Q932Umes_Hold,              Q932Pmes_Hold);
+	Q931SetMesProc(Q932mes_HOLD_ACKNOWLEDGE,     i, Q932ProcHoldAckNT,           Q932Umes_HoldAck,           Q932Pmes_HoldAck);
+	Q931SetMesProc(Q932mes_HOLD_REJECT,          i, Q932ProcHoldRejectNT,        Q932Umes_HoldReject,        Q932Pmes_HoldReject);
+	Q931SetMesProc(Q932mes_REGISTER,             i, Q932ProcRegisterNT,          Q932Umes_Register,          Q932Pmes_Register);
+	Q931SetMesProc(Q932mes_RETRIEVE,             i, Q932ProcRetrieveNT,          Q932Umes_Retrieve,          Q932Pmes_Retrieve);
+	Q931SetMesProc(Q932mes_RETRIEVE_ACKNOWLEDGE, i, Q932ProcRetrieveAckNT,       Q932Umes_RetrieveAck,       Q932Pmes_RetrieveAck);
+	Q931SetMesProc(Q932mes_RETRIEVE_REJECT,      i, Q932ProcRetrieveRejectNT,    Q932Umes_RetrieveReject,    Q932Pmes_RetrieveReject);
+
+	/* Set up the IE encoder/decoder handle table.*/ 
+	Q931SetIEProc(Q931ie_SEGMENTED_MESSAGE,                i, Q931Pie_Segment,       Q931Uie_Segment);
+	Q931SetIEProc(Q931ie_BEARER_CAPABILITY,                i, Q931Pie_BearerCap,     Q931Uie_BearerCap);
+	Q931SetIEProc(Q931ie_CAUSE,                            i, Q931Pie_Cause,         Q931Uie_Cause);
+	Q931SetIEProc(Q931ie_CALL_IDENTITY,                    i, Q931Pie_CallID,        Q931Uie_CallID);
+	Q931SetIEProc(Q931ie_CALL_STATE,                       i, Q931Pie_CallState,     Q931Uie_CallState);
+	Q931SetIEProc(Q931ie_CHANNEL_IDENTIFICATION,           i, Q931Pie_ChanID,        Q931Uie_ChanID);
+	Q931SetIEProc(Q931ie_PROGRESS_INDICATOR,               i, Q931Pie_ProgInd,       Q931Uie_ProgInd);
+	Q931SetIEProc(Q931ie_NETWORK_SPECIFIC_FACILITIES,      i, Q931Pie_NetFac,        Q931Uie_NetFac);
+	Q931SetIEProc(Q931ie_NOTIFICATION_INDICATOR,           i, Q931Pie_NotifInd,      Q931Uie_NotifInd);
+	Q931SetIEProc(Q931ie_DISPLAY,                          i, Q931Pie_Display,       Q931Uie_Display);
+	Q931SetIEProc(Q931ie_DATETIME,                         i, Q931Pie_DateTime,      Q931Uie_DateTime);
+	Q931SetIEProc(Q931ie_KEYPAD_FACILITY,                  i, Q931Pie_KeypadFac,     Q931Uie_KeypadFac);
+	Q931SetIEProc(Q931ie_SIGNAL,                           i, Q931Pie_Signal,        Q931Uie_Signal);
+	Q931SetIEProc(Q931ie_TRANSIT_DELAY_SELECTION_AND_IND,  i, Q931Pie_TransNetSel,   Q931Uie_TransNetSel);
+	Q931SetIEProc(Q931ie_CALLING_PARTY_NUMBER,             i, Q931Pie_CallingNum,    Q931Uie_CallingNum);
+	Q931SetIEProc(Q931ie_CALLING_PARTY_SUBADDRESS,         i, Q931Pie_CallingSub,    Q931Uie_CallingSub);
+	Q931SetIEProc(Q931ie_CALLED_PARTY_NUMBER,              i, Q931Pie_CalledNum,     Q931Uie_CalledNum);
+	Q931SetIEProc(Q931ie_CALLED_PARTY_SUBADDRESS,          i, Q931Pie_CalledSub,     Q931Uie_CalledSub);
+	Q931SetIEProc(Q931ie_TRANSIT_NETWORK_SELECTION,        i, Q931Pie_TransNetSel,   Q931Uie_TransNetSel);
+	Q931SetIEProc(Q931ie_RESTART_INDICATOR,                i, Q931Pie_RestartInd,    Q931Uie_RestartInd);
+	Q931SetIEProc(Q931ie_LOW_LAYER_COMPATIBILITY,          i, Q931Pie_LLComp,        Q931Uie_LLComp);
+	Q931SetIEProc(Q931ie_HIGH_LAYER_COMPATIBILITY,         i, Q931Pie_HLComp,        Q931Uie_HLComp);
+	Q931SetIEProc(Q931ie_USER_USER,                        i, Q931Pie_UserUser,      Q931Uie_UserUser);
+	Q931SetIEProc(Q931ie_GENERIC_DIGITS, 	               i, Q931Pie_GenericDigits, Q931Uie_GenericDigits);
+
+	/* The following define a state machine. The point is that the Message	*/
+	/* procs can when search this to find out if the message/state			*/
+	/* combination is legale. If not, the proc for unexpected message apply.*/
+
+	/* TODO define state table here */
+}

Added: freeswitch/trunk/libs/openzap/src/isdn/DMSStateTE.c (0 => 17141)


--- freeswitch/trunk/libs/openzap/src/isdn/DMSStateTE.c	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/src/isdn/DMSStateTE.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,284 @@
+/*****************************************************************************
+
+  FileName:		DMSStateTE.c
+
+  Contents:		DMS-100 ISDN State Engine for TE (User Mode).
+
+			The controlling state engine for Q.931 is the state engine
+			on the NT side. The state engine on the TE side is a slave 
+			of this. The TE side maintain it's own states as described in
+			ITU-T Q931, but will in	raise conditions be overridden by 
+			the NT side.
+
+			This reference implementation uses a process per message,
+			meaning that each message must check call states. This
+			is easier for dialect maintenance as each message proc
+			can be replaced individually. A new TE variant only
+			need to copy the Q931CreateTE and replace those procs or
+			need to override.
+
+  License/Copyright:
+
+  Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+  email:janvb@caselaboratories.com  
+
+  Copyright (c) 2007, Michael Jerris. All rights reserved.
+  email:mike@jerris.com  
+
+  Redistribution and use in source and binary forms, with or without 
+  modification, are permitted provided that the following conditions are 
+  met:
+
+	* Redistributions of source code must retain the above copyright notice, 
+	  this list of conditions and the following disclaimer.
+	* Redistributions in binary form must reproduce the above copyright notice, 
+	  this list of conditions and the following disclaimer in the documentation 
+	  and/or other materials provided with the distribution.
+	* Neither the name of the Case Labs, Ltd nor the names of its contributors 
+	  may be used to endorse or promote products derived from this software 
+	  without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
+  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
+  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+  POSSIBILITY OF SUCH DAMAGE.
+*****************************************************************************/
+
+#include "DMS.h"
+extern L3INT Q931L4HeaderSpace;
+
+/*****************************************************************************
+  Function:		DMSCreateTE
+
+  Description:	Will create the National TE as a Dialect in the stack. The first
+				bulk set up the message handlers, the second bulk the IE
+				encoders/coders, and the last bulk set up the state table.
+
+  Parameters:	i		Dialect index
+*****************************************************************************/
+void DMSCreateTE(L3UCHAR i)
+{
+	Q931SetMesProc(Q931mes_ALERTING,             i, Q931ProcAlertingTE,          Q931Umes_Alerting,          Q931Pmes_Alerting);
+	Q931SetMesProc(Q931mes_CALL_PROCEEDING,      i, Q931ProcCallProceedingTE,    Q931Umes_CallProceeding,    Q931Pmes_CallProceeding);
+	Q931SetMesProc(Q931mes_CONNECT,              i, DMSProc0x07TE, 	             DMSUmes_0x07,               DMSPmes_0x07);
+	Q931SetMesProc(Q931mes_CONNECT_ACKNOWLEDGE,  i, DMSProc0x0fTE, 	             DMSUmes_0x0f,               DMSPmes_0x0f);
+	Q931SetMesProc(Q931mes_PROGRESS,             i, Q931ProcProgressTE,          Q931Umes_Progress,          Q931Pmes_Progress);
+	Q931SetMesProc(Q931mes_SETUP,                i, Q931ProcSetupTE,             DMSUmes_Setup,              DMSPmes_Setup);
+	Q931SetMesProc(Q931mes_SETUP_ACKNOWLEDGE,    i, Q931ProcSetupAckTE,          Q931Umes_SetupAck,          Q931Pmes_SetupAck);
+	Q931SetMesProc(Q931mes_RESUME,               i, Q931ProcResumeTE,            Q931Umes_Resume,            Q931Pmes_Resume);
+	Q931SetMesProc(Q931mes_RESUME_ACKNOWLEDGE,   i, Q931ProcResumeAckTE,         Q931Umes_ResumeAck,         Q931Pmes_ResumeAck);
+	Q931SetMesProc(Q931mes_RESUME_REJECT,        i, Q931ProcResumeRejectTE,      Q931Umes_ResumeReject,      Q931Pmes_ResumeReject);
+	Q931SetMesProc(Q931mes_SUSPEND,              i, Q931ProcSuspendTE,           Q931Umes_Suspend,           Q931Pmes_Suspend);
+	Q931SetMesProc(Q931mes_SUSPEND_ACKNOWLEDGE,  i, Q931ProcSuspendAckTE,        Q931Umes_SuspendAck,        Q931Pmes_SuspendAck);
+	Q931SetMesProc(Q931mes_SUSPEND_REJECT,       i, Q931ProcSuspendRejectTE,     Q931Umes_SuspendReject,     Q931Pmes_SuspendReject);
+	Q931SetMesProc(Q931mes_USER_INFORMATION,     i, Q931ProcUserInformationTE,   Q931Umes_UserInformation,   Q931Pmes_UserInformation);
+	Q931SetMesProc(Q931mes_DISCONNECT,           i, Q931ProcDisconnectTE,        Q931Umes_Disconnect,        Q931Pmes_Disconnect);
+	Q931SetMesProc(Q931mes_RELEASE,              i, Q931ProcReleaseTE,           Q931Umes_Release,           Q931Pmes_Release);
+	Q931SetMesProc(Q931mes_RELEASE_COMPLETE,     i, Q931ProcReleaseCompleteTE,   Q931Umes_ReleaseComplete,   Q931Pmes_ReleaseComplete);
+	Q931SetMesProc(Q931mes_RESTART,              i, Q931ProcRestartTE,           Q931Umes_Restart,           Q931Pmes_Restart);
+	Q931SetMesProc(Q931mes_RESTART_ACKNOWLEDGE,  i, Q931ProcRestartAckTE,        Q931Umes_RestartAck,        Q931Pmes_RestartAck);
+	Q931SetMesProc(Q931mes_CONGESTION_CONTROL,   i, Q931ProcCongestionControlTE, Q931Umes_CongestionControl, Q931Pmes_CongestionControl);
+	Q931SetMesProc(Q931mes_INFORMATION,          i, Q931ProcInformationTE,       Q931Umes_Information,       Q931Pmes_Information);
+	Q931SetMesProc(Q931mes_NOTIFY,               i, Q931ProcNotifyTE,            Q931Umes_Notify,            Q931Pmes_Notify);
+	Q931SetMesProc(Q931mes_STATUS,               i, Q931ProcStatusTE,            Q931Umes_Status,            Q931Pmes_Status);
+	Q931SetMesProc(Q931mes_STATUS_ENQUIRY,       i, Q931ProcStatusEnquiryTE,     Q931Umes_StatusEnquiry,     Q931Pmes_StatusEnquiry);
+	Q931SetMesProc(Q931mes_SEGMENT,              i, Q931ProcSegmentTE,           Q931Umes_Segment,           Q931Pmes_Segment);
+
+	Q931SetMesProc(Q932mes_FACILITY,             i, Q932ProcFacilityTE,          Q932Umes_Facility,          Q932Pmes_Facility);
+	Q931SetMesProc(Q932mes_HOLD,                 i, Q932ProcHoldTE,              Q932Umes_Hold,              Q932Pmes_Hold);
+	Q931SetMesProc(Q932mes_HOLD_ACKNOWLEDGE,     i, Q932ProcHoldAckTE,           Q932Umes_HoldAck,           Q932Pmes_HoldAck);
+	Q931SetMesProc(Q932mes_HOLD_REJECT,          i, Q932ProcHoldRejectTE,        Q932Umes_HoldReject,        Q932Pmes_HoldReject);
+	Q931SetMesProc(Q932mes_REGISTER,             i, Q932ProcRegisterTE,          Q932Umes_Register,          Q932Pmes_Register);
+	Q931SetMesProc(Q932mes_RETRIEVE,             i, Q932ProcRetrieveTE,          Q932Umes_Retrieve,          Q932Pmes_Retrieve);
+	Q931SetMesProc(Q932mes_RETRIEVE_ACKNOWLEDGE, i, Q932ProcRetrieveAckTE,       Q932Umes_RetrieveAck,       Q932Pmes_RetrieveAck);
+	Q931SetMesProc(Q932mes_RETRIEVE_REJECT,      i, Q932ProcRetrieveRejectTE,    Q932Umes_RetrieveReject,    Q932Pmes_RetrieveReject);
+
+	/* Set up the IE encoder/decoder handle table.*/ 
+	Q931SetIEProc(Q931ie_SEGMENTED_MESSAGE,                i, Q931Pie_Segment,       Q931Uie_Segment);
+	Q931SetIEProc(Q931ie_BEARER_CAPABILITY,                i, Q931Pie_BearerCap,     Q931Uie_BearerCap);
+	Q931SetIEProc(Q931ie_CAUSE,                            i, Q931Pie_Cause,         Q931Uie_Cause);
+	Q931SetIEProc(Q931ie_CALL_IDENTITY,                    i, Q931Pie_CallID,        Q931Uie_CallID);
+	Q931SetIEProc(Q931ie_CALL_STATE,                       i, Q931Pie_CallState,     Q931Uie_CallState);
+	Q931SetIEProc(Q931ie_CHANGE_STATUS,                    i, Q931Pie_ChangeStatus,  Q931Uie_ChangeStatus);
+	Q931SetIEProc(Q931ie_CHANNEL_IDENTIFICATION,           i, Q931Pie_ChanID,        Q931Uie_ChanID);
+	Q931SetIEProc(Q931ie_PROGRESS_INDICATOR,               i, Q931Pie_ProgInd,       Q931Uie_ProgInd);
+	Q931SetIEProc(Q931ie_NETWORK_SPECIFIC_FACILITIES,      i, Q931Pie_NetFac,        Q931Uie_NetFac);
+	Q931SetIEProc(Q931ie_NOTIFICATION_INDICATOR,           i, Q931Pie_NotifInd,      Q931Uie_NotifInd);
+	Q931SetIEProc(Q931ie_DISPLAY,                          i, Q931Pie_Display,       Q931Uie_Display);
+	Q931SetIEProc(Q931ie_DATETIME,                         i, Q931Pie_DateTime,      Q931Uie_DateTime);
+	Q931SetIEProc(Q931ie_KEYPAD_FACILITY,                  i, Q931Pie_KeypadFac,     Q931Uie_KeypadFac);
+	Q931SetIEProc(Q931ie_SIGNAL,                           i, Q931Pie_Signal,        Q931Uie_Signal);
+	Q931SetIEProc(Q931ie_TRANSIT_DELAY_SELECTION_AND_IND,  i, Q931Pie_TransNetSel,   Q931Uie_TransNetSel);
+	Q931SetIEProc(Q931ie_CALLING_PARTY_NUMBER,             i, Q931Pie_CallingNum,    Q931Uie_CallingNum);
+	Q931SetIEProc(Q931ie_CALLING_PARTY_SUBADDRESS,         i, Q931Pie_CallingSub,    Q931Uie_CallingSub);
+	Q931SetIEProc(Q931ie_CALLED_PARTY_NUMBER,              i, Q931Pie_CalledNum,     Q931Uie_CalledNum);
+	Q931SetIEProc(Q931ie_CALLED_PARTY_SUBADDRESS,          i, Q931Pie_CalledSub,     Q931Uie_CalledSub);
+	Q931SetIEProc(Q931ie_TRANSIT_NETWORK_SELECTION,        i, Q931Pie_TransNetSel,   Q931Uie_TransNetSel);
+	Q931SetIEProc(Q931ie_RESTART_INDICATOR,                i, Q931Pie_RestartInd,    Q931Uie_RestartInd);
+	Q931SetIEProc(Q931ie_LOW_LAYER_COMPATIBILITY,          i, Q931Pie_LLComp,        Q931Uie_LLComp);
+	Q931SetIEProc(Q931ie_HIGH_LAYER_COMPATIBILITY,         i, Q931Pie_HLComp,        Q931Uie_HLComp);
+	Q931SetIEProc(Q931ie_USER_USER,                        i, Q931Pie_UserUser,      Q931Uie_UserUser);
+	Q931SetIEProc(Q931ie_GENERIC_DIGITS,                   i, Q931Pie_GenericDigits, Q931Uie_GenericDigits);
+
+	/* The following define a state machine. The point is that the Message	*/
+	/* procs can when search this to find out if the message/state			*/
+	/* combination is legale. If not, the proc for unexpected message apply.*/
+
+	/* State 0 Idle */
+	Q931AddStateEntry(i, Q931_U0, Q931mes_RESUME,           2);
+	Q931AddStateEntry(i, Q931_U0, Q931mes_SETUP,            4);
+	Q931AddStateEntry(i, Q931_U0, Q931mes_SETUP,            2);
+	Q931AddStateEntry(i, Q931_U0, Q931mes_STATUS,           4);
+	Q931AddStateEntry(i, Q931_U0, Q931mes_RELEASE,          4);
+	Q931AddStateEntry(i, Q931_U0, Q931mes_RELEASE_COMPLETE, 4);
+
+	/* State 1 Call Initiating */
+	Q931AddStateEntry(i, Q931_U1, Q931mes_DISCONNECT,        2);
+	Q931AddStateEntry(i, Q931_U1, Q931mes_SETUP_ACKNOWLEDGE, 4);
+	Q931AddStateEntry(i, Q931_U1, Q931mes_RELEASE_COMPLETE,  4);
+	Q931AddStateEntry(i, Q931_U1, Q931mes_CALL_PROCEEDING,   4);
+	Q931AddStateEntry(i, Q931_U1, Q931mes_ALERTING,          4);
+	Q931AddStateEntry(i, Q931_U1, Q931mes_CONNECT,           4);
+
+	/* State 2 Overlap Sending */
+	Q931AddStateEntry(i, Q931_U2, Q931mes_INFORMATION,     2);
+	Q931AddStateEntry(i, Q931_U2, Q931mes_CALL_PROCEEDING, 4);
+	Q931AddStateEntry(i, Q931_U2, Q931mes_ALERTING,        4);
+	Q931AddStateEntry(i, Q931_U2, Q931mes_PROGRESS,        4);
+	Q931AddStateEntry(i, Q931_U2, Q931mes_CONNECT,         4);
+	Q931AddStateEntry(i, Q931_U2, Q931mes_RELEASE,         2);
+
+	/* State 3 Outgoing Call Proceeding */
+	Q931AddStateEntry(i, Q931_U3, Q931mes_PROGRESS, 4);
+	Q931AddStateEntry(i, Q931_U3, Q931mes_ALERTING, 4);
+	Q931AddStateEntry(i, Q931_U3, Q931mes_CONNECT,  4);
+	Q931AddStateEntry(i, Q931_U3, Q931mes_RELEASE,  2);
+
+	/* State 4 Call Delivered */
+	Q931AddStateEntry(i, Q931_U4, Q931mes_CONNECT, 4);
+
+	/* State 6 Call Precent */
+	Q931AddStateEntry(i, Q931_U6, Q931mes_INFORMATION,      2);	
+	Q931AddStateEntry(i, Q931_U6, Q931mes_ALERTING,         2);	
+	Q931AddStateEntry(i, Q931_U6, Q931mes_CALL_PROCEEDING,  2);	
+	Q931AddStateEntry(i, Q931_U6, Q931mes_CONNECT,          2);	
+	Q931AddStateEntry(i, Q931_U6, Q931mes_RELEASE_COMPLETE, 2);	
+	Q931AddStateEntry(i, Q931_U6, Q931mes_RELEASE,          4);	
+	Q931AddStateEntry(i, Q931_U6, Q931mes_DISCONNECT,       4);	
+
+	/* State 7 Call Received */
+	Q931AddStateEntry(i, Q931_U7, Q931mes_CONNECT, 2);
+
+	/* State 8 Connect request */
+	Q931AddStateEntry(i, Q931_U8, Q931mes_CONNECT_ACKNOWLEDGE, 4);
+
+	/* State 9 Incoming Call Proceeding */
+	Q931AddStateEntry(i, Q931_U9, Q931mes_CONNECT,  2);
+	Q931AddStateEntry(i, Q931_U9, Q931mes_ALERTING, 2);
+	Q931AddStateEntry(i, Q931_U9, Q931mes_PROGRESS, 2);
+
+	/* State 10 Active */
+	Q931AddStateEntry(i, Q931_U10, Q931mes_SUSPEND, 2);
+	Q931AddStateEntry(i, Q931_U10, Q931mes_NOTIFY,  4);
+	Q931AddStateEntry(i, Q931_U10, Q931mes_NOTIFY,  2);
+
+	/* State 11 Disconnect Request */
+	Q931AddStateEntry(i, Q931_U11, Q931mes_RELEASE,    4);
+	Q931AddStateEntry(i, Q931_U11, Q931mes_DISCONNECT, 4);
+	Q931AddStateEntry(i, Q931_U11, Q931mes_NOTIFY,     4);
+
+	/* State 12 Disconnect Ind */
+	Q931AddStateEntry(i, Q931_U12, Q931mes_RELEASE,	4);
+	Q931AddStateEntry(i, Q931_U12, Q931mes_RELEASE, 2);
+
+	/* State 15 Suspend Request */
+	Q931AddStateEntry(i, Q931_U15, Q931mes_SUSPEND_ACKNOWLEDGE, 4);
+	Q931AddStateEntry(i, Q931_U15, Q931mes_SUSPEND_REJECT,      4);
+	Q931AddStateEntry(i, Q931_U15, Q931mes_DISCONNECT,          4);
+	Q931AddStateEntry(i, Q931_U15, Q931mes_RELEASE,             4);
+
+/* TODO
+	Q931AddStateEntry(i, Q931_U17,
+	Q931AddStateEntry(i, Q931_U19,
+	Q931AddStateEntry(i, Q931_U25,
+*/
+}
+
+/*****************************************************************************
+
+  Function:		DMSProc0x0fTE
+
+*****************************************************************************/
+L3INT DMSProc0x0fTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	if (pMes->ProtDisc == 8) {
+		/* Find the call using CRV */
+		ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+		if (ret != Q931E_NO_ERROR)
+			return ret;
+
+		/* TODO chack against state table for illegal or unexpected message here*/
+
+		/* TODO - Set correct timer here */
+		Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	}
+	if (iFrom == 4) {
+		/* TODO Add proc here*/
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here*/
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+
+		if (pMes->ProtDisc == 3 && pTrunk->autoServiceAck) {
+			Q931AckService(pTrunk, buf);
+		}
+	}
+	return ret;
+
+}
+
+/*****************************************************************************
+
+  Function:		DMSProc0x07TE
+
+*****************************************************************************/
+L3INT DMSProc0x07TE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	if (pMes->ProtDisc == 8) {
+		/* Find the call using CRV */
+		ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+		if (ret != Q931E_NO_ERROR)
+			return ret;
+
+		/* TODO chack against state table for illegal or unexpected message here*/
+
+		/* TODO - Set correct timer here */
+		Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	}
+	if (iFrom == 4) {
+		/* TODO Add proc here*/
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here*/
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+
+}

Added: freeswitch/trunk/libs/openzap/src/isdn/DMSmes.c (0 => 17141)


--- freeswitch/trunk/libs/openzap/src/isdn/DMSmes.c	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/src/isdn/DMSmes.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,344 @@
+/*****************************************************************************
+
+  FileName:	DMSmes.c
+
+  Contents:	Pack/Unpack functions. These functions will unpack a DMS-100 ISDN
+		message from the bit packed original format into structs
+		that contains variables sized by the user. It will also pack
+		the struct back into a Q.931 message as required.
+
+		See national.h for description. 
+
+  License/Copyright:
+
+  Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+  email:janvb@caselaboratories.com  
+
+  Copyright (c) 2007, Michael Jerris. All rights reserved.
+  email:mike@jerris.com  
+
+  Redistribution and use in source and binary forms, with or without 
+  modification, are permitted provided that the following conditions are 
+  met:
+
+	* Redistributions of source code must retain the above copyright notice, 
+	  this list of conditions and the following disclaimer.
+	* Redistributions in binary form must reproduce the above copyright notice, 
+	  this list of conditions and the following disclaimer in the documentation 
+	  and/or other materials provided with the distribution.
+	* Neither the name of the Case Labs, Ltd nor the names of its contributors 
+	  may be used to endorse or promote products derived from this software 
+	  without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
+  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
+  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+  POSSIBILITY OF SUCH DAMAGE.
+
+*****************************************************************************/
+
+#include "DMS.h"
+
+/*****************************************************************************
+
+  Function:	 DMSUmes_Setup
+
+*****************************************************************************/
+L3INT DMSUmes_Setup(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+	L3INT ir = 0;
+	L3INT OOff = 0;
+	L3INT rc = Q931E_NO_ERROR;
+	L3UCHAR last_codeset = 0, codeset = 0;
+	L3UCHAR shift_lock = 1;
+
+	while (IOff < Size) {
+		if (!shift_lock) {
+			codeset = last_codeset;
+		}
+
+		if ((IBuf[IOff] & 0xF0) == Q931ie_SHIFT ) {
+			shift_lock = (IBuf[IOff] & 0x08);
+			if (shift_lock) {
+				last_codeset = codeset;
+			}
+			codeset = ((IBuf[IOff] & 0x07));
+			IOff++;
+		}
+
+		if (codeset == 0) {
+			switch (IBuf[IOff]) {
+			case Q931ie_SENDING_COMPLETE:
+			case Q931ie_BEARER_CAPABILITY:
+			case Q931ie_CHANNEL_IDENTIFICATION:
+			case Q931ie_PROGRESS_INDICATOR:
+			case Q931ie_NETWORK_SPECIFIC_FACILITIES:
+			case Q931ie_DISPLAY:
+			case Q931ie_DATETIME:
+			case Q931ie_KEYPAD_FACILITY:
+			case Q931ie_SIGNAL:
+			case Q931ie_CALLING_PARTY_NUMBER:
+			case Q931ie_CALLING_PARTY_SUBADDRESS:
+			case Q931ie_CALLED_PARTY_NUMBER:
+			case Q931ie_CALLED_PARTY_SUBADDRESS:
+			case Q931ie_TRANSIT_NETWORK_SELECTION:
+			case Q931ie_LOW_LAYER_COMPATIBILITY:
+			case Q931ie_HIGH_LAYER_COMPATIBILITY:
+				rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+				if (rc != Q931E_NO_ERROR) 
+					return rc;
+				break;
+			case Q931ie_REPEAT_INDICATOR:
+				if (ir < 2) {
+					rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+					ir++;
+				} else {
+					return Q931E_ILLEGAL_IE;
+				}
+				break;
+			default:
+				return Q931E_ILLEGAL_IE;
+				break;
+			}
+		} else if (codeset == 6) {
+			switch (IBuf[IOff]) {
+			case Q931ie_GENERIC_DIGITS:
+				rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+				if (rc != Q931E_NO_ERROR) 
+					return rc;
+				break;
+			default:
+				return Q931E_ILLEGAL_IE;
+				break;
+			}
+
+		} else {
+			return Q931E_ILLEGAL_IE;
+		}
+	}
+	mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:	 DMSPmes_Setup
+
+  Decription:	Pack a Q931mes_Generic into a real Q.931 message. The user will
+				set up a SETUP message and issue this to the stack where it
+				is processed by Q931ProcSetup that processes and validates
+				it before it actually sends it out. This function is called
+				to compute the real Q.931 message.
+
+  Parameters:	IBuf[IN]	Ptr to un-packed struct
+				ISize[IN]	Size of input buffer (unpacked message).
+				OBuf[OUT]	Ptr to packed 'octet' wise message.
+				OSize[OUT]	Size of packed message.
+
+  Called By:	Q931ProcSetup
+
+*****************************************************************************/
+L3INT DMSPmes_Setup(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+	L3INT rc = Q931E_NO_ERROR;
+	Q931mes_Generic *pMes = (Q931mes_Generic *)IBuf;
+	L3INT Octet = 0;
+
+	/* Q931 Message Header */
+	Q931MesgHeader(pTrunk, pMes, OBuf, *OSize, &Octet);
+	
+	/* Sending Complete */
+	if (Q931IsIEPresent(pMes->SendComplete)) {
+		OBuf[Octet++]	= (L3UCHAR)(pMes->SendComplete & 0x00ff);
+	}
+
+	/* Repeat Indicator */
+	if (Q931IsIEPresent(pMes->RepeatInd)) {
+		OBuf[Octet++]	= (L3UCHAR)(pMes->RepeatInd & 0x00ff);		
+	}
+
+	/* Bearer capability */
+	if (Q931IsIEPresent(pMes->BearerCap)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_BEARER_CAPABILITY](pTrunk, Q931GetIEPtr(pMes->BearerCap,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	} else {
+		rc = Q931E_BEARERCAP;
+	}
+
+	/* Channel Identification */
+	if (Q931IsIEPresent(pMes->ChanID)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CHANNEL_IDENTIFICATION](pTrunk, Q931GetIEPtr(pMes->ChanID,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Progress indicator */
+	if (Q931IsIEPresent(pMes->ProgInd)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_PROGRESS_INDICATOR](pTrunk, Q931GetIEPtr(pMes->ProgInd,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Network spesific facilities */
+	if (Q931IsIEPresent(pMes->NetFac)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_NETWORK_SPECIFIC_FACILITIES](pTrunk, Q931GetIEPtr(pMes->NetFac,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Display */
+	if (Q931IsIEPresent(pMes->Display)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_DISPLAY](pTrunk, Q931GetIEPtr(pMes->Display,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Date/Time */
+	if (Q931IsIEPresent(pMes->DateTime)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_DATETIME](pTrunk, Q931GetIEPtr(pMes->DateTime,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Keypad Facility */
+	if (Q931IsIEPresent(pMes->KeypadFac)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_KEYPAD_FACILITY](pTrunk, Q931GetIEPtr(pMes->KeypadFac,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Signal */
+	if (Q931IsIEPresent(pMes->Signal)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_SIGNAL](pTrunk, Q931GetIEPtr(pMes->Signal,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Calling Party Number */
+	if (Q931IsIEPresent(pMes->CallingNum)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CALLING_PARTY_NUMBER](pTrunk, Q931GetIEPtr(pMes->CallingNum,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Calling Party Subaddress */
+	if (Q931IsIEPresent(pMes->CallingSub)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CALLING_PARTY_SUBADDRESS](pTrunk, Q931GetIEPtr(pMes->CallingSub,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Called Party number */
+	if (Q931IsIEPresent(pMes->CalledNum)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CALLED_PARTY_NUMBER](pTrunk, Q931GetIEPtr(pMes->CalledNum,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+
+	/* Called party subaddress */
+	if (Q931IsIEPresent(pMes->CalledSub)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CALLED_PARTY_SUBADDRESS](pTrunk, Q931GetIEPtr(pMes->CalledSub,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Transit network selection */
+	if (Q931IsIEPresent(pMes->TransNetSel)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_TRANSIT_NETWORK_SELECTION](pTrunk, Q931GetIEPtr(pMes->TransNetSel,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Repeat Indicator */
+	if (Q931IsIEPresent(pMes->LLRepeatInd)) {
+		rc = Q931E_UNKNOWN_IE;/* TODO */
+	}
+
+	/* Low Layer Compatibility */
+	if (Q931IsIEPresent(pMes->LLComp)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_LOW_LAYER_COMPATIBILITY](pTrunk, Q931GetIEPtr(pMes->LLComp,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* High Layer Compatibility */
+	if (Q931IsIEPresent(pMes->HLComp)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_HIGH_LAYER_COMPATIBILITY](pTrunk, Q931GetIEPtr(pMes->HLComp,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	*OSize = Octet;	
+	return rc;
+}
+
+
+/*****************************************************************************
+
+  Function:	 DMSUmes_0x0f
+
+*****************************************************************************/
+L3INT DMSUmes_0x0f(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+	if (mes->ProtDisc == 8) {
+		return Q931Umes_ConnectAck(pTrunk, IBuf, mes, IOff, Size);
+	}
+
+	if (mes->ProtDisc == 3) {
+		return Q931Umes_Service(pTrunk, IBuf, mes, IOff, Size);
+	}
+
+	return Q931E_UNKNOWN_MESSAGE;
+}
+
+/*****************************************************************************
+
+  Function:	 DMSPmes_0x0f
+
+*****************************************************************************/
+L3INT DMSPmes_0x0f(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+	Q931mes_Generic *mes = (Q931mes_Generic *)IBuf;
+
+	if (mes->ProtDisc == 8) {
+		return Q931Pmes_ConnectAck(pTrunk, IBuf, ISize, OBuf, OSize);
+	}
+
+	if (mes->ProtDisc == 3) {
+		return Q931Pmes_Service(pTrunk, IBuf, ISize, OBuf, OSize);
+	}
+
+	return Q931E_UNKNOWN_MESSAGE;
+}
+
+/*****************************************************************************
+
+  Function:	 DMSUmes_0x07
+
+*****************************************************************************/
+L3INT DMSUmes_0x07(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+	if (mes->ProtDisc == 8) {
+		return Q931Umes_Connect(pTrunk, IBuf, mes, IOff, Size);
+	}
+
+	if (mes->ProtDisc == 3) {
+		return Q931Umes_ServiceAck(pTrunk, IBuf, mes, IOff, Size);
+	}
+
+	return Q931E_UNKNOWN_MESSAGE;
+}
+
+/*****************************************************************************
+
+  Function:	 DMSPmes_0x07
+
+*****************************************************************************/
+L3INT DMSPmes_0x07(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+	Q931mes_Generic *mes = (Q931mes_Generic *)IBuf;
+
+	if (mes->ProtDisc == 8) {
+		return Q931Pmes_Connect(pTrunk, IBuf, ISize, OBuf, OSize);
+	}
+
+	if (mes->ProtDisc == 3) {
+		return Q931Pmes_ServiceAck(pTrunk, IBuf, ISize, OBuf, OSize);
+	}
+
+	return Q931E_UNKNOWN_MESSAGE;
+}

Added: freeswitch/trunk/libs/openzap/src/isdn/EuroISDNStateNT.c (0 => 17141)


--- freeswitch/trunk/libs/openzap/src/isdn/EuroISDNStateNT.c	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/src/isdn/EuroISDNStateNT.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,44 @@
+/*****************************************************************************
+
+  FileName:		EuroISDNStateNT.c
+
+  Contents:		EuroISDN State Engine for NT (Network Mode).
+
+			The controlling state engine for Q.931 is the state engine
+			on the NT side. The state engine on the TE side is a slave 
+			of this. The TE side maintain it's own states as described in
+			ITU-T Q931, but will in	raise conditions be overridden by 
+			the NT side.
+
+  License/Copyright:
+
+  Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+  email:janvb@caselaboratories.com  
+
+  Redistribution and use in source and binary forms, with or without 
+  modification, are permitted provided that the following conditions are 
+  met:
+
+	* Redistributions of source code must retain the above copyright notice, 
+	  this list of conditions and the following disclaimer.
+	* Redistributions in binary form must reproduce the above copyright notice, 
+	  this list of conditions and the following disclaimer in the documentation 
+	  and/or other materials provided with the distribution.
+	* Neither the name of the Case Labs, Ltd nor the names of its contributors 
+	  may be used to endorse or promote products derived from this software 
+	  without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
+  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
+  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+  POSSIBILITY OF SUCH DAMAGE.
+*****************************************************************************/
+
+#include "Q931.h"

Added: freeswitch/trunk/libs/openzap/src/isdn/EuroISDNStateTE.c (0 => 17141)


--- freeswitch/trunk/libs/openzap/src/isdn/EuroISDNStateTE.c	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/src/isdn/EuroISDNStateTE.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,58 @@
+/*****************************************************************************
+
+  FileName:		EuroISDNStateTE.c
+
+  Contents:		EuroISDN State Engine for TE (User Mode).
+
+			The controlling state engine for Q.931 is the state engine
+			on the NT side. The state engine on the TE side is a slave 
+			of this. The TE side maintain it's own states as described in
+			ITU-T Q931, but will in	raise conditions be overridden by 
+			the NT side.
+
+  License/Copyright:
+
+  Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+  email:janvb@caselaboratories.com  
+
+  Redistribution and use in source and binary forms, with or without 
+  modification, are permitted provided that the following conditions are 
+  met:
+
+	* Redistributions of source code must retain the above copyright notice, 
+	  this list of conditions and the following disclaimer.
+	* Redistributions in binary form must reproduce the above copyright notice, 
+	  this list of conditions and the following disclaimer in the documentation 
+	  and/or other materials provided with the distribution.
+	* Neither the name of the Case Labs, Ltd nor the names of its contributors 
+	  may be used to endorse or promote products derived from this software 
+	  without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
+  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
+  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+  POSSIBILITY OF SUCH DAMAGE.
+*****************************************************************************/
+
+#include "Q931.h"
+
+/*
+  EuroISDN is a sub-set of Q.931. Q.931 is very generic as it embrase a lot,
+  while EuroISDN is more exact and make decitions on some of the 
+  'implementation options' in the original standard. EuroISDN will 
+  however run smoothly under the generic space, so these functions are more 
+  for show 
+*/
+#if 0
+static void EuroISDNCreateTE(L3UCHAR i)
+{
+	Q931CreateTE(i);
+}
+#endif

Added: freeswitch/trunk/libs/openzap/src/isdn/Q921.c (0 => 17141)


--- freeswitch/trunk/libs/openzap/src/isdn/Q921.c	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/src/isdn/Q921.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,3517 @@
+/*****************************************************************************
+
+  FileName:     q921.c
+
+  Description:  Contains the implementation of a Q.921 protocol
+
+  Created:      27.dec.2000/JVB
+
+  License/Copyright:
+
+  Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+  email:janvb@caselaboratories.com  
+
+  Redistribution and use in source and binary forms, with or without 
+  modification, are permitted provided that the following conditions are 
+  met:
+
+    * Redistributions of source code must retain the above copyright notice, 
+	  this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright notice, 
+	  this list of conditions and the following disclaimer in the documentation 
+	  and/or other materials provided with the distribution.
+    * Neither the name of the Case Labs, Ltd nor the names of its contributors 
+	  may be used to endorse or promote products derived from this software 
+	  without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
+  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
+  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+  POSSIBILITY OF SUCH DAMAGE.
+
+*****************************************************************************/
+
+/****************************************************************************
+ * Changes:
+ *
+ * - June-August 2008: Stefan Knoblich <s.knoblich@axsentis.de>:
+ *     Add PTMP TEI management (NT + TE mode)
+ *     Add timers
+ *     Add retransmit counters
+ *     Add logging
+ *     Various cleanups
+ *     Queues, retransmission of I frames
+ *     PTMP NT mode
+ *
+ *
+ * TODO:
+ *
+ * - Cleanup queueing, test retransmission
+ *
+ * - Q921Start() /-Stop() TEI acquire + release
+ *   (move everything related into these functions)
+ *
+ * - Q.921 '97 Appendix I (and maybe III, IV)
+ *
+ * - More complete Appendix II
+ *
+ * - Test PTP mode
+ *
+ * - PTMP NT mode (in progress)
+ *
+ * - NT mode TEI management: (ab)use T202 for TEI Check Request retransmission
+ *
+ * - General cleanup (move all non-public declarations into private header file)
+ *
+ * - Statistics, per-Frame type debug message filter
+ *
+ ****************************************************************************/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+
+#include "Q921.h"
+#include "Q921priv.h"
+#include "mfifo.h"
+
+#ifdef WIN32
+#pragma warning(disable:4100 4244)
+#endif
+
+/******************************************************************************************************
+ * Actual code below this line
+ ******************************************************************************************************/
+
+
+/**
+ * Q921StateNames
+ * \brief	Static array of state name / value mappings
+ */
+static struct Q921StateName {
+	Q921State_t value;
+	const char *name;
+} Q921StateNames[10] = {
+	{ Q921_STATE_STOPPED, "Stopped" },
+	{ Q921_STATE_TEI_UNASSIGNED, "TEI Unassigned" },
+	{ Q921_STATE_TEI_AWAITING, "TEI Awaiting Assignment" },
+	{ Q921_STATE_TEI_ESTABLISH, "TEI Awaiting Establishment" },
+	{ Q921_STATE_TEI_ASSIGNED, "TEI Assigned" },
+	{ Q921_STATE_AWAITING_ESTABLISHMENT, "Awaiting Establishment" },
+	{ Q921_STATE_AWAITING_RELEASE, "Awaiting Release" },
+	{ Q921_STATE_MULTIPLE_FRAME_ESTABLISHED, "Multiple Frame Mode Established" },
+	{ Q921_STATE_TIMER_RECOVERY, "Timer Recovery" },
+	{ 0, 0 }
+};
+
+/**
+ * Q921State2Name
+ * \brief	Convert state value to name
+ * \param[in]	state	the state value
+ * \return	the state name or "Unknown"
+ *
+ * \author	Stefan Knoblich
+ */
+static const char *Q921State2Name(Q921State_t state)
+{
+	struct Q921StateName *p = Q921StateNames;
+
+	while(p->name) {
+		if(p->value == state)
+			return p->name;
+		p++;
+	}
+
+	return "Unknown";
+}
+
+
+/**
+ * Q921SendEnquiry
+ */
+static int Q921SendEnquiry(L2TRUNK trunk, L2UCHAR tei)
+{
+	struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+	/* send enquiry: begin */
+	if(Q921_CHECK_FLAG(link, Q921_FLAG_RECV_BUSY)) {
+
+		Q921SendRNR(trunk, trunk->sapi, Q921_COMMAND(trunk), tei, 1);
+	}
+	else {
+		Q921SendRR(trunk, trunk->sapi, Q921_COMMAND(trunk), tei, 1);
+	}
+
+	/* clear acknowledge pending */
+	Q921_CLEAR_FLAG(link, Q921_FLAG_ACK_PENDING);
+
+	/* "Start" T200 */
+	Q921T200TimerReset(trunk, tei);
+
+	/* send enquiry: end */
+	return 1;
+}
+
+/**
+ * Q921SendEnquiryResponse
+ */
+static int Q921SendEnquiryResponse(L2TRUNK trunk, L2UCHAR tei)
+{
+	struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+	/* send enquiry: begin */
+	if(Q921_CHECK_FLAG(link, Q921_FLAG_RECV_BUSY)) {
+
+		Q921SendRNR(trunk, trunk->sapi, Q921_RESPONSE(trunk), tei, 1);
+	}
+	else {
+		Q921SendRR(trunk, trunk->sapi, Q921_RESPONSE(trunk), tei, 1);
+
+		/* clear acknowledge pending */
+		Q921_CLEAR_FLAG(link, Q921_FLAG_ACK_PENDING);
+	}
+	/* send enquiry: end */
+	return 1;
+}
+
+/**
+ * Q921ResetExceptionConditions
+ * \brief	Reset Q.921 Exception conditions procedure
+ * \param	trunk	Q.921 data structure
+ * \param	tei	TEI
+ * \todo	Do something
+ */
+static void Q921ResetExceptionConditions(L2TRUNK trunk, L2UCHAR tei)
+{
+	struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+	/* Clear peer receiver busy */
+	Q921_CLEAR_FLAG(link, Q921_FLAG_PEER_RECV_BUSY);
+
+	/* Clear reject exception */
+	Q921_CLEAR_FLAG(link, Q921_FLAG_REJECT);
+
+	/* Clear own receiver busy */
+	Q921_CLEAR_FLAG(link, Q921_FLAG_RECV_BUSY);
+
+	/* Clear acknowledge pending */
+	Q921_CLEAR_FLAG(link, Q921_FLAG_ACK_PENDING);
+
+	return;
+}
+
+/**
+ * Q921EstablishDataLink
+ * \brief	Q.921 Establish data link procedure
+ * \param	trunk	Q.921 data structure
+ * \param	tei	TEI
+ * \return	always 1 (success)
+ */
+static int Q921EstablishDataLink(L2TRUNK trunk, L2UCHAR tei)
+{
+	struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+	/* reset exception conditions */
+	Q921ResetExceptionConditions(trunk, tei);
+
+	/* RC = 0 */
+	link->N200 = 0;
+
+	/* Send SABME */
+	Q921SendSABME(trunk, trunk->sapi, Q921_COMMAND(trunk), tei, 1);
+
+	/* Restart T200, stop T203 */
+	Q921T200TimerReset(trunk, tei);
+	Q921T203TimerStop(trunk, tei);
+
+	return 1;
+}
+
+/**
+ * Q921NrErrorRecovery
+ * \brief	NR(R) Error recovery procedure
+ * \param	trunk	Q.921 data structure
+ * \param	tei	TEI
+ * \return	always 1 (success)
+ */
+static int Q921NrErrorRecovery(L2TRUNK trunk, L2UCHAR tei)
+{
+	struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+	/* MDL Error indication (J) */
+
+	/* Establish datalink */
+	Q921EstablishDataLink(trunk, tei);
+
+	/* Clear L3 initiated */
+	Q921_CLEAR_FLAG(link, Q921_FLAG_L3_INITIATED);
+
+	return 1;
+}
+
+
+/**
+ * Q921InvokeRetransmission
+ * \brief	I Frame retransmission procedure
+ * \param	trunk	Q.921 data structure
+ * \param	tei	TEI
+ * \param	nr	N(R) for retransmission
+ * \return	always 1 (success)
+ */
+static int Q921InvokeRetransmission(L2TRUNK trunk, L2UCHAR tei, L2UCHAR nr)
+{
+	struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+	L2UCHAR *mes;
+	L2INT qpos, qnum, size = 0;
+
+	qnum = MFIFOGetMesCount(link->IFrameResendQueue);
+	qpos = qnum - 1;
+
+	/*
+	 * slightly different than what is shown in the spec
+	 * (Q.921 '97 Annex B, Figure B.9, page 104)
+	 * 
+	 * what the above mentioned figure probably means is:
+	 * "as long as V(S) != N(R), move the pointer marking
+	 *  the first frame to start resending at to the previous
+	 *  frame"
+	 *
+	 * if we actually implemented it as shown in the figure, we'd be
+	 * resending frames in the wrong order (moving backwards in time)
+	 * meaning we'd have to add an incoming queue to reorder the frames
+	 *
+	 */
+	/*
+	 * TODO: There's a "traditional" off-by-one error hidden in the original
+	 *       mfifo implementation + it's late, i'm tired and being lazy,
+	 *       so i'll probably have added another one :P
+	 *
+	 *       wow, the first while loop sucks and can be removed
+	 */
+	while(link->vs != nr && qpos > 0) {	/* ???? */
+		/* V(S) = V(S) - 1 */
+		Q921_DEC_COUNTER(link->vs);	/* huh? backwards? */
+
+		/* next frame in queue (backtrack along I queue) ??? */
+		qpos--;
+	}
+
+	/*
+	 * being lazy and trying to avoid mod 128 math this way...
+	 */
+	if(link->vs != nr && !qpos) {
+		/* fatal, we don't have enough history to resend all missing frames */
+		/* TODO: how to handle this? */
+	}
+
+	/*
+	 * resend frames in correct order (oldest missing frame first,
+	 * contrary to what the spec figure shows)
+	 */
+	while(qpos < qnum) {
+		/* Grab frame's buffer ptr and size from queue */
+		mes = MFIFOGetMesPtrOffset(link->IFrameResendQueue, &size, qpos);
+		if(mes) {
+			/* requeue frame (TODO: check queue full condition) */
+			MFIFOWriteMes(link->IFrameQueue, mes, size);
+
+			/* set I frame queued */
+		}
+
+		qpos++;
+	}
+
+	return 1;
+}
+
+
+static int Q921AcknowledgePending(L2TRUNK trunk, L2UCHAR tei)
+{
+	struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+	switch(link->state) {
+	case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
+	case Q921_STATE_TIMER_RECOVERY:
+		if(Q921_CHECK_FLAG(link, Q921_FLAG_ACK_PENDING)) {
+			/* clear acknowledge pending */
+			Q921_CLEAR_FLAG(link, Q921_FLAG_ACK_PENDING);
+
+			/* send RR */
+			Q921SendRR(trunk, trunk->sapi, Q921_COMMAND(trunk), tei, 0);
+
+			return 1;
+		}
+		break;
+
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+/*****************************************************************************
+
+  Function:     Q921_InitTrunk
+
+  Decription:   Initialize a Q.921 trunk so it is ready for use. This 
+                function MUST be called before you call any other functions.
+
+*****************************************************************************/
+int Q921_InitTrunk(L2TRUNK trunk,
+					L2UCHAR sapi,
+					L2UCHAR tei,
+					Q921NetUser_t NetUser,
+					Q921NetType_t NetType,
+					L2INT hsize,
+					Q921Tx21CB_t cb21,
+					Q921Tx23CB_t cb23,
+					void *priv21,
+					void *priv23)
+{
+	int numlinks = 0;
+
+	trunk->sapi = sapi;
+	trunk->tei = tei;
+	trunk->NetUser = NetUser;
+	trunk->NetType = NetType;
+	trunk->Q921Tx21Proc = cb21;
+	trunk->Q921Tx23Proc = cb23;
+	trunk->PrivateData21 = priv21;
+	trunk->PrivateData23 = priv23;
+	trunk->Q921HeaderSpace = hsize;
+
+	numlinks = Q921_IS_PTMP_NT(trunk) ? Q921_TEI_MAX : 1;
+
+	if (trunk->initialized != INITIALIZED_MAGIC) {
+		MFIFOCreate(trunk->HDLCInQueue, Q921MAXHDLCSPACE, 10);
+
+		/*
+		 * Allocate space for per-link context(s)
+		 */
+		trunk->context = malloc(numlinks * sizeof(struct Q921_Link));
+		if(!trunk->context)
+			return -1;
+
+		trunk->initialized = INITIALIZED_MAGIC;
+	}
+
+	/* timeout default values */
+	trunk->T200Timeout = 1000;	/*   1 second  */
+	trunk->T203Timeout = 10000;	/*  10 seconds */
+	trunk->T202Timeout = 2000;	/*   2 seconds */
+	trunk->T201Timeout = 200000;	/* 200 seconds */
+	trunk->TM01Timeout = 10000;	/*  10 seconds */
+
+	/* octet / retransmit counter default limits */
+	trunk->N200Limit   = 3;		/*   3 retransmits */
+	trunk->N201Limit   = 260;	/* 260 octets      */
+	trunk->N202Limit   = 3;		/*   3 retransmits */
+	trunk->k           = 7;		/*   7 outstanding ACKs */
+
+	/* reset counters, timers, etc. */
+	trunk->T202 = 0;
+	trunk->N202 = 0;
+
+	/* Reset per-link contexts */
+	memset(trunk->context, 0, numlinks * sizeof(struct Q921_Link));
+
+	/* clear tei map */
+	memset(trunk->tei_map, 0, Q921_TEI_MAX + 1);
+
+	if(Q921_IS_PTMP(trunk)) {
+		/*
+		 * We're either the Network side (NT, TEI = 0)
+		 * or user-side equipment (TE) which will get it's TEI via
+		 * dynamic assignment
+		 */
+		trunk->tei = 0;
+	}
+
+	return 0;
+}
+
+
+/**
+ * Q921Tx21Proc
+ * \brief	Submit frame to layer 1 (for sending)
+ * \param[in]	trunk	Pointer to trunk struct
+ * \param[in]	mes	pointer to message buffer
+ * \param[in]	size	size of message
+ * \return	> 0 on success; <= 0 on error
+ */
+static int Q921Tx21Proc(L2TRUNK trunk, L2UCHAR *Msg, L2INT size)
+{
+	Q921LogMesg(trunk, Q921_LOG_DEBUG, 0, Msg, size, "Sending frame");
+
+	return trunk->Q921Tx21Proc(trunk->PrivateData21, Msg, size);
+}
+
+
+/**
+ * Q921Tx23Proc
+ * \brief	Submit frame to layer 3
+ * \param[in]	trunk	Pointer to trunk struct
+ * \param[in]	mes	pointer to message buffer
+ * \param[in]	size	size of message
+ * \return	> 0 on success; <= 0 on error
+ */
+static int Q921Tx23Proc(L2TRUNK trunk, Q921DLMsg_t ind, L2UCHAR tei, L2UCHAR *Msg, L2INT size)
+{
+	return trunk->Q921Tx23Proc(trunk->PrivateData23, ind, tei, Msg, size);
+}
+
+
+/**
+ * Q921LogProc
+ * \brief	Used for logging, converts to string and submits to higher level log function via callback
+ * \param[in]	trunk	Pointer to trunk struct
+ * \param[in]	level	Q921 Loglevel
+ * \param[in]	fmt	format of logmessage
+ * \return	>= 0 on success, < 0 on error
+ *
+ * \author	Stefan Knoblich
+ */
+static int Q921Log(L2TRUNK trunk, Q921LogLevel_t level, const char *fmt, ...)
+{
+	char  buf[Q921_LOGBUFSIZE];
+	L2INT len;
+	va_list ap;
+
+	if(!trunk->Q921LogProc)
+		return 0;
+
+	if(trunk->loglevel < level)
+		return 0;
+
+	va_start(ap, fmt);
+
+	len = vsnprintf(buf, sizeof(buf)-1, fmt, ap);
+	if(len <= 0) {
+		/* TODO: error handling */
+		return -1;
+	}
+	if(len >= sizeof(buf))
+		len = sizeof(buf) - 1;
+
+	buf[len] = '\0';
+
+	va_end(ap);
+
+	return trunk->Q921LogProc(trunk->PrivateDataLog, level, buf, len);
+}
+
+
+static int print_hex(char *buf, int bsize, const unsigned char *in, const int len)
+{
+	static const char hex[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
+	int offset = 0;
+	int pos    = 0;
+	int nr     = 0;
+
+	buf[pos++] = '[';
+	bsize -= 3;
+
+	while((bsize - pos) > 0 && offset < len) {
+		buf[pos++] = hex[(in[offset] & 0xF0) >> 4];
+		buf[pos++] = hex[(in[offset++]   & 0x0F)];
+
+		if(++nr == 32 && offset < len && (bsize - pos) > 3) {
+			nr = 0;
+			buf[pos++] = ']';
+			buf[pos++] = '\n';
+			buf[pos++] = '[';
+		}
+		else if(offset < len) {
+			buf[pos++] = ' ';
+		}
+	}
+
+	buf[pos++] = ']';
+	buf[pos++] = '\n';
+	buf[pos]   = '\0';
+
+	return pos;
+}
+
+#define APPEND_MSG(buf, off, lef, fmt, ...) 			\
+	len = snprintf(buf + off, lef, fmt, ##__VA_ARGS__);	\
+	if(len > 0) { 						\
+		off += len;					\
+		lef -= len;					\
+	} else {						\
+		goto out;					\
+	}
+
+/**
+ * Q921LogProcMesg
+ * \brief	Used for logging, converts to string and submits to higher level log function via callback
+ * \param[in]	trunk	Pointer to trunk struct
+ * \param[in]	level	Q921 Loglevel
+ * \param[in]	received	direction of the message (received = 1, sending = 0)
+ * \param[in]	mes	pointer to message buffer
+ * \param[in]	size	size of message
+ * \param[in]	fmt	format of logmessage
+ * \return	>= 0 on success, < 0 on error
+ *
+ * \author	Stefan Knoblich
+ */
+static int Q921LogMesg(L2TRUNK trunk, Q921LogLevel_t level, L2UCHAR received, L2UCHAR *mes, L2INT size, const char *fmt, ...)
+{
+	char  buf[Q921_LOGBUFSIZE];
+	size_t len, left;
+	va_list ap;
+
+	if(!trunk->Q921LogProc)
+		return 0;
+
+	if(trunk->loglevel < level)
+		return 0;
+
+	if(!mes)
+		return 0;
+
+	memset(buf, 0, sizeof(buf));
+
+	left = sizeof(buf) - 1;
+
+	va_start(ap, fmt);
+
+	len = vsnprintf(buf, left, fmt, ap);
+	if(len > 0)
+		left -= len;
+	else {
+		/* TODO: error handling */
+		return -1;
+	}
+
+	va_end(ap);
+
+	if(trunk->loglevel == Q921_LOG_DEBUG) {
+		char pbuf[1024];
+		size_t pleft, poffset;
+		L2UCHAR sapi, tei, cr;
+		L2UCHAR *pmes = mes + trunk->Q921HeaderSpace;
+		struct Q921_Link *link;
+
+		memset(pbuf, 0, sizeof(pbuf));
+
+		pleft   = sizeof(pbuf);
+		poffset = 0;
+
+		/*
+		 * Decode packet
+		 */
+		sapi = (pmes[0] & 0xfc) >> 2;
+		cr   = (pmes[0] & 0x02) >> 1;
+		tei  = (pmes[1] & 0xfe) >> 1;
+		link  = Q921_LINK_CONTEXT(trunk, tei);
+
+		/* make cr actually useful */
+		cr   = (received) ? Q921_IS_COMMAND(trunk, cr) : Q921_IS_RESPONSE(trunk, cr);
+
+		/* filter */
+		if((pmes[2] & 0x01) == 0x00) {
+ 			;
+		}
+		else if((pmes[2] & 0x03) == 0x01) {
+			; //return 0;
+		}
+		else if((pmes[2] & 0x03) == 0x03) {
+			;
+		}
+
+		APPEND_MSG(pbuf, poffset, pleft, "\n----------------- Q.921 Packet [%s%s] ---------------\n", received ? "Incoming" : "Outgoing",
+						(tei == link->tei || tei == Q921_TEI_BCAST) ? "" : ", Ignored" );
+
+		/* common header */
+		APPEND_MSG(pbuf, poffset, pleft, "    SAPI: %u, TEI: %u, C/R: %s (%d)\n\n", sapi, tei, (cr) ? "Command" : "Response", (mes[0] & 0x02) >> 1 );
+
+		/*
+		 * message specific
+		 */
+		if((pmes[2] & 0x01) == 0x00) {
+			/*
+			 * I frame
+			 */
+			L2UCHAR pf = pmes[3] & 0x01;	/* poll / final flag */
+			L2UCHAR nr = pmes[3] >> 1;	/* receive sequence number */
+			L2UCHAR ns = pmes[2] >> 1;	/* send sequence number */
+
+			APPEND_MSG(pbuf, poffset, pleft, "    Type: I Frame\n          P/F: %d, N(S): %d, N(R): %d  [V(A): %d, V(R): %d, V(S): %d]\n", pf, ns, nr,
+														link->va, link->vr, link->vs);
+
+			/* Dump content of I Frames for foreign TEIs */
+			if(tei != link->tei) {
+				APPEND_MSG(pbuf, poffset, pleft, "    CONTENT:\n");
+
+				len = print_hex(pbuf + poffset, (int)pleft, &pmes[4], size - (trunk->Q921HeaderSpace + 4));
+				poffset += len;
+				pleft   -= len;
+			}
+		}
+		else if((pmes[2] & 0x03) == 0x01) {
+			/*
+			 * S frame
+			 */
+			L2UCHAR sv = (pmes[2] & 0x0c) >> 2;	/* supervisory format id */
+			L2UCHAR pf =  pmes[3] & 0x01;		/* poll / final flag */
+			L2UCHAR nr =  pmes[3] >> 1;		/* receive sequence number */
+			const char *type;
+
+			switch(sv) {
+			case 0x00:	/* RR : Receive Ready */
+				type = "RR (Receive Ready)";
+				break;
+
+			case 0x02:	/* RNR : Receive Not Ready */
+				type = "RNR (Receiver Not Ready)";
+				break;
+
+			case 0x04:	/* REJ : Reject */
+				type = "REJ (Reject)";
+				break;
+
+			default:	/* Invalid / Unknown */
+				type = "Unknown";
+				break;
+			}
+
+			APPEND_MSG(pbuf, poffset, pleft, "    Type: S Frame, SV: %s\n          P/F: %d, N(R): %d  [V(A): %d, V(R): %d, V(S): %d]\n", type, pf, nr,
+														link->va, link->vr, link->vs);
+		}
+		else if((pmes[2] & 0x03) == 0x03) {
+			/*
+			 * U frame
+			 */
+			L2UCHAR m  = (pmes[2] & 0xe0) >> 3 | (pmes[2] & 0x0c) >> 2;	/* modifier function id */
+			L2UCHAR pf = (pmes[2] & 0x10) >> 4;				/* poll / final flag */
+			const char *type;
+
+			switch(m) {
+			case 0x00:
+				type = "UI (Unnumbered Information)";
+				break;
+
+			case 0x03:
+				type = "DM (Disconnected Mode)";
+				break;
+
+			case 0x08:
+				type = "DISC (Disconnect)";
+				break;
+
+			case 0x0c:
+				type = "UA (Unnumbered Acknowledgement)";
+				break;
+
+			case 0x0f:
+				type = "SABME";
+				break;
+
+			case 0x11:
+				type = "FRMR (Frame Reject)";
+				break;
+
+			case 0x17:
+				type = "XID (Exchange Identification)";
+				break;
+
+			default:
+				type = "Unknown";
+			}
+
+
+			APPEND_MSG(pbuf, poffset, pleft, "    Type: U Frame (%s)\n          P/F: %d\n", type, pf);
+
+			if(m == 0x00) {
+				switch(pmes[3]) {
+				case Q921_LAYER_ENT_ID_TEI:
+					type = "TEI Mgmt";
+					break;
+
+				case Q921_LAYER_ENT_ID_Q931:
+					type = "Q.931";
+					break;
+
+				default:
+					type = "Unknown";
+				}
+
+				if(pmes[3] == Q921_LAYER_ENT_ID_TEI) {
+					const char *command = "";
+
+					switch(pmes[6]) {
+					case Q921_TEI_ID_REQUEST:
+						command = "Request";
+						break;
+					case Q921_TEI_ID_VERIFY:
+						command = "Verify";
+						break;
+					case Q921_TEI_ID_CHECKREQ:
+						command = "Check req";
+						break;
+					case Q921_TEI_ID_CHECKRESP:
+						command = "Check resp";
+						break;
+					case Q921_TEI_ID_REMOVE:
+						command = "Remove";
+						break;
+					case Q921_TEI_ID_ASSIGNED:
+						command = "Assign";
+						break;
+					case Q921_TEI_ID_DENIED:
+						command = "Denied";
+						break;
+					}
+					APPEND_MSG(pbuf, poffset, pleft, "    ENT ID: %d (%s), COMMAND: %d (%s), RI: %#x, AI: %d\n",
+							 pmes[3], type, pmes[6], command, (int)((pmes[4] << 8) | pmes[5]), pmes[7] >> 1);
+				}
+				else {
+					APPEND_MSG(pbuf, poffset, pleft, "    ENT ID: %d (%s), MESSAGE CONTENT:\n", pmes[3], type);
+
+					len = print_hex(pbuf + poffset, (int)pleft, &pmes[3], size - (trunk->Q921HeaderSpace + 3));
+					poffset += len;
+					pleft   -= len;
+				}
+			}
+		}	
+		else {
+			/*
+			 * Unknown
+			 */
+			strncat(pbuf + poffset, "  -- unknown frame type --\n", pleft);
+
+			len = (sizeof(pbuf) - poffset) - strlen(pbuf + poffset);
+			if(len > 0) {
+				poffset += len;
+				pleft   -= len;
+			} else
+				goto out;
+		}
+
+		APPEND_MSG(pbuf, poffset, pleft, "\n    Q.921 state: \"%s\" (%d) [flags: %c%c%c%c]\n", Q921State2Name(link->state), link->state,
+											Q921_CHECK_FLAG(link, Q921_FLAG_ACK_PENDING) ? 'A' : '-',
+											Q921_CHECK_FLAG(link, Q921_FLAG_REJECT) ? 'R' : '-',
+											Q921_CHECK_FLAG(link, Q921_FLAG_PEER_RECV_BUSY) ? 'P' : '-',
+											Q921_CHECK_FLAG(link, Q921_FLAG_RECV_BUSY) ? 'B' : '-');
+
+		strncat(pbuf + poffset, "----------------------------------------------\n\n", pleft);
+
+		len = (sizeof(pbuf) - poffset) - strlen(pbuf + poffset);
+		if(len > 0) {
+			poffset += len;
+			pleft   -= len;
+		} else
+			goto out;
+
+
+		/* concat buffers together */
+		len = strlen(pbuf);
+		if(len <= left)
+			strncat(buf, pbuf, left);
+		else
+			strncat(buf, "-- packet truncated --\n", left);
+	}
+
+out:
+	buf[sizeof(buf) - 1] = '\0';
+
+	return trunk->Q921LogProc(trunk->PrivateDataLog, level, buf, (int)strlen(buf));
+}
+
+/*****************************************************************************
+
+  Function:     Q921TimeTick
+
+  Description:  Called periodically from an external source to allow the 
+                stack to process and maintain it's own timers.
+
+  Return Value: none
+
+*****************************************************************************/
+static L2ULONG (*Q921GetTimeProc) (void) = NULL; /* callback for func reading time in ms */
+static L2ULONG tLast = {0};
+
+static L2ULONG Q921GetTime(void)
+{
+	L2ULONG tNow = 0;
+
+	if(Q921GetTimeProc)
+	{
+		tNow = Q921GetTimeProc();
+		if(tNow < tLast)	/* wrapped */
+		{
+			/* TODO */
+		}
+		tLast = tNow;
+	}
+	return tNow;
+}
+
+/*
+ * T200 handling (per-TEI in PTMP NT mode, tei=0 otherwise)
+ */
+static void Q921T200TimerStart(L2TRUNK trunk, L2UCHAR tei)
+{
+	struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+	if (!link->T200) {
+		link->T200 = Q921GetTime() + trunk->T200Timeout;
+
+		Q921Log(trunk, Q921_LOG_DEBUG, "T200 (timeout: %d msecs) started for TEI %d\n", trunk->T200Timeout, tei);
+	}
+}
+
+static void Q921T200TimerStop(L2TRUNK trunk, L2UCHAR tei)
+{
+	struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+	link->T200 = 0;
+
+	Q921Log(trunk, Q921_LOG_DEBUG, "T200 stopped for TEI %d\n", tei);
+}
+
+static void Q921T200TimerReset(L2TRUNK trunk, L2UCHAR tei)
+{
+	struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+	link->T200 = Q921GetTime() + trunk->T200Timeout;
+
+	Q921Log(trunk, Q921_LOG_DEBUG, "T200 (timeout: %d msecs) restarted for TEI %d\n", trunk->T200Timeout, tei);
+}
+
+/*
+ * T203 handling (per-TEI in PTMP NT mode, tei=0 otherwise)
+ */
+static void Q921T203TimerStart(L2TRUNK trunk, L2UCHAR tei)
+{
+	struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+	if (!link->T203) {
+		link->T203 = Q921GetTime() + trunk->T203Timeout;
+
+		Q921Log(trunk, Q921_LOG_DEBUG, "T203 (timeout: %d msecs) started for TEI %d\n", trunk->T203Timeout, tei);
+	}
+}
+
+static void Q921T203TimerStop(L2TRUNK trunk, L2UCHAR tei)
+{
+	struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+	link->T203 = 0;
+
+	Q921Log(trunk, Q921_LOG_DEBUG, "T203 stopped for TEI %d\n", tei);
+}
+
+static void Q921T203TimerReset(L2TRUNK trunk, L2UCHAR tei)
+{
+	struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+	link->T203 = Q921GetTime() + trunk->T203Timeout;
+
+	Q921Log(trunk, Q921_LOG_DEBUG, "T203 (timeout: %d msecs) restarted for TEI %d\n", trunk->T203Timeout, tei);
+}
+
+/*
+ * T202 handling (TEI message timeout, TE mode only)
+ */
+static void Q921T202TimerStart(L2TRUNK trunk)
+{
+	if (!trunk->T202) {
+		trunk->T202 = Q921GetTime() + trunk->T202Timeout;
+
+		Q921Log(trunk, Q921_LOG_DEBUG, "T202 (timeout: %d msecs) started\n", trunk->T202Timeout);
+	}
+}
+
+static void Q921T202TimerStop(L2TRUNK trunk)
+{
+	trunk->T202 = 0;
+
+	Q921Log(trunk, Q921_LOG_DEBUG, "T202 stopped\n");
+}
+
+static void Q921T202TimerReset(L2TRUNK trunk)
+{
+	trunk->T202 = Q921GetTime() + trunk->T202Timeout;
+
+	Q921Log(trunk, Q921_LOG_DEBUG, "T202 (timeout: %d msecs) restarted\n", trunk->T202Timeout);
+}
+
+/*
+ * T201 handling (TEI management (NT side), per-TEI)
+ */
+static void Q921T201TimerStart(L2TRUNK trunk, L2UCHAR tei)
+{
+	struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+	if (!link->T201) {
+		link->T201 = Q921GetTime() + trunk->T201Timeout;
+
+		Q921Log(trunk, Q921_LOG_DEBUG, "T201 (timeout: %d msecs) started for TEI %d\n", trunk->T201Timeout, tei);
+	}	
+}
+
+static void Q921T201TimerStop(L2TRUNK trunk, L2UCHAR tei)
+{
+	struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+	link->T201 = 0;
+
+	Q921Log(trunk, Q921_LOG_DEBUG, "T201 stopped for TEI %d\n", tei);
+}
+
+#ifdef __UNUSED_FOR_NOW__
+static void Q921T201TimerReset(L2TRUNK trunk, L2UCHAR tei)
+{
+	struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+	link->T201 = Q921GetTime() + trunk->T201Timeout;
+
+	Q921Log(trunk, Q921_LOG_DEBUG, "T201 (timeout: %d msecs) restarted for TEI %d\n", trunk->T201Timeout, tei);
+}
+#endif
+
+/*
+ * TM01 handling (Datalink inactivity shutdown timer)
+ */
+static void Q921TM01TimerStart(L2TRUNK trunk, L2UCHAR tei)
+{
+	struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+	if (!link->TM01) {
+		link->TM01 = Q921GetTime() + trunk->TM01Timeout;
+
+		Q921Log(trunk, Q921_LOG_DEBUG, "TM01 (timeout: %d msecs) started for TEI %d\n", trunk->TM01Timeout, tei);
+	}
+}
+
+#ifdef __UNUSED_FOR_NOW__
+static void Q921TM01TimerStop(L2TRUNK trunk, L2UCHAR tei)
+{
+	struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+	link->TM01 = 0;
+
+	Q921Log(trunk, Q921_LOG_DEBUG, "TM01 stopped for TEI %d\n", tei);
+}
+#endif
+
+static void Q921TM01TimerReset(L2TRUNK trunk, L2UCHAR tei)
+{
+	struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+	link->TM01 = Q921GetTime() + trunk->TM01Timeout;
+
+	Q921Log(trunk, Q921_LOG_DEBUG, "TM01 (timeout: %d msecs) restarted for TEI %d\n", trunk->TM01Timeout, tei);
+}
+
+/*
+ * Expiry callbacks
+ */
+static void Q921T200TimerExpire(L2TRUNK trunk, L2UCHAR tei)
+{
+	struct Q921_Link *link   = Q921_LINK_CONTEXT(trunk, tei);
+	struct Q921_Link *trlink = Q921_TRUNK_CONTEXT(trunk);
+
+	Q921Log(trunk, Q921_LOG_DEBUG, "T200 expired for TEI %d (trunk TEI %d)\n", tei, trlink->tei);
+
+	/* Stop timer first */
+	Q921T200TimerStop(trunk, tei);
+
+	switch(link->state) {
+	case Q921_STATE_AWAITING_ESTABLISHMENT:
+		if(link->N200 >= trunk->N200Limit) {
+			/* Discard I queue */
+			MFIFOClear(link->IFrameQueue);
+
+			/* MDL-Error indication (G) */
+			Q921Log(trunk, Q921_LOG_ERROR, "Failed to establish Q.921 link in %d retries\n", link->N200);
+
+			/* DL-Release indication */
+			Q921Tx23Proc(trunk, Q921_DL_RELEASE, tei, NULL, 0);
+
+			/* change state (no action) */
+			Q921ChangeState(trunk, Q921_STATE_TEI_ASSIGNED, tei);
+		} else {
+			/* Increment retry counter */
+			link->N200++;
+
+			/* Send SABME */
+			Q921SendSABME(trunk,
+					trunk->sapi,
+					Q921_COMMAND(trunk),
+					tei,
+					1);
+
+			/* Start T200 */
+			Q921T200TimerStart(trunk, tei);
+		}
+		break;
+
+	case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
+		link->N200 = 0;
+
+		if(!Q921_CHECK_FLAG(link, Q921_FLAG_PEER_RECV_BUSY)) {
+			/* get last transmitted I frame */
+
+			/* V(S) = V(S) - 1 */
+			Q921_DEC_COUNTER(link->vs);
+
+			/* retransmit I frame */
+
+			/* V(S) = V(S) + 1 (done by Q921SendI() ) */
+			//Q921_INC_COUNTER(link->vs);
+
+			/* clear acknowledge pending */
+			Q921_CLEAR_FLAG(link, Q921_FLAG_ACK_PENDING);
+
+			/* Start T200 */
+			Q921T200TimerStart(trunk, tei);
+		} else {
+			/* transmit enquiry */
+			Q921SendEnquiry(trunk, tei);
+		}
+
+		/* increment counter */
+		link->N200++;
+
+		/* change state (no action) */
+		Q921ChangeState(trunk, Q921_STATE_TIMER_RECOVERY, tei);
+		break;
+
+	case Q921_STATE_TIMER_RECOVERY:
+		if(link->N200 == trunk->N200Limit) {
+			/* MDL Error indication (I) */
+
+			/* Establish data link */
+			Q921EstablishDataLink(trunk, tei);
+
+			/* Clear L3 initiated */
+			Q921_CLEAR_FLAG(link, Q921_FLAG_L3_INITIATED);
+
+			/* change state (no action) */
+			Q921ChangeState(trunk, Q921_STATE_AWAITING_ESTABLISHMENT, tei);
+		} else {
+			if(link->vs == link->va) {
+				/* transmit enquiry */
+				Q921SendEnquiry(trunk, tei);
+
+			} else if(!Q921_CHECK_FLAG(link, Q921_FLAG_PEER_RECV_BUSY)) {
+				/* get last transmitted frame */
+
+				/* V(S) = V(S) - 1 */
+				Q921_DEC_COUNTER(link->vs);
+
+				/* retrans frame */
+
+				/* V(S) = V(S) + 1 (done by Q921SendI() ) */
+				//Q921_INC_COUNTER(link->vs);
+
+				/* clear acknowledge pending */
+				Q921_CLEAR_FLAG(link, Q921_FLAG_ACK_PENDING);
+
+				/* Start T200 */
+				Q921T200TimerStart(trunk, tei);
+			}
+
+			/* increment counter */
+			link->N200++;
+
+			/* no state change */
+		}
+		break;
+
+	default:
+		break;
+	}
+}
+
+static void Q921T203TimerExpire(L2TRUNK trunk, L2UCHAR tei)
+{
+	struct Q921_Link *link   = Q921_LINK_CONTEXT(trunk, tei);
+	struct Q921_Link *trlink = Q921_TRUNK_CONTEXT(trunk);
+
+	Q921Log(trunk, Q921_LOG_DEBUG, "T203 expired for TEI %d (trunk TEI %d)\n", tei, trlink->tei);
+
+	/* Stop Timer first */
+	Q921T203TimerStop(trunk, tei);
+
+	switch(link->state) {
+	case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
+		/* Send Enquiry */
+		Q921SendEnquiry(trunk, tei);
+
+		/* RC = 0 */
+		link->N200 = 0;
+
+		/* no state change */
+		break;
+
+	default:
+		break;
+	}
+}
+
+static void Q921T202TimerExpire(L2TRUNK trunk)
+{
+	struct Q921_Link *link = Q921_TRUNK_CONTEXT(trunk);
+
+	Q921T202TimerReset(trunk);
+
+	Q921Log(trunk, Q921_LOG_DEBUG, "T202 expired for Q.921 trunk with TEI %d\n", link->tei);
+
+	/* todo: implement resend counter */
+
+	switch(link->state) {
+	case Q921_STATE_TEI_ASSIGNED:	/* Tei identity verify timeout */
+		Q921TeiSendVerifyRequest(trunk);
+		break;
+
+	default:			/* Tei assignment request timeout (TODO: refine) */
+
+		if(trunk->N202 >= trunk->N202Limit) {
+			/* Too many retransmits, reset counter, stop timer and handle case (TODO) */
+			trunk->N202 = 0;
+
+			Q921T202TimerStop(trunk);
+
+			return;
+		}
+		Q921TeiSendAssignRequest(trunk);
+
+		trunk->N202++;
+	}
+}
+
+static void Q921T201TimerExpire(L2TRUNK trunk, L2UCHAR tei)
+{
+	struct Q921_Link *link   = Q921_LINK_CONTEXT(trunk, tei);
+	struct Q921_Link *trlink = Q921_TRUNK_CONTEXT(trunk);
+
+	Q921Log(trunk, Q921_LOG_DEBUG, "T201 expired for TEI %d (trunk TEI: %d)\n", tei, trlink->tei);
+
+	Q921T201TimerStop(trunk, tei);
+
+	/* NOTE: abusing N202 for this */
+	if(link->N202 < trunk->N202Limit) {
+		/* send check request */
+		Q921TeiSendCheckRequest(trunk, tei);
+
+		/* increment counter */
+		link->N202++;
+	} else {
+		/* put context in STOPPED state */
+		Q921ChangeState(trunk, Q921_STATE_STOPPED, tei);
+
+		/* NOTE: should we clear the link too? */
+		memset(link, 0, sizeof(struct Q921_Link));
+
+		/* mark TEI free */
+		trunk->tei_map[tei] = 0;
+	}
+}
+
+#ifdef __UNUSED_FOR_NOW__
+static void Q921TM01TimerExpire(L2TRUNK trunk, L2UCHAR tei)
+{
+	struct Q921_Link *link   = Q921_LINK_CONTEXT(trunk, tei);
+	struct Q921_Link *trlink = Q921_TRUNK_CONTEXT(trunk);
+
+	Q921Log(trunk, Q921_LOG_DEBUG, "TM01 expired for TEI %d (trunk TEI: %d)\n", tei, trlink->tei);
+
+	/* Restart TM01 */
+	Q921TM01TimerReset(trunk, tei);
+
+	switch(link->state) {
+	case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
+	case Q921_STATE_TIMER_RECOVERY:
+/*
+ * NT-only, needs more support from L3
+ */
+#if 0
+		/* No activity, shutdown link */
+		Q921SendDISC(trunk, trunk->sapi, Q921_COMMAND(trunk), tei, 1);
+
+		/* clear I queue */
+		MFIFOClear(link->IFrameQueue);
+
+		/* change state */
+		Q921ChangeState(trunk, Q921_STATE_AWAITING_RELEASE, tei);
+#endif
+		break;
+
+	default:
+		break;
+	}
+}
+#endif
+
+/*
+ * Timer Tick function
+ */
+void Q921TimerTick(L2TRUNK trunk)
+{
+	struct Q921_Link *link;
+	L2ULONG tNow = Q921GetTime();
+	int numlinks = Q921_IS_PTMP_NT(trunk) ? Q921_TEI_MAX : 1;
+	int x;
+
+	for(x = 0; x <= numlinks; x++) {
+		link = Q921_LINK_CONTEXT(trunk, x);
+
+		/* TODO: check if TEI is assigned and skip check if not (speedup!) */
+		if(link->state == Q921_STATE_STOPPED)
+			continue;
+
+		if (link->T200 && tNow > link->T200) {
+			Q921T200TimerExpire(trunk, link->tei);
+		}
+		if (link->T203 && tNow > link->T203) {
+			Q921T203TimerExpire(trunk, link->tei);		
+		}
+
+		if(Q921_IS_PTMP_NT(trunk) && link->tei) {
+			if (link->T201 && tNow > link->T201) {
+				Q921T201TimerExpire(trunk, link->tei);
+			}
+		}
+
+		if(!Q921_IS_PTMP_NT(trunk)) {
+			if (trunk->T202 && tNow > trunk->T202) {
+				Q921T202TimerExpire(trunk);
+			}
+		}
+
+		/* Send enqueued I frame, if available */
+		Q921SendQueuedIFrame(trunk, link->tei);
+
+		/* Send ack if pending */
+		Q921AcknowledgePending(trunk, link->tei);
+	}
+
+}
+
+void Q921SetGetTimeCB(L2ULONG (*callback)(void))
+{
+    Q921GetTimeProc = callback;
+}
+
+/*****************************************************************************
+
+  Function:     Q921QueueHDLCFrame
+
+  Description:  Called to receive and queue an incoming HDLC frame. Will
+                queue this in Q921HDLCInQueue. The called must either call
+                Q921Rx12 directly afterwards or signal Q921Rx12 to be called
+                later. Q921Rx12 will read from the same queue and process
+                the frame.
+
+                This function assumes that the message contains header 
+                space. This is removed for internal Q921 processing, but 
+                must be keept for I frames.
+
+  Parameters:   trunk   trunk #
+                b       ptr to frame;
+                size    size of frame in bytes
+
+*****************************************************************************/
+int Q921QueueHDLCFrame(L2TRUNK trunk, L2UCHAR *b, L2INT size)
+{
+    return MFIFOWriteMes(trunk->HDLCInQueue, b, size);
+}
+
+/**
+ * Q921EnqueueI
+ * \brief	Put I frame into transmit queue
+ *
+ */
+static int Q921EnqueueI(L2TRUNK trunk, L2UCHAR Sapi, char cr, L2UCHAR Tei, char pf, L2UCHAR *mes, L2INT size)
+{
+	struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, Tei);
+
+	/* I frame header */
+	mes[trunk->Q921HeaderSpace+0] = ((Sapi << 2) & 0xfc) | ((cr << 1) & 0x02);
+	mes[trunk->Q921HeaderSpace+1] = (Tei << 1) | 0x01;
+	mes[trunk->Q921HeaderSpace+2] = 0x00;
+	mes[trunk->Q921HeaderSpace+3] = (pf & 0x01);
+
+	Q921Log(trunk, Q921_LOG_DEBUG, "Enqueueing I frame for TEI %d [%d]\n", link->tei, Tei);
+
+	/* transmit queue, (TODO: check for full condition!) */
+	MFIFOWriteMes(link->IFrameQueue, mes, size);
+
+	/* try to send queued frame */
+	Q921SendQueuedIFrame(trunk, link->tei);
+
+	return 1;
+}
+
+/**
+ * Q921SendQueuedIFrame
+ * \brief	Try to transmit queued I frame (if available)
+ */
+static int Q921SendQueuedIFrame(L2TRUNK trunk, L2UCHAR tei)
+{
+	struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+	L2INT size = 0;
+	L2UCHAR *mes;
+
+	if(MFIFOGetMesCount(link->IFrameQueue) == 0) {
+		return 0;
+	}
+
+	/* Link ready? */
+	if(link->state != Q921_STATE_MULTIPLE_FRAME_ESTABLISHED) {
+		return 0;
+	}
+
+	/* peer receiver busy? */
+	if(Q921_CHECK_FLAG(link, Q921_FLAG_PEER_RECV_BUSY)) {
+		return 0;
+	}
+
+	/* V(S) = V(A) + k? */
+	if(link->vs == ((link->va + trunk->k) % 128)) {
+		Q921Log(trunk, Q921_LOG_WARNING, "Maximum number (%d) of outstanding I frames reached for TEI %d\n", trunk->k, tei);
+		return 0;
+	}
+
+	mes = MFIFOGetMesPtr(link->IFrameQueue, &size);
+	if(mes) {
+		/* Fill in + update counter values */
+		mes[trunk->Q921HeaderSpace+2]  = link->vs << 1;
+		mes[trunk->Q921HeaderSpace+3] |= link->vr << 1;
+
+		if(MFIFOGetMesCount(link->IFrameQueue) == 0) {
+			/* clear I frame queued */
+		}
+
+		/* Send I frame */
+		Q921Tx21Proc(trunk, mes, size);
+
+		/* V(S) = V(S) + 1 */
+		Q921_INC_COUNTER(link->vs);
+
+		/* clear acknowledge pending */
+		Q921_CLEAR_FLAG(link, Q921_FLAG_ACK_PENDING);
+
+		/* T200 running? */
+		if(!link->T200) {
+			/* Stop T203, Start T200 */
+			Q921T200TimerStart(trunk, tei);
+			Q921T203TimerStop(trunk, tei);
+		}
+
+		/* put frame into resend queue */
+		MFIFOWriteMesOverwrite(link->IFrameResendQueue, mes, size);
+
+		/* dequeue frame */
+		MFIFOKillNext(link->IFrameQueue);
+
+		/* Restart TM01 */
+		if(Q921_IS_NT(trunk)) {
+			Q921TM01TimerReset(trunk, tei);
+		}
+
+		/* no state change */
+		return 1;
+	}
+
+	return 0;
+}
+
+/**
+ * Q921SendS
+ * \brief	Prepare and send S frame
+ */
+static int Q921SendS(L2TRUNK trunk, L2UCHAR Sapi, char cr, L2UCHAR Tei, char pf, L2UCHAR sv, L2UCHAR *mes, L2INT size)
+{
+	struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, Tei);
+
+	if(!Q921_IS_READY(link)) {
+		/* don't even bother trying */
+		Q921Log(trunk, Q921_LOG_DEBUG, "Link not ready, discarding S frame for TEI %d\n", Tei);
+		return 0;
+	}
+
+	/* S frame header */
+	mes[trunk->Q921HeaderSpace+0] = ((Sapi << 2) & 0xfc) | ((cr << 1) & 0x02);
+	mes[trunk->Q921HeaderSpace+1] = (Tei << 1) | 0x01;
+	mes[trunk->Q921HeaderSpace+2] = ((sv << 2) & 0x0c) | 0x01;
+	mes[trunk->Q921HeaderSpace+3] = (link->vr << 1) | (pf & 0x01);
+
+	return Q921Tx21Proc(trunk, mes, size);
+}
+
+
+/**
+ * Q921SendU
+ * \brief	Prepare and send U frame
+ */
+static int Q921SendU(L2TRUNK trunk, L2UCHAR Sapi, char cr, L2UCHAR Tei, char pf, L2UCHAR m, L2UCHAR *mes, L2INT size)
+{
+	struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, Tei);
+
+	/* U frame header */
+	mes[trunk->Q921HeaderSpace+0] = ((Sapi << 2) & 0xfc) | ((cr << 1) & 0x02);
+	mes[trunk->Q921HeaderSpace+1] = (Tei << 1) | 0x01;
+	mes[trunk->Q921HeaderSpace+2] = ((m << 3) & 0xe0) | ((pf << 4) & 0x10) | ((m << 2) & 0x0c) | 0x03;
+
+	/* link not ready? enqueue non-TEI-mgmt UI (DL-UNIT DATA) frames */
+	if(m == 0x00 && Sapi != Q921_SAPI_TEI && link->state < Q921_STATE_TEI_ASSIGNED) {
+
+		/* write frame to queue */
+		MFIFOWriteMes(link->UIFrameQueue, mes, size);
+
+		Q921Log(trunk, Q921_LOG_DEBUG, "Link not ready, UI Frame of size %d bytes queued for TEI %d\n", size, Tei);
+		return 1;
+	}
+
+	return Q921Tx21Proc(trunk, mes, size);
+}
+
+/**
+ * TODO: NT mode handling? Need a way to get Link context from Q.931
+ */
+int Q921Rx32(L2TRUNK trunk, Q921DLMsg_t ind, L2UCHAR tei, L2UCHAR * Mes, L2INT Size)
+{
+	struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);	/* TODO: need real link tei for NT mode */
+	L2INT res = 0;
+
+	Q921Log(trunk, Q921_LOG_DEBUG, "Got frame from Q.931, type: %d, tei: %d, size: %d\n", ind, tei, Size);
+
+	switch(ind) {
+	case Q921_DL_ESTABLISH:
+		/*
+		 * Hmm...
+		 */
+		switch(link->state) {
+		case Q921_STATE_TEI_ASSIGNED:
+			if(!Q921_IS_NT(trunk)) {
+				/* establish data link */
+				Q921EstablishDataLink(trunk, link->tei);
+
+				/* Set layer 3 initiated */
+				Q921_SET_FLAG(link, Q921_FLAG_L3_INITIATED);
+
+				/* change state (no action) */
+				Q921ChangeState(trunk, Q921_STATE_AWAITING_ESTABLISHMENT, link->tei);
+			}
+			break;
+
+		case Q921_STATE_AWAITING_ESTABLISHMENT:
+			if(!Q921_IS_NT(trunk)) {
+				/* Discard I queue */
+				MFIFOClear(link->IFrameQueue);
+
+				/* Set layer 3 initiated */
+				Q921_SET_FLAG(link, Q921_FLAG_L3_INITIATED);
+			}
+			break;
+
+		case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
+		case Q921_STATE_TIMER_RECOVERY:
+			if(!Q921_IS_NT(trunk)) {
+				/* Discard I queue */
+				MFIFOClear(link->IFrameQueue);
+
+				/* establish data link */
+				Q921EstablishDataLink(trunk, link->tei);
+
+				/* Set layer 3 initiated */
+				Q921_SET_FLAG(link, Q921_FLAG_L3_INITIATED);
+
+				/* change state (no action) */
+				Q921ChangeState(trunk, Q921_STATE_AWAITING_ESTABLISHMENT, link->tei);
+			}
+			break;
+
+		default:
+			break;
+		}
+		break;
+
+	case Q921_DL_RELEASE:
+		switch(link->state) {
+		case Q921_STATE_TEI_ASSIGNED:
+			/* send DL-RELEASE confirm */
+			Q921Tx23Proc(trunk, Q921_DL_RELEASE, tei, NULL, 0);
+			break;
+
+		case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
+		case Q921_STATE_TIMER_RECOVERY:
+			if(!Q921_IS_NT(trunk)) {
+				/* Discard I queue */
+				MFIFOClear(link->IFrameQueue);
+
+				/* RC = 0 */
+				link->N200 = 0;
+
+				/* send DISC command */
+				Q921SendDISC(trunk, trunk->sapi, Q921_COMMAND(trunk), link->tei, 1);
+
+				/* Stop T203, restart T200 */
+				if(link->state == Q921_STATE_MULTIPLE_FRAME_ESTABLISHED) {
+					Q921T203TimerStop(trunk, link->tei);
+				}
+				Q921T200TimerReset(trunk, link->tei);
+
+				/* change state */
+				Q921ChangeState(trunk, Q921_STATE_AWAITING_RELEASE, link->tei);
+			}
+			break;
+
+		default:
+			break;
+		}
+		break;
+
+	case Q921_DL_DATA:	/* DL-DATA request */
+		res = Q921EnqueueI(trunk, 
+				trunk->sapi, 
+				Q921_COMMAND(trunk),
+				link->tei,
+				0, 
+				Mes, 
+				Size);
+
+		if(link->state < Q921_STATE_MULTIPLE_FRAME_ESTABLISHED) {
+			/* Treat as implicit DL-ESTABLISH request */
+
+			/* establish data link */
+			Q921EstablishDataLink(trunk, link->tei);
+
+			/* Set layer 3 initiated */
+			Q921_SET_FLAG(link, Q921_FLAG_L3_INITIATED);
+
+			/* change state (no action) */
+			Q921ChangeState(trunk, Q921_STATE_AWAITING_ESTABLISHMENT, link->tei);
+		}
+		break;
+
+	case Q921_DL_UNIT_DATA:		/* DL-UNIT DATA request */
+		res = Q921SendUN(trunk,
+				trunk->sapi,
+				Q921_COMMAND(trunk),
+				Q921_TEI_BCAST,
+				0,
+				Mes,
+				Size);
+		/* NOTE: Let the other side initiate link establishment */
+		break;
+
+	default:
+		break;
+	}
+
+	return res;
+}
+/*****************************************************************************
+
+  Function:     Q921SendRR
+
+  Description:  Compose and send Receive Ready.
+
+  Parameters:   trunk       trunk #
+                Sapi        Sapi
+                cr          C/R field.
+                Tei         Tei.
+                pf          P/F fiels octet 5
+
+  Return Value: 0 if failed, 1 if Send.
+
+*****************************************************************************/
+
+static int Q921SendRR(L2TRUNK trunk, int Sapi, int cr, int Tei, int pf)
+{
+	L2UCHAR mes[25];
+
+	return Q921SendS(trunk, Sapi, cr, Tei, pf, 0x00, mes, trunk->Q921HeaderSpace+4);
+}
+
+/*****************************************************************************
+
+  Function:     Q921SendRNR
+
+  Description:  Compose and send Receive Nor Ready
+
+  Parameters:   trunk       trunk #
+                Sapi        Sapi
+                cr          C/R field.
+                Tei         Tei.
+                pf          P/F fiels octet 5
+
+  Return Value: 0 if failed, 1 if Send.
+
+*****************************************************************************/
+static int Q921SendRNR(L2TRUNK trunk, int Sapi, int cr, int Tei, int pf)
+{
+	L2UCHAR mes[25];
+
+	return Q921SendS(trunk, Sapi, cr, Tei, pf, 0x01, mes, trunk->Q921HeaderSpace+4);
+}
+
+/*****************************************************************************
+
+  Function:     Q921SendREJ
+
+  Description:  Compose and Send Reject.
+
+  Parameters:   trunk       trunk #
+                Sapi        Sapi
+                cr          C/R field.
+                Tei         Tei.
+                pf          P/F fiels octet 5
+
+  Return Value: 0 if failed, 1 if Send.
+
+*****************************************************************************/
+static int Q921SendREJ(L2TRUNK trunk, int Sapi, int cr, int Tei, int pf)
+{
+	L2UCHAR mes[25];
+
+	return Q921SendS(trunk, Sapi, cr, Tei, pf, 0x03, mes, trunk->Q921HeaderSpace+4);
+}
+
+/*****************************************************************************
+
+  Function:     Q921SendSABME
+
+  Description:  Compose and send SABME
+
+  Parameters:   trunk       trunk #
+                Sapi        Sapi
+                cr          C/R field.
+                Tei         Tei.
+                pf          P fiels octet 4
+
+  Return Value: 0 if failed, 1 if Send.
+
+*****************************************************************************/
+static int Q921SendSABME(L2TRUNK trunk, int Sapi, int cr, int Tei, int pf)
+{
+	L2UCHAR mes[25];
+
+	return Q921SendU(trunk, Sapi, cr, Tei, pf, 0x0f, mes, trunk->Q921HeaderSpace+3);
+}
+
+
+/**
+ * Q921Start
+ * \brief	Start trunk
+ * \param[in]	trunk	pointer to Q921 data struct
+ * \return	> 0 on success; <= 0 on error
+ */
+int Q921Start(L2TRUNK trunk)
+{
+	int x, numlinks = Q921_IS_PTMP_NT(trunk) ? Q921_TEI_MAX : 1;
+	struct Q921_Link *link = Q921_TRUNK_CONTEXT(trunk);
+
+	if(trunk->initialized != INITIALIZED_MAGIC)
+		return 0;
+
+	memset(trunk->context, 0, numlinks * sizeof(struct Q921_Link));
+
+	/* Common init part */
+	for(x = 0; x <= numlinks; x++) {
+		link = Q921_LINK_CONTEXT(trunk, x);
+
+		link->state = Q921_STATE_TEI_UNASSIGNED;
+		link->tei   = 0;
+
+		/* Initialize per-TEI I + UI queues */
+		MFIFOCreate(link->UIFrameQueue, Q921MAXHDLCSPACE, 10);
+		MFIFOCreate(link->IFrameQueue,  Q921MAXHDLCSPACE, 10);
+		MFIFOCreate(link->IFrameResendQueue, Q921MAXHDLCSPACE, 10);
+	}
+
+	if(Q921_IS_PTMP_TE(trunk)) {
+		link->state = Q921_STATE_TEI_UNASSIGNED;
+		link->tei   = 0;
+	}
+	else if(Q921_IS_PTMP_NT(trunk)) {
+		link = Q921_TRUNK_CONTEXT(trunk);
+
+		link->state = Q921_STATE_TEI_ASSIGNED;
+		link->tei   = trunk->tei;
+
+		/* clear tei map */
+		memset(trunk->tei_map, 0, Q921_TEI_MAX + 1);
+	}
+	else {
+		link->state = Q921_STATE_TEI_ASSIGNED;
+		link->tei   = trunk->tei;
+	}
+
+	Q921Log(trunk, Q921_LOG_DEBUG, "Starting trunk %p (sapi: %d, tei: %d, mode: %s %s)\n",
+				 trunk,
+				 trunk->sapi,
+				 link->tei,
+				 Q921_IS_PTMP(trunk) ? "PTMP" : "PTP",
+				 Q921_IS_TE(trunk) ? "TE" : "NT");
+
+	if(Q921_IS_PTP(trunk)) {
+		Q921Log(trunk, Q921_LOG_DEBUG, "Sending SABME\n");
+
+		return Q921SendSABME(trunk, 
+					trunk->sapi, 
+					Q921_COMMAND(trunk),
+					link->tei, 
+					1);
+
+	} else if(Q921_IS_PTMP_NT(trunk)) {
+
+		Q921Log(trunk, Q921_LOG_DEBUG, "Revoking all TEIs\n");
+
+		return Q921TeiSendRemoveRequest(trunk, Q921_TEI_BCAST);	/* Revoke all TEIs in use */
+	} else {
+
+		Q921Log(trunk, Q921_LOG_DEBUG, "Requesting TEI\n");
+
+		return Q921TeiSendAssignRequest(trunk);
+	}
+}
+
+
+/**
+ * Q921Stop
+ * \brief	Stop trunk
+ * \param[in]	trunk	pointer to Q921 data struct
+ * \return	> 0 on success; <= 0 on error
+ *
+ * \author	Stefan Knoblich
+ */
+int Q921Stop(L2TRUNK trunk)
+{
+	struct Q921_Link *link;
+	int x, numlinks;
+
+	if(!trunk)
+		return -1;
+
+	link = Q921_TRUNK_CONTEXT(trunk);
+	numlinks = Q921_IS_PTMP_NT(trunk) ? Q921_TEI_MAX : 1;
+
+	if(Q921_IS_STOPPED(link))
+		return 0;
+
+	/* Release TEI */
+	if(Q921_IS_PTMP_TE(trunk)) {
+		/* send verify request */
+		Q921TeiSendVerifyRequest(trunk);
+
+		/* drop TEI */
+		link->tei  = 0;
+	}
+
+	/* Stop timers, stop link, flush queues */
+	for(x = 0; x <= numlinks; x++) {
+		Q921T200TimerStop(trunk, x);
+		Q921T203TimerStop(trunk, x);
+		Q921T201TimerStop(trunk, x);
+
+		/* Change state (no action) */
+		Q921ChangeState(trunk, Q921_STATE_STOPPED, x);
+
+		/* Flush per-tei I/UI queues */
+		MFIFOClear(link->UIFrameQueue);
+		MFIFOClear(link->IFrameQueue);
+		MFIFOClear(link->IFrameResendQueue);
+	}
+	Q921T202TimerStop(trunk);
+
+	/* Flush HDLC queue */
+	MFIFOClear(trunk->HDLCInQueue);
+
+	return 0;
+}
+
+
+/*****************************************************************************
+
+  Function:     Q921SendDM
+
+  Description:  Compose and Send DM (Disconnected Mode)
+
+  Parameters:   trunk       trunk #
+                Sapi        Sapi
+                cr          C/R field.
+                Tei         Tei.
+                pf          F fiels octet 4
+
+  Return Value: 0 if failed, 1 if Send.
+
+*****************************************************************************/
+static int Q921SendDM(L2TRUNK trunk, int Sapi, int cr, int Tei, int pf)
+{
+	L2UCHAR mes[25];
+
+	return Q921SendU(trunk, Sapi, cr, Tei, pf, 0x03, mes, trunk->Q921HeaderSpace+3);
+}
+
+/*****************************************************************************
+
+  Function:     Q921SendDISC
+
+  Description:  Compose and Send Disconnect
+
+  Parameters:   trunk       trunk #
+                Sapi        Sapi
+                cr          C/R field.
+                Tei         Tei.
+                pf          P fiels octet 4
+
+  Return Value: 0 if failed, 1 if Send.
+
+*****************************************************************************/
+static int Q921SendDISC(L2TRUNK trunk, int Sapi, int cr, int Tei, int pf)
+{
+	L2UCHAR mes[25];
+
+	return Q921SendU(trunk, Sapi, cr, Tei, pf, 0x08, mes, trunk->Q921HeaderSpace+3);
+}
+
+/*****************************************************************************
+
+  Function:     Q921SendUA
+
+  Description:  Compose and Send UA
+
+  Parameters:   trunk       trunk #
+                Sapi        Sapi
+                cr          C/R field.
+                Tei         Tei.
+                pf          F fiels octet 4
+
+  Return Value: 0 if failed, 1 if Send.
+
+*****************************************************************************/
+static int Q921SendUA(L2TRUNK trunk, int Sapi, int cr, int Tei, int pf)
+{
+	L2UCHAR mes[25];
+
+	return Q921SendU(trunk, Sapi, cr, Tei, pf, 0x0c, mes, trunk->Q921HeaderSpace+3);
+}
+
+static int Q921SendUN(L2TRUNK trunk, int Sapi, int cr, int Tei, int pf, L2UCHAR *mes, L2INT size)
+{
+	return Q921SendU(trunk, Sapi, cr, Tei, pf, 0x00, mes, size+trunk->Q921HeaderSpace+3);
+}
+
+
+/**
+ * Q921ProcSABME
+ * \brief	Handle incoming SABME
+ * \param[in]	trunk	pointer to Q921 data struct
+ * \param[in]	mes	pointer to message buffer
+ * \param[in]	size	size of message
+ * \return	> 0 on success, <= 0 on error
+ */
+static int Q921ProcSABME(L2TRUNK trunk, L2UCHAR *mes, L2INT size)
+{
+	L2UCHAR pf = (mes[2] & 0x10) >> 4;				/* poll / final flag */
+	L2UCHAR tei = (mes[1] & 0xfe) >> 1;
+	struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+	switch(link->state) {
+	case Q921_STATE_TEI_ASSIGNED:
+		/* send UA */
+		Q921SendUA(trunk,
+				trunk->sapi,
+				Q921_RESPONSE(trunk),	/* or command? */
+				tei, pf);
+
+		/* clear counters */
+		link->vr=0;
+		link->vs=0;
+		link->va=0;
+
+		/* TODO: send DL-Establish indication to Q.931 */
+		Q921Tx23Proc(trunk, Q921_DL_ESTABLISH, tei, NULL, 0);
+
+		/* start T203 */
+		Q921T203TimerStart(trunk, tei);
+
+		/* change state (no action) */
+		Q921ChangeState(trunk, Q921_STATE_MULTIPLE_FRAME_ESTABLISHED, tei);
+		break;
+
+	case Q921_STATE_AWAITING_ESTABLISHMENT:
+		/* send UA */
+		Q921SendUA(trunk,
+				trunk->sapi,
+				Q921_RESPONSE(trunk),
+				tei, pf);
+
+		/* no state change */
+		break;
+
+	case Q921_STATE_AWAITING_RELEASE:
+		/* send DM */
+		Q921SendDM(trunk,
+				trunk->sapi,
+				Q921_RESPONSE(trunk),
+				tei, pf);
+
+		/* no state change */
+		break;
+
+	case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
+	case Q921_STATE_TIMER_RECOVERY:
+		/* send UA */
+		Q921SendUA(trunk,
+				trunk->sapi,
+				Q921_RESPONSE(trunk),
+				tei, pf);
+
+		/* clear exception conditions */
+		Q921ResetExceptionConditions(trunk, tei);
+
+		/* send MDL-Error indication */
+
+		/* V(S) == V(A) ? */
+		if(link->vs != link->va) {
+			/* clear I queue */
+			MFIFOClear(link->IFrameQueue);
+
+			/* DL-Establish indication */
+			Q921Tx23Proc(trunk, Q921_DL_ESTABLISH, tei, NULL, 0);
+		}
+
+		/* clear counters */
+		link->vr=0;
+		link->vs=0;
+		link->va=0;
+
+		/* Stop T200, start T203 */
+		Q921T200TimerStop(trunk, tei);
+		Q921T203TimerStart(trunk, tei);
+
+		/* state change only if in TIMER_RECOVERY state */
+		if(link->state == Q921_STATE_TIMER_RECOVERY)
+			Q921ChangeState(trunk, Q921_STATE_MULTIPLE_FRAME_ESTABLISHED, tei);
+		break;
+
+	default:
+		break;
+	}
+
+	return 1;
+}
+
+
+/**
+ * Q921ProcDM
+ * \brief	Handle incoming DM
+ * \param[in]	trunk	pointer to Q921 data struct
+ * \param[in]	mes	pointer to message buffer
+ * \param[in]	size	size of message
+ * \return	> 0 on success, <= 0 on error
+ */
+static int Q921ProcDM(L2TRUNK trunk, L2UCHAR *mes, L2INT size)
+{
+	L2UCHAR pf = (mes[2] & 0x10) >> 4;				/* poll / final flag */
+	L2UCHAR tei = (mes[1] & 0xfe) >> 1;
+	struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+	switch(link->state) {
+	case Q921_STATE_TEI_ASSIGNED:
+		if(!pf) {
+			/* to next state (no action) */
+			Q921ChangeState(trunk, Q921_STATE_AWAITING_ESTABLISHMENT, tei);
+		}
+		break;
+
+	case Q921_STATE_AWAITING_ESTABLISHMENT:
+	case Q921_STATE_AWAITING_RELEASE:
+		if(pf) {
+			if(link->state == Q921_STATE_AWAITING_ESTABLISHMENT) {
+				/* Discard I queue */
+				MFIFOClear(link->IFrameQueue);
+			}
+
+			/* Send DL-Release indication to Q.931 */
+			Q921Tx23Proc(trunk, Q921_DL_RELEASE, tei, NULL, 0);
+
+			/* Stop T200 */
+			Q921T200TimerStop(trunk, tei);
+
+			/* Change state (no action) */
+			Q921ChangeState(trunk, Q921_STATE_TEI_ASSIGNED, tei);
+		}
+		break;
+
+	case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
+		if(pf) {
+			/* MDL-Error indication (B) */
+
+			/* no state change */
+		} else {
+			/* MDL-Error indication (E) */
+
+			/* establish data link */
+			Q921EstablishDataLink(trunk, tei);
+
+			/* clear L3 initiated */
+			Q921_CLEAR_FLAG(link, Q921_FLAG_L3_INITIATED);
+
+			/* change state (no action?) */
+			Q921ChangeState(trunk, Q921_STATE_AWAITING_ESTABLISHMENT, tei);
+		}
+		break;
+
+	case Q921_STATE_TIMER_RECOVERY:
+		if(pf) {
+			/* MDL Error indication (B) */
+		} else {
+			/* MDL Error indication (E) */
+		}
+
+		/* establish data link */
+		Q921EstablishDataLink(trunk, tei);
+
+		/* clear layer 3 initiated */
+		Q921_CLEAR_FLAG(link, Q921_FLAG_L3_INITIATED);
+
+		/* change state */
+		Q921ChangeState(trunk, Q921_STATE_AWAITING_ESTABLISHMENT, tei);
+		break;
+
+	default:
+		break;
+	}
+
+	return 1;
+}
+
+/**
+ * Q921ProcUA
+ * \brief	Handle incoming UA
+ * \param[in]	trunk	pointer to Q921 data struct
+ * \param[in]	mes	pointer to message buffer
+ * \param[in]	size	size of message
+ * \return	> 0 on success, <= 0 on error
+ */
+static int Q921ProcUA(L2TRUNK trunk, L2UCHAR *mes, L2INT size)
+{
+	L2UCHAR pf = (mes[2] & 0x10) >> 4;				/* poll / final flag */
+	L2UCHAR tei = (mes[1] & 0xfe) >> 1;
+	struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+	switch(link->state) {
+	case Q921_STATE_TEI_ASSIGNED:
+	case Q921_STATE_TIMER_RECOVERY:
+		/* MDL Error indication (C, D) */
+		Q921Log(trunk, Q921_LOG_ERROR, "Received UA frame in invalid state\n");
+		break;
+
+	case Q921_STATE_AWAITING_ESTABLISHMENT:
+		if(pf) {
+			/* TODO: other fancy stuff (see docs) */
+			if(Q921_CHECK_FLAG(link, Q921_FLAG_L3_INITIATED)) {	/* layer3 initiated */
+				link->vr = 0;
+
+				/* DL-Establish confirm */
+				Q921Tx23Proc(trunk, Q921_DL_ESTABLISH_CONFIRM, tei, NULL, 0);
+
+			} else if(link->vs != link->va) {
+
+				/* discard I queue */
+				MFIFOClear(link->IFrameQueue);
+
+				/* DL-Establish indication */
+				Q921Tx23Proc(trunk, Q921_DL_ESTABLISH, tei, NULL, 0);
+			}
+
+			/* Stop T200, start T203 */
+			Q921T200TimerStop(trunk, tei);
+			Q921T203TimerStart(trunk, tei);
+
+			link->vs = 0;
+			link->va = 0;
+
+			/* change state (no action) */
+			Q921ChangeState(trunk, Q921_STATE_MULTIPLE_FRAME_ESTABLISHED, tei);
+		} else {
+			/* MDL Error indication (C, D) */
+			Q921Log(trunk, Q921_LOG_ERROR, "Received UA frame is not a response to a request\n");
+
+			/* no state change */
+		}
+		break;
+
+	case Q921_STATE_AWAITING_RELEASE:
+		if(pf) {
+			/* DL Release confirm */
+			Q921Tx23Proc(trunk, Q921_DL_RELEASE_CONFIRM, tei, NULL, 0);
+
+			/* Stop T200 */
+			Q921T200TimerStop(trunk, tei);
+
+			/* change state (no action) */
+			Q921ChangeState(trunk, Q921_STATE_TEI_ASSIGNED, tei);
+		} else {
+			/* MDL Error indication (D) */
+			Q921Log(trunk, Q921_LOG_ERROR, "Received UA frame is not a response to a request\n");
+
+			/* no state change */
+		}
+		break;
+
+	case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
+		/* MDL Error indication (C, D) */
+		Q921Log(trunk, Q921_LOG_ERROR, "Received UA frame in invalid state\n");
+
+		/* no state change */
+		break;
+
+	default:
+		break;
+	}
+
+	return 1;
+}
+
+
+/**
+ * Q921ProcDISC
+ * \brief	Handle incoming DISC
+ * \param[in]	trunk	pointer to Q921 data struct
+ * \param[in]	mes	pointer to message buffer
+ * \param[in]	size	size of message
+ * \return	> 0 on success, <= 0 on error
+ */
+static int Q921ProcDISC(L2TRUNK trunk, L2UCHAR *mes, L2INT size)
+{
+	L2UCHAR pf  = (mes[2] & 0x10) >> 4;				/* poll / final flag */
+	L2UCHAR tei = (mes[1] & 0xfe) >> 1;
+	struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+	switch(link->state) {
+	case Q921_STATE_TEI_ASSIGNED:
+	case Q921_STATE_AWAITING_ESTABLISHMENT:
+		/* Send DM */
+		Q921SendDM(trunk,
+				trunk->sapi,
+				Q921_RESPONSE(trunk),
+				tei, pf);
+
+		/* no state change */
+		break;
+
+	case Q921_STATE_AWAITING_RELEASE:
+		Q921SendUA(trunk,
+				trunk->sapi,
+				Q921_RESPONSE(trunk),
+				tei, pf);
+
+		/* no state change */
+		break;
+
+	case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
+	case Q921_STATE_TIMER_RECOVERY:
+		/* Discard I queue */
+		MFIFOClear(link->IFrameQueue);
+
+		/* send UA */
+		Q921SendUA(trunk,
+				trunk->sapi,
+				Q921_RESPONSE(trunk),
+				tei, pf);
+		
+		/* DL Release indication */
+		Q921Tx23Proc(trunk, Q921_DL_RELEASE, tei, NULL, 0);
+
+		/* Stop T200 */
+		Q921T200TimerStop(trunk, tei);
+
+		if(link->state == Q921_STATE_MULTIPLE_FRAME_ESTABLISHED) {
+			/* Stop T203 */
+			Q921T203TimerStop(trunk, tei);
+		}
+
+		/* change state (no action) */
+		Q921ChangeState(trunk, Q921_STATE_TEI_ASSIGNED, tei);
+		break;
+
+	default:
+		Q921Log(trunk, Q921_LOG_ERROR, "Invalid DISC received in state \"%s\" (%d)", Q921State2Name(link->state), link->state);
+		break;
+	}
+
+	return 1;
+}
+
+
+/**
+ * Q921ProcRR
+ * \brief	Handle incoming RR
+ * \param[in]	trunk	pointer to Q921 data struct
+ * \param[in]	mes	pointer to message buffer
+ * \param[in]	size	size of message
+ * \return	> 0 on success, <= 0 on error
+ */
+static int Q921ProcRR(L2TRUNK trunk, L2UCHAR *mes, L2INT size)
+{
+	L2UCHAR cr = (mes[0] & 0x02) >> 1;
+	L2UCHAR pf =  mes[3] & 0x01;		/* poll / final flag */
+	L2UCHAR nr = (mes[3] >> 1);
+//	L2UCHAR	sapi = (mes[0] & 0xfc) >> 2;
+	L2UCHAR	tei  = (mes[1] & 0xfe) >> 1;
+	struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+	switch(link->state) {
+	case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
+		/* clear receiver peer busy */
+		Q921_CLEAR_FLAG(link, Q921_FLAG_PEER_RECV_BUSY);
+
+		if (Q921_IS_COMMAND(trunk, cr)) { /* if this is a command */
+			if(pf) {
+				/* Enquiry response */
+				Q921SendEnquiryResponse(trunk, tei);
+			}
+		} else {
+			if(pf) {
+				/* MDL Error indication */
+			}
+		}
+
+		/* */
+		if(link->va <= nr && nr <= link->vs) {
+
+			if(nr == link->vs) {
+				/* V(A) = N(R) */
+				link->va = nr;
+
+				/* Stop T200, restart T203 */
+				Q921T200TimerStop(trunk, tei);
+				Q921T203TimerReset(trunk, tei);
+
+			} else if(nr == link->va) {
+
+				/* do nothing */
+
+			} else {
+				/* V(A) = N(R) */
+				link->va = nr;
+
+				/* Restart T200 */
+				Q921T200TimerReset(trunk, tei);
+			}
+			/* no state change */
+
+		} else {
+			/* N(R) Error recovery */
+			Q921NrErrorRecovery(trunk, tei);
+
+			/* change state (no action) */
+			Q921ChangeState(trunk, Q921_STATE_AWAITING_ESTABLISHMENT, tei);
+		}
+		break;
+
+	case Q921_STATE_TIMER_RECOVERY:
+		/* clear receiver peer busy */
+		Q921_CLEAR_FLAG(link, Q921_FLAG_PEER_RECV_BUSY);
+
+		/* command + P? */
+		if(Q921_IS_COMMAND(trunk, cr) && pf) {
+			/* Enquiry response */
+			Q921SendEnquiryResponse(trunk, tei);
+		}
+
+		/* */
+		if(link->va <= nr && nr <= link->vs) {
+			/* V(A) = N(R) */
+			link->va = nr;
+
+			if(!Q921_IS_COMMAND(trunk, cr) && pf) {
+				/* Stop T200, start T203 */
+				Q921T200TimerStop(trunk, tei);
+				Q921T203TimerStart(trunk, tei);
+
+				/* Invoke retransmission */
+				Q921InvokeRetransmission(trunk, tei, nr);
+
+				/* change state (no action) */
+				Q921ChangeState(trunk, Q921_STATE_MULTIPLE_FRAME_ESTABLISHED, tei);
+			}
+			/* no state change otherwise */
+		} else {
+			/* N(R) Error recovery */
+			Q921NrErrorRecovery(trunk, tei);
+
+			/* change state (no action) */
+			Q921ChangeState(trunk, Q921_STATE_AWAITING_ESTABLISHMENT, tei);
+		}
+		break;
+
+	default:
+		break;
+	}
+	return 1;
+}
+
+
+/**
+ * Q921ProcREJ
+ * \brief	Handle incoming REJ
+ * \param[in]	trunk	pointer to Q921 data struct
+ * \param[in]	mes	pointer to message buffer
+ * \param[in]	size	size of message
+ * \return	> 0 on success, <= 0 on error
+ */
+static int Q921ProcREJ(L2TRUNK trunk, L2UCHAR *mes, L2INT size)
+{
+	L2UCHAR cr = (mes[0] & 0x02) >> 1;
+	L2UCHAR pf =  mes[3] & 0x01;		/* poll / final flag */
+	L2UCHAR nr = (mes[3] >> 1);
+//	L2UCHAR	sapi = (mes[0] & 0xfc) >> 2;
+	L2UCHAR	tei  = (mes[1] & 0xfe) >> 1;
+	struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+	switch(link->state) {
+	case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
+		/* clear receiver peer busy */
+		Q921_CLEAR_FLAG(link, Q921_FLAG_PEER_RECV_BUSY);
+
+		/* command? */
+		if(Q921_IS_COMMAND(trunk, cr)) {
+			if(pf) {
+				/* Enquiry response */
+				Q921SendEnquiryResponse(trunk, tei);
+			}
+		} else {
+			if(pf) {
+				/* MDL Error indication (A) */
+			}
+		}
+
+		/* */
+		if(link->va <= nr && nr <= link->vs) {
+
+			/* V(A) = N(R) */
+			link->va = nr;
+
+			/* Stop T200, start T203 */
+			Q921T200TimerStop(trunk, tei);
+			Q921T203TimerStart(trunk, tei);
+
+			/* Invoke retransmission of frame >N(R)  (?) */
+			Q921InvokeRetransmission(trunk, tei, nr);
+
+			/* no state change */
+		} else {
+			/* N(R) Error recovery */
+			Q921NrErrorRecovery(trunk, tei);
+
+			/* change state (no action) */
+			Q921ChangeState(trunk, Q921_STATE_AWAITING_ESTABLISHMENT, tei);
+		}
+		break;
+
+	case Q921_STATE_TIMER_RECOVERY:
+		/* clear receiver peer busy */
+		Q921_CLEAR_FLAG(link, Q921_FLAG_PEER_RECV_BUSY);
+
+		/* command + P ? */
+		if(Q921_IS_COMMAND(trunk, cr) && pf) {
+			/* Enquiry response */
+			Q921SendEnquiryResponse(trunk, tei);
+		}
+
+		/* */
+		if(link->va <= nr && nr <= link->vs) {
+
+			/* V(A) = N(R) */
+			link->va = nr;
+
+			if(!Q921_IS_COMMAND(trunk, cr) && pf) {
+				/* Stop T200, start T203 */
+				Q921T200TimerStop(trunk, tei);
+				Q921T203TimerStart(trunk, tei);
+
+				/* Invoke retransmission */
+				Q921InvokeRetransmission(trunk, tei, nr);
+
+				/* change state (no action) */
+				Q921ChangeState(trunk, Q921_STATE_MULTIPLE_FRAME_ESTABLISHED, tei);
+			}
+			/* no state change otherwise */
+		} else {
+			/* N(R) Error recovery */
+			Q921NrErrorRecovery(trunk, tei);
+
+			/* change state (no action) */
+			Q921ChangeState(trunk, Q921_STATE_AWAITING_ESTABLISHMENT, tei);
+		}
+		break;
+
+	default:
+		break;
+	}
+
+	return 1;
+}
+
+
+/**
+ * Q921ProcRNR
+ * \brief	Handle incoming RNR
+ * \param[in]	trunk	pointer to Q921 data struct
+ * \param[in]	mes	pointer to message buffer
+ * \param[in]	size	size of message
+ * \return	> 0 on success, <= 0 on error
+ */
+static int Q921ProcRNR(L2TRUNK trunk, L2UCHAR *mes, L2INT size)
+{
+	L2UCHAR cr = (mes[0] & 0x02) >> 1;
+	L2UCHAR pf =  mes[3] & 0x01;		/* poll / final flag */
+	L2UCHAR nr = (mes[3] >> 1);
+//	L2UCHAR	sapi = (mes[0] & 0xfc) >> 2;
+	L2UCHAR	tei  = (mes[1] & 0xfe) >> 1;
+	struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+	switch(link->state) {
+	case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
+		/* set peer receiver busy */
+		Q921_SET_FLAG(link, Q921_FLAG_PEER_RECV_BUSY);
+
+		/* command? */
+		if(Q921_IS_COMMAND(trunk, cr)) {
+			if(pf) {
+				/* Enquiry response */
+				Q921SendEnquiryResponse(trunk, tei);
+			}
+		} else {
+			if(pf) {
+				/* MDL Error indication (A) */
+			}
+		}
+
+		/* */
+		if(link->va <= nr && nr <= link->vs) {
+
+			/* V(A) = N(R) */
+			link->va = nr;
+
+			/* Stop T203, restart T200 */
+			Q921T200TimerReset(trunk, tei);
+			Q921T203TimerStop(trunk, tei);
+
+			/* no state change */
+		} else {
+			/* N(R) Error recovery */
+			Q921NrErrorRecovery(trunk, tei);
+
+			/* change state (no action) */
+			Q921ChangeState(trunk, Q921_STATE_AWAITING_ESTABLISHMENT, tei);
+		}
+		break;
+
+	case Q921_STATE_TIMER_RECOVERY:
+		/* set peer receiver busy */
+		Q921_SET_FLAG(link, Q921_FLAG_PEER_RECV_BUSY);
+
+		/* command + P? */
+		if(Q921_IS_COMMAND(trunk, cr) && pf) {
+			/* Enquiry response */
+			Q921SendEnquiryResponse(trunk, tei);
+		}
+
+		/* */
+		if(link->va <= nr && nr <= link->vs) {
+
+			/* V(A) = N(R) */
+			link->va = nr;
+
+			if(!Q921_IS_COMMAND(trunk, cr) && pf) {
+				/* Restart T200 */
+				Q921T200TimerReset(trunk, tei);
+
+				/* Invoke retransmission */
+				Q921InvokeRetransmission(trunk, tei, nr);
+
+				/* change state (no action) */
+				Q921ChangeState(trunk, Q921_STATE_MULTIPLE_FRAME_ESTABLISHED, tei);
+			}
+			/* no state change otherwise */
+		} else {
+			/* N(R) Error recovery */
+			Q921NrErrorRecovery(trunk, tei);
+
+			/* change state (no action) */
+			Q921ChangeState(trunk, Q921_STATE_AWAITING_ESTABLISHMENT, tei);
+		}
+		break;
+
+	default:
+		break;
+	}
+
+	return 1;
+}
+
+#if 0
+static int Q921SetReceiverBusy(L2TRUNK trunk)
+{
+	struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+	switch(link->state) {
+	case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
+		if(!Q921_CHECK_FLAG(link, Q921_FLAG_RECV_BUSY)) {
+			/* set own receiver busy */
+			Q921_SET_FLAG(link, Q921_FLAG_RECV_BUSY);
+
+			/* send RR response */
+			Q921SendRR(trunk, trunk->sapi, Q921_RESPONSE(trunk), link->tei, 0);
+
+			/* clear ack pending */
+			Q921_CLEAR_FLAG(link, Q921_FLAG_ACK_PENDING);
+		}
+		break;
+
+	case Q921_STATE_TIMER_RECOVERY:
+		if(!Q921_CHECK_FLAG(link, Q921_FLAG_RECV_BUSY)) {
+			/* set own receiver busy */
+			Q921_SET_FLAG(link, Q921_FLAG_RECV_BUSY);
+
+			/* send RNR response */
+			Q921SendRNR(trunk, trunk->sapi, Q921_RESPONSE(trunk), link->tei, 0);
+
+			/* clear ack pending */
+			Q921_CLEAR_FLAG(link, Q921_FLAG_ACK_PENDING);
+		}
+		break;
+
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int Q921ClearReceiverBusy(L2TRUNK trunk)
+{
+	struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+	switch(link->state) {
+	case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
+	case Q921_STATE_TIMER_RECOVERY:
+		if(Q921_CHECK_FLAG(link, Q921_FLAG_RECV_BUSY)) {
+			/* clear own receiver busy */
+			Q921_CLEAR_FLAG(link, Q921_FLAG_RECV_BUSY);
+
+			/* send RNR response */
+			Q921SendRNR(trunk, trunk->sapi, Q921_RESPONSE(trunk), link->tei, 0);
+
+			/* clear ack pending */
+			Q921_CLEAR_FLAG(link, Q921_FLAG_ACK_PENDING);
+		}
+		break;
+
+	default:
+		break;
+	}
+
+	return 0;
+}
+#endif
+
+static int Q921ProcIFrame(L2TRUNK trunk, L2UCHAR *mes, L2INT size)
+{
+	/* common fields: get sapi, tei and cr */
+//	L2UCHAR sapi = (mes[0] & 0xfc) >> 2;
+//	L2UCHAR cr   = (mes[0] & 0x02) >> 1;
+	L2UCHAR tei  = (mes[1] & 0xfe) >> 1;
+	L2UCHAR pf   =  mes[3] & 0x01;		/* poll / final flag */
+	L2UCHAR nr   =  mes[3] >> 1;		/* receive sequence number */
+	L2UCHAR ns   =  mes[2] >> 1;		/* send sequence number */
+	L2UCHAR discard = 0;
+	struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+	/* Ignore I frames in earlier states */
+	if(link->state < Q921_STATE_MULTIPLE_FRAME_ESTABLISHED) {
+		Q921Log(trunk, Q921_LOG_NOTICE, "I frame in invalid state ignored\n");
+		return 0;
+	}
+
+	/* Receiver busy? */
+	if(Q921_CHECK_FLAG(link, Q921_FLAG_RECV_BUSY)) {
+		/* discard information */
+		discard = 1;
+
+		if(pf) {
+			/* send RNR Response */
+			Q921SendRNR(trunk, trunk->sapi, Q921_RESPONSE(trunk), tei, 1);
+
+			/* Clear ack pending */
+			Q921_CLEAR_FLAG(link, Q921_FLAG_ACK_PENDING);
+		}
+	}
+	else {
+		if(ns != link->vr) {
+			/* discard information */
+			discard = 1;
+
+			if(Q921_CHECK_FLAG(link, Q921_FLAG_REJECT) && pf) {
+
+				/* Send RR response */
+				Q921SendRR(trunk, trunk->sapi, Q921_RESPONSE(trunk), tei, 1);
+
+				/* clear ack pending */
+				Q921_CLEAR_FLAG(link, Q921_FLAG_ACK_PENDING);
+			}
+			else if(!Q921_CHECK_FLAG(link, Q921_FLAG_REJECT)){
+
+				/* set reject exception */
+				Q921_SET_FLAG(link, Q921_FLAG_REJECT);
+
+				/* Send REJ response */
+				Q921SendREJ(trunk, trunk->sapi, Q921_RESPONSE(trunk), tei, pf);
+
+				/* clear ack pending */
+				Q921_CLEAR_FLAG(link, Q921_FLAG_ACK_PENDING);
+			}
+		}
+		else {
+			/* V(R) = V(R) + 1 */
+			Q921_INC_COUNTER(link->vr);
+
+			/* clear reject exception */
+			Q921_CLEAR_FLAG(link, Q921_FLAG_REJECT);
+
+			/* DL-Data indication */
+			Q921Tx23Proc(trunk, Q921_DL_DATA, tei, mes, size);
+
+			if(pf) {
+				/* Send RR response */
+				Q921SendRR(trunk, trunk->sapi, Q921_RESPONSE(trunk), tei, 1);
+
+				/* clear ack pending */
+				Q921_CLEAR_FLAG(link, Q921_FLAG_ACK_PENDING);
+			}
+			else if(!Q921_CHECK_FLAG(link, Q921_FLAG_ACK_PENDING)) {
+				/* ack pending */
+
+				/* Send RR response */
+				Q921SendRR(trunk, trunk->sapi, Q921_RESPONSE(trunk), tei, 0);
+				
+				/* set ack pending*/
+				Q921_SET_FLAG(link, Q921_FLAG_ACK_PENDING);
+			}
+		}
+	}
+
+
+	switch(link->state) {
+	case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
+		if(link->va <= nr && nr <= link->vs) {
+			if(Q921_CHECK_FLAG(link, Q921_FLAG_PEER_RECV_BUSY)) {
+				link->va = nr;
+			}
+			else if(nr == link->vs) {
+				/* V(A) = N(R) */
+				link->va = nr;
+
+				/* stop t200, restart t203 */
+				Q921T200TimerStop(trunk, tei);
+				Q921T203TimerReset(trunk, tei);
+			}
+			else if(nr != link->va) {
+				/* V(A) = N(R) */
+				link->va = nr;
+
+				/* restart T200 */
+				Q921T200TimerReset(trunk, tei);
+			}
+
+			/* Restart TM01 */
+			if(Q921_IS_NT(trunk)) {
+				Q921TM01TimerReset(trunk, tei);
+			}
+		}
+		else {
+			/* N(R) error recovery */
+			Q921NrErrorRecovery(trunk, tei);
+
+			/* change state (no action) */
+			Q921ChangeState(trunk, Q921_STATE_AWAITING_ESTABLISHMENT, tei);
+		}
+		break;
+
+	case Q921_STATE_TIMER_RECOVERY:
+		if(link->va <= nr && nr <= link->vs) {
+			/* V(A) = N(R) */
+			link->va = nr;
+
+			/* Restart TM01 */
+			if(Q921_IS_NT(trunk)) {
+				Q921TM01TimerReset(trunk, tei);
+			}
+		}
+		else {
+			/* N(R) error recovery */
+			Q921NrErrorRecovery(trunk, tei);
+
+			/* change state (no action) */
+			Q921ChangeState(trunk, Q921_STATE_AWAITING_ESTABLISHMENT, tei);
+		}
+		break;
+
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+
+static int Q921ProcSFrame(L2TRUNK trunk, L2UCHAR *mes, L2INT size)
+{
+	L2UCHAR sv = (mes[2] & 0x0c) >> 2;	/* supervisory format id */
+	//L2UCHAR pf = mes[3] & 0x01;		/* poll / final flag */
+	//L2UCHAR nr = mes[3] >> 1;		/* receive sequence number */
+	L2INT res = -1;
+
+	switch(sv) {
+	case 0x00:	/* RR : Receive Ready */
+		res = Q921ProcRR(trunk, mes, size);
+		break;
+
+	case 0x02:	/* RNR : Receive Not Ready */
+		res = Q921ProcRNR(trunk, mes, size);
+		break;
+
+	case 0x04:	/* REJ : Reject */
+		res = Q921ProcREJ(trunk, mes, size);
+		break;
+
+	default:	/* Invalid / Unknown */
+		Q921Log(trunk, Q921_LOG_ERROR, "Invalid S frame type %d\n", sv);
+		break;
+	}
+
+	return res;
+}
+
+
+
+static int Q921ProcUFrame(L2TRUNK trunk, L2UCHAR *mes, L2INT size) 
+{
+	L2UCHAR m  = (mes[2] & 0xe0) >> 3 | (mes[2] & 0x0c) >> 2;	/* modifier function id */
+//	L2UCHAR pf = (mes[2] & 0x10) >> 4;				/* poll / final flag */
+	L2INT res = -1;
+
+	switch(m) {
+	case 0x00:	/* UN : Unnumbered Information */
+		if(mes[3] == Q921_LAYER_ENT_ID_TEI)
+		{
+			if(!Q921_IS_PTMP(trunk)) {
+				/* wtf? nice try */
+				return res;
+			}
+
+			switch(mes[6]) {
+			case Q921_TEI_ID_REQUEST:	/* (TE ->) NT */
+				res = Q921TeiProcAssignRequest(trunk, mes, size);
+				break;
+
+			case Q921_TEI_ID_ASSIGNED:	/* (NT ->) TE */
+			case Q921_TEI_ID_DENIED:
+				res = Q921TeiProcAssignResponse(trunk, mes, size);
+				break;
+
+			case Q921_TEI_ID_CHECKREQ:	/* (NT ->) TE */
+				res = Q921TeiProcCheckRequest(trunk, mes, size);
+				break;
+
+			case Q921_TEI_ID_CHECKRESP:	/* (TE ->) NT */
+				res = Q921TeiProcCheckResponse(trunk, mes, size);
+				break;
+
+			case Q921_TEI_ID_REMOVE:	/* (NT ->) TE */
+				res = Q921TeiProcRemoveRequest(trunk, mes, size);
+				break;
+
+			case Q921_TEI_ID_VERIFY:	/* (TE ->) NT */
+				res = Q921TeiProcVerifyRequest(trunk, mes, size);
+				break;
+
+			default:			/* Invalid / Unknown */
+				Q921Log(trunk, Q921_LOG_ERROR, "Invalid UN message from TEI management/endpoint\n");
+				break;
+			}
+		}
+		else if(mes[3] == Q921_LAYER_ENT_ID_Q931) {
+
+			Q921Log(trunk, Q921_LOG_DEBUG, "UI Frame for Layer 3 received\n");
+
+			res = Q921Tx23Proc(trunk, Q921_DL_UNIT_DATA, 0, mes, size);
+		}
+		break;
+
+	case 0x03:	/* DM : Disconnect Mode */
+		res = Q921ProcDM(trunk, mes, size);
+		break;
+
+	case 0x08:	/* DISC : Disconnect */
+		res = Q921ProcDISC(trunk, mes, size);
+		break;
+
+	case 0x0c:	/* UA : Unnumbered Acknowledgement */
+		res = Q921ProcUA(trunk, mes, size);
+		break;
+
+	case 0x0f:	/* SABME  : Set Asynchronous Balanced Mode Extend */
+		res = Q921ProcSABME(trunk, mes, size);
+		break;
+
+	case 0x11:	/* FRMR : Frame Reject */
+	case 0x17:	/* XID : Exchange Identification */
+		res = 0;
+		break;
+
+	default:	/* Unknown / Invalid */
+		Q921Log(trunk, Q921_LOG_ERROR, "Invalid U frame type: %d\n", m);
+		break;
+	}
+
+	return res;
+}
+
+
+/*****************************************************************************
+
+  Function:     Q921Rx12
+
+  Description:  Called to process a message frame from layer 1. Will 
+                identify the message and call the proper 'processor' for
+                layer 2 messages and forward I frames to the layer 3 entity.
+
+                Q921Rx12 will check the input fifo for a message, and if a 
+                message exist process one message before it exits. The caller
+                must either call Q921Rx12 polling or keep track on # 
+                messages in the queue.
+
+  Parameters:   trunk       trunk #.
+
+  Return Value: # messages processed (always 1 or 0).
+
+*****************************************************************************/
+int Q921Rx12(L2TRUNK trunk)
+{
+	L2INT size;     /* receive size & Q921 frame size*/
+	L2UCHAR *smes = MFIFOGetMesPtr(trunk->HDLCInQueue, &size);
+
+	if(smes)
+	{
+		struct Q921_Link *link;
+		L2UCHAR sapi, tei;
+		L2UCHAR *mes;
+		L2INT rs;
+
+		rs  = size - trunk->Q921HeaderSpace;
+		mes = &smes[trunk->Q921HeaderSpace];
+
+		Q921LogMesg(trunk, Q921_LOG_DEBUG, 1, mes, rs, "New packet received (%d bytes)", rs);
+
+		/* common fields: get sapi, tei and cr */
+		sapi = (mes[0] & 0xfc) >> 2;
+		tei  = (mes[1] & 0xfe) >> 1;
+		link  = Q921_LINK_CONTEXT(trunk, tei);
+
+		if(Q921_IS_PTMP_TE(trunk) && (
+			 (link->state >= Q921_STATE_TEI_ASSIGNED && tei != link->tei && tei != Q921_TEI_BCAST) ||			/* Assigned TEI: Only BCAST and directed */
+			 (link->state == Q921_STATE_TEI_UNASSIGNED && tei != Q921_TEI_BCAST)))					/* No assigned TEI: Only BCAST */
+		{
+			/* Ignore Messages with foreign TEIs */
+			goto out;
+		}
+
+		if((mes[2] & 0x01) == 0x00) {		/* I frame */
+			Q921ProcIFrame(trunk, mes, rs);
+		}
+		else if((mes[2] & 0x03) == 0x01) {	/* S frame */
+			Q921ProcSFrame(trunk, mes, rs);
+		}
+		else if((mes[2] & 0x03) == 0x03) {	/* U frame */
+			Q921ProcUFrame(trunk, mes, rs);
+		}
+		else {
+			Q921Log(trunk, Q921_LOG_ERROR, "Invalid frame type: %d\n", (int)(mes[2] & 0x03));
+			/* TODO: send FRMR or REJ */
+		}
+
+out:
+		MFIFOKillNext(trunk->HDLCInQueue);
+
+		return 1;
+	}
+
+	return 0;
+}
+
+/*
+ * Misc
+ */
+/**
+ * Q921SetLogCB
+ * \brief	Set logging callback
+ * \param[in]	trunk	pointer to Q921 data struct
+ * \param[in]	func	pointer to logging callback function
+ * \param[in]	priv	pointer to private data
+ *
+ * \author	Stefan Knoblich
+ */
+void Q921SetLogCB(L2TRUNK trunk, Q921LogCB_t func, void *priv)
+{
+	if(!trunk)
+		return;
+
+	trunk->Q921LogProc = func;
+	trunk->PrivateDataLog = priv;
+}
+
+/**
+ * Q921SetLogLevel
+ * \brief	Set loglevel of Q.921 logging functions
+ * \param[in]	trunk	pointer to Q921 data struct
+ * \param[in]	level	new loglevel
+ *
+ * \author	Stefan Knoblich
+ */
+void Q921SetLogLevel(L2TRUNK trunk, Q921LogLevel_t level)
+{
+	if(!trunk)
+		return;
+
+    if (level < Q921_LOG_NONE) {
+        level = Q921_LOG_NONE;
+    } else if (level > Q921_LOG_DEBUG) {
+        level = Q921_LOG_DEBUG;
+    }
+
+	trunk->loglevel = level;
+}
+
+
+/**
+ * Q921ChangeState
+ * \brief	Change state, invoke neccessary actions
+ * \param[in]	trunk	pointer to Q921 data struct
+ * \param[in]	state	state to change to
+ * \return	> 0 on success; <= 0 on error
+ *
+ * \author	Stefan Knoblich
+ */
+static int Q921ChangeState(L2TRUNK trunk, Q921State_t state, L2UCHAR tei)
+{
+	struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+	Q921State_t oldstate = link->state;
+	int res = 0;
+
+	Q921Log(trunk, Q921_LOG_DEBUG, "Changing state from \"%s\" (%d) to \"%s\" (%d) for TEI %d\n",
+				Q921State2Name(oldstate), oldstate,
+				Q921State2Name(state), state,
+				tei);
+
+	/*
+	 * generic actions (depending on the target state only)
+	 */
+	switch(state) {
+	case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
+		/* Start TM01 */
+		if(Q921_IS_NT(trunk)) {
+			Q921TM01TimerStart(trunk, tei);
+		}
+		break;
+
+	default:
+		break;
+	}
+
+	/*
+	 * actions that depend on type of the old -> new state transition
+	 */
+	switch(oldstate) {
+	case Q921_STATE_STOPPED:
+
+		switch(state) {
+		case Q921_STATE_TEI_UNASSIGNED:
+			if(Q921_IS_PTMP_TE(trunk)) {
+				res = Q921TeiSendAssignRequest(trunk);
+			}
+			break;
+
+		case Q921_STATE_TEI_ASSIGNED:
+			if(Q921_IS_PTMP_NT(trunk)) {
+				res = Q921TeiSendRemoveRequest(trunk, Q921_TEI_BCAST);
+			}
+			break;
+
+		default:
+			break;
+		}
+		break;
+
+	default:
+		break;
+	}
+
+	link->state = state;
+
+	Q921Log(trunk, Q921_LOG_DEBUG, "Q921ChangeState() returns %d, new state is \"%s\" (%d) for TEI %d\n", res, Q921State2Name(state), state, tei);
+
+	return res;
+}
+
+/*
+ * TEI Management functions
+ * \note	All TEI-mgmt UN frames are sent with cr = command!
+ */
+static int Q921TeiSend(L2TRUNK trunk, L2UCHAR type, L2USHORT ri, L2UCHAR ai)
+{
+	L2UCHAR mes[10];
+	L2UCHAR offset = Q921_UFRAME_DATA_OFFSET(trunk);
+
+	mes[offset++] = Q921_LAYER_ENT_ID_TEI;	/* layer management entity identifier */
+	mes[offset++] = (ri & 0xff00) >> 8;	/* reference number upper part */
+	mes[offset++] =  ri & 0xff;		/* reference number lower part */
+	mes[offset++] = type;			/* message type: Identity Request */
+	mes[offset++] = ai << 1 | 0x01;		/* action indicator: TEI */
+
+	return Q921SendU(trunk, Q921_SAPI_TEI, Q921_COMMAND(trunk), Q921_TEI_BCAST, 0, 0x00, mes, offset);
+}
+
+
+/**
+ * Q921TeiSendAssignRequest
+ * \brief	Ask for new TEI (TE mode only)
+ * \param[in]	trunk	pointer to Q921 data struct
+ * \return	> 0 on success, <= 0 on error
+ *
+ * \author	Stefan Knoblich
+ */
+static int Q921TeiSendAssignRequest(L2TRUNK trunk)
+{
+	struct Q921_Link *link = Q921_TRUNK_CONTEXT(trunk);
+	L2INT res;
+
+	if (!Q921_IS_PTMP_TE(trunk))	/* only ptmp te mode*/
+		return 0;
+
+#ifndef WIN32
+		link->ri = (L2USHORT)(random() % 0xffff);
+#else
+		link->ri = (L2USHORT)(rand() % 0xffff); //todo
+#endif
+
+	/* send TEI assign request */
+	res = Q921TeiSend(trunk, Q921_TEI_ID_REQUEST, link->ri, Q921_TEI_BCAST);
+
+	/* start T202 */
+	Q921T202TimerStart(trunk);
+
+	return res;
+}
+
+
+/**
+ * Q921TeiProcessAssignResponse
+ * \brief	Process assign response (TE mode only)
+ * \param[in]	trunk	pointer to Q921 data struct
+ * \param[in]	mes	pointer to message buffer
+ * \param[in]	size	size of message
+ * \return	> 0 on success; <= 0 on error
+ *
+ * \author	Stefan Knoblich
+ */
+static int Q921TeiProcAssignResponse(L2TRUNK trunk, L2UCHAR *mes, L2INT size)
+{
+	struct Q921_Link *link = Q921_TRUNK_CONTEXT(trunk);
+	L2UCHAR offset = Q921_UFRAME_DATA_OFFSET(trunk);
+	L2USHORT ri = 0;
+
+	if (!Q921_IS_PTMP_TE(trunk))	/* PTMP TE only */
+		return 0;
+
+	ri = (mes[offset + 1] << 8) | mes[offset + 2];
+
+	if(ri != link->ri) {
+		/* hmmm ..., not our response i guess */
+		return 0;
+	}
+
+	switch(mes[offset + 3]) {
+	case Q921_TEI_ID_ASSIGNED:
+		/* Yay, use the new TEI and change state to assigned */
+		link->tei      = mes[offset + 4] >> 1;
+
+		Q921Log(trunk, Q921_LOG_DEBUG, "Assigned TEI %d, setting state to TEI_ASSIGNED\n", link->tei);
+
+		Q921ChangeState(trunk, Q921_STATE_TEI_ASSIGNED, link->tei);
+		break;
+
+	case Q921_TEI_ID_DENIED:
+		/* oops, what to do now? */
+		if ((mes[offset + 4] >> 1) == Q921_TEI_BCAST) {
+			/* No more free TEIs? this is bad */
+
+			//Q921TeiSendVerifyRequest(trunk, Q921_TEI_BCAST); /* TODO: does this work ?? */
+		} else {
+			/* other reason, this is fatal, shutdown link */
+		}
+
+		Q921Log(trunk, Q921_LOG_DEBUG, "TEI assignment has been denied, reason: %s\n",
+			 ((mes[offset +4] >> 1) == Q921_TEI_BCAST) ? "No free TEIs available" : "Unknown");
+
+		Q921ChangeState(trunk, Q921_STATE_TEI_UNASSIGNED, link->tei);
+		break;
+
+	default:
+		return 0;
+	}
+
+	/* stop T202 */
+	Q921T202TimerStop(trunk);
+
+	return 1;
+}
+
+
+/**
+ * Q921TeiSendVerifyRequest
+ * \brief	Verify TEI (TE mode only)
+ * \param[in]	trunk	pointer to Q921 data struct
+ * \return	> 0 on success; <= 0 on error
+ *
+ * \author	Stefan Knoblich
+ */
+static int Q921TeiSendVerifyRequest(L2TRUNK trunk)
+{
+	struct Q921_Link *link = Q921_TRUNK_CONTEXT(trunk);
+	L2INT res;
+
+	if (!Q921_IS_PTMP_TE(trunk))	/* only ptmp te mode*/
+		return 0;
+
+	/* Request running? */
+	if (trunk->T202)
+		return 0;
+
+	/* Send TEI verify request */
+	res = Q921TeiSend(trunk, Q921_TEI_ID_VERIFY, link->ri, link->tei);
+
+	/* start T202 */
+	Q921T202TimerStart(trunk);
+
+	return res;
+}
+
+
+/**
+ * Q921TeiProcCheckRequest
+ * \brief	Process Check Request (TE mode only)
+ * \param[in]	trunk	pointer to Q921 data struct
+ * \param[in]	mes	pointer to message buffer
+ * \param[in]	size	size of message
+ * \return	> 0 on success; <= 0 on error
+ *
+ * \author	Stefan Knoblich
+ */
+static int Q921TeiProcCheckRequest(L2TRUNK trunk, L2UCHAR *mes, L2INT size)
+{
+	struct Q921_Link *link = Q921_TRUNK_CONTEXT(trunk);
+	L2UCHAR offset = Q921_UFRAME_DATA_OFFSET(trunk);
+	L2UCHAR tei = (mes[offset + 4] >> 1);		/* action indicator => tei */
+	L2INT res = 0;
+
+	if (!Q921_IS_PTMP_TE(trunk))	/* ptmp te mode only */
+		return 0;
+
+	Q921Log(trunk, Q921_LOG_DEBUG, "Received TEI Check request for TEI %d\n", tei);
+
+	if (tei == Q921_TEI_BCAST || tei == link->tei) {
+		/*
+		 * Broadcast TEI check or for our assigned TEI
+		 */
+
+		/* send TEI check reponse */
+		res = Q921TeiSend(trunk, Q921_TEI_ID_CHECKRESP, link->ri, link->tei);
+
+		Q921T202TimerStop(trunk);
+	}
+
+	return res;
+}
+
+
+/**
+ * Q921TeiProcRemoveRequest
+ * \brief	Process remove Request (TE mode only)
+ * \param[in]	trunk	pointer to Q921 data struct
+ * \param[in]	mes	pointer to message buffer
+ * \param[in]	size	size of message
+ * \return	> 0 on success; <= 0 on error
+ *
+ * \author	Stefan Knoblich
+ */
+static int Q921TeiProcRemoveRequest(L2TRUNK trunk, L2UCHAR *mes, L2INT size)
+{
+	struct Q921_Link *link = Q921_TRUNK_CONTEXT(trunk);
+	L2UCHAR offset = Q921_UFRAME_DATA_OFFSET(trunk);
+	L2UCHAR tei = (mes[offset + 4] >> 1);		/* action indicator => tei */
+	L2INT res = 0;
+
+	if (!Q921_IS_PTMP_TE(trunk))	/* ptmp te mode only */
+		return 0;
+
+	Q921Log(trunk, Q921_LOG_DEBUG, "Received TEI Remove request for TEI %d\n", tei);
+
+	if (tei == Q921_TEI_BCAST || tei == link->tei) {
+		/*
+		 * Broadcast TEI remove or for our assigned TEI
+		 */
+
+		/* reset tei */
+		link->tei  = 0;
+
+		/* change state (no action) */
+		Q921ChangeState(trunk, Q921_STATE_TEI_UNASSIGNED, link->tei);
+
+		/* TODO: hmm, request new one ? */
+		res = Q921TeiSendAssignRequest(trunk);
+	}
+	return res;
+}
+
+
+/**
+ * Q921TeiProcAssignRequest
+ * \brief	Process assign request from peer (NT mode only)
+ * \param[in]	trunk	pointer to Q921 data struct
+ * \param[in]	mes	pointer to message buffer
+ * \param[in]	size	size of message
+ * \return	> 0 on success; <= 0 on error
+ *
+ * \author	Stefan Knoblich
+ */
+static int Q921TeiProcAssignRequest(L2TRUNK trunk, L2UCHAR *mes, L2INT size)
+{
+	L2UCHAR offset = Q921_UFRAME_DATA_OFFSET(trunk);
+	L2USHORT ri = 0;
+	L2UCHAR tei = 0;
+
+	if (!Q921_IS_PTMP_NT(trunk))	/* PTMP NT only */
+		return 0;
+
+	ri  = (mes[offset + 1] << 8) | mes[offset + 2];
+	tei =  mes[offset + 4] >> 1;
+
+	if(tei == Q921_TEI_BCAST) {
+		int x;
+
+		/* dynamically allocate TEI */
+		for(x = Q921_TEI_DYN_MIN, tei = 0; x <= Q921_TEI_MAX; x++) {
+			if(!trunk->tei_map[x]) {
+				tei = x;
+				break;
+			}
+		}
+	}
+	else if(!(tei > 0 && tei < Q921_TEI_DYN_MIN)) {
+		/* reject TEIs that are not in the static area */
+		Q921TeiSendDenyResponse(trunk, 0, ri);
+
+		return 0;
+	}
+
+	if(!tei) {
+		/* no free TEI found */
+		Q921TeiSendDenyResponse(trunk, Q921_TEI_BCAST, ri);
+	}
+	else {
+		struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
+
+		/* mark used */
+		trunk->tei_map[tei] = 1;
+
+		/* assign tei */
+		link->tei = tei;
+
+		/* put context in TEI ASSIGNED state */
+		Q921ChangeState(trunk, Q921_STATE_TEI_ASSIGNED, tei);
+
+		/* send assign response */
+		Q921TeiSendAssignedResponse(trunk, tei, ri);
+
+		/* Start T201 */
+		Q921T201TimerStart(trunk, tei);
+	}
+	return 0;
+}
+
+/**
+ * Q921TeiSendCheckRequest
+ * \brief	Send check request (NT mode only)
+ * \param[in]	trunk	pointer to Q921 data struct
+ * \param[in]	tei	TEI to check
+ * \return	> 0 on success; <= 0 on error
+ *
+ * \author	Stefan Knoblich
+ */
+static int Q921TeiSendCheckRequest(L2TRUNK trunk, L2UCHAR tei)
+{
+	L2INT res = 0;
+
+	if (!Q921_IS_PTMP_NT(trunk))	/* PTMP NT only */
+		return 0;
+
+	/* send TEI check request */
+	res = Q921TeiSend(trunk, Q921_TEI_ID_CHECKREQ, 0, tei);
+
+	/* (Re-)Start T201 timer */
+	Q921T201TimerStart(trunk, tei);
+
+	return res;
+}
+
+/**
+ * Q921TeiProcCheckResponse
+ * \brief	Process Check Response (NT mode only)
+ * \param[in]	trunk	pointer to Q921 data struct
+ * \param[in]	mes	pointer to message buffer
+ * \param[in]	size	size of message
+ * \return	> 0 on success; <= 0 on error
+ *
+ * \author	Stefan Knoblich
+ */
+static int Q921TeiProcCheckResponse(L2TRUNK trunk, L2UCHAR *mes, L2INT size)
+{
+	struct Q921_Link *link;
+	L2UCHAR offset = Q921_UFRAME_DATA_OFFSET(trunk);
+	L2USHORT ri = 0;
+	L2UCHAR tei = 0;
+
+	if (!Q921_IS_PTMP_NT(trunk))	/* PTMP NT mode only */
+		return 0;
+
+	ri  = (mes[offset + 1] << 8) | mes[offset + 2];
+	tei =  mes[offset + 4] >> 1;
+
+	/* restart T201 */
+	Q921T201TimerStop(trunk, tei);
+
+	/* reset counter */
+	link       = Q921_LINK_CONTEXT(trunk, tei);
+	link->N202 = 0;
+
+	if(!(tei > 0 && tei < Q921_TEI_MAX) || !trunk->tei_map[tei]) {
+		/* TODO: Should we send a DISC first? */
+
+		/* TEI not assigned? Invalid TEI? */
+		Q921TeiSendRemoveRequest(trunk, tei);
+
+		/* change state */
+		Q921ChangeState(trunk, Q921_STATE_STOPPED, tei);
+
+		/* clear */
+		memset(link, 0, sizeof(struct Q921_Link));
+	} else {
+		/* Start T201 */
+		Q921T201TimerStart(trunk, tei);
+	}
+
+	return 0;
+}
+
+
+/**
+ * Q921TeiProcVerifyRequest
+ * \brief	Process Verify Request (NT mode only)
+ * \param[in]	trunk	pointer to Q921 data struct
+ * \param[in]	mes	pointer to message buffer
+ * \param[in]	size	size of message
+ * \return	> 0 on success; <= 0 on error
+ *
+ * \author	Stefan Knoblich
+ */
+static int Q921TeiProcVerifyRequest(L2TRUNK trunk, L2UCHAR *mes, L2INT size)
+{
+	L2UCHAR resp[25];
+	L2UCHAR offset = Q921_UFRAME_DATA_OFFSET(trunk);
+	L2UCHAR tei = 0;
+
+	if (!Q921_IS_PTMP_NT(trunk))	/* PTMP NT mode only */
+		return 0;
+
+	tei = mes[offset + 4] >> 1;
+
+	/* todo: handle response... verify assigned TEI */
+	resp[offset + 0] = 0;
+
+	return 0;
+}
+
+/**
+ * Q921TeiSendDenyResponse
+ * \brief	Send Deny Response (NT mode only)
+ * \param[in]	trunk	pointer to Q921 data struct
+ * \return	> 0 on success; <= 0 on error
+ *
+ * \author	Stefan Knoblich
+ */
+static int Q921TeiSendDenyResponse(L2TRUNK trunk, L2UCHAR tei, L2USHORT ri)
+{
+	if (!Q921_IS_PTMP_NT(trunk))	/* PTMP NT only */
+		return 0;
+
+	return Q921TeiSend(trunk, Q921_TEI_ID_DENIED, ri, tei);
+}
+
+
+/**
+ * Q921TeiSendAssignedResponse
+ * \brief	Send Assigned Response (NT mode only)
+ * \param[in]	trunk	pointer to Q921 data struct
+ * \param[in]	tei	TEI to assign
+ * \param[in]	ri	RI of request
+ * \return	> 0 on success; <= 0 on error
+ *
+ * \author	Stefan Knoblich
+ */
+static int Q921TeiSendAssignedResponse(L2TRUNK trunk, L2UCHAR tei, L2USHORT ri)
+{
+	if (!Q921_IS_PTMP_NT(trunk))	/* PTMP NT only */
+		return 0;
+
+	return Q921TeiSend(trunk, Q921_TEI_ID_ASSIGNED, ri, tei);
+}
+
+/**
+ * Q921TeiSendRemoveRequest
+ * \brief	Send Remove Request (NT mode only)
+ * \param[in]	trunk	pointer to Q921 data struct
+ * \param[in]	tei	TEI to remove
+ * \return	> 0 on success; <= 0 on error
+ *
+ * \author	Stefan Knoblich
+ */
+static int Q921TeiSendRemoveRequest(L2TRUNK trunk, L2UCHAR tei)
+{
+	if (!Q921_IS_PTMP_NT(trunk))	/* PTMP NT only */
+		return 0;
+
+	return Q921TeiSend(trunk, Q921_TEI_ID_REMOVE, 0, tei);
+}

Added: freeswitch/trunk/libs/openzap/src/isdn/Q931.c (0 => 17141)


--- freeswitch/trunk/libs/openzap/src/isdn/Q931.c	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/src/isdn/Q931.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,888 @@
+/*****************************************************************************
+
+  FileName:	 Q931.c
+
+  Contents:	 Implementation of Q.931 stack main interface functions. 
+				See q931.h for description. 
+
+  License/Copyright:
+
+  Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+  email:janvb@caselaboratories.com  
+
+  Redistribution and use in source and binary forms, with or without 
+  modification, are permitted provided that the following conditions are 
+  met:
+
+	* Redistributions of source code must retain the above copyright notice, 
+	  this list of conditions and the following disclaimer.
+	* Redistributions in binary form must reproduce the above copyright notice, 
+	  this list of conditions and the following disclaimer in the documentation 
+	  and/or other materials provided with the distribution.
+	* Neither the name of the Case Labs, Ltd nor the names of its contributors 
+	  may be used to endorse or promote products derived from this software 
+	  without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
+  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
+  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+  POSSIBILITY OF SUCH DAMAGE.
+*****************************************************************************/
+
+#include "Q921.h"
+#include "Q931.h"
+#include "national.h"
+#include "DMS.h"
+#include "5ESS.h"
+
+
+/*****************************************************************************
+
+  Dialect function pointers tables.
+
+  The following function pointer arrays define pack/unpack functions and 
+  processing furnctions for the different Q.931 based dialects.
+
+  The arrays are initialized with pointers to dummy functions and later
+  overrided with pointers to actual functions as new dialects are added.
+
+  The initial Q.931 will as an example define 2 dialects as it treats User
+  and Network mode as separate ISDN dialects.
+
+  The API messages Q931AddProc, Q931AddMes, Q931AddIE are used to initialize
+  these table entries during system inititialization of a stack.
+
+*****************************************************************************/
+q931proc_func_t *Q931Proc[Q931MAXDLCT][Q931MAXMES];
+
+q931umes_func_t *Q931Umes[Q931MAXDLCT][Q931MAXMES];
+q931pmes_func_t *Q931Pmes[Q931MAXDLCT][Q931MAXMES];
+
+q931uie_func_t *Q931Uie[Q931MAXDLCT][Q931MAXIE];
+q931pie_func_t *Q931Pie[Q931MAXDLCT][Q931MAXIE];
+
+q931timeout_func_t *Q931Timeout[Q931MAXDLCT][Q931MAXTIMER];
+q931timer_t         Q931Timer[Q931MAXDLCT][Q931MAXTIMER];
+
+void (*Q931CreateDialectCB[Q931MAXDLCT])(L3UCHAR iDialect) = { NULL, NULL };
+
+Q931State Q931st[Q931MAXSTATE];
+
+/*****************************************************************************
+
+  Core system tables and variables.
+
+*****************************************************************************/
+
+L3INT Q931L4HeaderSpace = {0};	/* header space to be ignoder/inserted */
+				/* at head of each message. */
+
+L3INT Q931L2HeaderSpace = {4};	/* Q921 header space, sapi, tei etc */
+
+/*****************************************************************************
+
+  Main interface callback functions. 
+
+*****************************************************************************/
+
+Q931ErrorCB_t Q931ErrorProc;			/* callback for error messages. */
+L3ULONG (*Q931GetTimeProc) (void) = NULL;	/* callback for func reading time in ms */
+
+/*****************************************************************************
+
+  Function:	 Q931SetL4HeaderSpace
+
+  Description:  Set the # of bytes to be inserted/ignored at the head of
+		each message. Q931 will issue a message with space for header
+		and the user will use this to fill in whatever header info
+		is required to support the architecture used.
+
+*****************************************************************************/
+void Q931SetL4HeaderSpace(L3INT space)
+{
+	Q931L4HeaderSpace = space;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931SetL2HeaderSpace
+
+  Description:  Set the # of bytes to be inserted/ignored at the head of
+		each message. Q931 will issue a message with space for header
+		and the user will use this to fill in whatever header info
+		is required to support the architecture used.
+
+*****************************************************************************/
+void Q931SetL2HeaderSpace(L3INT space)
+{
+	Q931L2HeaderSpace = space;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931ProcDummy
+
+  Description:  Dummy function for message processing.
+
+*****************************************************************************/
+L3INT Q931ProcDummy(Q931_TrunkInfo_t *pTrunk, L3UCHAR * b,L3INT c)
+{
+	return Q931E_INTERNAL;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931UmesDummy
+
+  Description:  Dummy function for message processing
+
+*****************************************************************************/
+L3INT Q931UmesDummy(Q931_TrunkInfo_t *pTrunk,L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT IOff, L3INT Size)
+{
+	return Q931E_UNKNOWN_MESSAGE;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931UieDummy
+
+  Description:  Dummy function for message processing
+
+*****************************************************************************/
+L3INT Q931UieDummy(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff)
+{
+	return Q931E_UNKNOWN_IE;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931PmesDummy
+
+  Description:  Dummy function for message processing
+
+*****************************************************************************/
+L3INT Q931PmesDummy(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+	return Q931E_UNKNOWN_MESSAGE;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931PieDummy
+
+  Description:  Dummy function for message processing
+
+*****************************************************************************/
+L3INT Q931PieDummy(Q931_TrunkInfo_t *pTrunk,L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+	return Q931E_UNKNOWN_IE;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931TxDummy
+
+  Description:  Dummy function for message processing
+
+*****************************************************************************/
+L3INT Q931TxDummy(Q931_TrunkInfo_t *pTrunk, L3UCHAR * b, L3INT n)
+{
+	return Q931E_MISSING_CB;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931ErrorDummy
+
+  Description:  Dummy function for error processing
+
+*****************************************************************************/
+L3INT Q931ErrorDummy(void *priv, L3INT a, L3INT b, L3INT c)
+{
+	return 0;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Initialize
+
+  Description:  This function Initialize the stack. 
+  
+		Will set up the trunk array, channel
+		arrays and initialize Q931 function arrays before it finally
+		set up EuroISDN processing with User as dialect 0 and 
+		Network as dialect 1.
+
+  Note:		 Initialization of other stacks should be inserted after
+		the initialization of EuroISDN.
+
+*****************************************************************************/
+void Q931Initialize()
+{
+	L3INT x,y;
+
+	/* Secure the callbacks to default procs */
+	Q931ErrorProc = Q931ErrorDummy;
+
+	/* The user will only add the message handlers and IE handlers he need,
+	 * so we need to initialize every single entry to a default function
+	 * that will throw an appropriate error if they are ever called.
+	 */
+	for (x = 0; x < Q931MAXDLCT; x++) {
+		for (y = 0; y < Q931MAXMES; y++) {
+			Q931Proc[x][y] = Q931ProcDummy;
+			Q931Umes[x][y] = Q931UmesDummy;
+			Q931Pmes[x][y] = Q931PmesDummy;
+		}
+		for (y = 0; y < Q931MAXIE; y++) {
+			Q931Pie[x][y] = Q931PieDummy;
+			Q931Uie[x][y] = Q931UieDummy;
+		}
+		for (y = 0; y < Q931MAXTIMER; y++) {
+			Q931Timeout[x][y] = Q931TimeoutDummy;
+			Q931Timer[x][y]   = 0;
+		}
+	}
+
+	if (Q931CreateDialectCB[Q931_Dialect_Q931 + Q931_TE] == NULL)
+		Q931AddDialect(Q931_Dialect_Q931 + Q931_TE, Q931CreateTE);
+
+	if (Q931CreateDialectCB[Q931_Dialect_Q931 + Q931_NT] == NULL)
+		Q931AddDialect(Q931_Dialect_Q931 + Q931_NT, Q931CreateNT);
+
+	if (Q931CreateDialectCB[Q931_Dialect_National + Q931_TE] == NULL)
+		Q931AddDialect(Q931_Dialect_National + Q931_TE, nationalCreateTE);
+
+	if (Q931CreateDialectCB[Q931_Dialect_National + Q931_NT] == NULL)
+		Q931AddDialect(Q931_Dialect_National + Q931_NT, nationalCreateNT);
+
+	if (Q931CreateDialectCB[Q931_Dialect_DMS + Q931_TE] == NULL)
+		Q931AddDialect(Q931_Dialect_DMS + Q931_TE, DMSCreateTE);
+
+	if (Q931CreateDialectCB[Q931_Dialect_DMS + Q931_NT] == NULL)
+		Q931AddDialect(Q931_Dialect_DMS + Q931_NT, DMSCreateNT);
+
+	if (Q931CreateDialectCB[Q931_Dialect_5ESS + Q931_TE] == NULL)
+		Q931AddDialect(Q931_Dialect_5ESS + Q931_TE, ATT5ESSCreateTE);
+
+	if (Q931CreateDialectCB[Q931_Dialect_5ESS + Q931_NT] == NULL)
+		Q931AddDialect(Q931_Dialect_5ESS + Q931_NT, ATT5ESSCreateNT);
+
+	/* The last step we do is to call the callbacks to create the dialects  */
+	for (x = 0; x < Q931MAXDLCT; x++) {
+		if (Q931CreateDialectCB[x] != NULL) {
+			Q931CreateDialectCB[x]((L3UCHAR)x);
+		}   
+	}
+}
+
+/**
+ * Q931TimerTick
+ * \brief	Periodically called to update and check for expired timers
+ * \param	pTrunk	Q.931 trunk
+ */
+void Q931TimerTick(Q931_TrunkInfo_t *pTrunk)
+{
+	struct Q931_Call *call = NULL;
+	L3ULONG now = 0;
+	L3INT x;
+
+	/* TODO: Loop through all active calls, check timers and call timout procs
+	 * if timers are expired.
+	 * Implement a function array so each dialect can deal with their own
+	 * timeouts.
+	 */
+	now = Q931GetTime();
+
+	for (x = 0; x < Q931MAXCALLPERTRUNK; x++) {
+		call = &pTrunk->call[x];
+
+		if (!call->InUse || !call->Timer || !call->TimerID)
+			continue;
+
+		if (call->Timer <= now) {
+			/* Stop Timer */
+			Q931StopTimer(pTrunk, x, call->TimerID);
+
+			/* Invoke dialect timeout callback */
+			Q931Timeout[pTrunk->Dialect][call->TimerID](pTrunk, x);
+		}
+	}
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Rx23
+
+  Description:  Receive message from layer 2 (LAPD). Receiving a message 
+				is always done in 2 steps. First the message must be 
+				interpreted and translated to a static struct. Secondly
+				the message is processed and responded to.
+
+				The Q.931 message contains a static header that is 
+				interpreted in this function. The rest is interpreted
+				in a sub function according to mestype.
+
+  Parameters:   pTrunk  [IN]	Ptr to trunk info.
+				buf	 [IN]	Ptr to buffer containing message.
+				Size	[IN]	Size of message.
+
+  Return Value: Error Code. 0 = No Error, < 0 :error, > 0 : Warning
+				see q931errors.h for details.
+
+*****************************************************************************/
+L3INT Q931Rx23(Q931_TrunkInfo_t *pTrunk, L3INT ind, L3UCHAR tei, L3UCHAR * buf, L3INT Size)
+{
+	L3UCHAR *Mes = NULL;
+	L3INT RetCode = Q931E_NO_ERROR;
+	Q931mes_Generic *m = (Q931mes_Generic *) pTrunk->L3Buf;
+	L3INT ISize;
+	L3INT IOff = 0;
+	L3INT L2HSize = Q931L2HeaderSpace;
+
+	switch (ind) {
+	case Q921_DL_UNIT_DATA:		/* DL-UNITDATA indication (UI frame, 3 byte header) */
+		L2HSize = 3;
+
+	case Q921_DL_DATA:		/* DL-DATA indication (I frame, 4 byte header) */
+		/* Reset our decode buffer */
+		memset(pTrunk->L3Buf, 0, sizeof(pTrunk->L3Buf));
+
+		/* L2 Header Offset */
+		Mes = &buf[L2HSize];
+
+		/* Protocol Discriminator */
+		m->ProtDisc = Mes[IOff++];
+
+		/* CRV */
+		m->CRVFlag = (Mes[IOff + 1] >> 7) & 0x01;
+		m->CRV = Q931Uie_CRV(pTrunk, Mes, m->buf, &IOff, &ISize);
+
+		/* Message Type */
+		m->MesType = Mes[IOff++];
+
+		/* Store tei */
+		m->Tei = tei;
+
+		/* d'oh a little ugly but this saves us from:
+		 *	a) doing Q.921 work in the lower levels (extracting the TEI ourselves)
+		 *	b) adding a tei parameter to _all_ Proc functions
+		 */
+		if (tei) {
+			L3INT callIndex = 0;
+
+			/* Find the call using CRV */
+			RetCode = Q931FindCRV(pTrunk, m->CRV, &callIndex);
+			if (RetCode == Q931E_NO_ERROR && !pTrunk->call[callIndex].Tei) {
+				pTrunk->call[callIndex].Tei = tei;
+			}
+		}
+
+		Q931Log(pTrunk, Q931_LOG_DEBUG, "Received message from Q.921 (ind %d, tei %d, size %d)\nMesType: %d, CRVFlag %d (%s), CRV %d (Dialect: %d)\n", ind, m->Tei, Size,
+						 m->MesType, m->CRVFlag, m->CRVFlag ? "Terminator" : "Originator", m->CRV, pTrunk->Dialect);
+
+		RetCode = Q931Umes[pTrunk->Dialect][m->MesType](pTrunk, Mes, (Q931mes_Generic *)pTrunk->L3Buf, IOff, Size - L2HSize);
+		if (RetCode >= Q931E_NO_ERROR) {
+			RetCode = Q931Proc[pTrunk->Dialect][m->MesType](pTrunk, pTrunk->L3Buf, 2);
+		}
+		break;
+
+	default:
+		break;
+	}
+
+	return RetCode;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Tx34
+
+  Description:  Called from the stack to send a message to layer 4.
+
+  Parameters:   Mes[IN]	 Ptr to message buffer.
+		Size[IN]	Message size in bytes.
+
+  Return Value: Error Code. 0 = No Error, < 0 :error, > 0 : Warning
+		see q931errors.h for details.
+
+*****************************************************************************/
+L3INT Q931Tx34(Q931_TrunkInfo_t *pTrunk, L3UCHAR * Mes, L3INT Size)
+{
+	Q931Log(pTrunk, Q931_LOG_DEBUG, "Sending message to Layer4 (size: %d)\n", Size);
+
+	if (pTrunk->Q931Tx34CBProc) {
+		return pTrunk->Q931Tx34CBProc(pTrunk->PrivateData34, Mes, Size);
+	}
+	return Q931E_MISSING_CB;	
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Rx43
+
+  Description:  Receive message from Layer 4 (application).
+
+  Parameters:   pTrunk[IN]  Trunk #.
+		buf[IN]	 Message Pointer.
+		Size[IN]	Message size in bytes.
+
+  Return Value: Error Code. 0 = No Error, < 0 :error, > 0 : Warning
+		see q931errors.h for details.
+
+*****************************************************************************/
+L3INT Q931Rx43(Q931_TrunkInfo_t *pTrunk,L3UCHAR * buf, L3INT Size)
+{
+	Q931mes_Header *ptr = (Q931mes_Header*)&buf[Q931L4HeaderSpace];
+	L3INT RetCode = Q931E_NO_ERROR;
+
+	Q931Log(pTrunk, Q931_LOG_DEBUG, "Receiving message from Layer4 (size: %d, type: %d)\n", Size, ptr->MesType);
+
+	RetCode = Q931Proc[pTrunk->Dialect][ptr->MesType](pTrunk, buf, 4);
+
+	Q931Log(pTrunk, Q931_LOG_DEBUG, "Q931Rx43 return code: %d\n", RetCode);
+
+	return RetCode;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Tx32
+
+  Description:  Called from the stack to send a message to L2. The input is 
+				always a non-packed message so it will first make a proper
+				call to create a packed message before it transmits that
+				message to layer 2.
+
+  Parameters:   pTrunk[IN]  Trunk #  
+				buf[IN]	 Ptr to message buffer.
+				Size[IN]	Message size in bytes.
+
+  Return Value: Error Code. 0 = No Error, < 0 :error, > 0 : Warning
+				see q931errors.h for details.
+
+*****************************************************************************/
+L3INT Q931Tx32Data(Q931_TrunkInfo_t *pTrunk, L3UCHAR bcast, L3UCHAR * Mes, L3INT Size)
+{
+	Q931mes_Generic *ptr = (Q931mes_Generic*)Mes;
+	L3INT RetCode = Q931E_NO_ERROR;
+	L3INT iDialect = pTrunk->Dialect;
+	L3INT Offset = bcast ? (Q931L2HeaderSpace - 1) : Q931L2HeaderSpace;
+	L3INT OSize;
+
+	Q931Log(pTrunk, Q931_LOG_DEBUG, "Sending message to Q.921 (size: %d)\n", Size);
+
+	memset(pTrunk->L2Buf, 0, sizeof(pTrunk->L2Buf));
+
+	/* Call pack function through table. */
+	RetCode = Q931Pmes[iDialect][ptr->MesType](pTrunk, (Q931mes_Generic *)Mes, Size, &pTrunk->L2Buf[Offset], &OSize);
+	if (RetCode >= Q931E_NO_ERROR) {
+		L3INT callIndex;
+		L3UCHAR tei = 0;
+
+		if (ptr->CRV) {
+			/* Find the call using CRV */
+			RetCode = Q931FindCRV(pTrunk, ptr->CRV, &callIndex);
+			if (RetCode != Q931E_NO_ERROR)
+				return RetCode;
+
+			tei = pTrunk->call[callIndex].Tei;
+		}
+
+		if (pTrunk->Q931Tx32CBProc) {
+			RetCode = pTrunk->Q931Tx32CBProc(pTrunk->PrivateData32, bcast ? Q921_DL_UNIT_DATA : Q921_DL_DATA, tei, pTrunk->L2Buf, OSize + Offset);
+		} else {
+			RetCode = Q931E_MISSING_CB;
+		}
+	}
+
+	return RetCode;
+}
+
+
+/*****************************************************************************
+
+  Function:	 Q931SetError
+
+  Description:  Called from the stack to indicate an error. 
+
+  Parameters:   ErrID	   ID of ie or message causing error.
+		ErrPar1	 Error parameter 1
+		ErrPar2	 Error parameter 2.
+
+
+*****************************************************************************/
+void Q931SetError(Q931_TrunkInfo_t *pTrunk,L3INT ErrID, L3INT ErrPar1, L3INT ErrPar2)
+{
+	if (pTrunk->Q931ErrorCBProc) {
+		pTrunk->Q931ErrorCBProc(pTrunk->PrivateData34, ErrID, ErrPar1, ErrPar2);
+	} else {
+		Q931ErrorProc(pTrunk->PrivateData34, ErrID, ErrPar1, ErrPar2);
+	}
+}
+
+void Q931SetDefaultErrorCB(Q931ErrorCB_t Q931ErrorPar)
+{
+	Q931ErrorProc = Q931ErrorPar;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931CreateCRV
+
+  Description:  Create a CRV entry and return it's index. The function will 
+		locate a free entry in the call tables allocate it and 
+		allocate a unique CRV value attached to it.
+
+  Parameters:   pTrunk	  [IN]	Trunk number
+		callindex   [OUT]   return call table index.
+
+  Return Value: Error Code. 0 = No Error, < 0 :error, > 0 : Warning
+		see q931errors.h for details.
+****************************************************************************/
+L3INT Q931CreateCRV(Q931_TrunkInfo_t *pTrunk, L3INT * callIndex)
+{
+	L3INT CRV = Q931GetUniqueCRV(pTrunk);
+
+	return Q931AllocateCRV(pTrunk, CRV, callIndex);
+}
+
+
+L3INT Q931ReleaseCRV(Q931_TrunkInfo_t *pTrunk, L3INT CRV)
+{
+	int callIndex;
+	
+	if ((Q931FindCRV(pTrunk, CRV, &callIndex)) == Q931E_NO_ERROR) {
+		pTrunk->call[callIndex].InUse = 0;
+		return Q931E_NO_ERROR;
+	}
+
+	return Q931E_INVALID_CRV;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931AllocateCRV
+
+  Description:  Allocate a call table entry and assigns the given CRV value
+		to it.
+
+  Parameters:   pTrunk	  [IN]	Trunk number
+		iCRV		[IN]	Call Reference Value.
+		callindex   [OUT]   return call table index.
+
+  Return Value: Error Code. 0 = No Error, < 0 :error, > 0 : Warning
+		see q931errors.h for details.
+
+*****************************************************************************/
+L3INT Q931AllocateCRV(Q931_TrunkInfo_t *pTrunk, L3INT iCRV, L3INT * callIndex)
+{
+	L3INT x;
+	for (x = 0; x < Q931MAXCALLPERTRUNK; x++) {
+		if (!pTrunk->call[x].InUse) {
+			pTrunk->call[x].CRV     = iCRV;
+			pTrunk->call[x].BChan   = 255;
+			pTrunk->call[x].State   = 0;	/* null state - idle */
+			pTrunk->call[x].TimerID = 0;	/* no timer running */
+			pTrunk->call[x].Timer   = 0;
+			pTrunk->call[x].InUse   = 1;	/* mark as used */
+			*callIndex = x;
+			return Q931E_NO_ERROR;
+		}
+	}
+	return Q931E_TOMANYCALLS;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931GetCallState
+
+  Description:  Look up CRV and return current call state. A non existing
+				CRV is the same as state zero (0).
+
+  Parameters:   pTrunk  [IN]	Trunk number.
+				iCRV	[IN]	CRV
+
+  Return Value: Call State.
+
+*****************************************************************************/
+L3INT Q931GetCallState(Q931_TrunkInfo_t *pTrunk, L3INT iCRV)
+{
+	L3INT x;
+	for (x = 0; x < Q931MAXCALLPERTRUNK; x++) {
+		if (pTrunk->call[x].InUse) {
+			if (pTrunk->call[x].CRV == iCRV) {
+				return pTrunk->call[x].State;
+			}
+		}
+	}
+	return 0; /* assume state zero for non existing CRV's */
+}
+
+/**
+ * Q931StartTimer
+ * \brief	Start a timer
+ * \param	pTrunk		Q.931 trunk
+ * \param	callindex	Index of the call
+ * \param	iTimerID	ID of timer
+ * \return	always 0
+ */
+L3INT Q931StartTimer(Q931_TrunkInfo_t *pTrunk, L3INT callIndex, L3USHORT iTimerID)
+{
+#if 0
+	L3ULONG duration = Q931Timer[pTrunk->Dialect][iTimerID];
+
+	if (duration) {
+		pTrunk->call[callIndex].Timer   = Q931GetTime() + duration;
+		pTrunk->call[callIndex].TimerID = iTimerID;
+	}
+#endif
+	return 0;
+}
+
+/**
+ * Q931StopTimer
+ * \brief	Stop a timer
+ * \param	pTrunk		Q.931 trunk
+ * \param	callindex	Index of the call
+ * \param	iTimerID	ID of timer
+ * \return	always 0
+ */
+L3INT Q931StopTimer(Q931_TrunkInfo_t *pTrunk, L3INT callindex, L3USHORT iTimerID)
+{
+	if (pTrunk->call[callindex].TimerID == iTimerID)
+		pTrunk->call[callindex].TimerID = 0;
+
+	return 0;
+}
+
+L3INT Q931SetState(Q931_TrunkInfo_t *pTrunk, L3INT callIndex, L3INT iState)
+{
+	pTrunk->call[callIndex].State = iState;
+
+	return 0;
+}
+
+L3ULONG Q931GetTime()
+{
+	L3ULONG tNow = 0;
+	static L3ULONG tLast = 0;
+
+	if (Q931GetTimeProc != NULL) {
+		tNow = Q931GetTimeProc();
+		if (tNow < tLast) {	/* wrapped */
+			/* TODO */
+		}
+		tLast = tNow;
+	}
+	return tNow;
+}
+
+void Q931SetGetTimeCB(L3ULONG (*callback)(void))
+{
+	Q931GetTimeProc = callback;
+}
+
+L3INT Q931FindCRV(Q931_TrunkInfo_t *pTrunk, L3INT crv, L3INT *callindex)
+{
+	L3INT x;
+	for (x = 0; x < Q931MAXCALLPERTRUNK; x++) {
+		if (pTrunk->call[x].InUse) {
+			if (pTrunk->call[x].CRV == crv) {
+				*callindex = x;
+				return Q931E_NO_ERROR;
+			}
+		}
+	}
+	return Q931E_INVALID_CRV;
+}
+
+
+void Q931AddDialect(L3UCHAR i, void (*callback)(L3UCHAR iD ))
+{
+	if (i < Q931MAXDLCT) {
+		Q931CreateDialectCB[i] = callback;
+	}
+}
+
+/*****************************************************************************
+  Function:	 Q931AddStateEntry
+
+  Description:  Find an empty entry in the dialects state table and add this
+				entry.
+*****************************************************************************/
+void Q931AddStateEntry(L3UCHAR iD, L3INT iState,    L3INT iMes,    L3UCHAR cDir)
+{
+	int x;
+	for (x = 0; x < Q931MAXSTATE; x++) {
+		if (Q931st[x].Message == 0) {
+			Q931st[x].State     = iState;
+			Q931st[x].Message   = iMes;
+			Q931st[x].Direction = cDir;
+			/* TODO Sort table and use bsearch */
+			return;
+		}
+	}
+}
+
+/*****************************************************************************
+  Function:	 Q931IsEventLegal
+
+  Description:  Check state table for matching criteria to indicate if this
+				Message is legal in this state or not.
+
+  Note:		 Someone write a bsearch or invent something smart here
+				please - sequential is ok for now.
+*****************************************************************************/
+L3BOOL Q931IsEventLegal(L3UCHAR iD, L3INT iState, L3INT iMes, L3UCHAR cDir)
+{
+	int x;
+	/* TODO Sort table and use bsearch */
+	for (x = 0; x < Q931MAXSTATE; x++) {
+		if (Q931st[x].State == iState && Q931st[x].Message == iMes &&
+		    Q931st[x].Direction == cDir) {
+			return L3TRUE;
+		}
+	}
+	return L3FALSE;
+}
+
+/*****************************************************************************
+  Function:	 q931_error_to_name()
+
+  Description:  Check state table for matching criteria to indicate if this
+				Message is legal in this state or not.
+
+  Note:		 Someone write a bsearch or invent something smart here
+				please - sequential is ok for now.
+*****************************************************************************/
+static const char *q931_error_names[] = {
+	"Q931E_NO_ERROR",			/* 0 */
+
+	"Q931E_UNKNOWN_MESSAGE",		/* -3001 */
+	"Q931E_ILLEGAL_IE",			/* -3002 */
+	"Q931E_UNKNOWN_IE",			/* -3003 */
+	"Q931E_BEARERCAP",			/* -3004 */
+	"Q931E_HLCOMP",				/* -3005 */
+	"Q931E_LLCOMP",				/* -3006 */
+	"Q931E_INTERNAL",			/* -3007 */
+	"Q931E_MISSING_CB",			/* -3008 */
+	"Q931E_UNEXPECTED_MESSAGE",		/* -3009 */
+	"Q931E_ILLEGAL_MESSAGE",		/* -3010 */
+	"Q931E_TOMANYCALLS",			/* -3011 */
+	"Q931E_INVALID_CRV",			/* -3012 */
+	"Q931E_CALLID",				/* -3013 */
+	"Q931E_CALLSTATE",			/* -3014 */
+	"Q931E_CALLEDSUB",			/* -3015 */
+	"Q931E_CALLEDNUM",			/* -3016 */
+	"Q931E_CALLINGNUM",			/* -3017 */
+	"Q931E_CALLINGSUB",			/* -3018 */
+	"Q931E_CAUSE",				/* -3019 */
+	"Q931E_CHANID",				/* -3020 */
+	"Q931E_DATETIME",			/* -3021 */
+	"Q931E_DISPLAY",			/* -3022 */
+	"Q931E_KEYPADFAC",			/* -3023 */
+	"Q931E_NETFAC",				/* -3024 */
+	"Q931E_NOTIFIND",			/* -3025 */
+	"Q931E_PROGIND",			/* -3026 */
+	"Q931E_RESTARTIND",			/* -3027 */
+	"Q931E_SEGMENT",			/* -3028 */
+	"Q931E_SIGNAL",				/* -3029 */
+	"Q931E_GENERIC_DIGITS"			/* -3030 */
+
+};
+
+#define Q931_MAX_ERROR 30
+
+const char *q931_error_to_name(q931_error_t error)
+{
+	int index = 0;
+	if ((int)error < 0) {
+		index = (((int)error * -1) -3000);
+	}
+	if (index < 0 || index > Q931_MAX_ERROR) {
+		return "";
+	}
+	return q931_error_names[index];
+}
+/*
+ * Logging
+ */
+#include <stdarg.h>
+
+L3INT Q931Log(Q931_TrunkInfo_t *trunk, Q931LogLevel_t level, const char *fmt, ...)
+{
+	char buf[Q931_LOGBUFSIZE];
+	L3INT len;
+	va_list ap;
+
+	if (!trunk->Q931LogCBProc)
+		return 0;
+
+	if (trunk->loglevel < level)
+		return 0;
+
+	va_start(ap, fmt);
+
+	len = vsnprintf(buf, sizeof(buf)-1, fmt, ap);
+	if (len <= 0) {
+		/* TODO: error handling */
+		return -1;
+	}
+	if (len >= sizeof(buf))
+		len = sizeof(buf) - 1;
+
+	buf[len] = '\0';
+
+	va_end(ap);
+
+	return trunk->Q931LogCBProc(trunk->PrivateDataLog, level, buf, len);
+}
+
+/**
+ * Q921SetLogCB
+ * \brief	Set Logging callback function and private data
+ */
+void Q931SetLogCB(Q931_TrunkInfo_t *trunk, Q931LogCB_t func, void *priv)
+{
+	trunk->Q931LogCBProc  = func;
+	trunk->PrivateDataLog = priv;
+}
+
+/**
+ * Q921SetLogLevel
+ * \brief	Set Loglevel
+ */
+void Q931SetLogLevel(Q931_TrunkInfo_t *trunk, Q931LogLevel_t level)
+{
+    if(!trunk)
+        return;
+
+    if (level < Q931_LOG_NONE) {
+        level = Q931_LOG_NONE;
+    } else if (level > Q931_LOG_DEBUG) {
+        level = Q931_LOG_DEBUG;
+    }
+
+	trunk->loglevel = level;
+}
+
+/**
+ * Q931TimeoutDummy
+ * \brief	Dummy handler for timeouts
+ * \param	pTrunk		Q.931 trunk
+ * \param	callIndex	Index of call
+ */
+L3INT Q931TimeoutDummy(Q931_TrunkInfo_t *pTrunk, L3INT callIndex)
+{
+	Q931Log(pTrunk, Q931_LOG_DEBUG, "Timer %d of call %d (CRV: %d) timed out\n", pTrunk->call[callIndex].TimerID, callIndex, pTrunk->call[callIndex].CRV);
+
+	return 0;
+}

Added: freeswitch/trunk/libs/openzap/src/isdn/Q931StateNT.c (0 => 17141)


--- freeswitch/trunk/libs/openzap/src/isdn/Q931StateNT.c	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/src/isdn/Q931StateNT.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,1218 @@
+/*****************************************************************************
+
+  FileName:		q931StateNT.c
+
+  Contents:		Q.931 State Engine for NT (Network Mode).
+
+			The controlling state engine for Q.931 is the state engine
+			on the NT side. The state engine on the TE side is a slave 
+			of this. The TE side maintain it's own states as described in
+			ITU-T Q931, but will in	raise conditions be overridden by 
+			the NT side.
+
+  License/Copyright:
+
+  Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+  email:janvb@caselaboratories.com  
+
+  Redistribution and use in source and binary forms, with or without 
+  modification, are permitted provided that the following conditions are 
+  met:
+
+	* Redistributions of source code must retain the above copyright notice, 
+	  this list of conditions and the following disclaimer.
+	* Redistributions in binary form must reproduce the above copyright notice, 
+	  this list of conditions and the following disclaimer in the documentation 
+	  and/or other materials provided with the distribution.
+	* Neither the name of the Case Labs, Ltd nor the names of its contributors 
+	  may be used to endorse or promote products derived from this software 
+	  without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
+  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
+  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+  POSSIBILITY OF SUCH DAMAGE.
+*****************************************************************************/
+
+#include "Q931.h"
+
+extern L3INT Q931L4HeaderSpace;
+
+/*****************************************************************************
+  Function:		Q931CreateNT
+
+  Description:	Will create the Q931 NT as a Dialect in the stack. The first
+				bulk set up the message handlers, the second bulk the IE
+				encoders/coders, and the last bulk set up the state table.
+
+  Parameters:	i		Dialect index
+*****************************************************************************/
+void Q931CreateNT(L3UCHAR i)
+{
+	Q931SetMesProc(Q931mes_ALERTING,             i, Q931ProcAlertingNT,          Q931Umes_Alerting,          Q931Pmes_Alerting);
+	Q931SetMesProc(Q931mes_CALL_PROCEEDING,      i, Q931ProcCallProceedingNT,    Q931Umes_CallProceeding,    Q931Pmes_CallProceeding);
+	Q931SetMesProc(Q931mes_CONNECT,              i, Q931ProcConnectNT,           Q931Umes_Connect,           Q931Pmes_Connect);
+	Q931SetMesProc(Q931mes_CONNECT_ACKNOWLEDGE,  i, Q931ProcConnectAckNT,        Q931Umes_ConnectAck,        Q931Pmes_ConnectAck);
+	Q931SetMesProc(Q931mes_PROGRESS,             i, Q931ProcProgressNT,          Q931Umes_Progress,          Q931Pmes_Progress);
+	Q931SetMesProc(Q931mes_SETUP,                i, Q931ProcSetupNT,             Q931Umes_Setup,             Q931Pmes_Setup);
+	Q931SetMesProc(Q931mes_SETUP_ACKNOWLEDGE,    i, Q931ProcSetupAckNT,          Q931Umes_SetupAck,          Q931Pmes_SetupAck);
+	Q931SetMesProc(Q931mes_RESUME,               i, Q931ProcResumeNT,            Q931Umes_Resume,            Q931Pmes_Resume);
+	Q931SetMesProc(Q931mes_RESUME_ACKNOWLEDGE,   i, Q931ProcResumeAckNT,         Q931Umes_ResumeAck,         Q931Pmes_ResumeAck);
+	Q931SetMesProc(Q931mes_RESUME_REJECT,        i, Q931ProcResumeRejectNT,      Q931Umes_ResumeReject,      Q931Pmes_ResumeReject);
+	Q931SetMesProc(Q931mes_SUSPEND,              i, Q931ProcSuspendNT,           Q931Umes_Suspend,           Q931Pmes_Suspend);
+	Q931SetMesProc(Q931mes_SUSPEND_ACKNOWLEDGE,  i, Q931ProcSuspendAckNT,        Q931Umes_SuspendAck,        Q931Pmes_SuspendAck);
+	Q931SetMesProc(Q931mes_SUSPEND_REJECT,       i, Q931ProcSuspendRejectNT,     Q931Umes_SuspendReject,     Q931Pmes_SuspendReject);
+	Q931SetMesProc(Q931mes_USER_INFORMATION,     i, Q931ProcUserInformationNT,   Q931Umes_UserInformation,   Q931Pmes_UserInformation);
+	Q931SetMesProc(Q931mes_DISCONNECT,           i, Q931ProcDisconnectNT,        Q931Umes_Disconnect,        Q931Pmes_Disconnect);
+	Q931SetMesProc(Q931mes_RELEASE,              i, Q931ProcReleaseNT,           Q931Umes_Release,           Q931Pmes_Release);
+	Q931SetMesProc(Q931mes_RELEASE_COMPLETE,     i, Q931ProcReleaseCompleteNT,   Q931Umes_ReleaseComplete,   Q931Pmes_ReleaseComplete);
+	Q931SetMesProc(Q931mes_RESTART,              i, Q931ProcRestartNT,           Q931Umes_Restart,           Q931Pmes_Restart);
+	Q931SetMesProc(Q931mes_RESTART_ACKNOWLEDGE,  i, Q931ProcRestartAckNT,        Q931Umes_RestartAck,        Q931Pmes_RestartAck);
+	Q931SetMesProc(Q931mes_CONGESTION_CONTROL,   i, Q931ProcCongestionControlNT, Q931Umes_CongestionControl, Q931Pmes_CongestionControl);
+	Q931SetMesProc(Q931mes_INFORMATION,          i, Q931ProcInformationNT,       Q931Umes_Information,       Q931Pmes_Information);
+	Q931SetMesProc(Q931mes_NOTIFY,               i, Q931ProcNotifyNT,            Q931Umes_Notify,            Q931Pmes_Notify);
+	Q931SetMesProc(Q931mes_STATUS,               i, Q931ProcStatusNT,            Q931Umes_Status,            Q931Pmes_Status);
+	Q931SetMesProc(Q931mes_STATUS_ENQUIRY,       i, Q931ProcStatusEnquiryNT,     Q931Umes_StatusEnquiry,     Q931Pmes_StatusEnquiry);
+	Q931SetMesProc(Q931mes_SEGMENT,              i, Q931ProcSegmentNT,           Q931Umes_Segment,           Q931Pmes_Segment);
+
+	Q931SetMesProc(Q932mes_FACILITY,             i, Q932ProcFacilityNT,          Q932Umes_Facility,          Q932Pmes_Facility);
+	Q931SetMesProc(Q932mes_HOLD,                 i, Q932ProcHoldNT,              Q932Umes_Hold,              Q932Pmes_Hold);
+	Q931SetMesProc(Q932mes_HOLD_ACKNOWLEDGE,     i, Q932ProcHoldAckNT,           Q932Umes_HoldAck,           Q932Pmes_HoldAck);
+	Q931SetMesProc(Q932mes_HOLD_REJECT,          i, Q932ProcHoldRejectNT,        Q932Umes_HoldReject,        Q932Pmes_HoldReject);
+	Q931SetMesProc(Q932mes_REGISTER,             i, Q932ProcRegisterNT,          Q932Umes_Register,          Q932Pmes_Register);
+	Q931SetMesProc(Q932mes_RETRIEVE,             i, Q932ProcRetrieveNT,          Q932Umes_Retrieve,          Q932Pmes_Retrieve);
+	Q931SetMesProc(Q932mes_RETRIEVE_ACKNOWLEDGE, i, Q932ProcRetrieveAckNT,       Q932Umes_RetrieveAck,       Q932Pmes_RetrieveAck);
+	Q931SetMesProc(Q932mes_RETRIEVE_REJECT,      i, Q932ProcRetrieveRejectNT,    Q932Umes_RetrieveReject,    Q932Pmes_RetrieveReject);
+
+	/* Set up the IE encoder/decoder handle table.*/ 
+	Q931SetIEProc(Q931ie_SEGMENTED_MESSAGE,                i, Q931Pie_Segment,     Q931Uie_Segment);
+	Q931SetIEProc(Q931ie_BEARER_CAPABILITY,                i, Q931Pie_BearerCap,   Q931Uie_BearerCap);
+	Q931SetIEProc(Q931ie_CAUSE,                            i, Q931Pie_Cause,       Q931Uie_Cause);
+	Q931SetIEProc(Q931ie_CALL_IDENTITY,                    i, Q931Pie_CallID,      Q931Uie_CallID);
+	Q931SetIEProc(Q931ie_CALL_STATE,                       i, Q931Pie_CallState,   Q931Uie_CallState);
+	Q931SetIEProc(Q931ie_CHANNEL_IDENTIFICATION,           i, Q931Pie_ChanID,      Q931Uie_ChanID);
+	Q931SetIEProc(Q931ie_PROGRESS_INDICATOR,               i, Q931Pie_ProgInd,     Q931Uie_ProgInd);
+	Q931SetIEProc(Q931ie_NETWORK_SPECIFIC_FACILITIES,      i, Q931Pie_NetFac,      Q931Uie_NetFac);
+	Q931SetIEProc(Q931ie_NOTIFICATION_INDICATOR,           i, Q931Pie_NotifInd,    Q931Uie_NotifInd);
+	Q931SetIEProc(Q931ie_DISPLAY,                          i, Q931Pie_Display,     Q931Uie_Display);
+	Q931SetIEProc(Q931ie_DATETIME,                         i, Q931Pie_DateTime,    Q931Uie_DateTime);
+	Q931SetIEProc(Q931ie_KEYPAD_FACILITY,                  i, Q931Pie_KeypadFac,   Q931Uie_KeypadFac);
+	Q931SetIEProc(Q931ie_SIGNAL,                           i, Q931Pie_Signal,      Q931Uie_Signal);
+	Q931SetIEProc(Q931ie_TRANSIT_DELAY_SELECTION_AND_IND,  i, Q931Pie_TransNetSel, Q931Uie_TransNetSel);
+	Q931SetIEProc(Q931ie_CALLING_PARTY_NUMBER,             i, Q931Pie_CallingNum,  Q931Uie_CallingNum);
+	Q931SetIEProc(Q931ie_CALLING_PARTY_SUBADDRESS,         i, Q931Pie_CallingSub,  Q931Uie_CallingSub);
+	Q931SetIEProc(Q931ie_CALLED_PARTY_NUMBER,              i, Q931Pie_CalledNum,   Q931Uie_CalledNum);
+	Q931SetIEProc(Q931ie_CALLED_PARTY_SUBADDRESS,          i, Q931Pie_CalledSub,   Q931Uie_CalledSub);
+	Q931SetIEProc(Q931ie_TRANSIT_NETWORK_SELECTION,        i, Q931Pie_TransNetSel, Q931Uie_TransNetSel);
+	Q931SetIEProc(Q931ie_RESTART_INDICATOR,                i, Q931Pie_RestartInd,  Q931Uie_RestartInd);
+	Q931SetIEProc(Q931ie_LOW_LAYER_COMPATIBILITY,          i, Q931Pie_LLComp,      Q931Uie_LLComp);
+	Q931SetIEProc(Q931ie_HIGH_LAYER_COMPATIBILITY,         i, Q931Pie_HLComp,      Q931Uie_HLComp);
+	Q931SetIEProc(Q931ie_USER_USER,                        i, Q931Pie_UserUser,    Q931Uie_UserUser);
+
+	Q931SetIEProc(Q931ie_CONNECTED_NUMBER,   i, Q931Pie_Generic, Q931Uie_Generic);
+	Q931SetIEProc(Q931ie_FACILITY,           i, Q931Pie_Generic, Q931Uie_Generic);
+	Q931SetIEProc(Q931ie_REDIRECTING_NUMBER, i, Q931Pie_Generic, Q931Uie_Generic);
+
+	/* The following define a state machine. The point is that the Message
+	 * procs can when search this to find out if the message/state
+	 * combination is legale. If not, the proc for unexpected message apply.
+	 */
+
+	/* TODO define state table here */
+
+	/* Timer default values */
+	Q931SetTimerDefault(i, Q931_TIMER_T301, 180000);	/* T301: 180s */
+	Q931SetTimerDefault(i, Q931_TIMER_T302,  15000);	/* T302:  15s */
+	Q931SetTimerDefault(i, Q931_TIMER_T303,   4000);	/* T303:   4s */
+	Q931SetTimerDefault(i, Q931_TIMER_T304,  20000);	/* T304:  20s */
+	Q931SetTimerDefault(i, Q931_TIMER_T305,  30000);	/* T305:  30s */
+	Q931SetTimerDefault(i, Q931_TIMER_T306,  30000);	/* T306:  30s */
+	Q931SetTimerDefault(i, Q931_TIMER_T307, 180000);	/* T307: 180s */
+	Q931SetTimerDefault(i, Q931_TIMER_T308,   4000);	/* T308:   4s */
+	Q931SetTimerDefault(i, Q931_TIMER_T309,  60000);	/* T309:  60s */
+	Q931SetTimerDefault(i, Q931_TIMER_T310,  10000);	/* T310:  10s */
+	Q931SetTimerDefault(i, Q931_TIMER_T312,  12000);	/* T312:  12s */
+	Q931SetTimerDefault(i, Q931_TIMER_T314,   4000);	/* T314:   4s */
+	Q931SetTimerDefault(i, Q931_TIMER_T316, 120000);	/* T316: 120s */
+	Q931SetTimerDefault(i, Q931_TIMER_T317,  90000);	/* T317:  90s */
+	Q931SetTimerDefault(i, Q931_TIMER_T320,  30000);	/* T320:  30s */
+	Q931SetTimerDefault(i, Q931_TIMER_T321,  30000);	/* T321:  30s */
+	Q931SetTimerDefault(i, Q931_TIMER_T322,   4000);	/* T322:   4s */
+}
+
+/*****************************************************************************
+
+  Function:		Q931ProcAlertingNT
+
+*****************************************************************************/
+L3INT Q931ProcAlertingNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Find the call using CRV */
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	/* Reset 4 sec timer. */
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom == 4) {
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q931ProcCallProceedingNT
+
+*****************************************************************************/
+L3INT Q931ProcCallProceedingNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Find the call using CRV */
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	/* TODO chack against state table for illegal or unexpected message here*/
+
+	/* TODO - Set correct timer here */
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom == 4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q931ProcConnectNT
+
+*****************************************************************************/
+L3INT Q931ProcConnectNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Find the call using CRV */
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	/* TODO chack against state table for illegal or unexpected message here*/
+
+	/* TODO - Set correct timer here */
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom == 4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q931ProcConnectAckNT
+
+*****************************************************************************/
+L3INT Q931ProcConnectAckNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Find the call using CRV */
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	/* TODO chack against state table for illegal or unexpected message here*/
+
+	/* TODO - Set correct timer here */
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom == 4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q931ProcProgressNT
+
+*****************************************************************************/
+L3INT Q931ProcProgressNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Find the call using CRV */
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	/* TODO chack against state table for illegal or unexpected message here*/
+
+	/* TODO - Set correct timer here */
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom == 4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q931ProcSetupNT
+
+  Description:	Process a SETUP message.
+
+ *****************************************************************************/
+L3INT Q931ProcSetupNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Generic *pMes = (Q931mes_Generic *)&buf[Q931L4HeaderSpace];
+	L3INT rc = 0;
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Reject SETUP on existing calls */
+	if (Q931GetCallState(pTrunk, pMes->CRV) != Q931_U0) {
+		Q931Disconnect(pTrunk, iFrom, pMes->CRV, 81);
+		return Q931E_UNEXPECTED_MESSAGE;
+	}
+
+	/* outgoing call */
+	if (iFrom == 4) {
+		ret = Q931CreateCRV(pTrunk, &callIndex);
+		if (ret)
+		        return ret;
+
+		pMes->CRV = pTrunk->call[callIndex].CRV;
+
+		/*
+		 * Outgoing SETUP message will be broadcasted in PTMP mode
+		 */
+		ret = Q931Tx32Data(pTrunk, Q931_IS_PTP(pTrunk) ? 0 : 1, buf, pMes->Size);
+		if (ret)
+	        	return ret;
+
+		Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+		Q931SetState(pTrunk, callIndex, Q931_U1);
+	}
+	/* incoming call */
+	else {
+		/* Locate free CRV entry and store info */
+		ret = Q931AllocateCRV(pTrunk, pMes->CRV, &callIndex);
+		if (ret != Q931E_NO_ERROR) {
+			/* Not possible to allocate CRV entry, so must reject call */
+			Q931Disconnect(pTrunk, iFrom, pMes->CRV, 42);
+			return ret;
+		}
+
+		/* store TEI in call */
+		pTrunk->call[callIndex].Tei = pMes->Tei;
+
+		/* Send setup indication to user */
+		ret = Q931Tx34(pTrunk, (L3UCHAR*)pMes, pMes->Size);
+		if (ret != Q931E_NO_ERROR) {
+			return ret;
+		} else {
+			/* Must be full queue, meaning we can't process the call */
+			/* so we must disconnect */
+			Q931Disconnect(pTrunk, iFrom, pMes->CRV, 81);
+			return ret;
+		}
+#if 0
+		/* TODO: Unreachable code??? */
+		/* Set state U6 */
+		Q931SetState(pTrunk, callIndex, Q931_U6);
+		Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+#endif
+	}
+
+	return rc;
+}
+
+/*****************************************************************************
+
+  Function:		Q931ProcSetupAckNT
+
+  Description:	Used to acknowedge a SETUP. Usually the first initial
+				response recevide back used to buy some time.
+
+				Note that ChanID (B Channel Assignment) might come here from
+				NT side.
+
+*****************************************************************************/
+L3INT Q931ProcSetupAckNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Find the call using CRV */
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	/* TODO chack against state table for illegal or unexpected message here*/
+
+	/* TODO - Set correct timer here */
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom == 4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q931ProcResumeNT
+
+*****************************************************************************/
+L3INT Q931ProcResumeNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Find the call using CRV */
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	/* TODO chack against state table for illegal or unexpected message here */
+
+	/* TODO - Set correct timer here */
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom == 4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q931ProcResumeAckNT
+
+*****************************************************************************/
+L3INT Q931ProcResumeAckNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Find the call using CRV */
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	/* TODO chack against state table for illegal or unexpected message here*/
+
+	/* TODO - Set correct timer here */
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom == 4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q931ProcResumeRejectNT
+
+*****************************************************************************/
+L3INT Q931ProcResumeRejectNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Find the call using CRV */
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	/* TODO chack against state table for illegal or unexpected message here*/
+
+	/* TODO - Set correct timer here */
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom == 4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q931ProcSuspendNT
+
+*****************************************************************************/
+L3INT Q931ProcSuspendNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Find the call using CRV */
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	/* TODO chack against state table for illegal or unexpected message here*/
+
+	/* TODO - Set correct timer here */
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom == 4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q931ProcSuspendAckNT
+
+*****************************************************************************/
+L3INT Q931ProcSuspendAckNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Find the call using CRV */
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	/* TODO chack against state table for illegal or unexpected message here*/
+
+	/* TODO - Set correct timer here */
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom == 4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q931ProcSuspendRejectNT
+
+*****************************************************************************/
+L3INT Q931ProcSuspendRejectNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Find the call using CRV */
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	/* TODO chack against state table for illegal or unexpected message here*/
+
+	/* TODO - Set correct timer here */
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom == 4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q931ProcInformationNT
+
+*****************************************************************************/
+L3INT Q931ProcUserInformationNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Find the call using CRV */
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	/* TODO chack against state table for illegal or unexpected message here*/
+
+	/* TODO - Set correct timer here */
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom == 4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q931ProcDisconnectNT
+
+*****************************************************************************/
+L3INT Q931ProcDisconnectNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Find the call using CRV */
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	/* TODO chack against state table for illegal or unexpected message here*/
+
+	/* TODO - Set correct timer here */
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom == 4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q931ProcReleaseNT
+
+*****************************************************************************/
+L3INT Q931ProcReleaseNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Find the call using CRV */
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	/* TODO chack against state table for illegal or unexpected message here*/
+
+	/* TODO - Set correct timer here */
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom == 4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q931ProcReleaseCompleteNT
+
+*****************************************************************************/
+L3INT Q931ProcReleaseCompleteNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Find the call using CRV */
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	/* TODO chack against state table for illegal or unexpected message here*/
+
+	/* TODO - Set correct timer here */
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom == 4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q931ProcRestartNT
+
+*****************************************************************************/
+L3INT Q931ProcRestartNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Find the call using CRV */
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	/* TODO chack against state table for illegal or unexpected message here*/
+
+	/* TODO - Set correct timer here */
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom == 4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q931ProcRestartAckNT
+
+*****************************************************************************/
+L3INT Q931ProcRestartAckNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Find the call using CRV */
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	/* TODO chack against state table for illegal or unexpected message here*/
+
+	/* TODO - Set correct timer here */
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom == 4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q931ProcCongestionControlNT
+
+*****************************************************************************/
+L3INT Q931ProcCongestionControlNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Find the call using CRV */
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	/* TODO chack against state table for illegal or unexpected message here*/
+
+	/* TODO - Set correct timer here */
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom == 4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q931ProcInformationNT
+
+*****************************************************************************/
+L3INT Q931ProcInformationNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Find the call using CRV */
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	/* TODO chack against state table for illegal or unexpected message here*/
+
+	/* TODO - Set correct timer here */
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom == 4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q931ProcNotifyNT
+
+*****************************************************************************/
+L3INT Q931ProcNotifyNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Find the call using CRV */
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	/* TODO chack against state table for illegal or unexpected message here*/
+
+	/* TODO - Set correct timer here */
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom == 4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q931ProcStatusNT
+
+*****************************************************************************/
+L3INT Q931ProcStatusNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Find the call using CRV */
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	/* TODO chack against state table for illegal or unexpected message here*/
+
+	/* TODO - Set correct timer here */
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom == 4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q931ProcStatusEnquiryNT
+
+*****************************************************************************/
+L3INT Q931ProcStatusEnquiryNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Find the call using CRV */
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	/* TODO chack against state table for illegal or unexpected message here*/
+
+	/* TODO - Set correct timer here */
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom == 4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q931ProcSegmentNT
+
+*****************************************************************************/
+L3INT Q931ProcSegmentNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Find the call using CRV */
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	/* TODO chack against state table for illegal or unexpected message here*/
+
+	/* TODO - Set correct timer here */
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom == 4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+}
+
+/****************************************************************************/
+/******************* Q.932 - Supplementary Services *************************/
+/****************************************************************************/
+
+/*****************************************************************************
+
+  Function:		Q932ProcFacilityNT
+
+*****************************************************************************/
+L3INT Q932ProcFacilityNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Find the call using CRV */
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	/* TODO chack against state table for illegal or unexpected message here*/
+
+	/* TODO - Set correct timer here */
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom == 4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q932ProcHoldNT
+
+*****************************************************************************/
+L3INT Q932ProcHoldNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Find the call using CRV */
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	/* TODO chack against state table for illegal or unexpected message here*/
+
+	/* TODO - Set correct timer here */
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom == 4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q932ProcHoldAckNT
+
+*****************************************************************************/
+L3INT Q932ProcHoldAckNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Find the call using CRV */
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	/* TODO chack against state table for illegal or unexpected message here*/
+
+	/* TODO - Set correct timer here */
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom == 4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q932ProcHoldRejectNT
+
+*****************************************************************************/
+L3INT Q932ProcHoldRejectNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Find the call using CRV */
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	/* TODO chack against state table for illegal or unexpected message here*/
+
+	/* TODO - Set correct timer here */
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom == 4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q932ProcRegisterTE
+
+*****************************************************************************/
+L3INT Q932ProcRegisterNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Find the call using CRV */
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	/* TODO chack against state table for illegal or unexpected message here*/
+
+	/* TODO - Set correct timer here */
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom == 4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q932ProcRetrieveNT
+
+*****************************************************************************/
+L3INT Q932ProcRetrieveNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Find the call using CRV */
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	/* TODO chack against state table for illegal or unexpected message here*/
+
+	/* TODO - Set correct timer here */
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom == 4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q931ProcRetrieveAckNT
+
+*****************************************************************************/
+L3INT Q932ProcRetrieveAckNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Find the call using CRV */
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	/* TODO chack against state table for illegal or unexpected message here*/
+
+	/* TODO - Set correct timer here */
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom == 4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q931ProcRetrieveRejectNT
+
+*****************************************************************************/
+L3INT Q932ProcRetrieveRejectNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Find the call using CRV */
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	/* TODO chack against state table for illegal or unexpected message here*/
+
+	/* TODO - Set correct timer here */
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom == 4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+}

Added: freeswitch/trunk/libs/openzap/src/isdn/Q931StateTE.c (0 => 17141)


--- freeswitch/trunk/libs/openzap/src/isdn/Q931StateTE.c	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/src/isdn/Q931StateTE.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,1310 @@
+/*****************************************************************************
+
+  FileName:		q931StateTE.c
+
+  Contents:		Q.931 State Engine for TE (User Mode).
+
+			The controlling state engine for Q.931 is the state engine
+			on the NT side. The state engine on the TE side is a slave 
+			of this. The TE side maintain it's own states as described in
+			ITU-T Q931, but will in	raise conditions be overridden by 
+			the NT side.
+
+			This reference implementation uses a process per message,
+			meaning that each message must check call states. This
+			is easier for dialect maintenance as each message proc
+			can be replaced individually. A new TE variant only
+			need to copy the Q931CreateTE and replace those procs or
+			need to override.
+
+  License/Copyright:
+
+  Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+  email:janvb@caselaboratories.com  
+
+  Redistribution and use in source and binary forms, with or without 
+  modification, are permitted provided that the following conditions are 
+  met:
+
+	* Redistributions of source code must retain the above copyright notice, 
+	  this list of conditions and the following disclaimer.
+	* Redistributions in binary form must reproduce the above copyright notice, 
+	  this list of conditions and the following disclaimer in the documentation 
+	  and/or other materials provided with the distribution.
+	* Neither the name of the Case Labs, Ltd nor the names of its contributors 
+	  may be used to endorse or promote products derived from this software 
+	  without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
+  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
+  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+  POSSIBILITY OF SUCH DAMAGE.
+*****************************************************************************/
+
+#include "Q931.h"
+
+extern L3INT Q931L4HeaderSpace;
+
+/*****************************************************************************
+  Function:		Q931CreateTE
+
+  Description:	Will create the Q931 TE as a Dialect in the stack. The first
+				bulk set up the message handlers, the second bulk the IE
+				encoders/coders, and the last bulk set up the state table.
+
+  Parameters:	i		Dialect index
+*****************************************************************************/
+void Q931CreateTE(L3UCHAR i)
+{
+	Q931SetMesProc(Q931mes_ALERTING,             i, Q931ProcAlertingTE,          Q931Umes_Alerting,          Q931Pmes_Alerting);
+	Q931SetMesProc(Q931mes_CALL_PROCEEDING,      i, Q931ProcCallProceedingTE,    Q931Umes_CallProceeding,    Q931Pmes_CallProceeding);
+	Q931SetMesProc(Q931mes_CONNECT,              i, Q931ProcConnectTE,           Q931Umes_Connect,           Q931Pmes_Connect);
+	Q931SetMesProc(Q931mes_CONNECT_ACKNOWLEDGE,  i, Q931ProcConnectAckTE,        Q931Umes_ConnectAck,        Q931Pmes_ConnectAck);
+	Q931SetMesProc(Q931mes_PROGRESS,             i, Q931ProcProgressTE,          Q931Umes_Progress,          Q931Pmes_Progress);
+	Q931SetMesProc(Q931mes_SETUP,                i, Q931ProcSetupTE,             Q931Umes_Setup,             Q931Pmes_Setup);
+	Q931SetMesProc(Q931mes_SETUP_ACKNOWLEDGE,    i, Q931ProcSetupAckTE,          Q931Umes_SetupAck,          Q931Pmes_SetupAck);
+	Q931SetMesProc(Q931mes_RESUME,               i, Q931ProcResumeTE,            Q931Umes_Resume,            Q931Pmes_Resume);
+	Q931SetMesProc(Q931mes_RESUME_ACKNOWLEDGE,   i, Q931ProcResumeAckTE,         Q931Umes_ResumeAck,         Q931Pmes_ResumeAck);
+	Q931SetMesProc(Q931mes_RESUME_REJECT,        i, Q931ProcResumeRejectTE,      Q931Umes_ResumeReject,      Q931Pmes_ResumeReject);
+	Q931SetMesProc(Q931mes_SUSPEND,              i, Q931ProcSuspendTE,           Q931Umes_Suspend,           Q931Pmes_Suspend);
+	Q931SetMesProc(Q931mes_SUSPEND_ACKNOWLEDGE,  i, Q931ProcSuspendAckTE,        Q931Umes_SuspendAck,        Q931Pmes_SuspendAck);
+	Q931SetMesProc(Q931mes_SUSPEND_REJECT,       i, Q931ProcSuspendRejectTE,     Q931Umes_SuspendReject,     Q931Pmes_SuspendReject);
+	Q931SetMesProc(Q931mes_USER_INFORMATION,     i, Q931ProcUserInformationTE,   Q931Umes_UserInformation,   Q931Pmes_UserInformation);
+	Q931SetMesProc(Q931mes_DISCONNECT,           i, Q931ProcDisconnectTE,        Q931Umes_Disconnect,        Q931Pmes_Disconnect);
+	Q931SetMesProc(Q931mes_RELEASE,              i, Q931ProcReleaseTE,           Q931Umes_Release,           Q931Pmes_Release);
+	Q931SetMesProc(Q931mes_RELEASE_COMPLETE,     i, Q931ProcReleaseCompleteTE,   Q931Umes_ReleaseComplete,   Q931Pmes_ReleaseComplete);
+	Q931SetMesProc(Q931mes_RESTART,              i, Q931ProcRestartTE,           Q931Umes_Restart,           Q931Pmes_Restart);
+	Q931SetMesProc(Q931mes_RESTART_ACKNOWLEDGE,  i, Q931ProcRestartAckTE,        Q931Umes_RestartAck,        Q931Pmes_RestartAck);
+	Q931SetMesProc(Q931mes_CONGESTION_CONTROL,   i, Q931ProcCongestionControlTE, Q931Umes_CongestionControl, Q931Pmes_CongestionControl);
+	Q931SetMesProc(Q931mes_INFORMATION,          i, Q931ProcInformationTE,       Q931Umes_Information,       Q931Pmes_Information);
+	Q931SetMesProc(Q931mes_NOTIFY,               i, Q931ProcNotifyTE,            Q931Umes_Notify,            Q931Pmes_Notify);
+	Q931SetMesProc(Q931mes_STATUS,               i, Q931ProcStatusTE,            Q931Umes_Status,            Q931Pmes_Status);
+	Q931SetMesProc(Q931mes_STATUS_ENQUIRY,       i, Q931ProcStatusEnquiryTE,     Q931Umes_StatusEnquiry,     Q931Pmes_StatusEnquiry);
+	Q931SetMesProc(Q931mes_SEGMENT,              i, Q931ProcSegmentTE,           Q931Umes_Segment,           Q931Pmes_Segment);
+
+	Q931SetMesProc(Q932mes_FACILITY,             i, Q932ProcFacilityTE,          Q932Umes_Facility,          Q932Pmes_Facility);
+	Q931SetMesProc(Q932mes_HOLD,                 i, Q932ProcHoldTE,              Q932Umes_Hold,              Q932Pmes_Hold);
+	Q931SetMesProc(Q932mes_HOLD_ACKNOWLEDGE,     i, Q932ProcHoldAckTE,           Q932Umes_HoldAck,           Q932Pmes_HoldAck);
+	Q931SetMesProc(Q932mes_HOLD_REJECT,          i, Q932ProcHoldRejectTE,        Q932Umes_HoldReject,        Q932Pmes_HoldReject);
+	Q931SetMesProc(Q932mes_REGISTER,             i, Q932ProcRegisterTE,          Q932Umes_Register,          Q932Pmes_Register);
+	Q931SetMesProc(Q932mes_RETRIEVE,             i, Q932ProcRetrieveTE,          Q932Umes_Retrieve,          Q932Pmes_Retrieve);
+	Q931SetMesProc(Q932mes_RETRIEVE_ACKNOWLEDGE, i, Q932ProcRetrieveAckTE,       Q932Umes_RetrieveAck,       Q932Pmes_RetrieveAck);
+	Q931SetMesProc(Q932mes_RETRIEVE_REJECT,      i, Q932ProcRetrieveRejectTE,    Q932Umes_RetrieveReject,    Q932Pmes_RetrieveReject);
+
+	/* Set up the IE encoder/decoder handle table.*/ 
+	Q931SetIEProc(Q931ie_SEGMENTED_MESSAGE,                i, Q931Pie_Segment,     Q931Uie_Segment);
+	Q931SetIEProc(Q931ie_BEARER_CAPABILITY,                i, Q931Pie_BearerCap,   Q931Uie_BearerCap);
+	Q931SetIEProc(Q931ie_CAUSE,                            i, Q931Pie_Cause,       Q931Uie_Cause);
+	Q931SetIEProc(Q931ie_CALL_IDENTITY,                    i, Q931Pie_CallID,      Q931Uie_CallID);
+	Q931SetIEProc(Q931ie_CALL_STATE,                       i, Q931Pie_CallState,   Q931Uie_CallState);
+	Q931SetIEProc(Q931ie_CHANNEL_IDENTIFICATION,           i, Q931Pie_ChanID,      Q931Uie_ChanID);
+	Q931SetIEProc(Q931ie_PROGRESS_INDICATOR,               i, Q931Pie_ProgInd,     Q931Uie_ProgInd);
+	Q931SetIEProc(Q931ie_NETWORK_SPECIFIC_FACILITIES,      i, Q931Pie_NetFac,      Q931Uie_NetFac);
+	Q931SetIEProc(Q931ie_NOTIFICATION_INDICATOR,           i, Q931Pie_NotifInd,    Q931Uie_NotifInd);
+	Q931SetIEProc(Q931ie_DISPLAY,                          i, Q931Pie_Display,     Q931Uie_Display);
+	Q931SetIEProc(Q931ie_DATETIME,                         i, Q931Pie_DateTime,    Q931Uie_DateTime);
+	Q931SetIEProc(Q931ie_KEYPAD_FACILITY,                  i, Q931Pie_KeypadFac,   Q931Uie_KeypadFac);
+	Q931SetIEProc(Q931ie_SIGNAL,                           i, Q931Pie_Signal,      Q931Uie_Signal);
+	Q931SetIEProc(Q931ie_TRANSIT_DELAY_SELECTION_AND_IND,  i, Q931Pie_TransNetSel, Q931Uie_TransNetSel);
+	Q931SetIEProc(Q931ie_CALLING_PARTY_NUMBER,             i, Q931Pie_CallingNum,  Q931Uie_CallingNum);
+	Q931SetIEProc(Q931ie_CALLING_PARTY_SUBADDRESS,         i, Q931Pie_CallingSub,  Q931Uie_CallingSub);
+	Q931SetIEProc(Q931ie_CALLED_PARTY_NUMBER,              i, Q931Pie_CalledNum,   Q931Uie_CalledNum);
+	Q931SetIEProc(Q931ie_CALLED_PARTY_SUBADDRESS,          i, Q931Pie_CalledSub,   Q931Uie_CalledSub);
+	Q931SetIEProc(Q931ie_TRANSIT_NETWORK_SELECTION,        i, Q931Pie_TransNetSel, Q931Uie_TransNetSel);
+	Q931SetIEProc(Q931ie_RESTART_INDICATOR,                i, Q931Pie_RestartInd,  Q931Uie_RestartInd);
+	Q931SetIEProc(Q931ie_LOW_LAYER_COMPATIBILITY,          i, Q931Pie_LLComp,      Q931Uie_LLComp);
+	Q931SetIEProc(Q931ie_HIGH_LAYER_COMPATIBILITY,         i, Q931Pie_HLComp,      Q931Uie_HLComp);
+	Q931SetIEProc(Q931ie_USER_USER,                        i, Q931Pie_UserUser,    Q931Uie_UserUser);
+
+	Q931SetIEProc(Q931ie_CONNECTED_NUMBER,   i, Q931Pie_Generic, Q931Uie_Generic);
+	Q931SetIEProc(Q931ie_FACILITY,           i, Q931Pie_Generic, Q931Uie_Generic);
+	Q931SetIEProc(Q931ie_REDIRECTING_NUMBER, i, Q931Pie_Generic, Q931Uie_Generic);
+
+	/* The following define a state machine. The point is that the Message
+	 * procs can when search this to find out if the message/state
+	 * combination is legale. If not, the proc for unexpected message apply.
+	 */
+
+	/* State 0 Idle */
+	Q931AddStateEntry(i, Q931_U0, Q931mes_RESUME,           2);
+	Q931AddStateEntry(i, Q931_U0, Q931mes_SETUP,            4);
+	Q931AddStateEntry(i, Q931_U0, Q931mes_SETUP,            2);
+	Q931AddStateEntry(i, Q931_U0, Q931mes_STATUS,           4);
+	Q931AddStateEntry(i, Q931_U0, Q931mes_RELEASE,          4);
+	Q931AddStateEntry(i, Q931_U0, Q931mes_RELEASE_COMPLETE, 4);
+
+	/* State 1 Call Initiating */
+	Q931AddStateEntry(i, Q931_U1, Q931mes_DISCONNECT,        2);
+	Q931AddStateEntry(i, Q931_U1, Q931mes_SETUP_ACKNOWLEDGE, 4);
+	Q931AddStateEntry(i, Q931_U1, Q931mes_RELEASE_COMPLETE,  4);
+	Q931AddStateEntry(i, Q931_U1, Q931mes_CALL_PROCEEDING,   4);
+	Q931AddStateEntry(i, Q931_U1, Q931mes_ALERTING,          4);
+	Q931AddStateEntry(i, Q931_U1, Q931mes_CONNECT,           4);
+
+	/* State 2 Overlap Sending */
+	Q931AddStateEntry(i, Q931_U2, Q931mes_INFORMATION,     2);
+	Q931AddStateEntry(i, Q931_U2, Q931mes_CALL_PROCEEDING, 4);
+	Q931AddStateEntry(i, Q931_U2, Q931mes_ALERTING,        4);
+	Q931AddStateEntry(i, Q931_U2, Q931mes_PROGRESS,        4);
+	Q931AddStateEntry(i, Q931_U2, Q931mes_CONNECT,         4);
+	Q931AddStateEntry(i, Q931_U2, Q931mes_RELEASE,         2);
+
+	/* State 3 Outgoing Call Proceeding */
+	Q931AddStateEntry(i, Q931_U3, Q931mes_PROGRESS, 4);
+	Q931AddStateEntry(i, Q931_U3, Q931mes_ALERTING, 4);
+	Q931AddStateEntry(i, Q931_U3, Q931mes_CONNECT,  4);
+	Q931AddStateEntry(i, Q931_U3, Q931mes_RELEASE,  2);
+
+	/* State 4 Call Delivered */
+	Q931AddStateEntry(i, Q931_U4, Q931mes_CONNECT, 4);
+
+	/* State 6 Call Precent */
+	Q931AddStateEntry(i, Q931_U6, Q931mes_INFORMATION,      2);
+	Q931AddStateEntry(i, Q931_U6, Q931mes_ALERTING,         2);
+	Q931AddStateEntry(i, Q931_U6, Q931mes_CALL_PROCEEDING,  2);
+	Q931AddStateEntry(i, Q931_U6, Q931mes_CONNECT,          2);
+	Q931AddStateEntry(i, Q931_U6, Q931mes_RELEASE_COMPLETE, 2);
+	Q931AddStateEntry(i, Q931_U6, Q931mes_RELEASE,          4);
+	Q931AddStateEntry(i, Q931_U6, Q931mes_DISCONNECT,       4);
+
+	/* State 7 Call Received */
+	Q931AddStateEntry(i, Q931_U7, Q931mes_CONNECT, 2);
+
+	/* State 8 Connect request */
+	Q931AddStateEntry(i, Q931_U8, Q931mes_CONNECT_ACKNOWLEDGE, 4);
+
+	/* State 9 Incoming Call Proceeding */
+	Q931AddStateEntry(i, Q931_U9, Q931mes_CONNECT,  2);
+	Q931AddStateEntry(i, Q931_U9, Q931mes_ALERTING, 2);
+	Q931AddStateEntry(i, Q931_U9, Q931mes_PROGRESS, 2);
+
+	/* State 10 Active */
+	Q931AddStateEntry(i, Q931_U10, Q931mes_SUSPEND, 2);
+	Q931AddStateEntry(i, Q931_U10, Q931mes_NOTIFY,  4);
+	Q931AddStateEntry(i, Q931_U10, Q931mes_NOTIFY,  2);
+
+	/* State 11 Disconnect Request */
+	Q931AddStateEntry(i, Q931_U11, Q931mes_RELEASE,    4);
+	Q931AddStateEntry(i, Q931_U11, Q931mes_DISCONNECT, 4);
+	Q931AddStateEntry(i, Q931_U11, Q931mes_NOTIFY,     4);
+
+	/* State 12 Disconnect Ind */
+	Q931AddStateEntry(i, Q931_U12, Q931mes_RELEASE, 4);
+	Q931AddStateEntry(i, Q931_U12, Q931mes_RELEASE, 2);
+
+	/* State 15 Suspend Request */
+	Q931AddStateEntry(i, Q931_U15, Q931mes_SUSPEND_ACKNOWLEDGE, 4);
+	Q931AddStateEntry(i, Q931_U15, Q931mes_SUSPEND_REJECT,      4);
+	Q931AddStateEntry(i, Q931_U15, Q931mes_DISCONNECT,          4);
+	Q931AddStateEntry(i, Q931_U15, Q931mes_RELEASE,             4);
+
+/* TODO
+	Q931AddStateEntry(i, Q931_U17,
+	Q931AddStateEntry(i, Q931_U19,
+	Q931AddStateEntry(i, Q931_U25,
+*/
+
+	/* Timer default values */
+	Q931SetTimerDefault(i, Q931_TIMER_T301, 180000);	/* T301: 180s */
+	Q931SetTimerDefault(i, Q931_TIMER_T302,  15000);	/* T302:  15s */
+	Q931SetTimerDefault(i, Q931_TIMER_T303,   4000);	/* T303:   4s */
+	Q931SetTimerDefault(i, Q931_TIMER_T304,  30000);	/* T304:  30s */
+	Q931SetTimerDefault(i, Q931_TIMER_T305,  30000);	/* T305:  30s */
+	Q931SetTimerDefault(i, Q931_TIMER_T308,   4000);	/* T308:   4s */
+	Q931SetTimerDefault(i, Q931_TIMER_T309,  60000);	/* T309:  60s */
+	Q931SetTimerDefault(i, Q931_TIMER_T310,  60000);	/* T310:  60s */
+	Q931SetTimerDefault(i, Q931_TIMER_T313,   4000);	/* T313:   4s */
+	Q931SetTimerDefault(i, Q931_TIMER_T314,   4000);	/* T314:   4s */
+	Q931SetTimerDefault(i, Q931_TIMER_T316, 120000);	/* T316: 120s */
+	Q931SetTimerDefault(i, Q931_TIMER_T317,  90000);	/* T317:  90s */
+	Q931SetTimerDefault(i, Q931_TIMER_T318,   4000);	/* T318:   4s */
+	Q931SetTimerDefault(i, Q931_TIMER_T319,   4000);	/* T319:   4s */
+	Q931SetTimerDefault(i, Q931_TIMER_T321,  30000);	/* T321:  30s */
+	Q931SetTimerDefault(i, Q931_TIMER_T322,   4000);	/* T322:   4s */
+}
+
+/*****************************************************************************
+
+  Function:		Q931ProcAlertingTE
+
+*****************************************************************************/
+L3INT Q931ProcAlertingTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Find the call using CRV */
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	/* Reset 4 sec timer. */
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom == 4) {
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q931ProcCallProceedingTE
+
+*****************************************************************************/
+L3INT Q931ProcCallProceedingTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Find the call using CRV */
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	/* TODO chack against state table for illegal or unexpected message here */
+
+	/* TODO - Set correct timer here */
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom == 4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q931ProcConnectTE
+
+*****************************************************************************/
+L3INT Q931ProcConnectTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Find the call using CRV */
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	/* TODO chack against state table for illegal or unexpected message here */
+
+	/* TODO - Set correct timer here */
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom ==4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+		if (pTrunk->autoConnectAck) {
+			Q931AckConnect(pTrunk, buf);
+		}
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q931ProcConnectAckTE
+
+*****************************************************************************/
+L3INT Q931ProcConnectAckTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Find the call using CRV */
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	/* TODO chack against state table for illegal or unexpected message here */
+
+	/* TODO - Set correct timer here */
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom ==4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q931ProcProgressTE
+
+*****************************************************************************/
+L3INT Q931ProcProgressTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Find the call using CRV */
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	/* TODO chack against state table for illegal or unexpected message here */
+
+	/* TODO - Set correct timer here */
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom ==4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q931ProcSetupTE
+
+*****************************************************************************/
+L3INT Q931ProcSetupTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Generic *pMes = (Q931mes_Generic *)&buf[Q931L4HeaderSpace];
+	L3INT rc = 0;
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Reject SETUP on existing calls */
+	if (Q931GetCallState(pTrunk, pMes->CRV) != Q931_U0) {
+		Q931Disconnect(pTrunk, iFrom, pMes->CRV, 81);
+		return Q931E_UNEXPECTED_MESSAGE;
+	}
+
+	/* outgoing call */
+	if (iFrom == 4) {
+		ret = Q931CreateCRV(pTrunk, &callIndex);
+		if (ret)
+			return ret;
+		pMes->CRV = pTrunk->call[callIndex].CRV;
+
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+		if (ret)
+			return ret;
+
+		Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+
+		/* TODO: Add this back when we get the state stuff more filled out */
+		/*Q931SetState(pTrunk, callIndex, Q931_U1);*/
+	}
+	/* incoming call */
+	else {
+		/* Locate free CRV entry and store info */
+		ret = Q931AllocateCRV(pTrunk, pMes->CRV, &callIndex);
+		if (ret != Q931E_NO_ERROR) {
+			/* Not possible to allocate CRV entry, so must reject call */
+			Q931Disconnect(pTrunk, iFrom, pMes->CRV, 42);
+			return ret;
+		}
+
+		/* Send setup indication to user */
+		ret = Q931Tx34(pTrunk, (L3UCHAR*)pMes, pMes->Size);
+		if (ret != Q931E_NO_ERROR) {
+			if (pTrunk->autoSetupAck) {
+				Q931AckSetup(pTrunk, buf);
+			}
+			return ret;
+		} else {
+			/* Must be full queue, meaning we can't process the call */
+			/* so we must disconnect */
+			Q931Disconnect(pTrunk, iFrom, pMes->CRV, 81);
+			 return ret;
+		}
+#if 0
+		/* TODO: Unreachable code??? */
+		/* Set state U6 */
+		Q931SetState(pTrunk, callIndex, Q931_U6);
+
+		Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+#endif
+	}
+	return rc;
+}
+
+/*****************************************************************************
+
+  Function:		Q931ProcSetupAckTE
+
+  Description:	Used to acknowedge a SETUP. Usually the first initial
+				response recevide back used to buy some time. L4 sending this
+				should only be passed on. L2 sending this means that we set
+				a new timer (and pass it to L4).
+
+				Note that ChanID (B Channel Assignment) might come here from
+				NT side.
+
+*****************************************************************************/
+L3INT Q931ProcSetupAckTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom ==4) {
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q931ProcResumeTE
+
+*****************************************************************************/
+L3INT Q931ProcResumeTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Generic * pMes = (Q931mes_Generic *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	if (Q931GetCallState(pTrunk, pMes->CRV) == Q931_U0 && iFrom ==4) {
+		/* Call reference selection */
+		ret = Q931CreateCRV(pTrunk, &callIndex);
+		if (ret != Q931E_NO_ERROR)
+			return ret;
+		pMes->CRV = pTrunk->call[callIndex].CRV;
+
+		/* Send RESUME to network */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+		if (ret != Q931E_NO_ERROR)
+			return ret;
+
+		/* Start timer T318 */
+		Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T318);
+
+		/* set state U17 */
+		Q931SetState(pTrunk, callIndex, Q931_U17);
+	} else {
+		return Q931E_ILLEGAL_MESSAGE;
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q931ProcResumeAckTE
+
+*****************************************************************************/
+L3INT Q931ProcResumeAckTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Find the call using CRV */
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	/* TODO chack against state table for illegal or unexpected message here */
+
+	/* TODO - Set correct timer here */
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom ==4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q931ProcResumeRejectTE
+
+*****************************************************************************/
+L3INT Q931ProcResumeRejectTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Find the call using CRV */
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	/* TODO chack against state table for illegal or unexpected message here */
+
+	/* TODO - Set correct timer here */
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom ==4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q931ProcSuspendTE
+
+*****************************************************************************/
+L3INT Q931ProcSuspendTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Find the call using CRV */
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	/* TODO chack against state table for illegal or unexpected message here */
+
+	/* TODO - Set correct timer here */
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom ==4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q931ProcSuspendAckTE
+
+*****************************************************************************/
+L3INT Q931ProcSuspendAckTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Find the call using CRV */
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	/* TODO chack against state table for illegal or unexpected message here */
+
+	/* TODO - Set correct timer here */
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom ==4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q931ProcSuspendRejectTE
+
+*****************************************************************************/
+L3INT Q931ProcSuspendRejectTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Find the call using CRV */
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	/* TODO chack against state table for illegal or unexpected message here */
+
+	/* TODO - Set correct timer here */
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom ==4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q931ProcInformationTE
+
+*****************************************************************************/
+L3INT Q931ProcUserInformationTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Find the call using CRV */
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	/* TODO chack against state table for illegal or unexpected message here */
+
+	/* TODO - Set correct timer here */
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom ==4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q931ProcDisconnectTE
+
+*****************************************************************************/
+L3INT Q931ProcDisconnectTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	Q931Log(pTrunk, Q931_LOG_DEBUG, "Processing DISCONNECT message from %s for CRV: %d (%#hx)\n",
+						 iFrom == 4 ? "Local" : "Remote", pMes->CRV, pMes->CRV);
+
+	/* Find the call using CRV */
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	/* TODO chack against state table for illegal or unexpected message here */
+
+	/* TODO - Set correct timer here */
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom ==4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q931ProcReleaseTE
+
+*****************************************************************************/
+L3INT Q931ProcReleaseTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Generic *pMes = (Q931mes_Generic *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT state = Q931GetCallState(pTrunk, pMes->CRV);
+	L3INT ret = Q931E_NO_ERROR;
+
+	if (iFrom == 4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (state == Q931_U0 && iFrom == 2) {
+		Q931Tx34(pTrunk, buf, pMes->Size);
+		ret = Q931ReleaseComplete(pTrunk, buf);
+	} else {
+		ret = Q931ProcUnexpectedMessage(pTrunk, buf, iFrom);
+	}
+	if (pMes->CRV && iFrom == 2) {
+		/* Find the call using CRV */
+		if ((Q931FindCRV(pTrunk, pMes->CRV, &callIndex)) != Q931E_NO_ERROR)
+			return ret;
+		pTrunk->call[callIndex].InUse = 0;
+	}
+
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q931ProcReleaseCompleteTE
+
+*****************************************************************************/
+L3INT Q931ProcReleaseCompleteTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Generic *pMes = (Q931mes_Generic *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	} else {
+		if (pMes->CRV) {
+			/* Find the call using CRV */
+			ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+			if (ret != Q931E_NO_ERROR)
+				return ret;
+			pTrunk->call[callIndex].InUse = 0;
+
+			/* TODO: experimental, send RELEASE_COMPLETE message */
+		        ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+		}
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q931ProcRestartTE
+
+*****************************************************************************/
+L3INT Q931ProcRestartTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	if (pMes->CRV) {
+		/* Find the call using CRV */
+		ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+		if (ret != Q931E_NO_ERROR)
+			return ret;
+
+		/* TODO - Set correct timer here */
+		Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	}
+
+	/* TODO chack against state table for illegal or unexpected message here */
+
+	if (iFrom ==4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+
+		if (pTrunk->autoRestartAck) {
+			Q931AckRestart(pTrunk, buf);
+		}
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q931ProcRestartAckTE
+
+*****************************************************************************/
+L3INT Q931ProcRestartAckTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	if (pMes->CRV) {
+		/* Find the call using CRV */
+		ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+		if (ret != Q931E_NO_ERROR)
+			return ret;
+		/* TODO - Set correct timer here */
+		Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	}
+
+	/* TODO chack against state table for illegal or unexpected message here */
+
+	if (iFrom ==4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q931ProcCongestionControlTE
+
+*****************************************************************************/
+L3INT Q931ProcCongestionControlTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Find the call using CRV */
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	/* TODO chack against state table for illegal or unexpected message here */
+
+	/* TODO - Set correct timer here */
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom ==4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q931ProcInformationTE
+
+*****************************************************************************/
+L3INT Q931ProcInformationTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Find the call using CRV */
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	/* TODO chack against state table for illegal or unexpected message here */
+
+	/* TODO - Set correct timer here */
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom ==4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q931ProcNotifyTE
+
+*****************************************************************************/
+L3INT Q931ProcNotifyTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Find the call using CRV */
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	/* TODO chack against state table for illegal or unexpected message here */
+
+	/* TODO - Set correct timer here */
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom ==4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q931ProcStatusTE
+
+*****************************************************************************/
+L3INT Q931ProcStatusTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Find the call using CRV */
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	/* TODO chack against state table for illegal or unexpected message here */
+
+	/* TODO - Set correct timer here */
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom ==4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q931ProcStatusEnquiryTE
+
+*****************************************************************************/
+L3INT Q931ProcStatusEnquiryTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Find the call using CRV */
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	/* TODO chack against state table for illegal or unexpected message here */
+
+	/* TODO - Set correct timer here */
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom ==4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q931ProcSegmentTE
+
+*****************************************************************************/
+L3INT Q931ProcSegmentTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Find the call using CRV */
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	/* TODO chack against state table for illegal or unexpected message here */
+
+	/* TODO - Set correct timer here */
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom ==4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+}
+
+/****************************************************************************/
+/******************* Q.932 - Supplementary Services *************************/
+/****************************************************************************/
+
+/*****************************************************************************
+
+  Function:		Q932ProcRetrieveTE
+
+*****************************************************************************/
+L3INT Q932ProcFacilityTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Find the call using CRV */
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	/* TODO chack against state table for illegal or unexpected message here */
+
+	/* TODO - Set correct timer here */
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom ==4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q932ProcRetrieveTE
+
+*****************************************************************************/
+L3INT Q932ProcHoldTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Find the call using CRV */
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	/* TODO chack against state table for illegal or unexpected message here */
+
+	/* TODO - Set correct timer here */
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom ==4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q932ProcRetrieveTE
+
+*****************************************************************************/
+L3INT Q932ProcHoldAckTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Find the call using CRV */
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	/* TODO chack against state table for illegal or unexpected message here */
+
+	/* TODO - Set correct timer here */
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom ==4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q932ProcRetrieveTE
+
+*****************************************************************************/
+L3INT Q932ProcHoldRejectTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Find the call using CRV */
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	/* TODO chack against state table for illegal or unexpected message here */
+
+	/* TODO - Set correct timer here */
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom ==4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q932ProcRegisterTE
+
+*****************************************************************************/
+L3INT Q932ProcRegisterTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Find the call using CRV */
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	/* TODO chack against state table for illegal or unexpected message here */
+
+	/* TODO - Set correct timer here */
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom ==4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q932ProcRetrieveTE
+
+*****************************************************************************/
+L3INT Q932ProcRetrieveTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Find the call using CRV */
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	/* TODO chack against state table for illegal or unexpected message here */
+
+	/* TODO - Set correct timer here */
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom ==4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q931ProcRetrieveAckTE
+
+*****************************************************************************/
+L3INT Q932ProcRetrieveAckTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Find the call using CRV */
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	/* TODO chack against state table for illegal or unexpected message here */
+
+	/* TODO - Set correct timer here */
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom ==4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+}
+
+/*****************************************************************************
+
+  Function:		Q931ProcRetrieveRejectTE
+
+*****************************************************************************/
+L3INT Q932ProcRetrieveRejectTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom)
+{
+	Q931mes_Header *pMes = (Q931mes_Header *)&buf[Q931L4HeaderSpace];
+	L3INT callIndex;
+	L3INT ret = Q931E_NO_ERROR;
+
+	/* Find the call using CRV */
+	ret = Q931FindCRV(pTrunk, pMes->CRV, &callIndex);
+	if (ret != Q931E_NO_ERROR)
+		return ret;
+
+	/* TODO chack against state table for illegal or unexpected message here */
+
+	/* TODO - Set correct timer here */
+	Q931StartTimer(pTrunk, callIndex, Q931_TIMER_T303);
+	if (iFrom ==4) {
+		/* TODO Add proc here */
+		ret = Q931Tx32Data(pTrunk, 0, buf, pMes->Size);
+	}
+	else if (iFrom == 2) {
+		/* TODO Add proc here */
+		ret = Q931Tx34(pTrunk, buf, pMes->Size);
+	}
+	return ret;
+}

Added: freeswitch/trunk/libs/openzap/src/isdn/Q931api.c (0 => 17141)


--- freeswitch/trunk/libs/openzap/src/isdn/Q931api.c	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/src/isdn/Q931api.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,598 @@
+/*****************************************************************************
+
+  FileName:		Q931api.c
+
+  Contents:		api (Application Programming Interface) functions.
+				See	q931.h for description. 
+
+  License/Copyright:
+
+  Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+  email:janvb@caselaboratories.com  
+
+  Redistribution and use in source and binary forms, with or without 
+  modification, are permitted provided that the following conditions are 
+  met:
+
+    * Redistributions of source code must retain the above copyright notice, 
+	  this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright notice, 
+	  this list of conditions and the following disclaimer in the documentation 
+	  and/or other materials provided with the distribution.
+    * Neither the name of the Case Labs, Ltd nor the names of its contributors 
+	  may be used to endorse or promote products derived from this software 
+	  without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
+  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
+  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+  POSSIBILITY OF SUCH DAMAGE.
+*****************************************************************************/
+
+#include "Q931.h"
+#include "memory.h"
+
+extern L3INT Q931L4HeaderSpace;
+
+/*
+L3INT Q931CreateMesIndex(L3INT mc)
+{
+    if(mc < 0 || mc > 127 )
+        return Q931E_INTERNAL;
+
+    if(Q931MesCount >127)
+        return Q931E_INTERNAL;
+
+    Q931MesIndex[mc] = Q931MesCount ++;
+
+    return Q931E_NO_ERROR;
+}
+*/
+/*
+L3INT Q931CreateIEIndex(L3INT iec)
+{
+    if(iec < 0 || iec > 127 )
+        return Q931E_INTERNAL;
+
+    if(Q931IECount > 127)
+        return Q931E_INTERNAL;
+
+    Q931IEIndex[iec] = Q931IECount ++;
+
+    return Q931E_NO_ERROR;
+}
+*/
+
+L3INT Q931Api_InitTrunk(Q931_TrunkInfo_t *pTrunk,
+						Q931Dialect_t Dialect,
+						Q931NetUser_t NetUser,
+						Q931_TrunkType_t TrunkType,
+						Q931Tx34CB_t Q931Tx34CBProc,
+						Q931Tx32CB_t Q931Tx32CBProc,
+						Q931ErrorCB_t Q931ErrorCBProc,
+						void *PrivateData32,
+						void *PrivateData34)
+{
+	int y, dchannel, maxchans, has_sync = 0;
+
+	switch(TrunkType)
+	{
+	case Q931_TrType_E1:
+		dchannel = 16;
+		maxchans = 31;
+		has_sync = 1;
+		break;
+
+	case Q931_TrType_T1:
+	case Q931_TrType_J1:
+		dchannel = 24;
+		maxchans = 24;
+		break;
+
+	case Q931_TrType_BRI:
+	case Q931_TrType_BRI_PTMP:
+		dchannel = 3;
+		maxchans = 3;
+		break;
+
+	default:
+		return 0;
+	}
+
+	pTrunk->Q931Tx34CBProc = Q931Tx34CBProc;
+	pTrunk->Q931Tx32CBProc = Q931Tx32CBProc;
+	pTrunk->Q931ErrorCBProc = Q931ErrorCBProc;
+	pTrunk->PrivateData32 = PrivateData32;
+	pTrunk->PrivateData34 = PrivateData34;
+
+    pTrunk->LastCRV			= 0;
+    pTrunk->Dialect			= Dialect + NetUser;       
+    pTrunk->Enabled			= 0;
+    pTrunk->TrunkType		= TrunkType;
+    pTrunk->NetUser			= NetUser;
+    pTrunk->TrunkState		= 0;
+	pTrunk->autoRestartAck	= 0;
+    for(y=0; y < Q931MAXCHPERTRUNK; y++)
+    {
+        pTrunk->ch[y].Available = 1;
+
+        if(has_sync && y == 0)
+        {
+            pTrunk->ch[y].ChanType = Q931_ChType_Sync;
+        }
+        else if(y == dchannel)
+        {
+            pTrunk->ch[y].ChanType = Q931_ChType_D;
+        }
+        else if(y > maxchans)
+        {
+            pTrunk->ch[y].ChanType = Q931_ChType_NotUsed;
+        }
+        else
+        {
+			pTrunk->ch[y].ChanType = Q931_ChType_B;
+        }
+    }
+
+    for(y=0; y < Q931MAXCALLPERTRUNK; y++)
+    {
+        pTrunk->call[y].InUse = 0;
+
+    }
+	return 1;
+}
+
+void Q931SetMesProc(L3UCHAR mes, L3UCHAR dialect, q931proc_func_t *Q931ProcFunc, q931umes_func_t *Q931UmesFunc, q931pmes_func_t *Q931PmesFunc)
+{
+    if(Q931ProcFunc != NULL)
+        Q931Proc[dialect][mes] = Q931ProcFunc;
+    if(Q931UmesFunc != NULL)
+        Q931Umes[dialect][mes] = Q931UmesFunc;
+    if(Q931PmesFunc != NULL)
+        Q931Pmes[dialect][mes] = Q931PmesFunc;
+}
+
+void Q931SetIEProc(L3UCHAR iec, L3UCHAR dialect, q931pie_func_t *Q931PieProc, q931uie_func_t *Q931UieProc)
+{
+    if(Q931PieProc != NULL)
+        Q931Pie[dialect][iec] = Q931PieProc;
+    if(Q931UieProc != NULL)
+        Q931Uie[dialect][iec] = Q931UieProc;
+}
+
+void Q931SetTimeoutProc(L3UCHAR dialect, L3UCHAR timer, q931timeout_func_t *Q931TimeoutProc)
+{
+	if(Q931Timeout != NULL)
+		Q931Timeout[dialect][timer] = Q931TimeoutProc;
+}
+
+void Q931SetTimerDefault(L3UCHAR dialect, L3UCHAR timer, q931timer_t timeout)
+{
+	Q931Timer[dialect][timer] = timeout;
+}
+
+L3INT Q931GetMesSize(Q931mes_Generic *pMes)
+{
+	
+    L3UCHAR *p = &pMes->buf[0];
+    L3INT Size = (L3INT)(p - (L3UCHAR *)pMes);
+    return Size;
+}
+
+/*****************************************************************************
+
+  Function:     q931AppendIE    
+
+  Description:  Append IE to the message.
+
+  Parameters:   pm      Ptr to message.
+                pi      Ptr to information element
+
+  Return Value  ie setting
+
+*****************************************************************************/
+
+ie Q931AppendIE( L3UCHAR *pm, L3UCHAR *pi)
+{
+	ie IE = 0;
+	Q931mes_Generic * pMes= (Q931mes_Generic *)pm;
+	Q931ie_BearerCap * pIE= (Q931ie_BearerCap *)pi;
+	L3INT iISize = pIE->Size;
+
+	L3UCHAR *pBuf = &pMes->buf[0];
+	L3INT Off = (L3INT)(pMes->Size - (pBuf - pm));
+	IE = (ie)(Off | 0x8000);
+
+	memcpy(&pm[pMes->Size], pi, iISize);
+
+	pMes->Size += iISize;
+
+	return IE;
+}
+
+/*****************************************************************************
+*****************************************************************************/
+static L3INT crv={1};
+
+L3INT Q931GetUniqueCRV(Q931_TrunkInfo_t *pTrunk)
+{
+	L3INT max = (Q931_IS_BRI(pTrunk)) ? Q931_BRI_MAX_CRV : Q931_PRI_MAX_CRV;
+
+	crv++;
+	crv = (crv <= max) ? crv : 1;
+
+	return crv;
+}
+
+L3INT Q931InitMesGeneric(Q931mes_Generic *pMes)
+{
+	memset(pMes, 0, sizeof(*pMes));
+	pMes->ProtDisc		= 0x08;
+	pMes->Size			= Q931GetMesSize(pMes);
+
+	return 0;
+}
+
+L3INT Q931InitMesResume(Q931mes_Generic * pMes)
+{
+	pMes->ProtDisc		= 0x08;
+	pMes->CRV			= 0;		/* CRV to be allocated, might be receive*/
+	pMes->MesType		= Q931mes_RESUME;
+
+	pMes->Size			= Q931GetMesSize(pMes);
+    pMes->CallID        = 0;        /* Channel Identification               */
+	return 0;
+}
+
+L3INT Q931InitMesRestartAck(Q931mes_Generic * pMes)
+{
+	pMes->ProtDisc		= 0x08;
+	pMes->CRV			= 0;		/* CRV to be allocated, might be receive*/
+	pMes->MesType		= Q931mes_RESTART_ACKNOWLEDGE;
+
+	pMes->Size			= Q931GetMesSize(pMes);
+    pMes->ChanID        = 0;        /* Channel Identification               */
+	pMes->Display		= 0;
+	pMes->RestartInd	= 0;
+	pMes->RestartWin	= 0;
+	return 0;
+}
+
+L3INT Q931InitIEBearerCap(Q931ie_BearerCap *pIE)
+{
+	pIE->IEId			= Q931ie_BEARER_CAPABILITY;
+	pIE->Size			= sizeof(Q931ie_BearerCap);
+	pIE->CodStand		= 0;
+	pIE->ITC			= 0;
+	pIE->TransMode		= 0;
+	pIE->ITR			= 0x10;
+	pIE->RateMul		= 0;
+
+	pIE->Layer1Ident	= 0;
+	pIE->UIL1Prot		= 0;        /* User Information Layer 1 Protocol    */
+	pIE->SyncAsync		= 0;        /* Sync/Async                           */
+	pIE->Negot			= 0;                
+	pIE->UserRate		= 0;
+	pIE->InterRate		= 0;        /* Intermediate Rate                    */
+	pIE->NIConTx		= 0;
+	pIE->NIConRx		= 0;
+	pIE->FlowCtlTx		= 0;        /* Flow control on Tx                   */
+	pIE->FlowCtlRx		= 0;        /* Flow control on Rx                   */
+	pIE->HDR			= 0;
+	pIE->MultiFrame		= 0;        /* Multi frame support                  */
+	pIE->Mode			= 0;
+	pIE->LLInegot		= 0;
+	pIE->Assignor		= 0;        /* Assignor/assignee                    */
+	pIE->InBandNeg		= 0;        /* In-band/out-band negot.              */
+	pIE->NumStopBits	= 0;        /* Number of stop bits                  */
+	pIE->NumDataBits	= 0;        /* Number of data bits.                 */
+	pIE->Parity			= 0;
+	pIE->DuplexMode		= 0;
+	pIE->ModemType		= 0;
+	pIE->Layer2Ident	= 0;
+	pIE->UIL2Prot		= 0;        /* User Information Layer 2 Protocol    */
+	pIE->Layer3Ident	= 0;           
+	pIE->UIL3Prot		= 0;        /* User Information Layer 3 Protocol    */
+	pIE->AL3Info1		= 0;
+	pIE->AL3Info2		= 0;
+
+	return 0;
+}
+
+L3INT Q931InitIEChanID(Q931ie_ChanID *pIE)
+{
+	pIE->IEId			= Q931ie_CHANNEL_IDENTIFICATION;
+	pIE->Size			= sizeof(Q931ie_ChanID);
+	pIE->IntIDPresent	= 0;        /* Int. id. present                     */
+	pIE->IntType		= 0;        /* Int. type                            */
+	pIE->PrefExcl		= 0;        /* Pref./Excl.                          */
+	pIE->DChanInd		= 0;        /* D-channel ind.                       */
+	pIE->InfoChanSel	= 0;        /* Info. channel selection              */
+	pIE->InterfaceID	= 0;        /* Interface identifier                 */
+	pIE->CodStand		= 0;		/* Code standard                        */
+	pIE->NumMap			= 0;        /* Number/Map                           */
+	pIE->ChanMapType	= 0;        /* Channel type/Map element type        */
+	pIE->ChanSlot		= 0;        /* Channel number/Slot map              */
+
+	return 0;
+}
+
+L3INT Q931InitIEProgInd(Q931ie_ProgInd * pIE)
+{
+	pIE->IEId			= Q931ie_PROGRESS_INDICATOR;
+	pIE->Size			= sizeof(Q931ie_ProgInd);
+	pIE->CodStand		= 0;        /* Coding standard                      */
+	pIE->Location		= 0;        /* Location                             */
+	pIE->ProgDesc		= 0;        /* Progress description                 */
+
+	return 0;
+}
+
+L3INT Q931InitIENetFac(Q931ie_NetFac * pIE)
+{
+	pIE->IEId			= Q931ie_NETWORK_SPECIFIC_FACILITIES;
+	pIE->Size			= sizeof(Q931ie_NetFac);
+	pIE->LenNetID		= 0;        /* Length of network facilities id.     */
+	pIE->TypeNetID		= 0;        /* Type of network identification       */
+	pIE->NetIDPlan		= 0;        /* Network identification plan.         */
+	pIE->NetFac			= 0;        /* Network specific facility spec.      */
+	pIE->NetID[0]		= 0;
+	return 0;
+}
+
+L3INT Q931InitIEDisplay(Q931ie_Display * pIE)
+{
+	pIE->IEId			= Q931ie_DISPLAY;
+	pIE->Size			= sizeof(Q931ie_Display);
+	pIE->Display[0]		= 0;
+	return 0;
+}
+
+L3INT Q931InitIEDateTime(Q931ie_DateTime * pIE)
+{
+	pIE->IEId			= Q931ie_DATETIME;
+	pIE->Size			= sizeof(Q931ie_DateTime);
+	pIE->Year			= 0;        /* Year                                 */
+	pIE->Month			= 0;        /* Month                                */
+	pIE->Day			= 0;        /* Day                                  */
+	pIE->Hour			= 0;        /* Hour                                 */
+	pIE->Minute			= 0;        /* Minute                               */
+	pIE->Second			= 0;        /* Second                               */
+
+	return 0;
+}
+
+L3INT Q931InitIEKeypadFac(Q931ie_KeypadFac * pIE)
+{
+	pIE->IEId			= Q931ie_KEYPAD_FACILITY;
+	pIE->Size			= sizeof(Q931ie_KeypadFac);
+	pIE->KeypadFac[0]	= 0;
+	return 0;
+}
+
+L3INT Q931InitIESignal(Q931ie_Signal * pIE)
+{
+	pIE->IEId			= Q931ie_SIGNAL;
+	pIE->Size			= sizeof(Q931ie_Signal);
+	pIE->Signal			= 0;
+	return 0;
+}
+
+L3INT Q931InitIECallingNum(Q931ie_CallingNum * pIE)
+{
+	pIE->IEId			= Q931ie_CALLING_PARTY_NUMBER;
+	pIE->Size			= sizeof(Q931ie_CallingNum);
+	pIE->TypNum			= 0;        /* Type of number                       */
+	pIE->NumPlanID		= 0;        /* Numbering plan identification        */
+	pIE->PresInd		= 0;        /* Presentation indicator               */
+	pIE->ScreenInd		= 0;        /* Screening indicator                  */
+	pIE->Digit[0]		= 0;        /* Number digits (IA5)                  */
+
+	return 0;
+}
+
+L3INT Q931InitIECallingSub(Q931ie_CallingSub * pIE)
+{
+	pIE->IEId			= Q931ie_CALLING_PARTY_SUBADDRESS;
+	pIE->Size			= sizeof(Q931ie_CallingSub);
+	pIE->TypNum			= 0;        /* Type of subaddress                   */
+	pIE->OddEvenInd		= 0;        /* Odd/Even indicator                   */
+	pIE->Digit[0]		= 0;        /* Digits                               */
+
+	return 0;
+}
+
+L3INT Q931InitIECalledNum(Q931ie_CalledNum * pIE)
+{
+	pIE->IEId			= Q931ie_CALLED_PARTY_NUMBER;
+	pIE->Size			= sizeof(Q931ie_CalledNum);
+	pIE->TypNum			= 0;        /* Type of Number                       */
+	pIE->NumPlanID		= 0;        /* Numbering plan identification        */
+	pIE->Digit[0]		= 0;        /* Digit (IA5)                          */
+
+	return 0;
+}
+
+L3INT Q931InitIECalledSub(Q931ie_CalledSub * pIE)
+{
+	pIE->IEId			= Q931ie_CALLED_PARTY_SUBADDRESS;
+	pIE->Size			= sizeof(Q931ie_CalledSub);
+	pIE->TypNum			= 0;        /* Type of subaddress                   */
+	pIE->OddEvenInd		= 0;        /* Odd/Even indicator                   */
+	pIE->Digit[0]		= 0;        /* Digits                               */
+
+	return 0;
+}
+
+L3INT Q931InitIETransNetSel(Q931ie_TransNetSel * pIE)
+{
+	pIE->IEId			= Q931ie_TRANSIT_NETWORK_SELECTION;
+	pIE->Size			= sizeof(Q931ie_TransNetSel);
+	pIE->Type			= 0;        /* Type of network identifier           */
+	pIE->NetIDPlan		= 0;        /* Network idetification plan           */
+	pIE->NetID[0]		= 0;        /* Network identification(IA5)          */
+
+	return 0;
+}
+
+L3INT Q931InitIELLComp(Q931ie_LLComp * pIE)
+{
+	pIE->IEId			= Q931ie_LOW_LAYER_COMPATIBILITY;
+	pIE->Size			= sizeof(Q931ie_LLComp);
+
+	pIE->CodStand		= 0;        /* Coding standard                      */
+	pIE->ITransCap		= 0;        /* Information transfer capability      */
+	pIE->NegotInd		= 0;        /* Negot indic.                         */
+	pIE->TransMode		= 0;        /* Transfer Mode                        */
+	pIE->InfoRate		= 0;        /* Information transfer rate            */
+	pIE->RateMul		= 0;        /* Rate multiplier                      */
+	pIE->Layer1Ident	= 0;        /* Layer 1 ident.                       */
+	pIE->UIL1Prot		= 0;        /* User information layer 1 protocol    */
+	pIE->SyncAsync		= 0;        /* Synch/asynch                         */
+	pIE->Negot			= 0;        /* Negot                                */
+	pIE->UserRate		= 0;        /* User rate                            */
+	pIE->InterRate		= 0;        /* Intermediate rate                    */
+	pIE->NIConTx		= 0;        /* NIC on Tx                            */
+	pIE->NIConRx		= 0;        /* NIC on Rx                            */
+	pIE->FlowCtlTx		= 0;        /* Flow control on Tx                   */
+	pIE->FlowCtlRx		= 0;        /* Flow control on Rx                   */
+	pIE->HDR			= 0;        /* Hdr/no hdr                           */
+	pIE->MultiFrame		= 0;        /* Multiframe                           */
+	pIE->ModeL1			= 0;		/* Mode L1								*/
+	pIE->NegotLLI		= 0;        /* Negot. LLI                           */
+	pIE->Assignor		= 0;        /* Assignor/Assignor ee                 */
+	pIE->InBandNeg		= 0;        /* In-band negot.                       */
+	pIE->NumStopBits	= 0;        /* Number of stop bits                  */
+	pIE->NumDataBits	= 0;        /* Number of data bits                  */
+	pIE->Parity			= 0;        /* Parity                               */
+	pIE->DuplexMode		= 0;        /* Duplex Mode                          */
+	pIE->ModemType		= 0;        /* Modem type                           */
+	pIE->Layer2Ident	= 0;        /* Layer 2 ident.                       */
+	pIE->UIL2Prot		= 0;        /* User information layer 2 protocol    */
+	pIE->ModeL2			= 0;        /* ModeL2                               */
+	pIE->Q933use		= 0;        /* Q.9333 use                           */
+	pIE->UsrSpcL2Prot	= 0;        /* User specified layer 2 protocol info */
+	pIE->WindowSize		= 0;        /* Window size (k)                      */
+	pIE->Layer3Ident	= 0;        /* Layer 3 ident                        */
+	pIE->OptL3Info		= 0;        /* Optional layer 3 protocol info.      */
+	pIE->ModeL3			= 0;        /* Mode of operation                    */
+#if 0
+	pIE->ModeX25op		= 0;        /* Mode of operation X.25               */
+#endif
+	pIE->DefPackSize	= 0;        /* Default packet size                  */
+	pIE->PackWinSize	= 0;        /* Packet window size                   */
+	pIE->AddL3Info		= 0;        /* Additional Layer 3 protocol info     */
+
+	return 0;
+}
+
+L3INT Q931InitIEHLComp(Q931ie_HLComp * pIE)
+{
+	pIE->IEId			= Q931ie_HIGH_LAYER_COMPATIBILITY;
+	pIE->Size			= sizeof(Q931ie_HLComp);
+
+	return 0;
+}
+
+L3INT Q931ProcUnknownMessage(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom)
+{
+	/* TODO:  Unhandled paramaters */
+	(void)pTrunk;
+	(void)b;
+	(void)iFrom;
+
+    return 0;
+}
+
+L3INT Q931ProcUnexpectedMessage(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom)
+{
+	/* TODO:  Unhandled paramaters */
+	(void)pTrunk;
+	(void)b;
+	(void)iFrom;
+
+    return 0;
+}
+
+L3INT Q931Disconnect(Q931_TrunkInfo_t *pTrunk, L3INT iTo, L3INT iCRV, L3INT iCause)
+{
+	/* TODO:  Unhandled paramaters */
+	(void)pTrunk;
+	(void)iTo;
+	(void)iCRV;
+	(void)iCause;
+
+    return 0;
+}
+
+L3INT Q931ReleaseComplete(Q931_TrunkInfo_t *pTrunk, L3UCHAR *buf)
+{
+    Q931mes_Header *ptr = (Q931mes_Header*)&buf[Q931L4HeaderSpace];
+	ptr->MesType = Q931mes_RELEASE_COMPLETE;
+	ptr->CRVFlag = !(ptr->CRVFlag);
+	return Q931Tx32Data(pTrunk,0,buf,ptr->Size);
+}
+
+L3INT Q931AckRestart(Q931_TrunkInfo_t *pTrunk, L3UCHAR *buf)
+{
+	L3INT RetCode;
+
+    Q931mes_Header *ptr = (Q931mes_Header*)&buf[Q931L4HeaderSpace];
+	ptr->MesType = Q931mes_RESTART_ACKNOWLEDGE;
+	//if (ptr->CRV) {
+		ptr->CRVFlag = !(ptr->CRVFlag);
+		//}
+
+	RetCode = Q931Proc[pTrunk->Dialect][ptr->MesType](pTrunk, buf, 4);
+
+    return RetCode;
+}
+
+L3INT Q931AckSetup(Q931_TrunkInfo_t *pTrunk, L3UCHAR *buf)
+{
+	L3INT RetCode;
+
+    Q931mes_Header *ptr = (Q931mes_Header*)&buf[Q931L4HeaderSpace];
+	ptr->MesType = Q931mes_SETUP_ACKNOWLEDGE;
+
+	RetCode = Q931Proc[pTrunk->Dialect][ptr->MesType](pTrunk, buf, 4);
+
+    return RetCode;
+}
+
+L3INT Q931AckConnect(Q931_TrunkInfo_t *pTrunk, L3UCHAR *buf)
+{
+	L3INT RetCode;
+
+    Q931mes_Header *ptr = (Q931mes_Header*)&buf[Q931L4HeaderSpace];
+	ptr->MesType = Q931mes_CONNECT_ACKNOWLEDGE;
+
+	RetCode = Q931Proc[pTrunk->Dialect][ptr->MesType](pTrunk, buf, 4);
+
+    return RetCode;
+}
+
+L3INT Q931AckService(Q931_TrunkInfo_t *pTrunk, L3UCHAR *buf)
+{
+	L3INT RetCode;
+
+    Q931mes_Header *ptr = (Q931mes_Header*)&buf[Q931L4HeaderSpace];
+	ptr->MesType = Q931mes_SERVICE_ACKNOWLEDGE;
+	if (ptr->CRV) {
+		ptr->CRVFlag = !(ptr->CRVFlag);
+	}
+
+	RetCode = Q931Proc[pTrunk->Dialect][ptr->MesType](pTrunk, buf, 4);
+
+    return RetCode;
+}
+
+Q931_ENUM_NAMES(DIALECT_TYPE_NAMES, DIALECT_STRINGS)
+Q931_STR2ENUM(q931_str2Q931Dialect_type, q931_Q931Dialect_type2str, Q931Dialect_t, DIALECT_TYPE_NAMES, Q931_Dialect_Count)

Added: freeswitch/trunk/libs/openzap/src/isdn/Q931ie.c (0 => 17141)


--- freeswitch/trunk/libs/openzap/src/isdn/Q931ie.c	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/src/isdn/Q931ie.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,3074 @@
+/*****************************************************************************
+
+  FileName:	 Q931ie.c
+
+  Contents:	 Information Element Pack/Unpack functions. 
+  
+		These functions will pack out a Q931 message from the bit 
+		packed original format into structs that are easier to process 
+		and pack the same structs back into bit fields when sending
+		messages out.
+
+		The messages contains a short for each possible IE. The MSB 
+		bit flags the precense of an IE, while the remaining bits 
+		are the offset into a buffer to find the actual IE.
+
+		Each IE are supported by 3 functions:
+
+		Q931Pie_XXX	 Pack struct into Q.931 IE
+		Q931Uie_XXX	 Unpack Q.931 IE into struct
+		Q931InitIEXXX   Initialize IE (see Q931api.c).
+
+  Dialect Note: This file will only contain standard DSS1 IE. Other IE as 
+		used in QSIG, NI2, Q.932 etc are located in separate files.
+
+		See	q931.h for description. 
+
+  License/Copyright:
+
+  Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+  email:janvb@caselaboratories.com  
+
+  Redistribution and use in source and binary forms, with or without 
+  modification, are permitted provided that the following conditions are 
+  met:
+
+	* Redistributions of source code must retain the above copyright notice, 
+	  this list of conditions and the following disclaimer.
+	* Redistributions in binary form must reproduce the above copyright notice, 
+	  this list of conditions and the following disclaimer in the documentation 
+	  and/or other materials provided with the distribution.
+	* Neither the name of the Case Labs, Ltd nor the names of its contributors 
+	  may be used to endorse or promote products derived from this software 
+	  without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
+  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
+  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+  POSSIBILITY OF SUCH DAMAGE.
+*****************************************************************************/
+
+#include "Q931.h"
+
+#ifdef _MSC_VER
+#ifndef __inline__
+#define __inline__ __inline
+#endif
+#if (_MSC_VER >= 1400)			/* VC8+ */
+#ifndef _CRT_SECURE_NO_DEPRECATE
+#define _CRT_SECURE_NO_DEPRECATE
+#endif
+#ifndef _CRT_NONSTDC_NO_DEPRECATE
+#define _CRT_NONSTDC_NO_DEPRECATE
+#endif
+#endif
+#ifndef strcasecmp
+#define strcasecmp(s1, s2) _stricmp(s1, s2)
+#endif
+#ifndef strncasecmp
+#define strncasecmp(s1, s2, n) _strnicmp(s1, s2, n)
+#endif
+#ifndef snprintf
+#define snprintf _snprintf
+#endif
+#endif
+
+/*****************************************************************************
+
+  Macro:		Q931MoreIE
+
+  Description:  Local helper macro detecting if there is more IE space left
+		based on the 3 standard parameters Octet, Off and IESpace.
+		This can be used to test if the IE is completed to avoid
+		that the header of the next IE is interpreted as a part of
+		the current IE.
+
+*****************************************************************************/
+#define Q931MoreIE() (Octet + Off - 2 < IESize)
+
+#define Q931IESizeTest(x) {\
+	if (Octet + Off - 2 != IESize) {\
+		Q931SetError(pTrunk, x, Octet, Off);\
+		return x;\
+	}\
+}
+
+/*****************************************************************************
+
+  Function:	 Q931ReadExt
+
+  Description:  Many of the octets in the standard have an MSB 'ext.1'. This
+				means that the octet usually is the latest octet, but that a
+				futhure standard may extend the octet. A stack must be able 
+				to handle such extensions by skipping the extension octets.
+
+				This function will increase the offset counter with 1 for 
+				each octet with an MSB of zero. This will allow the stack to
+				skip extensions wihout knowing anything about them.
+
+  Parameters:   IBuf	ptr to octet array.
+				Off	 Starting offset counter
+
+  Return Value: New offset value.
+
+*****************************************************************************/
+
+L3INT Q931ReadExt(L3UCHAR * IBuf, L3INT Off)
+{
+	L3INT c = 0;
+	while ((IBuf[c] & 0x80) == 0) {
+		c++;
+	}
+	return Off + c;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Uie_BearerCap
+
+  Description:  Unpack a bearer capability ie.
+
+  Parameters:   pIE[OUT]	ptr to Information Element id.
+		IBuf[IN]	ptr to a packed ie.
+		OBuf[OUT]	ptr to buffer for Unpacked ie.
+		IOff[IN\OUT]	Input buffer offset
+		OOff[IN\OUT]	Output buffer offset
+
+		Ibuf and OBuf points directly to buffers. The IOff and OOff
+		must be updated, but are otherwise not used in the ie unpack.
+
+  Return Value: Error Message
+
+*****************************************************************************/
+
+L3INT Q931Uie_BearerCap(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff) 
+{
+	Q931ie_BearerCap *pie = (Q931ie_BearerCap*)OBuf;
+	ie *pIE = &pMsg->BearerCap;
+	L3INT Off = 0;
+	L3INT Octet = 0;
+	L3INT IESize;
+	*pIE = 0;
+
+	/* Octet 1 */
+	pie->IEId = IBuf[Octet++];
+
+	/* Octet 2 */
+	IESize = IBuf[Octet++]; 
+
+	/* Octet 3 */
+	pie->CodStand = ieGetOctet((IBuf[Octet] & 0x60) >> 5);
+	pie->ITC      = ieGetOctet(IBuf[Octet] & 0x1f);
+	Off           = Q931ReadExt(&IBuf[Octet], Off);
+	Octet++;
+
+	/* Octet 4 */
+	pie->TransMode = ieGetOctet((IBuf[Octet + Off] & 0x60) >> 5);
+	pie->ITR       = ieGetOctet(IBuf[Octet + Off] & 0x1f);
+	Off            = Q931ReadExt(&IBuf[Octet + Off], Off);
+	Octet++;
+
+	/* Octet 4.1. Rate multiplier is only present if ITR = Multirate		*/
+	if (pie->ITR == 0x18) {
+		pie->RateMul = ieGetOctet(IBuf[Octet + Off] & 0x7f);
+		Off = Q931ReadExt(&IBuf[Octet + Off], Off);
+		Off ++;
+	}
+
+	/* Octet 5 */
+	if ((IBuf[Octet + Off] & 0x60) == 0x20 && Q931MoreIE()) {
+		pie->Layer1Ident = ieGetOctet((IBuf[Octet + Off] & 0x60) >> 5);
+		pie->UIL1Prot    = ieGetOctet(IBuf[Octet + Off] & 0x1f);
+		Octet++;
+
+		/* Octet 5a. The octet may be present if ITC is unrestrictd digital info
+		 * and UIL1Prot is either V.110, I.460 and X.30 or V.120. It may also
+		 * be present if ITC = 3.1 kHz audio and UIL1Prot is G.711.
+		 * Bit 8 of Octet 5 = 0 indicates that 5a is present.
+		 */
+
+		if (IsQ931Ext(IBuf[Octet + Off - 1])) {
+			if (((pie->ITC == 0x08) && (pie->UIL1Prot == 0x01 || pie->UIL1Prot == 0x08))
+			|| ((pie->ITC == 0x10) && (pie->UIL1Prot == 0x02 || pie->UIL1Prot == 0x03))) {
+				pie->SyncAsync = ieGetOctet((IBuf[Octet + Off] & 0x40) >> 6);
+				pie->Negot     = ieGetOctet((IBuf[Octet + Off] & 0x20) >> 5);
+				pie->UserRate  = ieGetOctet(IBuf[Octet + Off] & 0x1f);
+				Off ++;
+			}
+			else {
+				/* We have detected bit 8 = 0, but no setting that require the  */
+				/* additional octets ??? */
+				Q931SetError(pTrunk, Q931E_BEARERCAP, 5,Off);
+				return Q931E_BEARERCAP;
+			}
+
+			/* Octet 5b. Two different structures used. */
+			if (IsQ931Ext(IBuf[Octet + Off - 1])) {
+				if (pie->UIL1Prot == 0x01) { /* ITU V.110, I.460 and X.30 */
+					pie->InterRate = ieGetOctet((IBuf[Octet + Off] & 0x60) >> 5);
+					pie->NIConTx   = ieGetOctet((IBuf[Octet + Off] & 0x10) >> 4);
+					pie->NIConRx   = ieGetOctet((IBuf[Octet + Off] & 0x08) >> 3);
+					pie->FlowCtlTx = ieGetOctet((IBuf[Octet + Off] & 0x04) >> 2);
+					pie->FlowCtlRx = ieGetOctet((IBuf[Octet + Off] & 0x20) >> 1);
+					Off++;
+				}
+				else if (pie->UIL1Prot == 0x08) { /* ITU V.120 */
+					pie->HDR        = ieGetOctet((IBuf[Octet + Off] & 0x40) >> 6);
+					pie->MultiFrame = ieGetOctet((IBuf[Octet + Off] & 0x20) >> 5);
+					pie->Mode       = ieGetOctet((IBuf[Octet + Off] & 0x10) >> 4);
+					pie->LLInegot   = ieGetOctet((IBuf[Octet + Off] & 0x08) >> 3);
+					pie->Assignor   = ieGetOctet((IBuf[Octet + Off] & 0x04) >> 2);
+					pie->InBandNeg  = ieGetOctet((IBuf[Octet + Off] & 0x02) >> 1);
+					Off++;
+				}
+				else {
+					Q931SetError(pTrunk,Q931E_BEARERCAP, 5,Off);
+					return Q931E_BEARERCAP;
+				}
+
+				/* Octet 5c */
+				if (IsQ931Ext(IBuf[Octet + Off - 1])) {
+					pie->NumStopBits = ieGetOctet((IBuf[Octet + Off] & 0x60) >> 5);
+					pie->NumDataBits = ieGetOctet((IBuf[Octet + Off] & 0x18) >> 3);
+					pie->Parity      = ieGetOctet(IBuf[Octet + Off] & 0x07);
+					Off++;
+
+					/* Octet 5d */
+					if (IsQ931Ext(IBuf[Octet + Off - 1])) {
+						pie->DuplexMode = ieGetOctet((IBuf[Octet + Off] & 0x40) >> 6);
+						pie->ModemType  = ieGetOctet(IBuf[Octet + Off] & 0x3f);
+						Off ++;
+					}
+				}
+			}
+		}
+	}
+
+	/* Octet 6 */
+	if ((IBuf[Octet + Off] & 0x60) == 0x40 && Q931MoreIE()) {
+		pie->Layer2Ident = ieGetOctet((IBuf[Octet + Off] & 0x60) >> 5);
+		pie->UIL2Prot    = ieGetOctet(IBuf[Octet + Off] & 0x1f);
+
+		Off = Q931ReadExt(&IBuf[Octet + Off], Off);
+		Octet ++;
+	}
+
+	/* Octet 7 */
+	if ((IBuf[Octet + Off] & 0x60) == 0x60 && Q931MoreIE()) {
+		pie->Layer3Ident = ieGetOctet((IBuf[Octet + Off] & 0x60) >> 5);
+		pie->UIL3Prot    = ieGetOctet(IBuf[Octet + Off] & 0x1f);
+		Octet++;
+
+		/* Octet 7a */
+		if (IsQ931Ext(IBuf[Octet + Off - 1])) {
+			if (pie->UIL3Prot == 0x0c) {
+				pie->AL3Info1 = ieGetOctet(IBuf[Octet + Off] & 0x0f);
+				Off++;
+
+				/* Octet 7b */
+				if (IsQ931Ext(IBuf[Octet + Off])) {
+					pie->AL3Info2 = ieGetOctet(IBuf[Octet + Off] & 0x0f);
+					Off++;
+				}
+			}
+			else {
+				Q931SetError(pTrunk,Q931E_BEARERCAP, 7, Off);
+				return Q931E_BEARERCAP;
+
+			}
+		}
+	}
+
+	Q931IESizeTest(Q931E_BEARERCAP);
+	Q931SetIE(*pIE, *OOff);
+
+	*IOff = (*IOff) + Octet + Off;
+	*OOff = (*OOff) + sizeof(Q931ie_BearerCap);
+	pie->Size = sizeof(Q931ie_BearerCap);
+
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Pie_BearerCap
+
+  Description:  Packing a Q.931 Bearer Capability element from a generic 
+				struct into a packed octet structure in accordance with the
+				standard.
+
+  Parameters:   IBuf[IN]		Ptr to struct.
+				OBuf[OUT]		Ptr tp packed output buffer.
+				Octet[IN/OUT]	Offset into OBuf.
+
+  Return Value:	Error code, 0 = OK
+
+*****************************************************************************/
+
+L3INT Q931Pie_BearerCap(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+	Q931ie_BearerCap *pIE = (Q931ie_BearerCap*)IBuf;
+	L3INT rc = 0;
+	L3INT Beg = *Octet; /* remember current offset */
+	L3INT li;
+
+	Q931Log(pTrunk, Q931_LOG_DEBUG, "Encoding Bearer Capability IE\n");
+
+	OBuf[(*Octet)++] = Q931ie_BEARER_CAPABILITY ;
+	li = (*Octet)++; /* remember length position */
+
+	/* Octet 3 - Coding standard / Information transfer capability */
+	OBuf[(*Octet)++] = 0x80 | ((pIE->CodStand << 5) & 0x60) | (pIE->ITC & 0x1f);
+
+	/* Octet 4 - Transfer mode / Information transfer rate */
+	OBuf[(*Octet)++] = 0x80 | ((pIE->TransMode << 5) & 0x60) | (pIE->ITR & 0x1f);
+
+	if (pIE->ITR == 0x18) {
+		/* Octet 4.1 - Rate Multiplier */
+		OBuf[(*Octet)++] = 0x80 | (pIE->RateMul & 0x7f);
+	}
+
+	/* Octet 5 - Layer 1 Ident / User information layer 1 protocol */
+	if (pIE->Layer1Ident == 0x01) {
+		if (((pIE->ITC == 0x08) && (pIE->UIL1Prot == 0x01 || pIE->UIL1Prot == 0x08)) ||
+		   ((pIE->ITC == 0x10) && (pIE->UIL1Prot == 0x02 || pIE->UIL1Prot == 0x03))) {
+			OBuf[(*Octet)++] = 0x00 | ((pIE->Layer1Ident << 5) & 0x60) | (pIE->UIL1Prot & 0x15);
+			
+			/* Octet 5a - SyncAsync/Negot/UserRate */
+			OBuf[(*Octet)++] = 0x00 | ((pIE->SyncAsync << 6) & 0x40) | ((pIE->Negot << 5) & 0x20) | (pIE->UserRate & 0x1f);
+
+			/* Octet 5b - one of two types */
+			if (pIE->UIL1Prot == 0x01) { /* ITU V.110, I.460 and X.30	*/
+				/* Octet 5b - Intermed rate/ Nic on Tx/Nix on Rx/FlowCtlTx/FlowCtlRx */
+				OBuf[(*Octet)++] = 0x00 
+						| ((pIE->InterRate << 6) & 0x60)
+						| ((pIE->NIConTx   << 4) & 0x10)
+						| ((pIE->NIConRx   << 3) & 0x08)
+						| ((pIE->FlowCtlTx << 2) & 0x04)
+						| ((pIE->FlowCtlRx << 1) & 0x02);
+			}
+			else if (pIE->UIL1Prot == 0x08) { /* ITU V.120 */
+				/* Octet 5b - HDR/Multiframe/Mode/LLINegot/Assignor/Inbandneg*/
+				OBuf[(*Octet)++] = 0x00
+						| ((pIE->InterRate  << 6) & 0x60)
+						| ((pIE->MultiFrame << 5) & 0x20)
+						| ((pIE->Mode       << 4) & 0x10)
+						| ((pIE->LLInegot   << 3) & 0x08)
+						| ((pIE->Assignor   << 2) & 0x04)
+						| ((pIE->InBandNeg  << 1) & 0x02);
+			}
+
+			/* Octet 5c - NumStopBits/NumStartBits/Parity					*/
+			OBuf[(*Octet)++] = 0x00
+					| ((pIE->NumStopBits << 5) & 0x60)
+					| ((pIE->NumDataBits << 3) & 0x18)
+					| (pIE->Parity & 0x07);
+
+			/* Octet 5d - Duplex Mode/Modem Type */
+			OBuf[(*Octet)++] = 0x80 | ((pIE->DuplexMode << 6) & 0x40) | (pIE->ModemType & 0x3f);
+		}
+		else {
+			OBuf[(*Octet)++] = 0x80 | ((pIE->Layer1Ident << 5) & 0x60) | (pIE->UIL1Prot & 0x1f);
+		}
+	}
+
+	/* Octet 6 - Layer2Ident/User information layer 2 prtocol */
+	if (pIE->Layer2Ident == 0x02) {
+		OBuf[(*Octet)++] = 0x80 | ((pIE->Layer2Ident << 5) & 0x60) | (pIE->UIL2Prot & 0x1f);
+	}
+
+	/* Octet 7 - Layer 3 Ident/ User information layer 3 protocol */
+	if (pIE->Layer3Ident == 0x03) {
+		if (pIE->UIL3Prot == 0x0c) {
+			OBuf[(*Octet)++] = 0x00 | ((pIE->Layer3Ident << 5) & 0x60) | (pIE->UIL3Prot & 0x1f);
+
+			/* Octet 7a - Additional information layer 3 msb */
+			OBuf[(*Octet)++] = 0x00 | (pIE->AL3Info1 & 0x0f);
+
+			/* Octet 7b - Additional information layer 3 lsb */
+			OBuf[(*Octet)++] = 0x80 | (pIE->AL3Info2 & 0x0f);
+		}
+		else {
+			OBuf[(*Octet)++] = 0x80 | ((pIE->Layer3Ident << 5) & 0x60) | (pIE->UIL3Prot & 0x1f);
+		}
+	}
+
+	OBuf[li] = (L3UCHAR)((*Octet) - Beg) - 2;
+	return rc;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Uie_CallID
+
+  Parameters:   pIE[OUT]		ptr to Information Element id.
+				IBuf[IN]		ptr to a packed ie.
+				OBuf[OUT]	   ptr to buffer for Unpacked ie.
+				IOff[IN\OUT]	Input buffer offset
+				OOff[IN\OUT]	Output buffer offset
+
+
+				Ibuf and OBuf points directly to buffers. The IOff and OOff
+				must be updated, but are otherwise not used in the ie unpack.
+
+  Return Value: Error Message
+
+*****************************************************************************/
+L3INT Q931Uie_CallID(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff)
+{
+	Q931ie_CallID *pie = (Q931ie_CallID*)OBuf;
+	ie *pIE = &pMsg->CallID;
+	L3INT Off = 0;
+	L3INT Octet = 0;
+	L3INT x = 0;
+	L3INT IESize;
+
+	*pIE = 0;
+
+	/* Octet 1 */
+	pie->IEId = IBuf[Octet++];
+
+	/* Octet 2 */
+	IESize = IBuf[Octet++]; 
+
+	/* Octet 3 */
+	do {
+		pie->CallId[x] = IBuf[Octet + Off] & 0x7f;
+		Off++;
+		x++;
+	} while (Q931MoreIE());
+
+	Q931IESizeTest(Q931E_CALLID);
+	Q931SetIE(*pIE, *OOff);
+
+	*IOff = (*IOff) + Octet + Off;
+	*OOff = (*OOff) + sizeof(Q931ie_CallID) + x - 1;
+	pie->Size = (L3UCHAR)(sizeof(Q931ie_CallID) + x - 1);
+
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Pie_CallID
+
+  Parameters:   IBuf[IN]		Ptr to struct.
+				OBuf[OUT]		Ptr tp packed output buffer.
+				Octet[IN/OUT]	Offset into OBuf.
+
+  Return Value:	Error code, 0 = OK
+
+*****************************************************************************/
+
+L3INT Q931Pie_CallID(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+	Q931ie_CallID *pIE = (Q931ie_CallID*)IBuf;
+	L3INT rc = 0;
+	L3INT Beg = *Octet;/* remember current offset */
+	L3INT li;
+	L3INT sCI = pIE->Size - sizeof(Q931ie_CallID) + 1;
+	L3INT x;
+
+	OBuf[(*Octet)++] = Q931ie_CALL_IDENTITY ;
+	li = (*Octet)++; /* remember length position */
+
+	for (x = 0; x < sCI; x++) {
+		OBuf[(*Octet)++] = pIE->CallId[x];
+	}
+
+	OBuf[(*Octet) - 1] |= 0x80; /* set complete flag at last octet*/
+
+	OBuf[li] = (L3UCHAR)((*Octet) - Beg) - 2;
+	return rc;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Uie_CallState
+
+  Parameters:   pIE[OUT]		ptr to Information Element id.
+				IBuf[IN]		ptr to a packed ie.
+				OBuf[OUT]	   ptr to buffer for Unpacked ie.
+				IOff[IN\OUT]	Input buffer offset
+				OOff[IN\OUT]	Output buffer offset
+
+				Ibuf and OBuf points directly to buffers. The IOff and OOff
+				must be updated, but are otherwise not used in the ie unpack.
+
+  Return Value: Error Message
+
+*****************************************************************************/
+L3INT Q931Uie_CallState(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff)
+{
+	Q931ie_CallState *pie = (Q931ie_CallState*)OBuf;
+	ie *pIE = &pMsg->CallState;
+	L3INT Off = 0;
+	L3INT Octet = 0;
+	L3INT IESize;
+
+	*pIE = 0;
+
+	/* Octet 1 */
+	pie->IEId = IBuf[Octet++];
+
+	/* Octet 2 */
+	IESize = IBuf[Octet++];
+
+	/* Octet 3 */
+	pie->CodStand  = (IBuf[Octet + Off] >> 6) & 0x03;
+	pie->CallState =  IBuf[Octet + Off] & 0x3f;
+	Octet++;
+
+	Q931IESizeTest(Q931E_CALLSTATE);
+	Q931SetIE(*pIE, *OOff);
+
+	*IOff = (*IOff) + Octet + Off;
+	*OOff = (*OOff) + sizeof(Q931ie_CallState);
+	pie->Size = sizeof(Q931ie_CallState);
+
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Pie_CallState
+
+  Parameters:   IBuf[IN]		Ptr to struct.
+				OBuf[OUT]		Ptr tp packed output buffer.
+				Octet[IN/OUT]	Offset into OBuf.
+
+  Return Value: Error code, 0 = OK
+
+*****************************************************************************/
+L3INT Q931Pie_CallState(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+	Q931ie_CallState *pIE = (Q931ie_CallState*)IBuf;
+	L3INT rc = 0;
+	L3INT Beg = *Octet; /* remember current offset */
+	L3INT li;
+
+	OBuf[(*Octet)++] = Q931ie_CALL_STATE;
+	li = (*Octet)++; /* remember length position */
+
+	OBuf[(*Octet)++] = (pIE->CodStand << 6) | (pIE->CallState & 0x3f);
+
+	OBuf[li] = (L3UCHAR)((*Octet) - Beg) - 2;
+	return rc;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Uie_CalledSub
+
+  Parameters:   pIE[OUT]		ptr to Information Element id.
+				IBuf[IN]		ptr to a packed ie.
+				OBuf[OUT]	   ptr to buffer for Unpacked ie.
+				IOff[IN\OUT]	Input buffer offset
+				OOff[IN\OUT]	Output buffer offset
+
+				Ibuf and OBuf points directly to buffers. The IOff and OOff
+				must be updated, but are otherwise not used in the ie unpack.
+
+  Return Value: Error Message
+
+*****************************************************************************/
+L3INT Q931Uie_CalledSub(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff)
+{
+	Q931ie_CalledSub *pie = (Q931ie_CalledSub*)OBuf;
+	ie *pIE = &pMsg->CalledSub;
+	L3INT Off = 0;
+	L3INT Octet = 0;
+	L3INT x;
+	L3INT IESize;
+
+	*pIE = 0;
+
+	/* Octet 1 */
+	pie->IEId = IBuf[Octet++];
+
+	/* Octet 2 */
+	IESize = IBuf[Octet++]; 
+
+	/* Octet 3 */
+	pie->TypNum     = (IBuf[Octet + Off] >> 4) & 0x07;
+	pie->OddEvenInd = (IBuf[Octet + Off] >> 3) & 0x01;
+	Octet++;
+	
+	/* Octet 4 */
+	x = 0;
+	do {
+		pie->Digit[x] = IBuf[Octet + Off] & 0x7f;
+		Off++;
+		x++;
+	} while (Q931MoreIE() && x < 20);
+
+	Q931IESizeTest(Q931E_CALLEDSUB);
+	Q931SetIE(*pIE, *OOff);
+
+	*IOff = (*IOff) + Octet + Off;
+	*OOff = (*OOff) + sizeof(Q931ie_CalledSub) + x - 1;
+	pie->Size = (L3UCHAR)(sizeof(Q931ie_CalledSub) + x - 1);
+
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Pie_CalledSub
+
+  Parameters:   IBuf[IN]		Ptr to struct.
+				OBuf[OUT]		Ptr tp packed output buffer.
+				Octet[IN/OUT]	Offset into OBuf.
+
+  Return Value:	Error code, 0 = OK
+
+*****************************************************************************/
+L3INT Q931Pie_CalledSub(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+	Q931ie_CalledSub *pIE = (Q931ie_CalledSub*)IBuf;
+	L3INT rc = 0;
+	L3INT Beg = *Octet;
+	L3INT li;
+	L3INT sN = pIE->Size - sizeof(Q931ie_CalledSub) + 1;
+	L3INT x;
+
+	/* Octet 1 */
+	OBuf[(*Octet)++] = Q931ie_CALLED_PARTY_SUBADDRESS;
+	li = (*Octet)++;
+
+	/* Octet 3 */
+	OBuf[(*Octet)++] = 0x80 | (pIE->TypNum << 4) | (pIE->OddEvenInd << 3);
+	
+	/* Octet 4 */
+	for (x = 0; x<sN; x++) {
+		OBuf[(*Octet)++] = pIE->Digit[x];
+	}
+
+	OBuf[(*Octet) - 1] |= 0x80; /* Terminate bit */
+
+	OBuf[li] = (L3UCHAR)((*Octet) - Beg) - 2;
+	return rc;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Uie_CalledNum
+
+  Parameters:   pIE[OUT]		ptr to Information Element id.
+				IBuf[IN]		ptr to a packed ie.
+				OBuf[OUT]	   ptr to buffer for Unpacked ie.
+				IOff[IN\OUT]	Input buffer offset
+				OOff[IN\OUT]	Output buffer offset
+
+				Ibuf and OBuf points directly to buffers. The IOff and OOff
+				must be updated, but are otherwise not used in the ie unpack.
+
+  Return Value: Error Message
+
+*****************************************************************************/
+L3INT Q931Uie_CalledNum(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff)
+{
+	Q931ie_CalledNum *pie = (Q931ie_CalledNum*)OBuf;
+	ie *pIE = &pMsg->CalledNum;
+	L3INT Off = 0;
+	L3INT Octet = 0;
+	L3INT x;
+	L3INT IESize; /* # digits in this case */
+
+	*pIE = 0;
+
+	/* Octet 1 */
+	pie->IEId = IBuf[Octet++];
+
+	/* Octet 2 */
+	IESize = IBuf[Octet++]; 
+
+	/* Octet 3 */
+	pie->TypNum    = (IBuf[Octet + Off] >> 4) & 0x07;
+	pie->NumPlanID =  IBuf[Octet + Off] & 0x0f;
+	Octet++;
+
+	/* Octet 4*/
+	x = 0;
+	do {
+		pie->Digit[x] = IBuf[Octet + Off] & 0x7f;
+		Off++;
+		x++;
+	} while ((IBuf[Octet + Off]&0x80) == 0 && Q931MoreIE());
+
+	pie->Digit[x] = '\0';
+
+	Q931SetIE(*pIE, *OOff);
+
+	*IOff = (*IOff) + Octet + Off;
+	*OOff = (*OOff) + sizeof(Q931ie_CalledNum) + x;
+	pie->Size = (L3UCHAR)(sizeof(Q931ie_CalledNum) + x);
+
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Pie_CalledNum
+
+  Parameters:   IBuf[IN]		Ptr to struct.
+				OBuf[OUT]		Ptr tp packed output buffer.
+				Octet[IN/OUT]	Offset into OBuf.
+
+  Return Value:	Error code, 0 = OK
+
+*****************************************************************************/
+L3INT Q931Pie_CalledNum(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+	Q931ie_CalledNum *pIE = (Q931ie_CalledNum*)IBuf;
+	L3INT rc = 0;
+	L3INT Beg = *Octet;
+	L3INT li;
+	L3INT sN = pIE->Size - sizeof(Q931ie_CalledNum);
+	L3INT x;
+
+	/* Octet 1 */
+	OBuf[(*Octet)++] = Q931ie_CALLED_PARTY_NUMBER;
+	
+	/* Octet 2 */
+	li = (*Octet)++;
+
+	/* Octet 3 */
+	OBuf[(*Octet)++] = 0x80 | (pIE->TypNum << 4) | (pIE->NumPlanID);
+	
+	/* Octet 4 */
+	for (x = 0; x<sN; x++) {
+		OBuf[(*Octet)++] = pIE->Digit[x];
+	}
+
+	OBuf[li] = (L3UCHAR)((*Octet) - Beg) - 2;
+	return rc;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Uie_CallingNum
+
+  Parameters:   pIE[OUT]		ptr to Information Element id.
+				IBuf[IN]		ptr to a packed ie.
+				OBuf[OUT]	   ptr to buffer for Unpacked ie.
+				IOff[IN\OUT]	Input buffer offset
+				OOff[IN\OUT]	Output buffer offset
+
+				Ibuf and OBuf points directly to buffers. The IOff and OOff
+				must be updated, but are otherwise not used in the ie unpack.
+
+  Return Value: Error Message
+
+*****************************************************************************/
+L3INT Q931Uie_CallingNum(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff)
+{
+	Q931ie_CallingNum *pie = (Q931ie_CallingNum*)OBuf;
+	ie *pIE = &pMsg->CallingNum;
+	L3INT Off = 0;
+	L3INT Octet = 0;
+	L3INT x;
+	L3INT IESize;
+
+	*pIE = 0;
+
+	/* Octet 1 */
+	pie->IEId = IBuf[Octet++];
+
+	/* Octet 2 */
+	IESize = IBuf[Octet++]; 
+
+	/* Octet 3 */
+	pie->TypNum    = (IBuf[Octet + Off] >> 4) & 0x07;
+	pie->NumPlanID =  IBuf[Octet + Off] & 0x0f;
+
+	/* Octet 3a */
+	if ((IBuf[Octet + Off] & 0x80) == 0) {
+		Off++;
+		pie->PresInd   = (IBuf[Octet + Off] >> 5) & 0x03;
+		pie->ScreenInd =  IBuf[Octet + Off] & 0x03;
+	}
+	Octet++;
+
+	/* Octet 4 */
+	x = 0;
+	while (Q931MoreIE()) {
+		pie->Digit[x++] = IBuf[Octet + Off] & 0x7f;
+
+		if ((IBuf[Octet + Off] & 0x80) != 0) {
+			break;
+		}
+		Off++;
+	}
+	pie->Digit[x] = '\0';
+
+	Q931IESizeTest(Q931E_CALLINGNUM);
+	Q931SetIE(*pIE, *OOff);
+
+	*IOff = (*IOff) + Octet + Off;
+	*OOff = (*OOff) + sizeof(Q931ie_CallingNum) + x;
+	pie->Size = (L3UCHAR)(sizeof(Q931ie_CallingNum) + x);
+
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Pie_CallingNum
+
+  Parameters:   IBuf[IN]		Ptr to struct.
+				OBuf[OUT]		Ptr tp packed output buffer.
+				Octet[IN/OUT]	Offset into OBuf.
+
+  Return Value:	Error code, 0 = OK
+
+*****************************************************************************/
+L3INT Q931Pie_CallingNum(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+	Q931ie_CallingNum *pIE = (Q931ie_CallingNum*)IBuf;
+	L3INT rc = 0;
+	L3INT Beg = *Octet;
+	L3INT li;
+	L3INT sN = pIE->Size - sizeof(Q931ie_CallingNum);
+	L3INT x;
+
+	/* Octet 1 */
+	OBuf[(*Octet)++] = Q931ie_CALLING_PARTY_NUMBER;
+	
+	/* Octet 2 */
+	li = (*Octet)++;
+
+	/* Octet 3 */
+	OBuf[(*Octet)++] = 0x00 | (pIE->TypNum << 4) | (pIE->NumPlanID);
+	
+	/* Octet 4 */
+	OBuf[(*Octet)++] = 0x80;
+
+	/* Octet 5 */
+	for (x = 0; x<sN; x++) {
+		OBuf[(*Octet)++] = pIE->Digit[x];
+	}
+
+	OBuf[li] = (L3UCHAR)((*Octet) - Beg) - 2;
+	return rc;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Uie_CallingSub
+
+  Parameters:   pIE[OUT]		ptr to Information Element id.
+				IBuf[IN]		ptr to a packed ie.
+				OBuf[OUT]	   ptr to buffer for Unpacked ie.
+				IOff[IN\OUT]	Input buffer offset
+				OOff[IN\OUT]	Output buffer offset
+
+				Ibuf and OBuf points directly to buffers. The IOff and OOff
+				must be updated, but are otherwise not used in the ie unpack.
+
+  Return Value: Error Message
+
+*****************************************************************************/
+L3INT Q931Uie_CallingSub(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff)
+{
+	Q931ie_CallingSub *pie = (Q931ie_CallingSub*)OBuf;
+	ie *pIE = &pMsg->CallingSub;
+	L3INT Off = 0;
+	L3INT Octet = 0;
+	L3INT x;
+	L3INT IESize;
+
+	*pIE = 0;
+
+	/* Octet 1 */
+	pie->IEId = IBuf[Octet++];
+
+	/* Octet 2 */
+	IESize = IBuf[Octet++]; 
+
+	/* Octet 3 */
+	pie->TypNum     = (IBuf[Octet + Off] >> 4) & 0x07;
+	pie->OddEvenInd = (IBuf[Octet + Off] >> 3) & 0x01;
+	Octet++;
+	
+	/* Octet 4*/
+	x = 0;
+	do {
+		pie->Digit[x] = IBuf[Octet + Off] & 0x7f;
+		Off++;
+		x++;
+	} while (Q931MoreIE() && x < 20);
+
+	Q931IESizeTest(Q931E_CALLINGSUB);
+	Q931SetIE(*pIE, *OOff);
+
+	*IOff = (*IOff) + Octet + Off;
+	*OOff = (*OOff) + sizeof(Q931ie_CallingSub) + x -1;
+	pie->Size = (L3UCHAR)(sizeof(Q931ie_CallingSub) + x -1);
+
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Pie_CallingSub
+
+  Parameters:   IBuf[IN]		Ptr to struct.
+				OBuf[OUT]		Ptr tp packed output buffer.
+				Octet[IN/OUT]	Offset into OBuf.
+
+  Return Value:	Error code, 0 = OK
+
+*****************************************************************************/
+L3INT Q931Pie_CallingSub(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+	Q931ie_CallingSub *pIE = (Q931ie_CallingSub*)IBuf;
+	L3INT rc = 0;
+	L3INT Beg = *Octet;
+	L3INT li;
+	L3INT sN = pIE->Size - sizeof(Q931ie_CallingSub) + 1;
+	L3INT x;
+
+	/* Octet 1 */
+	OBuf[(*Octet)++] = Q931ie_CALLING_PARTY_SUBADDRESS;
+	li = (*Octet)++;
+
+	/* Octet 3 */
+	OBuf[(*Octet)++] = 0x80 | (pIE->TypNum << 4) | (pIE->OddEvenInd << 3);
+	
+	/* Octet 4 */
+	for (x = 0; x<sN; x++) {
+		OBuf[(*Octet)++] = pIE->Digit[x];
+	}
+
+	OBuf[(*Octet) - 1] |= 0x80; /* Terminate bit */
+
+	OBuf[li] = (L3UCHAR)((*Octet) - Beg) - 2;
+	return rc;
+}
+
+/*****************************************************************************
+
+  Function:		Q931Uie_Cause
+  
+  Parameters:   pIE[OUT]		ptr to Information Element id.
+				IBuf[IN]		ptr to a packed ie.
+				OBuf[OUT]	   ptr to buffer for Unpacked ie.
+				IOff[IN\OUT]	Input buffer offset
+				OOff[IN\OUT]	Output buffer offset
+
+				Ibuf and OBuf points directly to buffers. The IOff and OOff
+				must be updated, but are otherwise not used in the ie unpack.
+
+  Return Value: Error Message
+
+*****************************************************************************/
+L3INT Q931Uie_Cause(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff) 
+{
+	Q931ie_Cause *pie = (Q931ie_Cause*)OBuf;
+	ie *pIE = &pMsg->Cause;
+	L3INT Off = 0;
+	L3INT Octet = 0;
+	L3INT IESize;
+
+	*pIE = 0;
+
+	pie->IEId = IBuf[Octet++];
+
+	/* Octet 2*/
+	IESize = IBuf[Octet++]; 
+
+	/* Octet 3*/
+	pie->CodStand = (IBuf[Octet + Off]>>5) & 0x03;
+	pie->Location =  IBuf[Octet + Off] & 0x0f;
+
+	/* Octet 3a */
+	if ((IBuf[Octet + Off] & 0x80) == 0) {
+		Off++;
+		pie->Recom = IBuf[Octet + Off] & 0x7f;
+	}
+	Octet++;
+
+	/* Octet 4 */
+	pie->Value = IBuf[Octet + Off] & 0x7f;
+	Octet++;
+
+	/* Consume optional Diagnostic bytes */
+	while (Q931MoreIE()) {
+		Off++;
+	};
+
+	Q931IESizeTest(Q931E_CAUSE);
+	Q931SetIE(*pIE, *OOff);
+
+	*IOff = (*IOff) + Octet + Off;
+	*OOff = (*OOff) + sizeof(Q931ie_Cause);
+	pie->Size = sizeof(Q931ie_Cause);
+
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:		Q931Pie_Cause
+
+  Parameters:   IBuf[IN]		Ptr to struct.
+				OBuf[OUT]		Ptr tp packed output buffer.
+				Octet[IN/OUT]	Offset into OBuf.
+
+  Return Value:	Error code, 0 = OK
+
+*****************************************************************************/
+L3INT Q931Pie_Cause(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+	Q931ie_Cause *pIE = (Q931ie_Cause*)IBuf;
+	L3INT rc = 0;
+	L3INT Beg = *Octet;
+	L3INT li;
+
+	OBuf[(*Octet)++] = Q931ie_CAUSE;
+	li = (*Octet)++;
+
+	/* Octet 3 */
+	OBuf[(*Octet)++] = 0x80 | (pIE->CodStand<<5) | pIE->Location;
+
+	/* Octet 3a - currently not supported in send */
+
+	/* Octet 4 */
+	OBuf[(*Octet)++] = 0x80 | pIE->Value;
+
+	/* Octet 5 - diagnostics not supported in send */
+
+	OBuf[li] = (L3UCHAR)((*Octet) - Beg) - 2;
+	return rc;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Uie_CongLevel
+  
+  Parameters:   pIE[OUT]		ptr to Information Element id.
+				IBuf[IN]		ptr to a packed ie.
+				OBuf[OUT]	   ptr to buffer for Unpacked ie.
+				IOff[IN\OUT]	Input buffer offset
+				OOff[IN\OUT]	Output buffer offset
+
+				Ibuf and OBuf points directly to buffers. The IOff and OOff
+				must be updated, but are otherwise not used in the ie unpack.
+
+  Return Value: Error Message
+
+*****************************************************************************/
+L3INT Q931Uie_CongLevel(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff) 
+{
+	Q931ie_CongLevel *pie = (Q931ie_CongLevel*)OBuf;
+	ie *pIE = &pMsg->CongestionLevel;
+	L3INT Off = 0;
+	L3INT Octet = 0;
+
+	*pIE = 0;
+
+	pie->IEId      = IBuf[Octet] & 0xf0;
+	pie->CongLevel = IBuf[Octet] & 0x0f;
+	Octet ++;
+
+	Q931SetIE(*pIE, *OOff);
+
+	*IOff = (*IOff) + Octet + Off;
+	*OOff = (*OOff) + sizeof(Q931ie_CongLevel);
+	pie->Size = sizeof(Q931ie_CongLevel);
+
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Pie_CongLevel
+
+  Parameters:   IBuf[IN]		Ptr to struct.
+				OBuf[OUT]		Ptr tp packed output buffer.
+				Octet[IN/OUT]	Offset into OBuf.
+
+  Return Value: Error code, 0 = OK
+
+*****************************************************************************/
+L3INT Q931Pie_CongLevel(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+	Q931ie_CongLevel *pIE = (Q931ie_CongLevel*)IBuf;
+	L3INT rc = 0;
+	/* L3INT Beg = *Octet; */
+
+	OBuf[(*Octet)++] = Q931ie_CONGESTION_LEVEL | pIE->CongLevel;
+
+	return rc;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Uie_ChanID
+
+  Parameters:   IBuf[IN]		ptr to a packed ie.
+				OBuf[OUT]	   ptr to buffer for Unpacked ie.
+				IOff[IN\OUT]	Input buffer offset
+				OOff[IN\OUT]	Output buffer offset
+
+				Ibuf and OBuf points directly to buffers. The IOff and OOff
+				must be updated, but are otherwise not used in the ie unpack.
+
+  Return Value:	Error code, 0 = OK
+
+*****************************************************************************/
+L3INT Q931Uie_ChanID(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR *OBuf, L3INT *IOff, L3INT *OOff)
+{
+	Q931ie_ChanID *pie = (Q931ie_ChanID*)OBuf;
+	ie *pIE = &pMsg->ChanID;
+	L3INT Off = 0;
+	L3INT Octet = 0;
+	L3INT IESize;
+//18 04 e1 80 83 01
+	*pIE = 0;
+
+	Q931Log(pTrunk, Q931_LOG_DEBUG, "Decoding ChanID IE\n");
+
+	/* Octet 1 */
+	pie->IEId = IBuf[Octet++];
+
+	/* Octet 2 */
+	IESize    = IBuf[Octet++]; 
+
+	/* Octet 3 */
+	pie->IntIDPresent = (IBuf[Octet] >> 6) & 0x01;
+	pie->IntType      = (IBuf[Octet] >> 5) & 0x01;
+	pie->PrefExcl     = (IBuf[Octet] >> 3) & 0x01;
+	pie->DChanInd     = (IBuf[Octet] >> 2) & 0x01;
+	pie->InfoChanSel  =  IBuf[Octet] & 0x03;
+
+	Off = Q931ReadExt(&IBuf[Octet++], Off);
+
+	/* Octet 3.1 */
+	if (pie->IntIDPresent) {
+		pie->InterfaceID = IBuf[Octet + Off] & 0x7f;
+
+		/* Temp fix. Interface id can be extended using the extension bit */
+		/* this will read the octets, but do nothing with them. this is done */
+		/* because the usage of this field is a little unclear */
+		/* 30.jan.2001/JVB */
+		Off = Q931ReadExt(&IBuf[Octet + Off], Off);
+		Off++;
+	}
+
+	if ((Octet + Off - 2) != IESize) {
+		/* Octet 3.2 */
+		if (pie->IntType == 1) {        /* PRI etc */
+			pie->CodStand    = (IBuf[Octet + Off] >> 5) & 0x03;
+			pie->NumMap      = (IBuf[Octet + Off] >> 4) & 0x01;
+			pie->ChanMapType =  IBuf[Octet + Off] & 0x0f;
+			Off++;
+
+			/* Octet 3.3 */
+			/* Temp fix. Assume B channel. H channels not supported */
+			pie->ChanSlot = IBuf[Octet + Off] & 0x7f;
+
+			/* Some dialects don't follow the extension coding properly for this, but this should be safe for all */
+			if ((Octet + Off - 1) != IESize) {
+				Off = Q931ReadExt(&IBuf[Octet + Off], Off);
+			}
+			Off++;
+		}
+	}
+
+	Q931IESizeTest(Q931E_CHANID);
+	Q931SetIE(*pIE, *OOff);
+
+	*IOff = (*IOff) + Octet + Off;
+	*OOff = (*OOff) + sizeof(Q931ie_ChanID);
+	pie->Size = sizeof(Q931ie_ChanID);
+
+	if (pTrunk->loglevel == Q931_LOG_DEBUG) {
+		const char *iface;
+		char tmp[100] = "";
+
+		if (!pie->IntType) {
+			switch (pie->InfoChanSel) {
+			case 0x0:
+				iface = "None";
+				break;
+			case 0x1:
+				iface = "B1";
+				break;
+			case 0x2:
+				iface = "B2";
+				break;
+			default:
+				iface = "Any Channel";
+			}
+
+			snprintf(tmp, sizeof(tmp)-1, "InfoChanSel: %d (%s)", pie->InfoChanSel, iface);
+		}
+
+		Q931Log(pTrunk, Q931_LOG_DEBUG,
+			"\n-------------------------- Q.931 Channel ID ------------------------\n"
+			"    Pref/Excl: %s, Interface Type: %s\n"
+			"    %s\n"
+			"--------------------------------------------------------------------\n\n",
+			((pie->PrefExcl) ? "Preferred" : "Exclusive"),
+			((pie->IntType) ? "PRI/Other" : "BRI"),
+			tmp);
+	}
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Pie_ChanID
+
+  Parameters:   IBuf[IN]		Ptr to struct.
+				OBuf[OUT]		Ptr tp packed output buffer.
+				Octet[IN/OUT]	Offset into OBuf.
+
+  Return Value:	Error code, 0 = OK
+
+*****************************************************************************/
+L3INT Q931Pie_ChanID(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+	Q931ie_ChanID *pIE = (Q931ie_ChanID*)IBuf;
+	L3INT rc = Q931E_NO_ERROR;
+	L3INT Beg = *Octet;	/* remember current offset */
+	L3INT li;
+
+	OBuf[(*Octet)++] = Q931ie_CHANNEL_IDENTIFICATION;
+	li = (*Octet)++; /* remember length position */
+
+	/* Octet 3 flags & BRI chan # */
+	OBuf[(*Octet)++] = 0x80 
+			| ((pIE->IntIDPresent << 6) & 0x40)
+			| ((pIE->IntType << 5) & 0x20)
+			| ((pIE->PrefExcl << 3) & 0x08)
+			|  (pIE->InfoChanSel & 0x03);
+
+	/* Octet 3.1 - Interface Identifier */
+	if (pIE->IntIDPresent) {
+		OBuf[(*Octet)++] = 0x80 | (pIE->InterfaceID & 0x7f);
+	}
+
+	/* Octet 3.2 & 3.3 - PRI */
+	if (pIE->IntType) {
+		OBuf[(*Octet)++]  = 0x80
+			| ((pIE->CodStand << 5) & 0x60)
+			| ((pIE->NumMap << 4) & 0x10)
+			|  (pIE->ChanMapType & 0x0f);		/* TODO: support all possible channel map types */
+
+		/* Octet 3.3 Channel number */
+		switch (pIE->ChanMapType) {
+		case 0x6:	/* Slot map: H0 Channel Units */	/* unsupported, Octets 3.3.1 - 3.3.3 */
+			return Q931E_CHANID;
+
+		case 0x8:	/* Slot map: H11 Channel Units */
+		case 0x9:	/* Slot map: H12 Channel Units */
+		default:	/* Channel number */
+			OBuf[(*Octet)++] = 0x80 | (pIE->ChanSlot & 0x7f);
+			break;
+		}
+	}
+
+	OBuf[li] = (L3UCHAR)((*Octet) - Beg) - 2;
+	return rc;
+}
+
+
+/*****************************************************************************
+
+  Function:	 Q931Uie_CRV
+
+  Description:  Reading CRV. 
+
+				The CRV is currently returned in the return value that 
+				Q921Rx23 will assign to the CRV field in the unpacked
+				message. CRV is basically 2 bytes etc, but the spec allows
+				the use of longer CRV values.
+  
+  Parameters:   pIE[OUT]		ptr to Information Element id.
+				IBuf[IN]		ptr to a packed ie.
+				OBuf[OUT]	   ptr to buffer for Unpacked ie.
+				IOff[IN\OUT]	Input buffer offset
+				OOff[IN\OUT]	Output buffer offset
+
+				Ibuf and OBuf points directly to buffers. The IOff and OOff
+				must be updated, but are otherwise not used in the ie unpack.
+
+  Return Value: CRV
+
+*****************************************************************************/
+L3USHORT Q931Uie_CRV(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *IOff, L3INT *OOff)
+{
+	L3USHORT CRV = 0;
+	L3INT Octet = *IOff;
+	L3INT l = IBuf[Octet++]; 
+
+	if (l == 1) {	/* One octet CRV */
+		CRV = IBuf[Octet++] & 0x7F;
+	}
+	else if (l == 2) {	/* two octet CRV */
+		CRV  = (IBuf[Octet++] & 0x7f) << 8;
+		CRV |=  IBuf[Octet++];
+	}
+	else {
+		/* Long CRV is not used, so we skip this */
+		/* TODO: is it right to set to 0 here? */
+		CRV = 0;
+		Octet += l;
+	}
+
+	*IOff = Octet;
+	return CRV;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Uie_DateTime
+
+  Parameters:   pTrunk		[IN]		Ptr to trunk information.
+				pIE			[OUT]       ptr to Information Element id.
+				IBuf		[IN]		ptr to a packed ie.
+				OBuf		[OUT]	   ptr to buffer for Unpacked ie.
+				IOff		[IN\OUT]	Input buffer offset
+				OOff		[IN\OUT]	Output buffer offset
+
+				Ibuf and OBuf points directly to buffers. The IOff and OOff
+				must be updated, but are otherwise not used in the ie unpack.
+
+  Return Value: Error Message
+
+*****************************************************************************/
+L3INT Q931Uie_DateTime(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *IOff, L3INT *OOff)
+{
+	Q931ie_DateTime * pie = (Q931ie_DateTime*)OBuf;
+	ie *pIE = &pMsg->DateTime;
+	L3INT Off = 0;
+	L3INT Octet = 0;
+	L3INT IESize = 0;
+
+	*pIE = 0;
+
+	pie->IEId = IBuf[Octet++];
+	
+	/* Octet 2 */
+	IESize = IBuf[Octet++]; 
+
+	/* Octet 3 - Year */
+	pie->Year = IBuf[Octet++];
+
+	/* Octet 4 - Month */
+	pie->Month = IBuf[Octet++];
+
+	/* Octet 5 - Day */
+	pie->Day = IBuf[Octet++];
+
+	/*******************************************************************
+		The remaining part of the IE are optioinal, but only the length 
+		can now tell us wherever these fields are present or not
+		(always remember: IESize does not include ID and Size octet)
+	********************************************************************/
+	pie->Format = 0;
+
+	/* Octet 6 - Hour (optional)*/
+	if (IESize >= 4) {
+		pie->Format = 1;
+		pie->Hour = IBuf[Octet++];
+
+		/* Octet 7 - Minute (optional)*/
+		if (IESize >= 5) {
+			pie->Format = 2;
+			pie->Minute = IBuf[Octet++];
+
+			/* Octet 8 - Second (optional)*/
+			if (IESize >= 6) {
+				pie->Format = 3;
+				pie->Second = IBuf[Octet++];
+			}
+		}
+	}
+
+	Q931IESizeTest(Q931E_DATETIME);
+	Q931SetIE(*pIE, *OOff);
+
+	*IOff = (*IOff) + Octet + Off;
+	*OOff = (*OOff) + sizeof(Q931ie_DateTime);
+	pie->Size = sizeof(Q931ie_DateTime);
+
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Pie_DateTime
+
+  Parameters:   IBuf[IN]		Ptr to struct.
+				OBuf[OUT]		Ptr tp packed output buffer.
+				Octet[IN/OUT]	Offset into OBuf.
+
+  Return Value:	Error code, 0 = OK
+
+*****************************************************************************/
+L3INT Q931Pie_DateTime(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+	Q931ie_DateTime *pIE = (Q931ie_DateTime*)IBuf;
+	L3INT rc = 0;
+	L3INT Beg = *Octet;
+	L3INT li;
+
+	OBuf[(*Octet)++] = Q931ie_DATETIME;
+	li = (*Octet)++;
+
+	OBuf[(*Octet)++] = pIE->Year;
+	OBuf[(*Octet)++] = pIE->Month;
+	OBuf[(*Octet)++] = pIE->Day;
+	if (pIE->Format >= 1) {
+		OBuf[(*Octet)++] = pIE->Hour;
+
+		if (pIE->Format >= 2) {
+			OBuf[(*Octet)++] = pIE->Minute;
+
+			if (pIE->Format >= 3) {
+				OBuf[(*Octet)++] = pIE->Second;
+			}
+		}
+	}
+
+	OBuf[li] = (L3UCHAR)((*Octet)-Beg) - 2;
+	return rc;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Uie_Display
+
+  Parameters:   pIE[OUT]		ptr to Information Element id.
+				IBuf[IN]		ptr to a packed ie.
+				OBuf[OUT]	   ptr to buffer for Unpacked ie.
+				IOff[IN\OUT]	Input buffer offset
+				OOff[IN\OUT]	Output buffer offset
+
+				Ibuf and OBuf points directly to buffers. The IOff and OOff
+				must be updated, but are otherwise not used in the ie unpack.
+
+  Return Value: Error Message
+
+*****************************************************************************/
+L3INT Q931Uie_Display(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff)
+{
+	Q931ie_Display *pie = (Q931ie_Display*)OBuf;
+	ie *pIE = &pMsg->Display;
+	L3INT Off = 0;
+	L3INT Octet = 0;
+	L3INT IESize;
+	L3INT x;
+
+	*pIE = 0;
+
+	pie->IEId = IBuf[Octet++];
+	IESize    = IBuf[Octet++]; 
+
+	for (x = 0; x<IESize; x++) {
+		pie->Display[x] = IBuf[Octet + Off] & 0x7f;
+		Off++;
+	}
+
+	Q931IESizeTest(Q931E_DISPLAY);
+	Q931SetIE(*pIE, *OOff);
+
+	*IOff = (*IOff) + Octet + Off;
+	*OOff = (*OOff) + sizeof(Q931ie_Display) + x - 1;
+	pie->Size = (L3UCHAR)(sizeof(Q931ie_Display) + x - 1);
+
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Pie_Display
+
+  Parameters:   IBuf[IN]		Ptr to struct.
+				OBuf[OUT]		Ptr tp packed output buffer.
+				Octet[IN/OUT]	Offset into OBuf.
+
+  Return Value:	Error code, 0 = OK
+
+*****************************************************************************/
+L3INT Q931Pie_Display(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+	Q931ie_Display *pIE = (Q931ie_Display*)IBuf;
+	L3INT rc = 0;
+	L3INT Beg = *Octet;
+	L3INT li;
+	L3INT DSize;
+	L3INT x;
+
+	OBuf[(*Octet)++] = Q931ie_DISPLAY;
+	li = (*Octet)++;
+
+	DSize = pIE->Size - sizeof(Q931ie_Display);
+
+	for (x = 0; x< DSize; x++) {
+		
+		OBuf[(*Octet)++] = pIE->Display[x];
+	}
+
+	OBuf[li] = (L3UCHAR)((*Octet) - Beg) - 2;
+	return rc;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Uie_HLComp
+
+  Parameters:   pIE[OUT]		ptr to Information Element id.
+				IBuf[IN]		ptr to a packed ie.
+				OBuf[OUT]	   ptr to buffer for Unpacked ie.
+				IOff[IN\OUT]	Input buffer offset
+				OOff[IN\OUT]	Output buffer offset
+
+				Ibuf and OBuf points directly to buffers. The IOff and OOff
+				must be updated, but are otherwise not used in the ie unpack.
+
+  Return Value: Error Message
+
+*****************************************************************************/
+L3INT Q931Uie_HLComp(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff) 
+{
+	Q931ie_HLComp * pie = (Q931ie_HLComp*)OBuf;
+	ie *pIE = &pMsg->HLComp;
+	L3INT Off = 0;
+	L3INT Octet = 0;
+	L3INT IESize;
+
+	*pIE = 0;
+
+	pie->IEId = IBuf[Octet++];
+
+	/* Octet */
+	IESize = IBuf[Octet++]; 
+
+	/* Octet 3*/
+	pie->CodStand  = (IBuf[Octet + Off] >>5) & 0x03;
+	pie->Interpret = (IBuf[Octet + Off] >>2) & 0x07;
+	pie->PresMeth  =  IBuf[Octet + Off] & 0x03;
+	Octet++;
+
+	/* Octet 4 */
+	pie->HLCharID = IBuf[Octet + Off] & 0x7f;
+	Octet++;
+	
+	/* Octet 4a*/
+	if ((IBuf[Octet + Off - 1] & 0x80) == 0 && Q931MoreIE()) {
+		if (pie->HLCharID == 0x5e || pie->HLCharID == 0x5f) {
+			pie->EHLCharID = IBuf[Octet + Off] & 0x7f;
+			Off++;
+		}
+		else if ( pie->HLCharID >= 0xc3 && pie->HLCharID <= 0xcf) {
+			pie->EVideoTlfCharID = IBuf[Octet + Off] & 0x7f;
+			Off++;
+		}
+		else {
+			/* error Octet 4a indicated, but invalid value in Octet 4. */
+			Q931SetError(pTrunk,Q931E_HLCOMP, 4, Off);
+			return Q931E_HLCOMP;
+		}
+		Off = Q931ReadExt(&IBuf[Octet + Off], Off);
+	}
+
+	Q931IESizeTest(Q931E_HLCOMP);
+	Q931SetIE(*pIE, *OOff);
+
+	*IOff = (*IOff) + Octet + Off;
+	*OOff = (*OOff) + sizeof(Q931ie_HLComp);
+	pie->Size = sizeof(Q931ie_HLComp);
+
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Pie_HLComp
+
+  Parameters:   IBuf[IN]		Ptr to struct.
+				OBuf[OUT]		Ptr tp packed output buffer.
+				Octet[IN/OUT]	Offset into OBuf.
+
+  Return Value:	Error code, 0 = OK
+
+*****************************************************************************/
+L3INT Q931Pie_HLComp(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+	Q931ie_HLComp *pIE = (Q931ie_HLComp*)IBuf;
+	L3INT rc = 0;
+	L3INT Beg = *Octet;
+	L3INT li;
+
+	OBuf[(*Octet)++] = Q931ie_HIGH_LAYER_COMPATIBILITY;
+	li = (*Octet)++;
+
+	/* Octet 3 */
+	OBuf[(*Octet)++] = 0x80 | ((pIE->CodStand << 5) & 0x60) | ((pIE->Interpret << 2) & 0x1c) | (pIE->PresMeth & 0x03);
+
+	/* Octet 4 */
+	OBuf[(*Octet)++] = pIE->HLCharID;
+
+	/* Octet 4a */
+	if (pIE->HLCharID == 0x5e || pIE->HLCharID == 0x5f) {
+		OBuf[(*Octet)++] = 0x80 | (pIE->EHLCharID & 0x7f);
+	}
+	else if ( pIE->HLCharID >= 0xc3 && pIE->HLCharID <= 0xcf) {
+		OBuf[(*Octet)++] = 0x80 | (pIE->EVideoTlfCharID & 0x7f);
+	}
+	else {
+		OBuf[(*Octet) - 1] |= 0x80;
+	}
+
+	OBuf[li] = (L3UCHAR)((*Octet) - Beg) - 2;
+	return rc;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Uie_KeypadFac
+
+  Parameters:   pIE[OUT]		ptr to Information Element id.
+				IBuf[IN]		ptr to a packed ie.
+				OBuf[OUT]	   ptr to buffer for Unpacked ie.
+				IOff[IN\OUT]	Input buffer offset
+				OOff[IN\OUT]	Output buffer offset
+
+				Ibuf and OBuf points directly to buffers. The IOff and OOff
+				must be updated, but are otherwise not used in the ie unpack.
+
+  Return Value: Error Message
+
+*****************************************************************************/
+L3INT Q931Uie_KeypadFac(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff)
+{
+	Q931ie_KeypadFac *pie = (Q931ie_KeypadFac*)OBuf;
+	ie *pIE = &pMsg->KeypadFac;
+	L3INT Off = 0;
+	L3INT Octet = 0;
+	L3INT IESize;
+	L3INT x;
+
+	*pIE = 0;
+
+	pie->IEId = IBuf[Octet++];
+	IESize = IBuf[Octet++]; 
+
+	for (x = 0; x<IESize; x++) {
+		pie->KeypadFac[x] = IBuf[Octet + Off] & 0x7f;
+		Off++;
+	}
+
+	Q931IESizeTest(Q931E_KEYPADFAC);
+	Q931SetIE(*pIE, *OOff);
+
+	*IOff = (*IOff) + Octet + Off;
+	*OOff = (*OOff) + sizeof(Q931ie_KeypadFac) + x - 1;
+	pie->Size = (L3UCHAR)(sizeof(Q931ie_KeypadFac) + x - 1);
+
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Pie_KeypadFac
+
+  Parameters:   IBuf[IN]		Ptr to struct.
+				OBuf[OUT]		Ptr tp packed output buffer.
+				Octet[IN/OUT]	Offset into OBuf.
+
+  Return Value:	Error code, 0 = OK
+
+*****************************************************************************/
+L3INT Q931Pie_KeypadFac(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+	Q931ie_KeypadFac *pIE = (Q931ie_KeypadFac*)IBuf;
+	L3INT rc = 0;
+	L3INT Beg = *Octet;
+	L3INT li;
+	L3INT DSize;
+	L3INT x;
+
+	OBuf[(*Octet)++] = Q931ie_KEYPAD_FACILITY;
+	li = (*Octet)++;
+
+	DSize = pIE->Size - sizeof(Q931ie_KeypadFac) + 1;
+
+	for (x = 0; x< DSize; x++) {
+		OBuf[(*Octet)++] = pIE->KeypadFac[x];
+	}
+
+	OBuf[li] = (L3UCHAR)((*Octet) - Beg) - 2;
+	return rc;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Uie_LLComp
+
+  Parameters:   pIE[OUT]		ptr to Information Element id.
+				IBuf[IN]		ptr to a packed ie.
+				OBuf[OUT]	   ptr to buffer for Unpacked ie.
+				IOff[IN\OUT]	Input buffer offset
+				OOff[IN\OUT]	Output buffer offset
+
+				Ibuf and OBuf points directly to buffers. The IOff and OOff
+				must be updated, but are otherwise not used in the ie unpack.
+
+  Return Value: Error Message
+
+*****************************************************************************/
+L3INT Q931Uie_LLComp(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff)
+{
+	Q931ie_LLComp *pie = (Q931ie_LLComp*)OBuf;
+	ie *pIE = &pMsg->LLComp;
+	L3INT Off = 0;
+	L3INT Octet = 0;
+	L3INT IESize;
+
+	*pIE = 0;
+
+	pie->IEId = IBuf[Octet++];
+
+	/* Octet 2 */
+	IESize = IBuf[Octet++]; 
+
+	/* Octet 3 */
+	pie->CodStand  = (IBuf[Octet + Off] >> 5) & 0x03;
+	pie->ITransCap =  IBuf[Octet + Off] & 0x1f;
+	Octet++;
+
+	/* Octet 3a*/
+	if (IsQ931Ext(IBuf[Octet + Off - 1])) {
+		pie->NegotInd = (IBuf[Octet + Off] >> 6) & 0x01;
+		Off++;
+	}
+
+	/* Octet 4 */
+	pie->TransMode = (IBuf[Octet + Off] >> 5) & 0x03;
+	pie->InfoRate  =  IBuf[Octet + Off] & 0x1f;
+
+	Octet++;
+
+	/* Octet 4.1 */
+	if (pie->InfoRate == 0x14) { /* Mutirate */
+		pie->RateMul = IBuf[Octet + Off] & 0x7f;
+		Off++;
+	}
+
+	/* Octet 5 - Layer 1 Ident */
+	if ((IBuf[Octet + Off] & 0x60) == 0x20) { /* Layer 1 Ident ? */
+		pie->Layer1Ident = (IBuf[Octet + Off] >> 5) & 0x03;
+		pie->UIL1Prot    =  IBuf[Octet + Off] & 0x1f;
+		Octet++;
+
+		/* Octet 5a */
+		if (IsQ931Ext(IBuf[Octet + Off - 1])) {
+			pie->SyncAsync = (IBuf[Octet + Off] >> 6) & 0x01;
+			pie->Negot     = (IBuf[Octet + Off] >> 5) & 0x01;
+			pie->UserRate  =  IBuf[Octet + Off] & 0x1f;
+			Off++;
+
+			/* Octet 5b - 2 options */
+			if (IsQ931Ext(IBuf[Octet + Off - 1])) {
+				if (pie->UIL1Prot == 0x01) { /* V.110, I.460 and X.30*/
+					pie->InterRate = (IBuf[Octet + Off] >> 5) & 0x03;
+					pie->NIConTx   = (IBuf[Octet + Off] >> 4) & 0x01;
+					pie->NIConRx   = (IBuf[Octet + Off] >> 3) & 0x01;
+					pie->FlowCtlTx = (IBuf[Octet + Off] >> 2) & 0x01;
+					pie->FlowCtlRx = (IBuf[Octet + Off] >> 1) & 0x01;
+					Off++;
+				}
+				else if (pie->UIL1Prot == 0x80) { /* V.120 */
+					pie->HDR        = (IBuf[Octet + Off] >> 6) & 0x01;
+					pie->MultiFrame = (IBuf[Octet + Off] >> 5) & 0x01;
+					pie->ModeL1     = (IBuf[Octet + Off] >> 4) & 0x01;
+					pie->NegotLLI   = (IBuf[Octet + Off] >> 3) & 0x01;
+					pie->Assignor   = (IBuf[Octet + Off] >> 2) & 0x01;
+					pie->InBandNeg  = (IBuf[Octet + Off] >> 1) & 0x01;
+					Off++;
+				}
+				else if (pie->UIL1Prot == 0x07) { /* non standard */
+					Off = Q931ReadExt(&IBuf[Octet + Off], Off);
+					Off++;
+				}
+				else {
+					Q931SetError(pTrunk,Q931E_LLCOMP, 5,2);
+					return Q931E_LLCOMP;
+				}
+
+				/* Octet 5c */
+				if (IsQ931Ext(IBuf[Octet + Off - 1])) {
+					pie->NumStopBits = (IBuf[Octet + Off] >> 5) & 0x03;
+					pie->NumDataBits = (IBuf[Octet + Off] >> 3) & 0x03;
+					pie->Parity      =  IBuf[Octet + Off] & 0x07;
+					Off++;
+
+					/* Octet 5d */
+					if (IsQ931Ext(IBuf[Octet + Off - 1])) {
+						pie->DuplexMode	= (IBuf[Octet + Off] >> 6) & 0x01;
+						pie->ModemType  =  IBuf[Octet + Off] & 0x3f;
+						Off = Q931ReadExt(&IBuf[Octet + Off], Off);
+						Off++;
+					}
+				}
+			}
+		}
+	}
+
+	/* Octet 6 - Layer 2 Ident */
+	if ((IBuf[Octet + Off] & 0x60) == 0x40) { /* Layer 1 Ident ? */
+		pie->Layer2Ident = (IBuf[Octet + Off] >>5) & 0x03;
+		pie->UIL2Prot    =  IBuf[Octet + Off] & 0x1f;
+		Octet++;
+
+		/* Octet 6a */
+		if (IsQ931Ext(IBuf[Octet + Off - 1])) {
+			if (pie->UIL2Prot == 0x10) { /* 2nd 6a */
+				pie->UsrSpcL2Prot = IBuf[Octet + Off] & 0x7f;
+				Off++;
+			}
+			else { /* assume 1st 6a */
+				pie->ModeL2  = (IBuf[Octet + Off] >> 5) & 0x03;
+				pie->Q933use =  IBuf[Octet + Off] & 0x03;
+				Off++;
+			}
+			/* Octet 6b */
+			if (IsQ931Ext(IBuf[Octet + Off - 1])) {
+				pie->WindowSize = IBuf[Octet + Off] & 0x7f;
+				Off++;
+			}
+		}
+	}
+
+	/* Octet 7 - layer 3 Ident */
+	if ((IBuf[Octet + Off] & 0x60) == 0x60) { /* Layer 3 Ident ? */
+		pie->Layer3Ident = (IBuf[Octet + Off] >> 5) & 0x03;
+		pie->UIL3Prot    =  IBuf[Octet + Off] & 0x1f;
+		Octet++;
+
+		/* Octet 7a */
+		if (IsQ931Ext(IBuf[Octet + Off - 1])) {
+			if (pie->UIL3Prot == 0x0b) {
+				/* Octet 7a + 7b AddL3Info */
+				pie->AddL3Info = ((IBuf[Octet + Off] << 4) & 0xf0)
+								| (IBuf[Octet + Off + 1] & 0x0f);
+				Off += 2;
+			}
+			else {
+				if (pie->UIL3Prot == 0x1f) {
+					pie->ModeL3 = (IBuf[Octet + Off] >> 5) & 0x03;
+					Off++;
+				}
+				else {
+					pie->OptL3Info = IBuf[Octet + Off] & 0x7f;
+					Off++;
+				}
+
+				/* Octet 7b*/
+				if (IsQ931Ext(IBuf[Octet + Off - 1])) {
+					pie->DefPackSize = IBuf[Octet + Off] & 0x0f;
+					Off++;
+
+					/* Octet 7c */
+					if (IsQ931Ext(IBuf[Octet + Off - 1])) {
+						pie->PackWinSize= IBuf[Octet + Off] & 0x7f;
+					}
+				}
+			}
+		}
+	}
+
+	Q931IESizeTest(Q931E_LLCOMP);
+	Q931SetIE(*pIE, *OOff);
+
+	*IOff = (*IOff) + Octet + Off;
+	*OOff = (*OOff) + sizeof(Q931ie_LLComp);
+	pie->Size = sizeof(Q931ie_LLComp);
+
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Pie_LLComp
+
+  Parameters:   IBuf[IN]		Ptr to struct.
+				OBuf[OUT]		Ptr tp packed output buffer.
+				Octet[IN/OUT]	Offset into OBuf.
+
+  Return Value: Error code, 0 = OK
+
+*****************************************************************************/
+L3INT Q931Pie_LLComp(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+	Q931ie_LLComp *pIE = (Q931ie_LLComp*)IBuf;
+	L3INT rc = 0;
+	L3INT Beg = *Octet;
+	L3INT li;
+
+	OBuf[(*Octet)++] = Q931ie_LOW_LAYER_COMPATIBILITY;
+	li = (*Octet)++;
+
+	/* Octet 3 */
+	OBuf[(*Octet)++] = (pIE->CodStand << 6) | pIE->ITransCap;
+
+	/* Octet 3a */
+	OBuf[(*Octet)++] = 0x80 | (pIE->NegotInd << 6);
+
+	/* Octet 4 */
+	OBuf[(*Octet)++] = 0x80 | (pIE->TransMode << 5) | pIE->InfoRate;
+
+	/* Octet 4.1 */
+	if (pIE->InfoRate == 0x18) {
+		OBuf[(*Octet)++] = 0x80 | pIE->RateMul;
+	}
+
+	/* Octet 5 */
+	if (pIE->Layer1Ident == 0x01) {
+		OBuf[(*Octet)++] = (pIE->Layer1Ident << 5) | pIE->UIL1Prot;
+		
+		/* Octet 5a */
+		if ((pIE->ITransCap == 0x08 && (pIE->UIL1Prot == 0x01 || pIE->UIL1Prot == 0x08))
+			|| (pIE->ITransCap == 0x10 && (pIE->UIL1Prot == 0x02 || pIE->UIL1Prot == 0x03))) {
+			OBuf[(*Octet)++] = (pIE->SyncAsync<<6) | (pIE->Negot<<5) | pIE->UserRate;
+			
+			/* Octet 5b*/
+			if (pIE->UIL1Prot == 0x01) {
+				OBuf[(*Octet)++] =  (pIE->InterRate << 5)
+							| (pIE->NIConTx << 4)
+							| (pIE->NIConTx << 3)
+							| (pIE->FlowCtlTx << 2)
+							| (pIE->FlowCtlRx << 1);
+			}
+			else if (pIE->UIL1Prot == 0x08) {
+				OBuf[(*Octet)++] =  (pIE->HDR << 6)
+							| (pIE->MultiFrame << 5)
+							| (pIE->ModeL1 << 4)
+							| (pIE->NegotLLI << 3)
+							| (pIE->Assignor << 2)
+							| (pIE->InBandNeg << 1);
+			}
+			else {
+				OBuf[(*Octet) - 1] |= 0x80;
+			}
+
+			/* How to detect wherever 5c and 5d is to present is not clear
+			 * but they have been inculded as 'standard'
+			 * Octet 5c
+			 */
+			if (pIE->UIL1Prot == 0x01 || pIE->UIL1Prot == 0x08) {
+				OBuf[(*Octet)++] = (pIE->NumStopBits << 5) | (pIE->NumDataBits << 3) | pIE->Parity ;
+
+				/* Octet 5d */
+				OBuf[(*Octet)++] = 0x80 | (pIE->DuplexMode << 6) | pIE->ModemType;
+			}
+		}
+		else {
+			OBuf[(*Octet) - 1] |= 0x80;
+		}
+	}
+
+	/* Octet 6 */
+	if (pIE->Layer2Ident == 0x02) {
+		OBuf[(*Octet)++] = (pIE->Layer2Ident << 5) | pIE->UIL2Prot;
+
+		/* Octet 6a*/
+		if (pIE->UIL2Prot == 0x02 /* Q.921/I.441 */
+		|| pIE->UIL2Prot == 0x06 /* X.25 link layer */
+		|| pIE->UIL2Prot == 0x07 /* X.25 multilink */
+		|| pIE->UIL2Prot == 0x09 /* HDLC ARM */
+		|| pIE->UIL2Prot == 0x0a /* HDLC NRM */
+		|| pIE->UIL2Prot == 0x0b /* HDLC ABM */
+		|| pIE->UIL2Prot == 0x0d /* X.75 SLP */
+		|| pIE->UIL2Prot == 0x0e /* Q.922 */
+		|| pIE->UIL2Prot == 0x11) { /* ISO/ECE 7776 DTE-DCE */
+			OBuf[(*Octet)++] = (pIE->ModeL2 << 5) | pIE->Q933use;
+
+			/* Octet 6b */
+			OBuf[(*Octet)++] = 0x80 | pIE->WindowSize;
+		}
+		else if (pIE->UIL2Prot == 0x10) { /* User Specific */
+			OBuf[(*Octet)++] = 0x80 | pIE->UsrSpcL2Prot;
+		}
+		else {
+			OBuf[(*Octet) - 1] |= 0x80;
+		}
+	}
+
+	/* Octet 7 */
+	if (pIE->Layer3Ident == 0x03) {
+		OBuf[(*Octet)++] = (pIE->Layer3Ident << 5) | pIE->UIL3Prot;
+
+		/* Octet 7a - 3 different ones */
+		if (pIE->UIL3Prot == 0x10) {
+			OBuf[(*Octet++)] = 0x80 | pIE->OptL3Info;
+		}
+		else if (pIE->UIL3Prot == 0x06
+			||  pIE->UIL3Prot == 0x07
+			||  pIE->UIL3Prot == 0x08) {
+			OBuf[(*Octet)++] = pIE->ModeL3 << 5;
+
+			/* Octet 7b note 7 */
+			OBuf[(*Octet)++] = pIE->DefPackSize;
+
+			/* Octet 7c note 7 */
+			OBuf[(*Octet)++] = 0x80 | pIE->PackWinSize;
+		}
+		else if (pIE->UIL3Prot == 0x0b) {
+			OBuf[(*Octet)++] = (pIE->AddL3Info >> 4) & 0x0f;
+			OBuf[(*Octet)++] = 0x80 | (pIE->AddL3Info & 0x0f);
+		}
+		else {
+			OBuf[(*Octet) - 1] |= 0x80;
+		}
+	}
+	else {
+		Q931SetError(pTrunk,Q931E_LLCOMP, 7,0);
+		rc = Q931E_LLCOMP;
+	}
+
+	OBuf[li] = (L3UCHAR)((*Octet) - Beg) - 2;
+	return rc;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Uie_NetFac
+
+  Parameters:   pIE[OUT]		ptr to Information Element id.
+				IBuf[IN]		ptr to a packed ie.
+				OBuf[OUT]	   ptr to buffer for Unpacked ie.
+				IOff[IN\OUT]	Input buffer offset
+				OOff[IN\OUT]	Output buffer offset
+
+				Ibuf and OBuf points directly to buffers. The IOff and OOff
+				must be updated, but are otherwise not used in the ie unpack.
+
+  Return Value: Error Message
+
+*****************************************************************************/
+L3INT Q931Uie_NetFac(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff)
+{
+	Q931ie_NetFac *pie = (Q931ie_NetFac*)OBuf;
+	ie *pIE = &pMsg->NetFac;
+	L3INT Off = 0;
+	L3INT Octet = 0;
+	L3INT x = 0;
+	L3INT IESize;
+
+	*pIE = 0;
+
+	pie->IEId = IBuf[Octet++];
+
+	/* Octet 2 */
+	IESize = IBuf[Octet++]; 
+
+	pie->LenNetID = IBuf[Octet + Off]; /* full octet is used */
+	Octet++;
+
+	if (pie->LenNetID > 0) {
+		/* Octet 3.1 */
+		pie->TypeNetID = (IBuf[Octet + Off] >> 4) & 0x0f;
+		pie->NetIDPlan =  IBuf[Octet + Off] & 0x0f;
+		Off = Q931ReadExt(&IBuf[Octet], Off);
+		Off++;
+
+		/* Octet 3.2*/
+		for (x = 0; x < pie->LenNetID; x++) {
+			pie->NetID[x] = IBuf[Octet + Off] & 0x7f;
+			Off++;
+		}
+	}
+
+	/* Octet 4*/
+	pie->NetFac = IBuf[Octet + Off]; /* Full Octet is used */
+	Octet++;
+
+	Q931IESizeTest(Q931E_NETFAC);
+	Q931SetIE(*pIE, *OOff);
+
+	*IOff = (*IOff) + Octet + Off;
+	*OOff = (*OOff) + sizeof(Q931ie_NetFac) + x - 1;
+	pie->Size = (L3UCHAR)(sizeof(Q931ie_NetFac) + x - 1);
+
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Pie_NetFac
+
+  Parameters:   IBuf[IN]		Ptr to struct.
+				OBuf[OUT]		Ptr tp packed output buffer.
+				Octet[IN/OUT]	Offset into OBuf.
+
+  Return Value:	Error code, 0 = OK
+
+*****************************************************************************/
+L3INT Q931Pie_NetFac(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+	Q931ie_NetFac *pIE = (Q931ie_NetFac*)IBuf;
+	L3INT rc = Q931E_NO_ERROR;
+	L3INT Beg = *Octet;
+	L3INT li;
+	L3INT x;
+
+	OBuf[(*Octet)++] = Q931ie_NETWORK_SPECIFIC_FACILITIES;
+	li = (*Octet)++;
+
+	/* Octet 3 */
+	OBuf[(*Octet)++] = pIE->LenNetID;
+
+	if (pIE->LenNetID > 0) {
+		/* Octet 3.1 */
+		OBuf[(*Octet)++] = 0x80 | (pIE->TypeNetID << 4) | pIE->NetIDPlan;
+
+		/* Octet 3.2 */
+		for (x = 0; x <pIE->LenNetID; x++) {
+			OBuf[(*Octet)++] = pIE->NetID[x];
+		}
+	}
+
+	/* Octet 4 */
+	OBuf[(*Octet)++] = pIE->NetFac;
+
+	OBuf[li] = (L3UCHAR)((*Octet) - Beg) - 2;
+	return rc;
+}
+
+/*****************************************************************************
+
+  Function:		Q931Uie_NotifInd
+
+  Parameters:   pIE[OUT]		ptr to Information Element id.
+				IBuf[IN]		ptr to a packed ie.
+				OBuf[OUT]	   ptr to buffer for Unpacked ie.
+				IOff[IN\OUT]	Input buffer offset
+				OOff[IN\OUT]	Output buffer offset
+
+				Ibuf and OBuf points directly to buffers. The IOff and OOff
+				must be updated, but are otherwise not used in the ie unpack.
+
+  Return Value: Error Message
+
+*****************************************************************************/
+L3INT Q931Uie_NotifInd(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff)
+{
+	Q931ie_NotifInd *pie = (Q931ie_NotifInd*)OBuf;
+	ie *pIE = &pMsg->NotifInd;
+	L3INT Off = 0;
+	L3INT Octet = 0;
+	L3INT IESize;
+
+	*pIE = 0;
+
+	pie->IEId = IBuf[Octet++];
+
+	/* Octet 2*/
+	IESize = IBuf[Octet++]; 
+
+	/* Octet 3 */
+	pie->Notification = IBuf[Octet + Off] & 0x7f;
+
+	Off = Q931ReadExt(&IBuf[Octet], Off);
+	Octet++;
+
+	Q931IESizeTest(Q931E_NOTIFIND);
+	Q931SetIE(*pIE, *OOff);
+
+	*IOff = (*IOff) + Octet + Off;
+	*OOff = (*OOff) + sizeof(Q931ie_NotifInd);
+	pie->Size = sizeof(Q931ie_NotifInd);
+
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Pie_NotifInd
+
+  Parameters:   IBuf[IN]		Ptr to struct.
+				OBuf[OUT]		Ptr tp packed output buffer.
+				Octet[IN/OUT]	Offset into OBuf.
+
+  Return Value:	Error code, 0 = OK
+
+*****************************************************************************/
+L3INT Q931Pie_NotifInd(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+	Q931ie_NotifInd *pIE = (Q931ie_NotifInd*)IBuf;
+	L3INT rc = Q931E_NO_ERROR;
+	L3INT Beg = *Octet;
+	L3INT li;
+
+	OBuf[(*Octet)++] = Q931ie_NOTIFICATION_INDICATOR;
+	li = (*Octet)++;
+
+	/* Octet 3 */
+	OBuf[(*Octet)++] = pIE->Notification;
+
+	OBuf[li] = (L3UCHAR)((*Octet) - Beg) - 2;
+	return rc;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Uie_ProgInd
+
+  Parameters:   pIE[OUT]		ptr to Information Element id.
+				IBuf[IN]		ptr to a packed ie.
+				OBuf[OUT]	   ptr to buffer for Unpacked ie.
+				IOff[IN\OUT]	Input buffer offset
+				OOff[IN\OUT]	Output buffer offset
+
+				Ibuf and OBuf points directly to buffers. The IOff and OOff
+				must be updated, but are otherwise not used in the ie unpack.
+
+  Return Value: Error Message
+
+*****************************************************************************/
+L3INT Q931Uie_ProgInd(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff)
+{
+	Q931ie_ProgInd *pie = (Q931ie_ProgInd*)OBuf;
+	ie *pIE = &pMsg->ProgInd;
+	L3INT Off = 0;
+	L3INT Octet = 0;
+	L3INT IESize;
+
+	*pIE = 0;
+
+	pie->IEId = IBuf[Octet++];
+
+	/* Octet 2 */
+	IESize = IBuf[Octet++]; 
+
+	/* Octet 3 */
+	pie->CodStand = (IBuf[Octet + Off] >> 5) & 0x03;
+	pie->Location =  IBuf[Octet + Off] & 0x0f;
+
+	Off = Q931ReadExt(&IBuf[Octet], Off);
+	Octet++;
+
+	/* Octet 4 */
+	pie->ProgDesc = IBuf[Octet + Off] & 0x7f;
+	Off = Q931ReadExt(&IBuf[Octet], Off);
+	Octet++;
+
+	Q931IESizeTest(Q931E_PROGIND);
+	Q931SetIE(*pIE, *OOff);
+
+	*IOff = (*IOff) + Octet + Off;
+	*OOff = (*OOff) + sizeof(Q931ie_ProgInd);
+	pie->Size = sizeof(Q931ie_ProgInd);
+
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Pie_ProgInd
+
+  Parameters:   IBuf[IN]		Ptr to struct.
+				OBuf[OUT]	   Ptr tp packed output buffer.
+				Octet[IN/OUT]   Offset L3INTo OBuf.
+
+  Return Value: Error code, 0 = OK
+
+*****************************************************************************/
+L3INT Q931Pie_ProgInd(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+	Q931ie_ProgInd *pIE = (Q931ie_ProgInd*)IBuf;
+	L3INT rc = Q931E_NO_ERROR;
+	L3INT Beg = *Octet;
+	L3INT li;
+
+	OBuf[(*Octet)++] = Q931ie_PROGRESS_INDICATOR;
+	li = (*Octet)++;
+
+	/* Octet 3 */
+	OBuf[(*Octet)++] = 0x80 | (pIE->CodStand << 5) | pIE->Location;
+
+	/* Octet 4 */
+	OBuf[(*Octet)++] = 0x80 | pIE->ProgDesc;
+
+	OBuf[li] = (L3UCHAR)((*Octet) - Beg) - 2;
+	return rc;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Uie_RepeatInd
+
+  Parameters:   pIE[OUT]		ptr to Information Element id.
+				IBuf[IN]		ptr to a packed ie.
+				OBuf[OUT]	   ptr to buffer for Unpacked ie.
+				IOff[IN\OUT]	Input buffer offset
+				OOff[IN\OUT]	Output buffer offset
+
+				Ibuf and OBuf points directly to buffers. The IOff and OOff
+				must be updated, but are otherwise not used in the ie unpack.
+
+  Return Value: Error Message
+
+*****************************************************************************/
+L3INT Q931Uie_RepeatInd(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff)
+{
+	Q931ie_RepeatInd *pie = (Q931ie_RepeatInd*)OBuf;
+	ie *pIE = &pMsg->RepeatInd;
+	L3INT Off = 0;
+	L3INT Octet = 0;
+
+	*pIE = 0;
+
+	pie->IEId      = IBuf[Octet] & 0xf0;
+	pie->RepeatInd = IBuf[Octet] & 0x0f;
+	Octet ++;
+
+	Q931SetIE(*pIE, *OOff);
+
+	*IOff = (*IOff) + Octet + Off;
+	*OOff = (*OOff) + sizeof(Q931ie_RepeatInd);
+	pie->Size = sizeof(Q931ie_RepeatInd);
+
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Pie_RepeatInd
+
+  Parameters:   IBuf[IN]		Ptr to struct.
+				OBuf[OUT]		Ptr tp packed output buffer.
+				Octet[IN/OUT]	Offset into OBuf.
+
+  Return Value:	Error code, 0 = OK
+
+*****************************************************************************/
+L3INT Q931Pie_RepeatInd(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+	Q931ie_RepeatInd *pIE = (Q931ie_RepeatInd*)IBuf;
+	L3INT rc = 0;
+	/* L3INT Beg = *Octet; */
+
+	OBuf[(*Octet)++] = Q931ie_REPEAT_INDICATOR | pIE->RepeatInd;
+
+	return rc;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Uie_RevChargeInd
+
+  Parameters:   pIE[OUT]		ptr to Information Element id.
+				IBuf[IN]		ptr to a packed ie.
+				OBuf[OUT]	   ptr to buffer for Unpacked ie.
+				IOff[IN\OUT]	Input buffer offset
+				OOff[IN\OUT]	Output buffer offset
+
+				Ibuf and OBuf points directly to buffers. The IOff and OOff
+				must be updated, but are otherwise not used in the ie unpack.
+
+  Return Value: Error Message
+
+*****************************************************************************/
+L3INT Q931Uie_RevChargeInd(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff)
+{
+	ie iE;
+	/* ie *pIE = &pMsg->RevChargeInd; */
+	Q931SetIE(iE, *OOff);
+
+	return iE;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Pie_RevChargeInd
+
+  Parameters:   IBuf[IN]		Ptr to struct.
+				OBuf[OUT]		Ptr tp packed output buffer.
+				Octet[IN/OUT]	Offset into OBuf.
+
+  Return Value:	Error code, 0 = OK
+
+*****************************************************************************/
+L3INT Q931Pie_RevChargeInd(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+	L3BOOL RetCode = L3FALSE;
+
+	NoWarning(OBuf);
+	NoWarning(IBuf);
+
+	return RetCode;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Uie_RestartInd
+
+  Parameters:   pIE[OUT]		ptr to Information Element id.
+				IBuf[IN]		ptr to a packed ie.
+				OBuf[OUT]	   ptr to buffer for Unpacked ie.
+				IOff[IN\OUT]	Input buffer offset
+				OOff[IN\OUT]	Output buffer offset
+
+				Ibuf and OBuf points directly to buffers. The IOff and OOff
+				must be updated, but are otherwise not used in the ie unpack.
+
+  Return Value: Error Message
+
+*****************************************************************************/
+L3INT Q931Uie_RestartInd(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff)
+{
+	Q931ie_RestartInd *pie = (Q931ie_RestartInd*)OBuf;
+	ie *pIE = &pMsg->RestartInd;
+	L3INT Off = 0;
+	L3INT Octet = 0;
+	L3INT IESize;
+
+	*pIE = 0;
+
+	pie->IEId = IBuf[Octet++];
+
+	/* Octet 2 */
+	IESize = IBuf[Octet++]; 
+
+	/* Octet 3 */
+	pie->Class = IBuf[Octet + Off] & 0x07;
+	pie->Spare = IBuf[Octet + Off] & 0x78;
+
+	Off = Q931ReadExt(&IBuf[Octet], Off);
+	Octet++;
+
+	Q931IESizeTest(Q931E_RESTARTIND);
+	Q931SetIE(*pIE, *OOff);
+
+	*IOff = (*IOff) + Octet + Off;
+	*OOff = (*OOff) + sizeof(Q931ie_RestartInd);
+	pie->Size = sizeof(Q931ie_RestartInd);
+
+
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Pie_RestartInd
+
+  Parameters:   IBuf[IN]		Ptr to struct.
+				OBuf[OUT]		Ptr tp packed output buffer.
+				Octet[IN/OUT]	Offset into OBuf.
+
+  Return Value:	Error code, 0 = OK
+
+*****************************************************************************/
+L3INT Q931Pie_RestartInd(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+	Q931ie_RestartInd *pIE = (Q931ie_RestartInd*)IBuf;
+	L3INT rc = Q931E_NO_ERROR;
+	L3INT Beg = *Octet;
+	L3INT li;
+
+	OBuf[(*Octet)++] = Q931ie_RESTART_INDICATOR;
+	li = (*Octet)++;
+
+	/* Octet 3*/
+	OBuf[(*Octet)++] = 0x80 | pIE->Class ;
+
+	OBuf[li] = (L3UCHAR)((*Octet) - Beg) - 2;
+	return rc;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Uie_Segment
+
+  Parameters:   pIE[OUT]		ptr to Information Element id.
+				IBuf[IN]		ptr to a packed ie.
+				OBuf[OUT]	   ptr to buffer for Unpacked ie.
+				IOff[IN\OUT]	Input buffer offset
+				OOff[IN\OUT]	Output buffer offset
+
+				Ibuf and OBuf points directly to buffers. The IOff and OOff
+				must be updated, but are otherwise not used in the ie unpack.
+
+  Return Value: Error Message
+
+*****************************************************************************/
+L3INT Q931Uie_Segment(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff)
+{
+	Q931ie_Segment *pie = (Q931ie_Segment*)OBuf;
+	ie *pIE = &pMsg->Segment;
+	L3INT Off = 0;
+	L3INT Octet = 0;
+	L3INT IESize;
+
+	*pIE = 0;
+
+	pie->IEId = IBuf[Octet++];
+	Octet++;
+
+	/* Octet 2*/
+	IESize = IBuf[Octet++]; 
+
+	/* Octet 3 */
+	pie->FSI       = (IBuf[Octet + Off] & 0x80) >> 7;
+	pie->NumSegRem =  IBuf[Octet + Off] & 0x7f;
+	Octet++;
+
+	/* Octet 4 */
+	pie->SegType = IBuf[Octet + Off] & 0x7f;
+	Octet++;
+	
+	Q931IESizeTest(Q931E_SEGMENT);
+	Q931SetIE(*pIE, *OOff);
+
+	*IOff = (*IOff) + Octet + Off;
+	*OOff = (*OOff) + sizeof(Q931ie_Segment);
+	pie->Size = sizeof(Q931ie_Segment);
+
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Pie_Segment
+
+  Parameters:   IBuf[IN]		Ptr to struct.
+				OBuf[OUT]		Ptr tp packed output buffer.
+				Octet[IN/OUT]	Offset into OBuf.
+
+  Return Value:	Error code, 0 = OK
+
+*****************************************************************************/
+L3INT Q931Pie_Segment(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+	Q931ie_Segment *pIE = (Q931ie_Segment*)IBuf;
+	L3INT rc = Q931E_NO_ERROR;
+	L3INT Beg = *Octet;
+	L3INT li;
+
+	OBuf[(*Octet)++] = Q931ie_SEGMENTED_MESSAGE;
+	li = (*Octet)++;
+
+	/* Octet 3 */
+	OBuf[(*Octet)++] = (pIE->FSI << 7) | pIE->NumSegRem;
+
+	/* Octet 4 */
+	OBuf[(*Octet)++] = pIE->SegType;
+
+	OBuf[li] = (L3UCHAR)((*Octet) - Beg) - 2;
+	return rc;
+}
+
+/*****************************************************************************
+
+  Function:		Q931Uie_SendComplete
+
+  Parameters:   pIE[OUT]		ptr to Information Element id.
+				IBuf[IN]		ptr to a packed ie.
+				OBuf[OUT]	   ptr to buffer for Unpacked ie.
+				IOff[IN\OUT]	Input buffer offset
+				OOff[IN\OUT]	Output buffer offset
+
+				Ibuf and OBuf points directly to buffers. The IOff and OOff
+				must be updated, but are otherwise not used in the ie unpack.
+
+  Return Value: Error Message
+
+*****************************************************************************/
+L3INT Q931Uie_SendComplete(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff)
+{
+	Q931ie_SendComplete *pie = (Q931ie_SendComplete*)OBuf;
+	ie *pIE = &pMsg->SendComplete;
+	L3INT Off = 0;
+	L3INT Octet = 0;
+
+	*pIE = 0;
+	Octet++;
+
+	Q931SetIE(*pIE, *OOff);
+
+	*IOff = (*IOff) + Octet + Off;
+	*OOff = (*OOff) + sizeof(Q931ie_SendComplete);
+	pie->Size = sizeof(Q931ie_SendComplete);
+
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Pie_ProgInd
+
+  Parameters:   IBuf[IN]		Ptr to struct.
+				OBuf[OUT]	   Ptr tp packed output buffer.
+				Octet[IN/OUT]   Offset into OBuf.
+
+  Return Value: Error code, 0 = OK
+
+*****************************************************************************/
+L3INT Q931Pie_SendComplete(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+	/* Q931ie_SendComplete * pIE = (Q931ie_SendComplete*)IBuf; */
+	L3INT rc = Q931E_NO_ERROR;
+	/* L3INT Beg = *Octet; */
+
+	OBuf[(*Octet)++] = 0x80 | (L3UCHAR)Q931ie_SENDING_COMPLETE;
+
+	return rc;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Uie_Signal
+
+  Parameters:   pIE[OUT]		ptr to Information Element id.
+				IBuf[IN]		ptr to a packed ie.
+				OBuf[OUT]	   ptr to buffer for Unpacked ie.
+				IOff[IN\OUT]	Input buffer offset
+				OOff[IN\OUT]	Output buffer offset
+
+				Ibuf and OBuf points directly to buffers. The IOff and OOff
+				must be updated, but are otherwise not used in the ie unpack.
+
+  Return Value: Error Message
+
+*****************************************************************************/
+L3INT Q931Uie_Signal(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff)
+{
+	Q931ie_Signal *pie = (Q931ie_Signal*)OBuf;
+	ie *pIE = &pMsg->Signal;
+	L3INT Off = 0;
+	L3INT Octet = 0;
+	L3INT IESize;
+
+	*pIE = 0;
+
+	pie->IEId = IBuf[Octet++];
+
+	/* Octet 2 */
+	IESize = IBuf[Octet++]; 
+
+	/* Octet 3 */
+	pie->Signal = IBuf[Octet + Off];
+	Octet++;
+
+	Q931IESizeTest(Q931E_SIGNAL);
+	Q931SetIE(*pIE, *OOff);
+
+	*IOff = (*IOff) + Octet + Off;
+	*OOff = (*OOff) + sizeof(Q931ie_Signal);
+	pie->Size = sizeof(Q931ie_Signal);
+
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Pie_Signal
+
+  Parameters:   IBuf[IN]		Ptr to struct.
+				OBuf[OUT]		Ptr tp packed output buffer.
+				Octet[IN/OUT]	Offset into OBuf.
+
+  Return Value:	Error code, 0 = OK
+
+*****************************************************************************/
+L3INT Q931Pie_Signal(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+	Q931ie_Signal *pIE = (Q931ie_Signal*)IBuf;
+	L3INT rc = Q931E_NO_ERROR;
+	L3INT Beg = *Octet;
+	L3INT li;
+
+	OBuf[(*Octet)++] = Q931ie_SIGNAL;
+	li = (*Octet)++;
+
+	/* Octet 3 */
+	OBuf[(*Octet)++] = pIE->Signal;
+
+	OBuf[li] = (L3UCHAR)((*Octet) - Beg) - 2;
+	return rc;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Uie_TransNetSel
+
+  Parameters:   pIE[OUT]		ptr to Information Element id.
+				IBuf[IN]		ptr to a packed ie.
+				OBuf[OUT]	   ptr to buffer for Unpacked ie.
+				IOff[IN\OUT]	Input buffer offset
+				OOff[IN\OUT]	Output buffer offset
+
+				Ibuf and OBuf points directly to buffers. The IOff and OOff
+				must be updated, but are otherwise not used in the ie unpack.
+
+  Return Value: Error Message
+
+*****************************************************************************/
+L3INT Q931Uie_TransNetSel(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff)
+{
+	Q931ie_TransNetSel *pie = (Q931ie_TransNetSel*)OBuf;
+	ie *pIE = &pMsg->TransNetSel;
+	L3INT Off = 0;
+	L3INT Octet = 0;
+	L3INT x = 0;
+	L3INT l;
+
+	*pIE = 0;
+
+	pie->IEId = IBuf[Octet++];
+
+	/* Octet 2 */
+	l = IBuf[Octet++] - 3; 
+
+	/* Octet 3 */
+	pie->Type = (IBuf[Octet + Off] >> 4) & 0x07;
+
+	Off = Q931ReadExt(&IBuf[Octet], Off);
+	Octet++;
+
+	for (x = 0; x < l; x++) {
+		pie->NetID[x] = IBuf[Octet + Off] & 0x7f;
+		Off++;
+	}
+
+	Q931SetIE(*pIE, *OOff);
+
+	*IOff = (*IOff) + Octet + Off;
+	*OOff = (*OOff) + sizeof(Q931ie_TransNetSel) + x - 1;
+	pie->Size = (L3UCHAR)(sizeof(Q931ie_TransNetSel) + x - 1);
+
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Pie_TransNetSel
+
+  Parameters:   IBuf[IN]		Ptr to struct.
+				OBuf[OUT]		Ptr tp packed output buffer.
+				Octet[IN/OUT]	Offset into OBuf.
+
+  Return Value:	Error code, 0 = OK
+
+*****************************************************************************/
+L3INT Q931Pie_TransNetSel(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+	Q931ie_TransNetSel *pIE = (Q931ie_TransNetSel*)IBuf;
+	L3INT rc = Q931E_NO_ERROR;
+	L3INT Beg = *Octet;
+	L3INT li;
+	L3INT x;
+	L3INT l;
+
+	OBuf[(*Octet)++] = Q931ie_TRANSIT_NETWORK_SELECTION;
+	li = (*Octet)++;
+
+	/* Octet 3 */
+	OBuf[(*Octet)++] = 0x80 | (pIE->Type << 4) | pIE->NetIDPlan;
+
+	/* Octet 4 */
+	l = pIE->Size - sizeof(Q931ie_TransNetSel) + 1;
+	for (x = 0; x < l; x++) {
+		OBuf[(*Octet)++] = pIE->NetID[x];
+	}
+
+	OBuf[li] = (L3UCHAR)((*Octet) - Beg) - 2;
+	return rc;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Uie_UserUser
+
+  Parameters:   pIE[OUT]		ptr to Information Element id.
+				IBuf[IN]		ptr to a packed ie.
+				OBuf[OUT]	   ptr to buffer for Unpacked ie.
+				IOff[IN\OUT]	Input buffer offset
+				OOff[IN\OUT]	Output buffer offset
+
+				Ibuf and OBuf points directly to buffers. The IOff and OOff
+				must be updated, but are otherwise not used in the ie unpack.
+
+  Return Value: Error Message
+
+*****************************************************************************/
+L3INT Q931Uie_UserUser(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff)
+{
+	Q931ie_UserUser *pie = (Q931ie_UserUser*)OBuf;
+	ie *pIE = &pMsg->UserUser;
+	L3INT Off = 0;
+	L3INT Octet = 0;
+	L3INT l;
+
+	*pIE = 0;
+
+	pie->IEId = IBuf[Octet++];
+
+	/* Octet 2 */
+	l = IBuf[Octet++] - 1;
+
+	/* Octet 3 */
+	pie->ProtDisc = IBuf[Octet++];
+
+	for (Off = 0; Off < l; Off++) {
+		pie->User[Off] = IBuf[Octet + Off];
+	}
+
+	Q931SetIE(*pIE, *OOff);
+
+	*IOff = (*IOff) + Octet + Off;
+	*OOff = (*OOff) + sizeof(Q931ie_UserUser) + Off - 1;
+	pie->Size = (L3UCHAR)(sizeof(Q931ie_UserUser) + Off - 1);
+
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Pie_UserUser
+
+  Parameters:   IBuf[IN]		Ptr to struct.
+				OBuf[OUT]		Ptr tp packed output buffer.
+				Octet[IN/OUT]	Offset into OBuf.
+
+  Return Value:	Error code, 0 = OK
+
+*****************************************************************************/
+L3INT Q931Pie_UserUser(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+	Q931ie_UserUser *pIE = (Q931ie_UserUser*)IBuf;
+	L3INT rc = Q931E_NO_ERROR;
+	L3INT Beg = *Octet;
+	L3INT li;
+	L3INT x;
+	L3INT l;
+
+	OBuf[(*Octet)++] = Q931ie_USER_USER;
+	li = (*Octet)++;
+
+	/* Octet 3 */
+	OBuf[(*Octet)++] = pIE->ProtDisc;
+
+	/* Octet 4 */
+	l = pIE->Size - sizeof(Q931ie_UserUser) + 1;
+	for (x = 0; x < l; x++) {
+		OBuf[(*Octet)++] = pIE->User[x];
+	}
+
+	OBuf[li] = (L3UCHAR)((*Octet) - Beg) - 2;
+	return rc;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Uie_GenericDigits
+
+  Parameters:   pIE[OUT]		ptr to Information Element id.
+				IBuf[IN]		ptr to a packed ie.
+				OBuf[OUT]	   ptr to buffer for Unpacked ie.
+				IOff[IN\OUT]	Input buffer offset
+				OOff[IN\OUT]	Output buffer offset
+
+
+				Ibuf and OBuf points directly to buffers. The IOff and OOff
+				must be updated, but are otherwise not used in the ie unpack.
+
+  Return Value: Error Message
+
+*****************************************************************************/
+L3INT Q931Uie_GenericDigits(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff)
+{
+	Q931ie_GenericDigits *pie = (Q931ie_GenericDigits*)OBuf;
+	ie *pIE = &pMsg->GenericDigits;
+	L3INT Off = 0;
+	L3INT Octet = 0;
+	L3INT x;
+	L3INT IESize;
+
+	*pIE = 0;
+
+	/* Octet 1 */
+	pie->IEId = IBuf[Octet++];
+
+	/* Octet 2 */
+	IESize = IBuf[Octet++]; 
+
+	/* Octet 3 */
+	pie->Type     = (IBuf[Octet]) & 0x1F;
+	pie->Encoding = (IBuf[Octet] >> 5) & 0x07;
+	Octet++;
+	
+	/* Octet 4*/
+	if (pie->Encoding == 0) { /* BCD Even */
+		x = 0;
+		do {
+			pie->Digit[x++] =  IBuf[Octet + Off] & 0x0f;
+			pie->Digit[x++] = (IBuf[Octet + Off] >> 4) & 0x0f;
+			Off++;
+		} while (Q931MoreIE());
+	} else if (pie->Encoding == 1) { /* BCD Odd */
+		x = 0;
+		do {
+			pie->Digit[x++] = IBuf[Octet + Off] & 0x0f;
+			if (Q931MoreIE()) {
+				pie->Digit[x] = (IBuf[Octet + Off] >> 4) & 0x0f;
+			}
+			x++;
+			Off++;
+		} while (Q931MoreIE());
+	} else if (pie->Encoding == 2) { /* IA5 */
+		x = 0;
+		do {
+			pie->Digit[x++] = IBuf[Octet + Off] & 0x7f;
+			Off++;
+		} while (Q931MoreIE());
+	} else {
+		/* Binary encoding type unkown */
+		Q931SetError(pTrunk, Q931E_GENERIC_DIGITS, Octet, Off);
+		return Q931E_GENERIC_DIGITS;
+	}
+
+	Q931IESizeTest(Q931E_GENERIC_DIGITS);
+	Q931SetIE(*pIE, *OOff);
+
+	*IOff = (*IOff) + Octet + Off;
+	*OOff = (*OOff) + sizeof(Q931ie_CallingSub) + x - 1;
+	pie->Size = (L3UCHAR)(sizeof(Q931ie_CallingSub) + x - 1);
+
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Pie_GenericDigits
+
+  Parameters:   IBuf[IN]		Ptr to struct.
+				OBuf[OUT]		Ptr tp packed output buffer.
+				Octet[IN/OUT]	Offset into OBuf.
+
+  Return Value:	Error code, 0 = OK
+
+*****************************************************************************/
+
+L3INT Q931Pie_GenericDigits(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+	OBuf[(*Octet)++] = (Q931ie_GENERIC_DIGITS & 0xFF);
+	OBuf[(*Octet)++] = 0;
+
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Uie_ChangeStatus
+
+  Parameters:   pIE[OUT]		ptr to Information Element id.
+				IBuf[IN]		ptr to a packed ie.
+				OBuf[OUT]	   ptr to buffer for Unpacked ie.
+				IOff[IN\OUT]	Input buffer offset
+				OOff[IN\OUT]	Output buffer offset
+
+				Ibuf and OBuf points directly to buffers. The IOff and OOff
+				must be updated, but are otherwise not used in the ie unpack.
+
+  Return Value: Error Message
+
+*****************************************************************************/
+L3INT Q931Uie_ChangeStatus(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff)
+{
+	Q931ie_ChangeStatus *pie = (Q931ie_ChangeStatus*)OBuf;
+	ie *pIE = &pMsg->ChangeStatus;
+	L3INT Off = 0;
+	L3INT Octet = 0;
+	L3INT IESize;
+
+	*pIE = 0;
+
+	pie->IEId = IBuf[Octet++];
+
+	/* Octet 2 */
+	IESize = IBuf[Octet++]; 
+
+	/* Octet 3 */
+	pie->Preference = (IBuf[Octet + Off] >> 6) & 0x01;
+	pie->Spare      =  IBuf[Octet + Off] & 0x38;
+	pie->NewStatus  =  IBuf[Octet + Off] & 0x07;
+	Octet++;
+
+	Q931SetIE(*pIE, *OOff);
+
+	*IOff = (*IOff) + Octet + Off;
+	*OOff = (*OOff) + sizeof(Q931ie_ChangeStatus);
+	pie->Size = sizeof(Q931ie_ChangeStatus);
+
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Pie_ChangeStatus
+
+  Parameters:   IBuf[IN]		Ptr to struct.
+				OBuf[OUT]		Ptr tp packed output buffer.
+				Octet[IN/OUT]	Offset into OBuf.
+
+  Return Value:	Error code, 0 = OK
+
+*****************************************************************************/
+L3INT Q931Pie_ChangeStatus(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+	Q931ie_ChangeStatus *pIE = (Q931ie_ChangeStatus*)IBuf;
+	L3INT rc = Q931E_NO_ERROR;
+	L3INT Beg = *Octet;
+	L3INT li;
+
+	OBuf[(*Octet)++] = Q931ie_CHANGE_STATUS;
+	li = (*Octet)++;
+
+	/* Octet 3 */
+	OBuf[(*Octet)++] = 0x80 | pIE->NewStatus | ((pIE->Preference & 0x01) << 6);
+
+	OBuf[li] = (L3UCHAR)((*Octet) - Beg) - 2;
+	return rc;
+}
+
+
+
+L3INT Q931Uie_Generic(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *IOff, L3INT *OOff)
+{
+	L3INT Octet = 0;
+	L3UCHAR id = 0;
+
+	/* id */
+	id = IBuf[Octet++];
+
+	/* Length */
+	Octet += IBuf[Octet];
+	Octet++;
+
+	Q931Log(pTrunk, Q931_LOG_DEBUG, "Discarding IE %#hhx with length %d\n", id, Octet - 2);
+
+	*IOff += Octet;
+	return Q931E_NO_ERROR;
+}
+
+L3INT Q931Pie_Generic(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
+{
+	/* do nothing */
+	return Q931E_NO_ERROR;
+}

Added: freeswitch/trunk/libs/openzap/src/isdn/Q931mes.c (0 => 17141)


--- freeswitch/trunk/libs/openzap/src/isdn/Q931mes.c	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/src/isdn/Q931mes.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,1870 @@
+/*****************************************************************************
+
+  FileName:	Q931mes.c
+
+  Contents:	Pack/Unpack functions. These functions will unpack a Q931 
+		message from the bit packed original format into structs
+		that contains variables sized by the user. It will also pack
+		the struct back into a Q.931 message as required.
+
+		See q931.h for description. 
+
+  License/Copyright:
+
+  Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+  email:janvb@caselaboratories.com  
+
+  Redistribution and use in source and binary forms, with or without 
+  modification, are permitted provided that the following conditions are 
+  met:
+
+	* Redistributions of source code must retain the above copyright notice, 
+	  this list of conditions and the following disclaimer.
+	* Redistributions in binary form must reproduce the above copyright notice, 
+	  this list of conditions and the following disclaimer in the documentation 
+	  and/or other materials provided with the distribution.
+	* Neither the name of the Case Labs, Ltd nor the names of its contributors 
+	  may be used to endorse or promote products derived from this software 
+	  without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
+  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
+  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+  POSSIBILITY OF SUCH DAMAGE.
+
+*****************************************************************************/
+
+#include "Q931.h"
+
+/**
+ * Q931MesgHeader
+ * \brief	Create Q.931 Message header
+ */
+L3INT Q931MesgHeader(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *mes, L3UCHAR *OBuf, L3INT Size, L3INT *IOff)
+{
+	L3INT Octet = *IOff;
+
+	Q931Log(pTrunk, Q931_LOG_DEBUG, "Creating Q.931 Message Header:\n    ProtDisc %d (%#x), CRV %d (%#x), CRVflag: %d (%#x), MesType: %d (%#x)\n",
+			 mes->ProtDisc, mes->ProtDisc, mes->CRV, mes->CRV, mes->CRVFlag, mes->CRVFlag, mes->MesType, mes->MesType);
+
+	OBuf[Octet++] = mes->ProtDisc;				/* Protocol discriminator */
+	if (!Q931_IS_BRI(pTrunk)) {
+		OBuf[Octet++] = 2;									/* length is 2 octets */
+		OBuf[Octet++] = (L3UCHAR)((mes->CRV >> 8) & 0x7f) | ((mes->CRVFlag << 7) & 0x80);	/* msb */
+		OBuf[Octet++] = (L3UCHAR) (mes->CRV & 0xff);						/* lsb */
+	} else {
+		OBuf[Octet++] = 1;									/* length is 1 octet */
+		OBuf[Octet++] = (L3UCHAR) (mes->CRV & 0x7f) | ((mes->CRVFlag << 7) & 0x80);		/* CRV & flag */
+	}
+	OBuf[Octet++] = mes->MesType;				/* message header */
+
+	*IOff = Octet;
+	return 0;
+}
+
+
+/*****************************************************************************
+
+  Function:	 Q931Umes_Alerting
+
+*****************************************************************************/
+
+L3INT Q931Umes_Alerting(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+	L3INT OOff = 0;
+	L3INT rc = Q931E_NO_ERROR;
+
+	while (IOff < Size) {
+		switch (IBuf[IOff]) {
+		case Q931ie_BEARER_CAPABILITY: 
+		case Q931ie_CHANNEL_IDENTIFICATION:
+		case Q931ie_PROGRESS_INDICATOR:
+		case Q931ie_DISPLAY:
+		case Q931ie_SIGNAL:
+		case Q931ie_HIGH_LAYER_COMPATIBILITY:
+		case Q931ie_USER_USER:
+			rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+			if (rc != Q931E_NO_ERROR) 
+				return rc;
+			break;
+		default:
+			return Q931E_ILLEGAL_IE;
+			break;
+		}
+	}
+
+	mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Pmes_Alerting
+
+*****************************************************************************/
+L3INT Q931Pmes_Alerting(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+	Q931mes_Generic *pMes = (Q931mes_Generic *)IBuf;
+	L3INT rc = Q931E_NO_ERROR;
+	L3INT Octet = 0;
+
+	/* Q931 Message Header */
+	Q931MesgHeader(pTrunk, pMes, OBuf, *OSize, &Octet);
+	
+	/* Bearer capability */
+	if (Q931IsIEPresent(pMes->BearerCap)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_BEARER_CAPABILITY](pTrunk, Q931GetIEPtr(pMes->BearerCap,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Channel Identification */
+	if (Q931IsIEPresent(pMes->ChanID)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CHANNEL_IDENTIFICATION](pTrunk, Q931GetIEPtr(pMes->ChanID,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Progress indicator */
+	if (Q931IsIEPresent(pMes->ProgInd)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_PROGRESS_INDICATOR](pTrunk, Q931GetIEPtr(pMes->ProgInd,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Display */
+	if (Q931IsIEPresent(pMes->Display)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_DISPLAY](pTrunk, Q931GetIEPtr(pMes->Display,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Signal */
+	if (Q931IsIEPresent(pMes->Signal)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_SIGNAL](pTrunk, Q931GetIEPtr(pMes->Signal,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* High Layer Compatibility */
+	if (Q931IsIEPresent(pMes->HLComp)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_HIGH_LAYER_COMPATIBILITY](pTrunk, Q931GetIEPtr(pMes->HLComp,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	*OSize = Octet;	
+	return rc;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Umes_CallProceeding
+
+*****************************************************************************/
+L3INT Q931Umes_CallProceeding(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+	L3INT OOff = 0;
+	L3INT rc = Q931E_NO_ERROR;
+
+	while (IOff < Size) {
+		switch (IBuf[IOff]) {
+		case Q931ie_BEARER_CAPABILITY:
+		case Q931ie_CHANNEL_IDENTIFICATION:
+		case Q931ie_PROGRESS_INDICATOR:
+		case Q931ie_DISPLAY:
+		case Q931ie_HIGH_LAYER_COMPATIBILITY:
+			rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+			if (rc != Q931E_NO_ERROR) 
+				return rc;
+			break;
+		default:
+			return Q931E_ILLEGAL_IE;
+			break;
+		}
+	}
+
+	mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Pmes_CallProceeding
+
+*****************************************************************************/
+L3INT Q931Pmes_CallProceeding(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+	Q931mes_Generic *pMes = (Q931mes_Generic *)IBuf;
+	L3INT rc = Q931E_NO_ERROR;
+	L3INT Octet = 0;
+
+	/* Q931 Message Header */
+	Q931MesgHeader(pTrunk, pMes, OBuf, *OSize, &Octet);
+	
+	/* Bearer capability */
+	if (Q931IsIEPresent(pMes->BearerCap)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_BEARER_CAPABILITY](pTrunk, Q931GetIEPtr(pMes->BearerCap,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Channel Identification */
+	if (Q931IsIEPresent(pMes->ChanID)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CHANNEL_IDENTIFICATION](pTrunk, Q931GetIEPtr(pMes->ChanID,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+	
+	/* Progress indicator */
+	if (Q931IsIEPresent(pMes->ProgInd)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_PROGRESS_INDICATOR](pTrunk, Q931GetIEPtr(pMes->ProgInd,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Display */
+	if (Q931IsIEPresent(pMes->Display)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_DISPLAY](pTrunk, Q931GetIEPtr(pMes->Display,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* High Layer Compatibility */
+	if (Q931IsIEPresent(pMes->HLComp)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_HIGH_LAYER_COMPATIBILITY](pTrunk, Q931GetIEPtr(pMes->HLComp,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	*OSize = Octet;	
+	return rc;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Umes_CongestionControl
+
+*****************************************************************************/
+L3INT Q931Umes_CongestionControl(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+	L3BOOL RetCode = L3FALSE;
+
+	NoWarning(mes);
+	NoWarning(IBuf);
+
+	return RetCode;
+}
+
+
+/*****************************************************************************
+
+  Function:	 Q931Pmes_CongestionControl
+
+*****************************************************************************/
+L3INT Q931Pmes_CongestionControl(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+	L3BOOL RetCode = L3FALSE;
+
+	NoWarning(OBuf);
+	NoWarning(IBuf);
+
+	*OSize = 0;	
+	return RetCode;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Umes_Connect
+
+*****************************************************************************/
+L3INT Q931Umes_Connect(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+	L3INT OOff = 0;
+	L3INT rc = Q931E_NO_ERROR;
+
+	while (IOff < Size) {
+		switch (IBuf[IOff]) {
+		case Q931ie_BEARER_CAPABILITY:
+		case Q931ie_CHANNEL_IDENTIFICATION:
+		case Q931ie_PROGRESS_INDICATOR:
+		case Q931ie_DISPLAY:
+		case Q931ie_DATETIME:
+		case Q931ie_SIGNAL:
+		case Q931ie_LOW_LAYER_COMPATIBILITY:
+		case Q931ie_HIGH_LAYER_COMPATIBILITY:
+		case Q931ie_CONNECTED_NUMBER:		/* not actually used, seen while testing BRI PTMP TE */
+		case Q931ie_USER_USER:
+			rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+			if (rc != Q931E_NO_ERROR) 
+				return rc;
+			break;
+
+		default:
+			Q931Log(pTrunk, Q931_LOG_ERROR, "Illegal IE %#hhx in Connect Message\n", IBuf[IOff]);
+
+			return Q931E_ILLEGAL_IE;
+			break;
+		}
+	}
+
+	mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Pmes_Connect
+
+*****************************************************************************/
+L3INT Q931Pmes_Connect(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+	Q931mes_Generic *pMes = (Q931mes_Generic *)IBuf;
+	L3INT rc = Q931E_NO_ERROR;
+	L3INT Octet = 0;
+
+	/* Q931 Message Header */
+	Q931MesgHeader(pTrunk, pMes, OBuf, *OSize, &Octet);
+	
+	/* Bearer capability */
+	if (Q931IsIEPresent(pMes->BearerCap)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_BEARER_CAPABILITY](pTrunk, Q931GetIEPtr(pMes->BearerCap,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Channel Identification */
+	if (Q931IsIEPresent(pMes->ChanID)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CHANNEL_IDENTIFICATION](pTrunk, Q931GetIEPtr(pMes->ChanID,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Progress indicator */
+	if (Q931IsIEPresent(pMes->ProgInd)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_PROGRESS_INDICATOR](pTrunk, Q931GetIEPtr(pMes->ProgInd,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Display */
+	if (Q931IsIEPresent(pMes->Display)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_DISPLAY](pTrunk, Q931GetIEPtr(pMes->Display,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Date/Time */
+	if (Q931IsIEPresent(pMes->DateTime)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_DATETIME](pTrunk, Q931GetIEPtr(pMes->DateTime,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Signal */
+	if (Q931IsIEPresent(pMes->Signal)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_SIGNAL](pTrunk, Q931GetIEPtr(pMes->Signal,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Low Layer Compatibility */
+	if (Q931IsIEPresent(pMes->LLComp)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_LOW_LAYER_COMPATIBILITY](pTrunk, Q931GetIEPtr(pMes->LLComp,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* High Layer Compatibility */
+	if (Q931IsIEPresent(pMes->HLComp)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_HIGH_LAYER_COMPATIBILITY](pTrunk, Q931GetIEPtr(pMes->HLComp,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	*OSize = Octet;	
+	return rc;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Umes_ConnectAck
+
+*****************************************************************************/
+L3INT Q931Umes_ConnectAck(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+	L3INT OOff = 0;
+	L3INT rc = Q931E_NO_ERROR;
+
+	while (IOff < Size) {
+		switch (IBuf[IOff]) {
+		case Q931ie_DISPLAY:
+		case Q931ie_SIGNAL:
+			rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+			if (rc != Q931E_NO_ERROR) 
+				return rc;
+			break;
+		default:
+			return Q931E_ILLEGAL_IE;
+			break;
+		}
+	}
+
+	mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+	return Q931E_NO_ERROR;
+}
+
+
+/*****************************************************************************
+
+  Function:	 Q931Pmes_ConnectAck
+
+*****************************************************************************/
+L3INT Q931Pmes_ConnectAck(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+	Q931mes_Generic *pMes = (Q931mes_Generic *)IBuf;
+	L3INT rc = Q931E_NO_ERROR;
+	L3INT Octet = 0;
+
+	/* Q931 Message Header */
+	Q931MesgHeader(pTrunk, pMes, OBuf, *OSize, &Octet);
+	
+	/* Display */
+	if (Q931IsIEPresent(pMes->Display)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_DISPLAY](pTrunk, Q931GetIEPtr(pMes->Display,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Signal */
+	if (Q931IsIEPresent(pMes->Signal)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_SIGNAL](pTrunk, Q931GetIEPtr(pMes->Signal,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	*OSize = Octet;	
+	return rc;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Umes_Disconnect
+
+*****************************************************************************/
+L3INT Q931Umes_Disconnect(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+	L3INT OOff = 0;
+	L3INT rc = Q931E_NO_ERROR;
+
+	while (IOff < Size) {
+		switch (IBuf[IOff]) {
+		case Q931ie_CAUSE:
+		case Q931ie_PROGRESS_INDICATOR:
+		case Q931ie_DISPLAY:
+		case Q931ie_SIGNAL:
+		case Q931ie_FACILITY:
+		case Q931ie_USER_USER:
+			rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+			if (rc != Q931E_NO_ERROR) 
+				return rc;
+			break;
+		default:
+			return Q931E_ILLEGAL_IE;
+			break;
+		}
+	}
+
+	mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Pmes_Disconnect
+
+*****************************************************************************/
+L3INT Q931Pmes_Disconnect(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+	Q931mes_Generic *pMes = (Q931mes_Generic *)IBuf;
+	L3INT rc = Q931E_NO_ERROR;
+	L3INT Octet = 0;
+
+	/* Q931 Message Header */
+	Q931MesgHeader(pTrunk, pMes, OBuf, *OSize, &Octet);
+	
+	/* Cause */
+	if (Q931IsIEPresent(pMes->Cause)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CAUSE](pTrunk, Q931GetIEPtr(pMes->Cause,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+	
+	/* Progress indicator */
+	if (Q931IsIEPresent(pMes->ProgInd)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_PROGRESS_INDICATOR](pTrunk, Q931GetIEPtr(pMes->ProgInd,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Display */
+	if (Q931IsIEPresent(pMes->Display)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_DISPLAY](pTrunk, Q931GetIEPtr(pMes->Display,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Signal */
+	if (Q931IsIEPresent(pMes->Signal)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_SIGNAL](pTrunk, Q931GetIEPtr(pMes->Signal,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	*OSize = Octet;	
+	return rc;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Umes_Information
+
+*****************************************************************************/
+L3INT Q931Umes_Information(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+	L3INT OOff = 0;
+	L3INT rc = Q931E_NO_ERROR;
+
+	while (IOff < Size) {
+		switch (IBuf[IOff]) {
+		case Q931ie_SENDING_COMPLETE:
+		case Q931ie_DISPLAY:
+		case Q931ie_KEYPAD_FACILITY:
+		case Q931ie_CALLED_PARTY_NUMBER:
+			rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+			if (rc != Q931E_NO_ERROR) 
+				return rc;
+			break;
+		default:
+			return Q931E_ILLEGAL_IE;
+			break;
+		}
+	}
+
+	mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Pmes_Information
+
+*****************************************************************************/
+L3INT Q931Pmes_Information(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+	Q931mes_Generic *pMes = (Q931mes_Generic *)IBuf;
+	L3INT rc = Q931E_NO_ERROR;
+	L3INT Octet = 0;
+
+	/* Q931 Message Header */
+	Q931MesgHeader(pTrunk, pMes, OBuf, *OSize, &Octet);
+
+	/* Sending Complete */
+	if (Q931IsIEPresent(pMes->SendComplete)) {
+		OBuf[Octet++]	= (L3UCHAR)(pMes->SendComplete & 0x00ff);
+	}
+
+	/* Display */
+	if (Q931IsIEPresent(pMes->Display)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_DISPLAY](pTrunk, Q931GetIEPtr(pMes->Display,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Keypad Facility */
+	if (Q931IsIEPresent(pMes->KeypadFac)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_KEYPAD_FACILITY](pTrunk, Q931GetIEPtr(pMes->KeypadFac,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Signal */
+	if (Q931IsIEPresent(pMes->Signal)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_SIGNAL](pTrunk, Q931GetIEPtr(pMes->Signal,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Called Party number */
+	if (Q931IsIEPresent(pMes->CalledNum)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CALLED_PARTY_NUMBER](pTrunk, Q931GetIEPtr(pMes->CalledNum,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	*OSize = Octet;	
+	return rc;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Umes_Notify
+
+*****************************************************************************/
+L3INT Q931Umes_Notify(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+	L3INT OOff = 0;
+	L3INT rc = Q931E_NO_ERROR;
+
+	while (IOff < Size) {
+		switch (IBuf[IOff]) {
+		case Q931ie_BEARER_CAPABILITY:
+		case Q931ie_NOTIFICATION_INDICATOR:
+		case Q931ie_DISPLAY:
+			rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+			if (rc != Q931E_NO_ERROR) 
+				return rc;
+			break;
+		default:
+			return Q931E_ILLEGAL_IE;
+			break;
+		}
+	}
+
+	mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Pmes_Notify
+
+*****************************************************************************/
+L3INT Q931Pmes_Notify(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+	Q931mes_Generic *pMes = (Q931mes_Generic *)IBuf;
+	L3INT rc = Q931E_NO_ERROR;
+	L3INT Octet = 0;
+
+	/* Q931 Message Header */
+	Q931MesgHeader(pTrunk, pMes, OBuf, *OSize, &Octet);
+	
+	/* Bearer capability */
+	if (Q931IsIEPresent(pMes->BearerCap)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_BEARER_CAPABILITY](pTrunk, Q931GetIEPtr(pMes->BearerCap,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Display */
+	if (Q931IsIEPresent(pMes->Display)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_DISPLAY](pTrunk, Q931GetIEPtr(pMes->Display,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	*OSize = Octet;	
+	return rc;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Umes_Progress
+
+*****************************************************************************/
+L3INT Q931Umes_Progress(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+	L3INT OOff = 0;
+	L3INT rc = Q931E_NO_ERROR;
+
+	while (IOff < Size) {
+		switch (IBuf[IOff]) {
+		case Q931ie_BEARER_CAPABILITY:
+		case Q931ie_CAUSE:
+		case Q931ie_PROGRESS_INDICATOR:
+		case Q931ie_DISPLAY:
+		case Q931ie_HIGH_LAYER_COMPATIBILITY:
+			rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+			if (rc != Q931E_NO_ERROR) 
+				return rc;
+			break;
+		default:
+			return Q931E_ILLEGAL_IE;
+			break;
+		}
+	}
+
+	mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Pmes_Progress
+
+*****************************************************************************/
+L3INT Q931Pmes_Progress(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+	Q931mes_Generic *pMes = (Q931mes_Generic *)IBuf;
+	L3INT rc = Q931E_NO_ERROR;
+	L3INT Octet = 0;
+
+	/* Q931 Message Header */
+	Q931MesgHeader(pTrunk, pMes, OBuf, *OSize, &Octet);
+	
+	/* Bearer capability */
+	if (Q931IsIEPresent(pMes->BearerCap)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_BEARER_CAPABILITY](pTrunk, Q931GetIEPtr(pMes->BearerCap,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Cause */
+	if (Q931IsIEPresent(pMes->Cause)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CAUSE](pTrunk, Q931GetIEPtr(pMes->Cause,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Progress indicator */
+	if (Q931IsIEPresent(pMes->ProgInd)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_PROGRESS_INDICATOR](pTrunk, Q931GetIEPtr(pMes->ProgInd,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Display */
+	if (Q931IsIEPresent(pMes->Display)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_DISPLAY](pTrunk, Q931GetIEPtr(pMes->Display,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* High Layer Compatibility */
+	if (Q931IsIEPresent(pMes->HLComp)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_HIGH_LAYER_COMPATIBILITY](pTrunk, Q931GetIEPtr(pMes->HLComp,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	*OSize = Octet;	
+	return rc;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Umes_Release
+
+*****************************************************************************/
+L3INT Q931Umes_Release(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+	L3INT OOff = 0;
+	L3INT rc = Q931E_NO_ERROR;
+
+	while (IOff < Size) {
+		switch (IBuf[IOff]) {
+		case Q931ie_CAUSE:
+		case Q931ie_DISPLAY:
+		case Q931ie_SIGNAL:
+		case Q931ie_USER_USER:
+			rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+			if (rc != Q931E_NO_ERROR) 
+				return rc;
+			break;
+		default:
+			return Q931E_ILLEGAL_IE;
+			break;
+		}
+	}
+
+	mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Pmes_Release
+
+*****************************************************************************/
+L3INT Q931Pmes_Release(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+	Q931mes_Generic *pMes = (Q931mes_Generic *)IBuf;
+	L3INT rc = Q931E_NO_ERROR;
+	L3INT Octet = 0;
+
+	/* Q931 Message Header */
+	Q931MesgHeader(pTrunk, pMes, OBuf, *OSize, &Octet);
+	
+	/* Cause */
+	if (Q931IsIEPresent(pMes->Cause)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CAUSE](pTrunk, Q931GetIEPtr(pMes->Cause,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Display */
+	if (Q931IsIEPresent(pMes->Display)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_DISPLAY](pTrunk, Q931GetIEPtr(pMes->Display,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Signal */
+	if (Q931IsIEPresent(pMes->Signal)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_SIGNAL](pTrunk, Q931GetIEPtr(pMes->Signal,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	*OSize = Octet;	
+	return rc;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Umes_ReleaseComplete
+
+*****************************************************************************/
+L3INT Q931Umes_ReleaseComplete(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+	L3INT OOff = 0;
+	L3INT rc = Q931E_NO_ERROR;
+
+	while (IOff < Size) {
+		switch (IBuf[IOff]) {
+		case Q931ie_CAUSE:
+		case Q931ie_DISPLAY:
+		case Q931ie_SIGNAL:
+		case Q931ie_USER_USER:
+			rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+			if (rc != Q931E_NO_ERROR) 
+				return rc;
+			break;
+		default:
+			return Q931E_ILLEGAL_IE;
+			break;
+		}
+	}
+
+	mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Pmes_ReleaseComplete
+
+*****************************************************************************/
+L3INT Q931Pmes_ReleaseComplete(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+	Q931mes_Generic *pMes = (Q931mes_Generic *)IBuf;
+	L3INT rc = Q931E_NO_ERROR;
+	L3INT Octet = 0;
+
+	/* Q931 Message Header */
+	Q931MesgHeader(pTrunk, pMes, OBuf, *OSize, &Octet);
+	
+	/* Cause */
+	if (Q931IsIEPresent(pMes->Cause)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CAUSE](pTrunk, Q931GetIEPtr(pMes->Cause,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Display */
+	if (Q931IsIEPresent(pMes->Display)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_DISPLAY](pTrunk, Q931GetIEPtr(pMes->Display,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Signal */
+	if (Q931IsIEPresent(pMes->Signal)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_SIGNAL](pTrunk, Q931GetIEPtr(pMes->Signal,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	*OSize = Octet;	
+	return rc;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Umes_Restart
+
+*****************************************************************************/
+L3INT Q931Umes_Restart(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+	L3INT OOff = 0;
+	L3INT rc = Q931E_NO_ERROR;
+
+	while (IOff < Size) {
+		switch (IBuf[IOff]) {
+		case Q931ie_CHANNEL_IDENTIFICATION:
+		case Q931ie_DISPLAY:
+		case Q931ie_RESTART_INDICATOR:
+			rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+			if (rc != Q931E_NO_ERROR) 
+				return rc;
+			break;
+		default:
+			return Q931E_ILLEGAL_IE;
+			break;
+		}
+	}
+
+	mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Pmes_Restart
+
+*****************************************************************************/
+L3INT Q931Pmes_Restart(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+	Q931mes_Generic *pMes = (Q931mes_Generic *)IBuf;
+	L3INT rc = Q931E_NO_ERROR;
+	L3INT Octet = 0;
+
+	/* Q931 Message Header */
+	Q931MesgHeader(pTrunk, pMes, OBuf, *OSize, &Octet);
+   
+	/* ChanID */
+	if (Q931IsIEPresent(pMes->ChanID)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CHANNEL_IDENTIFICATION](pTrunk, Q931GetIEPtr(pMes->ChanID,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Display */
+	if (Q931IsIEPresent(pMes->Display)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_DISPLAY](pTrunk, Q931GetIEPtr(pMes->Display,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* RestartInd */
+	if (Q931IsIEPresent(pMes->RestartInd)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_RESTART_INDICATOR](pTrunk, Q931GetIEPtr(pMes->RestartInd,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	*OSize = Octet;	
+	return rc;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Umes_RestartAck
+
+*****************************************************************************/
+L3INT Q931Umes_RestartAck(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT IOff, L3INT Size)
+{
+	Q931mes_Generic *mes = (Q931mes_Generic*)OBuf;
+	L3INT OOff = 0;
+	L3INT rc = Q931E_NO_ERROR;
+
+	while (IOff < Size) {
+		switch (IBuf[IOff]) {
+		case Q931ie_CHANNEL_IDENTIFICATION:
+		case Q931ie_DISPLAY:
+		case Q931ie_RESTART_INDICATOR:
+			rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+			if (rc != Q931E_NO_ERROR) 
+				return rc;
+			break;
+		default:
+			return Q931E_ILLEGAL_IE;
+			break;
+		}
+	}
+
+	mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Pmes_RestartAck
+
+*****************************************************************************/
+L3INT Q931Pmes_RestartAck(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+	Q931mes_Generic *pMes = (Q931mes_Generic *)IBuf;
+	L3INT rc = Q931E_NO_ERROR;
+	L3INT Octet = 0;
+
+	/* Q931 Message Header */
+	Q931MesgHeader(pTrunk, pMes, OBuf, *OSize, &Octet);
+	
+	/* ChanID */
+	if (Q931IsIEPresent(pMes->ChanID)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CHANNEL_IDENTIFICATION](pTrunk, Q931GetIEPtr(pMes->ChanID,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Display */
+	if (Q931IsIEPresent(pMes->Display)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_DISPLAY](pTrunk, Q931GetIEPtr(pMes->Display,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* RestartInd */
+	if (Q931IsIEPresent(pMes->RestartInd)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_RESTART_INDICATOR](pTrunk, Q931GetIEPtr(pMes->RestartInd,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	*OSize = Octet;	
+	return rc;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Umes_Resume
+
+*****************************************************************************/
+L3INT Q931Umes_Resume(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+	L3INT OOff = 0;
+	L3INT rc = Q931E_NO_ERROR;
+
+	while (IOff < Size) {
+		switch (IBuf[IOff]) {
+		case Q931ie_CALL_IDENTITY:
+			rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+			if (rc != Q931E_NO_ERROR) 
+				return rc;
+			break;
+		default:
+			return Q931E_ILLEGAL_IE;
+			break;
+		}
+	}
+
+	mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Pmes_Resume
+
+*****************************************************************************/
+L3INT Q931Pmes_Resume(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+	Q931mes_Generic *pMes = (Q931mes_Generic *)IBuf;
+	L3INT rc = Q931E_NO_ERROR;
+	L3INT Octet = 0;
+
+	/* Q931 Message Header */
+	Q931MesgHeader(pTrunk, pMes, OBuf, *OSize, &Octet);
+
+	/* Call Identity */
+	if (Q931IsIEPresent(pMes->CallID)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CALL_IDENTITY](pTrunk, Q931GetIEPtr(pMes->CallID,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	*OSize = Octet;	
+	return rc;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Umes_ResumeAck
+
+*****************************************************************************/
+L3INT Q931Umes_ResumeAck(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+	L3INT OOff = 0;
+	L3INT rc = Q931E_NO_ERROR;
+
+	while (IOff < Size) {
+		switch (IBuf[IOff]) {
+		case Q931ie_CHANNEL_IDENTIFICATION:
+		case Q931ie_DISPLAY:
+			rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+			if (rc != Q931E_NO_ERROR) 
+				return rc;
+			break;
+		default:
+			return Q931E_ILLEGAL_IE;
+			break;
+		}
+	}
+
+	mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+	return Q931E_NO_ERROR;
+}
+
+
+/*****************************************************************************
+
+  Function:	 Q931Pmes_ResumeAck
+
+*****************************************************************************/
+L3INT Q931Pmes_ResumeAck(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+	Q931mes_Generic *pMes = (Q931mes_Generic *)IBuf;
+	L3INT rc = Q931E_NO_ERROR;
+	L3INT Octet = 0;
+
+	/* Q931 Message Header */
+	Q931MesgHeader(pTrunk, pMes, OBuf, *OSize, &Octet);
+	
+	/* Channel Identification */
+	if (Q931IsIEPresent(pMes->ChanID)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CHANNEL_IDENTIFICATION](pTrunk, Q931GetIEPtr(pMes->ChanID,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Display */
+	if (Q931IsIEPresent(pMes->Display)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_DISPLAY](pTrunk, Q931GetIEPtr(pMes->Display,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	*OSize = Octet;	
+	return rc;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Umes_ResumeReject
+
+*****************************************************************************/
+L3INT Q931Umes_ResumeReject(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+	L3INT OOff = 0;
+	L3INT rc = Q931E_NO_ERROR;
+
+	while (IOff < Size) {
+		switch (IBuf[IOff]) {
+		case Q931ie_CAUSE:
+		case Q931ie_DISPLAY:
+			rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+			if (rc != Q931E_NO_ERROR) 
+				return rc;
+			break;
+		default:
+			return Q931E_ILLEGAL_IE;
+			break;
+		}
+	}
+
+	mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+	return Q931E_NO_ERROR;
+}
+
+
+/*****************************************************************************
+
+  Function:	 Q931Pmes_ResumeReject
+
+*****************************************************************************/
+L3INT Q931Pmes_ResumeReject(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+	Q931mes_Generic *pMes = (Q931mes_Generic *)IBuf;
+	L3INT rc = Q931E_NO_ERROR;
+	L3INT Octet = 0;
+
+	/* Q931 Message Header	*/
+	Q931MesgHeader(pTrunk, pMes, OBuf, *OSize, &Octet);
+
+	/* Cause */
+	if (Q931IsIEPresent(pMes->Cause)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CAUSE](pTrunk, Q931GetIEPtr(pMes->Cause,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Display */
+	if (Q931IsIEPresent(pMes->Display)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_DISPLAY](pTrunk, Q931GetIEPtr(pMes->Display,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	*OSize = Octet;	
+	return rc;
+}
+
+L3INT Q931Umes_Segment(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT OOff)
+{
+	L3INT i = IOff;
+
+	return IOff - i;
+}
+
+L3INT Q931Pmes_Segment(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+	L3BOOL RetCode = L3FALSE;
+
+	*OSize = 0;	
+	return RetCode;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Umes_Setup
+
+*****************************************************************************/
+L3INT Q931Umes_Setup(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+	L3INT ir = 0;
+	L3INT OOff = 0;
+	L3INT rc = Q931E_NO_ERROR;
+
+	while (IOff < Size) {
+		switch (IBuf[IOff]) {
+		case Q931ie_SENDING_COMPLETE:
+			IOff++;
+			break;
+
+		case Q931ie_BEARER_CAPABILITY:
+		case Q931ie_CHANNEL_IDENTIFICATION:
+		case Q931ie_PROGRESS_INDICATOR:
+		case Q931ie_NETWORK_SPECIFIC_FACILITIES:
+		case Q931ie_DISPLAY:
+		case Q931ie_DATETIME:
+		case Q931ie_KEYPAD_FACILITY:
+		case Q931ie_SIGNAL:
+		case Q931ie_CALLING_PARTY_NUMBER:
+		case Q931ie_CALLING_PARTY_SUBADDRESS:
+		case Q931ie_CALLED_PARTY_NUMBER:
+		case Q931ie_CALLED_PARTY_SUBADDRESS:
+		case Q931ie_TRANSIT_NETWORK_SELECTION:
+		case Q931ie_LOW_LAYER_COMPATIBILITY:
+		case Q931ie_HIGH_LAYER_COMPATIBILITY:
+		case Q931ie_FACILITY:
+		case Q931ie_USER_USER:
+		case Q931ie_REDIRECTING_NUMBER:
+			rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+			if (rc != Q931E_NO_ERROR) 
+				return rc;
+			break;
+
+		case Q931ie_REPEAT_INDICATOR:
+			if (ir < 2) {
+				rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+				ir++;
+			} else {
+				return Q931E_ILLEGAL_IE;
+			}
+			break;
+
+		default:
+			return Q931E_ILLEGAL_IE;
+			break;
+		}
+	}
+
+	mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Pmes_Setup
+
+  Decription:	Pack a Q931mes_Generic into a real Q.931 message. The user will
+				set up a SETUP message and issue this to the stack where it
+				is processed by Q931ProcSetup that processes and validates
+				it before it actually sends it out. This function is called
+				to compute the real Q.931 message.
+
+  Parameters:	IBuf[IN]	Ptr to un-packed struct
+				ISize[IN]	Size of input buffer (unpacked message).
+				OBuf[OUT]	Ptr to packed 'octet' wise message.
+				OSize[OUT]	Size of packed message.
+
+  Called By:	Q931ProcSetup
+
+*****************************************************************************/
+L3INT Q931Pmes_Setup(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+	Q931mes_Generic *pMes = (Q931mes_Generic *)IBuf;
+	L3INT rc = Q931E_NO_ERROR;
+	L3INT Octet = 0;
+
+	/* Q931 Message Header */
+	Q931MesgHeader(pTrunk, pMes, OBuf, *OSize, &Octet);
+
+	/* Sending Complete */
+	if (Q931IsIEPresent(pMes->SendComplete)) {
+		OBuf[Octet++] = (L3UCHAR)Q931ie_SENDING_COMPLETE & 0xff;
+	}
+
+	/* Repeat Indicator */
+	if (Q931IsIEPresent(pMes->RepeatInd)) {
+		OBuf[Octet++] = (L3UCHAR)Q931ie_REPEAT_INDICATOR & 0xff;		
+	}
+
+	/* Bearer capability */
+	if (Q931IsIEPresent(pMes->BearerCap)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_BEARER_CAPABILITY](pTrunk, Q931GetIEPtr(pMes->BearerCap,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	} else {
+		rc = Q931E_BEARERCAP;
+	}
+
+	/* Channel Identification */
+	if (Q931IsIEPresent(pMes->ChanID)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CHANNEL_IDENTIFICATION](pTrunk, Q931GetIEPtr(pMes->ChanID,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Progress indicator */
+	if (Q931IsIEPresent(pMes->ProgInd)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_PROGRESS_INDICATOR](pTrunk, Q931GetIEPtr(pMes->ProgInd,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Network spesific facilities */
+	if (Q931IsIEPresent(pMes->NetFac)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_NETWORK_SPECIFIC_FACILITIES](pTrunk, Q931GetIEPtr(pMes->NetFac,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Display */
+	if (Q931IsIEPresent(pMes->Display)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_DISPLAY](pTrunk, Q931GetIEPtr(pMes->Display,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Date/Time */
+	if (Q931IsIEPresent(pMes->DateTime)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_DATETIME](pTrunk, Q931GetIEPtr(pMes->DateTime,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Keypad Facility */
+	if (Q931IsIEPresent(pMes->KeypadFac)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_KEYPAD_FACILITY](pTrunk, Q931GetIEPtr(pMes->KeypadFac,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Signal */
+	if (Q931IsIEPresent(pMes->Signal)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_SIGNAL](pTrunk, Q931GetIEPtr(pMes->Signal,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Calling Party Number */
+	if (Q931IsIEPresent(pMes->CallingNum)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CALLING_PARTY_NUMBER](pTrunk, Q931GetIEPtr(pMes->CallingNum,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Calling Party Subaddress */
+	if (Q931IsIEPresent(pMes->CallingSub)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CALLING_PARTY_SUBADDRESS](pTrunk, Q931GetIEPtr(pMes->CallingSub,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Called Party number */
+	if (Q931IsIEPresent(pMes->CalledNum)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CALLED_PARTY_NUMBER](pTrunk, Q931GetIEPtr(pMes->CalledNum,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Called party subaddress */
+	if (Q931IsIEPresent(pMes->CalledSub)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CALLED_PARTY_SUBADDRESS](pTrunk, Q931GetIEPtr(pMes->CalledSub,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Transit network selection */
+	if (Q931IsIEPresent(pMes->TransNetSel)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_TRANSIT_NETWORK_SELECTION](pTrunk, Q931GetIEPtr(pMes->TransNetSel,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Repeat Indicator */
+	if (Q931IsIEPresent(pMes->LLRepeatInd)) {
+		rc = Q931E_UNKNOWN_IE;/* TODO */
+	}
+
+	/* Low Layer Compatibility */
+	if (Q931IsIEPresent(pMes->LLComp)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_LOW_LAYER_COMPATIBILITY](pTrunk, Q931GetIEPtr(pMes->LLComp,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* High Layer Compatibility */
+	if (Q931IsIEPresent(pMes->HLComp)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_HIGH_LAYER_COMPATIBILITY](pTrunk, Q931GetIEPtr(pMes->HLComp,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	*OSize = Octet;	
+	return rc;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Umes_SetupAck
+
+*****************************************************************************/
+L3INT Q931Umes_SetupAck(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+	L3INT OOff = 0;
+	L3INT rc = Q931E_NO_ERROR;
+
+	while (IOff < Size) {
+		switch (IBuf[IOff]) {
+		case Q931ie_CHANNEL_IDENTIFICATION:
+		case Q931ie_PROGRESS_INDICATOR:
+		case Q931ie_DISPLAY:
+		case Q931ie_SIGNAL:
+			rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+			if (rc != Q931E_NO_ERROR) 
+				return rc;
+			break;
+		default:
+			return Q931E_ILLEGAL_IE;
+			break;
+		}
+	}
+
+	mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Pmes_SetupAck
+
+*****************************************************************************/
+L3INT Q931Pmes_SetupAck(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+	Q931mes_Generic *pMes = (Q931mes_Generic *)IBuf;
+	L3INT rc = Q931E_NO_ERROR;
+	L3INT Octet = 0;
+
+	/* Q931 Message Header */
+	Q931MesgHeader(pTrunk, pMes, OBuf, *OSize, &Octet);
+	
+	/* Channel Identification */
+	if (Q931IsIEPresent(pMes->ChanID)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CHANNEL_IDENTIFICATION](pTrunk, Q931GetIEPtr(pMes->ChanID,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Progress indicator */
+	if (Q931IsIEPresent(pMes->ProgInd)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_PROGRESS_INDICATOR](pTrunk, Q931GetIEPtr(pMes->ProgInd,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Display */
+	if (Q931IsIEPresent(pMes->Display)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_DISPLAY](pTrunk, Q931GetIEPtr(pMes->Display,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Signal */
+	if (Q931IsIEPresent(pMes->Signal)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_SIGNAL](pTrunk, Q931GetIEPtr(pMes->Signal,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	*OSize = Octet;	
+	return rc;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Umes_Status
+
+*****************************************************************************/
+L3INT Q931Umes_Status(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+	L3INT OOff = 0;
+	L3INT rc = Q931E_NO_ERROR;
+
+	while (IOff < Size) {
+		switch (IBuf[IOff]) {
+		case Q931ie_CAUSE:
+		case Q931ie_CALL_STATE:
+		case Q931ie_DISPLAY:
+			rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+			if (rc != Q931E_NO_ERROR) 
+				return rc;
+			break;
+		default:
+			return Q931E_ILLEGAL_IE;
+			break;
+		}
+	}
+
+	mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+	return Q931E_NO_ERROR;
+}
+
+
+/*****************************************************************************
+
+  Function:	 Q931Pmes_Status
+
+*****************************************************************************/
+L3INT Q931Pmes_Status(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+	Q931mes_Generic *pMes = (Q931mes_Generic *)IBuf;
+	L3INT rc = Q931E_NO_ERROR;
+	L3INT Octet = 0;
+
+	/* Q931 Message Header */
+	Q931MesgHeader(pTrunk, pMes, OBuf, *OSize, &Octet);
+	
+	/* Cause */
+	if (Q931IsIEPresent(pMes->Cause)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CAUSE](pTrunk, Q931GetIEPtr(pMes->Cause,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Call State */
+	if (Q931IsIEPresent(pMes->CallState)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CALL_STATE](pTrunk, Q931GetIEPtr(pMes->CallState,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Display */
+	if (Q931IsIEPresent(pMes->Display)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_DISPLAY](pTrunk, Q931GetIEPtr(pMes->Display,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	*OSize = Octet;	
+	return rc;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Umes_StatusEnquiry
+
+*****************************************************************************/
+L3INT Q931Umes_StatusEnquiry(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+	L3INT OOff = 0;
+	L3INT rc = Q931E_NO_ERROR;
+
+	while (IOff < Size) {
+		switch (IBuf[IOff]) {
+		case Q931ie_DISPLAY:
+			rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+			if (rc != Q931E_NO_ERROR) 
+				return rc;
+			break;
+		default:
+			return Q931E_ILLEGAL_IE;
+			break;
+		}
+	}
+
+	mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Pmes_StatusEnquiry
+
+*****************************************************************************/
+L3INT Q931Pmes_StatusEnquiry(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+	Q931mes_Generic *pMes = (Q931mes_Generic *)IBuf;
+	L3INT rc = Q931E_NO_ERROR;
+	L3INT Octet = 0;
+
+	/* Q931 Message Header */
+	Q931MesgHeader(pTrunk, pMes, OBuf, *OSize, &Octet);
+	
+	/* Display */
+	if (Q931IsIEPresent(pMes->Display)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_DISPLAY](pTrunk, Q931GetIEPtr(pMes->Display,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	*OSize = Octet;	
+
+	return rc;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Umes_Suspend
+
+*****************************************************************************/
+L3INT Q931Umes_Suspend(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+	L3INT OOff = 0;
+	L3INT rc = Q931E_NO_ERROR;
+
+	while (IOff < Size) {
+		switch (IBuf[IOff]) {
+		case Q931ie_CALL_IDENTITY:
+			rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+			if (rc != Q931E_NO_ERROR) 
+				return rc;
+			break;
+		default:
+			return Q931E_ILLEGAL_IE;
+			break;
+		}
+	}
+
+	mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Pmes_Suspend
+
+*****************************************************************************/
+L3INT Q931Pmes_Suspend(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+	Q931mes_Generic *pMes = (Q931mes_Generic *)IBuf;
+	L3INT rc = Q931E_NO_ERROR;
+	L3INT Octet = 0;
+
+	/* Q931 Message Header */
+	Q931MesgHeader(pTrunk, pMes, OBuf, *OSize, &Octet);
+	
+	/* Call Identity */
+	if (Q931IsIEPresent(pMes->CallID)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CALL_IDENTITY](pTrunk, Q931GetIEPtr(pMes->CallID,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	*OSize = Octet;	
+	return rc;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Umes_SuspendAck
+
+*****************************************************************************/
+L3INT Q931Umes_SuspendAck(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+	L3INT OOff = 0;
+	L3INT rc = Q931E_NO_ERROR;
+
+	while (IOff < Size) {
+		switch (IBuf[IOff]) {
+		case Q931ie_DISPLAY:
+			rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+			if (rc != Q931E_NO_ERROR) 
+				return rc;
+			break;
+		default:
+			return Q931E_ILLEGAL_IE;
+			break;
+		}
+	}
+
+	mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Pmes_SuspendAck
+
+*****************************************************************************/
+L3INT Q931Pmes_SuspendAck(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+	Q931mes_Generic *pMes = (Q931mes_Generic *)IBuf;
+	L3INT rc = Q931E_NO_ERROR;
+	L3INT Octet = 0;
+
+	/* Q931 Message Header */
+	Q931MesgHeader(pTrunk, pMes, OBuf, *OSize, &Octet);
+	
+	/* Display */
+	if (Q931IsIEPresent(pMes->Display)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_DISPLAY](pTrunk, Q931GetIEPtr(pMes->Display,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	*OSize = Octet;	
+	return rc;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Umes_SuspendReject
+
+*****************************************************************************/
+L3INT Q931Umes_SuspendReject(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+	L3INT OOff = 0;
+	L3INT rc = Q931E_NO_ERROR;
+
+	while (IOff < Size) {
+		switch (IBuf[IOff]) {
+		case Q931ie_CAUSE:
+		case Q931ie_DISPLAY:
+			rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+			if (rc != Q931E_NO_ERROR) 
+				return rc;
+			break;
+		default:
+			return Q931E_ILLEGAL_IE;
+			break;
+		}
+	}
+
+	mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Pmes_SuspendReject
+
+*****************************************************************************/
+L3INT Q931Pmes_SuspendReject(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+	Q931mes_Generic *pMes = (Q931mes_Generic *)IBuf;
+	L3INT rc = Q931E_NO_ERROR;
+	L3INT Octet = 0;
+
+	/* Q931 Message Header */
+	Q931MesgHeader(pTrunk, pMes, OBuf, *OSize, &Octet);
+	
+	/* Cause */
+	if (Q931IsIEPresent(pMes->Cause)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CAUSE](pTrunk, Q931GetIEPtr(pMes->Cause,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Display */
+	if (Q931IsIEPresent(pMes->Display)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_DISPLAY](pTrunk, Q931GetIEPtr(pMes->Display,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	*OSize = Octet;	
+	return rc;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Umes_UserInformation
+
+*****************************************************************************/
+L3INT Q931Umes_UserInformation(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT I, L3INT O)
+{
+	L3BOOL RetCode = L3FALSE;
+
+	NoWarning(mes);
+	NoWarning(IBuf);
+
+	return RetCode;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Pmes_UserInformation
+
+*****************************************************************************/
+L3INT Q931Pmes_UserInformation(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+	L3BOOL RetCode = L3FALSE;
+
+	NoWarning(OBuf);
+	NoWarning(IBuf);
+
+	*OSize = 0;	
+
+	return RetCode;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Umes_Service
+
+*****************************************************************************/
+L3INT Q931Umes_Service(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+	L3INT OOff = 0;
+	L3INT rc = Q931E_NO_ERROR;
+
+	while (IOff < Size) {
+		switch (IBuf[IOff]) {
+		case Q931ie_CHANNEL_IDENTIFICATION:
+			rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+			if (rc != Q931E_NO_ERROR) 
+				return rc;
+			break;
+		case Q931ie_CHANGE_STATUS:
+			rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+			if (rc != Q931E_NO_ERROR) 
+				return rc;
+			break;
+		default:
+			return Q931E_ILLEGAL_IE;
+			break;
+		}
+	}
+
+	mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Pmes_Service
+
+*****************************************************************************/
+L3INT Q931Pmes_Service(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+	Q931mes_Generic *pMes = (Q931mes_Generic *)IBuf;
+	L3INT rc = Q931E_NO_ERROR;
+	L3INT Octet = 0;
+
+	/* Q931 Message Header */
+	Q931MesgHeader(pTrunk, pMes, OBuf, *OSize, &Octet);
+	
+	/* Display */
+	if (Q931IsIEPresent(pMes->ChanID)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CHANNEL_IDENTIFICATION](pTrunk, Q931GetIEPtr(pMes->ChanID,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	if (Q931IsIEPresent(pMes->ChangeStatus)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CHANGE_STATUS](pTrunk, Q931GetIEPtr(pMes->ChangeStatus,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	*OSize = Octet;	
+	return rc;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Umes_ServiceAck
+
+*****************************************************************************/
+L3INT Q931Umes_ServiceAck(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+	L3INT OOff = 0;
+	L3INT rc = Q931E_NO_ERROR;
+
+	while (IOff < Size) {
+		switch (IBuf[IOff]) {
+		case Q931ie_CHANNEL_IDENTIFICATION:
+			rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+			if (rc != Q931E_NO_ERROR) 
+				return rc;
+			break;
+		case Q931ie_CHANGE_STATUS:
+			rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+			if (rc != Q931E_NO_ERROR) 
+				return rc;
+			break;
+		default:
+			return Q931E_ILLEGAL_IE;
+			break;
+		}
+	}
+
+	mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Pmes_ServiceAck
+
+*****************************************************************************/
+L3INT Q931Pmes_ServiceAck(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+	Q931mes_Generic *pMes = (Q931mes_Generic *)IBuf;
+	L3INT rc = Q931E_NO_ERROR;
+	L3INT Octet = 0;
+
+	/* Q931 Message Header */
+	Q931MesgHeader(pTrunk, pMes, OBuf, *OSize, &Octet);
+	
+	if (Q931IsIEPresent(pMes->ChangeStatus)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CHANGE_STATUS](pTrunk, Q931GetIEPtr(pMes->ChangeStatus,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	if (Q931IsIEPresent(pMes->ChanID)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CHANNEL_IDENTIFICATION](pTrunk, Q931GetIEPtr(pMes->ChanID,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	*OSize = Octet;	
+	return rc;
+}

Added: freeswitch/trunk/libs/openzap/src/isdn/Q932mes.c (0 => 17141)


--- freeswitch/trunk/libs/openzap/src/isdn/Q932mes.c	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/src/isdn/Q932mes.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,286 @@
+/*****************************************************************************
+
+  FileName:		Q932mes.c
+
+  Contents:		Q.932 Message Encoders/Decoders
+
+  License/Copyright:
+
+  Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+  email:janvb@caselaboratories.com  
+
+  Redistribution and use in source and binary forms, with or without 
+  modification, are permitted provided that the following conditions are 
+  met:
+
+	* Redistributions of source code must retain the above copyright notice, 
+	  this list of conditions and the following disclaimer.
+	* Redistributions in binary form must reproduce the above copyright notice, 
+	  this list of conditions and the following disclaimer in the documentation 
+	  and/or other materials provided with the distribution.
+	* Neither the name of the Case Labs, Ltd nor the names of its contributors 
+	  may be used to endorse or promote products derived from this software 
+	  without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
+  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
+  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+  POSSIBILITY OF SUCH DAMAGE.
+*****************************************************************************/
+
+#include "Q931.h"
+
+/*****************************************************************************
+
+  Function:	 Q932Umes_Facility
+
+*****************************************************************************/
+
+L3INT Q932Umes_Facility(Q931_TrunkInfo_t *pTrunk,L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+	L3INT OOff = 0;
+
+	/* TODO */
+
+	mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Pmes_Facility
+
+*****************************************************************************/
+L3INT Q932Pmes_Facility(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+	L3BOOL RetCode = L3FALSE;
+
+	NoWarning(OBuf);
+	NoWarning(IBuf);
+
+	return RetCode;
+}
+
+/*****************************************************************************
+
+  Function:	 Q932Umes_Hold
+
+*****************************************************************************/
+
+L3INT Q932Umes_Hold(Q931_TrunkInfo_t *pTrunk,L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+	L3INT OOff = 0;
+
+	/* TODO */
+
+	mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Pmes_Hold
+
+*****************************************************************************/
+L3INT Q932Pmes_Hold(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+	L3BOOL RetCode = L3FALSE;
+
+	NoWarning(OBuf);
+	NoWarning(IBuf);
+
+	return RetCode;
+}
+
+/*****************************************************************************
+
+  Function:	 Q932Umes_HoldAck
+
+*****************************************************************************/
+
+L3INT Q932Umes_HoldAck(Q931_TrunkInfo_t *pTrunk,L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+	L3INT OOff = 0;
+
+	/* TODO */
+
+	mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Pmes_HoldAck
+
+*****************************************************************************/
+L3INT Q932Pmes_HoldAck(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+	L3BOOL RetCode = L3FALSE;
+
+	NoWarning(OBuf);
+	NoWarning(IBuf);
+
+	return RetCode;
+}
+
+/*****************************************************************************
+
+  Function:	 Q932Umes_HoldReject
+
+*****************************************************************************/
+
+L3INT Q932Umes_HoldReject(Q931_TrunkInfo_t *pTrunk,L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+	L3INT OOff = 0;
+
+	/* TODO */
+
+	mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Pmes_HoldReject
+
+*****************************************************************************/
+L3INT Q932Pmes_HoldReject(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+	L3BOOL RetCode = L3FALSE;
+
+	NoWarning(OBuf);
+	NoWarning(IBuf);
+
+	return RetCode;
+}
+
+/*****************************************************************************
+
+  Function:	 Q932Umes_Register
+
+*****************************************************************************/
+
+L3INT Q932Umes_Register(Q931_TrunkInfo_t *pTrunk,L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+	L3INT OOff = 0;
+
+	/* TODO */
+
+	mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Pmes_Register
+
+*****************************************************************************/
+L3INT Q932Pmes_Register(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+	L3BOOL RetCode = L3FALSE;
+
+	NoWarning(OBuf);
+	NoWarning(IBuf);
+
+	return RetCode;
+}
+
+/*****************************************************************************
+
+  Function:	 Q932Umes_Retrieve
+
+*****************************************************************************/
+
+L3INT Q932Umes_Retrieve(Q931_TrunkInfo_t *pTrunk,L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+	L3INT OOff = 0;
+
+	/* TODO */
+
+	mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Pmes_Retrieve
+
+*****************************************************************************/
+L3INT Q932Pmes_Retrieve(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+	L3BOOL RetCode = L3FALSE;
+
+	NoWarning(OBuf);
+	NoWarning(IBuf);
+
+	return RetCode;
+}
+
+/*****************************************************************************
+
+  Function:	 Q932Umes_RetrieveAck
+
+*****************************************************************************/
+
+L3INT Q932Umes_RetrieveAck(Q931_TrunkInfo_t *pTrunk,L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+	L3INT OOff = 0;
+
+	/* TODO */
+
+	mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Pmes_RetrieveAck
+
+*****************************************************************************/
+L3INT Q932Pmes_RetrieveAck(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+	L3BOOL RetCode = L3FALSE;
+
+	NoWarning(OBuf);
+	NoWarning(IBuf);
+
+	return RetCode;
+}
+
+/*****************************************************************************
+
+  Function:	 Q932Umes_RetrieveReject
+
+*****************************************************************************/
+
+L3INT Q932Umes_RetrieveReject(Q931_TrunkInfo_t *pTrunk,L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+	L3INT OOff = 0;
+
+	/* TODO */
+
+	mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:	 Q931Pmes_RetrieveReject
+
+*****************************************************************************/
+L3INT Q932Pmes_RetrieveReject(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+	L3BOOL RetCode = L3FALSE;
+
+	NoWarning(OBuf);
+	NoWarning(IBuf);
+
+	return RetCode;
+}

Added: freeswitch/trunk/libs/openzap/src/isdn/include/5ESS.h (0 => 17141)


--- freeswitch/trunk/libs/openzap/src/isdn/include/5ESS.h	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/src/isdn/include/5ESS.h	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,103 @@
+/******************************************************************************
+
+  FileName:         5ESS.h
+
+  Contents:         Header and definition for the AT&T 5ESS ISDN dialect. The 
+                    header contains the following parts:
+
+                    - Definition of codes
+                    - Definition of information elements (5ESSie_).
+                    - Definition of messages (5ESSmes_).
+                    - Function prototypes.
+
+  Description:      The AT&T 5ESS ISDN dialect here covers ????
+
+  Related Files:    5ESS.h              AT&T 5ESS ISDN Definitions
+                    5ESSie.c            AT&T 5ESS ISDN IE encoders/coders (not extant yet)
+                                        See Q931ie.c for IE encoders/coders
+                    5ESSStateTE.c       AT&T 5ESS ISDN TE State Engine
+                    5ESSStateNT.c       AT&T 5ESS ISDN NT State Engine
+
+  License/Copyright:
+
+  Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+  email:janvb@caselaboratories.com  
+
+  Copyright (c) 2007, Michael Jerris. All rights reserved.
+  email:mike@jerris.com  
+  
+  Copyright (c) 2007, Michael S. Collins, All rights reserved.
+  email:mcollins@fcnetwork.com
+
+  Redistribution and use in source and binary forms, with or without 
+  modification, are permitted provided that the following conditions are 
+  met:
+
+    * Redistributions of source code must retain the above copyright notice, 
+    this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright notice, 
+    this list of conditions and the following disclaimer in the documentation 
+    and/or other materials provided with the distribution.
+    * Neither the name of the Case Labs, Ltd nor the names of its contributors 
+    may be used to endorse or promote products derived from this software 
+    without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
+  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
+  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+  POSSIBILITY OF SUCH DAMAGE.
+******************************************************************************/
+
+#ifndef _5ESS_NL
+#define _5ESS_NL
+
+#include "Q931.h"
+
+/*****************************************************************************
+
+  Q.931 Message codes
+  Only 5ESS specific message and ie types 
+  here the rest are inherited from Q931.h
+  
+*****************************************************************************/
+
+
+/*****************************************************************************
+
+  Q.931 Message Pack/Unpack functions. Implemented in 5ESSmes.c
+  Note: Because C variables may not begin with numeric digit, all identifiers
+        are prefixed with "ATT5ESS" instead of a bare "5ESS"
+
+*****************************************************************************/
+L3INT ATT5ESSUmes_Setup(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT IOff, L3INT Size);
+L3INT ATT5ESSPmes_Setup(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT ATT5ESSUmes_SetupAck(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT IOff, L3INT Size);
+L3INT ATT5ESSPmes_SetupAck(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+
+L3INT ATT5ESSUmes_0x07(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size);
+L3INT ATT5ESSPmes_0x07(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT ATT5ESSUmes_0x0f(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size);
+L3INT ATT5ESSPmes_0x0f(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+
+
+
+/*****************************************************************************
+
+  Q.931 Process Function Prototyping. Implemented in 5ESSStateTE.c
+
+*****************************************************************************/
+L3INT ATT5ESSProc0x0fTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom);
+L3INT ATT5ESSProc0x07TE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom);
+
+
+void ATT5ESSCreateTE(L3UCHAR i);
+void ATT5ESSCreateNT(L3UCHAR i);
+
+#endif /* _5ESS_NL */

Added: freeswitch/trunk/libs/openzap/src/isdn/include/DMS.h (0 => 17141)


--- freeswitch/trunk/libs/openzap/src/isdn/include/DMS.h	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/src/isdn/include/DMS.h	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,91 @@
+/******************************************************************************
+
+  FileName:         national.h
+
+  Contents:         Header and definition for the National ISDN dialect. The 
+										header contents the following parts:
+                    - Definition of codes
+                    - Definition of information elements (nationalie_).
+                    - Definition of messages (nationalmes_).
+                    - Function prototypes.
+
+  Description:		The National ISDN dialect here covers ????
+
+  Related Files:	national.h			National ISDN Definitions
+			nationalie.c			National ISDN IE encoders/coders
+			nationalStateTE.c		National ISDN TE State Engine
+			nationalStateNT.c		National ISDN NT State Engine
+
+  License/Copyright:
+
+  Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+  email:janvb@caselaboratories.com  
+
+  Copyright (c) 2007, Michael Jerris. All rights reserved.
+  email:mike@jerris.com  
+
+  Redistribution and use in source and binary forms, with or without 
+  modification, are permitted provided that the following conditions are 
+  met:
+
+    * Redistributions of source code must retain the above copyright notice, 
+	  this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright notice, 
+	  this list of conditions and the following disclaimer in the documentation 
+	  and/or other materials provided with the distribution.
+    * Neither the name of the Case Labs, Ltd nor the names of its contributors 
+	  may be used to endorse or promote products derived from this software 
+	  without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
+  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
+  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+  POSSIBILITY OF SUCH DAMAGE.
+******************************************************************************/
+
+#ifndef _DMS_NL
+#define _DMS_NL
+
+#include "Q931.h"
+
+/*****************************************************************************
+
+  Q.931 Message codes
+  Only National specific message and ie types 
+  here the rest are inherited from national.h
+  
+*****************************************************************************/
+
+
+/*****************************************************************************
+
+  Q.931 Message Pack/Unpack functions. Implemented in nationalmes.c
+
+*****************************************************************************/
+L3INT DMSUmes_Setup(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT IOff, L3INT Size);
+L3INT DMSPmes_Setup(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT DMSUmes_0x07(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size);
+L3INT DMSPmes_0x07(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT DMSUmes_0x0f(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size);
+L3INT DMSPmes_0x0f(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+
+/*****************************************************************************
+
+  Q.931 Process Function Prototyping. Implemented in nationalStateTE.c
+
+*****************************************************************************/
+
+L3INT DMSProc0x0fTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom);
+L3INT DMSProc0x07TE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * buf, L3INT iFrom);
+
+void DMSCreateTE(L3UCHAR i);
+void DMSCreateNT(L3UCHAR i);
+
+#endif /* _DMS_NL */

Added: freeswitch/trunk/libs/openzap/src/isdn/include/Q921.h (0 => 17141)


--- freeswitch/trunk/libs/openzap/src/isdn/include/Q921.h	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/src/isdn/include/Q921.h	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,227 @@
+/*****************************************************************************
+
+  FileName:     q921.h
+
+  Description:  Contains headers of a Q.921 protocol.
+
+  Note:         This header file is the only include file that should be 
+                acessed by users of the Q.921 stack.
+
+  Interface:    The Q.921 stack contains 2 layers. 
+
+                -   One interface layer.
+                -   One driver layer.
+
+                The interface layer contains the interface functions required 
+                for a layer 2 stack to be able to send and receive messages.
+
+                The driver layer will simply feed bytes into the ship as
+                required and queue messages received out from the ship.
+
+                Q921TimeTick        The Q.921 like any other blackbox 
+                                    modules contains no thread by it's own
+                                    and must therefore be called regularly 
+                                    by an external 'thread' to do maintenance
+                                    etc.
+
+                Q921Rx32            Receive message from layer 3. Called by
+                                    the layer 3 stack to send a message.
+
+
+				NOTE: The following are not yet implemented
+
+                OnQ921Error         Function called every if an error is 
+                                    detected.
+
+                OnQ921Log           Function called if logging is active.
+
+
+                <TODO> Maintenance/Configuration interface
+				<TODO> Logging
+				<TODO> DL_ message passing to layer 3
+				<TODO> Timers
+				<TODO> Api commands to tell 921 to stop and start for a trunk
+
+  Created:      27.dec.2000/JVB
+
+  License/Copyright:
+
+  Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+  email:janvb@caselaboratories.com  
+
+  Redistribution and use in source and binary forms, with or without 
+  modification, are permitted provided that the following conditions are 
+  met:
+
+    * Redistributions of source code must retain the above copyright notice, 
+	  this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright notice, 
+	  this list of conditions and the following disclaimer in the documentation 
+	  and/or other materials provided with the distribution.
+    * Neither the name of the Case Labs, Ltd nor the names of its contributors 
+	  may be used to endorse or promote products derived from this software 
+	  without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
+  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
+  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+  POSSIBILITY OF SUCH DAMAGE.
+
+*****************************************************************************/
+
+/****************************************************************************
+ * Changes:
+ *
+ * - June,July 2008: Stefan Knoblich <s.knoblich@axsentis.de>:
+ *     Add PTMP TEI management
+ *     Add timers
+ *     Add retransmit counters
+ *     Add logging
+ *     Various cleanups
+ *
+ ****************************************************************************/
+
+#ifndef _Q921
+#define _Q921
+
+#define Q921MAXHDLCSPACE 3000
+#define L2UCHAR		unsigned char		/* Min 8 bit			*/
+#define L2USHORT	unsigned short		/* 16 bit			*/
+#define L2INT		int			/* Min 16 bit signed		*/
+#define L2ULONG		unsigned long		/* Min 32 bit			*/
+#define L2TRUNK		Q921Data_t *
+
+#define Q921_TEI_BCAST		127
+#define Q921_TEI_MAX		Q921_TEI_BCAST
+
+#define Q921_TEI_DYN_MIN	64
+#define Q921_TEI_DYN_MAX	126
+
+
+typedef enum			/* Network/User Mode		*/
+{
+	Q921_TE=0,		/*  0 : User Mode		*/
+	Q921_NT=1		/*  1 : Network Mode		*/
+} Q921NetUser_t;
+
+typedef enum			/* Type of connection		*/
+{
+	Q921_PTP=0,		/* 0 : Point-To-Point		*/
+	Q921_PTMP=1		/* 1 : Point-To-Multipoint	*/
+} Q921NetType_t;
+
+typedef enum
+{
+	Q921_LOG_NONE = -1,
+	Q921_LOG_EMERG = 0,
+	Q921_LOG_ALERT,
+	Q921_LOG_CRIT,
+	Q921_LOG_ERROR,
+	Q921_LOG_WARNING,
+	Q921_LOG_NOTICE,
+	Q921_LOG_INFO,
+	Q921_LOG_DEBUG
+} Q921LogLevel_t;
+
+
+/*
+ * Messages for L2 <-> L3 communication
+ */
+typedef enum {
+	Q921_DL_ESTABLISH = 0,
+	Q921_DL_ESTABLISH_CONFIRM,
+	Q921_DL_RELEASE,
+	Q921_DL_RELEASE_CONFIRM,
+	Q921_DL_DATA,
+	Q921_DL_UNIT_DATA
+} Q921DLMsg_t;
+
+typedef int (*Q921Tx21CB_t) (void *, L2UCHAR *, L2INT);
+typedef int (*Q921Tx23CB_t) (void *, Q921DLMsg_t ind, L2UCHAR tei, L2UCHAR *, L2INT);
+typedef int (*Q921LogCB_t) (void *, Q921LogLevel_t, char *, L2INT);
+
+struct Q921_Link;
+
+typedef struct Q921Data
+{
+	L2INT initialized;
+
+	L2UCHAR sapi;			/*!< User assigned SAPI */
+	L2UCHAR tei;			/*!< User assigned TEI value */
+
+	L2INT Q921HeaderSpace;
+	Q921NetUser_t NetUser;
+	Q921NetType_t NetType;
+
+	struct Q921_Link *context;	/*!< per-TEI / link context space */
+
+	/* timers */
+	L2ULONG T202;			/*!< PTMP TE mode TEI retransmit timer */
+	L2ULONG T200Timeout;
+	L2ULONG T201Timeout;
+	L2ULONG T202Timeout;
+	L2ULONG T203Timeout;
+
+	L2ULONG TM01Timeout;
+
+	/* counters */
+	L2ULONG N200Limit;		/*!< max retransmit */
+
+	L2ULONG N202;			/*!< PTMP TE mode retransmit counter */
+	L2ULONG N202Limit;		/*!< PTMP TE mode max retransmit */
+
+	L2ULONG N201Limit;		/*!< max number of octets */
+	L2ULONG k;			/*!< max number of unacknowledged I frames */
+
+	/* callbacks and callback data pointers */
+	Q921Tx21CB_t Q921Tx21Proc;
+	Q921Tx23CB_t Q921Tx23Proc;
+	void *PrivateData21;
+	void *PrivateData23;
+
+	/* logging */
+	Q921LogLevel_t	loglevel;	/*!< trunk loglevel */
+	Q921LogCB_t	Q921LogProc;	/*!< log callback procedure */
+	void *PrivateDataLog;		/*!< private data pointer for log proc */
+
+	/* tei mgmt */
+	L2UCHAR tei_map[Q921_TEI_MAX];	/*!< */
+
+	L2UCHAR HDLCInQueue[Q921MAXHDLCSPACE];	/*!< HDLC input queue */
+} Q921Data_t;
+
+/*
+ * Public functions
+ */
+int Q921_InitTrunk(L2TRUNK trunk,
+					L2UCHAR sapi,
+					L2UCHAR tei,
+					Q921NetUser_t NetUser,
+					Q921NetType_t NetType,
+					L2INT hsize,
+					Q921Tx21CB_t cb21,
+					Q921Tx23CB_t cb23,
+					void *priv21,
+					void *priv23);
+int Q921Start(L2TRUNK trunk);
+int Q921Stop(L2TRUNK trunk);
+
+void Q921SetLogCB(L2TRUNK trunk, Q921LogCB_t func, void *priv);
+void Q921SetLogLevel(L2TRUNK trunk, Q921LogLevel_t level);
+
+int Q921Rx12(L2TRUNK trunk);
+int Q921Rx32(L2TRUNK trunk, Q921DLMsg_t ind, L2UCHAR tei, L2UCHAR * Mes, L2INT Size);
+
+int Q921QueueHDLCFrame(L2TRUNK trunk, L2UCHAR *b, L2INT size);
+
+void Q921SetGetTimeCB(L2ULONG (*callback)(void));
+void Q921TimerTick(L2TRUNK trunk);
+
+#endif

Added: freeswitch/trunk/libs/openzap/src/isdn/include/Q921priv.h (0 => 17141)


--- freeswitch/trunk/libs/openzap/src/isdn/include/Q921priv.h	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/src/isdn/include/Q921priv.h	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,321 @@
+/*****************************************************************************
+
+  FileName:     Q921priv.h
+
+  Description:  Private declarations
+
+  Created:      08.Aug.2008/STKN
+
+  License/Copyright:
+
+  Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+  email:janvb@caselaboratories.com  
+
+  Copyright (c) 2008, Stefan Knoblich, axsentis GmbH. All rights reserved.
+  email:s.knoblich@axsentis.de  
+
+  Redistribution and use in source and binary forms, with or without 
+  modification, are permitted provided that the following conditions are 
+  met:
+
+    * Redistributions of source code must retain the above copyright notice, 
+	  this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright notice, 
+	  this list of conditions and the following disclaimer in the documentation 
+	  and/or other materials provided with the distribution.
+    * Neither the name of the Case Labs, Ltd nor the names of its contributors 
+	  may be used to endorse or promote products derived from this software 
+	  without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
+  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
+  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+  POSSIBILITY OF SUCH DAMAGE.
+
+*****************************************************************************/
+#ifndef _Q921_PRIV_H_
+#define _Q921_PRIV_H_
+
+#ifdef _MSC_VER
+#ifndef __inline__
+#define __inline__ __inline
+#endif
+#if (_MSC_VER >= 1400)			/* VC8+ */
+#ifndef _CRT_SECURE_NO_DEPRECATE
+#define _CRT_SECURE_NO_DEPRECATE
+#endif
+#ifndef _CRT_NONSTDC_NO_DEPRECATE
+#define _CRT_NONSTDC_NO_DEPRECATE
+#endif
+#endif
+#ifndef strcasecmp
+#define strcasecmp(s1, s2) _stricmp(s1, s2)
+#endif
+#ifndef strncasecmp
+#define strncasecmp(s1, s2, n) _strnicmp(s1, s2, n)
+#endif
+#ifndef snprintf
+#define snprintf _snprintf
+#endif
+#endif
+
+typedef enum			/* Q.921 States */
+{
+	Q921_STATE_STOPPED = 0,			/* Trunk stopped */
+	Q921_STATE_TEI_UNASSIGNED = 1,		/* TEI unassigned */
+	Q921_STATE_TEI_AWAITING,		/* Assign awaiting TEI */
+	Q921_STATE_TEI_ESTABLISH,		/* Establish awaiting TEI */
+	Q921_STATE_TEI_ASSIGNED,		/* TEI assigned */
+	Q921_STATE_AWAITING_ESTABLISHMENT,	/* Awaiting establishment */
+	Q921_STATE_AWAITING_RELEASE,		/* Awaiting release */
+	Q921_STATE_MULTIPLE_FRAME_ESTABLISHED,	/* Multiple frame established */
+	Q921_STATE_TIMER_RECOVERY		/* Timer recovery */
+} Q921State_t;
+
+/*
+ * Flags
+ */
+enum Q921_Flags {
+	Q921_FLAG_L3_INITIATED = (1 << 0),
+
+	Q921_FLAG_UI_FRAME_QUEUED = (1 << 1),
+	Q921_FLAG_I_FRAME_QUEUED  = (1 << 2),
+
+	Q921_FLAG_ACK_PENDING = (1 << 3),
+	Q921_FLAG_REJECT      = (1 << 4),
+
+	Q921_FLAG_RECV_BUSY      = (1 << 5),
+	Q921_FLAG_PEER_RECV_BUSY = (1 << 6)
+};
+
+#define Q921_SET_FLAG(x, f)	((x)->flags |= f)
+#define Q921_CHECK_FLAG(x, f)	((x)->flags & f)
+#define Q921_CLEAR_FLAG(x, f)	((x)->flags &= ~f)
+
+
+/*
+ * dynamic TEI handling
+ */
+#define Q921_SAPI_TEI		63	/* SAPI for all TEI Messages */
+#define Q921_LAYER_ENT_ID_TEI	0x0f	/* UN Layer Management Entity ID for TEI Mgmt */
+#define Q921_LAYER_ENT_ID_Q931	0x08	/* Q.931 Layer Management Entity ID */
+
+
+typedef enum {
+	Q921_TEI_ID_REQUEST = 1,
+	Q921_TEI_ID_ASSIGNED,
+	Q921_TEI_ID_DENIED,
+	Q921_TEI_ID_CHECKREQ,
+	Q921_TEI_ID_CHECKRESP,
+	Q921_TEI_ID_REMOVE,
+	Q921_TEI_ID_VERIFY
+} Q921TeiMessageType_t;
+
+
+/**
+ * Per-Datalink context
+ */
+struct Q921_Link {
+	L2UCHAR tei;		/*!< This endpoint's TEI */
+
+	L2UCHAR va;
+	L2UCHAR vs;
+	L2UCHAR vr;
+
+	L2INT flags;
+	Q921State_t state;
+
+	L2ULONG N202;		/*!< PTMP TE mode retransmit counter */
+	L2ULONG N200;		/*!< retransmit counter (per-TEI in PTMP NT mode) */
+
+	L2ULONG TM01;		/*!< Datalink inactivity disconnect timer */
+
+	L2ULONG T200;
+	L2ULONG T201;		/*!< PTMP NT mode timer */
+	L2ULONG T203;
+
+	L2USHORT ri;		/*!< random id for TEI request mgmt */
+
+	/* I + UI Frame queue */
+	L2UCHAR UIFrameQueue[Q921MAXHDLCSPACE];
+	L2UCHAR  IFrameQueue[Q921MAXHDLCSPACE];
+	L2UCHAR  IFrameResendQueue[Q921MAXHDLCSPACE];
+};
+
+
+#define Q921_LINK_CONTEXT(tr, tei) \
+	(Q921_IS_PTMP_NT(tr) && tei != Q921_TEI_BCAST) ? ((struct Q921_Link *)&(tr)->context[tei]) : (tr)->context
+
+#define Q921_TRUNK_CONTEXT(tr) \
+	(tr)->context
+
+#define Q921_LOGBUFSIZE		2000
+#define INITIALIZED_MAGIC	42
+
+/*
+ * Helper macros
+ */
+#define Q921_INC_COUNTER(x)		(x = (x + 1) % 128)
+#define Q921_DEC_COUNTER(x)		(x = (x) ? (x - 1) : 127)
+
+#define Q921_UFRAME_HEADER_SIZE		3
+#define Q921_UFRAME_DATA_OFFSET(tr)	((tr)->Q921HeaderSpace + Q921_UFRAME_HEADER_SIZE)
+
+#define Q921_SFRAME_HEADER_SIZE		4
+#define Q921_SFRAME_DATA_OFFSET(tr)	((tr)->Q921HeaderSpace + Q921_SFRAME_HEADER_SIZE)
+
+#define Q921_IFRAME_HEADER_SIZE		4
+#define Q921_IFRAME_DATA_OFFSET(tr)	((tr)->Q921HeaderSpace + Q921_IFRAME_HEADER_SIZE)
+
+#define Q921_IS_TE(x)			((x)->NetUser == Q921_TE)
+#define Q921_IS_NT(x)			((x)->NetUser == Q921_NT)
+
+#define Q921_IS_STOPPED(tr)		((tr)->state == Q921_STATE_STOPPED)
+
+/* TODO: rework this one */
+#define Q921_IS_READY(tr)		((tr)->state >= Q921_STATE_TEI_ASSIGNED)
+
+#define Q921_IS_PTMP(x)			((x)->NetType == Q921_PTMP)
+#define Q921_IS_PTMP_TE(x)		((x)->NetType == Q921_PTMP && (x)->NetUser == Q921_TE)
+#define Q921_IS_PTMP_NT(x)		((x)->NetType == Q921_PTMP && (x)->NetUser == Q921_NT)
+
+#define Q921_IS_PTP(x)			((x)->NetType == Q921_PTP)
+#define Q921_IS_PTP_TE(x)		((x)->NetType == Q921_PTP && (x)->NetUser == Q921_TE)
+#define Q921_IS_PTP_NT(x)		((x)->NetType == Q921_PTP && (x)->NetUser == Q921_NT)
+
+/* Make life a little easier */
+#define Q921_COMMAND(x)			((x)->NetUser == Q921_TE ? 0 : 1)
+#define Q921_RESPONSE(x)		((x)->NetUser == Q921_TE ? 1 : 0)
+
+#define Q921_IS_COMMAND(tr, x)		((x) == (Q921_IS_TE(tr) ? 1 : 0))
+#define Q921_IS_RESPONSE(tr, x)		((x) == (Q921_IS_TE(tr) ? 0 : 1))
+
+
+/*******************************************************************************
+ * Private functions
+ *******************************************************************************/
+
+/*
+ * L1 / L2 Interface
+ */
+static int Q921Tx21Proc(L2TRUNK trunk, L2UCHAR *Msg, L2INT size);
+static int Q921Tx23Proc(L2TRUNK trunk, Q921DLMsg_t ind, L2UCHAR tei, L2UCHAR *Msg, L2INT size);
+
+
+/*
+ * Timers
+ */
+static L2ULONG Q921GetTime(void);
+
+static void Q921T200TimerStart(L2TRUNK trunk, L2UCHAR tei);
+static void Q921T200TimerStop(L2TRUNK trunk, L2UCHAR tei);
+static void Q921T200TimerReset(L2TRUNK trunk, L2UCHAR tei);
+static void Q921T200TimerExpire(L2TRUNK trunk, L2UCHAR tei);
+
+static void Q921T201TimerStart(L2TRUNK trunk, L2UCHAR tei);
+static void Q921T201TimerStop(L2TRUNK trunk, L2UCHAR tei);
+/* static void Q921T201TimerReset(L2TRUNK trunk, L2UCHAR tei); - Unused for now */
+static void Q921T201TimerExpire(L2TRUNK trunk, L2UCHAR tei);
+
+static void Q921T202TimerStart(L2TRUNK trunk);
+static void Q921T202TimerStop(L2TRUNK trunk);
+static void Q921T202TimerReset(L2TRUNK trunk);
+static void Q921T202TimerExpire(L2TRUNK trunk);
+
+static void Q921T203TimerStart(L2TRUNK trunk, L2UCHAR tei);
+static void Q921T203TimerStop(L2TRUNK trunk, L2UCHAR tei);
+static void Q921T203TimerReset(L2TRUNK trunk, L2UCHAR tei);
+static void Q921T203TimerExpire(L2TRUNK trunk, L2UCHAR tei);
+
+static void Q921TM01TimerStart(L2TRUNK trunk, L2UCHAR tei);
+/* static void Q921TM01TimerStop(L2TRUNK trunk, L2UCHAR tei); - Unused for now */
+static void Q921TM01TimerReset(L2TRUNK trunk, L2UCHAR tei);
+/* static void Q921TM01TimerExpire(L2TRUNK trunk, L2UCHAR tei); - Unused for now */
+
+/*
+ * Frame encoding
+ */
+static int Q921SendS(L2TRUNK trunk, L2UCHAR Sapi, char cr, L2UCHAR Tei, char pf, L2UCHAR sv, L2UCHAR *mes, L2INT size);
+static int Q921SendU(L2TRUNK trunk, L2UCHAR Sapi, char cr, L2UCHAR Tei, char pf, L2UCHAR m, L2UCHAR *mes, L2INT size);
+
+static int Q921SendRNR(L2TRUNK trunk, int Sapi, int cr, int Tei, int pf);
+static int Q921SendREJ(L2TRUNK trunk, int Sapi, int cr, int Tei, int pf);
+static int Q921SendSABME(L2TRUNK trunk, int Sapi, int cr, int Tei, int pf);
+static int Q921SendDM(L2TRUNK trunk, int Sapi, int cr, int Tei, int pf);
+static int Q921SendDISC(L2TRUNK trunk, int Sapi, int cr, int Tei, int pf);
+static int Q921SendUA(L2TRUNK trunk, int Sapi, int cr, int Tei, int pf);
+static int Q921SendUN(L2TRUNK trunk, int Sapi, int cr, int Tei, int pf, L2UCHAR *mes, L2INT size);
+static int Q921SendRR(L2TRUNK trunk, int Sapi, int cr, int Tei, int pf);
+
+/*
+ * Frame decoding
+ */
+static int Q921ProcIFrame(L2TRUNK trunk, L2UCHAR *mes, L2INT size);
+static int Q921ProcSFrame(L2TRUNK trunk, L2UCHAR *mes, L2INT size);
+static int Q921ProcUFrame(L2TRUNK trunk, L2UCHAR *mes, L2INT size);
+
+static int Q921ProcSABME(L2TRUNK trunk, L2UCHAR *mes, L2INT size);
+static int Q921ProcDM(L2TRUNK trunk, L2UCHAR *mes, L2INT size);
+static int Q921ProcUA(L2TRUNK trunk, L2UCHAR *mes, L2INT size);
+static int Q921ProcDISC(L2TRUNK trunk, L2UCHAR *mes, L2INT size);
+static int Q921ProcRR(L2TRUNK trunk, L2UCHAR *mes, L2INT size);
+static int Q921ProcRNR(L2TRUNK trunk, L2UCHAR *mes, L2INT size);
+static int Q921ProcREJ(L2TRUNK trunk, L2UCHAR *mes, L2INT size);
+
+
+/*
+ * (Common) procedures defined in the Q.921 SDL
+ */
+static int Q921SendEnquiry(L2TRUNK trunk, L2UCHAR tei);
+static int Q921SendEnquiryResponse(L2TRUNK trunk, L2UCHAR tei);
+static void Q921ResetExceptionConditions(L2TRUNK trunk, L2UCHAR tei);
+static int Q921EstablishDataLink(L2TRUNK trunk, L2UCHAR tei);
+static int Q921NrErrorRecovery(L2TRUNK trunk, L2UCHAR tei);
+static int Q921InvokeRetransmission(L2TRUNK trunk, L2UCHAR tei, L2UCHAR nr);
+static int Q921AcknowledgePending(L2TRUNK trunk, L2UCHAR tei);
+/*
+static int Q921SetReceiverBusy(L2TRUNK trunk);
+static int Q921ClearReceiverBusy(L2TRUNK trunk);
+*/
+
+/*
+ * Queueing
+ */
+static int Q921SendQueuedIFrame(L2TRUNK trunk, L2UCHAR tei);
+static int Q921EnqueueI(L2TRUNK trunk, L2UCHAR Sapi, char cr, L2UCHAR Tei, char pf, L2UCHAR *mes, L2INT size);
+
+/*
+ * TEI management
+ */
+static int Q921TeiSendAssignRequest(L2TRUNK trunk);
+static int Q921TeiProcAssignResponse(L2TRUNK trunk, L2UCHAR *mes, L2INT size);
+static int Q921TeiSendVerifyRequest(L2TRUNK trunk);
+static int Q921TeiProcCheckRequest(L2TRUNK trunk, L2UCHAR *mes, L2INT size);
+static int Q921TeiProcRemoveRequest(L2TRUNK trunk, L2UCHAR *mes, L2INT size);
+static int Q921TeiProcAssignRequest(L2TRUNK trunk, L2UCHAR *mes, L2INT size);
+static int Q921TeiProcCheckResponse(L2TRUNK trunk, L2UCHAR *mes, L2INT size);
+static int Q921TeiProcVerifyRequest(L2TRUNK trunk, L2UCHAR *mes, L2INT size);
+static int Q921TeiSendRemoveRequest(L2TRUNK trunk, L2UCHAR tei);
+static int Q921TeiSendDenyResponse(L2TRUNK trunk, L2UCHAR tei, L2USHORT ri);
+static int Q921TeiSendAssignedResponse(L2TRUNK trunk, L2UCHAR tei, L2USHORT ri);
+static int Q921TeiSendCheckRequest(L2TRUNK trunk, L2UCHAR tei);
+
+/*
+ * Logging
+ */
+static int Q921Log(L2TRUNK trunk, Q921LogLevel_t level, const char *fmt, ...);
+static int Q921LogMesg(L2TRUNK trunk, Q921LogLevel_t level, L2UCHAR received, L2UCHAR *mes, L2INT size, const char *fmt, ...);
+
+/*
+ * State handling
+ */
+static int Q921ChangeState(L2TRUNK trunk, Q921State_t state, L2UCHAR tei);
+
+#endif

Added: freeswitch/trunk/libs/openzap/src/isdn/include/Q931.h (0 => 17141)


--- freeswitch/trunk/libs/openzap/src/isdn/include/Q931.h	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/src/isdn/include/Q931.h	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,1175 @@
+/******************************************************************************
+
+  FileName:         Q931.h
+
+  Contents:         Header and definition for the ITU-T Q.931 stack. The 
+                    header contents the following parts:
+
+                    - Definition of codes
+                    - Definition of information elements (Q931ie_).
+                    - Definition of messages (Q931mes_).
+                    - Definitian of variables (var_).
+                    - Function prototypes.
+
+  Description:		The Q.931 stack provided here covers ITU-T Q.931 w/Q.932
+                    supplementary services for both PRI, BRI and variants. 
+                    The stack is generic and designed to deal with variants as
+                    needed.
+
+                    The stack uses the following interface functions:
+
+                    - Q931Initialize	Initialize the Q.931 stack.
+                    - Q931Rx23			Receive a message from layer 2
+                    - Q931Tx32			Send a message to layer 2
+                    - Q931Rx43			Receive a message from layer 4 or above.
+                    - Q931Tx34			Send a message to layer 4 or above.
+                    - Q931TimeTick		Periodical timer processing.
+                    - Q931ErrorProc		Callback for stack error message.
+
+                    The protocol is a module with no external dependencies and
+                    can easely be ported to any operating system like Windows,
+                    Linux, rtos and others.
+
+  Related Files:	Q931.h				Q.931 Definitions
+                    Q931.c				Q.931 Interface Functions.
+                    Q931api.c			Low level L4 API functions.
+
+                    Q932.h				Q.932 Suplementary Services
+                    Q932mes.c			Q.932 encoders/coders
+
+                    Q931mes.c			Q.931 Message encoders/coders
+                    Q931ie.c			Q.931 IE encoders/coders
+                    Q931StateTE.c		Generic Q.931 TE State Engine
+                    Q931StateNT.c		Generic Q.931 NT State Engine
+
+  Design Note 1:	For each variant please add separate files starting with 
+                    the	variant short-name as follows:
+
+                    <variant>.h			Spesific headers needed.
+                    <variant>mes.c		Message encoders/decores.
+                    <variant>ie.c		IE encoders/decoders.
+                    <variant>StateTE.c	TE side state engine.
+                    <variant>StateNT.c	NT side state engine.
+
+  Design Note 2:	The stack is deliberatly made non-threading. Use 1 
+                    thread per Trunk, but lock access from the timertick
+                    and rx, tx functions. And make sure the callbacks only
+                    dump messages to a queue, no time-consuming processing
+                    inside stack processing. 
+
+                    All stack processing is async 'fire and forget', meaning
+                    that there are not, and should not be any time-consuming
+                    processing within the stack-time. The best way to thread 
+                    a stack is to use one single thread that signal 5 queues.
+                    
+                    - Incoming L2 queue.
+                    - Incoming L4 queue.
+                    - Outgoing L2 queue.
+                    - Outgoing L4 queue.
+                    - Error/Trace queue.
+
+  Design Note 3:	DSP optimization. The L3 (Rx23) can be called directly
+                    from a HDLC receiver without usage of queues for optimized 
+                    processing. But keep in mind that Q.931 calls Tx34 or Tx32 
+                    as part	of receiving a message from Layer 2.
+
+  License/Copyright:
+
+  Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+  email:janvb@caselaboratories.com  
+
+  Redistribution and use in source and binary forms, with or without 
+  modification, are permitted provided that the following conditions are 
+  met:
+
+    * Redistributions of source code must retain the above copyright notice, 
+	  this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright notice, 
+	  this list of conditions and the following disclaimer in the documentation 
+	  and/or other materials provided with the distribution.
+    * Neither the name of the Case Labs, Ltd nor the names of its contributors 
+	  may be used to endorse or promote products derived from this software 
+	  without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
+  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
+  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+  POSSIBILITY OF SUCH DAMAGE.
+******************************************************************************/
+
+#ifndef _Q931_NL
+#define _Q931_NL
+
+/* uncomment the #define below to add x.25 support to the Q.931				*/
+/* #define Q931_X25_SUPPORT */
+
+#include "stdio.h"
+
+#ifdef _MSC_VER
+#pragma warning(disable:4100)
+#ifndef strcasecmp
+#define strcasecmp(s1, s2) _stricmp(s1, s2)
+#endif
+#endif
+#include <string.h>
+
+
+/*****************************************************************************
+
+  Enum helper macros  <Need description of these macros>
+
+*****************************************************************************/
+#define Q931_ENUM_NAMES(_NAME, _STRINGS) static const char * _NAME [] = { _STRINGS , NULL };
+#define Q931_STR2ENUM_P(_FUNC1, _FUNC2, _TYPE) _TYPE _FUNC1 (const char *name); const char * _FUNC2 (_TYPE type);
+#define Q931_STR2ENUM(_FUNC1, _FUNC2, _TYPE, _STRINGS, _MAX)	\
+	_TYPE _FUNC1 (const char *name)								\
+	{														\
+		int i;												\
+		_TYPE t = _MAX ;									\
+															\
+		for (i = 0; i < _MAX ; i++) {						\
+			if (!strcasecmp(name, _STRINGS[i])) {			\
+				t = (_TYPE) i;								\
+				break;										\
+			}												\
+		}													\
+															\
+		return t;											\
+	}														\
+	const char * _FUNC2 (_TYPE type)						\
+	{														\
+		if (type > _MAX) {									\
+			type = _MAX;									\
+		}													\
+		return _STRINGS[(int)type];							\
+	}														\
+
+/*****************************************************************************
+
+  Error Codes
+
+*****************************************************************************/
+typedef enum {
+	Q931E_NO_ERROR				=	0,
+
+	Q931E_UNKNOWN_MESSAGE		=	-3001,
+	Q931E_ILLEGAL_IE			=	-3002,
+	Q931E_UNKNOWN_IE			=	-3003,
+	Q931E_BEARERCAP				=	-3004,
+	Q931E_HLCOMP				=	-3005,
+	Q931E_LLCOMP				=	-3006,
+	Q931E_INTERNAL              =	-3007,
+	Q931E_MISSING_CB            =	-3008,
+	Q931E_UNEXPECTED_MESSAGE    =	-3009,
+	Q931E_ILLEGAL_MESSAGE		=	-3010,
+	Q931E_TOMANYCALLS           =	-3011,
+	Q931E_INVALID_CRV           =	-3012,
+	Q931E_CALLID                =	-3013,
+	Q931E_CALLSTATE             =	-3014,
+	Q931E_CALLEDSUB             =	-3015,
+	Q931E_CALLEDNUM             =	-3016,
+	Q931E_CALLINGNUM            =	-3017,
+	Q931E_CALLINGSUB            =	-3018,
+	Q931E_CAUSE                 =	-3019,
+	Q931E_CHANID                =	-3020,
+	Q931E_DATETIME              =	-3021,
+	Q931E_DISPLAY               =	-3022,
+	Q931E_KEYPADFAC             =	-3023,
+	Q931E_NETFAC                =	-3024,
+	Q931E_NOTIFIND              =	-3025,
+	Q931E_PROGIND               =	-3026,
+	Q931E_RESTARTIND            =	-3027,
+	Q931E_SEGMENT               =	-3028,
+	Q931E_SIGNAL                =	-3029,
+	Q931E_GENERIC_DIGITS		=	-3030
+} q931_error_t;
+
+/* The q931_error_t enum should be kept in sync with the q931_error_names array in Q931.c */ 
+
+const char *q931_error_to_name(q931_error_t error);
+
+/*****************************************************************************
+
+	Some speed optimization can be achieved by changing all variables to the 
+	word size of your processor. A 32 bit processor has to do a lot of extra 
+	work to read a packed 8 bit integer. Changing all fields to 32 bit integer 
+	will result in usage of some extra space, but will speed up the stack.
+
+	The stack has been designed to allow L3UCHAR etc. to be any size of 8 bit
+	or larger.
+
+*****************************************************************************/
+
+#define L3UCHAR		unsigned char		/* Min 8 bit						*/
+#define L3USHORT	unsigned short		/* Min 16 bit unsigned				*/
+#define L3UINT		unsigned int		/* Min 16 bit unsigned	            */
+#define L3INT       int                 /* Min 16 bit signed                */
+#define L3ULONG		unsigned long		/* Min 32 bit						*/
+#define L3BOOL      char				/* Min 1 bit, valuse 0 & 1 only		*/
+
+#define L3TRUE      1
+#define L3FALSE     0 
+
+/*****************************************************************************
+
+  Global defines.
+
+*****************************************************************************/
+
+typedef L3USHORT ie;                /* Special data type to hold a dynamic  */
+                                    /* or optional information element as   */
+                                    /* part of a message struct. MSB = 1    */
+                                    /* indicate that the ie is present, the */
+                                    /* last 15 bits is an offset ( or the   */
+                                    /* value for single octet ) to the      */
+                                    /* struct holding the ie. Offset = 0    */
+                                    /* is buf[1] etc.                       */
+                                    /* ie == 0xffff indicates error         */
+
+/*****************************************************************************
+	
+	MAXTRUNKS sets how many physical trunks this system might have. This 
+	number should be keept at a minimum since it will use global space.
+
+	It is recommended that you leave MAXCHPERTRUNK as is
+
+*****************************************************************************/
+
+#define	Q931_LOGBUFSIZE	1024		/* size of logging buffer		*/
+
+#define Q931L4BUF	1000		/* size of message buffer		*/
+
+#define Q931L2BUF	300		/* size of message buffer		*/
+
+#define Q931MAXTRUNKS	4		/* Total number of trunks that will be	*/
+					/* processed by this instance of the	*/
+					/* stack				*/
+
+#define Q931MAXCHPERTRUNK	32	/* Number of channels per trunk. The	*/
+					/* stack uses a static set of 32	*/
+					/* channels regardless if it is E1, T1	*/
+					/* or BRI that actually is used.	*/
+
+#define Q931MAXCALLPERTRUNK	(Q931MAXCHPERTRUNK * 2)
+					/* Number of max active CRV per trunk.  */
+					/* Q.931 can have more calls than there */
+					/* are channels.			*/
+
+
+#define Q931_IS_BRI(x)		((x)->TrunkType == Q931_TrType_BRI || (x)->TrunkType == Q931_TrType_BRI_PTMP)
+#define Q931_IS_PRI(x)		(!Q931_IS_BRI(x))
+
+#define Q931_IS_PTP(x)		((x)->TrunkType != Q931_TrType_BRI_PTMP)
+#define Q931_IS_PTMP(X)		((x)->TrunkType == Q931_TrType_BRI_PTMP)
+
+#define Q931_BRI_MAX_CRV	127
+#define Q931_PRI_MAX_CRV	32767
+
+/*****************************************************************************
+
+  The following defines control the dialect switch tables and should only be
+  changed when a new dialect needs to be inserted into the stack.   
+
+  This stack uses an array of functions to know which function to call as   
+  it receives a SETUP message etc. A new dialect can when choose to use
+  the proc etc. for standard Q.931 or insert a modified proc.
+
+  This technique has also been used to distinguish between user and network
+  mode to make the code as easy to read and maintainable as possible.
+
+  A message and IE index have been used to save space. These indexes allowes
+  the message or IE code to be used directly and will give back a new index
+  into the table.
+
+*****************************************************************************/
+
+/* WARNING! Initialize Q931CreateDialectCB[] will NULL when increasing the */
+/* Q931MAXDLCT value to avoid Q931Initialize from crashing if one entry is */
+/* not used.								   */
+#define Q931MAXDLCT	8	/* Max dialects included in this        */
+				/* compile. User and Network count as   */
+				/* one dialect each.                    */
+
+#define Q931MAXMES	128		/* Number of messages				*/
+#define Q931MAXIE	255		/* Number of IE					*/
+#define Q931MAXUSEDIE	50		/* Maximum number of ie types per Dialect	*/
+#define Q931MAXCODESETS	7		/* Maximum number of codests (by spec, 0-7)	*/
+#define Q931MAXSTATE	100		/* Size of state tables			        */
+#define Q931MAXTIMER	25		/* Maximum number of timers 			*/
+
+/*****************************************************************************
+
+  Call States for ITU-T Q.931 TE (User Mode)
+
+*****************************************************************************/
+
+#define Q931_U0     0
+#define Q931_U1     1
+#define Q931_U2     2
+#define Q931_U3     3
+#define Q931_U4     4
+#define Q931_U6     6
+#define Q931_U7     7
+#define Q931_U8     8
+#define Q931_U9     9
+#define Q931_U10    10
+#define Q931_U11    11
+#define Q931_U12    12
+#define Q931_U15    15
+#define Q931_U17    17
+#define Q931_U19    19
+#define Q931_U25    25
+
+/*****************************************************************************
+
+  Call States for ITU-T Q.931 NT (Network Mode)
+
+*****************************************************************************/
+#define Q931_N0     (0x0100 | 0)
+#define Q931_N1     (0x0100 | 1)
+#define Q931_N2     (0x0100 | 2)
+#define Q931_N3     (0x0100 | 3)
+#define Q931_N4     (0x0100 | 4)
+#define Q931_N6     (0x0100 | 6)
+#define Q931_N7     (0x0100 | 7)
+#define Q931_N8     (0x0100 | 8)
+#define Q931_N9     (0x0100 | 9)
+#define Q931_N10    (0x0100 | 11)
+#define Q931_N11    (0x0100 | 11)
+#define Q931_N12    (0x0100 | 12)
+#define Q931_N15    (0x0100 | 15)
+#define Q931_N17    (0x0100 | 17)
+#define Q931_N19    (0x0100 | 19)
+#define Q931_N22    (0x0100 | 22)
+#define Q931_N25    (0x0100 | 25)
+
+/*****************************************************************************
+
+  Q.931 Message codes
+  
+*****************************************************************************/
+
+#define Q931mes_ALERTING             0x01 /* 0000 0001                   */        
+#define Q931mes_CALL_PROCEEDING      0x02 /* 0000 0010                   */
+#define Q931mes_CONNECT              0x07 /* 0000 0111                   */
+#define Q931mes_CONNECT_ACKNOWLEDGE  0x0f /* 0000 1111                   */
+#define Q931mes_PROGRESS             0x03 /* 0000 0011                   */
+#define Q931mes_SETUP                0x05 /* 0000 0101                   */
+#define Q931mes_SETUP_ACKNOWLEDGE    0x0d /* 0000 1101                   */
+#define Q931mes_RESUME               0x26 /* 0010 0110                   */
+#define Q931mes_RESUME_ACKNOWLEDGE   0x2e /* 0010 1110                   */
+#define Q931mes_RESUME_REJECT        0x22 /* 0010 0010                   */
+#define Q931mes_SUSPEND              0x25 /* 0010 0101                   */
+#define Q931mes_SUSPEND_ACKNOWLEDGE  0x2d /* 0010 1101                   */
+#define Q931mes_SUSPEND_REJECT       0x21 /* 0010 0001                   */
+#define Q931mes_USER_INFORMATION     0x20 /* 0010 0000                   */
+#define Q931mes_DISCONNECT           0x45 /* 0100 0101                   */
+#define Q931mes_RELEASE              0x4d /* 0100 1101                   */
+#define Q931mes_RELEASE_COMPLETE     0x5a /* 0101 1010                   */
+#define Q931mes_RESTART              0x46 /* 0100 0110                   */
+#define Q931mes_RESTART_ACKNOWLEDGE  0x4e /* 0100 1110                   */
+#define Q931mes_CONGESTION_CONTROL   0x79 /* 0111 1001                   */
+#define Q931mes_INFORMATION          0x7b /* 0111 1011                   */
+#define Q931mes_NOTIFY               0x6e /* 0110 1110                   */
+#define Q931mes_STATUS               0x7d /* 0111 1101                   */
+#define Q931mes_STATUS_ENQUIRY       0x75 /* 0111 0101                   */
+#define Q931mes_SEGMENT              0x60 /* 0110 0000                   */
+
+#define Q931mes_SERVICE              0x0f /* 0000 1111                   */
+#define Q931mes_SERVICE_ACKNOWLEDGE  0x07 /* 0000 0111                   */
+
+
+/**
+ * Generic Q.931 Timers
+ */
+enum {
+	Q931_TIMER_T300	= 1,		/* */
+	Q931_TIMER_T301,
+	Q931_TIMER_T302,
+	Q931_TIMER_T303,
+	Q931_TIMER_T304,
+	Q931_TIMER_T305,
+	Q931_TIMER_T306,
+	Q931_TIMER_T307,
+	Q931_TIMER_T308,
+	Q931_TIMER_T309,
+	Q931_TIMER_T310,
+	Q931_TIMER_T311,
+	Q931_TIMER_T312,
+	Q931_TIMER_T313,
+	Q931_TIMER_T314,
+	Q931_TIMER_T315,
+	Q931_TIMER_T316,
+	Q931_TIMER_T317,
+	Q931_TIMER_T318,
+	Q931_TIMER_T319,
+	Q931_TIMER_T320,
+	Q931_TIMER_T321,
+	Q931_TIMER_T322,
+};
+
+/**
+ * Q.931 ToN
+ */
+enum {
+	Q931_TON_UNKNOWN		= 0x00,
+	Q931_TON_INTERNATIONAL		= 0x01,
+	Q931_TON_NATIONAL		= 0x02,
+	Q931_TON_NETWORK_SPECIFIC	= 0x03,
+	Q931_TON_SUBSCRIBER_NUMBER	= 0x04,
+	Q931_TON_ABBREVIATED_NUMBER	= 0x06,
+	Q931_TON_RESERVED		= 0x07
+};
+
+/**
+ * Q.931 Numbering Plan
+ */
+enum {
+	Q931_NUMPLAN_UNKNOWN		= 0x00,
+	Q931_NUMPLAN_E164		= 0x01,
+	Q931_NUMPLAN_X121		= 0x03,
+	Q931_NUMPLAN_F69		= 0x04,
+	Q931_NUMPLAN_NATIONAL		= 0x08,
+	Q931_NUMPLAN_PRIVATE		= 0x09,
+	Q931_NUMPLAN_RESERVED		= 0x0e
+};
+
+/**
+ * Q.931 Presentation Indicator
+ */
+enum {
+	Q931_PRES_ALLOWED		= 0x00,
+	Q931_PRES_RESTRICTED		= 0x01,
+	Q931_PRES_NOT_AVAILABLE		= 0x02,
+	Q931_PRES_RESERVED		= 0x03
+};
+
+/**
+ * Q.931 Screening Indicator
+ */
+enum {
+	Q931_SCREEN_USER_NOT_SCREENED		= 0x00,
+	Q931_SCREEN_USER_VERIFIED_PASSED	= 0x01,
+	Q931_SCREEN_USER_VERIFIED_FAILED	= 0x02,
+	Q931_SCREEN_NETWORK			= 0x03
+};
+
+/**
+ * Q.931 Coding Standard
+ */
+enum {
+	Q931_CODING_ITU		= 0x00,
+	Q931_CODING_ISO		= 0x01,
+	Q931_CODING_NATIONAL	= 0x02,
+	Q931_CODING_NETWORK	= 0x03
+};
+
+/**
+ * Q.931 High layer characteristik id
+ */
+enum {
+	Q931_HLCHAR_TELEPHONY	= 0x01,
+	Q931_HLCHAR_FAX_G23	= 0x04,
+	Q931_HLCHAR_FAX_G4	= 0x21,
+	Q931_HLCHAR_FAX_G4II	= 0x24,
+	Q931_HLCHAR_T102	= 0x32,
+	Q931_HLCHAR_T101	= 0x33,
+	Q931_HLCHAR_F60		= 0x35,
+	Q931_HLCHAR_X400	= 0x38,
+	Q931_HLCHAR_X200	= 0x41
+};
+
+/**
+ * Q.931 User information layer 1 protocol
+ */
+enum {
+	Q931_UIL1P_V110		= 0x01,
+	Q931_UIL1P_I460		= 0x01,
+	Q931_UIL1P_X30		= 0x01,
+
+	Q931_UIL1P_G711U	= 0x02,
+	Q931_UIL1P_G711A	= 0x03,
+	Q931_UIL1P_G721		= 0x04,
+
+	Q931_UIL1P_H221		= 0x05,
+	Q931_UIL1P_H242		= 0x05,
+
+	Q931_UIL1P_H223		= 0x06,
+	Q931_UIL1P_H245		= 0x06,
+
+	Q931_UIL1P_RATE_ADAP	= 0x07,
+
+	Q931_UIL1P_V120		= 0x08,
+	Q931_UIL1P_X31		= 0x09
+};
+
+/**
+ * Q.931 Information Transfer Capability
+ */
+enum {
+	Q931_ITC_SPEECH			= 0x00,
+	Q931_ITC_UNRESTRICTED		= 0x08,
+	Q931_ITC_RESTRICTED		= 0x09,
+	Q931_ITC_3K1_AUDIO		= 0x10,
+	Q931_ITC_UNRESTRICTED_TONES	= 0x11,
+	Q931_ITC_VIDEO			= 0x18
+};
+
+/**
+ * Q.931 Information transfer rate
+ */
+enum {
+	Q931_ITR_PACKET	= 0x00,
+	Q931_ITR_64K	= 0x10,
+	Q931_ITR_128K	= 0x11,
+	Q931_ITR_384K	= 0x13,
+	Q931_ITR_1536K	= 0x15,
+	Q931_ITR_1920K	= 0x17,
+	Q931_ITR_MULTI	= 0x18
+};
+
+/*****************************************************************************
+
+  Struct:       Q931mes_Header
+
+  Description:  Used to read the header & message code.
+
+*****************************************************************************/
+typedef struct {
+	L3UINT	Size;           /* Size of message in bytes             */
+	L3UCHAR	ProtDisc;       /* Protocol Discriminator               */
+	L3UCHAR	MesType;        /* Message type                         */
+	L3UCHAR	CRVFlag;        /* Call reference value flag            */
+	L3INT	CRV;            /* Call reference value                 */
+
+} Q931mes_Header;
+
+/*****************************************************************************
+
+  Struct:       Q931mes_Generic
+
+  Description:  Generic header containing all IE's. This is not used, but is
+				provided in case a proprietary variant needs it.
+
+*****************************************************************************/
+typedef struct {
+	L3UINT		Size;           /* Size of message in bytes             */
+	L3UCHAR		ProtDisc;       /* Protocol Discriminator               */
+	L3UCHAR		MesType;        /* Message type                         */
+	L3UCHAR		CRVFlag;        /* Call reference value flag            */
+	L3INT		CRV;            /* Call reference value                 */
+
+	/* WARNING: don't touch anything above this line (TODO: use Q931mes_Header directly to make sure it's the same) */
+
+	L3UCHAR		Tei;            /* TEI                                  */
+
+	ie		Shift;
+	ie		MoreData;
+	ie		SendComplete;
+	ie		CongestionLevel;
+	ie		RepeatInd;
+
+	ie		Segment;        /* Segmented message                    */
+	ie		BearerCap;      /* Bearer Capability                    */
+	ie		Cause;          /* Cause                                */
+	ie		CallState;      /* Call State                           */
+	ie		CallID;			/* Call Identity                        */
+	ie		ChanID;         /* Channel Identification               */
+	ie		ChangeStatus;   /* Change Staus                         */
+	ie		ProgInd;        /* Progress Indicator                   */
+	ie		NetFac;         /* Network Spesific Facilities          */
+	ie		NotifInd;       /* Notification Indicator               */
+	ie		Display;        /* Display                              */
+	ie		DateTime;       /* Date/Time                            */
+	ie		KeypadFac;      /* Keypad Facility                      */
+	ie		Signal;         /* Signal                               */
+	ie		InfoRate;       /* Information rate                     */
+	ie		EndEndTxDelay;  /* End to End Transmit Delay            */
+	ie		TransDelSelInd; /* Transmit Delay Sel. and Ind.         */
+	ie		PackParam;      /* Packed Layer Binary parameters       */
+	ie		PackWinSize;    /* Packet Layer Window Size             */
+	ie		PackSize;       /* Packed Size                          */
+	ie		ClosedUserGrp;  /* Closed User Group                    */
+	ie		RevChargeInd;   /* Reverse Charging Indicator           */
+	ie		CalledNum;      /* Called Party Number                  */
+	ie		CalledSub;      /* Called Party subaddress              */
+	ie		CallingNum;     /* Calling Party Number                 */
+	ie		CallingSub;     /* Calling Party Subaddress             */
+	ie		RedirNum;       /* Redirection Number                   */
+	ie		TransNetSel;    /* Transmit Network Selection           */
+	ie		LLRepeatInd;    /* Repeat Indicator 2 LLComp            */
+	ie		RestartWin;     /* Restart Window                       */
+	ie		RestartInd;     /* Restart Indicator                    */
+	ie		LLComp;         /* Low Layer Compatibility              */
+	ie		HLComp;         /* High Layer Compatibility             */
+	ie		UserUser;       /* User-user                            */
+	ie		Escape;         /* Escape for extension                 */
+	ie		Switchhook;
+	ie		FeatAct;
+	ie		FeatInd;
+	ie		GenericDigits;
+
+	L3UCHAR		buf[1];			/* Buffer for IE's						*/
+
+} Q931mes_Generic;
+
+
+/*****************************************************************************
+
+  Struct:       Q931_TrunkInfo
+
+  Description:  TrunkInfo is the struct entry used to store Q.931 related 
+                information and state for E1/T1/J1 trunks and associated 
+                channels in the system. 
+
+				The user should store this information outside this stack
+				and needs to feed the interface functions with a pointer to
+				the TrunkInfo entry.
+
+*****************************************************************************/
+typedef struct Q931_TrunkInfo Q931_TrunkInfo_t;
+
+typedef enum {
+    Q931_LOG_NONE = -1,
+    Q931_LOG_EMERG,
+    Q931_LOG_ALERT,
+    Q931_LOG_CRIT,
+    Q931_LOG_ERROR,
+    Q931_LOG_WARNING,
+    Q931_LOG_NOTICE,
+    Q931_LOG_INFO,
+    Q931_LOG_DEBUG
+} Q931LogLevel_t;
+
+typedef L3INT (*Q931Tx34CB_t) (void *,L3UCHAR *, L3INT);
+typedef L3INT (*Q931Tx32CB_t) (void *, L3INT, L3UCHAR, L3UCHAR *, L3INT);
+typedef L3INT (*Q931ErrorCB_t) (void *,L3INT,L3INT,L3INT);
+typedef L3INT (*Q931LogCB_t) (void *, Q931LogLevel_t, char *, L3INT);
+
+typedef enum {					/* Network/User Mode.			*/
+	Q931_TE=0,				/*  0 : User Mode			*/
+	Q931_NT=1				/*  1 : Network Mode			*/
+} Q931NetUser_t;
+
+typedef enum {					/* Dialect enum                         */
+	Q931_Dialect_Q931     = 0,
+	Q931_Dialect_National = 2,
+	Q931_Dialect_DMS      = 4,
+	Q931_Dialect_5ESS     = 6,		/* Coming soon to a PRI stack near you! */
+
+	Q931_Dialect_Count
+} Q931Dialect_t;
+#define DIALECT_STRINGS "q931", "", "national", "", "dms", "", "5ess", ""
+Q931_STR2ENUM_P(q931_str2Q931Dialect_type, q931_Q931Dialect_type2str, Q931Dialect_t)
+
+typedef enum {					/* Trunk Line Type.			*/
+	Q931_TrType_E1 = 0,			/*  0 : E1 Trunk			*/
+	Q931_TrType_T1 = 1,			/*  1 : T1 Trunk			*/
+	Q931_TrType_J1 = 2,			/*  2 : J1 Trunk			*/
+	Q931_TrType_BRI	= 3,			/*  3 : BRI Trunk			*/
+	Q931_TrType_BRI_PTMP = 4		/*  4 : BRI PTMP Trunk			*/
+} Q931_TrunkType_t;
+
+typedef enum {					/* Trunk State			*/
+	Q931_TrState_NoAlignment=0,		/* Trunk not aligned		*/
+	Q931_TrState_Aligning=1,		/* Aligning in progress		*/
+	Q931_TrState_Aligned=2			/* Trunk Aligned		*/
+} Q931_TrunkState_t;
+
+typedef enum {
+	Q931_ChType_NotUsed=0,			/* Unused Channel						*/
+	Q931_ChType_B=1,			/* B Channel (Voice)					*/
+	Q931_ChType_D=2,			/* D Channel (Signalling)				*/
+	Q931_ChType_Sync=3			/* Sync Channel							*/
+} Q931_ChanType_t;
+
+struct Q931_Call
+{
+	L3UCHAR InUse;			/* Indicate if entry is in use.         */
+					/*  0 = Not in Use                      */
+					/*  1 = Active Call.                    */
+
+	L3UCHAR Tei;			/* Associated TEI 			*/
+
+	L3UCHAR BChan;			/* Associated B Channel.                */
+					/* 0 - 31 valid B chan			*/
+					/* 255 = Not allocated			*/
+
+	L3INT   CRV;			/* Associated CRV.                      */
+
+	L3UINT  State;			/* Call State.                          */
+					/*  0 is Idle, but other values are	*/
+					/*  defined per dialect.		*/
+					/*  Default usage is 1-99 for TE and    */
+					/*  101 - 199 for NT.			*/
+        
+	L3ULONG Timer;			/* Timer in ms. The TimeTick will check		*/
+					/* if this has exceeded the timeout, and	*/
+					/* if so call the timers timeout proc.		*/
+
+	L3USHORT TimerID;		/* Timer Identification/State           */
+					/* actual values defined by dialect	*/
+					/*  0 : No timer running                */
+					/*  ITU-T Q.931:301 - 322 Timer running */
+};
+
+struct Q931_TrunkInfo
+{
+	Q931NetUser_t    NetUser;		/* Network/User Mode.                   */
+	Q931_TrunkType_t TrunkType;		/* Trunk Line Type.                     */
+	Q931Dialect_t    Dialect;		/* Q.931 Based dialect index.           */
+
+	Q931Tx34CB_t     Q931Tx34CBProc;
+	Q931Tx32CB_t     Q931Tx32CBProc;
+	Q931ErrorCB_t    Q931ErrorCBProc;
+	Q931LogCB_t      Q931LogCBProc;
+	void *PrivateData32;
+	void *PrivateData34;
+	void *PrivateDataLog;
+
+	Q931LogLevel_t   loglevel;
+
+	L3UCHAR     Enabled;            /* Enabled/Disabled                     */
+                                    /*  0 = Disabled                        */
+                                    /*  1 = Enabled                         */
+
+	Q931_TrunkState_t TrunkState;
+
+    L3INT       LastCRV;            /* Last used crv for the trunk.         */
+
+    L3UCHAR L3Buf[Q931L4BUF];		/* message buffer for messages to be    */
+                                    /* send from Q.931 L4.                  */
+
+    L3UCHAR L2Buf[Q931L2BUF];		/* buffer for messages send to L2.      */
+
+	/* The auto flags below switch on/off automatic Ack messages. SETUP ACK */
+	/* as an example can be sent by the stack in response to SETUP to buy   */
+	/* time in processing on L4. Setting this to true will cause the stack  */
+	/* to automatically send this.											*/
+
+	L3BOOL	autoSetupAck;			/* Indicate if the stack should send    */
+									/* SETUP ACK or not. 0=No, 1 = Yes.		*/
+
+	L3BOOL  autoConnectAck;			/* Indicate if the stack should send    */
+									/* CONNECT ACT or not. 0=No, 1=Yes.		*/
+
+	L3BOOL  autoRestartAck;			/* Indicate if the stack should send    */
+									/* RESTART ACK or not. 0=No, 1=Yes.		*/
+
+	L3BOOL  autoServiceAck;			/* Indicate if the stack should send    */
+									/* SERVICE ACK or not. 0=No, 1=Yes.		*/
+
+	/* channel array holding info per channel. Usually defined to 32		*/
+	/* channels to fit an E1 since T1/J1 and BRI will fit inside a E1.		*/
+    struct _charray
+    {
+		Q931_ChanType_t ChanType;	/* Unused, B, D, Sync */
+
+        L3UCHAR Available;          /* Channel Available Flag               */
+                                    /*  0 : Avaiabled                       */
+                                    /*  1 : Used                            */
+
+        L3INT   CRV;                /* Associated CRV                       */
+
+    } ch[Q931MAXCHPERTRUNK];
+
+	/* Active Call information indentified by CRV. See Q931AllocateCRV for  */
+	/* initialization of call table.					*/
+	struct Q931_Call	call[Q931MAXCALLPERTRUNK];
+};
+
+/*****************************************************************************
+  
+  Struct:		Q931State
+
+  Description:	Define a Q931 State, legal events and next state for each
+				event. Used to simplify the state engine logic. Each state
+				engine defines its own state table and the logic need only
+				call a helper function to check if the message is legal
+				at this stage.
+
+*****************************************************************************/
+typedef struct
+{
+	L3INT		State;
+	L3INT		Message;
+	L3UCHAR		Direction;
+} Q931State;
+
+/*****************************************************************************
+
+  Proc table external references. 
+
+  The proc tables are defined in Q931.c and initialized in Q931Initialize.
+
+*****************************************************************************/
+typedef L3INT (q931proc_func_t) (Q931_TrunkInfo_t *pTrunk, L3UCHAR *, L3INT);
+
+typedef L3INT (q931umes_func_t) (Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT IOff, L3INT Size);
+typedef L3INT (q931pmes_func_t) (Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+
+typedef L3INT (q931uie_func_t) (Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff);
+typedef L3INT (q931pie_func_t) (Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet);
+
+typedef L3INT (q931timeout_func_t) (Q931_TrunkInfo_t *pTrunk, L3INT callIndex);
+typedef L3ULONG q931timer_t;
+
+extern q931proc_func_t *Q931Proc[Q931MAXDLCT][Q931MAXMES];
+
+extern q931umes_func_t *Q931Umes[Q931MAXDLCT][Q931MAXMES];
+extern q931pmes_func_t *Q931Pmes[Q931MAXDLCT][Q931MAXMES];
+
+extern q931uie_func_t *Q931Uie[Q931MAXDLCT][Q931MAXIE];
+extern q931pie_func_t *Q931Pie[Q931MAXDLCT][Q931MAXIE];
+
+extern q931timeout_func_t *Q931Timeout[Q931MAXDLCT][Q931MAXTIMER];
+extern q931timer_t         Q931Timer[Q931MAXDLCT][Q931MAXTIMER];
+
+
+/*****************************************************************************
+    
+  Macro:        GetIETotoSize
+
+  Syntax:       L3INT GetIETotSize(InfoElem ie);
+
+  Description:  Compute the total size in bytes of an info element including 
+                size of 'header'.    
+
+*****************************************************************************/
+#define Q931GetIETotSize(ie) (((ie.InfoID & 0x80) != 0) ? 1 : ie.LenIE) + 2)
+
+/*****************************************************************************
+
+  Macro:        IsIEPresent
+
+  Syntax:       BOOL IsIEPresent(ie InfoElement);
+
+  Description:  Return TRUE if the Information Element is included.
+
+*****************************************************************************/
+#define Q931IsIEPresent(x) ((x & 0x8000) != 0)
+
+/*****************************************************************************
+
+  Macro:        GetIEOffset and GetIEValue
+    
+  Syntax:       L3INT GetIEOffset(ie InfoElement)
+                L3INT GetIEValue(ie InfoElement)
+
+  Description:  Returns the offset (or the value )to the Information Element.
+
+  Note:         GetIEValue assumes that the 15 lsb bit is the value of a 
+                single octet information element. This macro can not be used
+                on a variable information element.
+
+*****************************************************************************/
+#define Q931GetIEOffset(x) (x & 0x7fff)
+#define Q931GetIEValue(x)  (x & 0x7fff)
+
+/*****************************************************************************
+
+  Macro:        Q931GetIEPtr
+
+  Syntax:       void * Q931GetIEPtr(ie InfoElement, L3UCHAR * Buf);
+
+  Description:  Compute a Ptr to the information element.
+
+*****************************************************************************/
+#define Q931GetIEPtr(ie,buf) ((void *)&buf[Q931GetIEOffset(ie)])
+
+/*****************************************************************************
+
+  Macro:        SetIE
+
+  Syntax:       void SetIE(ie InfoElement, L3INT Offset);
+
+  Description:  Set an information element.
+
+*****************************************************************************/
+#define Q931SetIE(x,o) { x = (ie)(o) | 0x8000; }
+
+/*****************************************************************************
+
+  Macro:        IsQ931Ext
+
+  Syntax        BOOL IsQ931Ext(L3UCHAR c)
+
+  Description:  Return true Check if the msb (bit 8) is 0. This indicate
+                that the octet is extended.
+
+*****************************************************************************/
+#define IsQ931Ext(x) ((x & 0x80) == 0)
+
+/*****************************************************************************
+
+  Macro:        ieGetOctet
+
+  Syntax:       unsigned L3UCHAR ieGetOctet(L3INT e)
+
+  Description:  Macro to fetch one byte from an integer. Mostly used to 
+                avoid warnings.
+
+*****************************************************************************/
+#define ieGetOctet(x) ((L3UCHAR)(x))
+
+/*****************************************************************************
+
+  Macro:        NoWarning
+
+  Syntax:       void NoWarning(x)
+
+  Description:  Macro to suppress unreferenced formal parameter warnings
+
+                Used during creation of the stack since the stack is 
+                developed for Warning Level 4 and this creates a lot of 
+                warning for the initial empty functions.
+
+*****************************************************************************/
+#define NoWarning(x) (x = x)
+
+/*****************************************************************************
+
+  External references. See Q931.c for details.
+
+*****************************************************************************/
+
+#include "Q931ie.h"
+
+#include "Q932.h"
+
+/*****************************************************************************
+
+  Q.931 Message Pack/Unpack functions. Implemented in Q931mes.c
+
+*****************************************************************************/
+L3INT Q931Pmes_Alerting(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q931Pmes_CallProceeding(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q931Pmes_Connect(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q931Pmes_ConnectAck(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q931Pmes_Progress(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q931Pmes_Setup(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q931Pmes_SetupAck(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q931Pmes_Resume(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q931Pmes_ResumeAck(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q931Pmes_ResumeReject(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q931Pmes_Suspend(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q931Pmes_SuspendAck(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q931Pmes_SuspendReject(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q931Pmes_UserInformation(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q931Pmes_Disconnect(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q931Pmes_Release(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q931Pmes_ReleaseComplete(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q931Pmes_Restart(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q931Pmes_RestartAck(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q931Pmes_CongestionControl(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q931Pmes_Information(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q931Pmes_Notify(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q931Pmes_Segment(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q931Pmes_Status(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q931Pmes_StatusEnquiry(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q931Pmes_Service(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q931Pmes_ServiceAck(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+
+
+L3INT Q931Umes_Alerting(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT I, L3INT O);
+L3INT Q931Umes_CallProceeding(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT I, L3INT O);
+L3INT Q931Umes_Connect(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT I, L3INT O);
+L3INT Q931Umes_ConnectAck(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT I, L3INT O);
+L3INT Q931Umes_Progress(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT I, L3INT O);
+L3INT Q931Umes_Setup(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT I, L3INT O);
+L3INT Q931Umes_SetupAck(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT I, L3INT O);
+L3INT Q931Umes_Resume(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT I, L3INT O);
+L3INT Q931Umes_ResumeAck(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT I, L3INT O);
+L3INT Q931Umes_ResumeReject(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT I, L3INT O);
+L3INT Q931Umes_Suspend(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT I, L3INT O);
+L3INT Q931Umes_SuspendAck(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT I, L3INT O);
+L3INT Q931Umes_SuspendReject(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT I, L3INT O);
+L3INT Q931Umes_UserInformation(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT I, L3INT O);
+L3INT Q931Umes_Disconnect(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT I, L3INT O);
+L3INT Q931Umes_Release(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT I, L3INT O);
+L3INT Q931Umes_ReleaseComplete(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT I, L3INT O);
+L3INT Q931Umes_Restart(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT I, L3INT O);
+L3INT Q931Umes_RestartAck(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT I, L3INT O);
+L3INT Q931Umes_CongestionControl(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT I, L3INT O);
+L3INT Q931Umes_Information(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT I, L3INT O);
+L3INT Q931Umes_Notify(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT I, L3INT O);
+L3INT Q931Umes_Segment(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT I, L3INT O);
+L3INT Q931Umes_Status(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT I, L3INT O);
+L3INT Q931Umes_StatusEnquiry(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT I, L3INT O);
+L3INT Q931Umes_Service(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size);
+L3INT Q931Umes_ServiceAck(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size);
+
+
+/*****************************************************************************
+
+  Q.931 Process Function Prototyping. Implemented in Q931StateTE.c
+
+*****************************************************************************/
+L3INT Q931ProcAlertingTE(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcCallProceedingTE(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcConnectTE(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcConnectAckTE(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcProgressTE(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcSetupTE(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcSetupAckTE(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcResumeTE(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcResumeAckTE(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcResumeRejectTE(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcSuspendTE(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcSuspendAckTE(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcSuspendRejectTE(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcUserInformationTE(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcDisconnectTE(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcReleaseTE(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcReleaseCompleteTE(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcRestartTE(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcRestartAckTE(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcCongestionControlTE(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcInformationTE(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcNotifyTE(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcStatusTE(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcStatusEnquiryTE(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcSegmentTE(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+
+L3INT Q931ProcAlertingNT(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcCallProceedingNT(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcConnectNT(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcConnectAckNT(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcProgressNT(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcSetupNT(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcSetupAckNT(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcResumeNT(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcResumeAckNT(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcResumeRejectNT(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcSuspendNT(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcSuspendAckNT(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcSuspendRejectNT(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcUserInformationNT(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcDisconnectNT(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcReleaseNT(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcReleaseCompleteNT(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcRestartNT(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcRestartAckNT(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcCongestionControlNT(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcInformationNT(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcNotifyNT(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcStatusNT(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcStatusEnquiryNT(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcSegmentNT(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+
+L3INT Q931ProcUnknownMessage(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+L3INT Q931ProcUnexpectedMessage(Q931_TrunkInfo_t *pTrunk,L3UCHAR * b, L3INT iFrom);
+
+/*****************************************************************************
+
+  Interface Function Prototypes. Implemented in Q931.c
+
+*****************************************************************************/
+void    Q931TimerTick(Q931_TrunkInfo_t *pTrunk);
+L3INT   Q931Rx23(Q931_TrunkInfo_t *pTrunk, L3INT ind, L3UCHAR tei, L3UCHAR * Mes, L3INT Size);
+L3INT   Q931Tx32Data(Q931_TrunkInfo_t *pTrunk, L3UCHAR bcast, L3UCHAR * Mes, L3INT Size);
+L3INT   Q931Rx43(Q931_TrunkInfo_t *pTrunk, L3UCHAR * Mes, L3INT Size);
+L3INT   Q931Tx34(Q931_TrunkInfo_t *pTrunk, L3UCHAR * Mes, L3INT Size);
+void    Q931SetError(Q931_TrunkInfo_t *pTrunk,L3INT ErrID, L3INT ErrPar1, L3INT ErrPar2);
+
+void	Q931SetDefaultErrorCB(Q931ErrorCB_t Q931ErrorPar);
+
+void    Q931CreateTE(L3UCHAR i);
+void    Q931CreateNT(L3UCHAR i);
+void    Q931SetMesCreateCB(L3INT (*callback)(void));
+void    Q931SetDialectCreateCB(L3INT (*callback)(L3INT));
+void    Q931SetHeaderSpace(L3INT space);
+
+void Q931SetMesProc(L3UCHAR mes, L3UCHAR dialect, q931proc_func_t *Q931ProcFunc, q931umes_func_t *Q931UmesFunc, q931pmes_func_t *Q931PmesFunc);
+void Q931SetIEProc(L3UCHAR iec, L3UCHAR dialect, q931pie_func_t *Q931PieProc, q931uie_func_t *Q931UieProc);
+void Q931SetTimeoutProc(L3UCHAR dialect, L3UCHAR timer, q931timeout_func_t *Q931TimeoutProc);
+void Q931SetTimerDefault(L3UCHAR dialect, L3UCHAR timer, q931timer_t timeout);
+
+void Q931Initialize(void);
+void Q931AddDialect(L3UCHAR iDialect, void (*Q931CreateDialectCB)(L3UCHAR iDialect));
+L3INT Q931InitMesSetup(Q931mes_Generic *p);
+L3INT Q931InitMesRestartAck(Q931mes_Generic * pMes);
+L3INT Q931InitMesGeneric(Q931mes_Generic *pMes);
+
+L3INT	Q931CreateCRV(Q931_TrunkInfo_t *pTrunk, L3INT * callIndex);
+L3INT	Q931ReleaseCRV(Q931_TrunkInfo_t *pTrunk, L3INT CRV);
+L3INT	Q931AllocateCRV(Q931_TrunkInfo_t *pTrunk, L3INT iCRV, L3INT * callIndex);
+L3INT   Q931FindCRV(Q931_TrunkInfo_t *pTrunk, L3INT crv, L3INT *callindex);
+L3INT	Q931GetCallState(Q931_TrunkInfo_t *pTrunk, L3INT iCRV);
+L3INT	Q931StartTimer(Q931_TrunkInfo_t *pTrunk, L3INT callIndex, L3USHORT iTimer);
+L3INT	Q931StopTimer(Q931_TrunkInfo_t *pTrunk, L3INT callindex, L3USHORT iTimer);
+L3INT	Q931SetState(Q931_TrunkInfo_t *pTrunk, L3INT callIndex, L3INT iState);
+L3ULONG Q931GetTime(void);
+void    Q931SetGetTimeCB(L3ULONG (*callback)(void));
+void	Q931AddStateEntry(L3UCHAR iD, L3INT iState, L3INT iMes, L3UCHAR cDir);
+L3BOOL	Q931IsEventLegal(L3UCHAR iD, L3INT iState, L3INT iMes, L3UCHAR cDir);
+
+/*****************************************************************************
+
+  Q.931 Low Level API Function Prototyping. Implemented in Q931API.c
+
+*****************************************************************************/
+ie Q931AppendIE(L3UCHAR *pm, L3UCHAR *pi);
+L3INT Q931GetUniqueCRV(Q931_TrunkInfo_t *pTrunk);
+
+L3INT Q931InitIEBearerCap(Q931ie_BearerCap *p);
+L3INT Q931InitIEChanID(Q931ie_ChanID *p);
+L3INT Q931InitIEProgInd(Q931ie_ProgInd *p);
+L3INT Q931InitIENetFac(Q931ie_NetFac * pIE);
+L3INT Q931InitIEDisplay(Q931ie_Display * pIE);
+L3INT Q931InitIEDateTime(Q931ie_DateTime * pIE);
+L3INT Q931InitIEKeypadFac(Q931ie_KeypadFac * pIE);
+L3INT Q931InitIESignal(Q931ie_Signal * pIE);
+L3INT Q931InitIECallingNum(Q931ie_CallingNum * pIE);
+L3INT Q931InitIECallingSub(Q931ie_CallingSub * pIE);
+L3INT Q931InitIECalledNum(Q931ie_CalledNum * pIE);
+L3INT Q931InitIECalledSub(Q931ie_CalledSub * pIE);
+L3INT Q931InitIETransNetSel(Q931ie_TransNetSel * pIE);
+L3INT Q931InitIELLComp(Q931ie_LLComp * pIE);
+L3INT Q931InitIEHLComp(Q931ie_HLComp * pIE);
+
+L3INT Q931Disconnect(Q931_TrunkInfo_t *pTrunk, L3INT iTo, L3INT iCRV, L3INT iCause);
+L3INT Q931ReleaseComplete(Q931_TrunkInfo_t *pTrunk, L3UCHAR *buf);
+L3INT Q931AckRestart(Q931_TrunkInfo_t *pTrunk, L3UCHAR *buf);
+L3INT Q931AckConnect(Q931_TrunkInfo_t *pTrunk, L3UCHAR *buf);
+L3INT Q931AckSetup(Q931_TrunkInfo_t *pTrunk, L3UCHAR *buf);
+L3INT Q931AckService(Q931_TrunkInfo_t *pTrunk, L3UCHAR *buf);
+
+L3INT Q931Api_InitTrunk(Q931_TrunkInfo_t *pTrunk,
+						Q931Dialect_t Dialect,
+						Q931NetUser_t NetUser,
+						Q931_TrunkType_t TrunkType,
+						Q931Tx34CB_t Q931Tx34CBProc,
+						Q931Tx32CB_t Q931Tx32CBProc,
+						Q931ErrorCB_t Q931ErrorCBProc,
+						void *PrivateData32,
+						void *PrivateData34);
+
+L3INT Q931GetMesSize(Q931mes_Generic *pMes);
+L3INT Q931InitMesResume(Q931mes_Generic * pMes);
+
+L3INT Q931Log(Q931_TrunkInfo_t *trunk, Q931LogLevel_t level, const char *fmt, ...);
+void Q931SetLogCB(Q931_TrunkInfo_t *trunk, Q931LogCB_t func, void *priv);
+void Q931SetLogLevel(Q931_TrunkInfo_t *trunk, Q931LogLevel_t level);
+
+void Q931SetL4HeaderSpace(L3INT space);
+void Q931SetL2HeaderSpace(L3INT space);
+L3INT Q931ProcDummy(Q931_TrunkInfo_t *pTrunk, L3UCHAR * b,L3INT c);
+L3INT Q931UmesDummy(Q931_TrunkInfo_t *pTrunk,L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT IOff, L3INT Size);
+L3INT Q931UieDummy(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff);
+L3INT Q931PmesDummy(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q931PieDummy(Q931_TrunkInfo_t *pTrunk,L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet);
+L3INT Q931TxDummy(Q931_TrunkInfo_t *pTrunk, L3UCHAR * b, L3INT n);
+L3INT Q931ErrorDummy(void *priv, L3INT a, L3INT b, L3INT c);
+L3INT Q931TimeoutDummy(Q931_TrunkInfo_t *pTrunk, L3INT callIndex);
+
+L3INT Q931MesgHeader(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *mes, L3UCHAR *OBuf, L3INT Size, L3INT *IOff);
+
+#endif /* _Q931_NL */

Added: freeswitch/trunk/libs/openzap/src/isdn/include/Q931ie.h (0 => 17141)


--- freeswitch/trunk/libs/openzap/src/isdn/include/Q931ie.h	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/src/isdn/include/Q931ie.h	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,1205 @@
+/******************************************************************************
+
+  FileName:         Q931ie.h
+
+  Contents:         Header and definition for the ITU-T Q.931 ie
+					structures and functions
+
+  License/Copyright:
+
+  Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+  email:janvb@caselaboratories.com  
+
+  Redistribution and use in source and binary forms, with or without 
+  modification, are permitted provided that the following conditions are 
+  met:
+
+    * Redistributions of source code must retain the above copyright notice, 
+	  this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright notice, 
+	  this list of conditions and the following disclaimer in the documentation 
+	  and/or other materials provided with the distribution.
+    * Neither the name of the Case Labs, Ltd nor the names of its contributors 
+	  may be used to endorse or promote products derived from this software 
+	  without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
+  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
+  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+  POSSIBILITY OF SUCH DAMAGE.
+******************************************************************************/
+
+#ifndef _Q931IE_NL
+#define _Q931IE_NL
+
+/* Codesets */
+
+typedef enum {
+
+	Q931_CODESET_0			= ( 0 ),
+	Q931_CODESET_1			= ( 1 << 8 ),
+	Q931_CODESET_2			= ( 2 << 8 ),
+	Q931_CODESET_3			= ( 3 << 8 ),
+	Q931_CODESET_4			= ( 4 << 8 ),
+	Q931_CODESET_5			= ( 5 << 8 ),
+	Q931_CODESET_6			= ( 6 << 8 ),
+	Q931_CODESET_7			= ( 7 << 8 )
+
+} q931_codeset_t;
+
+/* Single octet information elements */
+#define Q931ie_SHIFT                            0x90 /* 1001 ----       */
+#define Q931ie_MORE_DATA                        0xa0 /* 1010 ----       */
+#define Q931ie_SENDING_COMPLETE                 0xa1 /* 1010 0001       */
+#define Q931ie_CONGESTION_LEVEL                 0xb0 /* 1011 ----       */
+#define Q931ie_REPEAT_INDICATOR                 0xd0 /* 1101 ----       */
+
+/* Variable Length Information Elements */
+#define Q931ie_SEGMENTED_MESSAGE                0x00 /* 0000 0000       */
+#define Q931ie_CHANGE_STATUS                    0x01 /* 0000 0001       */
+#define Q931ie_BEARER_CAPABILITY                0x04 /* 0000 0100       */
+#define Q931ie_CAUSE                            0x08 /* 0000 1000       */
+#define Q931ie_CALL_IDENTITY                    0x10 /* 0001 0000       */
+#define Q931ie_CALL_STATE                       0x14 /* 0001 0100       */
+#define Q931ie_CHANNEL_IDENTIFICATION           0x18 /* 0001 1000       */
+#define Q931ie_PROGRESS_INDICATOR               0x1e /* 0001 1110       */
+#define Q931ie_NETWORK_SPECIFIC_FACILITIES      0x20 /* 0010 0000       */
+#define Q931ie_NOTIFICATION_INDICATOR           0x27 /* 0010 0111       */
+#define Q931ie_DISPLAY                          0x28 /* 0010 1000       */
+#define Q931ie_DATETIME                         0x29 /* 0010 1001       */
+#define Q931ie_KEYPAD_FACILITY                  0x2c /* 0010 1100       */
+#define Q931ie_SIGNAL                           0x34 /* 0011 0100       */
+#define Q931ie_SWITCHOOK                        0x36 /* 0011 0110       */
+#define Q931ie_FEATURE_ACTIVATION               0x38 /* 0011 1000       */
+#define Q931ie_FEATURE_INDICATION               0x39 /* 0011 1001       */
+#define Q931ie_INFORMATION_RATE                 0x40 /* 0100 0000       */
+#define Q931ie_END_TO_END_TRANSIT_DELAY         0x42 /* 0100 0010       */
+#define Q931ie_TRANSIT_DELAY_SELECTION_AND_IND  0x43 /* 0100 0011       */
+#define Q931ie_PACKED_LAYER_BIMARY_PARAMETERS   0x44 /* 0100 0100       */
+#define Q931ie_PACKED_LAYER_WINDOW_SIZE         0x45 /* 0100 0101       */
+#define Q931ie_PACKED_SIZE                      0x46 /* 0100 0110       */
+#define Q931ie_CALLING_PARTY_NUMBER             0x6c /* 0110 1100       */
+#define Q931ie_CALLING_PARTY_SUBADDRESS         0x6d /* 0110 1101       */
+#define Q931ie_CALLED_PARTY_NUMBER              0x70 /* 0111 0000       */
+#define Q931ie_CALLED_PARTY_SUBADDRESS          0x71 /* 0111 0001       */
+#define Q931ie_REDIRECTING_NUMBER               0x74 /* 0111 0100       */
+#define Q931ie_TRANSIT_NETWORK_SELECTION        0x78 /* 0111 1000       */
+#define Q931ie_RESTART_INDICATOR                0x79 /* 0111 1001       */
+#define Q931ie_LOW_LAYER_COMPATIBILITY          0x7c /* 0111 1100       */
+#define Q931ie_HIGH_LAYER_COMPATIBILITY         0x7d /* 0111 1101       */
+#define Q931ie_USER_USER                        0x7e /* 0111 1110       */
+#define Q931ie_ESCAPE_FOR_EX                    0x7f /* 0111 1111       */
+
+/* Variable Length Codeset 6 Information Elements */
+#define Q931ie_GENERIC_DIGITS                   0x37 /* 0011 0111       */
+
+/* Variable Length Information Element to shut up BRI testing */
+#define Q931ie_CONNECTED_NUMBER                 0x4c /* 0100 1101 */
+#define Q931ie_FACILITY                         0x1c /* 0001 1101 */
+
+
+/*****************************************************************************
+
+  Struct:        Q931ie_BearerCap
+
+  Description:   Bearer Capability Information Element.
+
+*****************************************************************************/
+
+typedef struct {
+
+    L3UCHAR IEId;                   /* 00000100 for Bearer Capability       */
+    L3UCHAR Size;                   /* Length of Information Element        */
+
+    L3UCHAR CodStand;               /* Coding Standard.                     */
+                                    /*  00 - ITU-T                          */
+                                    /*  01 - ISO/IEC                        */
+                                    /*  10 - National standard              */
+                                    /*  11 - Network side spesific          */
+
+    L3UCHAR ITC;                    /* Information Transfer Capability      */
+                                    /*  00000 - Speech                      */
+                                    /*  01000 - Unrestricted digital info   */
+                                    /*  01001 - Restricted digital info     */
+                                    /*  10000 - 3.1 kHz audio               */
+                                    /*  10001 - Unrestricted with tones     */
+                                    /*  11000 - Video                       */
+
+    L3UCHAR TransMode;              /* Transfer Mode.                       */
+                                    /*  00 - Circuit mode                   */
+                                    /*  10 - Packet mode                    */
+
+    L3UCHAR ITR;                    /* Information Transfer Rate.           */
+                                    /*  00000 - Packed mode                 */
+                                    /*  10000 - 64 kbit/s                   */
+                                    /*  10001 - 2 x 64 kbit/s               */
+                                    /*  10011 - 384 kbit/s                  */
+                                    /*  10101 - 1536 kbit/s                 */
+                                    /*  10111 - 1920 kbit/s                 */
+                                    /*  11000 - Multirat (64 kbit/s base)   */
+
+    L3UCHAR RateMul;                /* Rate Multiplier                      */
+
+    L3UCHAR Layer1Ident;			/* Layer 1 Ident.						*/
+
+    L3UCHAR UIL1Prot;               /* User Information Layer 1 Protocol    */
+									/*	00001 : ITU-T V.110, I.460 and X.30 */
+									/*  00010 : G.711 my-law				*/
+									/*  00011 : G.711 A-law					*/
+									/*  00100 : G.721						*/
+                                    /*  00101 : H.221 and H.242				*/
+									/*  00110 : H.223 and H.245				*/
+									/*  00111 : Non ITU-T Standard			*/
+									/*  01000 : ITU-T V.120					*/
+									/*  01001 : ITU-T X.31 HDLC flag stuff.	*/
+
+    L3UCHAR SyncAsync;              /* Sync/Async                           */
+									/*	0 : Syncronous data					*/
+									/*	1 : Asyncronous data				*/
+
+    L3UCHAR Negot;					/* Negotiation							*/
+									/*	0 : In-band negotiation not possib.	*/
+									/*  1 : In-band negotiation possible	*/
+
+    L3UCHAR UserRate;				/* User rate							*/
+									/*	00000 : I.460, V.110, X,30			*/
+									/*  00001 : 0.6 kbit/s x.1				*/
+									/*  00010 : 1.2 kbit/s					*/
+									/*  00011 : 2.4 kbit/s					*/
+									/*  00100 : 3.6 kbit/s					*/
+									/*  00101 : 4.8 kbit/s					*/
+									/*  00110 : 7.2 kbit/s					*/
+									/*  00111 : 8 kbit/s I.460				*/
+									/*  01000 : 9.6 kbit/s					*/
+									/*  01001 : 14.4 kbit/s					*/
+									/*  01010 : 16 kbit/s					*/
+									/*  01011 :	19.2 kbit/s					*/
+									/*  01100 : 32 kbit/s					*/
+									/*  01101 : 38.4 kbit/s					*/
+									/*  01110 : 48 kbit/s					*/
+									/*  01111 : 56 kbit/s					*/
+									/*  10000 : 57.6 kbit/s					*/
+									/*  10010 : 28.8 kbit/s					*/
+									/*  10100 : 24 kbit/s					*/
+									/*  10101 : 0.1345 kbit/s				*/
+									/*  10110 : 0.100 kbit/s				*/
+									/*  10111 : 0.075/1.2 kbit/s			*/
+									/*  11000 : 1.2/0.075/kbit/s			*/
+									/*  11001 : 0.050 kbit/s				*/
+									/*  11010 : 0.075 kbit/s				*/
+									/*  11011 : 0.110 kbit/s				*/
+									/*  11100 : 0.150 kbit/s				*/
+									/*  11101 : 0.200 kbit/s				*/
+									/*  11110 : 0.300 kbit/s				*/
+									/*  11111 : 12 kbit/s					*/
+
+    L3UCHAR InterRate;              /* Intermediate Rate                    */
+									/*	00 : Not used						*/
+									/*  01 : 8 kbit/s						*/
+									/*  10 : 16 kbit/s						*/
+									/*  11 : 32 kbit/s						*/
+
+    L3UCHAR NIConTx;				/* Network Indepentend Clock on transmit*/
+									/*	0 : Not required to send data  clc  */
+									/*  1 : Send data w/NIC clc				*/
+
+    L3UCHAR NIConRx;				/* NIC on Rx							*/
+									/*	0 : Cannot accept indep. clc		*/
+									/*  1 : data with indep. clc accepted	*/
+
+    L3UCHAR FlowCtlTx;              /* Flow control on Tx                   */
+									/*  0 : Send Flow ctrl not required		*/
+									/*  1 : Send flow ctrl required			*/
+
+    L3UCHAR FlowCtlRx;              /* Flow control on Rx                   */
+									/*  0 : cannot use receive flow ctrl	*/
+									/*  1 : Receive flow ctrl accepted		*/
+    L3UCHAR HDR;					/* HDR/No HDR							*/
+    L3UCHAR MultiFrame;             /* Multi frame support                  */
+									/*  0 : multiframe not supported		*/
+									/*  1 : multiframe supported			*/
+
+    L3UCHAR Mode;					/* Mode of operation					*/
+									/*	0 : bit transparent mode of operat.	*/
+									/*	1 : protocol sesitive mode of op.	*/
+
+    L3UCHAR LLInegot;				/* Logical link id negotiation (oct. 5b)*/
+									/*  0 : default LLI=256 only			*/
+									/*  1 : Full protocol negotiation		*/
+
+    L3UCHAR Assignor;               /* Assignor/assignee                    */
+									/*  0 : Default Asignee					*/
+									/*  1 : Assignor only					*/
+
+    L3UCHAR InBandNeg;              /* In-band/out-band negot.              */
+									/*  0 : negot done w/ USER INFO mes		*/
+									/*  1 : negot done in-band w/link zero	*/
+
+    L3UCHAR NumStopBits;            /* Number of stop bits					*/
+									/*  00 : Not used						*/
+									/*  01 : 1 bit							*/
+									/*  10 : 1.5 bits						*/
+									/*  11 : 2 bits							*/
+
+    L3UCHAR NumDataBits;            /* Number of data bits.                 */
+									/*  00 : not used						*/
+									/*  01 : 5 bits							*/
+									/*  10 : 7 bits							*/
+									/*  11 : 8 bits							*/
+
+    L3UCHAR Parity;					/* Parity Information					*/
+									/*	000 : Odd							*/
+									/*  010 : Even							*/
+									/*  011 : None							*/
+									/*  100 : Forced to 0					*/
+									/*  101 : Forced to 1					*/
+
+    L3UCHAR DuplexMode;				/* Mode duplex							*/
+									/*  0 : Half duplex						*/
+									/*  1 : Full duplex						*/
+
+    L3UCHAR ModemType;				/* Modem type, see Q.931 p 64			*/
+
+    L3UCHAR Layer2Ident;			/* Layer 2 Ident						*/
+
+    L3UCHAR UIL2Prot;               /* User Information Layer 2 Protocol    */
+									/*	00010 : Q.921/I.441					*/
+									/*  00110 : X.25						*/
+									/*  01100 : LAN logical link			*/
+
+    L3UCHAR Layer3Ident;            /* Layer 3 ident.						*/
+
+    L3UCHAR UIL3Prot;               /* User Information Layer 3 Protocol    */
+									/*	00010 : Q.931						*/
+									/*  00110 : X.25						*/
+									/*  01011 : ISO/IEC TR 9577				*/
+
+    L3UCHAR AL3Info1;				/* additional layer 3 info 1			*/
+
+    L3UCHAR AL3Info2;				/* additional layer 3 info 2			*/
+
+} Q931ie_BearerCap;
+
+/*****************************************************************************
+
+  Struct:       Q931ie_CallID
+
+
+*****************************************************************************/
+
+typedef struct {
+
+    L3UCHAR IEId;                   /* 00010000                             */
+    L3UCHAR Size;                   /* Length of Information Element        */
+    L3UCHAR CallId[1];				/* Call identity                        */
+
+} Q931ie_CallID;
+
+/*****************************************************************************
+
+  Struct:       Q931ie_CallState
+
+
+*****************************************************************************/
+
+typedef struct {
+
+    L3UCHAR IEId;                   /* 00010100                             */
+    L3UCHAR Size;                   /* Length of Information Element        */
+    L3UCHAR CodStand;               /* Coding Standard                      */
+    L3UCHAR CallState;              /* Call State Value                     */
+
+} Q931ie_CallState;
+
+/*****************************************************************************
+
+  Struct:		Q931ie_Cause
+
+  Description:	Cause IE as described in Q.850
+
+*****************************************************************************/
+typedef struct {
+
+    L3UCHAR IEId;                   /* 00010100                             */
+    L3UCHAR Size;                   /* Length of Information Element        */
+    L3UCHAR CodStand;               /* Coding Standard                      */
+	L3UCHAR Location;				/* Location								*/
+	L3UCHAR Recom;					/* Recommendation						*/
+	L3UCHAR Value;					/* Cause Value							*/
+	L3UCHAR	Diag[1];				/* Optional Diagnostics Field			*/
+
+} Q931ie_Cause;
+
+/*****************************************************************************
+
+  Struct:        Q931ie_CalledNum
+
+*****************************************************************************/
+typedef struct {
+
+    L3UCHAR IEId;                   /* 01110000                             */
+    L3UCHAR Size;                   /* Length of Information Element        */
+    L3UCHAR TypNum;                 /* Type of Number                       */
+    L3UCHAR NumPlanID;              /* Numbering plan identification        */
+    L3UCHAR Digit[1];				/* Digit (IA5)                          */
+
+} Q931ie_CalledNum;
+
+/*****************************************************************************
+
+  Struct:       Q931ie_CalledSub
+
+  Description:  Called party subaddress
+
+*****************************************************************************/
+
+typedef struct {
+
+    L3UCHAR IEId;                   /* 01110001                             */
+    L3UCHAR Size;                   /* Length of Information Element        */
+    L3UCHAR TypNum;                 /* Type of subaddress                   */
+    L3UCHAR OddEvenInd;             /* Odd/Even indicator                   */
+    L3UCHAR Digit[1];				/* digits                               */
+
+} Q931ie_CalledSub;
+
+/*****************************************************************************
+
+  Struct:       Q931ie_CallingNum
+
+  Description:  Calling party number
+
+*****************************************************************************/
+
+typedef struct {
+
+    L3UCHAR IEId;                   /* 01101100                             */
+    L3UCHAR Size;                   /* Length of Information Element        */
+    L3UCHAR TypNum;                 /* Type of number                       */
+    L3UCHAR NumPlanID;              /* Numbering plan identification        */
+    L3UCHAR PresInd;                /* Presentation indicator               */
+    L3UCHAR ScreenInd;              /* Screening indicator                  */
+    L3UCHAR Digit[1];				/* Number digits (IA5)                  */
+
+} Q931ie_CallingNum;
+
+/*****************************************************************************
+
+  Struct:        Q931ie_CallingSub
+
+  Description:   Calling party subaddress
+
+*****************************************************************************/
+
+typedef struct {
+
+    L3UCHAR IEId;                   /* 01101101                             */
+    L3UCHAR Size;                   /* Length of Information Element        */
+    L3UCHAR TypNum;                 /* Type of subaddress                   */
+    L3UCHAR OddEvenInd;             /* Odd/Even indicator                   */
+    L3UCHAR Digit[1];				/* digits                               */
+
+} Q931ie_CallingSub;
+
+/*****************************************************************************
+
+  Struct:       Q931ie_ChanID
+
+  Description:  Channel identification
+
+				Channel Identificationis one of the IE elements that differ
+				between BRI and PRI. IntType = 1 = BRI and ChanSlot is used
+				for channel number, while InfoChanSel is used for BRI.
+
+				ChanID is one of the most important IE as it is passed	
+				either though SETUP or CALL PROCEEDING to select the channel
+				to be used.
+
+*****************************************************************************/
+
+typedef struct {
+
+    L3UCHAR IEId;                   /* 00011000                             */
+    L3UCHAR Size;                   /* Length of Information Element        */
+    L3UCHAR IntIDPresent;           /* Int. id. present                     */
+    L3UCHAR IntType;                /* Interface Type                       */
+									/*	0 : Basic Interface	(BRI)			*/
+									/*  1 : Other interfaces, PRI etc.		*/
+
+    L3UCHAR PrefExcl;               /* Pref./Excl.                          */
+									/*	0 : Indicated channel is preffered	*/
+									/*  1 : Exclusive, no other accepted	*/
+
+    L3UCHAR DChanInd;               /* D-channel ind.                       */
+									/*  0 : chan is NOT D chan.				*/
+									/*  1 : chan is D chan					*/
+
+    L3UCHAR InfoChanSel;            /* Info. channel selection              */
+									/*  00 : No channel						*/
+									/*  01 : B1 channel						*/
+									/*  10 : B2 channel						*/
+									/*  11 : Any channel					*/
+
+    L3UCHAR InterfaceID;            /* Interface identifier                 */
+
+    L3UCHAR CodStand;		        /* Code standard                        */
+									/*  00 : ITU-T standardization coding	*/
+									/*  01 : ISO/IEC Standard				*/
+									/*  10 : National Standard				*/
+									/*  11 : Standard def. by network.		*/
+
+    L3UCHAR NumMap;                 /* Number/Map                           */
+									/*  0 : chan is in following octet		*/
+									/*  1 : chan is indicated by slot map	*/
+
+    L3UCHAR ChanMapType;            /* Channel type/Map element type        */
+									/*  0011 : B Channel units				*/
+									/*  0110 : H0 channel units				*/
+									/*  1000 : H11 channel units			*/
+									/*  1001 : H12 channel units			*/
+
+    L3UCHAR ChanSlot;               /* Channel number						*/
+
+} Q931ie_ChanID;
+
+/*****************************************************************************
+
+  Struct:       Q931ie_DateTime
+
+  Description:  Date/time
+
+*****************************************************************************/
+
+typedef struct {
+
+    L3UCHAR IEId;                   /* 00101001                             */
+    L3UCHAR Size;                   /* Length of Information Element        */
+    L3UCHAR Year;                   /* Year                                 */
+    L3UCHAR Month;                  /* Month                                */
+    L3UCHAR Day;                    /* Day                                  */
+    L3UCHAR Hour;                   /* Hour                                 */
+    L3UCHAR Minute;                 /* Minute                               */
+    L3UCHAR Second;                 /* Second                               */
+	L3UCHAR Format;					/* Indicate presense of Hour, Min & sec */
+									/*	0 : Only Date						*/
+									/*  1 : Hour present					*/
+									/*  2 : Hour and Minute present			*/
+									/*  3 : Hour, Minute and Second present	*/
+} Q931ie_DateTime;
+
+/*****************************************************************************
+
+  Struct:       Q931ie_Display
+
+  Description:  Display
+
+*****************************************************************************/
+
+typedef struct {
+
+    L3UCHAR IEId;                   /* 00101000                             */
+    L3UCHAR Size;                   /* Length of Information Element        */
+    L3UCHAR Display[1];             /* Display information (IA5)            */
+
+} Q931ie_Display;
+
+/*****************************************************************************
+
+  Struct:       Q931ie_HLComp
+
+  Description:  High layer compatibility
+
+*****************************************************************************/
+
+typedef struct {
+
+    L3UCHAR IEId;                   /* 01111101                             */
+    L3UCHAR Size;                   /* Length of Information Element        */
+    L3UCHAR CodStand;               /* Coding standard                      */
+    L3UCHAR Interpret;              /* Interpretation                       */
+    L3UCHAR PresMeth;               /* Presentation methor of prot. profile */
+    L3UCHAR HLCharID;               /* High layer characteristics id.       */
+    L3UCHAR EHLCharID;              /* Extended high layer character. id.   */
+    L3UCHAR EVideoTlfCharID;        /* Ext. videotelephony char. id.        */
+
+} Q931ie_HLComp;
+
+/*****************************************************************************
+
+  Struct:       Q931ie_KeypadFac
+
+  Description:  Keypad facility
+
+*****************************************************************************/
+
+typedef struct {
+    L3UCHAR IEId;                   /* 00101100                             */
+    L3UCHAR Size;                   /* Length of Information Element        */
+    L3UCHAR KeypadFac[1];           /* dynamic buffer                       */
+
+} Q931ie_KeypadFac;
+
+/*****************************************************************************
+
+  Struct:       Q931ie_LLComp
+
+  Description:  Low layer compatibility
+
+*****************************************************************************/
+
+typedef struct {
+
+    L3UCHAR IEId;                   /* 01111100                             */
+    L3UCHAR Size;                   /* Length of Information Element        */
+    L3UCHAR CodStand;               /* Coding standard                      */
+                                    /*  00 - ITU-T                          */
+                                    /*  01 - ISO/IEC                        */
+                                    /*  10 - National standard              */
+                                    /*  11 - Network side spesific          */
+
+    L3UCHAR ITransCap;              /* Information transfer capability      */
+                                    /*  00000 - Speech                      */
+                                    /*  01000 - Unrestricted digital info   */
+                                    /*  01001 - Restricted digital info     */
+                                    /*  10000 - 3.1 kHz audio               */
+                                    /*  10001 - Unrestricted with tones     */
+                                    /*  11000 - Video                       */
+
+    L3UCHAR NegotInd;               /* Negot indic.                         */
+									/*	0 : Out-band neg. not possib.       */
+									/*  1 : Out-band neg. possible	        */
+
+    L3UCHAR TransMode;              /* Transfer Mode                        */
+                                    /*  00 : Circuit Mode                   */
+                                    /*  10 : Packed Mode                    */
+
+    L3UCHAR InfoRate;               /* Information transfer rate            */
+                                    /*  00000 - Packed mode                 */
+                                    /*  10000 - 64 kbit/s                   */
+                                    /*  10001 - 2 x 64 kbit/s               */
+                                    /*  10011 - 384 kbit/s                  */
+                                    /*  10101 - 1536 kbit/s                 */
+                                    /*  10111 - 1920 kbit/s                 */
+                                    /*  11000 - Multirat (64 kbit/s base)   */
+
+    L3UCHAR RateMul;                /* Rate multiplier                      */
+    L3UCHAR Layer1Ident;            /* Layer 1 ident.                       */
+    L3UCHAR UIL1Prot;               /* User information layer 1 protocol    */
+									/*	00001 : ITU-T V.110, I.460 and X.30 */
+									/*  00010 : G.711 my-law				*/
+									/*  00011 : G.711 A-law					*/
+									/*  00100 : G.721						*/
+                                    /*  00101 : H.221 and H.242				*/
+									/*  00110 : H.223 and H.245				*/
+									/*  00111 : Non ITU-T Standard			*/
+									/*  01000 : ITU-T V.120					*/
+									/*  01001 : ITU-T X.31 HDLC flag stuff.	*/
+
+    L3UCHAR SyncAsync;              /* Synch/asynch                         */
+									/*	0 : Syncronous data					*/
+									/*	1 : Asyncronous data				*/
+
+    L3UCHAR Negot;                  /* Negot                                */
+									/*	0 : In-band negotiation not possib.	*/
+									/*  1 : In-band negotiation possible	*/
+
+    L3UCHAR UserRate;               /* User rate                            */
+									/*	00000 : I.460, V.110, X,30			*/
+									/*  00001 : 0.6 kbit/s x.1				*/
+									/*  00010 : 1.2 kbit/s					*/
+									/*  00011 : 2.4 kbit/s					*/
+									/*  00100 : 3.6 kbit/s					*/
+									/*  00101 : 4.8 kbit/s					*/
+									/*  00110 : 7.2 kbit/s					*/
+									/*  00111 : 8 kbit/s I.460				*/
+									/*  01000 : 9.6 kbit/s					*/
+									/*  01001 : 14.4 kbit/s					*/
+									/*  01010 : 16 kbit/s					*/
+									/*  01011 :	19.2 kbit/s					*/
+									/*  01100 : 32 kbit/s					*/
+									/*  01101 : 38.4 kbit/s					*/
+									/*  01110 : 48 kbit/s					*/
+									/*  01111 : 56 kbit/s					*/
+									/*  10000 : 57.6 kbit/s					*/
+									/*  10010 : 28.8 kbit/s					*/
+									/*  10100 : 24 kbit/s					*/
+									/*  10101 : 0.1345 kbit/s				*/
+									/*  10110 : 0.100 kbit/s				*/
+									/*  10111 : 0.075/1.2 kbit/s			*/
+									/*  11000 : 1.2/0.075/kbit/s			*/
+									/*  11001 : 0.050 kbit/s				*/
+									/*  11010 : 0.075 kbit/s				*/
+									/*  11011 : 0.110 kbit/s				*/
+									/*  11100 : 0.150 kbit/s				*/
+									/*  11101 : 0.200 kbit/s				*/
+									/*  11110 : 0.300 kbit/s				*/
+									/*  11111 : 12 kbit/s					*/
+
+    L3UCHAR InterRate;              /* Intermediate rate                    */
+									/*	00 : Not used						*/
+									/*  01 : 8 kbit/s						*/
+									/*  10 : 16 kbit/s						*/
+									/*  11 : 32 kbit/s						*/
+
+    L3UCHAR NIConTx;				/* Network Indepentend Clock on transmit*/
+									/*	0 : Not required to send data  clc  */
+									/*  1 : Send data w/NIC clc				*/
+
+    L3UCHAR NIConRx;				/* NIC on Rx							*/
+									/*	0 : Cannot accept indep. clc		*/
+									/*  1 : data with indep. clc accepted	*/
+
+    L3UCHAR FlowCtlTx;              /* Flow control on Tx                   */
+									/*  0 : Send Flow ctrl not required		*/
+									/*  1 : Send flow ctrl required			*/
+
+    L3UCHAR FlowCtlRx;              /* Flow control on Rx                   */
+									/*  0 : cannot use receive flow ctrl	*/
+									/*  1 : Receive flow ctrl accepted		*/
+    L3UCHAR HDR;					/* HDR/No HDR							*/
+    L3UCHAR MultiFrame;             /* Multi frame support                  */
+									/*  0 : multiframe not supported		*/
+									/*  1 : multiframe supported			*/
+
+	L3UCHAR ModeL1;					/* Mode L1								*/
+									/*	0 : bit transparent mode of operat.	*/
+									/*	1 : protocol sesitive mode of op.	*/
+
+    L3UCHAR NegotLLI;               /* Negot. LLI                           */
+									/*  0 : default LLI=256 only			*/
+									/*  1 : Full protocol negotiation		*/
+
+    L3UCHAR Assignor;               /* Assignor/Assignor ee                 */
+									/*  0 : Default Asignee					*/
+									/*  1 : Assignor only					*/
+
+    L3UCHAR InBandNeg;              /* In-band negot.                       */
+									/*  0 : negot done w/ USER INFO mes		*/
+									/*  1 : negot done in-band w/link zero	*/
+
+    L3UCHAR NumStopBits;            /* Number of stop bits					*/
+									/*  00 : Not used						*/
+									/*  01 : 1 bit							*/
+									/*  10 : 1.5 bits						*/
+									/*  11 : 2 bits							*/
+
+    L3UCHAR NumDataBits;            /* Number of data bits.                 */
+									/*  00 : not used						*/
+									/*  01 : 5 bits							*/
+									/*  10 : 7 bits							*/
+									/*  11 : 8 bits							*/
+
+    L3UCHAR Parity;					/* Parity Information					*/
+									/*	000 : Odd							*/
+									/*  010 : Even							*/
+									/*  011 : None							*/
+									/*  100 : Forced to 0					*/
+									/*  101 : Forced to 1					*/
+
+    L3UCHAR DuplexMode;				/* Mode duplex							*/
+									/*  0 : Half duplex						*/
+									/*  1 : Full duplex						*/
+
+    L3UCHAR ModemType;				/* Modem type, see Q.931 p 89			*/
+
+    L3UCHAR Layer2Ident;            /* Layer 2 ident.                       */
+
+    L3UCHAR UIL2Prot;               /* User information layer 2 protocol    */
+                                    /*  00001 : Basic mode ISO 1745         */
+									/*	00010 : Q.921/I.441					*/
+									/*  00110 : X.25 single link			*/
+                                    /*  00111 : X.25 multilink              */
+                                    /*  01000 : Extended LAPB T.71          */
+                                    /*  01001 : HDLC ARM                    */
+                                    /*  01010 : HDLC NRM                    */
+                                    /*  01011 : HDLC ABM                    */
+									/*  01100 : LAN logical link			*/
+                                    /*  01101 : X.75 SLP                    */
+                                    /*  01110 : Q.922                       */
+                                    /*  01111 : Q.922 core aspect           */
+                                    /*  10000 : User specified              */
+                                    /*  10001 : ISO/IEC 7776 DTE-DCE        */
+
+    L3UCHAR ModeL2;                 /* Mode                                 */
+									/*	01 : Normal Mode of operation    	*/
+									/*	10 : Extended mode of operation  	*/
+
+    L3UCHAR Q933use;                /* Q.9333 use                           */
+
+    L3UCHAR UsrSpcL2Prot;           /* User specified layer 2 protocol info */
+
+    L3UCHAR WindowSize;             /* Window size (k)                      */
+
+    L3UCHAR Layer3Ident;            /* Layer 3 ident                        */
+
+    L3UCHAR UIL3Prot;				/* User Information Layer 3 protocol	*/
+									/*	00010 : Q.931						*/
+									/*  00110 : X.25						*/
+                                    /*  00111 : 8208                        */
+                                    /*  01000 : X.233 ...                   */
+                                    /*  01001 : 6473                        */
+                                    /*  01010 : T.70                        */
+									/*  01011 : ISO/IEC TR 9577				*/
+                                    /*  10000 : User specified              */
+    L3UCHAR OptL3Info;              /* Optional Leyer 3 info                */
+
+    L3UCHAR ModeL3;                 /* Mode of operation                    */
+                                    /*  01 : Normal packed seq. numbering   */
+                                    /*  10 : Extended packed seq. numbering */
+
+    L3UCHAR DefPackSize;            /* Default packet size                  */
+
+    L3UCHAR PackWinSize;            /* Packet window size                   */
+
+    L3UCHAR AddL3Info;              /* Additional Layer 3 protocol info     */
+
+} Q931ie_LLComp;
+
+/*****************************************************************************
+
+  Struct:       Q931ie_NetFac;
+
+  Description:  Network-specific facilities
+
+*****************************************************************************/
+
+typedef struct {
+
+    L3UCHAR IEId;                   /* 00100000                             */
+    L3UCHAR Size;                   /* Length of Information Element        */
+    L3UCHAR LenNetID;               /* Length of network facilities id.     */
+    L3UCHAR TypeNetID;              /* Type of network identification       */
+    L3UCHAR NetIDPlan;              /* Network identification plan.         */
+    L3UCHAR NetFac;                 /* Network specific facility spec.      */
+    L3UCHAR NetID[1];               /* Network id. (IA5)                    */
+
+} Q931ie_NetFac;
+
+/*****************************************************************************
+
+  Struct:       Q931ie_NotifInd;
+
+  Description:  Notification Indicator
+
+*****************************************************************************/
+
+typedef struct {
+
+    L3UCHAR IEId;                   /* 00100000                             */
+    L3UCHAR Size;                   /* Length of Information Element        */
+	L3UCHAR Notification;			/* Notification descriptor				*/
+
+} Q931ie_NotifInd;
+
+/*****************************************************************************
+
+  Struct:       Q931ie_ProgInd
+
+  Description:  Progress indicator
+
+*****************************************************************************/
+
+typedef struct {
+
+    L3UCHAR IEId;                   /* 00011110                             */
+    L3UCHAR Size;                   /* Length of Information Element        */
+    L3UCHAR CodStand;               /* Coding standard                      */
+    L3UCHAR Location;               /* Location                             */
+    L3UCHAR ProgDesc;               /* Progress description                 */
+
+} Q931ie_ProgInd;
+
+/*****************************************************************************
+
+  Struct;       Q931ie_Segment
+
+  Description:  Segmented message
+
+*****************************************************************************/
+
+typedef struct {
+
+    L3UCHAR IEId;                   /* 00000000                             */
+    L3UCHAR Size;                   /* Length of Information Element        */
+    L3UCHAR FSI;                    /* First segment indicator              */
+    L3UCHAR NumSegRem;              /* Number of segments remaining         */
+    L3UCHAR SegType;                /* Segment message type                 */
+
+} Q931ie_Segment;
+
+
+typedef struct {
+
+    L3UCHAR IEId;                   /* 00000000                             */
+    L3UCHAR Size;                   /* Length of Information Element        */
+
+} Q931ie_SendComplete;
+
+/*****************************************************************************
+
+  Struct:       Q931ie_Signal
+
+  Description:  Signal
+
+*****************************************************************************/
+
+typedef struct {
+
+    L3UCHAR IEId;                   /* 00000000                             */
+    L3UCHAR Size;                   /* Length of Information Element        */
+    L3UCHAR Signal;                 /* Signal value                         */
+                                    /*  00000000    Dial tone on            */
+                                    /*  00000001    Ring back tone on       */
+                                    /*  00000010    Intercept tone on       */
+                                    /*  00000011    Network congestion on   */
+                                    /*  00000100    Busy tone on            */
+                                    /*  00000101    Confirm tone on         */
+                                    /*  00000110    Answer tone on          */
+                                    /*  00000111    Call waiting tone       */
+                                    /*  00001000    Off-hook warning tone   */
+                                    /*  00001001    Pre-emption tone on     */
+                                    /*  00111111    Tones off               */
+                                    /*  01000000    Alerting on - pattern 0 */
+                                    /*  01000001    Alerting on - pattern 1 */
+                                    /*  01000010    Alerting on - pattern 2 */
+                                    /*  01000011    Alerting on - pattern 3 */
+                                    /*  01000100    Alerting on - pattern 4 */
+                                    /*  01000101    Alerting on - pattern 5 */
+                                    /*  01000110    Alerting on - pattern 6 */
+                                    /*  01000111    Alerting on - pattern 7 */
+                                    /*  01001111    Alerting off            */
+} Q931ie_Signal;
+
+/*****************************************************************************
+
+  Struct:       Q931ie_TransDelSelInd
+
+  description:  Transit delay selection and indication
+
+*****************************************************************************/
+#ifdef Q931_X25_SUPPORT
+typedef struct {
+
+    L3UCHAR IEId;                   /* 00000000                             */
+    L3UCHAR Size;                   /* Length of Information Element        */
+    L3ULONG TxDSIValue;             /* Trans. delay sel. & ind. value       */ 
+
+} Q931ie_TransDelSelInd;
+#endif
+
+/*****************************************************************************
+
+  Struct:       Q931ie_TransNetSel
+
+  Description:  Transit network selection
+
+*****************************************************************************/
+
+typedef struct {
+
+    L3UCHAR IEId;                   /* 01111000                             */
+    L3UCHAR Size;                   /* Length of Information Element        */
+    L3UCHAR Type;                   /* Type of network identifier           */
+    L3UCHAR NetIDPlan;              /* Network idetification plan           */
+    L3UCHAR NetID[1];               /* Network identification(IA5)          */
+
+} Q931ie_TransNetSel;
+
+/*****************************************************************************
+
+  Struct:       Q931ie_UserUser
+
+  Description:  User-user
+
+*****************************************************************************/
+
+typedef struct {
+
+    L3UCHAR IEId;                   /* 01111110                             */
+    L3UCHAR Size;                   /* Length of Information Element        */
+    L3UCHAR ProtDisc;               /* Protocol discriminator               */
+    L3UCHAR User[1];                /* User information                     */
+
+} Q931ie_UserUser;
+
+/*****************************************************************************
+
+  Struct:       Q931ie_ClosedUserGrp
+
+  Description:  Closed user group
+
+*****************************************************************************/
+#ifdef Q931_X25_SUPPORT
+typedef struct {
+
+    L3UCHAR IEId;                   /* 01000111                             */
+    L3UCHAR Size;                   /* Length of Information Element        */
+    L3UCHAR CUGInd;                 /* CUG indication                       */
+    L3UCHAR CUG[1];                 /* CUG index code (IA5)                 */
+
+} Q931ie_ClosedUserGrp;
+#endif
+
+/*****************************************************************************
+
+  Struct:		Q931ie_CongLevel
+
+  Description:	Congestion Level
+
+*****************************************************************************/
+typedef struct {
+
+    L3UCHAR IEId;                   /* 01000111                             */
+    L3UCHAR Size;                   /* Length of Information Element        */
+	L3UCHAR CongLevel;				/* Conguestion Level					*/
+
+} Q931ie_CongLevel;
+
+/*****************************************************************************
+
+  Struct:       Q931ie_EndEndTxDelay
+
+  Description:  End to end transit delay
+
+*****************************************************************************/
+#ifdef Q931_X25_SUPPORT
+typedef struct {
+
+    L3UCHAR IEId;                   /* 01000010                             */
+    L3UCHAR Size;                   /* Length of Information Element        */
+    L3ULONG CumTxDelay;             /* Cumulative transit delay value       */
+    L3ULONG ReqTxDelay;             /* Requested end to end transit delay   */
+    L3ULONG MaxTxDelay;             /* Maximum transit delay                */
+
+} Q931ie_EndEndTxDelay;
+#endif
+
+/*****************************************************************************
+
+  Struct:       Q931ie_InfoRate
+
+  Description:  Information Rate
+
+*****************************************************************************/
+#ifdef Q931_X25_SUPPORT
+typedef struct {
+
+    L3UCHAR IEId;                   /* 01100000                             */
+    L3UCHAR Size;                   /* Length of Information Element        */
+    L3UCHAR InInfoRate;             /* Incoming information rate            */
+    L3UCHAR OutInfoRate;            /* Outgoing information rate            */
+    L3UCHAR MinInInfoRate;          /* Minimum incoming information rate    */
+    L3UCHAR MinOutInfoRate;         /* Minimum outgoing information rate    */
+
+} Q931ie_InfoRate;
+#endif
+
+/*****************************************************************************
+
+  Struct:       Q931ie_PackParam
+
+  Description:  Packed layer binary parameters
+
+*****************************************************************************/
+#ifdef Q931_X25_SUPPORT
+typedef struct {
+
+    L3UCHAR IEId;                   /* 01000100                             */
+    L3UCHAR Size;                   /* Length of Information Element        */
+    L3UCHAR FastSel;                /* Fast selected                        */
+    L3UCHAR ExpData;                /* Exp. data                            */
+    L3UCHAR DelConf;                /* Delivery conf                        */
+    L3UCHAR Modulus;                /* Modulus                              */
+
+} Q931ie_PackParam;
+#endif
+
+/*****************************************************************************
+
+  Struct:       Q931ie_PackWinSize
+
+  Description:  Packed window size
+
+*****************************************************************************/
+#ifdef Q931_X25_SUPPORT
+typedef struct {
+
+    L3UCHAR IEId;                   /* 01000101                             */
+    L3UCHAR Size;                   /* Length of Information Element        */
+    L3UCHAR ForwardValue;           /* Forward value                        */
+    L3UCHAR BackwardValue;          /* Backward value                       */
+
+} Q931ie_PackWinSize;
+#endif
+
+/*****************************************************************************
+
+  Struct:       Q931ie_PackSize
+
+  Description:  Packet size
+
+*****************************************************************************/
+#ifdef Q931_X25_SUPPORT
+typedef struct {
+
+    L3UCHAR IEId;                   /* 01000110                             */
+    L3UCHAR Size;                   /* Length of Information Element        */
+    L3UCHAR ForwardValue;           /* Forward value                        */
+    L3UCHAR BackwardValue;          /* Backward value                       */
+
+} Q931ie_PackSize;
+#endif
+
+/*****************************************************************************
+
+  Struct:       Q931ie_RedirNum
+
+  Description:  Redirecting number
+
+*****************************************************************************/
+#ifdef Q931_X25_SUPPORT
+typedef struct {
+
+    L3UCHAR IEId;                   /* 01110100                             */
+    L3UCHAR Size;                   /* Length of Information Element        */
+    L3UCHAR TypeNum;                /* Type of number                       */
+    L3UCHAR NumPlanID;              /* Number plan identification           */
+    L3UCHAR PresInd;                /* Presentation indicator               */
+    L3UCHAR ScreenInd;              /* Screening indicator                  */
+    L3UCHAR Reason;                 /* Reason for redirection               */
+    L3UCHAR Digit[1];               /* Number digits (IA5)                  */
+
+} Q931ie_RedirNum;
+#endif
+
+typedef struct {
+
+    L3UCHAR IEId;                   /* 01110100                             */
+    L3UCHAR Size;                   /* Length of Information Element        */
+    L3UCHAR RepeatInd;              /* 0010 Prioritized list for selecting  */
+                                    /* one possible.                        */
+} Q931ie_RepeatInd;
+
+typedef struct {
+
+    L3UCHAR IEId;                   /* 01110100                             */
+    L3UCHAR Size;                   /* Length of Information Element        */
+    L3UCHAR Spare;                  /* Spare                                */
+    L3UCHAR Class;                  /* Class                                */
+                                    /*  000 Indicate channels               */
+                                    /*  110 Single interface                */
+                                    /*  111 All interfaces                  */
+} Q931ie_RestartInd;
+
+typedef struct {
+
+    L3UCHAR IEId;                   /* 01110100                             */
+    L3UCHAR Size;                   /* Length of Information Element        */
+	L3UCHAR Preference;             /* Preference 0 = reserved, 1 = channel */
+	L3UCHAR Spare;                  /* Spare                                */
+    L3UCHAR NewStatus;              /* NewStatus                            */
+                                    /*  000 In service                      */
+                                    /*  001 Maintenance                     */
+                                    /*  010 Out of service                  */
+} Q931ie_ChangeStatus;
+
+/*****************************************************************************
+
+  Struct:       Q931ie_GenericDigits
+
+
+*****************************************************************************/
+
+typedef struct {
+
+    L3UCHAR IEId;                   /* 00110111                             */
+    L3UCHAR Size;                   /* Length of Information Element        */
+    L3UCHAR Type;					/* Type of number                       */
+    L3UCHAR Encoding;				/* Encoding of number                   */
+    L3UCHAR Digit[1];				/* Number digits (IA5)                  */
+
+} Q931ie_GenericDigits;
+
+
+/*****************************************************************************
+
+  Q.931 Information Element Pack/Unpack functions. Implemented in Q931ie.c
+
+*****************************************************************************/
+q931pie_func_t Q931Pie_ChangeStatus;
+q931pie_func_t Q931Pie_BearerCap;
+q931pie_func_t Q931Pie_ChanID;
+q931pie_func_t Q931Pie_ProgInd;
+q931pie_func_t Q931Pie_Display;
+q931pie_func_t Q931Pie_Signal;
+q931pie_func_t Q931Pie_HLComp;
+q931pie_func_t Q931Pie_Segment;
+q931pie_func_t Q931Pie_DateTime;
+q931pie_func_t Q931Pie_Cause;
+q931pie_func_t Q931Pie_SendComplete;
+q931pie_func_t Q931Pie_KeypadFac;
+q931pie_func_t Q931Pie_NotifInd;
+q931pie_func_t Q931Pie_CallID;
+q931pie_func_t Q931Pie_RepeatInd;
+q931pie_func_t Q931Pie_NetFac;
+q931pie_func_t Q931Pie_CallingNum;
+q931pie_func_t Q931Pie_CallingSub;
+q931pie_func_t Q931Pie_CalledNum;
+q931pie_func_t Q931Pie_CalledSub;
+q931pie_func_t Q931Pie_CalledNum;
+q931pie_func_t Q931Pie_TransNetSel;
+q931pie_func_t Q931Pie_LLComp;
+q931pie_func_t Q931Pie_CallState;
+q931pie_func_t Q931Pie_RestartInd;
+q931pie_func_t Q931Pie_UserUser;
+
+q931pie_func_t Q931Pie_GenericDigits;
+
+L3USHORT Q931Uie_CRV(Q931_TrunkInfo_t *pTrunk,L3UCHAR * IBuf, L3UCHAR *OBuf, L3INT *IOff, L3INT *OOff);
+
+q931uie_func_t Q931Uie_ChangeStatus;
+q931uie_func_t Q931Uie_BearerCap;
+q931uie_func_t Q931Uie_ChanID;
+q931uie_func_t Q931Uie_ProgInd;
+q931uie_func_t Q931Uie_Display;
+q931uie_func_t Q931Uie_Signal;
+q931uie_func_t Q931Uie_HLComp;
+q931uie_func_t Q931Uie_Segment;
+q931uie_func_t Q931Uie_DateTime;
+q931uie_func_t Q931Uie_Cause;
+q931uie_func_t Q931Uie_SendComplete;
+q931uie_func_t Q931Uie_KeypadFac;
+q931uie_func_t Q931Uie_NotifInd;
+q931uie_func_t Q931Uie_CallID;
+q931uie_func_t Q931Uie_RepeatInd;
+q931uie_func_t Q931Uie_NetFac;
+q931uie_func_t Q931Uie_CallingNum;
+q931uie_func_t Q931Uie_CallingSub;
+q931uie_func_t Q931Uie_CalledNum;
+q931uie_func_t Q931Uie_CalledSub;
+q931uie_func_t Q931Uie_TransNetSel;
+q931uie_func_t Q931Uie_LLComp;
+q931uie_func_t Q931Uie_CallState;
+q931uie_func_t Q931Uie_RestartInd;
+q931uie_func_t Q931Uie_UserUser;
+
+q931uie_func_t Q931Uie_GenericDigits;
+
+
+L3INT Q931ReadExt(L3UCHAR * IBuf, L3INT Off);
+L3INT Q931Uie_CongLevel(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff);
+L3INT Q931Pie_CongLevel(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet);
+L3INT Q931Uie_RevChargeInd(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff);
+L3INT Q931Pie_RevChargeInd(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet);
+
+L3INT Q931Uie_Generic(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *IOff, L3INT *OOff);
+L3INT Q931Pie_Generic(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet);
+
+#endif /* _Q931IE_NL */

Added: freeswitch/trunk/libs/openzap/src/isdn/include/Q932.h (0 => 17141)


--- freeswitch/trunk/libs/openzap/src/isdn/include/Q932.h	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/src/isdn/include/Q932.h	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,95 @@
+/*****************************************************************************
+
+  FileName:		Q932.h
+
+  Contents:		Header w/structs for Q932 Suplementary Services.
+
+  NB:			Do NOT include this header directly, include Q931.h
+
+  License/Copyright:
+
+  Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+  email:janvb@caselaboratories.com  
+
+  Redistribution and use in source and binary forms, with or without 
+  modification, are permitted provided that the following conditions are 
+  met:
+
+    * Redistributions of source code must retain the above copyright notice, 
+	  this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright notice, 
+	  this list of conditions and the following disclaimer in the documentation 
+	  and/or other materials provided with the distribution.
+    * Neither the name of the Case Labs, Ltd nor the names of its contributors 
+	  may be used to endorse or promote products derived from this software 
+	  without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
+  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
+  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+  POSSIBILITY OF SUCH DAMAGE.
+*****************************************************************************/
+
+/*****************************************************************************
+  Q.932 Additional Message codes
+*****************************************************************************/
+
+#define Q932mes_HOLD                 0x24 /* 0010 0100                      */
+#define Q932mes_HOLD_ACKNOWLEDGE     0x28 /* 0010 1000                      */
+#define Q932mes_HOLD_REJECT          0x30 /* 0011 0000                      */
+#define Q932mes_RETRIEVE             0x31 /* 0011 0001                      */
+#define Q932mes_RETRIEVE_ACKNOWLEDGE 0x33 /* 0011 0011                      */
+#define Q932mes_RETRIEVE_REJECT      0x37 /* 0011 0111                      */
+#define Q932mes_FACILITY             0x62 /* 0110 0010                      */
+#define Q932mes_REGISTER             0x64 /* 0110 0100                      */
+
+/*****************************************************************************
+  Q.932 Additional EI Codes
+*****************************************************************************/
+#define Q932ie_FACILITY              0x1c /* 0001 1100                      */
+
+/*****************************************************************************
+  Function Prototypes.
+*****************************************************************************/
+L3INT Q932ProcFacilityTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * b, L3INT iFrom);
+L3INT Q932ProcHoldTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * b, L3INT iFrom);
+L3INT Q932ProcHoldAckTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * b, L3INT iFrom);
+L3INT Q932ProcHoldRejectTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * b, L3INT iFrom);
+L3INT Q932ProcRegisterTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * b, L3INT iFrom);
+L3INT Q932ProcRetrieveTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * b, L3INT iFrom);
+L3INT Q932ProcRetrieveAckTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * b, L3INT iFrom);
+L3INT Q932ProcRetrieveRejectTE(Q931_TrunkInfo_t *pTrunk, L3UCHAR * b, L3INT iFrom);
+
+L3INT Q932ProcFacilityNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * b, L3INT iFrom);
+L3INT Q932ProcHoldNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * b, L3INT iFrom);
+L3INT Q932ProcHoldAckNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * b, L3INT iFrom);
+L3INT Q932ProcHoldRejectNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * b, L3INT iFrom);
+L3INT Q932ProcRegisterNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * b, L3INT iFrom);
+L3INT Q932ProcRetrieveNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * b, L3INT iFrom);
+L3INT Q932ProcRetrieveAckNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * b, L3INT iFrom);
+L3INT Q932ProcRetrieveRejectNT(Q931_TrunkInfo_t *pTrunk, L3UCHAR * b, L3INT iFrom);
+
+L3INT Q932Pmes_Facility(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q932Pmes_Hold(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q932Pmes_HoldAck(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q932Pmes_HoldReject(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q932Pmes_Register(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q932Pmes_Retrieve(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q932Pmes_RetrieveAck(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+L3INT Q932Pmes_RetrieveReject(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+
+L3INT Q932Umes_Facility(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic * OBuf, L3INT I, L3INT O);
+L3INT Q932Umes_Hold(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic * OBuf, L3INT I, L3INT O);
+L3INT Q932Umes_HoldAck(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic * OBuf, L3INT I, L3INT O);
+L3INT Q932Umes_HoldReject(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic * OBuf, L3INT I, L3INT O);
+L3INT Q932Umes_Register(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic * OBuf, L3INT I, L3INT O);
+L3INT Q932Umes_Retrieve(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic * OBuf, L3INT I, L3INT O);
+L3INT Q932Umes_RetrieveAck(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic * OBuf, L3INT I, L3INT O);
+L3INT Q932Umes_RetrieveReject(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic * OBuf, L3INT I, L3INT O);

Added: freeswitch/trunk/libs/openzap/src/isdn/include/mfifo.h (0 => 17141)


--- freeswitch/trunk/libs/openzap/src/isdn/include/mfifo.h	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/src/isdn/include/mfifo.h	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,85 @@
+/*****************************************************************************
+
+  Filename:     mfifo.h
+
+  Contents:     header for MFIFO
+
+  License/Copyright:
+
+  Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+  email:janvb@caselaboratories.com  
+
+  Redistribution and use in source and binary forms, with or without 
+  modification, are permitted provided that the following conditions are 
+  met:
+
+    * Redistributions of source code must retain the above copyright notice, 
+	  this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright notice, 
+	  this list of conditions and the following disclaimer in the documentation 
+	  and/or other materials provided with the distribution.
+    * Neither the name of the Case Labs, Ltd nor the names of its contributors 
+	  may be used to endorse or promote products derived from this software 
+	  without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
+  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
+  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+  POSSIBILITY OF SUCH DAMAGE.
+*****************************************************************************/
+#ifndef _MFIFO
+#define _MFIFO
+
+/*****************************************************************************
+
+  Struct:		MINDEX
+
+  Description:	Message Index used to index a dynamic size Message FIFO.
+
+*****************************************************************************/
+typedef struct _mindex {
+    int offset;                     /* offset to message in buf             */
+    int size;                       /* size of message in bytes             */
+} MINDEX;
+
+/*****************************************************************************
+
+  Struct:		MFIFO
+
+  Description:	Message FIFO. Provides a dynamic sized message based FIFO
+				queue.
+
+*****************************************************************************/
+typedef struct {
+	int first;                      /* first out                            */
+	int last;                       /* last in + 1                          */
+	int bsize;                      /* buffer size                          */
+	unsigned char *buf;             /* ptr to start of buffer               */
+	int ixsize;                     /* index size                           */
+	MINDEX ix[1];                   /* message index                        */
+} MFIFO;
+
+/*****************************************************************************
+  Function prototypes.
+*****************************************************************************/
+int MFIFOCreate(unsigned char *buf, int size, int index);
+void MFIFOClear(unsigned char * buf);
+int MFIFOGetLBOffset(unsigned char *buf);
+int MFIFOGetFBOffset(unsigned char *buf);
+void MFIFOWriteIX(unsigned char *buf, unsigned char *mes, int size, int ix, int off);
+int MFIFOWriteMes(unsigned char *buf, unsigned char *mes, int size);
+unsigned char * MFIFOGetMesPtr(unsigned char *buf, int *size);
+void MFIFOKillNext(unsigned char *buf);
+
+unsigned char * MFIFOGetMesPtrOffset(unsigned char *buf, int *size, const int pos);
+int MFIFOGetMesCount(unsigned char *buf);
+int MFIFOWriteMesOverwrite(unsigned char *buf, unsigned char *mes, int size);
+
+#endif

Added: freeswitch/trunk/libs/openzap/src/isdn/include/national.h (0 => 17141)


--- freeswitch/trunk/libs/openzap/src/isdn/include/national.h	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/src/isdn/include/national.h	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,86 @@
+/******************************************************************************
+
+  FileName:         national.h
+
+  Contents:         Header and definition for the National ISDN dialect. The 
+                    header contents the following parts:
+                    - Definition of codes
+                    - Definition of information elements (nationalie_).
+                    - Definition of messages (nationalmes_).
+                    - Function prototypes.
+
+  Description:      The National ISDN dialect here covers ????
+
+  Related Files:	national.h			National ISDN Definitions
+			nationalie.c			National ISDN IE encoders/coders
+			nationalStateTE.c		National ISDN TE State Engine
+			nationalStateNT.c		National ISDN NT State Engine
+
+  License/Copyright:
+
+  Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+  email:janvb@caselaboratories.com  
+
+  Copyright (c) 2007, Michael Jerris. All rights reserved.
+  email:mike@jerris.com  
+
+  Redistribution and use in source and binary forms, with or without 
+  modification, are permitted provided that the following conditions are 
+  met:
+
+    * Redistributions of source code must retain the above copyright notice, 
+	  this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright notice, 
+	  this list of conditions and the following disclaimer in the documentation 
+	  and/or other materials provided with the distribution.
+    * Neither the name of the Case Labs, Ltd nor the names of its contributors 
+	  may be used to endorse or promote products derived from this software 
+	  without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
+  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
+  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+  POSSIBILITY OF SUCH DAMAGE.
+******************************************************************************/
+
+#ifndef _national_NATIONAL_NL
+#define _national_NATIONAL_NL
+
+#include "Q931.h"
+
+/*****************************************************************************
+
+  Q.931 Message codes
+  Only National specific message and ie types 
+  here the rest are inherited from national.h
+  
+*****************************************************************************/
+
+
+/*****************************************************************************
+
+  Q.931 Message Pack/Unpack functions. Implemented in nationalmes.c
+
+*****************************************************************************/
+L3INT nationalUmes_Setup(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT IOff, L3INT Size);
+L3INT nationalPmes_Setup(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize);
+
+#include "DMS.h"
+
+/*****************************************************************************
+
+  Q.931 Process Function Prototyping. Implemented in nationalStateTE.c
+
+*****************************************************************************/
+
+void nationalCreateTE(L3UCHAR i);
+void nationalCreateNT(L3UCHAR i);
+
+#endif /* _national_NATIONAL_NL */

Added: freeswitch/trunk/libs/openzap/src/isdn/mfifo.c (0 => 17141)


--- freeswitch/trunk/libs/openzap/src/isdn/mfifo.c	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/src/isdn/mfifo.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,399 @@
+/*****************************************************************************
+
+  Filename:	 mfifo.c
+
+  Description:  mfifo is a message orriented fifo system with support of
+				both message and byte per byte retriaval of messages.
+
+				The fifo has been designed with two usages in mind:
+
+				-   Queueing of frames for hdlc and feeding out byte per byte
+					with the possibility of re-sending of frames etc. 
+
+				- fifo for messages of dynamic size.
+
+				The fifo is allocated on top of any buffer and creates an
+				index of message in the queue. The user can write/read
+				messages or write messages and read the message one byte
+				at the time.
+
+  Interface:	
+				MFIFOCreate		 Create/reset/initialize fifo.
+				MFIFOClear		  Clear FIFO.
+				MFIFOWriteMes	   Write message into fifo
+				* MFIFOReadMes		Read message from fifo.
+				MFIFOGetMesPtr	  Get ptr to next message.
+				MFIFOKillNext	   Kill next message.
+
+				* currently not implemented.
+
+  Note:		 The message will always be saved continuously. If there is not
+				sufficient space at the end of the buffer, the fifo will skip
+				the last bytes and save the message at the top of the buffer.
+
+				This is required to allow direct ptr access to messages 
+				stored in the queue.
+
+  License/Copyright:
+
+  Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+  email:janvb@caselaboratories.com  
+
+  Redistribution and use in source and binary forms, with or without 
+  modification, are permitted provided that the following conditions are 
+  met:
+
+	* Redistributions of source code must retain the above copyright notice, 
+	  this list of conditions and the following disclaimer.
+	* Redistributions in binary form must reproduce the above copyright notice, 
+	  this list of conditions and the following disclaimer in the documentation 
+	  and/or other materials provided with the distribution.
+	* Neither the name of the Case Labs, Ltd nor the names of its contributors 
+	  may be used to endorse or promote products derived from this software 
+	  without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
+  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
+  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+  POSSIBILITY OF SUCH DAMAGE.
+*****************************************************************************/
+
+#include "mfifo.h"
+#include <memory.h>
+#include <stdlib.h>
+
+/*****************************************************************************
+
+  Function:	 MFIFOCreate
+
+  Description:  Creates a fifo on top of an existing buffer.
+
+  Parameters:   buf	 ptr to buffer.
+				size	size of buffer in bytes.
+				index   size of index entries (max no messages).
+
+  Return value: 0 if failure, 1 if ok.
+
+*****************************************************************************/
+int MFIFOCreate(unsigned char *buf, int size, int index)
+{
+	MFIFO *mf = (MFIFO *)buf;
+	
+	mf->first = mf->last = 0;
+	mf->ixsize = index;
+	mf->buf = &buf[sizeof(MFIFO) + (sizeof(MINDEX) * index)];
+
+	if (mf->buf > &buf[size])
+		return 0;
+
+	mf->bsize = size - sizeof(MFIFO) - (sizeof(MINDEX) * index);
+
+	return 1;
+}
+
+/*****************************************************************************
+
+  Function:	 MFIFOClear
+
+  Description:  Clear the FIFO
+
+  Paremeters:   buf	 ptr to fifo
+
+  Return Value: none
+
+*****************************************************************************/
+void MFIFOClear(unsigned char * buf)
+{
+	MFIFO *mf = (MFIFO *)buf;
+
+	mf->first = mf->last = 0;
+}
+
+/*****************************************************************************
+
+  Function:	 MFIFOGetLBOffset
+
+  Description:  Helper function caclulating offset to the 'first out' byte.
+
+  Paremeters:   buf	 ptr to fifo
+
+  Return Value: offset.
+
+*****************************************************************************/
+int MFIFOGetLBOffset(unsigned char *buf)
+{
+	MFIFO *mf = (MFIFO *)buf;
+
+	if (mf->last != mf->first)
+		return mf->ix[mf->last].offset;
+	
+	return 0;
+}
+
+/*****************************************************************************
+
+  Function:	 MFIFOGetFBOffset
+
+  Description:  Helper function calculating the offset to the 'first in' 
+				byte in the buffer. This is the position the next byte
+				entering the fifo will occupy.
+
+  Paremeters:   buf	 ptr to fifo
+
+  Return Value: offset
+
+*****************************************************************************/
+int MFIFOGetFBOffset(unsigned char *buf)
+{
+	MFIFO *mf = (MFIFO *)buf;
+	int x;
+
+	if (mf->last == mf->first)
+		return 0;
+
+	x = mf->first - 1;
+
+	if (x < 0)
+		x = mf->ixsize - 1;
+
+	return mf->ix[x].offset + mf->ix[x].size;
+}
+
+/*****************************************************************************
+
+  Function:	 MFIFOWriteIX
+
+  Description:  Helper function writing a calculated entry. The function
+				will perform a memcpy to move the message and set the index
+				values as well as increase the 'first in' index.
+
+  Paremeters:   buf	 ptr to fifo
+				mes	 ptr to message
+				size	size of message in bytes.
+				ix	  index to index entry.
+				off	 offset to position to receive the message
+
+  Return Value: none
+
+*****************************************************************************/
+void MFIFOWriteIX(unsigned char *buf, unsigned char *mes, int size, int ix, int off)
+{
+	MFIFO *mf = (MFIFO *)buf;
+	int x;
+
+	memcpy(&mf->buf[off], mes, size);
+	mf->ix[ix].offset = off;
+	mf->ix[ix].size = size;
+
+	x = mf->first + 1;
+
+	if (x >= mf->ixsize)
+		x = 0;
+
+	mf->first = x;
+}
+
+/*****************************************************************************
+
+  Function:	 MFIFOWriteMes
+
+  Description:  
+
+  Paremeters:
+
+  Return Value:
+
+*****************************************************************************/
+int MFIFOWriteMes(unsigned char *buf, unsigned char *mes, int size)
+{
+	MFIFO *mf = (MFIFO *)buf;
+	int of, ol, x;
+
+	x = mf->first + 1;
+
+	if (x >= mf->ixsize)
+		x = 0;
+
+	if (x == mf->last)
+		return 0; /* full queue */
+
+	of = MFIFOGetFBOffset(buf);
+	ol = MFIFOGetLBOffset(buf);
+	if (mf->last == mf->first) { /* empty queue */
+		mf->first = mf->last = 0; /* optimize */
+
+		MFIFOWriteIX(buf, mes, size, mf->first, 0);
+		return 1;
+	}
+	else if (of > ol) {
+		if (mf->bsize - of >= size) {
+			MFIFOWriteIX(buf, mes, size, mf->first, of);
+			return 1;
+		}
+		else if (ol > size) {
+			MFIFOWriteIX(buf, mes, size, mf->first, ol);
+			return 1;
+		}
+	}
+	else if (ol - of > size) {
+			MFIFOWriteIX(buf, mes, size, mf->first, of);
+			return 1;
+	}
+
+	return 0;
+}
+
+/*****************************************************************************
+
+  Function:	 MFIFOGetMesPtr
+
+  Description:  
+
+  Paremeters:
+
+  Return Value:
+
+*****************************************************************************/
+unsigned char * MFIFOGetMesPtr(unsigned char *buf, int *size)
+{
+	MFIFO *mf = (MFIFO *)buf;
+
+	if (mf->first == mf->last) {
+		return NULL;
+	}
+
+	*size = mf->ix[mf->last].size;
+	return &mf->buf[mf->ix[mf->last].offset];
+}
+
+/*****************************************************************************
+
+  Function:	 MFIFOKillNext
+
+  Description:  
+
+  Paremeters:
+
+  Return Value:
+
+*****************************************************************************/
+void MFIFOKillNext(unsigned char *buf)
+{
+	MFIFO *mf = (MFIFO *)buf;
+	int x;
+
+	if (mf->first != mf->last) {
+		x = mf->last + 1;
+		if (x >= mf->ixsize) {
+			x = 0;
+		}
+
+		mf->last = x;
+	}
+}
+
+
+/*
+ * Queue-style accessor functions
+ */
+
+/**
+ * MFIFOGetMesPtrOffset
+ * \brief	Get pointer to and size of message at position x
+ */
+unsigned char * MFIFOGetMesPtrOffset(unsigned char *buf, int *size, const int pos)
+{
+	MFIFO *mf = (MFIFO *)buf;
+	int x;
+
+	if (mf->first == mf->last) {
+		return NULL;
+	}
+
+	if (pos < 0 || pos >= mf->ixsize) {
+		return NULL;
+	}
+
+	x = pos - mf->last;
+	if (x < 0) {
+		x += (mf->ixsize - 1);
+	}
+
+	*size = mf->ix[x].size;
+	return &mf->buf[mf->ix[x].offset];
+}
+
+
+/**
+ * MFIFOGetMesCount
+ * \brief	How many messages are currently in the buffer?
+ */
+int MFIFOGetMesCount(unsigned char *buf)
+{
+	MFIFO *mf = (MFIFO *)buf;
+
+	if (mf->first == mf->last) {
+		return 0;
+	}
+	else if (mf->first > mf->last) {
+		return mf->first - mf->last;
+	}
+	else {
+		return (mf->ixsize - mf->last) + mf->first;
+	}
+}
+
+/**
+ * MFIFOWriteMesOverwrite
+ * \brief	Same as MFIFOWriteMes but old frames will be overwritten if the fifo is full
+ */
+int MFIFOWriteMesOverwrite(unsigned char *buf, unsigned char *mes, int size)
+{
+	MFIFO *mf = (MFIFO *)buf;
+	int of, ol, x;
+
+	x = mf->first + 1;
+
+	if (x >= mf->ixsize)
+		x = 0;
+
+	if (x == mf->last) {
+		/* advance last pointer */
+		mf->last++;
+
+		if (mf->last >= mf->ixsize)
+			mf->last = 0;
+	}
+
+	of = MFIFOGetFBOffset(buf);
+	ol = MFIFOGetLBOffset(buf);
+
+	if (mf->last == mf->first) {	/* empty queue */
+		mf->first = mf->last = 0;	/* optimize */
+
+		MFIFOWriteIX(buf, mes, size, mf->first, 0);
+		return 1;
+	}
+	else if (of > ol) {
+		if (mf->bsize - of >= size) {
+			MFIFOWriteIX(buf, mes, size, mf->first, of);
+			return 1;
+		}
+		else if (ol > size) {
+			MFIFOWriteIX(buf, mes, size, mf->first, ol);
+			return 1;
+		}
+	}
+	else if (ol - of > size) {
+		MFIFOWriteIX(buf, mes, size, mf->first, of);
+		return 1;
+	}
+	return 0;
+}

Added: freeswitch/trunk/libs/openzap/src/isdn/nationalStateNT.c (0 => 17141)


--- freeswitch/trunk/libs/openzap/src/isdn/nationalStateNT.c	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/src/isdn/nationalStateNT.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,130 @@
+/*****************************************************************************
+
+  FileName:		nationalStateNT.c
+
+  Contents:		National ISDN State Engine for NT (Network Mode).
+
+			The controlling state engine for Q.931 is the state engine
+			on the NT side. The state engine on the TE side is a slave 
+			of this. The TE side maintain it's own states as described in
+			ITU-T Q931, but will in	raise conditions be overridden by 
+			the NT side.
+
+  License/Copyright:
+
+  Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+  email:janvb@caselaboratories.com  
+
+  Copyright (c) 2007, Michael Jerris. All rights reserved.
+  email:mike@jerris.com  
+
+  Redistribution and use in source and binary forms, with or without 
+  modification, are permitted provided that the following conditions are 
+  met:
+
+	* Redistributions of source code must retain the above copyright notice, 
+	  this list of conditions and the following disclaimer.
+	* Redistributions in binary form must reproduce the above copyright notice, 
+	  this list of conditions and the following disclaimer in the documentation 
+	  and/or other materials provided with the distribution.
+	* Neither the name of the Case Labs, Ltd nor the names of its contributors 
+	  may be used to endorse or promote products derived from this software 
+	  without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
+  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
+  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+  POSSIBILITY OF SUCH DAMAGE.
+*****************************************************************************/
+
+#include "national.h"
+
+/*****************************************************************************
+  Function:		nationalCreateNT
+
+  Description:	Will create the National ISDN NT as a Dialect in the stack. The first
+				bulk set up the message handlers, the second bulk the IE
+				encoders/coders, and the last bulk set up the state table.
+
+  Parameters:	i		Dialect index
+*****************************************************************************/
+void nationalCreateNT(L3UCHAR i)
+{
+	Q931SetMesProc(Q931mes_ALERTING,             i, Q931ProcAlertingNT,          Q931Umes_Alerting,          Q931Pmes_Alerting);
+	Q931SetMesProc(Q931mes_CALL_PROCEEDING,      i, Q931ProcCallProceedingNT,    Q931Umes_CallProceeding,    Q931Pmes_CallProceeding);
+	Q931SetMesProc(Q931mes_CONNECT,              i, Q931ProcConnectNT,           Q931Umes_Connect,           Q931Pmes_Connect);
+	Q931SetMesProc(Q931mes_CONNECT_ACKNOWLEDGE,  i, Q931ProcConnectAckNT,        Q931Umes_ConnectAck,        Q931Pmes_ConnectAck);
+	Q931SetMesProc(Q931mes_PROGRESS,             i, Q931ProcProgressNT,          Q931Umes_Progress,          Q931Pmes_Progress);
+	Q931SetMesProc(Q931mes_SETUP,                i, Q931ProcSetupNT,             nationalUmes_Setup,         nationalPmes_Setup);
+	Q931SetMesProc(Q931mes_SETUP_ACKNOWLEDGE,    i, Q931ProcSetupAckNT,          Q931Umes_SetupAck,          Q931Pmes_SetupAck);
+	Q931SetMesProc(Q931mes_RESUME,               i, Q931ProcResumeNT,            Q931Umes_Resume,            Q931Pmes_Resume);
+	Q931SetMesProc(Q931mes_RESUME_ACKNOWLEDGE,   i, Q931ProcResumeAckNT,         Q931Umes_ResumeAck,         Q931Pmes_ResumeAck);
+	Q931SetMesProc(Q931mes_RESUME_REJECT,        i, Q931ProcResumeRejectNT,      Q931Umes_ResumeReject,      Q931Pmes_ResumeReject);
+	Q931SetMesProc(Q931mes_SUSPEND,              i, Q931ProcSuspendNT,           Q931Umes_Suspend,           Q931Pmes_Suspend);
+	Q931SetMesProc(Q931mes_SUSPEND_ACKNOWLEDGE,  i, Q931ProcSuspendAckNT,        Q931Umes_SuspendAck,        Q931Pmes_SuspendAck);
+	Q931SetMesProc(Q931mes_SUSPEND_REJECT,       i, Q931ProcSuspendRejectNT,     Q931Umes_SuspendReject,     Q931Pmes_SuspendReject);
+	Q931SetMesProc(Q931mes_USER_INFORMATION,     i, Q931ProcUserInformationNT,   Q931Umes_UserInformation,   Q931Pmes_UserInformation);
+	Q931SetMesProc(Q931mes_DISCONNECT,           i, Q931ProcDisconnectNT,        Q931Umes_Disconnect,        Q931Pmes_Disconnect);
+	Q931SetMesProc(Q931mes_RELEASE,              i, Q931ProcReleaseNT,           Q931Umes_Release,           Q931Pmes_Release);
+	Q931SetMesProc(Q931mes_RELEASE_COMPLETE,     i, Q931ProcReleaseCompleteNT,   Q931Umes_ReleaseComplete,   Q931Pmes_ReleaseComplete);
+	Q931SetMesProc(Q931mes_RESTART,              i, Q931ProcRestartNT,           Q931Umes_Restart,           Q931Pmes_Restart);
+	Q931SetMesProc(Q931mes_RESTART_ACKNOWLEDGE,  i, Q931ProcRestartAckNT,        Q931Umes_RestartAck,        Q931Pmes_RestartAck);
+	Q931SetMesProc(Q931mes_CONGESTION_CONTROL,   i, Q931ProcCongestionControlNT, Q931Umes_CongestionControl, Q931Pmes_CongestionControl);
+	Q931SetMesProc(Q931mes_INFORMATION,          i, Q931ProcInformationNT,       Q931Umes_Information,       Q931Pmes_Information);
+	Q931SetMesProc(Q931mes_NOTIFY,               i, Q931ProcNotifyNT,            Q931Umes_Notify,            Q931Pmes_Notify);
+	Q931SetMesProc(Q931mes_STATUS,               i, Q931ProcStatusNT,            Q931Umes_Status,            Q931Pmes_Status);
+	Q931SetMesProc(Q931mes_STATUS_ENQUIRY,       i, Q931ProcStatusEnquiryNT,     Q931Umes_StatusEnquiry,     Q931Pmes_StatusEnquiry);
+	Q931SetMesProc(Q931mes_SEGMENT,              i, Q931ProcSegmentNT,           Q931Umes_Segment,           Q931Pmes_Segment);
+
+	Q931SetMesProc(Q932mes_FACILITY,             i, Q932ProcFacilityNT,          Q932Umes_Facility,          Q932Pmes_Facility);
+	Q931SetMesProc(Q932mes_HOLD,                 i, Q932ProcHoldNT,              Q932Umes_Hold,              Q932Pmes_Hold);
+	Q931SetMesProc(Q932mes_HOLD_ACKNOWLEDGE,     i, Q932ProcHoldAckNT,           Q932Umes_HoldAck,           Q932Pmes_HoldAck);
+	Q931SetMesProc(Q932mes_HOLD_REJECT,          i, Q932ProcHoldRejectNT,        Q932Umes_HoldReject,        Q932Pmes_HoldReject);
+	Q931SetMesProc(Q932mes_REGISTER,             i, Q932ProcRegisterNT,          Q932Umes_Register,          Q932Pmes_Register);
+	Q931SetMesProc(Q932mes_RETRIEVE,             i, Q932ProcRetrieveNT,          Q932Umes_Retrieve,          Q932Pmes_Retrieve);
+	Q931SetMesProc(Q932mes_RETRIEVE_ACKNOWLEDGE, i, Q932ProcRetrieveAckNT,       Q932Umes_RetrieveAck,       Q932Pmes_RetrieveAck);
+	Q931SetMesProc(Q932mes_RETRIEVE_REJECT,      i, Q932ProcRetrieveRejectNT,    Q932Umes_RetrieveReject,    Q932Pmes_RetrieveReject);
+
+	/* Set up the IE encoder/decoder handle table.*/ 
+	Q931SetIEProc(Q931ie_SEGMENTED_MESSAGE,                i, Q931Pie_Segment,       Q931Uie_Segment);
+	Q931SetIEProc(Q931ie_BEARER_CAPABILITY,                i, Q931Pie_BearerCap,     Q931Uie_BearerCap);
+	Q931SetIEProc(Q931ie_CAUSE,                            i, Q931Pie_Cause,         Q931Uie_Cause);
+	Q931SetIEProc(Q931ie_CALL_IDENTITY,                    i, Q931Pie_CallID,        Q931Uie_CallID);
+	Q931SetIEProc(Q931ie_CALL_STATE,                       i, Q931Pie_CallState,     Q931Uie_CallState);
+	Q931SetIEProc(Q931ie_CHANNEL_IDENTIFICATION,           i, Q931Pie_ChanID,        Q931Uie_ChanID);
+	Q931SetIEProc(Q931ie_PROGRESS_INDICATOR,               i, Q931Pie_ProgInd,       Q931Uie_ProgInd);
+	Q931SetIEProc(Q931ie_NETWORK_SPECIFIC_FACILITIES,      i, Q931Pie_NetFac,        Q931Uie_NetFac);
+	Q931SetIEProc(Q931ie_NOTIFICATION_INDICATOR,           i, Q931Pie_NotifInd,      Q931Uie_NotifInd);
+	Q931SetIEProc(Q931ie_DISPLAY,                          i, Q931Pie_Display,       Q931Uie_Display);
+	Q931SetIEProc(Q931ie_DATETIME,                         i, Q931Pie_DateTime,      Q931Uie_DateTime);
+	Q931SetIEProc(Q931ie_KEYPAD_FACILITY,                  i, Q931Pie_KeypadFac,     Q931Uie_KeypadFac);
+	Q931SetIEProc(Q931ie_SIGNAL,                           i, Q931Pie_Signal,        Q931Uie_Signal);
+	Q931SetIEProc(Q931ie_TRANSIT_DELAY_SELECTION_AND_IND,  i, Q931Pie_TransNetSel,   Q931Uie_TransNetSel);
+	Q931SetIEProc(Q931ie_CALLING_PARTY_NUMBER,             i, Q931Pie_CallingNum,    Q931Uie_CallingNum);
+	Q931SetIEProc(Q931ie_CALLING_PARTY_SUBADDRESS,         i, Q931Pie_CallingSub,    Q931Uie_CallingSub);
+	Q931SetIEProc(Q931ie_CALLED_PARTY_NUMBER,              i, Q931Pie_CalledNum,     Q931Uie_CalledNum);
+	Q931SetIEProc(Q931ie_CALLED_PARTY_SUBADDRESS,          i, Q931Pie_CalledSub,     Q931Uie_CalledSub);
+	Q931SetIEProc(Q931ie_TRANSIT_NETWORK_SELECTION,        i, Q931Pie_TransNetSel,   Q931Uie_TransNetSel);
+	Q931SetIEProc(Q931ie_RESTART_INDICATOR,                i, Q931Pie_RestartInd,    Q931Uie_RestartInd);
+	Q931SetIEProc(Q931ie_LOW_LAYER_COMPATIBILITY,          i, Q931Pie_LLComp,        Q931Uie_LLComp);
+	Q931SetIEProc(Q931ie_HIGH_LAYER_COMPATIBILITY,         i, Q931Pie_HLComp,        Q931Uie_HLComp);
+	Q931SetIEProc(Q931ie_USER_USER,                        i, Q931Pie_UserUser,      Q931Uie_UserUser);
+	Q931SetIEProc(Q931ie_GENERIC_DIGITS,                   i, Q931Pie_GenericDigits, Q931Uie_GenericDigits);
+
+	Q931SetIEProc(Q931ie_CONNECTED_NUMBER, i, Q931Pie_Generic, Q931Uie_Generic);
+	Q931SetIEProc(Q931ie_FACILITY,         i, Q931Pie_Generic, Q931Uie_Generic);
+	Q931SetIEProc(Q931ie_REDIRECTING_NUMBER, i, Q931Pie_Generic, Q931Uie_Generic);
+
+	/* The following define a state machine. The point is that the Message	*/
+	/* procs can when search this to find out if the message/state			*/
+	/* combination is legale. If not, the proc for unexpected message apply.*/
+
+	/* TODO define state table here */
+}

Added: freeswitch/trunk/libs/openzap/src/isdn/nationalStateTE.c (0 => 17141)


--- freeswitch/trunk/libs/openzap/src/isdn/nationalStateTE.c	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/src/isdn/nationalStateTE.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,217 @@
+/*****************************************************************************
+
+  FileName:		nationalStateTE.c
+
+  Contents:		National ISDN State Engine for TE (User Mode).
+
+			The controlling state engine for Q.931 is the state engine
+			on the NT side. The state engine on the TE side is a slave 
+			of this. The TE side maintain it's own states as described in
+			ITU-T Q931, but will in	raise conditions be overridden by 
+			the NT side.
+
+			This reference implementation uses a process per message,
+			meaning that each message must check call states. This
+			is easier for dialect maintenance as each message proc
+			can be replaced individually. A new TE variant only
+			need to copy the Q931CreateTE and replace those procs or
+			need to override.
+
+  License/Copyright:
+
+  Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+  email:janvb@caselaboratories.com  
+
+  Copyright (c) 2007, Michael Jerris. All rights reserved.
+  email:mike@jerris.com  
+
+  Redistribution and use in source and binary forms, with or without 
+  modification, are permitted provided that the following conditions are 
+  met:
+
+	* Redistributions of source code must retain the above copyright notice, 
+	  this list of conditions and the following disclaimer.
+	* Redistributions in binary form must reproduce the above copyright notice, 
+	  this list of conditions and the following disclaimer in the documentation 
+	  and/or other materials provided with the distribution.
+	* Neither the name of the Case Labs, Ltd nor the names of its contributors 
+	  may be used to endorse or promote products derived from this software 
+	  without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
+  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
+  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+  POSSIBILITY OF SUCH DAMAGE.
+*****************************************************************************/
+
+#include "national.h"
+extern L3INT Q931L4HeaderSpace;
+
+/*****************************************************************************
+  Function:		nationalCreateTE
+
+  Description:	Will create the National TE as a Dialect in the stack. The first
+				bulk set up the message handlers, the second bulk the IE
+				encoders/coders, and the last bulk set up the state table.
+
+  Parameters:	i		Dialect index
+*****************************************************************************/
+void nationalCreateTE(L3UCHAR i)
+{
+	Q931SetMesProc(Q931mes_ALERTING,             i, Q931ProcAlertingTE,          Q931Umes_Alerting,          Q931Pmes_Alerting);
+	Q931SetMesProc(Q931mes_CALL_PROCEEDING,      i, Q931ProcCallProceedingTE,    Q931Umes_CallProceeding,    Q931Pmes_CallProceeding);
+	Q931SetMesProc(Q931mes_CONNECT,              i, DMSProc0x07TE,               DMSUmes_0x07,               DMSPmes_0x07);
+	Q931SetMesProc(Q931mes_CONNECT_ACKNOWLEDGE,  i, DMSProc0x0fTE,               DMSUmes_0x0f,               DMSPmes_0x0f);
+	Q931SetMesProc(Q931mes_PROGRESS,             i, Q931ProcProgressTE,          Q931Umes_Progress,          Q931Pmes_Progress);
+	Q931SetMesProc(Q931mes_SETUP,                i, Q931ProcSetupTE,             nationalUmes_Setup,         nationalPmes_Setup);
+	Q931SetMesProc(Q931mes_SETUP_ACKNOWLEDGE,    i, Q931ProcSetupAckTE,          Q931Umes_SetupAck,          Q931Pmes_SetupAck);
+	Q931SetMesProc(Q931mes_RESUME,               i, Q931ProcResumeTE,            Q931Umes_Resume,            Q931Pmes_Resume);
+	Q931SetMesProc(Q931mes_RESUME_ACKNOWLEDGE,   i, Q931ProcResumeAckTE,         Q931Umes_ResumeAck,         Q931Pmes_ResumeAck);
+	Q931SetMesProc(Q931mes_RESUME_REJECT,        i, Q931ProcResumeRejectTE,      Q931Umes_ResumeReject,      Q931Pmes_ResumeReject);
+	Q931SetMesProc(Q931mes_SUSPEND,              i, Q931ProcSuspendTE,           Q931Umes_Suspend,           Q931Pmes_Suspend);
+	Q931SetMesProc(Q931mes_SUSPEND_ACKNOWLEDGE,  i, Q931ProcSuspendAckTE,        Q931Umes_SuspendAck,        Q931Pmes_SuspendAck);
+	Q931SetMesProc(Q931mes_SUSPEND_REJECT,       i, Q931ProcSuspendRejectTE,     Q931Umes_SuspendReject,     Q931Pmes_SuspendReject);
+	Q931SetMesProc(Q931mes_USER_INFORMATION,     i, Q931ProcUserInformationTE,   Q931Umes_UserInformation,   Q931Pmes_UserInformation);
+	Q931SetMesProc(Q931mes_DISCONNECT,           i, Q931ProcDisconnectTE,        Q931Umes_Disconnect,        Q931Pmes_Disconnect);
+	Q931SetMesProc(Q931mes_RELEASE,              i, Q931ProcReleaseTE,           Q931Umes_Release,           Q931Pmes_Release);
+	Q931SetMesProc(Q931mes_RELEASE_COMPLETE,     i, Q931ProcReleaseCompleteTE,   Q931Umes_ReleaseComplete,   Q931Pmes_ReleaseComplete);
+	Q931SetMesProc(Q931mes_RESTART,              i, Q931ProcRestartTE,           Q931Umes_Restart,           Q931Pmes_Restart);
+	Q931SetMesProc(Q931mes_RESTART_ACKNOWLEDGE,  i, Q931ProcRestartAckTE,        Q931Umes_RestartAck,        Q931Pmes_RestartAck);
+	Q931SetMesProc(Q931mes_CONGESTION_CONTROL,   i, Q931ProcCongestionControlTE, Q931Umes_CongestionControl, Q931Pmes_CongestionControl);
+	Q931SetMesProc(Q931mes_INFORMATION,          i, Q931ProcInformationTE,       Q931Umes_Information,       Q931Pmes_Information);
+	Q931SetMesProc(Q931mes_NOTIFY,               i, Q931ProcNotifyTE,            Q931Umes_Notify,            Q931Pmes_Notify);
+	Q931SetMesProc(Q931mes_STATUS,               i, Q931ProcStatusTE,            Q931Umes_Status,            Q931Pmes_Status);
+	Q931SetMesProc(Q931mes_STATUS_ENQUIRY,       i, Q931ProcStatusEnquiryTE,     Q931Umes_StatusEnquiry,     Q931Pmes_StatusEnquiry);
+	Q931SetMesProc(Q931mes_SEGMENT,              i, Q931ProcSegmentTE,           Q931Umes_Segment,           Q931Pmes_Segment);
+
+	Q931SetMesProc(Q932mes_FACILITY,             i, Q932ProcFacilityTE,          Q932Umes_Facility,          Q932Pmes_Facility);
+	Q931SetMesProc(Q932mes_HOLD,                 i, Q932ProcHoldTE,              Q932Umes_Hold,              Q932Pmes_Hold);
+	Q931SetMesProc(Q932mes_HOLD_ACKNOWLEDGE,     i, Q932ProcHoldAckTE,           Q932Umes_HoldAck,           Q932Pmes_HoldAck);
+	Q931SetMesProc(Q932mes_HOLD_REJECT,          i, Q932ProcHoldRejectTE,        Q932Umes_HoldReject,        Q932Pmes_HoldReject);
+	Q931SetMesProc(Q932mes_REGISTER,             i, Q932ProcRegisterTE,          Q932Umes_Register,          Q932Pmes_Register);
+	Q931SetMesProc(Q932mes_RETRIEVE,             i, Q932ProcRetrieveTE,          Q932Umes_Retrieve,          Q932Pmes_Retrieve);
+	Q931SetMesProc(Q932mes_RETRIEVE_ACKNOWLEDGE, i, Q932ProcRetrieveAckTE,       Q932Umes_RetrieveAck,       Q932Pmes_RetrieveAck);
+	Q931SetMesProc(Q932mes_RETRIEVE_REJECT,      i, Q932ProcRetrieveRejectTE,    Q932Umes_RetrieveReject,    Q932Pmes_RetrieveReject);
+
+	/* Set up the IE encoder/decoder handle table.*/ 
+	Q931SetIEProc(Q931ie_SEGMENTED_MESSAGE,                i, Q931Pie_Segment,       Q931Uie_Segment);
+	Q931SetIEProc(Q931ie_BEARER_CAPABILITY,                i, Q931Pie_BearerCap,     Q931Uie_BearerCap);
+	Q931SetIEProc(Q931ie_CAUSE,                            i, Q931Pie_Cause,         Q931Uie_Cause);
+	Q931SetIEProc(Q931ie_CALL_IDENTITY,                    i, Q931Pie_CallID,        Q931Uie_CallID);
+	Q931SetIEProc(Q931ie_CALL_STATE,                       i, Q931Pie_CallState,     Q931Uie_CallState);
+	Q931SetIEProc(Q931ie_CHANGE_STATUS,                    i, Q931Pie_ChangeStatus,  Q931Uie_ChangeStatus);
+	Q931SetIEProc(Q931ie_CHANNEL_IDENTIFICATION,           i, Q931Pie_ChanID,        Q931Uie_ChanID);
+	Q931SetIEProc(Q931ie_PROGRESS_INDICATOR,               i, Q931Pie_ProgInd,       Q931Uie_ProgInd);
+	Q931SetIEProc(Q931ie_NETWORK_SPECIFIC_FACILITIES,      i, Q931Pie_NetFac,        Q931Uie_NetFac);
+	Q931SetIEProc(Q931ie_NOTIFICATION_INDICATOR,           i, Q931Pie_NotifInd,      Q931Uie_NotifInd);
+	Q931SetIEProc(Q931ie_DISPLAY,                          i, Q931Pie_Display,       Q931Uie_Display);
+	Q931SetIEProc(Q931ie_DATETIME,                         i, Q931Pie_DateTime,      Q931Uie_DateTime);
+	Q931SetIEProc(Q931ie_KEYPAD_FACILITY,                  i, Q931Pie_KeypadFac,     Q931Uie_KeypadFac);
+	Q931SetIEProc(Q931ie_SIGNAL,                           i, Q931Pie_Signal,        Q931Uie_Signal);
+	Q931SetIEProc(Q931ie_TRANSIT_DELAY_SELECTION_AND_IND,  i, Q931Pie_TransNetSel,   Q931Uie_TransNetSel);
+	Q931SetIEProc(Q931ie_CALLING_PARTY_NUMBER,             i, Q931Pie_CallingNum,    Q931Uie_CallingNum);
+	Q931SetIEProc(Q931ie_CALLING_PARTY_SUBADDRESS,         i, Q931Pie_CallingSub,    Q931Uie_CallingSub);
+	Q931SetIEProc(Q931ie_CALLED_PARTY_NUMBER,              i, Q931Pie_CalledNum,     Q931Uie_CalledNum);
+	Q931SetIEProc(Q931ie_CALLED_PARTY_SUBADDRESS,          i, Q931Pie_CalledSub,     Q931Uie_CalledSub);
+	Q931SetIEProc(Q931ie_TRANSIT_NETWORK_SELECTION,        i, Q931Pie_TransNetSel,   Q931Uie_TransNetSel);
+	Q931SetIEProc(Q931ie_RESTART_INDICATOR,                i, Q931Pie_RestartInd,    Q931Uie_RestartInd);
+	Q931SetIEProc(Q931ie_LOW_LAYER_COMPATIBILITY,          i, Q931Pie_LLComp,        Q931Uie_LLComp);
+	Q931SetIEProc(Q931ie_HIGH_LAYER_COMPATIBILITY,         i, Q931Pie_HLComp,        Q931Uie_HLComp);
+	Q931SetIEProc(Q931ie_USER_USER,                        i, Q931Pie_UserUser,      Q931Uie_UserUser);
+	Q931SetIEProc(Q931ie_GENERIC_DIGITS,                   i, Q931Pie_GenericDigits, Q931Uie_GenericDigits);
+
+	Q931SetIEProc(Q931ie_CONNECTED_NUMBER, i, Q931Pie_Generic, Q931Uie_Generic);
+	Q931SetIEProc(Q931ie_FACILITY,         i, Q931Pie_Generic, Q931Uie_Generic);
+	Q931SetIEProc(Q931ie_REDIRECTING_NUMBER, i, Q931Pie_Generic, Q931Uie_Generic);
+
+	/* The following define a state machine. The point is that the Message
+	 * procs can when search this to find out if the message/state
+	 * combination is legale. If not, the proc for unexpected message apply.
+	 */
+
+	/* State 0 Idle */
+	Q931AddStateEntry(i, Q931_U0, Q931mes_RESUME,           2);
+	Q931AddStateEntry(i, Q931_U0, Q931mes_SETUP,            4);
+	Q931AddStateEntry(i, Q931_U0, Q931mes_SETUP,            2);
+	Q931AddStateEntry(i, Q931_U0, Q931mes_STATUS,           4);
+	Q931AddStateEntry(i, Q931_U0, Q931mes_RELEASE,          4);
+	Q931AddStateEntry(i, Q931_U0, Q931mes_RELEASE_COMPLETE, 4);
+
+	/* State 1 Call Initiating */
+	Q931AddStateEntry(i, Q931_U1, Q931mes_DISCONNECT,        2);
+	Q931AddStateEntry(i, Q931_U1, Q931mes_SETUP_ACKNOWLEDGE, 4);
+	Q931AddStateEntry(i, Q931_U1, Q931mes_RELEASE_COMPLETE,  4);
+	Q931AddStateEntry(i, Q931_U1, Q931mes_CALL_PROCEEDING,   4);
+	Q931AddStateEntry(i, Q931_U1, Q931mes_ALERTING,          4);
+	Q931AddStateEntry(i, Q931_U1, Q931mes_CONNECT,           4);
+
+	/* State 2 Overlap Sending */
+	Q931AddStateEntry(i, Q931_U2, Q931mes_INFORMATION,     2);
+	Q931AddStateEntry(i, Q931_U2, Q931mes_CALL_PROCEEDING, 4);
+	Q931AddStateEntry(i, Q931_U2, Q931mes_ALERTING,        4);
+	Q931AddStateEntry(i, Q931_U2, Q931mes_PROGRESS,        4);
+	Q931AddStateEntry(i, Q931_U2, Q931mes_CONNECT,         4);
+	Q931AddStateEntry(i, Q931_U2, Q931mes_RELEASE,         2);
+
+	/* State 3 Outgoing Call Proceeding */
+	Q931AddStateEntry(i, Q931_U3, Q931mes_PROGRESS, 4);
+	Q931AddStateEntry(i, Q931_U3, Q931mes_ALERTING, 4);
+	Q931AddStateEntry(i, Q931_U3, Q931mes_CONNECT,  4);
+	Q931AddStateEntry(i, Q931_U3, Q931mes_RELEASE,  2);
+
+	/* State 4 Call Delivered */
+	Q931AddStateEntry(i, Q931_U4, Q931mes_CONNECT, 4);
+
+	/* State 6 Call Precent */
+	Q931AddStateEntry(i, Q931_U6, Q931mes_INFORMATION,      2);	
+	Q931AddStateEntry(i, Q931_U6, Q931mes_ALERTING,         2);	
+	Q931AddStateEntry(i, Q931_U6, Q931mes_CALL_PROCEEDING,  2);	
+	Q931AddStateEntry(i, Q931_U6, Q931mes_CONNECT,          2);	
+	Q931AddStateEntry(i, Q931_U6, Q931mes_RELEASE_COMPLETE, 2);	
+	Q931AddStateEntry(i, Q931_U6, Q931mes_RELEASE,          4);	
+	Q931AddStateEntry(i, Q931_U6, Q931mes_DISCONNECT,       4);	
+
+	/* State 7 Call Received */
+	Q931AddStateEntry(i, Q931_U7, Q931mes_CONNECT, 2);
+
+	/* State 8 Connect request */
+	Q931AddStateEntry(i, Q931_U8, Q931mes_CONNECT_ACKNOWLEDGE, 4);
+
+	/* State 9 Incoming Call Proceeding */
+	Q931AddStateEntry(i, Q931_U9, Q931mes_CONNECT,  2);
+	Q931AddStateEntry(i, Q931_U9, Q931mes_ALERTING, 2);
+	Q931AddStateEntry(i, Q931_U9, Q931mes_PROGRESS, 2);
+
+	/* State 10 Active */
+	Q931AddStateEntry(i, Q931_U10, Q931mes_SUSPEND, 2);
+	Q931AddStateEntry(i, Q931_U10, Q931mes_NOTIFY,  4);
+	Q931AddStateEntry(i, Q931_U10, Q931mes_NOTIFY,  2);
+
+	/* State 11 Disconnect Request */
+	Q931AddStateEntry(i, Q931_U11, Q931mes_RELEASE,    4);
+	Q931AddStateEntry(i, Q931_U11, Q931mes_DISCONNECT, 4);
+	Q931AddStateEntry(i, Q931_U11, Q931mes_NOTIFY,     4);
+
+	/* State 12 Disconnect Ind */
+	Q931AddStateEntry(i, Q931_U12, Q931mes_RELEASE, 4);
+	Q931AddStateEntry(i, Q931_U12, Q931mes_RELEASE, 2);
+
+	/* State 15 Suspend Request */
+	Q931AddStateEntry(i, Q931_U15, Q931mes_SUSPEND_ACKNOWLEDGE, 4);
+	Q931AddStateEntry(i, Q931_U15, Q931mes_SUSPEND_REJECT,      4);
+	Q931AddStateEntry(i, Q931_U15, Q931mes_DISCONNECT,          4);
+	Q931AddStateEntry(i, Q931_U15, Q931mes_RELEASE,             4);
+
+/* TODO
+	Q931AddStateEntry(i, Q931_U17,
+	Q931AddStateEntry(i, Q931_U19,
+	Q931AddStateEntry(i, Q931_U25,
+*/
+}

Added: freeswitch/trunk/libs/openzap/src/isdn/nationalmes.c (0 => 17141)


--- freeswitch/trunk/libs/openzap/src/isdn/nationalmes.c	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/src/isdn/nationalmes.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,269 @@
+/*****************************************************************************
+
+  FileName:	nationalmes.c
+
+  Contents:	Pack/Unpack functions. These functions will unpack a National ISDN
+		message from the bit packed original format into structs
+		that contains variables sized by the user. It will also pack
+		the struct back into a Q.931 message as required.
+
+		See national.h for description. 
+
+  License/Copyright:
+
+  Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
+  email:janvb@caselaboratories.com  
+
+  Copyright (c) 2007, Michael Jerris. All rights reserved.
+  email:mike@jerris.com  
+
+  Redistribution and use in source and binary forms, with or without 
+  modification, are permitted provided that the following conditions are 
+  met:
+
+	* Redistributions of source code must retain the above copyright notice, 
+	  this list of conditions and the following disclaimer.
+	* Redistributions in binary form must reproduce the above copyright notice, 
+	  this list of conditions and the following disclaimer in the documentation 
+	  and/or other materials provided with the distribution.
+	* Neither the name of the Case Labs, Ltd nor the names of its contributors 
+	  may be used to endorse or promote products derived from this software 
+	  without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
+  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
+  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+  POSSIBILITY OF SUCH DAMAGE.
+
+*****************************************************************************/
+
+#include "national.h"
+
+/*****************************************************************************
+
+  Function:	 nationalUmes_Setup
+
+*****************************************************************************/
+L3INT nationalUmes_Setup(Q931_TrunkInfo_t *pTrunk, L3UCHAR *IBuf, Q931mes_Generic *mes, L3INT IOff, L3INT Size)
+{
+	L3INT ir = 0;
+	L3INT OOff = 0;
+	L3INT rc = Q931E_NO_ERROR;
+	L3UCHAR last_codeset = 0, codeset = 0;
+	L3UCHAR shift_lock = 1;
+
+	while (IOff < Size) {
+		if (!shift_lock) {
+			codeset = last_codeset;
+		}
+
+		if ((IBuf[IOff] & 0xF0) == Q931ie_SHIFT ) {
+			shift_lock = (IBuf[IOff] & 0x08);
+			if (shift_lock) {
+				last_codeset = codeset;
+			}
+			codeset = ((IBuf[IOff] & 0x07));
+			IOff++;
+		}
+
+		if (codeset == 0) {
+			switch (IBuf[IOff]) {
+			case Q931ie_SENDING_COMPLETE:
+			case Q931ie_BEARER_CAPABILITY:
+			case Q931ie_CHANNEL_IDENTIFICATION:
+			case Q931ie_PROGRESS_INDICATOR:
+			case Q931ie_NETWORK_SPECIFIC_FACILITIES:
+			case Q931ie_DISPLAY:
+			case Q931ie_DATETIME:
+			case Q931ie_KEYPAD_FACILITY:
+			case Q931ie_SIGNAL:
+			case Q931ie_CALLING_PARTY_NUMBER:
+			case Q931ie_CALLING_PARTY_SUBADDRESS:
+			case Q931ie_CALLED_PARTY_NUMBER:
+			case Q931ie_CALLED_PARTY_SUBADDRESS:
+			case Q931ie_TRANSIT_NETWORK_SELECTION:
+			case Q931ie_LOW_LAYER_COMPATIBILITY:
+			case Q931ie_HIGH_LAYER_COMPATIBILITY:
+			case Q931ie_FACILITY:
+			case Q931ie_REDIRECTING_NUMBER:
+				rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+				if (rc != Q931E_NO_ERROR)
+					return rc;
+				break;
+			case Q931ie_REPEAT_INDICATOR:
+				if (ir < 2) {
+					rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+					ir++;
+				} else {
+					return Q931E_ILLEGAL_IE;
+				}
+				break;
+			default:
+				return Q931E_ILLEGAL_IE;
+				break;
+			}
+		} else if (codeset == 6) {
+			switch (IBuf[IOff]) {
+			case Q931ie_GENERIC_DIGITS:
+				rc = Q931Uie[pTrunk->Dialect][IBuf[IOff]](pTrunk, mes, &IBuf[IOff], &mes->buf[OOff], &IOff, &OOff);
+				if (rc != Q931E_NO_ERROR) 
+					return rc;
+				break;
+			default:
+				return Q931E_ILLEGAL_IE;
+				break;
+			}
+
+		} else {
+			return Q931E_ILLEGAL_IE;
+		}
+	}
+	mes->Size = sizeof(Q931mes_Generic) - 1 + OOff;
+	return Q931E_NO_ERROR;
+}
+
+/*****************************************************************************
+
+  Function:	 nationalPmes_Setup
+
+  Decription:	Pack a Q931mes_Generic into a real Q.931 message. The user will
+				set up a SETUP message and issue this to the stack where it
+				is processed by Q931ProcSetup that processes and validates
+				it before it actually sends it out. This function is called
+				to compute the real Q.931 message.
+
+  Parameters:	IBuf[IN]	Ptr to un-packed struct
+				ISize[IN]	Size of input buffer (unpacked message).
+				OBuf[OUT]	Ptr to packed 'octet' wise message.
+				OSize[OUT]	Size of packed message.
+
+  Called By:	Q931ProcSetup
+
+*****************************************************************************/
+L3INT nationalPmes_Setup(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
+{
+	L3INT rc = Q931E_NO_ERROR;
+	Q931mes_Generic *pMes = (Q931mes_Generic *)IBuf;
+	L3INT Octet = 0;
+
+	/* Q931 Message Header */
+	Q931MesgHeader(pTrunk, pMes, OBuf, *OSize, &Octet);
+
+	/* Sending Complete */
+	if (Q931IsIEPresent(pMes->SendComplete)) {
+		OBuf[Octet++]	= (L3UCHAR)(pMes->SendComplete & 0x00ff);
+	}
+
+	/* Repeat Indicator */
+	if (Q931IsIEPresent(pMes->RepeatInd)) {
+		OBuf[Octet++]	= (L3UCHAR)(pMes->RepeatInd & 0x00ff);		
+	}
+
+	/* Bearer capability */
+	if (Q931IsIEPresent(pMes->BearerCap)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_BEARER_CAPABILITY](pTrunk, Q931GetIEPtr(pMes->BearerCap,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+	else {
+		rc = Q931E_BEARERCAP;
+	}
+
+	/* Channel Identification */
+	if (Q931IsIEPresent(pMes->ChanID)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CHANNEL_IDENTIFICATION](pTrunk, Q931GetIEPtr(pMes->ChanID,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Progress indicator */
+	if (Q931IsIEPresent(pMes->ProgInd)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_PROGRESS_INDICATOR](pTrunk, Q931GetIEPtr(pMes->ProgInd,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Network spesific facilities */
+	if (Q931IsIEPresent(pMes->NetFac)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_NETWORK_SPECIFIC_FACILITIES](pTrunk, Q931GetIEPtr(pMes->NetFac,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Display */
+	if (Q931IsIEPresent(pMes->Display)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_DISPLAY](pTrunk, Q931GetIEPtr(pMes->Display,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Date/Time */
+	if (Q931IsIEPresent(pMes->DateTime)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_DATETIME](pTrunk, Q931GetIEPtr(pMes->DateTime,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Keypad Facility */
+	if (Q931IsIEPresent(pMes->KeypadFac)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_KEYPAD_FACILITY](pTrunk, Q931GetIEPtr(pMes->KeypadFac,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Signal */
+	if (Q931IsIEPresent(pMes->Signal)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_SIGNAL](pTrunk, Q931GetIEPtr(pMes->Signal,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Calling Party Number */
+	if (Q931IsIEPresent(pMes->CallingNum)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CALLING_PARTY_NUMBER](pTrunk, Q931GetIEPtr(pMes->CallingNum,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Calling Party Subaddress */
+	if (Q931IsIEPresent(pMes->CallingSub)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CALLING_PARTY_SUBADDRESS](pTrunk, Q931GetIEPtr(pMes->CallingSub,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Called Party number */
+	if (Q931IsIEPresent(pMes->CalledNum)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CALLED_PARTY_NUMBER](pTrunk, Q931GetIEPtr(pMes->CalledNum,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Called party subaddress */
+	if (Q931IsIEPresent(pMes->CalledSub)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_CALLED_PARTY_SUBADDRESS](pTrunk, Q931GetIEPtr(pMes->CalledSub,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Transit network selection */
+	if (Q931IsIEPresent(pMes->TransNetSel)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_TRANSIT_NETWORK_SELECTION](pTrunk, Q931GetIEPtr(pMes->TransNetSel,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* Repeat Indicator */
+	if (Q931IsIEPresent(pMes->LLRepeatInd)) {
+		rc = Q931E_UNKNOWN_IE;/* TODO */
+	}
+
+	/* Low Layer Compatibility */
+	if (Q931IsIEPresent(pMes->LLComp)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_LOW_LAYER_COMPATIBILITY](pTrunk, Q931GetIEPtr(pMes->LLComp,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	/* High Layer Compatibility */
+	if (Q931IsIEPresent(pMes->HLComp)) {
+		if ((rc = Q931Pie[pTrunk->Dialect][Q931ie_HIGH_LAYER_COMPATIBILITY](pTrunk, Q931GetIEPtr(pMes->HLComp,pMes->buf), OBuf, &Octet)) != 0)
+			return rc;
+	}
+
+	*OSize = Octet;	
+	return rc;
+}

Added: freeswitch/trunk/libs/openzap/src/libteletone_detect.c (0 => 17141)


--- freeswitch/trunk/libs/openzap/src/libteletone_detect.c	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/src/libteletone_detect.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,427 @@
+/* 
+ * libteletone
+ * Copyright (C) 2005/2006, Anthony Minessale II <anthmct@yahoo.com>
+ *
+ * Much less efficient expansion interface was added to allow for the detection of 
+ * a single arbitrary tone combination which may also exceed 2 simultaneous tones.
+ * (controlled by compile time constant TELETONE_MAX_TONES)
+ *
+ * Copyright (C) 2006 Anthony Minessale II <anthmct@yahoo.com>
+ *
+ * libteletone_detect.c Tone Detection Code
+ *
+ * Copyright (c) 2007, Anthony Minessale II
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.	 IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ********************************************************************************* 
+ *
+ * Derived from tone_detect.c - General telephony tone detection, and specific
+ * detection of DTMF.
+ *
+ * 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.
+ *
+ *
+ *
+ */
+
+#include <libteletone_detect.h>
+
+#ifndef _MSC_VER
+#include <stdint.h>
+#endif
+#include <string.h>
+#include <stdio.h>
+#include <time.h>
+#include <fcntl.h>
+
+
+static teletone_detection_descriptor_t dtmf_detect_row[GRID_FACTOR];
+static teletone_detection_descriptor_t dtmf_detect_col[GRID_FACTOR];
+static teletone_detection_descriptor_t dtmf_detect_row_2nd[GRID_FACTOR];
+static teletone_detection_descriptor_t dtmf_detect_col_2nd[GRID_FACTOR];
+
+static float dtmf_row[] = {697.0f,	770.0f,	 852.0f,  941.0f};
+static float dtmf_col[] = {1209.0f, 1336.0f, 1477.0f, 1633.0f};
+
+static char dtmf_positions[] = "123A" "456B" "789C" "*0#D";
+
+static void goertzel_init(teletone_goertzel_state_t *goertzel_state, teletone_detection_descriptor_t *tdesc) {
+	goertzel_state->v2 = goertzel_state->v3 = 0.0;
+	goertzel_state->fac = tdesc->fac;
+}
+
+TELETONE_API(void) teletone_goertzel_update(teletone_goertzel_state_t *goertzel_state,
+							  int16_t sample_buffer[],
+							  int samples)
+{
+	int i;
+	float v1;
+	
+	for (i = 0;	 i < samples;  i++) {
+		v1 = goertzel_state->v2;
+		goertzel_state->v2 = goertzel_state->v3;
+		goertzel_state->v3 = (float)(goertzel_state->fac*goertzel_state->v2 - v1 + sample_buffer[i]);
+	}
+}
+#ifdef _MSC_VER
+#pragma warning(disable:4244)
+#endif
+
+#define teletone_goertzel_result(gs) (double)(((gs)->v3 * (gs)->v3 + (gs)->v2 * (gs)->v2 - (gs)->v2 * (gs)->v3 * (gs)->fac))
+
+TELETONE_API(void) teletone_dtmf_detect_init (teletone_dtmf_detect_state_t *dtmf_detect_state, int sample_rate)
+{
+	int i;
+	float theta;
+
+	dtmf_detect_state->hit1 = dtmf_detect_state->hit2 = 0;
+
+	for (i = 0;	 i < GRID_FACTOR;  i++) {
+		theta = (float)(M_TWO_PI*(dtmf_row[i]/(float)sample_rate));
+		dtmf_detect_row[i].fac = (float)(2.0*cos(theta));
+
+		theta = (float)(M_TWO_PI*(dtmf_col[i]/(float)sample_rate));
+		dtmf_detect_col[i].fac = (float)(2.0*cos(theta));
+	
+		theta = (float)(M_TWO_PI*(dtmf_row[i]*2.0/(float)sample_rate));
+		dtmf_detect_row_2nd[i].fac = (float)(2.0*cos(theta));
+
+		theta = (float)(M_TWO_PI*(dtmf_col[i]*2.0/(float)sample_rate));
+		dtmf_detect_col_2nd[i].fac = (float)(2.0*cos(theta));
+	
+		goertzel_init (&dtmf_detect_state->row_out[i], &dtmf_detect_row[i]);
+		goertzel_init (&dtmf_detect_state->col_out[i], &dtmf_detect_col[i]);
+		goertzel_init (&dtmf_detect_state->row_out2nd[i], &dtmf_detect_row_2nd[i]);
+		goertzel_init (&dtmf_detect_state->col_out2nd[i], &dtmf_detect_col_2nd[i]);
+	
+		dtmf_detect_state->energy = 0.0;
+	}
+	dtmf_detect_state->current_sample = 0;
+	dtmf_detect_state->detected_digits = 0;
+	dtmf_detect_state->lost_digits = 0;
+	dtmf_detect_state->digits[0] = '\0';
+	dtmf_detect_state->mhit = 0;
+}
+
+TELETONE_API(void) teletone_multi_tone_init(teletone_multi_tone_t *mt, teletone_tone_map_t *map)
+{
+	float theta = 0;
+	int x = 0;
+
+	if (!mt->sample_rate) {
+		mt->sample_rate = 8000;
+	}
+
+	if (!mt->min_samples) {
+		mt->min_samples = 102;
+	}
+
+	mt->min_samples *= (mt->sample_rate / 8000);
+
+	if (!mt->positive_factor) {
+		mt->positive_factor = 2;
+	}
+
+	if(!mt->negative_factor) {
+		mt->negative_factor = 10;
+	}
+
+	if (!mt->hit_factor) {
+		mt->hit_factor = 2;
+	}
+
+	for(x = 0; x < TELETONE_MAX_TONES; x++) {
+		if ((int) map->freqs[x] == 0) {
+			break;
+		}
+		mt->tone_count++;
+		theta = (float)(M_TWO_PI*(map->freqs[x]/(float)mt->sample_rate));
+		mt->tdd[x].fac = (float)(2.0 * cos(theta));
+		goertzel_init (&mt->gs[x], &mt->tdd[x]);
+		goertzel_init (&mt->gs2[x], &mt->tdd[x]);
+	}
+
+}
+
+TELETONE_API(int) teletone_multi_tone_detect (teletone_multi_tone_t *mt,
+								int16_t sample_buffer[],
+								int samples)
+{
+	int sample, limit = 0, j, x = 0;
+	float v1, famp;
+	float eng_sum = 0, eng_all[TELETONE_MAX_TONES] = {0.0};
+	int gtest = 0, see_hit = 0;
+
+	for (sample = 0;  sample >= 0 && sample < samples; sample = limit) {
+		mt->total_samples++;
+
+		if ((samples - sample) >= (mt->min_samples - mt->current_sample)) {
+			limit = sample + (mt->min_samples - mt->current_sample);
+		} else {
+			limit = samples;
+		}
+		if (limit < 0 || limit > samples) {
+			limit = samples;
+		}
+
+		for (j = sample;  j < limit;  j++) {
+			famp = sample_buffer[j];
+			
+			mt->energy += famp*famp;
+
+			for(x = 0; x < TELETONE_MAX_TONES && x < mt->tone_count; x++) {
+				v1 = mt->gs[x].v2;
+				mt->gs[x].v2 = mt->gs[x].v3;
+				mt->gs[x].v3 = (float)(mt->gs[x].fac * mt->gs[x].v2 - v1 + famp);
+	
+				v1 = mt->gs2[x].v2;
+				mt->gs2[x].v2 = mt->gs2[x].v3;
+				mt->gs2[x].v3 = (float)(mt->gs2[x].fac*mt->gs2[x].v2 - v1 + famp);
+			}
+		}
+
+		mt->current_sample += (limit - sample);
+		if (mt->current_sample < mt->min_samples) {
+			continue;
+		}
+
+		eng_sum = 0;
+		for(x = 0; x < TELETONE_MAX_TONES && x < mt->tone_count; x++) {
+			eng_all[x] = (float)(teletone_goertzel_result (&mt->gs[x]));
+			eng_sum += eng_all[x];
+		}
+
+		gtest = 0;
+		for(x = 0; x < TELETONE_MAX_TONES && x < mt->tone_count; x++) {
+			gtest += teletone_goertzel_result (&mt->gs2[x]) < eng_all[x] ? 1 : 0;
+		}
+
+		if ((gtest >= 2 || gtest == mt->tone_count) && eng_sum > 42.0 * mt->energy) {
+			if(mt->negatives) {
+				mt->negatives--;
+			}
+			mt->positives++;
+
+			if(mt->positives >= mt->positive_factor) {
+				mt->hits++;
+			}
+			if (mt->hits >= mt->hit_factor) {
+				see_hit++;
+				mt->positives = mt->negatives = mt->hits = 0;
+			}
+		} else {
+			mt->negatives++;
+			if(mt->positives) {
+				mt->positives--;
+			}
+			if(mt->negatives > mt->negative_factor) {
+				mt->positives = mt->hits = 0;
+			}
+		}
+
+		/* Reinitialise the detector for the next block */
+		for(x = 0; x < TELETONE_MAX_TONES && x < mt->tone_count; x++) {
+			goertzel_init (&mt->gs[x], &mt->tdd[x]);
+			goertzel_init (&mt->gs2[x], &mt->tdd[x]);
+		}
+
+		mt->energy = 0.0;
+		mt->current_sample = 0;
+	}
+
+	return see_hit;
+}
+
+
+TELETONE_API(int) teletone_dtmf_detect (teletone_dtmf_detect_state_t *dtmf_detect_state,
+						  int16_t sample_buffer[],
+						  int samples)
+{
+	float row_energy[GRID_FACTOR];
+	float col_energy[GRID_FACTOR];
+	float famp;
+	float v1;
+	int i;
+	int j;
+	int sample;
+	int best_row;
+	int best_col;
+	char hit;
+	int limit;
+
+	hit = 0;
+	for (sample = 0;  sample < samples;	 sample = limit) {
+		/* BLOCK_LEN is optimised to meet the DTMF specs. */
+		if ((samples - sample) >= (BLOCK_LEN - dtmf_detect_state->current_sample)) {
+			limit = sample + (BLOCK_LEN - dtmf_detect_state->current_sample);
+		} else {
+			limit = samples;
+		}
+
+		for (j = sample;  j < limit;  j++) {
+			int x = 0;
+			famp = sample_buffer[j];
+			
+			dtmf_detect_state->energy += famp*famp;
+
+			for(x = 0; x < GRID_FACTOR; x++) {
+				v1 = dtmf_detect_state->row_out[x].v2;
+				dtmf_detect_state->row_out[x].v2 = dtmf_detect_state->row_out[x].v3;
+				dtmf_detect_state->row_out[x].v3 = (float)(dtmf_detect_state->row_out[x].fac*dtmf_detect_state->row_out[x].v2 - v1 + famp);
+	
+				v1 = dtmf_detect_state->col_out[x].v2;
+				dtmf_detect_state->col_out[x].v2 = dtmf_detect_state->col_out[x].v3;
+				dtmf_detect_state->col_out[x].v3 = (float)(dtmf_detect_state->col_out[x].fac*dtmf_detect_state->col_out[x].v2 - v1 + famp);
+
+				v1 = dtmf_detect_state->col_out2nd[x].v2;
+				dtmf_detect_state->col_out2nd[x].v2 = dtmf_detect_state->col_out2nd[x].v3;
+				dtmf_detect_state->col_out2nd[x].v3 = (float)(dtmf_detect_state->col_out2nd[x].fac*dtmf_detect_state->col_out2nd[x].v2 - v1 + famp);
+		
+				v1 = dtmf_detect_state->row_out2nd[x].v2;
+				dtmf_detect_state->row_out2nd[x].v2 = dtmf_detect_state->row_out2nd[x].v3;
+				dtmf_detect_state->row_out2nd[x].v3 = (float)(dtmf_detect_state->row_out2nd[x].fac*dtmf_detect_state->row_out2nd[x].v2 - v1 + famp);
+			}
+
+		}
+
+		dtmf_detect_state->current_sample += (limit - sample);
+		if (dtmf_detect_state->current_sample < BLOCK_LEN) {
+			continue;
+		}
+		/* We are at the end of a DTMF detection block */
+		/* Find the peak row and the peak column */
+		row_energy[0] = teletone_goertzel_result (&dtmf_detect_state->row_out[0]);
+		col_energy[0] = teletone_goertzel_result (&dtmf_detect_state->col_out[0]);
+
+		for (best_row = best_col = 0, i = 1;  i < GRID_FACTOR;	i++) {
+			row_energy[i] = teletone_goertzel_result (&dtmf_detect_state->row_out[i]);
+			if (row_energy[i] > row_energy[best_row]) {
+				best_row = i;
+			}
+			col_energy[i] = teletone_goertzel_result (&dtmf_detect_state->col_out[i]);
+			if (col_energy[i] > col_energy[best_col]) {
+				best_col = i;
+			}
+		}
+		hit = 0;
+		/* Basic signal level test and the twist test */
+		if (row_energy[best_row] >= DTMF_THRESHOLD &&
+			col_energy[best_col] >= DTMF_THRESHOLD &&
+			col_energy[best_col] < row_energy[best_row]*DTMF_REVERSE_TWIST &&
+			col_energy[best_col]*DTMF_NORMAL_TWIST > row_energy[best_row]) {
+			/* Relative peak test */
+			for (i = 0;	 i < GRID_FACTOR;  i++) {
+				if ((i != best_col	&&	col_energy[i]*DTMF_RELATIVE_PEAK_COL > col_energy[best_col]) ||
+					(i != best_row	&&	row_energy[i]*DTMF_RELATIVE_PEAK_ROW > row_energy[best_row])) {
+					break;
+				}
+			}
+			/* ... and second harmonic test */
+			if (i >= GRID_FACTOR && (row_energy[best_row] + col_energy[best_col]) > 42.0*dtmf_detect_state->energy &&
+				teletone_goertzel_result (&dtmf_detect_state->col_out2nd[best_col])*DTMF_2ND_HARMONIC_COL < col_energy[best_col] &&
+				teletone_goertzel_result (&dtmf_detect_state->row_out2nd[best_row])*DTMF_2ND_HARMONIC_ROW < row_energy[best_row]) {
+				hit = dtmf_positions[(best_row << 2) + best_col];
+				/* 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 == dtmf_detect_state->hit3	&&	dtmf_detect_state->hit3 != dtmf_detect_state->hit2) {
+					dtmf_detect_state->mhit = hit;
+					dtmf_detect_state->digit_hits[(best_row << 2) + best_col]++;
+					dtmf_detect_state->detected_digits++;
+					if (dtmf_detect_state->current_digits < TELETONE_MAX_DTMF_DIGITS) {
+						dtmf_detect_state->digits[dtmf_detect_state->current_digits++] = hit;
+						dtmf_detect_state->digits[dtmf_detect_state->current_digits] = '\0';
+					}
+					else
+						{
+							dtmf_detect_state->lost_digits++;
+						}
+				}
+			}
+		}
+		dtmf_detect_state->hit1 = dtmf_detect_state->hit2;
+		dtmf_detect_state->hit2 = dtmf_detect_state->hit3;
+		dtmf_detect_state->hit3 = hit;
+		/* Reinitialise the detector for the next block */
+		for (i = 0;	 i < GRID_FACTOR;  i++) {
+			goertzel_init (&dtmf_detect_state->row_out[i], &dtmf_detect_row[i]);
+			goertzel_init (&dtmf_detect_state->col_out[i], &dtmf_detect_col[i]);
+			goertzel_init (&dtmf_detect_state->row_out2nd[i], &dtmf_detect_row_2nd[i]);
+			goertzel_init (&dtmf_detect_state->col_out2nd[i], &dtmf_detect_col_2nd[i]);
+		}
+		dtmf_detect_state->energy = 0.0;
+		dtmf_detect_state->current_sample = 0;
+	}
+	if ((!dtmf_detect_state->mhit) || (dtmf_detect_state->mhit != hit)) {
+		dtmf_detect_state->mhit = 0;
+		return(0);
+	}
+	return (hit);
+}
+
+
+TELETONE_API(int) teletone_dtmf_get (teletone_dtmf_detect_state_t *dtmf_detect_state,
+					   char *buf,
+					   int max)
+{
+	teletone_assert(dtmf_detect_state->current_digits <= TELETONE_MAX_DTMF_DIGITS);
+
+	if (max > dtmf_detect_state->current_digits) {
+		max = dtmf_detect_state->current_digits;
+	}
+	if (max > 0) {
+		memcpy (buf, dtmf_detect_state->digits, max);
+		memmove (dtmf_detect_state->digits, dtmf_detect_state->digits + max, dtmf_detect_state->current_digits - max);
+		dtmf_detect_state->current_digits -= max;
+	}
+	buf[max] = '\0';
+	return	max;
+}
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */

Added: freeswitch/trunk/libs/openzap/src/libteletone_generate.c (0 => 17141)


--- freeswitch/trunk/libs/openzap/src/libteletone_generate.c	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/src/libteletone_generate.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,464 @@
+/* 
+ * libteletone_generate.c -- Tone Generator
+ *
+ * Copyright (c) 2007, Anthony Minessale II
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.	 IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <libteletone.h>
+
+#define SMAX 32767
+#define SMIN -32768
+#define normalize_to_16bit(n) if (n > SMAX) n = SMAX; else if (n < SMIN) n = SMIN;
+
+#ifdef _MSC_VER
+#pragma warning(disable:4706)
+#endif
+
+TELETONE_API_DATA int16_t TELETONE_SINES[SINE_TABLE_MAX] = {
+	0x00c9, 0x025b, 0x03ed, 0x057f, 0x0711, 0x08a2, 0x0a33, 0x0bc4,
+	0x0d54, 0x0ee4, 0x1073, 0x1201, 0x138f, 0x151c, 0x16a8, 0x1833,
+	0x19be, 0x1b47, 0x1cd0, 0x1e57, 0x1fdd, 0x2162, 0x22e5, 0x2467,
+	0x25e8, 0x2768, 0x28e5, 0x2a62, 0x2bdc, 0x2d55, 0x2ecc, 0x3042,
+	0x31b5, 0x3327, 0x3497, 0x3604, 0x3770, 0x38d9, 0x3a40, 0x3ba5,
+	0x3d08, 0x3e68, 0x3fc6, 0x4121, 0x427a, 0x43d1, 0x4524, 0x4675,
+	0x47c4, 0x490f, 0x4a58, 0x4b9e, 0x4ce1, 0x4e21, 0x4f5e, 0x5098,
+	0x51cf, 0x5303, 0x5433, 0x5560, 0x568a, 0x57b1, 0x58d4, 0x59f4,
+	0x5b10, 0x5c29, 0x5d3e, 0x5e50, 0x5f5e, 0x6068, 0x616f, 0x6272,
+	0x6371, 0x646c, 0x6564, 0x6657, 0x6747, 0x6832, 0x691a, 0x69fd,
+	0x6add, 0x6bb8, 0x6c8f, 0x6d62, 0x6e31, 0x6efb, 0x6fc2, 0x7083,
+	0x7141, 0x71fa, 0x72af, 0x735f, 0x740b, 0x74b3, 0x7556, 0x75f4,
+	0x768e, 0x7723, 0x77b4, 0x7840, 0x78c8, 0x794a, 0x79c9, 0x7a42,
+	0x7ab7, 0x7b27, 0x7b92, 0x7bf9, 0x7c5a, 0x7cb7, 0x7d0f, 0x7d63,
+	0x7db1, 0x7dfb, 0x7e3f, 0x7e7f, 0x7eba, 0x7ef0, 0x7f22, 0x7f4e,
+	0x7f75, 0x7f98, 0x7fb5, 0x7fce, 0x7fe2, 0x7ff1, 0x7ffa, 0x7fff
+};
+
+
+TELETONE_API(int) teletone_set_tone(teletone_generation_session_t *ts, int index, ...)
+{
+	va_list ap;
+	int i = 0;
+	teletone_process_t x = 0;
+
+	va_start(ap, index);
+	while (i < TELETONE_MAX_TONES && (x = va_arg(ap, teletone_process_t))) {
+		ts->TONES[index].freqs[i++] = x;
+	}
+	va_end(ap);
+
+	return (i > TELETONE_MAX_TONES) ? -1 : 0;
+	
+}
+
+TELETONE_API(int) teletone_set_map(teletone_tone_map_t *map, ...)
+{
+	va_list ap;
+	int i = 0;
+	teletone_process_t x = 0;
+
+	va_start(ap, map);
+	while (i < TELETONE_MAX_TONES && (x = va_arg(ap, teletone_process_t))) {
+		map->freqs[i++] = x;
+	}
+	va_end(ap);
+
+	return (i > TELETONE_MAX_TONES) ? -1 : 0;
+	
+}
+
+TELETONE_API(int) teletone_init_session(teletone_generation_session_t *ts, int buflen, tone_handler handler, void *user_data)
+{
+	memset(ts, 0, sizeof(*ts));
+	ts->rate = 8000;
+	ts->channels = 1;
+	ts->duration = 2000;
+	ts->wait = 500;
+	ts->tmp_duration = -1;
+	ts->tmp_wait = -1;
+	ts->handler = handler;
+	ts->user_data = user_data;
+	ts->volume = -7;
+	ts->decay_step = 0;
+	ts->decay_factor = 1;
+	if (buflen) {
+		if ((ts->buffer = calloc(buflen, sizeof(teletone_audio_t))) == 0) {
+			return -1;
+		}
+		ts->datalen = buflen;
+	} else {
+		ts->dynamic = 1024;
+	}
+	/* Add Standard DTMF Tones */
+	teletone_set_tone(ts, '1', 697.0, 1209.0, 0.0);
+	teletone_set_tone(ts, '2', 697.0, 1336.0, 0.0);
+	teletone_set_tone(ts, '3', 697.0, 1477.0, 0.0);
+	teletone_set_tone(ts, 'A', 697.0, 1633.0, 0.0);
+	teletone_set_tone(ts, '4', 770.0, 1209.0, 0.0);
+	teletone_set_tone(ts, '5', 770.0, 1336.0, 0.0);
+	teletone_set_tone(ts, '6', 770.0, 1477.0, 0.0);
+	teletone_set_tone(ts, 'B', 770.0, 1633.0, 0.0);
+	teletone_set_tone(ts, '7', 859.0, 1209.0, 0.0);
+	teletone_set_tone(ts, '8', 859.0, 1336.0, 0.0);
+	teletone_set_tone(ts, '9', 859.0, 1477.0, 0.0);
+	teletone_set_tone(ts, 'C', 859.0, 1633.0, 0.0);
+	teletone_set_tone(ts, '*', 941.0, 1209.0, 0.0);
+	teletone_set_tone(ts, '0', 941.0, 1336.0, 0.0);
+	teletone_set_tone(ts, '#', 941.0, 1477.0, 0.0);
+	teletone_set_tone(ts, 'D', 941.0, 1633.0, 0.0);
+	
+	return 0;
+}
+
+TELETONE_API(int) teletone_destroy_session(teletone_generation_session_t *ts)
+{
+	if (ts->buffer) {
+		free(ts->buffer);
+		ts->buffer = NULL;
+		ts->samples = 0;
+	}
+	return 0;
+}
+
+static int ensure_buffer(teletone_generation_session_t *ts, int need)
+{
+	need += ts->samples;
+	need *= sizeof(teletone_audio_t);
+	need *= ts->channels;
+
+	if (need > ts->datalen) {
+		teletone_audio_t *tmp;
+		ts->datalen = need + ts->dynamic;
+		tmp = realloc(ts->buffer, ts->datalen);
+		if (!tmp) {
+			return -1;
+		}
+		ts->buffer = tmp;
+	}
+
+	return 0;
+}
+
+TELETONE_API(int) teletone_mux_tones(teletone_generation_session_t *ts, teletone_tone_map_t *map)
+{
+	/*teletone_process_t period = (1.0 / ts->rate) / ts->channels;*/
+	int i, c;
+	int freqlen = 0;
+	teletone_dds_state_t tones[TELETONE_MAX_TONES+1];
+	//int decay = 0;
+	int duration;
+	int wait = 0;
+	int32_t sample;
+	int32_t dc = 0;
+	float vol = ts->volume;
+	ts->samples = 0;
+	memset(tones, 0, sizeof(tones[0]) * TELETONE_MAX_TONES);
+	duration = (ts->tmp_duration > -1) ? ts->tmp_duration : ts->duration;
+	wait = (ts->tmp_wait > -1) ? ts->tmp_wait : ts->wait;
+
+	if (map->freqs[0] > 0) {
+		for (freqlen = 0; freqlen < TELETONE_MAX_TONES && map->freqs[freqlen]; freqlen++) {
+			teletone_dds_state_set_tone(&tones[freqlen], map->freqs[freqlen], ts->rate, 0);
+			teletone_dds_state_set_tx_level(&tones[freqlen], vol);
+		}
+	
+		if (ts->channels > 1) {
+			duration *= ts->channels;
+		}
+
+		if (ts->dynamic) {
+			if (ensure_buffer(ts, duration)) {
+				return -1;
+			}
+		}
+
+		for (ts->samples = 0; ts->samples < ts->datalen && ts->samples < duration; ts->samples++) {
+			if (ts->decay_direction && ++dc >= ts->decay_step) {
+				float nvol = vol + ts->decay_direction * ts->decay_factor;
+				int j;
+
+				if (nvol <= TELETONE_VOL_DB_MAX && nvol >= TELETONE_VOL_DB_MIN) {
+					vol = nvol;
+					for (j = 0; j < TELETONE_MAX_TONES && map->freqs[j]; j++) {					
+						teletone_dds_state_set_tx_level(&tones[j], vol);
+					}
+					dc = 0;
+				}
+			}
+
+			sample = 128;
+
+			for (i = 0; i < freqlen; i++) {
+				int32_t s = teletone_dds_state_modulate_sample(&tones[i], 0);
+				sample += s;
+			}
+			sample /= freqlen;
+			ts->buffer[ts->samples] = (teletone_audio_t)sample;
+			
+			for (c = 1; c < ts->channels; c++) {
+				ts->buffer[ts->samples+1] = ts->buffer[ts->samples];
+				ts->samples++;
+			}
+			
+		}
+	}
+	if (ts->dynamic) {
+		if (ensure_buffer(ts, wait)) {
+			return -1;
+		}
+	}
+	for (c = 0; c < ts->channels; c++) {
+		for (i = 0; i < wait && ts->samples < ts->datalen; i++) {
+			ts->buffer[ts->samples++] = 0;
+		}
+	}
+
+	if (ts->debug && ts->debug_stream) {
+		if (map->freqs[0] <= 0) {
+			fprintf(ts->debug_stream, "wait %d (%dms)\n", wait, wait / (ts->rate / 1000));
+		} else {
+			fprintf(ts->debug_stream, "Generate: (");
+
+			for (i = 0; i < TELETONE_MAX_TONES && map->freqs[i]; i++) {
+				fprintf(ts->debug_stream, "%s%0.2f", i == 0 ? "" : "+",map->freqs[i]);
+			}
+			 
+			fprintf(ts->debug_stream, 
+					") [volume %0.2fdB; samples %d(%dms) x %d channel%s; wait %d(%dms); decay_factor %0.2fdB; decay_step %d(%dms); wrote %d bytes]\n",
+					ts->volume,
+					duration,
+					duration / (ts->rate / 1000), 
+					ts->channels,
+					ts->channels == 1 ? "" : "s",
+					wait,
+					wait / (ts->rate / 1000),
+					ts->decay_factor,
+					ts->decay_step,
+					ts->decay_step / (ts->rate / 1000),					
+					ts->samples * 2);
+		}
+	}	
+	return ts->samples;
+}
+
+/* don't ask */
+static char *my_strdup (const char *s)
+{
+	size_t len = strlen (s) + 1;
+	void *new = malloc (len);
+	
+	if (new == NULL) {
+		return NULL;
+	}
+
+	return (char *) memcpy (new, s, len);
+}
+
+TELETONE_API(int) teletone_run(teletone_generation_session_t *ts, const char *cmd)
+{
+	char *data = NULL, *cur = NULL, *end = NULL;
+	int var = 0, LOOPING = 0;
+	
+	if (!cmd) {
+		return -1;
+	}
+
+	do {
+		if (!(data = my_strdup(cmd))) {
+			return -1;
+		}
+
+		cur = data;
+
+		while (*cur) {
+			var = 0;
+			if (*cur == ' ' || *cur == '\r' || *cur == '\n') {
+				cur++;
+				continue;
+			}
+
+			if ((end = strchr(cur, ';')) != 0) {
+				*end++ = '\0';
+			}
+			
+			if (*(cur + 1) == '=') {
+				var = 1;
+				switch(*cur) {
+				case 'c':
+					ts->channels = atoi(cur + 2);
+					break;
+				case 'r':
+					ts->rate = atoi(cur + 2);
+					break;
+				case 'd':
+					ts->duration = atoi(cur + 2) * (ts->rate / 1000);
+					break;
+				case 'v':
+					{
+						float vol = (float)atof(cur + 2);
+						if (vol <= TELETONE_VOL_DB_MAX && vol >= TELETONE_VOL_DB_MIN) {
+							ts->volume = vol;
+						}
+					}
+					break;
+				case '>':
+					ts->decay_step = atoi(cur + 2) * (ts->rate / 1000);
+					ts->decay_direction = -1;
+					break;
+				case '<':
+					ts->decay_step = atoi(cur + 2) * (ts->rate / 1000);
+					ts->decay_direction = 1;
+					break;
+				case '+':
+					ts->decay_factor = (float)atof(cur + 2);
+					break;
+				case 'w':
+					ts->wait = atoi(cur + 2) * (ts->rate / 1000);
+					break;
+				case 'l':
+					ts->loops = atoi(cur + 2); 
+					break;
+				case 'L':
+					if (!LOOPING) {
+						ts->LOOPS = atoi(cur + 2); 
+					}
+					LOOPING++;
+					break;
+				}
+			} else {
+				while (*cur) {
+					char *p = NULL, *e = NULL;
+					teletone_tone_map_t mymap, *mapp = NULL;
+
+					if (*cur == ' ' || *cur == '\r' || *cur == '\n') {
+						cur++;
+						continue;
+					}
+					
+					ts->tmp_duration = -1;
+					ts->tmp_wait = -1;
+
+					memset(&mymap, 0, sizeof(mymap));
+
+					if (*(cur + 1) == '(') {
+						p = cur + 2;
+						if (*cur) {
+							char *next;
+							int i = 0;
+							if ((e = strchr(p, ')')) != 0) {
+								*e++ = '\0';
+							}
+							do {
+								if ((next = strchr(p, ',')) != 0) {
+									*next++ = '\0';
+								}
+								if (i == 0) {
+									ts->tmp_duration = atoi(p) * (ts->rate / 1000);
+									i++;
+								} else if (i == 1) {
+									ts->tmp_wait = atoi(p) * (ts->rate / 1000);
+									i++;
+								} else {
+									mymap.freqs[i++ - 2] = atof(p);
+								}
+								p = next;
+
+							} while (next && (i-2) < TELETONE_MAX_TONES);
+							if (i > 2 && *cur == '%') {
+								mapp = &mymap;
+							} else if ((i != 2 || *cur == '%')) { 
+								if (ts->debug && ts->debug_stream) {
+									fprintf(ts->debug_stream, "Syntax Error!\n");
+								}
+								goto bottom;
+							}
+						} 
+					}
+
+					if (*cur && !mapp) {
+						if (*cur > 0 && *cur < TELETONE_TONE_RANGE) { 
+							mapp = &ts->TONES[(int)*cur];
+						} else if (ts->debug && ts->debug_stream) {
+							fprintf(ts->debug_stream, "Map [%c] Out Of Range!\n", *cur);
+						}
+					}
+
+					if (mapp) {
+						if (mapp->freqs[0]) {
+							if (ts->handler) {
+								do {
+									ts->handler(ts, mapp);
+									if (ts->loops > 0) {
+										ts->loops--;
+									}
+								} while (ts->loops);
+							}
+						} else if (ts->debug && ts->debug_stream) {
+							fprintf(ts->debug_stream, "Ignoring Empty Map [%c]!\n", *cur);
+						}
+					}
+					
+					if (e) {
+						cur = e;
+					} else {
+						cur++;
+					}
+				}
+			}
+
+			if (end) {
+				cur = end;
+			} else if (*cur){
+				cur++;
+			}
+		}
+	bottom:
+		free(data);
+		data = NULL;
+		if (ts->LOOPS > 0) {
+			ts->LOOPS--;
+		}
+
+	} while (ts->LOOPS);
+
+	return 0;
+}
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */

Added: freeswitch/trunk/libs/openzap/src/m3ua/mstm3ua.c (0 => 17141)


--- freeswitch/trunk/libs/openzap/src/m3ua/mstm3ua.c	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/src/m3ua/mstm3ua.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,62 @@
+/* WARNING WORK IN PROGRESS
+ *  mstm3ua.c
+ *  mstss7d port
+ *
+ *  Created by Shane Burrell on 2/2/08.
+ *  Copyright 2008 Shane Burrell. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "mstm3ua.h"
+
+
+
+
+
+int build_m3ua_hdr(unsigned char len,unsigned char *bytemsg)
+
+{
+   
+	*bytemsg++ = M_VERSION_REL1;  // 1 Verison
+	//bytemsg[1] = 0x00;  // 2 RESERVED
+	//bytemsg[2] = M_CLASS_XFER;  // 3 Msg Class
+    //SS7 BOX Kludge
+	*bytemsg++ = 0x01;  // 2 RESERVED
+	*bytemsg++ = 0x00;  // 2 RESERVED				
+	
+	*bytemsg++ = M_TYPE_DATA	;  // 4 Msg Type
+
+	*bytemsg++ = len;  // 5 Msg LENGTH  81  32bit field
+	*bytemsg++ = 0x00;  // 6
+	*bytemsg++ = 0x00;  // 7
+	*bytemsg++ = 0x00;  // 8
+	return(0);
+
+};
\ No newline at end of file

Added: freeswitch/trunk/libs/openzap/src/m3ua/mstm3ua.h (0 => 17141)


--- freeswitch/trunk/libs/openzap/src/m3ua/mstm3ua.h	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/src/m3ua/mstm3ua.h	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,96 @@
+/*
+ *  mstm3ua.h
+ *  mstss7d
+ *
+ *  Created by Shane Burrell on 3/2/08.
+ *  Copyright 2008 Shane Burrell. All rights reserved.
+ *
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+typedef unsigned long m3ua_ulong;
+typedef unsigned short m3ua_ushort;
+typedef unsigned char m3ua_uchar;
+
+typedef unsigned char u8;
+typedef unsigned short u16;	/* Note: multi-byte values are little-endian */
+typedef unsigned long u32;
+
+
+
+
+#define M_TAG_NETWORK_APPEARANCE	1
+#define	M_TAG_PROTOCOL_DATA		3
+#define M_TAG_INFO_STRING		4
+#define M_TAG_AFFECTED_DPC		5
+#define M_TAG_ROUTING_CONTEXT		6
+#define M_TAG_DIAGNOSTIC_INFORMATION	7
+#define M_TAG_HEARTBEAT_DATA		8
+#define M_TAG_UNAVAILABILITY_CAUSE	9
+#define M_TAG_REASON			10
+#define	M_TAG_TRAFFIC_MODE_TYPE		11
+#define M_TAG_ERROR_CODE		12
+#define	M_TAG_STATUS_TYPE		13
+#define M_TAG_CONGESTED_INDICATIONS	14
+
+#define M_VERSION_REL1   1
+
+#define M_CLASS_MGMT	0x00
+#define M_CLASS_XFER	0x01
+#define	M_CLASS_SSNM	0x02
+#define M_CLASS_ASPSM	0x03
+#define M_CLASS_ASPTM	0x04
+#define M_CLASS_RKM		0x09
+
+#define M_TYPE_ERR		(0|M_CLASS_MGMT
+
+#define M_TYPE_NTFY		(1|M_CLASS_XFER)
+#define M_TYPE_DATA		(1|M_CLASS_XFER)
+
+#define M_TYPE_DUNA		(1|M_CLASS_SSNM)
+#define M_TYPE_DAVA		(2|M_CLASS_SSNM)
+#define M_TYPE_DUAD		(3|M_CLASS_SSNM)
+#define M_TYPE_SCON		(4|M_CLASS_SSNM)
+#define M_TYPE_DUPU		(5|M_CLASS_SSNM)
+
+#define	M_TYPE_UP		(1|M_CLASS_ASPSM)
+#define	M_TYPE_DOWN		(2|M_CLASS_ASPSM)
+#define	M_TYPE_BEAT		(3|M_CLASS_ASPSM)
+#define	M_TYPE_UP_ACK		(4|M_CLASS_ASPSM)
+#define	M_TYPE_DOWN_ACK		(5|M_CLASS_ASPSM)
+#define	M_TYPE_BEAT_ACK		(6|M_CLASS_ASPSM)
+
+#define M_TYPE_ACTIVE		(1|M_CLASS_ASPTM)
+#define M_TYPE_INACTIVE		(2|M_CLASS_ASPTM)
+#define M_TYPE_ACTIVE_ACK	(3|M_CLASS_ASPTM)
+#define M_TYPE_INACTIVE_ACK	(4|M_CLASS_ASPTM)
+
+#define M_CLASS_MASK	0xff00
+#define	M_TYPE_MASK	0x00ff
+

Added: freeswitch/trunk/libs/openzap/src/m3ua_client.c (0 => 17141)


--- freeswitch/trunk/libs/openzap/src/m3ua_client.c	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/src/m3ua_client.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,333 @@
+/*
+ *  m3ua_client.c
+ *  openzap
+ *
+ *  Created by Shane Burrell on 4/3/08.
+ *  Copyright 2008 Shane Burrell. All rights reserved.
+ *
+ * 
+  * Copyright (c) 2007, Anthony Minessale II, Nenad Corbic
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if HAVE_NETDB_H
+#include <netdb.h>
+#endif
+
+#include "openzap.h"
+#include <m3ua_client.h>
+
+
+#ifndef HAVE_GETHOSTBYNAME_R
+extern int gethostbyname_r (const char *__name,
+							struct hostent *__result_buf,
+							char *__buf, size_t __buflen,
+							struct hostent **__result,
+							int *__h_errnop);
+#endif
+
+struct m3uac_map {
+	uint32_t event_id;
+	const char *name;
+};
+
+static struct m3uac_map m3uac_table[] = {
+	{M3UA_EVENT_CALL_START, "CALL_START"},
+	{M3UA_EVENT_CALL_START_ACK, "CALL_START_ACK"},
+	{M3UA_EVENT_CALL_START_NACK, "CALL_START_NACK"},
+	{M3UA_EVENT_CALL_START_NACK_ACK, "CALL_START_NACK_ACK"},
+	{M3UA_EVENT_CALL_ANSWERED, "CALL_ANSWERED"},
+	{M3UA_EVENT_CALL_STOPPED, "CALL_STOPPED"},
+	{M3UA_EVENT_CALL_STOPPED_ACK, "CALL_STOPPED_ACK"},
+	{M3UA_EVENT_SYSTEM_RESTART, "SYSTEM_RESTART"},
+	{M3UA_EVENT_SYSTEM_RESTART_ACK, "SYSTEM_RESTART_ACK"},
+	{M3UA_EVENT_HEARTBEAT, "HEARTBEAT"},
+	{M3UA_EVENT_INSERT_CHECK_LOOP, "LOOP START"},
+	{M3UA_EVENT_REMOVE_CHECK_LOOP, "LOOP STOP"} 
+}; 
+
+
+
+static int create_conn_socket(m3uac_connection_t *mcon, char *local_ip, int local_port, char *ip, int port)
+{
+	int rc;
+	struct hostent *result, *local_result;
+	char buf[512], local_buf[512];
+	int err = 0;
+
+	memset(&mcon->remote_hp, 0, sizeof(mcon->remote_hp));
+	memset(&mcon->local_hp, 0, sizeof(mcon->local_hp));
+	mcon->socket = socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP);
+ 
+	zap_log(ZAP_LOG_DEBUG, "Creating L=%s:%d R=%s:%d\n",
+			local_ip,local_port,ip,port);
+
+	if (mcon->socket >= 0) {
+		int flag;
+
+		flag = 1;
+		gethostbyname_r(ip, &mcon->remote_hp, buf, sizeof(buf), &result, &err);
+		gethostbyname_r(local_ip, &mcon->local_hp, local_buf, sizeof(local_buf), &local_result, &err);
+		if (result && local_result) {
+			mcon->remote_addr.sin_family = mcon->remote_hp.h_addrtype;
+			memcpy((char *) &mcon->remote_addr.sin_addr.s_addr, mcon->remote_hp.h_addr_list[0], mcon->remote_hp.h_length);
+			mcon->remote_addr.sin_port = htons(port);
+
+			mcon->local_addr.sin_family = mcon->local_hp.h_addrtype;
+			memcpy((char *) &mcon->local_addr.sin_addr.s_addr, mcon->local_hp.h_addr_list[0], mcon->local_hp.h_length);
+			mcon->local_addr.sin_port = htons(local_port);
+
+
+			setsockopt(mcon->socket, IPPROTO_SCTP, SCTP_NODELAY, (char *)&flag, sizeof(int));
+
+			rc=listen(mcon->socket,100);
+			if (rc) {
+			close(mcon->socket);
+			mcon->socket = -1;
+			
+			}
+		}
+	}
+
+	zap_mutex_create(&mcon->mutex);
+
+	return mcon->socket;
+}
+
+int m3uac_connection_close(m3uac_connection_t *mcon)
+{
+	if (mcon->socket > -1) {
+		close(mcon->socket);
+	}
+
+	zap_mutex_lock(mcon->mutex);
+	zap_mutex_unlock(mcon->mutex);
+	zap_mutex_destroy(&mcon->mutex);
+	memset(mcon, 0, sizeof(*mcon));
+	mcon->socket = -1;
+
+	return 0;
+}
+
+int m3uac_connection_open(m3uac_connection_t *mcon, char *local_ip, int local_port, char *ip, int port)
+{
+	create_conn_socket(mcon, local_ip, local_port, ip, port);
+	return mcon->socket;
+}
+
+
+int m3uac_exec_command(m3uac_connection_t *mcon, int span, int chan, int id, int cmd, int cause)
+{
+    m3uac_event_t oevent;
+    int retry = 5;
+
+    m3uac_event_init(&oevent, cmd, chan, span);
+    oevent.release_cause = cause;
+
+	if (cmd == SIGBOOST_EVENT_SYSTEM_RESTART) {
+		mcon->rxseq_reset = 1;
+		mcon->txseq = 0;
+		mcon->rxseq = 0;
+		mcon->txwindow = 0;
+	}
+
+    if (id >= 0) {
+        oevent.call_setup_id = id;
+    }
+
+    while (m3uac_connection_write(mcon, &oevent) <= 0) {
+        if (--retry <= 0) {
+            zap_log(ZAP_LOG_CRIT, "Failed to tx on M3UA socket: %s\n", strerror(errno));
+            return -1;
+        } else {
+            zap_log(ZAP_LOG_WARNING, "Failed to tx on M3UA socket: %s :retry %i\n", strerror(errno), retry);
+			zap_sleep(1);
+        }
+    }
+
+    return 0;
+}
+
+
+
+m3uac_event_t *m3uac_connection_read(m3uac_connection_t *mcon, int iteration)
+{
+	unsigned int fromlen = sizeof(struct sockaddr_in);
+	int bytes = 0;
+
+	bytes = recvfrom(mcon->socket, &mcon->event, sizeof(mcon->event), MSG_DONTWAIT, 
+					 (struct sockaddr *) &mcon->local_addr, &fromlen);
+
+	if (bytes == sizeof(mcon->event) || bytes == (sizeof(mcon->event)-sizeof(uint32_t))) {
+
+		if (mcon->rxseq_reset) {
+			if (mcon->event.event_id == SIGBOOST_EVENT_SYSTEM_RESTART_ACK) {
+				zap_log(ZAP_LOG_DEBUG, "Rx sync ok\n");
+				mcon->rxseq = mcon->event.fseqno;
+				return &mcon->event;
+			}
+			errno=EAGAIN;
+			zap_log(ZAP_LOG_DEBUG, "Waiting for rx sync...\n");
+			return NULL;
+		}
+		
+		mcon->txwindow = mcon->txseq - mcon->event.bseqno;
+		mcon->rxseq++;
+
+		if (mcon->rxseq != mcon->event.fseqno) {
+			zap_log(ZAP_LOG_CRIT, "Invalid Sequence Number Expect=%i Rx=%i\n", mcon->rxseq, mcon->event.fseqno);
+			return NULL;
+		}
+
+		return &mcon->event;
+	} else {
+		if (iteration == 0) {
+			zap_log(ZAP_LOG_CRIT, "Invalid Event length from boost rxlen=%i evsz=%i\n", bytes, sizeof(mcon->event));
+			return NULL;
+		}
+	}
+
+	return NULL;
+}
+
+m3uac_event_t *m3uac_connection_readp(m3uac_connection_t *mcon, int iteration)
+{
+	unsigned int fromlen = sizeof(struct sockaddr_in);
+	int bytes = 0;
+
+	bytes = recvfrom(mcon->socket, &mcon->event, sizeof(mcon->event), MSG_DONTWAIT, (struct sockaddr *) &mcon->local_addr, &fromlen);
+
+	if (bytes == sizeof(mcon->event) || bytes == (sizeof(mcon->event)-sizeof(uint32_t))) {
+		return &mcon->event;
+	} else {
+		if (iteration == 0) {
+			zap_log(ZAP_LOG_CRIT, "Critical Error: PQ Invalid Event lenght from boost rxlen=%i evsz=%i\n", bytes, sizeof(mcon->event));
+			return NULL;
+		}
+	}
+
+	return NULL;
+}
+
+
+int m3uac_connection_write(m3uac_connection_t *mcon, ss7bc_event_t *event)
+{
+	int err;
+
+	if (!event || mcon->socket < 0 || !mcon->mutex) {
+		zap_log(ZAP_LOG_DEBUG,  "Critical Error: No Event Device\n");
+		return -EINVAL;
+	}
+
+	if (event->span > 16 || event->chan > 31) {
+		zap_log(ZAP_LOG_CRIT, "Critical Error: TX Cmd=%s Invalid Span=%i Chan=%i\n", m3uac_event_id_name(event->event_id), event->span,event->chan);
+		return -1;
+	}
+
+	gettimeofday(&event->tv,NULL);
+	
+	zap_mutex_lock(mcon->mutex);
+	event->fseqno = mcon->txseq++;
+	event->bseqno = mcon->rxseq;
+	err = sendto(mcon->socket, event, sizeof(m3uac_event_t), 0, (struct sockaddr *) &mcon->remote_addr, sizeof(mcon->remote_addr));
+	zap_mutex_unlock(mcon->mutex);
+
+	if (err != sizeof(m3uac_event_t)) {
+		err = -1;
+	}
+	
+ 	zap_log(ZAP_LOG_DEBUG, "TX EVENT: %s:(%X) [w%dg%d] Rc=%i CSid=%i Seq=%i Cd=[%s] Ci=[%s]\n",
+			m3uac_event_id_name(event->event_id),
+			event->event_id,
+			event->span+1,
+			event->chan+1,
+			event->release_cause,
+			event->call_setup_id,
+			event->fseqno,
+			(event->called_number_digits_count ? (char *) event->called_number_digits : "N/A"),
+			(event->calling_number_digits_count ? (char *) event->calling_number_digits : "N/A")
+			);
+
+	return err;
+}
+
+void m3uac_call_init(m3uac_event_t *event, const char *calling, const char *called, int setup_id)
+{
+	memset(event, 0, sizeof(m3uac_event_t));
+	event->event_id = M3UA_EVENT_CALL_START;
+
+	if (calling) {
+		strncpy((char*)event->calling_number_digits, calling, sizeof(event->calling_number_digits)-1);
+		event->calling_number_digits_count = strlen(calling);
+	}
+
+	if (called) {
+		strncpy((char*)event->called_number_digits, called, sizeof(event->called_number_digits)-1);
+		event->called_number_digits_count = strlen(called);
+	}
+		
+	event->call_setup_id = setup_id;
+	
+}
+
+void m3uac_event_init(m3uac_event_t *event, m3uac_event_id_t event_id, int chan, int span) 
+{
+	memset(event, 0, sizeof(ss7bc_event_t));
+	event->event_id = event_id;
+	event->chan = chan;
+	event->span = span;
+}
+
+const char *m3uac_event_id_name(uint32_t event_id)
+{
+	unsigned int x;
+	const char *ret = NULL;
+
+	for (x = 0 ; x < sizeof(m3uac_table)/sizeof(struct m3uac_map); x++) {
+		if (m3uac_table[x].event_id == event_id) {
+			ret = m3uac_table[x].name;
+			break;
+		}
+	}
+
+	return ret;
+}
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
+
+

Added: freeswitch/trunk/libs/openzap/src/m3ua_client.h (0 => 17141)


--- freeswitch/trunk/libs/openzap/src/m3ua_client.h	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/src/m3ua_client.h	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,164 @@
+/*
+ *  m3ua_client.h
+ *  openzap
+ *
+ *  Created by Shane Burrell on 4/3/08.
+ *  Copyright 2008 Shane Burrell. All rights reserved.
+ *
+ * Copyright (c) 2007, Anthony Minessale II, Nenad Corbic
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <ctype.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+// Fix this for portability
+#include <sctp.h>
+//#include <netinet/sctp.h>
+#include <arpa/inet.h>
+#include <stdarg.h>
+#include <netdb.h>
+//#include <sigboost.h>
+#include <sys/time.h>
+
+#define MAX_DIALED_DIGITS	31
+#define MAX_CALLING_NAME	31
+
+/* Next two defines are used to create the range of values for call_setup_id
+ * in the t_sigboost structure.
+ * 0..((CORE_MAX_SPANS * CORE_MAX_CHAN_PER_SPAN) - 1) */
+#define CORE_MAX_SPANS 		200
+#define CORE_MAX_CHAN_PER_SPAN 	30
+#define MAX_PENDING_CALLS 	CORE_MAX_SPANS * CORE_MAX_CHAN_PER_SPAN
+/* 0..(MAX_PENDING_CALLS-1) is range of call_setup_id below */
+#define SIZE_RDNIS		80
+
+//#undef MSGWINDOW
+#define MSGWINDOW
+
+
+typedef struct
+{
+	uint32_t	event_id;
+	uint32_t	fseqno;
+#ifdef MSGWINDOW
+	uint32_t	bseqno;
+#endif
+	uint16_t	call_setup_id;
+	uint32_t	trunk_group;
+	uint32_t	span;
+	uint32_t	chan;
+	uint8_t		called_number_digits_count;
+	char		called_number_digits [MAX_DIALED_DIGITS + 1]; /* it's a null terminated string */
+	uint8_t		calling_number_digits_count; /* it's an array */
+	char		calling_number_digits [MAX_DIALED_DIGITS + 1]; /* it's a null terminated string */
+	uint8_t		release_cause;
+	struct timeval  tv;
+	/* ref. Q.931 Table 4-11 and Q.951 Section 3 */
+	uint8_t		calling_number_screening_ind;
+	uint8_t		calling_number_presentation;
+	char		redirection_string [SIZE_RDNIS]; /* it's a null terminated string */
+	
+} t_m3ua;
+
+typedef t_m3ua m3uac_event_t;
+typedef uint32_t m3uac_event_id_t;
+
+
+typedef struct m3uac_ip_cfg
+{
+	char local_ip[25];
+	int local_port;
+	char remote_ip[25];
+	int remote_port;
+}m3uac_ip_cfg_t;
+
+struct m3uac_connection {
+	zap_socket_t socket;
+	struct sockaddr_in local_addr;
+	struct sockaddr_in remote_addr;
+	m3uac_event_t event;
+	struct hostent remote_hp;
+	struct hostent local_hp;
+	unsigned int flags;
+	zap_mutex_t *mutex;
+	FILE *log;
+	unsigned int txseq;
+	unsigned int rxseq;
+	unsigned int txwindow;
+	unsigned int rxseq_reset;
+	m3uac_ip_cfg_t cfg;
+	uint32_t hb_elapsed;
+	int up;
+};
+
+typedef enum {
+	MSU_FLAG_EVENT = (1 << 0)
+} m3uac_flag_t;
+
+typedef struct m3uac_connection m3uac_connection_t;
+
+static inline void sctp_no_nagle(int socket)
+{
+    //int flag = 1;
+    //setsockopt(socket, IPPROTO_SCTP, SCTP_NODELAY, (char *) &flag, sizeof(int));
+}
+
+int m3uac_connection_close(m3uac_connection_t *mcon);
+int m3uac_connection_open(m3uac_connection_t *mcon, char *local_ip, int local_port, char *ip, int port);
+m3uac_event_t *m3uac_connection_read(m3uac_connection_t *mcon, int iteration);
+m3uac_event_t *m3uac_connection_readp(m3uac_connection_t *mcon, int iteration);
+int m3uac_connection_write(m3uac_connection_t *mcon, m3uac_event_t *event);
+void m3uac_event_init(m3uac_event_t *event, m3uac_event_id_t event_id, int chan, int span);
+void m3uac_call_init(m3uac_event_t *event, const char *calling, const char *called, int setup_id);
+const char *m3uac_event_id_name(uint32_t event_id);
+int m3uac_exec_command(m3uac_connection_t *mcon, int span, int chan, int id, int cmd, int cause);
+
+
+
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */

Added: freeswitch/trunk/libs/openzap/src/ozmod/ozmod_analog/ozmod_analog.2005.vcproj (0 => 17141)


--- freeswitch/trunk/libs/openzap/src/ozmod/ozmod_analog/ozmod_analog.2005.vcproj	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/src/ozmod/ozmod_analog/ozmod_analog.2005.vcproj	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,202 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="8.00"
+	Name="ozmod_analog"
+	ProjectGUID="{37C94798-6E33-4B4F-8EE0-C72A7DC91157}"
+	RootNamespace="ozmod_analog"
+	Keyword="Win32Proj"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="2"
+			CharacterSet="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				AdditionalIncludeDirectories="..\..\include;..\..\isdn\include"
+				PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;OZMOD_ANALOG_EXPORTS"
+				MinimalRebuild="true"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="3"
+				UsePrecompiledHeader="0"
+				WarningLevel="4"
+				WarnAsError="true"
+				DebugInformationFormat="4"
+				DisableSpecificWarnings="4100"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				LinkIncremental="2"
+				GenerateDebugInformation="true"
+				SubSystem="2"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="2"
+			CharacterSet="1"
+			WholeProgramOptimization="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="2"
+				EnableIntrinsicFunctions="true"
+				AdditionalIncludeDirectories="..\..\include;..\..\isdn\include"
+				PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;OZMOD_ANALOG_EXPORTS"
+				RuntimeLibrary="2"
+				EnableFunctionLevelLinking="true"
+				UsePrecompiledHeader="0"
+				WarningLevel="4"
+				WarnAsError="true"
+				DebugInformationFormat="3"
+				DisableSpecificWarnings="4100"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				LinkIncremental="1"
+				GenerateDebugInformation="true"
+				SubSystem="2"
+				OptimizeReferences="2"
+				EnableCOMDATFolding="2"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<Filter
+			Name="Source Files"
+			Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+			>
+			<File
+				RelativePath="ozmod_analog.c"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="Header Files"
+			Filter="h;hpp;hxx;hm;inl;inc;xsd"
+			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+			>
+			<File
+				RelativePath="zap_analog.h"
+				>
+			</File>
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>

Added: freeswitch/trunk/libs/openzap/src/ozmod/ozmod_analog/ozmod_analog.2008.vcproj (0 => 17141)


--- freeswitch/trunk/libs/openzap/src/ozmod/ozmod_analog/ozmod_analog.2008.vcproj	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/src/ozmod/ozmod_analog/ozmod_analog.2008.vcproj	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,353 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="9.00"
+	Name="ozmod_analog"
+	ProjectGUID="{37C94798-6E33-4B4F-8EE0-C72A7DC91157}"
+	RootNamespace="ozmod_analog"
+	Keyword="Win32Proj"
+	TargetFrameworkVersion="196613"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+		<Platform
+			Name="x64"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="2"
+			CharacterSet="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				AdditionalIncludeDirectories="..\..\include;..\..\isdn\include"
+				PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;OZMOD_ANALOG_EXPORTS"
+				MinimalRebuild="true"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="3"
+				UsePrecompiledHeader="0"
+				WarningLevel="4"
+				WarnAsError="true"
+				DebugInformationFormat="4"
+				DisableSpecificWarnings="4100"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				LinkIncremental="2"
+				GenerateDebugInformation="true"
+				SubSystem="2"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="2"
+			CharacterSet="1"
+			WholeProgramOptimization="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="2"
+				EnableIntrinsicFunctions="true"
+				AdditionalIncludeDirectories="..\..\include;..\..\isdn\include"
+				PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;OZMOD_ANALOG_EXPORTS"
+				RuntimeLibrary="2"
+				EnableFunctionLevelLinking="true"
+				UsePrecompiledHeader="0"
+				WarningLevel="4"
+				WarnAsError="true"
+				DebugInformationFormat="3"
+				DisableSpecificWarnings="4100"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				LinkIncremental="1"
+				GenerateDebugInformation="true"
+				SubSystem="2"
+				OptimizeReferences="2"
+				EnableCOMDATFolding="2"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Debug|x64"
+			OutputDirectory="$(SolutionDir)$(PlatformName)\$(ConfigurationName)"
+			IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+			ConfigurationType="2"
+			CharacterSet="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+				TargetEnvironment="3"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				AdditionalIncludeDirectories="..\..\include;..\..\isdn\include"
+				PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;OZMOD_ANALOG_EXPORTS"
+				MinimalRebuild="true"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="3"
+				UsePrecompiledHeader="0"
+				WarningLevel="4"
+				WarnAsError="false"
+				DebugInformationFormat="3"
+				DisableSpecificWarnings="4100"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				LinkIncremental="2"
+				GenerateDebugInformation="true"
+				SubSystem="2"
+				TargetMachine="17"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|x64"
+			OutputDirectory="$(SolutionDir)$(PlatformName)\$(ConfigurationName)"
+			IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+			ConfigurationType="2"
+			CharacterSet="1"
+			WholeProgramOptimization="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+				TargetEnvironment="3"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="2"
+				EnableIntrinsicFunctions="true"
+				AdditionalIncludeDirectories="..\..\include;..\..\isdn\include"
+				PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;OZMOD_ANALOG_EXPORTS"
+				RuntimeLibrary="2"
+				EnableFunctionLevelLinking="true"
+				UsePrecompiledHeader="0"
+				WarningLevel="4"
+				WarnAsError="true"
+				DebugInformationFormat="3"
+				DisableSpecificWarnings="4100"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				LinkIncremental="1"
+				GenerateDebugInformation="true"
+				SubSystem="2"
+				OptimizeReferences="2"
+				EnableCOMDATFolding="2"
+				TargetMachine="17"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<Filter
+			Name="Source Files"
+			Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+			>
+			<File
+				RelativePath="ozmod_analog.c"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="Header Files"
+			Filter="h;hpp;hxx;hm;inl;inc;xsd"
+			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+			>
+			<File
+				RelativePath="zap_analog.h"
+				>
+			</File>
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>

Added: freeswitch/trunk/libs/openzap/src/ozmod/ozmod_analog/ozmod_analog.c (0 => 17141)


--- freeswitch/trunk/libs/openzap/src/ozmod/ozmod_analog/ozmod_analog.c	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/src/ozmod/ozmod_analog/ozmod_analog.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,1012 @@
+/*
+ * Copyright (c) 2007, Anthony Minessale II
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "openzap.h"
+#include "zap_analog.h"
+
+#ifndef localtime_r
+struct tm * localtime_r(const time_t *clock, struct tm *result);
+#endif
+
+static void *zap_analog_channel_run(zap_thread_t *me, void *obj);
+
+/**
+ * \brief Starts an FXO channel thread (outgoing call)
+ * \param zchan Channel to initiate call on
+ * \return Success or failure
+ *
+ * Initialises state, starts tone progress detection and runs the channel in a new a thread.
+ */
+static ZIO_CHANNEL_OUTGOING_CALL_FUNCTION(analog_fxo_outgoing_call)
+{
+	if (!zap_test_flag(zchan, ZAP_CHANNEL_OFFHOOK) && !zap_test_flag(zchan, ZAP_CHANNEL_INTHREAD)) {		
+		zap_channel_clear_needed_tones(zchan);
+		zap_channel_clear_detected_tones(zchan);
+
+		zap_channel_command(zchan, ZAP_COMMAND_OFFHOOK, NULL);
+		zap_channel_command(zchan, ZAP_COMMAND_ENABLE_PROGRESS_DETECT, NULL);
+		zchan->needed_tones[ZAP_TONEMAP_DIAL] = 1;
+		zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_DIALING);
+		zap_thread_create_detached(zap_analog_channel_run, zchan);
+		return ZAP_SUCCESS;
+	}
+
+	return ZAP_FAIL;
+}
+
+/**
+ * \brief Starts an FXS channel thread (outgoing call)
+ * \param zchan Channel to initiate call on
+ * \return Success or failure
+ *
+ * Indicates call waiting if channel is already in use, otherwise runs the channel in a new thread.
+ */
+static ZIO_CHANNEL_OUTGOING_CALL_FUNCTION(analog_fxs_outgoing_call)
+{
+
+	if (zap_test_flag(zchan, ZAP_CHANNEL_INTHREAD)) {
+		zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_CALLWAITING);
+	} else {
+		zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_GENRING);
+		zap_thread_create_detached(zap_analog_channel_run, zchan);
+	}
+
+	return ZAP_SUCCESS;
+}
+
+/**
+ * \brief Starts an analog span thread (monitor)
+ * \param span Span to monitor
+ * \return Success or failure
+ */
+static zap_status_t zap_analog_start(zap_span_t *span)
+{
+	zap_analog_data_t *analog_data = span->signal_data;
+	zap_set_flag(analog_data, ZAP_ANALOG_RUNNING);
+	return zap_thread_create_detached(zap_analog_run, span);
+}
+
+/**
+ * \brief Initialises an analog span from configuration variables
+ * \param span Span to configure
+ * \param sig_cb Callback function for event signals
+ * \param ap List of configuration variables
+ * \return Success or failure
+ */
+static ZIO_SIG_CONFIGURE_FUNCTION(zap_analog_configure_span)
+//zap_status_t zap_analog_configure_span(zap_span_t *span, char *tonemap, uint32_t digit_timeout, uint32_t max_dialstr, zio_signal_cb_t sig_cb)
+{
+	zap_analog_data_t *analog_data;
+	const char *tonemap = "us";
+	const char *hotline = "";
+	uint32_t digit_timeout = 10;
+	uint32_t max_dialstr = MAX_DTMF;
+	const char *var, *val;
+	int *intval;
+	uint32_t flags = ZAP_ANALOG_CALLERID;
+
+	assert(sig_cb != NULL);
+
+	if (span->signal_type) {
+		snprintf(span->last_error, sizeof(span->last_error), "Span is already configured for signalling.");
+		return ZAP_FAIL;
+	}
+	
+	analog_data = malloc(sizeof(*analog_data));
+	assert(analog_data != NULL);
+	memset(analog_data, 0, sizeof(*analog_data));
+
+	while ((var = va_arg(ap, char *))) {
+		if (!strcasecmp(var, "tonemap")) {
+			if (!(val = va_arg(ap, char *))) {
+				break;
+			}
+			tonemap = val;
+		} else if (!strcasecmp(var, "digit_timeout")) {
+			if (!(intval = va_arg(ap, int *))) {
+				break;
+			}
+			digit_timeout = *intval;
+		} else if (!strcasecmp(var, "enable_callerid")) {
+			if (!(val = va_arg(ap, char *))) {
+                break;
+            }
+			
+			if (zap_true(val)) {
+				flags |= ZAP_ANALOG_CALLERID;
+			} else {
+				flags &= ~ZAP_ANALOG_CALLERID;
+			}
+		} else if (!strcasecmp(var, "max_dialstr")) {
+			if (!(intval = va_arg(ap, int *))) {
+				break;
+			}
+			max_dialstr = *intval;
+		} else if (!strcasecmp(var, "hotline")) {
+			if (!(val = va_arg(ap, char *))) {
+				break;
+			}
+			hotline = val;
+		} else {
+			snprintf(span->last_error, sizeof(span->last_error), "Unknown parameter [%s]", var);
+			return ZAP_FAIL;
+		}			
+	}
+
+
+	if (digit_timeout < 2000 || digit_timeout > 10000) {
+		digit_timeout = 2000;
+	}
+
+	if ((max_dialstr < 1 && !strlen(hotline)) || max_dialstr > MAX_DTMF) {
+		max_dialstr = MAX_DTMF;
+	}
+	
+	span->start = zap_analog_start;
+	analog_data->flags = flags;
+	analog_data->digit_timeout = digit_timeout;
+	analog_data->max_dialstr = max_dialstr;
+	span->signal_cb = sig_cb;
+	strncpy(analog_data->hotline, hotline, sizeof(analog_data->hotline));
+	span->signal_type = ZAP_SIGTYPE_ANALOG;
+	span->signal_data = analog_data;
+	span->outgoing_call = span->trunk_type == ZAP_TRUNK_FXS ? analog_fxs_outgoing_call : analog_fxo_outgoing_call;
+	zap_span_load_tones(span, tonemap);
+
+	return ZAP_SUCCESS;
+
+}
+
+/**
+ * \brief Retrieves tone generation output to be sent
+ * \param ts Teletone generator
+ * \param map Tone map
+ * \return -1 on error, 0 on success
+ */
+static int teletone_handler(teletone_generation_session_t *ts, teletone_tone_map_t *map)
+{
+	zap_buffer_t *dt_buffer = ts->user_data;
+	int wrote;
+
+	if (!dt_buffer) {
+		return -1;
+	}
+	wrote = teletone_mux_tones(ts, map);
+	zap_buffer_write(dt_buffer, ts->buffer, wrote * 2);
+	return 0;
+}
+
+/**
+ * \brief Sends caller id on an analog channel (FSK coded)
+ * \param zchan Channel to send caller id on
+ */
+static void send_caller_id(zap_channel_t *zchan)
+{
+	zap_fsk_data_state_t fsk_data;
+	uint8_t databuf[1024] = "";
+	char time_str[9];
+	struct tm tm;
+	time_t now;
+	zap_mdmf_type_t mt = MDMF_INVALID;
+
+	time(&now);
+#ifdef WIN32
+	_tzset();
+	_localtime64_s(&tm, &now);
+#else
+	localtime_r(&now, &tm);
+#endif
+	strftime(time_str, sizeof(time_str), "%m%d%H%M", &tm);
+
+	zap_fsk_data_init(&fsk_data, databuf, sizeof(databuf));
+	zap_fsk_data_add_mdmf(&fsk_data, MDMF_DATETIME, (uint8_t *) time_str, 8);
+					
+	if (zap_strlen_zero(zchan->caller_data.cid_num.digits)) {
+		mt = MDMF_NO_NUM;
+		zap_set_string(zchan->caller_data.cid_num.digits, "O");
+	} else if (!strcasecmp(zchan->caller_data.cid_num.digits, "P") || !strcasecmp(zchan->caller_data.cid_num.digits, "O")) {
+		mt = MDMF_NO_NUM;
+	} else {
+		mt = MDMF_PHONE_NUM;
+	}
+	zap_fsk_data_add_mdmf(&fsk_data, mt, (uint8_t *) zchan->caller_data.cid_num.digits, (uint8_t)strlen(zchan->caller_data.cid_num.digits));
+
+	if (zap_strlen_zero(zchan->caller_data.cid_name)) {
+		mt = MDMF_NO_NAME;
+		zap_set_string(zchan->caller_data.cid_name, "O");
+	} else if (!strcasecmp(zchan->caller_data.cid_name, "P") || !strcasecmp(zchan->caller_data.cid_name, "O")) {
+		mt = MDMF_NO_NAME;
+	} else {
+		mt = MDMF_PHONE_NAME;
+	}
+	zap_fsk_data_add_mdmf(&fsk_data, mt, (uint8_t *) zchan->caller_data.cid_name, (uint8_t)strlen(zchan->caller_data.cid_name));
+					
+	zap_fsk_data_add_checksum(&fsk_data);
+	zap_channel_send_fsk_data(zchan, &fsk_data, -14);
+}
+
+/**
+ * \brief Main thread function for analog channel (outgoing call)
+ * \param me Current thread
+ * \param obj Channel to run in this thread
+ */
+static void *zap_analog_channel_run(zap_thread_t *me, void *obj)
+{
+	zap_channel_t *zchan = (zap_channel_t *) obj;
+	zap_buffer_t *dt_buffer = NULL;
+	teletone_generation_session_t ts;
+	uint8_t frame[1024];
+	zap_size_t len, rlen;
+	zap_tone_type_t tt = ZAP_TONE_DTMF;
+	char dtmf[MAX_DTMF+1] = "";
+	zap_size_t dtmf_offset = 0;
+	zap_analog_data_t *analog_data = zchan->span->signal_data;
+	zap_channel_t *closed_chan;
+	uint32_t state_counter = 0, elapsed = 0, collecting = 0, interval = 0, last_digit = 0, indicate = 0, dial_timeout = 30000;
+	zap_sigmsg_t sig;
+	zap_status_t status;
+	
+	zap_log(ZAP_LOG_DEBUG, "ANALOG CHANNEL thread starting.\n");
+
+	ts.buffer = NULL;
+
+	if (zap_channel_open_chan(zchan) != ZAP_SUCCESS) {
+		zap_log(ZAP_LOG_ERROR, "OPEN ERROR [%s]\n", zchan->last_error);
+		goto done;
+	}
+
+	if (zap_buffer_create(&dt_buffer, 1024, 3192, 0) != ZAP_SUCCESS) {
+		snprintf(zchan->last_error, sizeof(zchan->last_error), "memory error!");
+		zap_log(ZAP_LOG_ERROR, "MEM ERROR\n");
+		goto done;
+	}
+
+	if (zap_channel_command(zchan, ZAP_COMMAND_ENABLE_DTMF_DETECT, &tt) != ZAP_SUCCESS) {
+		snprintf(zchan->last_error, sizeof(zchan->last_error), "error initilizing tone detector!");
+		zap_log(ZAP_LOG_ERROR, "TONE ERROR\n");
+		goto done;
+	}
+
+	zap_set_flag_locked(zchan, ZAP_CHANNEL_INTHREAD);
+	teletone_init_session(&ts, 0, teletone_handler, dt_buffer);
+	ts.rate = 8000;
+#if 0
+	ts.debug = 1;
+	ts.debug_stream = stdout;
+#endif
+	zap_channel_command(zchan, ZAP_COMMAND_GET_INTERVAL, &interval);
+	zap_buffer_set_loops(dt_buffer, -1);
+	
+	memset(&sig, 0, sizeof(sig));
+	sig.chan_id = zchan->chan_id;
+	sig.span_id = zchan->span_id;
+	sig.channel = zchan;
+	
+	assert(interval != 0);
+
+	while (zap_running() && zap_test_flag(zchan, ZAP_CHANNEL_INTHREAD)) {
+		zap_wait_flag_t flags = ZAP_READ;
+		zap_size_t dlen = 0;
+		
+		len = sizeof(frame);
+		
+		elapsed += interval;
+		state_counter += interval;
+		
+		if (!zap_test_flag(zchan, ZAP_CHANNEL_STATE_CHANGE)) {
+			switch(zchan->state) {
+			case ZAP_CHANNEL_STATE_GET_CALLERID:
+				{
+					if (state_counter > 5000 || !zap_test_flag(zchan, ZAP_CHANNEL_CALLERID_DETECT)) {
+						zap_channel_command(zchan, ZAP_COMMAND_DISABLE_CALLERID_DETECT, NULL);
+						zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_IDLE);
+					}
+				}
+				break;
+			case ZAP_CHANNEL_STATE_DIALING:
+				{
+					if (state_counter > dial_timeout) {
+						if (zchan->needed_tones[ZAP_TONEMAP_DIAL]) {
+							zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_BUSY);
+						} else {
+							zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_UP);
+						}
+					} 
+				}
+				break;
+			case ZAP_CHANNEL_STATE_GENRING:
+				{
+					if (state_counter > 60000) {
+						zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_DOWN);
+					} else if (!zchan->fsk_buffer || !zap_buffer_inuse(zchan->fsk_buffer)) {
+						zap_sleep(interval);
+						continue;
+					}
+				}
+				break;
+			case ZAP_CHANNEL_STATE_DIALTONE:
+				{
+					if (!zap_test_flag(zchan, ZAP_CHANNEL_HOLD) && state_counter > 10000) {
+						zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_BUSY);
+					}
+				}
+				break;
+			case ZAP_CHANNEL_STATE_BUSY:
+				{
+					if (state_counter > 20000) {
+						zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_ATTN);
+					}
+				}
+				break;
+			case ZAP_CHANNEL_STATE_ATTN:
+				{
+					if (state_counter > 20000) {
+						zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_DOWN);
+					}
+				}
+				break;
+			case ZAP_CHANNEL_STATE_HANGUP:
+				{
+					if (state_counter > 500) {
+						if (zap_test_flag(zchan, ZAP_CHANNEL_RINGING)) {
+							zap_channel_command(zchan, ZAP_COMMAND_GENERATE_RING_OFF, NULL);
+						}
+						
+						if (zap_test_flag(zchan, ZAP_CHANNEL_OFFHOOK) && 
+							(zchan->last_state == ZAP_CHANNEL_STATE_RING || zchan->last_state == ZAP_CHANNEL_STATE_DIALTONE 
+							 || zchan->last_state >= ZAP_CHANNEL_STATE_IDLE)) {
+							zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_BUSY);
+						} else {
+							zchan->caller_data.hangup_cause = ZAP_CAUSE_NORMAL_CLEARING;
+							zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_DOWN);
+						}
+					}
+				}
+				break;
+			case ZAP_CHANNEL_STATE_CALLWAITING:
+				{
+					int done = 0;
+					
+					if (zchan->detected_tones[ZAP_TONEMAP_CALLWAITING_ACK] == 1) {
+						send_caller_id(zchan);
+						zchan->detected_tones[ZAP_TONEMAP_CALLWAITING_ACK]++;
+					} else if (state_counter > 600 && !zchan->detected_tones[ZAP_TONEMAP_CALLWAITING_ACK]) {
+						send_caller_id(zchan);
+						zchan->detected_tones[ZAP_TONEMAP_CALLWAITING_ACK]++;
+					} else if (state_counter > 1000 && !zchan->detected_tones[ZAP_TONEMAP_CALLWAITING_ACK]) {
+						done = 1;
+					} else if (state_counter > 10000) {
+						if (zchan->fsk_buffer) {
+							zap_buffer_zero(zchan->fsk_buffer);
+						} else {
+							zap_buffer_create(&zchan->fsk_buffer, 128, 128, 0);
+						}
+						
+						ts.user_data = zchan->fsk_buffer;
+						teletone_run(&ts, zchan->span->tone_map[ZAP_TONEMAP_CALLWAITING_SAS]);
+						ts.user_data = dt_buffer;
+						done = 1;
+					}
+
+					if (done) {
+						zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_UP);
+						zap_clear_flag_locked(zchan, ZAP_CHANNEL_STATE_CHANGE);
+						zap_clear_flag_locked(zchan->span, ZAP_SPAN_STATE_CHANGE);
+						zchan->detected_tones[ZAP_TONEMAP_CALLWAITING_ACK] = 0;
+					}
+				}
+			case ZAP_CHANNEL_STATE_UP:
+			case ZAP_CHANNEL_STATE_IDLE:
+				{
+					zap_sleep(interval);
+					continue;
+				}
+				break;
+			case ZAP_CHANNEL_STATE_DOWN:
+				{
+					goto done;
+				}
+				break;
+			default:
+				break;
+			}
+		} else {
+			zap_clear_flag_locked(zchan, ZAP_CHANNEL_STATE_CHANGE);
+			zap_clear_flag_locked(zchan->span, ZAP_SPAN_STATE_CHANGE);
+			zap_channel_complete_state(zchan);
+			indicate = 0;
+			state_counter = 0;
+
+			zap_log(ZAP_LOG_DEBUG, "Executing state handler on %d:%d for %s\n", 
+					zchan->span_id, zchan->chan_id,
+					zap_channel_state2str(zchan->state));
+			switch(zchan->state) {
+			case ZAP_CHANNEL_STATE_UP:
+				{
+					zap_channel_use(zchan);
+					zap_channel_clear_needed_tones(zchan);
+					zap_channel_flush_dtmf(zchan);
+						
+					if (zchan->type == ZAP_CHAN_TYPE_FXO && !zap_test_flag(zchan, ZAP_CHANNEL_OFFHOOK)) {
+						zap_channel_command(zchan, ZAP_COMMAND_OFFHOOK, NULL);
+					}
+
+					if (zchan->fsk_buffer && zap_buffer_inuse(zchan->fsk_buffer)) {
+						zap_log(ZAP_LOG_DEBUG, "Cancel FSK transmit due to early answer.\n");
+						zap_buffer_zero(zchan->fsk_buffer);
+					}
+
+					if (zchan->type == ZAP_CHAN_TYPE_FXS && zap_test_flag(zchan, ZAP_CHANNEL_RINGING)) {
+						zap_channel_command(zchan, ZAP_COMMAND_GENERATE_RING_OFF, NULL);
+					}
+
+					if (zchan->token_count == 1) {
+						zap_clear_flag(zchan, ZAP_CHANNEL_HOLD);
+					}
+
+					if (zap_test_flag(zchan, ZAP_CHANNEL_HOLD)) {
+						zap_clear_flag(zchan, ZAP_CHANNEL_HOLD);
+						sig.event_id = ZAP_SIGEVENT_ADD_CALL;
+					} else {
+						sig.event_id = ZAP_SIGEVENT_UP;
+					}
+
+					zap_span_send_signal(zchan->span, &sig);
+					continue;
+				}
+				break;
+			case ZAP_CHANNEL_STATE_DIALING:
+				{
+					zap_channel_use(zchan);
+				}
+				break;
+			case ZAP_CHANNEL_STATE_IDLE:
+				{
+					zap_channel_use(zchan);
+					sig.event_id = ZAP_SIGEVENT_START;
+
+					if (zchan->type == ZAP_CHAN_TYPE_FXO) {
+						zap_set_string(zchan->caller_data.dnis.digits, zchan->chan_number);
+					} else {
+						zap_set_string(zchan->caller_data.dnis.digits, dtmf);
+					}
+
+					zap_span_send_signal(zchan->span, &sig);
+					continue;
+				}
+				break;
+			case ZAP_CHANNEL_STATE_DOWN:
+				{
+					sig.event_id = ZAP_SIGEVENT_STOP;
+					zap_span_send_signal(zchan->span, &sig);
+					goto done;
+				}
+				break;
+			case ZAP_CHANNEL_STATE_DIALTONE:
+				{
+					memset(&zchan->caller_data, 0, sizeof(zchan->caller_data));
+					*dtmf = '\0';
+					dtmf_offset = 0;
+					zap_buffer_zero(dt_buffer);
+					teletone_run(&ts, zchan->span->tone_map[ZAP_TONEMAP_DIAL]);
+					indicate = 1;
+				}
+				break;
+			case ZAP_CHANNEL_STATE_CALLWAITING:
+				{
+					zchan->detected_tones[ZAP_TONEMAP_CALLWAITING_ACK] = 0;
+					if (zchan->fsk_buffer) {
+						zap_buffer_zero(zchan->fsk_buffer);
+					} else {
+						zap_buffer_create(&zchan->fsk_buffer, 128, 128, 0);
+					}
+					
+					ts.user_data = zchan->fsk_buffer;
+					teletone_run(&ts, zchan->span->tone_map[ZAP_TONEMAP_CALLWAITING_SAS]);
+					teletone_run(&ts, zchan->span->tone_map[ZAP_TONEMAP_CALLWAITING_CAS]);
+					ts.user_data = dt_buffer;
+				}
+				break;
+			case ZAP_CHANNEL_STATE_GENRING:
+				{
+					zap_sigmsg_t sig;
+
+					send_caller_id(zchan);
+					zap_channel_command(zchan, ZAP_COMMAND_GENERATE_RING_ON, NULL);
+
+					memset(&sig, 0, sizeof(sig));
+					sig.chan_id = zchan->chan_id;
+					sig.span_id = zchan->span_id;
+					sig.channel = zchan;
+					sig.event_id = ZAP_SIGEVENT_PROGRESS;
+					zap_span_send_signal(zchan->span, &sig);
+					
+				}
+				break;
+			case ZAP_CHANNEL_STATE_GET_CALLERID:
+				{
+					memset(&zchan->caller_data, 0, sizeof(zchan->caller_data));
+					zap_channel_command(zchan, ZAP_COMMAND_ENABLE_CALLERID_DETECT, NULL);
+					continue;
+				}
+				break;
+			case ZAP_CHANNEL_STATE_RING:
+				{
+					zap_buffer_zero(dt_buffer);
+					teletone_run(&ts, zchan->span->tone_map[ZAP_TONEMAP_RING]);
+					indicate = 1;
+					
+				}
+				break;
+			case ZAP_CHANNEL_STATE_BUSY:
+				{
+					zchan->caller_data.hangup_cause = ZAP_CAUSE_NORMAL_CIRCUIT_CONGESTION;
+					if (zap_test_flag(zchan, ZAP_CHANNEL_OFFHOOK) && !zap_test_flag(zchan, ZAP_CHANNEL_OUTBOUND)) {
+						zap_buffer_zero(dt_buffer);
+						teletone_run(&ts, zchan->span->tone_map[ZAP_TONEMAP_BUSY]);
+						indicate = 1;
+					} else {
+						zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_DOWN);
+					}
+				}
+				break;
+			case ZAP_CHANNEL_STATE_ATTN:
+				{
+					if (zap_test_flag(zchan, ZAP_CHANNEL_OFFHOOK) && !zap_test_flag(zchan, ZAP_CHANNEL_OUTBOUND)) {
+						zap_buffer_zero(dt_buffer);
+						teletone_run(&ts, zchan->span->tone_map[ZAP_TONEMAP_ATTN]);
+						indicate = 1;
+					} else {
+						zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_DOWN);
+					}
+				}
+				break;
+			default:
+				break;
+			}
+		}
+
+
+		if (zchan->state == ZAP_CHANNEL_STATE_DIALTONE || zchan->state == ZAP_CHANNEL_STATE_COLLECT) {
+			if ((dlen = zap_channel_dequeue_dtmf(zchan, dtmf + dtmf_offset, sizeof(dtmf) - strlen(dtmf)))) {
+
+				if (zchan->state == ZAP_CHANNEL_STATE_DIALTONE) {
+					zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_COLLECT);
+					collecting = 1;
+				}
+				dtmf_offset = strlen(dtmf);
+				last_digit = elapsed;
+				sig.event_id = ZAP_SIGEVENT_COLLECTED_DIGIT;
+				sig.raw_data = dtmf;
+				if (zap_span_send_signal(zchan->span, &sig) == ZAP_BREAK) {
+					collecting = 0;
+				}
+			}
+			else if(!analog_data->max_dialstr)
+			{
+				last_digit = elapsed;
+				collecting = 0;
+				strcpy(dtmf, analog_data->hotline);
+			}
+		}
+
+
+		if (last_digit && (!collecting || ((elapsed - last_digit > analog_data->digit_timeout) || strlen(dtmf) >= analog_data->max_dialstr))) {
+			zap_log(ZAP_LOG_DEBUG, "Number obtained [%s]\n", dtmf);
+			zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_IDLE);
+			last_digit = 0;
+			collecting = 0;
+		}
+
+		if (zap_channel_wait(zchan, &flags, interval * 2) != ZAP_SUCCESS) {
+			continue;
+		}
+
+		if (!(flags & ZAP_READ)) {
+			continue;
+		}
+
+		if (zap_channel_read(zchan, frame, &len) != ZAP_SUCCESS) {
+			zap_log(ZAP_LOG_ERROR, "READ ERROR [%s]\n", zchan->last_error);
+			goto done;
+		}
+
+		if (zchan->type == ZAP_CHAN_TYPE_FXO && zchan->detected_tones[0]) {
+			zap_sigmsg_t sig;
+			int i;
+			memset(&sig, 0, sizeof(sig));
+			sig.chan_id = zchan->chan_id;
+			sig.span_id = zchan->span_id;
+			sig.channel = zchan;
+			sig.event_id = ZAP_SIGEVENT_TONE_DETECTED;
+			
+			for (i = 1; i < ZAP_TONEMAP_INVALID; i++) {
+				if (zchan->detected_tones[i]) {
+					zap_log(ZAP_LOG_DEBUG, "Detected tone %s on %d:%d\n", zap_tonemap2str(i), zchan->span_id, zchan->chan_id);
+					sig.raw_data = &i;
+					zap_span_send_signal(zchan->span, &sig);
+				}
+			}
+			
+			if (zchan->detected_tones[ZAP_TONEMAP_BUSY] || 
+				zchan->detected_tones[ZAP_TONEMAP_FAIL1] ||
+				zchan->detected_tones[ZAP_TONEMAP_FAIL2] ||
+				zchan->detected_tones[ZAP_TONEMAP_FAIL3] ||
+				zchan->detected_tones[ZAP_TONEMAP_ATTN]
+				) {
+				zap_log(ZAP_LOG_ERROR, "Failure indication detected!\n");
+				zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_BUSY);
+			} else if (zchan->detected_tones[ZAP_TONEMAP_DIAL]) {
+				if (zap_strlen_zero(zchan->caller_data.ani.digits)) {
+					zap_log(ZAP_LOG_ERROR, "No Digits to send!\n");
+					zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_BUSY);
+				} else {
+					if (zap_channel_command(zchan, ZAP_COMMAND_SEND_DTMF, zchan->caller_data.ani.digits) != ZAP_SUCCESS) {
+						zap_log(ZAP_LOG_ERROR, "Send Digits Failed [%s]\n", zchan->last_error);
+						zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_BUSY);
+					} else {
+						state_counter = 0;
+						zchan->needed_tones[ZAP_TONEMAP_RING] = 1;
+						zchan->needed_tones[ZAP_TONEMAP_BUSY] = 1;
+						zchan->needed_tones[ZAP_TONEMAP_FAIL1] = 1;
+						zchan->needed_tones[ZAP_TONEMAP_FAIL2] = 1;
+						zchan->needed_tones[ZAP_TONEMAP_FAIL3] = 1;
+						dial_timeout = ((zchan->dtmf_on + zchan->dtmf_off) * strlen(zchan->caller_data.ani.digits)) + 2000;
+					}
+				}
+			} else if (zchan->detected_tones[ZAP_TONEMAP_RING]) {
+				zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_UP);
+			}
+			
+			zap_channel_clear_detected_tones(zchan);
+		}
+
+		if ((zchan->dtmf_buffer && zap_buffer_inuse(zchan->dtmf_buffer)) || (zchan->fsk_buffer && zap_buffer_inuse(zchan->fsk_buffer))) {
+			//rlen = len;
+			//memset(frame, 0, len);
+			//zap_channel_write(zchan, frame, sizeof(frame), &rlen);
+			continue;
+		}
+		
+		if (!indicate) {
+			continue;
+		}
+
+		if (zchan->type == ZAP_CHAN_TYPE_FXO && !zap_test_flag(zchan, ZAP_CHANNEL_OFFHOOK)) {
+			zap_channel_command(zchan, ZAP_COMMAND_OFFHOOK, NULL);
+		}
+
+		if (zchan->effective_codec != ZAP_CODEC_SLIN) {
+			len *= 2;
+		}
+
+		rlen = zap_buffer_read_loop(dt_buffer, frame, len);					
+		
+		if (zchan->effective_codec != ZAP_CODEC_SLIN) {
+			zio_codec_t codec_func = NULL;
+
+			if (zchan->native_codec == ZAP_CODEC_ULAW) {
+				codec_func = zio_slin2ulaw;
+			} else if (zchan->native_codec == ZAP_CODEC_ALAW) {
+				codec_func = zio_slin2alaw;
+			}
+
+			if (codec_func) {
+				status = codec_func(frame, sizeof(frame), &rlen);
+			} else {
+				snprintf(zchan->last_error, sizeof(zchan->last_error), "codec error!");
+				goto done;
+			}
+		}
+
+		zap_channel_write(zchan, frame, sizeof(frame), &rlen);
+	}
+
+ done:
+
+
+	if (zchan->type == ZAP_CHAN_TYPE_FXO && zap_test_flag(zchan, ZAP_CHANNEL_OFFHOOK)) {
+		zap_channel_command(zchan, ZAP_COMMAND_ONHOOK, NULL);
+	}
+
+	if (zchan->type == ZAP_CHAN_TYPE_FXS && zap_test_flag(zchan, ZAP_CHANNEL_RINGING)) {
+		zap_channel_command(zchan, ZAP_COMMAND_GENERATE_RING_OFF, NULL);
+	}
+
+	
+	closed_chan = zchan;
+	zap_channel_close(&zchan);
+
+	zap_channel_command(closed_chan, ZAP_COMMAND_SET_NATIVE_CODEC, NULL);
+
+	if (ts.buffer) {
+		teletone_destroy_session(&ts);
+	}
+
+	if (dt_buffer) {
+		zap_buffer_destroy(&dt_buffer);
+	}
+
+	if (closed_chan->state != ZAP_CHANNEL_STATE_DOWN) {
+		zap_set_state_locked(closed_chan, ZAP_CHANNEL_STATE_DOWN);
+	}
+
+	zap_log(ZAP_LOG_DEBUG, "ANALOG CHANNEL %d:%d thread ended.\n", closed_chan->span_id, closed_chan->chan_id);
+	zap_clear_flag(closed_chan, ZAP_CHANNEL_INTHREAD);
+
+	return NULL;
+}
+
+/**
+ * \brief Processes openzap event
+ * \param span Span on which the event was fired
+ * \param event Event to be treated
+ * \return Success or failure
+ */
+static __inline__ zap_status_t process_event(zap_span_t *span, zap_event_t *event)
+{
+	zap_sigmsg_t sig;
+	zap_analog_data_t *analog_data = event->channel->span->signal_data;
+	int locked = 0;
+	
+	memset(&sig, 0, sizeof(sig));
+	sig.chan_id = event->channel->chan_id;
+	sig.span_id = event->channel->span_id;
+	sig.channel = event->channel;
+
+
+	zap_log(ZAP_LOG_DEBUG, "EVENT [%s][%d:%d] STATE [%s]\n", 
+			zap_oob_event2str(event->enum_id), event->channel->span_id, event->channel->chan_id, zap_channel_state2str(event->channel->state));
+
+	zap_mutex_lock(event->channel->mutex);
+	locked++;
+
+	switch(event->enum_id) {
+	case ZAP_OOB_RING_START:
+		{
+			if (event->channel->type != ZAP_CHAN_TYPE_FXO) {
+				zap_log(ZAP_LOG_ERROR, "Cannot get a RING_START event on a non-fxo channel, please check your config.\n");
+				zap_set_state_locked(event->channel, ZAP_CHANNEL_STATE_DOWN);
+				goto end;
+			}
+			if (!event->channel->ring_count && (event->channel->state == ZAP_CHANNEL_STATE_DOWN && !zap_test_flag(event->channel, ZAP_CHANNEL_INTHREAD))) {
+				if (zap_test_flag(analog_data, ZAP_ANALOG_CALLERID)) {
+					zap_set_state_locked(event->channel, ZAP_CHANNEL_STATE_GET_CALLERID);
+				} else {
+					zap_set_state_locked(event->channel, ZAP_CHANNEL_STATE_IDLE);
+				}
+				event->channel->ring_count = 1;
+				zap_mutex_unlock(event->channel->mutex);
+				locked = 0;
+				zap_thread_create_detached(zap_analog_channel_run, event->channel);
+			} else {
+				event->channel->ring_count++;
+			}
+		}
+		break;
+	case ZAP_OOB_ONHOOK:
+		{
+			if (zap_test_flag(event->channel, ZAP_CHANNEL_RINGING)) {
+				zap_channel_command(event->channel, ZAP_COMMAND_GENERATE_RING_OFF, NULL);
+			}
+
+			if (event->channel->state != ZAP_CHANNEL_STATE_DOWN) {
+				zap_set_state_locked(event->channel, ZAP_CHANNEL_STATE_DOWN);
+			}
+
+		}
+		break;
+	case ZAP_OOB_FLASH:
+		{
+			if (event->channel->state == ZAP_CHANNEL_STATE_CALLWAITING) {
+				zap_set_state_locked(event->channel, ZAP_CHANNEL_STATE_UP);
+				zap_clear_flag_locked(event->channel, ZAP_CHANNEL_STATE_CHANGE);
+				zap_clear_flag_locked(event->channel->span, ZAP_SPAN_STATE_CHANGE);
+				event->channel->detected_tones[ZAP_TONEMAP_CALLWAITING_ACK] = 0;
+			} 
+
+			zap_channel_rotate_tokens(event->channel);
+			
+			if (zap_test_flag(event->channel, ZAP_CHANNEL_HOLD) && event->channel->token_count != 1) {
+				zap_set_state_locked(event->channel,  ZAP_CHANNEL_STATE_UP);
+			} else {
+				sig.event_id = ZAP_SIGEVENT_FLASH;
+				zap_span_send_signal(span, &sig);
+			}
+		}
+		break;
+	case ZAP_OOB_OFFHOOK:
+		{
+			if (event->channel->type == ZAP_CHAN_TYPE_FXS) {
+				if (zap_test_flag(event->channel, ZAP_CHANNEL_INTHREAD)) {
+					if (zap_test_flag(event->channel, ZAP_CHANNEL_RINGING)) {
+						zap_channel_command(event->channel, ZAP_COMMAND_GENERATE_RING_OFF, NULL);
+					}
+					zap_set_state_locked(event->channel, ZAP_CHANNEL_STATE_UP);
+				} else {
+					if(!analog_data->max_dialstr) {
+						zap_set_state_locked(event->channel, ZAP_CHANNEL_STATE_COLLECT);
+					} else {
+						zap_set_state_locked(event->channel, ZAP_CHANNEL_STATE_DIALTONE);
+					}						
+					zap_mutex_unlock(event->channel->mutex);
+					locked = 0;
+					zap_thread_create_detached(zap_analog_channel_run, event->channel);
+				}
+			} else {
+				if (!zap_test_flag(event->channel, ZAP_CHANNEL_INTHREAD)) {
+					if (zap_test_flag(event->channel, ZAP_CHANNEL_OFFHOOK)) {
+						zap_channel_command(event->channel, ZAP_COMMAND_ONHOOK, NULL);
+					}
+				}
+				zap_set_state_locked(event->channel, ZAP_CHANNEL_STATE_DOWN);
+			}
+		}
+	case ZAP_OOB_DTMF:
+		{
+			const char * digit_str = (const char *)event->data;
+			if(digit_str) {
+				if (event->channel->state == ZAP_CHANNEL_STATE_CALLWAITING && (*digit_str == 'D' || *digit_str == 'A')) {
+					event->channel->detected_tones[ZAP_TONEMAP_CALLWAITING_ACK]++;
+				} else {
+					zio_event_cb_t event_callback = NULL;
+					
+					zap_channel_queue_dtmf(event->channel, digit_str);
+					if (span->event_callback) {
+						event_callback = span->event_callback;
+					} else if (event->channel->event_callback) {
+						event_callback = event->channel->event_callback;
+					}
+					
+					if (event_callback) {
+						event->channel->event_header.channel = event->channel;
+						event->channel->event_header.e_type = ZAP_EVENT_DTMF;
+						event->channel->event_header.data = (void *)digit_str;
+						event_callback(event->channel, &event->channel->event_header);
+						event->channel->event_header.e_type = ZAP_EVENT_NONE;
+						event->channel->event_header.data = NULL;
+					}
+					
+				}
+				zap_safe_free(event->data);
+			}
+		}
+	case ZAP_OOB_ALARM_TRAP:
+		{
+			zap_set_flag_locked(event->channel, ZAP_CHANNEL_SUSPENDED);
+		}
+	case ZAP_OOB_ALARM_CLEAR:
+		{
+			zap_clear_flag_locked(event->channel, ZAP_CHANNEL_SUSPENDED);
+		}
+	}
+
+ end:
+
+	if (locked) {
+		zap_mutex_unlock(event->channel->mutex);
+	}
+	return ZAP_SUCCESS;
+}
+
+/**
+ * \brief Main thread function for analog span (monitor)
+ * \param me Current thread
+ * \param obj Span to run in this thread
+ */
+static void *zap_analog_run(zap_thread_t *me, void *obj)
+{
+	zap_span_t *span = (zap_span_t *) obj;
+	zap_analog_data_t *analog_data = span->signal_data;
+	int errs = 0;
+	
+	zap_log(ZAP_LOG_DEBUG, "ANALOG thread starting.\n");
+
+	while(zap_running() && zap_test_flag(analog_data, ZAP_ANALOG_RUNNING)) {
+		int waitms = 1000;
+		zap_status_t status;
+
+		if ((status = zap_span_poll_event(span, waitms)) != ZAP_FAIL) {
+			errs = 0;
+		}
+		
+		switch(status) {
+		case ZAP_SUCCESS:
+			{
+				zap_event_t *event;
+				while (zap_span_next_event(span, &event) == ZAP_SUCCESS) {
+					if (event->enum_id == ZAP_OOB_NOOP) {
+						continue;
+					}
+					if (process_event(span, event) != ZAP_SUCCESS) {
+						goto end;
+					}
+				}
+			}
+			break;
+		case ZAP_FAIL:
+			{
+				zap_log(ZAP_LOG_ERROR, "Failure Polling event! [%s]\n", span->last_error);
+				if (++errs > 300) {
+					zap_log(ZAP_LOG_CRIT, "Too Many Errors!\n");
+					goto end;
+				}
+			}
+			break;
+		default:
+			break;
+		}
+
+	}
+
+ end:
+
+	zap_clear_flag(analog_data, ZAP_ANALOG_RUNNING);
+	
+	zap_log(ZAP_LOG_DEBUG, "ANALOG thread ending.\n");
+
+	return NULL;
+}
+
+/**
+ * \brief Openzap analog signaling module initialisation
+ * \return Success
+ */
+static ZIO_SIG_LOAD_FUNCTION(zap_analog_init)
+{
+	return ZAP_SUCCESS;
+}
+
+/**
+ * \brief Openzap analog signaling module definition
+ */
+EX_DECLARE_DATA zap_module_t zap_module = {
+	"analog",
+	NULL,
+	NULL,
+	zap_analog_init,
+	zap_analog_configure_span,
+	NULL
+};
+
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */

Added: freeswitch/trunk/libs/openzap/src/ozmod/ozmod_analog/zap_analog.h (0 => 17141)


--- freeswitch/trunk/libs/openzap/src/ozmod/ozmod_analog/zap_analog.h	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/src/ozmod/ozmod_analog/zap_analog.h	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2007, Anthony Minessale II
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ZAP_ANALOG_H
+#define ZAP_ANALOG_H
+#include "openzap.h"
+
+typedef enum {
+	ZAP_ANALOG_RUNNING = (1 << 0),
+	ZAP_ANALOG_CALLERID = (1 << 1)
+} zap_analog_flag_t;
+
+#define ZAP_MAX_HOTLINE_STR		20
+#define MAX_DTMF 256
+
+struct zap_analog_data {
+	uint32_t flags;
+	uint32_t max_dialstr;
+	uint32_t digit_timeout;
+	char hotline[ZAP_MAX_HOTLINE_STR];
+};
+
+
+
+static void *zap_analog_run(zap_thread_t *me, void *obj);
+typedef struct zap_analog_data zap_analog_data_t;
+
+#endif
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */

Added: freeswitch/trunk/libs/openzap/src/ozmod/ozmod_analog_em/ozmod_analog_em.2005.vcproj (0 => 17141)


--- freeswitch/trunk/libs/openzap/src/ozmod/ozmod_analog_em/ozmod_analog_em.2005.vcproj	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/src/ozmod/ozmod_analog_em/ozmod_analog_em.2005.vcproj	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,202 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="8.00"
+	Name="ozmod_analog_em"
+	ProjectGUID="{C539D7C8-26A8-4A94-B938-77672165C130}"
+	RootNamespace="ozmod_analog_em"
+	Keyword="Win32Proj"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="2"
+			CharacterSet="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				AdditionalIncludeDirectories="..\..\include;..\..\isdn\include"
+				PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;OZMOD_ANALOG_EM_EXPORTS"
+				MinimalRebuild="true"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="3"
+				UsePrecompiledHeader="0"
+				WarningLevel="4"
+				WarnAsError="true"
+				DebugInformationFormat="4"
+				DisableSpecificWarnings="4100"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				LinkIncremental="2"
+				GenerateDebugInformation="true"
+				SubSystem="2"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="2"
+			CharacterSet="1"
+			WholeProgramOptimization="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="2"
+				EnableIntrinsicFunctions="true"
+				AdditionalIncludeDirectories="..\..\include;..\..\isdn\include"
+				PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;OZMOD_ANALOG_EM_EXPORTS"
+				RuntimeLibrary="2"
+				EnableFunctionLevelLinking="true"
+				UsePrecompiledHeader="0"
+				WarningLevel="4"
+				WarnAsError="true"
+				DebugInformationFormat="3"
+				DisableSpecificWarnings="4100"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				LinkIncremental="1"
+				GenerateDebugInformation="true"
+				SubSystem="2"
+				OptimizeReferences="2"
+				EnableCOMDATFolding="2"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<Filter
+			Name="Source Files"
+			Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+			>
+			<File
+				RelativePath="ozmod_analog_em.c"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="Header Files"
+			Filter="h;hpp;hxx;hm;inl;inc;xsd"
+			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+			>
+			<File
+				RelativePath="zap_analog_em.h"
+				>
+			</File>
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>

Added: freeswitch/trunk/libs/openzap/src/ozmod/ozmod_analog_em/ozmod_analog_em.2008.vcproj (0 => 17141)


--- freeswitch/trunk/libs/openzap/src/ozmod/ozmod_analog_em/ozmod_analog_em.2008.vcproj	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/src/ozmod/ozmod_analog_em/ozmod_analog_em.2008.vcproj	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,353 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="9.00"
+	Name="ozmod_analog_em"
+	ProjectGUID="{B3F49375-2834-4937-9D8C-4AC2EC911010}"
+	RootNamespace="ozmod_analog_em"
+	Keyword="Win32Proj"
+	TargetFrameworkVersion="196613"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+		<Platform
+			Name="x64"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="2"
+			CharacterSet="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				AdditionalIncludeDirectories="..\..\include;..\..\isdn\include"
+				PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;OZMOD_ANALOG_EM_EXPORTS"
+				MinimalRebuild="true"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="3"
+				UsePrecompiledHeader="0"
+				WarningLevel="4"
+				WarnAsError="true"
+				DebugInformationFormat="4"
+				DisableSpecificWarnings="4100"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				LinkIncremental="2"
+				GenerateDebugInformation="true"
+				SubSystem="2"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="2"
+			CharacterSet="1"
+			WholeProgramOptimization="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="2"
+				EnableIntrinsicFunctions="true"
+				AdditionalIncludeDirectories="..\..\include;..\..\isdn\include"
+				PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;OZMOD_ANALOG_EM_EXPORTS"
+				RuntimeLibrary="2"
+				EnableFunctionLevelLinking="true"
+				UsePrecompiledHeader="0"
+				WarningLevel="4"
+				WarnAsError="true"
+				DebugInformationFormat="3"
+				DisableSpecificWarnings="4100"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				LinkIncremental="1"
+				GenerateDebugInformation="true"
+				SubSystem="2"
+				OptimizeReferences="2"
+				EnableCOMDATFolding="2"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Debug|x64"
+			OutputDirectory="$(SolutionDir)$(PlatformName)\$(ConfigurationName)"
+			IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+			ConfigurationType="2"
+			CharacterSet="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+				TargetEnvironment="3"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				AdditionalIncludeDirectories="..\..\include;..\..\isdn\include"
+				PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;OZMOD_ANALOG_EM_EXPORTS"
+				MinimalRebuild="true"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="3"
+				UsePrecompiledHeader="0"
+				WarningLevel="4"
+				WarnAsError="false"
+				DebugInformationFormat="3"
+				DisableSpecificWarnings="4100"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				LinkIncremental="2"
+				GenerateDebugInformation="true"
+				SubSystem="2"
+				TargetMachine="17"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|x64"
+			OutputDirectory="$(SolutionDir)$(PlatformName)\$(ConfigurationName)"
+			IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+			ConfigurationType="2"
+			CharacterSet="1"
+			WholeProgramOptimization="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+				TargetEnvironment="3"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="2"
+				EnableIntrinsicFunctions="true"
+				AdditionalIncludeDirectories="..\..\include;..\..\isdn\include"
+				PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;OZMOD_ANALOG_EM_EXPORTS"
+				RuntimeLibrary="2"
+				EnableFunctionLevelLinking="true"
+				UsePrecompiledHeader="0"
+				WarningLevel="4"
+				WarnAsError="true"
+				DebugInformationFormat="3"
+				DisableSpecificWarnings="4100"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				LinkIncremental="1"
+				GenerateDebugInformation="true"
+				SubSystem="2"
+				OptimizeReferences="2"
+				EnableCOMDATFolding="2"
+				TargetMachine="17"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<Filter
+			Name="Source Files"
+			Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+			>
+			<File
+				RelativePath="ozmod_analog_em.c"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="Header Files"
+			Filter="h;hpp;hxx;hm;inl;inc;xsd"
+			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+			>
+			<File
+				RelativePath="zap_analog_em.h"
+				>
+			</File>
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>

Added: freeswitch/trunk/libs/openzap/src/ozmod/ozmod_analog_em/ozmod_analog_em.c (0 => 17141)


--- freeswitch/trunk/libs/openzap/src/ozmod/ozmod_analog_em/ozmod_analog_em.c	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/src/ozmod/ozmod_analog_em/ozmod_analog_em.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,707 @@
+/*
+ * Copyright (c) 2008, Anthony Minessale II
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Contributor(s):
+ *
+ * John Wehle (john@feith.com)
+ *
+ */
+
+#include "openzap.h"
+#include "zap_analog_em.h"
+
+#ifndef localtime_r
+struct tm * localtime_r(const time_t *clock, struct tm *result);
+#endif
+
+static void *zap_analog_em_channel_run(zap_thread_t *me, void *obj);
+
+/**
+ * \brief Starts an EM channel thread (outgoing call)
+ * \param zchan Channel to initiate call on
+ * \return Success or failure
+ *
+ * Initialises state, starts tone progress detection and runs the channel in a new a thread.
+ */
+static ZIO_CHANNEL_OUTGOING_CALL_FUNCTION(analog_em_outgoing_call)
+{
+	if (!zap_test_flag(zchan, ZAP_CHANNEL_OFFHOOK) && !zap_test_flag(zchan, ZAP_CHANNEL_INTHREAD)) {		
+		zap_channel_clear_needed_tones(zchan);
+		zap_channel_clear_detected_tones(zchan);
+
+		zap_set_flag(zchan, ZAP_CHANNEL_OUTBOUND);
+
+		zap_channel_command(zchan, ZAP_COMMAND_OFFHOOK, NULL);
+		zap_channel_command(zchan, ZAP_COMMAND_ENABLE_PROGRESS_DETECT, NULL);
+		zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_DIALING);
+		zap_thread_create_detached(zap_analog_em_channel_run, zchan);
+		return ZAP_SUCCESS;
+	}
+
+	return ZAP_FAIL;
+}
+
+/**
+ * \brief Starts an EM span thread (monitor)
+ * \param span Span to monitor
+ * \return Success or failure
+ */
+static zap_status_t zap_analog_em_start(zap_span_t *span)
+{
+	zap_analog_em_data_t *analog_data = span->signal_data;
+	zap_set_flag(analog_data, ZAP_ANALOG_EM_RUNNING);
+	return zap_thread_create_detached(zap_analog_em_run, span);
+}
+
+/**
+ * \brief Initialises an EM span from configuration variables
+ * \param span Span to configure
+ * \param sig_cb Callback function for event signals
+ * \param ap List of configuration variables
+ * \return Success or failure
+ */
+static ZIO_SIG_CONFIGURE_FUNCTION(zap_analog_em_configure_span)
+//zap_status_t zap_analog_em_configure_span(zap_span_t *span, char *tonemap, uint32_t digit_timeout, uint32_t max_dialstr, zio_signal_cb_t sig_cb)
+{
+	zap_analog_em_data_t *analog_data;
+	const char *tonemap = "us";
+	uint32_t digit_timeout = 10;
+	uint32_t max_dialstr = 11;
+	const char *var, *val;
+	int *intval;
+
+	assert(sig_cb != NULL);
+
+	if (span->signal_type) {
+		snprintf(span->last_error, sizeof(span->last_error), "Span is already configured for signalling.");
+		return ZAP_FAIL;
+	}
+	
+	analog_data = malloc(sizeof(*analog_data));
+	assert(analog_data != NULL);
+	memset(analog_data, 0, sizeof(*analog_data));
+
+	while((var = va_arg(ap, char *))) {
+		if (!strcasecmp(var, "tonemap")) {
+			if (!(val = va_arg(ap, char *))) {
+				break;
+			}
+			tonemap = val;
+		} else if (!strcasecmp(var, "digit_timeout")) {
+			if (!(intval = va_arg(ap, int *))) {
+				break;
+			}
+			digit_timeout = *intval;
+		} else if (!strcasecmp(var, "max_dialstr")) {
+			if (!(intval = va_arg(ap, int *))) {
+				break;
+			}
+			max_dialstr = *intval;
+		} else {
+			snprintf(span->last_error, sizeof(span->last_error), "Unknown parameter [%s]", var);
+			return ZAP_FAIL;
+		}
+	}
+
+
+	if (digit_timeout < 2000 || digit_timeout > 10000) {
+		digit_timeout = 2000;
+	}
+
+	if (max_dialstr < 2 || max_dialstr > MAX_DIALSTRING) {
+		zap_log(ZAP_LOG_ERROR, "Invalid max_dialstr, setting to %d\n", MAX_DIALSTRING);
+		max_dialstr = MAX_DIALSTRING;
+	}
+
+	span->start = zap_analog_em_start;
+	analog_data->digit_timeout = digit_timeout;
+	analog_data->max_dialstr = max_dialstr;
+	span->signal_cb = sig_cb;
+	span->signal_type = ZAP_SIGTYPE_ANALOG;
+	span->signal_data = analog_data;
+	span->outgoing_call = analog_em_outgoing_call;
+	zap_span_load_tones(span, tonemap);
+
+	return ZAP_SUCCESS;
+
+}
+
+/**
+ * \brief Retrieves tone generation output to be sent
+ * \param ts Teletone generator
+ * \param map Tone map
+ * \return -1 on error, 0 on success
+ */
+static int teletone_handler(teletone_generation_session_t *ts, teletone_tone_map_t *map)
+{
+	zap_buffer_t *dt_buffer = ts->user_data;
+	int wrote;
+
+	if (!dt_buffer) {
+		return -1;
+	}
+	wrote = teletone_mux_tones(ts, map);
+	zap_buffer_write(dt_buffer, ts->buffer, wrote * 2);
+	return 0;
+}
+
+/**
+ * \brief Main thread function for EM channel (outgoing call)
+ * \param me Current thread
+ * \param obj Channel to run in this thread
+ */
+static void *zap_analog_em_channel_run(zap_thread_t *me, void *obj)
+{
+	zap_channel_t *zchan = (zap_channel_t *) obj;
+	zap_buffer_t *dt_buffer = NULL;
+	teletone_generation_session_t ts;
+	uint8_t frame[1024];
+	zap_size_t len, rlen;
+	zap_tone_type_t tt = ZAP_TONE_DTMF;
+	char dtmf[128] = "";
+	zap_size_t dtmf_offset = 0;
+	zap_analog_em_data_t *analog_data = zchan->span->signal_data;
+	zap_channel_t *closed_chan;
+	uint32_t state_counter = 0, elapsed = 0, collecting = 0, interval = 0, last_digit = 0, indicate = 0, dial_timeout = 30000;
+	zap_sigmsg_t sig;
+	zap_status_t status;
+	
+	zap_log(ZAP_LOG_DEBUG, "ANALOG EM CHANNEL thread starting.\n");
+
+	ts.buffer = NULL;
+
+	if (zap_channel_open_chan(zchan) != ZAP_SUCCESS) {
+		zap_log(ZAP_LOG_ERROR, "OPEN ERROR [%s]\n", zchan->last_error);
+		goto done;
+	}
+
+	if (zap_buffer_create(&dt_buffer, 1024, 3192, 0) != ZAP_SUCCESS) {
+		snprintf(zchan->last_error, sizeof(zchan->last_error), "memory error!");
+		zap_log(ZAP_LOG_ERROR, "MEM ERROR\n");
+		goto done;
+	}
+
+	if (zap_channel_command(zchan, ZAP_COMMAND_ENABLE_DTMF_DETECT, &tt) != ZAP_SUCCESS) {
+		snprintf(zchan->last_error, sizeof(zchan->last_error), "error initilizing tone detector!");
+		zap_log(ZAP_LOG_ERROR, "TONE ERROR\n");
+		goto done;
+	}
+
+	zap_set_flag_locked(zchan, ZAP_CHANNEL_INTHREAD);
+	teletone_init_session(&ts, 0, teletone_handler, dt_buffer);
+	ts.rate = 8000;
+#if 0
+	ts.debug = 1;
+	ts.debug_stream = stdout;
+#endif
+	zap_channel_command(zchan, ZAP_COMMAND_GET_INTERVAL, &interval);
+	zap_buffer_set_loops(dt_buffer, -1);
+	
+	memset(&sig, 0, sizeof(sig));
+	sig.chan_id = zchan->chan_id;
+	sig.span_id = zchan->span_id;
+	sig.channel = zchan;
+	
+	assert(interval != 0);
+
+	while (zap_running() && zap_test_flag(zchan, ZAP_CHANNEL_INTHREAD)) {
+		zap_wait_flag_t flags = ZAP_READ;
+		zap_size_t dlen = 0;
+		
+		len = sizeof(frame);
+		
+		elapsed += interval;
+		state_counter += interval;
+		
+		if (!zap_test_flag(zchan, ZAP_CHANNEL_STATE_CHANGE)) {
+			switch(zchan->state) {
+			case ZAP_CHANNEL_STATE_DIALING:
+				{
+					if (! zchan->needed_tones[ZAP_TONEMAP_RING]
+						&& zap_test_flag(zchan, ZAP_CHANNEL_WINK)) {
+						if (zap_strlen_zero(zchan->caller_data.ani.digits)) {
+							zap_log(ZAP_LOG_ERROR, "No Digits to send!\n");
+							zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_BUSY);
+						} else {
+							if (zap_channel_command(zchan, ZAP_COMMAND_SEND_DTMF, zchan->caller_data.ani.digits) != ZAP_SUCCESS) {
+								zap_log(ZAP_LOG_ERROR, "Send Digits Failed [%s]\n", zchan->last_error);
+								zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_BUSY);
+							} else {
+								state_counter = 0;
+								zchan->needed_tones[ZAP_TONEMAP_RING] = 1;
+								zchan->needed_tones[ZAP_TONEMAP_BUSY] = 1;
+								zchan->needed_tones[ZAP_TONEMAP_FAIL1] = 1;
+								zchan->needed_tones[ZAP_TONEMAP_FAIL2] = 1;
+								zchan->needed_tones[ZAP_TONEMAP_FAIL3] = 1;
+								dial_timeout = ((zchan->dtmf_on + zchan->dtmf_off) * strlen(zchan->caller_data.ani.digits)) + 2000;
+							}
+						}
+						break;
+					}
+					if (state_counter > dial_timeout) {
+						if (!zap_test_flag(zchan, ZAP_CHANNEL_WINK)) {
+							zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_BUSY);
+						} else {
+							zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_UP);
+						}
+					} 
+				}
+				break;
+			case ZAP_CHANNEL_STATE_DIALTONE:
+				{
+					if (state_counter > 10000) {
+						zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_BUSY);
+					}
+				}
+				break;
+			case ZAP_CHANNEL_STATE_BUSY:
+				{
+					if (state_counter > 20000) {
+						zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_ATTN);
+					}
+				}
+				break;
+			case ZAP_CHANNEL_STATE_ATTN:
+				{
+					if (state_counter > 20000) {
+						zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_DOWN);
+					}
+				}
+				break;
+			case ZAP_CHANNEL_STATE_HANGUP:
+				{
+					if (state_counter > 500) {
+						if (zap_test_flag(zchan, ZAP_CHANNEL_OFFHOOK) && 
+							(zchan->last_state == ZAP_CHANNEL_STATE_RING || zchan->last_state == ZAP_CHANNEL_STATE_DIALTONE 
+							 || zchan->last_state >= ZAP_CHANNEL_STATE_IDLE)) {
+							zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_BUSY);
+						} else {
+							zchan->caller_data.hangup_cause = ZAP_CAUSE_NORMAL_CLEARING;
+							zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_DOWN);
+						}
+					}
+				}
+				break;
+			case ZAP_CHANNEL_STATE_UP:
+			case ZAP_CHANNEL_STATE_IDLE:
+				{
+					zap_sleep(interval);
+					continue;
+				}
+				break;
+			case ZAP_CHANNEL_STATE_DOWN:
+				{
+					goto done;
+				}
+				break;
+			default:
+				break;
+			}
+		} else {
+			zap_clear_flag_locked(zchan, ZAP_CHANNEL_STATE_CHANGE);
+			zap_clear_flag_locked(zchan->span, ZAP_SPAN_STATE_CHANGE);
+			zap_channel_complete_state(zchan);
+			indicate = 0;
+			state_counter = 0;
+
+			zap_log(ZAP_LOG_DEBUG, "Executing state handler on %d:%d for %s\n", 
+					zchan->span_id, zchan->chan_id,
+					zap_channel_state2str(zchan->state));
+			switch(zchan->state) {
+			case ZAP_CHANNEL_STATE_UP:
+				{
+					zap_channel_use(zchan);
+					zap_channel_clear_needed_tones(zchan);
+					zap_channel_flush_dtmf(zchan);
+
+					if (!zap_test_flag(zchan, ZAP_CHANNEL_OFFHOOK)) {
+						zap_channel_command(zchan, ZAP_COMMAND_OFFHOOK, NULL);
+					}
+
+					sig.event_id = ZAP_SIGEVENT_UP;
+
+					zap_span_send_signal(zchan->span, &sig);
+					continue;
+				}
+				break;
+			case ZAP_CHANNEL_STATE_DIALING:
+				{
+					zap_channel_use(zchan);
+				}
+				break;
+			case ZAP_CHANNEL_STATE_IDLE:
+				{
+					zap_channel_use(zchan);
+
+					if (zap_test_flag(zchan, ZAP_CHANNEL_OUTBOUND)) {
+						zap_set_string(zchan->caller_data.dnis.digits, zchan->chan_number);
+					} else {
+						zap_set_string(zchan->caller_data.dnis.digits, dtmf);
+					}
+
+					sig.event_id = ZAP_SIGEVENT_START;
+
+					zap_span_send_signal(zchan->span, &sig);
+					continue;
+				}
+				break;
+			case ZAP_CHANNEL_STATE_DOWN:
+				{
+					sig.event_id = ZAP_SIGEVENT_STOP;
+					zap_span_send_signal(zchan->span, &sig);
+					goto done;
+				}
+				break;
+			case ZAP_CHANNEL_STATE_DIALTONE:
+				{
+					memset(&zchan->caller_data, 0, sizeof(zchan->caller_data));
+					*dtmf = '\0';
+					dtmf_offset = 0;
+					zap_buffer_zero(dt_buffer);
+					teletone_run(&ts, zchan->span->tone_map[ZAP_TONEMAP_DIAL]);
+					indicate = 1;
+
+					zap_channel_command(zchan, ZAP_COMMAND_WINK, NULL);
+				}
+				break;
+			case ZAP_CHANNEL_STATE_RING:
+				{
+					zap_buffer_zero(dt_buffer);
+					teletone_run(&ts, zchan->span->tone_map[ZAP_TONEMAP_RING]);
+					indicate = 1;
+				}
+				break;
+			case ZAP_CHANNEL_STATE_BUSY:
+				{
+					zchan->caller_data.hangup_cause = ZAP_CAUSE_NORMAL_CIRCUIT_CONGESTION;
+					if (zap_test_flag(zchan, ZAP_CHANNEL_OFFHOOK) && !zap_test_flag(zchan, ZAP_CHANNEL_OUTBOUND)) {
+						zap_buffer_zero(dt_buffer);
+						teletone_run(&ts, zchan->span->tone_map[ZAP_TONEMAP_BUSY]);
+						indicate = 1;
+					} else {
+						zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_DOWN);
+					}
+				}
+				break;
+			case ZAP_CHANNEL_STATE_ATTN:
+				{
+					if (zap_test_flag(zchan, ZAP_CHANNEL_OFFHOOK) && !zap_test_flag(zchan, ZAP_CHANNEL_OUTBOUND)) {
+						zap_buffer_zero(dt_buffer);
+						teletone_run(&ts, zchan->span->tone_map[ZAP_TONEMAP_ATTN]);
+						indicate = 1;
+					} else {
+						zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_DOWN);
+					}
+				}
+				break;
+			default:
+				break;
+			}
+		}
+
+
+		if (zchan->state == ZAP_CHANNEL_STATE_DIALTONE || zchan->state == ZAP_CHANNEL_STATE_COLLECT) {
+			if ((dlen = zap_channel_dequeue_dtmf(zchan, dtmf + dtmf_offset, sizeof(dtmf) - strlen(dtmf)))) {
+
+				if (zchan->state == ZAP_CHANNEL_STATE_DIALTONE) {
+					zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_COLLECT);
+					collecting = 1;
+				}
+				dtmf_offset = strlen(dtmf);
+				last_digit = elapsed;
+				sig.event_id = ZAP_SIGEVENT_COLLECTED_DIGIT;
+				sig.raw_data = dtmf;
+				if (zap_span_send_signal(zchan->span, &sig) == ZAP_BREAK) {
+					collecting = 0;
+				}
+			}
+		}
+
+
+		if (last_digit && (!collecting || ((elapsed - last_digit > analog_data->digit_timeout) || strlen(dtmf) > analog_data->max_dialstr))) {
+			zap_log(ZAP_LOG_DEBUG, "Number obtained [%s]\n", dtmf);
+			zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_IDLE);
+			last_digit = 0;
+			collecting = 0;
+		}
+
+		if (zap_channel_wait(zchan, &flags, interval * 2) != ZAP_SUCCESS) {
+			continue;
+		}
+
+		if (!(flags & ZAP_READ)) {
+			continue;
+		}
+
+		if (zap_channel_read(zchan, frame, &len) != ZAP_SUCCESS) {
+			zap_log(ZAP_LOG_ERROR, "READ ERROR [%s]\n", zchan->last_error);
+			goto done;
+		}
+
+		if (zchan->detected_tones[0]) {
+			zap_sigmsg_t sig;
+			int i;
+			memset(&sig, 0, sizeof(sig));
+			sig.chan_id = zchan->chan_id;
+			sig.span_id = zchan->span_id;
+			sig.channel = zchan;
+			sig.event_id = ZAP_SIGEVENT_TONE_DETECTED;
+			
+			for (i = 1; i < ZAP_TONEMAP_INVALID; i++) {
+				if (zchan->detected_tones[i]) {
+					zap_log(ZAP_LOG_DEBUG, "Detected tone %s on %d:%d\n", zap_tonemap2str(i), zchan->span_id, zchan->chan_id);
+					sig.raw_data = &i;
+					zap_span_send_signal(zchan->span, &sig);
+				}
+			}
+			
+			if (zchan->detected_tones[ZAP_TONEMAP_BUSY] || 
+				zchan->detected_tones[ZAP_TONEMAP_FAIL1] ||
+				zchan->detected_tones[ZAP_TONEMAP_FAIL2] ||
+				zchan->detected_tones[ZAP_TONEMAP_FAIL3] ||
+				zchan->detected_tones[ZAP_TONEMAP_ATTN]
+				) {
+				zap_log(ZAP_LOG_ERROR, "Failure indication detected!\n");
+				zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_BUSY);
+			} else if (zchan->detected_tones[ZAP_TONEMAP_RING]) {
+				zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_UP);
+			}
+			
+			zap_channel_clear_detected_tones(zchan);
+		}
+
+		if ((zchan->dtmf_buffer && zap_buffer_inuse(zchan->dtmf_buffer))) {
+			rlen = len;
+			memset(frame, 0, len);
+			zap_channel_write(zchan, frame, sizeof(frame), &rlen);
+			continue;
+		}
+		
+		if (!indicate) {
+			continue;
+		}
+
+		if (zchan->effective_codec != ZAP_CODEC_SLIN) {
+			len *= 2;
+		}
+
+		rlen = zap_buffer_read_loop(dt_buffer, frame, len);
+
+		if (zchan->effective_codec != ZAP_CODEC_SLIN) {
+			zio_codec_t codec_func = NULL;
+
+			if (zchan->native_codec == ZAP_CODEC_ULAW) {
+				codec_func = zio_slin2ulaw;
+			} else if (zchan->native_codec == ZAP_CODEC_ALAW) {
+				codec_func = zio_slin2alaw;
+			}
+
+			if (codec_func) {
+				status = codec_func(frame, sizeof(frame), &rlen);
+			} else {
+				snprintf(zchan->last_error, sizeof(zchan->last_error), "codec error!");
+				goto done;
+			}
+		}
+
+		zap_channel_write(zchan, frame, sizeof(frame), &rlen);
+	}
+
+ done:
+
+	zap_channel_command(zchan, ZAP_COMMAND_ONHOOK, NULL);
+	
+	closed_chan = zchan;
+	zap_channel_close(&zchan);
+
+	zap_channel_command(closed_chan, ZAP_COMMAND_SET_NATIVE_CODEC, NULL);
+
+	if (ts.buffer) {
+		teletone_destroy_session(&ts);
+	}
+
+	if (dt_buffer) {
+		zap_buffer_destroy(&dt_buffer);
+	}
+
+	zap_clear_flag(closed_chan, ZAP_CHANNEL_INTHREAD);
+
+	zap_log(ZAP_LOG_DEBUG, "ANALOG EM CHANNEL thread ended.\n");
+
+	return NULL;
+}
+
+/**
+ * \brief Processes EM events coming from zaptel/dahdi
+ * \param span Span on which the event was fired
+ * \param event Event to be treated
+ * \return Success or failure
+ */
+static __inline__ zap_status_t process_event(zap_span_t *span, zap_event_t *event)
+{
+	zap_sigmsg_t sig;
+	int locked = 0;
+	
+	memset(&sig, 0, sizeof(sig));
+	sig.chan_id = event->channel->chan_id;
+	sig.span_id = event->channel->span_id;
+	sig.channel = event->channel;
+
+
+	zap_log(ZAP_LOG_DEBUG, "EVENT [%s][%d:%d] STATE [%s]\n", 
+			zap_oob_event2str(event->enum_id), event->channel->span_id, event->channel->chan_id, zap_channel_state2str(event->channel->state));
+
+	zap_mutex_lock(event->channel->mutex);
+	locked++;
+
+	switch(event->enum_id) {
+	case ZAP_OOB_ONHOOK:
+		{
+			if (event->channel->state != ZAP_CHANNEL_STATE_DOWN) {
+				zap_set_state_locked(event->channel, ZAP_CHANNEL_STATE_DOWN);
+			}
+
+		}
+		break;
+	case ZAP_OOB_OFFHOOK:
+		{
+			if (zap_test_flag(event->channel, ZAP_CHANNEL_INTHREAD)) {
+				zap_set_state_locked(event->channel, ZAP_CHANNEL_STATE_UP);
+			} else {
+				zap_set_state_locked(event->channel, ZAP_CHANNEL_STATE_DIALTONE);
+				zap_mutex_unlock(event->channel->mutex);
+				locked = 0;
+				zap_thread_create_detached(zap_analog_em_channel_run, event->channel);
+			}
+		break;
+		}
+	case ZAP_OOB_WINK:
+		{
+			if (event->channel->state != ZAP_CHANNEL_STATE_DIALING) {
+				zap_set_state_locked(event->channel, ZAP_CHANNEL_STATE_DOWN);
+			} else {
+				zap_set_flag_locked(event->channel, ZAP_CHANNEL_WINK);
+			}
+
+		}
+		break;
+	}
+	if (locked) {
+		zap_mutex_unlock(event->channel->mutex);
+	}
+	return ZAP_SUCCESS;
+}
+
+/**
+ * \brief Main thread function for EM span (monitor)
+ * \param me Current thread
+ * \param obj Span to run in this thread
+ */
+static void *zap_analog_em_run(zap_thread_t *me, void *obj)
+{
+	zap_span_t *span = (zap_span_t *) obj;
+	zap_analog_em_data_t *analog_data = span->signal_data;
+
+	zap_log(ZAP_LOG_DEBUG, "ANALOG EM thread starting.\n");
+
+	while(zap_running() && zap_test_flag(analog_data, ZAP_ANALOG_EM_RUNNING)) {
+		int waitms = 10;
+		zap_status_t status;
+
+		status = zap_span_poll_event(span, waitms);
+		
+		switch(status) {
+		case ZAP_SUCCESS:
+			{
+				zap_event_t *event;
+				while (zap_span_next_event(span, &event) == ZAP_SUCCESS) {
+					if (event->enum_id == ZAP_OOB_NOOP) {
+						continue;
+					}
+					if (process_event(span, event) != ZAP_SUCCESS) {
+						goto end;
+					}
+				}
+			}
+			break;
+		case ZAP_FAIL:
+			{
+				zap_log(ZAP_LOG_ERROR, "Failure Polling event! [%s]\n", span->last_error);
+			}
+			break;
+		default:
+			break;
+		}
+
+	}
+
+ end:
+
+	zap_clear_flag(analog_data, ZAP_ANALOG_EM_RUNNING);
+	
+	zap_log(ZAP_LOG_DEBUG, "ANALOG EM thread ending.\n");
+
+	return NULL;
+}
+
+/**
+ * \brief Openzap analog EM module initialisation
+ * \return Success
+ */
+static ZIO_SIG_LOAD_FUNCTION(zap_analog_em_init)
+{
+	return ZAP_SUCCESS;
+}
+
+/**
+ * \brief Openzap analog EM module definition
+ */
+EX_DECLARE_DATA zap_module_t zap_module = {
+	"analog_em",
+	NULL,
+	NULL,
+	zap_analog_em_init,
+	zap_analog_em_configure_span,
+	NULL
+};
+
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */

Added: freeswitch/trunk/libs/openzap/src/ozmod/ozmod_analog_em/zap_analog_em.h (0 => 17141)


--- freeswitch/trunk/libs/openzap/src/ozmod/ozmod_analog_em/zap_analog_em.h	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/src/ozmod/ozmod_analog_em/zap_analog_em.h	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2008, Anthony Minessale II
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Contributor(s):
+ *
+ * John Wehle (john@feith.com)
+ *
+ */
+
+#ifndef ZAP_ANALOG_EM_H
+#define ZAP_ANALOG_EM_H
+#include "openzap.h"
+
+#define MAX_DIALSTRING 256
+
+typedef enum {
+	ZAP_ANALOG_EM_RUNNING = (1 << 0)
+} zap_analog_em_flag_t;
+
+
+struct zap_analog_data {
+	uint32_t flags;
+	uint32_t max_dialstr;
+	uint32_t digit_timeout;
+};
+
+static void *zap_analog_em_run(zap_thread_t *me, void *obj);
+typedef struct zap_analog_data zap_analog_em_data_t;
+
+#endif
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */

Added: freeswitch/trunk/libs/openzap/src/ozmod/ozmod_isdn/ozmod_isdn.2005.vcproj (0 => 17141)


--- freeswitch/trunk/libs/openzap/src/ozmod/ozmod_isdn/ozmod_isdn.2005.vcproj	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/src/ozmod/ozmod_isdn/ozmod_isdn.2005.vcproj	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,316 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="8.00"
+	Name="ozmod_isdn"
+	ProjectGUID="{729344A5-D5E9-434D-8EE8-AF8C6C795D15}"
+	RootNamespace="ozmod_isdn"
+	Keyword="Win32Proj"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="2"
+			CharacterSet="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				AdditionalIncludeDirectories="..\..\isdn\include;..\..\include"
+				PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;OZMOD_ISDN_EXPORTS;_CRT_SECURE_NO_WARNINGS"
+				MinimalRebuild="true"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="3"
+				UsePrecompiledHeader="0"
+				WarningLevel="4"
+				WarnAsError="true"
+				DebugInformationFormat="4"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				LinkIncremental="2"
+				GenerateDebugInformation="true"
+				SubSystem="2"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="2"
+			CharacterSet="1"
+			WholeProgramOptimization="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="2"
+				EnableIntrinsicFunctions="true"
+				AdditionalIncludeDirectories="..\..\isdn\include;..\..\include"
+				PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;OZMOD_ISDN_EXPORTS;_CRT_SECURE_NO_WARNINGS"
+				RuntimeLibrary="2"
+				EnableFunctionLevelLinking="true"
+				UsePrecompiledHeader="0"
+				WarningLevel="4"
+				WarnAsError="true"
+				DebugInformationFormat="3"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				LinkIncremental="1"
+				GenerateDebugInformation="true"
+				SubSystem="2"
+				OptimizeReferences="2"
+				EnableCOMDATFolding="2"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<Filter
+			Name="Source Files"
+			Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+			>
+			<File
+				RelativePath="..\..\isdn\5ESSmes.c"
+				>
+			</File>
+			<File
+				RelativePath="..\..\isdn\5ESSStateNT.c"
+				>
+			</File>
+			<File
+				RelativePath="..\..\isdn\5ESSStateTE.c"
+				>
+			</File>
+			<File
+				RelativePath="..\..\isdn\DMSmes.c"
+				>
+			</File>
+			<File
+				RelativePath="..\..\isdn\DMSStateNT.c"
+				>
+			</File>
+			<File
+				RelativePath="..\..\isdn\DMSStateTE.c"
+				>
+			</File>
+			<File
+				RelativePath="..\..\isdn\EuroISDNStateNT.c"
+				>
+			</File>
+			<File
+				RelativePath="..\..\isdn\EuroISDNStateTE.c"
+				>
+			</File>
+			<File
+				RelativePath="..\..\isdn\mfifo.c"
+				>
+			</File>
+			<File
+				RelativePath="..\..\isdn\nationalmes.c"
+				>
+			</File>
+			<File
+				RelativePath="..\..\isdn\nationalStateNT.c"
+				>
+			</File>
+			<File
+				RelativePath="..\..\isdn\nationalStateTE.c"
+				>
+			</File>
+			<File
+				RelativePath="ozmod_isdn.c"
+				>
+			</File>
+			<File
+				RelativePath="..\..\isdn\Q921.c"
+				>
+			</File>
+			<File
+				RelativePath="..\..\isdn\Q931.c"
+				>
+			</File>
+			<File
+				RelativePath="..\..\isdn\Q931api.c"
+				>
+			</File>
+			<File
+				RelativePath="..\..\isdn\Q931ie.c"
+				>
+			</File>
+			<File
+				RelativePath="..\..\isdn\Q931mes.c"
+				>
+			</File>
+			<File
+				RelativePath="..\..\isdn\Q931StateNT.c"
+				>
+			</File>
+			<File
+				RelativePath="..\..\isdn\Q931StateTE.c"
+				>
+			</File>
+			<File
+				RelativePath="..\..\isdn\Q932mes.c"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="Header Files"
+			Filter="h;hpp;hxx;hm;inl;inc;xsd"
+			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+			>
+			<File
+				RelativePath="..\..\isdn\include\5ESS.h"
+				>
+			</File>
+			<File
+				RelativePath="..\..\isdn\include\DMS.h"
+				>
+			</File>
+			<File
+				RelativePath="..\..\isdn\include\mfifo.h"
+				>
+			</File>
+			<File
+				RelativePath="..\..\isdn\include\national.h"
+				>
+			</File>
+			<File
+				RelativePath="..\..\isdn\include\Q921.h"
+				>
+			</File>
+			<File
+				RelativePath="..\..\isdn\include\Q921priv.h"
+				>
+			</File>
+			<File
+				RelativePath="..\..\isdn\include\Q931.h"
+				>
+			</File>
+			<File
+				RelativePath="..\..\isdn\include\Q931ie.h"
+				>
+			</File>
+			<File
+				RelativePath="..\..\isdn\include\Q932.h"
+				>
+			</File>
+			<File
+				RelativePath="zap_isdn.h"
+				>
+			</File>
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>

Added: freeswitch/trunk/libs/openzap/src/ozmod/ozmod_isdn/ozmod_isdn.2008.vcproj (0 => 17141)


--- freeswitch/trunk/libs/openzap/src/ozmod/ozmod_isdn/ozmod_isdn.2008.vcproj	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/src/ozmod/ozmod_isdn/ozmod_isdn.2008.vcproj	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,465 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="9.00"
+	Name="ozmod_isdn"
+	ProjectGUID="{729344A5-D5E9-434D-8EE8-AF8C6C795D15}"
+	RootNamespace="ozmod_isdn"
+	Keyword="Win32Proj"
+	TargetFrameworkVersion="196613"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+		<Platform
+			Name="x64"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="2"
+			CharacterSet="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				AdditionalIncludeDirectories="..\..\isdn\include;..\..\include"
+				PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;OZMOD_ISDN_EXPORTS;_CRT_SECURE_NO_WARNINGS"
+				MinimalRebuild="true"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="3"
+				UsePrecompiledHeader="0"
+				WarningLevel="4"
+				WarnAsError="true"
+				DebugInformationFormat="4"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				LinkIncremental="2"
+				GenerateDebugInformation="true"
+				SubSystem="2"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="2"
+			CharacterSet="1"
+			WholeProgramOptimization="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="2"
+				EnableIntrinsicFunctions="true"
+				AdditionalIncludeDirectories="..\..\isdn\include;..\..\include"
+				PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;OZMOD_ISDN_EXPORTS;_CRT_SECURE_NO_WARNINGS"
+				RuntimeLibrary="2"
+				EnableFunctionLevelLinking="true"
+				UsePrecompiledHeader="0"
+				WarningLevel="4"
+				WarnAsError="true"
+				DebugInformationFormat="3"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				LinkIncremental="1"
+				GenerateDebugInformation="true"
+				SubSystem="2"
+				OptimizeReferences="2"
+				EnableCOMDATFolding="2"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Debug|x64"
+			OutputDirectory="$(SolutionDir)$(PlatformName)\$(ConfigurationName)"
+			IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+			ConfigurationType="2"
+			CharacterSet="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+				TargetEnvironment="3"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				AdditionalIncludeDirectories="..\..\isdn\include;..\..\include"
+				PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;OZMOD_ISDN_EXPORTS;_CRT_SECURE_NO_WARNINGS"
+				MinimalRebuild="true"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="3"
+				UsePrecompiledHeader="0"
+				WarningLevel="4"
+				WarnAsError="true"
+				DebugInformationFormat="3"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				LinkIncremental="2"
+				GenerateDebugInformation="true"
+				SubSystem="2"
+				TargetMachine="17"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|x64"
+			OutputDirectory="$(SolutionDir)$(PlatformName)\$(ConfigurationName)"
+			IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+			ConfigurationType="2"
+			CharacterSet="1"
+			WholeProgramOptimization="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+				TargetEnvironment="3"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="2"
+				EnableIntrinsicFunctions="true"
+				AdditionalIncludeDirectories="..\..\isdn\include;..\..\include"
+				PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;OZMOD_ISDN_EXPORTS;_CRT_SECURE_NO_WARNINGS"
+				RuntimeLibrary="2"
+				EnableFunctionLevelLinking="true"
+				UsePrecompiledHeader="0"
+				WarningLevel="4"
+				WarnAsError="true"
+				DebugInformationFormat="3"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				LinkIncremental="1"
+				GenerateDebugInformation="true"
+				SubSystem="2"
+				OptimizeReferences="2"
+				EnableCOMDATFolding="2"
+				TargetMachine="17"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<Filter
+			Name="Source Files"
+			Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+			>
+			<File
+				RelativePath="..\..\isdn\5ESSmes.c"
+				>
+			</File>
+			<File
+				RelativePath="..\..\isdn\5ESSStateNT.c"
+				>
+			</File>
+			<File
+				RelativePath="..\..\isdn\5ESSStateTE.c"
+				>
+			</File>
+			<File
+				RelativePath="..\..\isdn\DMSmes.c"
+				>
+			</File>
+			<File
+				RelativePath="..\..\isdn\DMSStateNT.c"
+				>
+			</File>
+			<File
+				RelativePath="..\..\isdn\DMSStateTE.c"
+				>
+			</File>
+			<File
+				RelativePath="..\..\isdn\EuroISDNStateNT.c"
+				>
+			</File>
+			<File
+				RelativePath="..\..\isdn\EuroISDNStateTE.c"
+				>
+			</File>
+			<File
+				RelativePath="..\..\isdn\mfifo.c"
+				>
+			</File>
+			<File
+				RelativePath="..\..\isdn\nationalmes.c"
+				>
+			</File>
+			<File
+				RelativePath="..\..\isdn\nationalStateNT.c"
+				>
+			</File>
+			<File
+				RelativePath="..\..\isdn\nationalStateTE.c"
+				>
+			</File>
+			<File
+				RelativePath="ozmod_isdn.c"
+				>
+			</File>
+			<File
+				RelativePath="..\..\isdn\Q921.c"
+				>
+			</File>
+			<File
+				RelativePath="..\..\isdn\Q931.c"
+				>
+			</File>
+			<File
+				RelativePath="..\..\isdn\Q931api.c"
+				>
+			</File>
+			<File
+				RelativePath="..\..\isdn\Q931ie.c"
+				>
+			</File>
+			<File
+				RelativePath="..\..\isdn\Q931mes.c"
+				>
+			</File>
+			<File
+				RelativePath="..\..\isdn\Q931StateNT.c"
+				>
+			</File>
+			<File
+				RelativePath="..\..\isdn\Q931StateTE.c"
+				>
+			</File>
+			<File
+				RelativePath="..\..\isdn\Q932mes.c"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="Header Files"
+			Filter="h;hpp;hxx;hm;inl;inc;xsd"
+			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+			>
+			<File
+				RelativePath="..\..\isdn\include\5ESS.h"
+				>
+			</File>
+			<File
+				RelativePath="..\..\isdn\include\DMS.h"
+				>
+			</File>
+			<File
+				RelativePath="..\..\isdn\include\mfifo.h"
+				>
+			</File>
+			<File
+				RelativePath="..\..\isdn\include\national.h"
+				>
+			</File>
+			<File
+				RelativePath="..\..\isdn\include\Q921.h"
+				>
+			</File>
+			<File
+				RelativePath="..\..\isdn\include\Q921priv.h"
+				>
+			</File>
+			<File
+				RelativePath="..\..\isdn\include\Q931.h"
+				>
+			</File>
+			<File
+				RelativePath="..\..\isdn\include\Q931ie.h"
+				>
+			</File>
+			<File
+				RelativePath="..\..\isdn\include\Q932.h"
+				>
+			</File>
+			<File
+				RelativePath="zap_isdn.h"
+				>
+			</File>
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>

Added: freeswitch/trunk/libs/openzap/src/ozmod/ozmod_isdn/ozmod_isdn.c (0 => 17141)


--- freeswitch/trunk/libs/openzap/src/ozmod/ozmod_isdn/ozmod_isdn.c	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/src/ozmod/ozmod_isdn/ozmod_isdn.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,2420 @@
+/*
+ * Copyright (c) 2007, Anthony Minessale II
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * Workaround for missing u_int / u_short types on solaris
+ */
+#if defined(HAVE_LIBPCAP) && defined(__SunOS)
+#define __EXTENSIONS__
+#endif
+
+#include "openzap.h"
+#include "Q931.h"
+#include "Q921.h"
+#ifdef WIN32
+#include <windows.h>
+#else
+#include <sys/time.h>
+#endif
+
+#include "zap_isdn.h"
+
+#define LINE "--------------------------------------------------------------------------------"
+//#define IODEBUG
+
+/* helper macros */
+#define ZAP_SPAN_IS_BRI(x)	((x)->trunk_type == ZAP_TRUNK_BRI || (x)->trunk_type == ZAP_TRUNK_BRI_PTMP)
+#define ZAP_SPAN_IS_NT(x)	(((zap_isdn_data_t *)(x)->signal_data)->mode == Q921_NT)
+
+
+#ifdef HAVE_LIBPCAP
+/*-------------------------------------------------------------------------*/
+/*Q931ToPcap functions*/
+#include <pcap.h>
+#endif
+
+#define SNAPLEN 1522
+#define MAX_ETHER_PAYLOAD_SIZE 1500
+#define MIN_ETHER_PAYLOAD_SIZE 42
+#define SIZE_ETHERNET           18
+#define VLANID_OFFSET           15
+#define SIZE_IP                 20
+#define SIZE_TCP                20
+#define SIZE_TPKT               4
+#define SIZE_ETHERNET_CRC       4
+#define OVERHEAD                SIZE_ETHERNET+SIZE_IP+SIZE_TCP+SIZE_TPKT
+#define MAX_Q931_SIZE           MAX_ETHER_PAYLOAD_SIZE-SIZE_IP-SIZE_TCP-SIZE_TPKT
+#define TPKT_SIZE_OFFSET        SIZE_ETHERNET+SIZE_IP+SIZE_TCP+2
+#define IP_SIZE_OFFSET          SIZE_ETHERNET+2
+#define TCP_SEQ_OFFSET		SIZE_ETHERNET+SIZE_IP+4
+
+#ifdef HAVE_LIBPCAP
+/*Some globals*/
+unsigned long           pcapfilesize = 0;
+unsigned long		tcp_next_seq_no_send = 0;
+unsigned long           tcp_next_seq_no_rec = 0;
+pcap_dumper_t           *pcapfile    = NULL;
+struct pcap_pkthdr      pcaphdr;
+pcap_t                  *pcaphandle  = NULL;
+char 			*pcapfn      = NULL;
+int			do_q931ToPcap= 0;
+
+/*Predefined Ethernet Frame with Q931-over-IP encapsulated - From remote TDM host to FreeSWITCH*/
+L3UCHAR  recFrame[SNAPLEN]= {
+                                /*IEEE 802.3 VLAN 802.1q Ethernet Frame Header*/
+                                2,0,1,0xAA,0xAA,0xAA,2,0,1,0xBB,0xBB,0xBB,0x81,0,0xE0,0,0x08,0,
+                                /*IPv4 Header (minimal size; no options)*/
+                                0x45,0,0,44,0,0,0,0,64,6,0,0,2,2,2,2,1,1,1,1,
+                                /*TCP-Header*/
+                                0,0x66,0,0x66,0,0,0,0,0,0,0,0,0x50,0,0,1,0,0,0,0,
+                                /*TPKT-Header RFC 1006*/
+                                3,0,0,0
+                            };
+
+/*Predefined Ethernet Frame with Q931-over-IP encapsulated - Frome FreeSWITCH to remote TDM host*/
+L3UCHAR  sendFrame[SNAPLEN]= {
+                                /*IEEE 802.3 VLAN 802.1q Ethernet Frame Header*/
+                                2,0,1,0xBB,0xBB,0xBB,2,0,1,0xAA,0xAA,0xAA,0x81,0,0xE0,0,0x08,0,
+                                /*IPv4 Header (minimal size; no options)*/
+                                0x45,0,0,44,0,0,0,0,64,6,0,0,1,1,1,1,2,2,2,2,
+                                /*TCP-Header*/
+                                0,0x66,0,0x66,0,0,0,0,0,0,0,0,0x50,0,0,1,0,0,0,0,
+                                /*TPKT-Header RFC 1006*/
+                                3,0,0,0
+                             };
+
+/**
+ * \brief Opens a pcap file for capture
+ * \return Success or failure
+ */
+static zap_status_t openPcapFile(void)
+{
+        if(!pcaphandle)
+        {
+                pcaphandle = pcap_open_dead(DLT_EN10MB, SNAPLEN);
+                if (!pcaphandle)
+                {
+                        zap_log(ZAP_LOG_ERROR, "Can't open pcap session: (%s)\n", pcap_geterr(pcaphandle));
+                        return ZAP_FAIL;
+                }
+        }
+
+        if(!pcapfile){
+                /* Open the dump file */
+                if(!(pcapfile=pcap_dump_open(pcaphandle, pcapfn))){
+                        zap_log(ZAP_LOG_ERROR, "Error opening output file (%s)\n", pcap_geterr(pcaphandle));
+                        return ZAP_FAIL;
+                }
+        }
+        else{
+                zap_log(ZAP_LOG_WARNING, "Pcap file is already open!\n");
+                return ZAP_FAIL;
+        }
+
+        zap_log(ZAP_LOG_DEBUG, "Pcap file '%s' successfully opened!\n", pcapfn);
+
+        pcaphdr.ts.tv_sec  	= 0;
+        pcaphdr.ts.tv_usec 	= 0;
+	pcapfilesize       	= 24;	/*current pcap file header seems to be 24 bytes*/
+	tcp_next_seq_no_send    = 0;
+	tcp_next_seq_no_rec	= 0;
+
+        return ZAP_SUCCESS;
+}
+
+/**
+ * \brief Closes a pcap file
+ * \return Success
+ */
+static zap_status_t closePcapFile(void)
+{
+	if (pcapfile) {
+		pcap_dump_close(pcapfile);
+		if (pcaphandle) pcap_close(pcaphandle);
+
+		zap_log(ZAP_LOG_DEBUG, "Pcap file closed! File size is %lu bytes.\n", pcapfilesize);
+
+		pcaphdr.ts.tv_sec 	= 0;
+		pcaphdr.ts.tv_usec 	= 0;
+		pcapfile		= NULL;
+		pcaphandle 		= NULL;
+		pcapfilesize		= 0;
+		tcp_next_seq_no_send	= 0;
+		tcp_next_seq_no_rec	= 0;
+	}
+
+	/*We have allways success with this? I think so*/
+	return ZAP_SUCCESS;
+}
+
+/**
+ * \brief Writes a Q931 packet to a pcap file
+ * \return Success or failure
+ */
+static zap_status_t writeQ931PacketToPcap(L3UCHAR* q931buf, L3USHORT q931size, L3ULONG span_id, L3USHORT direction)
+{
+        L3UCHAR                 *frame		= NULL;
+	struct timeval		ts;
+	u_char			spanid		= (u_char)span_id;
+	unsigned long 		*tcp_next_seq_no = NULL;
+
+	spanid=span_id;
+	
+        /*The total length of the ethernet frame generated by this function has a min length of 66
+        so we don't have to care about padding :)*/
+
+
+        /*FS is sending the packet*/
+        if(direction==0){
+		frame=sendFrame;
+		tcp_next_seq_no = &tcp_next_seq_no_send;
+        } 
+	/*FS is receiving the packet*/
+	else{
+		frame=recFrame;
+		tcp_next_seq_no = &tcp_next_seq_no_rec;
+	}
+
+	/*Set spanid in VLAN-ID tag*/
+        frame[VLANID_OFFSET]    = spanid;
+
+        /*** Write sent packet ***/
+        if(q931size > MAX_Q931_SIZE)
+        {
+                /*WARNING*/
+		zap_log(ZAP_LOG_WARNING, "Q931 packet size is too big (%u)! Ignoring it!\n", q931size);
+                return ZAP_FAIL;
+        }
+
+	/*Copy q931 buffer into frame*/
+        memcpy(frame+OVERHEAD,q931buf,q931size);
+
+	/*Store TCP sequence number in TCP header*/
+	frame[TCP_SEQ_OFFSET]=(*tcp_next_seq_no>>24)&0xFF;
+	frame[TCP_SEQ_OFFSET+1]=(*tcp_next_seq_no>>16)&0xFF;
+	frame[TCP_SEQ_OFFSET+2]=(*tcp_next_seq_no>>8)&0xFF;
+	frame[TCP_SEQ_OFFSET+3]=*tcp_next_seq_no & 0xFF;
+
+        /*Store size of TPKT packet*/
+        q931size+=4;
+        frame[TPKT_SIZE_OFFSET]=(q931size>>8)&0xFF;
+        frame[TPKT_SIZE_OFFSET+1]=q931size&0xFF;
+
+	/*Calc next TCP sequence number*/
+	*tcp_next_seq_no+=q931size;
+
+        /*Store size of IP packet*/
+        q931size+=SIZE_IP+SIZE_TCP;
+        frame[IP_SIZE_OFFSET]=(q931size>>8)&0xFF;
+        frame[IP_SIZE_OFFSET+1]=q931size&0xFF;
+
+        pcaphdr.caplen = SIZE_ETHERNET+SIZE_ETHERNET_CRC+q931size;
+        pcaphdr.len = pcaphdr.caplen;
+
+        /* Set Timestamp */
+        /* Get Time in ms. usecs would be better ...  */
+        gettimeofday(&ts, NULL);
+        /*Write it into packet header*/
+        pcaphdr.ts.tv_sec = ts.tv_sec;
+        pcaphdr.ts.tv_usec = ts.tv_usec;
+
+	pcap_dump((u_char*)pcapfile, &pcaphdr, frame);
+        pcap_dump_flush(pcapfile);
+
+        /*Maintain pcap file size*/
+        pcapfilesize+=pcaphdr.caplen;
+        pcapfilesize+=sizeof(struct pcap_pkthdr);
+
+	zap_log(ZAP_LOG_DEBUG, "Added %u bytes to pcap file. File size is now %lu, \n", q931size, pcapfilesize);
+
+        return ZAP_SUCCESS;
+}
+
+#endif
+
+/**
+ * \brief Unloads pcap IO
+ * \return Success or failure
+ */
+static ZIO_IO_UNLOAD_FUNCTION(close_pcap)
+{
+#ifdef HAVE_LIBPCAP
+	return closePcapFile();
+#else
+	return ZAP_SUCCESS;
+#endif
+}
+
+/*Q931ToPcap functions DONE*/
+/*-------------------------------------------------------------------------*/
+
+/**
+ * \brief Gets current time
+ * \return Current time (in ms)
+ */
+static L2ULONG zap_time_now(void)
+{
+	return (L2ULONG)zap_current_time_in_ms();
+}
+
+/**
+ * \brief Initialises an ISDN channel (outgoing call)
+ * \param zchan Channel to initiate call on
+ * \return Success or failure
+ */
+static ZIO_CHANNEL_OUTGOING_CALL_FUNCTION(isdn_outgoing_call)
+{
+	zap_status_t status = ZAP_SUCCESS;
+	zap_set_flag(zchan, ZAP_CHANNEL_OUTBOUND);
+	zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_DIALING);
+	return status;
+}
+
+/**
+ * \brief Requests an ISDN channel on a span (outgoing call)
+ * \param span Span where to get a channel
+ * \param chan_id Specific channel to get (0 for any)
+ * \param direction Call direction (inbound, outbound)
+ * \param caller_data Caller information
+ * \param zchan Channel to initialise
+ * \return Success or failure
+ */
+static ZIO_CHANNEL_REQUEST_FUNCTION(isdn_channel_request)
+{
+	Q931mes_Generic *gen = (Q931mes_Generic *) caller_data->raw_data;
+	Q931ie_BearerCap BearerCap;
+	Q931ie_ChanID ChanID = { 0 };
+	Q931ie_CallingNum CallingNum;
+	Q931ie_CallingNum *ptrCallingNum;
+	Q931ie_CalledNum CalledNum;
+	Q931ie_CalledNum *ptrCalledNum;
+	Q931ie_Display Display, *ptrDisplay;
+	Q931ie_HLComp HLComp;			/* High-Layer Compatibility IE */
+	Q931ie_ProgInd Progress;		/* Progress Indicator IE */
+	zap_status_t status = ZAP_FAIL;
+	zap_isdn_data_t *isdn_data = span->signal_data;
+	int sanity = 60000;
+	int codec  = 0;
+
+	/*
+	 * get codec type
+	 */
+	zap_channel_command(span->channels[chan_id], ZAP_COMMAND_GET_NATIVE_CODEC, &codec);
+
+	/*
+	 * Q.931 Setup Message
+	 */
+	Q931InitMesGeneric(gen);
+	gen->MesType = Q931mes_SETUP;
+	gen->CRVFlag = 0;		/* outgoing call */
+
+	/*
+	 * Bearer Capability IE
+	 */
+	Q931InitIEBearerCap(&BearerCap);
+	BearerCap.CodStand  = Q931_CODING_ITU;		/* ITU-T = 0, ISO/IEC = 1, National = 2, Network = 3 */
+	BearerCap.ITC       = Q931_ITC_SPEECH;		/* Speech */
+	BearerCap.TransMode = 0;			/* Circuit = 0, Packet = 1 */
+	BearerCap.ITR       = Q931_ITR_64K;		/* 64k */
+	BearerCap.Layer1Ident = 1;
+	BearerCap.UIL1Prot = (codec == ZAP_CODEC_ALAW) ? Q931_UIL1P_G711A : Q931_UIL1P_G711U;	/* U-law = 2, A-law = 3 */
+	gen->BearerCap = Q931AppendIE((L3UCHAR *) gen, (L3UCHAR *) &BearerCap);
+
+	/*
+	 * Channel ID IE
+	 */
+	Q931InitIEChanID(&ChanID);
+	ChanID.IntType = ZAP_SPAN_IS_BRI(span) ? 0 : 1;		/* PRI = 1, BRI = 0 */
+
+	if(!ZAP_SPAN_IS_NT(span)) {
+		ChanID.PrefExcl = (isdn_data->opts & ZAP_ISDN_OPT_SUGGEST_CHANNEL) ? 0 : 1; /* 0 = preferred, 1 exclusive */
+	} else {
+		ChanID.PrefExcl = 1;	/* always exclusive in NT-mode */
+	}
+
+	if(ChanID.IntType) {
+		ChanID.InfoChanSel = 1;				/* None = 0, See Slot = 1, Any = 3 */
+		ChanID.ChanMapType = 3; 			/* B-Chan */
+		ChanID.ChanSlot = (unsigned char)chan_id;
+	} else {
+		ChanID.InfoChanSel = (unsigned char)chan_id & 0x03;	/* None = 0, B1 = 1, B2 = 2, Any = 3 */
+	}
+	gen->ChanID = Q931AppendIE((L3UCHAR *) gen, (L3UCHAR *) &ChanID);
+
+	/*
+	 * Progress IE
+	 */
+	Q931InitIEProgInd(&Progress);
+	Progress.CodStand = Q931_CODING_ITU;	/* 0 = ITU */
+	Progress.Location = 0;  /* 0 = User, 1 = Private Network */
+	Progress.ProgDesc = 3;	/* 1 = Not end-to-end ISDN */
+	gen->ProgInd = Q931AppendIE((L3UCHAR *)gen, (L3UCHAR *)&Progress);
+
+	/*
+	 * Display IE
+	 */
+	if (!(isdn_data->opts & ZAP_ISDN_OPT_OMIT_DISPLAY_IE)) {
+		Q931InitIEDisplay(&Display);
+		Display.Size = Display.Size + (unsigned char)strlen(caller_data->cid_name);
+		gen->Display = Q931AppendIE((L3UCHAR *) gen, (L3UCHAR *) &Display);			
+		ptrDisplay = Q931GetIEPtr(gen->Display, gen->buf);
+		zap_copy_string((char *)ptrDisplay->Display, caller_data->cid_name, strlen(caller_data->cid_name)+1);
+	}
+
+	/*
+	 * Calling Number IE
+	 */
+	Q931InitIECallingNum(&CallingNum);
+	CallingNum.TypNum    = Q931_TON_UNKNOWN;
+	CallingNum.NumPlanID = Q931_NUMPLAN_E164;
+	CallingNum.PresInd   = Q931_PRES_ALLOWED;
+	CallingNum.ScreenInd = Q931_SCREEN_USER_NOT_SCREENED;
+	CallingNum.Size = CallingNum.Size + (unsigned char)strlen(caller_data->cid_num.digits);
+	gen->CallingNum = Q931AppendIE((L3UCHAR *) gen, (L3UCHAR *) &CallingNum);			
+	ptrCallingNum = Q931GetIEPtr(gen->CallingNum, gen->buf);
+	zap_copy_string((char *)ptrCallingNum->Digit, caller_data->cid_num.digits, strlen(caller_data->cid_num.digits)+1);
+
+
+	/*
+	 * Called number IE
+	 */
+	Q931InitIECalledNum(&CalledNum);
+	CalledNum.TypNum    = Q931_TON_UNKNOWN;
+	CalledNum.NumPlanID = Q931_NUMPLAN_E164;
+	CalledNum.Size = CalledNum.Size + (unsigned char)strlen(caller_data->ani.digits);
+	gen->CalledNum = Q931AppendIE((L3UCHAR *) gen, (L3UCHAR *) &CalledNum);
+	ptrCalledNum = Q931GetIEPtr(gen->CalledNum, gen->buf);
+	zap_copy_string((char *)ptrCalledNum->Digit, caller_data->ani.digits, strlen(caller_data->ani.digits)+1);
+
+	/*
+	 * High-Layer Compatibility IE   (Note: Required for AVM FritzBox)
+	 */
+	Q931InitIEHLComp(&HLComp);
+	HLComp.CodStand  = Q931_CODING_ITU;	/* ITU */
+	HLComp.Interpret = 4;	/* only possible value */
+	HLComp.PresMeth  = 1;   /* High-layer protocol profile */
+	HLComp.HLCharID  = 1;	/* Telephony = 1, Fax G2+3 = 4, Fax G4 = 65 (Class I)/ 68 (Class II or III) */
+	gen->HLComp = Q931AppendIE((L3UCHAR *) gen, (L3UCHAR *) &HLComp);
+
+	caller_data->call_state = ZAP_CALLER_STATE_DIALING;
+	Q931Rx43(&isdn_data->q931, (L3UCHAR *) gen, gen->Size);
+	
+	isdn_data->outbound_crv[gen->CRV] = caller_data;
+	//isdn_data->channels_local_crv[gen->CRV] = zchan;
+
+	while(zap_running() && caller_data->call_state == ZAP_CALLER_STATE_DIALING) {
+		zap_sleep(1);
+		
+		if (!--sanity) {
+			caller_data->call_state = ZAP_CALLER_STATE_FAIL;
+			break;
+		}
+	}
+	isdn_data->outbound_crv[gen->CRV] = NULL;
+	
+	if (caller_data->call_state == ZAP_CALLER_STATE_SUCCESS) {
+		zap_channel_t *new_chan = NULL;
+		int fail = 1;
+		
+		new_chan = NULL;
+		if (caller_data->chan_id < ZAP_MAX_CHANNELS_SPAN && caller_data->chan_id <= span->chan_count) {
+			new_chan = span->channels[caller_data->chan_id];
+		}
+
+		if (new_chan && (status = zap_channel_open_chan(new_chan) == ZAP_SUCCESS)) {
+			if (zap_test_flag(new_chan, ZAP_CHANNEL_INUSE) || new_chan->state != ZAP_CHANNEL_STATE_DOWN) {
+				if (new_chan->state == ZAP_CHANNEL_STATE_DOWN || new_chan->state >= ZAP_CHANNEL_STATE_TERMINATING) {
+					int x = 0;
+					zap_log(ZAP_LOG_WARNING, "Channel %d:%d ~ %d:%d is already in use waiting for it to become available.\n");
+					
+					for (x = 0; x < 200; x++) {
+						if (!zap_test_flag(new_chan, ZAP_CHANNEL_INUSE)) {
+							break;
+						}
+						zap_sleep(5);
+					}
+				}
+				if (zap_test_flag(new_chan, ZAP_CHANNEL_INUSE)) {
+					zap_log(ZAP_LOG_ERROR, "Channel %d:%d ~ %d:%d is already in use.\n",
+							new_chan->span_id,
+							new_chan->chan_id,
+							new_chan->physical_span_id,
+							new_chan->physical_chan_id
+							);
+					new_chan = NULL;
+				}
+			}
+
+			if (new_chan && new_chan->state == ZAP_CHANNEL_STATE_DOWN) {
+				isdn_data->channels_local_crv[gen->CRV] = new_chan;
+				memset(&new_chan->caller_data, 0, sizeof(new_chan->caller_data));
+				zap_set_flag(new_chan, ZAP_CHANNEL_OUTBOUND);
+				zap_set_state_locked(new_chan, ZAP_CHANNEL_STATE_DIALING);
+				switch(gen->MesType) {
+				case Q931mes_ALERTING:
+					new_chan->init_state = ZAP_CHANNEL_STATE_PROGRESS_MEDIA;
+					break;
+				case Q931mes_CONNECT:
+					new_chan->init_state = ZAP_CHANNEL_STATE_UP;
+					break;
+				default:
+					new_chan->init_state = ZAP_CHANNEL_STATE_PROGRESS;
+					break;
+				}
+
+				fail = 0;
+			} 
+		}
+		
+		if (!fail) {
+			*zchan = new_chan;
+			return ZAP_SUCCESS;
+		} else {
+			Q931ie_Cause cause;
+			gen->MesType = Q931mes_DISCONNECT;
+			cause.IEId = Q931ie_CAUSE;
+			cause.Size = sizeof(Q931ie_Cause);
+			cause.CodStand  = 0;
+			cause.Location = 1;
+			cause.Recom = 1;
+			//should we be casting here.. or do we need to translate value?
+			cause.Value = (unsigned char) ZAP_CAUSE_WRONG_CALL_STATE;
+			*cause.Diag = '\0';
+			gen->Cause = Q931AppendIE((L3UCHAR *) gen, (L3UCHAR *) &cause);
+			Q931Rx43(&isdn_data->q931, (L3UCHAR *) gen, gen->Size);
+
+			if (gen->CRV) {
+				Q931ReleaseCRV(&isdn_data->q931, gen->CRV);
+			}
+			
+			if (new_chan) {
+				zap_log(ZAP_LOG_CRIT, "Channel is busy\n");
+			} else {
+				zap_log(ZAP_LOG_CRIT, "Failed to open channel for new setup message\n");
+			}
+		}
+	}
+	
+	*zchan = NULL;
+	return ZAP_FAIL;
+
+}
+
+/**
+ * \brief Handler for Q931 error
+ * \param pvt Private structure (span?)
+ * \param id Error number
+ * \param p1 ??
+ * \param p2 ??
+ * \return 0
+ */
+static L3INT zap_isdn_931_err(void *pvt, L3INT id, L3INT p1, L3INT p2)
+{
+	zap_log(ZAP_LOG_ERROR, "ERROR: [%s] [%d] [%d]\n", q931_error_to_name(id), p1, p2);
+	return 0;
+}
+
+/**
+ * \brief Handler for Q931 event message
+ * \param pvt Span to handle
+ * \param msg Message string
+ * \param mlen Message string length
+ * \return 0
+ */
+static L3INT zap_isdn_931_34(void *pvt, L2UCHAR *msg, L2INT mlen)
+{
+	zap_span_t *span = (zap_span_t *) pvt;
+	zap_isdn_data_t *isdn_data = span->signal_data;
+	Q931mes_Generic *gen = (Q931mes_Generic *) msg;
+	uint32_t chan_id = 0;
+	int chan_hunt = 0;
+	zap_channel_t *zchan = NULL;
+	zap_caller_data_t *caller_data = NULL;
+
+	if (Q931IsIEPresent(gen->ChanID)) {
+		Q931ie_ChanID *chanid = Q931GetIEPtr(gen->ChanID, gen->buf);
+
+		if(chanid->IntType)
+			chan_id = chanid->ChanSlot;
+		else
+			chan_id = chanid->InfoChanSel;
+
+		/* "any" channel specified */
+		if(chanid->InfoChanSel == 3) {
+			chan_hunt++;
+		}
+	} else if (ZAP_SPAN_IS_NT(span)) {
+		/* no channel ie */
+		chan_hunt++;
+	}
+
+	assert(span != NULL);
+	assert(isdn_data != NULL);
+	
+	zap_log(ZAP_LOG_DEBUG, "Yay I got an event! Type:[%02x] Size:[%d] CRV: %d (%#hx, CTX: %s)\n", gen->MesType, gen->Size, gen->CRV, gen->CRV, gen->CRVFlag ? "Terminator" : "Originator");
+
+	if (gen->CRVFlag && (caller_data = isdn_data->outbound_crv[gen->CRV])) {
+		if (chan_id) {
+			caller_data->chan_id = chan_id;
+		}
+
+		switch(gen->MesType) {
+		case Q931mes_STATUS:
+		case Q931mes_CALL_PROCEEDING:
+			break;
+		case Q931mes_ALERTING:
+		case Q931mes_PROGRESS:
+		case Q931mes_CONNECT:
+			{
+				caller_data->call_state = ZAP_CALLER_STATE_SUCCESS;
+			}
+			break;
+		default:
+			caller_data->call_state = ZAP_CALLER_STATE_FAIL;
+			break;
+		}
+	
+		return 0;
+	}
+
+	if (gen->CRVFlag) {
+		zchan = isdn_data->channels_local_crv[gen->CRV];
+	} else {
+		zchan = isdn_data->channels_remote_crv[gen->CRV];
+	}
+
+	zap_log(ZAP_LOG_DEBUG, "zchan %x (%d:%d) source isdn_data->channels_%s_crv[%#hx]\n", zchan, zchan ? zchan->span_id : -1, zchan ? zchan->chan_id : -1, gen->CRVFlag ? "local" : "remote", gen->CRV);
+
+
+	if (gen->ProtDisc == 3) {
+		switch(gen->MesType) {
+		case Q931mes_SERVICE:
+			{
+				Q931ie_ChangeStatus *changestatus = Q931GetIEPtr(gen->ChangeStatus, gen->buf);
+				if (zchan) {
+					switch (changestatus->NewStatus) {
+					case 0: /* change status to "in service" */
+						{
+							zap_clear_flag_locked(zchan, ZAP_CHANNEL_SUSPENDED);
+							zap_log(ZAP_LOG_DEBUG, "Channel %d:%d in service\n", zchan->span_id, zchan->chan_id);
+							zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_RESTART);
+						}
+						break;
+					case 1: 
+						{ /* change status to "maintenance" */
+							zap_set_flag_locked(zchan, ZAP_CHANNEL_SUSPENDED);
+							zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_SUSPENDED);
+						}
+						break;
+					case 2:
+						{ /* change status to "out of service" */
+							zap_set_flag_locked(zchan, ZAP_CHANNEL_SUSPENDED);
+							zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_SUSPENDED);
+						}
+						break;
+					default: /* unknown */
+						{
+							break;
+						}
+					}
+				}
+			}
+			break;
+		default:
+			break;
+		}
+	} else {
+		switch(gen->MesType) {
+		case Q931mes_RESTART:
+			{
+				if (chan_id) {
+					zchan = span->channels[chan_id];
+				}
+				if (zchan) {
+					zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_RESTART);
+				} else {
+					uint32_t i;
+					for (i = 1; i < span->chan_count; i++) {
+						zap_set_state_locked((span->channels[i]), ZAP_CHANNEL_STATE_RESTART);
+					}
+				}
+			}
+			break;
+		case Q931mes_RELEASE:
+		case Q931mes_RELEASE_COMPLETE:
+			{
+				const char *what = gen->MesType == Q931mes_RELEASE ? "Release" : "Release Complete";
+				if (zchan) {
+					if (zchan->state == ZAP_CHANNEL_STATE_TERMINATING || zchan->state == ZAP_CHANNEL_STATE_HANGUP) {
+						if (gen->MesType == Q931mes_RELEASE) {
+							zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_HANGUP_COMPLETE);
+						} else {
+							zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_DOWN);
+						}
+					}
+					else if((gen->MesType == Q931mes_RELEASE && zchan->state <= ZAP_CHANNEL_STATE_UP) ||
+						(gen->MesType == Q931mes_RELEASE_COMPLETE && zchan->state == ZAP_CHANNEL_STATE_DIALING)) {
+
+						/*
+						 * Don't keep inbound channels open if the remote side hangs up before we answered
+						 */
+						Q931ie_Cause *cause = Q931GetIEPtr(gen->Cause, gen->buf);
+						zap_sigmsg_t sig;
+						zap_status_t status;
+
+						memset(&sig, 0, sizeof(sig));
+						sig.chan_id = zchan->chan_id;
+						sig.span_id = zchan->span_id;
+						sig.channel = zchan;
+						sig.channel->caller_data.hangup_cause = (cause) ? cause->Value : ZAP_CAUSE_NORMAL_UNSPECIFIED;
+
+						sig.event_id = ZAP_SIGEVENT_STOP;
+						status = zap_span_send_signal(zchan->span, &sig);
+
+						zap_log(ZAP_LOG_DEBUG, "Received %s in state %s, requested hangup for channel %d:%d\n", what, zap_channel_state2str(zchan->state), zchan->span_id, chan_id);
+					}
+					else {
+						zap_log(ZAP_LOG_DEBUG, "Ignoring %s on channel %d\n", what, chan_id);
+					}
+				} else {
+					zap_log(ZAP_LOG_CRIT, "Received %s with no matching channel %d\n", what, chan_id);
+				}
+			}
+			break;
+		case Q931mes_DISCONNECT:
+			{
+				if (zchan) {
+					Q931ie_Cause *cause = Q931GetIEPtr(gen->Cause, gen->buf);
+					zchan->caller_data.hangup_cause = cause->Value;
+					zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_TERMINATING);
+				} else {
+					zap_log(ZAP_LOG_CRIT, "Received Disconnect with no matching channel %d\n", chan_id);
+				}
+			}
+			break;
+		case Q931mes_ALERTING:
+			{
+				if (zchan) {
+					zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_PROGRESS_MEDIA);
+				} else {
+					zap_log(ZAP_LOG_CRIT, "Received Alerting with no matching channel %d\n", chan_id);
+				}
+			}
+			break;
+		case Q931mes_PROGRESS:
+			{
+				if (zchan) {
+					zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_PROGRESS);
+				} else {
+					zap_log(ZAP_LOG_CRIT, "Received Progress with no matching channel %d\n", chan_id);
+				}
+			}
+			break;
+		case Q931mes_CONNECT:
+			{
+				if (zchan) {
+					zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_UP);
+
+					gen->MesType = Q931mes_CONNECT_ACKNOWLEDGE;
+					gen->CRVFlag = 0;	/* outbound */
+					Q931Rx43(&isdn_data->q931, (L3UCHAR *) gen, gen->Size);
+				} else {
+					zap_log(ZAP_LOG_CRIT, "Received Connect with no matching channel %d\n", chan_id);
+				}
+			}
+			break;
+		case Q931mes_SETUP:
+			{
+				Q931ie_CallingNum *callingnum = Q931GetIEPtr(gen->CallingNum, gen->buf);
+				Q931ie_CalledNum *callednum = Q931GetIEPtr(gen->CalledNum, gen->buf);
+				int fail = 1;
+				int fail_cause = 0;
+				int overlap_dial = 0;
+				uint32_t cplen = mlen;
+
+				if(zchan && zchan == isdn_data->channels_remote_crv[gen->CRV]) {
+					zap_log(ZAP_LOG_INFO, "Duplicate SETUP message(?) for Channel %d:%d ~ %d:%d in state %s [ignoring]\n",
+									zchan->span_id,
+									zchan->chan_id,
+									zchan->physical_span_id,
+									zchan->physical_chan_id,
+									zap_channel_state2str(zchan->state));
+					break;
+				}
+				
+				zchan = NULL;
+				/*
+				 * Channel selection for incoming calls:
+				 */
+				if (ZAP_SPAN_IS_NT(span) && chan_hunt) {
+					uint32_t x;
+
+					/*
+					 * In NT-mode with channel selection "any",
+					 * try to find a free channel
+					 */
+					for (x = 1; x <= span->chan_count; x++) {
+						zap_channel_t *zc = span->channels[x];
+
+						if (!zap_test_flag(zc, ZAP_CHANNEL_INUSE) && zc->state == ZAP_CHANNEL_STATE_DOWN) {
+							zchan = zc;
+							break;
+						}
+					}
+				}
+				else if (!ZAP_SPAN_IS_NT(span) && chan_hunt) {
+					/*
+					 * In TE-mode this ("any") is invalid
+					 */
+					fail_cause = ZAP_CAUSE_CHANNEL_UNACCEPTABLE;
+
+					zap_log(ZAP_LOG_ERROR, "Invalid channel selection in incoming call (network side didn't specify a channel)\n");
+				}
+				else {
+					/*
+					 * Otherwise simply try to select the channel we've been told
+					 *
+					 * TODO: NT mode is abled to select a different channel if the one chosen
+					 *       by the TE side is already in use
+					 */
+					if (chan_id > 0 && chan_id < ZAP_MAX_CHANNELS_SPAN && chan_id <= span->chan_count) {
+						zchan = span->channels[chan_id];
+					}
+					else {
+						/* invalid channel id */
+						fail_cause = ZAP_CAUSE_CHANNEL_UNACCEPTABLE;
+
+						zap_log(ZAP_LOG_ERROR, "Invalid channel selection in incoming call (none selected or out of bounds)\n");
+					}
+				}
+
+				if (!callednum || !strlen((char *)callednum->Digit)) {
+					if (ZAP_SPAN_IS_NT(span)) {
+						zap_log(ZAP_LOG_NOTICE, "No destination number found, assuming overlap dial\n");
+						overlap_dial++;
+					}
+					else {
+						zap_log(ZAP_LOG_ERROR, "No destination number found\n");
+						zchan = NULL;
+					}
+				}
+
+				if (zchan) {
+					if (zap_test_flag(zchan, ZAP_CHANNEL_INUSE) || zchan->state != ZAP_CHANNEL_STATE_DOWN) {
+						if (zchan->state == ZAP_CHANNEL_STATE_DOWN || zchan->state >= ZAP_CHANNEL_STATE_TERMINATING) {
+							int x = 0;
+							zap_log(ZAP_LOG_WARNING, "Channel %d:%d ~ %d:%d is already in use waiting for it to become available.\n",
+									zchan->span_id,
+									zchan->chan_id,
+									zchan->physical_span_id,
+									zchan->physical_chan_id);
+
+							for (x = 0; x < 200; x++) {
+								if (!zap_test_flag(zchan, ZAP_CHANNEL_INUSE)) {
+									break;
+								}
+								zap_sleep(5);
+							}
+						}
+						if (zap_test_flag(zchan, ZAP_CHANNEL_INUSE)) {
+							zap_log(ZAP_LOG_ERROR, "Channel %d:%d ~ %d:%d is already in use.\n",
+									zchan->span_id,
+									zchan->chan_id,
+									zchan->physical_span_id,
+									zchan->physical_chan_id
+									);
+							zchan = NULL;
+						}
+					}
+
+					if (zchan && zchan->state == ZAP_CHANNEL_STATE_DOWN) {
+						isdn_data->channels_remote_crv[gen->CRV] = zchan;
+						memset(&zchan->caller_data, 0, sizeof(zchan->caller_data));
+
+						if (zchan->mod_data) {
+							memset(zchan->mod_data, 0, sizeof(zap_isdn_bchan_data_t));
+						}
+
+						zap_set_string(zchan->caller_data.cid_num.digits, (char *)callingnum->Digit);
+						zap_set_string(zchan->caller_data.cid_name, (char *)callingnum->Digit);
+						zap_set_string(zchan->caller_data.ani.digits, (char *)callingnum->Digit);
+						if (!overlap_dial) {
+							zap_set_string(zchan->caller_data.dnis.digits, (char *)callednum->Digit);
+						}
+
+						zchan->caller_data.CRV = gen->CRV;
+						if (cplen > sizeof(zchan->caller_data.raw_data)) {
+							cplen = sizeof(zchan->caller_data.raw_data);
+						}
+						gen->CRVFlag = !(gen->CRVFlag);
+						memcpy(zchan->caller_data.raw_data, msg, cplen);
+						zchan->caller_data.raw_data_len = cplen;
+						fail = 0;
+					} 
+				} 
+
+				if (fail) {
+					Q931ie_Cause cause;
+					gen->MesType = Q931mes_DISCONNECT;
+					gen->CRVFlag = 1;	/* inbound call */
+					cause.IEId = Q931ie_CAUSE;
+					cause.Size = sizeof(Q931ie_Cause);
+					cause.CodStand = Q931_CODING_ITU;
+					cause.Location = 1;
+					cause.Recom = 1;
+					//should we be casting here.. or do we need to translate value?
+					cause.Value = (unsigned char)((fail_cause) ? fail_cause : ZAP_CAUSE_WRONG_CALL_STATE);
+					*cause.Diag = '\0';
+					gen->Cause = Q931AppendIE((L3UCHAR *) gen, (L3UCHAR *) &cause);
+					Q931Rx43(&isdn_data->q931, (L3UCHAR *) gen, gen->Size);
+
+					if (gen->CRV) {
+						Q931ReleaseCRV(&isdn_data->q931, gen->CRV);
+					}
+
+					if (zchan) {
+						zap_log(ZAP_LOG_CRIT, "Channel is busy\n");
+					} else {
+						zap_log(ZAP_LOG_CRIT, "Failed to open channel for new setup message\n");
+					}
+					
+				} else {
+					Q931ie_ChanID ChanID;
+
+					/*
+					 * Update Channel ID IE
+					 */
+					Q931InitIEChanID(&ChanID);
+					ChanID.IntType = ZAP_SPAN_IS_BRI(zchan->span) ? 0 : 1;	/* PRI = 1, BRI = 0 */
+					ChanID.PrefExcl = ZAP_SPAN_IS_NT(zchan->span) ? 1 : 0;  /* Exclusive in NT-mode = 1, Preferred otherwise = 0 */
+					if(ChanID.IntType) {
+						ChanID.InfoChanSel = 1;		/* None = 0, See Slot = 1, Any = 3 */
+						ChanID.ChanMapType = 3;		/* B-Chan */
+						ChanID.ChanSlot = (unsigned char)zchan->chan_id;
+					} else {
+						ChanID.InfoChanSel = (unsigned char)zchan->chan_id & 0x03;	/* None = 0, B1 = 1, B2 = 2, Any = 3 */
+					}
+					gen->ChanID = Q931AppendIE((L3UCHAR *) gen, (L3UCHAR *) &ChanID);
+
+					if (overlap_dial) {
+						Q931ie_ProgInd progress;
+
+						/*
+						 * Setup Progress indicator
+						 */
+						progress.IEId = Q931ie_PROGRESS_INDICATOR;
+						progress.Size = sizeof(Q931ie_ProgInd);
+						progress.CodStand = Q931_CODING_ITU;	/* ITU */ 
+						progress.Location = 1;	/* private network serving the local user */
+						progress.ProgDesc = 8;	/* call is not end-to-end isdn = 1, in-band information available = 8 */
+						gen->ProgInd = Q931AppendIE((L3UCHAR *) gen, (L3UCHAR *) &progress);
+
+						/*
+						 * Send SETUP ACK
+						 */
+						gen->MesType = Q931mes_SETUP_ACKNOWLEDGE;
+						gen->CRVFlag = 1;	/* inbound call */
+						Q931Rx43(&isdn_data->q931, (L3UCHAR *) gen, gen->Size);
+
+						zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_DIALTONE);
+					} else {
+						/*
+						 * Advance to RING state
+						 */
+						zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_RING);
+					}
+				}
+			}
+			break;
+
+		case Q931mes_CALL_PROCEEDING:
+			{
+				if (zchan) {
+					zap_log(ZAP_LOG_CRIT, "Received CALL PROCEEDING message for channel %d\n", chan_id);
+					zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_PROGRESS);
+				} else {
+					zap_log(ZAP_LOG_CRIT, "Received CALL PROCEEDING with no matching channel %d\n", chan_id);
+				}
+			}
+			break;
+		case Q931mes_CONNECT_ACKNOWLEDGE:
+			{
+				if (zchan) {
+					zap_log(ZAP_LOG_DEBUG, "Received CONNECT_ACK message for channel %d\n", chan_id);
+				} else {
+					zap_log(ZAP_LOG_DEBUG, "Received CONNECT_ACK with no matching channel %d\n", chan_id);
+				}
+			}
+			break;
+
+		case Q931mes_INFORMATION:
+			{
+				if (zchan) {
+					zap_log(ZAP_LOG_CRIT, "Received INFORMATION message for channel %d\n", zchan->chan_id);
+
+					if (zchan->state == ZAP_CHANNEL_STATE_DIALTONE) {
+						char digit = '\0';
+
+						/*
+						 * overlap dial digit indication
+						 */
+						if (Q931IsIEPresent(gen->CalledNum)) {
+							zap_isdn_bchan_data_t *data = (zap_isdn_bchan_data_t *)zchan->mod_data;
+							Q931ie_CalledNum *callednum = Q931GetIEPtr(gen->CalledNum, gen->buf);
+							int pos;
+
+							digit = callednum->Digit[strlen((char *)callednum->Digit) - 1];
+							if (digit == '#') {
+								callednum->Digit[strlen((char *)callednum->Digit) - 1] = '\0';
+							}
+
+							/* TODO: make this more safe with strncat() */
+							pos = (int)strlen(zchan->caller_data.dnis.digits);
+							strcat(&zchan->caller_data.dnis.digits[pos],    (char *)callednum->Digit);
+
+							/* update timer */
+							data->digit_timeout = zap_time_now() + isdn_data->digit_timeout;
+
+							zap_log(ZAP_LOG_DEBUG, "Received new overlap digit (%s), destination number: %s\n", callednum->Digit, zchan->caller_data.dnis.digits);
+						}
+
+						if (Q931IsIEPresent(gen->SendComplete) || digit == '#') {
+							zap_log(ZAP_LOG_DEBUG, "Leaving overlap dial mode\n");
+
+							zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_RING);
+						}
+					}
+				} else {
+					zap_log(ZAP_LOG_CRIT, "Received INFORMATION message with no matching channel\n");
+				}
+			}
+			break;
+
+		case Q931mes_STATUS_ENQUIRY:
+			{
+				/*
+				 * !! HACK ALERT !!
+				 *
+				 * Map OpenZAP channel states to Q.931 states
+				 */
+				Q931ie_CallState state;
+				Q931ie_Cause cause;
+
+				gen->MesType = Q931mes_STATUS;
+				gen->CRVFlag = gen->CRVFlag ? 0 : 1;
+
+				state.CodStand  = Q931_CODING_ITU;	/* ITU-T */
+				state.CallState = Q931_U0;		/* Default: Null */
+
+				cause.IEId = Q931ie_CAUSE;
+				cause.Size = sizeof(Q931ie_Cause);
+				cause.CodStand = Q931_CODING_ITU;	/* ITU */
+				cause.Location = 1;	/* private network */
+				cause.Recom    = 1;	/* */
+				*cause.Diag    = '\0';
+
+				if(zchan) {
+					switch(zchan->state) {
+					case ZAP_CHANNEL_STATE_UP:
+						state.CallState = Q931_U10;	/* Active */
+						break;
+					case ZAP_CHANNEL_STATE_RING:
+						state.CallState = Q931_U6;	/* Call present */
+						break;
+					case ZAP_CHANNEL_STATE_DIALING:
+						state.CallState = Q931_U1;	/* Call initiated */
+						break;
+					case ZAP_CHANNEL_STATE_DIALTONE:
+						state.CallState = Q931_U25;	/* Overlap receiving */
+						break;
+
+					/* TODO: map missing states */
+
+					default:
+						state.CallState = Q931_U0;
+					}
+
+					cause.Value = 30;	/* response to STATUS ENQUIRY */
+				} else {
+					cause.Value = 98;	/* */
+				}
+
+				gen->CallState = Q931AppendIE((L3UCHAR *) gen, (L3UCHAR *) &state);
+				gen->Cause     = Q931AppendIE((L3UCHAR *) gen, (L3UCHAR *) &cause);
+				Q931Rx43(&isdn_data->q931, (L3UCHAR *) gen, gen->Size);
+			}
+			break;
+
+		default:
+			zap_log(ZAP_LOG_CRIT, "Received unhandled message %d (%#x)\n", (int)gen->MesType, (int)gen->MesType);
+			break;
+		}
+	}
+
+	return 0;
+}
+
+/**
+ * \brief Handler for Q921 read event
+ * \param pvt Span were message is coming from
+ * \param ind Q921 indication
+ * \param tei Terminal Endpoint Identifier
+ * \param msg Message string
+ * \param mlen Message string length
+ * \return 0 on success, 1 on failure
+ */
+static int zap_isdn_921_23(void *pvt, Q921DLMsg_t ind, L2UCHAR tei, L2UCHAR *msg, L2INT mlen)
+{
+	int ret, offset = (ind == Q921_DL_DATA) ? 4 : 3;
+	char bb[4096] = "";
+
+	switch(ind) {
+	case Q921_DL_DATA:
+	case Q921_DL_UNIT_DATA:
+		print_hex_bytes(msg + offset, mlen - offset, bb, sizeof(bb));
+#ifdef HAVE_LIBPCAP
+		/*Q931ToPcap*/
+                if(do_q931ToPcap==1){
+			zap_span_t *span = (zap_span_t *) pvt;
+                        if(writeQ931PacketToPcap(msg + offset, mlen - offset, span->span_id, 1) != ZAP_SUCCESS){
+                                zap_log(ZAP_LOG_WARNING, "Couldn't write Q931 buffer to pcap file!\n");
+                        }
+                }
+                /*Q931ToPcap done*/
+#endif
+		zap_log(ZAP_LOG_DEBUG, "READ %d\n%s\n%s\n\n\n", (int)mlen - offset, LINE, bb);
+	
+	default:
+		ret = Q931Rx23(pvt, ind, tei, msg, mlen);
+		if (ret != 0)
+			zap_log(ZAP_LOG_DEBUG, "931 parse error [%d] [%s]\n", ret, q931_error_to_name(ret));
+		break;
+	}
+
+	return ((ret >= 0) ? 1 : 0);
+}
+
+/**
+ * \brief Handler for Q921 write event
+ * \param pvt Span were message is coming from
+ * \param msg Message string
+ * \param mlen Message string length
+ * \return 0 on success, -1 on failure
+ */
+static int zap_isdn_921_21(void *pvt, L2UCHAR *msg, L2INT mlen)
+{
+	zap_span_t *span = (zap_span_t *) pvt;
+	zap_size_t len = (zap_size_t) mlen;
+	zap_isdn_data_t *isdn_data = span->signal_data;
+
+#ifdef IODEBUG
+	char bb[4096] = "";
+	print_hex_bytes(msg, len, bb, sizeof(bb));
+	print_bits(msg, (int)len, bb, sizeof(bb), ZAP_ENDIAN_LITTLE, 0);
+	zap_log(ZAP_LOG_DEBUG, "WRITE %d\n%s\n%s\n\n", (int)len, LINE, bb);
+
+#endif
+
+	assert(span != NULL);
+	return zap_channel_write(isdn_data->dchan, msg, len, &len) == ZAP_SUCCESS ? 0 : -1;
+}
+
+/**
+ * \brief Handler for channel state change
+ * \param zchan Channel to handle
+ */
+static __inline__ void state_advance(zap_channel_t *zchan)
+{
+	Q931mes_Generic *gen = (Q931mes_Generic *) zchan->caller_data.raw_data;
+	zap_isdn_data_t *isdn_data = zchan->span->signal_data;
+	zap_sigmsg_t sig;
+	zap_status_t status;
+
+	zap_log(ZAP_LOG_DEBUG, "%d:%d STATE [%s]\n", 
+			zchan->span_id, zchan->chan_id, zap_channel_state2str(zchan->state));
+
+	memset(&sig, 0, sizeof(sig));
+	sig.chan_id = zchan->chan_id;
+	sig.span_id = zchan->span_id;
+	sig.channel = zchan;
+
+	switch (zchan->state) {
+	case ZAP_CHANNEL_STATE_DOWN:
+		{
+			if (gen->CRV) {
+				if (zap_test_flag(zchan, ZAP_CHANNEL_OUTBOUND)) {
+					isdn_data->channels_local_crv[gen->CRV] = NULL;
+				} else {
+					isdn_data->channels_remote_crv[gen->CRV] = NULL;
+				}
+				Q931ReleaseCRV(&isdn_data->q931, gen->CRV);
+			}
+			zap_channel_done(zchan);
+		}
+		break;
+	case ZAP_CHANNEL_STATE_PROGRESS:
+		{
+			if (zap_test_flag(zchan, ZAP_CHANNEL_OUTBOUND)) {
+				sig.event_id = ZAP_SIGEVENT_PROGRESS;
+				if ((status = zap_span_send_signal(zchan->span, &sig) != ZAP_SUCCESS)) {
+					zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_HANGUP);
+				}
+			} else {
+				gen->MesType = Q931mes_CALL_PROCEEDING;
+				gen->CRVFlag = 1;	/* inbound */
+
+				if (ZAP_SPAN_IS_NT(zchan->span)) {
+					Q931ie_ChanID ChanID;
+
+					/*
+					 * Set new Channel ID
+					 */
+					Q931InitIEChanID(&ChanID);
+					ChanID.IntType = ZAP_SPAN_IS_BRI(zchan->span) ? 0 : 1;		/* PRI = 1, BRI = 0 */
+					ChanID.PrefExcl = 1;	/* always exclusive in NT-mode */
+
+					if(ChanID.IntType) {
+						ChanID.InfoChanSel = 1;		/* None = 0, See Slot = 1, Any = 3 */
+						ChanID.ChanMapType = 3; 	/* B-Chan */
+						ChanID.ChanSlot = (unsigned char)zchan->chan_id;
+					} else {
+						ChanID.InfoChanSel = (unsigned char)zchan->chan_id & 0x03;	/* None = 0, B1 = 1, B2 = 2, Any = 3 */
+					}
+					gen->ChanID = Q931AppendIE((L3UCHAR *) gen, (L3UCHAR *) &ChanID);
+				}
+
+				Q931Rx43(&isdn_data->q931, (void *)gen, gen->Size);
+			}
+		}
+		break;
+	case ZAP_CHANNEL_STATE_DIALTONE:
+		{
+			zap_isdn_bchan_data_t *data = (zap_isdn_bchan_data_t *)zchan->mod_data;
+
+			if (data) {
+				data->digit_timeout = zap_time_now() + isdn_data->digit_timeout;
+			}
+		}
+		break;
+	case ZAP_CHANNEL_STATE_RING:
+		{
+			if (!zap_test_flag(zchan, ZAP_CHANNEL_OUTBOUND)) {
+				sig.event_id = ZAP_SIGEVENT_START;
+				if ((status = zap_span_send_signal(zchan->span, &sig) != ZAP_SUCCESS)) {
+					zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_HANGUP);
+				}
+			}
+		}
+		break;
+	case ZAP_CHANNEL_STATE_RESTART:
+		{
+			zchan->caller_data.hangup_cause = ZAP_CAUSE_NORMAL_UNSPECIFIED;
+			sig.event_id = ZAP_SIGEVENT_RESTART;
+			status = zap_span_send_signal(zchan->span, &sig);
+			zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_DOWN);
+		}
+		break;
+	case ZAP_CHANNEL_STATE_PROGRESS_MEDIA:
+		{
+			if (zap_test_flag(zchan, ZAP_CHANNEL_OUTBOUND)) {
+				sig.event_id = ZAP_SIGEVENT_PROGRESS_MEDIA;
+				if ((status = zap_span_send_signal(zchan->span, &sig) != ZAP_SUCCESS)) {
+					zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_HANGUP);
+				}
+			} else {
+				if (!zap_test_flag(zchan, ZAP_CHANNEL_OPEN)) {
+					if (zap_channel_open_chan(zchan) != ZAP_SUCCESS) {
+						zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_HANGUP);
+						return;
+					}
+				}
+				gen->MesType = Q931mes_ALERTING;
+				gen->CRVFlag = 1;	/* inbound call */
+				Q931Rx43(&isdn_data->q931, (void *)gen, gen->Size);
+			}
+		}
+		break;
+	case ZAP_CHANNEL_STATE_UP:
+		{
+			if (zap_test_flag(zchan, ZAP_CHANNEL_OUTBOUND)) {
+				sig.event_id = ZAP_SIGEVENT_UP;
+				if ((status = zap_span_send_signal(zchan->span, &sig) != ZAP_SUCCESS)) {
+					zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_HANGUP);
+				}
+			} else {
+				if (!zap_test_flag(zchan, ZAP_CHANNEL_OPEN)) {
+					if (zap_channel_open_chan(zchan) != ZAP_SUCCESS) {
+						zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_HANGUP);
+						return;
+					}
+				}
+				gen->MesType = Q931mes_CONNECT;
+				gen->BearerCap = 0;
+				gen->CRVFlag = 1;	/* inbound call */
+				Q931Rx43(&isdn_data->q931, (void *)gen, zchan->caller_data.raw_data_len);
+			}
+		}
+		break;
+	case ZAP_CHANNEL_STATE_DIALING:
+		if (!(isdn_data->opts & ZAP_ISDN_OPT_SUGGEST_CHANNEL)) {
+			Q931ie_BearerCap BearerCap;
+			Q931ie_ChanID ChanID;
+			Q931ie_CallingNum CallingNum;
+			Q931ie_CallingNum *ptrCallingNum;
+			Q931ie_CalledNum CalledNum;
+			Q931ie_CalledNum *ptrCalledNum;
+			Q931ie_Display Display, *ptrDisplay;
+			Q931ie_HLComp HLComp;			/* High-Layer Compatibility IE */
+			Q931ie_ProgInd Progress;		/* Progress Indicator IE */
+			int codec  = 0;
+
+			/*
+			 * get codec type
+			 */
+			zap_channel_command(zchan->span->channels[zchan->chan_id], ZAP_COMMAND_GET_NATIVE_CODEC, &codec);
+
+			/*
+			 * Q.931 Setup Message
+			 */ 
+			Q931InitMesGeneric(gen);
+			gen->MesType = Q931mes_SETUP;
+			gen->CRVFlag = 0;		/* outbound(?) */
+
+			/*
+			 * Bearer Capability IE
+			 */
+			Q931InitIEBearerCap(&BearerCap);
+			BearerCap.CodStand  = Q931_CODING_ITU;	/* ITU-T = 0, ISO/IEC = 1, National = 2, Network = 3 */
+			BearerCap.ITC       = Q931_ITC_SPEECH;	/* Speech */
+			BearerCap.TransMode = 0;		/* Circuit = 0, Packet = 1 */
+			BearerCap.ITR       = Q931_ITR_64K;	/* 64k = 16, Packet mode = 0 */
+			BearerCap.Layer1Ident = 1;
+			BearerCap.UIL1Prot = (codec == ZAP_CODEC_ALAW) ? 3 : 2;	/* U-law = 2, A-law = 3 */
+			gen->BearerCap = Q931AppendIE((L3UCHAR *) gen, (L3UCHAR *) &BearerCap);
+
+			/*
+			 * ChannelID IE
+			 */
+			Q931InitIEChanID(&ChanID);
+			ChanID.IntType = ZAP_SPAN_IS_BRI(zchan->span) ? 0 : 1;	/* PRI = 1, BRI = 0 */
+			ChanID.PrefExcl = ZAP_SPAN_IS_NT(zchan->span) ? 1 : 0;  /* Exclusive in NT-mode = 1, Preferred otherwise = 0 */
+			if(ChanID.IntType) {
+				ChanID.InfoChanSel = 1;		/* None = 0, See Slot = 1, Any = 3 */
+				ChanID.ChanMapType = 3;		/* B-Chan */
+				ChanID.ChanSlot = (unsigned char)zchan->chan_id;
+			} else {
+				ChanID.InfoChanSel = (unsigned char)zchan->chan_id & 0x03;	/* None = 0, B1 = 1, B2 = 2, Any = 3 */
+			}
+			gen->ChanID = Q931AppendIE((L3UCHAR *) gen, (L3UCHAR *) &ChanID);
+
+			/*
+			 * Progress IE
+			 */
+			Q931InitIEProgInd(&Progress);
+			Progress.CodStand = Q931_CODING_ITU;	/* 0 = ITU */
+			Progress.Location = 0;  /* 0 = User, 1 = Private Network */
+			Progress.ProgDesc = 3;	/* 1 = Not end-to-end ISDN */
+			gen->ProgInd = Q931AppendIE((L3UCHAR *)gen, (L3UCHAR *)&Progress);
+
+			/*
+			 * Display IE
+			 */
+			if (!(isdn_data->opts & ZAP_ISDN_OPT_OMIT_DISPLAY_IE)) {
+				Q931InitIEDisplay(&Display);
+				Display.Size = Display.Size + (unsigned char)strlen(zchan->caller_data.cid_name);
+				gen->Display = Q931AppendIE((L3UCHAR *) gen, (L3UCHAR *) &Display);
+				ptrDisplay = Q931GetIEPtr(gen->Display, gen->buf);
+				zap_copy_string((char *)ptrDisplay->Display, zchan->caller_data.cid_name, strlen(zchan->caller_data.cid_name)+1);
+			}
+
+			/*
+			 * CallingNum IE
+			 */ 
+			Q931InitIECallingNum(&CallingNum);
+			CallingNum.TypNum    = zchan->caller_data.ani.type;
+			CallingNum.NumPlanID = Q931_NUMPLAN_E164;
+			CallingNum.PresInd   = Q931_PRES_ALLOWED;
+			CallingNum.ScreenInd = Q931_SCREEN_USER_NOT_SCREENED;
+			CallingNum.Size = CallingNum.Size + (unsigned char)strlen(zchan->caller_data.cid_num.digits);
+			gen->CallingNum = Q931AppendIE((L3UCHAR *) gen, (L3UCHAR *) &CallingNum);
+			ptrCallingNum = Q931GetIEPtr(gen->CallingNum, gen->buf);
+			zap_copy_string((char *)ptrCallingNum->Digit, zchan->caller_data.cid_num.digits, strlen(zchan->caller_data.cid_num.digits)+1);
+
+			/*
+			 * CalledNum IE
+			 */
+			Q931InitIECalledNum(&CalledNum);
+			CalledNum.TypNum    = Q931_TON_UNKNOWN;
+			CalledNum.NumPlanID = Q931_NUMPLAN_E164;
+			CalledNum.Size = CalledNum.Size + (unsigned char)strlen(zchan->caller_data.ani.digits);
+			gen->CalledNum = Q931AppendIE((L3UCHAR *) gen, (L3UCHAR *) &CalledNum);
+			ptrCalledNum = Q931GetIEPtr(gen->CalledNum, gen->buf);
+			zap_copy_string((char *)ptrCalledNum->Digit, zchan->caller_data.ani.digits, strlen(zchan->caller_data.ani.digits)+1);
+
+			/*
+			 * High-Layer Compatibility IE   (Note: Required for AVM FritzBox)
+			 */
+			Q931InitIEHLComp(&HLComp);
+			HLComp.CodStand  = Q931_CODING_ITU;	/* ITU */
+			HLComp.Interpret = 4;	/* only possible value */
+			HLComp.PresMeth  = 1;   /* High-layer protocol profile */
+			HLComp.HLCharID  = Q931_HLCHAR_TELEPHONY;	/* Telephony = 1, Fax G2+3 = 4, Fax G4 = 65 (Class I)/ 68 (Class II or III) */   /* TODO: make accessible from user layer */
+			gen->HLComp = Q931AppendIE((L3UCHAR *) gen, (L3UCHAR *) &HLComp);
+
+			Q931Rx43(&isdn_data->q931, (L3UCHAR *) gen, gen->Size);
+			isdn_data->channels_local_crv[gen->CRV] = zchan;
+		}
+		break;
+	case ZAP_CHANNEL_STATE_HANGUP_COMPLETE:
+		{
+			/* reply RELEASE with RELEASE_COMPLETE message */
+			if(zchan->last_state == ZAP_CHANNEL_STATE_HANGUP) {
+				gen->MesType = Q931mes_RELEASE_COMPLETE;
+
+				Q931Rx43(&isdn_data->q931, (L3UCHAR *) gen, gen->Size);
+			}
+			zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_DOWN);
+		}
+		break;
+	case ZAP_CHANNEL_STATE_HANGUP:
+		{
+			Q931ie_Cause cause;
+
+			zap_log(ZAP_LOG_DEBUG, "Hangup: Direction %s\n", zap_test_flag(zchan, ZAP_CHANNEL_OUTBOUND) ? "Outbound" : "Inbound");
+
+			gen->CRVFlag = zap_test_flag(zchan, ZAP_CHANNEL_OUTBOUND) ? 0 : 1;
+
+			cause.IEId = Q931ie_CAUSE;
+			cause.Size = sizeof(Q931ie_Cause);
+			cause.CodStand = Q931_CODING_ITU;	/* ITU */
+			cause.Location = 1;	/* private network */
+			cause.Recom    = 1;	/* */
+
+			/*
+			 * BRI PTMP needs special handling here...
+			 * TODO: cleanup / refine (see above)
+			 */
+			if (zchan->last_state == ZAP_CHANNEL_STATE_RING) {
+				/*
+				 * inbound call [was: number unknown (= not found in routing state)]
+				 * (in Q.931 spec terms: Reject request)
+				 */
+				gen->MesType = Q931mes_RELEASE_COMPLETE;
+
+				//cause.Value = (unsigned char) ZAP_CAUSE_UNALLOCATED;
+				cause.Value = (unsigned char) zchan->caller_data.hangup_cause;
+				*cause.Diag = '\0';
+				gen->Cause = Q931AppendIE((L3UCHAR *) gen, (L3UCHAR *) &cause);
+				Q931Rx43(&isdn_data->q931, (L3UCHAR *) gen, gen->Size);
+
+				/* we're done, release channel */
+				//zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_HANGUP_COMPLETE);
+				zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_DOWN);
+			}
+			else if (zchan->last_state <= ZAP_CHANNEL_STATE_PROGRESS) {
+				/*
+				 * just release all unanswered calls [was: inbound call, remote side hung up before we answered]
+				 */
+				gen->MesType = Q931mes_RELEASE;
+
+				cause.Value = (unsigned char) zchan->caller_data.hangup_cause;
+				*cause.Diag = '\0';
+				gen->Cause = Q931AppendIE((L3UCHAR *) gen, (L3UCHAR *) &cause);
+				Q931Rx43(&isdn_data->q931, (void *)gen, gen->Size);
+
+				/* this will be triggered by the RELEASE_COMPLETE reply */
+				/* zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_HANGUP_COMPLETE); */
+			}
+			else {
+				/*
+				 * call connected, hangup
+				 */
+				gen->MesType = Q931mes_DISCONNECT;
+
+				cause.Value = (unsigned char) zchan->caller_data.hangup_cause;
+				*cause.Diag = '\0';
+				gen->Cause = Q931AppendIE((L3UCHAR *) gen, (L3UCHAR *) &cause);
+				Q931Rx43(&isdn_data->q931, (L3UCHAR *) gen, gen->Size);
+			}
+		}
+		break;
+	case ZAP_CHANNEL_STATE_TERMINATING:
+		{
+			zap_log(ZAP_LOG_DEBUG, "Terminating: Direction %s\n", zap_test_flag(zchan, ZAP_CHANNEL_OUTBOUND) ? "Outbound" : "Inbound");
+
+			sig.event_id = ZAP_SIGEVENT_STOP;
+			status = zap_span_send_signal(zchan->span, &sig);
+			gen->MesType = Q931mes_RELEASE;
+			gen->CRVFlag = zap_test_flag(zchan, ZAP_CHANNEL_OUTBOUND) ? 0 : 1;
+			Q931Rx43(&isdn_data->q931, (void *)gen, gen->Size);
+		}
+	default:
+		break;
+	}
+}
+
+/**
+ * \brief Checks current state on a span
+ * \param span Span to check status on
+ */
+static __inline__ void check_state(zap_span_t *span)
+{
+    if (zap_test_flag(span, ZAP_SPAN_STATE_CHANGE)) {
+        uint32_t j;
+        zap_clear_flag_locked(span, ZAP_SPAN_STATE_CHANGE);
+        for(j = 1; j <= span->chan_count; j++) {
+            if (zap_test_flag((span->channels[j]), ZAP_CHANNEL_STATE_CHANGE)) {
+				zap_mutex_lock(span->channels[j]->mutex);
+                zap_clear_flag((span->channels[j]), ZAP_CHANNEL_STATE_CHANGE);
+                state_advance(span->channels[j]);
+                zap_channel_complete_state(span->channels[j]);
+				zap_mutex_unlock(span->channels[j]->mutex);
+            }
+        }
+    }
+}
+
+/**
+ * \brief Processes Openzap event on a span
+ * \param span Span to process event on
+ * \param event Event to process
+ * \return Success or failure
+ */
+static __inline__ zap_status_t process_event(zap_span_t *span, zap_event_t *event)
+{
+	zap_log(ZAP_LOG_DEBUG, "EVENT [%s][%d:%d] STATE [%s]\n", 
+			zap_oob_event2str(event->enum_id), event->channel->span_id, event->channel->chan_id, zap_channel_state2str(event->channel->state));
+
+	switch(event->enum_id) {
+	case ZAP_OOB_ALARM_TRAP:
+		{
+			if (event->channel->state != ZAP_CHANNEL_STATE_DOWN) {
+				if (event->channel->type == ZAP_CHAN_TYPE_B) {
+					zap_set_state_locked(event->channel, ZAP_CHANNEL_STATE_RESTART);
+				}
+			}
+			
+
+			zap_set_flag(event->channel, ZAP_CHANNEL_SUSPENDED);
+
+			
+			zap_channel_get_alarms(event->channel);
+			zap_log(ZAP_LOG_WARNING, "channel %d:%d (%d:%d) has alarms! [%s]\n", 
+					event->channel->span_id, event->channel->chan_id, 
+					event->channel->physical_span_id, event->channel->physical_chan_id, 
+					event->channel->last_error);
+		}
+		break;
+	case ZAP_OOB_ALARM_CLEAR:
+		{
+			
+			zap_log(ZAP_LOG_WARNING, "channel %d:%d (%d:%d) alarms Cleared!\n", event->channel->span_id, event->channel->chan_id,
+					event->channel->physical_span_id, event->channel->physical_chan_id);
+
+			zap_clear_flag(event->channel, ZAP_CHANNEL_SUSPENDED);
+			zap_channel_get_alarms(event->channel);
+		}
+		break;
+	}
+
+	return ZAP_SUCCESS;
+}
+
+/**
+ * \brief Checks for events on a span
+ * \param span Span to check for events
+ */
+static __inline__ void check_events(zap_span_t *span)
+{
+	zap_status_t status;
+
+	status = zap_span_poll_event(span, 5);
+
+	switch(status) {
+	case ZAP_SUCCESS:
+		{
+			zap_event_t *event;
+			while (zap_span_next_event(span, &event) == ZAP_SUCCESS) {
+				if (event->enum_id == ZAP_OOB_NOOP) {
+					continue;
+				}
+				if (process_event(span, event) != ZAP_SUCCESS) {
+					break;
+				}
+			}
+		}
+		break;
+	case ZAP_FAIL:
+		{
+			zap_log(ZAP_LOG_DEBUG, "Event Failure! %d\n", zap_running());
+		}
+		break;
+	default:
+		break;
+	}
+}
+
+/**
+ * \brief Retrieves tone generation output to be sent
+ * \param ts Teletone generator
+ * \param map Tone map
+ * \return -1 on error, 0 on success
+ */
+static int teletone_handler(teletone_generation_session_t *ts, teletone_tone_map_t *map)
+{
+	zap_buffer_t *dt_buffer = ts->user_data;
+	int wrote;
+
+	if (!dt_buffer) {
+		return -1;
+	}
+	wrote = teletone_mux_tones(ts, map);
+	zap_buffer_write(dt_buffer, ts->buffer, wrote * 2);
+	return 0;
+}
+
+/**
+ * \brief Main thread function for tone generation on a span
+ * \param me Current thread
+ * \param obj Span to generate tones on
+ */
+static void *zap_isdn_tones_run(zap_thread_t *me, void *obj)
+{
+	zap_span_t *span = (zap_span_t *) obj;
+	zap_isdn_data_t *isdn_data = span->signal_data;
+	zap_buffer_t *dt_buffer = NULL;
+	teletone_generation_session_t ts = {{{{0}}}};
+	unsigned char frame[1024];
+	uint32_t x;
+	int interval = 0;
+	int offset = 0;
+
+	zap_log(ZAP_LOG_DEBUG, "ISDN tones thread starting.\n");
+	zap_set_flag(isdn_data, ZAP_ISDN_TONES_RUNNING);
+
+	if (zap_buffer_create(&dt_buffer, 1024, 1024, 0) != ZAP_SUCCESS) {
+		snprintf(isdn_data->dchan->last_error, sizeof(isdn_data->dchan->last_error), "memory error!");
+		zap_log(ZAP_LOG_ERROR, "MEM ERROR\n");
+		goto done;
+	}
+	zap_buffer_set_loops(dt_buffer, -1);
+
+	/* get a tone generation friendly interval to avoid distortions */
+	for (x = 1; x <= span->chan_count; x++) {
+		if (span->channels[x]->type != ZAP_CHAN_TYPE_DQ921) {
+			zap_channel_command(span->channels[x], ZAP_COMMAND_GET_INTERVAL, &interval);
+			break;
+		}
+	}
+	if (!interval) {
+		interval = 20;
+	}
+	zap_log(ZAP_LOG_NOTICE, "Tone generating interval %d\n", interval);
+
+	/* init teletone */
+	teletone_init_session(&ts, 0, teletone_handler, dt_buffer);
+	ts.rate     = 8000;
+	ts.duration = ts.rate;
+
+	/* main loop */
+	while(zap_running() && zap_test_flag(isdn_data, ZAP_ISDN_TONES_RUNNING) && !zap_test_flag(isdn_data, ZAP_ISDN_STOP)) {
+		zap_wait_flag_t flags;
+		zap_status_t status;
+		int last_chan_state = 0;
+		int gated = 0;
+		L2ULONG now = zap_time_now();
+
+		/*
+		 * check b-channel states and generate & send tones if neccessary
+		 */
+		for (x = 1; x <= span->chan_count; x++) {
+			zap_channel_t *zchan = span->channels[x];
+			zap_size_t len = sizeof(frame), rlen;
+
+			if (zchan->type == ZAP_CHAN_TYPE_DQ921) {
+				continue;
+			}
+
+			/*
+			 * Generate tones based on current bchan state
+			 * (Recycle buffer content if succeeding channels share the
+			 *  same state, this saves some cpu cycles)
+			 */
+			switch (zchan->state) {
+			case ZAP_CHANNEL_STATE_DIALTONE:
+				{
+					zap_isdn_bchan_data_t *data = (zap_isdn_bchan_data_t *)zchan->mod_data;
+
+					/* check overlap dial timeout first before generating tone */
+					if (data && data->digit_timeout && data->digit_timeout <= now) {
+						if (strlen(zchan->caller_data.dnis.digits) > 0) {
+							zap_log(ZAP_LOG_DEBUG, "Overlap dial timeout, advancing to RING state\n");
+							zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_RING);
+						} else {
+							/* no digits received, hangup */
+							zap_log(ZAP_LOG_DEBUG, "Overlap dial timeout, no digits received, going to HANGUP state\n");
+							zchan->caller_data.hangup_cause = ZAP_CAUSE_RECOVERY_ON_TIMER_EXPIRE;	/* TODO: probably wrong cause value */
+							zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_HANGUP);
+						}
+						data->digit_timeout = 0;
+						continue;
+					}
+
+					if (last_chan_state != zchan->state) {
+						zap_buffer_zero(dt_buffer);
+						teletone_run(&ts, zchan->span->tone_map[ZAP_TONEMAP_DIAL]);
+						last_chan_state = zchan->state;
+					}
+				}
+				break;
+
+			case ZAP_CHANNEL_STATE_RING:
+				{
+					if (last_chan_state != zchan->state) {
+						zap_buffer_zero(dt_buffer);
+						teletone_run(&ts, zchan->span->tone_map[ZAP_TONEMAP_RING]);
+						last_chan_state = zchan->state;
+					}
+				}
+				break;
+
+			default:	/* Not in a tone generating state, go to next round */
+				continue;
+			}
+
+			if (!zap_test_flag(zchan, ZAP_CHANNEL_OPEN)) {
+				if (zap_channel_open_chan(zchan) != ZAP_SUCCESS) {
+					zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_HANGUP);
+					continue;
+				}
+				zap_log(ZAP_LOG_NOTICE, "Successfully opened channel %d:%d\n", zchan->span_id, zchan->chan_id);
+			}
+
+			flags = ZAP_READ;
+
+			status = zap_channel_wait(zchan, &flags, (gated) ? 0 : interval);
+			switch(status) {
+			case ZAP_FAIL:
+				continue;
+
+			case ZAP_TIMEOUT:
+				gated = 1;
+				continue;
+
+			default:
+				if (!(flags & ZAP_READ)) {
+					continue;
+				}
+			}
+			gated = 1;
+
+			status = zap_channel_read(zchan, frame, &len);
+			if (status != ZAP_SUCCESS || len <= 0) {
+				continue;
+			}
+
+			if (zchan->effective_codec != ZAP_CODEC_SLIN) {
+				len *= 2;
+			}
+
+			/* seek to current offset */
+			zap_buffer_seek(dt_buffer, offset);
+
+			rlen = zap_buffer_read_loop(dt_buffer, frame, len);
+
+			if (zchan->effective_codec != ZAP_CODEC_SLIN) {
+				zio_codec_t codec_func = NULL;
+
+				if (zchan->native_codec == ZAP_CODEC_ULAW) {
+					codec_func = zio_slin2ulaw;
+				} else if (zchan->native_codec == ZAP_CODEC_ALAW) {
+					codec_func = zio_slin2alaw;
+				}
+
+				if (codec_func) {
+					status = codec_func(frame, sizeof(frame), &rlen);
+				} else {
+					snprintf(zchan->last_error, sizeof(zchan->last_error), "codec error!");
+					goto done;
+				}
+			}
+			zap_channel_write(zchan, frame, sizeof(frame), &rlen);
+		}
+
+		/*
+		 * sleep a bit if there was nothing to do
+		 */
+		if (!gated) {
+			zap_sleep(interval);
+		}
+
+		offset += (ts.rate / (1000 / interval)) << 1;
+		if (offset >= ts.rate) {
+			offset = 0;
+		}
+	}
+
+done:
+	if (ts.buffer) {
+		teletone_destroy_session(&ts);
+	}
+
+	if (dt_buffer) {
+		zap_buffer_destroy(&dt_buffer);
+	}
+
+	zap_log(ZAP_LOG_DEBUG, "ISDN tone thread ended.\n");
+	zap_clear_flag(isdn_data, ZAP_ISDN_TONES_RUNNING);
+
+	return NULL;
+}
+
+/**
+ * \brief Main thread function for an ISDN span
+ * \param me Current thread
+ * \param obj Span to monitor
+ */
+static void *zap_isdn_run(zap_thread_t *me, void *obj)
+{
+	zap_span_t *span = (zap_span_t *) obj;
+	zap_isdn_data_t *isdn_data = span->signal_data;
+	unsigned char frame[1024];
+	zap_size_t len = sizeof(frame);
+	int errs = 0;
+
+#ifdef WIN32
+    timeBeginPeriod(1);
+#endif
+
+	zap_log(ZAP_LOG_DEBUG, "ISDN thread starting.\n");
+	zap_set_flag(isdn_data, ZAP_ISDN_RUNNING);
+
+	Q921Start(&isdn_data->q921);
+
+	while(zap_running() && zap_test_flag(isdn_data, ZAP_ISDN_RUNNING) && !zap_test_flag(isdn_data, ZAP_ISDN_STOP)) {
+		zap_wait_flag_t flags = ZAP_READ;
+		zap_status_t status = zap_channel_wait(isdn_data->dchan, &flags, 100);
+
+		Q921TimerTick(&isdn_data->q921);
+		Q931TimerTick(&isdn_data->q931);
+		check_state(span);
+		check_events(span);
+
+		/*
+		 *
+		 */
+		switch(status) {
+		case ZAP_FAIL:
+			{
+				zap_log(ZAP_LOG_ERROR, "D-Chan Read Error!\n");
+				snprintf(span->last_error, sizeof(span->last_error), "D-Chan Read Error!");
+				if (++errs == 10) {
+					isdn_data->dchan->state = ZAP_CHANNEL_STATE_UP;
+					goto done;
+				}
+			}
+			break;
+		case ZAP_TIMEOUT:
+			{
+				errs = 0;
+			}
+			break;
+		default:
+			{
+				errs = 0;
+				if (flags & ZAP_READ) {
+
+					if (zap_test_flag(isdn_data->dchan, ZAP_CHANNEL_SUSPENDED)) {
+						zap_clear_flag_all(span, ZAP_CHANNEL_SUSPENDED);
+					}
+					len = sizeof(frame);
+					if (zap_channel_read(isdn_data->dchan, frame, &len) == ZAP_SUCCESS) {
+#ifdef IODEBUG
+						char bb[4096] = "";
+						print_hex_bytes(frame, len, bb, sizeof(bb));
+
+						print_bits(frame, (int)len, bb, sizeof(bb), ZAP_ENDIAN_LITTLE, 0);
+						zap_log(ZAP_LOG_DEBUG, "READ %d\n%s\n%s\n\n", (int)len, LINE, bb);
+#endif
+
+						Q921QueueHDLCFrame(&isdn_data->q921, frame, (int)len);
+						Q921Rx12(&isdn_data->q921);
+					}
+				} else {
+					zap_log(ZAP_LOG_DEBUG, "No Read FLAG!\n");
+				}
+			}
+			break;
+		}
+	}
+	
+ done:
+	zap_channel_close(&isdn_data->dchans[0]);
+	zap_channel_close(&isdn_data->dchans[1]);
+	zap_clear_flag(isdn_data, ZAP_ISDN_RUNNING);
+
+#ifdef WIN32
+    timeEndPeriod(1);
+#endif
+
+	zap_log(ZAP_LOG_DEBUG, "ISDN thread ended.\n");
+	return NULL;
+}
+
+/**
+ * \brief Openzap ISDN signaling module initialisation
+ * \return Success
+ */
+static ZIO_SIG_LOAD_FUNCTION(zap_isdn_init)
+{
+	Q931Initialize();
+
+	Q921SetGetTimeCB(zap_time_now);
+	Q931SetGetTimeCB(zap_time_now);
+
+	return ZAP_SUCCESS;
+}
+
+/**
+ * \brief Receives a Q931 indication message
+ * \param pvt Span were message is coming from
+ * \param ind Q931 indication
+ * \param tei Terminal Endpoint Identifier
+ * \param msg Message string
+ * \param mlen Message string length
+ * \return 0 on success
+ */
+static int q931_rx_32(void *pvt, Q921DLMsg_t ind, L3UCHAR tei, L3UCHAR *msg, L3INT mlen)
+{
+	int offset = 4;
+	char bb[4096] = "";
+
+	switch(ind) {
+	case Q921_DL_UNIT_DATA:
+		offset = 3;
+
+	case Q921_DL_DATA:
+		print_hex_bytes(msg + offset, mlen - offset, bb, sizeof(bb));
+#ifdef HAVE_LIBPCAP
+		/*Q931ToPcap*/
+		if(do_q931ToPcap==1){
+			zap_span_t *span = (zap_span_t *) pvt;
+			if(writeQ931PacketToPcap(msg + offset, mlen - offset, span->span_id, 0) != ZAP_SUCCESS){
+				zap_log(ZAP_LOG_WARNING, "Couldn't write Q931 buffer to pcap file!\n");	
+			}
+		}
+		/*Q931ToPcap done*/
+#endif
+		zap_log(ZAP_LOG_DEBUG, "WRITE %d\n%s\n%s\n\n", (int)mlen - offset, LINE, bb);
+		break;
+
+	default:
+		break;
+	}
+
+	return Q921Rx32(pvt, ind, tei, msg, mlen);
+}
+
+/**
+ * \brief Logs Q921 message
+ * \param pvt Span were message is coming from
+ * \param level Q921 log level
+ * \param msg Message string
+ * \param size Message string length
+ * \return 0
+ */
+static int zap_isdn_q921_log(void *pvt, Q921LogLevel_t level, char *msg, L2INT size)
+{
+	zap_span_t *span = (zap_span_t *) pvt;
+
+	zap_log("Span", "Q.921", span->span_id, (int)level, "%s", msg);
+	return 0;
+}
+
+/**
+ * \brief Logs Q931 message
+ * \param pvt Span were message is coming from
+ * \param level Q931 log level
+ * \param msg Message string
+ * \param size Message string length
+ * \return 0
+ */
+static L3INT zap_isdn_q931_log(void *pvt, Q931LogLevel_t level, char *msg, L3INT size)
+{
+	zap_span_t *span = (zap_span_t *) pvt;
+
+	zap_log("Span", "Q.931", span->span_id, (int)level, "%s", msg);
+	return 0;
+}
+/**
+ * \brief ISDN state map
+ */
+static zap_state_map_t isdn_state_map = {
+	{
+		{
+			ZSD_OUTBOUND,
+			ZSM_UNACCEPTABLE,
+			{ZAP_ANY_STATE},
+			{ZAP_CHANNEL_STATE_RESTART, ZAP_END}
+		},
+		{
+			ZSD_OUTBOUND,
+			ZSM_UNACCEPTABLE,
+			{ZAP_CHANNEL_STATE_RESTART, ZAP_END},
+			{ZAP_CHANNEL_STATE_DOWN, ZAP_END}
+		},
+		{
+			ZSD_OUTBOUND,
+			ZSM_UNACCEPTABLE,
+			{ZAP_CHANNEL_STATE_DOWN, ZAP_END},
+			{ZAP_CHANNEL_STATE_DIALING, ZAP_END}
+		},
+		{
+			ZSD_OUTBOUND,
+			ZSM_UNACCEPTABLE,
+			{ZAP_CHANNEL_STATE_DIALING, ZAP_END},
+			{ZAP_CHANNEL_STATE_PROGRESS_MEDIA, ZAP_CHANNEL_STATE_PROGRESS, ZAP_CHANNEL_STATE_UP, ZAP_CHANNEL_STATE_HANGUP, ZAP_CHANNEL_STATE_TERMINATING, ZAP_END}
+		},
+		{
+			ZSD_OUTBOUND,
+			ZSM_UNACCEPTABLE,
+			{ZAP_CHANNEL_STATE_PROGRESS_MEDIA, ZAP_CHANNEL_STATE_PROGRESS, ZAP_END},
+			{ZAP_CHANNEL_STATE_HANGUP, ZAP_CHANNEL_STATE_PROGRESS_MEDIA, ZAP_CHANNEL_STATE_TERMINATING, ZAP_CHANNEL_STATE_UP, ZAP_END}
+		},
+		{
+			ZSD_OUTBOUND,
+			ZSM_UNACCEPTABLE,
+			{ZAP_CHANNEL_STATE_HANGUP, ZAP_CHANNEL_STATE_TERMINATING, ZAP_END},
+			{ZAP_CHANNEL_STATE_HANGUP_COMPLETE, ZAP_CHANNEL_STATE_DOWN, ZAP_END}
+		},
+		{
+			ZSD_OUTBOUND,
+			ZSM_UNACCEPTABLE,
+			{ZAP_CHANNEL_STATE_HANGUP_COMPLETE, ZAP_END},
+			{ZAP_CHANNEL_STATE_DOWN, ZAP_END},
+		},
+		{
+			ZSD_OUTBOUND,
+			ZSM_UNACCEPTABLE,
+			{ZAP_CHANNEL_STATE_UP, ZAP_END},
+			{ZAP_CHANNEL_STATE_HANGUP, ZAP_CHANNEL_STATE_TERMINATING, ZAP_END}
+		},
+
+		/****************************************/
+		{
+			ZSD_INBOUND,
+			ZSM_UNACCEPTABLE,
+			{ZAP_ANY_STATE},
+			{ZAP_CHANNEL_STATE_RESTART, ZAP_END}
+		},
+		{
+			ZSD_INBOUND,
+			ZSM_UNACCEPTABLE,
+			{ZAP_CHANNEL_STATE_RESTART, ZAP_END},
+			{ZAP_CHANNEL_STATE_DOWN, ZAP_END}
+		},
+		{
+			ZSD_INBOUND,
+			ZSM_UNACCEPTABLE,
+			{ZAP_CHANNEL_STATE_DOWN, ZAP_END},
+			{ZAP_CHANNEL_STATE_DIALTONE, ZAP_CHANNEL_STATE_RING, ZAP_END}
+		},
+		{
+			ZSD_INBOUND,
+			ZSM_UNACCEPTABLE,
+			{ZAP_CHANNEL_STATE_DIALTONE, ZAP_END},
+			{ZAP_CHANNEL_STATE_RING, ZAP_CHANNEL_STATE_HANGUP, ZAP_CHANNEL_STATE_TERMINATING, ZAP_END}
+		},
+		{
+			ZSD_INBOUND,
+			ZSM_UNACCEPTABLE,
+			{ZAP_CHANNEL_STATE_RING, ZAP_END},
+			{ZAP_CHANNEL_STATE_HANGUP, ZAP_CHANNEL_STATE_TERMINATING, ZAP_CHANNEL_STATE_PROGRESS, ZAP_CHANNEL_STATE_PROGRESS_MEDIA, ZAP_CHANNEL_STATE_UP, ZAP_END}
+		},
+		{
+			ZSD_INBOUND,
+			ZSM_UNACCEPTABLE,
+			{ZAP_CHANNEL_STATE_HANGUP, ZAP_CHANNEL_STATE_TERMINATING, ZAP_END},
+			{ZAP_CHANNEL_STATE_HANGUP_COMPLETE, ZAP_CHANNEL_STATE_DOWN, ZAP_END},
+		},
+		{
+			ZSD_INBOUND,
+			ZSM_UNACCEPTABLE,
+			{ZAP_CHANNEL_STATE_HANGUP_COMPLETE, ZAP_END},
+			{ZAP_CHANNEL_STATE_DOWN, ZAP_END},
+		},
+		{
+			ZSD_INBOUND,
+			ZSM_UNACCEPTABLE,
+			{ZAP_CHANNEL_STATE_PROGRESS, ZAP_CHANNEL_STATE_PROGRESS_MEDIA, ZAP_END},
+			{ZAP_CHANNEL_STATE_HANGUP, ZAP_CHANNEL_STATE_TERMINATING, ZAP_CHANNEL_STATE_PROGRESS_MEDIA, 
+			 ZAP_CHANNEL_STATE_CANCEL, ZAP_CHANNEL_STATE_UP, ZAP_END},
+		},
+		{
+			ZSD_INBOUND,
+			ZSM_UNACCEPTABLE,
+			{ZAP_CHANNEL_STATE_UP, ZAP_END},
+			{ZAP_CHANNEL_STATE_HANGUP, ZAP_CHANNEL_STATE_TERMINATING, ZAP_END},
+		},
+		
+
+	}
+};
+
+/**
+ * \brief Stops an ISDN span
+ * \param span Span to halt
+ * \return Success
+ *
+ * Sets a stop flag and waits for the threads to end
+ */
+static zap_status_t zap_isdn_stop(zap_span_t *span)
+{
+	zap_isdn_data_t *isdn_data = span->signal_data;
+
+	if (!zap_test_flag(isdn_data, ZAP_ISDN_RUNNING)) {
+		return ZAP_FAIL;
+	}
+		
+	zap_set_flag(isdn_data, ZAP_ISDN_STOP);
+	
+	while(zap_test_flag(isdn_data, ZAP_ISDN_RUNNING)) {
+		zap_sleep(100);
+	}
+
+	while(zap_test_flag(isdn_data, ZAP_ISDN_TONES_RUNNING)) {
+		zap_sleep(100);
+	}
+
+	return ZAP_SUCCESS;
+	
+}
+
+/**
+ * \brief Starts an ISDN span
+ * \param span Span to halt
+ * \return Success or failure
+ *
+ * Launches a thread to monitor the span and a thread to generate tones on the span
+ */
+static zap_status_t zap_isdn_start(zap_span_t *span)
+{
+	zap_status_t ret;
+	zap_isdn_data_t *isdn_data = span->signal_data;
+
+	if (zap_test_flag(isdn_data, ZAP_ISDN_RUNNING)) {
+		return ZAP_FAIL;
+	}
+
+	zap_clear_flag(isdn_data, ZAP_ISDN_STOP);
+	ret = zap_thread_create_detached(zap_isdn_run, span);
+
+	if (ret != ZAP_SUCCESS) {
+		return ret;
+	}
+
+	if (ZAP_SPAN_IS_NT(span) && !(isdn_data->opts & ZAP_ISDN_OPT_DISABLE_TONES)) {
+		ret = zap_thread_create_detached(zap_isdn_tones_run, span);
+	}
+	return ret;
+}
+
+/**
+ * \brief Parses an option string to flags
+ * \param in String to parse for configuration options
+ * \return Flags
+ */
+static uint32_t parse_opts(const char *in)
+{
+	uint32_t flags = 0;
+	
+	if (!in) {
+		return 0;
+	}
+	
+	if (strstr(in, "suggest_channel")) {
+		flags |= ZAP_ISDN_OPT_SUGGEST_CHANNEL;
+	}
+
+	if (strstr(in, "omit_display")) {
+		flags |= ZAP_ISDN_OPT_OMIT_DISPLAY_IE;
+	}
+
+	if (strstr(in, "disable_tones")) {
+		flags |= ZAP_ISDN_OPT_DISABLE_TONES;
+	}
+
+	return flags;
+}
+
+/**
+ * \brief Initialises an ISDN span from configuration variables
+ * \param span Span to configure
+ * \param sig_cb Callback function for event signals
+ * \param ap List of configuration variables
+ * \return Success or failure
+ */
+static ZIO_SIG_CONFIGURE_FUNCTION(zap_isdn_configure_span)
+{
+	uint32_t i, x = 0;
+	zap_channel_t *dchans[2] = {0};
+	zap_isdn_data_t *isdn_data;
+	const char *tonemap = "us";
+	char *var, *val;
+	Q931Dialect_t dialect = Q931_Dialect_National;
+	int32_t digit_timeout = 0;
+	int q921loglevel = -1;
+	int q931loglevel = -1;
+#ifdef HAVE_LIBPCAP
+	int q931topcap   = -1; 	/*Q931ToPcap*/
+	int openPcap = 0; 	/*Flag: open Pcap file please*/
+#endif
+
+	if (span->signal_type) {
+#ifdef HAVE_LIBPCAP
+		/*Q931ToPcap: Get the content of the q931topcap and pcapfilename args given by mod_openzap */
+		while((var = va_arg(ap, char *))) {
+			if (!strcasecmp(var, "q931topcap")) {
+				q931topcap = va_arg(ap, int);
+				if(q931topcap==1) {
+					/*PCAP on*/;
+					openPcap=1;
+				} else if (q931topcap==0) {
+					/*PCAP off*/
+					if (closePcapFile() != ZAP_SUCCESS) return ZAP_FAIL;
+					do_q931ToPcap=0;
+					return ZAP_SUCCESS;
+				}
+			}
+			if (!strcasecmp(var, "pcapfilename")) {
+				/*Put filename into global var*/
+				pcapfn = va_arg(ap, char*);
+			}
+		}
+		/*We know now, that user wants to enable Q931ToPcap and what file name he wants, so open it please*/
+		if(openPcap==1){
+			if(openPcapFile() != ZAP_SUCCESS) return ZAP_FAIL;
+			do_q931ToPcap=1;
+			return ZAP_SUCCESS;
+		}
+		/*Q931ToPcap done*/
+#endif
+		snprintf(span->last_error, sizeof(span->last_error), "Span is already configured for signalling [%d].", span->signal_type);
+		return ZAP_FAIL;
+	}
+
+	if (span->trunk_type >= ZAP_TRUNK_NONE) {
+		zap_log(ZAP_LOG_WARNING, "Invalid trunk type '%s' defaulting to T1.\n", zap_trunk_type2str(span->trunk_type));
+		span->trunk_type = ZAP_TRUNK_T1;
+	}
+	
+	for(i = 1; i <= span->chan_count; i++) {
+		if (span->channels[i]->type == ZAP_CHAN_TYPE_DQ921) {
+			if (x > 1) {
+				snprintf(span->last_error, sizeof(span->last_error), "Span has more than 2 D-Channels!");
+				return ZAP_FAIL;
+			} else {
+				if (zap_channel_open(span->span_id, i, &dchans[x]) == ZAP_SUCCESS) {
+					zap_log(ZAP_LOG_DEBUG, "opening d-channel #%d %d:%d\n", x, dchans[x]->span_id, dchans[x]->chan_id);
+					dchans[x]->state = ZAP_CHANNEL_STATE_UP;
+					x++;
+				}
+			}
+		}
+	}
+
+	if (!x) {
+		snprintf(span->last_error, sizeof(span->last_error), "Span has no D-Channels!");
+		return ZAP_FAIL;
+	}
+
+	isdn_data = malloc(sizeof(*isdn_data));
+	assert(isdn_data != NULL);
+	memset(isdn_data, 0, sizeof(*isdn_data));
+	
+	isdn_data->mode = Q931_TE;
+	dialect = Q931_Dialect_National;
+	
+	while((var = va_arg(ap, char *))) {
+		if (!strcasecmp(var, "mode")) {
+			if (!(val = va_arg(ap, char *))) {
+				break;
+			}
+			isdn_data->mode = strcasecmp(val, "net") ? Q931_TE : Q931_NT;
+		} else if (!strcasecmp(var, "dialect")) {
+			if (!(val = va_arg(ap, char *))) {
+				break;
+			}
+			dialect = q931_str2Q931Dialect_type(val);
+			if (dialect == Q931_Dialect_Count) {
+				return ZAP_FAIL;
+			}
+		} else if (!strcasecmp(var, "opts")) {
+			if (!(val = va_arg(ap, char *))) {
+				break;
+			}
+			isdn_data->opts = parse_opts(val);
+		} else if (!strcasecmp(var, "tonemap")) {
+			if (!(val = va_arg(ap, char *))) {
+				break;
+			}
+			tonemap = (const char *)val;
+		} else if (!strcasecmp(var, "digit_timeout")) {
+			int *optp;
+			if (!(optp = va_arg(ap, int *))) {
+				break;
+			}
+			digit_timeout = *optp;
+		} else if (!strcasecmp(var, "q921loglevel")) {
+			q921loglevel = va_arg(ap, int);
+			if (q921loglevel < Q921_LOG_NONE) {
+				q921loglevel = Q921_LOG_NONE;
+			} else if (q921loglevel > Q921_LOG_DEBUG) {
+				q921loglevel = Q921_LOG_DEBUG;
+			}
+		} else if (!strcasecmp(var, "q931loglevel")) {
+			q931loglevel = va_arg(ap, int);
+			if (q931loglevel < Q931_LOG_NONE) {
+				q931loglevel = Q931_LOG_NONE;
+			} else if (q931loglevel > Q931_LOG_DEBUG) {
+				q931loglevel = Q931_LOG_DEBUG;
+			}
+		} else {
+			snprintf(span->last_error, sizeof(span->last_error), "Unknown parameter [%s]", var);
+			return ZAP_FAIL;
+		}
+	}
+
+
+	if (!digit_timeout) {
+		digit_timeout = DEFAULT_DIGIT_TIMEOUT;
+	}
+	else if (digit_timeout < 3000 || digit_timeout > 30000) {
+		zap_log(ZAP_LOG_WARNING, "Digit timeout %d ms outside of range (3000 - 30000 ms), using default (10000 ms)\n", digit_timeout);
+		digit_timeout = DEFAULT_DIGIT_TIMEOUT;
+	}
+
+	/* allocate per b-chan data */
+	if (isdn_data->mode == Q931_NT) {
+		zap_isdn_bchan_data_t *data;
+
+		data = malloc((span->chan_count - 1) * sizeof(zap_isdn_bchan_data_t));
+		if (!data) {
+			return ZAP_FAIL;
+		}
+
+		for (i = 1; i <= span->chan_count; i++, data++) {
+			if (span->channels[i]->type == ZAP_CHAN_TYPE_B) {
+				span->channels[i]->mod_data = data;
+				memset(data, 0, sizeof(zap_isdn_bchan_data_t));
+			}
+		}
+	}
+					
+	span->start = zap_isdn_start;
+	span->stop = zap_isdn_stop;
+	span->signal_cb = sig_cb;
+	isdn_data->dchans[0] = dchans[0];
+	isdn_data->dchans[1] = dchans[1];
+	isdn_data->dchan = isdn_data->dchans[0];
+	isdn_data->digit_timeout = digit_timeout;
+	
+	Q921_InitTrunk(&isdn_data->q921,
+				   0,
+				   0,
+				   isdn_data->mode,
+				   span->trunk_type == ZAP_TRUNK_BRI_PTMP ? Q921_PTMP : Q921_PTP,
+				   0,
+				   zap_isdn_921_21,
+				   (Q921Tx23CB_t)zap_isdn_921_23,
+				   span,
+				   &isdn_data->q931);
+
+	Q921SetLogCB(&isdn_data->q921, &zap_isdn_q921_log, isdn_data);
+	Q921SetLogLevel(&isdn_data->q921, (Q921LogLevel_t)q921loglevel);
+	
+	Q931Api_InitTrunk(&isdn_data->q931,
+					  dialect,
+					  isdn_data->mode,
+					  span->trunk_type,
+					  zap_isdn_931_34,
+					  (Q931Tx32CB_t)q931_rx_32,
+					  zap_isdn_931_err,
+					  &isdn_data->q921,
+					  span);
+
+	Q931SetLogCB(&isdn_data->q931, &zap_isdn_q931_log, isdn_data);
+	Q931SetLogLevel(&isdn_data->q931, (Q931LogLevel_t)q931loglevel);
+
+	isdn_data->q931.autoRestartAck = 1;
+	isdn_data->q931.autoConnectAck = 0;
+	isdn_data->q931.autoServiceAck = 1;
+	span->signal_data = isdn_data;
+	span->signal_type = ZAP_SIGTYPE_ISDN;
+	span->outgoing_call = isdn_outgoing_call;
+
+	if ((isdn_data->opts & ZAP_ISDN_OPT_SUGGEST_CHANNEL)) {
+		span->channel_request = isdn_channel_request;
+		span->suggest_chan_id = 1;
+	}
+	span->state_map = &isdn_state_map;
+
+	zap_span_load_tones(span, tonemap);
+
+	return ZAP_SUCCESS;
+}
+
+/**
+ * \brief Openzap ISDN signaling module definition
+ */
+EX_DECLARE_DATA zap_module_t zap_module = {
+	"isdn",
+	NULL,
+	close_pcap,
+	zap_isdn_init,
+	zap_isdn_configure_span,
+	NULL
+};
+
+
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */

Added: freeswitch/trunk/libs/openzap/src/ozmod/ozmod_isdn/zap_isdn.h (0 => 17141)


--- freeswitch/trunk/libs/openzap/src/ozmod/ozmod_isdn/zap_isdn.h	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/src/ozmod/ozmod_isdn/zap_isdn.h	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2007, Anthony Minessale II
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ZAP_ISDN_H
+#define ZAP_ISDN_H
+#include "openzap.h"
+
+#define DEFAULT_DIGIT_TIMEOUT	10000		/* default overlap timeout: 10 seconds */
+
+
+typedef enum {
+	ZAP_ISDN_OPT_NONE = 0,
+	ZAP_ISDN_OPT_SUGGEST_CHANNEL = (1 << 0),
+	ZAP_ISDN_OPT_OMIT_DISPLAY_IE = (1 << 1),	/*!< Do not send Caller name in outgoing SETUP message (= Display IE) */
+	ZAP_ISDN_OPT_DISABLE_TONES = (1 << 2),		/*!< Disable tone generating thread (NT mode) */
+
+	ZAP_ISDN_OPT_MAX = (2 << 0)
+} zap_isdn_opts_t;
+
+typedef enum {
+	ZAP_ISDN_RUNNING = (1 << 0),
+	ZAP_ISDN_TONES_RUNNING = (1 << 1),
+	ZAP_ISDN_STOP = (1 << 2)
+} zap_isdn_flag_t;
+
+
+struct zap_isdn_data {
+	Q921Data_t q921;
+	Q931_TrunkInfo_t q931;
+	zap_channel_t *dchan;
+	zap_channel_t *dchans[2];
+	struct zap_sigmsg sigmsg;
+	uint32_t flags;
+	int32_t mode;
+	int32_t digit_timeout;
+	zap_isdn_opts_t opts;
+	zap_caller_data_t *outbound_crv[32768];
+	zap_channel_t *channels_local_crv[32768];
+	zap_channel_t *channels_remote_crv[32768];
+};
+
+typedef struct zap_isdn_data zap_isdn_data_t;
+
+
+/* b-channel private data */
+struct zap_isdn_bchan_data
+{
+	L2ULONG digit_timeout;
+};
+
+typedef struct zap_isdn_bchan_data zap_isdn_bchan_data_t;
+
+
+#endif
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
+

Added: freeswitch/trunk/libs/openzap/src/ozmod/ozmod_libpri/lpwrap_pri.c (0 => 17141)


--- freeswitch/trunk/libs/openzap/src/ozmod/ozmod_libpri/lpwrap_pri.c	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/src/ozmod/ozmod_libpri/lpwrap_pri.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,303 @@
+/*
+ * Copyright (c) 2009, Anthony Minessale II
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+//#define IODEBUG
+
+#include "openzap.h"
+#include "lpwrap_pri.h"
+#ifndef HAVE_GETTIMEOFDAY
+
+#ifdef WIN32
+#include <mmsystem.h>
+
+static __inline int gettimeofday(struct timeval *tp, void *nothing)
+{
+#ifdef WITHOUT_MM_LIB
+	SYSTEMTIME st;
+	time_t tt;
+	struct tm tmtm;
+	/* mktime converts local to UTC */
+	GetLocalTime (&st);
+	tmtm.tm_sec = st.wSecond;
+	tmtm.tm_min = st.wMinute;
+	tmtm.tm_hour = st.wHour;
+	tmtm.tm_mday = st.wDay;
+	tmtm.tm_mon = st.wMonth - 1;
+	tmtm.tm_year = st.wYear - 1900;  tmtm.tm_isdst = -1;
+	tt = mktime (&tmtm);
+	tp->tv_sec = tt;
+	tp->tv_usec = st.wMilliseconds * 1000;
+#else
+	/**
+	 ** The earlier time calculations using GetLocalTime
+	 ** had a time resolution of 10ms.The timeGetTime, part
+	 ** of multimedia apis offer a better time resolution
+	 ** of 1ms.Need to link against winmm.lib for this
+	 **/
+	unsigned long Ticks = 0;
+	unsigned long Sec =0;
+	unsigned long Usec = 0;
+	Ticks = timeGetTime();
+
+	Sec = Ticks/1000;
+	Usec = (Ticks - (Sec*1000))*1000;
+	tp->tv_sec = Sec;
+	tp->tv_usec = Usec;
+#endif /* WITHOUT_MM_LIB */
+	(void)nothing;
+	return 0;
+}
+#endif /* WIN32 */
+#endif /* HAVE_GETTIMEOFDAY */
+
+static struct lpwrap_pri_event_list LPWRAP_PRI_EVENT_LIST[] = {
+	{0, LPWRAP_PRI_EVENT_ANY, "ANY"},
+	{1, LPWRAP_PRI_EVENT_DCHAN_UP, "DCHAN_UP"},
+	{2, LPWRAP_PRI_EVENT_DCHAN_DOWN, "DCHAN_DOWN"},
+	{3, LPWRAP_PRI_EVENT_RESTART, "RESTART"},
+	{4, LPWRAP_PRI_EVENT_CONFIG_ERR, "CONFIG_ERR"},
+	{5, LPWRAP_PRI_EVENT_RING, "RING"},
+	{6, LPWRAP_PRI_EVENT_HANGUP, "HANGUP"},
+	{7, LPWRAP_PRI_EVENT_RINGING, "RINGING"},
+	{8, LPWRAP_PRI_EVENT_ANSWER, "ANSWER"},
+	{9, LPWRAP_PRI_EVENT_HANGUP_ACK, "HANGUP_ACK"},
+	{10, LPWRAP_PRI_EVENT_RESTART_ACK, "RESTART_ACK"},
+	{11, LPWRAP_PRI_EVENT_FACNAME, "FACNAME"},
+	{12, LPWRAP_PRI_EVENT_INFO_RECEIVED, "INFO_RECEIVED"},
+	{13, LPWRAP_PRI_EVENT_PROCEEDING, "PROCEEDING"},
+	{14, LPWRAP_PRI_EVENT_SETUP_ACK, "SETUP_ACK"},
+	{15, LPWRAP_PRI_EVENT_HANGUP_REQ, "HANGUP_REQ"},
+	{16, LPWRAP_PRI_EVENT_NOTIFY, "NOTIFY"},
+	{17, LPWRAP_PRI_EVENT_PROGRESS, "PROGRESS"},
+	{18, LPWRAP_PRI_EVENT_KEYPAD_DIGIT, "KEYPAD_DIGIT"},
+	{19, LPWRAP_PRI_EVENT_IO_FAIL, "IO_FAIL"},
+};
+
+#define LINE "--------------------------------------------------------------------------------"
+
+const char *lpwrap_pri_event_str(lpwrap_pri_event_t event_id)
+{ 
+	return LPWRAP_PRI_EVENT_LIST[event_id].name;
+}
+
+static int __pri_lpwrap_read(struct pri *pri, void *buf, int buflen)
+{
+	struct lpwrap_pri *spri = (struct lpwrap_pri *) pri_get_userdata(pri);
+	zap_size_t len = buflen;
+	int res;
+	zap_status_t zst;
+
+	if ((zst = zap_channel_read(spri->dchan, buf, &len)) != ZAP_SUCCESS) {
+		if (zst == ZAP_FAIL) {
+			zap_log(ZAP_LOG_CRIT, "span %d D-READ FAIL! [%s]\n", spri->span->span_id, spri->dchan->last_error);
+			spri->errs++;
+		} else {
+			zap_log(ZAP_LOG_CRIT, "span %d D-READ TIMEOUT\n", spri->span->span_id);
+		}
+		
+		zap_clear_flag(spri, LPWRAP_PRI_READY);
+		return -1;
+	}
+	spri->errs = 0;
+	res = (int)len;
+	memset(&((unsigned char*)buf)[res],0,2);
+	res+=2;
+
+#ifdef IODEBUG
+	{
+		char bb[2048] = { 0 };
+
+		print_hex_bytes(buf, res - 2, bb, sizeof(bb));
+		zap_log(ZAP_LOG_DEBUG, "READ %d\n", res-2);
+	}
+#endif
+
+	return res;
+}
+
+static int __pri_lpwrap_write(struct pri *pri, void *buf, int buflen)
+{
+	struct lpwrap_pri *spri = (struct lpwrap_pri *) pri_get_userdata(pri);
+	zap_size_t len = buflen -2;
+
+	if (zap_channel_write(spri->dchan, buf, buflen, &len) != ZAP_SUCCESS) {
+		zap_log(ZAP_LOG_CRIT, "span %d D-WRITE FAIL! [%s]\n", spri->span->span_id, spri->dchan->last_error);
+		zap_clear_flag(spri, LPWRAP_PRI_READY);
+		return -1;
+	}
+
+#ifdef IODEBUG
+	{
+		char bb[2048] = { 0 };
+
+		print_hex_bytes(buf, buflen - 2, bb, sizeof(bb));
+		zap_log(ZAP_LOG_DEBUG, "WRITE %d\n", (int)buflen-2);
+	}
+#endif
+
+	return (int) buflen;
+}
+
+int lpwrap_init_pri(struct lpwrap_pri *spri, zap_span_t *span, zap_channel_t *dchan, int swtype, int node, int debug)
+{
+	int ret = -1;
+
+	memset(spri, 0, sizeof(struct lpwrap_pri));
+	
+	spri->dchan = dchan;
+	spri->span = span;
+
+	if ((spri->pri = pri_new_cb(spri->dchan->sockfd, node, swtype, __pri_lpwrap_read, __pri_lpwrap_write, spri))){
+		unsigned char buf[4] = { 0 };
+		size_t buflen = sizeof(buf), len = 0;
+		pri_set_debug(spri->pri, debug);
+		ret = 0;
+		zap_set_flag(spri, LPWRAP_PRI_READY);
+		zap_channel_write(spri->dchan, buf, buflen, &len);
+	} else {
+		fprintf(stderr, "Unable to create PRI\n");
+	}
+
+	return ret;
+}
+
+
+int lpwrap_one_loop(struct lpwrap_pri *spri)
+{
+	fd_set rfds, efds;
+	struct timeval now = {0,0}, *next;
+	pri_event *event;
+	event_handler handler;
+    int sel;
+	
+	if (spri->on_loop) {
+		if ((sel = spri->on_loop(spri)) < 0) {
+			return sel;
+		}
+	}
+
+	if (spri->errs >= 2) {
+		spri->errs = 0;
+		return -1;
+	}
+
+	FD_ZERO(&rfds);
+	FD_ZERO(&efds);
+
+#ifdef _MSC_VER
+	//Windows macro for FD_SET includes a warning C4127: conditional expression is constant
+#pragma warning(push)
+#pragma warning(disable:4127)
+#endif
+
+	FD_SET(pri_fd(spri->pri), &rfds);
+	FD_SET(pri_fd(spri->pri), &efds);
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+	now.tv_sec = 0;
+	now.tv_usec = 100000;
+
+	sel = select(pri_fd(spri->pri) + 1, &rfds, NULL, &efds, &now);
+
+	event = NULL;
+
+	if (!sel) {
+		if ((next = pri_schedule_next(spri->pri))) {
+			gettimeofday(&now, NULL);
+			if (now.tv_sec >= next->tv_sec && (now.tv_usec >= next->tv_usec || next->tv_usec <= 100000)) {
+				//zap_log(ZAP_LOG_DEBUG, "Check event\n");
+				event = pri_schedule_run(spri->pri);
+			}
+		}
+	} else if (sel > 0) {
+		event = pri_check_event(spri->pri);
+	}
+
+	if (event) {
+		/* 0 is catchall event handler */
+		if ((handler = spri->eventmap[event->e] ? spri->eventmap[event->e] : spri->eventmap[0] ? spri->eventmap[0] : NULL)) {
+			handler(spri, event->e, event);
+		} else {
+			zap_log(ZAP_LOG_CRIT, "No event handler found for event %d.\n", event->e);
+		}
+	}
+
+
+	return sel;
+
+
+	if ((handler = spri->eventmap[LPWRAP_PRI_EVENT_IO_FAIL] ? spri->eventmap[LPWRAP_PRI_EVENT_IO_FAIL] : spri->eventmap[0] ? spri->eventmap[0] : NULL)) {
+		handler(spri, LPWRAP_PRI_EVENT_IO_FAIL, NULL);
+	}
+
+	return -1;
+}
+
+int lpwrap_run_pri(struct lpwrap_pri *spri)
+{
+	int ret = 0;
+	
+	for (;;){
+		ret = lpwrap_one_loop(spri);
+
+		if (ret < 0) {
+
+#ifndef WIN32 //This needs to be adressed fror WIN32 still
+			if (errno == EINTR){
+				/* Igonore an interrupted system call */
+				continue;
+			}
+#endif	
+			zap_log(ZAP_LOG_CRIT, "Error = %i [%s]\n", ret, strerror(errno));
+			break;
+		}
+	}
+
+	return ret;
+
+}
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
+

Added: freeswitch/trunk/libs/openzap/src/ozmod/ozmod_libpri/lpwrap_pri.h (0 => 17141)


--- freeswitch/trunk/libs/openzap/src/ozmod/ozmod_libpri/lpwrap_pri.h	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/src/ozmod/ozmod_libpri/lpwrap_pri.h	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2009, Anthony Minessale II
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _LPWRAP_PRI_H
+#define _LPWRAP_PRI_H
+#include <libpri.h>
+#include <openzap.h>
+
+
+#define LPWRAP_MAX_CHAN_PER_SPAN 32
+
+typedef enum {
+	LPWRAP_PRI_EVENT_ANY           = 0,
+	LPWRAP_PRI_EVENT_DCHAN_UP      = PRI_EVENT_DCHAN_UP,
+	LPWRAP_PRI_EVENT_DCHAN_DOWN    = PRI_EVENT_DCHAN_DOWN,
+	LPWRAP_PRI_EVENT_RESTART       = PRI_EVENT_RESTART,
+	LPWRAP_PRI_EVENT_CONFIG_ERR    = PRI_EVENT_CONFIG_ERR,
+	LPWRAP_PRI_EVENT_RING          = PRI_EVENT_RING,
+	LPWRAP_PRI_EVENT_HANGUP        = PRI_EVENT_HANGUP,
+	LPWRAP_PRI_EVENT_RINGING       = PRI_EVENT_RINGING,
+	LPWRAP_PRI_EVENT_ANSWER        = PRI_EVENT_ANSWER,
+	LPWRAP_PRI_EVENT_HANGUP_ACK    = PRI_EVENT_HANGUP_ACK,
+	LPWRAP_PRI_EVENT_RESTART_ACK   = PRI_EVENT_RESTART_ACK,
+	LPWRAP_PRI_EVENT_FACNAME       = PRI_EVENT_FACNAME,
+	LPWRAP_PRI_EVENT_INFO_RECEIVED = PRI_EVENT_INFO_RECEIVED,
+	LPWRAP_PRI_EVENT_PROCEEDING    = PRI_EVENT_PROCEEDING,
+	LPWRAP_PRI_EVENT_SETUP_ACK     = PRI_EVENT_SETUP_ACK,
+	LPWRAP_PRI_EVENT_HANGUP_REQ    = PRI_EVENT_HANGUP_REQ,
+	LPWRAP_PRI_EVENT_NOTIFY        = PRI_EVENT_NOTIFY,
+	LPWRAP_PRI_EVENT_PROGRESS      = PRI_EVENT_PROGRESS,
+	LPWRAP_PRI_EVENT_KEYPAD_DIGIT  = PRI_EVENT_KEYPAD_DIGIT,
+	LPWRAP_PRI_EVENT_IO_FAIL       = 19,
+
+	/* don't touch */
+	LPWRAP_PRI_EVENT_MAX
+} lpwrap_pri_event_t;
+
+typedef enum {
+	LPWRAP_PRI_NETWORK = PRI_NETWORK,
+	LPWRAP_PRI_CPE = PRI_CPE
+} lpwrap_pri_node_t;
+
+typedef enum {
+	LPWRAP_PRI_SWITCH_UNKNOWN     = PRI_SWITCH_UNKNOWN,
+	LPWRAP_PRI_SWITCH_NI2         = PRI_SWITCH_NI2,
+	LPWRAP_PRI_SWITCH_DMS100      = PRI_SWITCH_DMS100,
+	LPWRAP_PRI_SWITCH_LUCENT5E    = PRI_SWITCH_LUCENT5E,
+	LPWRAP_PRI_SWITCH_ATT4ESS     = PRI_SWITCH_ATT4ESS,
+	LPWRAP_PRI_SWITCH_EUROISDN_E1 = PRI_SWITCH_EUROISDN_E1,
+	LPWRAP_PRI_SWITCH_EUROISDN_T1 = PRI_SWITCH_EUROISDN_T1,
+	LPWRAP_PRI_SWITCH_NI1         = PRI_SWITCH_NI1,
+	LPWRAP_PRI_SWITCH_GR303_EOC   = PRI_SWITCH_GR303_EOC,
+	LPWRAP_PRI_SWITCH_GR303_TMC   = PRI_SWITCH_GR303_TMC,
+	LPWRAP_PRI_SWITCH_QSIG        = PRI_SWITCH_QSIG,
+
+	/* don't touch */
+	LPWRAP_PRI_SWITCH_MAX
+} lpwrap_pri_switch_t;
+
+typedef enum {
+	LPWRAP_PRI_READY = (1 << 0)
+} lpwrap_pri_flag_t;
+
+struct lpwrap_pri;
+typedef int (*event_handler)(struct lpwrap_pri *, lpwrap_pri_event_t, pri_event *);
+typedef int (*loop_handler)(struct lpwrap_pri *);
+
+struct lpwrap_pri {
+	struct pri *pri;
+	zap_span_t *span;
+	zap_channel_t *dchan;
+	unsigned int flags;
+	void *private_info;
+	event_handler eventmap[LPWRAP_PRI_EVENT_MAX];
+	loop_handler on_loop;
+	int errs;
+};
+
+typedef struct lpwrap_pri lpwrap_pri_t;
+
+struct lpwrap_pri_event_list {
+	int event_id;
+	int pri_event;
+	const char *name;
+};
+
+
+
+#define LPWRAP_MAP_PRI_EVENT(spri, event, func) spri.eventmap[event] = func;
+
+const char *lpwrap_pri_event_str(lpwrap_pri_event_t event_id);
+int lpwrap_one_loop(struct lpwrap_pri *spri);
+int lpwrap_init_pri(struct lpwrap_pri *spri, zap_span_t *span, zap_channel_t *dchan, int swtype, int node, int debug);
+int lpwrap_run_pri(struct lpwrap_pri *spri);
+
+#endif

Added: freeswitch/trunk/libs/openzap/src/ozmod/ozmod_libpri/ozmod_libpri.c (0 => 17141)


--- freeswitch/trunk/libs/openzap/src/ozmod/ozmod_libpri/ozmod_libpri.c	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/src/ozmod/ozmod_libpri/ozmod_libpri.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,1363 @@
+/*
+ * Copyright (c) 2007, Anthony Minessale II
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "openzap.h"
+#include "ozmod_libpri.h"
+
+/**
+ * \brief Unloads libpri IO module
+ * \return Success
+ */
+static ZIO_IO_UNLOAD_FUNCTION(zap_libpri_unload)
+{
+	return ZAP_SUCCESS;
+}
+
+/**
+ * \brief Starts a libpri channel (outgoing call)
+ * \param zchan Channel to initiate call on
+ * \return Success or failure
+ */
+static ZIO_CHANNEL_OUTGOING_CALL_FUNCTION(isdn_outgoing_call)
+{
+	zap_status_t status = ZAP_SUCCESS;
+	zap_set_flag(zchan, ZAP_CHANNEL_OUTBOUND);
+	zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_DIALING);
+	return status;
+}
+
+/**
+ * \brief Requests an libpri channel on a span (outgoing call)
+ * \param span Span where to get a channel (unused)
+ * \param chan_id Specific channel to get (0 for any) (unused)
+ * \param direction Call direction (unused)
+ * \param caller_data Caller information (unused)
+ * \param zchan Channel to initialise (unused)
+ * \return Failure
+ */
+static ZIO_CHANNEL_REQUEST_FUNCTION(isdn_channel_request)
+{
+	return ZAP_FAIL;
+}
+
+#ifdef WIN32
+/**
+ * \brief Logs a libpri error
+ * \param s Error string
+ */
+static void s_pri_error(char *s)
+#else
+/**
+ * \brief Logs a libpri error
+ * \param pri libpri structure (unused)
+ * \param s Error string
+ */
+static void s_pri_error(struct pri *pri, char *s)
+#endif
+{
+	zap_log(ZAP_LOG_ERROR, "%s", s);
+}
+
+#ifdef WIN32
+/**
+ * \brief Logs a libpri message
+ * \param s Message string
+ */
+static void s_pri_message(char *s)
+#else
+/**
+ * \brief Logs a libpri message
+ * \param pri libpri structure (unused)
+ * \param s Message string
+ */
+static void s_pri_message(struct pri *pri, char *s)
+#endif
+{
+		zap_log(ZAP_LOG_DEBUG, "%s", s);
+}
+
+/**
+ * \brief Parses an option string to flags
+ * \param in String to parse for configuration options
+ * \return Flags
+ */
+static uint32_t parse_opts(const char *in)
+{
+	uint32_t flags = 0;
+	
+	if (!in) {
+		return 0;
+	}
+	
+	if (strstr(in, "suggest_channel")) {
+		flags |= OZMOD_LIBPRI_OPT_SUGGEST_CHANNEL;
+	}
+	
+	if (strstr(in, "omit_display")) {
+		flags |= OZMOD_LIBPRI_OPT_OMIT_DISPLAY_IE;
+	}
+	
+	if (strstr(in, "omit_redirecting_number")) {
+		flags |= OZMOD_LIBPRI_OPT_OMIT_REDIRECTING_NUMBER_IE;
+	}
+
+	return flags;
+}
+
+/**
+ * \brief Parses a debug string to flags
+ * \param in Debug string to parse for
+ * \return Flags
+ */
+static int parse_debug(const char *in)
+{
+	int flags = 0;
+
+	if (!in) {
+		return 0;
+	}
+
+	if (strstr(in, "q921_raw")) {
+		flags |= PRI_DEBUG_Q921_RAW;
+	}
+
+	if (strstr(in, "q921_dump")) {
+		flags |= PRI_DEBUG_Q921_DUMP;
+	}
+
+	if (strstr(in, "q921_state")) {
+		flags |= PRI_DEBUG_Q921_STATE;
+	}
+
+	if (strstr(in, "config")) {
+		flags |= PRI_DEBUG_CONFIG;
+	}
+
+	if (strstr(in, "q931_dump")) {
+		flags |= PRI_DEBUG_Q931_DUMP;
+	}
+
+	if (strstr(in, "q931_state")) {
+		flags |= PRI_DEBUG_Q931_STATE;
+	}
+
+	if (strstr(in, "q931_anomaly")) {
+		flags |= PRI_DEBUG_Q931_ANOMALY;
+	}
+
+	if (strstr(in, "apdu")) {
+		flags |= PRI_DEBUG_APDU;
+	}
+
+	if (strstr(in, "aoc")) {
+		flags |= PRI_DEBUG_AOC;
+	}
+
+	if (strstr(in, "all")) {
+		flags |= PRI_DEBUG_ALL;
+	}
+
+	if (strstr(in, "none")) {
+		flags = 0;
+	}
+
+	return flags;
+}
+
+static zap_io_interface_t zap_libpri_interface;
+
+static zap_status_t zap_libpri_start(zap_span_t *span);
+
+/**
+ * \brief API function to kill or debug a libpri span
+ * \param stream API stream handler
+ * \param data String containing argurments
+ * \return Flags
+ */
+static ZIO_API_FUNCTION(zap_libpri_api)
+{
+	char *mycmd = NULL, *argv[10] = { 0 };
+    int argc = 0;
+	
+	if (data) {
+		mycmd = strdup(data);
+		argc = zap_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
+	}
+
+	if (argc == 2) {
+		if (!strcasecmp(argv[0], "kill")) {
+			int span_id = atoi(argv[1]);
+			zap_span_t *span = NULL;
+
+			if (zap_span_find_by_name(argv[1], &span) == ZAP_SUCCESS || zap_span_find(span_id, &span) == ZAP_SUCCESS) {
+				zap_libpri_data_t *isdn_data = span->signal_data;
+
+				if (span->start != zap_libpri_start) {
+					stream->write_function(stream, "%s: -ERR invalid span.\n", __FILE__);
+					goto done;
+				}
+
+				zap_clear_flag((&isdn_data->spri), LPWRAP_PRI_READY);
+				stream->write_function(stream, "%s: +OK killed.\n", __FILE__);
+				goto done;
+			} else {
+				stream->write_function(stream, "%s: -ERR invalid span.\n", __FILE__);
+				goto done;
+			}
+		}
+	}
+
+	if (argc > 2) {
+		if (!strcasecmp(argv[0], "debug")) {
+			zap_span_t *span = NULL;
+
+			if (zap_span_find_by_name(argv[1], &span) == ZAP_SUCCESS) {
+				zap_libpri_data_t *isdn_data = span->signal_data;
+				if (span->start != zap_libpri_start) {
+					stream->write_function(stream, "%s: -ERR invalid span.\n", __FILE__);
+					goto done;
+				}
+
+				pri_set_debug(isdn_data->spri.pri, parse_debug(argv[2]));				
+				stream->write_function(stream, "%s: +OK debug set.\n", __FILE__);
+				goto done;
+			} else {
+				stream->write_function(stream, "%s: -ERR invalid span.\n", __FILE__);
+				goto done;
+			}
+		}
+
+	}
+
+	stream->write_function(stream, "%s: -ERR invalid command.\n", __FILE__);
+	
+ done:
+
+	zap_safe_free(mycmd);
+
+	return ZAP_SUCCESS;
+}
+
+/**
+ * \brief Loads libpri IO module
+ * \param zio Openzap IO interface
+ * \return Success
+ */
+static ZIO_IO_LOAD_FUNCTION(zap_libpri_io_init)
+{
+	assert(zio != NULL);
+	memset(&zap_libpri_interface, 0, sizeof(zap_libpri_interface));
+
+	zap_libpri_interface.name = "libpri";
+	zap_libpri_interface.api = zap_libpri_api;
+
+	*zio = &zap_libpri_interface;
+
+	return ZAP_SUCCESS;
+}
+
+/**
+ * \brief Loads libpri signaling module
+ * \param zio Openzap IO interface
+ * \return Success
+ */
+static ZIO_SIG_LOAD_FUNCTION(zap_libpri_init)
+{
+	pri_set_error(s_pri_error);
+	pri_set_message(s_pri_message);
+	return ZAP_SUCCESS;
+}
+
+/**
+ * \brief libpri state map
+ */
+static zap_state_map_t isdn_state_map = {
+	{
+		{
+			ZSD_OUTBOUND,
+			ZSM_UNACCEPTABLE,
+			{ZAP_ANY_STATE},
+			{ZAP_CHANNEL_STATE_RESTART, ZAP_END}
+		},
+		{
+			ZSD_OUTBOUND,
+			ZSM_UNACCEPTABLE,
+			{ZAP_CHANNEL_STATE_RESTART, ZAP_END},
+			{ZAP_CHANNEL_STATE_DOWN, ZAP_END}
+		},
+		{
+			ZSD_OUTBOUND,
+			ZSM_UNACCEPTABLE,
+			{ZAP_CHANNEL_STATE_DOWN, ZAP_END},
+			{ZAP_CHANNEL_STATE_DIALING, ZAP_END}
+		},
+		{
+			ZSD_OUTBOUND,
+			ZSM_UNACCEPTABLE,
+			{ZAP_CHANNEL_STATE_DIALING, ZAP_END},
+			{ZAP_CHANNEL_STATE_PROGRESS_MEDIA, ZAP_CHANNEL_STATE_PROGRESS, ZAP_CHANNEL_STATE_UP, ZAP_CHANNEL_STATE_HANGUP, ZAP_CHANNEL_STATE_TERMINATING, ZAP_END}
+		},
+		{
+			ZSD_OUTBOUND,
+			ZSM_UNACCEPTABLE,
+			{ZAP_CHANNEL_STATE_PROGRESS_MEDIA, ZAP_CHANNEL_STATE_PROGRESS, ZAP_END},
+			{ZAP_CHANNEL_STATE_HANGUP, ZAP_CHANNEL_STATE_PROGRESS_MEDIA, ZAP_CHANNEL_STATE_TERMINATING, ZAP_CHANNEL_STATE_UP, ZAP_END}
+		},
+		{
+			ZSD_OUTBOUND,
+			ZSM_UNACCEPTABLE,
+			{ZAP_CHANNEL_STATE_HANGUP, ZAP_CHANNEL_STATE_TERMINATING, ZAP_END},
+			{ZAP_CHANNEL_STATE_HANGUP_COMPLETE, ZAP_CHANNEL_STATE_DOWN, ZAP_END}
+		},
+		{
+			ZSD_OUTBOUND,
+			ZSM_UNACCEPTABLE,
+			{ZAP_CHANNEL_STATE_HANGUP_COMPLETE, ZAP_END},
+			{ZAP_CHANNEL_STATE_DOWN, ZAP_END},
+		},
+		{
+			ZSD_OUTBOUND,
+			ZSM_UNACCEPTABLE,
+			{ZAP_CHANNEL_STATE_UP, ZAP_END},
+			{ZAP_CHANNEL_STATE_HANGUP, ZAP_CHANNEL_STATE_TERMINATING, ZAP_END}
+		},
+
+		/****************************************/
+		{
+			ZSD_INBOUND,
+			ZSM_UNACCEPTABLE,
+			{ZAP_ANY_STATE},
+			{ZAP_CHANNEL_STATE_RESTART, ZAP_END}
+		},
+		{
+			ZSD_INBOUND,
+			ZSM_UNACCEPTABLE,
+			{ZAP_CHANNEL_STATE_RESTART, ZAP_END},
+			{ZAP_CHANNEL_STATE_DOWN, ZAP_END}
+		},
+		{
+			ZSD_INBOUND,
+			ZSM_UNACCEPTABLE,
+			{ZAP_CHANNEL_STATE_DOWN, ZAP_END},
+			{ZAP_CHANNEL_STATE_DIALTONE, ZAP_CHANNEL_STATE_RING, ZAP_END}
+		},
+		{
+			ZSD_INBOUND,
+			ZSM_UNACCEPTABLE,
+			{ZAP_CHANNEL_STATE_DIALTONE, ZAP_END},
+			{ZAP_CHANNEL_STATE_RING, ZAP_CHANNEL_STATE_HANGUP, ZAP_CHANNEL_STATE_TERMINATING, ZAP_END}
+		},
+		{
+			ZSD_INBOUND,
+			ZSM_UNACCEPTABLE,
+			{ZAP_CHANNEL_STATE_RING, ZAP_END},
+			{ZAP_CHANNEL_STATE_HANGUP, ZAP_CHANNEL_STATE_TERMINATING, ZAP_CHANNEL_STATE_PROGRESS, ZAP_CHANNEL_STATE_PROGRESS_MEDIA, ZAP_CHANNEL_STATE_UP, ZAP_END}
+		},
+		{
+			ZSD_INBOUND,
+			ZSM_UNACCEPTABLE,
+			{ZAP_CHANNEL_STATE_HANGUP, ZAP_CHANNEL_STATE_TERMINATING, ZAP_END},
+			{ZAP_CHANNEL_STATE_HANGUP_COMPLETE, ZAP_CHANNEL_STATE_DOWN, ZAP_END},
+		},
+		{
+			ZSD_INBOUND,
+			ZSM_UNACCEPTABLE,
+			{ZAP_CHANNEL_STATE_HANGUP_COMPLETE, ZAP_END},
+			{ZAP_CHANNEL_STATE_DOWN, ZAP_END},
+		},
+		{
+			ZSD_INBOUND,
+			ZSM_UNACCEPTABLE,
+			{ZAP_CHANNEL_STATE_PROGRESS, ZAP_CHANNEL_STATE_PROGRESS_MEDIA, ZAP_END},
+			{ZAP_CHANNEL_STATE_HANGUP, ZAP_CHANNEL_STATE_TERMINATING, ZAP_CHANNEL_STATE_PROGRESS_MEDIA, 
+			 ZAP_CHANNEL_STATE_CANCEL, ZAP_CHANNEL_STATE_UP, ZAP_END},
+		},
+		{
+			ZSD_INBOUND,
+			ZSM_UNACCEPTABLE,
+			{ZAP_CHANNEL_STATE_UP, ZAP_END},
+			{ZAP_CHANNEL_STATE_HANGUP, ZAP_CHANNEL_STATE_TERMINATING, ZAP_END},
+		},
+		
+
+	}
+};
+
+/**
+ * \brief Handler for channel state change
+ * \param zchan Channel to handle
+ */
+static __inline__ void state_advance(zap_channel_t *zchan)
+{
+	//Q931mes_Generic *gen = (Q931mes_Generic *) zchan->caller_data.raw_data;
+	zap_libpri_data_t *isdn_data = zchan->span->signal_data;
+	zap_status_t status;
+	zap_sigmsg_t sig;
+	q931_call *call = (q931_call *) zchan->call_data;
+	
+	
+	zap_log(ZAP_LOG_DEBUG, "%d:%d STATE [%s]\n", 
+			zchan->span_id, zchan->chan_id, zap_channel_state2str(zchan->state));
+
+
+#if 0
+	if (!zap_test_flag(zchan, ZAP_CHANNEL_OUTBOUND) && !call) {
+		zap_log(ZAP_LOG_WARNING, "NO CALL!!!!\n");
+	}
+#endif
+
+	
+	memset(&sig, 0, sizeof(sig));
+	sig.chan_id = zchan->chan_id;
+	sig.span_id = zchan->span_id;
+	sig.channel = zchan;
+
+
+	switch (zchan->state) {
+	case ZAP_CHANNEL_STATE_DOWN:
+		{
+			zchan->call_data = NULL;
+			zap_channel_done(zchan);			
+		}
+		break;
+	case ZAP_CHANNEL_STATE_PROGRESS:
+		{
+			if (zap_test_flag(zchan, ZAP_CHANNEL_OUTBOUND)) {
+				sig.event_id = ZAP_SIGEVENT_PROGRESS;
+				if ((status = zap_span_send_signal(zchan->span, &sig) != ZAP_SUCCESS)) {
+					zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_HANGUP);
+				}
+			} else if (call) {
+				pri_progress(isdn_data->spri.pri, call, zchan->chan_id, 1);
+			} else {
+				zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_RESTART);
+			}
+		}
+		break;
+	case ZAP_CHANNEL_STATE_PROGRESS_MEDIA:
+		{
+			if (zap_test_flag(zchan, ZAP_CHANNEL_OUTBOUND)) {
+				sig.event_id = ZAP_SIGEVENT_PROGRESS_MEDIA;
+				if ((status = zap_span_send_signal(zchan->span, &sig) != ZAP_SUCCESS)) {
+					zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_HANGUP);
+				}
+			} else if (call) {
+				pri_proceeding(isdn_data->spri.pri, call, zchan->chan_id, 1);
+			} else {
+				zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_RESTART);
+			}
+		}
+		break;
+	case ZAP_CHANNEL_STATE_RING:
+		{
+			if (!zap_test_flag(zchan, ZAP_CHANNEL_OUTBOUND)) {
+				if (call) {
+					pri_acknowledge(isdn_data->spri.pri, call, zchan->chan_id, 0);
+					sig.event_id = ZAP_SIGEVENT_START;
+					if ((status = zap_span_send_signal(zchan->span, &sig) != ZAP_SUCCESS)) {
+						zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_HANGUP);
+					}
+				} else {
+					zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_RESTART);
+				}
+			}
+		}
+		break;
+	case ZAP_CHANNEL_STATE_RESTART:
+		{
+			zchan->caller_data.hangup_cause = ZAP_CAUSE_NORMAL_UNSPECIFIED;
+			sig.event_id = ZAP_SIGEVENT_RESTART;
+			status = zap_span_send_signal(zchan->span, &sig);
+			zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_DOWN);
+		}
+		break;
+	case ZAP_CHANNEL_STATE_UP:
+		{
+			if (zap_test_flag(zchan, ZAP_CHANNEL_OUTBOUND)) {
+				sig.event_id = ZAP_SIGEVENT_UP;
+				if ((status = zap_span_send_signal(zchan->span, &sig) != ZAP_SUCCESS)) {
+					zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_HANGUP);
+				}
+			} else if (call) {
+				pri_answer(isdn_data->spri.pri, call, 0, 1);
+			} else {
+				zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_RESTART);
+			}
+		}
+		break;
+	case ZAP_CHANNEL_STATE_DIALING:
+		if (isdn_data) {
+			struct pri_sr *sr;
+			int dp;
+
+			if (!(call = pri_new_call(isdn_data->spri.pri))) {
+				zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_RESTART);
+				return;
+			}
+
+			
+			dp = zchan->caller_data.ani.type;
+			switch(dp) {
+			case ZAP_TON_NATIONAL:
+				dp = PRI_NATIONAL_ISDN;
+				break;
+			case ZAP_TON_INTERNATIONAL:
+				dp = PRI_INTERNATIONAL_ISDN;
+				break;
+			case ZAP_TON_SUBSCRIBER_NUMBER:
+				dp = PRI_LOCAL_ISDN;
+				break;
+			default:
+				dp = isdn_data->dp;
+			}
+
+			zchan->call_data = call;
+			sr = pri_sr_new();
+			assert(sr);
+			pri_sr_set_channel(sr, zchan->chan_id, 0, 0);
+			pri_sr_set_bearer(sr, 0, isdn_data->l1);
+			pri_sr_set_called(sr, zchan->caller_data.ani.digits, dp, 1);
+			pri_sr_set_caller(sr, zchan->caller_data.cid_num.digits, (isdn_data->opts & OZMOD_LIBPRI_OPT_OMIT_DISPLAY_IE ? NULL : zchan->caller_data.cid_name),
+						dp, (zchan->caller_data.pres != 1 ? PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN : PRES_PROHIB_USER_NUMBER_NOT_SCREENED));
+
+			if (!(isdn_data->opts & OZMOD_LIBPRI_OPT_OMIT_REDIRECTING_NUMBER_IE)) {
+				pri_sr_set_redirecting(sr, zchan->caller_data.cid_num.digits, dp, PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN, PRI_REDIR_UNCONDITIONAL);
+			}
+
+			if (pri_setup(isdn_data->spri.pri, call, sr)) {
+				zchan->caller_data.hangup_cause = ZAP_CAUSE_DESTINATION_OUT_OF_ORDER;				
+				zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_HANGUP);
+			}
+
+			pri_sr_free(sr);
+		}
+
+		break;
+	case ZAP_CHANNEL_STATE_HANGUP:
+		{
+			if (call) {
+				pri_hangup(isdn_data->spri.pri, call, zchan->caller_data.hangup_cause);
+				pri_destroycall(isdn_data->spri.pri, call);
+				zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_DOWN);
+			} else {
+				zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_RESTART);
+			}
+		}
+		break;
+	case ZAP_CHANNEL_STATE_HANGUP_COMPLETE:
+		break;
+	case ZAP_CHANNEL_STATE_TERMINATING:
+		{
+			sig.event_id = ZAP_SIGEVENT_STOP;
+			status = zap_span_send_signal(zchan->span, &sig);
+			zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_DOWN);
+
+		}
+	default:
+		break;
+	}
+
+
+
+	return;
+}
+
+/**
+ * \brief Checks current state on a span
+ * \param span Span to check status on
+ */
+static __inline__ void check_state(zap_span_t *span)
+{
+    if (zap_test_flag(span, ZAP_SPAN_STATE_CHANGE)) {
+        uint32_t j;
+        zap_clear_flag_locked(span, ZAP_SPAN_STATE_CHANGE);
+        for(j = 1; j <= span->chan_count; j++) {
+            if (zap_test_flag((span->channels[j]), ZAP_CHANNEL_STATE_CHANGE)) {
+				zap_mutex_lock(span->channels[j]->mutex);
+                zap_clear_flag((span->channels[j]), ZAP_CHANNEL_STATE_CHANGE);
+                state_advance(span->channels[j]);
+                zap_channel_complete_state(span->channels[j]);
+				zap_mutex_unlock(span->channels[j]->mutex);
+            }
+        }
+    }
+}
+
+/**
+ * \brief Handler for libpri information event (incoming call?)
+ * \param spri Pri wrapper structure (libpri, span, dchan)
+ * \param event_type Event type (unused)
+ * \param pevent Event
+ * \return 0
+ */
+static int on_info(lpwrap_pri_t *spri, lpwrap_pri_event_t event_type, pri_event *pevent)
+{
+
+	zap_log(ZAP_LOG_DEBUG, "number is: %s\n", pevent->ring.callednum);
+	if (strlen(pevent->ring.callednum) > 3) {
+		zap_log(ZAP_LOG_DEBUG, "final number is: %s\n", pevent->ring.callednum);
+		pri_answer(spri->pri, pevent->ring.call, 0, 1);
+	}
+	return 0;
+}
+
+/**
+ * \brief Handler for libpri hangup event
+ * \param spri Pri wrapper structure (libpri, span, dchan)
+ * \param event_type Event type (unused)
+ * \param pevent Event
+ * \return 0
+ */
+static int on_hangup(lpwrap_pri_t *spri, lpwrap_pri_event_t event_type, pri_event *pevent)
+{
+	zap_span_t *span = spri->private_info;
+	zap_channel_t *zchan = NULL;
+	q931_call *call = NULL;
+	zchan = span->channels[pevent->hangup.channel];
+	
+	if (zchan) {
+		call = (q931_call *) zchan->call_data;
+		zap_log(ZAP_LOG_DEBUG, "-- Hangup on channel %d:%d\n", spri->span->span_id, pevent->hangup.channel);
+		zchan->caller_data.hangup_cause = pevent->hangup.cause;
+		pri_release(spri->pri, call, 0);
+		pri_destroycall(spri->pri, call);
+		zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_TERMINATING);
+	} else {
+		zap_log(ZAP_LOG_DEBUG, "-- Hangup on channel %d:%d %s but it's not in use?\n", spri->span->span_id,
+				pevent->hangup.channel, zchan->chan_id);
+	}
+
+	return 0;
+}
+
+/**
+ * \brief Handler for libpri answer event
+ * \param spri Pri wrapper structure (libpri, span, dchan)
+ * \param event_type Event type (unused)
+ * \param pevent Event
+ * \return 0
+ */
+static int on_answer(lpwrap_pri_t *spri, lpwrap_pri_event_t event_type, pri_event *pevent)
+{
+	zap_span_t *span = spri->private_info;
+	zap_channel_t *zchan = NULL;
+
+	zchan = span->channels[pevent->answer.channel];
+	
+	if (zchan) {
+		zap_log(ZAP_LOG_DEBUG, "-- Answer on channel %d:%d\n", spri->span->span_id, pevent->answer.channel);
+		zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_UP);
+	} else {
+		zap_log(ZAP_LOG_DEBUG, "-- Answer on channel %d:%d %s but it's not in use?\n", spri->span->span_id, pevent->answer.channel, zchan->chan_id);
+				
+	}
+
+	return 0;
+}
+
+/**
+ * \brief Handler for libpri proceed event
+ * \param spri Pri wrapper structure (libpri, span, dchan)
+ * \param event_type Event type (unused)
+ * \param pevent Event
+ * \return 0
+ */
+static int on_proceed(lpwrap_pri_t *spri, lpwrap_pri_event_t event_type, pri_event *pevent)
+{
+	zap_span_t *span = spri->private_info;
+	zap_channel_t *zchan = NULL;
+	
+	zchan = span->channels[pevent->proceeding.channel];
+	
+	if (zchan) {
+		zap_log(ZAP_LOG_DEBUG, "-- Proceeding on channel %d:%d\n", spri->span->span_id, pevent->proceeding.channel);
+		zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_PROGRESS_MEDIA);
+	} else {
+		zap_log(ZAP_LOG_DEBUG, "-- Proceeding on channel %d:%d %s but it's not in use?\n", spri->span->span_id,
+						  pevent->proceeding.channel, zchan->chan_id);
+	}
+
+	return 0;
+}
+
+/**
+ * \brief Handler for libpri ringing event
+ * \param spri Pri wrapper structure (libpri, span, dchan)
+ * \param event_type Event type (unused)
+ * \param pevent Event
+ * \return 0
+ */
+static int on_ringing(lpwrap_pri_t *spri, lpwrap_pri_event_t event_type, pri_event *pevent)
+{
+	zap_span_t *span = spri->private_info;
+	zap_channel_t *zchan = NULL;
+
+	zchan = span->channels[pevent->ringing.channel];
+	
+	if (zchan) {
+		zap_log(ZAP_LOG_DEBUG, "-- Ringing on channel %d:%d\n", spri->span->span_id, pevent->ringing.channel);
+		/* we may get on_ringing even when we're already in ZAP_CHANNEL_STATE_PROGRESS_MEDIA */
+		if (zchan->state == ZAP_CHANNEL_STATE_PROGRESS_MEDIA) {
+			/* dont try to move to STATE_PROGRESS to avoid annoying veto warning */
+			return 0;
+		}
+		zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_PROGRESS);
+	} else {
+		zap_log(ZAP_LOG_DEBUG, "-- Ringing on channel %d:%d %s but it's not in use?\n", spri->span->span_id,
+						  pevent->ringing.channel, zchan->chan_id);
+	}
+
+	return 0;
+}
+
+/**
+ * \brief Handler for libpri ring event
+ * \param spri Pri wrapper structure (libpri, span, dchan)
+ * \param event_type Event type (unused)
+ * \param pevent Event
+ * \return 0 on success
+ */
+static int on_ring(lpwrap_pri_t *spri, lpwrap_pri_event_t event_type, pri_event *pevent)
+{
+	zap_span_t *span = spri->private_info;
+	zap_channel_t *zchan = NULL;
+	int ret = 0;
+
+	//switch_mutex_lock(globals.channel_mutex);
+	
+	zchan = span->channels[pevent->ring.channel];
+	if (!zchan || zchan->state != ZAP_CHANNEL_STATE_DOWN || zap_test_flag(zchan, ZAP_CHANNEL_INUSE)) {
+		zap_log(ZAP_LOG_WARNING, "--Duplicate Ring on channel %d:%d (ignored)\n", spri->span->span_id, pevent->ring.channel);
+		ret = 0;
+		goto done;
+	}
+
+	if (zap_channel_open_chan(zchan) != ZAP_SUCCESS) {
+		zap_log(ZAP_LOG_WARNING, "--Failure opening channel %d:%d (ignored)\n", spri->span->span_id, pevent->ring.channel);
+		ret = 0;
+		goto done;
+	}
+	
+
+	zap_log(ZAP_LOG_NOTICE, "-- Ring on channel %d:%d (from %s to %s)\n", spri->span->span_id, pevent->ring.channel,
+					  pevent->ring.callingnum, pevent->ring.callednum);
+	
+	memset(&zchan->caller_data, 0, sizeof(zchan->caller_data));
+	
+	zap_set_string(zchan->caller_data.cid_num.digits, (char *)pevent->ring.callingnum);
+	if (!zap_strlen_zero((char *)pevent->ring.callingname)) {
+		zap_set_string(zchan->caller_data.cid_name, (char *)pevent->ring.callingname);
+	} else {
+		zap_set_string(zchan->caller_data.cid_name, (char *)pevent->ring.callingnum);
+	}
+	zap_set_string(zchan->caller_data.ani.digits, (char *)pevent->ring.callingani);
+	zap_set_string(zchan->caller_data.dnis.digits, (char *)pevent->ring.callednum);
+	
+	if (pevent->ring.ani2 >= 0) {
+		snprintf(zchan->caller_data.aniII, 5, "%.2d", pevent->ring.ani2);
+	}
+	
+	// scary to trust this pointer, you'd think they would give you a copy of the call data so you own it......
+	zchan->call_data = pevent->ring.call;
+	
+	zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_RING);
+	
+ done:
+	//switch_mutex_unlock(globals.channel_mutex);
+
+	return ret;
+}
+
+/**
+ * \brief Processes openzap event
+ * \param span Span on which the event was fired
+ * \param event Event to be treated
+ * \return Success or failure
+ */
+static __inline__ zap_status_t process_event(zap_span_t *span, zap_event_t *event)
+{
+	zap_log(ZAP_LOG_DEBUG, "EVENT [%s][%d][%d:%d] STATE [%s]\n", 
+			zap_oob_event2str(event->enum_id), event->enum_id, event->channel->span_id, event->channel->chan_id, zap_channel_state2str(event->channel->state));
+
+	switch(event->enum_id) {
+	case ZAP_OOB_ALARM_TRAP:
+		{
+			if (event->channel->state != ZAP_CHANNEL_STATE_DOWN) {
+				if (event->channel->type == ZAP_CHAN_TYPE_B) {
+					zap_set_state_locked(event->channel, ZAP_CHANNEL_STATE_RESTART);
+				}
+			}
+			
+
+			zap_set_flag(event->channel, ZAP_CHANNEL_SUSPENDED);
+
+			
+			zap_channel_get_alarms(event->channel);
+			zap_log(ZAP_LOG_WARNING, "channel %d:%d (%d:%d) has alarms! [%s]\n", 
+					event->channel->span_id, event->channel->chan_id, 
+					event->channel->physical_span_id, event->channel->physical_chan_id, 
+					event->channel->last_error);
+		}
+		break;
+	case ZAP_OOB_ALARM_CLEAR:
+		{
+			zap_log(ZAP_LOG_WARNING, "channel %d:%d (%d:%d) alarms Cleared!\n", event->channel->span_id, event->channel->chan_id,
+					event->channel->physical_span_id, event->channel->physical_chan_id);
+
+			zap_clear_flag(event->channel, ZAP_CHANNEL_SUSPENDED);
+			zap_channel_get_alarms(event->channel);
+		}
+		break;
+	}
+
+	return ZAP_SUCCESS;
+}
+
+/**
+ * \brief Checks for events on a span
+ * \param span Span to check for events
+ */
+static __inline__ void check_events(zap_span_t *span)
+{
+	zap_status_t status;
+
+	status = zap_span_poll_event(span, 5);
+
+	switch(status) {
+	case ZAP_SUCCESS:
+		{
+			zap_event_t *event;
+			while (zap_span_next_event(span, &event) == ZAP_SUCCESS) {
+				if (event->enum_id == ZAP_OOB_NOOP) {
+					continue;
+				}
+				if (process_event(span, event) != ZAP_SUCCESS) {
+					break;
+				}
+			}
+		}
+		break;
+	case ZAP_FAIL:
+		{
+			zap_log(ZAP_LOG_DEBUG, "Event Failure! %d\n", zap_running());
+			zap_sleep(2000);
+		}
+		break;
+	default:
+		break;
+	}
+}
+
+/**
+ * \brief Checks flags on a pri span
+ * \param spri Pri wrapper structure (libpri, span, dchan)
+ * \return 0 on success, -1 on error
+ */
+static int check_flags(lpwrap_pri_t *spri)
+{
+	zap_span_t *span = spri->private_info;
+
+	if (!zap_running() || zap_test_flag(span, ZAP_SPAN_STOP_THREAD)) {
+		return -1;
+	}
+
+	check_state(span);
+	check_events(span);
+
+
+	return 0;
+}
+
+/**
+ * \brief Handler for libpri restart event
+ * \param spri Pri wrapper structure (libpri, span, dchan)
+ * \param event_type Event type (unused)
+ * \param pevent Event
+ * \return 0
+ */
+static int on_restart(lpwrap_pri_t *spri, lpwrap_pri_event_t event_type, pri_event *pevent)
+{
+	zap_span_t *span = spri->private_info;
+	zap_channel_t *zchan;
+
+	zap_log(ZAP_LOG_NOTICE, "-- Restarting %d:%d\n", spri->span->span_id, pevent->restart.channel);
+
+	zchan = span->channels[pevent->restart.channel];
+
+	if (!zchan) {
+		return 0;
+	}
+
+	if (pevent->restart.channel < 1) {
+		zap_set_state_all(zchan->span, ZAP_CHANNEL_STATE_RESTART);
+	} else {
+		zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_RESTART);
+	}
+
+	return 0;
+}
+
+/**
+ * \brief Handler for libpri dchan up event
+ * \param spri Pri wrapper structure (libpri, span, dchan)
+ * \param event_type Event type (unused)
+ * \param pevent Event
+ * \return 0
+ */
+static int on_dchan_up(lpwrap_pri_t *spri, lpwrap_pri_event_t event_type, pri_event *pevent)
+{
+	
+	if (!zap_test_flag(spri, LPWRAP_PRI_READY)) {
+		zap_log(ZAP_LOG_INFO, "Span %d D-Chan UP!\n", spri->span->span_id);
+		zap_set_flag(spri, LPWRAP_PRI_READY);
+		zap_set_state_all(spri->span, ZAP_CHANNEL_STATE_RESTART);
+	}
+
+	return 0;
+}
+
+/**
+ * \brief Handler for libpri dchan down event
+ * \param spri Pri wrapper structure (libpri, span, dchan)
+ * \param event_type Event type (unused)
+ * \param pevent Event
+ * \return 0
+ */
+static int on_dchan_down(lpwrap_pri_t *spri, lpwrap_pri_event_t event_type, pri_event *pevent)
+{
+
+	if (zap_test_flag(spri, LPWRAP_PRI_READY)) {
+		zap_log(ZAP_LOG_INFO, "Span %d D-Chan DOWN!\n", spri->span->span_id);
+		zap_clear_flag(spri, LPWRAP_PRI_READY);
+		zap_set_state_all(spri->span, ZAP_CHANNEL_STATE_RESTART);
+		
+	}
+
+	return 0;
+}
+
+/**
+ * \brief Handler for any libpri event
+ * \param spri Pri wrapper structure (libpri, span, dchan)
+ * \param event_type Event type (unused)
+ * \param pevent Event
+ * \return 0
+ */
+static int on_anything(lpwrap_pri_t *spri, lpwrap_pri_event_t event_type, pri_event *pevent)
+{
+
+	zap_log(ZAP_LOG_DEBUG, "Caught Event span %d %u (%s)\n", spri->span->span_id, event_type, lpwrap_pri_event_str(event_type));
+	return 0;
+}
+
+/**
+ * \brief Handler for libpri io fail event
+ * \param spri Pri wrapper structure (libpri, span, dchan)
+ * \param event_type Event type (unused)
+ * \param pevent Event
+ * \return 0
+ */
+static int on_io_fail(lpwrap_pri_t *spri, lpwrap_pri_event_t event_type, pri_event *pevent)
+{
+
+	zap_log(ZAP_LOG_DEBUG, "Caught Event span %d %u (%s)\n", spri->span->span_id, event_type, lpwrap_pri_event_str(event_type));
+	return 0;
+}
+
+/**
+ * \brief Main thread function for libpri span (monitor)
+ * \param me Current thread
+ * \param obj Span to run in this thread
+ */
+static void *zap_libpri_run(zap_thread_t *me, void *obj)
+{
+	zap_span_t *span = (zap_span_t *) obj;
+	zap_libpri_data_t *isdn_data = span->signal_data;
+	int i, x = 0;
+	int down = 0;
+	int got_d = 0;
+	
+	zap_set_flag(span, ZAP_SPAN_IN_THREAD);
+	
+	while(zap_running() && !zap_test_flag(span, ZAP_SPAN_STOP_THREAD)) {
+		if (!got_d) {
+			for(i = 1; i <= span->chan_count; i++) {
+				if (span->channels[i]->type == ZAP_CHAN_TYPE_DQ921) {
+					if (zap_channel_open(span->span_id, i, &isdn_data->dchan) == ZAP_SUCCESS) {
+						zap_log(ZAP_LOG_DEBUG, "opening d-channel #%d %d:%d\n", x, isdn_data->dchan->span_id, isdn_data->dchan->chan_id);
+						isdn_data->dchan->state = ZAP_CHANNEL_STATE_UP;
+						got_d = 1;
+						x++;
+						break;
+					}
+				}
+			}
+		}
+		
+		
+		if (lpwrap_init_pri(&isdn_data->spri,
+								  span,  // span
+								  isdn_data->dchan, // dchan
+								  isdn_data->pswitch,
+								  isdn_data->node,
+								  isdn_data->debug) < 0) {
+			snprintf(span->last_error, sizeof(span->last_error), "PRI init FAIL!");
+		} else {
+
+			LPWRAP_MAP_PRI_EVENT(isdn_data->spri, LPWRAP_PRI_EVENT_ANY, on_anything);
+			LPWRAP_MAP_PRI_EVENT(isdn_data->spri, LPWRAP_PRI_EVENT_RING, on_ring);
+			LPWRAP_MAP_PRI_EVENT(isdn_data->spri, LPWRAP_PRI_EVENT_RINGING, on_ringing);
+			//LPWRAP_MAP_PRI_EVENT(isdn_data->spri, LPWRAP_PRI_EVENT_SETUP_ACK, on_proceed);
+			LPWRAP_MAP_PRI_EVENT(isdn_data->spri, LPWRAP_PRI_EVENT_PROCEEDING, on_proceed);
+			LPWRAP_MAP_PRI_EVENT(isdn_data->spri, LPWRAP_PRI_EVENT_ANSWER, on_answer);
+			LPWRAP_MAP_PRI_EVENT(isdn_data->spri, LPWRAP_PRI_EVENT_DCHAN_UP, on_dchan_up);
+			LPWRAP_MAP_PRI_EVENT(isdn_data->spri, LPWRAP_PRI_EVENT_DCHAN_DOWN, on_dchan_down);
+			LPWRAP_MAP_PRI_EVENT(isdn_data->spri, LPWRAP_PRI_EVENT_HANGUP_REQ, on_hangup);
+			LPWRAP_MAP_PRI_EVENT(isdn_data->spri, LPWRAP_PRI_EVENT_HANGUP, on_hangup);
+			LPWRAP_MAP_PRI_EVENT(isdn_data->spri, LPWRAP_PRI_EVENT_INFO_RECEIVED, on_info);
+			LPWRAP_MAP_PRI_EVENT(isdn_data->spri, LPWRAP_PRI_EVENT_RESTART, on_restart);
+			LPWRAP_MAP_PRI_EVENT(isdn_data->spri, LPWRAP_PRI_EVENT_IO_FAIL, on_io_fail);
+
+			if (down) {
+				zap_log(ZAP_LOG_INFO, "PRI back up on span %d\n", isdn_data->spri.span->span_id);
+				zap_set_state_all(span, ZAP_CHANNEL_STATE_RESTART);
+				down = 0;
+			}
+
+			isdn_data->spri.on_loop = check_flags;
+			isdn_data->spri.private_info = span;
+			lpwrap_run_pri(&isdn_data->spri);
+
+		}
+
+		if (!zap_running() || zap_test_flag(span, ZAP_SPAN_STOP_THREAD)) {
+			break;
+		}
+
+		zap_log(ZAP_LOG_CRIT, "PRI down on span %d\n", isdn_data->spri.span->span_id);
+
+		if (!down) {
+			zap_set_state_all(span, ZAP_CHANNEL_STATE_RESTART);
+			check_state(span);
+		}
+
+		check_state(span);
+		check_events(span);
+
+		down++;
+		zap_sleep(5000);
+	}
+
+	zap_log(ZAP_LOG_DEBUG, "PRI thread ended on span %d\n", isdn_data->spri.span->span_id);
+
+	zap_clear_flag(span, ZAP_SPAN_IN_THREAD);
+	zap_clear_flag(isdn_data, OZMOD_LIBPRI_RUNNING);
+
+	return NULL;
+}
+
+/**
+ * \brief Stops a libpri span
+ * \param span Span to halt
+ * \return Success
+ *
+ * Sets a stop flag and waits for the thread to end
+ */
+static zap_status_t zap_libpri_stop(zap_span_t *span)
+{
+	zap_libpri_data_t *isdn_data = span->signal_data;
+
+	if (!zap_test_flag(isdn_data, OZMOD_LIBPRI_RUNNING)) {
+		return ZAP_FAIL;
+	}
+
+	zap_set_state_all(span, ZAP_CHANNEL_STATE_RESTART);
+	check_state(span);
+	zap_set_flag(span, ZAP_SPAN_STOP_THREAD);
+	while(zap_test_flag(span, ZAP_SPAN_IN_THREAD)) {
+		zap_sleep(100);
+	}
+	check_state(span);
+
+	return ZAP_SUCCESS;
+}
+
+/**
+ * \brief Starts a libpri span
+ * \param span Span to halt
+ * \return Success or failure
+ *
+ * Launches a thread to monitor the span
+ */
+static zap_status_t zap_libpri_start(zap_span_t *span)
+{
+	zap_status_t ret;
+	zap_libpri_data_t *isdn_data = span->signal_data;
+
+	if (zap_test_flag(isdn_data, OZMOD_LIBPRI_RUNNING)) {
+		return ZAP_FAIL;
+	}
+
+	zap_clear_flag(span, ZAP_SPAN_STOP_THREAD);
+	zap_clear_flag(span, ZAP_SPAN_IN_THREAD);
+
+	zap_set_flag(isdn_data, OZMOD_LIBPRI_RUNNING);
+	ret = zap_thread_create_detached(zap_libpri_run, span);
+
+	if (ret != ZAP_SUCCESS) {
+		return ret;
+	}
+
+	return ret;
+}
+
+/**
+ * \brief Converts a node string to node value
+ * \param node Node string to convert
+ * \return -1 on failure, node value on success
+ */
+static int str2node(char *node)
+{
+	if (!strcasecmp(node, "cpe") || !strcasecmp(node, "user"))
+		return PRI_CPE;
+	if (!strcasecmp(node, "network") || !strcasecmp(node, "net"))
+		return PRI_NETWORK;
+	return -1;
+}
+
+/**
+ * \brief Converts a switch string to switch value
+ * \param swtype Swtype string to convert
+ * \return Switch value
+ */
+static int str2switch(char *swtype)
+{
+	if (!strcasecmp(swtype, "ni1"))
+		return PRI_SWITCH_NI1;
+	if (!strcasecmp(swtype, "ni2"))
+		return PRI_SWITCH_NI2;
+	if (!strcasecmp(swtype, "dms100"))
+		return PRI_SWITCH_DMS100;
+	if (!strcasecmp(swtype, "lucent5e") || !strcasecmp(swtype, "5ess"))
+		return PRI_SWITCH_LUCENT5E;
+	if (!strcasecmp(swtype, "att4ess") || !strcasecmp(swtype, "4ess"))
+		return PRI_SWITCH_ATT4ESS;
+	if (!strcasecmp(swtype, "euroisdn"))
+		return PRI_SWITCH_EUROISDN_E1;
+	if (!strcasecmp(swtype, "gr303eoc"))
+		return PRI_SWITCH_GR303_EOC;
+	if (!strcasecmp(swtype, "gr303tmc"))
+		return PRI_SWITCH_GR303_TMC;
+	return PRI_SWITCH_DMS100;
+}
+
+/**
+ * \brief Converts a L1 string to L1 value
+ * \param l1 L1 string to convert
+ * \return L1 value
+ */
+static int str2l1(char *l1)
+{
+	if (!strcasecmp(l1, "alaw"))
+		return PRI_LAYER_1_ALAW;
+	
+	return PRI_LAYER_1_ULAW;
+}
+
+/**
+ * \brief Converts a DP string to DP value
+ * \param dp DP string to convert
+ * \return DP value
+ */
+static int str2dp(char *dp)
+{
+	if (!strcasecmp(dp, "international"))
+		return PRI_INTERNATIONAL_ISDN;
+	if (!strcasecmp(dp, "national"))
+		return PRI_NATIONAL_ISDN;
+	if (!strcasecmp(dp, "local"))
+		return PRI_LOCAL_ISDN;
+	if (!strcasecmp(dp, "private"))
+		return PRI_PRIVATE;
+	if (!strcasecmp(dp, "unknown"))
+		return PRI_UNKNOWN;
+
+	return PRI_UNKNOWN;
+}
+
+/**
+ * \brief Initialises a libpri span from configuration variables
+ * \param span Span to configure
+ * \param sig_cb Callback function for event signals
+ * \param ap List of configuration variables
+ * \return Success or failure
+ */
+static ZIO_SIG_CONFIGURE_FUNCTION(zap_libpri_configure_span)
+{
+	uint32_t i, x = 0;
+	//zap_channel_t *dchans[2] = {0};
+	zap_libpri_data_t *isdn_data;
+	char *var, *val;
+	char *debug = NULL;
+
+	if (span->trunk_type >= ZAP_TRUNK_NONE) {
+		zap_log(ZAP_LOG_WARNING, "Invalid trunk type '%s' defaulting to T1.\n", zap_trunk_type2str(span->trunk_type));
+		span->trunk_type = ZAP_TRUNK_T1;
+	}
+	
+	for(i = 1; i <= span->chan_count; i++) {
+		if (span->channels[i]->type == ZAP_CHAN_TYPE_DQ921) {
+			if (x > 1) {
+				snprintf(span->last_error, sizeof(span->last_error), "Span has more than 2 D-Channels!");
+				return ZAP_FAIL;
+			} else {
+#if 0
+				if (zap_channel_open(span->span_id, i, &dchans[x]) == ZAP_SUCCESS) {
+					zap_log(ZAP_LOG_DEBUG, "opening d-channel #%d %d:%d\n", x, dchans[x]->span_id, dchans[x]->chan_id);
+					dchans[x]->state = ZAP_CHANNEL_STATE_UP;
+					x++;
+				}
+#endif
+			}
+		}
+	}
+	
+#if 0
+	if (!x) {
+		snprintf(span->last_error, sizeof(span->last_error), "Span has no D-Channels!");
+		return ZAP_FAIL;
+	}
+#endif
+
+	isdn_data = malloc(sizeof(*isdn_data));
+	assert(isdn_data != NULL);
+	memset(isdn_data, 0, sizeof(*isdn_data));
+
+    if (span->trunk_type == ZAP_TRUNK_E1) {
+        zap_log(ZAP_LOG_NOTICE, "Setting default Layer 1 to ALAW since this is an E1 trunk\n");
+        isdn_data->l1 = PRI_LAYER_1_ALAW;
+    } else if (span->trunk_type == ZAP_TRUNK_T1) {
+        zap_log(ZAP_LOG_NOTICE, "Setting default Layer 1 to ULAW since this is a T1 trunk\n");
+        isdn_data->l1 = PRI_LAYER_1_ULAW;
+    }
+	
+	while((var = va_arg(ap, char *))) {
+		if (!strcasecmp(var, "node")) {
+			int node;
+			if (!(val = va_arg(ap, char *))) {
+				break;
+			}
+			node = str2node(val);
+			if (-1 == node) {
+				zap_log(ZAP_LOG_ERROR, "Unknown node type %s, defaulting to CPE mode\n", val);
+				node = PRI_CPE;
+			}
+			isdn_data->node = node;
+		} else if (!strcasecmp(var, "switch")) {
+			if (!(val = va_arg(ap, char *))) {
+				break;
+			}
+			isdn_data->pswitch = str2switch(val);
+		} else if (!strcasecmp(var, "opts")) {
+			if (!(val = va_arg(ap, char *))) {
+				break;
+			}
+			isdn_data->opts = parse_opts(val);
+		} else if (!strcasecmp(var, "dp")) {
+			if (!(val = va_arg(ap, char *))) {
+				break;
+			}
+			isdn_data->dp = str2dp(val);
+		} else if (!strcasecmp(var, "l1")) {
+			if (!(val = va_arg(ap, char *))) {
+				break;
+			}
+			isdn_data->l1 = str2l1(val);
+		} else if (!strcasecmp(var, "debug")) {
+			if (!(val = va_arg(ap, char *))) {
+				break;
+			}
+			debug = val;
+		} else {
+			snprintf(span->last_error, sizeof(span->last_error), "Unknown parameter [%s]", var);
+			return ZAP_FAIL;
+		}
+	}
+    
+	span->start = zap_libpri_start;
+	span->stop = zap_libpri_stop;
+	span->signal_cb = sig_cb;
+	//isdn_data->dchans[0] = dchans[0];
+	//isdn_data->dchans[1] = dchans[1];
+	//isdn_data->dchan = isdn_data->dchans[0];
+	
+	isdn_data->debug = parse_debug(debug);
+		
+
+	span->signal_data = isdn_data;
+	span->signal_type = ZAP_SIGTYPE_ISDN;
+	span->outgoing_call = isdn_outgoing_call;
+
+	if ((isdn_data->opts & OZMOD_LIBPRI_OPT_SUGGEST_CHANNEL)) {
+		span->channel_request = isdn_channel_request;
+		span->suggest_chan_id = 1;
+	}
+
+	span->state_map = &isdn_state_map;
+
+	return ZAP_SUCCESS;
+}
+
+/**
+ * \brief Openzap libpri signaling and IO module definition
+ */
+zap_module_t zap_module = { 
+	"libpri",
+	zap_libpri_io_init,
+	zap_libpri_unload,
+	zap_libpri_init,
+	zap_libpri_configure_span,
+	NULL
+};
+
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */

Added: freeswitch/trunk/libs/openzap/src/ozmod/ozmod_libpri/ozmod_libpri.h (0 => 17141)


--- freeswitch/trunk/libs/openzap/src/ozmod/ozmod_libpri/ozmod_libpri.h	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/src/ozmod/ozmod_libpri/ozmod_libpri.h	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2009, Anthony Minessale II
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#ifndef OZMOD_LIBPRI_H
+#define OZMOD_LIBPRI_H
+#include "openzap.h"
+#include "lpwrap_pri.h"
+
+typedef enum {
+	OZMOD_LIBPRI_OPT_NONE = 0,
+	OZMOD_LIBPRI_OPT_SUGGEST_CHANNEL = (1 << 0),
+	OZMOD_LIBPRI_OPT_OMIT_DISPLAY_IE = (1 << 1),
+	OZMOD_LIBPRI_OPT_OMIT_REDIRECTING_NUMBER_IE = (1 << 2),
+		
+	OZMOD_LIBPRI_OPT_MAX = (1 << 3)
+} zap_isdn_opts_t;
+
+typedef enum {
+	OZMOD_LIBPRI_RUNNING = (1 << 0)
+} zap_isdn_flag_t;
+
+
+struct zap_libpri_data {
+	zap_channel_t *dchan;
+	zap_channel_t *dchans[2];
+	struct zap_sigmsg sigmsg;
+	uint32_t flags;
+	int32_t mode;
+	zap_isdn_opts_t opts;
+
+	int node;
+	int pswitch;
+	char *dialplan;
+	unsigned int l1;
+	unsigned int dp;
+
+	int debug;
+
+	lpwrap_pri_t spri;
+};
+
+typedef struct zap_libpri_data zap_libpri_data_t;
+
+
+/* b-channel private data */
+struct zap_isdn_bchan_data
+{
+	int32_t digit_timeout;
+};
+
+typedef struct zap_isdn_bchan_data zap_isdn_bchan_data_t;
+
+
+#endif
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
+

Added: freeswitch/trunk/libs/openzap/src/ozmod/ozmod_pika/ozmod_pika.2005.vcproj (0 => 17141)


--- freeswitch/trunk/libs/openzap/src/ozmod/ozmod_pika/ozmod_pika.2005.vcproj	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/src/ozmod/ozmod_pika/ozmod_pika.2005.vcproj	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,197 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="8.00"
+	Name="ozmod_pika"
+	ProjectGUID="{E886B4D5-AB4F-4092-B8F4-3B06E1E462EF}"
+	RootNamespace="ozmod_pika"
+	Keyword="Win32Proj"
+	TargetFrameworkVersion="196613"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="2"
+			CharacterSet="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				AdditionalIncludeDirectories="..\..\isdn\include;..\..\include;..\..\..\pika\aoh\inc"
+				PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;OZMOD_PIKA_EXPORTS"
+				MinimalRebuild="true"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="3"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				DebugInformationFormat="4"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="pikahmpapi.lib"
+				LinkIncremental="2"
+				AdditionalLibraryDirectories="..\..\..\pika\aoh\lib"
+				GenerateDebugInformation="true"
+				SubSystem="2"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="2"
+			CharacterSet="1"
+			WholeProgramOptimization="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="2"
+				EnableIntrinsicFunctions="true"
+				AdditionalIncludeDirectories="..\..\isdn\include;..\..\include;..\..\..\pika\aoh\inc"
+				PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;OZMOD_PIKA_EXPORTS"
+				RuntimeLibrary="2"
+				EnableFunctionLevelLinking="true"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				DebugInformationFormat="3"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="pikahmpapi.lib"
+				LinkIncremental="1"
+				AdditionalLibraryDirectories="..\..\..\pika\aoh\lib"
+				GenerateDebugInformation="true"
+				SubSystem="2"
+				OptimizeReferences="2"
+				EnableCOMDATFolding="2"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<Filter
+			Name="Source Files"
+			Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+			>
+			<File
+				RelativePath=".\ozmod_pika.c"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="Header Files"
+			Filter="h;hpp;hxx;hm;inl;inc;xsd"
+			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+			>
+			<File
+				RelativePath=".\zap_pika.h"
+				>
+			</File>
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>

Added: freeswitch/trunk/libs/openzap/src/ozmod/ozmod_pika/ozmod_pika.2008.vcproj (0 => 17141)


--- freeswitch/trunk/libs/openzap/src/ozmod/ozmod_pika/ozmod_pika.2008.vcproj	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/src/ozmod/ozmod_pika/ozmod_pika.2008.vcproj	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,197 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="9.00"
+	Name="ozmod_pika"
+	ProjectGUID="{E886B4D5-AB4F-4092-B8F4-3B06E1E462EF}"
+	RootNamespace="ozmod_pika"
+	Keyword="Win32Proj"
+	TargetFrameworkVersion="196613"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="2"
+			CharacterSet="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				AdditionalIncludeDirectories="..\..\isdn\include;..\..\include;..\..\..\pika\aoh\inc"
+				PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;OZMOD_PIKA_EXPORTS"
+				MinimalRebuild="true"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="3"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				DebugInformationFormat="4"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="pikahmpapi.lib"
+				LinkIncremental="2"
+				AdditionalLibraryDirectories="..\..\..\pika\aoh\lib"
+				GenerateDebugInformation="true"
+				SubSystem="2"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="2"
+			CharacterSet="1"
+			WholeProgramOptimization="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="2"
+				EnableIntrinsicFunctions="true"
+				AdditionalIncludeDirectories="..\..\isdn\include;..\..\include;..\..\..\pika\aoh\inc"
+				PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;OZMOD_PIKA_EXPORTS"
+				RuntimeLibrary="2"
+				EnableFunctionLevelLinking="true"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				DebugInformationFormat="3"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="pikahmpapi.lib"
+				LinkIncremental="1"
+				AdditionalLibraryDirectories="..\..\..\pika\aoh\lib"
+				GenerateDebugInformation="true"
+				SubSystem="2"
+				OptimizeReferences="2"
+				EnableCOMDATFolding="2"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<Filter
+			Name="Source Files"
+			Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+			>
+			<File
+				RelativePath=".\ozmod_pika.c"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="Header Files"
+			Filter="h;hpp;hxx;hm;inl;inc;xsd"
+			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+			>
+			<File
+				RelativePath=".\zap_pika.h"
+				>
+			</File>
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>

Added: freeswitch/trunk/libs/openzap/src/ozmod/ozmod_pika/ozmod_pika.c (0 => 17141)


--- freeswitch/trunk/libs/openzap/src/ozmod/ozmod_pika/ozmod_pika.c	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/src/ozmod/ozmod_pika/ozmod_pika.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,1469 @@
+/*
+ * Copyright (c) 2007, Anthony Minessale II
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#include "openzap.h"
+#include "zap_pika.h"
+
+
+#define MAX_NUMBER_OF_TRUNKS 64
+#define PIKA_BLOCK_SIZE 160
+#define PIKA_BLOCK_LEN 20
+#define PIKA_NUM_BUFFERS 8
+#define TRY_OR_DIE(__code, __status, __label) if ((status = __code ) != __status) goto __label
+#define pk_atof(__a) (PK_FLOAT) atof(__a)
+
+PK_VOID PK_CALLBACK media_out_callback(PKH_TPikaEvent *event);
+
+ZAP_ENUM_NAMES(PIKA_SPAN_NAMES, PIKA_SPAN_STRINGS)
+PIKA_STR2ENUM(pika_str2span, pika_span2str, PIKA_TSpanFraming, PIKA_SPAN_NAMES, PIKA_SPAN_INVALID)
+
+ZAP_ENUM_NAMES(PIKA_SPAN_ENCODING_NAMES, PIKA_SPAN_ENCODING_STRINGS)
+PIKA_STR2ENUM(pika_str2span_encoding, pika_span_encoding2str, PIKA_TSpanEncoding, PIKA_SPAN_ENCODING_NAMES, PIKA_SPAN_ENCODING_INVALID)
+
+ZAP_ENUM_NAMES(PIKA_LL_NAMES, PIKA_LL_STRINGS)
+PIKA_STR2ENUM(pika_str2loop_length, pika_loop_length2str, PIKA_TSpanLoopLength, PIKA_LL_NAMES, PIKA_SPAN_LOOP_INVALID)
+
+ZAP_ENUM_NAMES(PIKA_LBO_NAMES, PIKA_LBO_STRINGS)
+PIKA_STR2ENUM(pika_str2lbo, pika_lbo2str, PIKA_TSpanBuildOut, PIKA_LBO_NAMES, PIKA_SPAN_LBO_INVALID)
+
+ZAP_ENUM_NAMES(PIKA_SPAN_COMPAND_MODE_NAMES, PIKA_SPAN_COMPAND_MODE_STRINGS)
+PIKA_STR2ENUM(pika_str2compand_mode, pika_compand_mode2str, PIKA_TSpanCompandMode, PIKA_SPAN_COMPAND_MODE_NAMES, PIKA_SPAN_COMPAND_MODE_INVALID)
+
+
+typedef enum {
+	PK_FLAG_READY = (1 << 0),
+	PK_FLAG_LOCKED = (1 << 1)
+} pk_flag_t;
+
+struct general_config {
+	uint32_t region;
+};
+typedef struct general_config general_config_t;
+
+struct pika_channel_profile {
+	char name[80];
+	PKH_TRecordConfig record_config;
+	PKH_TPlayConfig play_config;
+	int ec_enabled;
+	PKH_TECConfig ec_config;
+	PKH_TSpanConfig span_config;
+	general_config_t general_config;
+	int cust_span;
+};
+typedef struct pika_channel_profile pika_channel_profile_t;
+
+static struct {
+	PKH_TSystemDeviceList board_list;
+	TPikaHandle open_boards[MAX_NUMBER_OF_TRUNKS];
+	TPikaHandle system_handle;
+	PKH_TSystemConfig system_config;
+	PKH_TRecordConfig record_config;
+	PKH_TPlayConfig play_config;
+	PKH_TECConfig ec_config;
+	PKH_TSpanConfig t1_span_config;
+	PKH_TSpanConfig e1_span_config;
+	zap_hash_t *profile_hash;
+	general_config_t general_config;
+} globals;
+
+
+struct pika_span_data {
+	TPikaHandle event_queue;
+	PKH_TPikaEvent last_oob_event;
+	uint32_t boardno;
+	PKH_TSpanConfig span_config;
+	TPikaHandle handle;
+	uint32_t flags;
+};
+typedef struct pika_span_data pika_span_data_t;
+
+struct pika_chan_data {
+	TPikaHandle handle;
+	TPikaHandle media_in;
+	TPikaHandle media_out;
+	TPikaHandle media_in_queue;
+	TPikaHandle media_out_queue;
+	PKH_TPikaEvent last_media_event;
+	PKH_TPikaEvent last_oob_event;
+	PKH_TRecordConfig record_config;
+	PKH_TPlayConfig play_config;
+	int ec_enabled;
+	PKH_TECConfig ec_config;
+	PKH_THDLCConfig hdlc_config;
+	zap_buffer_t *digit_buffer;
+	zap_mutex_t *digit_mutex;
+	zap_size_t dtmf_len;
+	uint32_t flags;
+	uint32_t hdlc_bytes;
+};
+typedef struct pika_chan_data pika_chan_data_t;
+
+static const char *pika_board_type_string(PK_UINT type)
+{
+	if (type == PKH_BOARD_TYPE_DIGITAL_GATEWAY) {
+		return "digital_gateway";
+	}
+
+	if (type == PKH_BOARD_TYPE_ANALOG_GATEWAY) {
+		return "analog_gateway";
+	}
+
+	return "unknown";
+}
+
+/**
+ * \brief Process configuration variable for a pika profile
+ * \param category Pika profile name
+ * \param var Variable name
+ * \param val Variable value
+ * \param lineno Line number from configuration file (unused)
+ * \return Success
+ */
+static ZIO_CONFIGURE_FUNCTION(pika_configure)
+{
+	pika_channel_profile_t *profile = NULL;
+	int ok = 1;
+
+	if (!(profile = (pika_channel_profile_t *) hashtable_search(globals.profile_hash, (char *)category))) {
+		profile = malloc(sizeof(*profile));
+		memset(profile, 0, sizeof(*profile));
+		zap_set_string(profile->name, category);
+		profile->ec_config = globals.ec_config;
+		profile->record_config = globals.record_config;
+		profile->play_config = globals.play_config;
+		hashtable_insert(globals.profile_hash, (void *)profile->name, profile, HASHTABLE_FLAG_NONE);
+		zap_log(ZAP_LOG_INFO, "creating profile [%s]\n", category);
+	}
+
+	if (!strcasecmp(var, "rx-gain")) {
+		profile->record_config.gain = pk_atof(val);
+	} else if (!strcasecmp(var, "rx-agc-enabled")) {
+		profile->record_config.AGC.enabled = zap_true(val);
+	} else if (!strcasecmp(var, "rx-agc-targetPower")) {
+		profile->record_config.AGC.targetPower = pk_atof(val);
+	} else if (!strcasecmp(var, "rx-agc-minGain")) {
+		profile->record_config.AGC.minGain = pk_atof(val);
+	} else if (!strcasecmp(var, "rx-agc-maxGain")) {
+		profile->record_config.AGC.maxGain = pk_atof(val);
+	} else if (!strcasecmp(var, "rx-agc-attackRate")) {
+		profile->record_config.AGC.attackRate = atoi(val);
+	} else if (!strcasecmp(var, "rx-agc-decayRate")) {
+		profile->record_config.AGC.decayRate = atoi(val);
+	} else if (!strcasecmp(var, "rx-agc-speechThreshold")) {
+		profile->record_config.AGC.speechThreshold = pk_atof(val);
+	} else if (!strcasecmp(var, "rx-vad-enabled")) {
+		profile->record_config.VAD.enabled = zap_true(val);
+	} else if (!strcasecmp(var, "rx-vad-activationThreshold")) {
+		profile->record_config.VAD.activationThreshold = pk_atof(val);
+	} else if (!strcasecmp(var, "rx-vad-activationDebounceTime")) {
+		profile->record_config.VAD.activationDebounceTime = atoi(val);
+	} else if (!strcasecmp(var, "rx-vad-deactivationThreshold")) {
+		profile->record_config.VAD.deactivationThreshold = pk_atof(val);
+	} else if (!strcasecmp(var, "rx-vad-deactivationDebounceTime")) {
+		profile->record_config.VAD.deactivationDebounceTime = atoi(val);
+	} else if (!strcasecmp(var, "rx-vad-preSpeechBufferSize")) {
+		profile->record_config.VAD.preSpeechBufferSize = atoi(val);
+	} else if (!strcasecmp(var, "tx-gain")) {
+		profile->play_config.gain = pk_atof(val);
+	} else if (!strcasecmp(var, "tx-agc-enabled")) {
+		profile->play_config.AGC.enabled = zap_true(val);
+	} else if (!strcasecmp(var, "tx-agc-targetPower")) {
+		profile->play_config.AGC.targetPower = pk_atof(val);
+	} else if (!strcasecmp(var, "tx-agc-minGain")) {
+		profile->play_config.AGC.minGain = pk_atof(val);
+	} else if (!strcasecmp(var, "tx-agc-maxGain")) {
+		profile->play_config.AGC.maxGain = pk_atof(val);
+	} else if (!strcasecmp(var, "tx-agc-attackRate")) {
+		profile->play_config.AGC.attackRate = atoi(val);
+	} else if (!strcasecmp(var, "tx-agc-decayRate")) {
+		profile->play_config.AGC.decayRate = atoi(val);
+	} else if (!strcasecmp(var, "tx-agc-speechThreshold")) {
+		profile->play_config.AGC.speechThreshold = pk_atof(val);
+	} else if (!strcasecmp(var, "ec-enabled")) {
+		profile->ec_enabled = zap_true(val);
+	} else if (!strcasecmp(var, "ec-doubleTalkerThreshold")) {
+		profile->ec_config.doubleTalkerThreshold = pk_atof(val);
+	} else if (!strcasecmp(var, "ec-speechPresentThreshold")) {
+		profile->ec_config.speechPresentThreshold = pk_atof(val);
+	} else if (!strcasecmp(var, "ec-echoSuppressionThreshold")) {
+		profile->ec_config.echoSuppressionThreshold = pk_atof(val);
+	} else if (!strcasecmp(var, "ec-echoSuppressionEnabled")) {
+		profile->ec_config.echoSuppressionEnabled = zap_true(val);
+	} else if (!strcasecmp(var, "ec-comfortNoiseEnabled")) {
+		profile->ec_config.comfortNoiseEnabled = zap_true(val);
+	} else if (!strcasecmp(var, "ec-adaptationModeEnabled")) {
+		profile->ec_config.adaptationModeEnabled = zap_true(val);
+	} else if (!strcasecmp(var, "framing")) {
+		profile->span_config.framing = pika_str2span(val);
+		profile->cust_span++;
+	} else if (!strcasecmp(var, "encoding")) {
+		profile->span_config.encoding = pika_str2span_encoding(val);
+		profile->cust_span++;
+	} else if (!strcasecmp(var, "loopLength")) {
+		profile->span_config.loopLength = pika_str2loop_length(val);
+		profile->cust_span++;
+	} else if (!strcasecmp(var, "buildOut")) {
+		profile->span_config.buildOut = pika_str2lbo(val);
+		profile->cust_span++;
+	} else if (!strcasecmp(var, "compandMode")) {
+		profile->span_config.compandMode = pika_str2compand_mode(val);
+		profile->cust_span++;
+	} else if (!strcasecmp(var, "region")) {
+		if (!strcasecmp(val, "eu")) {
+			profile->general_config.region = PKH_TRUNK_EU;
+		} else {
+			profile->general_config.region = PKH_TRUNK_NA;
+		}
+	} else {
+		ok = 0;
+	}
+
+	if (ok) {
+		zap_log(ZAP_LOG_INFO, "setting param [%s]=[%s] for profile [%s]\n", var, val, category);
+	} else {
+		zap_log(ZAP_LOG_ERROR, "unknown param [%s]\n", var);
+	}
+
+	return ZAP_SUCCESS;
+}
+
+/**
+ * \brief Pika event handler
+ * \param event Pika event
+ */
+PK_VOID PK_CALLBACK media_out_callback(PKH_TPikaEvent *event)
+{
+	PK_STATUS pk_status;
+	zap_channel_t *zchan = event->userData;
+	pika_chan_data_t *chan_data = (pika_chan_data_t *) zchan->mod_data;
+
+	//PK_CHAR event_text[PKH_EVENT_MAX_NAME_LENGTH];
+	//PKH_EVENT_GetText(event->id, event_text, sizeof(event_text));
+	//zap_log(ZAP_LOG_DEBUG, "Event: %s\n", event_text);
+	
+	switch (event->id) {
+	case PKH_EVENT_PLAY_IDLE:
+		{
+			while (zap_buffer_inuse(chan_data->digit_buffer)) {
+				char dtmf[128] = "";
+				zap_mutex_lock(chan_data->digit_mutex);
+				chan_data->dtmf_len = zap_buffer_read(chan_data->digit_buffer, dtmf, sizeof(dtmf));
+				pk_status = PKH_TG_PlayDTMF(chan_data->media_out, dtmf);
+				zap_mutex_unlock(chan_data->digit_mutex);
+			}
+		}
+		break;
+	case PKH_EVENT_TG_TONE_PLAYED:
+		{
+
+			if (!event->p1) {
+				zap_mutex_lock(chan_data->digit_mutex);
+				PKH_PLAY_Start(chan_data->media_out);
+				chan_data->dtmf_len = 0;
+				zap_mutex_unlock(chan_data->digit_mutex);
+			}
+
+				
+		}
+		break;
+	default:
+		break;
+	}
+
+}
+
+/**
+ * \brief Initialises a range of pika channels
+ * \param span Openzap span
+ * \param boardno Pika board number
+ * \param spanno Pika span number
+ * \param start Initial pika channel number
+ * \param end Final pika channel number
+ * \param type Openzap channel type
+ * \param name Openzap span name
+ * \param number Openzap span number
+ * \param profile Pika channel profile
+ * \return number of spans configured
+ */
+static unsigned pika_open_range(zap_span_t *span, unsigned boardno, unsigned spanno, unsigned start, unsigned end, 
+								zap_chan_type_t type, char *name, char *number, pika_channel_profile_t *profile)
+{
+	unsigned configured = 0, x;
+	PK_STATUS status;
+	PK_CHAR error_text[PKH_ERROR_MAX_NAME_LENGTH];
+	pika_span_data_t *span_data;
+
+	if (boardno >= globals.board_list.numberOfBoards) {
+		zap_log(ZAP_LOG_ERROR, "Board %u is not present!\n", boardno);
+		return 0;
+	}
+
+	if (!globals.open_boards[boardno]) {
+		status = PKH_BOARD_Open(globals.board_list.board[boardno].id,
+								NULL,
+								&globals.open_boards[boardno]);
+		if(status != PK_SUCCESS) {
+			zap_log(ZAP_LOG_ERROR, "Error: PKH_BOARD_Open %d failed(%s)!\n",  boardno,
+					PKH_ERROR_GetText(status, error_text, sizeof(error_text)));
+			return 0;
+		}
+
+		zap_log(ZAP_LOG_DEBUG, "Open board %u\n",  boardno);
+
+		//PKH_BOARD_SetDebugTrace(globals.open_boards[boardno], 1, 0);
+		
+	}
+
+	if (span->mod_data) {
+		span_data = span->mod_data;
+	} else {
+		span_data = malloc(sizeof(*span_data));
+		assert(span_data != NULL);
+		memset(span_data, 0, sizeof(*span_data));
+		span_data->boardno = boardno;
+		
+		status = PKH_QUEUE_Create(PKH_QUEUE_TYPE_NORMAL, &span_data->event_queue);
+		
+		if (status != PK_SUCCESS) {
+			zap_log(ZAP_LOG_ERROR, "Error: PKH_QUEUE_Create failed(%s)!\n",
+					PKH_ERROR_GetText(status, error_text, sizeof(error_text)));
+			free(span_data);
+			return 0;
+		}
+
+		//PKH_QUEUE_Attach(span_data->event_queue, globals.open_boards[boardno], NULL);
+
+		span->mod_data = span_data;
+	}
+
+	if (type == ZAP_CHAN_TYPE_FXS || type == ZAP_CHAN_TYPE_FXO) {
+		start--;
+		end--;
+	}
+
+	for(x = start; x < end; x++) {
+		zap_channel_t *chan;
+		pika_chan_data_t *chan_data = NULL;
+
+		chan_data = malloc(sizeof *chan_data);
+		assert(chan_data);
+		memset(chan_data, 0, sizeof(*chan_data));
+		zap_span_add_channel(span, 0, type, &chan);
+		chan->mod_data = chan_data;
+
+		if ((type == ZAP_CHAN_TYPE_B || type == ZAP_CHAN_TYPE_DQ921) && !span_data->handle) {
+			PKH_TBoardConfig boardConfig;
+			
+			TRY_OR_DIE(PKH_BOARD_GetConfig(globals.open_boards[boardno], &boardConfig), PK_SUCCESS, error);
+			if ((profile && profile->general_config.region == PKH_TRUNK_EU) || zap_test_flag(span_data, PK_FLAG_LOCKED)) {
+				if (span->trunk_type == ZAP_TRUNK_T1) {
+					zap_log(ZAP_LOG_WARNING, "Changing trunk type to E1 based on previous config.\n");
+				}
+				span->trunk_type = ZAP_TRUNK_E1;
+			}
+
+			if (span->trunk_type == ZAP_TRUNK_T1) {
+				if (zap_test_flag(span_data, PK_FLAG_LOCKED)) {
+					zap_log(ZAP_LOG_WARNING, "Already locked into E1 mode!\n");
+				}
+			} else if (span->trunk_type == ZAP_TRUNK_E1) {
+				boardConfig.specific.DigitalGateway.interfaceType = PKH_BOARD_INTERFACE_TYPE_E1;
+				if ((status = PKH_BOARD_SetConfig(globals.open_boards[boardno], &boardConfig)) != PK_SUCCESS) {
+					zap_log(ZAP_LOG_ERROR, "Error: [%s]\n",
+							PKH_ERROR_GetText(status, error_text, sizeof(error_text)));
+				}
+				zap_set_flag(span_data, PK_FLAG_LOCKED);
+			}
+			
+			TRY_OR_DIE(PKH_SPAN_Open(globals.open_boards[boardno], spanno, NULL, &span_data->handle), PK_SUCCESS, error);
+			TRY_OR_DIE(PKH_SPAN_GetConfig(span_data->handle, &span_data->span_config), PK_SUCCESS, error);
+			TRY_OR_DIE(PKH_QUEUE_Attach(span_data->event_queue, span_data->handle, (PK_VOID*) span), PK_SUCCESS, error);
+		}
+
+		if (type == ZAP_CHAN_TYPE_FXO) {
+			PKH_TTrunkConfig trunkConfig;
+			
+			TRY_OR_DIE(PKH_TRUNK_Open(globals.open_boards[boardno], x, &chan_data->handle), PK_SUCCESS, error);
+			TRY_OR_DIE(PKH_TRUNK_Seize(chan_data->handle), PK_SUCCESS, error);
+
+			if (profile && profile->general_config.region == PKH_TRUNK_EU) {
+				TRY_OR_DIE(PKH_TRUNK_GetConfig(chan_data->handle, &trunkConfig), PK_SUCCESS, error);
+				trunkConfig.internationalControl = PKH_PHONE_INTERNATIONAL_CONTROL_EU;
+				trunkConfig.audioFormat = PKH_AUDIO_ALAW;
+				trunkConfig.compandMode = PKH_PHONE_AUDIO_ALAW;
+				chan->native_codec = chan->effective_codec = ZAP_CODEC_ALAW;
+				TRY_OR_DIE(PKH_TRUNK_SetConfig(chan_data->handle, &trunkConfig), PK_SUCCESS, error);
+			} else {
+				chan->native_codec = chan->effective_codec = ZAP_CODEC_ULAW;
+			}
+
+			
+			TRY_OR_DIE(PKH_QUEUE_Attach(span_data->event_queue, chan_data->handle, (PK_VOID*) chan), PK_SUCCESS, error);
+			TRY_OR_DIE(PKH_TRUNK_GetMediaStreams(chan_data->handle, &chan_data->media_in, &chan_data->media_out), PK_SUCCESS, error);
+			TRY_OR_DIE(PKH_QUEUE_Create(PKH_QUEUE_TYPE_NORMAL, &chan_data->media_in_queue), PK_SUCCESS, error);
+			TRY_OR_DIE(PKH_QUEUE_Attach(chan_data->media_in_queue, chan_data->media_in, (PK_VOID*) chan), PK_SUCCESS, error);
+			TRY_OR_DIE(PKH_QUEUE_Create(PKH_QUEUE_TYPE_CALLBACK, &chan_data->media_out_queue), PK_SUCCESS, error);
+			TRY_OR_DIE(PKH_QUEUE_SetEventHandler(chan_data->media_out_queue, media_out_callback), PK_SUCCESS, error);
+			TRY_OR_DIE(PKH_QUEUE_Attach(chan_data->media_out_queue, chan_data->media_out, (PK_VOID*) chan), PK_SUCCESS, error);
+			TRY_OR_DIE(PKH_TRUNK_Start(chan_data->handle), PK_SUCCESS, error);
+		} else if (type == ZAP_CHAN_TYPE_FXS) {
+			PKH_TPhoneConfig phoneConfig;
+
+			if (profile && profile->general_config.region == PKH_TRUNK_EU) {
+				TRY_OR_DIE(PKH_PHONE_GetConfig(chan_data->handle, &phoneConfig), PK_SUCCESS, error);
+				phoneConfig.internationalControl = PKH_PHONE_INTERNATIONAL_CONTROL_EU;
+				phoneConfig.compandMode = PKH_PHONE_AUDIO_ALAW;
+				chan->native_codec = chan->effective_codec = ZAP_CODEC_ALAW;
+				TRY_OR_DIE(PKH_PHONE_SetConfig(chan_data->handle, &phoneConfig), PK_SUCCESS, error);
+			} else {
+				chan->native_codec = chan->effective_codec = ZAP_CODEC_ULAW;
+			}
+
+			TRY_OR_DIE(PKH_PHONE_Open(globals.open_boards[boardno], x, &chan_data->handle), PK_SUCCESS, error);
+			TRY_OR_DIE(PKH_PHONE_Seize(chan_data->handle), PK_SUCCESS, error);
+			TRY_OR_DIE(PKH_PHONE_GetMediaStreams(chan_data->handle, &chan_data->media_in, &chan_data->media_out), PK_SUCCESS, error);
+			TRY_OR_DIE(PKH_QUEUE_Attach(span_data->event_queue, chan_data->handle, (PK_VOID*) chan), PK_SUCCESS, error);
+			TRY_OR_DIE(PKH_QUEUE_Create(PKH_QUEUE_TYPE_NORMAL, &chan_data->media_in_queue), PK_SUCCESS, error);
+			TRY_OR_DIE(PKH_QUEUE_Attach(chan_data->media_in_queue, chan_data->media_in, (PK_VOID*) chan), PK_SUCCESS, error);
+			TRY_OR_DIE(PKH_QUEUE_Create(PKH_QUEUE_TYPE_CALLBACK, &chan_data->media_out_queue), PK_SUCCESS, error);
+			TRY_OR_DIE(PKH_QUEUE_SetEventHandler(chan_data->media_out_queue, media_out_callback), PK_SUCCESS, error);
+			TRY_OR_DIE(PKH_QUEUE_Attach(chan_data->media_out_queue, chan_data->media_out, (PK_VOID*) chan), PK_SUCCESS, error);
+			TRY_OR_DIE(PKH_PHONE_Start(chan_data->handle), PK_SUCCESS, error);
+		} else if (type == ZAP_CHAN_TYPE_B) {
+			TRY_OR_DIE(PKH_SPAN_SeizeChannel(span_data->handle, x), PK_SUCCESS, error);
+			TRY_OR_DIE(PKH_SPAN_GetMediaStreams(span_data->handle, x, &chan_data->media_in, &chan_data->media_out), PK_SUCCESS, error);
+			TRY_OR_DIE(PKH_QUEUE_Create(PKH_QUEUE_TYPE_NORMAL, &chan_data->media_in_queue), PK_SUCCESS, error);
+			TRY_OR_DIE(PKH_QUEUE_Attach(chan_data->media_in_queue, chan_data->media_in, (PK_VOID*) chan), PK_SUCCESS, error);
+			TRY_OR_DIE(PKH_QUEUE_Create(PKH_QUEUE_TYPE_CALLBACK, &chan_data->media_out_queue), PK_SUCCESS, error);
+			TRY_OR_DIE(PKH_QUEUE_SetEventHandler(chan_data->media_out_queue, media_out_callback), PK_SUCCESS, error);
+			TRY_OR_DIE(PKH_QUEUE_Attach(chan_data->media_out_queue, chan_data->media_out, (PK_VOID*) chan), PK_SUCCESS, error);
+		} else if (type == ZAP_CHAN_TYPE_DQ921) {
+			TRY_OR_DIE(PKH_SPAN_HDLC_Open(span_data->handle, PKH_SPAN_HDLC_MODE_NORMAL, &chan_data->handle), PK_SUCCESS, error);
+			TRY_OR_DIE(PKH_SPAN_HDLC_GetConfig(chan_data->handle, &chan_data->hdlc_config), PK_SUCCESS, error);
+			chan_data->hdlc_config.channelId = x;
+			TRY_OR_DIE(PKH_SPAN_HDLC_SetConfig(chan_data->handle, &chan_data->hdlc_config), PK_SUCCESS, error);
+			TRY_OR_DIE(PKH_QUEUE_Create(PKH_QUEUE_TYPE_NORMAL, &chan_data->media_in_queue), PK_SUCCESS, error);
+			TRY_OR_DIE(PKH_QUEUE_Attach(chan_data->media_in_queue, chan_data->handle, (PK_VOID*) chan), PK_SUCCESS, error);
+			TRY_OR_DIE(PKH_QUEUE_Attach(span_data->event_queue, chan_data->handle, (PK_VOID*) chan), PK_SUCCESS, error);
+
+			if (profile) {
+				if (profile->cust_span) {
+					span_data->span_config.framing = profile->span_config.framing;
+					span_data->span_config.encoding = profile->span_config.encoding;
+					span_data->span_config.loopLength = profile->span_config.loopLength;
+					span_data->span_config.buildOut = profile->span_config.buildOut;
+					span_data->span_config.compandMode = profile->span_config.compandMode;
+				} else {
+					if (profile->general_config.region == PKH_TRUNK_EU) {
+						span_data->span_config = globals.e1_span_config;
+					} else {
+						span_data->span_config = globals.t1_span_config;
+					}
+				}
+			} else {
+				if (span->trunk_type == ZAP_TRUNK_E1) {
+					span_data->span_config = globals.e1_span_config;
+				} else {
+					span_data->span_config = globals.t1_span_config;
+				}
+			}
+			
+			PKH_SPAN_SetConfig(span_data->handle, &span_data->span_config);
+			TRY_OR_DIE(PKH_SPAN_Start(span_data->handle), PK_SUCCESS, error);
+		}
+		
+		goto ok;
+
+	error:
+		PKH_ERROR_GetText(status, error_text, sizeof(error_text));
+		zap_log(ZAP_LOG_ERROR, "failure configuring device b%ds%dc%d [%s]\n", boardno, spanno, x, error_text);
+		continue;
+	ok:
+		zap_set_flag(chan_data, PK_FLAG_READY);
+		status = PKH_RECORD_GetConfig(chan_data->media_in, &chan_data->record_config);
+		chan_data->record_config.encoding = PKH_RECORD_ENCODING_MU_LAW;
+		chan_data->record_config.samplingRate = PKH_RECORD_SAMPLING_RATE_8KHZ;
+		chan_data->record_config.bufferSize = PIKA_BLOCK_SIZE;
+		chan_data->record_config.numberOfBuffers = PIKA_NUM_BUFFERS;
+		chan_data->record_config.VAD.enabled = PK_FALSE;
+		//chan_data->record_config.speechSegmentEventsEnabled = PK_FALSE;
+		//chan_data->record_config.gain = rxgain;
+
+		status = PKH_PLAY_GetConfig(chan_data->media_out, &chan_data->play_config);
+		chan_data->play_config.encoding = PKH_RECORD_ENCODING_MU_LAW;
+		chan_data->play_config.samplingRate = PKH_RECORD_SAMPLING_RATE_8KHZ;
+		chan_data->play_config.AGC.enabled = PK_FALSE;
+		zap_log(ZAP_LOG_INFO, "configuring device b%ds%dc%d as OpenZAP device %d:%d\n", boardno, spanno, x, chan->span_id, chan->chan_id);
+
+		if (profile) {
+			zap_log(ZAP_LOG_INFO, "applying config profile %s to device %d:%d\n", profile->name, chan->span_id, chan->chan_id);
+			chan_data->record_config.gain = profile->record_config.gain;
+			chan_data->record_config.AGC = profile->record_config.AGC;
+			chan_data->record_config.VAD = profile->record_config.VAD;
+			chan_data->play_config.gain = profile->play_config.gain;
+			chan_data->play_config.AGC = profile->play_config.AGC;
+			chan_data->ec_enabled = profile->ec_enabled;
+			chan_data->ec_config = profile->ec_config;
+		}
+		
+		if (type == ZAP_CHAN_TYPE_B) {
+			if (span_data->span_config.compandMode == PKH_SPAN_COMPAND_MODE_A_LAW) {
+				chan->native_codec = chan->effective_codec = ZAP_CODEC_ALAW;
+			} else {
+				chan->native_codec = chan->effective_codec = ZAP_CODEC_ULAW;
+			}
+		}
+
+		status = PKH_RECORD_SetConfig(chan_data->media_in, &chan_data->record_config);
+		status = PKH_PLAY_SetConfig(chan_data->media_out, &chan_data->play_config);
+
+		chan->physical_span_id = spanno;
+		chan->physical_chan_id = x;
+
+		chan->rate = 8000;
+		chan->packet_len = (uint32_t)chan_data->record_config.bufferSize;
+		chan->effective_interval = chan->native_interval = chan->packet_len / 8;
+
+		PKH_RECORD_Start(chan_data->media_in);
+		PKH_PLAY_Start(chan_data->media_out);
+		if (chan_data->ec_enabled) {
+			PKH_EC_SetConfig(chan_data->media_in, &chan_data->ec_config);
+			PKH_EC_Start(chan_data->media_in, chan_data->media_in, chan_data->media_out);
+		}
+
+		if (!zap_strlen_zero(name)) {
+			zap_copy_string(chan->chan_name, name, sizeof(chan->chan_name));
+		}
+		
+		if (!zap_strlen_zero(number)) {
+			zap_copy_string(chan->chan_number, number, sizeof(chan->chan_number));
+		}
+
+		zap_channel_set_feature(chan, ZAP_CHANNEL_FEATURE_DTMF_GENERATE);
+		zap_buffer_create(&chan_data->digit_buffer, 128, 128, 0);
+		zap_mutex_create(&chan_data->digit_mutex);
+
+		configured++;
+	} 
+
+	
+	return configured;
+}
+
+/**
+ * \brief Initialises an openzap pika span from a configuration string
+ * \param span Openzap span
+ * \param str Configuration string
+ * \param type Openzap span type
+ * \param name Openzap span name
+ * \param number Openzap span number
+ * \return Success or failure
+ */
+static ZIO_CONFIGURE_SPAN_FUNCTION(pika_configure_span)
+{
+	int items, i;
+    char *mydata, *item_list[10];
+	char *bd, *sp, *ch = NULL, *mx;
+	int boardno;
+	int channo;
+	int spanno;
+	int top = 0;
+	unsigned configured = 0;
+	char *profile_name = NULL;
+	pika_channel_profile_t *profile = NULL;
+
+	assert(str != NULL);
+
+	mydata = strdup(str);
+	assert(mydata != NULL);
+
+	if ((profile_name = strchr(mydata, '@'))) {
+		*profile_name++ = '\0';
+		if (!zap_strlen_zero(profile_name)) {
+			profile = (pika_channel_profile_t *) hashtable_search(globals.profile_hash, (char *)profile_name);
+		}
+	}
+		
+	items = zap_separate_string(mydata, ',', item_list, (sizeof(item_list) / sizeof(item_list[0])));
+
+	for(i = 0; i < items; i++) {
+		bd = item_list[i];
+		if ((sp = strchr(bd, ':'))) {
+			*sp++ = '\0';
+			if ((ch = strchr(sp, ':'))) {
+				*ch++ = '\0';
+			}
+		}
+		
+		if (!(bd && sp && ch)) {
+			zap_log(ZAP_LOG_ERROR, "Invalid input\n");
+			continue;
+		}
+
+		boardno = atoi(bd);
+		channo = atoi(ch);
+		spanno = atoi(sp);
+
+
+		if (boardno < 0) {
+			zap_log(ZAP_LOG_ERROR, "Invalid board number %d\n", boardno);
+			continue;
+		}
+
+		if (channo < 0) {
+			zap_log(ZAP_LOG_ERROR, "Invalid channel number %d\n", channo);
+			continue;
+		}
+
+		if (spanno < 0) {
+			zap_log(ZAP_LOG_ERROR, "Invalid span number %d\n", channo);
+			continue;
+		}
+		
+		if ((mx = strchr(ch, '-'))) {
+			mx++;
+			top = atoi(mx) + 1;
+		} else {
+			top = channo + 1;
+		}
+		
+		
+		if (top < 0) {
+			zap_log(ZAP_LOG_ERROR, "Invalid range number %d\n", top);
+			continue;
+		}
+
+		configured += pika_open_range(span, boardno, spanno, channo, top, type, name, number, profile);
+
+	}
+	
+	free(mydata);
+
+	return configured;
+}
+
+/**
+ * \brief Opens Pika channel
+ * \param zchan Channel to open
+ * \return Success or failure
+ */
+static ZIO_OPEN_FUNCTION(pika_open) 
+{
+	pika_chan_data_t *chan_data = (pika_chan_data_t *) zchan->mod_data;
+
+	if (!chan_data && !zap_test_flag(chan_data, PK_FLAG_READY)) {
+		return ZAP_FAIL;
+	}
+
+	if (chan_data->media_in_queue) {
+		PKH_QUEUE_Flush(chan_data->media_in_queue);
+	}
+
+	if (zchan->type == ZAP_CHAN_TYPE_FXS || zchan->type == ZAP_CHAN_TYPE_FXO || zchan->type == ZAP_CHAN_TYPE_B) {
+		PKH_PLAY_Start(chan_data->media_out);
+	}
+	return ZAP_SUCCESS;
+}
+
+/**
+ * \brief Closes Pika channel
+ * \param zchan Channel to close
+ * \return Success
+ */
+static ZIO_CLOSE_FUNCTION(pika_close)
+{
+	return ZAP_SUCCESS;
+}
+
+/**
+ * \brief Waits for an event on a Pika channel
+ * \param zchan Channel to open
+ * \param flags Type of event to wait for
+ * \param to Time to wait (in ms)
+ * \return Success, failure or timeout
+ */
+static ZIO_WAIT_FUNCTION(pika_wait)
+{
+	pika_chan_data_t *chan_data = (pika_chan_data_t *) zchan->mod_data;
+	PK_STATUS status;
+	zap_wait_flag_t myflags = *flags;
+	PK_CHAR event_text[PKH_EVENT_MAX_NAME_LENGTH];
+
+	*flags = ZAP_NO_FLAGS;	
+
+	if (myflags & ZAP_READ) {
+		if (chan_data->hdlc_bytes) {
+			*flags |= ZAP_READ;
+			return ZAP_SUCCESS;
+		}
+		status = PKH_QUEUE_WaitOnEvent(chan_data->media_in_queue, to, &chan_data->last_media_event);
+		
+		if (status == PK_SUCCESS) {
+			if (chan_data->last_media_event.id == PKH_EVENT_QUEUE_TIMEOUT || chan_data->last_media_event.id == PKH_EVENT_RECORD_BUFFER_OVERFLOW) {
+				return ZAP_TIMEOUT;
+			}
+			
+			*flags |= ZAP_READ;
+			return ZAP_SUCCESS;
+		}
+
+		PKH_EVENT_GetText(chan_data->last_media_event.id, event_text, sizeof(event_text));
+		zap_log(ZAP_LOG_DEBUG, "Event: %s\n", event_text);
+	}
+
+	return ZAP_SUCCESS;
+}
+
+/**
+ * \brief Reads data from a Pika channel
+ * \param zchan Channel to read from
+ * \param data Data buffer
+ * \param datalen Size of data buffer
+ * \return Success or failure
+ */
+static ZIO_READ_FUNCTION(pika_read)
+{
+	pika_chan_data_t *chan_data = (pika_chan_data_t *) zchan->mod_data;
+	PK_STATUS status;
+	PK_CHAR event_text[PKH_EVENT_MAX_NAME_LENGTH];
+	uint32_t len;
+
+	if (zchan->type == ZAP_CHAN_TYPE_DQ921) {
+		if ((status = PKH_SPAN_HDLC_GetMessage(chan_data->handle, data, *datalen)) == PK_SUCCESS) {
+			*datalen = chan_data->hdlc_bytes;
+			chan_data->hdlc_bytes = 0;
+			return ZAP_SUCCESS;
+		}
+		return ZAP_FAIL;
+	}
+
+	if (!(len = chan_data->last_media_event.p0)) {
+		len = zchan->packet_len;
+	}
+	
+	if (len < *datalen) {
+		*datalen = len;
+	}
+
+	if ((status = PKH_RECORD_GetData(chan_data->media_in, data, *datalen)) == PK_SUCCESS) {
+		return ZAP_SUCCESS;
+	}
+
+
+	PKH_ERROR_GetText(status, event_text, sizeof(event_text));
+	zap_log(ZAP_LOG_DEBUG, "ERR: %s\n", event_text);
+	return ZAP_FAIL;
+}
+
+/**
+ * \brief Writes data to a Pika channel
+ * \param zchan Channel to write to
+ * \param data Data buffer
+ * \param datalen Size of data buffer
+ * \return Success or failure
+ */
+static ZIO_WRITE_FUNCTION(pika_write)
+{
+	pika_chan_data_t *chan_data = (pika_chan_data_t *) zchan->mod_data;
+	PK_STATUS status;
+
+	if (zchan->type == ZAP_CHAN_TYPE_DQ921) {
+		if ((status = PKH_SPAN_HDLC_SendMessage(chan_data->handle, data, *datalen)) == PK_SUCCESS) {
+			return ZAP_SUCCESS;
+		}
+		return ZAP_FAIL;
+	}
+
+	if (PKH_PLAY_AddData(chan_data->media_out, 0, data, *datalen) == PK_SUCCESS) {
+		return ZAP_SUCCESS;
+	}
+
+	return ZAP_FAIL;
+}
+
+/**
+ * \brief Executes an Openzap command on a Pika channel
+ * \param zchan Channel to execute command on
+ * \param command Openzap command to execute
+ * \param obj Object (unused)
+ * \return Success or failure
+ */
+static ZIO_COMMAND_FUNCTION(pika_command)
+{
+	pika_chan_data_t *chan_data = (pika_chan_data_t *) zchan->mod_data;
+	//pika_span_data_t *span_data = (pika_span_data_t *) zchan->span->mod_data;
+	PK_STATUS pk_status;
+	zap_status_t status = ZAP_SUCCESS;
+
+	switch(command) {
+	case ZAP_COMMAND_OFFHOOK:
+		{
+			if ((pk_status = PKH_TRUNK_SetHookSwitch(chan_data->handle, PKH_TRUNK_OFFHOOK)) != PK_SUCCESS) {
+				PKH_ERROR_GetText(pk_status, zchan->last_error, sizeof(zchan->last_error));
+				GOTO_STATUS(done, ZAP_FAIL);
+			} else {
+				zap_set_flag_locked(zchan, ZAP_CHANNEL_OFFHOOK);
+			}
+		}
+		break;
+	case ZAP_COMMAND_ONHOOK:
+		{
+			if ((pk_status = PKH_TRUNK_SetHookSwitch(chan_data->handle, PKH_TRUNK_ONHOOK)) != PK_SUCCESS) {
+				PKH_ERROR_GetText(pk_status, zchan->last_error, sizeof(zchan->last_error));
+				GOTO_STATUS(done, ZAP_FAIL);
+			} else {
+				zap_clear_flag_locked(zchan, ZAP_CHANNEL_OFFHOOK);
+			}
+		}
+		break;
+	case ZAP_COMMAND_GENERATE_RING_ON:
+		{
+			if ((pk_status = PKH_PHONE_RingStart(chan_data->handle, 0, 0)) != PK_SUCCESS) {
+				PKH_ERROR_GetText(pk_status, zchan->last_error, sizeof(zchan->last_error));
+				GOTO_STATUS(done, ZAP_FAIL);
+			} else {
+				zap_set_flag_locked(zchan, ZAP_CHANNEL_RINGING);
+			}
+		}
+		break;
+	case ZAP_COMMAND_GENERATE_RING_OFF:
+		{
+			if ((pk_status = PKH_PHONE_RingStop(chan_data->handle)) != PK_SUCCESS) {
+				PKH_ERROR_GetText(pk_status, zchan->last_error, sizeof(zchan->last_error));
+				GOTO_STATUS(done, ZAP_FAIL);
+			} else {
+				zap_clear_flag_locked(zchan, ZAP_CHANNEL_RINGING);
+			}
+		}
+		break;
+	case ZAP_COMMAND_GET_INTERVAL:
+		{
+
+			ZAP_COMMAND_OBJ_INT = zchan->native_interval;
+
+		}
+		break;
+	case ZAP_COMMAND_SET_INTERVAL: 
+		{
+			int interval = ZAP_COMMAND_OBJ_INT;
+			int len = interval * 8;
+			chan_data->record_config.bufferSize = len;
+			chan_data->record_config.numberOfBuffers = (PK_UINT)chan_data->record_config.bufferSize;
+			zchan->packet_len = (uint32_t)chan_data->record_config.bufferSize;
+			zchan->effective_interval = zchan->native_interval = zchan->packet_len / 8;
+			PKH_RECORD_SetConfig(chan_data->media_in, &chan_data->record_config);
+			GOTO_STATUS(done, ZAP_SUCCESS);
+		}
+		break;
+	case ZAP_COMMAND_GET_DTMF_ON_PERIOD:
+		{
+
+			ZAP_COMMAND_OBJ_INT = zchan->dtmf_on;
+			GOTO_STATUS(done, ZAP_SUCCESS);
+
+		}
+		break;
+	case ZAP_COMMAND_GET_DTMF_OFF_PERIOD:
+		{			
+				ZAP_COMMAND_OBJ_INT = zchan->dtmf_on;
+				GOTO_STATUS(done, ZAP_SUCCESS);
+		}
+		break;
+	case ZAP_COMMAND_SET_DTMF_ON_PERIOD:
+		{
+			int val = ZAP_COMMAND_OBJ_INT;
+			if (val > 10 && val < 1000) {
+				zchan->dtmf_on = val;
+				GOTO_STATUS(done, ZAP_SUCCESS);
+			} else {
+				snprintf(zchan->last_error, sizeof(zchan->last_error), "invalid value %d range 10-1000", val);
+				GOTO_STATUS(done, ZAP_FAIL);
+			}
+		}
+		break;
+	case ZAP_COMMAND_SET_DTMF_OFF_PERIOD:
+		{
+			int val = ZAP_COMMAND_OBJ_INT;
+			if (val > 10 && val < 1000) {
+				zchan->dtmf_off = val;
+				GOTO_STATUS(done, ZAP_SUCCESS);
+			} else {
+				snprintf(zchan->last_error, sizeof(zchan->last_error), "invalid value %d range 10-1000", val);
+				GOTO_STATUS(done, ZAP_FAIL);
+			}
+		}
+		break;
+	case ZAP_COMMAND_SEND_DTMF:
+		{
+			char *digits = ZAP_COMMAND_OBJ_CHAR_P;
+			zap_log(ZAP_LOG_DEBUG, "Adding DTMF SEQ [%s]\n", digits);
+			zap_mutex_lock(chan_data->digit_mutex);
+			zap_buffer_write(chan_data->digit_buffer, digits, strlen(digits));
+			zap_mutex_unlock(chan_data->digit_mutex);
+			pk_status = PKH_PLAY_Stop(chan_data->media_out);
+			
+			if (pk_status != PK_SUCCESS) {
+				PKH_ERROR_GetText(pk_status, zchan->last_error, sizeof(zchan->last_error));
+				GOTO_STATUS(done, ZAP_FAIL);
+			}
+			GOTO_STATUS(done, ZAP_SUCCESS);
+		}
+		break;
+	default:
+		break;
+	};
+
+ done:
+	return status;
+}
+
+/**
+ * \brief Checks for events on a Pika span
+ * \param span Span to check for events
+ * \param ms Time to wait for event
+ * \return Success if event is waiting or failure if not
+ */
+static ZIO_SPAN_POLL_EVENT_FUNCTION(pika_poll_event)
+{
+	pika_span_data_t *span_data = (pika_span_data_t *) span->mod_data;
+	PK_STATUS status;
+	PK_CHAR event_text[PKH_EVENT_MAX_NAME_LENGTH];
+
+	status = PKH_QUEUE_WaitOnEvent(span_data->event_queue, ms, &span_data->last_oob_event);
+
+	if (status == PK_SUCCESS) {
+		zap_channel_t *zchan = NULL;
+		uint32_t *data = (uint32_t *) span_data->last_oob_event.userData;
+		zap_data_type_t data_type = ZAP_TYPE_NONE;
+
+		if (span_data->last_oob_event.id == PKH_EVENT_QUEUE_TIMEOUT) {
+			return ZAP_TIMEOUT;
+		}
+
+		if (data) {
+			data_type = *data;
+		}
+
+		if (data_type == ZAP_TYPE_CHANNEL) {
+			zchan = span_data->last_oob_event.userData;
+		} else if (data_type == ZAP_TYPE_SPAN) {
+            zap_time_t last_event_time = zap_current_time_in_ms();
+			uint32_t event_id = 0;
+
+			switch (span_data->last_oob_event.id) {
+			case PKH_EVENT_SPAN_ALARM_T1_RED:
+			case PKH_EVENT_SPAN_ALARM_T1_YELLOW:
+			case PKH_EVENT_SPAN_ALARM_T1_AIS:
+			case PKH_EVENT_SPAN_ALARM_E1_RED:
+			case PKH_EVENT_SPAN_ALARM_E1_RAI:
+			case PKH_EVENT_SPAN_ALARM_E1_AIS:
+			case PKH_EVENT_SPAN_ALARM_E1_RMAI:
+			case PKH_EVENT_SPAN_ALARM_E1_TS16AIS:
+			case PKH_EVENT_SPAN_ALARM_E1_TS16LOS:
+			case PKH_EVENT_SPAN_OUT_OF_SYNC:
+			case PKH_EVENT_SPAN_FRAMING_ERROR:
+			case PKH_EVENT_SPAN_LOSS_OF_SIGNAL:
+			case PKH_EVENT_SPAN_OUT_OF_CRC_MF_SYNC:
+			case PKH_EVENT_SPAN_OUT_OF_CAS_MF_SYNC:
+				event_id = ZAP_OOB_ALARM_TRAP;
+				break;
+			case PKH_EVENT_SPAN_ALARM_T1_RED_CLEAR:
+			case PKH_EVENT_SPAN_ALARM_T1_YELLOW_CLEAR:
+			case PKH_EVENT_SPAN_ALARM_T1_AIS_CLEAR:
+			case PKH_EVENT_SPAN_ALARM_E1_RED_CLEAR:
+			case PKH_EVENT_SPAN_ALARM_E1_RAI_CLEAR:
+			case PKH_EVENT_SPAN_ALARM_E1_AIS_CLEAR:
+			case PKH_EVENT_SPAN_ALARM_E1_RMAI_CLEAR:
+			case PKH_EVENT_SPAN_ALARM_E1_TS16AIS_CLEAR:
+			case PKH_EVENT_SPAN_ALARM_E1_TS16LOS_CLEAR:
+			case PKH_EVENT_SPAN_IN_SYNC:
+			case PKH_EVENT_SPAN_LOSS_OF_SIGNAL_CLEAR:
+			case PKH_EVENT_SPAN_IN_CRC_MF_SYNC:
+			case PKH_EVENT_SPAN_IN_CAS_MF_SYNC:
+				event_id = ZAP_OOB_ALARM_CLEAR;
+				break;
+			case PKH_EVENT_SPAN_MESSAGE:
+			case PKH_EVENT_SPAN_ABCD_SIGNAL_CHANGE:
+				break;
+			}
+
+			if (event_id) {
+				uint32_t x = 0;
+				zap_channel_t *zchan;
+				pika_chan_data_t *chan_data;
+				for(x = 1; x <= span->chan_count; x++) {
+					zchan = span->channels[x];
+					assert(zchan != NULL);
+					chan_data = (pika_chan_data_t *) zchan->mod_data;
+					assert(chan_data != NULL);
+					
+
+					zap_set_flag(zchan, ZAP_CHANNEL_EVENT);
+					zchan->last_event_time = last_event_time;
+					chan_data->last_oob_event = span_data->last_oob_event;
+				}
+
+			}
+
+		}
+		
+		PKH_EVENT_GetText(span_data->last_oob_event.id, event_text, sizeof(event_text));
+		//zap_log(ZAP_LOG_DEBUG, "Event: %s\n", event_text);
+		
+		if (zchan) {
+			pika_chan_data_t *chan_data = (pika_chan_data_t *) zchan->mod_data;
+
+			assert(chan_data != NULL);
+			zap_set_flag(zchan, ZAP_CHANNEL_EVENT);
+            zchan->last_event_time = zap_current_time_in_ms();
+			chan_data->last_oob_event = span_data->last_oob_event;
+		}
+
+		return ZAP_SUCCESS;
+	}
+
+	return ZAP_FAIL;
+}
+
+/**
+ * \brief Retrieves an event from a Pika span
+ * \param span Span to retrieve event from
+ * \param event Openzap event to return
+ * \return Success or failure
+ */
+static ZIO_SPAN_NEXT_EVENT_FUNCTION(pika_next_event)
+{
+	uint32_t i, event_id = 0;
+	
+	for(i = 1; i <= span->chan_count; i++) {
+		if (zap_test_flag(span->channels[i], ZAP_CHANNEL_EVENT)) {
+			pika_chan_data_t *chan_data = (pika_chan_data_t *) span->channels[i]->mod_data;
+			PK_CHAR event_text[PKH_EVENT_MAX_NAME_LENGTH];
+			
+			zap_clear_flag(span->channels[i], ZAP_CHANNEL_EVENT);
+			
+			PKH_EVENT_GetText(chan_data->last_oob_event.id, event_text, sizeof(event_text));
+
+			switch(chan_data->last_oob_event.id) {
+			case PKH_EVENT_HDLC_MESSAGE:
+				chan_data->hdlc_bytes = chan_data->last_oob_event.p2;
+				continue;
+			case PKH_EVENT_TRUNK_HOOKFLASH:
+				event_id = ZAP_OOB_FLASH;
+				break;
+			case PKH_EVENT_TRUNK_RING_OFF:
+				event_id = ZAP_OOB_RING_STOP;
+				break;
+			case PKH_EVENT_TRUNK_RING_ON:
+				event_id = ZAP_OOB_RING_START;
+				break;
+
+			case PKH_EVENT_PHONE_OFFHOOK:
+				zap_set_flag_locked(span->channels[i], ZAP_CHANNEL_OFFHOOK);
+				event_id = ZAP_OOB_OFFHOOK;
+				break;
+
+			case PKH_EVENT_TRUNK_BELOW_THRESHOLD:
+			case PKH_EVENT_TRUNK_ABOVE_THRESHOLD:
+			case PKH_EVENT_PHONE_ONHOOK:
+				zap_clear_flag_locked(span->channels[i], ZAP_CHANNEL_OFFHOOK);
+				event_id = ZAP_OOB_ONHOOK;
+				break;
+
+
+
+			case PKH_EVENT_SPAN_ALARM_T1_RED:
+				zap_set_alarm_flag(span->channels[i], ZAP_ALARM_RED);
+				snprintf(span->channels[i]->last_error, sizeof(span->channels[i]->last_error), "RED ALARM");
+				event_id = ZAP_OOB_ALARM_TRAP;
+				break;
+			case PKH_EVENT_SPAN_ALARM_T1_YELLOW:
+				zap_set_alarm_flag(span->channels[i], ZAP_ALARM_YELLOW);
+				snprintf(span->channels[i]->last_error, sizeof(span->channels[i]->last_error), "YELLOW ALARM");
+				event_id = ZAP_OOB_ALARM_TRAP;
+				break;
+			case PKH_EVENT_SPAN_ALARM_T1_AIS:
+				zap_set_alarm_flag(span->channels[i], ZAP_ALARM_AIS);
+				snprintf(span->channels[i]->last_error, sizeof(span->channels[i]->last_error), "AIS ALARM");
+				event_id = ZAP_OOB_ALARM_TRAP;
+				break;
+			case PKH_EVENT_SPAN_ALARM_E1_RED:
+				zap_set_alarm_flag(span->channels[i], ZAP_ALARM_RED);
+				snprintf(span->channels[i]->last_error, sizeof(span->channels[i]->last_error), "RED ALARM");
+				event_id = ZAP_OOB_ALARM_TRAP;
+				break;
+			case PKH_EVENT_SPAN_ALARM_E1_RAI:
+				zap_set_alarm_flag(span->channels[i], ZAP_ALARM_RAI);
+				snprintf(span->channels[i]->last_error, sizeof(span->channels[i]->last_error), "RAI ALARM");
+				event_id = ZAP_OOB_ALARM_TRAP;
+				break;
+			case PKH_EVENT_SPAN_ALARM_E1_AIS:
+				zap_set_alarm_flag(span->channels[i], ZAP_ALARM_AIS);
+				snprintf(span->channels[i]->last_error, sizeof(span->channels[i]->last_error), "AIS ALARM");
+				event_id = ZAP_OOB_ALARM_TRAP;
+				break;
+			case PKH_EVENT_SPAN_ALARM_E1_RMAI:
+			case PKH_EVENT_SPAN_ALARM_E1_TS16AIS:
+			case PKH_EVENT_SPAN_ALARM_E1_TS16LOS:
+			case PKH_EVENT_SPAN_OUT_OF_SYNC:
+			case PKH_EVENT_SPAN_FRAMING_ERROR:
+			case PKH_EVENT_SPAN_LOSS_OF_SIGNAL:
+			case PKH_EVENT_SPAN_OUT_OF_CRC_MF_SYNC:
+			case PKH_EVENT_SPAN_OUT_OF_CAS_MF_SYNC:
+				zap_set_alarm_flag(span->channels[i], ZAP_ALARM_GENERAL);
+				snprintf(span->channels[i]->last_error, sizeof(span->channels[i]->last_error), "GENERAL ALARM");
+				event_id = ZAP_OOB_ALARM_TRAP;
+				break;
+			case PKH_EVENT_SPAN_ALARM_T1_RED_CLEAR:
+				zap_set_alarm_flag(span->channels[i], ZAP_ALARM_RED);
+			case PKH_EVENT_SPAN_ALARM_T1_YELLOW_CLEAR:
+				zap_set_alarm_flag(span->channels[i], ZAP_ALARM_YELLOW);
+			case PKH_EVENT_SPAN_ALARM_T1_AIS_CLEAR:
+				zap_set_alarm_flag(span->channels[i], ZAP_ALARM_AIS);
+			case PKH_EVENT_SPAN_ALARM_E1_RED_CLEAR:
+				zap_set_alarm_flag(span->channels[i], ZAP_ALARM_RED);
+			case PKH_EVENT_SPAN_ALARM_E1_RAI_CLEAR:
+				zap_set_alarm_flag(span->channels[i], ZAP_ALARM_RAI);
+			case PKH_EVENT_SPAN_ALARM_E1_AIS_CLEAR:
+				zap_set_alarm_flag(span->channels[i], ZAP_ALARM_AIS);
+			case PKH_EVENT_SPAN_ALARM_E1_RMAI_CLEAR:
+			case PKH_EVENT_SPAN_ALARM_E1_TS16AIS_CLEAR:
+			case PKH_EVENT_SPAN_ALARM_E1_TS16LOS_CLEAR:
+			case PKH_EVENT_SPAN_IN_SYNC:
+			case PKH_EVENT_SPAN_LOSS_OF_SIGNAL_CLEAR:
+			case PKH_EVENT_SPAN_IN_CRC_MF_SYNC:
+			case PKH_EVENT_SPAN_IN_CAS_MF_SYNC:
+				zap_clear_alarm_flag(span->channels[i], ZAP_ALARM_GENERAL);
+				event_id = ZAP_OOB_ALARM_CLEAR;
+				break;
+			case PKH_EVENT_SPAN_MESSAGE:
+			case PKH_EVENT_SPAN_ABCD_SIGNAL_CHANGE:
+				break;
+
+
+
+
+			case PKH_EVENT_TRUNK_ONHOOK:
+			case PKH_EVENT_TRUNK_OFFHOOK:				
+			case PKH_EVENT_TRUNK_DIALED :
+			case PKH_EVENT_TRUNK_REVERSAL:
+			case PKH_EVENT_TRUNK_LCSO:
+			case PKH_EVENT_TRUNK_DROPOUT:
+			case PKH_EVENT_TRUNK_LOF:
+			case PKH_EVENT_TRUNK_RX_OVERLOAD:
+			default:
+				zap_log(ZAP_LOG_DEBUG, "Unhandled event %d on channel %d [%s]\n", chan_data->last_oob_event.id, i, event_text);
+				event_id = ZAP_OOB_INVALID;
+				break;
+			}
+
+			span->channels[i]->last_event_time = 0;
+			span->event_header.e_type = ZAP_EVENT_OOB;
+			span->event_header.enum_id = event_id;
+			span->event_header.channel = span->channels[i];
+			*event = &span->event_header;
+			return ZAP_SUCCESS;
+		}
+	}
+
+	return ZAP_FAIL;
+}
+
+/**
+ * \brief Destroys a Pika Span
+ * \param span Span to destroy
+ * \return Success
+ */
+static ZIO_SPAN_DESTROY_FUNCTION(pika_span_destroy)
+{
+	pika_span_data_t *span_data = (pika_span_data_t *) span->mod_data;
+	
+	if (span_data) {
+		PKH_QUEUE_Destroy(span_data->event_queue);
+		free(span_data);
+	}
+	
+	return ZAP_SUCCESS;
+}
+
+/**
+ * \brief Destroys a Pika Channel
+ * \param zchan Channel to destroy
+ * \return Success or failure
+ */
+static ZIO_CHANNEL_DESTROY_FUNCTION(pika_channel_destroy)
+{
+	pika_chan_data_t *chan_data = (pika_chan_data_t *) zchan->mod_data;
+	pika_span_data_t *span_data = (pika_span_data_t *) zchan->span->mod_data;
+	
+	if (!chan_data) {
+		return ZAP_FAIL;
+	}
+
+	if (!zap_test_flag(chan_data, PK_FLAG_READY)) {
+		goto end;
+	}
+
+	PKH_RECORD_Stop(chan_data->media_in);
+	PKH_PLAY_Stop(chan_data->media_out);
+	PKH_QUEUE_Destroy(chan_data->media_in_queue);
+	PKH_QUEUE_Destroy(chan_data->media_out_queue);
+	
+	switch(zchan->type) {
+	case ZAP_CHAN_TYPE_FXS:
+		PKH_QUEUE_Detach(span_data->event_queue, chan_data->handle);
+		PKH_PHONE_Close(chan_data->handle);
+		break;
+	case ZAP_CHAN_TYPE_FXO:
+		PKH_QUEUE_Detach(span_data->event_queue, chan_data->handle);
+		PKH_TRUNK_Close(chan_data->handle);
+		break;
+	case ZAP_CHAN_TYPE_DQ921:
+		PKH_SPAN_Stop(span_data->handle);
+		break;
+	default:
+		break;
+	}
+
+
+	zap_mutex_destroy(&chan_data->digit_mutex);
+	zap_buffer_destroy(&chan_data->digit_buffer);
+
+ end:
+	zap_safe_free(chan_data);
+	
+	return ZAP_SUCCESS;
+}
+
+/**
+ * \brief Gets alarms from a Pika Channel (does nothing)
+ * \param zchan Channel to get alarms from
+ * \return Failure
+ */
+static ZIO_GET_ALARMS_FUNCTION(pika_get_alarms)
+{
+	return ZAP_FAIL;
+}
+
+static zap_io_interface_t pika_interface;
+
+/**
+ * \brief Loads Pika IO module
+ * \param zio Openzap IO interface
+ * \return Success or failure
+ */
+static ZIO_IO_LOAD_FUNCTION(pika_init)
+{
+
+	PK_STATUS status;
+	PK_CHAR error_text[PKH_ERROR_MAX_NAME_LENGTH];
+	uint32_t i;
+	int ok = 0;
+	PKH_TLogMasks m;
+	TPikaHandle tmpHandle;
+
+	assert(zio != NULL);
+	memset(&pika_interface, 0, sizeof(pika_interface));
+	memset(&globals, 0, sizeof(globals));
+	globals.general_config.region = PKH_TRUNK_NA;
+
+	globals.profile_hash = create_hashtable(16, zap_hash_hashfromstring, zap_hash_equalkeys);
+
+	// Open the system object, to enumerate boards configured for this system
+	if ((status = PKH_SYSTEM_Open(&globals.system_handle)) != PK_SUCCESS) {
+		zap_log(ZAP_LOG_ERROR, "Error: PKH_SYSTEM_Open failed(%s)!\n",
+				PKH_ERROR_GetText(status, error_text, sizeof(error_text)));
+		return ZAP_FAIL;
+	}
+
+	// Retrieves a list of all boards in this system, existing,
+	// or listed in pika.cfg
+	if ((status = PKH_SYSTEM_Detect(globals.system_handle, &globals.board_list)) != PK_SUCCESS) {
+		zap_log(ZAP_LOG_ERROR, "Error: PKH_SYSTEM_Detect failed(%s)!\n",
+				PKH_ERROR_GetText(status, error_text, sizeof(error_text)));
+		return ZAP_FAIL;
+	}
+	
+	PKH_SYSTEM_GetConfig(globals.system_handle, &globals.system_config);
+	globals.system_config.maxAudioProcessBlockSize = PIKA_BLOCK_LEN;
+	globals.system_config.playBufferSize = PIKA_BLOCK_SIZE;
+	globals.system_config.recordBufferSize = PIKA_BLOCK_SIZE;
+	globals.system_config.recordNumberOfBuffers = PIKA_NUM_BUFFERS;
+	PKH_SYSTEM_SetConfig(globals.system_handle, &globals.system_config);
+
+	status = PKH_MEDIA_STREAM_Create(&tmpHandle);
+	status = PKH_RECORD_GetConfig(tmpHandle, &globals.record_config);
+	status = PKH_PLAY_GetConfig(tmpHandle, &globals.play_config);
+	status = PKH_EC_GetConfig(tmpHandle, &globals.ec_config);
+	status = PKH_MEDIA_STREAM_Destroy(tmpHandle);
+
+	
+
+	zap_log(ZAP_LOG_DEBUG, "Found %u board%s\n", globals.board_list.numberOfBoards, globals.board_list.numberOfBoards == 1 ? "" : "s");
+	for(i = 0; i < globals.board_list.numberOfBoards; ++i) {
+		zap_log(ZAP_LOG_INFO, "Found PIKA board type:[%s] id:[%u] serno:[%u]\n", 
+				pika_board_type_string(globals.board_list.board[i].type), globals.board_list.board[i].id, (uint32_t)
+				globals.board_list.board[i].serialNumber);
+
+		if (globals.board_list.board[i].type == PKH_BOARD_TYPE_DIGITAL_GATEWAY) {
+			TPikaHandle board_handle, span_handle;
+			PKH_TBoardConfig boardConfig;
+			PKH_BOARD_GetConfig(board_handle, &boardConfig);
+			PKH_BOARD_Open(globals.board_list.board[i].id, NULL, &board_handle);
+			PKH_SPAN_Open(board_handle, 0, NULL, &span_handle);
+			PKH_SPAN_GetConfig(span_handle, &globals.t1_span_config);
+			PKH_SPAN_Close(span_handle);
+			boardConfig.specific.DigitalGateway.interfaceType = PKH_BOARD_INTERFACE_TYPE_E1;
+			PKH_BOARD_SetConfig(board_handle, &boardConfig);
+			PKH_SPAN_Open(board_handle, 0, NULL, &span_handle);
+			PKH_SPAN_GetConfig(span_handle, &globals.e1_span_config);
+			PKH_SPAN_Close(span_handle);
+			boardConfig.specific.DigitalGateway.interfaceType = PKH_BOARD_INTERFACE_TYPE_T1;
+			PKH_BOARD_SetConfig(board_handle, &boardConfig);
+			PKH_BOARD_Close(board_handle);
+		}
+		ok++;
+
+	}
+
+	if (!ok) {
+		return ZAP_FAIL;
+	}
+	
+	pika_interface.name = "pika";
+	pika_interface.configure =  pika_configure;
+	pika_interface.configure_span = pika_configure_span;
+	pika_interface.open = pika_open;
+	pika_interface.close = pika_close;
+	pika_interface.wait = pika_wait;
+	pika_interface.read = pika_read;
+	pika_interface.write = pika_write;
+	pika_interface.command = pika_command;
+	pika_interface.poll_event = pika_poll_event;
+	pika_interface.next_event = pika_next_event;
+	pika_interface.channel_destroy = pika_channel_destroy;
+	pika_interface.span_destroy = pika_span_destroy;
+	pika_interface.get_alarms = pika_get_alarms;
+	*zio = &pika_interface;
+
+
+	zap_log(ZAP_LOG_INFO, "Dumping Default configs:\n");
+	zap_log(ZAP_LOG_INFO, "rx-gain => %0.2f\n", (float)globals.record_config.gain);
+	zap_log(ZAP_LOG_INFO, "rx-agc-enabled => %s\n", globals.record_config.AGC.enabled ? "true" : "false");
+	zap_log(ZAP_LOG_INFO, "rx-agc-targetPower => %0.2f\n", (float)globals.record_config.AGC.targetPower);
+	zap_log(ZAP_LOG_INFO, "rx-agc-minGain => %0.2f\n", (float)globals.record_config.AGC.minGain);
+	zap_log(ZAP_LOG_INFO, "rx-agc-maxGain => %0.2f\n", (float)globals.record_config.AGC.maxGain);
+	zap_log(ZAP_LOG_INFO, "rx-agc-attackRate => %d\n", (int)globals.record_config.AGC.attackRate);
+	zap_log(ZAP_LOG_INFO, "rx-agc-decayRate => %d\n", (int)globals.record_config.AGC.decayRate);
+	zap_log(ZAP_LOG_INFO, "rx-agc-speechThreshold => %0.2f\n", (float)globals.record_config.AGC.speechThreshold);
+	zap_log(ZAP_LOG_INFO, "rx-vad-enabled => %s\n", globals.record_config.VAD.enabled ? "true" : "false");
+	zap_log(ZAP_LOG_INFO, "rx-vad-activationThreshold => %0.2f\n", (float)globals.record_config.VAD.activationThreshold);
+	zap_log(ZAP_LOG_INFO, "rx-vad-activationDebounceTime => %d\n", (int)globals.record_config.VAD.activationDebounceTime);
+	zap_log(ZAP_LOG_INFO, "rx-vad-deactivationThreshold => %0.2f\n", (float)globals.record_config.VAD.deactivationThreshold);
+	zap_log(ZAP_LOG_INFO, "rx-vad-deactivationDebounceTime => %d\n", (int)globals.record_config.VAD.deactivationDebounceTime);
+	zap_log(ZAP_LOG_INFO, "rx-vad-preSpeechBufferSize => %d\n", (int)globals.record_config.VAD.preSpeechBufferSize);
+	zap_log(ZAP_LOG_INFO, "tx-gain => %0.2f\n", (float)globals.play_config.gain);
+	zap_log(ZAP_LOG_INFO, "tx-agc-enabled => %s\n", globals.play_config.AGC.enabled ? "true" : "false");
+	zap_log(ZAP_LOG_INFO, "tx-agc-targetPower => %0.2f\n", (float)globals.play_config.AGC.targetPower);
+	zap_log(ZAP_LOG_INFO, "tx-agc-minGain => %0.2f\n", (float)globals.play_config.AGC.minGain);
+	zap_log(ZAP_LOG_INFO, "tx-agc-maxGain => %0.2f\n", (float)globals.play_config.AGC.maxGain);
+	zap_log(ZAP_LOG_INFO, "tx-agc-attackRate => %d\n", (int)globals.play_config.AGC.attackRate);
+	zap_log(ZAP_LOG_INFO, "tx-agc-decayRate => %d\n", (int)globals.play_config.AGC.decayRate);
+	zap_log(ZAP_LOG_INFO, "tx-agc-speechThreshold => %0.2f\n", (float)globals.play_config.AGC.speechThreshold);
+	zap_log(ZAP_LOG_INFO, "ec-doubleTalkerThreshold => %0.2f\n", (float)globals.ec_config.doubleTalkerThreshold);
+	zap_log(ZAP_LOG_INFO, "ec-speechPresentThreshold => %0.2f\n", (float)globals.ec_config.speechPresentThreshold);
+	zap_log(ZAP_LOG_INFO, "ec-echoSuppressionThreshold => %0.2f\n", (float)globals.ec_config.echoSuppressionThreshold);
+	zap_log(ZAP_LOG_INFO, "ec-echoSuppressionEnabled => %s\n", globals.ec_config.echoSuppressionEnabled ? "true" : "false");
+	zap_log(ZAP_LOG_INFO, "ec-comfortNoiseEnabled => %s\n", globals.ec_config.comfortNoiseEnabled ? "true" : "false");
+	zap_log(ZAP_LOG_INFO, "ec-adaptationModeEnabled => %s\n", globals.ec_config.adaptationModeEnabled ? "true" : "false");
+
+	
+
+	memset(&m, 0, sizeof(m));
+	//m.apiMask = 0xffffffff;
+	//PKH_LOG_SetMasks(&m);
+
+	return ZAP_SUCCESS;
+}
+
+/**
+ * \brief Unloads Pika IO module
+ * \return Success
+ */
+static ZIO_IO_UNLOAD_FUNCTION(pika_destroy)
+{
+	uint32_t x;
+	PK_STATUS status;
+	PK_CHAR error_text[PKH_ERROR_MAX_NAME_LENGTH];
+
+	for (x = 0; x < MAX_NUMBER_OF_TRUNKS; x++) {
+		if (globals.open_boards[x]) {
+			zap_log(ZAP_LOG_INFO, "Closing board %u\n", x);
+			PKH_BOARD_Close(globals.open_boards[x]);
+		}
+	}
+
+	// The system can now be closed.
+	if ((status = PKH_SYSTEM_Close(globals.system_handle)) != PK_SUCCESS) {
+		zap_log(ZAP_LOG_ERROR, "Error: PKH_SYSTEM_Close failed(%s)!\n",
+				PKH_ERROR_GetText(status, error_text, sizeof(error_text)));
+	} else {
+		zap_log(ZAP_LOG_INFO, "Closing system handle\n");
+	}
+
+	hashtable_destroy(globals.profile_hash);
+
+	return ZAP_SUCCESS;
+}
+
+/**
+ * \brief Pika IO module definition
+ */
+EX_DECLARE_DATA zap_module_t zap_module = { 
+	"pika",
+	pika_init,
+	pika_destroy,
+};
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
+

Added: freeswitch/trunk/libs/openzap/src/ozmod/ozmod_pika/zap_pika.h (0 => 17141)


--- freeswitch/trunk/libs/openzap/src/ozmod/ozmod_pika/zap_pika.h	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/src/ozmod/ozmod_pika/zap_pika.h	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2007, Anthony Minessale II
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ZAP_PIKA_H
+#define ZAP_PIKA_H
+#include "openzap.h"
+#include "pikahmpapi.h"
+
+
+
+#define PIKA_STR2ENUM_P(_FUNC1, _FUNC2, _TYPE) _TYPE _FUNC1 (const char *name); const char * _FUNC2 (_TYPE type);
+#define PIKA_STR2ENUM(_FUNC1, _FUNC2, _TYPE, _STRINGS, _MAX)	\
+	_TYPE _FUNC1 (const char *name)								\
+	{														\
+		int i;												\
+		_TYPE t = _MAX ;									\
+															\
+		for (i = 0; i < _MAX ; i++) {						\
+			if (!strcasecmp(name, _STRINGS[i])) {			\
+				t = (_TYPE) i;								\
+				break;										\
+			}												\
+		}													\
+															\
+		return t;											\
+	}														\
+	const char * _FUNC2 (_TYPE type)						\
+	{														\
+		if (type > _MAX) {									\
+			type = _MAX;									\
+		}													\
+		return _STRINGS[(int)type];							\
+	}
+
+
+typedef enum {
+	PIKA_SPAN_FRAMING_T1_D4,
+	PIKA_SPAN_FRAMING_T1_ESF,
+	PIKA_SPAN_FRAMING_E1_BASIC,
+	PIKA_SPAN_FRAMING_E1_CRC4,
+	PIKA_SPAN_INVALID
+} PIKA_TSpanFraming;
+#define PIKA_SPAN_STRINGS "T1_D4", "T1_ESF", "E1_BASIC", "E1_CRC4"
+PIKA_STR2ENUM_P(pika_str2span, pika_span2str, PIKA_TSpanFraming)
+
+typedef enum {
+	PIKA_SPAN_ENCODING_T1_AMI_ZS_NONE,
+	PIKA_SPAN_ENCODING_T1_AMI_ZS_GTE,
+	PIKA_SPAN_ENCODING_T1_AMI_ZS_BELL,
+	PIKA_SPAN_ENCODING_T1_AMI_ZS_JAM8,
+	PIKA_SPAN_ENCODING_T1_B8ZS,
+	PIKA_SPAN_ENCODING_E1_AMI,
+	PIKA_SPAN_ENCODING_E1_HDB3,
+	PIKA_SPAN_ENCODING_INVALID
+} PIKA_TSpanEncoding;
+#define PIKA_SPAN_ENCODING_STRINGS "T1_AMI_ZS_NONE", "T1_AMI_ZS_GTE", "T1_AMI_ZS_BELL", "T1_AMI_ZS_JAM8", "T1_B8ZS", "E1_AMI", "E1_HDB3"
+PIKA_STR2ENUM_P(pika_str2span_encoding, pika_span_encoding2str, PIKA_TSpanEncoding)
+
+typedef enum {
+	PIKA_SPAN_LOOP_LENGTH_SHORT_HAUL,
+	PIKA_SPAN_LOOP_LENGTH_LONG_HAUL,
+	PIKA_SPAN_LOOP_INVALID
+} PIKA_TSpanLoopLength;
+#define PIKA_LL_STRINGS "SHORT_HAUL", "LONG_HAUL"
+PIKA_STR2ENUM_P(pika_str2loop_length, pika_loop_length2str, PIKA_TSpanLoopLength)
+
+typedef enum {
+	PIKA_SPAN_LBO_T1_LONG_0_DB,
+	PIKA_SPAN_LBO_T1_LONG_7_DB,
+	PIKA_SPAN_LBO_T1_LONG_15_DB,
+	PIKA_SPAN_LBO_T1_LONG_22_DB,
+	PIKA_SPAN_LBO_T1_SHORT_133_FT,
+	PIKA_SPAN_LBO_T1_SHORT_266_FT,
+	PIKA_SPAN_LBO_T1_SHORT_399_FT,
+	PIKA_SPAN_LBO_T1_SHORT_533_FT,
+	PIKA_SPAN_LBO_T1_SHORT_655_FT,
+	PIKA_SPAN_LBO_E1_WAVEFORM_120_OHM,
+	PIKA_SPAN_LBO_INVALID
+} PIKA_TSpanBuildOut;
+#define PIKA_LBO_STRINGS "T1_LONG_0_DB", "T1_LONG_7_DB", "T1_LONG_15_DB", "T1_LONG_22_DB", "T1_SHORT_133_FT", "T1_SHORT_266_FT", "T1_SHORT_399_FT", "T1_SHORT_533_FT", "T1_SHORT_655_FT", "E1_WAVEFORM_120_OHM"
+PIKA_STR2ENUM_P(pika_str2lbo, pika_lbo2str, PIKA_TSpanBuildOut)
+
+typedef enum {
+	PIKA_SPAN_COMPAND_MODE_MU_LAW = 1,
+	PIKA_SPAN_COMPAND_MODE_A_LAW,
+	PIKA_SPAN_COMPAND_MODE_INVALID
+} PIKA_TSpanCompandMode;
+#define PIKA_SPAN_COMPAND_MODE_STRINGS "MU_LAW", "A_LAW"
+PIKA_STR2ENUM_P(pika_str2compand_mode, pika_compand_mode2str, PIKA_TSpanCompandMode)
+
+#endif
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */

Added: freeswitch/trunk/libs/openzap/src/ozmod/ozmod_r2/ozmod_r2.c (0 => 17141)


--- freeswitch/trunk/libs/openzap/src/ozmod/ozmod_r2/ozmod_r2.c	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/src/ozmod/ozmod_r2/ozmod_r2.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,1364 @@
+/*
+ * Copyright (c) 2009, Moises Silva <moy@sangoma.com>
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <pthread.h>
+#include <openr2.h>
+#include "openzap.h"
+
+/* debug thread count for r2 legs */
+static zap_mutex_t* g_thread_count_mutex;
+static int32_t g_thread_count = 0;
+
+/* when the users kills a span we clear this flag to kill the signaling thread */
+/* FIXME: what about the calls that are already up-and-running? */
+typedef enum {
+	ZAP_R2_RUNNING = (1 << 0),
+} zap_r2_flag_t;
+
+/* private call information stored in zchan->call_data void* ptr */
+#define R2CALL(zchan) ((zap_r2_call_t*)((zchan)->call_data))
+typedef struct zap_r2_call_t {
+    openr2_chan_t *r2chan;
+	int accepted:1;
+	int answer_pending:1;
+	int state_ack_pending:1;
+	int disconnect_rcvd:1;
+	int zap_started:1;
+	zap_channel_state_t chanstate;
+	zap_size_t dnis_index;
+	zap_size_t ani_index;
+	char name[10];
+} zap_r2_call_t;
+
+/* this is just used as place holder in the stack when configuring the span to avoid using bunch of locals */
+typedef struct oz_r2_conf_s {
+	/* openr2 types */
+	openr2_variant_t variant;
+	openr2_calling_party_category_t category;
+	openr2_log_level_t loglevel;
+
+	/* strings */
+	char *logdir;
+	char *advanced_protocol_file;
+
+	/* ints */
+	int32_t max_ani;
+	int32_t max_dnis;
+	int32_t mfback_timeout; 
+	int32_t metering_pulse_timeout;
+
+	/* booleans */
+	int immediate_accept;
+	int skip_category;
+	int get_ani_first;
+	int call_files;
+	int double_answer;
+	int charge_calls;
+	int forced_release;
+	int allow_collect_calls;
+} oz_r2_conf_t;
+
+/* r2 configuration stored in span->signal_data */
+typedef struct zap_r2_data_s {
+	/* span flags */
+	zap_r2_flag_t flags;
+	/* openr2 handle for the R2 variant context */
+	openr2_context_t *r2context;
+	/* category to use when making calls */
+	openr2_calling_party_category_t category;
+	/* whether to use OR2_CALL_WITH_CHARGE or OR2_CALL_NO_CHARGE when accepting a call */
+	int charge_calls:1;
+	/* allow or reject collect calls */
+	int allow_collect_calls:1;
+	/* whether to use forced release when hanging up */
+	int forced_release:1;
+	/* whether accept the call when offered, or wait until the user decides to accept */
+	int accept_on_offer:1;
+} zap_r2_data_t;
+
+/* one element per span will be stored in g_mod_data_hash global var to keep track of them
+   and destroy them on module unload */
+typedef struct zap_r2_span_pvt_s {
+	openr2_context_t *r2context; /* r2 context allocated for this span */
+	zap_hash_t *r2calls; /* hash table of allocated call data per channel for this span */
+} zap_r2_span_pvt_t;
+
+/* span monitor thread */
+static void *zap_r2_run(zap_thread_t *me, void *obj);
+
+/* channel monitor thread */
+static void *zap_r2_channel_run(zap_thread_t *me, void *obj);
+
+/* hash of all the private span allocations
+   we need to keep track of them to destroy them when unloading the module 
+   since openzap does not notify signaling modules when destroying a span
+   span -> zap_r2_mod_allocs_t */
+static zap_hash_t *g_mod_data_hash;
+
+/* IO interface for the command API */
+static zap_io_interface_t g_zap_r2_interface;
+
+static void oz_r2_clean_call(zap_r2_call_t *call)
+{
+    openr2_chan_t *r2chan = call->r2chan;
+    memset(call, 0, sizeof(*call));
+    call->r2chan = r2chan;
+}
+
+static void oz_r2_accept_call(zap_channel_t *zchan)
+{
+	openr2_chan_t *r2chan = R2CALL(zchan)->r2chan;
+	// FIXME: not always accept as no charge, let the user decide that
+	// also we should check the return code from openr2_chan_accept_call and handle error condition
+	// hanging up the call with protocol error as the reason, this openr2 API will fail only when there something
+	// wrong at the I/O layer or the library itself
+	openr2_chan_accept_call(r2chan, OR2_CALL_NO_CHARGE);
+	R2CALL(zchan)->accepted = 1;
+}
+
+static void oz_r2_answer_call(zap_channel_t *zchan)
+{
+	openr2_chan_t *r2chan = R2CALL(zchan)->r2chan;
+	// FIXME
+	// 1. check openr2_chan_answer_call return code
+	// 2. The openr2_chan_answer_call_with_mode should be used depending on user settings
+	// openr2_chan_answer_call_with_mode(r2chan, OR2_ANSWER_SIMPLE);
+	openr2_chan_answer_call(r2chan);
+	R2CALL(zchan)->answer_pending = 0;
+}
+
+static ZIO_CHANNEL_OUTGOING_CALL_FUNCTION(r2_outgoing_call)
+{
+	zap_status_t status;
+	zap_mutex_lock(zchan->mutex);
+
+	/* the channel may be down but the thread not quite done */
+	zap_wait_for_flag_cleared(zchan, ZAP_CHANNEL_INTHREAD, 200);
+
+	if (zap_test_flag(zchan, ZAP_CHANNEL_INTHREAD)) {
+		zap_log(ZAP_LOG_ERROR, "%d:%d Yay! R2 outgoing call in channel that is already in thread.\n", 
+				zchan->span_id, zchan->chan_id);
+		zap_mutex_unlock(zchan->mutex);
+		return ZAP_FAIL;
+	}
+
+	oz_r2_clean_call(zchan->call_data);
+	R2CALL(zchan)->chanstate = ZAP_CHANNEL_STATE_DOWN;
+	zap_channel_set_state(zchan, ZAP_CHANNEL_STATE_DIALING, 0);
+	zap_set_flag(zchan, ZAP_CHANNEL_OUTBOUND);
+	R2CALL(zchan)->zap_started = 1;
+	zap_mutex_unlock(zchan->mutex);
+
+	status = zap_thread_create_detached(zap_r2_channel_run, zchan);
+	if (status == ZAP_FAIL) {
+		zap_log(ZAP_LOG_ERROR, "%d:%d Cannot handle request to start call in channel, failed to create thread!\n", 
+				zchan->span_id, zchan->chan_id);
+		zap_channel_done(zchan);
+		return ZAP_FAIL;
+	}
+
+	return ZAP_SUCCESS;
+}
+
+static zap_status_t zap_r2_start(zap_span_t *span)
+{
+	zap_r2_data_t *r2_data = span->signal_data;
+	zap_set_flag(r2_data, ZAP_R2_RUNNING);
+	return zap_thread_create_detached(zap_r2_run, span);
+}
+
+/* always called from the monitor thread */
+static void zap_r2_on_call_init(openr2_chan_t *r2chan)
+{
+	zap_channel_t *zchan = openr2_chan_get_client_data(r2chan);
+	zap_status_t status;
+	zap_log(ZAP_LOG_NOTICE, "Received request to start call on chan %d\n", openr2_chan_get_number(r2chan));
+
+	zap_mutex_lock(zchan->mutex);
+
+	if (zchan->state != ZAP_CHANNEL_STATE_DOWN) {
+		zap_log(ZAP_LOG_ERROR, "Cannot handle request to start call in channel %d, invalid state (%d)\n", 
+				openr2_chan_get_number(r2chan), zchan->state);
+		zap_mutex_unlock(zchan->mutex);
+		return;
+	}
+
+	/* the channel may be down but the thread not quite done */
+	zap_wait_for_flag_cleared(zchan, ZAP_CHANNEL_INTHREAD, 200);
+
+	if (zap_test_flag(zchan, ZAP_CHANNEL_INTHREAD)) {
+		zap_log(ZAP_LOG_ERROR, "Cannot handle request to start call in channel %d, already in thread!\n", 
+				openr2_chan_get_number(r2chan));
+		zap_mutex_unlock(zchan->mutex);
+		return;
+	}
+	oz_r2_clean_call(zchan->call_data);
+	R2CALL(zchan)->chanstate = ZAP_CHANNEL_STATE_DOWN;
+	zap_channel_set_state(zchan, ZAP_CHANNEL_STATE_COLLECT, 0);
+	zap_mutex_unlock(zchan->mutex);
+
+	status = zap_thread_create_detached(zap_r2_channel_run, zchan);
+	if (status == ZAP_FAIL) {
+		zap_log(ZAP_LOG_ERROR, "Cannot handle request to start call in channel %d, failed to create thread!\n", 
+				openr2_chan_get_number(r2chan));
+	}
+}
+
+/* only called for incoming calls when the ANI, DNIS etc is complete and the user has to decide either to accept or reject the call */
+static void zap_r2_on_call_offered(openr2_chan_t *r2chan, const char *ani, const char *dnis, openr2_calling_party_category_t category)
+{
+	zap_sigmsg_t sigev;
+	zap_channel_t *zchan = openr2_chan_get_client_data(r2chan);
+
+	zap_log(ZAP_LOG_NOTICE, "Call offered on chan %d, ANI = %s, DNIS = %s, Category = %s\n", openr2_chan_get_number(r2chan), 
+			ani, dnis, openr2_proto_get_category_string(category));
+
+	/* notify the user about the new call */
+	memset(&sigev, 0, sizeof(sigev));
+	sigev.chan_id = zchan->chan_id;
+	sigev.span_id = zchan->span_id;
+	sigev.channel = zchan;
+	sigev.event_id = ZAP_SIGEVENT_START;
+
+	if (zap_span_send_signal(zchan->span, &sigev) != ZAP_SUCCESS) {
+		zap_log(ZAP_LOG_NOTICE, "Failed to handle call offered on chan %d\n", openr2_chan_get_number(r2chan));
+		openr2_chan_disconnect_call(r2chan, OR2_CAUSE_OUT_OF_ORDER);
+		zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_CANCEL);
+		return; 
+	}
+	zap_channel_use(zchan);
+	R2CALL(zchan)->zap_started = 1; 
+}
+
+static void zap_r2_on_call_accepted(openr2_chan_t *r2chan, openr2_call_mode_t mode)
+{
+	zap_channel_t *zchan = openr2_chan_get_client_data(r2chan);
+	zap_log(ZAP_LOG_NOTICE, "Call accepted on chan %d\n", openr2_chan_get_number(r2chan));
+	/* at this point the MF signaling has ended and there is no point on keep reading */
+	openr2_chan_disable_read(r2chan);
+	if (OR2_DIR_BACKWARD == openr2_chan_get_direction(r2chan)) {
+		R2CALL(zchan)->state_ack_pending = 1;
+		if (R2CALL(zchan)->answer_pending) {
+			zap_log(ZAP_LOG_DEBUG, "Answer was pending on chan %d, answering now.\n", openr2_chan_get_number(r2chan));
+			oz_r2_answer_call(zchan);
+			return;
+		}
+	} else {
+		zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_PROGRESS);
+	}
+}
+
+static void zap_r2_on_call_answered(openr2_chan_t *r2chan)
+{
+	zap_channel_t *zchan = openr2_chan_get_client_data(r2chan);
+	zap_log(ZAP_LOG_NOTICE, "Call answered on chan %d\n", openr2_chan_get_number(r2chan));
+	/* notify the upper layer of progress in the outbound call */
+	if (OR2_DIR_FORWARD == openr2_chan_get_direction(r2chan)) {
+		zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_UP);
+	}
+}
+
+/* may be called in the signaling or media thread depending on whether the hangup is product of MF or CAS signaling */
+static void zap_r2_on_call_disconnect(openr2_chan_t *r2chan, openr2_call_disconnect_cause_t cause)
+{
+	zap_sigmsg_t sigev;
+	zap_r2_data_t *r2data;
+	zap_channel_t *zchan = openr2_chan_get_client_data(r2chan);
+	zap_log(ZAP_LOG_NOTICE, "Call disconnected on chan %d\n", openr2_chan_get_number(r2chan));
+
+	zap_log(ZAP_LOG_DEBUG, "Got openr2 disconnection, clearing call on channel %d\n", zchan->physical_chan_id);
+
+	R2CALL(zchan)->disconnect_rcvd = 1;
+
+	/* acknowledge the hangup, cause will be ignored. From here to -> HANGUP once the openzap side hangs up as well */
+	openr2_chan_disconnect_call(r2chan, OR2_CAUSE_NORMAL_CLEARING);
+
+	/* if the call has not been started yet we must go to HANGUP right here */ 
+	if (!R2CALL(zchan)->zap_started) {
+		zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_HANGUP);
+		return;
+	}
+
+	/* FIXME: use the cause received from openr2 and map it to zap cause  */
+	zchan->caller_data.hangup_cause  = ZAP_CAUSE_NORMAL_CLEARING; 
+
+	/* notify the user of the call terminating */
+	memset(&sigev, 0, sizeof(sigev));
+	sigev.chan_id = zchan->chan_id;
+	sigev.span_id = zchan->span_id;
+	sigev.channel = zchan;
+	sigev.event_id = ZAP_SIGEVENT_STOP;
+	r2data = zchan->span->signal_data;
+
+	zap_span_send_signal(zchan->span, &sigev);
+}
+
+static void zap_r2_on_call_end(openr2_chan_t *r2chan)
+{
+	zap_channel_t *zchan = openr2_chan_get_client_data(r2chan);
+	zap_log(ZAP_LOG_NOTICE, "Call finished on chan %d\n", openr2_chan_get_number(r2chan));
+	/* this means the openzap side disconnected the call, therefore we must move to DOWN here */
+	if (!R2CALL(zchan)->disconnect_rcvd) {
+		zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_DOWN);
+		return;
+	}
+}
+
+static void zap_r2_on_call_read(openr2_chan_t *r2chan, const unsigned char *buf, int buflen)
+{
+	zap_log(ZAP_LOG_NOTICE, "Call read data on chan %d\n", openr2_chan_get_number(r2chan));
+}
+
+static void zap_r2_on_hardware_alarm(openr2_chan_t *r2chan, int alarm)
+{
+	zap_log(ZAP_LOG_NOTICE, "Alarm on chan %d (%d)\n", openr2_chan_get_number(r2chan), alarm);
+}
+
+static void zap_r2_on_os_error(openr2_chan_t *r2chan, int errorcode)
+{
+	zap_log(ZAP_LOG_ERROR, "OS error on chan %d: %s\n", openr2_chan_get_number(r2chan), strerror(errorcode));
+}
+
+static void zap_r2_on_protocol_error(openr2_chan_t *r2chan, openr2_protocol_error_t reason)
+{
+	zap_sigmsg_t sigev;
+	zap_r2_data_t *r2data;
+	zap_channel_t *zchan = openr2_chan_get_client_data(r2chan);
+
+	zap_log(ZAP_LOG_ERROR, "Protocol error on chan %d\n", openr2_chan_get_number(r2chan));
+
+	R2CALL(zchan)->disconnect_rcvd = 1;
+
+	if (!R2CALL(zchan)->zap_started) {
+		zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_HANGUP);
+		return;
+	}
+
+	zchan->caller_data.hangup_cause  = ZAP_CAUSE_PROTOCOL_ERROR; 
+
+	/* notify the user of the call terminating */
+	memset(&sigev, 0, sizeof(sigev));
+	sigev.chan_id = zchan->chan_id;
+	sigev.span_id = zchan->span_id;
+	sigev.channel = zchan;
+	sigev.event_id = ZAP_SIGEVENT_STOP;
+	r2data = zchan->span->signal_data;
+
+	zap_span_send_signal(zchan->span, &sigev);
+}
+
+static void zap_r2_on_line_blocked(openr2_chan_t *r2chan)
+{
+	zap_log(ZAP_LOG_NOTICE, "Far end blocked on chan %d\n", openr2_chan_get_number(r2chan));
+}
+
+static void zap_r2_on_line_idle(openr2_chan_t *r2chan)
+{
+	zap_log(ZAP_LOG_NOTICE, "Far end unblocked on chan %d\n", openr2_chan_get_number(r2chan));
+}
+
+static void zap_r2_write_log(openr2_log_level_t level, const char *message)
+{
+	switch (level) {
+		case OR2_LOG_NOTICE:
+			zap_log(ZAP_LOG_NOTICE, "%s", message);
+			break;
+		case OR2_LOG_WARNING:
+			zap_log(ZAP_LOG_WARNING, "%s", message);
+			break;
+		case OR2_LOG_ERROR:
+			zap_log(ZAP_LOG_ERROR, "%s", message);
+			break;
+		case OR2_LOG_STACK_TRACE:
+		case OR2_LOG_MF_TRACE:
+		case OR2_LOG_CAS_TRACE:
+		case OR2_LOG_DEBUG:
+		case OR2_LOG_EX_DEBUG:
+			zap_log(ZAP_LOG_DEBUG, "%s", message);
+			break;
+		default:
+			zap_log(ZAP_LOG_WARNING, "We should handle logging level %d here.\n", level);
+			zap_log(ZAP_LOG_DEBUG, "%s", message);
+			break;
+	}
+}
+
+static void zap_r2_on_context_log(openr2_context_t *r2context, openr2_log_level_t level, const char *fmt, va_list ap)
+{
+#define CONTEXT_TAG "Context -"
+	char logmsg[256];
+	char completemsg[sizeof(logmsg) + sizeof(CONTEXT_TAG) - 1];
+	vsnprintf(logmsg, sizeof(logmsg), fmt, ap);
+	snprintf(completemsg, sizeof(completemsg), CONTEXT_TAG "%s", logmsg);
+	zap_r2_write_log(level, completemsg);
+#undef CONTEXT_TAG
+}
+
+static void zap_r2_on_chan_log(openr2_chan_t *r2chan, openr2_log_level_t level, const char *fmt, va_list ap)
+{
+#define CHAN_TAG "Chan "
+	char logmsg[256];
+	char completemsg[sizeof(logmsg) + sizeof(CHAN_TAG) - 1];
+	vsnprintf(logmsg, sizeof(logmsg), fmt, ap);
+	snprintf(completemsg, sizeof(completemsg), CHAN_TAG "%d: %s", openr2_chan_get_number(r2chan), logmsg);
+	zap_r2_write_log(level, completemsg);
+#undef CHAN_TAG
+}
+
+static int zap_r2_on_dnis_digit_received(openr2_chan_t *r2chan, char digit)
+{
+	zap_sigmsg_t sigev;
+	zap_r2_data_t *r2data;
+	zap_channel_t *zchan = openr2_chan_get_client_data(r2chan);
+	zap_size_t collected_len = R2CALL(zchan)->dnis_index;
+
+	zap_log(ZAP_LOG_DEBUG, "DNIS digit %d received chan %d\n", digit, openr2_chan_get_number(r2chan));
+
+	/* save the digit we just received */ 
+	zchan->caller_data.dnis.digits[collected_len] = digit;
+	collected_len++;
+	zchan->caller_data.dnis.digits[collected_len] = '\0';
+	R2CALL(zchan)->dnis_index = collected_len;
+
+	/* notify the user about the new digit and check if we should stop requesting more DNIS */
+	memset(&sigev, 0, sizeof(sigev));
+	sigev.chan_id = zchan->chan_id;
+	sigev.span_id = zchan->span_id;
+	sigev.channel = zchan;
+	sigev.event_id = ZAP_SIGEVENT_COLLECTED_DIGIT;
+	r2data = zchan->span->signal_data;
+	if (zap_span_send_signal(zchan->span, &sigev) == ZAP_BREAK) {
+		zap_log(ZAP_LOG_NOTICE, "Requested to stop getting DNIS. Current DNIS = %s on chan %d\n", zchan->caller_data.dnis.digits, openr2_chan_get_number(r2chan));
+		return OR2_STOP_DNIS_REQUEST; 
+	}
+
+	/* the only other reason to stop requesting DNIS is that there is no more room to save it */
+	if (collected_len == (sizeof(zchan->caller_data.dnis.digits) - 1)) {
+		zap_log(ZAP_LOG_NOTICE, "No more room for DNIS. Current DNIS = %s on chan %d\n", zchan->caller_data.dnis.digits, openr2_chan_get_number(r2chan));
+		return OR2_STOP_DNIS_REQUEST;
+	}
+
+	return OR2_CONTINUE_DNIS_REQUEST; 
+}
+
+static void zap_r2_on_ani_digit_received(openr2_chan_t *r2chan, char digit)
+{
+	zap_channel_t *zchan = openr2_chan_get_client_data(r2chan);
+	zap_size_t collected_len = R2CALL(zchan)->ani_index;
+
+	/* check if we should drop ANI */
+	if (collected_len == (sizeof(zchan->caller_data.ani.digits) - 1)) {
+		zap_log(ZAP_LOG_NOTICE, "No more room for ANI %c on chan %d, digit dropped.\n", digit, openr2_chan_get_number(r2chan));
+		return;
+	}
+	zap_log(ZAP_LOG_DEBUG, "ANI digit %c received chan %d\n", digit, openr2_chan_get_number(r2chan));
+
+	/* save the digit we just received */ 
+	zchan->caller_data.ani.digits[collected_len++] = digit;
+	zchan->caller_data.ani.digits[collected_len] = '\0';
+}
+
+static openr2_event_interface_t zap_r2_event_iface = {
+	.on_call_init = zap_r2_on_call_init,
+	.on_call_offered = zap_r2_on_call_offered,
+	.on_call_accepted = zap_r2_on_call_accepted,
+	.on_call_answered = zap_r2_on_call_answered,
+	.on_call_disconnect = zap_r2_on_call_disconnect,
+	.on_call_end = zap_r2_on_call_end,
+	.on_call_read = zap_r2_on_call_read,
+	.on_hardware_alarm = zap_r2_on_hardware_alarm,
+	.on_os_error = zap_r2_on_os_error,
+	.on_protocol_error = zap_r2_on_protocol_error,
+	.on_line_blocked = zap_r2_on_line_blocked,
+	.on_line_idle = zap_r2_on_line_idle,
+	/* cast seems to be needed to get rid of the annoying warning regarding format attribute  */
+	.on_context_log = (openr2_handle_context_logging_func)zap_r2_on_context_log,
+	.on_dnis_digit_received = zap_r2_on_dnis_digit_received,
+	.on_ani_digit_received = zap_r2_on_ani_digit_received,
+	/* so far we do nothing with billing pulses */
+	.on_billing_pulse_received = NULL
+};
+
+static int zap_r2_io_set_cas(openr2_chan_t *r2chan, int cas)
+{
+	zap_channel_t *zap_chan = openr2_chan_get_fd(r2chan);
+	zap_status_t status = zap_channel_command(zap_chan, ZAP_COMMAND_SET_CAS_BITS, &cas);
+	if (ZAP_FAIL == status) {
+		return -1;
+	}
+	return 0;
+}
+
+static int zap_r2_io_get_cas(openr2_chan_t *r2chan, int *cas)
+{
+	zap_channel_t *zap_chan = openr2_chan_get_fd(r2chan);
+	zap_status_t status = zap_channel_command(zap_chan, ZAP_COMMAND_GET_CAS_BITS, cas);
+	if (ZAP_FAIL == status) {
+		return -1;
+	}
+	return 0;
+}
+
+static int zap_r2_io_flush_write_buffers(openr2_chan_t *r2chan)
+{
+	zap_channel_t *zap_chan = openr2_chan_get_fd(r2chan);
+	zap_status_t status = zap_channel_command(zap_chan, ZAP_COMMAND_FLUSH_TX_BUFFERS, NULL);
+	if (ZAP_FAIL == status) {
+		return -1;
+	}
+	return 0;
+}
+
+static int zap_r2_io_write(openr2_chan_t *r2chan, const void *buf, int size)
+{
+	zap_channel_t *zap_chan = openr2_chan_get_fd(r2chan);
+	zap_size_t outsize = size;
+	zap_status_t status = zap_channel_write(zap_chan, (void *)buf, size, &outsize);
+	if (ZAP_FAIL == status) {
+		return -1;
+	}
+	return outsize;
+}
+
+static int zap_r2_io_read(openr2_chan_t *r2chan, const void *buf, int size)
+{
+	zap_channel_t *zap_chan = openr2_chan_get_fd(r2chan);
+	zap_size_t outsize = size;
+	zap_status_t status = zap_channel_read(zap_chan, (void *)buf, &outsize);
+	if (ZAP_FAIL == status) {
+		return -1;
+	}
+	return outsize;
+}
+
+static int zap_r2_io_wait(openr2_chan_t *r2chan, int *flags, int block)
+{
+	zap_status_t status;
+	zap_wait_flag_t zapflags = 0;
+
+	zap_channel_t *zap_chan = openr2_chan_get_fd(r2chan);
+	int32_t timeout = block ? -1 : 0;
+
+	if (*flags & OR2_IO_READ) {
+		zapflags |= ZAP_READ;
+	}
+	if (*flags & OR2_IO_WRITE) {
+		zapflags |= ZAP_WRITE;
+	}
+	if (*flags & OR2_IO_OOB_EVENT) {
+		zapflags |= ZAP_EVENTS;
+	}
+
+	status = zap_channel_wait(zap_chan, &zapflags, timeout);
+
+	if (ZAP_SUCCESS != status) {
+		return -1;
+	}
+
+	*flags = 0;
+	if (zapflags & ZAP_READ) {
+		*flags |= OR2_IO_READ;
+	}
+	if (zapflags & ZAP_WRITE) {
+		*flags |= OR2_IO_WRITE;
+	}
+	if (zapflags & ZAP_EVENTS) {
+		*flags |= OR2_IO_OOB_EVENT;
+	}
+
+	return 0;
+}
+
+/* The following openr2 hooks never get called, read on for reasoning ... */
+/* since openzap takes care of opening the file descriptor and using openr2_chan_new_from_fd, openr2 should never call this hook */
+static openr2_io_fd_t zap_r2_io_open(openr2_context_t *r2context, int channo)
+{
+	zap_log(ZAP_LOG_ERROR, "I should not be called (I/O open)!!\n");
+	return NULL;
+}
+
+/* since openzap takes care of closing the file descriptor and uses openr2_chan_new_from_fd, openr2 should never call this hook */
+static int zap_r2_io_close(openr2_chan_t *r2chan)
+{
+	zap_log(ZAP_LOG_ERROR, "I should not be called (I/O close)!!\n");
+	return 0;
+}
+
+/* since openzap takes care of opening the file descriptor and using openr2_chan_new_from_fd, openr2 should never call this hook */
+static int zap_r2_io_setup(openr2_chan_t *r2chan)
+{
+	zap_log(ZAP_LOG_ERROR, "I should not be called (I/O Setup)!!\n");
+	return 0;
+}
+
+/* since the signaling thread calls openr2_chan_process_cas_signaling directly, openr2 should never call this hook */
+static int zap_r2_io_get_oob_event(openr2_chan_t *r2chan, openr2_oob_event_t *event)
+{
+	*event = 0;
+	zap_log(ZAP_LOG_ERROR, "I should not be called (I/O get oob event)!!\n");
+	return 0;
+}
+
+static openr2_io_interface_t zap_r2_io_iface = {
+	.open = zap_r2_io_open, /* never called */
+	.close = zap_r2_io_close, /* never called */
+	.set_cas = zap_r2_io_set_cas,
+	.get_cas = zap_r2_io_get_cas,
+	.flush_write_buffers = zap_r2_io_flush_write_buffers,
+	.write = zap_r2_io_write,
+	.read = zap_r2_io_read,
+	.setup = zap_r2_io_setup, /* never called */
+	.wait = zap_r2_io_wait,
+	.get_oob_event = zap_r2_io_get_oob_event /* never called */
+};
+
+static ZIO_SIG_CONFIGURE_FUNCTION(zap_r2_configure_span)
+	//zap_status_t (zap_span_t *span, zio_signal_cb_t sig_cb, va_list ap)
+{
+	int i = 0;
+	int conf_failure = 0;
+	char *var = NULL;
+	char *val = NULL;
+	zap_r2_data_t *r2data = NULL;
+	zap_r2_span_pvt_t *spanpvt = NULL;
+	zap_r2_call_t *r2call = NULL;
+	openr2_chan_t *r2chan = NULL;
+
+	assert(sig_cb != NULL);
+
+	oz_r2_conf_t r2conf = 
+	{
+		.variant = OR2_VAR_ITU,
+		.category = OR2_CALLING_PARTY_CATEGORY_NATIONAL_SUBSCRIBER,
+		.loglevel = OR2_LOG_ERROR | OR2_LOG_WARNING,
+		.max_ani = 10,
+		.max_dnis = 4,
+		.mfback_timeout = -1,
+		.metering_pulse_timeout = -1,
+		.allow_collect_calls = -1,
+		.immediate_accept = -1,
+		.skip_category = -1,
+		.forced_release = -1,
+		.charge_calls = -1,
+		.get_ani_first = -1,
+		.call_files = -1,
+		.logdir = NULL,
+		.advanced_protocol_file = NULL 
+	};
+
+
+	if (span->signal_type) {
+		snprintf(span->last_error, sizeof(span->last_error), "Span is already configured for signalling.");
+		return ZAP_FAIL;
+	}
+
+	while ((var = va_arg(ap, char *))) {
+		zap_log(ZAP_LOG_DEBUG, "Reading R2 parameter %s for span %d\n", var, span->span_id);
+		if (!strcasecmp(var, "variant")) {
+			if (!(val = va_arg(ap, char *))) {
+				break;
+			}
+			if (zap_strlen_zero_buf(val)) {
+				zap_log(ZAP_LOG_NOTICE, "Ignoring empty R2 variant parameter\n");
+				continue;
+			}
+			r2conf.variant = openr2_proto_get_variant(val);
+			if (r2conf.variant == OR2_VAR_UNKNOWN) {
+				zap_log(ZAP_LOG_ERROR, "Unknown R2 variant %s\n", val);
+				conf_failure = 1;
+				break;
+			}
+			zap_log(ZAP_LOG_DEBUG, "Configuring R2 span %d for variant %s\n", span->span_id, val);
+		} else if (!strcasecmp(var, "category")) {
+			if (!(val = va_arg(ap, char *))) {
+				break;
+			}
+			if (zap_strlen_zero_buf(val)) {
+				zap_log(ZAP_LOG_NOTICE, "Ignoring empty R2 category parameter\n");
+				continue;
+			}
+			r2conf.category = openr2_proto_get_category(val);
+			if (r2conf.category == OR2_CALLING_PARTY_CATEGORY_UNKNOWN) {
+				zap_log(ZAP_LOG_ERROR, "Unknown R2 caller category %s\n", val);
+				conf_failure = 1;
+				break;
+			}
+			zap_log(ZAP_LOG_DEBUG, "Configuring R2 span %d with default category %s\n", span->span_id, val);
+		} else if (!strcasecmp(var, "logdir")) {
+			if (!(val = va_arg(ap, char *))) {
+				break;
+			}
+			if (zap_strlen_zero_buf(val)) {
+				zap_log(ZAP_LOG_NOTICE, "Ignoring empty R2 logdir parameter\n");
+				continue;
+			}
+			r2conf.logdir = val;
+			zap_log(ZAP_LOG_DEBUG, "Configuring R2 span %d with logdir %s\n", span->span_id, val);
+		} else if (!strcasecmp(var, "logging")) {
+			if (!(val = va_arg(ap, char *))) {
+				break;
+			}
+			if (zap_strlen_zero_buf(val)) {
+				zap_log(ZAP_LOG_NOTICE, "Ignoring empty R2 logging parameter\n");
+				continue;
+			}
+			openr2_log_level_t tmplevel;
+			char *clevel;
+			char *logval = malloc(strlen(val)+1); /* alloca man page scared me, so better to use good ol' malloc  */
+			if (!logval) {
+				zap_log(ZAP_LOG_WARNING, "Ignoring R2 logging parameter: '%s', failed to alloc memory\n", val);
+				continue;
+			}
+			strcpy(logval, val);
+			while (logval) {
+				clevel = strsep(&logval, ",");
+				if (-1 == (tmplevel = openr2_log_get_level(clevel))) {
+					zap_log(ZAP_LOG_WARNING, "Ignoring invalid R2 logging level: '%s'\n", clevel);
+					continue;
+				}
+				r2conf.loglevel |= tmplevel;
+				zap_log(ZAP_LOG_DEBUG, "Configuring R2 span %d with loglevel %s\n", span->span_id, clevel);
+			}
+			free(logval);
+		} else if (!strcasecmp(var, "advanced_protocol_file")) {
+			if (!(val = va_arg(ap, char *))) {
+				break;
+			}
+			if (zap_strlen_zero_buf(val)) {
+				zap_log(ZAP_LOG_NOTICE, "Ignoring empty R2 advanced_protocol_file parameter\n");
+				continue;
+			}
+			r2conf.advanced_protocol_file = val;
+			zap_log(ZAP_LOG_DEBUG, "Configuring R2 span %d with advanced protocol file %s\n", span->span_id, val);
+		} else if (!strcasecmp(var, "allow_collect_calls")) {
+			r2conf.allow_collect_calls = va_arg(ap, int);
+			zap_log(ZAP_LOG_DEBUG, "Configuring R2 span %d with allow collect calls max ani = %d\n", span->span_id, r2conf.allow_collect_calls);
+		} else if (!strcasecmp(var, "double_answer")) {
+			r2conf.double_answer = va_arg(ap, int);
+			zap_log(ZAP_LOG_DEBUG, "Configuring R2 span %d with double answer = %d\n", span->span_id, r2conf.double_answer);
+		} else if (!strcasecmp(var, "immediate_accept")) {
+			r2conf.immediate_accept = va_arg(ap, int);
+			zap_log(ZAP_LOG_DEBUG, "Configuring R2 span %d with immediate accept = %d\n", span->span_id, r2conf.immediate_accept);
+		} else if (!strcasecmp(var, "skip_category")) {
+			r2conf.skip_category = va_arg(ap, int);
+			zap_log(ZAP_LOG_DEBUG, "Configuring R2 span %d with skip category = %d\n", span->span_id, r2conf.skip_category);
+		} else if (!strcasecmp(var, "forced_release")) {
+			r2conf.forced_release = va_arg(ap, int);
+			zap_log(ZAP_LOG_DEBUG, "Configuring R2 span %d with forced release = %d\n", span->span_id, r2conf.forced_release);
+		} else if (!strcasecmp(var, "charge_calls")) {
+			r2conf.charge_calls = va_arg(ap, int);
+			zap_log(ZAP_LOG_DEBUG, "Configuring R2 span %d with charge calls = %d\n", span->span_id, r2conf.charge_calls);
+		} else if (!strcasecmp(var, "get_ani_first")) {
+			r2conf.get_ani_first = va_arg(ap, int);
+			zap_log(ZAP_LOG_DEBUG, "Configuring R2 span %d with get ani first = %d\n", span->span_id, r2conf.get_ani_first);
+		} else if (!strcasecmp(var, "call_files")) {
+			r2conf.call_files = va_arg(ap, int);
+			zap_log(ZAP_LOG_DEBUG, "Configuring R2 span %d with call files = %d\n", span->span_id, r2conf.call_files);
+		} else if (!strcasecmp(var, "mfback_timeout")) {
+			r2conf.mfback_timeout = va_arg(ap, int);
+			zap_log(ZAP_LOG_DEBUG, "Configuring R2 span %d with MF backward timeout = %dms\n", span->span_id, r2conf.mfback_timeout);
+		} else if (!strcasecmp(var, "metering_pulse_timeout")) {
+			r2conf.metering_pulse_timeout = va_arg(ap, int);
+			zap_log(ZAP_LOG_DEBUG, "Configuring R2 span %d with metering pulse timeout = %dms\n", span->span_id, r2conf.metering_pulse_timeout);
+		} else if (!strcasecmp(var, "max_ani")) {
+			r2conf.max_ani = va_arg(ap, int);
+			zap_log(ZAP_LOG_DEBUG, "Configuring R2 span %d with max ani = %d\n", span->span_id, r2conf.max_ani);
+		} else if (!strcasecmp(var, "max_dnis")) {
+			r2conf.max_dnis = va_arg(ap, int);
+			zap_log(ZAP_LOG_DEBUG, "Configuring R2 span %d with max dnis = %d\n", span->span_id, r2conf.max_dnis);
+		} else {
+			snprintf(span->last_error, sizeof(span->last_error), "Unknown R2 parameter [%s]", var);
+			return ZAP_FAIL;
+		}
+	}
+
+	if (conf_failure) {
+		snprintf(span->last_error, sizeof(span->last_error), "R2 configuration error");
+		return ZAP_FAIL;
+	}
+
+	r2data = malloc(sizeof(*r2data));
+	if (!r2data) {
+		snprintf(span->last_error, sizeof(span->last_error), "Failed to allocate R2 data.");
+		return ZAP_FAIL;
+	}
+	memset(r2data, 0, sizeof(*r2data));
+
+	spanpvt = malloc(sizeof(*spanpvt));
+	if (!spanpvt) {
+		snprintf(span->last_error, sizeof(span->last_error), "Failed to allocate private span data container.");
+		goto fail;
+	}
+	memset(spanpvt, 0, sizeof(*spanpvt));
+
+	r2data->r2context = openr2_context_new(r2conf.variant, &zap_r2_event_iface, r2conf.max_ani, r2conf.max_dnis);
+	if (!r2data->r2context) {
+		snprintf(span->last_error, sizeof(span->last_error), "Cannot create openr2 context for span.");
+		goto fail;
+	}
+	openr2_context_set_io_type(r2data->r2context, OR2_IO_CUSTOM, &zap_r2_io_iface);
+	openr2_context_set_log_level(r2data->r2context, r2conf.loglevel);
+	openr2_context_set_ani_first(r2data->r2context, r2conf.get_ani_first);
+	openr2_context_set_skip_category_request(r2data->r2context, r2conf.skip_category);
+	openr2_context_set_mf_back_timeout(r2data->r2context, r2conf.mfback_timeout);
+	openr2_context_set_metering_pulse_timeout(r2data->r2context, r2conf.metering_pulse_timeout);
+	openr2_context_set_double_answer(r2data->r2context, r2conf.double_answer);
+	openr2_context_set_immediate_accept(r2data->r2context, r2conf.immediate_accept);
+	if (r2conf.logdir) {
+		openr2_context_set_log_directory(r2data->r2context, r2conf.logdir);
+	}
+	if (r2conf.advanced_protocol_file) {
+		openr2_context_configure_from_advanced_file(r2data->r2context, r2conf.advanced_protocol_file);
+	}
+
+	spanpvt->r2calls = create_hashtable(ZAP_MAX_CHANNELS_SPAN, zap_hash_hashfromstring, zap_hash_equalkeys);
+	if (!spanpvt->r2calls) {
+		snprintf(span->last_error, sizeof(span->last_error), "Cannot create channel calls hash for span.");
+		goto fail;
+	}
+
+	for (i = 1; (i <= span->chan_count) && (i <= ZAP_MAX_CHANNELS_SPAN); i++) {
+		r2chan = openr2_chan_new_from_fd(r2data->r2context, span->channels[i], span->channels[i]->physical_chan_id);
+		if (!r2chan) {
+			snprintf(span->last_error, sizeof(span->last_error), "Cannot create all openr2 channels for span.");
+			goto fail;
+		}
+		if (r2conf.call_files) {
+			openr2_chan_enable_call_files(r2chan);
+			openr2_chan_set_log_level(r2chan, r2conf.loglevel);
+		}
+
+		r2call = malloc(sizeof(*r2call));
+		if (!r2call) {
+			snprintf(span->last_error, sizeof(span->last_error), "Cannot create all R2 call data structures for the span.");
+			zap_safe_free(r2chan);
+			goto fail;
+		}
+		memset(r2call, 0, sizeof(*r2call));
+		openr2_chan_set_logging_func(r2chan, zap_r2_on_chan_log);
+		openr2_chan_set_client_data(r2chan, span->channels[i]);
+        r2call->r2chan = r2chan;
+		span->channels[i]->call_data = r2call;
+		/* value and key are the same so just free one of them */
+		snprintf(r2call->name, sizeof(r2call->name), "chancall%d", i);
+		hashtable_insert(spanpvt->r2calls, (void *)r2call->name, r2call, HASHTABLE_FLAG_FREE_VALUE);
+
+	}
+	spanpvt->r2context = r2data->r2context;
+
+	/* just the value must be freed by the hash */
+	hashtable_insert(g_mod_data_hash, (void *)span->name, spanpvt, HASHTABLE_FLAG_FREE_VALUE);
+
+	span->start = zap_r2_start;
+	r2data->flags = 0;
+	span->signal_cb = sig_cb;
+	span->signal_type = ZAP_SIGTYPE_R2;
+	span->signal_data = r2data;
+	span->outgoing_call = r2_outgoing_call;
+
+	return ZAP_SUCCESS;
+
+fail:
+
+	if (r2data && r2data->r2context) {
+		openr2_context_delete(r2data->r2context);
+	}
+	if (spanpvt && spanpvt->r2calls) {
+		hashtable_destroy(spanpvt->r2calls);
+	}
+	zap_safe_free(r2data);
+	zap_safe_free(spanpvt);
+	return ZAP_FAIL;
+
+}
+
+static void *zap_r2_channel_run(zap_thread_t *me, void *obj)
+{
+	zap_channel_t *closed_chan;
+	uint32_t interval = 0;
+	zap_sigmsg_t sigev;
+	zap_channel_t *zchan = (zap_channel_t *)obj;
+	openr2_chan_t *r2chan = R2CALL(zchan)->r2chan;
+
+	zap_set_flag_locked(zchan, ZAP_CHANNEL_INTHREAD);
+
+	zap_mutex_lock(g_thread_count_mutex);
+	g_thread_count++;
+	zap_mutex_unlock(g_thread_count_mutex);
+
+	zap_log(ZAP_LOG_DEBUG, "R2 CHANNEL thread starting on %d in state %s.\n", 
+			zchan->physical_chan_id,
+			zap_channel_state2str(zchan->state));
+
+	if (zap_channel_open_chan(zchan) != ZAP_SUCCESS) {
+		zap_log(ZAP_LOG_ERROR, "OPEN ERROR [%s]\n", zchan->last_error);
+		goto endthread;
+	}
+
+	zap_channel_command(zchan, ZAP_COMMAND_GET_INTERVAL, &interval);
+
+	assert(interval != 0);
+	zap_log(ZAP_LOG_DEBUG, "Got %d interval for chan %d\n", interval, zchan->physical_chan_id);
+
+	if (!zap_test_flag(zchan, ZAP_CHANNEL_OUTBOUND)) {
+		/* FIXME: is this needed? */
+		memset(zchan->caller_data.dnis.digits, 0, sizeof(zchan->caller_data.collected));
+		memset(zchan->caller_data.ani.digits, 0, sizeof(zchan->caller_data.collected));
+	}
+
+	memset(&sigev, 0, sizeof(sigev));
+	sigev.chan_id = zchan->chan_id;
+	sigev.span_id = zchan->span_id;
+	sigev.channel = zchan;
+
+	while (zap_running()) {
+		int32_t read_enabled = openr2_chan_get_read_enabled(r2chan);
+		zap_wait_flag_t flags = read_enabled ? ( ZAP_READ | ZAP_WRITE ) : 0;
+
+		if (zap_test_flag(zchan, ZAP_CHANNEL_STATE_CHANGE) && (R2CALL(zchan)->chanstate != zchan->state)) {
+
+			zap_log(ZAP_LOG_DEBUG, "Executing state handler on %d:%d for %s\n", zchan->span_id, zchan->chan_id, zap_channel_state2str(zchan->state));
+			R2CALL(zchan)->chanstate = zchan->state;
+
+			if (!zap_test_flag(zchan, ZAP_CHANNEL_OUTBOUND) && !R2CALL(zchan)->accepted &&
+					(zchan->state == ZAP_CHANNEL_STATE_PROGRESS ||
+					 zchan->state == ZAP_CHANNEL_STATE_PROGRESS_MEDIA ||
+					 zchan->state == ZAP_CHANNEL_STATE_UP) ) {
+				/* if an accept ack will be required we should not acknowledge the state change just yet, 
+				   it will be done below after processing the MF signals, otherwise we have a race condition between openzap calling
+				   openr2_chan_answer_call and openr2 accepting the call first, if openzap calls openr2_chan_answer_call before the accept cycle
+				   completes, openr2 will fail to answer the call */
+				zap_log(ZAP_LOG_DEBUG, "State ack in chan %d:%d for state %s will have to wait a bit\n", zchan->span_id, zchan->chan_id, zap_channel_state2str(zchan->state));
+			} else if (zchan->state != ZAP_CHANNEL_STATE_DOWN){
+				/* the down state will be completed in zap_channel_done below */
+				zap_clear_flag_locked(zchan, ZAP_CHANNEL_STATE_CHANGE);
+				zap_channel_complete_state(zchan);
+			}
+
+			switch (zchan->state) {
+
+				/* starting an incoming call */
+				case ZAP_CHANNEL_STATE_COLLECT: 
+					{
+						zap_log(ZAP_LOG_DEBUG, "COLLECT: Starting processing of incoming call in channel %d with interval %d\n", zchan->physical_chan_id, interval);
+					}
+					break;
+
+					/* starting an outgoing call */
+				case ZAP_CHANNEL_STATE_DIALING:
+					{
+						// FIXME: use user defined calling party
+						zap_channel_use(zchan);
+						zap_log(ZAP_LOG_DEBUG, "DIALING: Starting processing of outgoing call in channel %d with interval %d\n", zchan->physical_chan_id, interval);
+						if (openr2_chan_make_call(r2chan, zchan->caller_data.cid_num.digits, zchan->caller_data.ani.digits, OR2_CALLING_PARTY_CATEGORY_NATIONAL_SUBSCRIBER)) {
+							zap_log(ZAP_LOG_ERROR, "%d:%d Failed to make call in R2 channel, openr2_chan_make_call failed\n", zchan->span_id, zchan->chan_id);
+							zchan->caller_data.hangup_cause = ZAP_CAUSE_DESTINATION_OUT_OF_ORDER;
+							zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_HANGUP);
+						}
+					}
+					break;
+
+					/* the call is ringing */
+				case ZAP_CHANNEL_STATE_PROGRESS:
+				case ZAP_CHANNEL_STATE_PROGRESS_MEDIA:
+					{
+						if (!zap_test_flag(zchan, ZAP_CHANNEL_OUTBOUND)) {
+							if (!R2CALL(zchan)->accepted) {
+								zap_log(ZAP_LOG_DEBUG, "PROGRESS: Accepting call on channel %d\n", zchan->physical_chan_id);
+								oz_r2_accept_call(zchan);
+							} 
+						} else {
+							zap_log(ZAP_LOG_DEBUG, "PROGRESS: Notifying progress in channel %d\n", zchan->physical_chan_id);
+							sigev.event_id = ZAP_SIGEVENT_PROGRESS;
+							if (zap_span_send_signal(zchan->span, &sigev) != ZAP_SUCCESS) {
+								zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_HANGUP);
+							}
+						}
+					}
+					break;
+
+					/* the call was answered */
+				case ZAP_CHANNEL_STATE_UP:
+					{
+						zap_log(ZAP_LOG_DEBUG, "UP: Call was answered on channel %d\n", zchan->physical_chan_id);
+						if (!zap_test_flag(zchan, ZAP_CHANNEL_OUTBOUND)) {
+							if (!R2CALL(zchan)->accepted) {
+								zap_log(ZAP_LOG_DEBUG, "UP: Call has not been accepted, need to accept first\n");
+								// the answering will be done in the on_call_accepted handler
+								oz_r2_accept_call(zchan);
+								R2CALL(zchan)->answer_pending = 1;
+							} else {
+								oz_r2_answer_call(zchan);
+							}
+						} else {
+							zap_log(ZAP_LOG_DEBUG, "UP: Notifying of call answered in channel %d\n", zchan->physical_chan_id);
+							sigev.event_id = ZAP_SIGEVENT_UP;
+							if (zap_span_send_signal(zchan->span, &sigev) != ZAP_SUCCESS) {
+								zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_HANGUP);
+							}
+						}
+					}
+					break;
+
+					/* just got hangup */
+				case ZAP_CHANNEL_STATE_HANGUP: 
+					{
+						/* FIXME: the cause should be retrieved from zchan->caller_data.hangup_cause and translated from Q931 to R2 cause */
+						zap_log(ZAP_LOG_DEBUG, "HANGUP: Clearing call on channel %d\n", zchan->physical_chan_id);
+						if (!R2CALL(zchan)->disconnect_rcvd) {
+							/* this will disconnect the call, but need to wait for the call end before moving to DOWN */
+							openr2_chan_disconnect_call(r2chan, OR2_CAUSE_NORMAL_CLEARING);
+						} else {
+							/* at this point on_call_end possibly was already called, 
+							 * but we needed to wait for the openzap confirmation before moving to DOWN */
+							zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_DOWN);
+						}
+					}
+					break;
+
+					/* just got hangup from the openzap side due to abnormal failure */
+				case ZAP_CHANNEL_STATE_CANCEL:
+					{
+						zap_log(ZAP_LOG_DEBUG, "CANCEL: Unable to receive call on channel %d\n", zchan->physical_chan_id);
+						openr2_chan_disconnect_call(r2chan, OR2_CAUSE_OUT_OF_ORDER);
+					}
+					break;
+
+					/* finished call for good */
+				case ZAP_CHANNEL_STATE_DOWN: 
+					{
+						zap_log(ZAP_LOG_DEBUG, "DOWN: Placing channel %d back to the pool of available channels\n", zchan->physical_chan_id);
+						zap_channel_done(zchan);
+						goto endthread;
+					}
+					break;
+
+				default:
+					{
+						zap_log(ZAP_LOG_ERROR, "%s: Unhandled channel state change in channel %d\n", zap_channel_state2str(zchan->state), zchan->physical_chan_id);
+					}
+					break;
+
+			}
+		}
+
+		if (flags) {
+			if (zap_channel_wait(zchan, &flags, interval * 2) != ZAP_SUCCESS) {
+				zap_log(ZAP_LOG_DEBUG, "zap_channel_wait did not return ZAP_SUCCESS\n");
+				continue;
+			}
+
+			/* handle timeout events first if any */
+			openr2_chan_run_schedule(r2chan);
+
+			/* openr2 will now try to detect MF tones, make sense out of them, reply if necessary with another tone and trigger 
+			 * telephony events via the call event interface we provided when creating the R2 context.
+			 * openr2 will also call our I/O callbacks to retrieve audio from the channel and call our wait poll I/O registered callback
+			 * and will not return from this function until the I/O poll callback returns no pending events
+			 * */
+			openr2_chan_process_mf_signaling(r2chan);
+			if (R2CALL(zchan)->state_ack_pending) {
+				zap_clear_flag_locked(zchan, ZAP_CHANNEL_STATE_CHANGE);
+				zap_channel_complete_state(zchan);
+				R2CALL(zchan)->state_ack_pending = 0;
+			}
+		} else {
+			/* once the MF signaling has end we just loop here waiting for state changes */
+			zap_sleep(interval);
+		}
+
+	}
+
+endthread:
+
+	closed_chan = zchan;
+	zap_channel_close(&closed_chan);
+	zap_clear_flag(zchan, ZAP_CHANNEL_INTHREAD);
+	zap_log(ZAP_LOG_DEBUG, "R2 channel %d thread ended.\n", zchan->physical_chan_id);
+
+	zap_mutex_lock(g_thread_count_mutex);
+	g_thread_count--;
+	zap_mutex_unlock(g_thread_count_mutex);
+
+	return NULL;
+}
+
+static void *zap_r2_run(zap_thread_t *me, void *obj)
+{
+	openr2_chan_t *r2chan;
+	zap_status_t status;
+	zap_span_t *span = (zap_span_t *) obj;
+	zap_r2_data_t *r2data = span->signal_data;
+	int waitms = 1000;
+	int i;
+
+	zap_log(ZAP_LOG_DEBUG, "OpenR2 monitor thread started.\n");
+  r2chan = NULL;
+	for (i = 1; i <= span->chan_count; i++) {
+		r2chan = R2CALL(span->channels[i])->r2chan;
+		openr2_chan_set_idle(r2chan);
+		openr2_chan_process_cas_signaling(r2chan);
+	}
+
+	while (zap_running() && zap_test_flag(r2data, ZAP_R2_RUNNING)) {
+		status = zap_span_poll_event(span, waitms);
+		if (ZAP_FAIL == status) {
+			zap_log(ZAP_LOG_ERROR, "Failure Polling event! [%s]\n", span->last_error);
+			continue;
+		}
+		if (ZAP_SUCCESS == status) {
+			zap_event_t *event;
+			while (zap_span_next_event(span, &event) == ZAP_SUCCESS) {
+				if (event->enum_id == ZAP_OOB_CAS_BITS_CHANGE) {
+                    r2chan = R2CALL(event->channel)->r2chan;
+					zap_log(ZAP_LOG_DEBUG, "Handling CAS on channel %d.\n", openr2_chan_get_number(r2chan));
+					// we only expect CAS and other OOB events on this thread/loop, once a call is started
+					// the MF events (in-band signaling) are handled in the call thread
+					openr2_chan_process_cas_signaling(r2chan);
+				} else {
+					zap_log(ZAP_LOG_DEBUG, "Ignoring event %d on channel %d.\n", event->enum_id, openr2_chan_get_number(r2chan));
+					// XXX TODO: handle alarms here XXX
+				}
+			}
+		} else if (status != ZAP_TIMEOUT) {
+			zap_log(ZAP_LOG_ERROR, "zap_span_poll_event returned %d.\n", status);
+		} else {
+			//zap_log(ZAP_LOG_DEBUG, "timed out waiting for event on span %d\n", span->span_id);
+		}
+	}
+
+    /*
+    FIXME: we should set BLOCKED but at this point I/O routines of openzap caused segfault
+	for (i = 1; i <= span->chan_count; i++) {
+		r2chan = R2CALL(span->channels[i])->r2chan;
+		openr2_chan_set_blocked(r2chan);
+	}
+    */
+
+	zap_clear_flag(r2data, ZAP_R2_RUNNING);
+	zap_log(ZAP_LOG_DEBUG, "R2 thread ending.\n");
+
+	return NULL;
+
+}
+
+static ZIO_API_FUNCTION(zap_r2_api)
+{
+	char *mycmd = NULL, *argv[10] = { 0 };
+	int argc = 0;
+
+	if (data) {
+		mycmd = strdup(data);
+		argc = zap_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
+	}
+
+	if (argc == 2) {
+		if (!strcasecmp(argv[0], "kill")) {
+			int span_id = atoi(argv[1]);
+			zap_span_t *span = NULL;
+
+			if (zap_span_find_by_name(argv[1], &span) == ZAP_SUCCESS || zap_span_find(span_id, &span) == ZAP_SUCCESS) {
+				zap_r2_data_t *r2data = span->signal_data;
+
+				if (span->start != zap_r2_start) {
+					stream->write_function(stream, "-ERR invalid span.\n");
+					goto done;
+				}
+
+				zap_clear_flag(r2data, ZAP_R2_RUNNING);
+				stream->write_function(stream, "+OK killed.\n");
+				goto done;
+			} else {
+				stream->write_function(stream, "-ERR invalid span.\n");
+				goto done;
+			}
+		}
+
+		if (!strcasecmp(argv[0], "status")) {
+			int span_id = atoi(argv[1]);
+			zap_r2_data_t *r2data = NULL;
+			zap_span_t *span = NULL;
+			openr2_chan_t *r2chan = NULL;
+			openr2_context_t *r2context = NULL;
+			int i = 0;
+
+			if (zap_span_find_by_name(argv[1], &span) == ZAP_SUCCESS || zap_span_find(span_id, &span) == ZAP_SUCCESS) {
+				if (span->start != zap_r2_start) {
+					stream->write_function(stream, "-ERR not an R2 span.\n");
+					goto done;
+				}
+				if (!(r2data =  span->signal_data)) {
+					stream->write_function(stream, "-ERR invalid span. No R2 singal data in span.\n");
+					goto done;
+				}
+				r2context = r2data->r2context;
+				openr2_variant_t r2variant = openr2_context_get_variant(r2context);
+				stream->write_function(stream, 
+						"Variant: %s\n"
+						"Max ANI: %d\n"
+						"Max DNIS: %d\n"
+						"ANI First: %s\n"
+						"Immediate Accept: %s\n",
+						openr2_proto_get_variant_string(r2variant),
+						openr2_context_get_max_ani(r2context),
+						openr2_context_get_max_dnis(r2context),
+						openr2_context_get_ani_first(r2context) ? "Yes" : "No",
+						openr2_context_get_immediate_accept(r2context) ? "Yes" : "No");
+				stream->write_function(stream, "\n");
+				stream->write_function(stream, "%4s %-12.12s %-12.12s\n", "Channel", "Tx CAS", "Rx CAS");
+				for (i = 1; i <= span->chan_count; i++) {
+					if (i == 16) continue;
+					r2chan = R2CALL(span->channels[i])->r2chan;
+					stream->write_function(stream, "%4d    %-12.12s %-12.12s\n", 
+							span->channels[i]->physical_chan_id,
+							openr2_chan_get_tx_cas_string(r2chan),
+							openr2_chan_get_rx_cas_string(r2chan));
+				}
+				stream->write_function(stream, "\n");
+				stream->write_function(stream, "+OK.\n");
+				goto done;
+			} else {
+				stream->write_function(stream, "-ERR invalid span.\n");
+				goto done;
+			}
+		}
+
+	}
+
+	if (argc == 1) {
+		if (!strcasecmp(argv[0], "threads")) {
+			zap_mutex_lock(g_thread_count_mutex);
+			stream->write_function(stream, "%d R2 channel threads up\n", g_thread_count);
+			zap_mutex_unlock(g_thread_count_mutex);
+			stream->write_function(stream, "+OK.\n");
+			goto done;
+		}
+
+		if (!strcasecmp(argv[0], "version")) {
+			stream->write_function(stream, "OpenR2 version: %s, revision: %s\n", openr2_get_version(), openr2_get_revision());
+			stream->write_function(stream, "+OK.\n");
+			goto done;
+		}
+
+		if (!strcasecmp(argv[0], "variants")) {
+			int32_t numvariants = 0;
+			const openr2_variant_entry_t *variants = openr2_proto_get_variant_list(&numvariants);
+			if (!variants) {
+				stream->write_function(stream, "-ERR failed to retrieve openr2 variant list.\n");
+				goto done;
+			}
+#define VARIANT_FORMAT "%4s %40s\n"
+			stream->write_function(stream, VARIANT_FORMAT, "Variant Code", "Country");
+			numvariants--;
+			for (; numvariants; numvariants--) {
+				stream->write_function(stream, VARIANT_FORMAT, variants[numvariants].name, variants[numvariants].country);
+			}
+			stream->write_function(stream, "+OK.\n");
+#undef VARIANT_FORMAT
+			goto done;
+		}
+	}
+
+	stream->write_function(stream, "-ERR invalid command.\n");
+
+done:
+
+	zap_safe_free(mycmd);
+
+	return ZAP_SUCCESS;
+
+}
+
+static ZIO_IO_LOAD_FUNCTION(zap_r2_io_init)
+{
+	assert(zio != NULL);
+	memset(&g_zap_r2_interface, 0, sizeof(g_zap_r2_interface));
+
+	g_zap_r2_interface.name = "r2";
+	g_zap_r2_interface.api = zap_r2_api;
+
+	*zio = &g_zap_r2_interface;
+
+	return ZAP_SUCCESS;
+}
+
+static ZIO_SIG_LOAD_FUNCTION(zap_r2_init)
+{
+	g_mod_data_hash = create_hashtable(10, zap_hash_hashfromstring, zap_hash_equalkeys);
+	if (!g_mod_data_hash) {
+		return ZAP_FAIL;
+	}
+	zap_mutex_create(&g_thread_count_mutex);
+	return ZAP_SUCCESS;
+}
+
+static ZIO_SIG_UNLOAD_FUNCTION(zap_r2_destroy)
+{
+	zap_hash_iterator_t *i = NULL;
+	zap_r2_span_pvt_t *spanpvt = NULL;
+	const void *key = NULL;
+	void *val = NULL;
+	for (i = hashtable_first(g_mod_data_hash); i; i = hashtable_next(i)) {
+		hashtable_this(i, &key, NULL, &val);
+		if (key && val) {
+			spanpvt = val;
+			openr2_context_delete(spanpvt->r2context);
+			hashtable_destroy(spanpvt->r2calls);
+		}
+	}
+	hashtable_destroy(g_mod_data_hash);
+	zap_mutex_destroy(&g_thread_count_mutex);
+	return ZAP_SUCCESS;
+}
+
+zap_module_t zap_module = { 
+	"r2",
+	zap_r2_io_init,
+	NULL,
+	zap_r2_init,
+	zap_r2_configure_span,
+	zap_r2_destroy
+};
+	
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4
+ */

Added: freeswitch/trunk/libs/openzap/src/ozmod/ozmod_sangoma_boost/ozmod_sangoma_boost.c (0 => 17141)


--- freeswitch/trunk/libs/openzap/src/ozmod/ozmod_sangoma_boost/ozmod_sangoma_boost.c	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/src/ozmod/ozmod_sangoma_boost/ozmod_sangoma_boost.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,1768 @@
+/*
+ * Copyright (c) 2007, Anthony Minessale II
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "openzap.h"
+#include "sangoma_boost_client.h"
+#include "zap_sangoma_boost.h"
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+
+#define MAX_TRUNK_GROUPS 64
+static time_t congestion_timeouts[MAX_TRUNK_GROUPS];
+
+/**
+ * \brief Strange flag
+ */
+typedef enum {
+	SFLAG_FREE_REQ_ID = (1 << 0),
+	SFLAG_SENT_FINAL_MSG = (1 << 1),
+	SFLAG_SENT_ACK = (1 << 2),
+	SFLAG_RECVD_ACK = (1 << 3),
+	SFLAG_HANGUP = (1 << 4),
+	SFLAG_TERMINATING = (1 << 5)
+} sflag_t;
+
+typedef uint16_t sangoma_boost_request_id_t;
+
+/**
+ * \brief SANGOMA boost request status
+ */
+typedef enum {
+	BST_FREE,
+	BST_WAITING,
+	BST_ACK,
+	BST_READY,
+	BST_FAIL
+} sangoma_boost_request_status_t;
+
+/**
+ * \brief SANGOMA boost request structure
+ */
+typedef struct {
+	sangoma_boost_request_status_t status;
+	sangomabc_short_event_t event;
+	zap_span_t *span;
+	zap_channel_t *zchan;
+	int hangup_cause;
+	int flags;
+} sangoma_boost_request_t;
+
+//#define MAX_REQ_ID ZAP_MAX_PHYSICAL_SPANS_PER_LOGICAL_SPAN * ZAP_MAX_CHANNELS_PHYSICAL_SPAN
+#define MAX_REQ_ID 6000
+
+static uint16_t SETUP_GRID[ZAP_MAX_PHYSICAL_SPANS_PER_LOGICAL_SPAN+1][ZAP_MAX_CHANNELS_PHYSICAL_SPAN+1] = {{ 0 }};
+
+static sangoma_boost_request_t OUTBOUND_REQUESTS[MAX_REQ_ID+1] = {{ 0 }};
+
+static zap_mutex_t *request_mutex = NULL;
+
+static uint8_t req_map[MAX_REQ_ID+1] = { 0 };
+static uint8_t nack_map[MAX_REQ_ID+1] = { 0 };
+
+/**
+ * \brief Releases span and channel from setup grid
+ * \param span Span number
+ * \param chan Channel number
+ * \param func Calling function
+ * \param line Line number on request
+ * \return NULL if not found, channel otherwise
+ */
+static void __release_request_id_span_chan(int span, int chan, const char *func, int line)
+{
+	int id;
+
+	zap_mutex_lock(request_mutex);
+	if ((id = SETUP_GRID[span][chan])) {
+		assert(id <= MAX_REQ_ID);
+		req_map[id] = 0;
+		SETUP_GRID[span][chan] = 0;
+	}
+	zap_mutex_unlock(request_mutex);
+}
+#define release_request_id_span_chan(s, c) __release_request_id_span_chan(s, c, __FUNCTION__, __LINE__)
+
+/**
+ * \brief Releases request ID
+ * \param func Calling function
+ * \param line Line number on request
+ * \return NULL if not found, channel otherwise
+ */
+static void __release_request_id(sangoma_boost_request_id_t r, const char *func, int line)
+{
+	assert(r <= MAX_REQ_ID);
+	zap_mutex_lock(request_mutex);
+	req_map[r] = 0;
+	zap_mutex_unlock(request_mutex);
+}
+#define release_request_id(r) __release_request_id(r, __FUNCTION__, __LINE__)
+
+static sangoma_boost_request_id_t last_req = 0;
+
+/**
+ * \brief Gets the first available tank request ID
+ * \param func Calling function
+ * \param line Line number on request
+ * \return 0 on failure, request ID on success
+ */
+static sangoma_boost_request_id_t __next_request_id(const char *func, int line)
+{
+	sangoma_boost_request_id_t r = 0, i = 0;
+	int found=0;
+	
+	zap_mutex_lock(request_mutex);
+	//r = ++last_req;
+	//while(!r || req_map[r]) {
+
+	for (i=1; i<= MAX_REQ_ID; i++){
+		r = ++last_req;
+
+		if (r >= MAX_REQ_ID) {
+			r = i = last_req = 1;
+		}
+
+		if (req_map[r]) {
+			/* Busy find another */
+			continue;
+
+		}
+
+		req_map[r] = 1;
+		found=1;
+		break;
+
+	}
+
+	zap_mutex_unlock(request_mutex);
+
+	if (!found) {
+		return 0;
+	}
+
+	return r;
+}
+#define next_request_id() __next_request_id(__FUNCTION__, __LINE__)
+
+/**
+ * \brief Finds the channel that triggered an event
+ * \param span Span where to search the channel
+ * \param event SANGOMA event
+ * \param force Do not wait for the channel to be available if in use
+ * \return NULL if not found, channel otherwise
+ */
+static zap_channel_t *find_zchan(zap_span_t *span, sangomabc_short_event_t *event, int force)
+{
+	int i;
+	zap_channel_t *zchan = NULL;
+
+	for(i = 1; i <= span->chan_count; i++) {
+		if (span->channels[i]->physical_span_id == event->span+1 && span->channels[i]->physical_chan_id == event->chan+1) {
+			zchan = span->channels[i];
+			if (force || (zchan->state == ZAP_CHANNEL_STATE_DOWN && !zap_test_flag(zchan, ZAP_CHANNEL_INUSE))) {
+				break;
+			} else {
+				zchan = NULL;
+				zap_log(ZAP_LOG_DEBUG, "Channel %d:%d ~ %d:%d is already in use.\n",
+						span->channels[i]->span_id,
+						span->channels[i]->chan_id,
+						span->channels[i]->physical_span_id,
+						span->channels[i]->physical_chan_id
+						);
+				break;
+			}
+		}
+	}
+
+	return zchan;
+}
+
+static int check_congestion(int trunk_group)
+{
+	if (congestion_timeouts[trunk_group]) {
+		time_t now = time(NULL);
+
+		if (now >= congestion_timeouts[trunk_group]) {
+			congestion_timeouts[trunk_group] = 0;
+		} else {
+			return 1;
+		}
+	}
+
+	return 0;
+}
+
+
+/**
+ * \brief Requests an sangoma boost channel on a span (outgoing call)
+ * \param span Span where to get a channel
+ * \param chan_id Specific channel to get (0 for any)
+ * \param direction Call direction
+ * \param caller_data Caller information
+ * \param zchan Channel to initialise
+ * \return Success or failure
+ */
+static ZIO_CHANNEL_REQUEST_FUNCTION(sangoma_boost_channel_request)
+{
+	zap_sangoma_boost_data_t *sangoma_boost_data = span->signal_data;
+	zap_status_t status = ZAP_FAIL;
+	sangoma_boost_request_id_t r;
+	sangomabc_event_t event = {0};
+
+		/* sanity has to be more than 8 seconds.
+	 * In PRI specs, timeout is 4 seconds for remote switch to respond to a SETUP,
+	 * and PRI stack will retransmit a second SETUP after the first timeout, so
+	 * we should allow for at least 8 seconds */
+
+	int sanity = 10000;
+	sangoma_boost_request_status_t st;
+	char ani[128] = "";
+	char *gr = NULL;
+	uint32_t count = 0;
+	int tg=0;
+	
+	if (zap_test_flag(span, ZAP_SPAN_SUSPENDED)) {
+		zap_log(ZAP_LOG_CRIT, "SPAN is not online.\n");
+		*zchan = NULL;
+		return ZAP_FAIL;
+	}
+	
+	zap_set_string(ani, caller_data->ani.digits);
+
+	if ((gr = strchr(ani, '@'))) {
+		*gr++ = '\0';
+	}
+
+	if (gr && *(gr+1)) {
+		tg = atoi(gr+1);
+		if (tg > 0) {
+			tg--;
+		}
+	}
+	event.trunk_group = tg;
+
+	if (check_congestion(tg)) {
+		zap_log(ZAP_LOG_CRIT, "All circuits are busy. Trunk Group=%i (BOOST REQUESTED BACK OFF)\n",tg+1);
+		*zchan = NULL;
+		return ZAP_FAIL;
+	}
+
+	zap_span_channel_use_count(span, &count);
+
+	if (count >= span->chan_count) {
+		zap_log(ZAP_LOG_CRIT, "All circuits are busy.\n");
+		*zchan = NULL;
+		return ZAP_FAIL;
+	}
+
+	r = next_request_id();
+	if (r == 0) {
+		zap_log(ZAP_LOG_CRIT, "All tanks ids are busy.\n");
+		*zchan = NULL;
+		return ZAP_FAIL;
+	}
+
+	/* sangomabc_call_init (event, calling, called, setup_id) */
+	sangomabc_call_init(&event, caller_data->cid_num.digits, ani, r);
+	//sangoma_bc_call_init will clear the trunk_group val so we need to set it again	
+	event.trunk_group=tg;
+	
+	if (gr && *(gr+1)) {
+
+		switch(*gr) {
+        case 'g':
+            event.hunt_group = SIGBOOST_HUNTGRP_SEQ_ASC;
+            break;
+        case 'G':
+            event.hunt_group = SIGBOOST_HUNTGRP_SEQ_DESC;
+            break;
+        case 'r':
+            event.hunt_group = SIGBOOST_HUNTGRP_RR_ASC;
+            break;
+        case 'R':
+            event.hunt_group = SIGBOOST_HUNTGRP_RR_DESC;
+            break;
+        default:
+			zap_log(ZAP_LOG_WARNING, "Failed to determine huntgroup (%s)\n", gr);
+            event.hunt_group = SIGBOOST_HUNTGRP_SEQ_ASC;
+		}
+	}
+
+	zap_set_string(event.calling_name, caller_data->cid_name);
+	zap_set_string(event.rdnis.digits, caller_data->rdnis.digits);
+
+	if (strlen(caller_data->rdnis.digits)) {
+			event.rdnis.digits_count = strlen(caller_data->rdnis.digits)+1;
+			event.rdnis.ton = caller_data->rdnis.type;
+			event.rdnis.npi = caller_data->rdnis.plan;
+	}
+
+	event.calling.screening_ind = caller_data->screen;
+	event.calling.presentation_ind = caller_data->pres;
+
+	event.calling.ton = caller_data->cid_num.type;
+	event.calling.npi = caller_data->cid_num.plan;
+
+	event.called.ton = caller_data->ani.type;
+	event.called.npi = caller_data->ani.plan;
+
+	OUTBOUND_REQUESTS[r].status = BST_WAITING;
+	OUTBOUND_REQUESTS[r].span = span;
+
+	if (sangomabc_connection_write(&sangoma_boost_data->mcon, &event) <= 0) {
+		zap_log(ZAP_LOG_CRIT, "Failed to tx on ISUP socket [%s]\n", strerror(errno));
+		status = ZAP_FAIL;
+		*zchan = NULL;
+		goto done;
+	}
+
+	while(zap_running() && OUTBOUND_REQUESTS[r].status == BST_WAITING) {
+		zap_sleep(1);
+		if (--sanity <= 0) {
+			status = ZAP_FAIL;
+			*zchan = NULL;
+			goto done;
+		}
+	}
+	
+	if (OUTBOUND_REQUESTS[r].status == BST_READY && OUTBOUND_REQUESTS[r].zchan) {
+		*zchan = OUTBOUND_REQUESTS[r].zchan;
+		status = ZAP_SUCCESS;
+	} else {
+		status = ZAP_FAIL;
+        *zchan = NULL;
+	}
+
+ done:
+
+	st = OUTBOUND_REQUESTS[r].status;
+	OUTBOUND_REQUESTS[r].status = BST_FREE;	
+
+	if (status == ZAP_FAIL) {
+		if (st == BST_FAIL) {
+			caller_data->hangup_cause = OUTBOUND_REQUESTS[r].hangup_cause;
+		} else {
+			caller_data->hangup_cause = ZAP_CAUSE_RECOVERY_ON_TIMER_EXPIRE;
+		}
+	}
+
+	if (st == BST_FAIL) {
+		release_request_id(r);
+	} else if (st != BST_READY) {
+		assert(r <= MAX_REQ_ID);
+		nack_map[r] = 1;
+		sangomabc_exec_command(&sangoma_boost_data->mcon,
+							   0,
+							   0,
+							   r,
+							   SIGBOOST_EVENT_CALL_START_NACK,
+							   0,
+							   0);
+	}
+
+	return status;
+}
+
+/**
+ * \brief Starts an sangoma boost channel (outgoing call)
+ * \param zchan Channel to initiate call on
+ * \return Success
+ */
+static ZIO_CHANNEL_OUTGOING_CALL_FUNCTION(sangoma_boost_outgoing_call)
+{
+	zap_status_t status = ZAP_SUCCESS;
+
+	return status;
+}
+
+/**
+ * \brief Handler for call start ack no media event
+ * \param mcon sangoma boost connection
+ * \param event Event to handle
+ */
+static void handle_call_progress(zap_span_t *span, sangomabc_connection_t *mcon, sangomabc_short_event_t *event)
+{
+	zap_channel_t *zchan;
+
+
+	if ((zchan = find_zchan(span, event, 1))) {
+		zap_mutex_lock(zchan->mutex);
+		if (zchan->state == ZAP_CHANNEL_STATE_HOLD) {
+			if ((event->flags & SIGBOOST_PROGRESS_MEDIA)) {
+				zchan->init_state = ZAP_CHANNEL_STATE_PROGRESS_MEDIA;
+				zap_log(ZAP_LOG_DEBUG, "Channel init state updated to PROGRESS_MEDIA [Csid:%d]\n", event->call_setup_id);
+			} else if ((event->flags & SIGBOOST_PROGRESS_RING)) {
+				zchan->init_state = ZAP_CHANNEL_STATE_PROGRESS;
+				zap_log(ZAP_LOG_DEBUG, "Channel init state updated to PROGRESS [Csid:%d]\n", event->call_setup_id);
+			} else {
+				zchan->init_state = ZAP_CHANNEL_STATE_IDLE;
+				zap_log(ZAP_LOG_DEBUG, "Channel init state updated to IDLE [Csid:%d]\n", event->call_setup_id);
+			}			
+		} else {
+			if ((event->flags & SIGBOOST_PROGRESS_MEDIA)) {
+				zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_PROGRESS_MEDIA);
+			} else if ((event->flags & SIGBOOST_PROGRESS_RING)) {
+				zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_PROGRESS);
+			} else {
+				zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_IDLE);
+			}
+		}
+		zap_mutex_unlock(zchan->mutex);
+	}
+}
+
+/**
+ * \brief Handler for call start ack event
+ * \param mcon sangoma boost connection
+ * \param event Event to handle
+ */
+static void handle_call_start_ack(sangomabc_connection_t *mcon, sangomabc_short_event_t *event)
+{
+	zap_channel_t *zchan;
+
+	if (nack_map[event->call_setup_id]) {
+		return;
+	}
+
+	OUTBOUND_REQUESTS[event->call_setup_id].event = *event;
+	SETUP_GRID[event->span][event->chan] = event->call_setup_id;
+
+	if ((zchan = find_zchan(OUTBOUND_REQUESTS[event->call_setup_id].span, event, 0))) {
+		if (zap_channel_open_chan(zchan) != ZAP_SUCCESS) {
+			zap_log(ZAP_LOG_ERROR, "OPEN ERROR [%s]\n", zchan->last_error);
+		} else {
+			zap_set_flag(zchan, ZAP_CHANNEL_OUTBOUND);
+			zap_set_flag_locked(zchan, ZAP_CHANNEL_INUSE);
+			zchan->extra_id = event->call_setup_id;
+			zap_log(ZAP_LOG_DEBUG, "Assign chan %d:%d (%d:%d) CSid=%d\n", zchan->span_id, zchan->chan_id, event->span+1,event->chan+1, event->call_setup_id);
+			zchan->sflags = SFLAG_RECVD_ACK;
+
+			if ((event->flags & SIGBOOST_PROGRESS_MEDIA)) {
+				zchan->init_state = ZAP_CHANNEL_STATE_PROGRESS_MEDIA;
+				zap_log(ZAP_LOG_DEBUG, "Channel init state changed to PROGRESS_MEDIA [Csid:%d]\n", event->call_setup_id);
+			} else if ((event->flags & SIGBOOST_PROGRESS_RING)) {
+				zchan->init_state = ZAP_CHANNEL_STATE_PROGRESS;
+				zap_log(ZAP_LOG_DEBUG, "Channel init state changed to PROGRESS [Csid:%d]\n", event->call_setup_id);
+			} else {
+				zchan->init_state = ZAP_CHANNEL_STATE_IDLE;
+				zap_log(ZAP_LOG_DEBUG, "Channel init state changed to IDLE [Csid:%d]\n", event->call_setup_id);
+			}
+			
+			zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_HOLD);
+
+			OUTBOUND_REQUESTS[event->call_setup_id].flags = event->flags;
+			OUTBOUND_REQUESTS[event->call_setup_id].zchan = zchan;
+			OUTBOUND_REQUESTS[event->call_setup_id].status = BST_READY;
+			return;
+		}
+	} 
+	
+	//printf("WTF BAD ACK CSid=%d span=%d chan=%d\n", event->call_setup_id, event->span+1,event->chan+1);
+	if ((zchan = find_zchan(OUTBOUND_REQUESTS[event->call_setup_id].span, event, 1))) {
+		//printf("WTF BAD ACK2 %d:%d (%d:%d) CSid=%d xtra_id=%d out=%d state=%s\n", zchan->span_id, zchan->chan_id, event->span+1,event->chan+1, event->call_setup_id, zchan->extra_id, zap_test_flag(zchan, ZAP_CHANNEL_OUTBOUND), zap_channel_state2str(zchan->state));
+	}
+
+	zap_set_sflag(zchan, SFLAG_SENT_FINAL_MSG);
+	zap_log(ZAP_LOG_CRIT, "START ACK CANT FIND A CHAN %d:%d\n", event->span+1,event->chan+1);
+	sangomabc_exec_command(mcon,
+						   event->span,
+						   event->chan,
+						   event->call_setup_id,
+						   SIGBOOST_EVENT_CALL_STOPPED,
+						   ZAP_CAUSE_DESTINATION_OUT_OF_ORDER, 0);
+	OUTBOUND_REQUESTS[event->call_setup_id].status = BST_FAIL;
+	OUTBOUND_REQUESTS[event->call_setup_id].hangup_cause = ZAP_CAUSE_DESTINATION_OUT_OF_ORDER;
+	
+}
+
+/**
+ * \brief Handler for call done event
+ * \param span Span where event was fired
+ * \param mcon sangoma boost connection
+ * \param event Event to handle
+ */
+static void handle_call_done(zap_span_t *span, sangomabc_connection_t *mcon, sangomabc_short_event_t *event)
+{
+	zap_channel_t *zchan;
+	int r = 0;
+
+	if ((zchan = find_zchan(span, event, 1))) {
+		zap_mutex_lock(zchan->mutex);
+
+		if (zchan->state == ZAP_CHANNEL_STATE_DOWN || zchan->state == ZAP_CHANNEL_STATE_HANGUP_COMPLETE || zap_test_sflag(zchan, SFLAG_TERMINATING)) {
+			goto done;
+		}
+
+		zap_set_state_r(zchan, ZAP_CHANNEL_STATE_HANGUP_COMPLETE, 0, r);
+		if (r) {
+			zap_set_sflag(zchan, SFLAG_FREE_REQ_ID);
+			zap_mutex_unlock(zchan->mutex);
+			return;
+		}
+	} 
+
+ done:
+	
+	if (zchan) {
+		zap_mutex_unlock(zchan->mutex);
+	}
+
+	if (event->call_setup_id) {
+		release_request_id(event->call_setup_id);
+	} else {
+		release_request_id_span_chan(event->span, event->chan);
+	}
+}
+
+/**
+ * \brief Handler for call start nack event
+ * \param span Span where event was fired
+ * \param mcon sangoma boost connection
+ * \param event Event to handle
+ */
+static void handle_call_start_nack(zap_span_t *span, sangomabc_connection_t *mcon, sangomabc_short_event_t *event)
+{
+	zap_channel_t *zchan;
+
+	if (event->release_cause == SIGBOOST_CALL_SETUP_NACK_ALL_CKTS_BUSY) {
+		uint32_t count = 0;
+		int delay = 0;
+		int tg=event->trunk_group;
+
+		zap_span_channel_use_count(span, &count);
+
+		delay = (int) (count / 100) * 2;
+		
+		if (delay > 10) {
+			delay = 10;
+		} else if (delay < 1) {
+			delay = 1;
+		}
+
+		if (tg < 0 || tg >= MAX_TRUNK_GROUPS) {
+			zap_log(ZAP_LOG_CRIT, "Invalid All Ckt Busy trunk group number %i\n", tg);
+			tg=0;
+		}
+		
+		congestion_timeouts[tg] = time(NULL) + delay;
+		event->release_cause = 17;
+
+	} else if (event->release_cause == SIGBOOST_CALL_SETUP_CSUPID_DBL_USE) {
+		event->release_cause = 17;
+	}
+
+	if (event->call_setup_id) {
+
+		sangomabc_exec_command(mcon,
+							   0,
+							   0,
+							   event->call_setup_id,
+							   SIGBOOST_EVENT_CALL_START_NACK_ACK,
+							   0, 0);
+		
+		OUTBOUND_REQUESTS[event->call_setup_id].event = *event;
+		OUTBOUND_REQUESTS[event->call_setup_id].status = BST_FAIL;
+		OUTBOUND_REQUESTS[event->call_setup_id].hangup_cause = event->release_cause;
+		return;
+	} else {
+		if ((zchan = find_zchan(span, event, 1))) {
+			int r = 0;
+			assert(!zap_test_flag(zchan, ZAP_CHANNEL_OUTBOUND));
+	
+			zchan->call_data = (void*)(intptr_t)event->event_id;
+
+			zap_mutex_lock(zchan->mutex);
+			zap_set_state_r(zchan, ZAP_CHANNEL_STATE_TERMINATING, 0, r);
+			if (r == ZAP_STATE_CHANGE_SUCCESS) {
+				zchan->caller_data.hangup_cause = event->release_cause;
+			}
+			zap_mutex_unlock(zchan->mutex);
+			if (r) {
+				return;
+			}
+		}
+	}
+
+	if (zchan) {
+		zap_set_sflag_locked(zchan, SFLAG_SENT_FINAL_MSG);
+	}
+
+	/* nobody else will do it so we have to do it ourselves */
+	sangomabc_exec_command(mcon,
+						   event->span,
+						   event->chan,
+						   0,
+						   SIGBOOST_EVENT_CALL_START_NACK_ACK,
+						   0, 0);
+}
+
+/**
+ * \brief Handler for call stop event
+ * \param span Span where event was fired
+ * \param mcon sangoma boost connection
+ * \param event Event to handle
+ */
+static void handle_call_stop(zap_span_t *span, sangomabc_connection_t *mcon, sangomabc_short_event_t *event)
+{
+	zap_channel_t *zchan;
+	
+	if ((zchan = find_zchan(span, event, 1))) {
+		int r = 0;
+
+		zap_mutex_lock(zchan->mutex);
+
+		if (zap_test_sflag(zchan, SFLAG_HANGUP)) {
+			/* racing condition where both sides initiated a hangup 
+			 * Do not change current state as channel is already clearing
+			 * itself through local initiated hangup */
+			
+			sangomabc_exec_command(mcon,
+								   zchan->physical_span_id-1,
+								   zchan->physical_chan_id-1,
+								   0,
+								   SIGBOOST_EVENT_CALL_STOPPED_ACK,
+								   0, 0);
+			zap_mutex_unlock(zchan->mutex);
+			return;
+		} else {
+			if (zchan->state == ZAP_CHANNEL_STATE_HOLD) {
+				zchan->init_state = ZAP_CHANNEL_STATE_TERMINATING;
+				zap_log(ZAP_LOG_DEBUG, "Channel init state updated to TERMINATING [Csid:%d]\n", event->call_setup_id);			
+				OUTBOUND_REQUESTS[event->call_setup_id].hangup_cause = event->release_cause;  
+				zchan->caller_data.hangup_cause = event->release_cause;
+				zap_mutex_unlock(zchan->mutex);
+				return;
+			} else {
+				zap_set_state_r(zchan, ZAP_CHANNEL_STATE_TERMINATING, 0, r);
+			}
+		}
+
+		if (r == ZAP_STATE_CHANGE_SUCCESS) {
+			zchan->caller_data.hangup_cause = event->release_cause;
+		}
+
+		if (r) {
+			zap_set_sflag(zchan, SFLAG_FREE_REQ_ID);
+		}
+
+		zap_mutex_unlock(zchan->mutex);
+
+		if (r) {
+			return;
+		}
+	} /* else we have to do it ourselves.... */
+
+	zap_log(ZAP_LOG_WARNING, "We could not find chan: s%dc%d\n", event->span, event->chan);
+	release_request_id_span_chan(event->span, event->chan);
+}
+
+/**
+ * \brief Handler for call answer event
+ * \param span Span where event was fired
+ * \param mcon sangoma boost connection
+ * \param event Event to handle
+ */
+static void handle_call_answer(zap_span_t *span, sangomabc_connection_t *mcon, sangomabc_short_event_t *event)
+{
+	zap_channel_t *zchan;
+	
+	if ((zchan = find_zchan(span, event, 1))) {
+		zap_mutex_lock(zchan->mutex);
+		if (zchan->state == ZAP_CHANNEL_STATE_HOLD) {
+			zchan->init_state = ZAP_CHANNEL_STATE_UP;
+		} else {
+			int r = 0;
+			zap_set_state_r(zchan, ZAP_CHANNEL_STATE_UP, 0, r);
+		}
+		zap_mutex_unlock(zchan->mutex);
+	} else {
+		zap_log(ZAP_LOG_CRIT, "ANSWER CANT FIND A CHAN %d:%d\n", event->span+1,event->chan+1);
+		sangomabc_exec_command(mcon,
+							   event->span,
+							   event->chan,
+							   event->call_setup_id,
+							   SIGBOOST_EVENT_CALL_STOPPED,
+							   ZAP_CAUSE_DESTINATION_OUT_OF_ORDER, 0);
+	}
+}
+
+static __inline__ void advance_chan_states(zap_channel_t *zchan);
+
+/**
+ * \brief Handler for call start event
+ * \param span Span where event was fired
+ * \param mcon sangoma boost connection
+ * \param event Event to handle
+ */
+static void handle_call_start(zap_span_t *span, sangomabc_connection_t *mcon, sangomabc_event_t *event)
+{
+	zap_channel_t *zchan;
+	int hangup_cause = ZAP_CAUSE_CALL_REJECTED;
+
+	if (!(zchan = find_zchan(span, (sangomabc_short_event_t*)event, 0))) {
+		if ((zchan = find_zchan(span, (sangomabc_short_event_t*)event, 1))) {
+			int r;
+			if (zchan->state == ZAP_CHANNEL_STATE_UP) {
+				zap_log(ZAP_LOG_CRIT, "ZCHAN STATE UP -> Changed to TERMINATING %d:%d\n", event->span+1,event->chan+1);
+				zap_set_state_r(zchan, ZAP_CHANNEL_STATE_TERMINATING, 0, r);
+			} else if (zap_test_sflag(zchan, SFLAG_HANGUP)) { 
+				zap_log(ZAP_LOG_CRIT, "ZCHAN STATE HANGUP -> Changed to HANGUP COMPLETE %d:%d\n", event->span+1,event->chan+1);
+				zap_set_state_r(zchan, ZAP_CHANNEL_STATE_HANGUP_COMPLETE, 0, r);
+			} else {
+				zap_log(ZAP_LOG_CRIT, "ZCHAN STATE INVALID %s on IN CALL %d:%d\n", zap_channel_state2str(zchan->state),event->span+1,event->chan+1);
+
+			}
+			zap_set_sflag(zchan, SFLAG_SENT_FINAL_MSG);
+			zchan=NULL;
+		}
+		zap_log(ZAP_LOG_CRIT, "START CANT FIND CHAN %d:%d\n", event->span+1,event->chan+1);
+		goto error;
+	}
+
+	if (zap_channel_open_chan(zchan) != ZAP_SUCCESS) {
+		zap_log(ZAP_LOG_CRIT, "START CANT OPEN CHAN %d:%d\n", event->span+1,event->chan+1);
+		goto error;
+	}
+	
+	zchan->sflags = 0;
+	zap_set_string(zchan->caller_data.cid_num.digits, (char *)event->calling.digits);
+	zap_set_string(zchan->caller_data.cid_name, (char *)event->calling.digits);
+	zap_set_string(zchan->caller_data.ani.digits, (char *)event->calling.digits);
+	zap_set_string(zchan->caller_data.dnis.digits, (char *)event->called.digits);
+	zap_set_string(zchan->caller_data.rdnis.digits, (char *)event->rdnis.digits);
+
+	if (strlen(event->calling_name)) {
+		zap_set_string(zchan->caller_data.cid_name, (char *)event->calling_name);
+	}
+
+	zchan->caller_data.cid_num.plan = event->calling.npi;
+	zchan->caller_data.cid_num.type = event->calling.ton;
+
+	zchan->caller_data.ani.plan = event->calling.npi;
+	zchan->caller_data.ani.type = event->calling.ton;
+
+	zchan->caller_data.dnis.plan = event->called.npi;
+	zchan->caller_data.dnis.type = event->called.ton;
+
+	zchan->caller_data.rdnis.plan = event->rdnis.npi;
+	zchan->caller_data.rdnis.type = event->rdnis.ton;
+
+	zchan->caller_data.screen = event->calling.screening_ind;
+	zchan->caller_data.pres = event->calling.presentation_ind;
+
+	if (event->custom_data_size) {
+		char* p = NULL;
+
+		p = strstr((char*)event->custom_data,"PRI001-ANI2-");
+		if (p!=NULL) {
+			int ani2 = 0;
+			sscanf(p, "PRI001-ANI2-%d", &ani2);
+			snprintf(zchan->caller_data.aniII, 5, "%.2d", ani2);
+		}	
+	}
+
+	zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_RING);
+	return;
+
+ error:
+	if (zchan) {
+		hangup_cause = zchan->caller_data.hangup_cause;
+	} else {
+		zap_log(ZAP_LOG_CRIT, "START CANT FIND A CHAN %d:%d\n", event->span+1,event->chan+1);
+		hangup_cause = ZAP_CAUSE_REQUESTED_CHAN_UNAVAIL;
+	}
+	sangomabc_exec_command(mcon,
+						   event->span,
+						   event->chan,
+						   0,
+						   SIGBOOST_EVENT_CALL_START_NACK,
+						   hangup_cause, 0);
+		
+}
+
+static void handle_call_loop_start(zap_span_t *span, sangomabc_connection_t *mcon, sangomabc_short_event_t *event)
+{
+	zap_status_t res = ZAP_FAIL;
+	zap_channel_t *zchan;
+
+	if (!(zchan = find_zchan(span, (sangomabc_short_event_t*)event, 0))) {
+		zap_log(ZAP_LOG_CRIT, "CANNOT START LOOP, CHAN NOT AVAILABLE %d:%d\n", event->span+1,event->chan+1);
+		return;
+	}
+
+	if (zap_channel_open_chan(zchan) != ZAP_SUCCESS) {
+		zap_log(ZAP_LOG_CRIT, "CANNOT START LOOP, CANT OPEN CHAN %d:%d\n", event->span+1,event->chan+1);
+		return;
+	}
+
+	zap_set_state_r(zchan, ZAP_CHANNEL_STATE_IN_LOOP, 0, res);
+	if (res != ZAP_SUCCESS) {
+		zap_log(ZAP_LOG_CRIT, "yay, could not set the state of the channel to IN_LOOP, loop will fail\n");
+		zap_channel_done(zchan);
+		return;
+	}
+	zap_channel_command(zchan, ZAP_COMMAND_ENABLE_LOOP, NULL);
+}
+
+static void handle_call_loop_stop(zap_span_t *span, sangomabc_connection_t *mcon, sangomabc_short_event_t *event)
+{
+	zap_channel_t *zchan;
+	zap_status_t res = ZAP_FAIL;
+	if (!(zchan = find_zchan(span, (sangomabc_short_event_t*)event, 1))) {
+		zap_log(ZAP_LOG_CRIT, "CANNOT STOP LOOP, INVALID CHAN REQUESTED %d:%d\n", event->span+1,event->chan+1);
+		return;
+	}
+	if (zchan->state != ZAP_CHANNEL_STATE_IN_LOOP) {
+		zap_log(ZAP_LOG_ERROR, "Got stop loop request in a channel that is not in loop, ignoring ...\n");
+		return;
+	}
+	zap_channel_command(zchan, ZAP_COMMAND_DISABLE_LOOP, NULL);
+	/* even when we did not sent a msg we set this flag to avoid sending call stop in the DOWN state handler */
+	zap_set_flag(zchan, SFLAG_SENT_FINAL_MSG);
+	zap_set_state_r(zchan, ZAP_CHANNEL_STATE_DOWN, 0, res);
+}
+
+/**
+ * \brief Handler for heartbeat event
+ * \param mcon sangoma boost connection
+ * \param event Event to handle
+ */
+static void handle_heartbeat(sangomabc_connection_t *mcon, sangomabc_short_event_t *event)
+{
+	int err;
+	
+	err = sangomabc_connection_writep(mcon, (sangomabc_event_t*)event);
+	
+	if (err <= 0) {
+		zap_log(ZAP_LOG_CRIT, "Failed to tx on ISUP socket [%s]: %s\n", strerror(errno));
+	}
+	
+	mcon->hb_elapsed = 0;
+
+    return;
+}
+
+/**
+ * \brief Handler for restart ack event
+ * \param mcon sangoma boost connection
+ * \param span Span where event was fired
+ * \param event Event to handle
+ */
+static void handle_restart_ack(sangomabc_connection_t *mcon, zap_span_t *span, sangomabc_short_event_t *event)
+{
+	zap_log(ZAP_LOG_DEBUG, "RECV RESTART ACK\n");
+}
+
+/**
+ * \brief Handler for restart event
+ * \param mcon sangoma boost connection
+ * \param span Span where event was fired
+ * \param event Event to handle
+ */
+static void handle_restart(sangomabc_connection_t *mcon, zap_span_t *span, sangomabc_short_event_t *event)
+{
+	zap_sangoma_boost_data_t *sangoma_boost_data = span->signal_data;
+
+    mcon->rxseq_reset = 0;
+	zap_set_flag((&sangoma_boost_data->mcon), MSU_FLAG_DOWN);
+	zap_set_flag_locked(span, ZAP_SPAN_SUSPENDED);
+	zap_set_flag(sangoma_boost_data, ZAP_SANGOMA_BOOST_RESTARTING);
+	
+	mcon->hb_elapsed = 0;
+}
+
+/**
+ * \brief Handler for incoming digit event
+ * \param mcon sangoma boost connection
+ * \param span Span where event was fired
+ * \param event Event to handle
+ */
+static void handle_incoming_digit(sangomabc_connection_t *mcon, zap_span_t *span, sangomabc_event_t *event)
+{
+	zap_channel_t *zchan = NULL;
+	char digits[MAX_DIALED_DIGITS + 2] = "";
+	
+	if (!(zchan = find_zchan(span, (sangomabc_short_event_t *)event, 1))) {
+		zap_log(ZAP_LOG_ERROR, "Invalid channel\n");
+		return;
+	}
+	
+	if (event->called_number_digits_count == 0) {
+		zap_log(ZAP_LOG_WARNING, "Error Incoming digit with len %s %d [w%dg%d]\n",
+			   	event->called_number_digits,
+			   	event->called_number_digits_count,
+			   	event->span+1, event->chan+1);
+		return;
+	}
+
+	zap_log(ZAP_LOG_WARNING, "Incoming digit with len %s %d [w%dg%d]\n",
+			   	event->called_number_digits,
+			   	event->called_number_digits_count,
+			   	event->span+1, event->chan+1);
+
+	memcpy(digits, event->called_number_digits, event->called_number_digits_count);
+	zap_channel_queue_dtmf(zchan, digits);
+
+	return;
+}
+
+
+/**
+ * \brief Checks if span has state changes pending and processes 
+ * \param span Span where event was fired
+ * \param event Event to handle
+ */
+static zap_channel_t* event_process_states(zap_span_t *span, sangomabc_short_event_t *event) 
+{
+    zap_channel_t *zchan = NULL;
+    
+    switch (event->event_id) {
+        case SIGBOOST_EVENT_CALL_START_NACK:
+        case SIGBOOST_EVENT_CALL_START_NACK_ACK:
+            if (event->call_setup_id) {
+                return NULL;
+            } 
+            //if event->span and event->chan is valid, fall-through
+        case SIGBOOST_EVENT_CALL_START:
+        case SIGBOOST_EVENT_CALL_START_ACK:
+        case SIGBOOST_EVENT_CALL_STOPPED:
+        case SIGBOOST_EVENT_CALL_PROGRESS:
+        case SIGBOOST_EVENT_CALL_ANSWERED:
+        case SIGBOOST_EVENT_CALL_STOPPED_ACK:
+        case SIGBOOST_EVENT_DIGIT_IN:
+        case SIGBOOST_EVENT_INSERT_CHECK_LOOP:
+        case SIGBOOST_EVENT_REMOVE_CHECK_LOOP:
+            if (!(zchan = find_zchan(span, (sangomabc_short_event_t*)event, 1))) {
+                zap_log(ZAP_LOG_DEBUG, "PROCESS STATES  CANT FIND CHAN %d:%d\n", event->span+1,event->chan+1);
+                return NULL;
+            }
+            break;
+        case SIGBOOST_EVENT_HEARTBEAT:
+        case SIGBOOST_EVENT_SYSTEM_RESTART_ACK:
+        case SIGBOOST_EVENT_SYSTEM_RESTART:
+        case SIGBOOST_EVENT_AUTO_CALL_GAP_ABATE:
+            return NULL;
+        default:
+            zap_log(ZAP_LOG_CRIT, "Unhandled event id:%d\n", event->event_id);
+            return NULL;
+    }
+
+    zap_mutex_lock(zchan->mutex);
+    advance_chan_states(zchan);
+    return zchan;
+}
+
+/**
+ * \brief Handler for sangoma boost event
+ * \param span Span where event was fired
+ * \param mcon sangoma boost connection
+ * \param event Event to handle
+ */
+static int parse_sangoma_event(zap_span_t *span, sangomabc_connection_t *mcon, sangomabc_short_event_t *event)
+{
+    zap_channel_t* zchan = NULL;
+	
+	if (!zap_running()) {
+		zap_log(ZAP_LOG_WARNING, "System is shutting down.\n");
+		goto end;
+	}
+
+	assert(event->call_setup_id <= MAX_REQ_ID);
+
+    /* process all pending state changes for that channel before
+        processing the new boost event */
+    zchan = event_process_states(span, event);
+
+    switch(event->event_id) {
+    case SIGBOOST_EVENT_CALL_START:
+		handle_call_start(span, mcon, (sangomabc_event_t*)event);
+		break;
+    case SIGBOOST_EVENT_CALL_STOPPED:
+		handle_call_stop(span, mcon, event);
+		break;
+    case SIGBOOST_EVENT_CALL_START_ACK:
+		handle_call_start_ack(mcon, event);
+		break;
+    case SIGBOOST_EVENT_CALL_PROGRESS:
+		handle_call_progress(span, mcon, event);
+		break;
+    case SIGBOOST_EVENT_CALL_START_NACK:
+		handle_call_start_nack(span, mcon, event);
+		break;
+    case SIGBOOST_EVENT_CALL_ANSWERED:
+		handle_call_answer(span, mcon, event);
+		break;
+    case SIGBOOST_EVENT_HEARTBEAT:
+		handle_heartbeat(mcon, event);
+		break;
+    case SIGBOOST_EVENT_CALL_STOPPED_ACK:
+		handle_call_done(span, mcon, event);
+		break;
+    case SIGBOOST_EVENT_CALL_START_NACK_ACK:
+		handle_call_done(span, mcon, event);
+		nack_map[event->call_setup_id] = 0;
+		break;
+    case SIGBOOST_EVENT_INSERT_CHECK_LOOP:
+		handle_call_loop_start(span, mcon, event);
+		break;
+    case SIGBOOST_EVENT_REMOVE_CHECK_LOOP:
+		handle_call_loop_stop(span, mcon, event);
+		break;
+    case SIGBOOST_EVENT_SYSTEM_RESTART_ACK:
+		handle_restart_ack(mcon, span, event);
+		break;
+	case SIGBOOST_EVENT_SYSTEM_RESTART:
+		handle_restart(mcon, span, event);
+		break;
+    case SIGBOOST_EVENT_AUTO_CALL_GAP_ABATE:
+		//handle_gap_abate(event);
+		break;
+	case SIGBOOST_EVENT_DIGIT_IN:
+		handle_incoming_digit(mcon, span, (sangomabc_event_t*)event);
+		break;
+    default:
+		zap_log(ZAP_LOG_WARNING, "No handler implemented for [%s]\n", sangomabc_event_id_name(event->event_id));
+		break;
+    }
+
+ end:
+    if(zchan != NULL) {
+        advance_chan_states(zchan);
+        zap_mutex_unlock(zchan->mutex);
+    }
+
+	return 0;
+}
+
+/**
+ * \brief Handler for channel state change
+ * \param zchan Channel to handle
+ */
+static __inline__ void state_advance(zap_channel_t *zchan)
+{
+
+	zap_sangoma_boost_data_t *sangoma_boost_data = zchan->span->signal_data;
+	sangomabc_connection_t *mcon = &sangoma_boost_data->mcon;
+	zap_sigmsg_t sig;
+	zap_status_t status;
+
+	zap_log(ZAP_LOG_DEBUG, "%d:%d STATE [%s]\n", zchan->span_id, zchan->chan_id, zap_channel_state2str(zchan->state));
+	
+	memset(&sig, 0, sizeof(sig));
+	sig.chan_id = zchan->chan_id;
+	sig.span_id = zchan->span_id;
+	sig.channel = zchan;
+
+	switch (zchan->state) {
+	case ZAP_CHANNEL_STATE_DOWN:
+		{
+			if (zap_test_sflag(zchan, SFLAG_FREE_REQ_ID)) {
+				release_request_id_span_chan(zchan->physical_span_id-1, zchan->physical_chan_id-1);
+			}
+
+			if (!zap_test_sflag(zchan, SFLAG_SENT_FINAL_MSG)) {
+				zap_set_sflag_locked(zchan, SFLAG_SENT_FINAL_MSG);
+
+				if (zchan->call_data && ((uint32_t)(intptr_t)zchan->call_data == SIGBOOST_EVENT_CALL_START_NACK)) {
+					sangomabc_exec_command(mcon,
+										   zchan->physical_span_id-1,
+										   zchan->physical_chan_id-1,
+										   0,
+										   SIGBOOST_EVENT_CALL_START_NACK_ACK,
+										   0, 0);
+					
+				} else {
+					sangomabc_exec_command(mcon,
+										   zchan->physical_span_id-1,
+										   zchan->physical_chan_id-1,
+										   0,
+										   SIGBOOST_EVENT_CALL_STOPPED_ACK,
+										   0, 0);
+				}
+			}
+
+			if (zchan->extra_id) {
+				zchan->extra_id = 0;
+			}
+			zchan->sflags = 0;
+			zchan->call_data = NULL;
+			zap_channel_done(zchan);
+		}
+		break;
+	case ZAP_CHANNEL_STATE_PROGRESS_MEDIA:
+		{
+			if (zap_test_flag(zchan, ZAP_CHANNEL_OUTBOUND)) {
+				sig.event_id = ZAP_SIGEVENT_PROGRESS_MEDIA;
+				if ((status = zap_span_send_signal(zchan->span, &sig) != ZAP_SUCCESS)) {
+					zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_HANGUP);
+				}
+			} else {
+				if (!zap_test_sflag(zchan, SFLAG_SENT_ACK)) {
+					zap_set_sflag(zchan, SFLAG_SENT_ACK);
+					sangomabc_exec_command(mcon,
+										   zchan->physical_span_id-1,
+										   zchan->physical_chan_id-1,
+										   0,
+										   SIGBOOST_EVENT_CALL_START_ACK,
+										   0,
+										   SIGBOOST_PROGRESS_MEDIA);
+				}
+			}
+		}
+		break;
+	case ZAP_CHANNEL_STATE_PROGRESS:
+		{
+			if (zap_test_flag(zchan, ZAP_CHANNEL_OUTBOUND)) {
+				sig.event_id = ZAP_SIGEVENT_PROGRESS;
+				if ((status = zap_span_send_signal(zchan->span, &sig) != ZAP_SUCCESS)) {
+					zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_HANGUP);
+				}
+			} else {
+				if (!zap_test_sflag(zchan, SFLAG_SENT_ACK)) {
+					zap_set_sflag(zchan, SFLAG_SENT_ACK);
+					sangomabc_exec_command(mcon,
+										   zchan->physical_span_id-1,
+										   zchan->physical_chan_id-1,
+										   0,
+										   SIGBOOST_EVENT_CALL_START_ACK,
+										   0,
+										   SIGBOOST_PROGRESS_RING);
+				}
+			}
+		}
+		break;
+	case ZAP_CHANNEL_STATE_IDLE:
+	case ZAP_CHANNEL_STATE_HOLD:
+		/* twiddle */
+		break;
+	case ZAP_CHANNEL_STATE_RING:
+		{
+			if (!zap_test_flag(zchan, ZAP_CHANNEL_OUTBOUND)) {
+				sig.event_id = ZAP_SIGEVENT_START;
+				if ((status = zap_span_send_signal(zchan->span, &sig) != ZAP_SUCCESS)) {
+					zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_HANGUP);
+				}
+			}
+		}
+		break;
+	case ZAP_CHANNEL_STATE_RESTART:
+		{
+			sig.event_id = ZAP_SIGEVENT_RESTART;
+			status = zap_span_send_signal(zchan->span, &sig);
+			zap_set_sflag_locked(zchan, SFLAG_SENT_FINAL_MSG);
+			zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_DOWN);
+		}
+		break;
+	case ZAP_CHANNEL_STATE_UP:
+		{
+			if (zap_test_flag(zchan, ZAP_CHANNEL_OUTBOUND)) {
+				sig.event_id = ZAP_SIGEVENT_UP;
+				if ((status = zap_span_send_signal(zchan->span, &sig) != ZAP_SUCCESS)) {
+					zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_HANGUP);
+				}
+			} else {
+				if (!(zap_test_flag(zchan, ZAP_CHANNEL_PROGRESS) || zap_test_flag(zchan, ZAP_CHANNEL_MEDIA))) {
+					sangomabc_exec_command(mcon,
+										   zchan->physical_span_id-1,
+										   zchan->physical_chan_id-1,
+										   0,
+										   SIGBOOST_EVENT_CALL_START_ACK,
+										   0, 0);
+				}
+				
+				sangomabc_exec_command(mcon,
+									   zchan->physical_span_id-1,
+									   zchan->physical_chan_id-1,
+									   0,
+									   SIGBOOST_EVENT_CALL_ANSWERED,
+									   0, 0);
+			}
+		}
+		break;
+	case ZAP_CHANNEL_STATE_DIALING:
+		{
+		}
+		break;
+	case ZAP_CHANNEL_STATE_HANGUP_COMPLETE:
+		{
+			zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_DOWN);
+		}
+		break;
+	case ZAP_CHANNEL_STATE_HANGUP:
+		{
+			zap_set_sflag_locked(zchan, SFLAG_HANGUP);
+
+			if (zap_test_sflag(zchan, SFLAG_SENT_FINAL_MSG) || zap_test_sflag(zchan, SFLAG_TERMINATING)) {
+				zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_HANGUP_COMPLETE);
+			} else {
+				zap_set_sflag_locked(zchan, SFLAG_SENT_FINAL_MSG);
+				
+				if (zap_test_flag(zchan, ZAP_CHANNEL_ANSWERED) || 
+					zap_test_flag(zchan, ZAP_CHANNEL_PROGRESS) || 
+					zap_test_flag(zchan, ZAP_CHANNEL_MEDIA) || zap_test_sflag(zchan, SFLAG_RECVD_ACK)) {
+					
+					sangomabc_exec_command(mcon,
+										   zchan->physical_span_id-1,
+										   zchan->physical_chan_id-1,
+										   0,
+										   SIGBOOST_EVENT_CALL_STOPPED,
+										   zchan->caller_data.hangup_cause, 0);
+				} else {
+					sangomabc_exec_command(mcon,
+										   zchan->physical_span_id-1,
+										   zchan->physical_chan_id-1,								   
+										   0,
+										   SIGBOOST_EVENT_CALL_START_NACK,
+										   zchan->caller_data.hangup_cause, 0);
+				}
+			}
+		}
+		break;
+	case ZAP_CHANNEL_STATE_TERMINATING:
+		{
+			zap_set_sflag_locked(zchan, SFLAG_TERMINATING);
+			sig.event_id = ZAP_SIGEVENT_STOP;
+			status = zap_span_send_signal(zchan->span, &sig);
+		}
+		break;
+	case ZAP_CHANNEL_STATE_IN_LOOP:
+		{
+			/* nothing to do, we sent the ZAP_COMMAND_ENABLE_LOOP command in handle_call_loop_start() right away */
+		}
+		break;
+	default:
+		break;
+	}
+}
+
+static __inline__ void advance_chan_states(zap_channel_t *zchan)
+{
+	while (zap_test_flag(zchan, ZAP_CHANNEL_STATE_CHANGE)) {
+		zap_clear_flag(zchan, ZAP_CHANNEL_STATE_CHANGE);
+		state_advance(zchan);
+		zap_channel_complete_state(zchan);
+	}
+}
+
+/**
+ * \brief Initialises outgoing requests array
+ */
+static __inline__ void init_outgoing_array(void)
+{
+	memset(&OUTBOUND_REQUESTS, 0, sizeof(OUTBOUND_REQUESTS));
+
+}
+
+/**
+ * \brief Checks current state on a span
+ * \param span Span to check status on
+ */
+static __inline__ void check_state(zap_span_t *span)
+{
+	zap_sangoma_boost_data_t *sangoma_boost_data = span->signal_data;
+	int susp = zap_test_flag(span, ZAP_SPAN_SUSPENDED);
+	
+	if (susp && zap_check_state_all(span, ZAP_CHANNEL_STATE_DOWN)) {
+		susp = 0;
+	}
+
+    if (zap_test_flag(span, ZAP_SPAN_STATE_CHANGE) || susp) {
+        uint32_t j;
+        zap_clear_flag_locked(span, ZAP_SPAN_STATE_CHANGE);
+        for(j = 1; j <= span->chan_count; j++) {
+            if (zap_test_flag((span->channels[j]), ZAP_CHANNEL_STATE_CHANGE) || susp) {
+				zap_mutex_lock(span->channels[j]->mutex);
+                zap_clear_flag((span->channels[j]), ZAP_CHANNEL_STATE_CHANGE);
+				if (susp && span->channels[j]->state != ZAP_CHANNEL_STATE_DOWN) {
+					zap_channel_set_state(span->channels[j], ZAP_CHANNEL_STATE_RESTART, 0);
+				}
+                state_advance(span->channels[j]);
+                zap_channel_complete_state(span->channels[j]);
+				zap_mutex_unlock(span->channels[j]->mutex);
+            }
+        }
+    }
+
+	if (zap_test_flag(sangoma_boost_data, ZAP_SANGOMA_BOOST_RESTARTING)) {
+		if (zap_check_state_all(span, ZAP_CHANNEL_STATE_DOWN)) {
+			sangomabc_exec_command(&sangoma_boost_data->mcon,
+								   0,
+								   0,
+								   -1,
+								   SIGBOOST_EVENT_SYSTEM_RESTART_ACK,
+								   0, 0);	
+			zap_clear_flag(sangoma_boost_data, ZAP_SANGOMA_BOOST_RESTARTING);
+			zap_clear_flag_locked(span, ZAP_SPAN_SUSPENDED);
+			zap_clear_flag((&sangoma_boost_data->mcon), MSU_FLAG_DOWN);
+			sangoma_boost_data->mcon.hb_elapsed = 0;
+			init_outgoing_array();
+		}
+	}
+}
+
+
+/**
+ * \brief Checks for events on a span
+ * \param span Span to check for events
+ */
+static __inline__ void check_events(zap_span_t *span, int ms_timeout)
+{
+	zap_status_t status;
+
+	status = zap_span_poll_event(span, ms_timeout);
+
+	switch(status) {
+	case ZAP_SUCCESS:
+		{
+			zap_event_t *event;
+			while (zap_span_next_event(span, &event) == ZAP_SUCCESS) {
+			// for now we do nothing with events, this is here
+			// just to have the hardware layer to get any HW DTMF
+			// events and enqueue the DTMF on the channel (done during zap_span_next_event())
+			}
+		}
+		break;
+	case ZAP_FAIL:
+		{
+			zap_log(ZAP_LOG_DEBUG, "Boost Check Event Failure Failure! %d\n", zap_running());
+		}
+		break;
+	default:
+		break;
+	}
+
+	return;
+}
+
+/**
+ * \brief Main thread function for sangoma boost span (monitor)
+ * \param me Current thread
+ * \param obj Span to run in this thread
+ */
+static void *zap_sangoma_events_run(zap_thread_t *me, void *obj)
+{
+    zap_span_t *span = (zap_span_t *) obj;
+	zap_sangoma_boost_data_t *sangoma_boost_data = span->signal_data;
+
+	while (zap_test_flag(sangoma_boost_data, ZAP_SANGOMA_BOOST_RUNNING) && zap_running()) {
+		check_events(span,100);
+	}
+
+	return NULL;
+}
+
+/**
+ * \brief Main thread function for sangoma boost span (monitor)
+ * \param me Current thread
+ * \param obj Span to run in this thread
+ */
+static void *zap_sangoma_boost_run(zap_thread_t *me, void *obj)
+{
+    zap_span_t *span = (zap_span_t *) obj;
+    zap_sangoma_boost_data_t *sangoma_boost_data = span->signal_data;
+	sangomabc_connection_t *mcon, *pcon;
+	uint32_t ms = 10; //, too_long = 20000;
+		
+
+	sangoma_boost_data->pcon = sangoma_boost_data->mcon;
+
+	if (sangomabc_connection_open(&sangoma_boost_data->mcon,
+							  sangoma_boost_data->mcon.cfg.local_ip,
+							  sangoma_boost_data->mcon.cfg.local_port,
+							  sangoma_boost_data->mcon.cfg.remote_ip,
+							  sangoma_boost_data->mcon.cfg.remote_port) < 0) {
+		zap_log(ZAP_LOG_ERROR, "Error: Opening MCON Socket [%d] %s\n", sangoma_boost_data->mcon.socket, strerror(errno));
+		goto end;
+    }
+ 
+	if (sangomabc_connection_open(&sangoma_boost_data->pcon,
+							  sangoma_boost_data->pcon.cfg.local_ip,
+							  ++sangoma_boost_data->pcon.cfg.local_port,
+							  sangoma_boost_data->pcon.cfg.remote_ip,
+							  ++sangoma_boost_data->pcon.cfg.remote_port) < 0) {
+		zap_log(ZAP_LOG_ERROR, "Error: Opening PCON Socket [%d] %s\n", sangoma_boost_data->pcon.socket, strerror(errno));
+		goto end;
+    }
+	
+	mcon = &sangoma_boost_data->mcon;
+	pcon = &sangoma_boost_data->pcon;
+
+	init_outgoing_array();
+
+	sangomabc_exec_commandp(pcon,
+					   0,
+					   0,
+					   -1,
+					   SIGBOOST_EVENT_SYSTEM_RESTART,
+					   0);
+	zap_set_flag(mcon, MSU_FLAG_DOWN);
+
+	while (zap_test_flag(sangoma_boost_data, ZAP_SANGOMA_BOOST_RUNNING)) {
+		fd_set rfds, efds;
+		struct timeval tv = { 0, ms * 1000 };
+		int max, activity, i = 0;
+		sangomabc_event_t *event = NULL;
+		
+		if (!zap_running()) {
+			sangomabc_exec_commandp(pcon,
+							   0,
+							   0,
+							   -1,
+							   SIGBOOST_EVENT_SYSTEM_RESTART,
+							   0);
+			zap_set_flag(mcon, MSU_FLAG_DOWN);
+			break;
+		}
+
+		FD_ZERO(&rfds);
+		FD_ZERO(&efds);
+		FD_SET(mcon->socket, &rfds);
+		FD_SET(mcon->socket, &efds);
+		FD_SET(pcon->socket, &rfds);
+		FD_SET(pcon->socket, &efds);
+
+		max = ((pcon->socket > mcon->socket) ? pcon->socket : mcon->socket) + 1;
+		
+		if ((activity = select(max, &rfds, NULL, &efds, &tv)) < 0) {
+			goto error;
+		}
+		
+		if (activity) {
+			if (FD_ISSET(pcon->socket, &efds) || FD_ISSET(mcon->socket, &efds)) {
+				goto error;
+			}
+
+			if (FD_ISSET(pcon->socket, &rfds)) {
+				while ((event = sangomabc_connection_readp(pcon, i))) {
+					parse_sangoma_event(span, pcon, (sangomabc_short_event_t*)event);
+					i++;
+				}
+			}
+			i=0;
+
+			if (FD_ISSET(mcon->socket, &rfds)) {
+				if ((event = sangomabc_connection_read(mcon, i))) {
+					parse_sangoma_event(span, mcon, (sangomabc_short_event_t*)event);
+					i++;
+				}
+			}
+
+		}
+		
+
+		pcon->hb_elapsed += ms;
+
+		if (zap_test_flag(span, ZAP_SPAN_SUSPENDED) || zap_test_flag(mcon, MSU_FLAG_DOWN)) {
+			pcon->hb_elapsed = 0;
+		}
+
+
+#if 0
+		if (pcon->hb_elapsed >= too_long) {
+			zap_log(ZAP_LOG_CRIT, "Lost Heartbeat!\n");
+			zap_set_flag_locked(span, ZAP_SPAN_SUSPENDED);
+			zap_set_flag(mcon, MSU_FLAG_DOWN);
+			sangomabc_exec_commandp(pcon,
+								0,
+								0,
+								-1,
+								SIGBOOST_EVENT_SYSTEM_RESTART,
+								0);
+		}
+#endif
+
+		if (zap_running()) {
+			check_state(span);
+		}
+	}
+
+	goto end;
+
+ error:
+	zap_log(ZAP_LOG_CRIT, "Socket Error!\n");
+
+ end:
+
+	sangomabc_connection_close(&sangoma_boost_data->mcon);
+	sangomabc_connection_close(&sangoma_boost_data->pcon);
+
+	zap_clear_flag(sangoma_boost_data, ZAP_SANGOMA_BOOST_RUNNING);
+
+	zap_log(ZAP_LOG_DEBUG, "SANGOMA_BOOST thread ended.\n");
+	return NULL;
+}
+
+/**
+ * \brief Loads sangoma boost signaling module
+ * \param zio Openzap IO interface
+ * \return Success
+ */
+static ZIO_SIG_LOAD_FUNCTION(zap_sangoma_boost_init)
+{
+	zap_mutex_create(&request_mutex);
+	
+	return ZAP_SUCCESS;
+}
+
+static zap_status_t zap_sangoma_boost_start(zap_span_t *span)
+{
+	int err;
+	zap_sangoma_boost_data_t *sangoma_boost_data = span->signal_data;
+	zap_set_flag(sangoma_boost_data, ZAP_SANGOMA_BOOST_RUNNING);
+	err=zap_thread_create_detached(zap_sangoma_boost_run, span);
+	if (err) {
+		zap_clear_flag(sangoma_boost_data, ZAP_SANGOMA_BOOST_RUNNING);
+		return err;
+	}
+	// launch the events thread to handle HW DTMF and possibly
+	// other events in the future
+	err=zap_thread_create_detached(zap_sangoma_events_run, span);
+	if (err) {
+		zap_clear_flag(sangoma_boost_data, ZAP_SANGOMA_BOOST_RUNNING);
+	}
+	return err;
+}
+
+static zap_state_map_t boost_state_map = {
+	{
+		{
+			ZSD_OUTBOUND,
+			ZSM_UNACCEPTABLE,
+			{ZAP_ANY_STATE},
+			{ZAP_CHANNEL_STATE_RESTART, ZAP_END}
+		},
+		{
+			ZSD_OUTBOUND,
+			ZSM_UNACCEPTABLE,
+			{ZAP_CHANNEL_STATE_RESTART, ZAP_END},
+			{ZAP_CHANNEL_STATE_DOWN, ZAP_END}
+		},
+		{
+			ZSD_OUTBOUND,
+			ZSM_UNACCEPTABLE,
+			{ZAP_CHANNEL_STATE_DOWN, ZAP_END},
+			{ZAP_CHANNEL_STATE_PROGRESS_MEDIA, ZAP_CHANNEL_STATE_PROGRESS, ZAP_CHANNEL_STATE_IDLE, ZAP_CHANNEL_STATE_HOLD, ZAP_END}
+		},
+		{
+			ZSD_OUTBOUND,
+			ZSM_UNACCEPTABLE,
+			{ZAP_CHANNEL_STATE_HOLD, ZAP_END},
+			{ZAP_CHANNEL_STATE_PROGRESS_MEDIA, ZAP_CHANNEL_STATE_PROGRESS, 
+			 ZAP_CHANNEL_STATE_IDLE, ZAP_CHANNEL_STATE_TERMINATING, ZAP_CHANNEL_STATE_UP, ZAP_END}
+		},
+		{
+			ZSD_OUTBOUND,
+			ZSM_UNACCEPTABLE,
+			{ZAP_CHANNEL_STATE_IDLE, ZAP_END},
+			{ZAP_CHANNEL_STATE_PROGRESS_MEDIA, ZAP_CHANNEL_STATE_PROGRESS, ZAP_END}
+		},
+		{
+			ZSD_OUTBOUND,
+			ZSM_UNACCEPTABLE,
+			{ZAP_CHANNEL_STATE_PROGRESS_MEDIA, ZAP_CHANNEL_STATE_PROGRESS, ZAP_CHANNEL_STATE_IDLE, ZAP_END},
+			{ZAP_CHANNEL_STATE_HANGUP, ZAP_CHANNEL_STATE_TERMINATING, ZAP_CHANNEL_STATE_UP, ZAP_END}
+		},
+		{
+			ZSD_OUTBOUND,
+			ZSM_UNACCEPTABLE,
+			{ZAP_CHANNEL_STATE_HANGUP, ZAP_CHANNEL_STATE_TERMINATING, ZAP_END},
+			{ZAP_CHANNEL_STATE_HANGUP_COMPLETE, ZAP_CHANNEL_STATE_HANGUP, ZAP_END}
+		},
+		{
+			ZSD_OUTBOUND,
+			ZSM_UNACCEPTABLE,
+			{ZAP_CHANNEL_STATE_HANGUP_COMPLETE, ZAP_END},
+			{ZAP_CHANNEL_STATE_DOWN, ZAP_END},
+		},
+		{
+			ZSD_OUTBOUND,
+			ZSM_UNACCEPTABLE,
+			{ZAP_CHANNEL_STATE_UP, ZAP_END},
+			{ZAP_CHANNEL_STATE_HANGUP, ZAP_CHANNEL_STATE_TERMINATING, ZAP_END}
+		},
+
+		/****************************************/
+		{
+			ZSD_INBOUND,
+			ZSM_UNACCEPTABLE,
+			{ZAP_ANY_STATE},
+			{ZAP_CHANNEL_STATE_RESTART, ZAP_END}
+		},
+		{
+			ZSD_INBOUND,
+			ZSM_UNACCEPTABLE,
+			{ZAP_CHANNEL_STATE_RESTART, ZAP_END},
+			{ZAP_CHANNEL_STATE_DOWN, ZAP_END}
+		},
+		{
+			ZSD_INBOUND,
+			ZSM_UNACCEPTABLE,
+			{ZAP_CHANNEL_STATE_DOWN},
+			{ZAP_CHANNEL_STATE_IN_LOOP, ZAP_END}
+		},
+		{
+			ZSD_INBOUND,
+			ZSM_UNACCEPTABLE,
+			{ZAP_CHANNEL_STATE_IN_LOOP},
+			{ZAP_CHANNEL_STATE_DOWN, ZAP_END}
+		},
+		{
+			ZSD_INBOUND,
+			ZSM_UNACCEPTABLE,
+			{ZAP_CHANNEL_STATE_DOWN, ZAP_END},
+			{ZAP_CHANNEL_STATE_RING, ZAP_END}
+		},
+		{
+			ZSD_INBOUND,
+			ZSM_UNACCEPTABLE,
+			{ZAP_CHANNEL_STATE_RING, ZAP_END},
+			{ZAP_CHANNEL_STATE_HANGUP, ZAP_CHANNEL_STATE_TERMINATING, ZAP_CHANNEL_STATE_PROGRESS, ZAP_CHANNEL_STATE_PROGRESS_MEDIA,ZAP_END}
+		},
+		{
+			ZSD_INBOUND,
+			ZSM_UNACCEPTABLE,
+			{ZAP_CHANNEL_STATE_HANGUP, ZAP_CHANNEL_STATE_TERMINATING, ZAP_END},
+			{ZAP_CHANNEL_STATE_HANGUP_COMPLETE, ZAP_CHANNEL_STATE_HANGUP, ZAP_END},
+		},
+		{
+			ZSD_INBOUND,
+			ZSM_UNACCEPTABLE,
+			{ZAP_CHANNEL_STATE_HANGUP_COMPLETE, ZAP_CHANNEL_STATE_TERMINATING, ZAP_END},
+			{ZAP_CHANNEL_STATE_DOWN, ZAP_END},
+		},
+		{
+			ZSD_INBOUND,
+			ZSM_UNACCEPTABLE,
+			{ZAP_CHANNEL_STATE_PROGRESS, ZAP_CHANNEL_STATE_PROGRESS_MEDIA, ZAP_END},
+			{ZAP_CHANNEL_STATE_HANGUP, ZAP_CHANNEL_STATE_TERMINATING, ZAP_CHANNEL_STATE_UP, ZAP_CHANNEL_STATE_PROGRESS_MEDIA, ZAP_END},
+		},
+		{
+			ZSD_INBOUND,
+			ZSM_UNACCEPTABLE,
+			{ZAP_CHANNEL_STATE_UP, ZAP_END},
+			{ZAP_CHANNEL_STATE_HANGUP, ZAP_CHANNEL_STATE_TERMINATING, ZAP_END},
+		},
+		
+
+	}
+};
+
+/**
+ * \brief Initialises an sangoma boost span from configuration variables
+ * \param span Span to configure
+ * \param sig_cb Callback function for event signals
+ * \param ap List of configuration variables
+ * \return Success or failure
+ */
+static ZIO_SIG_CONFIGURE_FUNCTION(zap_sangoma_boost_configure_span)
+{
+	zap_sangoma_boost_data_t *sangoma_boost_data = NULL;
+	const char *local_ip = "127.0.0.65", *remote_ip = "127.0.0.66";
+	int local_port = 53000, remote_port = 53000;
+	char *var, *val;
+	int *intval;
+
+	while((var = va_arg(ap, char *))) {
+		if (!strcasecmp(var, "local_ip")) {
+			if (!(val = va_arg(ap, char *))) {
+				break;
+			}
+			local_ip = val;
+		} else if (!strcasecmp(var, "remote_ip")) {
+			if (!(val = va_arg(ap, char *))) {
+				break;
+			}
+			remote_ip = val;
+		} else if (!strcasecmp(var, "local_port")) {
+			if (!(intval = va_arg(ap, int *))) {
+				break;
+			}
+			local_port = *intval;
+		} else if (!strcasecmp(var, "remote_port")) {
+			if (!(intval = va_arg(ap, int *))) {
+				break;
+			}
+			remote_port = *intval;
+		} else {
+			snprintf(span->last_error, sizeof(span->last_error), "Unknown parameter [%s]", var);
+			return ZAP_FAIL;
+		}
+	}
+
+
+	if (!local_ip && local_port && remote_ip && remote_port && sig_cb) {
+		zap_set_string(span->last_error, "missing params");
+		return ZAP_FAIL;
+	}
+
+	sangoma_boost_data = malloc(sizeof(*sangoma_boost_data));
+	assert(sangoma_boost_data);
+	memset(sangoma_boost_data, 0, sizeof(*sangoma_boost_data));
+	
+	zap_set_string(sangoma_boost_data->mcon.cfg.local_ip, local_ip);
+	sangoma_boost_data->mcon.cfg.local_port = local_port;
+	zap_set_string(sangoma_boost_data->mcon.cfg.remote_ip, remote_ip);
+	sangoma_boost_data->mcon.cfg.remote_port = remote_port;
+	span->signal_cb = sig_cb;
+	span->start = zap_sangoma_boost_start;
+	span->signal_data = sangoma_boost_data;
+    span->signal_type = ZAP_SIGTYPE_SANGOMABOOST;
+    span->outgoing_call = sangoma_boost_outgoing_call;
+	span->channel_request = sangoma_boost_channel_request;
+	span->state_map = &boost_state_map;
+	zap_set_flag_locked(span, ZAP_SPAN_SUSPENDED);
+
+	return ZAP_SUCCESS;
+}
+
+/**
+ * \brief Openzap sangoma boost signaling module definition
+ */
+zap_module_t zap_module = { 
+	"sangoma_boost",
+	NULL,
+	NULL,
+	zap_sangoma_boost_init,
+	zap_sangoma_boost_configure_span,
+	NULL
+};
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */

Added: freeswitch/trunk/libs/openzap/src/ozmod/ozmod_sangoma_boost/sangoma_boost_client.c (0 => 17141)


--- freeswitch/trunk/libs/openzap/src/ozmod/ozmod_sangoma_boost/sangoma_boost_client.c	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/src/ozmod/ozmod_sangoma_boost/sangoma_boost_client.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,527 @@
+/*
+ * Copyright (c) 2007, Anthony Minessale II, Nenad Corbic
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if HAVE_NETDB_H
+#include <netdb.h>
+#endif
+
+#include "openzap.h"
+#include <sangoma_boost_client.h>
+
+#ifndef HAVE_GETHOSTBYNAME_R
+extern int gethostbyname_r (const char *__name, 
+							struct hostent *__result_buf, 
+							char *__buf, size_t __buflen, 
+							struct hostent **__result, 
+							int *__h_errnop);
+#endif
+
+struct sangomabc_map {
+	uint32_t event_id;
+	const char *name;
+};
+
+static struct sangomabc_map sangomabc_table[] = {
+	{SIGBOOST_EVENT_CALL_START, "CALL_START"},
+	{SIGBOOST_EVENT_CALL_START_ACK, "CALL_START_ACK"}, 
+	{SIGBOOST_EVENT_CALL_START_NACK, "CALL_START_NACK"},
+	{SIGBOOST_EVENT_CALL_PROGRESS, "CALL PROGRESS"},
+	{SIGBOOST_EVENT_CALL_START_NACK_ACK, "CALL_START_NACK_ACK"}, 
+	{SIGBOOST_EVENT_CALL_ANSWERED, "CALL_ANSWERED"}, 
+	{SIGBOOST_EVENT_CALL_STOPPED, "CALL_STOPPED"}, 
+	{SIGBOOST_EVENT_CALL_STOPPED_ACK, "CALL_STOPPED_ACK"}, 
+	{SIGBOOST_EVENT_SYSTEM_RESTART, "SYSTEM_RESTART"}, 
+	{SIGBOOST_EVENT_SYSTEM_RESTART_ACK, "SYSTEM_RESTART_ACK"}, 
+	{SIGBOOST_EVENT_HEARTBEAT, "HEARTBEAT"}, 
+	{SIGBOOST_EVENT_INSERT_CHECK_LOOP, "LOOP START"}, 
+	{SIGBOOST_EVENT_REMOVE_CHECK_LOOP, "LOOP STOP"},
+	{SIGBOOST_EVENT_AUTO_CALL_GAP_ABATE, "AUTO_CALL_GAP_ABATE"},
+	{SIGBOOST_EVENT_DIGIT_IN, "DIGIT_IN"}
+}; 
+
+
+
+static void sangomabc_print_event_call(sangomabc_connection_t *mcon, sangomabc_event_t *event, int priority, int dir, const char *file, const char *func, int line)
+{
+	if (event->event_id == SIGBOOST_EVENT_HEARTBEAT)
+		return;
+
+	zap_log(file, func, line, ZAP_LOG_LEVEL_WARNING, "%s EVENT: %s:(%X) [w%dg%d] CSid=%i Seq=%i Cn=[%s] Cd=[%s] Ci=[%s] Rdnis=[%s]\n",
+		    dir ? "TX":"RX", 
+			sangomabc_event_id_name(event->event_id),
+			event->event_id,
+			event->span+1,
+			event->chan+1,
+			event->call_setup_id,
+			event->fseqno,
+			strlen(event->calling_name)?event->calling_name:"N/A",
+			(event->called_number_digits_count ? (char *) event->called_number_digits : "N/A"),
+			(event->calling_number_digits_count ? (char *) event->calling_number_digits : "N/A"),
+			event->isup_in_rdnis);
+
+}
+static void sangomabc_print_event_short(sangomabc_connection_t *mcon, sangomabc_short_event_t *event, int priority, int dir, const char *file, const char *func, int line)
+{
+	if (event->event_id == SIGBOOST_EVENT_HEARTBEAT)
+		return;
+	zap_log(file, func, line, ZAP_LOG_LEVEL_WARNING, "%s EVENT (%s): %s:(%X) [w%dg%d] Rc=%i CSid=%i Seq=%i \n", 
+			   dir ? "TX":"RX", 
+			   priority ? "P":"N", 	
+                           sangomabc_event_id_name(event->event_id), 
+                           event->event_id, 
+                           event->span+1, 
+                           event->chan+1, 
+                           event->release_cause, 
+                           event->call_setup_id, 
+                           event->fseqno);
+}
+
+
+static int create_conn_socket(sangomabc_connection_t *mcon, char *local_ip, int local_port, char *ip, int port)
+{
+	int rc;
+	struct hostent *result, *local_result;
+	char buf[512], local_buf[512];
+	int err = 0, local_err = 0;
+
+	memset(&mcon->remote_hp, 0, sizeof(mcon->remote_hp));
+	memset(&mcon->local_hp, 0, sizeof(mcon->local_hp));
+#ifdef HAVE_NETINET_SCTP_H
+	zap_log(ZAP_LOG_DEBUG, "Creating SCTP socket L=%s:%d R=%s:%d\n", 
+			local_ip, local_port, ip, port);
+	mcon->socket = socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP);
+#else
+	zap_log(ZAP_LOG_DEBUG, "Creating UDP socket L=%s:%d R=%s:%d\n", 
+			local_ip, local_port, ip, port);
+	mcon->socket = socket(AF_INET, SOCK_DGRAM, 0);
+#endif
+ 
+	if (mcon->socket >= 0) {
+		int flag;
+
+		flag = 1;
+#ifdef HAVE_GETHOSTBYNAME_R_FIVE
+		gethostbyname_r(ip, &mcon->remote_hp, buf, sizeof(buf), &err);
+		gethostbyname_r(local_ip, &mcon->local_hp, local_buf, sizeof(local_buf), &local_err);
+		if (!err && !local_err) {
+#else
+		gethostbyname_r(ip, &mcon->remote_hp, buf, sizeof(buf), &result, &err);
+		gethostbyname_r(local_ip, &mcon->local_hp, local_buf, sizeof(local_buf), &local_result, &local_err);
+		if (result && local_result) {
+#endif
+			mcon->remote_addr.sin_family = mcon->remote_hp.h_addrtype;
+			memcpy((char *) &mcon->remote_addr.sin_addr.s_addr, mcon->remote_hp.h_addr_list[0], mcon->remote_hp.h_length);
+			mcon->remote_addr.sin_port = htons(port);
+
+			mcon->local_addr.sin_family = mcon->local_hp.h_addrtype;
+			memcpy((char *) &mcon->local_addr.sin_addr.s_addr, mcon->local_hp.h_addr_list[0], mcon->local_hp.h_length);
+			mcon->local_addr.sin_port = htons(local_port);
+
+#ifdef HAVE_NETINET_SCTP_H
+			setsockopt(mcon->socket, IPPROTO_SCTP, SCTP_NODELAY, 
+					   (char *)&flag, sizeof(int));
+#endif
+
+			if ((rc = bind(mcon->socket, 
+						   (struct sockaddr *) &mcon->local_addr, 
+						   sizeof(mcon->local_addr))) < 0) {
+				close(mcon->socket);
+				mcon->socket = -1;
+			} else {
+#ifdef HAVE_NETINET_SCTP_H
+				rc=listen(mcon->socket, 100);
+				if (rc) {
+					close(mcon->socket);
+					mcon->socket = -1;
+				}
+#endif
+			}
+		}
+	}
+
+	zap_mutex_create(&mcon->mutex);
+
+	return mcon->socket;
+}
+
+int sangomabc_connection_close(sangomabc_connection_t *mcon)
+{
+	if (mcon->socket > -1) {
+		close(mcon->socket);
+	}
+
+	if (mcon->mutex) {
+		zap_mutex_lock(mcon->mutex);
+		zap_mutex_unlock(mcon->mutex);
+		zap_mutex_destroy(&mcon->mutex);
+	}
+	memset(mcon, 0, sizeof(*mcon));
+	mcon->socket = -1;
+
+	return 0;
+}
+
+int sangomabc_connection_open(sangomabc_connection_t *mcon, char *local_ip, int local_port, char *ip, int port)
+{
+	create_conn_socket(mcon, local_ip, local_port, ip, port);
+	return mcon->socket;
+}
+
+
+int sangomabc_exec_command(sangomabc_connection_t *mcon, int span, int chan, int id, int cmd, int cause, int flags)
+{
+    sangomabc_short_event_t oevent;
+    int retry = 5;
+
+    sangomabc_event_init(&oevent, cmd, chan, span);
+    oevent.release_cause = cause;
+	oevent.flags = flags;
+
+	if (cmd == SIGBOOST_EVENT_SYSTEM_RESTART || cmd == SIGBOOST_EVENT_SYSTEM_RESTART_ACK) {
+		mcon->rxseq_reset = 1;
+		mcon->txseq = 0;
+		mcon->rxseq = 0;
+		mcon->txwindow = 0;
+	}
+
+    if (id >= 0) {
+        oevent.call_setup_id = id;
+    }
+
+    while (sangomabc_connection_write(mcon, (sangomabc_event_t*)&oevent) <= 0) {
+        if (--retry <= 0) {
+            zap_log(ZAP_LOG_CRIT, "Failed to tx on ISUP socket: %s\n", strerror(errno));
+            return -1;
+        } else {
+            zap_log(ZAP_LOG_WARNING, "Failed to tx on ISUP socket: %s :retry %i\n", strerror(errno), retry);
+			zap_sleep(1);
+        }
+    }
+
+    return 0;
+}
+
+
+int sangomabc_exec_commandp(sangomabc_connection_t *pcon, int span, int chan, int id, int cmd, int cause)
+{
+    sangomabc_short_event_t oevent;
+    int retry = 5;
+
+    sangomabc_event_init(&oevent, cmd, chan, span);
+    oevent.release_cause = cause;
+
+    if (id >= 0) {
+        oevent.call_setup_id = id;
+    }
+
+    while (sangomabc_connection_writep(pcon, (sangomabc_event_t*)&oevent) <= 0) {
+        if (--retry <= 0) {
+            zap_log(ZAP_LOG_CRIT, "Failed to tx on ISUP socket: %s\n", strerror(errno));
+            return -1;
+        } else {
+            zap_log(ZAP_LOG_WARNING, "Failed to tx on ISUP socket: %s :retry %i\n", strerror(errno), retry);
+			zap_sleep(1);
+        }
+    }
+
+    return 0;
+}
+
+sangomabc_event_t *__sangomabc_connection_read(sangomabc_connection_t *mcon, int iteration, const char *file, const char *func, int line)
+{
+	unsigned int fromlen = sizeof(struct sockaddr_in);
+	int bytes = 0;
+	int msg_ok = 0;
+
+	bytes = recvfrom(mcon->socket, &mcon->event, sizeof(mcon->event), MSG_DONTWAIT, 
+					 (struct sockaddr *) &mcon->local_addr, &fromlen);
+
+	if (bytes <= 0) {
+		return NULL;
+	}
+
+    if (mcon->event.version != SIGBOOST_VERSION) {
+		zap_log(ZAP_LOG_CRIT, "Invalid Boost Version %i  Expecting %i\n",mcon->event.version, SIGBOOST_VERSION);
+    }   
+
+	/* Must check for < 0 cannot rely on bytes > MIN_SIZE_... compiler issue */
+	if (bytes < 0) {
+		msg_ok=0;
+
+	} else if ((bytes >= MIN_SIZE_CALLSTART_MSG) && boost_full_event(mcon->event.event_id)) {
+		msg_ok=1;
+		
+	} else if (bytes == sizeof(sangomabc_short_event_t)) {
+		msg_ok=1;
+
+	} else {
+		msg_ok=0;
+	}
+
+	if (msg_ok){
+
+		if (sangomabc_test_flag(mcon, MSU_FLAG_DOWN)) {
+			if (mcon->event.event_id != SIGBOOST_EVENT_SYSTEM_RESTART && 
+				mcon->event.event_id != SIGBOOST_EVENT_SYSTEM_RESTART_ACK && 
+				mcon->event.event_id != SIGBOOST_EVENT_HEARTBEAT) {
+				zap_log(file, func, line, ZAP_LOG_LEVEL_WARNING, "Not reading packets when connection is down. [%s]\n", 
+						sangomabc_event_id_name(mcon->event.event_id));
+				return NULL;
+			}
+		}
+
+		if  (boost_full_event(mcon->event.event_id)) {
+			sangomabc_print_event_call(mcon, &mcon->event, 0, 0, file, func, line);
+		} else {
+			sangomabc_print_event_short(mcon, (sangomabc_short_event_t*)&mcon->event, 0, 0, file, func, line);
+		}
+
+#if 0
+/* NC: NOT USED ANY MORE */
+		if (mcon->rxseq_reset) {
+			//if (mcon->event.event_id == SIGBOOST_EVENT_SYSTEM_RESTART_ACK) {
+				zap_log(ZAP_LOG_DEBUG, "Rx sync ok\n");
+				mcon->rxseq = mcon->event.fseqno;
+				return &mcon->event;
+				//}
+			errno=EAGAIN;
+			zap_log(ZAP_LOG_DEBUG, "Waiting for rx sync...\n");
+			return NULL;
+		}
+#endif
+		
+		mcon->txwindow = mcon->txseq - mcon->event.bseqno;
+		mcon->rxseq++;
+
+#if 0
+		if (mcon->rxseq != mcon->event.fseqno) {
+			zap_log(ZAP_LOG_CRIT, "Invalid Sequence Number Expect=%i Rx=%i\n", mcon->rxseq, mcon->event.fseqno);
+			return NULL;
+		}
+#endif
+
+		return &mcon->event;
+	} else {
+		if (iteration == 0) {
+			zap_log(ZAP_LOG_CRIT, "NC -  Invalid Event length from boost rxlen=%i evsz=%i\n", bytes, sizeof(mcon->event));
+			return NULL;
+		}
+	}
+
+	return NULL;
+}
+
+sangomabc_event_t *__sangomabc_connection_readp(sangomabc_connection_t *mcon, int iteration, const char *file, const char *func, int line)
+{
+	unsigned int fromlen = sizeof(struct sockaddr_in);
+	int bytes = 0;
+
+	bytes = recvfrom(mcon->socket, &mcon->event, sizeof(mcon->event), MSG_DONTWAIT, (struct sockaddr *) &mcon->local_addr, &fromlen);
+	
+	if (bytes <= 0) {
+		return NULL;
+	}
+
+    if (mcon->event.version != SIGBOOST_VERSION) {
+		zap_log(ZAP_LOG_CRIT, "Invalid Boost Version %i  Expecting %i\n",mcon->event.version, SIGBOOST_VERSION);
+    }   
+
+	if (bytes == sizeof(sangomabc_short_event_t)) {
+
+		if  (boost_full_event(mcon->event.event_id)) {
+			sangomabc_print_event_call(mcon, &mcon->event, 1, 0, file, func, line);
+		} else {
+			sangomabc_print_event_short(mcon, (sangomabc_short_event_t*)&mcon->event, 1, 0, file, func, line);
+		}
+
+		return &mcon->event;
+	} else {
+		if (iteration == 0) {
+			zap_log(ZAP_LOG_CRIT, "Critical Error: PQ Invalid Event lenght from boost rxlen=%i evsz=%i\n", bytes, sizeof(mcon->event));
+			return NULL;
+		}
+	}
+
+	return NULL;
+}
+
+
+int __sangomabc_connection_write(sangomabc_connection_t *mcon, sangomabc_event_t *event, const char *file, const char *func, int line)
+{
+	int err;
+	int event_size=MIN_SIZE_CALLSTART_MSG+event->isup_in_rdnis_size;
+ 
+	if (!event || mcon->socket < 0 || !mcon->mutex) {
+		zap_log(file, func, line, ZAP_LOG_LEVEL_CRIT, "Critical Error: No Event Device\n");
+		return -EINVAL;
+		abort();
+	}
+
+	if (event->span >= ZAP_MAX_PHYSICAL_SPANS_PER_LOGICAL_SPAN || event->chan >= ZAP_MAX_CHANNELS_PHYSICAL_SPAN ) {
+		zap_log(file, func, line, ZAP_LOG_LEVEL_CRIT, "Critical Error: TX Cmd=%s Invalid Span=%i Chan=%i\n", sangomabc_event_id_name(event->event_id), event->span, event->chan);
+		abort();
+		return -1;
+	}
+
+	if (!boost_full_event(event->event_id)) {
+		event_size=sizeof(sangomabc_short_event_t);
+	}	
+
+	if (sangomabc_test_flag(mcon, MSU_FLAG_DOWN)) {
+		if (event->event_id != SIGBOOST_EVENT_SYSTEM_RESTART && 
+			event->event_id != SIGBOOST_EVENT_SYSTEM_RESTART_ACK && 
+			event->event_id != SIGBOOST_EVENT_HEARTBEAT) {
+			zap_log(file, func, line, ZAP_LOG_LEVEL_WARNING, "Not writing packets when connection is down. [%s]\n",
+					sangomabc_event_id_name(event->event_id));
+			return 0;
+		}
+	}
+
+	zap_mutex_lock(mcon->mutex);
+	if (event->event_id == SIGBOOST_EVENT_SYSTEM_RESTART_ACK) {
+		mcon->txseq=0;
+		mcon->rxseq=0;
+		event->fseqno=0;	
+	} else {
+		event->fseqno = mcon->txseq++;
+	}
+	event->bseqno = mcon->rxseq;
+    event->version = SIGBOOST_VERSION; 
+	err = sendto(mcon->socket, event, event_size, 0, (struct sockaddr *) &mcon->remote_addr, sizeof(mcon->remote_addr));
+
+	zap_mutex_unlock(mcon->mutex);
+
+	if (err != event_size) {
+		err = -1;
+		abort();
+	}
+
+	if (boost_full_event(event->event_id)) {
+		sangomabc_print_event_call(mcon, event, 0, 1, file, func, line);
+	} else {
+		sangomabc_print_event_short(mcon, (sangomabc_short_event_t*)event, 0, 1, file, func, line);
+	}
+
+	return err;
+}
+
+
+int __sangomabc_connection_writep(sangomabc_connection_t *mcon, sangomabc_event_t *event, const char *file, const char *func, int line)
+{
+	int err;
+	int event_size=sizeof(sangomabc_event_t);
+
+	if (!event || mcon->socket < 0 || !mcon->mutex) {
+		zap_log(file, func, line, ZAP_LOG_LEVEL_CRIT, "Critical Error: No Event Device\n");
+		return -EINVAL;
+		abort();
+	}
+
+	if (!boost_full_event(event->event_id)) {
+		event_size=sizeof(sangomabc_short_event_t);
+	}	
+
+	zap_mutex_lock(mcon->mutex);
+    event->version = SIGBOOST_VERSION; 
+	err = sendto(mcon->socket, event, event_size, 0, (struct sockaddr *) &mcon->remote_addr, sizeof(mcon->remote_addr));
+	zap_mutex_unlock(mcon->mutex);
+
+	if (err != event_size) {
+		err = -1;
+		abort();
+	}
+
+	if (boost_full_event(event->event_id)) {
+		sangomabc_print_event_call(mcon, event, 1, 1, file, func, line);
+	} else {
+		sangomabc_print_event_short(mcon, (sangomabc_short_event_t*)event, 1, 1, file, func, line);
+	}
+
+	return err;
+}
+
+
+void sangomabc_call_init(sangomabc_event_t *event, const char *calling, const char *called, int setup_id)
+{
+	memset(event, 0, sizeof(sangomabc_event_t));
+	event->event_id = SIGBOOST_EVENT_CALL_START;
+
+	if (calling) {
+		strncpy((char*)event->calling_number_digits, calling, sizeof(event->calling_number_digits)-1);
+		event->calling_number_digits_count = strlen(calling);
+	}
+
+	if (called) {
+		strncpy((char*)event->called_number_digits, called, sizeof(event->called_number_digits)-1);
+		event->called_number_digits_count = strlen(called);
+	}
+		
+	event->call_setup_id = setup_id;
+	
+}
+
+void sangomabc_event_init(sangomabc_short_event_t *event, sangomabc_event_id_t event_id, int chan, int span)
+{
+	memset(event, 0, sizeof(sangomabc_short_event_t));
+	event->event_id = event_id;
+	event->chan = chan;
+	event->span = span;
+}
+
+const char *sangomabc_event_id_name(uint32_t event_id)
+{
+	unsigned int x;
+	const char *ret = NULL;
+
+	for (x = 0 ; x < sizeof(sangomabc_table)/sizeof(struct sangomabc_map); x++) {
+		if (sangomabc_table[x].event_id == event_id) {
+			ret = sangomabc_table[x].name;
+			break;
+		}
+	}
+
+	return ret;
+}
+
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
+

Added: freeswitch/trunk/libs/openzap/src/ozmod/ozmod_sangoma_boost/sangoma_boost_client.h (0 => 17141)


--- freeswitch/trunk/libs/openzap/src/ozmod/ozmod_sangoma_boost/sangoma_boost_client.h	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/src/ozmod/ozmod_sangoma_boost/sangoma_boost_client.h	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2007, Anthony Minessale II, Nenad Corbic
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _SANGOMABC_H
+#define _SANGOMABC_H
+
+#include <ctype.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#ifdef HAVE_NETINET_SCTP_H
+#include <netinet/sctp.h>
+#endif
+#include <arpa/inet.h>
+#include <stdarg.h>
+#include <netdb.h>
+#include <sigboost.h>
+#include <sys/time.h>
+
+#define sangomabc_test_flag(p,flag) 		({		\
+			((p)->flags & (flag));				\
+		})
+
+#define sangomabc_set_flag(p,flag) 		do {		\
+		((p)->flags |= (flag));					\
+	} while (0)
+
+#define sangomabc_clear_flag(p,flag) 		do {	\
+		((p)->flags &= ~(flag));				\
+	} while (0)
+
+#define sangomabc_copy_flags(dest,src,flagz)	do {	\
+		(dest)->flags &= ~(flagz);					\
+		(dest)->flags |= ((src)->flags & (flagz));	\
+	} while (0)
+
+typedef  t_sigboost_callstart sangomabc_event_t;
+typedef  t_sigboost_short sangomabc_short_event_t;
+typedef uint32_t sangomabc_event_id_t;
+
+typedef struct sangomabc_ip_cfg
+{
+	char local_ip[25];
+	int local_port;
+	char remote_ip[25];
+	int remote_port;
+}sangomabc_ip_cfg_t;
+
+typedef enum {
+	MSU_FLAG_EVENT = (1 << 0),
+	MSU_FLAG_DOWN = (1 << 1)
+} sangomabc_flag_t;
+
+
+struct sangomabc_connection {
+	zap_socket_t socket;
+	struct sockaddr_in local_addr;
+	struct sockaddr_in remote_addr;
+	sangomabc_event_t event;
+	struct hostent remote_hp;
+	struct hostent local_hp;
+	unsigned int flags;
+	zap_mutex_t *mutex;
+	FILE *log;
+	unsigned int txseq;
+	unsigned int rxseq;
+	unsigned int txwindow;
+	unsigned int rxseq_reset;
+	sangomabc_ip_cfg_t cfg;
+	uint32_t hb_elapsed;
+};
+
+typedef struct sangomabc_connection sangomabc_connection_t;
+
+/* disable nagle's algorythm */
+static inline void sctp_no_nagle(int socket)
+{
+#ifdef HAVE_NETINET_SCTP_H
+    int flag = 1;
+    setsockopt(socket, IPPROTO_SCTP, SCTP_NODELAY, (char *) &flag, sizeof(int));
+#endif
+}
+
+int sangomabc_connection_close(sangomabc_connection_t *mcon);
+int sangomabc_connection_open(sangomabc_connection_t *mcon, char *local_ip, int local_port, char *ip, int port);
+sangomabc_event_t *__sangomabc_connection_read(sangomabc_connection_t *mcon, int iteration, const char *file, const char *func, int line);
+sangomabc_event_t *__sangomabc_connection_readp(sangomabc_connection_t *mcon, int iteration, const char *file, const char *func, int line);
+int __sangomabc_connection_write(sangomabc_connection_t *mcon, sangomabc_event_t *event, const char *file, const char *func, int line);
+int __sangomabc_connection_writep(sangomabc_connection_t *mcon, sangomabc_event_t *event, const char *file, const char *func, int line);
+#define sangomabc_connection_write(_m,_e) __sangomabc_connection_write(_m, _e, __FILE__, __func__, __LINE__)
+#define sangomabc_connection_writep(_m,_e) __sangomabc_connection_writep(_m, _e, __FILE__, __func__, __LINE__)
+#define sangomabc_connection_read(_m,_e) __sangomabc_connection_read(_m, _e, __FILE__, __func__, __LINE__)
+#define sangomabc_connection_readp(_m,_e) __sangomabc_connection_readp(_m, _e, __FILE__, __func__, __LINE__)
+void sangomabc_event_init(sangomabc_short_event_t *event, sangomabc_event_id_t event_id, int chan, int span);
+void sangomabc_call_init(sangomabc_event_t *event, const char *calling, const char *called, int setup_id);
+const char *sangomabc_event_id_name(uint32_t event_id);
+int sangomabc_exec_command(sangomabc_connection_t *mcon, int span, int chan, int id, int cmd, int cause, int flags);
+int sangomabc_exec_commandp(sangomabc_connection_t *pcon, int span, int chan, int id, int cmd, int cause);
+
+#endif
+
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */

Added: freeswitch/trunk/libs/openzap/src/ozmod/ozmod_sangoma_boost/sigboost.h (0 => 17141)


--- freeswitch/trunk/libs/openzap/src/ozmod/ozmod_sangoma_boost/sigboost.h	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/src/ozmod/ozmod_sangoma_boost/sigboost.h	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,209 @@
+/****************************************************************************
+ * sigboost.h     $Revision: 1.13 $
+ *
+ * Definitions for the sigboost interface.
+ *
+ * WARNING WARNING WARNING
+ *
+ * This file is used by sangoma_mgd and perhaps other programs. Any changes 
+ * to this file must be coordinated with other user programs,
+ *
+ * Copyright (C) 2005  Xygnada Technology, Inc.
+ * 
+****************************************************************************/
+#ifndef _SIGBOOST_H_
+#define _SIGBOOST_H_
+
+#define SIGBOOST_VERSION 103
+
+#include <stdint.h>
+#include <sys/time.h>
+
+#ifdef HAVE_FREETDM
+#include <freetdm.h>
+#endif
+
+enum	e_sigboost_event_id_values
+{
+	SIGBOOST_EVENT_CALL_START			= 0x80, /*128*/
+	SIGBOOST_EVENT_CALL_START_ACK			= 0x81, /*129*/
+	SIGBOOST_EVENT_CALL_START_NACK			= 0x82, /*130*/
+	SIGBOOST_EVENT_CALL_START_NACK_ACK		= 0x83, /*131*/
+	SIGBOOST_EVENT_CALL_ANSWERED			= 0x84, /*132*/
+	SIGBOOST_EVENT_CALL_STOPPED			= 0x85, /*133*/
+	SIGBOOST_EVENT_CALL_STOPPED_ACK			= 0x86, /*134*/
+	SIGBOOST_EVENT_SYSTEM_RESTART			= 0x87, /*135*/
+	SIGBOOST_EVENT_SYSTEM_RESTART_ACK		= 0x88, /*136*/
+       /* CALL_RELEASED is aimed to fix a race condition that became obvious
+        * when the boost socket was replaced by direct function calls
+        * and the channel hunting was moved to freetdm, the problem is
+        * we can get CALL_STOPPED msg and reply with CALL_STOPPED_ACK
+        * but the signaling module will still (in PRI) send RELEASE and
+        * wait for RELEASE_COMPLETE from the isdn network before
+        * marking the channel as available, therefore freetdm should
+        * also not mark the channel as available until CALL_RELEASED
+        * is received, for socket mode we can continue working as usual
+        * with CALL_STOPPED being the last step because the hunting is
+        * done in the signaling module.
+	*
+	* CALL_RELEASED is only used in queue mode 
+        * */
+	SIGBOOST_EVENT_CALL_RELEASED                    = 0x51, /* 81 */
+	SIGBOOST_EVENT_CALL_PROGRESS            	= 0x50, /*decimal  80*/
+	/* Following IDs are ss7boost to sangoma_mgd only. */
+	SIGBOOST_EVENT_HEARTBEAT			= 0x89, /*137*/
+	SIGBOOST_EVENT_INSERT_CHECK_LOOP		= 0x8a, /*138*/
+	SIGBOOST_EVENT_REMOVE_CHECK_LOOP		= 0x8b, /*139*/
+	SIGBOOST_EVENT_AUTO_CALL_GAP_ABATE		= 0x8c, /*140*/
+	SIGBOOST_EVENT_DIGIT_IN					= 0x8d, /*141*/
+};
+enum	e_sigboost_release_cause_values
+{
+	SIGBOOST_RELEASE_CAUSE_UNDEFINED		= 0,
+	SIGBOOST_RELEASE_CAUSE_NORMAL			= 16,
+	/* probable elimination */
+	//SIGBOOST_RELEASE_CAUSE_BUSY			= 0x91, /* 145 */
+	//SIGBOOST_RELEASE_CAUSE_CALLED_NOT_EXIST	= 0x92, /* 146 */
+	//SIGBOOST_RELEASE_CAUSE_CIRCUIT_RESET		= 0x93, /* 147 */
+	//SIGBOOST_RELEASE_CAUSE_NOANSWER		= 0x94, /* 148 */
+};
+
+enum	e_sigboost_call_setup_ack_nack_cause_values
+{
+	//SIGBOOST_CALL_SETUP_NACK_ALL_CKTS_BUSY		= 34,  /* Q.850 value - don't use */
+	SIGBOOST_CALL_SETUP_NACK_ALL_CKTS_BUSY		= 117,  /* non Q.850 value indicates local all ckt busy 
+								   causing sangoma_mgd to perform automatic call 
+								   gapping*/
+	SIGBOOST_CALL_SETUP_NACK_TEST_CKT_BUSY		= 17,  /* Q.850 value */
+	SIGBOOST_CALL_SETUP_NACK_INVALID_NUMBER		= 28,  /* Q.850 value */
+	SIGBOOST_CALL_SETUP_CSUPID_DBL_USE		= 200, /* unused Q.850 value */
+};
+
+
+enum	e_sigboost_huntgroup_values
+{
+	SIGBOOST_HUNTGRP_SEQ_ASC	= 0x00, /* sequential with lowest available first */
+	SIGBOOST_HUNTGRP_SEQ_DESC	= 0x01, /* sequential with highest available first */
+	SIGBOOST_HUNTGRP_RR_ASC		= 0x02, /* round-robin with lowest available first */
+	SIGBOOST_HUNTGRP_RR_DESC	= 0x03, /* round-robin with highest available first */
+};
+
+enum e_sigboost_event_info_par_values
+{
+  	SIGBOOST_EVI_SPARE 				   	 	= 0x00, 
+  	SIGBOOST_EVI_ALERTING 					= 0x01, 
+  	SIGBOOST_EVI_PROGRESS 					= 0x02, 
+};
+
+enum e_sigboost_progress_flags
+{
+	SIGBOOST_PROGRESS_RING = (1 << 0),
+	SIGBOOST_PROGRESS_MEDIA = (1 << 1)
+};
+
+#define MAX_DIALED_DIGITS	31
+
+/* Next two defines are used to create the range of values for call_setup_id
+ * in the t_sigboost structure.
+ * 0..((CORE_MAX_SPANS * CORE_MAX_CHAN_PER_SPAN) - 1) */
+#define CORE_MAX_SPANS 		200
+#define CORE_MAX_CHAN_PER_SPAN 	32
+#define MAX_PENDING_CALLS 	CORE_MAX_SPANS * CORE_MAX_CHAN_PER_SPAN
+/* 0..(MAX_PENDING_CALLS-1) is range of call_setup_id below */
+
+/* Should only be used by server */
+#define MAX_CALL_SETUP_ID   0xFFFF
+
+#define SIZE_CUSTOM	900
+#define SIZE_RDNIS  SIZE_CUSTOM
+
+
+#pragma pack(1)
+
+typedef struct
+{
+	uint8_t			capability;
+	uint8_t			uil1p;
+} t_sigboost_bearer;
+
+typedef struct
+{
+	uint8_t			digits_count;
+	char			digits [MAX_DIALED_DIGITS + 1]; /* it's a null terminated string */
+	uint8_t 		npi;
+	uint8_t 		ton;
+	uint8_t			screening_ind;
+	uint8_t			presentation_ind;
+}t_sigboost_digits;
+
+typedef struct
+{
+	uint16_t		version;
+	uint32_t		event_id;
+	/* delete sequence numbers - SCTP does not need them */
+	uint32_t		fseqno;
+	uint32_t		bseqno;
+	uint16_t		call_setup_id;
+	uint32_t		trunk_group;
+	uint8_t			span;
+	uint8_t			chan;
+	uint32_t		flags;
+	/* struct timeval  	tv; */ 
+	t_sigboost_digits called;
+	t_sigboost_digits calling;
+	t_sigboost_digits rdnis;
+	/* ref. Q.931 Table 4-11 and Q.951 Section 3 */
+	char			calling_name[MAX_DIALED_DIGITS + 1];
+	t_sigboost_bearer 	bearer;
+	uint8_t			hunt_group;
+	uint16_t		custom_data_size;
+	char			custom_data[SIZE_CUSTOM]; /* it's a null terminated string */
+
+} t_sigboost_callstart;
+
+#define called_number_digits_count		called.digits_count
+#define called_number_digits			called.digits
+#define calling_number_digits_count		calling.digits_count
+#define calling_number_digits			calling.digits
+#define calling_number_screening_ind	calling.screening_ind
+#define calling_number_presentation		calling.presentation_ind
+
+#define isup_in_rdnis_size				custom_data_size
+#define isup_in_rdnis					custom_data
+
+
+#define MIN_SIZE_CALLSTART_MSG  sizeof(t_sigboost_callstart) - SIZE_CUSTOM
+
+typedef struct
+{
+	uint16_t		version;
+	uint32_t		event_id;
+	/* delete sequence numbers - SCTP does not need them */
+	uint32_t		fseqno;
+	uint32_t		bseqno;
+	uint16_t		call_setup_id;
+	uint32_t		trunk_group;
+	uint8_t			span;
+	uint8_t			chan;
+	uint32_t		flags;
+	/* struct timeval  	tv; */ 
+	uint8_t			release_cause;
+} t_sigboost_short;
+#pragma pack()
+
+
+static inline int boost_full_event(int event_id)
+{
+        switch (event_id) {
+        case SIGBOOST_EVENT_CALL_START:
+        case SIGBOOST_EVENT_DIGIT_IN:
+	case SIGBOOST_EVENT_CALL_PROGRESS:
+                return 1;
+        default:
+                break;
+        }
+
+        return 0;
+}
+
+#endif

Added: freeswitch/trunk/libs/openzap/src/ozmod/ozmod_sangoma_boost/zap_sangoma_boost.h (0 => 17141)


--- freeswitch/trunk/libs/openzap/src/ozmod/ozmod_sangoma_boost/zap_sangoma_boost.h	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/src/ozmod/ozmod_sangoma_boost/zap_sangoma_boost.h	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2007, Anthony Minessale II
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ZAP_SANGOMA_BOOST_H
+#define ZAP_SANGOMA_BOOST_H
+#include "sangoma_boost_client.h"
+#include "openzap.h"
+
+typedef enum {
+	ZAP_SANGOMA_BOOST_RUNNING = (1 << 0),
+	ZAP_SANGOMA_BOOST_RESTARTING = (1 << 1)
+} zap_sangoma_boost_flag_t;
+
+typedef struct zap_sangoma_boost_data {
+	sangomabc_connection_t mcon;
+	sangomabc_connection_t pcon;
+	uint32_t flags;
+} zap_sangoma_boost_data_t;
+
+#endif
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
+

Added: freeswitch/trunk/libs/openzap/src/ozmod/ozmod_skel/ozmod_skel.c (0 => 17141)


--- freeswitch/trunk/libs/openzap/src/ozmod/ozmod_skel/ozmod_skel.c	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/src/ozmod/ozmod_skel/ozmod_skel.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,152 @@
+/*
+ * Copyright (c) 2007, Anthony Minessale II
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#include "openzap.h"
+//#include "zap_skel.h"
+
+static ZIO_CONFIGURE_FUNCTION(skel_configure)
+{
+	return ZAP_FAIL;
+}
+
+static ZIO_CONFIGURE_SPAN_FUNCTION(skel_configure_span)
+{
+	return ZAP_FAIL;
+}
+
+static ZIO_OPEN_FUNCTION(skel_open) 
+{
+	return ZAP_FAIL;
+}
+
+static ZIO_CLOSE_FUNCTION(skel_close)
+{
+	return ZAP_FAIL;
+}
+
+static ZIO_WAIT_FUNCTION(skel_wait)
+{
+	return ZAP_FAIL;
+}
+
+static ZIO_READ_FUNCTION(skel_read)
+{
+	return ZAP_FAIL;
+}
+
+static ZIO_WRITE_FUNCTION(skel_write)
+{
+	return ZAP_FAIL;
+}
+
+static ZIO_COMMAND_FUNCTION(skel_command)
+{
+	return ZAP_FAIL;
+}
+
+static ZIO_SPAN_POLL_EVENT_FUNCTION(skel_poll_event)
+{
+	return ZAP_FAIL;
+}
+
+static ZIO_SPAN_NEXT_EVENT_FUNCTION(skel_next_event)
+{
+	return ZAP_FAIL;
+}
+
+static ZIO_CHANNEL_DESTROY_FUNCTION(skel_channel_destroy)
+{
+	return ZAP_FAIL;
+}
+
+static ZIO_SPAN_DESTROY_FUNCTION(skel_span_destroy)
+{
+	return ZAP_FAIL;
+}
+
+static ZIO_GET_ALARMS_FUNCTION(skel_get_alarms)
+{
+	return ZAP_FAIL;
+}
+
+static zap_io_interface_t skel_interface;
+
+static ZIO_IO_LOAD_FUNCTION(skel_init)
+{
+	assert(zio != NULL);
+	memset(&skel_interface, 0, sizeof(skel_interface));
+
+	skel_interface.name = "skel";
+	skel_interface.configure =  skel_configure;
+	skel_interface.configure_span =  skel_configure_span;
+	skel_interface.open = skel_open;
+	skel_interface.close = skel_close;
+	skel_interface.wait = skel_wait;
+	skel_interface.read = skel_read;
+	skel_interface.write = skel_write;
+	skel_interface.command = skel_command;
+	skel_interface.poll_event = skel_poll_event;
+	skel_interface.next_event = skel_next_event;
+	skel_interface.channel_destroy = skel_channel_destroy;
+	skel_interface.span_destroy = skel_span_destroy;
+	skel_interface.get_alarms = skel_get_alarms;
+	*zio = &skel_interface;
+
+	return ZAP_SUCCESS;
+}
+
+static ZIO_IO_UNLOAD_FUNCTION(skel_destroy)
+{
+	return ZAP_SUCCESS;
+}
+
+
+zap_module_t zap_module = { 
+	"skel",
+	skel_init,
+	skel_destroy,
+};
+
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
+

Added: freeswitch/trunk/libs/openzap/src/ozmod/ozmod_wanpipe/ozmod_wanpipe.2005.vcproj (0 => 17141)


--- freeswitch/trunk/libs/openzap/src/ozmod/ozmod_wanpipe/ozmod_wanpipe.2005.vcproj	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/src/ozmod/ozmod_wanpipe/ozmod_wanpipe.2005.vcproj	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,196 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="8.00"
+	Name="ozmod_wanpipe"
+	ProjectGUID="{1A145EE9-BBD8-45E5-98CD-EB4BE99E1DCD}"
+	RootNamespace="ozmod_wanpipe"
+	Keyword="Win32Proj"
+	TargetFrameworkVersion="131072"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="2"
+			CharacterSet="2"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				AdditionalIncludeDirectories="../../../src/include;../../../src/isdn/include;../../../wanpipe/include"
+				PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;"
+				MinimalRebuild="true"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="3"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				Detect64BitPortabilityProblems="true"
+				DebugInformationFormat="4"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="openzap.lib libsangoma.lib"
+				LinkIncremental="2"
+				AdditionalLibraryDirectories="&quot;$(OutDir)&quot;;../../../wanpipe/api/lib/x86"
+				GenerateDebugInformation="true"
+				SubSystem="1"
+				RandomizedBaseAddress="1"
+				DataExecutionPrevention="0"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="2"
+			CharacterSet="2"
+			WholeProgramOptimization="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalIncludeDirectories="../../../src/include;../../../src/isdn/include;../../../wanpipe/include"
+				PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
+				RuntimeLibrary="2"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				Detect64BitPortabilityProblems="true"
+				DebugInformationFormat="3"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="openzap.lib libsangoma.lib"
+				LinkIncremental="1"
+				AdditionalLibraryDirectories="&quot;$(OutDir)&quot;;../../../wanpipe/api/lib/x86"
+				GenerateDebugInformation="true"
+				SubSystem="1"
+				OptimizeReferences="2"
+				EnableCOMDATFolding="2"
+				RandomizedBaseAddress="1"
+				DataExecutionPrevention="0"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<Filter
+			Name="Source Files"
+			Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+			>
+			<File
+				RelativePath=".\ozmod_wanpipe.c"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="Header Files"
+			Filter="h;hpp;hxx;hm;inl;inc;xsd"
+			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+			>
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>

Added: freeswitch/trunk/libs/openzap/src/ozmod/ozmod_wanpipe/ozmod_wanpipe.2008.vcproj (0 => 17141)


--- freeswitch/trunk/libs/openzap/src/ozmod/ozmod_wanpipe/ozmod_wanpipe.2008.vcproj	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/src/ozmod/ozmod_wanpipe/ozmod_wanpipe.2008.vcproj	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,355 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="9.00"
+	Name="ozmod_wanpipe"
+	ProjectGUID="{1A145EE9-BBD8-45E5-98CD-EB4BE99E1DCD}"
+	RootNamespace="ozmod_wanpipe"
+	Keyword="Win32Proj"
+	TargetFrameworkVersion="131072"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+		<Platform
+			Name="x64"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="2"
+			CharacterSet="2"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				AdditionalIncludeDirectories="../../../src/include;../../../src/isdn/include;../../../wanpipe/include"
+				PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;"
+				MinimalRebuild="true"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="3"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				Detect64BitPortabilityProblems="true"
+				DebugInformationFormat="4"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="openzap.lib libsangoma.lib"
+				LinkIncremental="2"
+				AdditionalLibraryDirectories="&quot;$(OutDir)&quot;;../../../wanpipe/api/lib/x86"
+				GenerateDebugInformation="true"
+				SubSystem="1"
+				RandomizedBaseAddress="1"
+				DataExecutionPrevention="0"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Debug|x64"
+			OutputDirectory="$(SolutionDir)$(PlatformName)\$(ConfigurationName)"
+			IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+			ConfigurationType="2"
+			CharacterSet="2"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+				TargetEnvironment="3"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				AdditionalIncludeDirectories="../../../src/include;../../../src/isdn/include;../../../wanpipe/include"
+				PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;"
+				MinimalRebuild="true"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="3"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				Detect64BitPortabilityProblems="true"
+				DebugInformationFormat="3"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="openzap.lib libsangoma.lib"
+				LinkIncremental="2"
+				AdditionalLibraryDirectories="&quot;$(OutDir)&quot;;../../../wanpipe/api/lib/x64"
+				GenerateDebugInformation="true"
+				SubSystem="1"
+				RandomizedBaseAddress="1"
+				DataExecutionPrevention="0"
+				TargetMachine="17"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="2"
+			CharacterSet="2"
+			WholeProgramOptimization="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalIncludeDirectories="../../../src/include;../../../src/isdn/include;../../../wanpipe/include"
+				PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
+				RuntimeLibrary="2"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				Detect64BitPortabilityProblems="true"
+				DebugInformationFormat="3"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="openzap.lib libsangoma.lib"
+				LinkIncremental="1"
+				AdditionalLibraryDirectories="&quot;$(OutDir)&quot;;../../../wanpipe/api/lib/x86"
+				GenerateDebugInformation="true"
+				SubSystem="1"
+				OptimizeReferences="2"
+				EnableCOMDATFolding="2"
+				RandomizedBaseAddress="1"
+				DataExecutionPrevention="0"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|x64"
+			OutputDirectory="$(SolutionDir)$(PlatformName)\$(ConfigurationName)"
+			IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+			ConfigurationType="2"
+			CharacterSet="2"
+			WholeProgramOptimization="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+				TargetEnvironment="3"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalIncludeDirectories="../../../src/include;../../../src/isdn/include;../../../wanpipe/include"
+				PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
+				RuntimeLibrary="2"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				Detect64BitPortabilityProblems="true"
+				DebugInformationFormat="3"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="openzap.lib libsangoma.lib"
+				LinkIncremental="1"
+				AdditionalLibraryDirectories="&quot;$(OutDir)&quot;;../../../wanpipe/api/lib/x64"
+				GenerateDebugInformation="true"
+				SubSystem="1"
+				OptimizeReferences="2"
+				EnableCOMDATFolding="2"
+				RandomizedBaseAddress="1"
+				DataExecutionPrevention="0"
+				TargetMachine="17"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<Filter
+			Name="Source Files"
+			Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+			>
+			<File
+				RelativePath=".\ozmod_wanpipe.c"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="Header Files"
+			Filter="h;hpp;hxx;hm;inl;inc;xsd"
+			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+			>
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>

Added: freeswitch/trunk/libs/openzap/src/ozmod/ozmod_wanpipe/ozmod_wanpipe.c (0 => 17141)


--- freeswitch/trunk/libs/openzap/src/ozmod/ozmod_wanpipe/ozmod_wanpipe.c	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/src/ozmod/ozmod_wanpipe/ozmod_wanpipe.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,1235 @@
+/*
+ * Copyright (c) 2007, Anthony Minessale II
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifdef __sun
+#include <unistd.h>
+#include <stropts.h>
+#endif
+#include "openzap.h"
+#ifndef __WINDOWS__
+#include <poll.h>
+#include <sys/socket.h>
+#endif
+#include "libsangoma.h"
+
+#if defined(__WINDOWS__)
+/* remove this when http://jira.freeswitch.org/browse/FSBUILD-259 wanpipe issue is fixed */
+#define WINDOWS_BUILD_BROKEN 1
+/*! Backward compatible defines - current code is all using the old names*/ 
+#define sangoma_open_tdmapi_span_chan sangoma_open_api_span_chan
+#define sangoma_open_tdmapi_span sangoma_open_api_span
+#define sangoma_open_tdmapi_ctrl sangoma_open_api_ctrl
+#define sangoma_tdm_get_fe_status sangoma_get_fe_status
+#define sangoma_socket_close sangoma_close
+#define sangoma_tdm_get_hw_coding sangoma_get_hw_coding
+#define sangoma_tdm_set_fe_status sangoma_set_fe_status
+#define sangoma_tdm_get_link_status sangoma_get_link_status
+#define sangoma_tdm_flush_bufs sangoma_flush_bufs
+#define sangoma_tdm_cmd_exec sangoma_cmd_exec
+#define sangoma_tdm_read_event sangoma_read_event
+#define sangoma_readmsg_tdm sangoma_readmsg
+#define sangoma_readmsg_socket sangoma_readmsg
+#define sangoma_sendmsg_socket sangoma_writemsg
+#define sangoma_writemsg_tdm sangoma_writemsg
+#define sangoma_create_socket_intr sangoma_open_api_span_chan
+#endif
+
+/*! Starting with libsangoma 3 we can use the new libsangoma waitable API, the poor souls of those using a release were LIBSANGOMA version
+ * is defined but the version is not higher or equal to 3.0.0 will be forced to upgrade
+ * */
+#ifdef LIBSANGOMA_VERSION 
+#if LIBSANGOMA_VERSION_CODE < LIBSANGOMA_VERSION(3,0,0)
+#undef LIBSANGOMA_VERSION
+#endif
+#endif
+
+/**
+ * \brief Wanpipe flags
+ */
+typedef enum {
+	WP_RINGING = (1 << 0)
+} wp_flag_t;
+
+/**
+ * \brief Wanpipe globals
+ */
+static struct {
+	uint32_t codec_ms;
+	uint32_t wink_ms;
+	uint32_t flash_ms;
+	uint32_t ring_on_ms;
+	uint32_t ring_off_ms;
+} wp_globals;
+
+/* a bunch of this stuff should go into the wanpipe_tdm_api_iface.h */
+
+ZIO_SPAN_POLL_EVENT_FUNCTION(wanpipe_poll_event);
+ZIO_SPAN_NEXT_EVENT_FUNCTION(wanpipe_next_event);
+
+#define WP_INVALID_SOCKET -1 
+
+/**
+ * \brief Poll for event on a wanpipe socket
+ * \param fd Wanpipe socket descriptor
+ * \param timeout Time to wait for event
+ * \param flags Sangoma event flags
+ * \return -1 on failure, wanpipe event flags on success
+ *
+ * a cross platform way to poll on an actual pollset (span and/or list of spans) will probably also be needed for analog
+ * so we can have one analong handler thread that will deal with all the idle analog channels for events
+ * the alternative would be for the driver to provide one socket for all of the oob events for all analog channels
+ */
+static __inline__ int tdmv_api_wait_socket(zap_channel_t *zchan, int timeout, int *flags)
+{
+	
+#ifdef LIBSANGOMA_VERSION
+	int err;
+    uint32_t inflags = *flags;
+    uint32_t outflags = 0;
+	sangoma_wait_obj_t *sangoma_wait_obj = zchan->mod_data;
+
+	err = sangoma_waitfor(sangoma_wait_obj, inflags, &outflags, timeout);
+	*flags = 0;
+    if (err == SANG_STATUS_SUCCESS) {
+        *flags = outflags;
+        err = 1; /* ideally should be the number of file descriptors with something to read */
+    }
+    if (err == SANG_STATUS_APIPOLL_TIMEOUT) {
+        err = 0;
+    }
+    return err;
+#else
+ 	struct pollfd pfds[1];
+    int res;
+
+    memset(&pfds[0], 0, sizeof(pfds[0]));
+    pfds[0].fd = zchan->sockfd;
+    pfds[0].events = *flags;
+    res = poll(pfds, 1, timeout);
+	*flags = 0;
+
+	if (pfds[0].revents & POLLERR) {
+		res = -1;
+	}
+
+	if (res > 0) {
+		*flags = pfds[0].revents;
+	}
+
+    return res;
+#endif
+	
+}
+
+/**
+ * \brief Opens a sangoma channel socket (TDM API)
+ * \param span Span number
+ * \param chan Channel number
+ * \return 0 on success, wanpipe error code on failure
+ */
+static __inline__ sng_fd_t tdmv_api_open_span_chan(int span, int chan) 
+{
+	return sangoma_open_tdmapi_span_chan(span, chan);
+}
+
+#ifdef LIBSANGOMA_VERSION
+static __inline__ sng_fd_t __tdmv_api_open_span_chan(int span, int chan) 
+{ 
+	return  __sangoma_open_tdmapi_span_chan(span, chan);
+}                        
+#endif
+
+static zap_io_interface_t wanpipe_interface;
+
+/**
+ * \brief Inverts bit string
+ * \param cas_bits CAS bit string
+ * \return Swapped bits
+ */
+static unsigned char wanpipe_swap_bits(unsigned char cas_bits)
+{
+	unsigned char swapped_bits = 0x0;
+	if (cas_bits & 0x8) {
+		swapped_bits |= 0x1;
+	}
+	if (cas_bits & 0x4) {
+		swapped_bits |= 0x2;
+	}
+	if (cas_bits & 0x2) {
+		swapped_bits |= 0x4;
+	}
+	if (cas_bits & 0x1) {
+		swapped_bits |= 0x8;
+	}
+	return swapped_bits;
+}
+
+/**
+ * \brief Initialises a range of wanpipe channels
+ * \param span Openzap span
+ * \param spanno Wanpipe span number
+ * \param start Initial wanpipe channel number
+ * \param end Final wanpipe channel number
+ * \param type Openzap channel type
+ * \param name Openzap span name
+ * \param number Openzap span number
+ * \param cas_bits CAS bits
+ * \return number of spans configured
+ */
+static unsigned wp_open_range(zap_span_t *span, unsigned spanno, unsigned start, unsigned end, zap_chan_type_t type, char *name, char *number, unsigned char cas_bits)
+{
+	unsigned configured = 0, x;
+#ifdef LIBSANGOMA_VERSION
+	sangoma_status_t sangstatus;
+	sangoma_wait_obj_t *sangoma_wait_obj;
+#endif
+
+	if (type == ZAP_CHAN_TYPE_CAS) {
+		zap_log(ZAP_LOG_DEBUG, "Configuring Wanpipe CAS channels with abcd == 0x%X\n", cas_bits);
+	}	
+	for(x = start; x < end; x++) {
+		zap_channel_t *chan;
+		zap_socket_t sockfd = WP_INVALID_SOCKET;
+		const char *dtmf = "none";
+		if (!strncasecmp(span->name, "smg_prid_nfas", 8) && span->trunk_type == ZAP_TRUNK_T1 && x == 24) {
+#ifdef LIBSANGOMA_VERSION
+			sockfd = __tdmv_api_open_span_chan(spanno, x);
+#else
+			zap_log(ZAP_LOG_ERROR, "span %d channel %d cannot be configured as smg_prid_nfas, you need to compile openzap with newer libsangoma\n", spanno, x);
+#endif
+		} else {
+			sockfd = tdmv_api_open_span_chan(spanno, x);
+		}
+
+		if (sockfd == WP_INVALID_SOCKET) {
+			zap_log(ZAP_LOG_ERROR, "Failed to open wanpipe device span %d channel %d\n", spanno, x);
+			continue;
+		}
+		
+		if (zap_span_add_channel(span, sockfd, type, &chan) == ZAP_SUCCESS) {
+			wanpipe_tdm_api_t tdm_api;
+			memset(&tdm_api, 0, sizeof(tdm_api));
+#ifdef LIBSANGOMA_VERSION
+			sangstatus = sangoma_wait_obj_create(&sangoma_wait_obj, sockfd, SANGOMA_DEVICE_WAIT_OBJ);
+			if (sangstatus != SANG_STATUS_SUCCESS) {
+				zap_log(ZAP_LOG_ERROR, "failure create waitable object for s%dc%d\n", spanno, x);
+				continue;
+			}
+			chan->mod_data = sangoma_wait_obj;
+#endif
+			
+			chan->physical_span_id = spanno;
+			chan->physical_chan_id = x;
+			chan->rate = 8000;
+			
+			if (type == ZAP_CHAN_TYPE_FXS || type == ZAP_CHAN_TYPE_FXO || type == ZAP_CHAN_TYPE_B) {
+				int err;
+				
+				dtmf = "software";
+
+				/* FIXME: Handle Error Condition Check for return code */
+				err = sangoma_tdm_get_hw_coding(chan->sockfd, &tdm_api);
+
+				if (tdm_api.wp_tdm_cmd.hw_tdm_coding) {
+					chan->native_codec = chan->effective_codec = ZAP_CODEC_ALAW;
+				} else {
+					chan->native_codec = chan->effective_codec = ZAP_CODEC_ULAW;
+				}
+
+				err = sangoma_tdm_get_hw_dtmf(chan->sockfd, &tdm_api);
+				if (err > 0) {
+					err = sangoma_tdm_enable_dtmf_events(chan->sockfd, &tdm_api);
+					if (err == 0) {
+						zap_channel_set_feature(chan, ZAP_CHANNEL_FEATURE_DTMF_DETECT);
+						dtmf = "hardware";
+					}
+				}
+			}
+
+#ifdef LIBSANGOMA_VERSION
+			if (type == ZAP_CHAN_TYPE_FXS) {
+				if (sangoma_tdm_disable_ring_trip_detect_events(chan->sockfd, &tdm_api)) {
+					/* we had problems of on-hook/off-hook detection due to how ring trip events were handled
+					 * if this fails, I believe we will still work ok as long as we dont handle them incorrectly */
+					zap_log(ZAP_LOG_WARNING, "Failed to disable ring trip events in channel s%dc%d\n", spanno, x);
+				}
+			}
+#endif
+#if 0
+            if (type == ZAP_CHAN_TYPE_FXS || type == ZAP_CHAN_TYPE_FXO) {
+                /* Enable FLASH/Wink Events */
+                int err=sangoma_set_rm_rxflashtime(chan->sockfd, &tdm_api, wp_globals.flash_ms);
+                if (err == 0) {
+			        zap_log(ZAP_LOG_ERROR, "flash enabled s%dc%d\n", spanno, x);
+                } else {
+			        zap_log(ZAP_LOG_ERROR, "flash disabled s%dc%d\n", spanno, x);
+                }
+            }
+#endif
+
+			if (type == ZAP_CHAN_TYPE_CAS || type == ZAP_CHAN_TYPE_EM) {
+#ifdef LIBSANGOMA_VERSION
+				sangoma_tdm_write_rbs(chan->sockfd,&tdm_api,chan->physical_chan_id, wanpipe_swap_bits(cas_bits));
+
+				/* this should probably be done for old libsangoma but I am not sure if the API is available and I'm lazy to check,
+				   The poll rate is hard coded to 100 per second (done in the driver, is the max rate of polling allowed by wanpipe)
+				 */
+				if (sangoma_tdm_enable_rbs_events(chan->sockfd, &tdm_api, 100)) {
+					zap_log(ZAP_LOG_ERROR, "Failed to enable RBS/CAS events in device %d:%d fd:%d\n", chan->span_id, chan->chan_id, sockfd);
+					continue;
+				}
+				/* probably done by the driver but lets write defensive code this time */
+				sangoma_flush_bufs(chan->sockfd, &tdm_api);
+#else
+				/* 
+				 * With wanpipe 3.4.4.2 I get failure even though the events are enabled, /var/log/messages said:
+				 * wanpipe4: WARNING: Event type 9 is already pending!
+				 * wanpipe4: Failed to add new fe event 09 ch_map=FFFFFFFF!
+				 * may be we should not send an error until that is fixed in the driver
+				 */
+				if (sangoma_tdm_enable_rbs_events(chan->sockfd, &tdm_api, 100)) {
+					zap_log(ZAP_LOG_ERROR, "Failed to enable RBS/CAS events in device %d:%d fd:%d\n", chan->span_id, chan->chan_id, sockfd);
+				}
+				/* probably done by the driver but lets write defensive code this time */
+				sangoma_tdm_flush_bufs(chan->sockfd, &tdm_api);
+				sangoma_tdm_write_rbs(chan->sockfd,&tdm_api, wanpipe_swap_bits(cas_bits));
+#endif
+			}
+			
+			if (!zap_strlen_zero(name)) {
+				zap_copy_string(chan->chan_name, name, sizeof(chan->chan_name));
+			}
+
+			if (!zap_strlen_zero(number)) {
+				zap_copy_string(chan->chan_number, number, sizeof(chan->chan_number));
+			}
+			configured++;
+			zap_log(ZAP_LOG_INFO, "configuring device s%dc%d as OpenZAP device %d:%d fd:%d DTMF: %s\n",
+				spanno, x, chan->span_id, chan->chan_id, sockfd, dtmf);
+
+		} else {
+			zap_log(ZAP_LOG_ERROR, "zap_span_add_channel failed for wanpipe span %d channel %d\n", spanno, x);
+		}
+	}
+	
+	return configured;
+}
+
+/**
+ * \brief Process configuration variable for a Wanpipe profile
+ * \param category Wanpipe profile name
+ * \param var Variable name
+ * \param val Variable value
+ * \param lineno Line number from configuration file
+ * \return Success
+ */
+static ZIO_CONFIGURE_FUNCTION(wanpipe_configure)
+{
+	int num;
+
+	if (!strcasecmp(category, "defaults")) {
+		if (!strcasecmp(var, "codec_ms")) {
+			num = atoi(val);
+			if (num < 10 || num > 60) {
+				zap_log(ZAP_LOG_WARNING, "invalid codec ms at line %d\n", lineno);
+			} else {
+				wp_globals.codec_ms = num;
+			}
+		} else if (!strcasecmp(var, "wink_ms")) {
+			num = atoi(val);
+			if (num < 50 || num > 3000) {
+				zap_log(ZAP_LOG_WARNING, "invalid wink ms at line %d\n", lineno);
+			} else {
+				wp_globals.wink_ms = num;
+			}
+		} else if (!strcasecmp(var, "flash_ms")) {
+			num = atoi(val);
+			if (num < 50 || num > 3000) {
+				zap_log(ZAP_LOG_WARNING, "invalid flash ms at line %d\n", lineno);
+			} else {
+				wp_globals.flash_ms = num;
+			}
+		} else if (!strcasecmp(var, "ring_on_ms")) {
+			num = atoi(val);
+			if (num < 500 || num > 5000) {
+				zap_log(ZAP_LOG_WARNING, "invalid ring_on_ms at line %d (valid range 500 to 5000)\n", lineno);
+			} else {
+				wp_globals.ring_on_ms = num;
+			}
+		} else if (!strcasecmp(var, "ring_off_ms")) {
+			num = atoi(val);
+			if (num < 500 || num > 5000) {
+				zap_log(ZAP_LOG_WARNING, "invalid ring_off_ms at line %d (valid range 500 to 5000)\n", lineno);
+			} else {
+				wp_globals.ring_off_ms = num;
+			}
+		}
+	}
+
+	return ZAP_SUCCESS;
+}
+
+/**
+ * \brief Initialises an openzap Wanpipe span from a configuration string
+ * \param span Openzap span
+ * \param str Configuration string
+ * \param type Openzap span type
+ * \param name Openzap span name
+ * \param number Openzap span number
+ * \return Success or failure
+ */
+static ZIO_CONFIGURE_SPAN_FUNCTION(wanpipe_configure_span)
+{
+	int items, i;
+	char *mydata, *item_list[10];
+	char *sp, *ch, *mx;
+	unsigned char cas_bits = 0;
+	int channo;
+	int spanno;
+	int top = 0;
+	unsigned configured = 0;
+
+	assert(str != NULL);
+	
+
+	mydata = strdup(str);
+	assert(mydata != NULL);
+
+
+	items = zap_separate_string(mydata, ',', item_list, (sizeof(item_list) / sizeof(item_list[0])));
+
+	for(i = 0; i < items; i++) {
+		sp = item_list[i];
+		if ((ch = strchr(sp, ':'))) {
+			*ch++ = '\0';
+		}
+
+		if (!(sp && ch)) {
+			zap_log(ZAP_LOG_ERROR, "No valid wanpipe span and channel was specified\n");
+			continue;
+		}
+
+		channo = atoi(ch);
+		spanno = atoi(sp);
+
+		if (channo < 0) {
+			zap_log(ZAP_LOG_ERROR, "Invalid channel number %d\n", channo);
+			continue;
+		}
+
+		if (spanno < 0) {
+			zap_log(ZAP_LOG_ERROR, "Invalid span number %d\n", channo);
+			continue;
+		}
+		
+		if ((mx = strchr(ch, '-'))) {
+			mx++;
+			top = atoi(mx) + 1;
+		} else {
+			top = channo + 1;
+		}
+		
+		
+		if (top < 0) {
+			zap_log(ZAP_LOG_ERROR, "Invalid range number %d\n", top);
+			continue;
+		}
+		if (ZAP_CHAN_TYPE_CAS == type && zap_config_get_cas_bits(ch, &cas_bits)) {
+			zap_log(ZAP_LOG_ERROR, "Failed to get CAS bits in CAS channel\n");
+			continue;
+		}
+		configured += wp_open_range(span, spanno, channo, top, type, name, number, cas_bits);
+
+	}
+	
+	free(mydata);
+
+	return configured;
+}
+
+/**
+ * \brief Opens Wanpipe channel
+ * \param zchan Channel to open
+ * \return Success or failure
+ */
+static ZIO_OPEN_FUNCTION(wanpipe_open) 
+{
+
+	wanpipe_tdm_api_t tdm_api;
+
+	memset(&tdm_api,0,sizeof(tdm_api));
+	sangoma_tdm_flush_bufs(zchan->sockfd, &tdm_api);
+#ifdef LIBSANGOMA_VERSION
+	sangoma_flush_event_bufs(zchan->sockfd, &tdm_api);
+#endif
+
+	if (zchan->type == ZAP_CHAN_TYPE_DQ921 || zchan->type == ZAP_CHAN_TYPE_DQ931) {
+		zchan->native_codec = zchan->effective_codec = ZAP_CODEC_NONE;
+	} else {
+		zchan->effective_codec = zchan->native_codec;
+		
+		sangoma_tdm_set_usr_period(zchan->sockfd, &tdm_api, wp_globals.codec_ms);
+
+		zap_channel_set_feature(zchan, ZAP_CHANNEL_FEATURE_INTERVAL);
+		zchan->effective_interval = zchan->native_interval = wp_globals.codec_ms;
+		zchan->packet_len = zchan->native_interval * 8;
+	}
+
+	return ZAP_SUCCESS;
+}
+
+/**
+ * \brief Closes Wanpipe channel
+ * \param zchan Channel to close
+ * \return Success
+ */
+static ZIO_CLOSE_FUNCTION(wanpipe_close)
+{
+	return ZAP_SUCCESS;
+}
+
+/**
+ * \brief Executes an Openzap command on a Wanpipe channel
+ * \param zchan Channel to execute command on
+ * \param command Openzap command to execute
+ * \param obj Object (unused)
+ * \return Success or failure
+ */
+static ZIO_COMMAND_FUNCTION(wanpipe_command)
+{
+	wanpipe_tdm_api_t tdm_api;
+	int err = 0;
+
+	memset(&tdm_api, 0, sizeof(tdm_api));
+
+	switch(command) {
+	case ZAP_COMMAND_OFFHOOK:
+		{
+			err=sangoma_tdm_txsig_offhook(zchan->sockfd,&tdm_api);
+			if (err) {
+				snprintf(zchan->last_error, sizeof(zchan->last_error), "OFFHOOK Failed");
+				return ZAP_FAIL;
+			}
+			zap_set_flag_locked(zchan, ZAP_CHANNEL_OFFHOOK);
+		}
+		break;
+	case ZAP_COMMAND_ONHOOK:
+		{
+			err=sangoma_tdm_txsig_onhook(zchan->sockfd,&tdm_api);
+			if (err) {
+				snprintf(zchan->last_error, sizeof(zchan->last_error), "ONHOOK Failed");
+				return ZAP_FAIL;
+			}
+			zap_clear_flag_locked(zchan, ZAP_CHANNEL_OFFHOOK);
+		}
+		break;
+	case ZAP_COMMAND_GENERATE_RING_ON:
+		{
+			err=sangoma_tdm_txsig_start(zchan->sockfd,&tdm_api);
+			if (err) {
+				snprintf(zchan->last_error, sizeof(zchan->last_error), "Ring Failed");
+				return ZAP_FAIL;
+			}
+			zap_set_flag_locked(zchan, ZAP_CHANNEL_RINGING);
+			zap_set_pflag_locked(zchan, WP_RINGING);
+			zchan->ring_time = zap_current_time_in_ms() + wp_globals.ring_on_ms;
+		}
+		break;
+	case ZAP_COMMAND_GENERATE_RING_OFF:
+		{
+			err=sangoma_tdm_txsig_offhook(zchan->sockfd,&tdm_api);
+			if (err) {
+				snprintf(zchan->last_error, sizeof(zchan->last_error), "Ring-off Failed");
+				return ZAP_FAIL;
+			}
+			zap_clear_pflag_locked(zchan, WP_RINGING);
+			zap_clear_flag_locked(zchan, ZAP_CHANNEL_RINGING);
+		}
+		break;
+	case ZAP_COMMAND_GET_INTERVAL:
+		{
+			err=sangoma_tdm_get_usr_period(zchan->sockfd, &tdm_api);
+			if (err > 0 ) {
+				ZAP_COMMAND_OBJ_INT = err;
+				err=0;
+			}
+		}
+		break;
+	case ZAP_COMMAND_ENABLE_ECHOCANCEL:
+		{
+#ifndef WINDOWS_BUILD_BROKEN
+			err=sangoma_tdm_enable_hwec(zchan->sockfd, &tdm_api);
+			if (err) {
+             	snprintf(zchan->last_error, sizeof(zchan->last_error), "HWEC Enable Failed");
+				return ZAP_FAIL;
+			}
+#endif /* WINDOWS_BUILD_BROKEN */
+		}
+		break;
+	case ZAP_COMMAND_DISABLE_ECHOCANCEL:
+		{
+#ifndef WINDOWS_BUILD_BROKEN
+			err=sangoma_tdm_disable_hwec(zchan->sockfd, &tdm_api);
+			if (err) {
+             	snprintf(zchan->last_error, sizeof(zchan->last_error), "HWEC Disable Failed");
+				return ZAP_FAIL;
+			}
+#endif /* WINDOWS_BUILD_BROKEN */
+		}
+		break;
+	case ZAP_COMMAND_ENABLE_LOOP:
+		{
+#ifndef WINDOWS_BUILD_BROKEN
+#ifdef WP_API_FEATURE_LOOP
+         	err=sangoma_tdm_enable_loop(zchan->sockfd, &tdm_api);
+			if (err) {
+				snprintf(zchan->last_error, sizeof(zchan->last_error), "Loop Enable Failed");
+				return ZAP_FAIL;
+			}
+#endif		
+#endif /* WINDOWS_BUILD_BROKEN */
+		}
+	case ZAP_COMMAND_DISABLE_LOOP:
+		{
+#ifndef WINDOWS_BUILD_BROKEN
+#ifdef WP_API_FEATURE_LOOP
+         	err=sangoma_tdm_disable_loop(zchan->sockfd, &tdm_api);
+			if (err) {
+				snprintf(zchan->last_error, sizeof(zchan->last_error), "Loop Disable Failed");
+				return ZAP_FAIL;
+			}
+#endif	 
+#endif /* WINDOWS_BUILD_BROKEN */
+		}
+	case ZAP_COMMAND_SET_INTERVAL: 
+		{
+			err=sangoma_tdm_set_usr_period(zchan->sockfd, &tdm_api, ZAP_COMMAND_OBJ_INT);
+			zchan->packet_len = zchan->native_interval * (zchan->effective_codec == ZAP_CODEC_SLIN ? 16 : 8);
+		}
+		break;
+	case ZAP_COMMAND_SET_CAS_BITS:
+		{
+#ifdef LIBSANGOMA_VERSION
+			err = sangoma_tdm_write_rbs(zchan->sockfd,&tdm_api, zchan->physical_chan_id, wanpipe_swap_bits(ZAP_COMMAND_OBJ_INT));
+#else
+			err = sangoma_tdm_write_rbs(zchan->sockfd, &tdm_api, wanpipe_swap_bits(ZAP_COMMAND_OBJ_INT));
+#endif
+		}
+		break;
+	case ZAP_COMMAND_GET_CAS_BITS:
+		{
+#ifdef LIBSANGOMA_VERSION
+            unsigned char rbsbits;
+            err = sangoma_tdm_read_rbs(zchan->sockfd, &tdm_api, zchan->physical_chan_id, &rbsbits);
+            if (!err) {
+                ZAP_COMMAND_OBJ_INT = wanpipe_swap_bits(rbsbits);
+            }
+#else
+            // does sangoma_tdm_read_rbs is available here?
+			ZAP_COMMAND_OBJ_INT = zchan->rx_cas_bits;
+#endif
+		}
+		break;
+	default:
+		break;
+	};
+
+	if (err) {
+		snprintf(zchan->last_error, sizeof(zchan->last_error), "%s", strerror(errno));
+		return ZAP_FAIL;
+	}
+
+
+	return ZAP_SUCCESS;
+}
+
+/**
+ * \brief Reads data from a Wanpipe channel
+ * \param zchan Channel to read from
+ * \param data Data buffer
+ * \param datalen Size of data buffer
+ * \return Success, failure or timeout
+ */
+static ZIO_READ_FUNCTION(wanpipe_read)
+{
+	int rx_len = 0;
+	wp_tdm_api_rx_hdr_t hdrframe;
+
+	memset(&hdrframe, 0, sizeof(hdrframe));
+
+	rx_len = sangoma_readmsg_tdm(zchan->sockfd, &hdrframe, (int)sizeof(hdrframe), data, (int)*datalen,0);
+	*datalen = rx_len;
+
+	if (rx_len == 0 || rx_len == -17) {
+		return ZAP_TIMEOUT;
+	}
+
+	if (rx_len < 0) {
+		snprintf(zchan->last_error, sizeof(zchan->last_error), "%s", strerror(errno));
+		return ZAP_FAIL;
+	} 
+
+
+	return ZAP_SUCCESS;
+}
+
+/**
+ * \brief Writes data to a Wanpipe channel
+ * \param zchan Channel to write to
+ * \param data Data buffer
+ * \param datalen Size of data buffer
+ * \return Success or failure
+ */
+static ZIO_WRITE_FUNCTION(wanpipe_write)
+{
+	int bsent;
+	wp_tdm_api_tx_hdr_t hdrframe;
+
+	/* Do we even need the headerframe here? on windows, we don't even pass it to the driver */
+	memset(&hdrframe, 0, sizeof(hdrframe));
+	if (*datalen == 0) {
+		return ZAP_SUCCESS;
+	}
+	bsent = sangoma_writemsg_tdm(zchan->sockfd, &hdrframe, (int)sizeof(hdrframe), data, (unsigned short)(*datalen),0);
+
+	/* should we be checking if bsent == *datalen here? */
+	if (bsent > 0) {
+		*datalen = bsent;
+		return ZAP_SUCCESS;
+	}
+
+	return ZAP_FAIL;
+}
+
+/**
+ * \brief Waits for an event on a Wanpipe channel
+ * \param zchan Channel to open
+ * \param flags Type of event to wait for
+ * \param to Time to wait (in ms)
+ * \return Success, failure or timeout
+ */
+
+static ZIO_WAIT_FUNCTION(wanpipe_wait)
+{
+	int32_t inflags = 0;
+	int result;
+
+	if (*flags & ZAP_READ) {
+		inflags |= POLLIN;
+	}
+
+	if (*flags & ZAP_WRITE) {
+		inflags |= POLLOUT;
+	}
+
+	if (*flags & ZAP_EVENTS) {
+		inflags |= POLLPRI;
+	}
+
+	result = tdmv_api_wait_socket(zchan, to, &inflags);
+
+	*flags = ZAP_NO_FLAGS;
+
+	if (result < 0){
+		snprintf(zchan->last_error, sizeof(zchan->last_error), "Poll failed");
+		return ZAP_FAIL;
+	}
+
+	if (result == 0) {
+		return ZAP_TIMEOUT;
+	}
+
+	if (inflags & POLLIN) {
+		*flags |= ZAP_READ;
+	}
+
+	if (inflags & POLLOUT) {
+		*flags |= ZAP_WRITE;
+	}
+
+	if (inflags & POLLPRI) {
+		*flags |= ZAP_EVENTS;
+	}
+
+	return ZAP_SUCCESS;
+}
+
+/**
+ * \brief Checks for events on a Wanpipe span
+ * \param span Span to check for events
+ * \param ms Time to wait for event
+ * \return Success if event is waiting or failure if not
+ */
+ZIO_SPAN_POLL_EVENT_FUNCTION(wanpipe_poll_event)
+{
+#ifdef LIBSANGOMA_VERSION
+    sangoma_status_t sangstatus;
+	sangoma_wait_obj_t *pfds[ZAP_MAX_CHANNELS_SPAN] = { 0 };
+    uint32_t inflags[ZAP_MAX_CHANNELS_SPAN];
+    uint32_t outflags[ZAP_MAX_CHANNELS_SPAN];
+#else
+	struct pollfd pfds[ZAP_MAX_CHANNELS_SPAN];
+#endif
+
+	uint32_t i, j = 0, k = 0, l = 0;
+	int r;
+	
+	for(i = 1; i <= span->chan_count; i++) {
+		zap_channel_t *zchan = span->channels[i];
+
+		if (!strncasecmp(span->name, "smg_prid_nfas", 8) && span->trunk_type == ZAP_TRUNK_T1 && zchan->physical_chan_id == 24) {
+			continue;
+		} 
+
+#ifdef LIBSANGOMA_VERSION
+		if (!zchan->mod_data) {
+			continue; /* should never happen but happens when shutting down */
+		}
+		pfds[j] = zchan->mod_data;
+        inflags[j] = POLLPRI;
+#else
+		memset(&pfds[j], 0, sizeof(pfds[j]));
+		pfds[j].fd = span->channels[i]->sockfd;
+		pfds[j].events = POLLPRI;
+#endif
+
+		/* The driver probably should be able to do this wink/flash/ringing by itself this is sort of a hack to make it work! */
+
+		if (zap_test_flag(zchan, ZAP_CHANNEL_WINK) || zap_test_flag(zchan, ZAP_CHANNEL_FLASH)) {
+			l = 5;
+		}
+
+		j++;
+
+		if (zap_test_flag(zchan, ZAP_CHANNEL_RINGING)) {
+			l = 5;
+		}
+
+		if (zap_test_flag(zchan, ZAP_CHANNEL_RINGING) && zap_current_time_in_ms() >= zchan->ring_time) {
+			wanpipe_tdm_api_t tdm_api;
+			int err;
+			memset(&tdm_api, 0, sizeof(tdm_api));
+			if (zap_test_pflag(zchan, WP_RINGING)) {
+				err=sangoma_tdm_txsig_offhook(zchan->sockfd,&tdm_api);
+				if (err) {
+					snprintf(zchan->last_error, sizeof(zchan->last_error), "Ring-off Failed");
+					return ZAP_FAIL;
+				}
+				zap_clear_pflag_locked(zchan, WP_RINGING);
+				zchan->ring_time = zap_current_time_in_ms() + wp_globals.ring_off_ms;
+			} else {
+				err=sangoma_tdm_txsig_start(zchan->sockfd,&tdm_api);
+				if (err) {
+					snprintf(zchan->last_error, sizeof(zchan->last_error), "Ring Failed");
+					return ZAP_FAIL;
+				}
+				zap_set_pflag_locked(zchan, WP_RINGING);
+				zchan->ring_time = zap_current_time_in_ms() + wp_globals.ring_on_ms;
+			}
+		}
+	}
+
+	if (l) {
+		ms = l;
+	}
+#ifdef LIBSANGOMA_VERSION
+	sangstatus = sangoma_waitfor_many(pfds, inflags, outflags, j, ms);
+    if (SANG_STATUS_APIPOLL_TIMEOUT == sangstatus) {
+        r = 0;
+    } else if (SANG_STATUS_SUCCESS == sangstatus) {
+        r = 1; /* hopefully we never need how many changed -_- */
+    } else {
+        r = -1;
+    }
+#else
+	r = poll(pfds, j, ms);
+#endif
+	
+	if (r == 0) {
+		return l ? ZAP_SUCCESS : ZAP_TIMEOUT;
+	} else if (r < 0) {
+		snprintf(span->last_error, sizeof(span->last_error), "%s", strerror(errno));
+		return ZAP_FAIL;
+	}
+	
+	for(i = 1; i <= span->chan_count; i++) {
+		zap_channel_t *zchan = span->channels[i];
+
+#ifdef LIBSANGOMA_VERSION
+		if (outflags[i-1] & POLLPRI) {
+#else
+		if (pfds[i-1].revents & POLLPRI) {
+#endif
+			zap_set_flag(zchan, ZAP_CHANNEL_EVENT);
+			zchan->last_event_time = zap_current_time_in_ms();
+			k++;
+		}
+	}
+	
+
+	return k ? ZAP_SUCCESS : ZAP_FAIL;
+}
+
+/**
+ * \brief Gets alarms from a Wanpipe Channel
+ * \param zchan Channel to get alarms from
+ * \return Success or failure
+ */
+static ZIO_GET_ALARMS_FUNCTION(wanpipe_get_alarms)
+{
+	wanpipe_tdm_api_t tdm_api;
+	unsigned int alarms = 0;
+	int err;
+
+	memset(&tdm_api,0,sizeof(tdm_api));
+
+#ifdef LIBSANGOMA_VERSION
+	if ((err = sangoma_tdm_get_fe_alarms(zchan->sockfd, &tdm_api, &alarms))) {
+        snprintf(zchan->last_error, sizeof(zchan->last_error), "ioctl failed (%s)", strerror(errno));
+        snprintf(zchan->span->last_error, sizeof(zchan->span->last_error), "ioctl failed (%s)", strerror(errno));
+        return ZAP_FAIL;		
+	}
+#else
+	if ((err = sangoma_tdm_get_fe_alarms(zchan->sockfd, &tdm_api)) < 0){
+        snprintf(zchan->last_error, sizeof(zchan->last_error), "ioctl failed (%s)", strerror(errno));
+        snprintf(zchan->span->last_error, sizeof(zchan->span->last_error), "ioctl failed (%s)", strerror(errno));
+        return ZAP_FAIL;		
+	}
+	alarms = tdm_api.wp_tdm_cmd.fe_alarms;
+#endif
+	zchan->alarm_flags = ZAP_ALARM_NONE;
+
+	if (alarms & WAN_TE_BIT_ALARM_RED) {
+		zchan->alarm_flags |= ZAP_ALARM_RED;
+		alarms &= ~WAN_TE_BIT_ALARM_RED;
+	}
+
+	if (alarms & WAN_TE_BIT_ALARM_AIS) {
+		zchan->alarm_flags |= ZAP_ALARM_AIS;
+		zchan->alarm_flags |= ZAP_ALARM_BLUE;
+		alarms &= ~WAN_TE_BIT_ALARM_AIS;
+	}
+
+	if (alarms & WAN_TE_BIT_ALARM_RAI) {
+		zchan->alarm_flags |= ZAP_ALARM_RAI;
+		zchan->alarm_flags |= ZAP_ALARM_YELLOW;
+		alarms &= ~WAN_TE_BIT_ALARM_RAI;
+	}
+
+	/* still missing to map:
+	 * ZAP_ALARM_RECOVER
+	 * ZAP_ALARM_LOOPBACK
+	 * ZAP_ALARM_NOTOPEN
+	 * */
+
+	/* if we still have alarms that we did not map, set the general alarm */
+	if (alarms) {
+		zap_log(ZAP_LOG_DEBUG, "Unmapped wanpipe alarms: %d\n", alarms);
+		zchan->alarm_flags |= ZAP_ALARM_GENERAL;
+	}
+
+	return ZAP_SUCCESS;
+}
+
+/**
+ * \brief Retrieves an event from a wanpipe span
+ * \param span Span to retrieve event from
+ * \param event Openzap event to return
+ * \return Success or failure
+ */
+ZIO_SPAN_NEXT_EVENT_FUNCTION(wanpipe_next_event)
+{
+	uint32_t i,err;
+	zap_oob_event_t event_id;
+	for(i = 1; i <= span->chan_count; i++) {
+		if (span->channels[i]->last_event_time && !zap_test_flag(span->channels[i], ZAP_CHANNEL_EVENT)) {
+			uint32_t diff = (uint32_t)(zap_current_time_in_ms() - span->channels[i]->last_event_time);
+			/* XX printf("%u %u %u\n", diff, (unsigned)zap_current_time_in_ms(), (unsigned)span->channels[i]->last_event_time); */
+			if (zap_test_flag(span->channels[i], ZAP_CHANNEL_WINK)) {
+				if (diff > wp_globals.wink_ms) {
+					zap_clear_flag_locked(span->channels[i], ZAP_CHANNEL_WINK);
+					zap_clear_flag_locked(span->channels[i], ZAP_CHANNEL_FLASH);
+					zap_set_flag_locked(span->channels[i], ZAP_CHANNEL_OFFHOOK);
+					event_id = ZAP_OOB_OFFHOOK;
+					goto event;
+				}
+			}
+
+			if (zap_test_flag(span->channels[i], ZAP_CHANNEL_FLASH)) {
+				if (diff > wp_globals.flash_ms) {
+					zap_clear_flag_locked(span->channels[i], ZAP_CHANNEL_FLASH);
+					zap_clear_flag_locked(span->channels[i], ZAP_CHANNEL_WINK);
+					zap_clear_flag_locked(span->channels[i], ZAP_CHANNEL_OFFHOOK);
+					event_id = ZAP_OOB_ONHOOK;
+
+					if (span->channels[i]->type == ZAP_CHAN_TYPE_FXO) {
+						zap_channel_t *zchan = span->channels[i];
+						wanpipe_tdm_api_t tdm_api;
+						memset(&tdm_api, 0, sizeof(tdm_api));
+
+						sangoma_tdm_txsig_onhook(zchan->sockfd,&tdm_api);
+					}
+					goto event;
+				}
+			}
+		} 
+		if (zap_test_flag(span->channels[i], ZAP_CHANNEL_EVENT)) {
+			wanpipe_tdm_api_t tdm_api;
+			zap_channel_t *zchan = span->channels[i];
+			memset(&tdm_api, 0, sizeof(tdm_api));
+			zap_clear_flag(span->channels[i], ZAP_CHANNEL_EVENT);
+
+			err = sangoma_tdm_read_event(zchan->sockfd, &tdm_api);
+			if (err != ZAP_SUCCESS) {
+				snprintf(span->last_error, sizeof(span->last_error), "%s", strerror(errno));
+				return ZAP_FAIL;
+			}
+			
+			switch(tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_type) {
+
+			case WP_TDMAPI_EVENT_LINK_STATUS:
+				{
+					zap_sigmsg_t sigmsg;
+					memset(&sigmsg, 0, sizeof(sigmsg));
+					switch(tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_link_status) {
+					case WP_TDMAPI_EVENT_LINK_STATUS_CONNECTED:
+						event_id = ZAP_OOB_ALARM_CLEAR;
+						break;
+					default:
+						event_id = ZAP_OOB_ALARM_TRAP;
+						break;
+					};
+					sigmsg.chan_id = zchan->chan_id;
+					sigmsg.span_id = zchan->span_id;
+					sigmsg.channel = zchan;
+					sigmsg.event_id = (event_id == ZAP_OOB_ALARM_CLEAR) ? ZAP_SIGEVENT_ALARM_CLEAR : ZAP_SIGEVENT_ALARM_TRAP;
+					zap_span_send_signal(zchan->span, &sigmsg);
+				}
+				break;
+
+			case WP_TDMAPI_EVENT_RXHOOK:
+				{
+					if (span->channels[i]->type == ZAP_CHAN_TYPE_FXS) {
+						event_id = tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_hook_state & WP_TDMAPI_EVENT_RXHOOK_OFF ? ZAP_OOB_OFFHOOK : ZAP_OOB_ONHOOK;
+						if (event_id == ZAP_OOB_OFFHOOK) {
+							if (zap_test_flag(span->channels[i], ZAP_CHANNEL_FLASH)) {
+								zap_clear_flag_locked(span->channels[i], ZAP_CHANNEL_FLASH);
+								zap_clear_flag_locked(span->channels[i], ZAP_CHANNEL_WINK);
+								event_id = ZAP_OOB_FLASH;
+								goto event;
+							} else {
+								zap_set_flag_locked(span->channels[i], ZAP_CHANNEL_WINK);
+							}
+						} else {
+							if (zap_test_flag(span->channels[i], ZAP_CHANNEL_WINK)) {
+								zap_clear_flag_locked(span->channels[i], ZAP_CHANNEL_WINK);
+								zap_clear_flag_locked(span->channels[i], ZAP_CHANNEL_FLASH);
+								event_id = ZAP_OOB_WINK;
+								goto event;
+							} else {
+								zap_set_flag_locked(span->channels[i], ZAP_CHANNEL_FLASH);
+							}
+						}					
+						continue;
+					} else {
+						int err;
+						zap_channel_t *zchan = span->channels[i];
+						err=sangoma_tdm_txsig_onhook(zchan->sockfd,&tdm_api);
+						if (err) {
+							snprintf(span->channels[i]->last_error, sizeof(span->channels[i]->last_error), "ONHOOK Failed");
+							return ZAP_FAIL;
+						}
+						event_id = tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_hook_state & WP_TDMAPI_EVENT_RXHOOK_OFF ? ZAP_OOB_ONHOOK : ZAP_OOB_NOOP;	
+					}
+				}
+				break;
+			case WP_TDMAPI_EVENT_RING_DETECT:
+				{
+					event_id = tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_ring_state == WP_TDMAPI_EVENT_RING_PRESENT ? ZAP_OOB_RING_START : ZAP_OOB_RING_STOP;
+				}
+				break;
+				/*
+				disabled this ones when configuring, we don't need them, do we?
+			case WP_TDMAPI_EVENT_RING_TRIP_DETECT:
+				{
+					event_id = tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_ring_state == WP_TDMAPI_EVENT_RING_PRESENT ? ZAP_OOB_ONHOOK : ZAP_OOB_OFFHOOK;
+				}
+				break;
+				*/
+			case WP_TDMAPI_EVENT_RBS:
+				{
+					event_id = ZAP_OOB_CAS_BITS_CHANGE;
+					span->channels[i]->rx_cas_bits = wanpipe_swap_bits(tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_rbs_bits);
+				}
+				break;
+            case WP_TDMAPI_EVENT_DTMF:
+                {
+                    char tmp_dtmf[2] = { tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_dtmf_digit, 0 };
+					event_id = ZAP_OOB_NOOP;
+
+					//zap_log(ZAP_LOG_WARNING, "%d:%d queue hardware dtmf %s %s\n", zchan->span_id, zchan->chan_id, tmp_dtmf, 
+							//tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_dtmf_type == WAN_EC_TONE_PRESENT ? "on" : "off");
+                    if (tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_dtmf_type == WAN_EC_TONE_PRESENT) {
+						zap_set_flag_locked(zchan, ZAP_CHANNEL_MUTE);
+					}
+
+                    if (tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_dtmf_type == WAN_EC_TONE_STOP) {
+						zap_clear_flag_locked(zchan, ZAP_CHANNEL_MUTE);
+						if (zap_test_flag(zchan, ZAP_CHANNEL_INUSE)) {
+							zap_channel_queue_dtmf(zchan, tmp_dtmf);
+						}
+                    } 
+                }
+                break;
+			case WP_TDMAPI_EVENT_ALARM:
+				{
+					zap_sigmsg_t sigmsg;
+					zap_log(ZAP_LOG_DEBUG, "Got wanpipe alarms %d\n", tdm_api.wp_tdm_cmd.event.wp_api_event_alarm);
+					memset(&sigmsg, 0, sizeof(sigmsg));
+					event_id = ZAP_OOB_ALARM_TRAP;
+					sigmsg.chan_id = zchan->chan_id;
+					sigmsg.span_id = zchan->span_id;
+					sigmsg.channel = zchan;
+					sigmsg.event_id = (event_id == ZAP_OOB_ALARM_CLEAR) ? ZAP_SIGEVENT_ALARM_CLEAR : ZAP_SIGEVENT_ALARM_TRAP;
+					zap_span_send_signal(zchan->span, &sigmsg);
+				}
+				break;
+			default:
+				{
+					zap_log(ZAP_LOG_WARNING, "Unhandled event %d\n", tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_type);
+					event_id = ZAP_OOB_INVALID;
+				}
+				break;
+			}
+
+		event:
+
+			span->channels[i]->last_event_time = 0;
+			span->event_header.e_type = ZAP_EVENT_OOB;
+			span->event_header.enum_id = event_id;
+			span->event_header.channel = span->channels[i];
+			*event = &span->event_header;
+			return ZAP_SUCCESS;
+		}
+	}
+
+	return ZAP_FAIL;
+	
+}
+
+/**
+ * \brief Destroys a Wanpipe Channel
+ * \param zchan Channel to destroy
+ * \return Success
+ */
+static ZIO_CHANNEL_DESTROY_FUNCTION(wanpipe_channel_destroy)
+{
+#ifdef LIBSANGOMA_VERSION
+	if (zchan->mod_data) {
+	    sangoma_wait_obj_t *sangoma_wait_obj;
+		sangoma_wait_obj = zchan->mod_data;
+		zchan->mod_data = NULL;
+		sangoma_wait_obj_delete(&sangoma_wait_obj);
+	}
+#endif
+
+	if (zchan->sockfd > -1) {
+		close(zchan->sockfd);
+		zchan->sockfd = WP_INVALID_SOCKET;
+	}
+
+	return ZAP_SUCCESS;
+}
+
+/**
+ * \brief Loads wanpipe IO module
+ * \param zio Openzap IO interface
+ * \return Success
+ */
+static ZIO_IO_LOAD_FUNCTION(wanpipe_init)
+{
+	assert(zio != NULL);
+	memset(&wanpipe_interface, 0, sizeof(wanpipe_interface));
+
+	wp_globals.codec_ms = 20;
+	wp_globals.wink_ms = 150;
+	wp_globals.flash_ms = 750;
+	wp_globals.ring_on_ms = 2000;
+	wp_globals.ring_off_ms = 4000;
+	wanpipe_interface.name = "wanpipe";
+	wanpipe_interface.configure_span = wanpipe_configure_span;
+	wanpipe_interface.configure = wanpipe_configure;
+	wanpipe_interface.open = wanpipe_open;
+	wanpipe_interface.close = wanpipe_close;
+	wanpipe_interface.command = wanpipe_command;
+	wanpipe_interface.wait = wanpipe_wait;
+	wanpipe_interface.read = wanpipe_read;
+	wanpipe_interface.write = wanpipe_write;
+	wanpipe_interface.poll_event = wanpipe_poll_event;
+	wanpipe_interface.next_event = wanpipe_next_event;
+	wanpipe_interface.channel_destroy = wanpipe_channel_destroy;
+	wanpipe_interface.get_alarms = wanpipe_get_alarms;
+	*zio = &wanpipe_interface;
+
+	return ZAP_SUCCESS;
+}
+
+/**
+ * \brief Unloads wanpipe IO module
+ * \return Success
+ */
+static ZIO_IO_UNLOAD_FUNCTION(wanpipe_destroy)
+{
+	memset(&wanpipe_interface, 0, sizeof(wanpipe_interface));
+	return ZAP_SUCCESS;
+}
+
+/**
+ * \brief Openzap wanpipe IO module definition
+ */
+EX_DECLARE_DATA zap_module_t zap_module = { 
+	"wanpipe",
+	wanpipe_init,
+	wanpipe_destroy,
+};
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4 
+ */

Added: freeswitch/trunk/libs/openzap/src/ozmod/ozmod_wanpipe/wanpipe_tdm_api_iface.h (0 => 17141)


--- freeswitch/trunk/libs/openzap/src/ozmod/ozmod_wanpipe/wanpipe_tdm_api_iface.h	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/src/ozmod/ozmod_wanpipe/wanpipe_tdm_api_iface.h	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,351 @@
+/*****************************************************************************
+* wanpipe_tdm_api_iface.h 
+* 		
+* 		WANPIPE(tm) AFT TE1 Hardware Support
+*
+* Authors: 	Nenad Corbic <ncorbic@sangoma.com>
+*
+* Copyright (c) 2007 - 08, Sangoma Technologies
+* All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are met:
+*     * Redistributions of source code must retain the above copyright
+*       notice, this list of conditions and the following disclaimer.
+*     * Redistributions in binary form must reproduce the above copyright
+*       notice, this list of conditions and the following disclaimer in the
+*       documentation and/or other materials provided with the distribution.
+*     * Neither the name of the <organization> nor the
+*       names of its contributors may be used to endorse or promote products
+*       derived from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY <copyright holder> ``AS IS'' AND ANY
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+* DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
+* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+* ============================================================================
+* Oct 04, 2005	Nenad Corbic	Initial version.
+*
+* Jul 25, 2006	David Rokhvarg	<davidr@sangoma.com>	Ported to Windows.
+*****************************************************************************/
+
+#ifndef __WANPIPE_TDM_API_IFACE_H_
+#define __WANPIPE_TDM_API_IFACE_H_ 
+
+
+#if defined(__WINDOWS__)
+typedef HANDLE sng_fd_t;
+#else
+typedef int sng_fd_t;
+#endif
+
+/* Indicate to library that new features exist */
+#define WP_TDM_FEATURE_DTMF_EVENTS	1
+#define WP_TDM_FEATURE_FE_ALARM		1
+#define WP_TDM_FEATURE_EVENTS		1
+#define WP_TDM_FEATURE_LINK_STATUS	1
+
+enum wanpipe_tdm_api_cmds {
+
+	SIOC_WP_TDM_GET_USR_MTU_MRU,	/* 0x00 */
+
+	SIOC_WP_TDM_SET_USR_PERIOD,	/* 0x01 */
+	SIOC_WP_TDM_GET_USR_PERIOD,	/* 0x02 */
+	
+	SIOC_WP_TDM_SET_HW_MTU_MRU,	/* 0x03 */
+	SIOC_WP_TDM_GET_HW_MTU_MRU,	/* 0x04 */
+
+	SIOC_WP_TDM_SET_CODEC,		/* 0x05 */
+	SIOC_WP_TDM_GET_CODEC,		/* 0x06 */
+
+	SIOC_WP_TDM_SET_POWER_LEVEL,	/* 0x07 */
+	SIOC_WP_TDM_GET_POWER_LEVEL,	/* 0x08 */
+
+	SIOC_WP_TDM_TOGGLE_RX,		/* 0x09 */
+	SIOC_WP_TDM_TOGGLE_TX,		/* 0x0A */
+
+	SIOC_WP_TDM_GET_HW_CODING,	/* 0x0B */
+	SIOC_WP_TDM_SET_HW_CODING,	/* 0x0C */
+
+	SIOC_WP_TDM_GET_FULL_CFG,	/* 0x0D */
+
+	SIOC_WP_TDM_SET_EC_TAP,		/* 0x0E */
+	SIOC_WP_TDM_GET_EC_TAP,		/* 0x0F */
+	
+	SIOC_WP_TDM_ENABLE_RBS_EVENTS,	/* 0x10 */
+	SIOC_WP_TDM_DISABLE_RBS_EVENTS,	/* 0x11 */
+	SIOC_WP_TDM_WRITE_RBS_BITS,	/* 0x12 */
+	
+	SIOC_WP_TDM_GET_STATS,		/* 0x13 */
+	SIOC_WP_TDM_FLUSH_BUFFERS,	/* 0x14 */
+	
+	SIOC_WP_TDM_READ_EVENT,		/* 0x15 */
+	
+	SIOC_WP_TDM_SET_EVENT,		/* 0x16 */
+
+	SIOC_WP_TDM_SET_RX_GAINS,	/* 0x17 */
+	SIOC_WP_TDM_SET_TX_GAINS,	/* 0x18 */
+	SIOC_WP_TDM_CLEAR_RX_GAINS,	/* 0x19 */
+	SIOC_WP_TDM_CLEAR_TX_GAINS,	/* 0x1A */
+
+	SIOC_WP_TDM_GET_FE_ALARMS,	/* 0x1B */
+
+	SIOC_WP_TDM_ENABLE_HWEC,	/* 0x1C */
+	SIOC_WP_TDM_DISABLE_HWEC,	/* 0x1D */
+	
+	SIOC_WP_TDM_SET_FE_STATUS,	/* 0x1E */
+	SIOC_WP_TDM_GET_FE_STATUS,	/* 0x1F */
+
+	SIOC_WP_TDM_GET_HW_DTMF,	/* 0x20 */
+
+	SIOC_WP_TDM_NOTSUPP		/*  */
+
+};
+
+#define SIOC_WP_TDM_GET_LINK_STATUS SIOC_WP_TDM_GET_FE_STATUS
+
+enum wanpipe_tdm_api_events {
+	WP_TDMAPI_EVENT_NONE,
+	WP_TDMAPI_EVENT_RBS,
+	WP_TDMAPI_EVENT_ALARM,
+	WP_TDMAPI_EVENT_DTMF,
+	WP_TDMAPI_EVENT_RM_DTMF,
+	WP_TDMAPI_EVENT_RXHOOK,
+	WP_TDMAPI_EVENT_RING,
+	WP_TDMAPI_EVENT_RING_DETECT,
+	WP_TDMAPI_EVENT_RING_TRIP_DETECT,
+	WP_TDMAPI_EVENT_TONE,
+	WP_TDMAPI_EVENT_TXSIG_KEWL,
+	WP_TDMAPI_EVENT_TXSIG_START,
+	WP_TDMAPI_EVENT_TXSIG_OFFHOOK,
+	WP_TDMAPI_EVENT_TXSIG_ONHOOK,
+	WP_TDMAPI_EVENT_ONHOOKTRANSFER,
+	WP_TDMAPI_EVENT_SETPOLARITY,
+	WP_TDMAPI_EVENT_BRI_CHAN_LOOPBACK,
+	WP_TDMAPI_EVENT_LINK_STATUS
+};
+
+#define WP_TDMAPI_EVENT_FE_ALARM WP_TDMAPI_EVENT_ALARM
+
+
+#define WP_TDMAPI_EVENT_ENABLE		0x01
+#define WP_TDMAPI_EVENT_DISABLE		0x02
+#define WP_TDMAPI_EVENT_MODE_DECODE(mode)				\
+		((mode) == WP_TDMAPI_EVENT_ENABLE) ? "Enable" :	\
+		((mode) == WP_TDMAPI_EVENT_DISABLE) ? "Disable" :	\
+						"(Unknown mode)"
+
+#define WPTDM_A_BIT 			WAN_RBS_SIG_A
+#define WPTDM_B_BIT 			WAN_RBS_SIG_B
+#define WPTDM_C_BIT 			WAN_RBS_SIG_C
+#define WPTDM_D_BIT 			WAN_RBS_SIG_D
+ 
+#define WP_TDMAPI_EVENT_RXHOOK_OFF	0x01
+#define WP_TDMAPI_EVENT_RXHOOK_ON	0x02
+#define WP_TDMAPI_EVENT_RXHOOK_DECODE(state)				\
+		((state) == WP_TDMAPI_EVENT_RXHOOK_OFF) ? "Off-hook" :	\
+		((state) == WP_TDMAPI_EVENT_RXHOOK_ON) ? "On-hook" :	\
+						"(Unknown state)"
+
+#define WP_TDMAPI_EVENT_RING_PRESENT	0x01
+#define WP_TDMAPI_EVENT_RING_STOP	0x02
+#define WP_TDMAPI_EVENT_RING_DECODE(state)				\
+		((state) == WP_TDMAPI_EVENT_RING_PRESENT) ? "Ring Present" :	\
+		((state) == WP_TDMAPI_EVENT_RING_STOP) ? "Ring Stop" :	\
+						"(Unknown state)"
+
+#define WP_TDMAPI_EVENT_RING_TRIP_PRESENT	0x01
+#define WP_TDMAPI_EVENT_RING_TRIP_STOP	0x02
+#define WP_TDMAPI_EVENT_RING_TRIP_DECODE(state)				\
+		((state) == WP_TDMAPI_EVENT_RING_TRIP_PRESENT) ? "Ring Present" :	\
+		((state) == WP_TDMAPI_EVENT_RING_TRIP_STOP) ? "Ring Stop" :	\
+						"(Unknown state)"
+/*Link Status */
+#define WP_TDMAPI_EVENT_LINK_STATUS_CONNECTED		0x01
+#define WP_TDMAPI_EVENT_LINK_STATUS_DISCONNECTED	0x02
+#define WP_TDMAPI_EVENT_LINK_STATUS_DECODE(status)					\
+		((status) == WP_TDMAPI_EVENT_LINK_STATUS_CONNECTED) ? "Connected" :		\
+		((status) == WP_TDMAPI_EVENT_LINK_STATUS_DISCONNECTED)  ? "Disconnected" :		\
+							"Unknown"
+#define	WP_TDMAPI_EVENT_TONE_DIAL	0x01
+#define	WP_TDMAPI_EVENT_TONE_BUSY	0x02
+#define	WP_TDMAPI_EVENT_TONE_RING	0x03
+#define	WP_TDMAPI_EVENT_TONE_CONGESTION	0x04
+
+/* BRI channels list */						
+#define	WAN_BRI_BCHAN1		0x01
+#define	WAN_BRI_BCHAN2		0x02
+#define	WAN_BRI_DCHAN		0x03
+
+
+typedef struct {
+
+	u_int8_t	type;
+	u_int8_t	mode;
+	u_int32_t	time_stamp;
+	u_int8_t	channel;
+	u_int32_t	chan_map;
+	u_int8_t	span;
+	union {
+		struct {
+			u_int8_t	alarm;
+		} te1_alarm;
+		struct {
+			u_int8_t	rbs_bits;
+		} te1_rbs;
+		struct {
+			u_int8_t	state;
+			u_int8_t	sig;
+		} rm_hook;
+		struct {
+			u_int8_t	state;
+		} rm_ring;
+		struct {
+			u_int8_t	type;
+		} rm_tone;
+		struct {
+			u_int8_t	digit;	/* DTMF: digit  */
+			u_int8_t	port;	/* DTMF: SOUT/ROUT */
+			u_int8_t	type;	/* DTMF: PRESET/STOP */
+		} dtmf;
+		struct {
+			u_int16_t	polarity;
+			u_int16_t	ohttimer;
+		} rm_common;
+		struct{
+			u_int16_t status;
+		} linkstatus;
+	} wp_tdm_api_event_u;
+#define wp_tdm_api_event_type 		type
+#define wp_tdm_api_event_mode 		mode
+#define wp_tdm_api_event_alarm 		wp_tdm_api_event_u.te1_alarm.alarm
+#define wp_tdm_api_event_alarm 		wp_tdm_api_event_u.te1_alarm.alarm
+#define wp_tdm_api_event_rbs_bits 	wp_tdm_api_event_u.te1_rbs.rbs_bits
+#define wp_tdm_api_event_hook_state 	wp_tdm_api_event_u.rm_hook.state
+#define wp_tdm_api_event_hook_sig 	wp_tdm_api_event_u.rm_hook.sig
+#define wp_tdm_api_event_ring_state 	wp_tdm_api_event_u.rm_ring.state
+#define wp_tdm_api_event_tone_type 	wp_tdm_api_event_u.rm_tone.type
+#define wp_tdm_api_event_dtmf_digit 	wp_tdm_api_event_u.dtmf.digit
+#define wp_tdm_api_event_dtmf_type 	wp_tdm_api_event_u.dtmf.type
+#define wp_tdm_api_event_dtmf_port 	wp_tdm_api_event_u.dtmf.port
+#define wp_tdm_api_event_ohttimer 	wp_tdm_api_event_u.rm_common.ohttimer
+#define wp_tdm_api_event_polarity 	wp_tdm_api_event_u.rm_common.polarity
+#define wp_tdm_api_event_link_status	wp_tdm_api_event_u.linkstatus.status
+} wp_tdm_api_event_t;
+
+typedef struct {
+	union {
+		unsigned char	reserved[16];
+	}wp_rx_hdr_u;
+} wp_tdm_api_rx_hdr_t;
+
+typedef struct {
+        wp_tdm_api_rx_hdr_t	hdr;
+        unsigned char  		data[1];
+} wp_tdm_api_rx_element_t;
+
+typedef struct {
+	union {
+		struct {
+			unsigned char	_rbs_rx_bits;
+			unsigned int	_time_stamp;
+		}wp_tx;
+		unsigned char	reserved[16];
+	}wp_tx_hdr_u;
+#define wp_api_time_stamp 	wp_tx_hdr_u.wp_tx._time_stamp
+} wp_tdm_api_tx_hdr_t;
+
+typedef struct {
+        wp_tdm_api_tx_hdr_t	hdr;
+        unsigned char  		data[1];
+} wp_tdm_api_tx_element_t;
+
+
+
+typedef struct wp_tdm_chan_stats
+{
+	unsigned int	rx_packets;		/* total packets received	*/
+	unsigned int	tx_packets;		/* total packets transmitted	*/
+	unsigned int	rx_bytes;		/* total bytes received 	*/
+	unsigned int	tx_bytes;		/* total bytes transmitted	*/
+	unsigned int	rx_errors;		/* bad packets received		*/
+	unsigned int	tx_errors;		/* packet transmit problems	*/
+	unsigned int	rx_dropped;		/* no space in linux buffers	*/
+	unsigned int	tx_dropped;		/* no space available in linux	*/
+	unsigned int	multicast;		/* multicast packets received	*/
+#if !defined(__WINDOWS__)
+	unsigned int	collisions;
+#endif
+	/* detailed rx_errors: */
+	unsigned int	rx_length_errors;
+	unsigned int	rx_over_errors;		/* receiver ring buff overflow	*/
+	unsigned int	rx_crc_errors;		/* recved pkt with crc error	*/
+	unsigned int	rx_frame_errors;	/* recv'd frame alignment error */
+#if !defined(__WINDOWS__)
+	unsigned int	rx_fifo_errors;		/* recv'r fifo overrun		*/
+#endif
+	unsigned int	rx_missed_errors;	/* receiver missed packet	*/
+
+	/* detailed tx_errors */
+#if !defined(__WINDOWS__)
+	unsigned int	tx_aborted_errors;
+	unsigned int	tx_carrier_errors;
+#endif
+	unsigned int	tx_fifo_errors;
+	unsigned int	tx_heartbeat_errors;
+	unsigned int	tx_window_errors;
+	
+}wp_tdm_chan_stats_t;          
+
+
+ 
+typedef struct wanpipe_tdm_api_cmd{
+	unsigned int cmd;
+	unsigned int hw_tdm_coding;	/* Set/Get HW TDM coding: uLaw muLaw */
+	unsigned int hw_mtu_mru;	/* Set/Get HW TDM MTU/MRU */
+	unsigned int usr_period;	/* Set/Get User Period in ms */
+	unsigned int tdm_codec;		/* Set/Get TDM Codec: SLinear */
+	unsigned int power_level;	/* Set/Get Power level treshold */
+	unsigned int rx_disable;	/* Enable/Disable Rx */
+	unsigned int tx_disable;	/* Enable/Disable Tx */		
+	unsigned int usr_mtu_mru;	/* Set/Get User TDM MTU/MRU */
+	unsigned int ec_tap;		/* Echo Cancellation Tap */
+	unsigned int rbs_poll;		/* Enable/Disable RBS Polling */
+	unsigned int rbs_rx_bits;	/* Rx RBS Bits */
+	unsigned int rbs_tx_bits;	/* Tx RBS Bits */
+	unsigned int hdlc;			/* HDLC based device */
+	unsigned int idle_flag;		/* IDLE flag to Tx */
+	unsigned int fe_alarms;		/* FE Alarms detected */
+	wp_tdm_chan_stats_t stats;	/* TDM Statistics */
+	/* Do NOT add anything above this! Important for binary backward compatibility. */
+	wp_tdm_api_event_t event;	/* TDM Event */
+	unsigned int data_len;
+        void *data;	
+	unsigned char fe_status;	/* FE status - Connected or Disconnected */
+	unsigned int hw_dtmf;		/* HW DTMF enabled */
+}wanpipe_tdm_api_cmd_t;
+
+typedef struct wanpipe_tdm_api_event{
+	int (*wp_rbs_event)(sng_fd_t fd, unsigned char rbs_bits);
+	int (*wp_dtmf_event)(sng_fd_t fd, unsigned char dtmf, unsigned char type, unsigned char port);
+	int (*wp_rxhook_event)(sng_fd_t fd, unsigned char hook_state);
+	int (*wp_ring_detect_event)(sng_fd_t fd, unsigned char ring_state);
+	int (*wp_ring_trip_detect_event)(sng_fd_t fd, unsigned char ring_state);
+	int (*wp_fe_alarm_event)(sng_fd_t fd, unsigned char fe_alarm_event);
+	int (*wp_link_status_event)(sng_fd_t fd, unsigned char link_status_event);
+}wanpipe_tdm_api_event_t; 
+
+typedef struct wanpipe_tdm_api{
+	wanpipe_tdm_api_cmd_t	wp_tdm_cmd;
+	wanpipe_tdm_api_event_t wp_tdm_event;
+}wanpipe_tdm_api_t;
+
+
+#endif

Added: freeswitch/trunk/libs/openzap/src/ozmod/ozmod_zt/ozmod_zt.c (0 => 17141)


--- freeswitch/trunk/libs/openzap/src/ozmod/ozmod_zt/ozmod_zt.c	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/src/ozmod/ozmod_zt/ozmod_zt.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,1251 @@
+/*
+ * Copyright (c) 2007, Anthony Minessale II
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#include "openzap.h"
+#include "ozmod_zt.h"
+
+/**
+ * \brief Zaptel globals
+ */
+static struct {
+	uint32_t codec_ms;
+	uint32_t wink_ms;
+	uint32_t flash_ms;
+	uint32_t eclevel;
+	uint32_t etlevel;
+    float rxgain;
+    float txgain;
+} zt_globals;
+
+/**
+ * \brief General IOCTL codes
+ */
+struct ioctl_codes {
+    int GET_BLOCKSIZE;
+    int SET_BLOCKSIZE;
+    int FLUSH;
+    int SYNC;
+    int GET_PARAMS;
+    int SET_PARAMS;
+    int HOOK;
+    int GETEVENT;
+    int IOMUX;
+    int SPANSTAT;
+    int MAINT;
+    int GETCONF;
+    int SETCONF;
+    int CONFLINK;
+    int CONFDIAG;
+    int GETGAINS;
+    int SETGAINS;
+    int SPANCONFIG;
+    int CHANCONFIG;
+    int SET_BUFINFO;
+    int GET_BUFINFO;
+    int AUDIOMODE;
+    int ECHOCANCEL;
+    int HDLCRAWMODE;
+    int HDLCFCSMODE;
+    int SPECIFY;
+    int SETLAW;
+    int SETLINEAR;
+    int GETCONFMUTE;
+    int ECHOTRAIN;
+    int SETTXBITS;
+    int GETRXBITS;
+};
+
+/**
+ * \brief Zaptel IOCTL codes
+ */
+static struct ioctl_codes zt_ioctl_codes = {
+    .GET_BLOCKSIZE = ZT_GET_BLOCKSIZE,
+    .SET_BLOCKSIZE = ZT_SET_BLOCKSIZE,
+    .FLUSH = ZT_FLUSH,
+    .SYNC = ZT_SYNC,
+    .GET_PARAMS = ZT_GET_PARAMS,
+    .SET_PARAMS = ZT_SET_PARAMS,
+    .HOOK = ZT_HOOK,
+    .GETEVENT = ZT_GETEVENT,
+    .IOMUX = ZT_IOMUX,
+    .SPANSTAT = ZT_SPANSTAT,
+    .MAINT = ZT_MAINT,
+    .GETCONF = ZT_GETCONF,
+    .SETCONF = ZT_SETCONF,
+    .CONFLINK = ZT_CONFLINK,
+    .CONFDIAG = ZT_CONFDIAG,
+    .GETGAINS = ZT_GETGAINS,
+    .SETGAINS = ZT_SETGAINS,
+    .SPANCONFIG = ZT_SPANCONFIG,
+    .CHANCONFIG = ZT_CHANCONFIG,
+    .SET_BUFINFO = ZT_SET_BUFINFO,
+    .GET_BUFINFO = ZT_GET_BUFINFO,
+    .AUDIOMODE = ZT_AUDIOMODE,
+    .ECHOCANCEL = ZT_ECHOCANCEL,
+    .HDLCRAWMODE = ZT_HDLCRAWMODE,
+    .HDLCFCSMODE = ZT_HDLCFCSMODE,
+    .SPECIFY = ZT_SPECIFY,
+    .SETLAW = ZT_SETLAW,
+    .SETLINEAR = ZT_SETLINEAR,
+    .GETCONFMUTE = ZT_GETCONFMUTE,
+    .ECHOTRAIN = ZT_ECHOTRAIN,
+    .SETTXBITS = ZT_SETTXBITS,
+    .GETRXBITS = ZT_GETRXBITS
+};
+
+/**
+ * \brief Dahdi IOCTL codes
+ */
+static struct ioctl_codes dahdi_ioctl_codes = {
+    .GET_BLOCKSIZE = DAHDI_GET_BLOCKSIZE,
+    .SET_BLOCKSIZE = DAHDI_SET_BLOCKSIZE,
+    .FLUSH = DAHDI_FLUSH,
+    .SYNC = DAHDI_SYNC,
+    .GET_PARAMS = DAHDI_GET_PARAMS,
+    .SET_PARAMS = DAHDI_SET_PARAMS,
+    .HOOK = DAHDI_HOOK,
+    .GETEVENT = DAHDI_GETEVENT,
+    .IOMUX = DAHDI_IOMUX,
+    .SPANSTAT = DAHDI_SPANSTAT,
+    .MAINT = DAHDI_MAINT,
+    .GETCONF = DAHDI_GETCONF,
+    .SETCONF = DAHDI_SETCONF,
+    .CONFLINK = DAHDI_CONFLINK,
+    .CONFDIAG = DAHDI_CONFDIAG,
+    .GETGAINS = DAHDI_GETGAINS,
+    .SETGAINS = DAHDI_SETGAINS,
+    .SPANCONFIG = DAHDI_SPANCONFIG,
+    .CHANCONFIG = DAHDI_CHANCONFIG,
+    .SET_BUFINFO = DAHDI_SET_BUFINFO,
+    .GET_BUFINFO = DAHDI_GET_BUFINFO,
+    .AUDIOMODE = DAHDI_AUDIOMODE,
+    .ECHOCANCEL = DAHDI_ECHOCANCEL,
+    .HDLCRAWMODE = DAHDI_HDLCRAWMODE,
+    .HDLCFCSMODE = DAHDI_HDLCFCSMODE,
+    .SPECIFY = DAHDI_SPECIFY,
+    .SETLAW = DAHDI_SETLAW,
+    .SETLINEAR = DAHDI_SETLINEAR,
+    .GETCONFMUTE = DAHDI_GETCONFMUTE,
+    .ECHOTRAIN = DAHDI_ECHOTRAIN,
+    .SETTXBITS = DAHDI_SETTXBITS,
+    .GETRXBITS = DAHDI_GETRXBITS
+};
+
+#define ZT_INVALID_SOCKET -1
+static struct ioctl_codes codes;
+static const char *ctlpath = NULL;
+static const char *chanpath = NULL;
+
+static const char dahdi_ctlpath[] = "/dev/dahdi/ctl";
+static const char dahdi_chanpath[] = "/dev/dahdi/channel";
+
+static const char zt_ctlpath[] = "/dev/zap/ctl";
+static const char zt_chanpath[] = "/dev/zap/channel";
+
+static zap_socket_t CONTROL_FD = ZT_INVALID_SOCKET;
+
+ZIO_SPAN_NEXT_EVENT_FUNCTION(zt_next_event);
+ZIO_SPAN_POLL_EVENT_FUNCTION(zt_poll_event);
+
+/**
+ * \brief Initialises codec, and rx/tx gains
+ * \param g Structure for gains to be initialised
+ * \param rxgain RX gain value
+ * \param txgain TX gain value
+ * \param codec Codec
+ */
+static void zt_build_gains(struct zt_gains *g, float rxgain, float txgain, int codec)
+{
+	int j;
+	int k;
+	float linear_rxgain = pow(10.0, rxgain / 20.0);
+    float linear_txgain = pow(10.0, txgain / 20.0);
+
+	switch (codec) {
+	case ZAP_CODEC_ALAW:
+		for (j = 0; j < (sizeof(g->receive_gain) / sizeof(g->receive_gain[0])); j++) {
+			if (rxgain) {
+				k = (int) (((float) alaw_to_linear(j)) * linear_rxgain);
+				if (k > 32767) k = 32767;
+				if (k < -32767) k = -32767;
+				g->receive_gain[j] = linear_to_alaw(k);
+			} else {
+				g->receive_gain[j] = j;
+			}
+			if (txgain) {
+				k = (int) (((float) alaw_to_linear(j)) * linear_txgain);
+				if (k > 32767) k = 32767;
+				if (k < -32767) k = -32767;
+				g->transmit_gain[j] = linear_to_alaw(k);
+			} else {
+				g->transmit_gain[j] = j;
+			}
+		}
+		break;
+	case ZAP_CODEC_ULAW:
+		for (j = 0; j < (sizeof(g->receive_gain) / sizeof(g->receive_gain[0])); j++) {
+			if (rxgain) {
+				k = (int) (((float) ulaw_to_linear(j)) * linear_rxgain);
+				if (k > 32767) k = 32767;
+				if (k < -32767) k = -32767;
+				g->receive_gain[j] = linear_to_ulaw(k);
+			} else {
+				g->receive_gain[j] = j;
+			}
+			if (txgain) {
+				k = (int) (((float) ulaw_to_linear(j)) * linear_txgain);
+				if (k > 32767) k = 32767;
+				if (k < -32767) k = -32767;
+				g->transmit_gain[j] = linear_to_ulaw(k);
+			} else {
+				g->transmit_gain[j] = j;
+			}
+		}
+		break;
+	}
+}
+
+/**
+ * \brief Initialises a range of zaptel channels
+ * \param span Openzap span
+ * \param start Initial wanpipe channel number
+ * \param end Final wanpipe channel number
+ * \param type Openzap channel type
+ * \param name Openzap span name
+ * \param number Openzap span number
+ * \param cas_bits CAS bits
+ * \return number of spans configured
+ */
+static unsigned zt_open_range(zap_span_t *span, unsigned start, unsigned end, zap_chan_type_t type, char *name, char *number, unsigned char cas_bits)
+{
+	unsigned configured = 0, x;
+	zt_params_t ztp;
+
+	memset(&ztp, 0, sizeof(ztp));
+
+	if (type == ZAP_CHAN_TYPE_CAS) {
+		zap_log(ZAP_LOG_DEBUG, "Configuring CAS channels with abcd == 0x%X\n", cas_bits);
+	}	
+	for(x = start; x < end; x++) {
+		zap_channel_t *zchan;
+		zap_socket_t sockfd = ZT_INVALID_SOCKET;
+		int len;
+
+		sockfd = open(chanpath, O_RDWR);
+		if (sockfd != ZT_INVALID_SOCKET && zap_span_add_channel(span, sockfd, type, &zchan) == ZAP_SUCCESS) {
+
+			if (ioctl(sockfd, codes.SPECIFY, &x)) {
+				zap_log(ZAP_LOG_ERROR, "failure configuring device %s chan %d fd %d (%s)\n", chanpath, x, sockfd, strerror(errno));
+				close(sockfd);
+				continue;
+			}
+
+			if (zchan->type == ZAP_CHAN_TYPE_DQ921) {
+				struct zt_bufferinfo binfo;
+				memset(&binfo, 0, sizeof(binfo));
+				binfo.txbufpolicy = 0;
+				binfo.rxbufpolicy = 0;
+				binfo.numbufs = 32;
+				binfo.bufsize = 1024;
+				if (ioctl(sockfd, codes.SET_BUFINFO, &binfo)) {
+					zap_log(ZAP_LOG_ERROR, "failure configuring device %s as OpenZAP device %d:%d fd:%d\n", chanpath, zchan->span_id, zchan->chan_id, sockfd);
+					close(sockfd);
+					continue;
+				}
+			}
+
+			if (type == ZAP_CHAN_TYPE_FXS || type == ZAP_CHAN_TYPE_FXO) {
+				struct zt_chanconfig cc;
+				memset(&cc, 0, sizeof(cc));
+				cc.chan = cc.master = x;
+				
+				switch(type) {
+				case ZAP_CHAN_TYPE_FXS:
+					{
+						switch(span->start_type) {
+						case ZAP_ANALOG_START_KEWL:
+							cc.sigtype = ZT_SIG_FXOKS;
+							break;
+						case ZAP_ANALOG_START_LOOP:
+							cc.sigtype = ZT_SIG_FXOLS;
+							break;
+						case ZAP_ANALOG_START_GROUND:
+							cc.sigtype = ZT_SIG_FXOGS;
+							break;
+						default:
+							break;
+						}
+					}
+					break;
+				case ZAP_CHAN_TYPE_FXO:
+					{
+						switch(span->start_type) {
+						case ZAP_ANALOG_START_KEWL:
+							cc.sigtype = ZT_SIG_FXSKS;
+							break;
+						case ZAP_ANALOG_START_LOOP:
+							cc.sigtype = ZT_SIG_FXSLS;
+							break;
+						case ZAP_ANALOG_START_GROUND:
+							cc.sigtype = ZT_SIG_FXSGS;
+							break;
+						default:
+							break;
+						}
+					}
+					break;
+				default:
+					break;
+				}
+				
+				if (ioctl(CONTROL_FD, codes.CHANCONFIG, &cc)) {
+					zap_log(ZAP_LOG_WARNING, "this ioctl fails on older zaptel but is harmless if you used ztcfg\n[device %s chan %d fd %d (%s)]\n", chanpath, x, CONTROL_FD, strerror(errno));
+				}
+			}
+
+			if (type == ZAP_CHAN_TYPE_CAS) {
+				struct zt_chanconfig cc;
+				memset(&cc, 0, sizeof(cc));
+				cc.chan = cc.master = x;
+				cc.sigtype = ZT_SIG_CAS;
+				cc.idlebits = cas_bits;
+				if (ioctl(CONTROL_FD, codes.CHANCONFIG, &cc)) {
+					zap_log(ZAP_LOG_ERROR, "failure configuring device %s as OpenZAP device %d:%d fd:%d err:%s", chanpath, zchan->span_id, zchan->chan_id, sockfd, strerror(errno));
+					close(sockfd);
+					continue;
+				}
+			}
+
+			if (zchan->type != ZAP_CHAN_TYPE_DQ921 && zchan->type != ZAP_CHAN_TYPE_DQ931) {
+				len = zt_globals.codec_ms * 8;
+				if (ioctl(zchan->sockfd, codes.SET_BLOCKSIZE, &len)) {
+					zap_log(ZAP_LOG_ERROR, "failure configuring device %s as OpenZAP device %d:%d fd:%d err:%s\n", 
+							chanpath, zchan->span_id, zchan->chan_id, sockfd, strerror(errno));
+					close(sockfd);
+					continue;
+				}
+
+				zchan->packet_len = len;
+				zchan->effective_interval = zchan->native_interval = zchan->packet_len / 8;
+			
+				if (zchan->effective_codec == ZAP_CODEC_SLIN) {
+					zchan->packet_len *= 2;
+				}
+			}
+			
+			if (ioctl(sockfd, codes.GET_PARAMS, &ztp) < 0) {
+				zap_log(ZAP_LOG_ERROR, "failure configuring device %s as OpenZAP device %d:%d fd:%d\n", chanpath, zchan->span_id, zchan->chan_id, sockfd);
+				close(sockfd);
+				continue;
+			}
+
+			if (zchan->type == ZAP_CHAN_TYPE_DQ921) {
+				if (
+					(ztp.sig_type != ZT_SIG_HDLCRAW) &&
+					(ztp.sig_type != ZT_SIG_HDLCFCS) &&
+					(ztp.sig_type != ZT_SIG_HARDHDLC)
+					) {
+					zap_log(ZAP_LOG_ERROR, "Failure configuring device %s as OpenZAP device %d:%d fd:%d, hardware signaling is not HDLC, fix your Zap/DAHDI configuration!\n", chanpath, zchan->span_id, zchan->chan_id, sockfd);
+					close(sockfd);
+					continue;
+				}
+			}
+
+			zap_log(ZAP_LOG_INFO, "configuring device %s channel %d as OpenZAP device %d:%d fd:%d\n", chanpath, x, zchan->span_id, zchan->chan_id, sockfd);
+			
+			zchan->rate = 8000;
+			zchan->physical_span_id = ztp.span_no;
+			zchan->physical_chan_id = ztp.chan_no;
+			
+			if (type == ZAP_CHAN_TYPE_FXS || type == ZAP_CHAN_TYPE_FXO || type == ZAP_CHAN_TYPE_EM || type == ZAP_CHAN_TYPE_B) {
+				if (ztp.g711_type == ZT_G711_ALAW) {
+					zchan->native_codec = zchan->effective_codec = ZAP_CODEC_ALAW;
+				} else if (ztp.g711_type == ZT_G711_MULAW) {
+					zchan->native_codec = zchan->effective_codec = ZAP_CODEC_ULAW;
+				} else {
+					int type;
+
+					if (zchan->span->trunk_type == ZAP_TRUNK_E1) {
+						type = ZAP_CODEC_ALAW;
+					} else {
+						type = ZAP_CODEC_ULAW;
+					}
+
+					zchan->native_codec = zchan->effective_codec = type;
+
+				}
+			}
+
+			ztp.wink_time = zt_globals.wink_ms;
+			ztp.flash_time = zt_globals.flash_ms;
+
+			if (ioctl(sockfd, codes.SET_PARAMS, &ztp) < 0) {
+				zap_log(ZAP_LOG_ERROR, "failure configuring device %s as OpenZAP device %d:%d fd:%d\n", chanpath, zchan->span_id, zchan->chan_id, sockfd);
+				close(sockfd);
+				continue;
+			}
+
+			if (!zap_strlen_zero(name)) {
+				zap_copy_string(zchan->chan_name, name, sizeof(zchan->chan_name));
+			}
+			if (!zap_strlen_zero(number)) {
+				zap_copy_string(zchan->chan_number, number, sizeof(zchan->chan_number));
+			}
+			configured++;
+		} else {
+			zap_log(ZAP_LOG_ERROR, "failure configuring device %s\n", chanpath);
+		}
+	}
+	
+
+
+	return configured;
+}
+
+/**
+ * \brief Initialises an openzap zaptel span from a configuration string
+ * \param span Openzap span
+ * \param str Configuration string
+ * \param type Openzap span type
+ * \param name Openzap span name
+ * \param number Openzap span number
+ * \return Success or failure
+ */
+static ZIO_CONFIGURE_SPAN_FUNCTION(zt_configure_span)
+{
+
+	int items, i;
+	char *mydata, *item_list[10];
+	char *ch, *mx;
+	unsigned char cas_bits = 0;
+	int channo;
+	int top = 0;
+	unsigned configured = 0;
+
+	assert(str != NULL);
+	
+
+	mydata = strdup(str);
+	assert(mydata != NULL);
+
+
+	items = zap_separate_string(mydata, ',', item_list, (sizeof(item_list) / sizeof(item_list[0])));
+
+	for(i = 0; i < items; i++) {
+		ch = item_list[i];
+
+		if (!(ch)) {
+			zap_log(ZAP_LOG_ERROR, "Invalid input\n");
+			continue;
+		}
+
+		channo = atoi(ch);
+		
+		if (channo < 0) {
+			zap_log(ZAP_LOG_ERROR, "Invalid channel number %d\n", channo);
+			continue;
+		}
+
+		if ((mx = strchr(ch, '-'))) {
+			mx++;
+			top = atoi(mx) + 1;
+		} else {
+			top = channo + 1;
+		}
+		
+		
+		if (top < 0) {
+			zap_log(ZAP_LOG_ERROR, "Invalid range number %d\n", top);
+			continue;
+		}
+		if (ZAP_CHAN_TYPE_CAS == type && zap_config_get_cas_bits(ch, &cas_bits)) {
+			zap_log(ZAP_LOG_ERROR, "Failed to get CAS bits in CAS channel\n");
+			continue;
+		}
+		configured += zt_open_range(span, channo, top, type, name, number, cas_bits);
+
+	}
+	
+	free(mydata);
+
+	return configured;
+
+}
+
+/**
+ * \brief Process configuration variable for a zaptel profile
+ * \param category Wanpipe profile name
+ * \param var Variable name
+ * \param val Variable value
+ * \param lineno Line number from configuration file
+ * \return Success
+ */
+static ZIO_CONFIGURE_FUNCTION(zt_configure)
+{
+
+	int num;
+    float fnum;
+
+	if (!strcasecmp(category, "defaults")) {
+		if (!strcasecmp(var, "codec_ms")) {
+			num = atoi(val);
+			if (num < 10 || num > 60) {
+				zap_log(ZAP_LOG_WARNING, "invalid codec ms at line %d\n", lineno);
+			} else {
+				zt_globals.codec_ms = num;
+			}
+		} else if (!strcasecmp(var, "wink_ms")) {
+			num = atoi(val);
+			if (num < 50 || num > 3000) {
+				zap_log(ZAP_LOG_WARNING, "invalid wink ms at line %d\n", lineno);
+			} else {
+				zt_globals.wink_ms = num;
+			}
+		} else if (!strcasecmp(var, "flash_ms")) {
+			num = atoi(val);
+			if (num < 50 || num > 3000) {
+				zap_log(ZAP_LOG_WARNING, "invalid flash ms at line %d\n", lineno);
+			} else {
+				zt_globals.flash_ms = num;
+			}
+		} else if (!strcasecmp(var, "echo_cancel_level")) {
+			num = atoi(val);
+			if (num < 0 || num > 256) {
+                zap_log(ZAP_LOG_WARNING, "invalid echo can val at line %d\n", lineno);
+            } else {
+                zt_globals.eclevel = num;
+            }
+		} else if (!strcasecmp(var, "echo_train_level")) {
+			if (zt_globals.eclevel < 1) {
+				zap_log(ZAP_LOG_WARNING, "can't set echo train level without setting echo cancel level first at line %d\n", lineno);
+			} else {
+				num = atoi(val);
+				if (num < 0 || num > 256) {
+					zap_log(ZAP_LOG_WARNING, "invalid echo can val at line %d\n", lineno);
+				} else {
+					zt_globals.etlevel = num;
+				}
+			}
+		} else if (!strcasecmp(var, "rxgain")) {
+			fnum = (float)atof(val);
+			if (fnum < -100.0 || fnum > 100.0) {
+                zap_log(ZAP_LOG_WARNING, "invalid rxgain val at line %d\n", lineno);
+            } else {
+                zt_globals.rxgain = fnum;
+                zap_log(ZAP_LOG_INFO, "Setting rxgain val to %f\n", fnum);
+            }
+			
+		} else if (!strcasecmp(var, "txgain")) {
+			fnum = (float)atof(val);
+			if (fnum < -100.0 || fnum > 100.0) {
+                zap_log(ZAP_LOG_WARNING, "invalid txgain val at line %d\n", lineno);
+            } else {
+                zt_globals.txgain = fnum;
+                zap_log(ZAP_LOG_INFO, "Setting txgain val to %f\n", fnum);
+            }
+			
+		}
+	}
+
+	return ZAP_SUCCESS;
+}
+
+/**
+ * \brief Opens a zaptel channel
+ * \param zchan Channel to open
+ * \return Success or failure
+ */
+static ZIO_OPEN_FUNCTION(zt_open) 
+{
+	zap_channel_set_feature(zchan, ZAP_CHANNEL_FEATURE_INTERVAL);
+
+	if (zchan->type == ZAP_CHAN_TYPE_DQ921 || zchan->type == ZAP_CHAN_TYPE_DQ931) {
+		zchan->native_codec = zchan->effective_codec = ZAP_CODEC_NONE;
+	} else {
+		int blocksize = zt_globals.codec_ms * (zchan->rate / 1000);
+		int err;
+		if ((err = ioctl(zchan->sockfd, codes.SET_BLOCKSIZE, &blocksize))) {
+			snprintf(zchan->last_error, sizeof(zchan->last_error), "%s", strerror(errno));
+			return ZAP_FAIL;
+		} else {
+			zchan->effective_interval = zchan->native_interval;
+			zchan->packet_len = blocksize;
+			zchan->native_codec = zchan->effective_codec;
+		}
+		
+		if (zchan->type == ZAP_CHAN_TYPE_B) {
+			int one = 1;
+			if (ioctl(zchan->sockfd, codes.AUDIOMODE, &one)) {
+				snprintf(zchan->last_error, sizeof(zchan->last_error), "%s", strerror(errno));
+				zap_log(ZAP_LOG_ERROR, "%s\n", zchan->last_error);
+				return ZAP_FAIL;
+			}
+		}
+
+        if (zt_globals.rxgain || zt_globals.txgain) {
+            struct zt_gains gains;
+            memset(&gains, 0, sizeof(gains));
+
+            gains.chan_no = zchan->physical_chan_id;
+            zt_build_gains(&gains, zt_globals.rxgain, zt_globals.txgain, zchan->native_codec);
+
+            if(zt_globals.rxgain)
+                zap_log(ZAP_LOG_INFO, "Setting rxgain to %f on channel %d\n", zt_globals.rxgain, gains.chan_no);
+
+            if(zt_globals.txgain)
+                zap_log(ZAP_LOG_INFO, "Setting txgain to %f on channel %d\n", zt_globals.txgain, gains.chan_no);
+
+			if (ioctl(zchan->sockfd, codes.SETGAINS, &gains) < 0) {
+				zap_log(ZAP_LOG_ERROR, "failure configuring device %s as OpenZAP device %d:%d fd:%d\n", chanpath, zchan->span_id, zchan->chan_id, zchan->sockfd);
+   			}
+        }
+
+		if (zt_globals.eclevel >= 0) {
+			int len = zt_globals.eclevel;
+
+			if (len) {
+				zap_log(ZAP_LOG_INFO, "Setting echo cancel to %d taps for %d:%d\n", len, zchan->span_id, zchan->chan_id);
+			} else {
+				zap_log(ZAP_LOG_INFO, "Disable echo cancel for %d:%d\n", zchan->span_id, zchan->chan_id);
+			}
+
+			if (ioctl(zchan->sockfd, codes.ECHOCANCEL, &len)) {
+                zap_log(ZAP_LOG_WARNING, "Echo cancel not available for %d:%d\n", zchan->span_id, zchan->chan_id);
+			} else if (zt_globals.etlevel >= 0) {
+                len = zt_globals.etlevel;
+               	if (ioctl(zchan->sockfd, codes.ECHOTRAIN, &len)) {
+					zap_log(ZAP_LOG_WARNING, "Echo training not available for %d:%d\n", zchan->span_id, zchan->chan_id);
+                }
+			}
+		}
+		
+	}
+	return ZAP_SUCCESS;
+}
+
+/**
+ * \brief Closes zaptel channel
+ * \param zchan Channel to close
+ * \return Success
+ */
+static ZIO_CLOSE_FUNCTION(zt_close)
+{
+	return ZAP_SUCCESS;
+}
+
+/**
+ * \brief Executes an Openzap command on a zaptel channel
+ * \param zchan Channel to execute command on
+ * \param command Openzap command to execute
+ * \param obj Object (unused)
+ * \return Success or failure
+ */
+static ZIO_COMMAND_FUNCTION(zt_command)
+{
+	zt_params_t ztp;
+	int err = 0;
+
+	memset(&ztp, 0, sizeof(ztp));
+
+	switch(command) {
+	case ZAP_COMMAND_ENABLE_ECHOCANCEL:
+		{
+			int level = ZAP_COMMAND_OBJ_INT;
+			err = ioctl(zchan->sockfd, codes.ECHOCANCEL, &level);
+			ZAP_COMMAND_OBJ_INT = level;
+		}
+	case ZAP_COMMAND_DISABLE_ECHOCANCEL:
+		{
+			int level = 0;
+			err = ioctl(zchan->sockfd, codes.ECHOCANCEL, &level);
+			ZAP_COMMAND_OBJ_INT = level;
+		}
+		break;
+	case ZAP_COMMAND_ENABLE_ECHOTRAIN:
+		{
+			int level = ZAP_COMMAND_OBJ_INT;
+			err = ioctl(zchan->sockfd, codes.ECHOTRAIN, &level);
+			ZAP_COMMAND_OBJ_INT = level;
+		}
+	case ZAP_COMMAND_DISABLE_ECHOTRAIN:
+		{
+			int level = 0;
+			err = ioctl(zchan->sockfd, codes.ECHOTRAIN, &level);
+			ZAP_COMMAND_OBJ_INT = level;
+		}
+		break;
+	case ZAP_COMMAND_OFFHOOK:
+		{
+			int command = ZT_OFFHOOK;
+			if (ioctl(zchan->sockfd, codes.HOOK, &command)) {
+				snprintf(zchan->last_error, sizeof(zchan->last_error), "OFFHOOK Failed");
+				return ZAP_FAIL;
+			}
+			zap_set_flag_locked(zchan, ZAP_CHANNEL_OFFHOOK);
+		}
+		break;
+	case ZAP_COMMAND_ONHOOK:
+		{
+			int command = ZT_ONHOOK;
+			if (ioctl(zchan->sockfd, codes.HOOK, &command)) {
+				snprintf(zchan->last_error, sizeof(zchan->last_error), "ONHOOK Failed");
+				return ZAP_FAIL;
+			}
+			zap_clear_flag_locked(zchan, ZAP_CHANNEL_OFFHOOK);
+		}
+		break;
+	case ZAP_COMMAND_FLASH:
+		{
+			int command = ZT_FLASH;
+			if (ioctl(zchan->sockfd, codes.HOOK, &command)) {
+				snprintf(zchan->last_error, sizeof(zchan->last_error), "FLASH Failed");
+				return ZAP_FAIL;
+			}
+		}
+		break;
+	case ZAP_COMMAND_WINK:
+		{
+			int command = ZT_WINK;
+			if (ioctl(zchan->sockfd, codes.HOOK, &command)) {
+				snprintf(zchan->last_error, sizeof(zchan->last_error), "WINK Failed");
+				return ZAP_FAIL;
+			}
+		}
+		break;
+	case ZAP_COMMAND_GENERATE_RING_ON:
+		{
+			int command = ZT_RING;
+			if (ioctl(zchan->sockfd, codes.HOOK, &command)) {
+				snprintf(zchan->last_error, sizeof(zchan->last_error), "Ring Failed");
+				return ZAP_FAIL;
+			}
+			zap_set_flag_locked(zchan, ZAP_CHANNEL_RINGING);
+		}
+		break;
+	case ZAP_COMMAND_GENERATE_RING_OFF:
+		{
+			int command = ZT_RINGOFF;
+			if (ioctl(zchan->sockfd, codes.HOOK, &command)) {
+				snprintf(zchan->last_error, sizeof(zchan->last_error), "Ring-off failed");
+				return ZAP_FAIL;
+			}
+			zap_clear_flag_locked(zchan, ZAP_CHANNEL_RINGING);
+		}
+		break;
+	case ZAP_COMMAND_GET_INTERVAL:
+		{
+
+			if (!(err = ioctl(zchan->sockfd, codes.GET_BLOCKSIZE, &zchan->packet_len))) {
+				zchan->native_interval = zchan->packet_len / 8;
+				if (zchan->effective_codec == ZAP_CODEC_SLIN) {
+					zchan->packet_len *= 2;
+				}
+				ZAP_COMMAND_OBJ_INT = zchan->native_interval;
+			} 			
+		}
+		break;
+	case ZAP_COMMAND_SET_INTERVAL: 
+		{
+			int interval = ZAP_COMMAND_OBJ_INT;
+			int len = interval * 8;
+
+			if (!(err = ioctl(zchan->sockfd, codes.SET_BLOCKSIZE, &len))) {
+				zchan->packet_len = len;
+				zchan->effective_interval = zchan->native_interval = zchan->packet_len / 8;
+
+				if (zchan->effective_codec == ZAP_CODEC_SLIN) {
+					zchan->packet_len *= 2;
+				}
+			}
+		}
+		break;
+	case ZAP_COMMAND_SET_CAS_BITS:
+		{
+			int bits = ZAP_COMMAND_OBJ_INT;
+			err = ioctl(zchan->sockfd, codes.SETTXBITS, &bits);
+		}
+		break;
+	case ZAP_COMMAND_GET_CAS_BITS:
+		{
+			err = ioctl(zchan->sockfd, codes.GETRXBITS, &zchan->rx_cas_bits);
+			if (!err) {
+				ZAP_COMMAND_OBJ_INT = zchan->rx_cas_bits;
+			}
+		}
+		break;
+	case ZAP_COMMAND_FLUSH_TX_BUFFERS:
+		{
+			int flushmode = ZT_FLUSH_WRITE;
+			err = ioctl(zchan->sockfd, codes.FLUSH, &flushmode);
+		}
+		break;
+	case ZAP_COMMAND_FLUSH_RX_BUFFERS:
+		{
+			int flushmode = ZT_FLUSH_READ;
+			err = ioctl(zchan->sockfd, codes.FLUSH, &flushmode);
+		}
+		break;
+	case ZAP_COMMAND_FLUSH_BUFFERS:
+		{
+			int flushmode = ZT_FLUSH_BOTH;
+			err = ioctl(zchan->sockfd, codes.FLUSH, &flushmode);
+		}
+		break;
+	default:
+		err = ZAP_NOTIMPL;
+		break;
+	};
+
+	if (err && err != ZAP_NOTIMPL) {
+		snprintf(zchan->last_error, sizeof(zchan->last_error), "%s", strerror(errno));
+		return ZAP_FAIL;
+	}
+
+
+	return err == 0 ? ZAP_SUCCESS : err;
+}
+
+/**
+ * \brief Gets alarms from a zaptel Channel
+ * \param zchan Channel to get alarms from
+ * \return Success or failure
+ */
+static ZIO_GET_ALARMS_FUNCTION(zt_get_alarms)
+{
+	struct zt_spaninfo info;
+
+	memset(&info, 0, sizeof(info));
+	info.span_no = zchan->physical_span_id;
+
+	if (ioctl(CONTROL_FD, codes.SPANSTAT, &info)) {
+		snprintf(zchan->last_error, sizeof(zchan->last_error), "ioctl failed (%s)", strerror(errno));
+		snprintf(zchan->span->last_error, sizeof(zchan->span->last_error), "ioctl failed (%s)", strerror(errno));
+		return ZAP_FAIL;
+	}
+
+	zchan->alarm_flags = info.alarms;
+
+	return ZAP_SUCCESS;
+}
+
+/**
+ * \brief Waits for an event on a zaptel channel
+ * \param zchan Channel to open
+ * \param flags Type of event to wait for
+ * \param to Time to wait (in ms)
+ * \return Success, failure or timeout
+ */
+static ZIO_WAIT_FUNCTION(zt_wait)
+{
+	int32_t inflags = 0;
+	int result;
+    struct pollfd pfds[1];
+
+	if (*flags & ZAP_READ) {
+		inflags |= POLLIN;
+	}
+
+	if (*flags & ZAP_WRITE) {
+		inflags |= POLLOUT;
+	}
+
+	if (*flags & ZAP_EVENTS) {
+		inflags |= POLLPRI;
+	}
+
+
+    memset(&pfds[0], 0, sizeof(pfds[0]));
+    pfds[0].fd = zchan->sockfd;
+    pfds[0].events = inflags;
+    result = poll(pfds, 1, to);
+	*flags = 0;
+
+	if (pfds[0].revents & POLLERR) {
+		result = -1;
+	}
+
+	if (result > 0) {
+		inflags = pfds[0].revents;
+	}
+
+	*flags = ZAP_NO_FLAGS;
+
+	if (result < 0){
+		snprintf(zchan->last_error, sizeof(zchan->last_error), "Poll failed");
+		return ZAP_FAIL;
+	}
+
+	if (result == 0) {
+		return ZAP_TIMEOUT;
+	}
+
+	if (inflags & POLLIN) {
+		*flags |= ZAP_READ;
+	}
+
+	if (inflags & POLLOUT) {
+		*flags |= ZAP_WRITE;
+	}
+
+	if (inflags & POLLPRI) {
+		*flags |= ZAP_EVENTS;
+	}
+
+	return ZAP_SUCCESS;
+
+}
+
+/**
+ * \brief Checks for events on a zaptel span
+ * \param span Span to check for events
+ * \param ms Time to wait for event
+ * \return Success if event is waiting or failure if not
+ */
+ZIO_SPAN_POLL_EVENT_FUNCTION(zt_poll_event)
+{
+	struct pollfd pfds[ZAP_MAX_CHANNELS_SPAN];
+	uint32_t i, j = 0, k = 0;
+	int r;
+	
+	for(i = 1; i <= span->chan_count; i++) {
+		memset(&pfds[j], 0, sizeof(pfds[j]));
+		pfds[j].fd = span->channels[i]->sockfd;
+		pfds[j].events = POLLPRI;
+		j++;
+	}
+
+    r = poll(pfds, j, ms);
+
+	if (r == 0) {
+		return ZAP_TIMEOUT;
+	} else if (r < 0 || (pfds[i-1].revents & POLLERR)) {
+		snprintf(span->last_error, sizeof(span->last_error), "%s", strerror(errno));
+		return ZAP_FAIL;
+	}
+	
+	for(i = 1; i <= span->chan_count; i++) {
+		if (pfds[i-1].revents & POLLPRI) {
+			zap_set_flag(span->channels[i], ZAP_CHANNEL_EVENT);
+			span->channels[i]->last_event_time = zap_current_time_in_ms();
+			k++;
+		}
+	}
+
+	if (!k) {
+		snprintf(span->last_error, sizeof(span->last_error), "no matching descriptor");
+	}
+
+	return k ? ZAP_SUCCESS : ZAP_FAIL;
+}
+
+/**
+ * \brief Retrieves an event from a zaptel span
+ * \param span Span to retrieve event from
+ * \param event Openzap event to return
+ * \return Success or failure
+ */
+ZIO_SPAN_NEXT_EVENT_FUNCTION(zt_next_event)
+{
+	uint32_t i, event_id = 0;
+	zap_oob_event_t zt_event_id = 0;
+
+	for(i = 1; i <= span->chan_count; i++) {
+		if (zap_test_flag(span->channels[i], ZAP_CHANNEL_EVENT)) {
+			zap_clear_flag(span->channels[i], ZAP_CHANNEL_EVENT);
+			if (ioctl(span->channels[i]->sockfd, codes.GETEVENT, &zt_event_id) == -1) {
+				snprintf(span->last_error, sizeof(span->last_error), "%s", strerror(errno));
+				return ZAP_FAIL;
+			}
+
+			switch(zt_event_id) {
+			case ZT_EVENT_RINGEROFF:
+				{
+					return ZAP_FAIL;
+				}
+				break;
+			case ZT_EVENT_RINGERON:
+				{
+					return ZAP_FAIL;
+				}
+				break;
+			case ZT_EVENT_RINGBEGIN:
+				{
+					event_id = ZAP_OOB_RING_START;
+				}
+				break;
+			case ZT_EVENT_ONHOOK:
+				{
+					event_id = ZAP_OOB_ONHOOK;
+				}
+				break;
+			case ZT_EVENT_WINKFLASH:
+				{
+					if (span->channels[i]->state == ZAP_CHANNEL_STATE_DOWN || span->channels[i]->state == ZAP_CHANNEL_STATE_DIALING) {
+						event_id = ZAP_OOB_WINK;
+					} else {
+						event_id = ZAP_OOB_FLASH;
+					}
+				}
+				break;
+			case ZT_EVENT_RINGOFFHOOK:
+				{
+					if (span->channels[i]->type == ZAP_CHAN_TYPE_FXS || (span->channels[i]->type == ZAP_CHAN_TYPE_EM && span->channels[i]->state != ZAP_CHANNEL_STATE_UP)) {
+						zap_set_flag_locked(span->channels[i], ZAP_CHANNEL_OFFHOOK);
+						event_id = ZAP_OOB_OFFHOOK;
+					} else if (span->channels[i]->type == ZAP_CHAN_TYPE_FXO) {
+						event_id = ZAP_OOB_RING_START;
+					}
+				}
+				break;
+			case ZT_EVENT_ALARM:
+				{
+					zap_sigmsg_t sigmsg;
+					zap_channel_t *zchan = span->channels[i];
+					event_id = ZAP_OOB_ALARM_TRAP;
+					memset(&sigmsg, 0, sizeof(sigmsg));
+					sigmsg.chan_id = zchan->chan_id;
+					sigmsg.span_id = zchan->span_id;
+					sigmsg.channel = zchan;
+					sigmsg.event_id = ZAP_SIGEVENT_ALARM_TRAP;
+					zap_span_send_signal(zchan->span, &sigmsg);
+				}
+				break;
+			case ZT_EVENT_NOALARM:
+				{
+					zap_sigmsg_t sigmsg;
+					zap_channel_t *zchan = span->channels[i];
+					event_id = ZAP_OOB_ALARM_CLEAR;
+					memset(&sigmsg, 0, sizeof(sigmsg));
+					sigmsg.chan_id = zchan->chan_id;
+					sigmsg.span_id = zchan->span_id;
+					sigmsg.channel = zchan;
+					sigmsg.event_id = ZAP_SIGEVENT_ALARM_CLEAR;
+					zap_span_send_signal(zchan->span, &sigmsg);
+				}
+				break;
+			case ZT_EVENT_BITSCHANGED:
+				{
+					event_id = ZAP_OOB_CAS_BITS_CHANGE;
+					int bits = 0;
+					int err = ioctl(span->channels[i]->sockfd, codes.GETRXBITS, &bits);
+					if (err) {
+						return ZAP_FAIL;
+					}
+					span->channels[i]->rx_cas_bits = bits;
+				}
+				break;
+			default:
+				{
+					zap_log(ZAP_LOG_WARNING, "Unhandled event %d for %d:%d\n", zt_event_id, span->span_id, i);
+					event_id = ZAP_OOB_INVALID;
+				}
+				break;
+			}
+
+			span->channels[i]->last_event_time = 0;
+			span->event_header.e_type = ZAP_EVENT_OOB;
+			span->event_header.enum_id = event_id;
+			span->event_header.channel = span->channels[i];
+			*event = &span->event_header;
+			return ZAP_SUCCESS;
+		}
+	}
+
+	return ZAP_FAIL;
+	
+}
+
+/**
+ * \brief Reads data from a zaptel channel
+ * \param zchan Channel to read from
+ * \param data Data buffer
+ * \param datalen Size of data buffer
+ * \return Success, failure or timeout
+ */
+static ZIO_READ_FUNCTION(zt_read)
+{
+	zap_ssize_t r = 0;
+	int errs = 0;
+
+	while (errs++ < 30) {
+		if ((r = read(zchan->sockfd, data, *datalen)) > 0) {
+			break;
+		}
+		zap_sleep(10);
+		if (r == 0) {
+			errs--;
+		}
+	}
+
+	if (r > 0) {
+		*datalen = r;
+		if (zchan->type == ZAP_CHAN_TYPE_DQ921) {
+			*datalen -= 2;
+		}
+		return ZAP_SUCCESS;
+	}
+
+	return r == 0 ? ZAP_TIMEOUT : ZAP_FAIL;
+}
+
+/**
+ * \brief Writes data to a zaptel channel
+ * \param zchan Channel to write to
+ * \param data Data buffer
+ * \param datalen Size of data buffer
+ * \return Success or failure
+ */
+static ZIO_WRITE_FUNCTION(zt_write)
+{
+	zap_ssize_t w = 0;
+	zap_size_t bytes = *datalen;
+
+	if (zchan->type == ZAP_CHAN_TYPE_DQ921) {
+		memset(data+bytes, 0, 2);
+		bytes += 2;
+	}
+
+	w = write(zchan->sockfd, data, bytes);
+	
+	if (w >= 0) {
+		*datalen = w;
+		return ZAP_SUCCESS;
+	}
+
+	return ZAP_FAIL;
+}
+
+/**
+ * \brief Destroys a zaptel Channel
+ * \param zchan Channel to destroy
+ * \return Success
+ */
+static ZIO_CHANNEL_DESTROY_FUNCTION(zt_channel_destroy)
+{
+	close(zchan->sockfd);
+	zchan->sockfd = ZT_INVALID_SOCKET;
+
+	return ZAP_SUCCESS;
+}
+
+/**
+ * \brief Global Openzap IO interface for zaptel
+ */
+static zap_io_interface_t zt_interface;
+
+/**
+ * \brief Loads zaptel IO module
+ * \param zio Openzap IO interface
+ * \return Success or failure
+ */
+static ZIO_IO_LOAD_FUNCTION(zt_init)
+{
+	assert(zio != NULL);
+    struct stat statbuf;
+	memset(&zt_interface, 0, sizeof(zt_interface));
+	memset(&zt_globals, 0, sizeof(zt_globals));
+
+    if (!stat(zt_ctlpath, &statbuf)) {
+        zap_log(ZAP_LOG_NOTICE, "Using Zaptel control device\n");
+        ctlpath = zt_ctlpath;
+        chanpath = zt_chanpath;
+        memcpy(&codes, &zt_ioctl_codes, sizeof(codes));
+    } else if (!stat(dahdi_ctlpath, &statbuf)) {
+        zap_log(ZAP_LOG_NOTICE, "Using DAHDI control device\n");
+        ctlpath = dahdi_ctlpath;
+        chanpath = dahdi_chanpath;
+        memcpy(&codes, &dahdi_ioctl_codes, sizeof(codes));
+    } else {
+		zap_log(ZAP_LOG_ERROR, "No DAHDI or Zap control device found in /dev/\n");
+		return ZAP_FAIL;
+    }
+	if ((CONTROL_FD = open(ctlpath, O_RDWR)) < 0) {
+		zap_log(ZAP_LOG_ERROR, "Cannot open control device %s: %s\n", ctlpath, strerror(errno));
+		return ZAP_FAIL;
+	}
+
+	zt_globals.codec_ms = 20;
+	zt_globals.wink_ms = 150;
+	zt_globals.flash_ms = 750;
+	zt_globals.eclevel = 0;
+	zt_globals.etlevel = 0;
+	
+	zt_interface.name = "zt";
+	zt_interface.configure = zt_configure;
+	zt_interface.configure_span = zt_configure_span;
+	zt_interface.open = zt_open;
+	zt_interface.close = zt_close;
+	zt_interface.command = zt_command;
+	zt_interface.wait = zt_wait;
+	zt_interface.read = zt_read;
+	zt_interface.write = zt_write;
+	zt_interface.poll_event = zt_poll_event;
+	zt_interface.next_event = zt_next_event;
+	zt_interface.channel_destroy = zt_channel_destroy;
+	zt_interface.get_alarms = zt_get_alarms;
+	*zio = &zt_interface;
+
+	return ZAP_SUCCESS;
+}
+
+/**
+ * \brief Unloads zaptel IO module
+ * \return Success
+ */
+static ZIO_IO_UNLOAD_FUNCTION(zt_destroy)
+{
+	close(CONTROL_FD);
+	memset(&zt_interface, 0, sizeof(zt_interface));
+	return ZAP_SUCCESS;
+}
+
+/**
+ * \brief Openzap zaptel IO module definition
+ */
+zap_module_t zap_module = { 
+	"zt",
+	zt_init,
+	zt_destroy,
+};
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */

Added: freeswitch/trunk/libs/openzap/src/ozmod/ozmod_zt/ozmod_zt.h (0 => 17141)


--- freeswitch/trunk/libs/openzap/src/ozmod/ozmod_zt/ozmod_zt.h	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/src/ozmod/ozmod_zt/ozmod_zt.h	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,364 @@
+/*
+ * Copyright (c) 2007, Anthony Minessale II
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ZAP_ZT_H
+#define ZAP_ZT_H
+#include "openzap.h"
+#include <sys/ioctl.h>
+#include <poll.h>
+
+#ifdef __sun
+#include <unistd.h>
+#include <sys/ioccom.h>
+#include <stropts.h>
+#endif
+
+/* Hardware interface structures and defines */
+/* Based on documentation of the structures required for the hardware interface */
+/* from http://wiki.freeswitch.org/wiki/Zapata_zaptel_interface */
+
+/* Structures */
+
+/* Used with ioctl: ZT_GET_PARAMS and ZT_SET_PARAMS */
+struct zt_params {
+	int chan_no;			/* Channel Number							*/
+	int span_no;			/* Span Number								*/
+	int chan_position;		/* Channel Position							*/
+	int sig_type;			/* Signal Type (read-only)					*/
+	int sig_cap;			/* Signal Cap (read-only)					*/
+	int receive_offhook;	/* Receive is offhook (read-only)			*/
+	int receive_bits;		/* Number of bits in receive (read-only)	*/
+	int transmit_bits;		/* Number of bits in transmit (read-only)	*/
+	int transmit_hook_sig;	/* Transmit Hook Signal (read-only)			*/
+	int receive_hook_sig;	/* Receive Hook Signal (read-only)			*/
+	int g711_type;			/* Member of zt_g711_t (read-only)			*/
+	int idlebits;			/* bits for the idle state (read-only)		*/
+	char chan_name[40];		/* Channel Name								*/
+	int prewink_time;
+	int preflash_time;
+	int wink_time;
+	int flash_time;
+	int start_time;
+	int receive_wink_time;
+	int receive_flash_time;
+	int debounce_time;
+	int pulse_break_time;
+	int pulse_make_time;
+	int pulse_after_time;
+    /* latest version of this struct include chan_alarms field */
+    uint32_t chan_alarms;
+};
+
+typedef struct zt_params zt_params_t;
+
+/* Used with ioctl: ZT_CONFLINK, ZT_GETCONF and ZT_SETCONF */
+struct zt_confinfo {
+	int chan_no;			/* Channel Number, 0 for current */
+	int conference_number;
+	int conference_mode;
+};
+
+/* Used with ioctl: ZT_GETGAINS and ZT_SETGAINS */
+struct zt_gains {
+	int chan_no;						/* Channel Number, 0 for current	*/
+	unsigned char receive_gain[256];	/* Receive gain table				*/
+	unsigned char transmit_gain[256];	/* Transmit gain table				*/
+};
+
+/* Used with ioctl: ZT_SPANSTAT */
+struct zt_spaninfo {
+	int span_no;						/* span number (-1 to use name)				*/
+	char name[20];						/* Name of span								*/
+	char description[40];				/* Description of span						*/
+	int alarms;							/* alarms status							*/
+	int transmit_level;					/* Transmit level							*/
+	int receive_level;					/* Receive level							*/
+	int bpv_count;						/* Current BPV count						*/
+	int crc4_count;						/* Current CRC4 error count					*/
+	int ebit_count;						/* Current E-bit error count				*/
+	int fas_count;						/* Current FAS error count					*/
+	int irq_misses;						/* Current IRQ misses						*/
+	int sync_src;						/* Span # of sync source (0 = free run)		*/
+	int configured_chan_count;			/* Count of channels configured on the span	*/
+	int channel_count;					/* Total count of channels on the span		*/
+	int span_count;						/* Total count of zaptel spans on the system*/
+    /* end v1 of the struct */
+    /* as long as we don't use the fields below we should be ok regardless of the zaptel/dahdi version */
+    int lbo;                            /* Line Build Out */
+    int lineconfig;                     /* framing/coding */
+    /* end of v2 of the struct */
+    char lboname[40];                   /* Line Build Out in text form */
+    char location[40];                  /* span's device location in system */
+    char manufacturer[40];              /* manufacturer of span's device */
+    char devicetype[40];                /* span's device type */
+    int irq;                            /* span's device IRQ */
+    int linecompat;                     /* signaling modes possible on this span */
+    char spantype[6];                   /* type of span in text form */
+};
+
+struct zt_maintinfo {
+	int span_no;						/* span number											*/
+	int command;						/* Maintenance mode to set (from zt_maintenance_mode_t)	*/
+};
+
+struct zt_lineconfig {
+/* Used in ZT_SPANCONFIG */
+	int span;							/* Which span number (0 to use name)		*/
+	char name[20];						/* Name of span to use						*/
+	int lbo;							/* line build-outs							*/
+	int lineconfig;						/* line config parameters (framing, coding) */
+	int sync;							/* what level of sync source we are			*/
+};
+
+struct zt_chanconfig {
+/* Used in ZT_CHANCONFIG */
+	int chan;							/* Channel we're applying this to (0 to use name)										*/
+	char name[40];						/* Name of channel to use																*/
+	int sigtype;						/* Signal type																			*/
+	int deflaw;							/* Default law (ZT_LAW_DEFAULT, ZT_LAW_MULAW, or ZT_LAW_ALAW							*/
+	int master;							/* Master channel if sigtype is ZT_SLAVE												*/
+	int idlebits;						/* Idle bits (if this is a CAS channel) or channel to monitor (if this is DACS channel) */
+	char netdev_name[16];				/* name for the hdlc network device														*/
+};
+
+struct zt_bufferinfo {
+/* used in ZT_SET_BUFINFO and ZT_GET_BUFINFO */
+	int txbufpolicy;					/* Policy for handling receive buffers			*/
+	int rxbufpolicy;					/* Policy for handling receive buffers			*/
+	int numbufs;						/* How many buffers to use						*/
+	int bufsize;						/* How big each buffer is						*/
+	int readbufs;						/* How many read buffers are full (read-only)	*/
+	int writebufs;						/* How many write buffers are full (read-only)	*/
+};
+
+/* Enumerations */
+
+/* Values in zt_params structure for member g711_type */
+typedef enum {
+	ZT_G711_DEFAULT		= 0,	/* Default mulaw/alaw from the span */
+	ZT_G711_MULAW		= 1,
+	ZT_G711_ALAW		= 2
+} zt_g711_t;
+
+typedef enum {
+	ZT_EVENT_NONE			= 0,
+	ZT_EVENT_ONHOOK			= 1,
+	ZT_EVENT_RINGOFFHOOK	= 2,
+	ZT_EVENT_WINKFLASH		= 3,
+	ZT_EVENT_ALARM			= 4,
+	ZT_EVENT_NOALARM		= 5,
+	ZT_EVENT_ABORT			= 6,
+	ZT_EVENT_OVERRUN		= 7,
+	ZT_EVENT_BADFCS			= 8,
+	ZT_EVENT_DIALCOMPLETE	= 9, 
+	ZT_EVENT_RINGERON		= 10,
+	ZT_EVENT_RINGEROFF		= 11,
+	ZT_EVENT_HOOKCOMPLETE	= 12,
+	ZT_EVENT_BITSCHANGED	= 13,
+	ZT_EVENT_PULSE_START	= 14,
+	ZT_EVENT_TIMER_EXPIRED	= 15,
+	ZT_EVENT_TIMER_PING		= 16,
+	ZT_EVENT_POLARITY		= 17,
+	ZT_EVENT_RINGBEGIN		= 18
+} zt_event_t;
+
+typedef enum {
+	ZT_FLUSH_READ			= 1,
+	ZT_FLUSH_WRITE			= 2,
+	ZT_FLUSH_BOTH			= (ZT_FLUSH_READ | ZT_FLUSH_WRITE),
+	ZT_FLUSH_EVENT			= 4,
+	ZT_FLUSH_ALL			= (ZT_FLUSH_READ | ZT_FLUSH_WRITE | ZT_FLUSH_EVENT)
+} zt_flush_t;
+
+typedef enum {
+	ZT_IOMUX_READ			= 1,
+	ZT_IOMUX_WRITE			= 2,
+	ZT_IOMUX_WRITEEMPTY		= 4,
+	ZT_IOMUX_SIGEVENT		= 8,
+	ZT_IOMUX_NOWAIT			= 256
+} zt_iomux_t;
+
+typedef enum {
+	ZT_ONHOOK				= 0,
+	ZT_OFFHOOK				= 1,
+	ZT_WINK					= 2,
+	ZT_FLASH				= 3,
+	ZT_START				= 4,
+	ZT_RING					= 5,
+	ZT_RINGOFF				= 6
+} zt_hookstate_t;
+
+typedef enum {
+	ZT_MAINT_NONE			= 0, /* Normal Mode				*/
+	ZT_MAINT_LOCALLOOP		= 1, /* Local Loopback			*/
+	ZT_MAINT_REMOTELOOP		= 2, /* Remote Loopback			*/
+	ZT_MAINT_LOOPUP			= 3, /* Send Loopup Code		*/
+	ZT_MAINT_LOOPDOWN		= 4, /* Send Loopdown Code		*/
+	ZT_MAINT_LOOPSTOP		= 5  /* Stop Sending Loop Codes	*/
+} zt_maintenance_mode_t;
+
+typedef enum {
+/* Signalling type */
+ZT_SIG_NONE					= 0,						/* chan not configured. */
+
+ZT_SIG_FXSLS				= ((1 << 0) | (1 << 13)),	/* FXS, Loopstart */
+ZT_SIG_FXSGS				= ((1 << 1) | (1 << 13)),	/* FXS, Groundstart */
+ZT_SIG_FXSKS				= ((1 << 2) | (1 << 13)),	/* FXS, Kewlstart */
+ZT_SIG_FXOLS				= ((1 << 3) | (1 << 12)),	/* FXO, Loopstart */
+ZT_SIG_FXOGS				= ((1 << 4) | (1 << 12)),	/* FXO, Groupstart */
+ZT_SIG_FXOKS				= ((1 << 5) | (1 << 12)),	/* FXO, Kewlstart */
+ZT_SIG_EM					= (1 << 6),					/* E&M */
+ZT_SIG_CLEAR				= (1 << 7),
+ZT_SIG_HDLCRAW				= ((1 << 8)  | ZT_SIG_CLEAR),
+ZT_SIG_HDLCFCS				= ((1 << 9)  | ZT_SIG_HDLCRAW),
+ZT_SIG_CAS                  = (1 << 15),
+ZT_SIG_HARDHDLC				= ((1 << 19) | ZT_SIG_CLEAR),
+} zt_sigtype_t;
+
+typedef enum {
+ZT_DBIT = 1,
+ZT_CBIT = 2,
+ZT_BBIT = 4,
+ZT_ABIT = 8
+} zt_cas_bit_t;
+
+/* Defines */
+
+#define		ZT_MAX_BLOCKSIZE	8192
+#define		ZT_DEFAULT_MTU_MRU	2048
+
+/* ioctl defines */
+
+#define		ZT_CODE				'J'
+#define     DAHDI_CODE          0xDA
+
+
+#define		ZT_GET_BLOCKSIZE	_IOR  (ZT_CODE, 1, int)					/* Get Transfer Block Size. */
+#define		ZT_SET_BLOCKSIZE	_IOW  (ZT_CODE, 2, int)					/* Set Transfer Block Size. */
+#define		ZT_FLUSH			_IOW  (ZT_CODE, 3, int)					/* Flush Buffer(s) and stop I/O */
+#define		ZT_SYNC				_IOW  (ZT_CODE, 4, int)					/* Wait for Write to Finish */
+#define		ZT_GET_PARAMS		_IOR  (ZT_CODE, 5, struct zt_params)	/* Get channel parameters */
+#define		ZT_SET_PARAMS		_IOW  (ZT_CODE, 6, struct zt_params)	/* Set channel parameters */
+#define		ZT_HOOK				_IOW  (ZT_CODE, 7, int)					/* Set Hookswitch Status */
+#define		ZT_GETEVENT			_IOR  (ZT_CODE, 8, int)					/* Get Signalling Event */
+#define		ZT_IOMUX			_IOWR (ZT_CODE, 9, int)					/* Wait for something to happen (IO Mux) */
+#define		ZT_SPANSTAT			_IOWR (ZT_CODE, 10, struct zt_spaninfo) /* Get Span Status */
+#define		ZT_MAINT			_IOW  (ZT_CODE, 11, struct zt_maintinfo)/* Set Maintenance Mode for a span */
+#define		ZT_GETCONF			_IOWR (ZT_CODE, 12, struct zt_confinfo)	/* Get Conference Mode */
+#define		ZT_SETCONF			_IOWR (ZT_CODE, 13, struct zt_confinfo)	/* Set Conference Mode */
+#define		ZT_CONFLINK			_IOW  (ZT_CODE, 14, struct zt_confinfo)	/* Setup or Remove Conference Link */
+#define		ZT_CONFDIAG			_IOR  (ZT_CODE, 15, int)				/* Display Conference Diagnostic Information on Console */
+
+#define		ZT_GETGAINS			_IOWR (ZT_CODE, 16, struct zt_gains)	/* Get Channel audio gains */
+#define		ZT_SETGAINS			_IOWR (ZT_CODE, 17, struct zt_gains)	/* Set Channel audio gains */
+#define		ZT_SPANCONFIG		_IOW (ZT_CODE, 18, struct zt_lineconfig)/* Set Line (T1) Configurations and start system  */
+#define		ZT_CHANCONFIG		_IOW (ZT_CODE, 19, struct zt_chanconfig)/* Set Channel Configuration  */
+#define		ZT_SET_BUFINFO		_IOW (ZT_CODE, 27, struct zt_bufferinfo)/* Set buffer policy */
+#define		ZT_GET_BUFINFO		_IOR (ZT_CODE, 28, struct zt_bufferinfo)/* Get current buffer info */
+#define		ZT_AUDIOMODE		_IOW  (ZT_CODE, 32, int)				/* Set a clear channel into audio mode */
+#define		ZT_ECHOCANCEL		_IOW  (ZT_CODE, 33, int)				/* Control Echo Canceller */
+#define		ZT_HDLCRAWMODE		_IOW  (ZT_CODE, 36, int)				/* Set a clear channel into HDLC w/out FCS checking/calculation mode */
+#define		ZT_HDLCFCSMODE		_IOW  (ZT_CODE, 37, int)				/* Set a clear channel into HDLC w/ FCS mode */
+
+/* Specify a channel on /dev/zap/chan -- must be done before any other ioctl's and is only valid on /dev/zap/chan */
+#define		ZT_SPECIFY			_IOW  (ZT_CODE, 38, int)
+
+/* Temporarily set the law on a channel to ZT_LAW_DEFAULT, ZT_LAW_ALAW, or ZT_LAW_MULAW. Is reset on close. */
+#define		ZT_SETLAW			_IOW  (ZT_CODE, 39, int)
+
+/* Temporarily set the channel to operate in linear mode when non-zero or default law if 0 */
+#define		ZT_SETLINEAR		_IOW  (ZT_CODE, 40, int)
+
+#define		ZT_GETCONFMUTE		_IOR  (ZT_CODE, 49, int)				/* Get Conference to mute mode */
+#define		ZT_ECHOTRAIN		_IOW  (ZT_CODE, 50, int)				/* Control Echo Trainer */
+
+/* Set/Get CAS bits */
+#define ZT_SETTXBITS _IOW (ZT_CODE, 43, int)
+#define ZT_GETRXBITS _IOR (ZT_CODE, 45, int)
+
+#define		DAHDI_GET_BLOCKSIZE	_IOR  (DAHDI_CODE, 1, int)					/* Get Transfer Block Size. */
+#define		DAHDI_SET_BLOCKSIZE	_IOW  (DAHDI_CODE, 1, int)					/* Set Transfer Block Size. */
+#define		DAHDI_FLUSH			_IOW  (DAHDI_CODE, 3, int)					/* Flush Buffer(s) and stop I/O */
+#define		DAHDI_SYNC			_IO   (DAHDI_CODE, 4)					/* Wait for Write to Finish */
+#define		DAHDI_GET_PARAMS	_IOR  (DAHDI_CODE, 5, struct zt_params)	/* Get channel parameters */
+#define		DAHDI_SET_PARAMS	_IOW  (DAHDI_CODE, 5, struct zt_params)	/* Set channel parameters */
+#define		DAHDI_HOOK			_IOW  (DAHDI_CODE, 7, int)					/* Set Hookswitch Status */
+#define		DAHDI_GETEVENT		_IOR  (DAHDI_CODE, 8, int)					/* Get Signalling Event */
+#define		DAHDI_IOMUX			_IOWR (DAHDI_CODE, 9, int)					/* Wait for something to happen (IO Mux) */
+#define		DAHDI_SPANSTAT		_IOWR (DAHDI_CODE, 10, struct zt_spaninfo)  /* Get Span Status */
+#define		DAHDI_MAINT			_IOW  (DAHDI_CODE, 11, struct zt_maintinfo) /* Set Maintenance Mode for a span */
+#define		DAHDI_GETCONF		_IOR  (DAHDI_CODE, 12, struct zt_confinfo)	/* Get Conference Mode */
+#define		DAHDI_SETCONF		_IOW  (DAHDI_CODE, 12, struct zt_confinfo)	/* Set Conference Mode */
+#define		DAHDI_CONFLINK		_IOW  (DAHDI_CODE, 14, struct zt_confinfo)	/* Setup or Remove Conference Link */
+#define		DAHDI_CONFDIAG		_IOR  (DAHDI_CODE, 15, int)				/* Display Conference Diagnostic Information on Console */
+
+#define		DAHDI_GETGAINS		_IOR (DAHDI_CODE, 16, struct zt_gains)	/* Get Channel audio gains */
+#define		DAHDI_SETGAINS		_IOW (DAHDI_CODE, 16, struct zt_gains)	/* Set Channel audio gains */
+#define		DAHDI_SPANCONFIG	_IOW (DAHDI_CODE, 18, struct zt_lineconfig)/* Set Line (T1) Configurations and start system  */
+#define		DAHDI_CHANCONFIG	_IOW (DAHDI_CODE, 19, struct zt_chanconfig)/* Set Channel Configuration  */
+#define		DAHDI_SET_BUFINFO	_IOW (DAHDI_CODE, 27, struct zt_bufferinfo)/* Set buffer policy */
+#define		DAHDI_GET_BUFINFO	_IOR (DAHDI_CODE, 27, struct zt_bufferinfo)/* Get current buffer info */
+#define		DAHDI_AUDIOMODE		_IOW (DAHDI_CODE, 32, int)				/* Set a clear channel into audio mode */
+#define		DAHDI_ECHOCANCEL	_IOW (DAHDI_CODE, 33, int)				/* Control Echo Canceller */
+#define		DAHDI_HDLCRAWMODE	_IOW (DAHDI_CODE, 36, int)				/* Set a clear channel into HDLC w/out FCS checking/calculation mode */
+#define		DAHDI_HDLCFCSMODE	_IOW (DAHDI_CODE, 37, int)				/* Set a clear channel into HDLC w/ FCS mode */
+
+/* Specify a channel on /dev/dahdi/chan -- must be done before any other ioctl's and is only valid on /dev/dahdi/chan */
+#define		DAHDI_SPECIFY		_IOW  (DAHDI_CODE, 38, int)
+
+/* Temporarily set the law on a channel to DAHDI_LAW_DEFAULT, DAHDI_LAW_ALAW, or DAHDI_LAW_MULAW. Is reset on close. */
+#define		DAHDI_SETLAW		_IOW  (DAHDI_CODE, 39, int)
+
+/* Temporarily set the channel to operate in linear mode when non-zero or default law if 0 */
+#define		DAHDI_SETLINEAR		_IOW  (DAHDI_CODE, 40, int)
+
+#define		DAHDI_GETCONFMUTE	_IOR  (DAHDI_CODE, 49, int)				/* Get Conference to mute mode */
+#define		DAHDI_ECHOTRAIN		_IOW  (DAHDI_CODE, 50, int)				/* Control Echo Trainer */
+
+/* Set/Get CAS bits */
+#define DAHDI_SETTXBITS _IOW (DAHDI_CODE, 43, int)
+#define DAHDI_GETRXBITS _IOR (DAHDI_CODE, 43, int)
+
+
+#endif
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */

Added: freeswitch/trunk/libs/openzap/src/priserver.c (0 => 17141)


--- freeswitch/trunk/libs/openzap/src/priserver.c	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/src/priserver.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,328 @@
+/*****************************************************************************
+ * priserver.c Refactoring of pritest.c
+ *
+ * Author(s):   Anthony Minessale II <anthmct@yahoo.com>
+ *              Nenad Corbic <ncorbic@sangoma.com>
+ *
+ * Copyright:   (c) 2005 Anthony Minessale II
+ *
+ *      This program is free software; you can redistribute it and/or
+ *      modify it under the terms of the GNU General Public License
+ *      as published by the Free Software Foundation; either version
+ *      2 of the License, or (at your option) any later version.
+ * ============================================================================
+ */
+
+#include "openzap.h"
+#include <sangoma_pri.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/wait.h>
+
+typedef struct {
+	int pid;
+	q931_call call;
+	void *pri;
+	int ready;
+}call_info_t;
+
+
+#define SANGOMA_MAX_CHAN_PER_SPAN 32
+
+static call_info_t pidmap[SANGOMA_MAX_CHAN_PER_SPAN];
+
+ZIO_EVENT_CB_FUNCTION(my_zap_event_handler)
+{
+	if (event->e_type = ZAP_EVENT_DTMF) {
+		char *dtmf = event->data;
+		printf("DTMF %s\n", dtmf);
+	}
+}
+
+/* Stupid runtime process to play a file to a b channel*/
+#define BYTES 320
+#define MAX_BYTES 1000
+
+static int ready = 1;
+
+static void handle_SIGINT(int sig)
+{
+	if (sig) {
+		ready = 0;
+	}
+
+	return;
+}
+
+static void launch_channel(struct sangoma_pri *spri, int channo)
+{
+	pid_t pid;
+	int fd = 0, file = 0, inlen = 0, outlen = 0;
+	unsigned char inframe[MAX_BYTES], outframe[MAX_BYTES];
+	fd_set readfds;
+	int mtu_mru=BYTES / 2;
+	int err;
+	zap_channel_t *chan;
+	zap_codec_t codec = ZAP_CODEC_SLIN;
+	unsigned ms = 20;
+	unsigned int lead = 50;
+	int ifd = -1;
+	zap_tone_type_t tt = ZAP_TONE_DTMF;
+	char dtmf[] = "1234567890";
+	int loops = 0;
+
+	pid = fork();
+	
+	if (pid) {
+		pidmap[channo-1].pid = pid;
+		printf("-- Launching process %d to handle channel %d\n", pid, channo);
+		return;
+	}
+
+	signal(SIGINT, handle_SIGINT);
+
+	//ifd = open("/nfs/sounds/ptest.raw", O_WRONLY|O_CREAT|O_TRUNC, 777);
+	
+	memset(inframe, 0, MAX_BYTES);
+	memset(outframe, 0, MAX_BYTES);
+		
+	if (zap_channel_open(spri->span, channo, &chan) != ZAP_SUCCESS) {
+		printf("DEBUG cant open fd!\n");
+	}
+	
+
+
+#if 1
+	if (zap_channel_command(chan, ZAP_COMMAND_SET_CODEC, &codec) != ZAP_SUCCESS) {
+		printf("Critical Error: Failed to set driver codec!\n");
+		zap_channel_close(&chan);
+		exit(-1);
+	}
+#endif
+	
+#if 1
+	if (zap_channel_command(chan, ZAP_COMMAND_ENABLE_DTMF_DETECT, &tt) != ZAP_SUCCESS) {
+		printf("Critical Error: Failed to set dtmf detect!\n");
+		zap_channel_close(&chan);
+		exit(-1);
+	}
+	zap_channel_set_event_callback(chan, my_zap_event_handler);
+#endif
+
+
+	if (zap_channel_command(chan, ZAP_COMMAND_SET_INTERVAL, &ms) != ZAP_SUCCESS) {
+		printf("Critical Error: Failed to set codec interval!\n");
+		zap_channel_close(&chan);
+		exit(-1);
+	}
+		
+	file = open("sound.raw", O_RDONLY);
+	if (file < 0){
+		printf("Critical Error: Failed to open sound file!\n");
+		zap_channel_close(&chan);
+		exit(-1);
+	}
+
+
+	while(ready) {
+		zap_wait_flag_t flags = ZAP_READ;
+		zap_size_t len;
+		loops++;
+
+		if (lead) {
+			lead--;
+		}
+
+		if (!lead && loops == 300) {
+#if 1
+			if (zap_channel_command(chan, ZAP_COMMAND_SEND_DTMF, dtmf) != ZAP_SUCCESS) {
+				printf("Critical Error: Failed to send dtmf\n");
+				zap_channel_close(&chan);
+				exit(-1);
+			}
+#endif
+
+		}
+
+		if (zap_channel_wait(chan, &flags, 2000) != ZAP_SUCCESS) {
+			printf("wait FAIL! [%s]\n", chan->last_error);
+			break;
+		}
+	
+		if (flags & ZAP_READ) {
+			len = MAX_BYTES;
+			if (zap_channel_read(chan, inframe, &len) == ZAP_SUCCESS) {
+				//printf("READ: %d\n", len);
+				//write(ifd, inframe, len);
+				if(!lead && (outlen = read(file, outframe, len)) <= 0) {
+					break;
+				}
+
+			} else {
+				printf("READ FAIL! %d [%s]\n", len, chan->last_error);
+				break;
+			}
+			if (lead) {
+				continue;
+			} 
+			zap_channel_write(chan, outframe, sizeof(outframe), &len);
+		} else {
+			printf("BREAK");
+			break;
+		}
+	}
+
+	printf("loop done\n");
+
+	//sangoma_get_full_cfg(fd, &tdm_api);
+	close(file);
+	//close(ifd);
+
+	pri_hangup(spri->pri, channo, 16);
+	if (zap_channel_close(&chan) != ZAP_SUCCESS) {
+		printf("Critical Error: Failed to close channel [%s]\n", chan->last_error);
+	}
+
+	printf("Call Handler: Process Finished\n");
+	exit(0);
+}
+
+
+/* Event Handlers */
+
+static int on_info(struct sangoma_pri *spri, sangoma_pri_event_t event_type, pri_event *event) 
+{
+	printf( "number is: %s\n", event->ring.callednum);
+	if(strlen(event->ring.callednum) > 3) {
+		printf( "final number is: %s\n", event->ring.callednum);
+		pri_answer(spri->pri, event->ring.call, 0, 1);
+	}
+	return 0;
+}
+
+static int on_hangup(struct sangoma_pri *spri, sangoma_pri_event_t event_type, pri_event *event) 
+{
+	//pri_hangup(spri->pri, event->hangup.call, event->hangup.cause);
+	printf("-- Hanging up channel %d\n", event->hangup.channel);
+	if(pidmap[event->hangup.channel-1].pid) {
+		pri_hangup(spri->pri, event->hangup.call, 16);
+		pri_destroycall(spri->pri, event->hangup.call);
+		kill(pidmap[event->hangup.channel-1].pid, SIGINT);
+		pidmap[event->hangup.channel-1].pid = 0;
+	}
+	return 0;
+}
+
+static int on_ring(struct sangoma_pri *spri, sangoma_pri_event_t event_type, pri_event *event) 
+{
+	printf("-- Ring on channel %d (from %s to %s), answering...\n", event->ring.channel, event->ring.callingnum, event->ring.callednum);
+	pri_answer(spri->pri, event->ring.call, event->ring.channel, 1);
+	memcpy(&pidmap[event->ring.channel-1].call, event->ring.call, sizeof(q931_call));
+	pidmap[event->ring.channel-1].pri=spri->pri;
+	pidmap[event->ring.channel-1].call = *event->ring.call;
+	launch_channel(spri, event->ring.channel);
+	return 0;
+}
+
+static int on_restart(struct sangoma_pri *spri, sangoma_pri_event_t event_type, pri_event *event)
+{
+	printf("-- Restarting channel %d\n", event->restart.channel);
+	return 0;
+}
+
+static int on_anything(struct sangoma_pri *spri, sangoma_pri_event_t event_type, pri_event *event) 
+{
+	printf("%s: Caught Event %d (%s)\n", __FUNCTION__, event_type, sangoma_pri_event_str(event_type));
+	return 0;
+}
+
+/* Generic Reaper */
+static void chan_ended(int sig)
+{
+	int status;
+	int x;
+	struct rusage rusage;
+	pid_t pid;
+	pid = wait4(-1, &status, WNOHANG, &rusage);
+
+	printf("-- PID %d ended\n", pid);
+
+	for (x=0;x<SANGOMA_MAX_CHAN_PER_SPAN;x++) {
+		if (pid == pidmap[x].pid) {
+			pidmap[x].pid = 0;
+			if (pidmap[x].pri){
+				int err=pri_hangup(pidmap[x].pri, &pidmap[x].call, 16);
+				//pri_destroycall(pidmap[x].pri, &pidmap[x].call);
+				printf("Hanging up on PID %i Err=%i\n",pid,err);
+			}
+
+			pidmap[x].pri=NULL;
+			signal(SIGCHLD, chan_ended);
+			return;
+		}
+	}
+
+	if (pid > -1) {
+		fprintf(stderr, "--!! Unknown PID %d exited\n", pid);
+		signal(SIGCHLD, chan_ended);
+		return;
+	}
+}
+
+/* Our Program */
+int main(int argc, char *argv[])
+{
+	struct sangoma_pri spri;
+	int debug = 0;
+	if (argv[1]) {
+		debug = atoi(argv[1]);
+	}
+
+	zap_global_set_default_logger(ZAP_LOG_LEVEL_DEBUG);
+	if (zap_global_init() != ZAP_SUCCESS) {
+        fprintf(stderr, "Error loading OpenZAP\n");
+        exit(-1);
+    }
+
+    printf("OpenZAP loaded\n");
+
+
+	debug = PRI_DEBUG_Q931_DUMP | PRI_DEBUG_Q931_STATE;
+	printf("WTF %d\n", debug);
+
+	if (sangoma_init_pri(&spri,
+						 1,  // span
+						 24, // dchan
+						 SANGOMA_PRI_SWITCH_DMS100,
+						 SANGOMA_PRI_CPE,
+						 debug) < 0) {
+		return -1;
+	}
+	//spri.pri->debug = (PRI_DEBUG_Q931_DUMP | PRI_DEBUG_Q921_DUMP | PRI_DEBUG_Q921_RAW | PRI_DEBUG_Q921_STATE);
+
+	//pri_set_debug(&spri.pri, (PRI_DEBUG_Q931_DUMP | PRI_DEBUG_Q921_DUMP | PRI_DEBUG_Q921_RAW | PRI_DEBUG_Q921_STATE));
+
+	SANGOMA_MAP_PRI_EVENT(spri, SANGOMA_PRI_EVENT_ANY, on_anything);
+	SANGOMA_MAP_PRI_EVENT(spri, SANGOMA_PRI_EVENT_RING, on_ring);
+	SANGOMA_MAP_PRI_EVENT(spri, SANGOMA_PRI_EVENT_HANGUP, on_hangup);
+	SANGOMA_MAP_PRI_EVENT(spri, SANGOMA_PRI_EVENT_HANGUP_REQ, on_hangup);
+	SANGOMA_MAP_PRI_EVENT(spri, SANGOMA_PRI_EVENT_INFO_RECEIVED, on_info);
+	SANGOMA_MAP_PRI_EVENT(spri, SANGOMA_PRI_EVENT_RESTART, on_restart);
+
+	signal(SIGCHLD, chan_ended);
+	sangoma_run_pri(&spri);
+	return 0;
+}
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */

Added: freeswitch/trunk/libs/openzap/src/sangoma_pri.c (0 => 17141)


--- freeswitch/trunk/libs/openzap/src/sangoma_pri.c	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/src/sangoma_pri.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,251 @@
+/*****************************************************************************
+ * sangoma_pri.c libpri Sangoma integration
+ *
+ * Author(s):	Anthony Minessale II <anthmct@yahoo.com>
+ *              Nenad Corbic <ncorbic@sangoma.com>
+ *
+ * Copyright:	(c) 2005 Anthony Minessale II
+ *
+ *		This program is free software; you can redistribute it and/or
+ *		modify it under the terms of the GNU General Public License
+ *		as published by the Free Software Foundation; either version
+ *		2 of the License, or (at your option) any later version.
+ * ============================================================================
+ */
+
+#include "openzap.h"
+#include <sangoma_pri.h>
+#ifndef HAVE_GETTIMEOFDAY
+
+#ifdef WIN32
+#include <mmsystem.h>
+
+static __inline int gettimeofday(struct timeval *tp, void *nothing)
+{
+#ifdef WITHOUT_MM_LIB
+	SYSTEMTIME st;
+	time_t tt;
+	struct tm tmtm;
+	/* mktime converts local to UTC */
+	GetLocalTime (&st);
+	tmtm.tm_sec = st.wSecond;
+	tmtm.tm_min = st.wMinute;
+	tmtm.tm_hour = st.wHour;
+	tmtm.tm_mday = st.wDay;
+	tmtm.tm_mon = st.wMonth - 1;
+	tmtm.tm_year = st.wYear - 1900;  tmtm.tm_isdst = -1;
+	tt = mktime (&tmtm);
+	tp->tv_sec = tt;
+	tp->tv_usec = st.wMilliseconds * 1000;
+#else
+	/**
+	 ** The earlier time calculations using GetLocalTime
+	 ** had a time resolution of 10ms.The timeGetTime, part
+	 ** of multimedia apis offer a better time resolution
+	 ** of 1ms.Need to link against winmm.lib for this
+	 **/
+	unsigned long Ticks = 0;
+	unsigned long Sec =0;
+	unsigned long Usec = 0;
+	Ticks = timeGetTime();
+
+	Sec = Ticks/1000;
+	Usec = (Ticks - (Sec*1000))*1000;
+	tp->tv_sec = Sec;
+	tp->tv_usec = Usec;
+#endif /* WITHOUT_MM_LIB */
+	(void)nothing;
+	return 0;
+}
+#endif /* WIN32 */
+#endif /* HAVE_GETTIMEOFDAY */
+
+static struct sangoma_pri_event_list SANGOMA_PRI_EVENT_LIST[] = {
+	{0, SANGOMA_PRI_EVENT_ANY, "ANY"},
+	{1, SANGOMA_PRI_EVENT_DCHAN_UP, "DCHAN_UP"},
+	{2, SANGOMA_PRI_EVENT_DCHAN_DOWN, "DCHAN_DOWN"},
+	{3, SANGOMA_PRI_EVENT_RESTART, "RESTART"},
+	{4, SANGOMA_PRI_EVENT_CONFIG_ERR, "CONFIG_ERR"},
+	{5, SANGOMA_PRI_EVENT_RING, "RING"},
+	{6, SANGOMA_PRI_EVENT_HANGUP, "HANGUP"},
+	{7, SANGOMA_PRI_EVENT_RINGING, "RINGING"},
+	{8, SANGOMA_PRI_EVENT_ANSWER, "ANSWER"},
+	{9, SANGOMA_PRI_EVENT_HANGUP_ACK, "HANGUP_ACK"},
+	{10, SANGOMA_PRI_EVENT_RESTART_ACK, "RESTART_ACK"},
+	{11, SANGOMA_PRI_EVENT_FACNAME, "FACNAME"},
+	{12, SANGOMA_PRI_EVENT_INFO_RECEIVED, "INFO_RECEIVED"},
+	{13, SANGOMA_PRI_EVENT_PROCEEDING, "PROCEEDING"},
+	{14, SANGOMA_PRI_EVENT_SETUP_ACK, "SETUP_ACK"},
+	{15, SANGOMA_PRI_EVENT_HANGUP_REQ, "HANGUP_REQ"},
+	{16, SANGOMA_PRI_EVENT_NOTIFY, "NOTIFY"},
+	{17, SANGOMA_PRI_EVENT_PROGRESS, "PROGRESS"},
+	{18, SANGOMA_PRI_EVENT_KEYPAD_DIGIT, "KEYPAD_DIGIT"}
+};
+
+#define LINE "--------------------------------------------------------------------------------"
+
+char *sangoma_pri_event_str(sangoma_pri_event_t event_id)
+{ 
+	return SANGOMA_PRI_EVENT_LIST[event_id].name;
+}
+
+static int __pri_sangoma_read(struct pri *pri, void *buf, int buflen)
+{
+	struct sangoma_pri *spri = (struct sangoma_pri *) pri->userdata;
+	zap_size_t len = buflen;
+	int res;
+	char bb[4096] = "";
+
+
+	if (zap_channel_read(spri->zdchan, buf, &len) != ZAP_SUCCESS) {
+		printf("D-READ FAIL! [%s]\n", spri->zdchan->last_error);
+		return 0;
+	}
+	res = (int)len;
+	memset(&((unsigned char*)buf)[res],0,2);
+	res+=2;
+
+	//print_bits(buf, res-2, bb, sizeof(bb), 1, 0);
+	//zap_log(ZAP_LOG_DEBUG, "READ %d\n%s\n%s\n\n", res-2, LINE, bb);
+
+	return res;
+}
+
+static int __pri_sangoma_write(struct pri *pri, void *buf, int buflen)
+{
+	struct sangoma_pri *spri = (struct sangoma_pri *) pri->userdata;
+	int res;
+	zap_size_t len = buflen -2;
+	char bb[4096] = "";
+
+	if (zap_channel_write(spri->zdchan, buf, buflen, &len) != ZAP_SUCCESS) {
+		printf("D-WRITE FAIL! [%s]\n", spri->zdchan->last_error);
+        return 0;
+	}
+	
+	//print_bits(buf, (int)buflen-2, bb, sizeof(bb), 1, 0);
+	//zap_log(ZAP_LOG_DEBUG, "WRITE %d\n%s\n%s\n\n", (int)buflen-2, LINE, bb);
+
+	return (int) buflen;
+}
+
+int sangoma_init_pri(struct sangoma_pri *spri, int span, int dchan, int swtype, int node, int debug)
+{
+	int ret = -1;
+	zap_socket_t dfd = 0;
+
+	memset(spri, 0, sizeof(struct sangoma_pri));
+
+	if (zap_channel_open(span, dchan, &spri->zdchan) != ZAP_SUCCESS) {
+		fprintf(stderr, "Unable to open DCHAN %d for span %d (%s)\n", dchan, span, strerror(errno));
+	} else {
+		if ((spri->pri = pri_new_cb(spri->zdchan->sockfd, node, swtype, __pri_sangoma_read, __pri_sangoma_write, spri))){
+			spri->span = span;
+			pri_set_debug(spri->pri, debug);
+			ret = 0;
+		} else {
+			fprintf(stderr, "Unable to create PRI\n");
+		}
+	}
+	return ret;
+}
+
+
+int sangoma_one_loop(struct sangoma_pri *spri)
+{
+	fd_set rfds, efds;
+	struct timeval now = {0,0}, *next;
+	pri_event *event;
+    int sel;
+	
+	if (spri->on_loop) {
+		spri->on_loop(spri);
+	}
+
+	FD_ZERO(&rfds);
+	FD_ZERO(&efds);
+
+#ifdef _MSC_VER
+	//Windows macro for FD_SET includes a warning C4127: conditional expression is constant
+#pragma warning(push)
+#pragma warning(disable:4127)
+#endif
+
+	FD_SET(spri->pri->fd, &rfds);
+	FD_SET(spri->pri->fd, &efds);
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+	if ((next = pri_schedule_next(spri->pri))) {
+		gettimeofday(&now, NULL);
+		now.tv_sec = next->tv_sec - now.tv_sec;
+		now.tv_usec = next->tv_usec - now.tv_usec;
+		if (now.tv_usec < 0) {
+			now.tv_usec += 1000000;
+			now.tv_sec -= 1;
+		}
+		if (now.tv_sec < 0) {
+			now.tv_sec = 0;
+			now.tv_usec = 0;
+		}
+	}
+
+	sel = select(spri->pri->fd + 1, &rfds, NULL, &efds, next ? &now : NULL);
+	event = NULL;
+
+	if (!sel) {
+		event = pri_schedule_run(spri->pri);
+	} else if (sel > 0) {
+		event = pri_check_event(spri->pri);
+	}
+
+	if (event) {
+		event_handler handler;
+		/* 0 is catchall event handler */
+		if ((handler = spri->eventmap[event->e] ? spri->eventmap[event->e] : spri->eventmap[0] ? spri->eventmap[0] : NULL)) {
+			handler(spri, event->e, event);
+		} else {
+			fprintf(stderr,"No event handler found for event %d.\n", event->e);
+		}
+	}
+
+	return sel;
+}
+
+int sangoma_run_pri(struct sangoma_pri *spri)
+{
+	int ret = 0;
+
+	for (;;){
+		ret=sangoma_one_loop(spri);
+		if (ret < 0){
+
+#ifndef WIN32 //This needs to be adressed fror WIN32 still
+			if (errno == EINTR){
+				/* Igonore an interrupted system call */
+				continue;
+			}
+#endif	
+			printf("Error = %i\n",ret);
+			perror("Sangoma Run Pri: ");
+			break;		
+		}
+	}
+
+	return ret;
+
+}
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
+

Added: freeswitch/trunk/libs/openzap/src/sangoma_pri.h (0 => 17141)


--- freeswitch/trunk/libs/openzap/src/sangoma_pri.h	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/src/sangoma_pri.h	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,100 @@
+/*****************************************************************************
+ * libsangoma.c	AFT T1/E1: HDLC API Code Library
+ *
+ * Author(s):	Anthony Minessale II <anthmct@yahoo.com>
+ *              Nenad Corbic <ncorbic@sangoma.com>
+ *
+ * Copyright:	(c) 2005 Anthony Minessale II
+ *
+ *		This program is free software; you can redistribute it and/or
+ *		modify it under the terms of the GNU General Public License
+ *		as published by the Free Software Foundation; either version
+ *		2 of the License, or (at your option) any later version.
+ * ============================================================================
+ */
+
+#ifndef _SANGOMA_PRI_H
+#define _SANGOMA_PRI_H
+#include <libpri.h>
+#include <pri_internal.h>
+
+
+#define SANGOMA_MAX_CHAN_PER_SPAN 32
+
+typedef enum {
+	SANGOMA_PRI_EVENT_ANY = 0,
+	SANGOMA_PRI_EVENT_DCHAN_UP = PRI_EVENT_DCHAN_UP,
+	SANGOMA_PRI_EVENT_DCHAN_DOWN = PRI_EVENT_DCHAN_DOWN,
+	SANGOMA_PRI_EVENT_RESTART = PRI_EVENT_RESTART,
+	SANGOMA_PRI_EVENT_CONFIG_ERR = PRI_EVENT_CONFIG_ERR,
+	SANGOMA_PRI_EVENT_RING = PRI_EVENT_RING,
+	SANGOMA_PRI_EVENT_HANGUP = PRI_EVENT_HANGUP,
+	SANGOMA_PRI_EVENT_RINGING = PRI_EVENT_RINGING,
+	SANGOMA_PRI_EVENT_ANSWER = PRI_EVENT_ANSWER,
+	SANGOMA_PRI_EVENT_HANGUP_ACK = PRI_EVENT_HANGUP_ACK,
+	SANGOMA_PRI_EVENT_RESTART_ACK = PRI_EVENT_RESTART_ACK,
+	SANGOMA_PRI_EVENT_FACNAME = PRI_EVENT_FACNAME,
+	SANGOMA_PRI_EVENT_INFO_RECEIVED = PRI_EVENT_INFO_RECEIVED,
+	SANGOMA_PRI_EVENT_PROCEEDING = PRI_EVENT_PROCEEDING,
+	SANGOMA_PRI_EVENT_SETUP_ACK = PRI_EVENT_SETUP_ACK,
+	SANGOMA_PRI_EVENT_HANGUP_REQ = PRI_EVENT_HANGUP_REQ,
+	SANGOMA_PRI_EVENT_NOTIFY = PRI_EVENT_NOTIFY,
+	SANGOMA_PRI_EVENT_PROGRESS = PRI_EVENT_PROGRESS,
+	SANGOMA_PRI_EVENT_KEYPAD_DIGIT = PRI_EVENT_KEYPAD_DIGIT
+} sangoma_pri_event_t;
+
+typedef enum {
+	SANGOMA_PRI_NETWORK = PRI_NETWORK,
+	SANGOMA_PRI_CPE = PRI_CPE
+} sangoma_pri_node_t;
+
+typedef enum {
+	SANGOMA_PRI_SWITCH_UNKNOWN = PRI_SWITCH_UNKNOWN,
+	SANGOMA_PRI_SWITCH_NI2 = PRI_SWITCH_NI2,	   		
+	SANGOMA_PRI_SWITCH_DMS100 = PRI_SWITCH_DMS100,
+	SANGOMA_PRI_SWITCH_LUCENT5E = PRI_SWITCH_LUCENT5E,
+	SANGOMA_PRI_SWITCH_ATT4ESS = PRI_SWITCH_ATT4ESS,
+	SANGOMA_PRI_SWITCH_EUROISDN_E1 = PRI_SWITCH_EUROISDN_E1,
+	SANGOMA_PRI_SWITCH_EUROISDN_T1 = PRI_SWITCH_EUROISDN_T1,
+	SANGOMA_PRI_SWITCH_NI1 = PRI_SWITCH_NI1,
+	SANGOMA_PRI_SWITCH_GR303_EOC = PRI_SWITCH_GR303_EOC,
+	SANGOMA_PRI_SWITCH_GR303_TMC = PRI_SWITCH_GR303_TMC,
+	SANGOMA_PRI_SWITCH_QSIG = PRI_SWITCH_QSIG
+} sangoma_pri_switch_t;
+
+typedef enum {
+	SANGOMA_PRI_READY = (1 << 0)
+} sangoma_pri_flag_t;
+
+struct sangoma_pri;
+typedef int (*event_handler)(struct sangoma_pri *, sangoma_pri_event_t, pri_event *);
+typedef int (*loop_handler)(struct sangoma_pri *);
+#define MAX_EVENT 18
+
+struct sangoma_pri {
+	struct pri *pri;
+	int span;
+	int dchan;
+	unsigned int flags;
+	void *private_info;
+	event_handler eventmap[MAX_EVENT+1];
+	loop_handler on_loop;
+	zap_channel_t *zdchan;
+};
+
+struct sangoma_pri_event_list {
+	int event_id;
+	int pri_event;
+	char *name;
+};
+
+
+
+#define SANGOMA_MAP_PRI_EVENT(spri, event, func) spri.eventmap[event] = func;
+
+char *sangoma_pri_event_str(sangoma_pri_event_t event_id);
+int sangoma_one_loop(struct sangoma_pri *spri);
+int sangoma_init_pri(struct sangoma_pri *spri, int span, int dchan, int swtype, int node, int debug);
+int sangoma_run_pri(struct sangoma_pri *spri);
+
+#endif

Added: freeswitch/trunk/libs/openzap/src/ss7/README (0 => 17141)


--- freeswitch/trunk/libs/openzap/src/ss7/README	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/src/ss7/README	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,3 @@
+SS7 Coming soon
+
+-Shane Burrell-

Added: freeswitch/trunk/libs/openzap/src/testanalog.c (0 => 17141)


--- freeswitch/trunk/libs/openzap/src/testanalog.c	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/src/testanalog.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,133 @@
+#include "openzap.h"
+
+
+static void *test_call(zap_thread_t *me, void *obj)
+{
+	zap_channel_t *chan = (zap_channel_t *) obj;
+	uint8_t frame[1024];
+	zap_size_t len;
+	char *number = strdup("5551212");
+
+	zap_sleep(10 * 1000);
+	
+	zap_log(ZAP_LOG_DEBUG, "answer call and start echo test\n");
+
+	zap_set_state_locked(chan, ZAP_CHANNEL_STATE_UP);
+	zap_channel_command(chan, ZAP_COMMAND_SEND_DTMF, number);
+
+	while (chan->state == ZAP_CHANNEL_STATE_UP) {
+		zap_wait_flag_t flags = ZAP_READ;
+		
+		if (zap_channel_wait(chan, &flags, -1) == ZAP_FAIL) {
+			break;
+		}
+		len = sizeof(frame);
+		if (flags & ZAP_READ) {
+			if (zap_channel_read(chan, frame, &len) == ZAP_SUCCESS) {
+				//zap_log(ZAP_LOG_DEBUG, "WRITE %d\n", len);
+				zap_channel_write(chan, frame, sizeof(frame), &len);
+			} else {
+				break;
+			}
+		}
+	}
+	
+	if (chan->state == ZAP_CHANNEL_STATE_UP) {
+		zap_set_state_locked(chan, ZAP_CHANNEL_STATE_BUSY);
+	}
+
+	zap_log(ZAP_LOG_DEBUG, "call over\n");
+	free(number);
+	return NULL;
+}
+
+static ZIO_SIGNAL_CB_FUNCTION(on_signal)
+{
+	zap_log(ZAP_LOG_DEBUG, "got sig [%s]\n", zap_signal_event2str(sigmsg->event_id));
+
+	switch(sigmsg->event_id) {
+	case ZAP_SIGEVENT_START:
+		zap_set_state_locked(sigmsg->channel, ZAP_CHANNEL_STATE_RING);
+		zap_log(ZAP_LOG_DEBUG, "launching thread and indicating ring\n");
+		zap_thread_create_detached(test_call, sigmsg->channel);
+		break;
+	default:
+		break;
+	}
+
+	return ZAP_SUCCESS;
+}
+
+static int R = 0;
+#if 0
+static void handle_SIGINT(int sig)
+{
+	if (sig);
+	R = 0;
+	return;
+}
+#endif
+
+int main(int argc, char *argv[])
+{
+	zap_span_t *span;
+	int span_id;
+	int digit_timeout = 2000;
+	int max_dialstr = 11;
+
+	if (argc < 2) {
+		printf("usage %s <spanno>\n", argv[0]);
+		exit(-1);
+	}
+
+	span_id = atoi(argv[1]);
+
+	zap_global_set_default_logger(ZAP_LOG_LEVEL_DEBUG);
+
+	if (zap_global_init() != ZAP_SUCCESS) {
+		zap_log(ZAP_LOG_ERROR, "Error loading OpenZAP\n");
+		exit(-1);
+	}
+
+	zap_log(ZAP_LOG_DEBUG, "OpenZAP loaded\n");
+
+	if (zap_span_find(span_id, &span) != ZAP_SUCCESS) {
+		zap_log(ZAP_LOG_ERROR, "Error finding OpenZAP span\n");
+		goto done;
+	}
+	
+
+	if (zap_configure_span("analog", span, on_signal, 
+						   "tonemap", "us", 
+						   "digit_timeout", &digit_timeout,
+						   "max_dialstr", &max_dialstr,
+						   TAG_END
+						   ) != ZAP_SUCCESS) {
+		zap_log(ZAP_LOG_ERROR, "Error configuring OpenZAP span\n");
+		goto done;
+	}
+	zap_span_start(span);
+	
+	R = 1;
+
+	while(zap_running() && R) {
+		zap_sleep(1 * 1000);
+	}
+
+done:
+
+	zap_global_destroy();
+	return 0;
+}
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
+

Added: freeswitch/trunk/libs/openzap/src/testapp.c (0 => 17141)


--- freeswitch/trunk/libs/openzap/src/testapp.c	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/src/testapp.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,83 @@
+#include "openzap.h"
+
+int main(int argc, char *argv[])
+{
+	zap_global_set_default_logger(ZAP_LOG_LEVEL_DEBUG);
+	zap_channel_t *chan;
+	unsigned ms = 20;
+	zap_codec_t codec = ZAP_CODEC_SLIN;
+	unsigned runs = 1;
+
+
+	if (zap_global_init() != ZAP_SUCCESS) {
+		fprintf(stderr, "Error loading OpenZAP\n");
+		exit(-1);
+	}
+
+	printf("OpenZAP loaded\n");
+
+ top:
+	//if (zap_channel_open_any("wanpipe", 0, ZAP_TOP_DOWN, &chan) == ZAP_SUCCESS) {
+	if (zap_channel_open(1, 1, &chan) == ZAP_SUCCESS) {
+		int x = 0;
+		printf("opened channel %d:%d\n", chan->span_id, chan->chan_id);
+
+#if 1
+		if (zap_channel_command(chan, ZAP_COMMAND_SET_INTERVAL, &ms) == ZAP_SUCCESS) {
+			ms = 0;
+			zap_channel_command(chan, ZAP_COMMAND_GET_INTERVAL, &ms);
+			printf("interval set to %u\n", ms);
+		} else {
+			printf("set interval failed [%s]\n", chan->last_error);
+		}
+#endif
+		if (zap_channel_command(chan, ZAP_COMMAND_SET_CODEC, &codec) == ZAP_SUCCESS) {
+			codec = 1;
+			zap_channel_command(chan, ZAP_COMMAND_GET_CODEC, &codec);
+			printf("codec set to %u\n", codec);
+		} else {
+			printf("set codec failed [%s]\n", chan->last_error);
+		}
+
+		for(x = 0; x < 25; x++) {
+			unsigned char buf[2048];
+			zap_size_t len = sizeof(buf);
+			zap_wait_flag_t flags = ZAP_READ;
+
+			if (zap_channel_wait(chan, &flags, -1) == ZAP_FAIL) {
+				printf("wait FAIL! %u [%s]\n", (unsigned)len, chan->last_error);
+			}
+			if (flags & ZAP_READ) {
+				if (zap_channel_read(chan, buf, &len) == ZAP_SUCCESS) {
+					printf("READ: %u\n", (unsigned)len); 
+				} else {
+					printf("READ FAIL! %u [%s]\n", (unsigned)len, chan->last_error);
+					break;
+				}
+			} else {
+				printf("wait fail [%s]\n", chan->last_error);
+			}
+		}
+		zap_channel_close(&chan);
+	} else {
+		printf("open fail [%s]\n", chan->last_error);
+	}
+
+	if(--runs) {
+		goto top;
+	}
+
+	zap_global_destroy();
+	return 0;
+}
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */

Added: freeswitch/trunk/libs/openzap/src/testboost.c (0 => 17141)


--- freeswitch/trunk/libs/openzap/src/testboost.c	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/src/testboost.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,75 @@
+#include "openzap.h"
+
+static ZIO_SIGNAL_CB_FUNCTION(on_signal)
+{
+	return ZAP_FAIL;
+}
+
+static int R = 0;
+#if 0
+static void handle_SIGINT(int sig)
+{
+	if (sig);
+	R = 0;
+	return;
+}
+#endif
+int main(int argc, char *argv[])
+{
+	zap_span_t *span;
+	int local_port, remote_port;
+
+	local_port = remote_port = 53000;
+
+	zap_global_set_default_logger(ZAP_LOG_LEVEL_DEBUG);
+
+	if (argc < 2) {
+		printf("umm no\n");
+		exit(-1);
+	}
+
+	if (zap_global_init() != ZAP_SUCCESS) {
+		fprintf(stderr, "Error loading OpenZAP\n");
+		exit(-1);
+	}
+
+	printf("OpenZAP loaded\n");
+
+	if (zap_span_find(atoi(argv[1]), &span) != ZAP_SUCCESS) {
+		fprintf(stderr, "Error finding OpenZAP span\n");
+		goto done;
+	}
+	
+	if (zap_configure_span("ss7_boost", span, on_signal, 
+						   "local_ip", "127.0.0.65",
+						   "local_port", &local_port,
+						   "remote_ip", "127.0.0.66",
+						   "remote_port", &remote_port,
+						   TAG_END) == ZAP_SUCCESS) {
+		zap_span_start(span);
+	} else {
+		fprintf(stderr, "Error starting SS7_BOOST\n");
+		goto done;
+	}
+
+	while(zap_running() && R) {
+		zap_sleep(1 * 1000);
+	}
+
+ done:
+
+	zap_global_destroy();
+
+	return 0;
+}
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */

Added: freeswitch/trunk/libs/openzap/src/testcid.c (0 => 17141)


--- freeswitch/trunk/libs/openzap/src/testcid.c	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/src/testcid.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,108 @@
+#include "openzap.h"
+zap_status_t my_write_sample(int16_t *buf, zap_size_t buflen, void *user_data);
+
+struct helper {
+	int fd;
+	int wrote;
+};
+
+zap_status_t my_write_sample(int16_t *buf, zap_size_t buflen, void *user_data)
+{
+	struct helper *foo = (struct helper *) user_data;
+        size_t len;
+	len = write(foo->fd, buf, buflen * 2);
+        if (!len) return ZAP_FAIL;
+	foo->wrote += buflen * 2;
+	return ZAP_SUCCESS;
+}
+
+int main(int argc, char *argv[])
+{
+	struct zap_fsk_modulator fsk_trans;
+	zap_fsk_data_state_t fsk_data = {0};
+	int fd = -1;
+	int16_t buf[160] = {0};
+	ssize_t len = 0;
+	size_t type, mlen;
+	char *sp;
+	char str[128] = "";
+	char fbuf[256];
+	uint8_t databuf[1024] = "";
+	struct helper foo = {0};
+	//	int x, bytes, start_bits = 180, stop_bits = 5, sbits = 300;
+	char time_str[9];
+	struct tm tm;
+	time_t now;
+	
+	if (argc < 2) {
+		int x;
+		const char *url = "sip:cool@rad.com";
+
+		if ((fd = open("tone.raw", O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR)) < 0) {
+			fprintf(stderr, "File Error! [%s]\n", strerror(errno));
+			exit(-1);
+		}
+
+
+		time(&now);
+		localtime_r(&now, &tm);
+		strftime(time_str, sizeof(time_str), "%m%d%H%M", &tm);
+
+		zap_fsk_data_init(&fsk_data, databuf, sizeof(databuf));
+#if 1
+		
+		zap_fsk_data_add_mdmf(&fsk_data, MDMF_DATETIME, (uint8_t *)time_str, strlen(time_str));
+		//zap_fsk_data_add_mdmf(&fsk_data, MDMF_DATETIME, "06091213", 8);
+		zap_fsk_data_add_mdmf(&fsk_data, MDMF_PHONE_NUM, (uint8_t *)"14149361212", 7);
+		zap_fsk_data_add_mdmf(&fsk_data, MDMF_PHONE_NAME, (uint8_t *)"Fred Smith", 10);
+		for(x = 0; x < 0; x++)
+			zap_fsk_data_add_mdmf(&fsk_data, MDMF_ALT_ROUTE, (uint8_t *)url, strlen(url));
+#else
+		zap_fsk_data_add_sdmf(&fsk_data, "06061234", "0");
+		//zap_fsk_data_add_sdmf(&state, "06061234", "5551212");
+#endif
+		zap_fsk_data_add_checksum(&fsk_data);
+
+		foo.fd = fd;
+
+
+		zap_fsk_modulator_init(&fsk_trans, FSK_BELL202, 8000, &fsk_data, -14, 180, 5, 300, my_write_sample, &foo);
+		zap_fsk_modulator_send_all((&fsk_trans));
+
+		printf("%u %d %d\n", (unsigned) fsk_data.dlen, foo.wrote, fsk_trans.est_bytes);
+
+		if (fd > -1) {
+			close (fd);
+		}
+
+		return 0;
+	}
+
+	if (zap_fsk_demod_init(&fsk_data, 8000, (uint8_t *)fbuf, sizeof(fbuf))) {
+		printf("wtf\n");
+		return 0;
+	}
+
+	if ((fd = open(argv[1], O_RDONLY)) < 0) {
+		fprintf(stderr, "cant open file %s\n", argv[1]);
+		exit (-1);
+	}
+
+	while((len = read(fd, buf, sizeof(buf))) > 0) {
+		if (zap_fsk_demod_feed(&fsk_data, buf, len / 2) != ZAP_SUCCESS) {
+			break;
+		}
+	}
+
+	while(zap_fsk_data_parse(&fsk_data, &type, &sp, &mlen) == ZAP_SUCCESS) {
+		zap_copy_string(str, sp, mlen+1);
+		*(str+mlen) = '\0';
+		zap_clean_string(str);
+		printf("TYPE %u (%s) LEN %u VAL [%s]\n", (unsigned)type, zap_mdmf_type2str(type), (unsigned)mlen, str);
+	}
+
+	zap_fsk_demod_destroy(&fsk_data);
+
+	close(fd);
+	return 0;
+}

Added: freeswitch/trunk/libs/openzap/src/testisdn.c (0 => 17141)


--- freeswitch/trunk/libs/openzap/src/testisdn.c	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/src/testisdn.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,74 @@
+#include "openzap.h"
+#include <signal.h>
+
+
+static ZIO_SIGNAL_CB_FUNCTION(on_signal)
+{
+	return ZAP_FAIL;
+}
+
+static int R = 0;
+static void handle_SIGINT(int sig)
+{
+	if (sig);
+	R = 0;
+	return;
+}
+
+int main(int argc, char *argv[])
+{
+	zap_span_t *span;
+	
+	zap_global_set_default_logger(ZAP_LOG_LEVEL_DEBUG);
+
+	if (argc < 2) {
+		printf("umm no\n");
+		exit(-1);
+	}
+
+	if (zap_global_init() != ZAP_SUCCESS) {
+		fprintf(stderr, "Error loading OpenZAP\n");
+		exit(-1);
+	}
+
+	printf("OpenZAP loaded\n");
+
+	if (zap_span_find(atoi(argv[1]), &span) != ZAP_SUCCESS) {
+		fprintf(stderr, "Error finding OpenZAP span\n");
+		goto done;
+	}
+	
+	if (zap_configure_span("isdn", span, on_signal, 
+						   "mode", "te", 
+						   "dialect", "national",
+						   TAG_END) == ZAP_SUCCESS) {
+		zap_span_start(span);
+	} else {
+		fprintf(stderr, "Error starting ISDN D-Channel\n");
+		goto done;
+	}
+
+	signal(SIGINT, handle_SIGINT);
+	R = 1;
+	while(R) {
+		zap_sleep(1 * 1000);
+	}
+
+ done:
+
+	zap_global_destroy();
+
+	return 1;
+
+}
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */

Added: freeswitch/trunk/libs/openzap/src/testm3ua.c (0 => 17141)


--- freeswitch/trunk/libs/openzap/src/testm3ua.c	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/src/testm3ua.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,60 @@
+/*
+ *  testm3ua.c
+ *  openzap
+ *
+ *  Created by Shane Burrell on 4/8/08.
+ *  Copyright 2008 __MyCompanyName__. All rights reserved.
+ *
+ */
+
+#include "testm3ua.h"
+#include "openzap.h"
+#include "zap_m3ua.h"
+
+static ZIO_SIGNAL_CB_FUNCTION(on_signal)
+{
+	return ZAP_FAIL;
+}
+
+int main(int argc, char *argv[])
+{
+	zap_span_t *span;
+	//m3ua_data_t *data;
+
+	zap_global_set_default_logger(ZAP_LOG_LEVEL_DEBUG);
+
+	if (argc < 5) {
+		printf("more args needed\n");
+		exit(-1);
+	}
+
+	if (zap_global_init() != ZAP_SUCCESS) {
+		fprintf(stderr, "Error loading OpenZAP\n");
+		exit(-1);
+	}
+
+	printf("OpenZAP loaded\n");
+
+	if (zap_span_find(atoi(argv[1]), &span) != ZAP_SUCCESS) {
+		fprintf(stderr, "Error finding OpenZAP span\n");
+		goto done;
+	}
+	
+
+	if (zap_m3ua_configure_span(span) == ZAP_SUCCESS) {
+		//data = span->signal_data;
+		zap_m3ua_start(span);
+	} else {
+		fprintf(stderr, "Error starting M3UA\n");
+		goto done;
+	}
+
+	//while(zap_test_flag(data, ZAP_M3UA_RUNNING)) {
+	//	zap_sleep(1 * 1000);
+	//}
+
+ done:
+
+	zap_global_destroy();
+
+}

Added: freeswitch/trunk/libs/openzap/src/testpri.c (0 => 17141)


--- freeswitch/trunk/libs/openzap/src/testpri.c	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/src/testpri.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,162 @@
+#include "openzap.h"
+#include <signal.h>
+
+static int THREADS[4][31] = { {0} };
+static int R = 0;
+static int T = 0;
+static zap_mutex_t *mutex = NULL;
+
+
+static void *channel_run(zap_thread_t *me, void *obj)
+{
+	zap_channel_t *zchan = obj;
+	int fd = -1;
+	short buf[160];
+
+	zap_mutex_lock(mutex);
+	T++;
+	zap_mutex_unlock(mutex);
+
+	zap_set_state_locked_wait(zchan, ZAP_CHANNEL_STATE_UP);
+
+	if ((fd = open("test.raw", O_RDONLY, 0)) < 0) {
+		goto end;
+	}
+
+	while(R == 1 && THREADS[zchan->span_id][zchan->chan_id] == 1) {
+		ssize_t bytes = read(fd, buf, sizeof(buf));
+		size_t bbytes;
+
+		if (bytes <= 0) {
+			break;
+		}
+
+		bbytes = (size_t) bytes;
+
+		zio_slin2alaw(buf, sizeof(buf), &bbytes);
+
+		if (zap_channel_write(zchan, buf, sizeof(buf), &bbytes) != ZAP_SUCCESS) {
+			break;
+		}
+	}
+
+	close(fd);
+
+ end:
+
+	zap_set_state_locked_wait(zchan, ZAP_CHANNEL_STATE_HANGUP);
+
+	THREADS[zchan->span_id][zchan->chan_id] = 0;
+
+	zap_mutex_lock(mutex);
+	T = 0;
+	zap_mutex_unlock(mutex);
+	
+	return NULL;
+}
+
+static ZIO_SIGNAL_CB_FUNCTION(on_signal)
+{
+	zap_log(ZAP_LOG_DEBUG, "got sig %d:%d [%s]\n", sigmsg->channel->span_id, sigmsg->channel->chan_id, zap_signal_event2str(sigmsg->event_id));
+
+    switch(sigmsg->event_id) {
+
+	case ZAP_SIGEVENT_STOP:
+		THREADS[sigmsg->channel->span_id][sigmsg->channel->chan_id] = -1;
+		break;
+
+	case ZAP_SIGEVENT_START:
+		if (!THREADS[sigmsg->channel->span_id][sigmsg->channel->chan_id]) {
+			THREADS[sigmsg->channel->span_id][sigmsg->channel->chan_id] = 1;
+			zap_thread_create_detached(channel_run, sigmsg->channel);
+		}
+		
+		break;
+	default:
+		break;
+	}
+	
+	return ZAP_SUCCESS;
+}
+
+
+static void handle_SIGINT(int sig)
+{
+	if (sig);
+
+	zap_mutex_lock(mutex);
+	R = 0;
+	zap_mutex_unlock(mutex);
+
+	return;
+}
+
+int main(int argc, char *argv[])
+{
+	zap_span_t *span;
+	zap_mutex_create(&mutex);
+
+	zap_global_set_default_logger(ZAP_LOG_LEVEL_DEBUG);
+
+	if (argc < 2) {
+		printf("umm no\n");
+		exit(-1);
+	}
+
+	if (zap_global_init() != ZAP_SUCCESS) {
+		fprintf(stderr, "Error loading OpenZAP\n");
+		exit(-1);
+	}
+
+	printf("OpenZAP loaded\n");
+
+	if (zap_span_find(atoi(argv[1]), &span) != ZAP_SUCCESS) {
+		fprintf(stderr, "Error finding OpenZAP span\n");
+		goto done;
+	}
+	
+
+
+	if (zap_configure_span(
+						   "libpri", span, on_signal,
+						   "node", "cpe",
+						   "switch", "euroisdn",
+						   "dp", "unknown",
+						   "l1", "alaw",
+						   "debug", NULL,
+						   "opts", 0,
+						   TAG_END) == ZAP_SUCCESS) {
+						   
+
+		zap_span_start(span);
+	} else {
+		fprintf(stderr, "Error starting ISDN D-Channel\n");
+		goto done;
+	}
+
+	signal(SIGINT, handle_SIGINT);
+	zap_mutex_lock(mutex);
+	R = 1;
+	zap_mutex_unlock(mutex);
+	while(R || T) {
+		zap_sleep(1 * 1000);
+	}
+
+ done:
+
+	zap_global_destroy();
+
+	return 1;
+
+}
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */

Added: freeswitch/trunk/libs/openzap/src/testr2.c (0 => 17141)


--- freeswitch/trunk/libs/openzap/src/testr2.c	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/src/testr2.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,86 @@
+#include "openzap.h"
+#include <signal.h>
+
+static int R = 0;
+static zap_mutex_t *mutex = NULL;
+
+static ZIO_SIGNAL_CB_FUNCTION(on_r2_signal)
+{
+    zap_log(ZAP_LOG_DEBUG, "Got R2 channel sig [%s] in channel\n", zap_signal_event2str(sigmsg->event_id), sigmsg->channel->physical_chan_id);
+    return ZAP_SUCCESS;
+}
+
+static void handle_SIGINT(int sig)
+{
+	zap_mutex_lock(mutex);
+	R = 0;
+	zap_mutex_unlock(mutex);
+	return;
+}
+
+int main(int argc, char *argv[])
+{
+	zap_span_t *span;
+	zap_mutex_create(&mutex);
+
+	zap_global_set_default_logger(ZAP_LOG_LEVEL_DEBUG);
+
+	if (argc < 2) {
+		printf("umm no\n");
+		exit(-1);
+	}
+
+	if (zap_global_init() != ZAP_SUCCESS) {
+		fprintf(stderr, "Error loading OpenZAP\n");
+		exit(-1);
+	}
+
+	printf("OpenZAP loaded\n");
+
+	if (zap_span_find(atoi(argv[1]), &span) != ZAP_SUCCESS) {
+		fprintf(stderr, "Error finding OpenZAP span\n");
+		goto done;
+	}
+	
+
+
+	if (zap_configure_span("r2", span, on_r2_signal,
+						   "variant", "mx",
+						   "max_ani", 10,
+						   "max_dnis", 4,
+						   "logging", "all",
+						   TAG_END) == ZAP_SUCCESS) {
+						   
+
+		zap_span_start(span);
+	} else {
+		fprintf(stderr, "Error starting R2 span\n");
+		goto done;
+	}
+
+	signal(SIGINT, handle_SIGINT);
+	zap_mutex_lock(mutex);
+	R = 1;
+	zap_mutex_unlock(mutex);
+	while(R) {
+		zap_sleep(1 * 1000);
+	}
+
+ done:
+
+	zap_global_destroy();
+
+	return 1;
+
+}
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */

Added: freeswitch/trunk/libs/openzap/src/testtones.c (0 => 17141)


--- freeswitch/trunk/libs/openzap/src/testtones.c	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/src/testtones.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,76 @@
+#include "openzap.h"
+
+struct ttmp {
+	int fd;
+};
+
+static int teletone_handler(teletone_generation_session_t *ts, teletone_tone_map_t *map)
+{
+	struct ttmp *tmp = ts->user_data;
+	int wrote;
+	size_t len;
+
+	wrote = teletone_mux_tones(ts, map);
+	len = write(tmp->fd, ts->buffer, wrote * 2);
+	
+	if (!len) return -1;
+
+	return 0;
+}
+
+#if 1
+int main(int argc, char *argv[])
+{
+	teletone_generation_session_t ts;
+	struct ttmp tmp;
+
+	if (argc < 3) {
+		fprintf(stderr, "Arg Error! <file> <tones>\n");
+		exit(-1);
+	}
+
+	if ((tmp.fd = open(argv[1], O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR)) < 0) {
+		fprintf(stderr, "File Error! [%s]\n", strerror(errno));
+		exit(-1);
+	}
+
+	teletone_init_session(&ts, 0, teletone_handler, &tmp);
+	ts.rate = 8000;
+	ts.debug = 1;
+	ts.debug_stream = stdout;
+	teletone_run(&ts, argv[2]);
+	close(tmp.fd);
+
+	return 0;
+}
+#else 
+int32_t main(int argc, char *argv[])
+{
+	int32_t j, i, fd = -1;
+	int32_t rate = 8000;
+	/* SIT tones and durations */
+	float tones[] = { 913.8, 1370.6, 1776.7, 0 };
+	int32_t durations[] = {274, 274, 380, 0};
+	teletone_dds_state_t dds = {0};
+	int16_t sample;
+	size_t len = 1;
+
+	if (argc < 2 || (fd = open(argv[1], O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR)) < 0) {
+		fprintf(stderr, "File Error!\n", strerror(errno));
+		exit(-1);
+	}
+
+	for (j = 0; tones[j] && durations[j]; j++) {
+
+		teletone_dds_state_set_tone(&dds, tones[j], rate, -50);
+		
+		for(i = 0; (i < durations[j] * rate / 1000) && len != 0; i++) {
+			sample = teletone_dds_modulate_sample(&dds) * 20;
+			len = write(fd, &sample, sizeof(sample));
+		}
+
+	}
+	
+	close(fd);
+}
+#endif

Added: freeswitch/trunk/libs/openzap/src/uart.c (0 => 17141)


--- freeswitch/trunk/libs/openzap/src/uart.c	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/src/uart.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,124 @@
+
+/*
+ *	uart.c
+ *
+ *	Copyright (c) 2005 Robert Krten.  All Rights Reserved.
+ *
+ *	Redistribution and use in source and binary forms, with or without
+ *	modification, are permitted provided that the following conditions
+ *	are met:
+ *
+ *	1. Redistributions of source code must retain the above copyright
+ *	   notice, this list of conditions and the following disclaimer.
+ *	2. Redistributions in binary form must reproduce the above copyright
+ *	   notice, this list of conditions and the following disclaimer in the
+ *	   documentation and/or other materials provided with the distribution.
+ *
+ *	THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
+ *	ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ *	IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ *	ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE
+ *	FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ *	DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ *	OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ *	HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ *	LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ *	OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ *	SUCH DAMAGE.
+ *
+ *	This module contains a simple 8-bit UART, which performs a callback
+ *	with the decoded byte value.
+ *
+ *	2005 06 11	R. Krten		created
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include "uart.h"
+
+/*
+ *	dsp_uart_attr_init
+ *
+ *	Initializes the attributes structure; this must be done before the
+ *	attributes structure is used.
+*/
+
+void dsp_uart_attr_init (dsp_uart_attr_t *attr)
+{
+	memset (attr, 0, sizeof (*attr));
+}
+
+/*
+ *	dsp_uart_attr_get_bytehandler
+ *	dsp_uart_attr_set_bytehandler
+ *
+ *	These functions get and set their respective elements from the
+ *	attributes structure.  If an error code is returned, it is just
+ *	zero == ok, -1 == fail.
+*/
+
+bytehandler_func_t dsp_uart_attr_get_bytehandler(dsp_uart_attr_t *attr, void **bytehandler_arg)
+{
+	*bytehandler_arg = attr->bytehandler_arg;
+	return attr->bytehandler;
+}
+
+void dsp_uart_attr_set_bytehandler(dsp_uart_attr_t *attr, bytehandler_func_t bytehandler, void *bytehandler_arg)
+{
+	attr->bytehandler = bytehandler;
+	attr->bytehandler_arg = bytehandler_arg;
+}
+
+dsp_uart_handle_t *dsp_uart_create(dsp_uart_attr_t *attr)
+{
+	dsp_uart_handle_t *handle;
+
+	handle = malloc(sizeof (*handle));
+	if (handle) {
+		memset(handle, 0, sizeof (*handle));
+
+		/* fill the attributes member */
+		memcpy(&handle->attr, attr, sizeof (*attr));
+	}
+	return handle;
+}
+
+void dsp_uart_destroy(dsp_uart_handle_t **handle)
+{
+	if (*handle) {
+		free(*handle);
+		*handle = NULL;
+	}
+}
+
+
+void dsp_uart_bit_handler(void *x, int bit)
+{
+	dsp_uart_handle_t *handle = (dsp_uart_handle_t *) x;
+
+	if (!handle->have_start) {
+		if (bit) {
+			return;		/* waiting for start bit (0) */
+		}
+		handle->have_start = 1;
+		handle->data = 0;
+		handle->nbits = 0;
+		return;
+	}
+
+	handle->data >>= 1;
+	handle->data |= 0x80 * !!bit;
+	handle->nbits++;
+
+	if (handle->nbits == 8) {
+		handle->attr.bytehandler(handle->attr.bytehandler_arg, handle->data);
+		handle->nbits = 0;
+		handle->data = 0;
+		handle->have_start = 0;
+	}
+/* might consider handling errors in the future... */
+}
+

Added: freeswitch/trunk/libs/openzap/src/zap_buffer.c (0 => 17141)


--- freeswitch/trunk/libs/openzap/src/zap_buffer.c	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/src/zap_buffer.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,302 @@
+/*
+ * Copyright (c) 2007, Anthony Minessale II
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "openzap.h"
+#include "zap_buffer.h"
+
+static unsigned buffer_id = 0;
+
+struct zap_buffer {
+	unsigned char *data;
+	unsigned char *head;
+	zap_size_t used;
+	zap_size_t actually_used;
+	zap_size_t datalen;
+	zap_size_t max_len;
+	zap_size_t blocksize;
+	unsigned id;
+	int loops;
+};
+
+
+OZ_DECLARE(zap_status_t) zap_buffer_create(zap_buffer_t **buffer, zap_size_t blocksize, zap_size_t start_len, zap_size_t max_len)
+{
+	zap_buffer_t *new_buffer;
+
+	new_buffer = malloc(sizeof(*new_buffer));
+	if (new_buffer) {
+		memset(new_buffer, 0, sizeof(*new_buffer));
+
+		if (start_len) {
+			new_buffer->data = malloc(start_len);
+			if (!new_buffer->data) {
+				free(new_buffer);
+				return ZAP_MEMERR;
+			}
+			memset(new_buffer->data, 0, start_len);
+		}
+
+		new_buffer->max_len = max_len;
+		new_buffer->datalen = start_len;
+		new_buffer->id = buffer_id++;
+		new_buffer->blocksize = blocksize;
+		new_buffer->head = new_buffer->data;
+
+		*buffer = new_buffer;
+		return ZAP_SUCCESS;
+	}
+
+	return ZAP_MEMERR;
+}
+
+OZ_DECLARE(zap_size_t) zap_buffer_len(zap_buffer_t *buffer)
+{
+
+	assert(buffer != NULL);
+
+	return buffer->datalen;
+
+}
+
+
+OZ_DECLARE(zap_size_t) zap_buffer_freespace(zap_buffer_t *buffer)
+{
+	assert(buffer != NULL);
+
+
+	if (buffer->max_len) {
+		return (zap_size_t) (buffer->max_len - buffer->used);
+	}
+	return 1000000;
+
+}
+
+OZ_DECLARE(zap_size_t) zap_buffer_inuse(zap_buffer_t *buffer)
+{
+	assert(buffer != NULL);
+
+	return buffer->used;
+}
+
+OZ_DECLARE(zap_size_t) zap_buffer_seek(zap_buffer_t *buffer, zap_size_t datalen)
+{
+	zap_size_t reading = 0;
+
+	assert(buffer != NULL);
+
+	if (buffer->used < 1) {
+		buffer->used = 0;
+		return 0;
+	} else if (buffer->used >= datalen) {
+		reading = datalen;
+	} else {
+		reading = buffer->used;
+	}
+
+	buffer->used = buffer->actually_used - reading;
+	buffer->head = buffer->data + reading;
+
+	return reading;
+}
+
+OZ_DECLARE(zap_size_t) zap_buffer_toss(zap_buffer_t *buffer, zap_size_t datalen)
+{
+	zap_size_t reading = 0;
+
+	assert(buffer != NULL);
+
+	if (buffer->used < 1) {
+		buffer->used = 0;
+		return 0;
+	} else if (buffer->used >= datalen) {
+		reading = datalen;
+	} else {
+		reading = buffer->used;
+	}
+
+	buffer->used -= reading;
+	buffer->head += reading;
+
+	return buffer->used;
+}
+
+OZ_DECLARE(void) zap_buffer_set_loops(zap_buffer_t *buffer, int loops)
+{
+	buffer->loops = loops;
+}
+
+OZ_DECLARE(zap_size_t) zap_buffer_read_loop(zap_buffer_t *buffer, void *data, zap_size_t datalen)
+{
+	zap_size_t len;
+	if ((len = zap_buffer_read(buffer, data, datalen)) < datalen) {
+		if (buffer->loops == 0) {
+			return len;
+		}
+		buffer->head = buffer->data;
+		buffer->used = buffer->actually_used;
+		len = zap_buffer_read(buffer, (char*)data + len, datalen - len);
+		buffer->loops--;
+	}
+	return len;
+}
+
+OZ_DECLARE(zap_size_t) zap_buffer_read(zap_buffer_t *buffer, void *data, zap_size_t datalen)
+{
+	zap_size_t reading = 0;
+
+	assert(buffer != NULL);
+	assert(data != NULL);
+
+
+	if (buffer->used < 1) {
+		buffer->used = 0;
+		return 0;
+	} else if (buffer->used >= datalen) {
+		reading = datalen;
+	} else {
+		reading = buffer->used;
+	}
+
+	memcpy(data, buffer->head, reading);
+	buffer->used -= reading;
+	buffer->head += reading;
+
+	/* if (buffer->id == 4) printf("%u o %d = %d\n", buffer->id, (unsigned)reading, (unsigned)buffer->used); */
+	return reading;
+}
+
+OZ_DECLARE(zap_size_t) zap_buffer_write(zap_buffer_t *buffer, const void *data, zap_size_t datalen)
+{
+	zap_size_t freespace, actual_freespace;
+
+	assert(buffer != NULL);
+	assert(data != NULL);
+	assert(buffer->data != NULL);
+
+	if (!datalen) {
+		return buffer->used;
+	}
+
+	actual_freespace = buffer->datalen - buffer->actually_used;
+	if (actual_freespace < datalen && (!buffer->max_len || (buffer->used + datalen <= buffer->max_len))) {
+		memmove(buffer->data, buffer->head, buffer->used);
+		buffer->head = buffer->data;
+		buffer->actually_used = buffer->used;
+	}
+
+	freespace = buffer->datalen - buffer->used;
+
+	/*
+	  if (buffer->data != buffer->head) {
+	  memmove(buffer->data, buffer->head, buffer->used);
+	  buffer->head = buffer->data;
+	  }
+	*/
+	
+	if (freespace < datalen) {
+		zap_size_t new_size, new_block_size;
+		void *data;
+		
+		new_size = buffer->datalen + datalen;
+		new_block_size = buffer->datalen + buffer->blocksize;
+
+		if (new_block_size > new_size) {
+			new_size = new_block_size;
+		}
+		buffer->head = buffer->data;
+		data = realloc(buffer->data, new_size);
+		if (!data) {
+			return 0;
+		}
+		buffer->data = data;
+		buffer->head = buffer->data;
+		buffer->datalen = new_size;
+	}
+	
+
+	freespace = buffer->datalen - buffer->used;
+
+	if (freespace < datalen) {
+		return 0;
+	} else {
+		memcpy(buffer->head + buffer->used, data, datalen);
+		buffer->used += datalen;
+		buffer->actually_used += datalen;
+	}
+	/* if (buffer->id == 4) printf("%u i %d = %d\n", buffer->id, (unsigned)datalen, (unsigned)buffer->used); */
+
+	return buffer->used;
+}
+
+OZ_DECLARE(void) zap_buffer_zero(zap_buffer_t *buffer)
+{
+	assert(buffer != NULL);
+	assert(buffer->data != NULL);
+
+	buffer->used = 0;
+	buffer->actually_used = 0;
+	buffer->head = buffer->data;
+}
+
+OZ_DECLARE(zap_size_t) zap_buffer_zwrite(zap_buffer_t *buffer, const void *data, zap_size_t datalen)
+{
+	zap_size_t w;
+	
+	if (!(w = zap_buffer_write(buffer, data, datalen))) {
+		zap_buffer_zero(buffer);
+		return zap_buffer_write(buffer, data, datalen);
+	}
+
+	return w;
+}
+
+OZ_DECLARE(void) zap_buffer_destroy(zap_buffer_t **buffer)
+{
+	if (*buffer) {
+		free((*buffer)->data);
+		free(*buffer);
+	}
+
+	*buffer = NULL;
+}
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */

Added: freeswitch/trunk/libs/openzap/src/zap_callerid.c (0 => 17141)


--- freeswitch/trunk/libs/openzap/src/zap_callerid.c	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/src/zap_callerid.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,307 @@
+#include "openzap.h"
+#include "fsk.h"
+#include "uart.h"
+
+
+
+static void fsk_byte_handler (void *x, int data)
+{
+	zap_fsk_data_state_t *state = (zap_fsk_data_state_t *) x;
+	uint8_t byte = (uint8_t)data;
+
+ top:
+
+	if (state->init == 3) {
+		return;
+	}
+
+	if (state->dlen) {
+		goto add_byte;
+	}
+	
+	if (state->bpos == 1) {
+		state->blen = byte;
+
+		if ((uint32_t)(state->dlen = state->bpos + byte + 2) > state->bufsize) {
+			state->dlen = state->bufsize;
+		}
+		goto top;
+	}
+
+ add_byte:
+
+	if (state->bpos <= state->dlen) {
+		state->buf[state->bpos++] = byte;
+	} else {
+		state->init = 3;
+	}
+}
+
+OZ_DECLARE(zap_status_t) zap_fsk_data_init(zap_fsk_data_state_t *state, uint8_t *data, uint32_t datalen)
+{
+	memset(state, 0, sizeof(*state));
+	state->buf = data;
+	state->bufsize = datalen;
+	state->bpos = 2;
+
+	return ZAP_SUCCESS;
+}
+
+OZ_DECLARE(zap_status_t) zap_fsk_data_add_sdmf(zap_fsk_data_state_t *state, const char *date, char *number)
+{
+	size_t dlen = strlen(date);
+	size_t nlen = strlen(number);
+
+	state->buf[0] = ZAP_CID_TYPE_SDMF;
+	memcpy(&state->buf[state->bpos], date, dlen);
+	state->bpos += dlen;
+	memcpy(&state->buf[state->bpos], number, nlen);
+	state->bpos += nlen;
+
+	return ZAP_SUCCESS;
+}
+
+OZ_DECLARE(zap_status_t) zap_fsk_data_add_mdmf(zap_fsk_data_state_t *state, zap_mdmf_type_t type, const uint8_t *data, uint32_t datalen)
+{
+	state->buf[0] = ZAP_CID_TYPE_MDMF;
+	state->buf[state->bpos++] = type;
+	state->buf[state->bpos++] = (uint8_t)datalen;
+	memcpy(&state->buf[state->bpos], data, datalen);
+	state->bpos += datalen;
+	return ZAP_SUCCESS;
+}
+
+
+OZ_DECLARE(zap_status_t) zap_fsk_data_add_checksum(zap_fsk_data_state_t *state)
+{
+	uint32_t i;
+	uint8_t check = 0;
+
+	state->buf[1] = (uint8_t)(state->bpos - 2);
+
+	for (i = 0; i < state->bpos; i++) {
+		check = check + state->buf[i];
+	}
+
+	state->checksum = state->buf[state->bpos] = (uint8_t)(256 - check);
+	state->bpos++;
+
+	state->dlen = state->bpos;
+	state->blen = state->buf[1];
+
+	return ZAP_SUCCESS;
+}
+
+
+OZ_DECLARE(zap_status_t) zap_fsk_data_parse(zap_fsk_data_state_t *state, zap_size_t *type, char **data, zap_size_t *len)
+{
+
+	zap_size_t i;
+	int sum = 0;
+	
+ top:
+
+	if (state->checksum != 0 || state->ppos >= state->dlen - 1) {
+		return ZAP_FAIL;
+	}
+
+	if (!state->ppos) {
+		for(i = 0; i < state->bpos; i++) {
+			sum += state->buf[i];
+		}
+		state->checksum = sum % 256;
+		state->ppos = 2;		
+
+		if (state->buf[0] != ZAP_CID_TYPE_MDMF && state->buf[0] != ZAP_CID_TYPE_SDMF) {
+			state->checksum = -1;
+		}
+		goto top;
+	}
+
+	if (state->buf[0] == ZAP_CID_TYPE_SDMF) {
+		/* convert sdmf to mdmf so we don't need 2 parsers */
+		if (state->ppos == 2) {
+			*type = MDMF_DATETIME;
+			*len = 8;
+		} else {
+			if (state->buf[state->ppos] == 'P' || state->buf[state->ppos] == 'O') {
+				*type = MDMF_NO_NUM;
+				*len = 1;
+			} else {
+				*type = MDMF_PHONE_NUM;
+				*len = state->blen - 8;
+			}
+		}
+		*data = (char *)&state->buf[state->ppos];
+		state->ppos += *len;		
+		return ZAP_SUCCESS;
+	} else if (state->buf[0] == ZAP_CID_TYPE_MDMF) {
+		*type = state->buf[state->ppos++];
+		*len = state->buf[state->ppos++];
+		*data = (char *)&state->buf[state->ppos];
+		state->ppos += *len;
+		return ZAP_SUCCESS;
+	}
+
+	return ZAP_FAIL;
+}
+
+OZ_DECLARE(zap_status_t) zap_fsk_demod_feed(zap_fsk_data_state_t *state, int16_t *data, zap_size_t samples)
+{
+	uint32_t x;
+	int16_t *sp = data;
+
+	if (state->init == 3) {
+		return ZAP_FAIL;
+	}
+
+	for (x = 0; x < samples; x++) {
+		dsp_fsk_sample (state->fsk1200_handle, (double) *sp++ / 32767.0);
+		if (state->dlen && state->bpos >= state->dlen) {
+			state->init = 3;
+			return ZAP_FAIL;
+		}
+	}
+
+	return ZAP_SUCCESS;
+}
+
+OZ_DECLARE(zap_status_t) zap_fsk_demod_destroy(zap_fsk_data_state_t *state)
+{
+	dsp_fsk_destroy(&state->fsk1200_handle);
+	memset(state, 0, sizeof(*state));
+	return ZAP_SUCCESS;
+}
+
+OZ_DECLARE(int) zap_fsk_demod_init(zap_fsk_data_state_t *state, int rate, uint8_t *buf, zap_size_t bufsize)
+{
+
+	dsp_fsk_attr_t fsk1200_attr;
+
+	if (state->fsk1200_handle) {
+		dsp_fsk_destroy(&state->fsk1200_handle);
+	}
+
+	memset(state, 0, sizeof(*state));
+	memset(buf, 0, bufsize);
+	state->buf = buf;
+	state->bufsize = bufsize;
+	
+	dsp_fsk_attr_init (&fsk1200_attr);
+	dsp_fsk_attr_set_samplerate (&fsk1200_attr, rate);
+	dsp_fsk_attr_set_bytehandler (&fsk1200_attr, fsk_byte_handler, state);
+	state->fsk1200_handle = dsp_fsk_create (&fsk1200_attr);
+
+	if (state->fsk1200_handle == NULL) {
+		return ZAP_FAIL;
+	}
+
+	return ZAP_SUCCESS;
+}
+
+OZ_DECLARE(zap_size_t) zap_fsk_modulator_generate_bit(zap_fsk_modulator_t *fsk_trans, int8_t bit, int16_t *buf, zap_size_t buflen)
+{
+	zap_size_t i;
+		
+	for(i = 0 ; i < buflen; i++) {
+		fsk_trans->bit_accum += fsk_trans->bit_factor;
+		if (fsk_trans->bit_accum >= ZAP_FSK_MOD_FACTOR) {
+			fsk_trans->bit_accum -= (ZAP_FSK_MOD_FACTOR + fsk_trans->bit_factor);
+			break;
+		}
+
+		buf[i] = teletone_dds_state_modulate_sample(&fsk_trans->dds, bit);
+	}
+
+	return i;
+}
+
+
+OZ_DECLARE(int32_t) zap_fsk_modulator_generate_carrier_bits(zap_fsk_modulator_t *fsk_trans, uint32_t bits)
+{
+	uint32_t i = 0;
+	zap_size_t r = 0;
+	int8_t bit = 1;
+
+	for (i = 0; i < bits; i++) {
+		if ((r = zap_fsk_modulator_generate_bit(fsk_trans, bit, fsk_trans->sample_buffer, sizeof(fsk_trans->sample_buffer) / 2))) {
+			if (fsk_trans->write_sample_callback(fsk_trans->sample_buffer, r, fsk_trans->user_data) != ZAP_SUCCESS) {
+				break;
+			}
+		} else {
+			break;
+		}
+	}
+
+	return i;
+}
+
+
+OZ_DECLARE(void) zap_fsk_modulator_generate_chan_sieze(zap_fsk_modulator_t *fsk_trans)
+{
+	uint32_t i = 0;
+	zap_size_t r = 0;
+	int8_t bit = 0;
+	
+	for (i = 0; i < fsk_trans->chan_sieze_bits; i++) {
+		if ((r = zap_fsk_modulator_generate_bit(fsk_trans, bit, fsk_trans->sample_buffer, sizeof(fsk_trans->sample_buffer) / 2))) {
+			if (fsk_trans->write_sample_callback(fsk_trans->sample_buffer, r, fsk_trans->user_data) != ZAP_SUCCESS) {
+				break;
+			}
+		} else {
+			break;
+		}
+		bit = !bit;
+	}
+	
+
+}
+
+
+OZ_DECLARE(void) zap_fsk_modulator_send_data(zap_fsk_modulator_t *fsk_trans)
+{
+	zap_size_t r = 0;
+	int8_t bit = 0;
+
+	while((bit = zap_bitstream_get_bit(&fsk_trans->bs)) > -1) {
+		if ((r = zap_fsk_modulator_generate_bit(fsk_trans, bit, fsk_trans->sample_buffer, sizeof(fsk_trans->sample_buffer) / 2))) {
+			if (fsk_trans->write_sample_callback(fsk_trans->sample_buffer, r, fsk_trans->user_data) != ZAP_SUCCESS) {
+				break;
+			}
+		} else {
+			break;
+		}
+	}
+}
+
+
+OZ_DECLARE(zap_status_t) zap_fsk_modulator_init(zap_fsk_modulator_t *fsk_trans,
+									fsk_modem_types_t modem_type,
+									uint32_t sample_rate,
+									zap_fsk_data_state_t *fsk_data,
+									float db_level,
+									uint32_t carrier_bits_start,
+									uint32_t carrier_bits_stop,
+									uint32_t chan_sieze_bits,
+									zap_fsk_write_sample_t write_sample_callback,
+									void *user_data)
+{
+	memset(fsk_trans, 0, sizeof(*fsk_trans));
+	fsk_trans->modem_type = modem_type;
+	teletone_dds_state_set_tone(&fsk_trans->dds, fsk_modem_definitions[fsk_trans->modem_type].freq_space, sample_rate, 0);
+	teletone_dds_state_set_tone(&fsk_trans->dds, fsk_modem_definitions[fsk_trans->modem_type].freq_mark, sample_rate, 1);
+	fsk_trans->bit_factor = (uint32_t)((fsk_modem_definitions[fsk_trans->modem_type].baud_rate * ZAP_FSK_MOD_FACTOR) / (float)sample_rate);
+	fsk_trans->samples_per_bit = (uint32_t) (sample_rate / fsk_modem_definitions[fsk_trans->modem_type].baud_rate);
+	fsk_trans->est_bytes = (int32_t)(((fsk_data->dlen * 10) + carrier_bits_start + carrier_bits_stop + chan_sieze_bits) * ((fsk_trans->samples_per_bit + 1) * 2));
+	fsk_trans->bit_accum = 0;
+	fsk_trans->fsk_data = fsk_data;
+	teletone_dds_state_set_tx_level(&fsk_trans->dds, db_level);
+	zap_bitstream_init(&fsk_trans->bs, fsk_trans->fsk_data->buf, (uint32_t)fsk_trans->fsk_data->dlen, ZAP_ENDIAN_BIG, 1);
+	fsk_trans->carrier_bits_start = carrier_bits_start;
+	fsk_trans->carrier_bits_stop = carrier_bits_stop;
+	fsk_trans->chan_sieze_bits = chan_sieze_bits;
+	fsk_trans->write_sample_callback = write_sample_callback;
+	fsk_trans->user_data = user_data;
+	return ZAP_SUCCESS;
+}
+

Added: freeswitch/trunk/libs/openzap/src/zap_config.c (0 => 17141)


--- freeswitch/trunk/libs/openzap/src/zap_config.c	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/src/zap_config.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,251 @@
+/*
+ * Copyright (c) 2007, Anthony Minessale II
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "openzap.h"
+#include "zap_config.h"
+
+int zap_config_open_file(zap_config_t *cfg, const char *file_path)
+{
+	FILE *f;
+	const char *path = NULL;
+	char path_buf[1024];
+
+	if (file_path[0] == '/') {
+		path = file_path;
+	} else {
+		snprintf(path_buf, sizeof(path_buf), "%s%s%s", ZAP_CONFIG_DIR, ZAP_PATH_SEPARATOR, file_path);
+		path = path_buf;
+	}
+
+	if (!path) {
+		return 0;
+	}
+
+	memset(cfg, 0, sizeof(*cfg));
+	cfg->lockto = -1;
+	zap_log(ZAP_LOG_DEBUG, "Configuration file is %s.\n", path);
+	f = fopen(path, "r");
+
+	if (!f) {
+		if (file_path[0] != '/') {
+			int last = -1;
+			char *var, *val;
+
+			snprintf(path_buf, sizeof(path_buf), "%s%sopenzap.conf", ZAP_CONFIG_DIR, ZAP_PATH_SEPARATOR);
+			path = path_buf;
+
+			if ((f = fopen(path, "r")) == 0) {
+				return 0;
+			}
+
+			cfg->file = f;
+			zap_set_string(cfg->path, path);
+
+			while (zap_config_next_pair(cfg, &var, &val)) {
+				if ((cfg->sectno != last) && !strcmp(cfg->section, file_path)) {
+					cfg->lockto = cfg->sectno;
+					return 1;
+				}
+			}
+
+			zap_config_close_file(cfg);
+			memset(cfg, 0, sizeof(*cfg));
+			return 0;
+		}
+
+		return 0;
+	} else {
+		cfg->file = f;
+		zap_set_string(cfg->path, path);
+		return 1;
+	}
+}
+
+void zap_config_close_file(zap_config_t *cfg)
+{
+
+	if (cfg->file) {
+		fclose(cfg->file);
+	}
+
+	memset(cfg, 0, sizeof(*cfg));
+}
+
+
+
+int zap_config_next_pair(zap_config_t *cfg, char **var, char **val)
+{
+	int ret = 0;
+	char *p, *end;
+
+	*var = *val = NULL;
+
+	if (!cfg->path) {
+		return 0;
+	}
+
+	for (;;) {
+		cfg->lineno++;
+
+		if (!fgets(cfg->buf, sizeof(cfg->buf), cfg->file)) {
+			ret = 0;
+			break;
+		}
+		*var = cfg->buf;
+
+		if (**var == '[' && (end = strchr(*var, ']')) != 0) {
+			*end = '\0';
+			(*var)++;
+			if (**var == '+') {
+				(*var)++;
+				zap_copy_string(cfg->section, *var, sizeof(cfg->section));
+				cfg->sectno++;
+
+				if (cfg->lockto > -1 && cfg->sectno != cfg->lockto) {
+					break;
+				}
+				cfg->catno = 0;
+				cfg->lineno = 0;
+				*var = (char *) "";
+				*val = (char *) "";
+				return 1;
+			} else {
+				zap_copy_string(cfg->category, *var, sizeof(cfg->category));
+				cfg->catno++;
+			}
+			continue;
+		}
+
+
+
+		if (**var == '#' || **var == ';' || **var == '\n' || **var == '\r') {
+			continue;
+		}
+
+		if (!strncmp(*var, "__END__", 7)) {
+			break;
+		}
+
+
+		if ((end = strchr(*var, ';')) && *(end+1) == *end) {
+			*end = '\0';
+			end--;
+		} else if ((end = strchr(*var, '\n')) != 0) {
+			if (*(end - 1) == '\r') {
+				end--;
+			}
+			*end = '\0';
+		}
+
+		p = *var;
+		while ((*p == ' ' || *p == '\t') && p != end) {
+			*p = '\0';
+			p++;
+		}
+		*var = p;
+
+
+		if ((*val = strchr(*var, '=')) == 0) {
+			ret = -1;
+			/* log_printf(0, server.log, "Invalid syntax on %s: line %d\n", cfg->path, cfg->lineno); */
+			continue;
+		} else {
+			p = *val - 1;
+			*(*val) = '\0';
+			(*val)++;
+			if (*(*val) == '>') {
+				*(*val) = '\0';
+				(*val)++;
+			}
+
+			while ((*p == ' ' || *p == '\t') && p != *var) {
+				*p = '\0';
+				p--;
+			}
+
+			p = *val;
+			while ((*p == ' ' || *p == '\t') && p != end) {
+				*p = '\0';
+				p++;
+			}
+			*val = p;
+			ret = 1;
+			break;
+		}
+	}
+
+
+	return ret;
+
+}
+
+OZ_DECLARE (int) zap_config_get_cas_bits(char *strvalue, unsigned char *outbits)
+{
+	char cas_bits[5];
+	unsigned char bit = 0x8;
+	int x = 0;
+	char *double_colon = strchr(strvalue, ':');
+	if (!double_colon) {
+		zap_log(ZAP_LOG_ERROR, "No CAS bits specified: %s, :xxxx definition expected, where x is 1 or 0\n", strvalue);
+		return -1;
+	}
+	double_colon++;
+	*outbits = 0;
+	cas_bits[4] = 0;
+	if (sscanf(double_colon, "%c%c%c%c", &cas_bits[0], &cas_bits[1], &cas_bits[2], &cas_bits[3]) != 4) {
+		zap_log(ZAP_LOG_ERROR, "Invalid CAS bits specified: '%s', :xxxx definition expected, where x is 1 or 0\n", double_colon);
+		return -1;
+	}
+	zap_log(ZAP_LOG_DEBUG, "CAS bits specification found: %s\n", cas_bits);
+	for (; cas_bits[x]; x++) {
+		if ('1' == cas_bits[x]) {
+			*outbits |= bit;
+		} else if ('0' != cas_bits[x]) {
+			zap_log(ZAP_LOG_ERROR, "Invalid CAS pattern specified: %s, just 0 or 1 allowed for each bit\n");
+			return -1;
+		}
+		bit >>= 1;
+	}
+	return 0;
+}
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */

Added: freeswitch/trunk/libs/openzap/src/zap_cpu_monitor.c (0 => 17141)


--- freeswitch/trunk/libs/openzap/src/zap_cpu_monitor.c	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/src/zap_cpu_monitor.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,271 @@
+/*
+ * Copyright (c) 2009, Sangoma Technologies
+ * Moises Silva <moy@sangoma.com>
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Contributors:
+ * David Yat Sin <dyatsin@sangoma.com>
+ * 
+ */
+
+#ifdef WIN32
+#define _WIN32_WINNT 0x0501 // To make GetSystemTimes visible in windows.h
+#include <windows.h>
+#else /* LINUX */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <errno.h>
+#endif
+
+#include "openzap.h"
+#include "zap_cpu_monitor.h"
+struct zap_cpu_monitor_stats
+{
+	/* bool, just used to retrieve the values for the first time and not calculate the percentage of idle time */
+	int valid_last_times;
+
+	/* last calculated percentage of idle time */
+	double last_percentage_of_idle_time;
+
+#ifdef __linux__
+	/* all of these are the Linux jiffies last retrieved count */
+	unsigned long long last_user_time;
+	unsigned long long last_system_time;
+	unsigned long long last_idle_time;
+
+	unsigned long long last_nice_time;
+	unsigned long long last_irq_time;
+	unsigned long long last_soft_irq_time;
+	unsigned long long last_io_wait_time;
+	unsigned long long last_steal_time;
+
+	/* /proc/stat file descriptor used to retrieve the counters */
+	int procfd;
+	int initd;
+#elif defined (WIN32)  || defined (WIN64)
+	__int64 i64LastUserTime;
+	__int64 i64LastKernelTime;
+	__int64 i64LastIdleTime;
+#else
+/* Unsupported */
+#endif
+};
+
+#ifdef __linux__
+static zap_status_t zap_cpu_read_stats(struct zap_cpu_monitor_stats *p,
+											unsigned long long *user,
+											unsigned long long *nice,
+											unsigned long long *system,
+											unsigned long long *idle,
+											unsigned long long *iowait,
+											unsigned long long *irq,
+											unsigned long long *softirq,
+											unsigned long long *steal)
+{
+// the output of proc should not change that often from one kernel to other
+// see fs/proc/proc_misc.c or fs/proc/stat.c in the Linux kernel for more details
+// also man 5 proc is useful
+#define CPU_ELEMENTS 8 // change this if you change the format string
+#define CPU_INFO_FORMAT "cpu  %Lu %Lu %Lu %Lu %Lu %Lu %Lu %Lu"
+	static const char procfile[] = "/proc/stat";
+	int rc = 0;
+	int myerrno = 0;
+	int elements = 0;
+	const char *cpustr = NULL;
+	char statbuff[1024];
+
+	if (!p->initd) {
+		p->procfd = open(procfile, O_RDONLY, 0);
+		if(p->procfd == -1) {
+			zap_log(ZAP_LOG_ERROR, "Failed to open CPU statistics file %s: %s\n", procfile, strerror(myerrno));
+			return ZAP_FAIL;
+		}
+		p->initd = 1;
+	} else {
+		lseek(p->procfd, 0L, SEEK_SET);
+	}
+
+	rc = read(p->procfd, statbuff, sizeof(statbuff) - 1);
+	if (rc <= 0) {
+		myerrno = errno;
+		zap_log(ZAP_LOG_ERROR, "Failed to read CPU statistics file %s: %s\n", procfile, strerror(myerrno));
+		return ZAP_FAIL;
+	}
+
+	cpustr = strstr(statbuff, "cpu ");
+	if (!cpustr) {
+		zap_log(ZAP_LOG_ERROR, "wrong format for Linux proc cpu statistics: missing cpu string\n");
+		return ZAP_FAIL;
+	}
+
+	elements = sscanf(cpustr, CPU_INFO_FORMAT, user, nice, system, idle, iowait, irq, softirq, steal);
+	if (elements != CPU_ELEMENTS) {
+		zap_log(ZAP_LOG_ERROR, "wrong format for Linux proc cpu statistics: expected %d elements, but just found %d\n", CPU_ELEMENTS, elements);
+		return ZAP_FAIL;
+	}
+	return ZAP_SUCCESS;
+}
+#endif
+
+#ifdef __linux__
+OZ_DECLARE(zap_status_t) zap_cpu_get_system_idle_time (struct zap_cpu_monitor_stats *p, double *idle_percentage)
+{
+	unsigned long long user, nice, system, idle, iowait, irq, softirq, steal;
+	unsigned long long usertime, kerneltime, idletime, totaltime, halftime;
+
+	if (zap_cpu_read_stats(p, &user, &nice, &system, &idle, &iowait, &irq, &softirq, &steal)) {
+		zap_log(ZAP_LOG_ERROR, "Failed to retrieve Linux CPU statistics\n");
+		return ZAP_FAIL;
+	}
+
+	if (!p->valid_last_times) {
+		// we dont strictly need to save all of them but I feel code is more clear if we do
+		p->valid_last_times = 1;
+		p->last_user_time = user;
+		p->last_nice_time = nice;
+		p->last_system_time = system;
+		p->last_irq_time = irq;
+		p->last_soft_irq_time = softirq;
+		p->last_io_wait_time = iowait;
+		p->last_steal_time = steal;
+		p->last_idle_time = idle;
+		p->last_percentage_of_idle_time = 100.0;
+		*idle_percentage = p->last_percentage_of_idle_time;
+		return ZAP_SUCCESS;
+	}
+
+	usertime = (user - p->last_user_time) + (nice - p->last_nice_time);
+	kerneltime = (system - p->last_system_time) + (irq - p->last_irq_time) + (softirq - p->last_soft_irq_time);
+	kerneltime += (iowait - p->last_io_wait_time);
+	kerneltime += (steal - p->last_steal_time);
+	idletime = (idle - p->last_idle_time);
+
+	totaltime = usertime + kerneltime + idletime;
+	
+	if (totaltime <= 0) {
+		// this may happen if not enough time has elapsed and the jiffies counters are the same than the last time we checked
+		// jiffies depend on timer interrupts which depend on the number of HZ compile time setting of the kernel
+		// typical configs set HZ to 100 (that means, 100 jiffies updates per second, that is one each 10ms)
+		// avoid an arithmetic exception and return the same values
+		*idle_percentage = p->last_percentage_of_idle_time;
+		return ZAP_SUCCESS;
+	}
+
+	halftime = totaltime / 2UL;
+
+	p->last_percentage_of_idle_time = ((100 * idletime + halftime) / totaltime);
+	*idle_percentage = p->last_percentage_of_idle_time;
+
+	p->last_user_time = user;
+	p->last_nice_time = nice;
+	p->last_system_time = system;
+	p->last_irq_time = irq;
+	p->last_soft_irq_time = softirq;
+	p->last_io_wait_time = iowait;
+	p->last_steal_time = steal;
+	p->last_idle_time = idle;
+
+	return ZAP_SUCCESS;
+}
+
+#elif defined (WIN32) || defined (WIN64)
+OZ_DECLARE(zap_status_t) zap_cpu_get_system_idle_time(struct zap_cpu_monitor_stats *p, double *idle_percentage)
+{
+	FILETIME idleTime;
+	FILETIME kernelTime;
+	FILETIME userTime;
+  
+	if (!::GetSystemTimes(&idleTime, &kernelTime, &userTime)) {
+		return false;
+	}
+  
+	__int64 i64UserTime = (__int64)userTime.dwLowDateTime | ((__int64)userTime.dwHighDateTime << 32);
+
+	__int64 i64KernelTime = (__int64)kernelTime.dwLowDateTime | ((__int64)kernelTime.dwHighDateTime << 32);
+
+	__int64 i64IdleTime = (__int64)idleTime.dwLowDateTime | ((__int64)idleTime.dwHighDateTime << 32);
+
+	if (p->valid_last_times) {
+		__int64 i64User = i64UserTime - p->i64LastUserTime;
+		__int64 i64Kernel = i64KernelTime - p->i64LastKernelTime;
+		__int64 i64Idle = i64IdleTime - p->i64LastIdleTime;
+		__int64 i64System = i64User + i64Kernel;
+		*idle_percentage = 100.0 * i64Idle / i64System;
+	} else {
+		*idle_percentage = 100.0;
+		p->valid_last_times = 1;
+	}
+
+	/* Remember current value for the next call */
+	p->i64LastUserTime = i64UserTime;
+	p->i64LastKernelTime = i64KernelTime;
+	p->i64LastIdleTime = i64IdleTime;
+
+	/* Success */
+	return ZAP_SUCCESS;
+}
+#else
+/* Unsupported */
+OZ_DECLARE(zap_status_t) zap_cpu_get_system_idle_time(struct zap_cpu_monitor_stats *p, double *idle_percentage)
+{
+	return ZAP_FAIL;
+}
+#endif
+
+OZ_DECLARE(struct zap_cpu_monitor_stats*) zap_new_cpu_monitor(void)
+{
+	return calloc(1, sizeof(struct zap_cpu_monitor_stats));
+}
+
+OZ_DECLARE(void) zap_delete_cpu_monitor(struct zap_cpu_monitor_stats *p)
+{
+#ifdef __linux__
+	close(p->procfd);
+#endif
+	free(p);
+}
+
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */

Added: freeswitch/trunk/libs/openzap/src/zap_dso.c (0 => 17141)


--- freeswitch/trunk/libs/openzap/src/zap_dso.c	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/src/zap_dso.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,115 @@
+/* 
+ * Cross Platform dso/dll load abstraction
+ * Copyright(C) 2008 Michael Jerris
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so.
+ *
+ * This work is provided under this license on an "as is" basis, without warranty of any kind,
+ * either expressed or implied, including, without limitation, warranties that the covered code
+ * is free of defects, merchantable, fit for a particular purpose or non-infringing. The entire
+ * risk as to the quality and performance of the covered code is with you. Should any covered
+ * code prove defective in any respect, you (not the initial developer or any other contributor)
+ * assume the cost of any necessary servicing, repair or correction. This disclaimer of warranty
+ * constitutes an essential part of this license. No use of any covered code is authorized hereunder
+ * except under this disclaimer. 
+ *
+ */
+
+#include "zap_dso.h"
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef WIN32
+#include <windows.h>
+#include <stdio.h>
+
+
+void zap_dso_destroy(zap_dso_lib_t *lib) {
+	if (lib && *lib) {
+		FreeLibrary(*lib);
+		*lib = NULL;
+	}
+}
+
+zap_dso_lib_t zap_dso_open(const char *path, char **err) {
+    HINSTANCE lib;
+	
+	lib = LoadLibraryEx(path, NULL, 0);
+
+	if (!lib) {
+		LoadLibraryEx(path, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
+	}
+
+	if (!lib) {
+		DWORD error = GetLastError();
+		char tmp[80];
+		sprintf(tmp, "dll open error [%ul]\n", error);
+		*err = _strdup(tmp);
+	}
+
+	return lib;
+}
+
+void* zap_dso_func_sym(zap_dso_lib_t lib, const char *sym, char **err) {
+	FARPROC func = GetProcAddress(lib, sym);
+	if (!func) {
+		DWORD error = GetLastError();
+		char tmp[80];
+		sprintf(tmp, "dll sym error [%ul]\n", error);
+		*err = _strdup(tmp);
+	}
+	return (void *)(intptr_t)func; // this should really be addr - zap_dso_func_data
+}
+
+#else
+
+/*
+** {========================================================================
+** This is an implementation of loadlib based on the dlfcn interface.
+** The dlfcn interface is available in Linux, SunOS, Solaris, IRIX, FreeBSD,
+** NetBSD, AIX 4.2, HPUX 11, and  probably most other Unix flavors, at least
+** as an emulation layer on top of native functions.
+** =========================================================================
+*/
+
+
+#include <dlfcn.h>
+
+void zap_dso_destroy(zap_dso_lib_t *lib) {
+	if (lib && *lib) {
+		dlclose(*lib);
+		*lib = NULL;
+	}
+}
+
+zap_dso_lib_t zap_dso_open(const char *path, char **err) {
+	void *lib = dlopen(path, RTLD_NOW | RTLD_LOCAL);
+	if (lib == NULL) {
+		*err = strdup(dlerror());
+	}
+	return lib;
+}
+
+void *zap_dso_func_sym(zap_dso_lib_t lib, const char *sym, char **err) {
+	void *func = dlsym(lib, sym);
+	if (!func) {
+		*err = strdup(dlerror());
+	}
+	return func;
+}
+#endif
+
+/* }====================================================== */
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4
+ */

Added: freeswitch/trunk/libs/openzap/src/zap_io.c (0 => 17141)


--- freeswitch/trunk/libs/openzap/src/zap_io.c	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/src/zap_io.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,3526 @@
+/*
+ * Copyright (c) 2007, Anthony Minessale II
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define _GNU_SOURCE
+#ifndef WIN32
+#endif
+#include "openzap.h"
+#include <stdarg.h>
+#ifdef WIN32
+#include <io.h>
+#endif
+#ifdef ZAP_PIKA_SUPPORT
+#include "zap_pika.h"
+#endif
+#include "zap_cpu_monitor.h"
+
+static int time_is_init = 0;
+
+static void time_init(void)
+{
+#ifdef WIN32
+	timeBeginPeriod(1);
+#endif
+	time_is_init = 1;
+}
+
+static void time_end(void)
+{
+#ifdef WIN32
+	timeEndPeriod(1);
+#endif
+	time_is_init = 0;
+}
+
+
+OZ_DECLARE(zap_time_t) zap_current_time_in_ms(void)
+{
+#ifdef WIN32
+	return timeGetTime();
+#else
+	struct timeval tv;
+	gettimeofday(&tv, NULL);
+	return ((tv.tv_sec * 1000) + (tv.tv_usec / 1000));
+#endif
+}
+
+typedef struct {
+	uint8_t		running;
+	uint8_t 	alarm;
+	uint32_t	interval;
+	uint8_t		alarm_action_flags;
+	uint8_t		set_alarm_threshold;
+	uint8_t		reset_alarm_threshold;
+	zap_interrupt_t *interrupt;
+} cpu_monitor_t;
+
+static struct {
+	zap_hash_t *interface_hash;
+	zap_hash_t *module_hash;
+	zap_hash_t *span_hash;
+	zap_mutex_t *mutex;
+	zap_mutex_t *span_mutex;
+	uint32_t span_index;
+	uint32_t running;
+	zap_span_t *spans;
+	cpu_monitor_t cpu_monitor;
+} globals;
+
+static uint8_t zap_cpu_monitor_disabled = 0;
+
+enum zap_enum_cpu_alarm_action_flags
+{
+	ZAP_CPU_ALARM_ACTION_WARN = (1 << 0),
+	ZAP_CPU_ALARM_ACTION_REJECT = (1 << 1)
+};
+
+/* enum lookup funcs */
+ZAP_ENUM_NAMES(TONEMAP_NAMES, TONEMAP_STRINGS)
+ZAP_STR2ENUM(zap_str2zap_tonemap, zap_tonemap2str, zap_tonemap_t, TONEMAP_NAMES, ZAP_TONEMAP_INVALID)
+
+ZAP_ENUM_NAMES(OOB_NAMES, OOB_STRINGS)
+ZAP_STR2ENUM(zap_str2zap_oob_event, zap_oob_event2str, zap_oob_event_t, OOB_NAMES, ZAP_OOB_INVALID)
+
+ZAP_ENUM_NAMES(TRUNK_TYPE_NAMES, TRUNK_STRINGS)
+ZAP_STR2ENUM(zap_str2zap_trunk_type, zap_trunk_type2str, zap_trunk_type_t, TRUNK_TYPE_NAMES, ZAP_TRUNK_NONE)
+
+ZAP_ENUM_NAMES(START_TYPE_NAMES, START_TYPE_STRINGS)
+ZAP_STR2ENUM(zap_str2zap_analog_start_type, zap_analog_start_type2str, zap_analog_start_type_t, START_TYPE_NAMES, ZAP_ANALOG_START_NA)
+
+ZAP_ENUM_NAMES(SIGNAL_NAMES, SIGNAL_STRINGS)
+ZAP_STR2ENUM(zap_str2zap_signal_event, zap_signal_event2str, zap_signal_event_t, SIGNAL_NAMES, ZAP_SIGEVENT_INVALID)
+
+ZAP_ENUM_NAMES(CHANNEL_STATE_NAMES, CHANNEL_STATE_STRINGS)
+ZAP_STR2ENUM(zap_str2zap_channel_state, zap_channel_state2str, zap_channel_state_t, CHANNEL_STATE_NAMES, ZAP_CHANNEL_STATE_INVALID)
+
+ZAP_ENUM_NAMES(MDMF_TYPE_NAMES, MDMF_STRINGS)
+ZAP_STR2ENUM(zap_str2zap_mdmf_type, zap_mdmf_type2str, zap_mdmf_type_t, MDMF_TYPE_NAMES, MDMF_INVALID)
+
+ZAP_ENUM_NAMES(CHAN_TYPE_NAMES, CHAN_TYPE_STRINGS)
+ZAP_STR2ENUM(zap_str2zap_chan_type, zap_chan_type2str, zap_chan_type_t, CHAN_TYPE_NAMES, ZAP_CHAN_TYPE_COUNT)
+
+static zap_status_t zap_cpu_monitor_start(void);
+static void zap_cpu_monitor_stop(void);
+
+static const char *cut_path(const char *in)
+{
+	const char *p, *ret = in;
+	char delims[] = "/\\";
+	char *i;
+
+	for (i = delims; *i; i++) {
+		p = in;
+		while ((p = strchr(p, *i)) != 0) {
+			ret = ++p;
+		}
+	}
+	return ret;
+}
+
+static void null_logger(const char *file, const char *func, int line, int level, const char *fmt, ...)
+{
+	if (file && func && line && level && fmt) {
+		return;
+	}
+	return;
+}
+
+
+static const char *LEVEL_NAMES[] = {
+	"EMERG",
+	"ALERT",
+	"CRIT",
+	"ERROR",
+	"WARNING",
+	"NOTICE",
+	"INFO",
+	"DEBUG",
+	NULL
+};
+
+
+static int zap_log_level = 7;
+
+/* Cpu monitor thread */
+static void *zap_cpu_monitor_run(zap_thread_t *me, void *obj);
+
+static void default_logger(const char *file, const char *func, int line, int level, const char *fmt, ...)
+{
+	const char *fp;
+	char data[1024];
+	va_list ap;
+
+	if (level < 0 || level > 7) {
+		level = 7;
+	}
+	if (level > zap_log_level) {
+		return;
+	}
+	
+	fp = cut_path(file);
+
+	va_start(ap, fmt);
+
+	vsnprintf(data, sizeof(data), fmt, ap);
+
+
+	fprintf(stderr, "[%s] %s:%d %s() %s", LEVEL_NAMES[level], file, line, func, data);
+
+	va_end(ap);
+
+}
+
+static zap_status_t zap_set_caller_data(zap_span_t *span, zap_caller_data_t *caller_data)
+{
+	if (!caller_data) {
+		zap_log(ZAP_LOG_CRIT, "Error: trying to set caller data, but no caller_data!\n");
+		return ZAP_FAIL;
+	}
+
+	if (caller_data->cid_num.plan == ZAP_NPI_INVALID) {
+		caller_data->cid_num.plan = span->default_caller_data.cid_num.plan;
+	}
+
+	if (caller_data->cid_num.type == ZAP_TON_INVALID) {
+		caller_data->cid_num.type = span->default_caller_data.cid_num.type;
+	}
+
+	if (caller_data->ani.plan == ZAP_NPI_INVALID) {
+		caller_data->ani.plan = span->default_caller_data.ani.plan;
+	}
+
+	if (caller_data->ani.type == ZAP_TON_INVALID) {
+		caller_data->ani.type = span->default_caller_data.ani.type;
+	}
+
+	if (caller_data->rdnis.plan == ZAP_NPI_INVALID) {
+		caller_data->rdnis.plan = span->default_caller_data.rdnis.plan;
+	}
+
+	if (caller_data->rdnis.type == ZAP_NPI_INVALID) {
+		caller_data->rdnis.type = span->default_caller_data.rdnis.type;
+	}
+	return ZAP_SUCCESS;
+}
+
+OZ_DECLARE(zap_status_t) zap_channel_set_caller_data(zap_channel_t *zchan, zap_caller_data_t *caller_data)
+{
+	zap_status_t err = ZAP_SUCCESS;
+	if (!zchan) {
+		zap_log(ZAP_LOG_CRIT, "Error: trying to set caller data, but no zchan!\n");
+		return ZAP_FAIL;
+	}
+	if ((err = zap_set_caller_data(zchan->span, caller_data)) != ZAP_SUCCESS) {
+		return err; 
+	}
+	zchan->caller_data = *caller_data;
+	return ZAP_SUCCESS;
+}
+
+OZ_DECLARE_DATA zap_logger_t zap_log = null_logger;
+
+OZ_DECLARE(void) zap_global_set_logger(zap_logger_t logger)
+{
+	if (logger) {
+		zap_log = logger;
+	} else {
+		zap_log = null_logger;
+	}
+}
+
+OZ_DECLARE(void) zap_global_set_default_logger(int level)
+{
+	if (level < 0 || level > 7) {
+		level = 7;
+	}
+
+	zap_log = default_logger;
+	zap_log_level = level;
+}
+
+OZ_DECLARE_NONSTD(int) zap_hash_equalkeys(void *k1, void *k2)
+{
+    return strcmp((char *) k1, (char *) k2) ? 0 : 1;
+}
+
+OZ_DECLARE_NONSTD(uint32_t) zap_hash_hashfromstring(void *ky)
+{
+	unsigned char *str = (unsigned char *) ky;
+	uint32_t hash = 0;
+    int c;
+	
+	while ((c = *str++)) {
+        hash = c + (hash << 6) + (hash << 16) - hash;
+	}
+
+    return hash;
+}
+
+
+static zap_status_t zap_span_destroy(zap_span_t *span)
+{
+	zap_status_t status = ZAP_FAIL;
+	
+	if (zap_test_flag(span, ZAP_SPAN_CONFIGURED)) {
+		if (span->stop) {
+			span->stop(span);
+		}
+		if (span->zio && span->zio->span_destroy) {
+			zap_log(ZAP_LOG_INFO, "Destroying span %u type (%s)\n", span->span_id, span->type);
+			status = span->zio->span_destroy(span);
+			zap_safe_free(span->type);
+			zap_safe_free(span->dtmf_hangup);
+		}
+	}
+
+	return status;
+}
+
+static zap_status_t zap_channel_destroy(zap_channel_t *zchan)
+{
+
+	if (zap_test_flag(zchan, ZAP_CHANNEL_CONFIGURED)) {
+
+		while (zap_test_flag(zchan, ZAP_CHANNEL_INTHREAD)) {
+			zap_log(ZAP_LOG_INFO, "Waiting for thread to exit on channel %u:%u\n", zchan->span_id, zchan->chan_id);
+			zap_sleep(500);
+		}
+
+		zap_mutex_lock(zchan->pre_buffer_mutex);
+		zap_buffer_destroy(&zchan->pre_buffer);
+		zap_mutex_unlock(zchan->pre_buffer_mutex);
+
+		zap_buffer_destroy(&zchan->digit_buffer);
+		zap_buffer_destroy(&zchan->gen_dtmf_buffer);
+		zap_buffer_destroy(&zchan->dtmf_buffer);
+		zap_buffer_destroy(&zchan->fsk_buffer);
+		zchan->pre_buffer_size = 0;
+
+		hashtable_destroy(zchan->variable_hash);
+
+		zap_safe_free(zchan->dtmf_hangup_buf);
+
+		if (zchan->tone_session.buffer) {
+			teletone_destroy_session(&zchan->tone_session);
+			memset(&zchan->tone_session, 0, sizeof(zchan->tone_session));
+		}
+
+		
+		if (zchan->span->zio->channel_destroy) {
+			zap_log(ZAP_LOG_INFO, "Closing channel %s:%u:%u fd:%d\n", zchan->span->type, zchan->span_id, zchan->chan_id, zchan->sockfd);
+			if (zchan->span->zio->channel_destroy(zchan) == ZAP_SUCCESS) {
+				zap_clear_flag_locked(zchan, ZAP_CHANNEL_CONFIGURED);
+			} else {
+				zap_log(ZAP_LOG_ERROR, "Error Closing channel %u:%u fd:%d\n", zchan->span_id, zchan->chan_id, zchan->sockfd);
+			}
+		}
+
+		zap_mutex_destroy(&zchan->mutex);
+		zap_mutex_destroy(&zchan->pre_buffer_mutex);
+	}
+	
+	return ZAP_SUCCESS;
+}
+
+
+OZ_DECLARE(zap_status_t) zap_channel_get_alarms(zap_channel_t *zchan)
+{
+	zap_status_t status = ZAP_FAIL;
+
+	if (zap_test_flag(zchan, ZAP_CHANNEL_CONFIGURED)) {
+		if (zchan->span->zio->get_alarms) {
+			if ((status = zchan->span->zio->get_alarms(zchan)) == ZAP_SUCCESS) {
+				*zchan->last_error = '\0';
+				if (zap_test_alarm_flag(zchan, ZAP_ALARM_RED)) {
+					snprintf(zchan->last_error + strlen(zchan->last_error), sizeof(zchan->last_error) - strlen(zchan->last_error), "RED/");
+				}
+				if (zap_test_alarm_flag(zchan, ZAP_ALARM_YELLOW)) {
+					snprintf(zchan->last_error + strlen(zchan->last_error), sizeof(zchan->last_error) - strlen(zchan->last_error), "YELLOW/");
+				}
+				if (zap_test_alarm_flag(zchan, ZAP_ALARM_BLUE)) {
+					snprintf(zchan->last_error + strlen(zchan->last_error), sizeof(zchan->last_error) - strlen(zchan->last_error), "BLUE/");
+				}
+				if (zap_test_alarm_flag(zchan, ZAP_ALARM_LOOPBACK)) {
+					snprintf(zchan->last_error + strlen(zchan->last_error), sizeof(zchan->last_error) - strlen(zchan->last_error), "LOOP/");
+				}
+				if (zap_test_alarm_flag(zchan, ZAP_ALARM_RECOVER)) {
+					snprintf(zchan->last_error + strlen(zchan->last_error), sizeof(zchan->last_error) - strlen(zchan->last_error), "RECOVER/");
+				}
+				*(zchan->last_error + strlen(zchan->last_error) - 1) = '\0';
+
+			}
+		} else {
+			status = ZAP_NOTIMPL;
+		}
+	}
+	
+	return status;
+}
+
+static void zap_span_add(zap_span_t *span)
+{
+	zap_span_t *sp;
+	zap_mutex_lock(globals.span_mutex);
+	for (sp = globals.spans; sp && sp->next; sp = sp->next);
+	if (sp) {
+		sp->next = span;
+	} else {
+		globals.spans = span;
+	}
+	hashtable_insert(globals.span_hash, (void *)span->name, span, HASHTABLE_FLAG_NONE);
+	zap_mutex_unlock(globals.span_mutex);
+}
+
+#if 0
+static void zap_span_del(zap_span_t *span)
+{
+	zap_span_t *last = NULL, *sp;
+
+	zap_mutex_lock(globals.span_mutex);
+	for (sp = globals.spans; sp; sp = sp->next) {
+		
+		if (sp == span) {
+			if (last) {
+				last->next = sp->next;
+			} else {
+				globals.spans = sp->next;
+			}
+			hashtable_remove(globals.span_hash, (void *)sp->name);
+			break;
+		}
+
+		last = sp;
+	}
+	zap_mutex_unlock(globals.span_mutex);
+}
+#endif
+
+OZ_DECLARE(zap_status_t) zap_span_stop(zap_span_t *span)
+{
+	if (span->stop) {
+		span->stop(span);
+		return ZAP_SUCCESS;
+	}
+	
+	return ZAP_FAIL;
+}
+
+OZ_DECLARE(zap_status_t) zap_span_create(zap_io_interface_t *zio, zap_span_t **span, const char *name)
+{
+	zap_span_t *new_span = NULL;
+	zap_status_t status = ZAP_FAIL;
+
+	assert(zio != NULL);
+
+	zap_mutex_lock(globals.mutex);
+
+	if (globals.span_index < ZAP_MAX_SPANS_INTERFACE) {
+		new_span = malloc(sizeof(*new_span));
+		assert(new_span);
+		memset(new_span, 0, sizeof(*new_span));
+		status = zap_mutex_create(&new_span->mutex);
+		assert(status == ZAP_SUCCESS);
+		
+		zap_set_flag(new_span, ZAP_SPAN_CONFIGURED);
+		new_span->span_id = ++globals.span_index;
+		new_span->zio = zio;
+		zap_copy_string(new_span->tone_map[ZAP_TONEMAP_DIAL], "%(1000,0,350,440)", ZAP_TONEMAP_LEN);
+		zap_copy_string(new_span->tone_map[ZAP_TONEMAP_RING], "%(2000,4000,440,480)", ZAP_TONEMAP_LEN);
+		zap_copy_string(new_span->tone_map[ZAP_TONEMAP_BUSY], "%(500,500,480,620)", ZAP_TONEMAP_LEN);
+		zap_copy_string(new_span->tone_map[ZAP_TONEMAP_ATTN], "%(100,100,1400,2060,2450,2600)", ZAP_TONEMAP_LEN);
+		new_span->trunk_type = ZAP_TRUNK_NONE;
+		new_span->data_type = ZAP_TYPE_SPAN;
+
+		zap_mutex_lock(globals.span_mutex);
+		if (!zap_strlen_zero(name) && hashtable_search(globals.span_hash, (void *)name)) {
+			zap_log(ZAP_LOG_WARNING, "name %s is already used, substituting 'span%d' as the name\n", name, new_span->span_id);
+			name = NULL;
+		}
+		zap_mutex_unlock(globals.span_mutex);
+		
+		if (!name) {
+			char buf[128] = "";
+			snprintf(buf, sizeof(buf), "span%d", new_span->span_id);
+			name = buf;
+		}
+		new_span->name = strdup(name);
+		zap_span_add(new_span);
+		*span = new_span;
+		status = ZAP_SUCCESS;
+	}
+	zap_mutex_unlock(globals.mutex);
+	return status;
+}
+
+OZ_DECLARE(zap_status_t) zap_span_close_all(void)
+{
+	zap_span_t *span;
+	uint32_t i = 0, j;
+
+	zap_mutex_lock(globals.span_mutex);
+	for (span = globals.spans; span; span = span->next) {
+		if (zap_test_flag(span, ZAP_SPAN_CONFIGURED)) {
+			for(j = 1; j <= span->chan_count && span->channels[j]; j++) {
+				zap_channel_destroy(span->channels[j]);
+				i++;
+			}
+		} 
+	}
+	zap_mutex_unlock(globals.span_mutex);
+
+	return i ? ZAP_SUCCESS : ZAP_FAIL;
+}
+
+OZ_DECLARE(zap_status_t) zap_span_load_tones(zap_span_t *span, const char *mapname)
+{
+	zap_config_t cfg;
+	char *var, *val;
+	int x = 0;
+
+	if (!zap_config_open_file(&cfg, "tones.conf")) {
+		snprintf(span->last_error, sizeof(span->last_error), "error loading tones.");
+		return ZAP_FAIL;
+	}
+	
+	while (zap_config_next_pair(&cfg, &var, &val)) {
+		int detect = 0;
+
+		if (!strcasecmp(cfg.category, mapname) && var && val) {
+			uint32_t index;
+			char *name = NULL;
+
+			if (!strncasecmp(var, "detect-", 7)) {
+				name = var + 7;
+				detect = 1;
+			} else if (!strncasecmp(var, "generate-", 9)) {
+				name = var + 9;
+			} else {
+				zap_log(ZAP_LOG_WARNING, "Unknown tone name %s\n", var);
+				continue;
+			}
+
+			index = zap_str2zap_tonemap(name);
+
+			if (index >= ZAP_TONEMAP_INVALID || index == ZAP_TONEMAP_NONE) {
+				zap_log(ZAP_LOG_WARNING, "Unknown tone name %s\n", name);
+			} else {
+				if (detect) {
+					char *p = val, *next;
+					int i = 0;
+					do {
+						teletone_process_t this;
+						next = strchr(p, ',');
+						this = (teletone_process_t)atof(p);
+						span->tone_detect_map[index].freqs[i++] = this;
+						if (next) {
+							p = next + 1;
+						}
+					} while (next);
+					zap_log(ZAP_LOG_DEBUG, "added tone detect [%s] = [%s]\n", name, val);
+				}  else {
+					zap_log(ZAP_LOG_DEBUG, "added tone generation [%s] = [%s]\n", name, val);
+					zap_copy_string(span->tone_map[index], val, sizeof(span->tone_map[index]));
+				}
+				x++;
+			}
+		}
+	}
+
+	zap_config_close_file(&cfg);
+	
+	if (!x) {
+		snprintf(span->last_error, sizeof(span->last_error), "error loading tones.");
+		return ZAP_FAIL;
+	}
+
+	return ZAP_SUCCESS;
+	
+}
+
+#define ZAP_SLINEAR_MAX_VALUE 32767
+#define ZAP_SLINEAR_MIN_VALUE -32767
+static void reset_gain_table(unsigned char *gain_table, float new_gain, zap_codec_t codec_gain)
+{
+	/* sample value */
+	uint8_t sv = 0;
+	/* linear gain factor */
+	float lingain = 0;
+	/* linear value for each table sample */
+	float linvalue = 0;
+	/* amplified (or attenuated in case of negative amplification) sample value */
+	int ampvalue = 0;
+
+	/* gain tables are only for alaw and ulaw */
+	if (codec_gain != ZAP_CODEC_ALAW && codec_gain != ZAP_CODEC_ULAW) {
+		zap_log(ZAP_LOG_WARNING, "Not resetting gain table because codec is not ALAW or ULAW but %d\n", codec_gain);
+		return;
+	}
+
+	if (!new_gain) {
+		/* for a 0.0db gain table, each alaw/ulaw sample value is left untouched (0 ==0, 1 == 1, 2 == 2 etc)*/
+		sv = 0;
+		while (1) {
+			gain_table[sv] = (unsigned char)sv;
+			if (sv == (ZAP_GAINS_TABLE_SIZE - 1)) {
+				break;
+			}
+			sv++;
+		}
+		return;
+	}
+
+	/* use the 20log rule to increase the gain: http://en.wikipedia.org/wiki/Gain, http:/en.wikipedia.org/wiki/20_log_rule#Definitions */
+	lingain = (float)pow(10.0f, new_gain/20.0f);
+	sv = 0;
+	while (1) {
+		/* get the linear value for this alaw/ulaw sample value */
+		linvalue = codec_gain == ZAP_CODEC_ALAW ? (float)alaw_to_linear(sv) : (float)ulaw_to_linear(sv);
+
+		/* multiply the linear value and the previously calculated linear gain */
+		ampvalue = (int)(linvalue * lingain);
+
+		/* chop it if goes beyond the limits */
+		if (ampvalue > ZAP_SLINEAR_MAX_VALUE) {
+			ampvalue = ZAP_SLINEAR_MAX_VALUE;
+		}
+
+		if (ampvalue < ZAP_SLINEAR_MIN_VALUE) {
+			ampvalue = ZAP_SLINEAR_MIN_VALUE;
+		}
+		gain_table[sv] = codec_gain == ZAP_CODEC_ALAW ? linear_to_alaw(ampvalue) : linear_to_ulaw(ampvalue);
+		if (sv == (ZAP_GAINS_TABLE_SIZE-1)) {
+			break;
+		}
+		sv++;
+	}
+}
+
+OZ_DECLARE(zap_status_t) zap_span_add_channel(zap_span_t *span, zap_socket_t sockfd, zap_chan_type_t type, zap_channel_t **chan)
+{
+	unsigned i = 0;
+	if (span->chan_count < ZAP_MAX_CHANNELS_SPAN) {
+		zap_channel_t *new_chan = span->channels[++span->chan_count];
+
+		if (!new_chan) {
+			if (!(new_chan = malloc(sizeof(*new_chan)))) {
+				return ZAP_FAIL;
+			}
+			span->channels[span->chan_count] = new_chan;
+			memset(new_chan, 0, sizeof(*new_chan));
+		}
+
+		new_chan->type = type;
+		new_chan->sockfd = sockfd;
+		new_chan->zio = span->zio;
+		new_chan->span_id = span->span_id;
+		new_chan->chan_id = span->chan_count;
+		new_chan->span = span;
+		new_chan->fds[0] = -1;
+		new_chan->fds[1] = -1;
+		new_chan->data_type = ZAP_TYPE_CHANNEL;
+		if (!new_chan->dtmf_on) {
+			new_chan->dtmf_on = ZAP_DEFAULT_DTMF_ON;
+		}
+
+		if (!new_chan->dtmf_off) {
+			new_chan->dtmf_off = ZAP_DEFAULT_DTMF_OFF;
+		}
+
+		zap_mutex_create(&new_chan->mutex);
+		zap_mutex_create(&new_chan->pre_buffer_mutex);
+
+		zap_buffer_create(&new_chan->digit_buffer, 128, 128, 0);
+		zap_buffer_create(&new_chan->gen_dtmf_buffer, 128, 128, 0);
+		new_chan->variable_hash = create_hashtable(16, zap_hash_hashfromstring, zap_hash_equalkeys);
+
+		new_chan->dtmf_hangup_buf = calloc (span->dtmf_hangup_len + 1, sizeof (char));
+
+		/* set 0.0db gain table */
+		i = 0;
+		while (1) {
+			new_chan->txgain_table[i] = (unsigned char)i;
+			new_chan->rxgain_table[i] = (unsigned char)i;
+			if (i == (sizeof(new_chan->txgain_table)-1)) {
+				break;
+			}
+			i++;
+		}
+
+		zap_set_flag(new_chan, ZAP_CHANNEL_CONFIGURED | ZAP_CHANNEL_READY);
+		*chan = new_chan;
+		return ZAP_SUCCESS;
+	}
+
+	return ZAP_FAIL;
+}
+
+OZ_DECLARE(zap_status_t) zap_span_find_by_name(const char *name, zap_span_t **span)
+{
+	zap_status_t status = ZAP_FAIL;
+
+	zap_mutex_lock(globals.span_mutex);
+	if (!zap_strlen_zero(name)) {
+		if ((*span = hashtable_search(globals.span_hash, (void *)name))) {
+			status = ZAP_SUCCESS;
+		} else {
+			int span_id = atoi(name);
+
+			zap_span_find(span_id, span);
+			if (*span) {
+				status = ZAP_SUCCESS;
+			}
+		}
+	}
+	zap_mutex_unlock(globals.span_mutex);
+	
+	return status;
+}
+
+OZ_DECLARE(zap_status_t) zap_span_find(uint32_t id, zap_span_t **span)
+{
+	zap_span_t *fspan = NULL, *sp;
+
+	if (id > ZAP_MAX_SPANS_INTERFACE) {
+		return ZAP_FAIL;
+	}
+
+	zap_mutex_lock(globals.span_mutex);
+	for (sp = globals.spans; sp; sp = sp->next) {
+		if (sp->span_id == id) {
+			fspan = sp;
+			break;
+		}
+	}
+	zap_mutex_unlock(globals.span_mutex);
+
+	if (!fspan || !zap_test_flag(fspan, ZAP_SPAN_CONFIGURED)) {
+		return ZAP_FAIL;
+	}
+
+	*span = fspan;
+
+	return ZAP_SUCCESS;
+	
+}
+
+OZ_DECLARE(zap_status_t) zap_span_set_event_callback(zap_span_t *span, zio_event_cb_t event_callback)
+{
+	zap_mutex_lock(span->mutex);
+	span->event_callback = event_callback;
+	zap_mutex_unlock(span->mutex);
+	return ZAP_SUCCESS;
+}
+
+
+OZ_DECLARE(zap_status_t) zap_span_poll_event(zap_span_t *span, uint32_t ms)
+{
+	assert(span->zio != NULL);
+
+	if (span->zio->poll_event) {
+		return span->zio->poll_event(span, ms);
+	} else {
+		zap_log(ZAP_LOG_ERROR, "poll_event method not implemented in module %s!", span->zio->name);
+	}
+
+	return ZAP_NOTIMPL;
+}
+
+OZ_DECLARE(zap_status_t) zap_span_next_event(zap_span_t *span, zap_event_t **event)
+{
+	assert(span->zio != NULL);
+
+	if (span->zio->next_event) {
+		return span->zio->next_event(span, event);
+	} else {
+		zap_log(ZAP_LOG_ERROR, "next_event method not implemented in module %s!", span->zio->name);
+	}
+	
+	return ZAP_NOTIMPL;
+}
+
+static zap_status_t zchan_fsk_write_sample(int16_t *buf, zap_size_t buflen, void *user_data)
+{
+	zap_channel_t *zchan = (zap_channel_t *) user_data;
+	zap_buffer_write(zchan->fsk_buffer, buf, buflen * 2);
+	return ZAP_SUCCESS;
+}
+
+OZ_DECLARE(zap_status_t) zap_channel_send_fsk_data(zap_channel_t *zchan, zap_fsk_data_state_t *fsk_data, float db_level)
+{
+	struct zap_fsk_modulator fsk_trans;
+
+	if (!zchan->fsk_buffer) {
+		zap_buffer_create(&zchan->fsk_buffer, 128, 128, 0);
+	} else {
+		zap_buffer_zero(zchan->fsk_buffer);
+	}
+
+	if (zchan->token_count > 1) {
+		zap_fsk_modulator_init(&fsk_trans, FSK_BELL202, zchan->rate, fsk_data, db_level, 80, 5, 0, zchan_fsk_write_sample, zchan);
+		zap_fsk_modulator_send_all((&fsk_trans));
+	} else {
+		zap_fsk_modulator_init(&fsk_trans, FSK_BELL202, zchan->rate, fsk_data, db_level, 180, 5, 300, zchan_fsk_write_sample, zchan);
+		zap_fsk_modulator_send_all((&fsk_trans));
+		zchan->buffer_delay = 3500 / zchan->effective_interval;
+	}
+
+	return ZAP_SUCCESS;
+}
+
+
+OZ_DECLARE(zap_status_t) zap_channel_set_event_callback(zap_channel_t *zchan, zio_event_cb_t event_callback)
+{
+	zap_mutex_lock(zchan->mutex);
+	zchan->event_callback = event_callback;
+	zap_mutex_unlock(zchan->mutex);
+	return ZAP_SUCCESS;
+}
+
+OZ_DECLARE(zap_status_t) zap_channel_clear_token(zap_channel_t *zchan, const char *token)
+{
+	zap_status_t status = ZAP_FAIL;
+	
+	zap_mutex_lock(zchan->mutex);
+	if (token == NULL) {
+		memset(zchan->tokens, 0, sizeof(zchan->tokens));
+		zchan->token_count = 0;
+	} else if (*token != '\0') {
+		char tokens[ZAP_MAX_TOKENS][ZAP_TOKEN_STRLEN];
+		int32_t i, count = zchan->token_count;
+		memcpy(tokens, zchan->tokens, sizeof(tokens));
+		memset(zchan->tokens, 0, sizeof(zchan->tokens));
+		zchan->token_count = 0;		
+
+		for (i = 0; i < count; i++) {
+			if (strcmp(tokens[i], token)) {
+				zap_copy_string(zchan->tokens[zchan->token_count], tokens[i], sizeof(zchan->tokens[zchan->token_count]));
+				zchan->token_count++;
+			}
+		}
+
+		status = ZAP_SUCCESS;
+	}
+	zap_mutex_unlock(zchan->mutex);
+
+	return status;
+}
+
+OZ_DECLARE(void) zap_channel_rotate_tokens(zap_channel_t *zchan)
+{
+	if (zchan->token_count) {
+		memmove(zchan->tokens[1], zchan->tokens[0], zchan->token_count * ZAP_TOKEN_STRLEN);
+		zap_copy_string(zchan->tokens[0], zchan->tokens[zchan->token_count], ZAP_TOKEN_STRLEN);
+		*zchan->tokens[zchan->token_count] = '\0';
+	}
+}
+
+OZ_DECLARE(void) zap_channel_replace_token(zap_channel_t *zchan, const char *old_token, const char *new_token)
+{
+	unsigned int i;
+
+	if (zchan->token_count) {
+		for(i = 0; i < zchan->token_count; i++) {
+			if (!strcmp(zchan->tokens[i], old_token)) {
+				zap_copy_string(zchan->tokens[i], new_token, ZAP_TOKEN_STRLEN);
+				break;
+			}
+		}
+	}
+}
+
+OZ_DECLARE(zap_status_t) zap_channel_add_token(zap_channel_t *zchan, char *token, int end)
+{
+	zap_status_t status = ZAP_FAIL;
+
+	zap_mutex_lock(zchan->mutex);
+	if (zchan->token_count < ZAP_MAX_TOKENS) {
+		if (end) {
+			zap_copy_string(zchan->tokens[zchan->token_count++], token, ZAP_TOKEN_STRLEN);
+		} else {
+			memmove(zchan->tokens[1], zchan->tokens[0], zchan->token_count * ZAP_TOKEN_STRLEN);
+			zap_copy_string(zchan->tokens[0], token, ZAP_TOKEN_STRLEN);
+			zchan->token_count++;
+		}
+		status = ZAP_SUCCESS;
+	}
+	zap_mutex_unlock(zchan->mutex);
+
+	return status;
+}
+
+
+OZ_DECLARE(zap_status_t) zap_channel_complete_state(zap_channel_t *zchan)
+{
+	zap_channel_state_t state = zchan->state;
+
+	if (state == ZAP_CHANNEL_STATE_PROGRESS) {
+		zap_set_flag(zchan, ZAP_CHANNEL_PROGRESS);
+	} else if (state == ZAP_CHANNEL_STATE_UP) {
+		zap_set_flag(zchan, ZAP_CHANNEL_PROGRESS);
+		zap_set_flag(zchan, ZAP_CHANNEL_MEDIA);	
+		zap_set_flag(zchan, ZAP_CHANNEL_ANSWERED);	
+	} else if (state == ZAP_CHANNEL_STATE_PROGRESS_MEDIA) {
+		zap_set_flag(zchan, ZAP_CHANNEL_PROGRESS);	
+		zap_set_flag(zchan, ZAP_CHANNEL_MEDIA);	
+	}
+
+	return ZAP_SUCCESS;
+}
+
+static int zap_parse_state_map(zap_channel_t *zchan, zap_channel_state_t state, zap_state_map_t *state_map)
+{
+	int x = 0, ok = 0;
+	zap_state_direction_t direction = zap_test_flag(zchan, ZAP_CHANNEL_OUTBOUND) ? ZSD_OUTBOUND : ZSD_INBOUND;
+
+	for(x = 0; x < ZAP_MAP_NODE_SIZE; x++) {
+		int i = 0, proceed = 0;
+		if (!state_map->nodes[x].type) {
+			break;
+		}
+
+		if (state_map->nodes[x].direction != direction) {
+			continue;
+		}
+		
+		if (state_map->nodes[x].check_states[0] == ZAP_ANY_STATE) {
+			proceed = 1;
+		} else {
+			for(i = 0; i < ZAP_MAP_MAX; i++) {
+				if (state_map->nodes[x].check_states[i] == zchan->state) {
+					proceed = 1;
+					break;
+				}
+			}
+		}
+
+		if (!proceed) {
+			continue;
+		}
+		
+		for(i = 0; i < ZAP_MAP_MAX; i++) {
+			ok = (state_map->nodes[x].type == ZSM_ACCEPTABLE);
+			if (state_map->nodes[x].states[i] == ZAP_END) {
+				break;
+			}
+			if (state_map->nodes[x].states[i] == state) {
+				ok = !ok;
+				goto end;
+			}
+		}
+	}
+ end:
+	
+	return ok;
+}
+
+OZ_DECLARE(zap_status_t) zap_channel_set_state(zap_channel_t *zchan, zap_channel_state_t state, int lock)
+{
+	int ok = 1;
+	
+	if (!zap_test_flag(zchan, ZAP_CHANNEL_READY)) {
+		return ZAP_FAIL;
+	}
+
+	if (zap_test_flag(zchan->span, ZAP_SPAN_SUSPENDED)) {
+		if (state != ZAP_CHANNEL_STATE_RESTART && state != ZAP_CHANNEL_STATE_DOWN) {
+			return ZAP_FAIL;
+		}
+	}
+
+	if (lock) {
+		zap_mutex_lock(zchan->mutex);
+	}
+
+	if (zchan->span->state_map) {
+		ok = zap_parse_state_map(zchan, state, zchan->span->state_map);
+		goto end;
+	}
+
+	switch(zchan->state) {
+	case ZAP_CHANNEL_STATE_HANGUP:
+	case ZAP_CHANNEL_STATE_TERMINATING:
+		{
+			ok = 0;
+			switch(state) {
+			case ZAP_CHANNEL_STATE_DOWN:
+			case ZAP_CHANNEL_STATE_BUSY:
+			case ZAP_CHANNEL_STATE_RESTART:
+				ok = 1;
+				break;
+			default:
+				break;
+			}
+		}
+		break;
+	case ZAP_CHANNEL_STATE_UP:
+		{
+			ok = 1;
+			switch(state) {
+			case ZAP_CHANNEL_STATE_PROGRESS:
+			case ZAP_CHANNEL_STATE_PROGRESS_MEDIA:
+			case ZAP_CHANNEL_STATE_RING:
+				ok = 0;
+				break;
+			default:
+				break;
+			}
+		}
+		break;
+	case ZAP_CHANNEL_STATE_DOWN:
+		{
+			ok = 0;
+			
+			switch(state) {
+			case ZAP_CHANNEL_STATE_DIALTONE:
+			case ZAP_CHANNEL_STATE_COLLECT:
+			case ZAP_CHANNEL_STATE_DIALING:
+			case ZAP_CHANNEL_STATE_RING:
+			case ZAP_CHANNEL_STATE_PROGRESS_MEDIA:
+			case ZAP_CHANNEL_STATE_PROGRESS:				
+			case ZAP_CHANNEL_STATE_GET_CALLERID:
+			case ZAP_CHANNEL_STATE_GENRING:
+				ok = 1;
+				break;
+			default:
+				break;
+			}
+		}
+		break;
+	case ZAP_CHANNEL_STATE_BUSY:
+		{
+			switch(state) {
+			case ZAP_CHANNEL_STATE_UP:
+				ok = 0;
+				break;
+			default:
+				break;
+			}
+		}
+		break;
+	case ZAP_CHANNEL_STATE_RING:
+		{
+			switch(state) {
+			case ZAP_CHANNEL_STATE_UP:
+				ok = 1;
+				break;
+			default:
+				break;
+			}
+		}
+		break;
+	default:
+		break;
+	}
+
+ end:
+
+	if (state == zchan->state) {
+		ok = 0;
+	}
+	
+
+	if (ok) {
+		zap_set_flag(zchan, ZAP_CHANNEL_STATE_CHANGE);	
+		zap_set_flag_locked(zchan->span, ZAP_SPAN_STATE_CHANGE);	
+		zchan->last_state = zchan->state; 
+		zchan->state = state;
+	}
+
+	if (lock) {
+		zap_mutex_unlock(zchan->mutex);
+	}
+
+	return ok ? ZAP_SUCCESS : ZAP_FAIL;
+}
+
+OZ_DECLARE(zap_status_t) zap_span_channel_use_count(zap_span_t *span, uint32_t *count)
+{
+	uint32_t j;
+
+	*count = 0;
+	
+	if (!span || !zap_test_flag(span, ZAP_SPAN_CONFIGURED)) {
+		return ZAP_FAIL;
+	}
+	
+	for(j = 1; j <= span->chan_count && span->channels[j]; j++) {
+		if (span->channels[j]) {
+			if (zap_test_flag(span->channels[j], ZAP_CHANNEL_INUSE)) {
+				(*count)++;
+			}
+		}
+	}
+	
+	return ZAP_SUCCESS;
+}
+
+OZ_DECLARE(zap_status_t) zap_channel_open_any(uint32_t span_id, zap_direction_t direction, zap_caller_data_t *caller_data, zap_channel_t **zchan)
+{
+	zap_status_t status = ZAP_FAIL;
+	zap_channel_t *check;
+	uint32_t i, j, count;
+	zap_span_t *span = NULL;
+	uint32_t span_max;
+
+	if (span_id) {
+		zap_span_find(span_id, &span);
+
+		if (!span || !zap_test_flag(span, ZAP_SPAN_CONFIGURED)) {
+			zap_log(ZAP_LOG_CRIT, "SPAN NOT DEFINED!\n");
+			*zchan = NULL;
+            return ZAP_FAIL;
+		}
+
+		zap_span_channel_use_count(span, &count);
+
+		if (count >= span->chan_count) {
+			zap_log(ZAP_LOG_CRIT, "All circuits are busy.\n");
+			*zchan = NULL;
+			return ZAP_FAIL;
+		}
+
+		if (span->channel_request && !span->suggest_chan_id) {
+			zap_set_caller_data(span, caller_data);
+			return span->channel_request(span, 0, direction, caller_data, zchan);
+		}
+		
+		span_max = span_id;
+		j = span_id;
+	} else {
+		zap_log(ZAP_LOG_CRIT, "No span supplied\n");
+		*zchan = NULL;
+		return ZAP_FAIL;
+	}
+	
+	zap_mutex_lock(span->mutex);
+	
+	if (direction == ZAP_TOP_DOWN) {
+		i = 1;
+	} else {
+		i = span->chan_count;
+	}	
+		
+	for(;;) {
+
+		if (direction == ZAP_TOP_DOWN) {
+			if (i > span->chan_count) {
+				break;
+			}
+		} else {
+			if (i == 0) {
+				break;
+			}
+		}
+			
+		if (!(check = span->channels[i])) {
+			status = ZAP_FAIL;
+			break;
+		}
+			
+		if (zap_test_flag(check, ZAP_CHANNEL_READY) && 
+			!zap_test_flag(check, ZAP_CHANNEL_INUSE) && 
+			!zap_test_flag(check, ZAP_CHANNEL_SUSPENDED) && 
+			check->state == ZAP_CHANNEL_STATE_DOWN && 
+			check->type != ZAP_CHAN_TYPE_DQ921 &&
+			check->type != ZAP_CHAN_TYPE_DQ931
+			
+			) {
+
+			if (span && span->channel_request) {
+				zap_set_caller_data(span, caller_data);
+				status = span->channel_request(span, i, direction, caller_data, zchan);
+				break;
+			}
+
+			status = check->zio->open(check);
+				
+			if (status == ZAP_SUCCESS) {
+				zap_set_flag(check, ZAP_CHANNEL_INUSE);
+				zap_channel_open_chan(check);
+				*zchan = check;
+				break;
+			}
+		}
+		
+		if (direction == ZAP_TOP_DOWN) {
+			i++;
+		} else {
+			i--;
+		}
+	}
+
+	zap_mutex_unlock(span->mutex);
+
+	return status;
+}
+
+static zap_status_t zap_channel_reset(zap_channel_t *zchan)
+{
+	zap_clear_flag(zchan, ZAP_CHANNEL_OPEN);
+	zchan->event_callback = NULL;
+	zap_clear_flag(zchan, ZAP_CHANNEL_DTMF_DETECT);
+	zap_clear_flag(zchan, ZAP_CHANNEL_SUPRESS_DTMF);
+	zap_channel_done(zchan);
+	zap_clear_flag_locked(zchan, ZAP_CHANNEL_HOLD);
+
+	memset(zchan->tokens, 0, sizeof(zchan->tokens));
+	zchan->token_count = 0;
+
+	if (zchan->dtmf_buffer) {
+		zap_buffer_zero(zchan->dtmf_buffer);
+	}
+
+	if (zchan->gen_dtmf_buffer) {
+		zap_buffer_zero(zchan->gen_dtmf_buffer);
+	}
+
+	if (zchan->digit_buffer) {
+		zap_buffer_zero(zchan->digit_buffer);
+	}
+
+	if (!zchan->dtmf_on) {
+		zchan->dtmf_on = ZAP_DEFAULT_DTMF_ON;
+	}
+
+	if (!zchan->dtmf_off) {
+		zchan->dtmf_off = ZAP_DEFAULT_DTMF_OFF;
+	}
+	
+	memset(zchan->dtmf_hangup_buf, '\0', zchan->span->dtmf_hangup_len);
+
+	if (zap_test_flag(zchan, ZAP_CHANNEL_TRANSCODE)) {
+		zchan->effective_codec = zchan->native_codec;
+		zchan->packet_len = zchan->native_interval * (zchan->effective_codec == ZAP_CODEC_SLIN ? 16 : 8);
+		zap_clear_flag(zchan, ZAP_CHANNEL_TRANSCODE);
+	}
+
+	return ZAP_SUCCESS;
+}
+
+OZ_DECLARE(zap_status_t) zap_channel_init(zap_channel_t *zchan)
+{
+
+	if (zchan->init_state != ZAP_CHANNEL_STATE_DOWN) {
+		zap_set_state_locked(zchan, zchan->init_state);
+		zchan->init_state = ZAP_CHANNEL_STATE_DOWN;
+	}
+
+	return ZAP_SUCCESS;
+}
+
+OZ_DECLARE(zap_status_t) zap_channel_open_chan(zap_channel_t *zchan)
+{
+	zap_status_t status = ZAP_FAIL;
+
+	assert(zchan != NULL);
+
+	if (zap_test_flag(zchan, ZAP_CHANNEL_SUSPENDED)) {
+		snprintf(zchan->last_error, sizeof(zchan->last_error), "%s", "Channel is suspended");
+		return ZAP_FAIL;
+	}
+	if (globals.cpu_monitor.alarm &&
+			globals.cpu_monitor.alarm_action_flags & ZAP_CPU_ALARM_ACTION_REJECT) {
+
+		snprintf(zchan->last_error, sizeof(zchan->last_error), "%s", "CPU usage alarm is on - refusing to open channel\n");
+		zap_log(ZAP_LOG_WARNING, "CPU usage alarm is on - refusing to open channel\n");
+		zchan->caller_data.hangup_cause = ZAP_CAUSE_SWITCH_CONGESTION;
+		return ZAP_FAIL;
+	}
+	
+	if (!zap_test_flag(zchan, ZAP_CHANNEL_READY) || (status = zap_mutex_trylock(zchan->mutex)) != ZAP_SUCCESS) {
+		snprintf(zchan->last_error, sizeof(zchan->last_error), "Channel is not ready or is in use %d %d", zap_test_flag(zchan, ZAP_CHANNEL_READY), status);
+		return status;
+	}
+
+	status = ZAP_FAIL;
+
+	if (zap_test_flag(zchan, ZAP_CHANNEL_READY)) {
+		status = zchan->span->zio->open(zchan);
+		if (status == ZAP_SUCCESS) {
+			zap_set_flag(zchan, ZAP_CHANNEL_OPEN | ZAP_CHANNEL_INUSE);
+		}
+	} else {
+		snprintf(zchan->last_error, sizeof(zchan->last_error), "%s", "Channel is not ready");
+	}
+
+	zap_mutex_unlock(zchan->mutex);
+	return status;
+}
+
+OZ_DECLARE(zap_status_t) zap_channel_open(uint32_t span_id, uint32_t chan_id, zap_channel_t **zchan)
+{
+	zap_channel_t *check;
+	zap_status_t status = ZAP_FAIL;
+	zap_span_t *span = NULL;
+
+	zap_mutex_unlock(globals.mutex);
+	zap_span_find(span_id, &span);
+
+	if (!span || !zap_test_flag(span, ZAP_SPAN_CONFIGURED) || chan_id >= ZAP_MAX_CHANNELS_SPAN) {
+		zap_log(ZAP_LOG_CRIT, "SPAN NOT DEFINED!\n");
+		*zchan = NULL;
+		goto done;
+	}
+
+	if (span->channel_request) {
+		zap_log(ZAP_LOG_ERROR, "Individual channel selection not implemented on this span.\n");
+		*zchan = NULL;
+		goto done;
+	}
+	
+	if (!(check = span->channels[chan_id])) {
+		zap_log(ZAP_LOG_ERROR, "Invalid Channel %d\n", chan_id);
+		*zchan = NULL;
+		goto done;
+	}
+
+	if (zap_test_flag(check, ZAP_CHANNEL_SUSPENDED) || 
+		!zap_test_flag(check, ZAP_CHANNEL_READY) || (status = zap_mutex_trylock(check->mutex)) != ZAP_SUCCESS) {
+		*zchan = NULL;
+		goto done;
+	}
+	
+	status = ZAP_FAIL;
+
+	if (zap_test_flag(check, ZAP_CHANNEL_READY) && (!zap_test_flag(check, ZAP_CHANNEL_INUSE) || 
+													(check->type == ZAP_CHAN_TYPE_FXS && check->token_count == 1))) {
+		if (!zap_test_flag(check, ZAP_CHANNEL_OPEN)) {
+			status = check->zio->open(check);
+			if (status == ZAP_SUCCESS) {
+				zap_set_flag(check, ZAP_CHANNEL_OPEN);
+			}
+		} else {
+			status = ZAP_SUCCESS;
+		}
+		zap_set_flag(check, ZAP_CHANNEL_INUSE);
+		*zchan = check;
+	}
+	zap_mutex_unlock(check->mutex);
+
+	done:
+	zap_mutex_unlock(globals.mutex);
+
+	return status;
+}
+
+OZ_DECLARE(zap_status_t) zap_channel_outgoing_call(zap_channel_t *zchan)
+{
+	zap_status_t status;
+
+	assert(zchan != NULL);
+	
+	if (zchan->span->outgoing_call) {
+		if ((status = zchan->span->outgoing_call(zchan)) == ZAP_SUCCESS) {
+			zap_set_flag(zchan, ZAP_CHANNEL_OUTBOUND);
+		}
+		return status;
+	} else {
+		zap_log(ZAP_LOG_ERROR, "outgoing_call method not implemented!\n");
+	}
+	
+	return ZAP_FAIL;
+}
+
+OZ_DECLARE(zap_status_t) zap_channel_done(zap_channel_t *zchan)
+{
+	assert(zchan != NULL);
+
+	memset(&zchan->caller_data, 0, sizeof(zchan->caller_data));
+
+	zap_clear_flag_locked(zchan, ZAP_CHANNEL_INUSE);
+	zap_clear_flag_locked(zchan, ZAP_CHANNEL_OUTBOUND);
+	zap_clear_flag_locked(zchan, ZAP_CHANNEL_WINK);
+	zap_clear_flag_locked(zchan, ZAP_CHANNEL_FLASH);
+	zap_clear_flag_locked(zchan, ZAP_CHANNEL_STATE_CHANGE);
+	zap_clear_flag_locked(zchan, ZAP_CHANNEL_HOLD);
+	zap_clear_flag_locked(zchan, ZAP_CHANNEL_OFFHOOK);
+	zap_clear_flag_locked(zchan, ZAP_CHANNEL_RINGING);
+	zap_clear_flag_locked(zchan, ZAP_CHANNEL_PROGRESS_DETECT);
+	zap_clear_flag_locked(zchan, ZAP_CHANNEL_CALLERID_DETECT);
+	zap_clear_flag_locked(zchan, ZAP_CHANNEL_3WAY);
+	zap_clear_flag_locked(zchan, ZAP_CHANNEL_PROGRESS);
+	zap_clear_flag_locked(zchan, ZAP_CHANNEL_MEDIA);
+	zap_clear_flag_locked(zchan, ZAP_CHANNEL_ANSWERED);
+	zap_mutex_lock(zchan->pre_buffer_mutex);
+	zap_buffer_destroy(&zchan->pre_buffer);
+	zchan->pre_buffer_size = 0;
+	zap_mutex_unlock(zchan->pre_buffer_mutex);
+
+	zap_channel_flush_dtmf(zchan);
+
+	zchan->init_state = ZAP_CHANNEL_STATE_DOWN;
+	zchan->state = ZAP_CHANNEL_STATE_DOWN;
+	zap_log(ZAP_LOG_DEBUG, "channel done %u:%u\n", zchan->span_id, zchan->chan_id);
+
+	return ZAP_SUCCESS;
+}
+
+OZ_DECLARE(zap_status_t) zap_channel_use(zap_channel_t *zchan)
+{
+
+	assert(zchan != NULL);
+
+	zap_set_flag_locked(zchan, ZAP_CHANNEL_INUSE);
+
+	return ZAP_SUCCESS;
+}
+
+OZ_DECLARE(zap_status_t) zap_channel_close(zap_channel_t **zchan)
+{
+	zap_channel_t *check;
+	zap_status_t status = ZAP_FAIL;
+
+	assert(zchan != NULL);
+	check = *zchan;
+	*zchan = NULL;
+
+	if (!check) {
+		return ZAP_FAIL;
+	}
+
+	if (zap_test_flag(check, ZAP_CHANNEL_CONFIGURED)) {
+		zap_mutex_lock(check->mutex);
+		if (zap_test_flag(check, ZAP_CHANNEL_OPEN)) {
+			status = check->zio->close(check);
+			if (status == ZAP_SUCCESS) {
+				zap_channel_reset(check);
+				*zchan = NULL;
+			}
+		}
+		check->ring_count = 0;
+		zap_mutex_unlock(check->mutex);
+	}
+	
+	return status;
+}
+
+
+static zap_status_t zchan_activate_dtmf_buffer(zap_channel_t *zchan)
+{
+
+	if (!zchan->dtmf_buffer) {
+		if (zap_buffer_create(&zchan->dtmf_buffer, 1024, 3192, 0) != ZAP_SUCCESS) {
+			zap_log(ZAP_LOG_ERROR, "Failed to allocate DTMF Buffer!\n");
+			snprintf(zchan->last_error, sizeof(zchan->last_error), "buffer error");
+			return ZAP_FAIL;
+		} else {
+			zap_log(ZAP_LOG_DEBUG, "Created DTMF Buffer!\n");
+		}
+	}
+
+	
+	if (!zchan->tone_session.buffer) {
+		memset(&zchan->tone_session, 0, sizeof(zchan->tone_session));
+		teletone_init_session(&zchan->tone_session, 0, NULL, NULL);
+	}
+
+	zchan->tone_session.rate = zchan->rate;
+	zchan->tone_session.duration = zchan->dtmf_on * (zchan->tone_session.rate / 1000);
+	zchan->tone_session.wait = zchan->dtmf_off * (zchan->tone_session.rate / 1000);
+	zchan->tone_session.volume = -7;
+
+	/*
+	  zchan->tone_session.debug = 1;
+	  zchan->tone_session.debug_stream = stdout;
+	*/
+
+	return ZAP_SUCCESS;
+}
+
+OZ_DECLARE(zap_status_t) zap_channel_command(zap_channel_t *zchan, zap_command_t command, void *obj)
+{
+	zap_status_t status = ZAP_FAIL;
+	
+	assert(zchan != NULL);
+	assert(zchan->zio != NULL);
+
+	zap_mutex_lock(zchan->mutex);
+
+	switch(command) {
+
+	case ZAP_COMMAND_ENABLE_CALLERID_DETECT:
+		{
+			if (!zap_channel_test_feature(zchan, ZAP_CHANNEL_FEATURE_CALLERID)) {
+				if (zap_fsk_demod_init(&zchan->fsk, zchan->rate, zchan->fsk_buf, sizeof(zchan->fsk_buf)) != ZAP_SUCCESS) {
+					snprintf(zchan->last_error, sizeof(zchan->last_error), "%s", strerror(errno));
+					GOTO_STATUS(done, ZAP_FAIL);
+				}
+				zap_set_flag_locked(zchan, ZAP_CHANNEL_CALLERID_DETECT);
+			}
+		}
+		break;
+	case ZAP_COMMAND_DISABLE_CALLERID_DETECT:
+		{
+			if (!zap_channel_test_feature(zchan, ZAP_CHANNEL_FEATURE_CALLERID)) {
+				zap_fsk_demod_destroy(&zchan->fsk);
+				zap_clear_flag_locked(zchan, ZAP_CHANNEL_CALLERID_DETECT);
+			}
+		}
+		break;
+	case ZAP_COMMAND_TRACE_INPUT:
+		{
+			char *path = (char *) obj;
+			if (zchan->fds[0] > 0) {
+				close(zchan->fds[0]);
+				zchan->fds[0] = -1;
+			}
+			if ((zchan->fds[0] = open(path, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR)) > -1) {
+				zap_log(ZAP_LOG_DEBUG, "Tracing channel %u:%u to [%s]\n", zchan->span_id, zchan->chan_id, path);	
+				GOTO_STATUS(done, ZAP_SUCCESS);
+			}
+			
+			snprintf(zchan->last_error, sizeof(zchan->last_error), "%s", strerror(errno));
+			GOTO_STATUS(done, ZAP_FAIL);
+		}
+		break;
+	case ZAP_COMMAND_TRACE_OUTPUT:
+		{
+			char *path = (char *) obj;
+			if (zchan->fds[1] > 0) {
+				close(zchan->fds[1]);
+				zchan->fds[1] = -1;
+			}
+			if ((zchan->fds[1] = open(path, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR)) > -1) {
+				zap_log(ZAP_LOG_DEBUG, "Tracing channel %u:%u to [%s]\n", zchan->span_id, zchan->chan_id, path);	
+				GOTO_STATUS(done, ZAP_SUCCESS);
+			}
+			
+			snprintf(zchan->last_error, sizeof(zchan->last_error), "%s", strerror(errno));
+			GOTO_STATUS(done, ZAP_FAIL);
+		}
+		break;
+	case ZAP_COMMAND_SET_INTERVAL:
+		{
+			if (!zap_channel_test_feature(zchan, ZAP_CHANNEL_FEATURE_INTERVAL)) {
+				zchan->effective_interval = ZAP_COMMAND_OBJ_INT;
+				if (zchan->effective_interval == zchan->native_interval) {
+					zap_clear_flag(zchan, ZAP_CHANNEL_BUFFER);
+				} else {
+					zap_set_flag(zchan, ZAP_CHANNEL_BUFFER);
+				}
+				zchan->packet_len = zchan->native_interval * (zchan->effective_codec == ZAP_CODEC_SLIN ? 16 : 8);
+				GOTO_STATUS(done, ZAP_SUCCESS);
+			}
+		}
+		break;
+	case ZAP_COMMAND_GET_INTERVAL:
+		{
+			if (!zap_channel_test_feature(zchan, ZAP_CHANNEL_FEATURE_INTERVAL)) {
+				ZAP_COMMAND_OBJ_INT = zchan->effective_interval;
+				GOTO_STATUS(done, ZAP_SUCCESS);
+			}
+		}
+		break;
+	case ZAP_COMMAND_SET_CODEC:
+		{
+			if (!zap_channel_test_feature(zchan, ZAP_CHANNEL_FEATURE_CODECS)) {
+				zchan->effective_codec = ZAP_COMMAND_OBJ_INT;
+				
+				if (zchan->effective_codec == zchan->native_codec) {
+					zap_clear_flag(zchan, ZAP_CHANNEL_TRANSCODE);
+				} else {
+					zap_set_flag(zchan, ZAP_CHANNEL_TRANSCODE);
+				}
+				zchan->packet_len = zchan->native_interval * (zchan->effective_codec == ZAP_CODEC_SLIN ? 16 : 8);
+				GOTO_STATUS(done, ZAP_SUCCESS);
+			}
+		}
+		break;
+
+	case ZAP_COMMAND_SET_NATIVE_CODEC:
+		{
+			if (!zap_channel_test_feature(zchan, ZAP_CHANNEL_FEATURE_CODECS)) {
+				zchan->effective_codec = zchan->native_codec;
+				zap_clear_flag(zchan, ZAP_CHANNEL_TRANSCODE);
+				zchan->packet_len = zchan->native_interval * (zchan->effective_codec == ZAP_CODEC_SLIN ? 16 : 8);
+				GOTO_STATUS(done, ZAP_SUCCESS);
+			}
+		}
+		break;
+
+	case ZAP_COMMAND_GET_CODEC: 
+		{
+			if (!zap_channel_test_feature(zchan, ZAP_CHANNEL_FEATURE_CODECS)) {
+				ZAP_COMMAND_OBJ_INT = zchan->effective_codec;
+				GOTO_STATUS(done, ZAP_SUCCESS);
+			}
+		}
+		break;
+	case ZAP_COMMAND_GET_NATIVE_CODEC: 
+		{
+			if (!zap_channel_test_feature(zchan, ZAP_CHANNEL_FEATURE_CODECS)) {
+				ZAP_COMMAND_OBJ_INT = zchan->native_codec;
+				GOTO_STATUS(done, ZAP_SUCCESS);
+			}
+		}
+		break;
+	case ZAP_COMMAND_ENABLE_PROGRESS_DETECT:
+		{
+			if (!zap_channel_test_feature(zchan, ZAP_CHANNEL_FEATURE_PROGRESS)) {
+				/* if they don't have thier own, use ours */
+				zap_channel_clear_detected_tones(zchan);
+				zap_channel_clear_needed_tones(zchan);
+				teletone_multi_tone_init(&zchan->span->tone_finder[ZAP_TONEMAP_DIAL], &zchan->span->tone_detect_map[ZAP_TONEMAP_DIAL]);
+				teletone_multi_tone_init(&zchan->span->tone_finder[ZAP_TONEMAP_RING], &zchan->span->tone_detect_map[ZAP_TONEMAP_RING]);
+				teletone_multi_tone_init(&zchan->span->tone_finder[ZAP_TONEMAP_BUSY], &zchan->span->tone_detect_map[ZAP_TONEMAP_BUSY]);
+				zap_set_flag(zchan, ZAP_CHANNEL_PROGRESS_DETECT);
+				GOTO_STATUS(done, ZAP_SUCCESS);
+			}
+		}
+		break;
+	case ZAP_COMMAND_DISABLE_PROGRESS_DETECT:
+		{
+			if (!zap_channel_test_feature(zchan, ZAP_CHANNEL_FEATURE_PROGRESS)) {
+				zap_clear_flag_locked(zchan, ZAP_CHANNEL_PROGRESS_DETECT);
+				zap_channel_clear_detected_tones(zchan);
+				zap_channel_clear_needed_tones(zchan);
+				GOTO_STATUS(done, ZAP_SUCCESS);
+			}
+		}
+		break;
+	case ZAP_COMMAND_ENABLE_DTMF_DETECT:
+		{
+			/* if they don't have thier own, use ours */
+			if (!zap_channel_test_feature(zchan, ZAP_CHANNEL_FEATURE_DTMF_DETECT)) {
+				zap_tone_type_t tt = ZAP_COMMAND_OBJ_INT;
+				if (tt == ZAP_TONE_DTMF) {
+					teletone_dtmf_detect_init (&zchan->dtmf_detect, zchan->rate);
+					zap_set_flag_locked(zchan, ZAP_CHANNEL_DTMF_DETECT);
+					zap_set_flag_locked(zchan, ZAP_CHANNEL_SUPRESS_DTMF);
+					GOTO_STATUS(done, ZAP_SUCCESS);
+				} else {
+					snprintf(zchan->last_error, sizeof(zchan->last_error), "invalid command");
+					GOTO_STATUS(done, ZAP_FAIL);
+				}
+			}
+		}
+		break;
+	case ZAP_COMMAND_DISABLE_DTMF_DETECT:
+		{
+			if (!zap_channel_test_feature(zchan, ZAP_CHANNEL_FEATURE_DTMF_DETECT)) {
+				zap_tone_type_t tt = ZAP_COMMAND_OBJ_INT;
+                if (tt == ZAP_TONE_DTMF) {
+                    teletone_dtmf_detect_init (&zchan->dtmf_detect, zchan->rate);
+                    zap_clear_flag(zchan, ZAP_CHANNEL_DTMF_DETECT);
+					zap_clear_flag(zchan, ZAP_CHANNEL_SUPRESS_DTMF);
+					GOTO_STATUS(done, ZAP_SUCCESS);
+                } else {
+                    snprintf(zchan->last_error, sizeof(zchan->last_error), "invalid command");
+					GOTO_STATUS(done, ZAP_FAIL);
+                }
+			}
+		}
+
+	case ZAP_COMMAND_SET_PRE_BUFFER_SIZE:
+		{
+			int val = ZAP_COMMAND_OBJ_INT;
+
+			if (val < 0) {
+				val = 0;
+			}
+
+			zchan->pre_buffer_size = val * 8;
+
+			zap_mutex_lock(zchan->pre_buffer_mutex);
+			if (!zchan->pre_buffer_size) {
+				zap_buffer_destroy(&zchan->pre_buffer);
+			} else if (!zchan->pre_buffer) {
+				zap_buffer_create(&zchan->pre_buffer, 1024, zchan->pre_buffer_size, 0);
+			}
+			zap_mutex_unlock(zchan->pre_buffer_mutex);
+
+			GOTO_STATUS(done, ZAP_SUCCESS);
+
+		}
+		break;
+	case ZAP_COMMAND_GET_DTMF_ON_PERIOD:
+		{
+			if (!zap_channel_test_feature(zchan, ZAP_CHANNEL_FEATURE_DTMF_GENERATE)) {
+				ZAP_COMMAND_OBJ_INT = zchan->dtmf_on;
+				GOTO_STATUS(done, ZAP_SUCCESS);
+			}
+		}
+		break;
+	case ZAP_COMMAND_GET_DTMF_OFF_PERIOD:
+		{
+			if (!zap_channel_test_feature(zchan, ZAP_CHANNEL_FEATURE_DTMF_GENERATE)) {
+				ZAP_COMMAND_OBJ_INT = zchan->dtmf_on;
+				GOTO_STATUS(done, ZAP_SUCCESS);
+			}
+		}
+		break;
+	case ZAP_COMMAND_SET_DTMF_ON_PERIOD:
+		{
+			if (!zap_channel_test_feature(zchan, ZAP_CHANNEL_FEATURE_DTMF_GENERATE)) {
+				int val = ZAP_COMMAND_OBJ_INT;
+				if (val > 10 && val < 1000) {
+					zchan->dtmf_on = val;
+					GOTO_STATUS(done, ZAP_SUCCESS);
+				} else {
+					snprintf(zchan->last_error, sizeof(zchan->last_error), "invalid value %d range 10-1000", val);
+					GOTO_STATUS(done, ZAP_FAIL);
+				}
+			}
+		}
+		break;
+	case ZAP_COMMAND_SET_DTMF_OFF_PERIOD:
+		{
+			if (!zap_channel_test_feature(zchan, ZAP_CHANNEL_FEATURE_DTMF_GENERATE)) {
+				int val = ZAP_COMMAND_OBJ_INT;
+				if (val > 10 && val < 1000) {
+					zchan->dtmf_off = val;
+					GOTO_STATUS(done, ZAP_SUCCESS);
+				} else {
+					snprintf(zchan->last_error, sizeof(zchan->last_error), "invalid value %d range 10-1000", val);
+					GOTO_STATUS(done, ZAP_FAIL);
+				}
+			}
+		}
+		break;
+	case ZAP_COMMAND_SEND_DTMF:
+		{
+			if (!zap_channel_test_feature(zchan, ZAP_CHANNEL_FEATURE_DTMF_GENERATE)) {
+				char *digits = ZAP_COMMAND_OBJ_CHAR_P;
+				
+				if ((status = zchan_activate_dtmf_buffer(zchan)) != ZAP_SUCCESS) {
+					GOTO_STATUS(done, status);
+				}
+				
+				zap_buffer_write(zchan->gen_dtmf_buffer, digits, strlen(digits));
+				
+				GOTO_STATUS(done, ZAP_SUCCESS);
+			}
+		}
+		break;
+
+	case ZAP_COMMAND_DISABLE_ECHOCANCEL:
+		{
+			zap_mutex_lock(zchan->pre_buffer_mutex);
+			zap_buffer_destroy(&zchan->pre_buffer);
+			zchan->pre_buffer_size = 0;
+			zap_mutex_unlock(zchan->pre_buffer_mutex);
+		}
+		break;
+
+	case ZAP_COMMAND_SET_RX_GAIN:
+		{
+			zchan->rxgain = ZAP_COMMAND_OBJ_FLOAT;
+			reset_gain_table(zchan->rxgain_table, zchan->rxgain, zchan->native_codec);
+			if (zchan->rxgain == 0.0) {
+				zap_clear_flag(zchan, ZAP_CHANNEL_USE_RX_GAIN);
+			} else {
+				zap_set_flag(zchan, ZAP_CHANNEL_USE_RX_GAIN);
+			}
+			GOTO_STATUS(done, ZAP_SUCCESS);
+		}
+		break;
+	case ZAP_COMMAND_GET_RX_GAIN:
+		{
+			ZAP_COMMAND_OBJ_FLOAT = zchan->rxgain;
+			GOTO_STATUS(done, ZAP_SUCCESS);
+		}
+		break;
+	case ZAP_COMMAND_SET_TX_GAIN:
+		{
+			zchan->txgain = ZAP_COMMAND_OBJ_FLOAT;
+			reset_gain_table(zchan->txgain_table, zchan->txgain, zchan->native_codec);
+			if (zchan->txgain == 0.0) {
+				zap_clear_flag(zchan, ZAP_CHANNEL_USE_TX_GAIN);
+			} else {
+				zap_set_flag(zchan, ZAP_CHANNEL_USE_TX_GAIN);
+			}
+			GOTO_STATUS(done, ZAP_SUCCESS);
+		}
+		break;
+	case ZAP_COMMAND_GET_TX_GAIN:
+		{
+			ZAP_COMMAND_OBJ_FLOAT = zchan->txgain;
+			GOTO_STATUS(done, ZAP_SUCCESS);
+		}
+		break;
+	default:
+		break;
+	}
+
+	if (!zchan->zio->command) {
+		snprintf(zchan->last_error, sizeof(zchan->last_error), "method not implemented");
+		zap_log(ZAP_LOG_ERROR, "no command function defined by the I/O openzap module!\n");	
+		GOTO_STATUS(done, ZAP_FAIL);
+	}
+
+    status = zchan->zio->command(zchan, command, obj);
+
+	if (status == ZAP_NOTIMPL) {
+		snprintf(zchan->last_error, sizeof(zchan->last_error), "I/O command %d not implemented in backend", command);
+		zap_log(ZAP_LOG_ERROR, "I/O backend does not support command %d!\n", command);	
+	}
+done:
+	zap_mutex_unlock(zchan->mutex);
+	return status;
+
+}
+
+OZ_DECLARE(zap_status_t) zap_channel_wait(zap_channel_t *zchan, zap_wait_flag_t *flags, int32_t to)
+{
+	assert(zchan != NULL);
+	assert(zchan->zio != NULL);
+
+    if (!zap_test_flag(zchan, ZAP_CHANNEL_OPEN)) {
+		snprintf(zchan->last_error, sizeof(zchan->last_error), "channel not open");
+        return ZAP_FAIL;
+    }
+
+	if (!zchan->zio->wait) {
+		snprintf(zchan->last_error, sizeof(zchan->last_error), "method not implemented");
+		return ZAP_FAIL;
+	}
+
+    return zchan->zio->wait(zchan, flags, to);
+
+}
+
+/*******************************/
+ZIO_CODEC_FUNCTION(zio_slin2ulaw)
+{
+	int16_t sln_buf[512] = {0}, *sln = sln_buf;
+	uint8_t *lp = data;
+	uint32_t i;
+	zap_size_t len = *datalen;
+
+	if (max > len) {
+		max = len;
+	}
+
+	memcpy(sln, data, max);
+	
+	for(i = 0; i < max; i++) {
+		*lp++ = linear_to_ulaw(*sln++);
+	}
+
+	*datalen = max / 2;
+
+	return ZAP_SUCCESS;
+
+}
+
+
+ZIO_CODEC_FUNCTION(zio_ulaw2slin)
+{
+	int16_t *sln = data;
+	uint8_t law[1024] = {0}, *lp = law;
+	uint32_t i;
+	zap_size_t len = *datalen;
+	
+	if (max > len) {
+		max = len;
+	}
+
+	memcpy(law, data, max);
+
+	for(i = 0; i < max; i++) {
+		*sln++ = ulaw_to_linear(*lp++);
+	}
+	
+	*datalen = max * 2;
+
+	return ZAP_SUCCESS;
+}
+
+ZIO_CODEC_FUNCTION(zio_slin2alaw)
+{
+	int16_t sln_buf[512] = {0}, *sln = sln_buf;
+	uint8_t *lp = data;
+	uint32_t i;
+	zap_size_t len = *datalen;
+
+	if (max > len) {
+		max = len;
+	}
+
+	memcpy(sln, data, max);
+	
+	for(i = 0; i < max; i++) {
+		*lp++ = linear_to_alaw(*sln++);
+	}
+
+	*datalen = max / 2;
+
+	return ZAP_SUCCESS;
+
+}
+
+
+ZIO_CODEC_FUNCTION(zio_alaw2slin)
+{
+	int16_t *sln = data;
+	uint8_t law[1024] = {0}, *lp = law;
+	uint32_t i;
+	zap_size_t len = *datalen;
+	
+	if (max > len) {
+		max = len;
+	}
+
+	memcpy(law, data, max);
+
+	for(i = 0; i < max; i++) {
+		*sln++ = alaw_to_linear(*lp++);
+	}
+
+	*datalen = max * 2;
+
+	return ZAP_SUCCESS;
+}
+
+ZIO_CODEC_FUNCTION(zio_ulaw2alaw)
+{
+	zap_size_t len = *datalen;
+	uint32_t i;
+	uint8_t *lp = data;
+
+	if (max > len) {
+        max = len;
+    }
+
+	for(i = 0; i < max; i++) {
+		*lp = ulaw_to_alaw(*lp);
+		lp++;
+	}
+
+	return ZAP_SUCCESS;
+}
+
+ZIO_CODEC_FUNCTION(zio_alaw2ulaw)
+{
+	zap_size_t len = *datalen;
+	uint32_t i;
+	uint8_t *lp = data;
+
+	if (max > len) {
+        max = len;
+    }
+
+	for(i = 0; i < max; i++) {
+		*lp = alaw_to_ulaw(*lp);
+		lp++;
+	}
+
+	return ZAP_SUCCESS;
+}
+
+/******************************/
+
+OZ_DECLARE(void) zap_channel_clear_detected_tones(zap_channel_t *zchan)
+{
+	uint32_t i;
+
+	memset(zchan->detected_tones, 0, sizeof(zchan->detected_tones[0]) * ZAP_TONEMAP_INVALID);
+	
+	for (i = 1; i < ZAP_TONEMAP_INVALID; i++) {
+		zchan->span->tone_finder[i].tone_count = 0;
+	}
+}
+
+OZ_DECLARE(void) zap_channel_clear_needed_tones(zap_channel_t *zchan)
+{
+	memset(zchan->needed_tones, 0, sizeof(zchan->needed_tones[0]) * ZAP_TONEMAP_INVALID);
+}
+
+OZ_DECLARE(zap_size_t) zap_channel_dequeue_dtmf(zap_channel_t *zchan, char *dtmf, zap_size_t len)
+{
+	zap_size_t bytes = 0;
+
+	assert(zchan != NULL);
+
+	if (!zap_test_flag(zchan, ZAP_CHANNEL_READY)) {
+		return ZAP_FAIL;
+	}
+
+	if (zchan->digit_buffer && zap_buffer_inuse(zchan->digit_buffer)) {
+		zap_mutex_lock(zchan->mutex);
+		if ((bytes = zap_buffer_read(zchan->digit_buffer, dtmf, len)) > 0) {
+			*(dtmf + bytes) = '\0';
+		}
+		zap_mutex_unlock(zchan->mutex);
+	}
+
+	return bytes;
+}
+
+OZ_DECLARE(void) zap_channel_flush_dtmf(zap_channel_t *zchan)
+{
+	if (zchan->digit_buffer && zap_buffer_inuse(zchan->digit_buffer)) {
+		zap_mutex_lock(zchan->mutex);
+		zap_buffer_zero(zchan->digit_buffer);
+		zap_mutex_unlock(zchan->mutex);
+	}
+}
+
+OZ_DECLARE(zap_status_t) zap_channel_queue_dtmf(zap_channel_t *zchan, const char *dtmf)
+{
+	zap_status_t status;
+	register zap_size_t len, inuse;
+	zap_size_t wr = 0;
+	const char *p;
+	
+	assert(zchan != NULL);
+
+	if (zchan->pre_buffer) {
+		zap_buffer_zero(zchan->pre_buffer);
+	}
+
+	zap_mutex_lock(zchan->mutex);
+
+	inuse = zap_buffer_inuse(zchan->digit_buffer);
+	len = strlen(dtmf);
+	
+	if (len + inuse > zap_buffer_len(zchan->digit_buffer)) {
+		zap_buffer_toss(zchan->digit_buffer, strlen(dtmf));
+	}
+
+	if (zchan->span->dtmf_hangup_len) {
+		for (p = dtmf; zap_is_dtmf(*p); p++) {
+			memmove (zchan->dtmf_hangup_buf, zchan->dtmf_hangup_buf + 1, zchan->span->dtmf_hangup_len - 1);
+			zchan->dtmf_hangup_buf[zchan->span->dtmf_hangup_len - 1] = *p;
+			if (!strcmp(zchan->dtmf_hangup_buf, zchan->span->dtmf_hangup)) {
+				zap_log(ZAP_LOG_DEBUG, "DTMF hangup detected.\n");
+				zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_HANGUP);
+				break;
+			}
+		}
+	}
+
+	p = dtmf;
+	while (wr < len && p) {
+		if (zap_is_dtmf(*p)) {
+			wr++;
+		} else {
+			break;
+		}
+		p++;
+	}
+
+	status = zap_buffer_write(zchan->digit_buffer, dtmf, wr) ? ZAP_SUCCESS : ZAP_FAIL;
+	zap_mutex_unlock(zchan->mutex);
+	
+	return status;
+}
+
+
+static zap_status_t handle_dtmf(zap_channel_t *zchan, zap_size_t datalen)
+{
+	zap_buffer_t *buffer = NULL;
+	zap_size_t dblen = 0;
+	int wrote = 0;
+
+	if (zchan->gen_dtmf_buffer && (dblen = zap_buffer_inuse(zchan->gen_dtmf_buffer))) {
+		char digits[128] = "";
+		char *cur;
+		int x = 0;				 
+		
+		if (dblen > sizeof(digits) - 1) {
+			dblen = sizeof(digits) - 1;
+		}
+
+		if (zap_buffer_read(zchan->gen_dtmf_buffer, digits, dblen) && !zap_strlen_zero_buf(digits)) {
+			zap_log(ZAP_LOG_DEBUG, "%d:%d GENERATE DTMF [%s]\n", zchan->span_id, zchan->chan_id, digits);	
+		
+			cur = digits;
+
+			if (*cur == 'F') {
+				zap_channel_command(zchan, ZAP_COMMAND_FLASH, NULL);
+				cur++;
+			}
+
+			for (; *cur; cur++) {
+				if ((wrote = teletone_mux_tones(&zchan->tone_session, &zchan->tone_session.TONES[(int)*cur]))) {
+					zap_buffer_write(zchan->dtmf_buffer, zchan->tone_session.buffer, wrote * 2);
+					x++;
+				} else {
+					zap_log(ZAP_LOG_ERROR, "%d:%d Problem Adding DTMF SEQ [%s]\n", zchan->span_id, zchan->chan_id, digits);
+					return ZAP_FAIL;
+				}
+			}
+
+			if (x) {
+				zchan->skip_read_frames = (wrote / (zchan->effective_interval * 8)) + 4;
+			}
+		}
+	}
+	
+
+	if (!zchan->buffer_delay || --zchan->buffer_delay == 0) {
+		if (zchan->dtmf_buffer && (dblen = zap_buffer_inuse(zchan->dtmf_buffer))) {
+			buffer = zchan->dtmf_buffer;
+		} else if (zchan->fsk_buffer && (dblen = zap_buffer_inuse(zchan->fsk_buffer))) {
+			buffer = zchan->fsk_buffer;			
+		}
+	}
+
+	if (buffer) {
+		zap_size_t dlen = datalen;
+		uint8_t auxbuf[1024];
+		zap_size_t len, br, max = sizeof(auxbuf);
+		
+		if (zchan->native_codec != ZAP_CODEC_SLIN) {
+			dlen *= 2;
+		}
+		
+		len = dblen > dlen ? dlen : dblen;
+
+		br = zap_buffer_read(buffer, auxbuf, len);		
+		if (br < dlen) {
+			memset(auxbuf + br, 0, dlen - br);
+		}
+
+		if (zchan->native_codec != ZAP_CODEC_SLIN) {
+			if (zchan->native_codec == ZAP_CODEC_ULAW) {
+				zio_slin2ulaw(auxbuf, max, &dlen);
+			} else if (zchan->native_codec == ZAP_CODEC_ALAW) {
+				zio_slin2alaw(auxbuf, max, &dlen);
+			}
+		}
+		
+		return zchan->zio->write(zchan, auxbuf, &dlen);
+	} 
+
+	return ZAP_SUCCESS;
+
+}
+
+
+OZ_DECLARE(void) zap_generate_sln_silence(int16_t *data, uint32_t samples, uint32_t divisor)
+{
+    int16_t x;
+    uint32_t i;
+    int sum_rnd = 0;
+    int16_t rnd2 = (int16_t) zap_current_time_in_ms() * (int16_t) (intptr_t) data;
+
+    assert(divisor);
+
+    for (i = 0; i < samples; i++, sum_rnd = 0) {
+        for (x = 0; x < 6; x++) {
+            rnd2 = rnd2 * 31821U + 13849U;
+            sum_rnd += rnd2 ;
+        }
+        //switch_normalize_to_16bit(sum_rnd);
+        *data = (int16_t) ((int16_t) sum_rnd / (int) divisor);
+
+        data++;
+    }
+}
+
+
+
+OZ_DECLARE(zap_status_t) zap_channel_read(zap_channel_t *zchan, void *data, zap_size_t *datalen)
+{
+	zap_status_t status = ZAP_FAIL;
+	zio_codec_t codec_func = NULL;
+	zap_size_t max = *datalen;
+	unsigned i = 0;
+
+	assert(zchan != NULL);
+	assert(zchan->zio != NULL);
+	
+    if (!zap_test_flag(zchan, ZAP_CHANNEL_OPEN)) {
+		snprintf(zchan->last_error, sizeof(zchan->last_error), "channel not open");
+        return ZAP_FAIL;
+    }
+
+	if (!zchan->zio->read) {
+		snprintf(zchan->last_error, sizeof(zchan->last_error), "method not implemented");
+		return ZAP_FAIL;
+	}
+
+    status = zchan->zio->read(zchan, data, datalen);
+	if (zchan->fds[0] > -1) {
+		int dlen = (int) *datalen;
+		if (write(zchan->fds[0], data, dlen) != dlen) {
+			snprintf(zchan->last_error, sizeof(zchan->last_error), "file write error!");
+			return ZAP_FAIL;
+		}
+	}
+
+	if (status == ZAP_SUCCESS) {
+		if (zap_test_flag(zchan, ZAP_CHANNEL_USE_RX_GAIN) 
+			&& (zchan->native_codec == ZAP_CODEC_ALAW || zchan->native_codec == ZAP_CODEC_ULAW)) {
+			unsigned char *rdata = data;
+			for (i = 0; i < *datalen; i++) {
+				rdata[i] = zchan->rxgain_table[rdata[i]];
+			}
+		}
+		handle_dtmf(zchan, *datalen);
+	}
+
+	if (status == ZAP_SUCCESS && zap_test_flag(zchan, ZAP_CHANNEL_TRANSCODE) && zchan->effective_codec != zchan->native_codec) {
+		if (zchan->native_codec == ZAP_CODEC_ULAW && zchan->effective_codec == ZAP_CODEC_SLIN) {
+			codec_func = zio_ulaw2slin;
+		} else if (zchan->native_codec == ZAP_CODEC_ULAW && zchan->effective_codec == ZAP_CODEC_ALAW) {
+			codec_func = zio_ulaw2alaw;
+		} else if (zchan->native_codec == ZAP_CODEC_ALAW && zchan->effective_codec == ZAP_CODEC_SLIN) {
+			codec_func = zio_alaw2slin;
+		} else if (zchan->native_codec == ZAP_CODEC_ALAW && zchan->effective_codec == ZAP_CODEC_ULAW) {
+			codec_func = zio_alaw2ulaw;
+		}
+
+		if (codec_func) {
+			status = codec_func(data, max, datalen);
+		} else {
+			snprintf(zchan->last_error, sizeof(zchan->last_error), "codec error!");
+			status = ZAP_FAIL;
+		}
+	}
+
+	if (zap_test_flag(zchan, ZAP_CHANNEL_DTMF_DETECT) || zap_test_flag(zchan, ZAP_CHANNEL_PROGRESS_DETECT) || 
+		zap_test_flag(zchan, ZAP_CHANNEL_CALLERID_DETECT)) {
+		uint8_t sln_buf[1024] = {0};
+		int16_t *sln;
+		zap_size_t slen = 0;
+		char digit_str[80] = "";
+
+		if (zchan->effective_codec == ZAP_CODEC_SLIN) {
+			sln = data;
+			slen = *datalen / 2;
+		} else {
+			zap_size_t len = *datalen;
+			uint32_t i;
+			uint8_t *lp = data;
+
+			slen = sizeof(sln_buf) / 2;
+			if (len > slen) {
+				len = slen;
+			}
+
+			sln = (int16_t *) sln_buf;
+			for(i = 0; i < len; i++) {
+				if (zchan->effective_codec == ZAP_CODEC_ULAW) {
+					*sln++ = ulaw_to_linear(*lp++);
+				} else if (zchan->effective_codec == ZAP_CODEC_ALAW) {
+					*sln++ = alaw_to_linear(*lp++);
+				} else {
+					snprintf(zchan->last_error, sizeof(zchan->last_error), "codec error!");
+					return ZAP_FAIL;
+				}
+			}
+			sln = (int16_t *) sln_buf;
+			slen = len;
+		}
+
+		if (zap_test_flag(zchan, ZAP_CHANNEL_CALLERID_DETECT)) {
+			if (zap_fsk_demod_feed(&zchan->fsk, sln, slen) != ZAP_SUCCESS) {
+				zap_size_t type, mlen;
+				char str[128], *sp;
+				
+				while(zap_fsk_data_parse(&zchan->fsk, &type, &sp, &mlen) == ZAP_SUCCESS) {
+					*(str+mlen) = '\0';
+					zap_copy_string(str, sp, ++mlen);
+					zap_clean_string(str);
+					zap_log(ZAP_LOG_DEBUG, "FSK: TYPE %s LEN %d VAL [%s]\n", zap_mdmf_type2str(type), mlen-1, str);
+					
+					switch(type) {
+					case MDMF_DDN:
+					case MDMF_PHONE_NUM:
+						{
+							if (mlen > sizeof(zchan->caller_data.ani)) {
+								mlen = sizeof(zchan->caller_data.ani);
+							}
+							zap_set_string(zchan->caller_data.ani.digits, str);
+							zap_set_string(zchan->caller_data.cid_num.digits, zchan->caller_data.ani.digits);
+						}
+						break;
+					case MDMF_NO_NUM:
+						{
+							zap_set_string(zchan->caller_data.ani.digits, *str == 'P' ? "private" : "unknown");
+							zap_set_string(zchan->caller_data.cid_name, zchan->caller_data.ani.digits);
+						}
+						break;
+					case MDMF_PHONE_NAME:
+						{
+							if (mlen > sizeof(zchan->caller_data.cid_name)) {
+								mlen = sizeof(zchan->caller_data.cid_name);
+							}
+							zap_set_string(zchan->caller_data.cid_name, str);
+						}
+						break;
+					case MDMF_NO_NAME:
+						{
+							zap_set_string(zchan->caller_data.cid_name, *str == 'P' ? "private" : "unknown");
+						}
+					case MDMF_DATETIME:
+						{
+							if (mlen > sizeof(zchan->caller_data.cid_date)) {
+								mlen = sizeof(zchan->caller_data.cid_date);
+							}
+							zap_set_string(zchan->caller_data.cid_date, str);
+						}
+						break;
+					}
+				}
+				zap_channel_command(zchan, ZAP_COMMAND_DISABLE_CALLERID_DETECT, NULL);
+			}
+		}
+
+		if (zap_test_flag(zchan, ZAP_CHANNEL_PROGRESS_DETECT) && !zap_channel_test_feature(zchan, ZAP_CHANNEL_FEATURE_PROGRESS)) {
+			uint32_t i;
+
+			for (i = 1; i < ZAP_TONEMAP_INVALID; i++) {
+				if (zchan->span->tone_finder[i].tone_count) {
+					if (zchan->needed_tones[i] && teletone_multi_tone_detect(&zchan->span->tone_finder[i], sln, (int)slen)) {
+						if (++zchan->detected_tones[i]) {
+							zchan->needed_tones[i] = 0;
+							zchan->detected_tones[0]++;
+						}
+					}
+				}
+			}
+		}
+	
+		
+		if (zap_test_flag(zchan, ZAP_CHANNEL_DTMF_DETECT) && !zap_channel_test_feature(zchan, ZAP_CHANNEL_FEATURE_DTMF_DETECT)) {
+			teletone_dtmf_detect(&zchan->dtmf_detect, sln, (int)slen);
+			teletone_dtmf_get(&zchan->dtmf_detect, digit_str, sizeof(digit_str));
+
+			if(*digit_str) {
+				zio_event_cb_t event_callback = NULL;
+
+				if (zchan->state == ZAP_CHANNEL_STATE_CALLWAITING && (*digit_str == 'D' || *digit_str == 'A')) {
+					zchan->detected_tones[ZAP_TONEMAP_CALLWAITING_ACK]++;
+				} else {
+					zap_channel_queue_dtmf(zchan, digit_str);
+
+					if (zchan->span->event_callback) {
+						event_callback = zchan->span->event_callback;
+					} else if (zchan->event_callback) {
+						event_callback = zchan->event_callback;
+					}
+
+					if (event_callback) {
+						zchan->event_header.channel = zchan;
+						zchan->event_header.e_type = ZAP_EVENT_DTMF;
+						zchan->event_header.data = digit_str;
+						event_callback(zchan, &zchan->event_header);
+						zchan->event_header.e_type = ZAP_EVENT_NONE;
+						zchan->event_header.data = NULL;
+					}
+					if (zap_test_flag(zchan, ZAP_CHANNEL_SUPRESS_DTMF)) {
+						zchan->skip_read_frames = 20;
+					}
+				}
+			}
+		}
+	}
+
+	if (zchan->skip_read_frames > 0 || zap_test_flag(zchan, ZAP_CHANNEL_MUTE)) {
+		
+		zap_mutex_lock(zchan->pre_buffer_mutex);
+		if (zchan->pre_buffer && zap_buffer_inuse(zchan->pre_buffer)) {
+			zap_buffer_zero(zchan->pre_buffer);
+		}
+		zap_mutex_unlock(zchan->pre_buffer_mutex);
+
+
+		memset(data, 255, *datalen);
+
+		if (zchan->skip_read_frames > 0) {
+			zchan->skip_read_frames--;
+		}
+	}  else	{
+		zap_mutex_lock(zchan->pre_buffer_mutex);
+		if (zchan->pre_buffer_size && zchan->pre_buffer) {
+			zap_buffer_write(zchan->pre_buffer, data, *datalen);
+			if (zap_buffer_inuse(zchan->pre_buffer) >= zchan->pre_buffer_size) {
+				zap_buffer_read(zchan->pre_buffer, data, *datalen);
+			} else {
+				memset(data, 255, *datalen);
+			}
+		}
+		zap_mutex_unlock(zchan->pre_buffer_mutex);
+	}
+
+
+	return status;
+}
+
+
+OZ_DECLARE(zap_status_t) zap_channel_write(zap_channel_t *zchan, void *data, zap_size_t datasize, zap_size_t *datalen)
+{
+	zap_status_t status = ZAP_FAIL;
+	zio_codec_t codec_func = NULL;
+	zap_size_t max = datasize;
+	unsigned i = 0;
+
+	assert(zchan != NULL);
+	assert(zchan->zio != NULL);
+
+	if (!zchan->buffer_delay && 
+		((zchan->dtmf_buffer && zap_buffer_inuse(zchan->dtmf_buffer)) ||
+		 (zchan->fsk_buffer && zap_buffer_inuse(zchan->fsk_buffer)))) {
+		/* read size writing DTMF ATM */
+		return ZAP_SUCCESS;
+	}
+
+
+    if (!zap_test_flag(zchan, ZAP_CHANNEL_OPEN)) {
+		snprintf(zchan->last_error, sizeof(zchan->last_error), "channel not open");
+        return ZAP_FAIL;
+    }
+
+	if (!zchan->zio->write) {
+		snprintf(zchan->last_error, sizeof(zchan->last_error), "method not implemented");
+		return ZAP_FAIL;
+	}
+	
+	if (zap_test_flag(zchan, ZAP_CHANNEL_TRANSCODE) && zchan->effective_codec != zchan->native_codec) {
+		if (zchan->native_codec == ZAP_CODEC_ULAW && zchan->effective_codec == ZAP_CODEC_SLIN) {
+			codec_func = zio_slin2ulaw;
+		} else if (zchan->native_codec == ZAP_CODEC_ULAW && zchan->effective_codec == ZAP_CODEC_ALAW) {
+			codec_func = zio_alaw2ulaw;
+		} else if (zchan->native_codec == ZAP_CODEC_ALAW && zchan->effective_codec == ZAP_CODEC_SLIN) {
+			codec_func = zio_slin2alaw;
+		} else if (zchan->native_codec == ZAP_CODEC_ALAW && zchan->effective_codec == ZAP_CODEC_ULAW) {
+			codec_func = zio_ulaw2alaw;
+		}
+
+		if (codec_func) {
+			status = codec_func(data, max, datalen);
+		} else {
+			snprintf(zchan->last_error, sizeof(zchan->last_error), "codec error!");
+			status = ZAP_FAIL;
+		}
+	}	
+	
+	if (zchan->fds[1] > -1) {
+		int dlen = (int) *datalen;
+		if ((write(zchan->fds[1], data, dlen)) != dlen) {
+			snprintf(zchan->last_error, sizeof(zchan->last_error), "file write error!");
+			return ZAP_FAIL;
+		}
+	}
+
+	if (zap_test_flag(zchan, ZAP_CHANNEL_USE_TX_GAIN) 
+		&& (zchan->native_codec == ZAP_CODEC_ALAW || zchan->native_codec == ZAP_CODEC_ULAW)) {
+		unsigned char *wdata = data;
+		for (i = 0; i < *datalen; i++) {
+			wdata[i] = zchan->txgain_table[wdata[i]];
+		}
+	}
+    status = zchan->zio->write(zchan, data, datalen);
+
+	return status;
+}
+
+OZ_DECLARE(zap_status_t) zap_channel_clear_vars(zap_channel_t *zchan)
+{
+	if(zchan->variable_hash) {
+		hashtable_destroy(zchan->variable_hash);
+	}
+	zchan->variable_hash = create_hashtable(16, zap_hash_hashfromstring, zap_hash_equalkeys);
+
+	if(!zchan->variable_hash)
+		return ZAP_FAIL;
+	
+	return ZAP_SUCCESS;
+}
+
+OZ_DECLARE(zap_status_t) zap_channel_add_var(zap_channel_t *zchan, const char *var_name, const char *value)
+{
+	char *t_name = 0, *t_val = 0;
+
+	if(!zchan->variable_hash || !var_name || !value)
+	{
+		return ZAP_FAIL;
+	}
+
+	t_name = strdup(var_name);
+	t_val = strdup(value);
+
+	if(hashtable_insert(zchan->variable_hash, t_name, t_val, HASHTABLE_FLAG_FREE_KEY | HASHTABLE_FLAG_FREE_VALUE)) {
+		return ZAP_SUCCESS;
+	}
+	return ZAP_FAIL;
+}
+
+OZ_DECLARE(const char *) zap_channel_get_var(zap_channel_t *zchan, const char *var_name)
+{
+	if(!zchan->variable_hash || !var_name)
+	{
+		return NULL;
+	}
+	return (const char *) hashtable_search(zchan->variable_hash, (void *)var_name);
+}
+
+static struct {
+	zap_io_interface_t *pika_interface;
+} interfaces;
+
+
+OZ_DECLARE(char *) zap_api_execute(const char *type, const char *cmd)
+{
+	zap_io_interface_t *zio = NULL;
+	char *dup = NULL, *p;
+	char *rval = NULL;
+
+	if (type && !cmd) {
+		dup = strdup(type);
+		if ((p = strchr(dup, ' '))) {
+			*p++ = '\0';
+			cmd = p;
+		}
+
+		type = dup;
+	}
+	
+	zap_mutex_lock(globals.mutex);
+	if (!(zio = (zap_io_interface_t *) hashtable_search(globals.interface_hash, (void *)type))) {
+		zap_load_module_assume(type);
+		if ((zio = (zap_io_interface_t *) hashtable_search(globals.interface_hash, (void *)type))) {
+			zap_log(ZAP_LOG_INFO, "auto-loaded '%s'\n", type);
+		}
+	}
+	zap_mutex_unlock(globals.mutex);
+
+	if (zio && zio->api) {
+		zap_stream_handle_t stream = { 0 };
+		zap_status_t status;
+		ZAP_STANDARD_STREAM(stream);
+		status = zio->api(&stream, cmd);
+		
+		if (status != ZAP_SUCCESS) {
+			zap_safe_free(stream.data);
+		} else {
+			rval = (char *) stream.data;
+		}
+	}
+
+	zap_safe_free(dup);
+	
+	return rval;
+}
+
+static void zap_set_channels_gains(zap_span_t *span, int currindex, float rxgain, float txgain)
+{
+	unsigned chan_index = 0;
+
+	if (!span->chan_count) {
+		return;
+	}
+
+	for (chan_index = currindex+1; chan_index <= span->chan_count; chan_index++) {
+		if (!ZAP_IS_VOICE_CHANNEL(span->channels[chan_index])) {
+			continue;
+		}
+		zap_channel_command(span->channels[chan_index], ZAP_COMMAND_SET_RX_GAIN, &rxgain);
+		zap_channel_command(span->channels[chan_index], ZAP_COMMAND_SET_TX_GAIN, &txgain);
+	}
+}
+
+static zap_status_t load_config(void)
+{
+	char cfg_name[] = "openzap.conf";
+	zap_config_t cfg;
+	char *var, *val;
+	int catno = -1;
+	zap_span_t *span = NULL;
+	unsigned configured = 0, d = 0;
+	char name[80] = "";
+	char number[25] = "";
+	zap_io_interface_t *zio = NULL;
+	zap_analog_start_type_t tmp;
+	float rxgain = 0.0;
+	float txgain = 0.0;
+	int chanindex = 0;
+
+	if (!zap_config_open_file(&cfg, cfg_name)) {
+		return ZAP_FAIL;
+	}
+	
+	while (zap_config_next_pair(&cfg, &var, &val)) {
+		if (*cfg.category == '#') {
+			if (cfg.catno != catno) {
+				zap_log(ZAP_LOG_DEBUG, "Skipping %s\n", cfg.category);
+				catno = cfg.catno;
+			}
+		} else if (!strncasecmp(cfg.category, "span", 4)) {
+			if (cfg.catno != catno) {
+				char *type = cfg.category + 4;
+				char *name;
+				
+				if (*type == ' ') {
+					type++;
+				}
+				
+				zap_log(ZAP_LOG_DEBUG, "found config for span\n");
+				catno = cfg.catno;
+				
+				if (zap_strlen_zero(type)) {
+					zap_log(ZAP_LOG_CRIT, "failure creating span, no type specified.\n");
+					span = NULL;
+					continue;
+				}
+
+				if ((name = strchr(type, ' '))) {
+					*name++ = '\0';
+				}
+
+				zap_mutex_lock(globals.mutex);
+				if (!(zio = (zap_io_interface_t *) hashtable_search(globals.interface_hash, type))) {
+					zap_load_module_assume(type);
+					if ((zio = (zap_io_interface_t *) hashtable_search(globals.interface_hash, type))) {
+						zap_log(ZAP_LOG_INFO, "auto-loaded '%s'\n", type);
+					}
+				}
+				zap_mutex_unlock(globals.mutex);
+
+				if (!zio) {
+					zap_log(ZAP_LOG_CRIT, "failure creating span, no such type '%s'\n", type);
+					span = NULL;
+					continue;
+				}
+
+				if (!zio->configure_span) {
+					zap_log(ZAP_LOG_CRIT, "failure creating span, no configure_span method for '%s'\n", type);
+					span = NULL;
+					continue;
+				}
+
+				if (zap_span_create(zio, &span, name) == ZAP_SUCCESS) {
+					span->type = strdup(type);
+					d = 0;
+
+					zap_log(ZAP_LOG_DEBUG, "created span %d (%s) of type %s\n", span->span_id, span->name, type);
+					
+				} else {
+					zap_log(ZAP_LOG_CRIT, "failure creating span of type %s\n", type);
+					span = NULL;
+					continue;
+				}
+			}
+
+			if (!span) {
+				continue;
+			}
+
+			zap_log(ZAP_LOG_DEBUG, "span %d [%s]=[%s]\n", span->span_id, var, val);
+			
+			if (!strcasecmp(var, "trunk_type")) {
+				span->trunk_type = zap_str2zap_trunk_type(val);
+				zap_log(ZAP_LOG_DEBUG, "setting trunk type to '%s'\n", zap_trunk_type2str(span->trunk_type)); 
+			} else if (!strcasecmp(var, "name")) {
+				if (!strcasecmp(val, "undef")) {
+					*name = '\0';
+				} else {
+					zap_copy_string(name, val, sizeof(name));
+				}
+			} else if (!strcasecmp(var, "number")) {
+				if (!strcasecmp(val, "undef")) {
+					*number = '\0';
+				} else {
+					zap_copy_string(number, val, sizeof(number));
+				}
+			} else if (!strcasecmp(var, "analog-start-type")) {
+				if (span->trunk_type == ZAP_TRUNK_FXS || span->trunk_type == ZAP_TRUNK_FXO || span->trunk_type == ZAP_TRUNK_EM) {
+					if ((tmp = zap_str2zap_analog_start_type(val)) != ZAP_ANALOG_START_NA) {
+						span->start_type = tmp;
+						zap_log(ZAP_LOG_DEBUG, "changing start type to '%s'\n", zap_analog_start_type2str(span->start_type)); 
+					}
+				} else {
+					zap_log(ZAP_LOG_ERROR, "This option is only valid on analog trunks!\n");
+				}
+			} else if (!strcasecmp(var, "fxo-channel")) {
+				if (span->trunk_type == ZAP_TRUNK_NONE) {
+					span->trunk_type = ZAP_TRUNK_FXO;										
+					zap_log(ZAP_LOG_DEBUG, "setting trunk type to '%s' start(%s)\n", zap_trunk_type2str(span->trunk_type), 
+							zap_analog_start_type2str(span->start_type));
+				}
+				if (span->trunk_type == ZAP_TRUNK_FXO) {
+					chanindex = span->chan_count;
+					configured += zio->configure_span(span, val, ZAP_CHAN_TYPE_FXO, name, number);
+					zap_set_channels_gains(span, chanindex, rxgain, txgain);
+				} else {
+					zap_log(ZAP_LOG_WARNING, "Cannot add FXO channels to an FXS trunk!\n");
+				}
+			} else if (!strcasecmp(var, "fxs-channel")) {
+				if (span->trunk_type == ZAP_TRUNK_NONE) {
+					span->trunk_type = ZAP_TRUNK_FXS;
+					zap_log(ZAP_LOG_DEBUG, "setting trunk type to '%s' start(%s)\n", zap_trunk_type2str(span->trunk_type), 
+							zap_analog_start_type2str(span->start_type));
+				}
+				if (span->trunk_type == ZAP_TRUNK_FXS) {
+					chanindex = span->chan_count;
+					configured += zio->configure_span(span, val, ZAP_CHAN_TYPE_FXS, name, number);
+					zap_set_channels_gains(span, chanindex, rxgain, txgain);
+				} else {
+					zap_log(ZAP_LOG_WARNING, "Cannot add FXS channels to an FXO trunk!\n");
+				}
+			} else if (!strcasecmp(var, "em-channel")) {
+				if (span->trunk_type == ZAP_TRUNK_NONE) {
+					span->trunk_type = ZAP_TRUNK_EM;
+					zap_log(ZAP_LOG_DEBUG, "setting trunk type to '%s' start(%s)\n", zap_trunk_type2str(span->trunk_type), 
+							zap_analog_start_type2str(span->start_type));
+				}
+				if (span->trunk_type == ZAP_TRUNK_EM) {
+					chanindex = span->chan_count;
+					configured += zio->configure_span(span, val, ZAP_CHAN_TYPE_EM, name, number);
+					zap_set_channels_gains(span, chanindex, rxgain, txgain);
+				} else {
+					zap_log(ZAP_LOG_WARNING, "Cannot add EM channels to a non-EM trunk!\n");
+				}
+			} else if (!strcasecmp(var, "b-channel")) {
+				chanindex = span->chan_count;
+				configured += zio->configure_span(span, val, ZAP_CHAN_TYPE_B, name, number);
+				zap_set_channels_gains(span, chanindex, rxgain, txgain);
+			} else if (!strcasecmp(var, "d-channel")) {
+				if (d) {
+					zap_log(ZAP_LOG_WARNING, "ignoring extra d-channel\n");
+				} else {
+					zap_chan_type_t qtype;
+					if (!strncasecmp(val, "lapd:", 5)) {
+						qtype = ZAP_CHAN_TYPE_DQ931;
+						val += 5;
+					} else {
+						qtype = ZAP_CHAN_TYPE_DQ921;
+					}
+					configured += zio->configure_span(span, val, qtype, name, number);
+					d++;
+				}
+			} else if (!strcasecmp(var, "cas-channel")) {
+				chanindex = span->chan_count;
+				configured += zio->configure_span(span, val, ZAP_CHAN_TYPE_CAS, name, number);	
+				zap_set_channels_gains(span, chanindex, rxgain, txgain);
+			} else if (!strcasecmp(var, "dtmf_hangup")) {
+				span->dtmf_hangup = strdup(val);
+				span->dtmf_hangup_len = strlen(val);
+			} else if (!strcasecmp(var, "txgain")) {
+				if (sscanf(val, "%f", &txgain) != 1) {
+					zap_log(ZAP_LOG_ERROR, "invalid txgain: '%s'\n", val);
+				}
+			} else if (!strcasecmp(var, "rxgain")) {
+				if (sscanf(val, "%f", &rxgain) != 1) {
+					zap_log(ZAP_LOG_ERROR, "invalid rxgain: '%s'\n", val);
+				}
+			} else {
+				zap_log(ZAP_LOG_ERROR, "unknown span variable '%s'\n", var);
+			}
+		} else if (!strncasecmp(cfg.category, "general", 7)) {
+			if (!strncasecmp(var, "cpu_monitoring_interval", 24)) {
+				if (atoi(val) > 0) {
+					globals.cpu_monitor.interval = atoi(val);
+				} else {
+					zap_log(ZAP_LOG_ERROR, "Invalid cpu monitoring interval %s\n", val);
+				}
+			} else	if (!strncasecmp(var, "cpu_set_alarm_threshold", 22)) {
+				if (atoi(val) > 0 && atoi(val) < 100) {
+					globals.cpu_monitor.set_alarm_threshold = (uint8_t)atoi(val);
+				} else {
+					zap_log(ZAP_LOG_ERROR, "Invalid cpu alarm set threshold %s\n", val);
+				}
+			} else if (!strncasecmp(var, "cpu_reset_alarm_threshold", 22)) {
+				if (atoi(val) > 0 && atoi(val) < 100) {
+					globals.cpu_monitor.reset_alarm_threshold = (uint8_t)atoi(val);
+					if (globals.cpu_monitor.reset_alarm_threshold > globals.cpu_monitor.set_alarm_threshold) {
+						globals.cpu_monitor.reset_alarm_threshold = globals.cpu_monitor.set_alarm_threshold-10;
+						zap_log(ZAP_LOG_ERROR, "Cpu alarm reset threshold must be lower than set threshold, set threshold to %d\n", globals.cpu_monitor.reset_alarm_threshold);
+					}
+				} else {
+					zap_log(ZAP_LOG_ERROR, "Invalid cpu alarm reset threshold %s\n", val);
+				}
+			} else if (!strncasecmp(var, "cpu_alarm_action", 16)) {
+				char* p = val;
+				do {
+					if (!strncasecmp(p, "reject", 6)) {
+						globals.cpu_monitor.alarm_action_flags |= ZAP_CPU_ALARM_ACTION_REJECT;
+					} else if (!strncasecmp(p, "warn", 4)) {
+						globals.cpu_monitor.alarm_action_flags |= ZAP_CPU_ALARM_ACTION_WARN;
+					}
+					p = strchr(p, ',');
+					if (p) {
+						while(++p) if (*p != 0x20) break;
+					}
+				} while (p);
+			}
+		} else {
+			zap_log(ZAP_LOG_ERROR, "unknown param [%s] '%s' / '%s'\n", cfg.category, var, val);
+		}
+	}
+	zap_config_close_file(&cfg);
+
+	zap_log(ZAP_LOG_INFO, "Configured %u channel(s)\n", configured);
+	return configured ? ZAP_SUCCESS : ZAP_FAIL;
+}
+
+static zap_status_t process_module_config(zap_io_interface_t *zio)
+{
+	zap_config_t cfg;
+	char *var, *val;
+	char filename[256] = "";
+	assert(zio != NULL);
+
+	snprintf(filename, sizeof(filename), "%s.conf", zio->name);
+
+	if (!zio->configure) {
+		zap_log(ZAP_LOG_DEBUG, "Module %s does not support configuration.\n", zio->name);	
+		return ZAP_FAIL;
+	}
+
+	if (!zap_config_open_file(&cfg, filename)) {
+		zap_log(ZAP_LOG_ERROR, "Cannot open %s\n", filename);	
+		return ZAP_FAIL;
+	}
+
+	while (zap_config_next_pair(&cfg, &var, &val)) {
+		zio->configure(cfg.category, var, val, cfg.lineno);
+	}
+
+	zap_config_close_file(&cfg);	
+
+	return ZAP_SUCCESS;
+}
+
+OZ_DECLARE(int) zap_load_module(const char *name)
+{
+	zap_dso_lib_t lib;
+	int count = 0, x = 0;
+	char path[128] = "";
+	char *err;
+	zap_module_t *mod;
+
+#ifdef WIN32
+    const char *ext = ".dll";
+    //const char *EXT = ".DLL";
+#define ZAP_MOD_DIR "." //todo
+#elif defined (MACOSX) || defined (DARWIN)
+    const char *ext = ".dylib";
+    //const char *EXT = ".DYLIB";
+#else
+    const char *ext = ".so";
+    //const char *EXT = ".SO";
+#endif
+	
+	if (*name == *ZAP_PATH_SEPARATOR) {
+		snprintf(path, sizeof(path), "%s%s", name, ext);
+	} else {
+		snprintf(path, sizeof(path), "%s%s%s%s", ZAP_MOD_DIR, ZAP_PATH_SEPARATOR, name, ext);
+	}
+	
+	if (!(lib = zap_dso_open(path, &err))) {
+		zap_log(ZAP_LOG_ERROR, "Error loading %s [%s]\n", path, err);
+		zap_safe_free(err);
+		return 0;
+	}
+	
+	if (!(mod = (zap_module_t *) zap_dso_func_sym(lib, "zap_module", &err))) {
+		zap_log(ZAP_LOG_ERROR, "Error loading %s [%s]\n", path, err);
+		zap_safe_free(err);
+		return 0;
+	}
+
+	if (mod->io_load) {
+		zap_io_interface_t *interface1 = NULL; /* name conflict w/windows here */
+
+		if (mod->io_load(&interface1) != ZAP_SUCCESS || !interface1 || !interface1->name) {
+			zap_log(ZAP_LOG_ERROR, "Error loading %s\n", path);
+		} else {
+			zap_log(ZAP_LOG_INFO, "Loading IO from %s [%s]\n", path, interface1->name);
+			zap_mutex_lock(globals.mutex);
+			if (hashtable_search(globals.interface_hash, (void *)interface1->name)) {
+				zap_log(ZAP_LOG_ERROR, "Interface %s already loaded!\n", interface1->name);
+			} else {
+				hashtable_insert(globals.interface_hash, (void *)interface1->name, interface1, HASHTABLE_FLAG_NONE);
+				process_module_config(interface1);
+				x++;
+			}
+			zap_mutex_unlock(globals.mutex);
+		}
+	}
+
+	if (mod->sig_load) {
+		if (mod->sig_load() != ZAP_SUCCESS) {
+			zap_log(ZAP_LOG_ERROR, "Error loading %s\n", path);
+		} else {
+			zap_log(ZAP_LOG_INFO, "Loading SIG from %s\n", path);
+			x++;
+		}
+	}
+
+	if (x) {
+		char *p;
+		mod->lib = lib;
+		zap_set_string(mod->path, path);
+		if (mod->name[0] == '\0') {
+			if (!(p = strrchr(path, *ZAP_PATH_SEPARATOR))) {
+				p = path;
+			}
+			zap_set_string(mod->name, p);
+		}
+
+		zap_mutex_lock(globals.mutex);
+		if (hashtable_search(globals.module_hash, (void *)mod->name)) {
+			zap_log(ZAP_LOG_ERROR, "Module %s already loaded!\n", mod->name);
+			zap_dso_destroy(&lib);
+		} else {
+			hashtable_insert(globals.module_hash, (void *)mod->name, mod, HASHTABLE_FLAG_NONE);
+			count++;
+		}
+		zap_mutex_unlock(globals.mutex);
+	} else {
+		zap_log(ZAP_LOG_ERROR, "Unloading %s\n", path);
+		zap_dso_destroy(&lib);
+	}
+	
+	return count;
+}
+
+OZ_DECLARE(int) zap_load_module_assume(const char *name)
+{
+	char buf[256] = "";
+
+	snprintf(buf, sizeof(buf), "ozmod_%s", name);
+	return zap_load_module(buf);
+}
+
+OZ_DECLARE(int) zap_load_modules(void)
+{
+	char cfg_name[] = "modules.conf";
+	zap_config_t cfg;
+	char *var, *val;
+	int count = 0;
+
+	if (!zap_config_open_file(&cfg, cfg_name)) {
+        return ZAP_FAIL;
+    }
+
+	while (zap_config_next_pair(&cfg, &var, &val)) {
+        if (!strcasecmp(cfg.category, "modules")) {
+			if (!strcasecmp(var, "load")) {
+				count += zap_load_module(val);
+			}
+		}
+	}
+			
+	return count;
+}
+
+OZ_DECLARE(zap_status_t) zap_unload_modules(void)
+{
+	zap_hash_iterator_t *i;
+	zap_dso_lib_t lib;
+
+	for (i = hashtable_first(globals.module_hash); i; i = hashtable_next(i)) {
+		const void *key;
+		void *val;
+
+		hashtable_this(i, &key, NULL, &val);
+		
+		if (key && val) {
+			zap_module_t *mod = (zap_module_t *) val;
+
+			if (!mod) {
+				continue;
+			}
+
+			if (mod->io_unload) {
+				if (mod->io_unload() == ZAP_SUCCESS) {
+					zap_log(ZAP_LOG_INFO, "Unloading IO %s\n", mod->name);
+				} else {
+					zap_log(ZAP_LOG_ERROR, "Error unloading IO %s\n", mod->name);
+				}
+			} 
+
+			if (mod->sig_unload) {
+				if (mod->sig_unload() == ZAP_SUCCESS) {
+					zap_log(ZAP_LOG_INFO, "Unloading SIG %s\n", mod->name);
+				} else {
+					zap_log(ZAP_LOG_ERROR, "Error unloading SIG %s\n", mod->name);
+				}
+			} 
+			
+
+			zap_log(ZAP_LOG_INFO, "Unloading %s\n", mod->path);
+			lib = mod->lib;
+			zap_dso_destroy(&lib);
+			
+		}
+	}
+
+	return ZAP_SUCCESS;
+}
+
+OZ_DECLARE(zap_status_t) zap_configure_span(const char *type, zap_span_t *span, zio_signal_cb_t sig_cb, ...)
+{
+	zap_module_t *mod = (zap_module_t *) hashtable_search(globals.module_hash, (void *)type);
+	zap_status_t status = ZAP_FAIL;
+
+	if (!mod) {
+		zap_load_module_assume(type);
+		if ((mod = (zap_module_t *) hashtable_search(globals.module_hash, (void *)type))) {
+			zap_log(ZAP_LOG_INFO, "auto-loaded '%s'\n", type);
+		}
+	}
+
+	if (mod && mod->sig_configure) {
+		va_list ap;
+		va_start(ap, sig_cb);
+		status = mod->sig_configure(span, sig_cb, ap);
+		va_end(ap);
+	} else {
+		zap_log(ZAP_LOG_ERROR, "can't find '%s'\n", type);
+		status = ZAP_FAIL;
+	}
+
+	return status;
+}
+
+OZ_DECLARE(zap_status_t) zap_span_start(zap_span_t *span)
+{
+	if (span->start) {
+		return span->start(span);
+	}
+
+	return ZAP_FAIL;
+}
+
+OZ_DECLARE(zap_status_t) zap_span_send_signal(zap_span_t *span, zap_sigmsg_t *sigmsg)
+{
+	zap_status_t status = ZAP_FAIL;
+
+	if (span->signal_cb) {
+
+		if (sigmsg->channel) {
+			zap_mutex_lock(sigmsg->channel->mutex);
+		}
+
+		status = span->signal_cb(sigmsg);
+
+		if (sigmsg->channel) {
+			zap_mutex_unlock(sigmsg->channel->mutex);
+		}
+	}
+
+	return status;
+}
+
+
+OZ_DECLARE(zap_status_t) zap_global_init(void)
+{
+	int modcount;
+	
+	memset(&globals, 0, sizeof(globals));
+
+	time_init();
+	
+	zap_thread_override_default_stacksize(ZAP_THREAD_STACKSIZE);
+
+	memset(&interfaces, 0, sizeof(interfaces));
+	globals.interface_hash = create_hashtable(16, zap_hash_hashfromstring, zap_hash_equalkeys);
+	globals.module_hash = create_hashtable(16, zap_hash_hashfromstring, zap_hash_equalkeys);
+	globals.span_hash = create_hashtable(16, zap_hash_hashfromstring, zap_hash_equalkeys);
+	modcount = 0;
+	zap_mutex_create(&globals.mutex);
+	zap_mutex_create(&globals.span_mutex);
+	
+	modcount = zap_load_modules();
+	zap_log(ZAP_LOG_NOTICE, "Modules configured: %d \n", modcount);
+
+	globals.cpu_monitor.interval = 1000;
+	globals.cpu_monitor.alarm_action_flags = ZAP_CPU_ALARM_ACTION_WARN | ZAP_CPU_ALARM_ACTION_REJECT;
+	globals.cpu_monitor.set_alarm_threshold = 80;
+	globals.cpu_monitor.reset_alarm_threshold = 70;
+
+	if (load_config() != ZAP_SUCCESS) {
+		zap_log(ZAP_LOG_ERROR, "No modules configured!\n");
+		return ZAP_FAIL;
+	}
+
+	globals.running = 1;
+	if (!zap_cpu_monitor_disabled) {
+		if (zap_cpu_monitor_start() != ZAP_SUCCESS) {
+			return ZAP_FAIL;
+		}
+	}
+	return ZAP_SUCCESS;
+}
+
+OZ_DECLARE(uint32_t) zap_running(void)
+{
+	return globals.running;
+}
+
+
+OZ_DECLARE(zap_status_t) zap_global_destroy(void)
+{
+	unsigned int j;
+	zap_span_t *sp;
+
+	time_end();
+
+	globals.running = 0;
+	zap_cpu_monitor_stop();
+	zap_span_close_all();
+	zap_sleep(1000);
+	
+	zap_mutex_lock(globals.span_mutex);
+	for (sp = globals.spans; sp;) {
+		zap_span_t *cur_span = sp;
+		sp = sp->next;
+
+		if (cur_span) {
+			if (zap_test_flag(cur_span, ZAP_SPAN_CONFIGURED)) {
+				zap_mutex_lock(cur_span->mutex);
+				zap_clear_flag(cur_span, ZAP_SPAN_CONFIGURED);
+				for(j = 1; j <= cur_span->chan_count && cur_span->channels[j]; j++) {
+					zap_channel_t *cur_chan = cur_span->channels[j];
+					if (cur_chan) {
+						if (zap_test_flag(cur_chan, ZAP_CHANNEL_CONFIGURED)) {
+							zap_channel_destroy(cur_chan);
+						}
+						free(cur_chan);
+						cur_chan = NULL;
+					}
+				}
+				zap_mutex_unlock(cur_span->mutex);
+
+				if (cur_span->mutex) {
+					zap_mutex_destroy(&cur_span->mutex);
+				}
+
+				zap_safe_free(cur_span->signal_data);
+				zap_span_destroy(cur_span);
+			}
+
+			hashtable_remove(globals.span_hash, (void *)cur_span->name);
+			zap_safe_free(cur_span->type);
+			zap_safe_free(cur_span->name);
+			free(cur_span);
+			cur_span = NULL;
+		}
+	}
+	globals.spans = NULL;
+	zap_mutex_unlock(globals.span_mutex);
+
+	globals.span_index = 0;
+	
+	zap_unload_modules();
+
+	zap_mutex_lock(globals.mutex);
+	hashtable_destroy(globals.interface_hash);
+	hashtable_destroy(globals.module_hash);
+	hashtable_destroy(globals.span_hash);
+	zap_mutex_unlock(globals.mutex);
+	zap_mutex_destroy(&globals.mutex);
+	zap_mutex_destroy(&globals.span_mutex);
+	memset(&globals, 0, sizeof(globals));
+	return ZAP_SUCCESS;
+}
+
+
+OZ_DECLARE(uint32_t) zap_separate_string(char *buf, char delim, char **array, int arraylen)
+{
+	int argc;
+	char *ptr;
+	int quot = 0;
+	char qc = '\'';
+	int x;
+
+	if (!buf || !array || !arraylen) {
+		return 0;
+	}
+
+	memset(array, 0, arraylen * sizeof(*array));
+
+	ptr = buf;
+
+	for (argc = 0; *ptr && (argc < arraylen - 1); argc++) {
+		array[argc] = ptr;
+		for (; *ptr; ptr++) {
+			if (*ptr == qc) {
+				if (quot) {
+					quot--;
+				} else {
+					quot++;
+				}
+			} else if ((*ptr == delim) && !quot) {
+				*ptr++ = '\0';
+				break;
+			}
+		}
+	}
+
+	if (*ptr) {
+		array[argc++] = ptr;
+	}
+
+	/* strip quotes and leading / trailing spaces */
+	for (x = 0; x < argc; x++) {
+		char *p;
+
+		while(*(array[x]) == ' ') {
+			(array[x])++;
+		}
+		p = array[x];
+		while((p = strchr(array[x], qc))) {
+			memmove(p, p+1, strlen(p));
+			p++;
+		}
+		p = array[x] + (strlen(array[x]) - 1);
+		while(*p == ' ') {
+			*p-- = '\0';
+		}
+	}
+
+	return argc;
+}
+
+OZ_DECLARE(void) zap_bitstream_init(zap_bitstream_t *bsp, uint8_t *data, uint32_t datalen, zap_endian_t endian, uint8_t ss)
+{
+	memset(bsp, 0, sizeof(*bsp));
+	bsp->data = data;
+	bsp->datalen = datalen;
+	bsp->endian = endian;
+	bsp->ss = ss;
+	
+	if (endian < 0) {
+		bsp->top = bsp->bit_index = 7;
+		bsp->bot = 0;
+	} else {
+		bsp->top = bsp->bit_index = 0;
+		bsp->bot = 7;
+	}
+
+}
+
+OZ_DECLARE(int8_t) zap_bitstream_get_bit(zap_bitstream_t *bsp)
+{
+	int8_t bit = -1;
+	
+
+	if (bsp->byte_index >= bsp->datalen) {
+		goto done;
+	}
+
+	if (bsp->ss) {
+		if (!bsp->ssv) {
+			bsp->ssv = 1;
+			return 0;
+		} else if (bsp->ssv == 2) {
+			bsp->byte_index++;
+			bsp->ssv = 0;
+			return 1;
+		}
+	}
+
+
+
+
+	bit = (bsp->data[bsp->byte_index] >> (bsp->bit_index)) & 1;
+	
+	if (bsp->bit_index == bsp->bot) {
+		bsp->bit_index = bsp->top;
+		if (bsp->ss) {
+			bsp->ssv = 2;
+			goto done;
+		} 
+
+		if (++bsp->byte_index > bsp->datalen) {
+			bit = -1;
+			goto done;
+		}
+		
+	} else {
+		bsp->bit_index = bsp->bit_index + bsp->endian;
+	}
+
+
+ done:
+	return bit;
+}
+
+OZ_DECLARE(void) print_hex_bytes(uint8_t *data, zap_size_t dlen, char *buf, zap_size_t blen)
+{
+	char *bp = buf;
+	uint8_t *byte = data;
+	uint32_t i, j = 0;
+
+	if (blen < (dlen * 3) + 2) {
+        return;
+    }
+
+	*bp++ = '[';
+	j++;
+
+	for(i = 0; i < dlen; i++) {
+		snprintf(bp, blen-j, "%02x ", *byte++);
+		bp += 3;
+		j += 3;
+	}
+
+	*--bp = ']';
+
+}
+
+OZ_DECLARE(void) print_bits(uint8_t *b, int bl, char *buf, int blen, zap_endian_t e, uint8_t ss)
+{
+	zap_bitstream_t bs;
+	int j = 0, c = 0;
+	int8_t bit;
+	uint32_t last;
+
+	if (blen < (bl * 10) + 2) {
+        return;
+    }
+
+	zap_bitstream_init(&bs, b, bl, e, ss);
+	last = bs.byte_index;	
+	while((bit = zap_bitstream_get_bit(&bs)) > -1) {
+		buf[j++] = bit ? '1' : '0';
+		if (bs.byte_index != last) {
+			buf[j++] = ' ';
+			last = bs.byte_index;
+			if (++c == 8) {
+				buf[j++] = '\n';
+				c = 0;
+			}
+		}
+	}
+
+}
+
+
+
+OZ_DECLARE_NONSTD(zap_status_t) zap_console_stream_raw_write(zap_stream_handle_t *handle, uint8_t *data, zap_size_t datalen)
+{
+	zap_size_t need = handle->data_len + datalen;
+	
+	if (need >= handle->data_size) {
+		void *new_data;
+		need += handle->alloc_chunk;
+
+		if (!(new_data = realloc(handle->data, need))) {
+			return ZAP_MEMERR;
+		}
+
+		handle->data = new_data;
+		handle->data_size = need;
+	}
+
+	memcpy((uint8_t *) (handle->data) + handle->data_len, data, datalen);
+	handle->data_len += datalen;
+	handle->end = (uint8_t *) (handle->data) + handle->data_len;
+	*(uint8_t *)handle->end = '\0';
+
+	return ZAP_SUCCESS;
+}
+
+OZ_DECLARE(int) zap_vasprintf(char **ret, const char *fmt, va_list ap) /* code from switch_apr.c */
+{
+#ifdef HAVE_VASPRINTF
+	return vasprintf(ret, fmt, ap);
+#else
+	char *buf;
+	int len;
+	size_t buflen;
+	va_list ap2;
+	char *tmp = NULL;
+
+#ifdef _MSC_VER
+#if _MSC_VER >= 1500
+	/* hack for incorrect assumption in msvc header files for code analysis */
+	__analysis_assume(tmp);
+#endif
+	ap2 = ap;
+#else
+	va_copy(ap2, ap);
+#endif
+
+	len = vsnprintf(tmp, 0, fmt, ap2);
+
+	if (len > 0 && (buf = malloc((buflen = (size_t) (len + 1)))) != NULL) {
+		len = vsnprintf(buf, buflen, fmt, ap);
+		*ret = buf;
+	} else {
+		*ret = NULL;
+		len = -1;
+	}
+
+	va_end(ap2);
+	return len;
+#endif
+}
+
+OZ_DECLARE_NONSTD(zap_status_t) zap_console_stream_write(zap_stream_handle_t *handle, const char *fmt, ...)
+{
+	va_list ap;
+	char *buf = handle->data;
+	char *end = handle->end;
+	int ret = 0;
+	char *data = NULL;
+
+	if (handle->data_len >= handle->data_size) {
+		return ZAP_FAIL;
+	}
+
+	va_start(ap, fmt);
+	ret = zap_vasprintf(&data, fmt, ap);
+	va_end(ap);
+
+	if (data) {
+		zap_size_t remaining = handle->data_size - handle->data_len;
+		zap_size_t need = strlen(data) + 1;
+
+		if ((remaining < need) && handle->alloc_len) {
+			zap_size_t new_len;
+			void *new_data;
+
+			new_len = handle->data_size + need + handle->alloc_chunk;
+			if ((new_data = realloc(handle->data, new_len))) {
+				handle->data_size = handle->alloc_len = new_len;
+				handle->data = new_data;
+				buf = handle->data;
+				remaining = handle->data_size - handle->data_len;
+				handle->end = (uint8_t *) (handle->data) + handle->data_len;
+				end = handle->end;
+			} else {
+				zap_log(ZAP_LOG_CRIT, "Memory Error!\n");
+				free(data);
+				return ZAP_FAIL;
+			}
+		}
+
+		if (remaining < need) {
+			ret = -1;
+		} else {
+			ret = 0;
+			snprintf(end, remaining, "%s", data);
+			handle->data_len = strlen(buf);
+			handle->end = (uint8_t *) (handle->data) + handle->data_len;
+		}
+		free(data);
+	}
+
+	return ret ? ZAP_FAIL : ZAP_SUCCESS;
+}
+
+static void *zap_cpu_monitor_run(zap_thread_t *me, void *obj)
+{
+#ifndef WIN32
+	cpu_monitor_t *monitor = (cpu_monitor_t *)obj;
+	struct zap_cpu_monitor_stats *cpu_stats = zap_new_cpu_monitor();
+	if (!cpu_stats) {
+		return NULL;
+	}
+	monitor->running = 1;
+
+	while(zap_running()) {
+		double time;
+		if (zap_cpu_get_system_idle_time(cpu_stats, &time)) {
+			break;
+		}
+
+		if (monitor->alarm) {
+			if ((int)time >= (100-monitor->set_alarm_threshold)) {
+				zap_log(ZAP_LOG_DEBUG, "CPU alarm OFF (idle:%d)\n", (int) time);
+				monitor->alarm = 0;
+			}
+			if (monitor->alarm_action_flags & ZAP_CPU_ALARM_ACTION_WARN) {
+				zap_log(ZAP_LOG_WARNING, "CPU alarm is ON (cpu usage:%d)\n", (int) (100-time));
+			}
+		} else {
+			if ((int)time <= (100-monitor->reset_alarm_threshold)) {
+				zap_log(ZAP_LOG_DEBUG, "CPU alarm ON (idle:%d)\n", (int) time);
+				monitor->alarm = 1;
+			}
+		}
+		zap_interrupt_wait(monitor->interrupt, monitor->interval);
+	}
+	zap_delete_cpu_monitor(cpu_stats);
+	monitor->running = 0;
+#else
+	UNREFERENCED_PARAMETER(me);
+	UNREFERENCED_PARAMETER(obj);
+#endif
+
+	return NULL;
+}
+
+
+static zap_status_t zap_cpu_monitor_start(void)
+{
+	if (zap_interrupt_create(&globals.cpu_monitor.interrupt, ZAP_INVALID_SOCKET) != ZAP_SUCCESS) {
+		zap_log(ZAP_LOG_CRIT, "Failed to create CPU monitor interrupt\n");
+		return ZAP_FAIL;
+	}
+	
+	if (zap_thread_create_detached(zap_cpu_monitor_run, &globals.cpu_monitor) != ZAP_SUCCESS) {
+		zap_log(ZAP_LOG_CRIT, "Failed to create cpu monitor thread!!\n");
+		return ZAP_FAIL;
+	}
+	return ZAP_SUCCESS;
+}
+
+static void zap_cpu_monitor_stop(void)
+{
+	if (!globals.cpu_monitor.interrupt) {
+		return;
+	}
+
+	if (!globals.cpu_monitor.running) {
+		return;
+	}
+
+	if (zap_interrupt_signal(globals.cpu_monitor.interrupt) != ZAP_SUCCESS) {
+		zap_log(ZAP_LOG_CRIT, "Failed to stop CPU monitor\n");
+		return;
+	}
+
+	while(globals.cpu_monitor.running) {
+		zap_sleep(10);
+	}
+	
+	zap_interrupt_destroy(&globals.cpu_monitor.interrupt);
+}
+
+OZ_DECLARE(void) zap_cpu_monitor_disable(void)
+{
+	zap_cpu_monitor_disabled = 1;
+}
+
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */

Added: freeswitch/trunk/libs/openzap/src/zap_m3ua.c (0 => 17141)


--- freeswitch/trunk/libs/openzap/src/zap_m3ua.c	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/src/zap_m3ua.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,692 @@
+/*
+ *  zap_m3ua.c
+ *  openzap
+ *
+ *  Created by Shane Burrell on 4/3/08.
+ *  Copyright 2008 Shane Burrell. All rights reserved.
+ *
+ * 
+ * Copyright (c) 2007, Anthony Minessale II, Nenad Corbic * 
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#include "openzap.h"
+#include "m3ua_client.h"
+#include "zap_m3ua.h"
+
+#define MAX_REQ_ID MAX_PENDING_CALLS
+typedef uint16_t m3ua_request_id_t;
+
+typedef enum {
+	BST_FREE,
+	BST_WAITING,
+	BST_READY,
+	BST_FAIL
+} m3ua_request_status_t;
+
+typedef struct {
+	m3ua_request_status_t status;
+	m3uac_event_t event;
+	zap_span_t *span;
+	zap_channel_t *zchan;
+} m3ua_request_t;
+
+
+struct general_config {
+	uint32_t region;
+};
+typedef struct general_config general_config_t;
+
+
+struct m3ua_channel_profile {
+	char name[80];
+	int cust_span;
+	unsigned char opc[3];
+	unsigned char dpc[3];
+	int local_ip[4];
+	int local_port;
+	int remote_ip[4];
+	int remote_port;
+	int m3ua_mode;
+};
+typedef struct m3ua_channel_profile m3ua_channel_profile_t;
+
+static struct {
+	zap_hash_t *profile_hash;
+	general_config_t general_config;
+} globals;
+
+struct m3ua_span_data {
+	uint32_t boardno;
+	uint32_t flags;
+};
+typedef struct m3ua_span_data m3ua_span_data_t;
+
+struct m3ua_chan_data {
+	zap_buffer_t *digit_buffer;
+	zap_mutex_t *digit_mutex;
+	zap_size_t dtmf_len;
+	uint32_t flags;
+	uint32_t hdlc_bytes;
+};
+typedef struct m3ua_chan_data m3ua_chan_data_t;
+
+static zap_mutex_t *request_mutex = NULL;
+static zap_mutex_t *signal_mutex = NULL;
+
+static uint8_t req_map[MAX_REQ_ID+1] = { 0 };
+
+static void release_request_id(m3ua_request_id_t r)
+{
+	zap_mutex_lock(request_mutex);
+	req_map[r] = 0;
+	zap_mutex_unlock(request_mutex);
+}
+
+/*static m3ua_request_id_t next_request_id(void)
+{
+	m3ua_request_id_t r = 0;
+	int ok = 0;
+	
+	while(!ok) {
+		zap_mutex_lock(request_mutex);
+		for (r = 1; r <= MAX_REQ_ID; r++) {
+			if (!req_map[r]) {
+				ok = 1;
+				req_map[r] = 1;
+				break;
+			}
+		}
+		zap_mutex_unlock(request_mutex);
+		if (!ok) {
+			zap_sleep(5);
+		}
+	}
+	return r;
+}
+*/
+
+static __inline__ void state_advance(zap_channel_t *zchan)
+{
+
+	m3ua_data_t *m3ua_data = zchan->span->signal_data;
+	m3uac_connection_t *mcon = &m3ua_data->mcon;
+	zap_sigmsg_t sig;
+	zap_status_t status;
+
+	zap_log(ZAP_LOG_DEBUG, "%d:%d STATE [%s]\n", zchan->span_id, zchan->chan_id, zap_channel_state2str(zchan->state));
+	
+	memset(&sig, 0, sizeof(sig));
+	sig.chan_id = zchan->chan_id;
+	sig.span_id = zchan->span_id;
+	sig.channel = zchan;
+
+	switch (zchan->state) {
+	case ZAP_CHANNEL_STATE_DOWN:
+		{
+			if (zchan->extra_id) {
+				release_request_id((m3ua_request_id_t)zchan->extra_id);
+				zchan->extra_id = 0;
+			}
+			zap_channel_done(zchan);			
+		}
+		break;
+	case ZAP_CHANNEL_STATE_PROGRESS_MEDIA:
+	case ZAP_CHANNEL_STATE_PROGRESS:
+		{
+			if (zap_test_flag(zchan, ZAP_CHANNEL_OUTBOUND)) {
+				sig.event_id = ZAP_SIGEVENT_PROGRESS_MEDIA;
+				if ((status = m3ua_data->signal_cb(&sig) != ZAP_SUCCESS)) {
+					zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_HANGUP);
+				}
+			} else {
+				m3uac_exec_command(mcon,
+								   zchan->physical_span_id-1,
+								   zchan->physical_chan_id-1,								   
+								   0,
+								   SIGBOOST_EVENT_CALL_START_ACK,
+								   0);
+			}
+		}
+		break;
+	case ZAP_CHANNEL_STATE_RING:
+		{
+			if (!zap_test_flag(zchan, ZAP_CHANNEL_OUTBOUND)) {
+				sig.event_id = ZAP_SIGEVENT_START;
+				if ((status = m3ua_data->signal_cb(&sig) != ZAP_SUCCESS)) {
+					zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_HANGUP);
+				}
+			}
+
+		}
+		break;
+	case ZAP_CHANNEL_STATE_RESTART:
+		{
+			if (zchan->last_state != ZAP_CHANNEL_STATE_HANGUP && zchan->last_state != ZAP_CHANNEL_STATE_DOWN) {
+				zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_HANGUP);
+			} else {
+				zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_DOWN);
+			}
+		}
+		break;
+	case ZAP_CHANNEL_STATE_UP:
+		{
+			if (zap_test_flag(zchan, ZAP_CHANNEL_OUTBOUND)) {
+				sig.event_id = ZAP_SIGEVENT_UP;
+				if ((status = m3ua_data->signal_cb(&sig) != ZAP_SUCCESS)) {
+					zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_HANGUP);
+				}
+			} else {
+				if (!(zap_test_flag(zchan, ZAP_CHANNEL_PROGRESS) || zap_test_flag(zchan, ZAP_CHANNEL_MEDIA))) {
+					m3uac_exec_command(mcon,
+									   zchan->physical_span_id-1,
+									   zchan->physical_chan_id-1,								   
+									   0,
+									   SIGBOOST_EVENT_CALL_START_ACK,
+									   0);
+				}
+				
+				m3uac_exec_command(mcon,
+								   zchan->physical_span_id-1,
+								   zchan->physical_chan_id-1,								   
+								   0,
+								   SIGBOOST_EVENT_CALL_ANSWERED,
+								   0);
+			}
+		}
+		break;
+	case ZAP_CHANNEL_STATE_DIALING:
+		{
+		}
+		break;
+	case ZAP_CHANNEL_STATE_HANGUP_COMPLETE:
+		{
+			zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_DOWN);
+		}
+		break;
+	case ZAP_CHANNEL_STATE_HANGUP:
+		{
+			if (zap_test_flag(zchan, ZAP_CHANNEL_ANSWERED) || zap_test_flag(zchan, ZAP_CHANNEL_PROGRESS) || zap_test_flag(zchan, ZAP_CHANNEL_MEDIA)) {
+				m3uac_exec_command(mcon,
+								   zchan->physical_span_id-1,
+								   zchan->physical_chan_id-1,
+								   0,
+								   SIGBOOST_EVENT_CALL_STOPPED,
+								   zchan->caller_data.hangup_cause);
+			} else {
+				m3uac_exec_command(mcon,
+								   zchan->physical_span_id-1,
+								   zchan->physical_chan_id-1,								   
+								   0,
+								   SIGBOOST_EVENT_CALL_START_NACK,
+								   zchan->caller_data.hangup_cause);
+			}			
+		}
+		break;
+	case ZAP_CHANNEL_STATE_CANCEL:
+		{
+			sig.event_id = ZAP_SIGEVENT_STOP;
+			status = m3ua_data->signal_cb(&sig);
+			zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_DOWN);
+			m3uac_exec_command(mcon,
+							   zchan->physical_span_id-1,
+							   zchan->physical_chan_id-1,
+							   0,
+							   SIGBOOST_EVENT_CALL_START_NACK_ACK,
+							   0);
+		}
+		break;
+	case ZAP_CHANNEL_STATE_TERMINATING:
+		{
+			sig.event_id = ZAP_SIGEVENT_STOP;
+			status = m3ua_data->signal_cb(&sig);
+			zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_DOWN);
+			m3uac_exec_command(mcon,
+							   zchan->physical_span_id-1,
+							   zchan->physical_chan_id-1,
+							   0,
+							   SIGBOOST_EVENT_CALL_STOPPED_ACK,
+							   0);
+		}
+		break;
+	default:
+		break;
+	}
+}
+
+
+static __inline__ void check_state(zap_span_t *span)
+{
+    if (zap_test_flag(span, ZAP_SPAN_STATE_CHANGE)) {
+        uint32_t j;
+        zap_clear_flag_locked(span, ZAP_SPAN_STATE_CHANGE);
+        for(j = 1; j <= span->chan_count; j++) {
+            if (zap_test_flag((&span->channels[j]), ZAP_CHANNEL_STATE_CHANGE)) {
+                zap_clear_flag_locked((&span->channels[j]), ZAP_CHANNEL_STATE_CHANGE);
+                state_advance(&span->channels[j]);
+                zap_channel_complete_state(&span->channels[j]);
+            }
+        }
+    }
+}
+
+
+static int parse_ss7_event(zap_span_t *span, m3uac_connection_t *mcon, m3uac_event_t *event)
+{
+	zap_mutex_lock(signal_mutex);
+	
+	if (!zap_running()) {
+		zap_log(ZAP_LOG_WARNING, "System is shutting down.\n");
+		goto end;
+	}
+
+
+	if (zap_test_flag(span, ZAP_SPAN_SUSPENDED) && 
+		event->event_id != SIGBOOST_EVENT_SYSTEM_RESTART_ACK && event->event_id != SIGBOOST_EVENT_HEARTBEAT) {
+
+		zap_log(ZAP_LOG_WARNING,
+				"INVALID EVENT: %s:(%X) [w%dg%d] Rc=%i CSid=%i Seq=%i Cd=[%s] Ci=[%s]\n",
+				m3uac_event_id_name(event->event_id),
+				event->event_id,
+				event->span+1,
+				event->chan+1,
+				event->release_cause,
+				event->call_setup_id,
+				event->fseqno,
+				(event->called_number_digits_count ? (char *) event->called_number_digits : "N/A"),
+				(event->calling_number_digits_count ? (char *) event->calling_number_digits : "N/A")
+				);
+		
+		goto end;
+	}
+
+
+	zap_log(ZAP_LOG_DEBUG,
+			"RX EVENT: %s:(%X) [w%dg%d] Rc=%i CSid=%i Seq=%i Cd=[%s] Ci=[%s]\n",
+			   m3uac_event_id_name(event->event_id),
+			   event->event_id,
+			   event->span+1,
+			   event->chan+1,
+			   event->release_cause,
+			   event->call_setup_id,
+			   event->fseqno,
+			   (event->called_number_digits_count ? (char *) event->called_number_digits : "N/A"),
+			   (event->calling_number_digits_count ? (char *) event->calling_number_digits : "N/A")
+			   );
+
+
+	
+    switch(event->event_id) {
+
+    case SIGBOOST_EVENT_CALL_START:
+		//handle_call_start(span, mcon, event);
+		break;
+    case SIGBOOST_EVENT_CALL_STOPPED:
+		//handle_call_stop(span, mcon, event);
+		break;
+    case SIGBOOST_EVENT_CALL_START_ACK:
+		//handle_call_start_ack(mcon, event);
+		break;
+    case SIGBOOST_EVENT_CALL_START_NACK:
+		//handle_call_start_nack(span, mcon, event);
+		break;
+    case SIGBOOST_EVENT_CALL_ANSWERED:
+		//handle_call_answer(span, mcon, event);
+		break;
+    case SIGBOOST_EVENT_HEARTBEAT:
+		//handle_heartbeat(mcon, event);
+		break;
+    case SIGBOOST_EVENT_CALL_STOPPED_ACK:
+    case SIGBOOST_EVENT_CALL_START_NACK_ACK:
+		//handle_call_done(span, mcon, event);
+		break;
+    case SIGBOOST_EVENT_INSERT_CHECK_LOOP:
+		//handle_call_loop_start(event);
+		break;
+    case SIGBOOST_EVENT_REMOVE_CHECK_LOOP:
+		//handle_call_stop(event);
+		break;
+    case SIGBOOST_EVENT_SYSTEM_RESTART_ACK:
+		//handle_restart_ack(mcon, span, event);
+		break;
+    case SIGBOOST_EVENT_AUTO_CALL_GAP_ABATE:
+		//handle_gap_abate(event);
+		break;
+    default:
+		zap_log(ZAP_LOG_WARNING, "No handler implemented for [%s]\n", m3uac_event_id_name(event->event_id));
+		break;
+    }
+
+ end:
+
+	zap_mutex_unlock(signal_mutex);
+
+	return 0;
+}
+
+static ZIO_CONFIGURE_FUNCTION(m3ua_configure)
+{
+	m3ua_channel_profile_t *profile = NULL;
+
+	int ok = 1;
+
+	if (!(profile = (m3ua_channel_profile_t *) hashtable_search(globals.profile_hash, (char *)category))) {
+		profile = malloc(sizeof(*profile));
+		memset(profile, 0, sizeof(*profile));
+		zap_set_string(profile->name, category);
+		hashtable_insert(globals.profile_hash, (void *)profile->name, profile);
+		zap_log(ZAP_LOG_INFO, "creating profile [%s]\n", category);
+	}
+
+//	zap_set_string(m3ua_data->mcon. cfg.local_ip, local_ip);
+	if (!strcasecmp(var, "local_sctp_port")) {
+		profile->local_port = 30000 ;
+		profile->remote_port = 30000;
+		profile->cust_span++;
+	} 
+	ok = 1;
+	
+
+	if (ok) {
+		zap_log(ZAP_LOG_INFO, "setting param [%s]=[%s] for profile [%s]\n", var, val, category);
+	} else {
+		zap_log(ZAP_LOG_ERROR, "unknown param [%s]\n", var);
+	}
+
+	return ZAP_SUCCESS;
+}
+
+static ZIO_CONFIGURE_SPAN_FUNCTION(m3ua_configure_span)
+{
+
+	return ZAP_FAIL;
+}
+
+static ZIO_OPEN_FUNCTION(m3ua_open) 
+{
+	
+	return ZAP_FAIL;
+}
+
+static ZIO_CLOSE_FUNCTION(m3ua_close)
+{
+	
+	return ZAP_FAIL;
+}
+
+/*static ZIO_SET_INTERVAL_FUNCTION(m3ua_set_interval)
+{
+	
+	return 0;
+}*/
+
+static ZIO_WAIT_FUNCTION(m3ua_wait)
+{
+	
+	return ZAP_FAIL;
+}
+
+static ZIO_READ_FUNCTION(m3ua_read)
+{
+	
+	return ZAP_FAIL;
+}
+
+static ZIO_WRITE_FUNCTION(m3ua_write)
+{
+	
+	return ZAP_FAIL;
+}
+
+static ZIO_COMMAND_FUNCTION(m3ua_command)
+{
+	return ZAP_FAIL;
+}
+
+static ZIO_SPAN_POLL_EVENT_FUNCTION(m3ua_poll_event)
+{
+	return ZAP_FAIL;
+}
+
+static ZIO_SPAN_NEXT_EVENT_FUNCTION(m3ua_next_event)
+{
+	return ZAP_FAIL;
+}
+
+
+static ZIO_SPAN_DESTROY_FUNCTION(m3ua_span_destroy)
+{
+	m3ua_span_data_t *span_data = (m3ua_span_data_t *) span->mod_data;
+	
+	if (span_data) {
+		free(span_data);
+	}
+	
+	return ZAP_SUCCESS;
+}
+static ZIO_CHANNEL_DESTROY_FUNCTION(m3ua_channel_destroy)
+{
+	m3ua_chan_data_t *chan_data = (m3ua_chan_data_t *) zchan->mod_data;
+	m3ua_span_data_t *span_data = (m3ua_span_data_t *) zchan->span->mod_data;
+	
+	if (!chan_data) {
+		return ZAP_FAIL;
+	}
+
+	
+		
+
+
+
+	zap_mutex_destroy(&chan_data->digit_mutex);
+	zap_buffer_destroy(&chan_data->digit_buffer);
+
+
+	zap_safe_free(chan_data);
+	
+	if (span_data) {
+		free(span_data);
+	}
+	
+			
+	return ZAP_SUCCESS;
+}
+
+
+
+static ZIO_GET_ALARMS_FUNCTION(m3ua_get_alarms)
+{
+	return ZAP_FAIL;
+}
+
+static zap_io_interface_t m3ua_interface;
+
+zap_status_t m3ua_init(zap_io_interface_t **zint)
+{
+	assert(zint != NULL);
+	memset(&m3ua_interface, 0, sizeof(m3ua_interface));
+
+	m3ua_interface.name = "m3ua";
+	m3ua_interface.configure =  m3ua_configure;
+	m3ua_interface.configure_span =  m3ua_configure_span;
+	m3ua_interface.open = m3ua_open;
+	m3ua_interface.close = m3ua_close;
+	m3ua_interface.wait = m3ua_wait;
+	m3ua_interface.read = m3ua_read;
+	m3ua_interface.write = m3ua_write;
+	m3ua_interface.command = m3ua_command;
+	m3ua_interface.poll_event = m3ua_poll_event;
+	m3ua_interface.next_event = m3ua_next_event;
+	m3ua_interface.channel_destroy = m3ua_channel_destroy;
+	m3ua_interface.span_destroy = m3ua_span_destroy;
+	m3ua_interface.get_alarms = m3ua_get_alarms;
+	*zint = &m3ua_interface;
+
+	return ZAP_FAIL;
+}
+
+zap_status_t m3ua_destroy(void)
+{
+	return ZAP_FAIL;
+}
+
+
+static void *m3ua_run(zap_thread_t *me, void *obj)
+{
+    zap_span_t *span = (zap_span_t *) obj;
+    m3ua_data_t *m3ua_data = span->signal_data;
+	m3uac_connection_t *mcon, *pcon;
+	uint32_t ms = 10, too_long = 60000;
+		
+
+	m3ua_data->pcon = m3ua_data->mcon;
+
+	if (m3uac_connection_open(&m3ua_data->mcon,
+							  m3ua_data->mcon.cfg.local_ip,
+							  m3ua_data->mcon.cfg.local_port,
+							  m3ua_data->mcon.cfg.remote_ip,
+							  m3ua_data->mcon.cfg.remote_port) < 0) {
+		zap_log(ZAP_LOG_DEBUG, "Error: Opening MCON Socket [%d] %s\n", m3ua_data->mcon.socket, strerror(errno));
+		goto end;
+    }
+
+	if (m3uac_connection_open(&m3ua_data->pcon,
+							  m3ua_data->pcon.cfg.local_ip,
+							  ++m3ua_data->pcon.cfg.local_port,
+							  m3ua_data->pcon.cfg.remote_ip,
+							  m3ua_data->pcon.cfg.remote_port) < 0) {
+		zap_log(ZAP_LOG_DEBUG, "Error: Opening PCON Socket [%d] %s\n", m3ua_data->pcon.socket, strerror(errno));
+		goto end;
+    }
+	
+	mcon = &m3ua_data->mcon;
+	pcon = &m3ua_data->pcon;
+
+	top:
+
+	//init_outgoing_array();		
+
+	m3uac_exec_command(mcon,
+					   0,
+					   0,
+					   -1,
+					   SIGBOOST_EVENT_SYSTEM_RESTART,
+					   0);
+	
+	while (zap_test_flag(m3ua_data, ZAP_M3UA_RUNNING)) {
+		fd_set rfds, efds;
+		struct timeval tv = { 0, ms * 1000 };
+		int max, activity, i = 0;
+		m3uac_event_t *event = NULL;
+		
+		if (!zap_running()) {
+			m3uac_exec_command(mcon,
+							   0,
+							   0,
+							   -1,
+							   SIGBOOST_EVENT_SYSTEM_RESTART,
+							   0);
+			break;
+		}
+
+		FD_ZERO(&rfds);
+		FD_ZERO(&efds);
+		FD_SET(mcon->socket, &rfds);
+		FD_SET(mcon->socket, &efds);
+		FD_SET(pcon->socket, &rfds);
+		FD_SET(pcon->socket, &efds);
+
+		max = ((pcon->socket > mcon->socket) ? pcon->socket : mcon->socket) + 1;
+		
+		if ((activity = select(max, &rfds, NULL, &efds, &tv)) < 0) {
+			goto error;
+		}
+		
+		if (activity) {
+			if (FD_ISSET(pcon->socket, &efds) || FD_ISSET(mcon->socket, &efds)) {
+				goto error;
+			}
+
+			if (FD_ISSET(pcon->socket, &rfds)) {
+				if ((event = m3uac_connection_readp(pcon, i))) {
+					parse_ss7_event(span, mcon, event);
+				} else goto top;
+			}
+
+			if (FD_ISSET(mcon->socket, &rfds)) {
+				if ((event = m3uac_connection_read(mcon, i))) {
+					parse_ss7_event(span, mcon, event);
+				} else goto top;
+			}
+		}
+		
+		check_state(span);
+		mcon->hb_elapsed += ms;
+		
+		if (mcon->hb_elapsed >= too_long && (mcon->up || !zap_test_flag(span, ZAP_SPAN_SUSPENDED))) {
+			zap_set_state_all(span, ZAP_CHANNEL_STATE_RESTART);
+			zap_set_flag_locked(span, ZAP_SPAN_SUSPENDED);
+			mcon->up = 0;
+			zap_log(ZAP_LOG_CRIT, "Lost Heartbeat!\n");
+		}
+
+	}
+
+	goto end;
+
+ error:
+	zap_log(ZAP_LOG_CRIT, "Socket Error!\n");
+
+ end:
+
+	m3uac_connection_close(&m3ua_data->mcon);
+	m3uac_connection_close(&m3ua_data->pcon);
+
+	zap_clear_flag(m3ua_data, ZAP_M3UA_RUNNING);
+
+	zap_log(ZAP_LOG_DEBUG, "M3UA thread ended.\n");
+	return NULL;
+}
+zap_status_t m3ua_start(zap_span_t *span)
+{
+	m3ua_data_t *m3ua_data = span->signal_data;
+	zap_set_flag(m3ua_data, ZAP_M3UA_RUNNING);
+	return zap_thread_create_detached(m3ua_run, span);
+}
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+*/

Added: freeswitch/trunk/libs/openzap/src/zap_threadmutex.c (0 => 17141)


--- freeswitch/trunk/libs/openzap/src/zap_threadmutex.c	                        (rev 0)
+++ freeswitch/trunk/libs/openzap/src/zap_threadmutex.c	2010-03-30 13:41:49 UTC (rev 17141)
@@ -0,0 +1,454 @@
+/* 
+ * Cross Platform Thread/Mutex abstraction
+ * Copyright(C) 2007 Michael Jerris
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Soozware, and permit persons to whom the Soozware is
+ * furnished to do so.
+ *
+ * This work is provided under this license on an "as is" basis, without warranty of any kind,
+ * either expressed or implied, including, without limitation, warranties that the covered code
+ * is free of defects, merchantable, fit for a particular purpose or non-infringing. The entire
+ * risk as to the quality and performance of the covered code is with you. Should any covered
+ * code prove defective in any respect, you (not the initial developer or any other contributor)
+ * assume the cost of any necessary servicing, repair or correction. This disclaimer of warranty
+ * constitutes an essential part of this license. No use of any covered code is authorized hereunder
+ * except under this disclaimer. 
+ *
+ * Contributors: 
+ *
+ * Moises Silva <moy@sangoma.com>
+ *
+ */
+
+#ifdef WIN32
+/* required for TryEnterCriticalSection definition.  Must be defined before windows.h include */
+#define _WIN32_WINNT 0x0400
+#endif
+
+#include "openzap.h"
+#include "zap_threadmutex.h"
+
+#ifdef WIN32
+#include <process.h>
+
+#define ZAP_THREAD_CALLING_CONVENTION __stdcall
+
+struct zap_mutex {
+	CRITICAL_SECTION mutex;
+};
+
+#else
+#include <pthread.h>
+#include <poll.h>
+
+#define ZAP_THREAD_CALLING_CONVENTION
+
+struct zap_mutex {
+	pthread_mutex_t mutex;
+};
+
+#endif
+
+struct zap_interrupt {
+	zap_socket_t device;
+#ifdef WIN32
+	/* for generic interruption */
+	HANDLE event;
+#else
+	/* for generic interruption */
+	int readfd;
+	int writefd;
+#endif
+};
+
+struct zap_thread {
+#ifdef WIN32
+	void *handle;
+#else
+	pthread_t handle;
+#endif
+	void *private_data;
+	zap_thread_function_t function;
+	zap_size_t stack_size;
+#ifndef WIN32
+	pthread_attr_t attribute;
+#endif
+};
+
+zap_size_t thread_default_stacksize = 0;
+
+OZ_DECLARE(void) zap_thread_override_default_stacksize(zap_size_t size)
+{
+	thread_default_stacksize = size;
+}
+
+static void * ZAP_THREAD_CALLING_CONVENTION thread_launch(void *args)
+{
+	void *exit_val;
+    zap_thread_t *thread = (zap_thread_t *)args;
+	exit_val = thread->function(thread, thread->private_data);
+#ifndef WIN32
+	pthread_attr_destroy(&thread->attribute);
+#endif
+	zap_safe_free(thread);
+
+	return exit_val;
+}
+
+OZ_DECLARE(zap_status_t) zap_thread_create_detached(zap_thread_function_t func, void *data)
+{
+	return zap_thread_create_detached_ex(func, data, thread_default_stacksize);
+}
+
+OZ_DECLARE(zap_status_t) zap_thread_create_detached_ex(zap_thread_function_t func, void *data, zap_size_t stack_size)
+{
+	zap_thread_t *thread = NULL;
+	zap_status_t status = ZAP_FAIL;
+
+	if (!func || !(thread = (zap_thread_t *)malloc(sizeof(zap_thread_t)))) {
+		goto done;
+	}
+
+	thread->private_data = data;
+	thread->function = func;
+	thread->stack_size = stack_size;
+
+#if defined(WIN32)
+	thread->handle = (void *)_beginthreadex(NULL, (unsigned)thread->stack_size, (unsigned int (__stdcall *)(void *))thread_launch, thread, 0, NULL);
+	if (!thread->handle) {
+		goto fail;
+	}
+	CloseHandle(thread->handle);
+
+	status = ZAP_SUCCESS;
+	goto done;
+#else
+	
+	if (pthread_attr_init(&thread->attribute) != 0)	goto fail;
+
+	if (pthread_attr_setdetachstate(&thread->attribute, PTHREAD_CREATE_DETACHED) != 0) goto failpthread;
+
+	if (thread->stack_size && pthread_attr_setstacksize(&thread->attribute, thread->stack_size) != 0) goto failpthread;
+
+	if (pthread_create(&thread->handle, &thread->attribute, thread_launch, thread) != 0) goto failpthread;
+
+	status = ZAP_SUCCESS;
+	goto done;
+ failpthread:
+	pthread_attr_destroy(&thread->attribute);
+#endif
+
+ fail:
+	if (thread) {
+		zap_safe_free(thread);
+	}
+ done:
+	return status;
+}
+
+
+OZ_DECLARE(zap_status_t) zap_mutex_create(zap_mutex_t **mutex)
+{
+	zap_status_t status = ZAP_FAIL;
+#ifndef WIN32
+	pthread_mutexattr_t attr;
+#endif
+	zap_mutex_t *check = NULL;
+
+	check = (zap_mutex_t *)malloc(sizeof(**mutex));
+	if (!check)
+		goto done;
+#ifdef WIN32
+	InitializeCriticalSection(&check->mutex);
+#else
+	if (pthread_mutexattr_init(&attr))
+		goto done;
+
+	if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE))
+		goto fail;
+
+	if (pthread_mutex_init(&check->mutex, &attr))
+		goto fail;
+
+	goto success;
+
+ fail:
+	pthread_mutexattr_destroy(&attr);
+	goto done;
+
+ success:
+#endif
+	*mutex = check;
+	status = ZAP_SUCCESS;
+
+ done:
+	return status;
+}
+
+OZ_DECLARE(zap_status_t) zap_mutex_destroy(zap_mutex_t **mutex)
+{
+	zap_mutex_t *mp = *mutex;
+	*mutex = NULL;
+	if (!mp) {
+		return ZAP_FAIL;
+	}
+#ifdef WIN32
+	DeleteCriticalSection(&mp->mutex);
+#else
+	if (pthread_mutex_destroy(&mp->mutex))
+		return ZAP_FAIL;
+#endif
+	zap_safe_free(mp);
+	return ZAP_SUCCESS;
+}
+
+OZ_DECLARE(zap_status_t) _zap_mutex_lock(zap_mutex_t *mutex)
+{
+#ifdef WIN32
+	EnterCriticalSection(&mutex->mutex);
+#else
+	int err;
+	if ((err = pthread_mutex_lock(&mutex->mutex))) {
+		zap_log(ZAP_LOG_ERROR, "Failed to lock mutex %d:%s\n", err, strerror(err));
+		return ZAP_FAIL;
+	}
+#endif
+	return ZAP_SUCCESS;
+}
+
+OZ_DECLARE(zap_status_t) _zap_mutex_trylock(zap_mutex_t *mutex)
+{
+#ifdef WIN32
+	if (!TryEnterCriticalSection(&mutex->mutex))
+		return ZAP_FAIL;
+#else
+	if (pthread_mutex_trylock(&mutex->mutex))
+		return ZAP_FAIL;
+#endif
+	return ZAP_SUCCESS;
+}
+
+OZ_DECLARE(zap_status_t) _zap_mutex_unlock(zap_mutex_t *mutex)
+{
+#ifdef WIN32
+	LeaveCriticalSection(&mutex->mutex);
+#else
+	if (pthread_mutex_unlock(&mutex->mutex))
+		return ZAP_FAIL;
+#endif
+	return ZAP_SUCCESS;
+}
+
+
+OZ_DECLARE(zap_status_t) zap_interrupt_create(zap_interrupt_t **ininterrupt, zap_socket_t device)
+{
+	zap_interrupt_t *interrupt = NULL;
+#ifndef WIN32
+	int fds[2];
+#endif
+
+	interrupt = calloc(1, sizeof(*interrupt));
+	if (!interrupt) {
+		zap_log(ZAP_LOG_ERROR, "Failed to allocate interrupt memory\n");
+		return ZAP_FAIL;
+	}
+
+	interrupt->device = device;
+#ifdef WIN32
+	interrupt->event = CreateEvent(NULL, FALSE, FALSE, NULL);
+	if (!interrupt->event) {
+		zap_log(ZAP_LOG_ERROR, "Failed to allocate interrupt event\n");
+		goto failed;
+	}
+#else
+	if (pipe(fds)) {
+		zap_log(ZAP_LOG_ERROR, "Failed to allocate interrupt pipe: %s\n", strerror(errno));
+		goto failed;
+	}
+	
+	interrupt->readfd = fds[0];
+	interrupt->writefd = fds[1];
+#endif
+
+	*ininterrupt = interrupt;
+	return ZAP_SUCCESS;
+
+failed:
+	if (interrupt) {
+#ifndef WIN32
+		if (interrupt->readfd) {
+			close(interrupt->readfd);
+			close(interrupt->writefd);
+			interrupt->readfd = -1;
+			interrupt->writefd = -1;
+		}
+#endif
+		zap_safe_free(interrupt);
+	}
+	return ZAP_FAIL;
+}
+
+#define ONE_BILLION 1000000000
+
+OZ_DECLARE(zap_status_t) zap_interrupt_wait(zap_interrupt_t *interrupt, int ms)
+{
+	int num = 1;
+#ifdef WIN32
+	DWORD res = 0;
+	HANDLE ints[2];
+#else
+	int res = 0;
+	struct pollfd ints[2];
+	char pipebuf[255];
+#endif
+
+	/* start implementation */
+#ifdef WIN32
+	ints[0] = interrupt->event;
+	if (interrupt->device != ZAP_INVALID_SOCKET) {
+		num++;
+		ints[1] = interrupt->device;
+	}
+	res = WaitForMultipleObjects(num, ints, FALSE, ms >= 0 ? ms : INFINITE);
+	switch (res) {
+	case WAIT_TIMEOUT:
+		return ZAP_TIMEOUT;
+	case WAIT_FAILED:
+	case WAIT_ABANDONED: /* is it right to fail with abandoned? */
+		return ZAP_FAIL;
+	default:
+		if (res >= (sizeof(ints)/sizeof(ints[0]))) {
+			zap_log(ZAP_LOG_ERROR, "Error waiting for openzap interrupt event (WaitForSingleObject returned %d)\n", res);
+			return ZAP_FAIL;
+		}
+		return ZAP_SUCCESS;
+	}
+#else
+	ints[0].fd = interrupt->readfd;
+	ints[0].events = POLLIN;
+	ints[0].revents = 0;
+
+	if (interrupt->device != ZAP_INVALID_SOCKET) {
+		num++;
+		ints[1].fd = interrupt->device;
+		ints[1].events = POLLIN;
+		ints[1].revents = 0;
+	}
+
+	res = poll(ints, num, ms);
+	if (res == -1) {
+		zap_log(ZAP_LOG_CRIT, "interrupt poll failed (%s)\n", strerror(errno));
+		return ZAP_FAIL;
+	}
+
+	if (res == 0) {
+		return ZAP_TIMEOUT;
+	}
+
+	if (ints[0].revents & POLLIN) {
+		res = read(ints[0].fd, pipebuf, sizeof(pipebuf));
+		if (res == -1) {
+			zap_log(ZAP_LOG_CRIT, "reading interrupt descriptor failed (%s)\n", strerror(errno));
+		}
+	}
+
+	return ZAP_SUCCESS;
+#endif
+}
+
+OZ_DECLARE(zap_status_t) zap_interrupt_signal(zap_interrupt_t *interrupt)
+{
+#ifdef WIN32
+	if (!SetEvent(interrupt->event)) {
+		zap_log(ZAP_LOG_ERROR, "Failed to signal interrupt\n");
+		return ZAP_FAIL;
+	}
+#else
+	int err;
+	if ((err = write(interrupt->writefd, "w", 1)) != 1) {
+		zap_log(ZAP_LOG_ERROR, "Failed to signal interrupt: %s\n", errno, strerror(errno));
+		return ZAP_FAIL;
+	}
+#endif
+	return ZAP_SUCCESS;
+}
+
+OZ_DECLARE(zap_status_t) zap_interrupt_destroy(zap_interrupt_t **ininterrupt)
+{
+	zap_interrupt_t *interrupt = NULL;
+	interrupt = *ininterrupt;
+#ifdef WIN32
+	CloseHandle(interrupt->event);
+#else
+	close(interrupt->readfd);
+	close(interrupt->writefd);
+	interrupt->readfd = -1;
+	interrupt->writefd = -1;
+#endif
+	zap_safe_free(interrupt);
+	*ininterrupt = NULL;
+	return ZAP_SUCCESS;
+}
+
+OZ_DECLARE(zap_status_t) zap_interrupt_multiple_wait(zap_interrupt_t *interrupts[], zap_size_t size, int ms)
+{
+#ifndef WIN32
+	int i;
+	int res = 0;
+	int numdevices = 0;
+	char pipebuf[255];
+	struct pollfd ints[size*2];
+
+	memset(&ints, 0, sizeof(ints));
+
+	for (i = 0; i < size; i++) {
+		ints[i].events = POLLIN;
+		ints[i].revents = 0;
+		ints[i].fd = interrupts[i]->readfd;
+		if (interrupts[i]->device != ZAP_INVALID_SOCKET) {
+			ints[i+numdevices].events = POLLIN;
+			ints[i+numdevices].revents = 0;
+			ints[i+numdevices].fd = interrupts[i]->device;
+			numdevices++;
+		}
+	}
+
+	res = poll(ints, size + numdevices, ms);
+
+	if (res == -1) {
+		zap_log(ZAP_LOG_CRIT, "interrupt poll failed (%s)\n", strerror(errno));
+		return ZAP_FAIL;
+	}
+
+	if (res == 0) {
+		return ZAP_TIMEOUT;
+	}
+
+	for (i = size; i < zap_array_len(ints); i++) {
+		if (ints[i].revents & POLLIN) {
+			res = read(ints[0].fd, pipebuf, sizeof(pipebuf));
+			if (res == -1) {
+				zap_log(ZAP_LOG_CRIT, "reading interrupt descriptor failed (%s)\n", strerror(errno));
+			}
+		}
+	}
+
+#elif defined(__WINDOWS__)
+	UNREFERENCED_PARAMETER(interrupts);
+	UNREFERENCED_PARAMETER(size);
+	UNREFERENCED_PARAMETER(ms);
+#endif
+	return ZAP_SUCCESS;
+}
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */