<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[Freeswitch-trunk][17141] </title>
</head>
<body>
<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; }
#msg dl a { font-weight: bold}
#msg dl a:link { color:#fc3; }
#msg dl a:active { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<div id="header">FreeSWITCH Subversion</div>
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://fisheye.freeswitch.org/changelog/FreeSWITCH?cs=17141">17141</a></dd>
<dt>Author</dt> <dd>mikej</dd>
<dt>Date</dt> <dd>2010-03-30 08:41:49 -0500 (Tue, 30 Mar 2010)</dd>
</dl>
<h3>Log Message</h3>
<pre>Merge branch 'master' into svn</pre>
<h3>Added Paths</h3>
<ul>
<li>freeswitch/trunk/libs/freetdm/</li>
<li><a href="#freeswitchtrunklibsfreetdmgitignore">freeswitch/trunk/libs/freetdm/.gitignore</a></li>
<li><a href="#freeswitchtrunklibsfreetdmupdate">freeswitch/trunk/libs/freetdm/.update</a></li>
<li><a href="#freeswitchtrunklibsfreetdmAUTHORS">freeswitch/trunk/libs/freetdm/AUTHORS</a></li>
<li><a href="#freeswitchtrunklibsfreetdmChangeLog">freeswitch/trunk/libs/freetdm/ChangeLog</a></li>
<li><a href="#freeswitchtrunklibsfreetdmMakefileam">freeswitch/trunk/libs/freetdm/Makefile.am</a></li>
<li><a href="#freeswitchtrunklibsfreetdmNEWS">freeswitch/trunk/libs/freetdm/NEWS</a></li>
<li><a href="#freeswitchtrunklibsfreetdmREADME">freeswitch/trunk/libs/freetdm/README</a></li>
<li><a href="#freeswitchtrunklibsfreetdmTODO">freeswitch/trunk/libs/freetdm/TODO</a></li>
<li><a href="#freeswitchtrunklibsfreetdmacincludem4">freeswitch/trunk/libs/freetdm/acinclude.m4</a></li>
<li><a href="#freeswitchtrunklibsfreetdmbootstrap">freeswitch/trunk/libs/freetdm/bootstrap</a></li>
<li>freeswitch/trunk/libs/freetdm/build/</li>
<li><a href="#freeswitchtrunklibsfreetdmbuildlibpcapm4">freeswitch/trunk/libs/freetdm/build/libpcap.m4</a></li>
<li>freeswitch/trunk/libs/freetdm/conf/</li>
<li><a href="#freeswitchtrunklibsfreetdmconffreetdmconf">freeswitch/trunk/libs/freetdm/conf/freetdm.conf</a></li>
<li><a href="#freeswitchtrunklibsfreetdmconffreetdmconfxml">freeswitch/trunk/libs/freetdm/conf/freetdm.conf.xml</a></li>
<li><a href="#freeswitchtrunklibsfreetdmconfm3uaconf">freeswitch/trunk/libs/freetdm/conf/m3ua.conf</a></li>
<li><a href="#freeswitchtrunklibsfreetdmconfpikaconf">freeswitch/trunk/libs/freetdm/conf/pika.conf</a></li>
<li><a href="#freeswitchtrunklibsfreetdmconftonesconf">freeswitch/trunk/libs/freetdm/conf/tones.conf</a></li>
<li><a href="#freeswitchtrunklibsfreetdmconfwanpipeconf">freeswitch/trunk/libs/freetdm/conf/wanpipe.conf</a></li>
<li><a href="#freeswitchtrunklibsfreetdmconfztconf">freeswitch/trunk/libs/freetdm/conf/zt.conf</a></li>
<li><a href="#freeswitchtrunklibsfreetdmconfigureac">freeswitch/trunk/libs/freetdm/configure.ac</a></li>
<li><a href="#freeswitchtrunklibsfreetdmconfiguregnu">freeswitch/trunk/libs/freetdm/configure.gnu</a></li>
<li><a href="#freeswitchtrunklibsfreetdmcyginstallsh">freeswitch/trunk/libs/freetdm/cyginstall.sh</a></li>
<li>freeswitch/trunk/libs/freetdm/docs/</li>
<li><a href="#freeswitchtrunklibsfreetdmdocsDoxygenconf">freeswitch/trunk/libs/freetdm/docs/Doxygen.conf</a></li>
<li><a href="#freeswitchtrunklibsfreetdmfreetdm2008sln">freeswitch/trunk/libs/freetdm/freetdm.2008.sln</a></li>
<li><a href="#freeswitchtrunklibsfreetdmfreetdmpcin">freeswitch/trunk/libs/freetdm/freetdm.pc.in</a></li>
<li>freeswitch/trunk/libs/freetdm/mod_freetdm/</li>
<li><a href="#freeswitchtrunklibsfreetdmmod_freetdmMakefilein">freeswitch/trunk/libs/freetdm/mod_freetdm/Makefile.in</a></li>
<li><a href="#freeswitchtrunklibsfreetdmmod_freetdmmod_freetdm2008vcproj">freeswitch/trunk/libs/freetdm/mod_freetdm/mod_freetdm.2008.vcproj</a></li>
<li><a href="#freeswitchtrunklibsfreetdmmod_freetdmmod_freetdmc">freeswitch/trunk/libs/freetdm/mod_freetdm/mod_freetdm.c</a></li>
<li><a href="#freeswitchtrunklibsfreetdmmod_freetdmmod_openzap2005vcproj">freeswitch/trunk/libs/freetdm/mod_freetdm/mod_openzap.2005.vcproj</a></li>
<li>freeswitch/trunk/libs/freetdm/msvc/</li>
<li><a href="#freeswitchtrunklibsfreetdmmsvcfreetdm2008vcproj">freeswitch/trunk/libs/freetdm/msvc/freetdm.2008.vcproj</a></li>
<li><a href="#freeswitchtrunklibsfreetdmmsvcopenzap2005vcproj">freeswitch/trunk/libs/freetdm/msvc/openzap.2005.vcproj</a></li>
<li>freeswitch/trunk/libs/freetdm/msvc/testanalog/</li>
<li><a href="#freeswitchtrunklibsfreetdmmsvctestanalogtestanalog2005vcproj">freeswitch/trunk/libs/freetdm/msvc/testanalog/testanalog.2005.vcproj</a></li>
<li><a href="#freeswitchtrunklibsfreetdmmsvctestanalogtestanalog2008vcproj">freeswitch/trunk/libs/freetdm/msvc/testanalog/testanalog.2008.vcproj</a></li>
<li>freeswitch/trunk/libs/freetdm/msvc/testboost/</li>
<li><a href="#freeswitchtrunklibsfreetdmmsvctestboosttestboost2008vcproj">freeswitch/trunk/libs/freetdm/msvc/testboost/testboost.2008.vcproj</a></li>
<li><a href="#freeswitchtrunklibsfreetdmmsvctestboosttestsangomaboost2008vcproj">freeswitch/trunk/libs/freetdm/msvc/testboost/testsangomaboost.2008.vcproj</a></li>
<li>freeswitch/trunk/libs/freetdm/msvc/testisdn/</li>
<li><a href="#freeswitchtrunklibsfreetdmmsvctestisdntestisdn2005vcproj">freeswitch/trunk/libs/freetdm/msvc/testisdn/testisdn.2005.vcproj</a></li>
<li><a href="#freeswitchtrunklibsfreetdmmsvctestisdntestisdn2008vcproj">freeswitch/trunk/libs/freetdm/msvc/testisdn/testisdn.2008.vcproj</a></li>
<li><a href="#freeswitchtrunklibsfreetdmopenzap2005sln">freeswitch/trunk/libs/freetdm/openzap.2005.sln</a></li>
<li><a href="#freeswitchtrunklibsfreetdmozrenamesh">freeswitch/trunk/libs/freetdm/ozrename.sh</a></li>
<li><a href="#freeswitchtrunklibsfreetdmozreplacesh">freeswitch/trunk/libs/freetdm/ozreplace.sh</a></li>
<li>freeswitch/trunk/libs/freetdm/patches/</li>
<li><a href="#freeswitchtrunklibsfreetdmpatchesozdiff">freeswitch/trunk/libs/freetdm/patches/oz.diff</a></li>
<li>freeswitch/trunk/libs/freetdm/src/</li>
<li><a href="#freeswitchtrunklibsfreetdmsrcdetect_dtmfc">freeswitch/trunk/libs/freetdm/src/detect_dtmf.c</a></li>
<li><a href="#freeswitchtrunklibsfreetdmsrcdetect_tonesc">freeswitch/trunk/libs/freetdm/src/detect_tones.c</a></li>
<li><a href="#freeswitchtrunklibsfreetdmsrcfskc">freeswitch/trunk/libs/freetdm/src/fsk.c</a></li>
<li><a href="#freeswitchtrunklibsfreetdmsrcftdm_bufferc">freeswitch/trunk/libs/freetdm/src/ftdm_buffer.c</a></li>
<li><a href="#freeswitchtrunklibsfreetdmsrcftdm_calleridc">freeswitch/trunk/libs/freetdm/src/ftdm_callerid.c</a></li>
<li><a href="#freeswitchtrunklibsfreetdmsrcftdm_configc">freeswitch/trunk/libs/freetdm/src/ftdm_config.c</a></li>
<li><a href="#freeswitchtrunklibsfreetdmsrcftdm_dsoc">freeswitch/trunk/libs/freetdm/src/ftdm_dso.c</a></li>
<li><a href="#freeswitchtrunklibsfreetdmsrcftdm_ioc">freeswitch/trunk/libs/freetdm/src/ftdm_io.c</a></li>
<li><a href="#freeswitchtrunklibsfreetdmsrcftdm_m3uac">freeswitch/trunk/libs/freetdm/src/ftdm_m3ua.c</a></li>
<li><a href="#freeswitchtrunklibsfreetdmsrcftdm_queuec">freeswitch/trunk/libs/freetdm/src/ftdm_queue.c</a></li>
<li><a href="#freeswitchtrunklibsfreetdmsrcftdm_threadmutexc">freeswitch/trunk/libs/freetdm/src/ftdm_threadmutex.c</a></li>
<li>freeswitch/trunk/libs/freetdm/src/ftmod/</li>
<li>freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_analog/</li>
<li><a href="#freeswitchtrunklibsfreetdmsrcftmodftmod_analogftdm_analogh">freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_analog/ftdm_analog.h</a></li>
<li><a href="#freeswitchtrunklibsfreetdmsrcftmodftmod_analogftmod_analog2008vcproj">freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_analog/ftmod_analog.2008.vcproj</a></li>
<li><a href="#freeswitchtrunklibsfreetdmsrcftmodftmod_analogftmod_analogc">freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_analog/ftmod_analog.c</a></li>
<li><a href="#freeswitchtrunklibsfreetdmsrcftmodftmod_analogozmod_analog2005vcproj">freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_analog/ozmod_analog.2005.vcproj</a></li>
<li>freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_analog_em/</li>
<li><a href="#freeswitchtrunklibsfreetdmsrcftmodftmod_analog_emftdm_analog_emh">freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_analog_em/ftdm_analog_em.h</a></li>
<li><a href="#freeswitchtrunklibsfreetdmsrcftmodftmod_analog_emftmod_analog_em2008vcproj">freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_analog_em/ftmod_analog_em.2008.vcproj</a></li>
<li><a href="#freeswitchtrunklibsfreetdmsrcftmodftmod_analog_emftmod_analog_emc">freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_analog_em/ftmod_analog_em.c</a></li>
<li><a href="#freeswitchtrunklibsfreetdmsrcftmodftmod_analog_emozmod_analog_em2005vcproj">freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_analog_em/ozmod_analog_em.2005.vcproj</a></li>
<li>freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_isdn/</li>
<li><a href="#freeswitchtrunklibsfreetdmsrcftmodftmod_isdnftdm_isdnh">freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_isdn/ftdm_isdn.h</a></li>
<li><a href="#freeswitchtrunklibsfreetdmsrcftmodftmod_isdnftmod_isdn2008vcproj">freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_isdn/ftmod_isdn.2008.vcproj</a></li>
<li><a href="#freeswitchtrunklibsfreetdmsrcftmodftmod_isdnftmod_isdnc">freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_isdn/ftmod_isdn.c</a></li>
<li><a href="#freeswitchtrunklibsfreetdmsrcftmodftmod_isdnozmod_isdn2005vcproj">freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_isdn/ozmod_isdn.2005.vcproj</a></li>
<li>freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_libpri/</li>
<li><a href="#freeswitchtrunklibsfreetdmsrcftmodftmod_libpriftmod_libpric">freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_libpri/ftmod_libpri.c</a></li>
<li><a href="#freeswitchtrunklibsfreetdmsrcftmodftmod_libpriftmod_libprih">freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_libpri/ftmod_libpri.h</a></li>
<li><a href="#freeswitchtrunklibsfreetdmsrcftmodftmod_libprilpwrap_pric">freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_libpri/lpwrap_pri.c</a></li>
<li><a href="#freeswitchtrunklibsfreetdmsrcftmodftmod_libprilpwrap_prih">freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_libpri/lpwrap_pri.h</a></li>
<li>freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_pika/</li>
<li><a href="#freeswitchtrunklibsfreetdmsrcftmodftmod_pikaftdm_pikah">freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_pika/ftdm_pika.h</a></li>
<li><a href="#freeswitchtrunklibsfreetdmsrcftmodftmod_pikaftmod_pika2008vcproj">freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_pika/ftmod_pika.2008.vcproj</a></li>
<li><a href="#freeswitchtrunklibsfreetdmsrcftmodftmod_pikaftmod_pikac">freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_pika/ftmod_pika.c</a></li>
<li><a href="#freeswitchtrunklibsfreetdmsrcftmodftmod_pikaozmod_pika2005vcproj">freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_pika/ozmod_pika.2005.vcproj</a></li>
<li>freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_r2/</li>
<li><a href="#freeswitchtrunklibsfreetdmsrcftmodftmod_r2ftmod_r2c">freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c</a></li>
<li>freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_sangoma_boost/</li>
<li><a href="#freeswitchtrunklibsfreetdmsrcftmodftmod_sangoma_boostBOOSTlimitations">freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_sangoma_boost/BOOST.limitations</a></li>
<li><a href="#freeswitchtrunklibsfreetdmsrcftmodftmod_sangoma_boostboosttaskstxt">freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_sangoma_boost/boost-tasks.txt</a></li>
<li><a href="#freeswitchtrunklibsfreetdmsrcftmodftmod_sangoma_boostftdm_sangoma_boosth">freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_sangoma_boost/ftdm_sangoma_boost.h</a></li>
<li><a href="#freeswitchtrunklibsfreetdmsrcftmodftmod_sangoma_boostftmod_sangoma_boost2008vcproj">freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_sangoma_boost/ftmod_sangoma_boost.2008.vcproj</a></li>
<li><a href="#freeswitchtrunklibsfreetdmsrcftmodftmod_sangoma_boostftmod_sangoma_boostc">freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_sangoma_boost/ftmod_sangoma_boost.c</a></li>
<li><a href="#freeswitchtrunklibsfreetdmsrcftmodftmod_sangoma_boostsangoma_boost_clientc">freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_sangoma_boost/sangoma_boost_client.c</a></li>
<li><a href="#freeswitchtrunklibsfreetdmsrcftmodftmod_sangoma_boostsangoma_boost_clienth">freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_sangoma_boost/sangoma_boost_client.h</a></li>
<li><a href="#freeswitchtrunklibsfreetdmsrcftmodftmod_sangoma_boostsangoma_boost_interfaceh">freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_sangoma_boost/sangoma_boost_interface.h</a></li>
<li><a href="#freeswitchtrunklibsfreetdmsrcftmodftmod_sangoma_boostsigboosth">freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_sangoma_boost/sigboost.h</a></li>
<li>freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_skel/</li>
<li><a href="#freeswitchtrunklibsfreetdmsrcftmodftmod_skelftmod_skelc">freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_skel/ftmod_skel.c</a></li>
<li>freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_wanpipe/</li>
<li><a href="#freeswitchtrunklibsfreetdmsrcftmodftmod_wanpipeftmod_wanpipe2008vcproj">freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.2008.vcproj</a></li>
<li><a href="#freeswitchtrunklibsfreetdmsrcftmodftmod_wanpipeftmod_wanpipec">freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c</a></li>
<li><a href="#freeswitchtrunklibsfreetdmsrcftmodftmod_wanpipeozmod_wanpipe2005vcproj">freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_wanpipe/ozmod_wanpipe.2005.vcproj</a></li>
<li><a href="#freeswitchtrunklibsfreetdmsrcftmodftmod_wanpipewanpipe_tdm_api_ifaceh">freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_wanpipe/wanpipe_tdm_api_iface.h</a></li>
<li>freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_zt/</li>
<li><a href="#freeswitchtrunklibsfreetdmsrcftmodftmod_ztftmod_ztc">freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_zt/ftmod_zt.c</a></li>
<li><a href="#freeswitchtrunklibsfreetdmsrcftmodftmod_ztftmod_zth">freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_zt/ftmod_zt.h</a></li>
<li><a href="#freeswitchtrunklibsfreetdmsrcg711c">freeswitch/trunk/libs/freetdm/src/g711.c</a></li>
<li><a href="#freeswitchtrunklibsfreetdmsrchashtablec">freeswitch/trunk/libs/freetdm/src/hashtable.c</a></li>
<li><a href="#freeswitchtrunklibsfreetdmsrchashtable_itrc">freeswitch/trunk/libs/freetdm/src/hashtable_itr.c</a></li>
<li>freeswitch/trunk/libs/freetdm/src/include/</li>
<li><a href="#freeswitchtrunklibsfreetdmsrcincludefreetdmh">freeswitch/trunk/libs/freetdm/src/include/freetdm.h</a></li>
<li><a href="#freeswitchtrunklibsfreetdmsrcincludefskh">freeswitch/trunk/libs/freetdm/src/include/fsk.h</a></li>
<li><a href="#freeswitchtrunklibsfreetdmsrcincludeftdm_bufferh">freeswitch/trunk/libs/freetdm/src/include/ftdm_buffer.h</a></li>
<li><a href="#freeswitchtrunklibsfreetdmsrcincludeftdm_configh">freeswitch/trunk/libs/freetdm/src/include/ftdm_config.h</a></li>
<li><a href="#freeswitchtrunklibsfreetdmsrcincludeftdm_dsoh">freeswitch/trunk/libs/freetdm/src/include/ftdm_dso.h</a></li>
<li><a href="#freeswitchtrunklibsfreetdmsrcincludeftdm_m3uah">freeswitch/trunk/libs/freetdm/src/include/ftdm_m3ua.h</a></li>
<li><a href="#freeswitchtrunklibsfreetdmsrcincludeftdm_threadmutexh">freeswitch/trunk/libs/freetdm/src/include/ftdm_threadmutex.h</a></li>
<li><a href="#freeswitchtrunklibsfreetdmsrcincludeftdm_typesh">freeswitch/trunk/libs/freetdm/src/include/ftdm_types.h</a></li>
<li><a href="#freeswitchtrunklibsfreetdmsrcincludeg711h">freeswitch/trunk/libs/freetdm/src/include/g711.h</a></li>
<li><a href="#freeswitchtrunklibsfreetdmsrcincludehashtableh">freeswitch/trunk/libs/freetdm/src/include/hashtable.h</a></li>
<li><a href="#freeswitchtrunklibsfreetdmsrcincludehashtable_itrh">freeswitch/trunk/libs/freetdm/src/include/hashtable_itr.h</a></li>
<li><a href="#freeswitchtrunklibsfreetdmsrcincludehashtable_privateh">freeswitch/trunk/libs/freetdm/src/include/hashtable_private.h</a></li>
<li><a href="#freeswitchtrunklibsfreetdmsrcincludelibteletoneh">freeswitch/trunk/libs/freetdm/src/include/libteletone.h</a></li>
<li><a href="#freeswitchtrunklibsfreetdmsrcincludelibteletone_detecth">freeswitch/trunk/libs/freetdm/src/include/libteletone_detect.h</a></li>
<li><a href="#freeswitchtrunklibsfreetdmsrcincludelibteletone_generateh">freeswitch/trunk/libs/freetdm/src/include/libteletone_generate.h</a></li>
<li><a href="#freeswitchtrunklibsfreetdmsrcincludesangoma_tdm_apih">freeswitch/trunk/libs/freetdm/src/include/sangoma_tdm_api.h</a></li>
<li><a href="#freeswitchtrunklibsfreetdmsrcincludeuarth">freeswitch/trunk/libs/freetdm/src/include/uart.h</a></li>
<li>freeswitch/trunk/libs/freetdm/src/isdn/</li>
<li><a href="#freeswitchtrunklibsfreetdmsrcisdn5ESSStateNTc">freeswitch/trunk/libs/freetdm/src/isdn/5ESSStateNT.c</a></li>
<li><a href="#freeswitchtrunklibsfreetdmsrcisdn5ESSStateTEc">freeswitch/trunk/libs/freetdm/src/isdn/5ESSStateTE.c</a></li>
<li><a href="#freeswitchtrunklibsfreetdmsrcisdn5ESSmesc">freeswitch/trunk/libs/freetdm/src/isdn/5ESSmes.c</a></li>
<li><a href="#freeswitchtrunklibsfreetdmsrcisdnDMSStateNTc">freeswitch/trunk/libs/freetdm/src/isdn/DMSStateNT.c</a></li>
<li><a href="#freeswitchtrunklibsfreetdmsrcisdnDMSStateTEc">freeswitch/trunk/libs/freetdm/src/isdn/DMSStateTE.c</a></li>
<li><a href="#freeswitchtrunklibsfreetdmsrcisdnDMSmesc">freeswitch/trunk/libs/freetdm/src/isdn/DMSmes.c</a></li>
<li><a href="#freeswitchtrunklibsfreetdmsrcisdnEuroISDNStateNTc">freeswitch/trunk/libs/freetdm/src/isdn/EuroISDNStateNT.c</a></li>
<li><a href="#freeswitchtrunklibsfreetdmsrcisdnEuroISDNStateTEc">freeswitch/trunk/libs/freetdm/src/isdn/EuroISDNStateTE.c</a></li>
<li><a href="#freeswitchtrunklibsfreetdmsrcisdnQ921c">freeswitch/trunk/libs/freetdm/src/isdn/Q921.c</a></li>
<li><a href="#freeswitchtrunklibsfreetdmsrcisdnQ931c">freeswitch/trunk/libs/freetdm/src/isdn/Q931.c</a></li>
<li><a href="#freeswitchtrunklibsfreetdmsrcisdnQ931StateNTc">freeswitch/trunk/libs/freetdm/src/isdn/Q931StateNT.c</a></li>
<li><a href="#freeswitchtrunklibsfreetdmsrcisdnQ931StateTEc">freeswitch/trunk/libs/freetdm/src/isdn/Q931StateTE.c</a></li>
<li><a href="#freeswitchtrunklibsfreetdmsrcisdnQ931apic">freeswitch/trunk/libs/freetdm/src/isdn/Q931api.c</a></li>
<li><a href="#freeswitchtrunklibsfreetdmsrcisdnQ931iec">freeswitch/trunk/libs/freetdm/src/isdn/Q931ie.c</a></li>
<li><a href="#freeswitchtrunklibsfreetdmsrcisdnQ931mesc">freeswitch/trunk/libs/freetdm/src/isdn/Q931mes.c</a></li>
<li><a href="#freeswitchtrunklibsfreetdmsrcisdnQ932mesc">freeswitch/trunk/libs/freetdm/src/isdn/Q932mes.c</a></li>
<li>freeswitch/trunk/libs/freetdm/src/isdn/include/</li>
<li><a href="#freeswitchtrunklibsfreetdmsrcisdninclude5ESSh">freeswitch/trunk/libs/freetdm/src/isdn/include/5ESS.h</a></li>
<li><a href="#freeswitchtrunklibsfreetdmsrcisdnincludeDMSh">freeswitch/trunk/libs/freetdm/src/isdn/include/DMS.h</a></li>
<li><a href="#freeswitchtrunklibsfreetdmsrcisdnincludeQ921h">freeswitch/trunk/libs/freetdm/src/isdn/include/Q921.h</a></li>
<li><a href="#freeswitchtrunklibsfreetdmsrcisdnincludeQ921privh">freeswitch/trunk/libs/freetdm/src/isdn/include/Q921priv.h</a></li>
<li><a href="#freeswitchtrunklibsfreetdmsrcisdnincludeQ931h">freeswitch/trunk/libs/freetdm/src/isdn/include/Q931.h</a></li>
<li><a href="#freeswitchtrunklibsfreetdmsrcisdnincludeQ931ieh">freeswitch/trunk/libs/freetdm/src/isdn/include/Q931ie.h</a></li>
<li><a href="#freeswitchtrunklibsfreetdmsrcisdnincludeQ932h">freeswitch/trunk/libs/freetdm/src/isdn/include/Q932.h</a></li>
<li><a href="#freeswitchtrunklibsfreetdmsrcisdnincludemfifoh">freeswitch/trunk/libs/freetdm/src/isdn/include/mfifo.h</a></li>
<li><a href="#freeswitchtrunklibsfreetdmsrcisdnincludenationalh">freeswitch/trunk/libs/freetdm/src/isdn/include/national.h</a></li>
<li><a href="#freeswitchtrunklibsfreetdmsrcisdnmfifoc">freeswitch/trunk/libs/freetdm/src/isdn/mfifo.c</a></li>
<li><a href="#freeswitchtrunklibsfreetdmsrcisdnnationalStateNTc">freeswitch/trunk/libs/freetdm/src/isdn/nationalStateNT.c</a></li>
<li><a href="#freeswitchtrunklibsfreetdmsrcisdnnationalStateTEc">freeswitch/trunk/libs/freetdm/src/isdn/nationalStateTE.c</a></li>
<li><a href="#freeswitchtrunklibsfreetdmsrcisdnnationalmesc">freeswitch/trunk/libs/freetdm/src/isdn/nationalmes.c</a></li>
<li><a href="#freeswitchtrunklibsfreetdmsrclibteletone_detectc">freeswitch/trunk/libs/freetdm/src/libteletone_detect.c</a></li>
<li><a href="#freeswitchtrunklibsfreetdmsrclibteletone_generatec">freeswitch/trunk/libs/freetdm/src/libteletone_generate.c</a></li>
<li>freeswitch/trunk/libs/freetdm/src/m3ua/</li>
<li><a href="#freeswitchtrunklibsfreetdmsrcm3uamstm3uac">freeswitch/trunk/libs/freetdm/src/m3ua/mstm3ua.c</a></li>
<li><a href="#freeswitchtrunklibsfreetdmsrcm3uamstm3uah">freeswitch/trunk/libs/freetdm/src/m3ua/mstm3ua.h</a></li>
<li><a href="#freeswitchtrunklibsfreetdmsrcm3ua_clientc">freeswitch/trunk/libs/freetdm/src/m3ua_client.c</a></li>
<li><a href="#freeswitchtrunklibsfreetdmsrcm3ua_clienth">freeswitch/trunk/libs/freetdm/src/m3ua_client.h</a></li>
<li><a href="#freeswitchtrunklibsfreetdmsrcpriserverc">freeswitch/trunk/libs/freetdm/src/priserver.c</a></li>
<li><a href="#freeswitchtrunklibsfreetdmsrcsangoma_pric">freeswitch/trunk/libs/freetdm/src/sangoma_pri.c</a></li>
<li><a href="#freeswitchtrunklibsfreetdmsrcsangoma_prih">freeswitch/trunk/libs/freetdm/src/sangoma_pri.h</a></li>
<li>freeswitch/trunk/libs/freetdm/src/ss7/</li>
<li><a href="#freeswitchtrunklibsfreetdmsrcss7README">freeswitch/trunk/libs/freetdm/src/ss7/README</a></li>
<li><a href="#freeswitchtrunklibsfreetdmsrctestanalogc">freeswitch/trunk/libs/freetdm/src/testanalog.c</a></li>
<li><a href="#freeswitchtrunklibsfreetdmsrctestappc">freeswitch/trunk/libs/freetdm/src/testapp.c</a></li>
<li><a href="#freeswitchtrunklibsfreetdmsrctestboostc">freeswitch/trunk/libs/freetdm/src/testboost.c</a></li>
<li><a href="#freeswitchtrunklibsfreetdmsrctestcidc">freeswitch/trunk/libs/freetdm/src/testcid.c</a></li>
<li><a href="#freeswitchtrunklibsfreetdmsrctestisdnc">freeswitch/trunk/libs/freetdm/src/testisdn.c</a></li>
<li><a href="#freeswitchtrunklibsfreetdmsrctestm3uac">freeswitch/trunk/libs/freetdm/src/testm3ua.c</a></li>
<li><a href="#freeswitchtrunklibsfreetdmsrctestpric">freeswitch/trunk/libs/freetdm/src/testpri.c</a></li>
<li><a href="#freeswitchtrunklibsfreetdmsrctestr2c">freeswitch/trunk/libs/freetdm/src/testr2.c</a></li>
<li><a href="#freeswitchtrunklibsfreetdmsrctestsangomaboostc">freeswitch/trunk/libs/freetdm/src/testsangomaboost.c</a></li>
<li><a href="#freeswitchtrunklibsfreetdmsrctesttonesc">freeswitch/trunk/libs/freetdm/src/testtones.c</a></li>
<li><a href="#freeswitchtrunklibsfreetdmsrcuartc">freeswitch/trunk/libs/freetdm/src/uart.c</a></li>
<li>freeswitch/trunk/libs/openzap/</li>
<li><a href="#freeswitchtrunklibsopenzapgitignore">freeswitch/trunk/libs/openzap/.gitignore</a></li>
<li><a href="#freeswitchtrunklibsopenzapupdate">freeswitch/trunk/libs/openzap/.update</a></li>
<li><a href="#freeswitchtrunklibsopenzapAUTHORS">freeswitch/trunk/libs/openzap/AUTHORS</a></li>
<li><a href="#freeswitchtrunklibsopenzapChangeLog">freeswitch/trunk/libs/openzap/ChangeLog</a></li>
<li><a href="#freeswitchtrunklibsopenzapMakefileam">freeswitch/trunk/libs/openzap/Makefile.am</a></li>
<li><a href="#freeswitchtrunklibsopenzapNEWS">freeswitch/trunk/libs/openzap/NEWS</a></li>
<li><a href="#freeswitchtrunklibsopenzapREADME">freeswitch/trunk/libs/openzap/README</a></li>
<li><a href="#freeswitchtrunklibsopenzapacincludem4">freeswitch/trunk/libs/openzap/acinclude.m4</a></li>
<li><a href="#freeswitchtrunklibsopenzapbootstrap">freeswitch/trunk/libs/openzap/bootstrap</a></li>
<li>freeswitch/trunk/libs/openzap/build/</li>
<li><a href="#freeswitchtrunklibsopenzapbuildlibpcapm4">freeswitch/trunk/libs/openzap/build/libpcap.m4</a></li>
<li>freeswitch/trunk/libs/openzap/conf/</li>
<li><a href="#freeswitchtrunklibsopenzapconfm3uaconf">freeswitch/trunk/libs/openzap/conf/m3ua.conf</a></li>
<li><a href="#freeswitchtrunklibsopenzapconfopenzapconf">freeswitch/trunk/libs/openzap/conf/openzap.conf</a></li>
<li><a href="#freeswitchtrunklibsopenzapconfopenzapconfxml">freeswitch/trunk/libs/openzap/conf/openzap.conf.xml</a></li>
<li><a href="#freeswitchtrunklibsopenzapconfpikaconf">freeswitch/trunk/libs/openzap/conf/pika.conf</a></li>
<li><a href="#freeswitchtrunklibsopenzapconftonesconf">freeswitch/trunk/libs/openzap/conf/tones.conf</a></li>
<li><a href="#freeswitchtrunklibsopenzapconfwanpipeconf">freeswitch/trunk/libs/openzap/conf/wanpipe.conf</a></li>
<li><a href="#freeswitchtrunklibsopenzapconfztconf">freeswitch/trunk/libs/openzap/conf/zt.conf</a></li>
<li><a href="#freeswitchtrunklibsopenzapconfigureac">freeswitch/trunk/libs/openzap/configure.ac</a></li>
<li><a href="#freeswitchtrunklibsopenzapconfiguregnu">freeswitch/trunk/libs/openzap/configure.gnu</a></li>
<li>freeswitch/trunk/libs/openzap/docs/</li>
<li><a href="#freeswitchtrunklibsopenzapdocsDoxygenconf">freeswitch/trunk/libs/openzap/docs/Doxygen.conf</a></li>
<li>freeswitch/trunk/libs/openzap/mod_openzap/</li>
<li><a href="#freeswitchtrunklibsopenzapmod_openzapMakefilein">freeswitch/trunk/libs/openzap/mod_openzap/Makefile.in</a></li>
<li><a href="#freeswitchtrunklibsopenzapmod_openzapmod_openzap2005vcproj">freeswitch/trunk/libs/openzap/mod_openzap/mod_openzap.2005.vcproj</a></li>
<li><a href="#freeswitchtrunklibsopenzapmod_openzapmod_openzap2008vcproj">freeswitch/trunk/libs/openzap/mod_openzap/mod_openzap.2008.vcproj</a></li>
<li><a href="#freeswitchtrunklibsopenzapmod_openzapmod_openzapc">freeswitch/trunk/libs/openzap/mod_openzap/mod_openzap.c</a></li>
<li>freeswitch/trunk/libs/openzap/msvc/</li>
<li><a href="#freeswitchtrunklibsopenzapmsvcopenzap2005vcproj">freeswitch/trunk/libs/openzap/msvc/openzap.2005.vcproj</a></li>
<li><a href="#freeswitchtrunklibsopenzapmsvcopenzap2008vcproj">freeswitch/trunk/libs/openzap/msvc/openzap.2008.vcproj</a></li>
<li>freeswitch/trunk/libs/openzap/msvc/testanalog/</li>
<li><a href="#freeswitchtrunklibsopenzapmsvctestanalogtestanalog2005vcproj">freeswitch/trunk/libs/openzap/msvc/testanalog/testanalog.2005.vcproj</a></li>
<li><a href="#freeswitchtrunklibsopenzapmsvctestanalogtestanalog2008vcproj">freeswitch/trunk/libs/openzap/msvc/testanalog/testanalog.2008.vcproj</a></li>
<li>freeswitch/trunk/libs/openzap/msvc/testisdn/</li>
<li><a href="#freeswitchtrunklibsopenzapmsvctestisdntestisdn2005vcproj">freeswitch/trunk/libs/openzap/msvc/testisdn/testisdn.2005.vcproj</a></li>
<li><a href="#freeswitchtrunklibsopenzapmsvctestisdntestisdn2008vcproj">freeswitch/trunk/libs/openzap/msvc/testisdn/testisdn.2008.vcproj</a></li>
<li><a href="#freeswitchtrunklibsopenzapopenzap2005sln">freeswitch/trunk/libs/openzap/openzap.2005.sln</a></li>
<li><a href="#freeswitchtrunklibsopenzapopenzap2008sln">freeswitch/trunk/libs/openzap/openzap.2008.sln</a></li>
<li><a href="#freeswitchtrunklibsopenzapopenzappcin">freeswitch/trunk/libs/openzap/openzap.pc.in</a></li>
<li>freeswitch/trunk/libs/openzap/patches/</li>
<li><a href="#freeswitchtrunklibsopenzappatchesozdiff">freeswitch/trunk/libs/openzap/patches/oz.diff</a></li>
<li>freeswitch/trunk/libs/openzap/src/</li>
<li><a href="#freeswitchtrunklibsopenzapsrcdetect_dtmfc">freeswitch/trunk/libs/openzap/src/detect_dtmf.c</a></li>
<li><a href="#freeswitchtrunklibsopenzapsrcdetect_tonesc">freeswitch/trunk/libs/openzap/src/detect_tones.c</a></li>
<li><a href="#freeswitchtrunklibsopenzapsrcfskc">freeswitch/trunk/libs/openzap/src/fsk.c</a></li>
<li><a href="#freeswitchtrunklibsopenzapsrcg711c">freeswitch/trunk/libs/openzap/src/g711.c</a></li>
<li><a href="#freeswitchtrunklibsopenzapsrchashtablec">freeswitch/trunk/libs/openzap/src/hashtable.c</a></li>
<li><a href="#freeswitchtrunklibsopenzapsrchashtable_itrc">freeswitch/trunk/libs/openzap/src/hashtable_itr.c</a></li>
<li>freeswitch/trunk/libs/openzap/src/include/</li>
<li><a href="#freeswitchtrunklibsopenzapsrcincludefskh">freeswitch/trunk/libs/openzap/src/include/fsk.h</a></li>
<li><a href="#freeswitchtrunklibsopenzapsrcincludeg711h">freeswitch/trunk/libs/openzap/src/include/g711.h</a></li>
<li><a href="#freeswitchtrunklibsopenzapsrcincludehashtableh">freeswitch/trunk/libs/openzap/src/include/hashtable.h</a></li>
<li><a href="#freeswitchtrunklibsopenzapsrcincludehashtable_itrh">freeswitch/trunk/libs/openzap/src/include/hashtable_itr.h</a></li>
<li><a href="#freeswitchtrunklibsopenzapsrcincludehashtable_privateh">freeswitch/trunk/libs/openzap/src/include/hashtable_private.h</a></li>
<li><a href="#freeswitchtrunklibsopenzapsrcincludelibteletoneh">freeswitch/trunk/libs/openzap/src/include/libteletone.h</a></li>
<li><a href="#freeswitchtrunklibsopenzapsrcincludelibteletone_detecth">freeswitch/trunk/libs/openzap/src/include/libteletone_detect.h</a></li>
<li><a href="#freeswitchtrunklibsopenzapsrcincludelibteletone_generateh">freeswitch/trunk/libs/openzap/src/include/libteletone_generate.h</a></li>
<li><a href="#freeswitchtrunklibsopenzapsrcincludeopenzaph">freeswitch/trunk/libs/openzap/src/include/openzap.h</a></li>
<li><a href="#freeswitchtrunklibsopenzapsrcincludesangoma_tdm_apih">freeswitch/trunk/libs/openzap/src/include/sangoma_tdm_api.h</a></li>
<li><a href="#freeswitchtrunklibsopenzapsrcincludeuarth">freeswitch/trunk/libs/openzap/src/include/uart.h</a></li>
<li><a href="#freeswitchtrunklibsopenzapsrcincludezap_bufferh">freeswitch/trunk/libs/openzap/src/include/zap_buffer.h</a></li>
<li><a href="#freeswitchtrunklibsopenzapsrcincludezap_configh">freeswitch/trunk/libs/openzap/src/include/zap_config.h</a></li>
<li><a href="#freeswitchtrunklibsopenzapsrcincludezap_cpu_monitorh">freeswitch/trunk/libs/openzap/src/include/zap_cpu_monitor.h</a></li>
<li><a href="#freeswitchtrunklibsopenzapsrcincludezap_dsoh">freeswitch/trunk/libs/openzap/src/include/zap_dso.h</a></li>
<li><a href="#freeswitchtrunklibsopenzapsrcincludezap_m3uah">freeswitch/trunk/libs/openzap/src/include/zap_m3ua.h</a></li>
<li><a href="#freeswitchtrunklibsopenzapsrcincludezap_threadmutexh">freeswitch/trunk/libs/openzap/src/include/zap_threadmutex.h</a></li>
<li><a href="#freeswitchtrunklibsopenzapsrcincludezap_typesh">freeswitch/trunk/libs/openzap/src/include/zap_types.h</a></li>
<li>freeswitch/trunk/libs/openzap/src/isdn/</li>
<li><a href="#freeswitchtrunklibsopenzapsrcisdn5ESSStateNTc">freeswitch/trunk/libs/openzap/src/isdn/5ESSStateNT.c</a></li>
<li><a href="#freeswitchtrunklibsopenzapsrcisdn5ESSStateTEc">freeswitch/trunk/libs/openzap/src/isdn/5ESSStateTE.c</a></li>
<li><a href="#freeswitchtrunklibsopenzapsrcisdn5ESSmesc">freeswitch/trunk/libs/openzap/src/isdn/5ESSmes.c</a></li>
<li><a href="#freeswitchtrunklibsopenzapsrcisdnDMSStateNTc">freeswitch/trunk/libs/openzap/src/isdn/DMSStateNT.c</a></li>
<li><a href="#freeswitchtrunklibsopenzapsrcisdnDMSStateTEc">freeswitch/trunk/libs/openzap/src/isdn/DMSStateTE.c</a></li>
<li><a href="#freeswitchtrunklibsopenzapsrcisdnDMSmesc">freeswitch/trunk/libs/openzap/src/isdn/DMSmes.c</a></li>
<li><a href="#freeswitchtrunklibsopenzapsrcisdnEuroISDNStateNTc">freeswitch/trunk/libs/openzap/src/isdn/EuroISDNStateNT.c</a></li>
<li><a href="#freeswitchtrunklibsopenzapsrcisdnEuroISDNStateTEc">freeswitch/trunk/libs/openzap/src/isdn/EuroISDNStateTE.c</a></li>
<li><a href="#freeswitchtrunklibsopenzapsrcisdnQ921c">freeswitch/trunk/libs/openzap/src/isdn/Q921.c</a></li>
<li><a href="#freeswitchtrunklibsopenzapsrcisdnQ931c">freeswitch/trunk/libs/openzap/src/isdn/Q931.c</a></li>
<li><a href="#freeswitchtrunklibsopenzapsrcisdnQ931StateNTc">freeswitch/trunk/libs/openzap/src/isdn/Q931StateNT.c</a></li>
<li><a href="#freeswitchtrunklibsopenzapsrcisdnQ931StateTEc">freeswitch/trunk/libs/openzap/src/isdn/Q931StateTE.c</a></li>
<li><a href="#freeswitchtrunklibsopenzapsrcisdnQ931apic">freeswitch/trunk/libs/openzap/src/isdn/Q931api.c</a></li>
<li><a href="#freeswitchtrunklibsopenzapsrcisdnQ931iec">freeswitch/trunk/libs/openzap/src/isdn/Q931ie.c</a></li>
<li><a href="#freeswitchtrunklibsopenzapsrcisdnQ931mesc">freeswitch/trunk/libs/openzap/src/isdn/Q931mes.c</a></li>
<li><a href="#freeswitchtrunklibsopenzapsrcisdnQ932mesc">freeswitch/trunk/libs/openzap/src/isdn/Q932mes.c</a></li>
<li>freeswitch/trunk/libs/openzap/src/isdn/include/</li>
<li><a href="#freeswitchtrunklibsopenzapsrcisdninclude5ESSh">freeswitch/trunk/libs/openzap/src/isdn/include/5ESS.h</a></li>
<li><a href="#freeswitchtrunklibsopenzapsrcisdnincludeDMSh">freeswitch/trunk/libs/openzap/src/isdn/include/DMS.h</a></li>
<li><a href="#freeswitchtrunklibsopenzapsrcisdnincludeQ921h">freeswitch/trunk/libs/openzap/src/isdn/include/Q921.h</a></li>
<li><a href="#freeswitchtrunklibsopenzapsrcisdnincludeQ921privh">freeswitch/trunk/libs/openzap/src/isdn/include/Q921priv.h</a></li>
<li><a href="#freeswitchtrunklibsopenzapsrcisdnincludeQ931h">freeswitch/trunk/libs/openzap/src/isdn/include/Q931.h</a></li>
<li><a href="#freeswitchtrunklibsopenzapsrcisdnincludeQ931ieh">freeswitch/trunk/libs/openzap/src/isdn/include/Q931ie.h</a></li>
<li><a href="#freeswitchtrunklibsopenzapsrcisdnincludeQ932h">freeswitch/trunk/libs/openzap/src/isdn/include/Q932.h</a></li>
<li><a href="#freeswitchtrunklibsopenzapsrcisdnincludemfifoh">freeswitch/trunk/libs/openzap/src/isdn/include/mfifo.h</a></li>
<li><a href="#freeswitchtrunklibsopenzapsrcisdnincludenationalh">freeswitch/trunk/libs/openzap/src/isdn/include/national.h</a></li>
<li><a href="#freeswitchtrunklibsopenzapsrcisdnmfifoc">freeswitch/trunk/libs/openzap/src/isdn/mfifo.c</a></li>
<li><a href="#freeswitchtrunklibsopenzapsrcisdnnationalStateNTc">freeswitch/trunk/libs/openzap/src/isdn/nationalStateNT.c</a></li>
<li><a href="#freeswitchtrunklibsopenzapsrcisdnnationalStateTEc">freeswitch/trunk/libs/openzap/src/isdn/nationalStateTE.c</a></li>
<li><a href="#freeswitchtrunklibsopenzapsrcisdnnationalmesc">freeswitch/trunk/libs/openzap/src/isdn/nationalmes.c</a></li>
<li><a href="#freeswitchtrunklibsopenzapsrclibteletone_detectc">freeswitch/trunk/libs/openzap/src/libteletone_detect.c</a></li>
<li><a href="#freeswitchtrunklibsopenzapsrclibteletone_generatec">freeswitch/trunk/libs/openzap/src/libteletone_generate.c</a></li>
<li>freeswitch/trunk/libs/openzap/src/m3ua/</li>
<li><a href="#freeswitchtrunklibsopenzapsrcm3uamstm3uac">freeswitch/trunk/libs/openzap/src/m3ua/mstm3ua.c</a></li>
<li><a href="#freeswitchtrunklibsopenzapsrcm3uamstm3uah">freeswitch/trunk/libs/openzap/src/m3ua/mstm3ua.h</a></li>
<li><a href="#freeswitchtrunklibsopenzapsrcm3ua_clientc">freeswitch/trunk/libs/openzap/src/m3ua_client.c</a></li>
<li><a href="#freeswitchtrunklibsopenzapsrcm3ua_clienth">freeswitch/trunk/libs/openzap/src/m3ua_client.h</a></li>
<li>freeswitch/trunk/libs/openzap/src/ozmod/</li>
<li>freeswitch/trunk/libs/openzap/src/ozmod/ozmod_analog/</li>
<li><a href="#freeswitchtrunklibsopenzapsrcozmodozmod_analogozmod_analog2005vcproj">freeswitch/trunk/libs/openzap/src/ozmod/ozmod_analog/ozmod_analog.2005.vcproj</a></li>
<li><a href="#freeswitchtrunklibsopenzapsrcozmodozmod_analogozmod_analog2008vcproj">freeswitch/trunk/libs/openzap/src/ozmod/ozmod_analog/ozmod_analog.2008.vcproj</a></li>
<li><a href="#freeswitchtrunklibsopenzapsrcozmodozmod_analogozmod_analogc">freeswitch/trunk/libs/openzap/src/ozmod/ozmod_analog/ozmod_analog.c</a></li>
<li><a href="#freeswitchtrunklibsopenzapsrcozmodozmod_analogzap_analogh">freeswitch/trunk/libs/openzap/src/ozmod/ozmod_analog/zap_analog.h</a></li>
<li>freeswitch/trunk/libs/openzap/src/ozmod/ozmod_analog_em/</li>
<li><a href="#freeswitchtrunklibsopenzapsrcozmodozmod_analog_emozmod_analog_em2005vcproj">freeswitch/trunk/libs/openzap/src/ozmod/ozmod_analog_em/ozmod_analog_em.2005.vcproj</a></li>
<li><a href="#freeswitchtrunklibsopenzapsrcozmodozmod_analog_emozmod_analog_em2008vcproj">freeswitch/trunk/libs/openzap/src/ozmod/ozmod_analog_em/ozmod_analog_em.2008.vcproj</a></li>
<li><a href="#freeswitchtrunklibsopenzapsrcozmodozmod_analog_emozmod_analog_emc">freeswitch/trunk/libs/openzap/src/ozmod/ozmod_analog_em/ozmod_analog_em.c</a></li>
<li><a href="#freeswitchtrunklibsopenzapsrcozmodozmod_analog_emzap_analog_emh">freeswitch/trunk/libs/openzap/src/ozmod/ozmod_analog_em/zap_analog_em.h</a></li>
<li>freeswitch/trunk/libs/openzap/src/ozmod/ozmod_isdn/</li>
<li><a href="#freeswitchtrunklibsopenzapsrcozmodozmod_isdnozmod_isdn2005vcproj">freeswitch/trunk/libs/openzap/src/ozmod/ozmod_isdn/ozmod_isdn.2005.vcproj</a></li>
<li><a href="#freeswitchtrunklibsopenzapsrcozmodozmod_isdnozmod_isdn2008vcproj">freeswitch/trunk/libs/openzap/src/ozmod/ozmod_isdn/ozmod_isdn.2008.vcproj</a></li>
<li><a href="#freeswitchtrunklibsopenzapsrcozmodozmod_isdnozmod_isdnc">freeswitch/trunk/libs/openzap/src/ozmod/ozmod_isdn/ozmod_isdn.c</a></li>
<li><a href="#freeswitchtrunklibsopenzapsrcozmodozmod_isdnzap_isdnh">freeswitch/trunk/libs/openzap/src/ozmod/ozmod_isdn/zap_isdn.h</a></li>
<li>freeswitch/trunk/libs/openzap/src/ozmod/ozmod_libpri/</li>
<li><a href="#freeswitchtrunklibsopenzapsrcozmodozmod_libprilpwrap_pric">freeswitch/trunk/libs/openzap/src/ozmod/ozmod_libpri/lpwrap_pri.c</a></li>
<li><a href="#freeswitchtrunklibsopenzapsrcozmodozmod_libprilpwrap_prih">freeswitch/trunk/libs/openzap/src/ozmod/ozmod_libpri/lpwrap_pri.h</a></li>
<li><a href="#freeswitchtrunklibsopenzapsrcozmodozmod_libpriozmod_libpric">freeswitch/trunk/libs/openzap/src/ozmod/ozmod_libpri/ozmod_libpri.c</a></li>
<li><a href="#freeswitchtrunklibsopenzapsrcozmodozmod_libpriozmod_libprih">freeswitch/trunk/libs/openzap/src/ozmod/ozmod_libpri/ozmod_libpri.h</a></li>
<li>freeswitch/trunk/libs/openzap/src/ozmod/ozmod_pika/</li>
<li><a href="#freeswitchtrunklibsopenzapsrcozmodozmod_pikaozmod_pika2005vcproj">freeswitch/trunk/libs/openzap/src/ozmod/ozmod_pika/ozmod_pika.2005.vcproj</a></li>
<li><a href="#freeswitchtrunklibsopenzapsrcozmodozmod_pikaozmod_pika2008vcproj">freeswitch/trunk/libs/openzap/src/ozmod/ozmod_pika/ozmod_pika.2008.vcproj</a></li>
<li><a href="#freeswitchtrunklibsopenzapsrcozmodozmod_pikaozmod_pikac">freeswitch/trunk/libs/openzap/src/ozmod/ozmod_pika/ozmod_pika.c</a></li>
<li><a href="#freeswitchtrunklibsopenzapsrcozmodozmod_pikazap_pikah">freeswitch/trunk/libs/openzap/src/ozmod/ozmod_pika/zap_pika.h</a></li>
<li>freeswitch/trunk/libs/openzap/src/ozmod/ozmod_r2/</li>
<li><a href="#freeswitchtrunklibsopenzapsrcozmodozmod_r2ozmod_r2c">freeswitch/trunk/libs/openzap/src/ozmod/ozmod_r2/ozmod_r2.c</a></li>
<li>freeswitch/trunk/libs/openzap/src/ozmod/ozmod_sangoma_boost/</li>
<li><a href="#freeswitchtrunklibsopenzapsrcozmodozmod_sangoma_boostozmod_sangoma_boostc">freeswitch/trunk/libs/openzap/src/ozmod/ozmod_sangoma_boost/ozmod_sangoma_boost.c</a></li>
<li><a href="#freeswitchtrunklibsopenzapsrcozmodozmod_sangoma_boostsangoma_boost_clientc">freeswitch/trunk/libs/openzap/src/ozmod/ozmod_sangoma_boost/sangoma_boost_client.c</a></li>
<li><a href="#freeswitchtrunklibsopenzapsrcozmodozmod_sangoma_boostsangoma_boost_clienth">freeswitch/trunk/libs/openzap/src/ozmod/ozmod_sangoma_boost/sangoma_boost_client.h</a></li>
<li><a href="#freeswitchtrunklibsopenzapsrcozmodozmod_sangoma_boostsigboosth">freeswitch/trunk/libs/openzap/src/ozmod/ozmod_sangoma_boost/sigboost.h</a></li>
<li><a href="#freeswitchtrunklibsopenzapsrcozmodozmod_sangoma_boostzap_sangoma_boosth">freeswitch/trunk/libs/openzap/src/ozmod/ozmod_sangoma_boost/zap_sangoma_boost.h</a></li>
<li>freeswitch/trunk/libs/openzap/src/ozmod/ozmod_skel/</li>
<li><a href="#freeswitchtrunklibsopenzapsrcozmodozmod_skelozmod_skelc">freeswitch/trunk/libs/openzap/src/ozmod/ozmod_skel/ozmod_skel.c</a></li>
<li>freeswitch/trunk/libs/openzap/src/ozmod/ozmod_wanpipe/</li>
<li><a href="#freeswitchtrunklibsopenzapsrcozmodozmod_wanpipeozmod_wanpipe2005vcproj">freeswitch/trunk/libs/openzap/src/ozmod/ozmod_wanpipe/ozmod_wanpipe.2005.vcproj</a></li>
<li><a href="#freeswitchtrunklibsopenzapsrcozmodozmod_wanpipeozmod_wanpipe2008vcproj">freeswitch/trunk/libs/openzap/src/ozmod/ozmod_wanpipe/ozmod_wanpipe.2008.vcproj</a></li>
<li><a href="#freeswitchtrunklibsopenzapsrcozmodozmod_wanpipeozmod_wanpipec">freeswitch/trunk/libs/openzap/src/ozmod/ozmod_wanpipe/ozmod_wanpipe.c</a></li>
<li><a href="#freeswitchtrunklibsopenzapsrcozmodozmod_wanpipewanpipe_tdm_api_ifaceh">freeswitch/trunk/libs/openzap/src/ozmod/ozmod_wanpipe/wanpipe_tdm_api_iface.h</a></li>
<li>freeswitch/trunk/libs/openzap/src/ozmod/ozmod_zt/</li>
<li><a href="#freeswitchtrunklibsopenzapsrcozmodozmod_ztozmod_ztc">freeswitch/trunk/libs/openzap/src/ozmod/ozmod_zt/ozmod_zt.c</a></li>
<li><a href="#freeswitchtrunklibsopenzapsrcozmodozmod_ztozmod_zth">freeswitch/trunk/libs/openzap/src/ozmod/ozmod_zt/ozmod_zt.h</a></li>
<li><a href="#freeswitchtrunklibsopenzapsrcpriserverc">freeswitch/trunk/libs/openzap/src/priserver.c</a></li>
<li><a href="#freeswitchtrunklibsopenzapsrcsangoma_pric">freeswitch/trunk/libs/openzap/src/sangoma_pri.c</a></li>
<li><a href="#freeswitchtrunklibsopenzapsrcsangoma_prih">freeswitch/trunk/libs/openzap/src/sangoma_pri.h</a></li>
<li>freeswitch/trunk/libs/openzap/src/ss7/</li>
<li><a href="#freeswitchtrunklibsopenzapsrcss7README">freeswitch/trunk/libs/openzap/src/ss7/README</a></li>
<li><a href="#freeswitchtrunklibsopenzapsrctestanalogc">freeswitch/trunk/libs/openzap/src/testanalog.c</a></li>
<li><a href="#freeswitchtrunklibsopenzapsrctestappc">freeswitch/trunk/libs/openzap/src/testapp.c</a></li>
<li><a href="#freeswitchtrunklibsopenzapsrctestboostc">freeswitch/trunk/libs/openzap/src/testboost.c</a></li>
<li><a href="#freeswitchtrunklibsopenzapsrctestcidc">freeswitch/trunk/libs/openzap/src/testcid.c</a></li>
<li><a href="#freeswitchtrunklibsopenzapsrctestisdnc">freeswitch/trunk/libs/openzap/src/testisdn.c</a></li>
<li><a href="#freeswitchtrunklibsopenzapsrctestm3uac">freeswitch/trunk/libs/openzap/src/testm3ua.c</a></li>
<li><a href="#freeswitchtrunklibsopenzapsrctestpric">freeswitch/trunk/libs/openzap/src/testpri.c</a></li>
<li><a href="#freeswitchtrunklibsopenzapsrctestr2c">freeswitch/trunk/libs/openzap/src/testr2.c</a></li>
<li><a href="#freeswitchtrunklibsopenzapsrctesttonesc">freeswitch/trunk/libs/openzap/src/testtones.c</a></li>
<li><a href="#freeswitchtrunklibsopenzapsrcuartc">freeswitch/trunk/libs/openzap/src/uart.c</a></li>
<li><a href="#freeswitchtrunklibsopenzapsrczap_bufferc">freeswitch/trunk/libs/openzap/src/zap_buffer.c</a></li>
<li><a href="#freeswitchtrunklibsopenzapsrczap_calleridc">freeswitch/trunk/libs/openzap/src/zap_callerid.c</a></li>
<li><a href="#freeswitchtrunklibsopenzapsrczap_configc">freeswitch/trunk/libs/openzap/src/zap_config.c</a></li>
<li><a href="#freeswitchtrunklibsopenzapsrczap_cpu_monitorc">freeswitch/trunk/libs/openzap/src/zap_cpu_monitor.c</a></li>
<li><a href="#freeswitchtrunklibsopenzapsrczap_dsoc">freeswitch/trunk/libs/openzap/src/zap_dso.c</a></li>
<li><a href="#freeswitchtrunklibsopenzapsrczap_ioc">freeswitch/trunk/libs/openzap/src/zap_io.c</a></li>
<li><a href="#freeswitchtrunklibsopenzapsrczap_m3uac">freeswitch/trunk/libs/openzap/src/zap_m3ua.c</a></li>
<li><a href="#freeswitchtrunklibsopenzapsrczap_threadmutexc">freeswitch/trunk/libs/openzap/src/zap_threadmutex.c</a></li>
</ul>
</div>
<div id="patch">
<h3>Diff</h3>
<a id="freeswitchtrunklibsfreetdmgitignore"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/.gitignore (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/trunk/libs/freetdm/.gitignore         (rev 0)
+++ freeswitch/trunk/libs/freetdm/.gitignore        2010-03-30 13:41:49 UTC (rev 17141)
</span><span class="lines">@@ -0,0 +1,13 @@
</span><ins>+*.o
+*.lo
+*.so
+*.a
+*.orig
+*.rej
+*.log
+
+Makefile
+config.*
+configure
+libtool
+aclocal.m4
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmupdate"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/.update (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/trunk/libs/freetdm/.update         (rev 0)
+++ freeswitch/trunk/libs/freetdm/.update        2010-03-30 13:41:49 UTC (rev 17141)
</span><span class="lines">@@ -0,0 +1 @@
</span><ins>+Fri Oct 3 17:54:41 EDT 2008
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmAUTHORS"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/AUTHORS ( => )</h4>
<pre class="diff"><span>
<span class="info">
Added: freeswitch/trunk/libs/freetdm/ChangeLog
</span><span class="cx">===================================================================
</span></span></pre></div>
<a id="freeswitchtrunklibsfreetdmMakefileam"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/Makefile.am (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/trunk/libs/freetdm/Makefile.am         (rev 0)
+++ freeswitch/trunk/libs/freetdm/Makefile.am        2010-03-30 13:41:49 UTC (rev 17141)
</span><span class="lines">@@ -0,0 +1,276 @@
</span><ins>+# 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
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmNEWS"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/NEWS ( => )</h4>
<pre class="diff"><span>
<span class="info">
Added: freeswitch/trunk/libs/freetdm/README
</span><span class="cx">===================================================================
</span><del>--- freeswitch/trunk/libs/freetdm/README         (rev 0)
</del><ins>+++ freeswitch/trunk/libs/freetdm/README        2010-03-30 13:41:49 UTC (rev 17141)
</ins><span class="lines">@@ -0,0 +1,3 @@
</span><ins>+FREETDM (WORK IN PROGRESS)
+
+*shrug*
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmTODO"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/TODO (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/trunk/libs/freetdm/TODO         (rev 0)
+++ freeswitch/trunk/libs/freetdm/TODO        2010-03-30 13:41:49 UTC (rev 17141)
</span><span class="lines">@@ -0,0 +1,9 @@
</span><ins>+== 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
+
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmacincludem4"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/acinclude.m4 (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/trunk/libs/freetdm/acinclude.m4         (rev 0)
+++ freeswitch/trunk/libs/freetdm/acinclude.m4        2010-03-30 13:41:49 UTC (rev 17141)
</span><span class="lines">@@ -0,0 +1 @@
</span><ins>+m4_include([build/libpcap.m4])
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmbootstrap"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/bootstrap (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/trunk/libs/freetdm/bootstrap         (rev 0)
+++ freeswitch/trunk/libs/freetdm/bootstrap        2010-03-30 13:41:49 UTC (rev 17141)
</span><span class="lines">@@ -0,0 +1,6 @@
</span><ins>+#!/bin/bash
+autoheader
+libtoolize --force --copy
+aclocal
+automake -f --copy --add-missing
+autoconf
</ins><span class="cx">Property changes on: freeswitch/trunk/libs/freetdm/bootstrap
</span><span class="cx">___________________________________________________________________
</span><span class="cx">Name: svn:executable
</span><span class="cx"> + *
</span></span></pre></div>
<a id="freeswitchtrunklibsfreetdmbuildlibpcapm4"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/build/libpcap.m4 (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,144 @@
</span><ins>+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
+        ])
+
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmconffreetdmconf"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/conf/freetdm.conf (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,19 @@
</span><ins>+[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
+
+
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmconffreetdmconfxml"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/conf/freetdm.conf.xml (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,45 @@
</span><ins>+<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>
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmconfm3uaconf"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/conf/m3ua.conf (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,38 @@
</span><ins>+;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
+
+
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmconfpikaconf"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/conf/pika.conf (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,41 @@
</span><ins>+; 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
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmconftonesconf"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/conf/tones.conf (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,63 @@
</span><ins>+[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
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmconfwanpipeconf"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/conf/wanpipe.conf (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,4 @@
</span><ins>+[defaults]
+codec_ms => 20
+wink_ms => 150
+flash_ms => 750
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmconfztconf"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/conf/zt.conf (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,8 @@
</span><ins>+[defaults]
+codec_ms => 20
+wink_ms => 150
+flash_ms => 750
+echo_cancel_level => 64
+rxgain => 0.0
+txgain => 0.0
+
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmconfigureac"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/configure.ac (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/trunk/libs/freetdm/configure.ac         (rev 0)
+++ freeswitch/trunk/libs/freetdm/configure.ac        2010-03-30 13:41:49 UTC (rev 17141)
</span><span class="lines">@@ -0,0 +1,181 @@
</span><ins>+# -*- 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
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmconfiguregnu"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/configure.gnu (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/trunk/libs/freetdm/configure.gnu         (rev 0)
+++ freeswitch/trunk/libs/freetdm/configure.gnu        2010-03-30 13:41:49 UTC (rev 17141)
</span><span class="lines">@@ -0,0 +1,3 @@
</span><ins>+#! /bin/sh
+./configure "$@" --with-pic
+
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmcyginstallsh"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/cyginstall.sh (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/trunk/libs/freetdm/cyginstall.sh         (rev 0)
+++ freeswitch/trunk/libs/freetdm/cyginstall.sh        2010-03-30 13:41:49 UTC (rev 17141)
</span><span class="lines">@@ -0,0 +1,11 @@
</span><ins>+#!/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
+
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmdocsDoxygenconf"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/docs/Doxygen.conf (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,277 @@
</span><ins>+# 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
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmfreetdm2008sln"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/freetdm.2008.sln (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,112 @@
</span><ins>+
+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
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmfreetdmpcin"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/freetdm.pc.in (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,17 @@
</span><ins>+#
+# 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}
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmmod_freetdmMakefilein"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/mod_freetdm/Makefile.in (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,23 @@
</span><ins>+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
+
+
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmmod_freetdmmod_freetdm2008vcproj"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/mod_freetdm/mod_freetdm.2008.vcproj (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,369 @@
</span><ins>+<?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>
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmmod_freetdmmod_freetdmc"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/mod_freetdm/mod_freetdm.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,3193 @@
</span><ins>+/*
+ * 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:
+ */
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmmod_freetdmmod_openzap2005vcproj"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/mod_freetdm/mod_openzap.2005.vcproj (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,201 @@
</span><ins>+<?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>
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmmsvcfreetdm2008vcproj"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/msvc/freetdm.2008.vcproj (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,455 @@
</span><ins>+<?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>
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmmsvcopenzap2005vcproj"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/msvc/openzap.2005.vcproj (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,301 @@
</span><ins>+<?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>
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmmsvctestanalogtestanalog2005vcproj"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/msvc/testanalog/testanalog.2005.vcproj (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,193 @@
</span><ins>+<?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>
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmmsvctestanalogtestanalog2008vcproj"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/msvc/testanalog/testanalog.2008.vcproj (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,349 @@
</span><ins>+<?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>
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmmsvctestboosttestboost2008vcproj"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/msvc/testboost/testboost.2008.vcproj (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,191 @@
</span><ins>+<?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>
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmmsvctestboosttestsangomaboost2008vcproj"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/msvc/testboost/testsangomaboost.2008.vcproj (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,191 @@
</span><ins>+<?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>
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmmsvctestisdntestisdn2005vcproj"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/msvc/testisdn/testisdn.2005.vcproj (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,193 @@
</span><ins>+<?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>
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmmsvctestisdntestisdn2008vcproj"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/msvc/testisdn/testisdn.2008.vcproj (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,349 @@
</span><ins>+<?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>
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmopenzap2005sln"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/openzap.2005.sln (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,82 @@
</span><ins>+
+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
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmozrenamesh"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/ozrename.sh (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/trunk/libs/freetdm/ozrename.sh         (rev 0)
+++ freeswitch/trunk/libs/freetdm/ozrename.sh        2010-03-30 13:41:49 UTC (rev 17141)
</span><span class="lines">@@ -0,0 +1,99 @@
</span><ins>+# 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/
+
</ins><span class="cx">Property changes on: freeswitch/trunk/libs/freetdm/ozrename.sh
</span><span class="cx">___________________________________________________________________
</span><span class="cx">Name: svn:executable
</span><span class="cx"> + *
</span></span></pre></div>
<a id="freeswitchtrunklibsfreetdmozreplacesh"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/ozreplace.sh (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/trunk/libs/freetdm/ozreplace.sh         (rev 0)
+++ freeswitch/trunk/libs/freetdm/ozreplace.sh        2010-03-30 13:41:49 UTC (rev 17141)
</span><span class="lines">@@ -0,0 +1,13 @@
</span><ins>+##### 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
+
</ins><span class="cx">Property changes on: freeswitch/trunk/libs/freetdm/ozreplace.sh
</span><span class="cx">___________________________________________________________________
</span><span class="cx">Name: svn:executable
</span><span class="cx"> + *
</span></span></pre></div>
<a id="freeswitchtrunklibsfreetdmpatchesozdiff"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/patches/oz.diff (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,134 @@
</span><ins>+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;
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrcdetect_dtmfc"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/detect_dtmf.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,33 @@
</span><ins>+//#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;
+}
+
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrcdetect_tonesc"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/detect_tones.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,32 @@
</span><ins>+//#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;
+}
+
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrcfskc"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/fsk.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,351 @@
</span><ins>+
+/*
+ *        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;
+        }
+}
+
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrcftdm_bufferc"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/ftdm_buffer.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,302 @@
</span><ins>+/*
+ * 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:
+ */
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrcftdm_calleridc"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/ftdm_callerid.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,307 @@
</span><ins>+#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;
+}
+
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrcftdm_configc"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/ftdm_config.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,251 @@
</span><ins>+/*
+ * 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:
+ */
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrcftdm_dsoc"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/ftdm_dso.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,116 @@
</span><ins>+/*
+ * 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
+ */
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrcftdm_ioc"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/ftdm_io.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,3927 @@
</span><ins>+/*
+ * 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:
+ */
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrcftdm_m3uac"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/ftdm_m3ua.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,692 @@
</span><ins>+/*
+ * 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:
+*/
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrcftdm_queuec"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/ftdm_queue.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,234 @@
</span><ins>+/*
+ * 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:
+ */
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrcftdm_threadmutexc"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/ftdm_threadmutex.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,457 @@
</span><ins>+/*
+ * 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:
+ */
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrcftmodftmod_analogftdm_analogh"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_analog/ftdm_analog.h (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,69 @@
</span><ins>+/*
+ * 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:
+ */
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrcftmodftmod_analogftmod_analog2008vcproj"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_analog/ftmod_analog.2008.vcproj (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,353 @@
</span><ins>+<?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>
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrcftmodftmod_analogftmod_analogc"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_analog/ftmod_analog.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,975 @@
</span><ins>+/*
+ * 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:
+ */
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrcftmodftmod_analogozmod_analog2005vcproj"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_analog/ozmod_analog.2005.vcproj (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,202 @@
</span><ins>+<?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>
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrcftmodftmod_analog_emftdm_analog_emh"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_analog_em/ftdm_analog_em.h (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,70 @@
</span><ins>+/*
+ * 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:
+ */
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrcftmodftmod_analog_emftmod_analog_em2008vcproj"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_analog_em/ftmod_analog_em.2008.vcproj (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,353 @@
</span><ins>+<?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>
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrcftmodftmod_analog_emftmod_analog_emc"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_analog_em/ftmod_analog_em.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,707 @@
</span><ins>+/*
+ * 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:
+ */
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrcftmodftmod_analog_emozmod_analog_em2005vcproj"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_analog_em/ozmod_analog_em.2005.vcproj (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,202 @@
</span><ins>+<?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>
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrcftmodftmod_isdnftdm_isdnh"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_isdn/ftdm_isdn.h (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,96 @@
</span><ins>+/*
+ * 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:
+ */
+
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrcftmodftmod_isdnftmod_isdn2008vcproj"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_isdn/ftmod_isdn.2008.vcproj (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,465 @@
</span><ins>+<?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>
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrcftmodftmod_isdnftmod_isdnc"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_isdn/ftmod_isdn.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,2420 @@
</span><ins>+/*
+ * 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:
+ */
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrcftmodftmod_isdnozmod_isdn2005vcproj"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_isdn/ozmod_isdn.2005.vcproj (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,316 @@
</span><ins>+<?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>
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrcftmodftmod_libpriftmod_libpric"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_libpri/ftmod_libpri.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,1364 @@
</span><ins>+/*
+ * 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:
+ */
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrcftmodftmod_libpriftmod_libprih"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_libpri/ftmod_libpri.h (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,97 @@
</span><ins>+/*
+ * 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:
+ */
+
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrcftmodftmod_libprilpwrap_pric"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_libpri/lpwrap_pri.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,303 @@
</span><ins>+/*
+ * 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:
+ */
+
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrcftmodftmod_libprilpwrap_prih"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_libpri/lpwrap_pri.h (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,126 @@
</span><ins>+/*
+ * 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
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrcftmodftmod_pikaftdm_pikah"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_pika/ftdm_pika.h (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,132 @@
</span><ins>+/*
+ * 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:
+ */
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrcftmodftmod_pikaftmod_pika2008vcproj"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_pika/ftmod_pika.2008.vcproj (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,197 @@
</span><ins>+<?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>
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrcftmodftmod_pikaftmod_pikac"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_pika/ftmod_pika.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,1469 @@
</span><ins>+/*
+ * 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:
+ */
+
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrcftmodftmod_pikaozmod_pika2005vcproj"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_pika/ozmod_pika.2005.vcproj (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,197 @@
</span><ins>+<?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>
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrcftmodftmod_r2ftmod_r2c"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,1363 @@
</span><ins>+/*
+ * 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
+ */
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrcftmodftmod_sangoma_boostBOOSTlimitations"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_sangoma_boost/BOOST.limitations (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,20 @@
</span><ins>+== 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)
+
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrcftmodftmod_sangoma_boostboosttaskstxt"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_sangoma_boost/boost-tasks.txt (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,146 @@
</span><ins>+== 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.
+
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrcftmodftmod_sangoma_boostftdm_sangoma_boosth"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_sangoma_boost/ftdm_sangoma_boost.h (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,74 @@
</span><ins>+/*
+ * 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:
+ */
+
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrcftmodftmod_sangoma_boostftmod_sangoma_boost2008vcproj"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_sangoma_boost/ftmod_sangoma_boost.2008.vcproj (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,215 @@
</span><ins>+<?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>
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrcftmodftmod_sangoma_boostftmod_sangoma_boostc"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_sangoma_boost/ftmod_sangoma_boost.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,2273 @@
</span><ins>+/*
+ * 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:
+ */
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrcftmodftmod_sangoma_boostsangoma_boost_clientc"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_sangoma_boost/sangoma_boost_client.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,575 @@
</span><ins>+/*
+ * 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:
+ */
+
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrcftmodftmod_sangoma_boostsangoma_boost_clienth"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_sangoma_boost/sangoma_boost_client.h (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,159 @@
</span><ins>+/*
+ * 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:
+ */
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrcftmodftmod_sangoma_boostsangoma_boost_interfaceh"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_sangoma_boost/sangoma_boost_interface.h (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,244 @@
</span><ins>+/*
+ * 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:
+ */
+
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrcftmodftmod_sangoma_boostsigboosth"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_sangoma_boost/sigboost.h (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,203 @@
</span><ins>+/****************************************************************************
+ * 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
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrcftmodftmod_skelftmod_skelc"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_skel/ftmod_skel.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,152 @@
</span><ins>+/*
+ * 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:
+ */
+
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrcftmodftmod_wanpipeftmod_wanpipe2008vcproj"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.2008.vcproj (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,355 @@
</span><ins>+<?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>
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrcftmodftmod_wanpipeftmod_wanpipec"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,1238 @@
</span><ins>+/*
+ * 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
+ */
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrcftmodftmod_wanpipeozmod_wanpipe2005vcproj"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_wanpipe/ozmod_wanpipe.2005.vcproj (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,196 @@
</span><ins>+<?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>
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrcftmodftmod_wanpipewanpipe_tdm_api_ifaceh"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_wanpipe/wanpipe_tdm_api_iface.h (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,351 @@
</span><ins>+/*****************************************************************************
+* 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
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrcftmodftmod_ztftmod_ztc"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_zt/ftmod_zt.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,1232 @@
</span><ins>+/*
+ * 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:
+ */
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrcftmodftmod_ztftmod_zth"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/ftmod/ftmod_zt/ftmod_zt.h (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,364 @@
</span><ins>+/*
+ * 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:
+ */
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrcg711c"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/g711.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,104 @@
</span><ins>+/*
+ * 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:
+ */
+
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrchashtablec"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/hashtable.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,340 @@
</span><ins>+/*
+ * 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:
+ */
+
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrchashtable_itrc"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/hashtable_itr.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,186 @@
</span><ins>+/*
+ * 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:
+ */
+
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrcincludefreetdmh"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/include/freetdm.h (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,968 @@
</span><ins>+/*
+ * 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:
+ */
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrcincludefskh"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/include/fsk.h (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,121 @@
</span><ins>+/*
+ *        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        
+
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrcincludeftdm_bufferh"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/include/ftdm_buffer.h (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,154 @@
</span><ins>+/*
+ * 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:
+ */
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrcincludeftdm_configh"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/include/ftdm_config.h (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,145 @@
</span><ins>+/*
+ * 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:
+ */
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrcincludeftdm_dsoh"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/include/ftdm_dso.h (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,51 @@
</span><ins>+/*
+ * 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
+ */
+
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrcincludeftdm_m3uah"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/include/ftdm_m3ua.h (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,134 @@
</span><ins>+/*
+ * 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:
+ */
+
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrcincludeftdm_threadmutexh"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/include/ftdm_threadmutex.h (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,68 @@
</span><ins>+/*
+ * 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:
+ */
+
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrcincludeftdm_typesh"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/include/ftdm_types.h (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,708 @@
</span><ins>+/*
+ * 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:
+ */
+
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrcincludeg711h"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/include/g711.h (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,395 @@
</span><ins>+/*
+ * 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:
+ */
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrcincludehashtableh"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/include/hashtable.h (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,235 @@
</span><ins>+/* 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:
+ */
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrcincludehashtable_itrh"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/include/hashtable_itr.h (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,134 @@
</span><ins>+/* 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:
+ */
+
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrcincludehashtable_privateh"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/include/hashtable_private.h (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,110 @@
</span><ins>+/* 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:
+ */
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrcincludelibteletoneh"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/include/libteletone.h (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,161 @@
</span><ins>+/*
+ * 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:
+ */
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrcincludelibteletone_detecth"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/include/libteletone_detect.h (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,240 @@
</span><ins>+/*
+ * 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:
+ */
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrcincludelibteletone_generateh"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/include/libteletone_generate.h (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,281 @@
</span><ins>+/*
+ * 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:
+ */
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrcincludesangoma_tdm_apih"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/include/sangoma_tdm_api.h (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,321 @@
</span><ins>+/*****************************************************************************
+ * 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:
+ */
+
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrcincludeuarth"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/include/uart.h (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,83 @@
</span><ins>+/*
+ *        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
+
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrcisdn5ESSStateNTc"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/isdn/5ESSStateNT.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,132 @@
</span><ins>+/*****************************************************************************
+
+ 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 */
+}
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrcisdn5ESSStateTEc"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/isdn/5ESSStateTE.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,291 @@
</span><ins>+/*****************************************************************************
+
+ 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;
+
+}
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrcisdn5ESSmesc"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/isdn/5ESSmes.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,361 @@
</span><ins>+/*****************************************************************************
+
+ 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;
+}
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrcisdnDMSStateNTc"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/isdn/DMSStateNT.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,126 @@
</span><ins>+/*****************************************************************************
+
+ 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 */
+}
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrcisdnDMSStateTEc"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/isdn/DMSStateTE.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,284 @@
</span><ins>+/*****************************************************************************
+
+ 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;
+
+}
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrcisdnDMSmesc"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/isdn/DMSmes.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,344 @@
</span><ins>+/*****************************************************************************
+
+ 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;
+}
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrcisdnEuroISDNStateNTc"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/isdn/EuroISDNStateNT.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,44 @@
</span><ins>+/*****************************************************************************
+
+ 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"
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrcisdnEuroISDNStateTEc"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/isdn/EuroISDNStateTE.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,58 @@
</span><ins>+/*****************************************************************************
+
+ 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
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrcisdnQ921c"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/isdn/Q921.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,3518 @@
</span><ins>+/*****************************************************************************
+
+ 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);
+}
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrcisdnQ931c"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/isdn/Q931.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,888 @@
</span><ins>+/*****************************************************************************
+
+ 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;
+}
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrcisdnQ931StateNTc"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/isdn/Q931StateNT.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,1218 @@
</span><ins>+/*****************************************************************************
+
+ 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;
+}
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrcisdnQ931StateTEc"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/isdn/Q931StateTE.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,1310 @@
</span><ins>+/*****************************************************************************
+
+ 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;
+}
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrcisdnQ931apic"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/isdn/Q931api.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,598 @@
</span><ins>+/*****************************************************************************
+
+ 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)
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrcisdnQ931iec"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/isdn/Q931ie.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,3074 @@
</span><ins>+/*****************************************************************************
+
+ 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;
+}
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrcisdnQ931mesc"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/isdn/Q931mes.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,1870 @@
</span><ins>+/*****************************************************************************
+
+ 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;
+}
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrcisdnQ932mesc"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/isdn/Q932mes.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,286 @@
</span><ins>+/*****************************************************************************
+
+ 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;
+}
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrcisdninclude5ESSh"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/isdn/include/5ESS.h (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,103 @@
</span><ins>+/******************************************************************************
+
+ 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 */
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrcisdnincludeDMSh"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/isdn/include/DMS.h (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,91 @@
</span><ins>+/******************************************************************************
+
+ 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 */
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrcisdnincludeQ921h"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/isdn/include/Q921.h (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,227 @@
</span><ins>+/*****************************************************************************
+
+ 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
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrcisdnincludeQ921privh"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/isdn/include/Q921priv.h (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,321 @@
</span><ins>+/*****************************************************************************
+
+ 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
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrcisdnincludeQ931h"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/isdn/include/Q931.h (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,1175 @@
</span><ins>+/******************************************************************************
+
+ 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 */
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrcisdnincludeQ931ieh"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/isdn/include/Q931ie.h (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,1205 @@
</span><ins>+/******************************************************************************
+
+ 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 */
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrcisdnincludeQ932h"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/isdn/include/Q932.h (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,95 @@
</span><ins>+/*****************************************************************************
+
+ 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);
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrcisdnincludemfifoh"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/isdn/include/mfifo.h (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,85 @@
</span><ins>+/*****************************************************************************
+
+ 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
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrcisdnincludenationalh"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/isdn/include/national.h (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,86 @@
</span><ins>+/******************************************************************************
+
+ 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 */
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrcisdnmfifoc"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/isdn/mfifo.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,399 @@
</span><ins>+/*****************************************************************************
+
+ 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;
+}
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrcisdnnationalStateNTc"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/isdn/nationalStateNT.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,130 @@
</span><ins>+/*****************************************************************************
+
+ 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 */
+}
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrcisdnnationalStateTEc"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/isdn/nationalStateTE.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,217 @@
</span><ins>+/*****************************************************************************
+
+ 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,
+*/
+}
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrcisdnnationalmesc"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/isdn/nationalmes.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,269 @@
</span><ins>+/*****************************************************************************
+
+ 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;
+}
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrclibteletone_detectc"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/libteletone_detect.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,427 @@
</span><ins>+/*
+ * 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:
+ */
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrclibteletone_generatec"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/libteletone_generate.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,452 @@
</span><ins>+/*
+ * 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:
+ */
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrcm3uamstm3uac"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/m3ua/mstm3ua.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,62 @@
</span><ins>+/* 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);
+
+};
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrcm3uamstm3uah"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/m3ua/mstm3ua.h (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,96 @@
</span><ins>+/*
+ * 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
+
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrcm3ua_clientc"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/m3ua_client.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,333 @@
</span><ins>+/*
+ * 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:
+ */
+
+
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrcm3ua_clienth"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/m3ua_client.h (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,164 @@
</span><ins>+/*
+ * 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:
+ */
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrcpriserverc"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/priserver.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,328 @@
</span><ins>+/*****************************************************************************
+ * 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:
+ */
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrcsangoma_pric"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/sangoma_pri.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,251 @@
</span><ins>+/*****************************************************************************
+ * 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:
+ */
+
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrcsangoma_prih"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/sangoma_pri.h (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,100 @@
</span><ins>+/*****************************************************************************
+ * 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
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrcss7README"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/ss7/README (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,3 @@
</span><ins>+SS7 Coming soon
+
+-Shane Burrell-
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrctestanalogc"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/testanalog.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,133 @@
</span><ins>+#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:
+ */
+
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrctestappc"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/testapp.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,83 @@
</span><ins>+#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:
+ */
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrctestboostc"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/testboost.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,82 @@
</span><ins>+#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:
+ */
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrctestcidc"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/testcid.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,108 @@
</span><ins>+#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;
+}
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrctestisdnc"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/testisdn.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,74 @@
</span><ins>+#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:
+ */
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrctestm3uac"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/testm3ua.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,60 @@
</span><ins>+/*
+ * 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();
+
+}
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrctestpric"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/testpri.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,162 @@
</span><ins>+#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:
+ */
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrctestr2c"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/testr2.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,86 @@
</span><ins>+#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:
+ */
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrctestsangomaboostc"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/testsangomaboost.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,378 @@
</span><ins>+/*
+ * 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:
+ */
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrctesttonesc"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/testtones.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,76 @@
</span><ins>+#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
</ins></span></pre></div>
<a id="freeswitchtrunklibsfreetdmsrcuartc"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/freetdm/src/uart.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,125 @@
</span><ins>+
+/*
+ *        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... */
+}
+
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapgitignore"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/.gitignore (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/trunk/libs/openzap/.gitignore         (rev 0)
+++ freeswitch/trunk/libs/openzap/.gitignore        2010-03-30 13:41:49 UTC (rev 17141)
</span><span class="lines">@@ -0,0 +1,13 @@
</span><ins>+*.o
+*.lo
+*.so
+*.a
+*.orig
+*.rej
+*.log
+
+Makefile
+config.*
+configure
+libtool
+aclocal.m4
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapupdate"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/.update (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/trunk/libs/openzap/.update         (rev 0)
+++ freeswitch/trunk/libs/openzap/.update        2010-03-30 13:41:49 UTC (rev 17141)
</span><span class="lines">@@ -0,0 +1 @@
</span><ins>+Fri Oct 3 17:54:41 EDT 2008
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapAUTHORS"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/AUTHORS ( => )</h4>
<pre class="diff"><span>
<span class="info">
Added: freeswitch/trunk/libs/openzap/ChangeLog
</span><span class="cx">===================================================================
</span></span></pre></div>
<a id="freeswitchtrunklibsopenzapMakefileam"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/Makefile.am (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/trunk/libs/openzap/Makefile.am         (rev 0)
+++ freeswitch/trunk/libs/openzap/Makefile.am        2010-03-30 13:41:49 UTC (rev 17141)
</span><span class="lines">@@ -0,0 +1,272 @@
</span><ins>+# 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
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapNEWS"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/NEWS ( => )</h4>
<pre class="diff"><span>
<span class="info">
Added: freeswitch/trunk/libs/openzap/README
</span><span class="cx">===================================================================
</span><del>--- freeswitch/trunk/libs/openzap/README         (rev 0)
</del><ins>+++ freeswitch/trunk/libs/openzap/README        2010-03-30 13:41:49 UTC (rev 17141)
</ins><span class="lines">@@ -0,0 +1,3 @@
</span><ins>+OPENZAP (WORK IN PROGRESS)
+
+*shrug*
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapacincludem4"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/acinclude.m4 (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/trunk/libs/openzap/acinclude.m4         (rev 0)
+++ freeswitch/trunk/libs/openzap/acinclude.m4        2010-03-30 13:41:49 UTC (rev 17141)
</span><span class="lines">@@ -0,0 +1 @@
</span><ins>+m4_include([build/libpcap.m4])
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapbootstrap"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/bootstrap (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/trunk/libs/openzap/bootstrap         (rev 0)
+++ freeswitch/trunk/libs/openzap/bootstrap        2010-03-30 13:41:49 UTC (rev 17141)
</span><span class="lines">@@ -0,0 +1,6 @@
</span><ins>+#!/bin/bash
+autoheader
+libtoolize --force --copy
+aclocal
+automake -f --copy --add-missing
+autoconf
</ins><span class="cx">Property changes on: freeswitch/trunk/libs/openzap/bootstrap
</span><span class="cx">___________________________________________________________________
</span><span class="cx">Name: svn:executable
</span><span class="cx"> + *
</span></span></pre></div>
<a id="freeswitchtrunklibsopenzapbuildlibpcapm4"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/build/libpcap.m4 (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,144 @@
</span><ins>+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
+        ])
+
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapconfm3uaconf"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/conf/m3ua.conf (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,38 @@
</span><ins>+;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
+
+
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapconfopenzapconf"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/conf/openzap.conf (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,19 @@
</span><ins>+[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
+
+
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapconfopenzapconfxml"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/conf/openzap.conf.xml (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,45 @@
</span><ins>+<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>
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapconfpikaconf"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/conf/pika.conf (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,41 @@
</span><ins>+; 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
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapconftonesconf"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/conf/tones.conf (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,63 @@
</span><ins>+[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
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapconfwanpipeconf"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/conf/wanpipe.conf (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,4 @@
</span><ins>+[defaults]
+codec_ms => 20
+wink_ms => 150
+flash_ms => 750
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapconfztconf"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/conf/zt.conf (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,8 @@
</span><ins>+[defaults]
+codec_ms => 20
+wink_ms => 150
+flash_ms => 750
+echo_cancel_level => 64
+rxgain => 0.0
+txgain => 0.0
+
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapconfigureac"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/configure.ac (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/trunk/libs/openzap/configure.ac         (rev 0)
+++ freeswitch/trunk/libs/openzap/configure.ac        2010-03-30 13:41:49 UTC (rev 17141)
</span><span class="lines">@@ -0,0 +1,181 @@
</span><ins>+# -*- 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
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapconfiguregnu"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/configure.gnu (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/trunk/libs/openzap/configure.gnu         (rev 0)
+++ freeswitch/trunk/libs/openzap/configure.gnu        2010-03-30 13:41:49 UTC (rev 17141)
</span><span class="lines">@@ -0,0 +1,4 @@
</span><ins>+#! /bin/sh
+srcpath=$(dirname $0 2>/dev/null ) || srcpath="."
+$srcpath/configure "$@" --with-pic
+
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapdocsDoxygenconf"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/docs/Doxygen.conf (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,277 @@
</span><ins>+# 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
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapmod_openzapMakefilein"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/mod_openzap/Makefile.in (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,23 @@
</span><ins>+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
+
+
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapmod_openzapmod_openzap2005vcproj"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/mod_openzap/mod_openzap.2005.vcproj (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,201 @@
</span><ins>+<?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>
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapmod_openzapmod_openzap2008vcproj"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/mod_openzap/mod_openzap.2008.vcproj (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,369 @@
</span><ins>+<?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>
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapmod_openzapmod_openzapc"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/mod_openzap/mod_openzap.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,3221 @@
</span><ins>+/*
+ * 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:
+ */
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapmsvcopenzap2005vcproj"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/msvc/openzap.2005.vcproj (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,301 @@
</span><ins>+<?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>
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapmsvcopenzap2008vcproj"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/msvc/openzap.2008.vcproj (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,451 @@
</span><ins>+<?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>
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapmsvctestanalogtestanalog2005vcproj"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/msvc/testanalog/testanalog.2005.vcproj (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,193 @@
</span><ins>+<?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>
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapmsvctestanalogtestanalog2008vcproj"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/msvc/testanalog/testanalog.2008.vcproj (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,349 @@
</span><ins>+<?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>
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapmsvctestisdntestisdn2005vcproj"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/msvc/testisdn/testisdn.2005.vcproj (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,193 @@
</span><ins>+<?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>
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapmsvctestisdntestisdn2008vcproj"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/msvc/testisdn/testisdn.2008.vcproj (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,349 @@
</span><ins>+<?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>
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapopenzap2005sln"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/openzap.2005.sln (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,82 @@
</span><ins>+
+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
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapopenzap2008sln"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/openzap.2008.sln (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,119 @@
</span><ins>+
+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
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapopenzappcin"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/openzap.pc.in (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,17 @@
</span><ins>+#
+# 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}
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzappatchesozdiff"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/patches/oz.diff (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,134 @@
</span><ins>+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;
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapsrcdetect_dtmfc"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/src/detect_dtmf.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,33 @@
</span><ins>+//#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;
+}
+
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapsrcdetect_tonesc"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/src/detect_tones.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,32 @@
</span><ins>+//#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;
+}
+
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapsrcfskc"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/src/fsk.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,351 @@
</span><ins>+
+/*
+ *        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;
+        }
+}
+
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapsrcg711c"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/src/g711.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,104 @@
</span><ins>+/*
+ * 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:
+ */
+
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapsrchashtablec"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/src/hashtable.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,339 @@
</span><ins>+/*
+ * 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:
+ */
+
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapsrchashtable_itrc"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/src/hashtable_itr.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,186 @@
</span><ins>+/*
+ * 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:
+ */
+
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapsrcincludefskh"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/src/include/fsk.h (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,113 @@
</span><ins>+/*
+ *        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        
+
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapsrcincludeg711h"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/src/include/g711.h (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,395 @@
</span><ins>+/*
+ * 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:
+ */
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapsrcincludehashtableh"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/src/include/hashtable.h (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,228 @@
</span><ins>+/* 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:
+ */
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapsrcincludehashtable_itrh"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/src/include/hashtable_itr.h (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,129 @@
</span><ins>+/* 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:
+ */
+
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapsrcincludehashtable_privateh"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/src/include/hashtable_private.h (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,105 @@
</span><ins>+/* 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:
+ */
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapsrcincludelibteletoneh"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/src/include/libteletone.h (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,161 @@
</span><ins>+/*
+ * 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:
+ */
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapsrcincludelibteletone_detecth"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/src/include/libteletone_detect.h (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,240 @@
</span><ins>+/*
+ * 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:
+ */
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapsrcincludelibteletone_generateh"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/src/include/libteletone_generate.h (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,281 @@
</span><ins>+/*
+ * 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:
+ */
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapsrcincludeopenzaph"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/src/include/openzap.h (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,797 @@
</span><ins>+/*
+ * 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:
+ */
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapsrcincludesangoma_tdm_apih"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/src/include/sangoma_tdm_api.h (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,321 @@
</span><ins>+/*****************************************************************************
+ * 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:
+ */
+
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapsrcincludeuarth"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/src/include/uart.h (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,76 @@
</span><ins>+/*
+ *        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
+
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapsrcincludezap_bufferh"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/src/include/zap_buffer.h (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,146 @@
</span><ins>+/*
+ * 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:
+ */
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapsrcincludezap_configh"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/src/include/zap_config.h (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,138 @@
</span><ins>+/*
+ * 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:
+ */
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapsrcincludezap_cpu_monitorh"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/src/include/zap_cpu_monitor.h (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,74 @@
</span><ins>+/* * 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:
+ */
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapsrcincludezap_dsoh"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/src/include/zap_dso.h (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,44 @@
</span><ins>+/*
+ * 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
+ */
+
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapsrcincludezap_m3uah"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/src/include/zap_m3ua.h (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,128 @@
</span><ins>+/*
+ * 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:
+ */
+
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapsrcincludezap_threadmutexh"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/src/include/zap_threadmutex.h (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,56 @@
</span><ins>+/*
+ * 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:
+ */
+
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapsrcincludezap_typesh"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/src/include/zap_types.h (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,639 @@
</span><ins>+/*
+ * 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:
+ */
+
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapsrcisdn5ESSStateNTc"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/src/isdn/5ESSStateNT.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,132 @@
</span><ins>+/*****************************************************************************
+
+ 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 */
+}
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapsrcisdn5ESSStateTEc"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/src/isdn/5ESSStateTE.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,291 @@
</span><ins>+/*****************************************************************************
+
+ 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;
+
+}
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapsrcisdn5ESSmesc"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/src/isdn/5ESSmes.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,361 @@
</span><ins>+/*****************************************************************************
+
+ 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;
+}
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapsrcisdnDMSStateNTc"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/src/isdn/DMSStateNT.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,126 @@
</span><ins>+/*****************************************************************************
+
+ 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 */
+}
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapsrcisdnDMSStateTEc"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/src/isdn/DMSStateTE.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,284 @@
</span><ins>+/*****************************************************************************
+
+ 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;
+
+}
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapsrcisdnDMSmesc"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/src/isdn/DMSmes.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,344 @@
</span><ins>+/*****************************************************************************
+
+ 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;
+}
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapsrcisdnEuroISDNStateNTc"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/src/isdn/EuroISDNStateNT.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,44 @@
</span><ins>+/*****************************************************************************
+
+ 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"
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapsrcisdnEuroISDNStateTEc"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/src/isdn/EuroISDNStateTE.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,58 @@
</span><ins>+/*****************************************************************************
+
+ 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
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapsrcisdnQ921c"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/src/isdn/Q921.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,3517 @@
</span><ins>+/*****************************************************************************
+
+ 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);
+}
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapsrcisdnQ931c"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/src/isdn/Q931.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,888 @@
</span><ins>+/*****************************************************************************
+
+ 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;
+}
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapsrcisdnQ931StateNTc"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/src/isdn/Q931StateNT.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,1218 @@
</span><ins>+/*****************************************************************************
+
+ 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;
+}
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapsrcisdnQ931StateTEc"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/src/isdn/Q931StateTE.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,1310 @@
</span><ins>+/*****************************************************************************
+
+ 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;
+}
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapsrcisdnQ931apic"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/src/isdn/Q931api.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,598 @@
</span><ins>+/*****************************************************************************
+
+ 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)
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapsrcisdnQ931iec"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/src/isdn/Q931ie.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,3074 @@
</span><ins>+/*****************************************************************************
+
+ 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;
+}
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapsrcisdnQ931mesc"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/src/isdn/Q931mes.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,1870 @@
</span><ins>+/*****************************************************************************
+
+ 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;
+}
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapsrcisdnQ932mesc"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/src/isdn/Q932mes.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,286 @@
</span><ins>+/*****************************************************************************
+
+ 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;
+}
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapsrcisdninclude5ESSh"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/src/isdn/include/5ESS.h (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,103 @@
</span><ins>+/******************************************************************************
+
+ 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 */
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapsrcisdnincludeDMSh"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/src/isdn/include/DMS.h (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,91 @@
</span><ins>+/******************************************************************************
+
+ 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 */
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapsrcisdnincludeQ921h"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/src/isdn/include/Q921.h (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,227 @@
</span><ins>+/*****************************************************************************
+
+ 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
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapsrcisdnincludeQ921privh"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/src/isdn/include/Q921priv.h (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,321 @@
</span><ins>+/*****************************************************************************
+
+ 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
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapsrcisdnincludeQ931h"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/src/isdn/include/Q931.h (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,1175 @@
</span><ins>+/******************************************************************************
+
+ 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 */
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapsrcisdnincludeQ931ieh"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/src/isdn/include/Q931ie.h (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,1205 @@
</span><ins>+/******************************************************************************
+
+ 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 */
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapsrcisdnincludeQ932h"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/src/isdn/include/Q932.h (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,95 @@
</span><ins>+/*****************************************************************************
+
+ 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);
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapsrcisdnincludemfifoh"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/src/isdn/include/mfifo.h (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,85 @@
</span><ins>+/*****************************************************************************
+
+ 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
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapsrcisdnincludenationalh"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/src/isdn/include/national.h (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,86 @@
</span><ins>+/******************************************************************************
+
+ 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 */
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapsrcisdnmfifoc"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/src/isdn/mfifo.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,399 @@
</span><ins>+/*****************************************************************************
+
+ 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;
+}
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapsrcisdnnationalStateNTc"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/src/isdn/nationalStateNT.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,130 @@
</span><ins>+/*****************************************************************************
+
+ 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 */
+}
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapsrcisdnnationalStateTEc"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/src/isdn/nationalStateTE.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,217 @@
</span><ins>+/*****************************************************************************
+
+ 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,
+*/
+}
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapsrcisdnnationalmesc"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/src/isdn/nationalmes.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,269 @@
</span><ins>+/*****************************************************************************
+
+ 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;
+}
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapsrclibteletone_detectc"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/src/libteletone_detect.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,427 @@
</span><ins>+/*
+ * 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:
+ */
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapsrclibteletone_generatec"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/src/libteletone_generate.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,464 @@
</span><ins>+/*
+ * 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:
+ */
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapsrcm3uamstm3uac"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/src/m3ua/mstm3ua.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,62 @@
</span><ins>+/* 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);
+
+};
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="freeswitchtrunklibsopenzapsrcm3uamstm3uah"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/src/m3ua/mstm3ua.h (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,96 @@
</span><ins>+/*
+ * 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
+
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapsrcm3ua_clientc"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/src/m3ua_client.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,333 @@
</span><ins>+/*
+ * 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:
+ */
+
+
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapsrcm3ua_clienth"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/src/m3ua_client.h (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,164 @@
</span><ins>+/*
+ * 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:
+ */
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapsrcozmodozmod_analogozmod_analog2005vcproj"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/src/ozmod/ozmod_analog/ozmod_analog.2005.vcproj (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,202 @@
</span><ins>+<?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>
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapsrcozmodozmod_analogozmod_analog2008vcproj"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/src/ozmod/ozmod_analog/ozmod_analog.2008.vcproj (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,353 @@
</span><ins>+<?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>
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapsrcozmodozmod_analogozmod_analogc"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/src/ozmod/ozmod_analog/ozmod_analog.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,1012 @@
</span><ins>+/*
+ * 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:
+ */
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapsrcozmodozmod_analogzap_analogh"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/src/ozmod/ozmod_analog/zap_analog.h (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,69 @@
</span><ins>+/*
+ * 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:
+ */
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapsrcozmodozmod_analog_emozmod_analog_em2005vcproj"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/src/ozmod/ozmod_analog_em/ozmod_analog_em.2005.vcproj (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,202 @@
</span><ins>+<?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>
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapsrcozmodozmod_analog_emozmod_analog_em2008vcproj"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/src/ozmod/ozmod_analog_em/ozmod_analog_em.2008.vcproj (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,353 @@
</span><ins>+<?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>
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapsrcozmodozmod_analog_emozmod_analog_emc"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/src/ozmod/ozmod_analog_em/ozmod_analog_em.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,707 @@
</span><ins>+/*
+ * 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:
+ */
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapsrcozmodozmod_analog_emzap_analog_emh"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/src/ozmod/ozmod_analog_em/zap_analog_em.h (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,70 @@
</span><ins>+/*
+ * 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:
+ */
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapsrcozmodozmod_isdnozmod_isdn2005vcproj"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/src/ozmod/ozmod_isdn/ozmod_isdn.2005.vcproj (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,316 @@
</span><ins>+<?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>
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapsrcozmodozmod_isdnozmod_isdn2008vcproj"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/src/ozmod/ozmod_isdn/ozmod_isdn.2008.vcproj (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,465 @@
</span><ins>+<?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>
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapsrcozmodozmod_isdnozmod_isdnc"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/src/ozmod/ozmod_isdn/ozmod_isdn.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,2420 @@
</span><ins>+/*
+ * 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:
+ */
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapsrcozmodozmod_isdnzap_isdnh"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/src/ozmod/ozmod_isdn/zap_isdn.h (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,96 @@
</span><ins>+/*
+ * 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:
+ */
+
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapsrcozmodozmod_libprilpwrap_pric"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/src/ozmod/ozmod_libpri/lpwrap_pri.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,303 @@
</span><ins>+/*
+ * 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:
+ */
+
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapsrcozmodozmod_libprilpwrap_prih"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/src/ozmod/ozmod_libpri/lpwrap_pri.h (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,126 @@
</span><ins>+/*
+ * 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
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapsrcozmodozmod_libpriozmod_libpric"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/src/ozmod/ozmod_libpri/ozmod_libpri.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,1363 @@
</span><ins>+/*
+ * 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:
+ */
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapsrcozmodozmod_libpriozmod_libprih"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/src/ozmod/ozmod_libpri/ozmod_libpri.h (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,97 @@
</span><ins>+/*
+ * 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:
+ */
+
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapsrcozmodozmod_pikaozmod_pika2005vcproj"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/src/ozmod/ozmod_pika/ozmod_pika.2005.vcproj (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,197 @@
</span><ins>+<?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>
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapsrcozmodozmod_pikaozmod_pika2008vcproj"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/src/ozmod/ozmod_pika/ozmod_pika.2008.vcproj (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,197 @@
</span><ins>+<?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>
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapsrcozmodozmod_pikaozmod_pikac"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/src/ozmod/ozmod_pika/ozmod_pika.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,1469 @@
</span><ins>+/*
+ * 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:
+ */
+
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapsrcozmodozmod_pikazap_pikah"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/src/ozmod/ozmod_pika/zap_pika.h (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,132 @@
</span><ins>+/*
+ * 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:
+ */
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapsrcozmodozmod_r2ozmod_r2c"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/src/ozmod/ozmod_r2/ozmod_r2.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,1364 @@
</span><ins>+/*
+ * 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
+ */
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapsrcozmodozmod_sangoma_boostozmod_sangoma_boostc"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/src/ozmod/ozmod_sangoma_boost/ozmod_sangoma_boost.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,1768 @@
</span><ins>+/*
+ * 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:
+ */
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapsrcozmodozmod_sangoma_boostsangoma_boost_clientc"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/src/ozmod/ozmod_sangoma_boost/sangoma_boost_client.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,527 @@
</span><ins>+/*
+ * 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:
+ */
+
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapsrcozmodozmod_sangoma_boostsangoma_boost_clienth"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/src/ozmod/ozmod_sangoma_boost/sangoma_boost_client.h (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,148 @@
</span><ins>+/*
+ * 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:
+ */
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapsrcozmodozmod_sangoma_boostsigboosth"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/src/ozmod/ozmod_sangoma_boost/sigboost.h (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,209 @@
</span><ins>+/****************************************************************************
+ * 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
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapsrcozmodozmod_sangoma_boostzap_sangoma_boosth"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/src/ozmod/ozmod_sangoma_boost/zap_sangoma_boost.h (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,62 @@
</span><ins>+/*
+ * 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:
+ */
+
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapsrcozmodozmod_skelozmod_skelc"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/src/ozmod/ozmod_skel/ozmod_skel.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,152 @@
</span><ins>+/*
+ * 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:
+ */
+
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapsrcozmodozmod_wanpipeozmod_wanpipe2005vcproj"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/src/ozmod/ozmod_wanpipe/ozmod_wanpipe.2005.vcproj (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,196 @@
</span><ins>+<?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>
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapsrcozmodozmod_wanpipeozmod_wanpipe2008vcproj"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/src/ozmod/ozmod_wanpipe/ozmod_wanpipe.2008.vcproj (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,355 @@
</span><ins>+<?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>
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapsrcozmodozmod_wanpipeozmod_wanpipec"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/src/ozmod/ozmod_wanpipe/ozmod_wanpipe.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,1235 @@
</span><ins>+/*
+ * 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
+ */
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapsrcozmodozmod_wanpipewanpipe_tdm_api_ifaceh"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/src/ozmod/ozmod_wanpipe/wanpipe_tdm_api_iface.h (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,351 @@
</span><ins>+/*****************************************************************************
+* 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
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapsrcozmodozmod_ztozmod_ztc"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/src/ozmod/ozmod_zt/ozmod_zt.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,1251 @@
</span><ins>+/*
+ * 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:
+ */
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapsrcozmodozmod_ztozmod_zth"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/src/ozmod/ozmod_zt/ozmod_zt.h (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,364 @@
</span><ins>+/*
+ * 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:
+ */
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapsrcpriserverc"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/src/priserver.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,328 @@
</span><ins>+/*****************************************************************************
+ * 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:
+ */
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapsrcsangoma_pric"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/src/sangoma_pri.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,251 @@
</span><ins>+/*****************************************************************************
+ * 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:
+ */
+
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapsrcsangoma_prih"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/src/sangoma_pri.h (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,100 @@
</span><ins>+/*****************************************************************************
+ * 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
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapsrcss7README"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/src/ss7/README (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,3 @@
</span><ins>+SS7 Coming soon
+
+-Shane Burrell-
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapsrctestanalogc"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/src/testanalog.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,133 @@
</span><ins>+#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:
+ */
+
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapsrctestappc"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/src/testapp.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,83 @@
</span><ins>+#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:
+ */
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapsrctestboostc"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/src/testboost.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,75 @@
</span><ins>+#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:
+ */
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapsrctestcidc"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/src/testcid.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,108 @@
</span><ins>+#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;
+}
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapsrctestisdnc"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/src/testisdn.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,74 @@
</span><ins>+#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:
+ */
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapsrctestm3uac"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/src/testm3ua.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,60 @@
</span><ins>+/*
+ * 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();
+
+}
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapsrctestpric"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/src/testpri.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,162 @@
</span><ins>+#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:
+ */
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapsrctestr2c"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/src/testr2.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,86 @@
</span><ins>+#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:
+ */
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapsrctesttonesc"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/src/testtones.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,76 @@
</span><ins>+#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
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapsrcuartc"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/src/uart.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,124 @@
</span><ins>+
+/*
+ *        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... */
+}
+
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapsrczap_bufferc"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/src/zap_buffer.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,302 @@
</span><ins>+/*
+ * 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:
+ */
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapsrczap_calleridc"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/src/zap_callerid.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,307 @@
</span><ins>+#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;
+}
+
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapsrczap_configc"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/src/zap_config.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,251 @@
</span><ins>+/*
+ * 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:
+ */
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapsrczap_cpu_monitorc"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/src/zap_cpu_monitor.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,271 @@
</span><ins>+/*
+ * 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:
+ */
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapsrczap_dsoc"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/src/zap_dso.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,115 @@
</span><ins>+/*
+ * 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
+ */
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapsrczap_ioc"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/src/zap_io.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,3526 @@
</span><ins>+/*
+ * 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:
+ */
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapsrczap_m3uac"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/src/zap_m3ua.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,692 @@
</span><ins>+/*
+ * 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:
+*/
</ins></span></pre></div>
<a id="freeswitchtrunklibsopenzapsrczap_threadmutexc"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/libs/openzap/src/zap_threadmutex.c (0 => 17141)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,454 @@
</span><ins>+/*
+ * 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:
+ */
</ins></span></pre>
</div>
</div>
<div id="footer">See you at ClueCon</div>
</body>
</html>