[Freeswitch-svn] [commit] r8321 - in freeswitch/trunk: . libs/iax src/mod/endpoints/mod_iax

Freeswitch SVN anthm at freeswitch.org
Thu May 8 19:25:36 EDT 2008


Author: anthm
Date: Thu May  8 19:25:36 2008
New Revision: 8321

Added:
   freeswitch/trunk/src/mod/endpoints/mod_iax/answer.h
   freeswitch/trunk/src/mod/endpoints/mod_iax/frame.h
   freeswitch/trunk/src/mod/endpoints/mod_iax/iax-client.h
   freeswitch/trunk/src/mod/endpoints/mod_iax/iax-mutex.c
   freeswitch/trunk/src/mod/endpoints/mod_iax/iax-mutex.h
   freeswitch/trunk/src/mod/endpoints/mod_iax/iax.c
   freeswitch/trunk/src/mod/endpoints/mod_iax/iax.h
   freeswitch/trunk/src/mod/endpoints/mod_iax/iax2-parser.c
   freeswitch/trunk/src/mod/endpoints/mod_iax/iax2-parser.h
   freeswitch/trunk/src/mod/endpoints/mod_iax/iax2.h
   freeswitch/trunk/src/mod/endpoints/mod_iax/jitterbuf.c
   freeswitch/trunk/src/mod/endpoints/mod_iax/jitterbuf.h
   freeswitch/trunk/src/mod/endpoints/mod_iax/md5.c
   freeswitch/trunk/src/mod/endpoints/mod_iax/md5.h
   freeswitch/trunk/src/mod/endpoints/mod_iax/winiphone.c
   freeswitch/trunk/src/mod/endpoints/mod_iax/winpoop.h
Removed:
   freeswitch/trunk/libs/iax/
Modified:
   freeswitch/trunk/configure.in
   freeswitch/trunk/src/mod/endpoints/mod_iax/Makefile

Log:
slim down iax build

Modified: freeswitch/trunk/configure.in
==============================================================================
--- freeswitch/trunk/configure.in	(original)
+++ freeswitch/trunk/configure.in	Thu May  8 19:25:36 2008
@@ -593,7 +593,6 @@
 AC_CONFIG_SUBDIRS(libs/voipcodecs)
 AC_CONFIG_SUBDIRS(libs/codec/ilbc)
 AC_CONFIG_SUBDIRS(libs/curl)
-AC_CONFIG_SUBDIRS(libs/iax)
 AC_CONFIG_SUBDIRS(libs/iksemel)
 AC_CONFIG_SUBDIRS(libs/js/nsprpub)
 AC_CONFIG_SUBDIRS(libs/js)

Modified: freeswitch/trunk/src/mod/endpoints/mod_iax/Makefile
==============================================================================
--- freeswitch/trunk/src/mod/endpoints/mod_iax/Makefile	(original)
+++ freeswitch/trunk/src/mod/endpoints/mod_iax/Makefile	Thu May  8 19:25:36 2008
@@ -1,11 +1,6 @@
 BASE=../../../..
+LOCAL_CFLAGS=-I. -DNEWJB -DLIBIAX
+LOCAL_OBJS=iax2-parser.o iax.o md5.o jitterbuf.o iax-mutex.o
 
-IAX_DIR=$(BASE)/libs/iax
-IAXLA=$(IAX_DIR)/src/libiax.la
-LOCAL_CFLAGS=-I$(IAX_DIR)/src
-LOCAL_LIBADD=$(IAXLA)
 include $(BASE)/build/modmake.rules
 
-$(IAXLA): $(IAX_DIR) $(IAX_DIR)/.update
-	cd $(IAX_DIR) && $(MAKE)
-

Added: freeswitch/trunk/src/mod/endpoints/mod_iax/answer.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/src/mod/endpoints/mod_iax/answer.h	Thu May  8 19:25:36 2008
@@ -0,0 +1,237 @@
+/*
+  * Signed 16-bit audio data
+  *
+  * Source: answer.raw
+  *
+  * Copyright (C) 1999, Mark Spencer and Linux Support Services
+  *
+  * Distributed under the terms of the GNU General Public License
+  *
+  */
+
+static signed short answer[] = {
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 0x19b7, 0x0245, 0xeee5, 0xb875, 0xd9a4, 0x6018, 0x660a, 0xc3c6, 
+0x8741, 0xff55, 0x4c2e, 0x2146, 0xfed2, 0xf079, 0xcbd4, 0xe561, 0x3c41, 0x3166, 
+0xd425, 0xdc59, 0x2748, 0x087d, 0xc72b, 0xfe3a, 0x4681, 0x14c6, 0xcf45, 0xdd38, 
+0xf8dd, 0x0a39, 0x3a5a, 0x32b9, 0xbfec, 0x957f, 0x15a3, 0x70f4, 0x1d95, 0xbfc4, 
+0xd367, 0xfda0, 0x0dc0, 0x29eb, 0x1fc2, 0xd684, 0xcab1, 0x19c7, 0x29ef, 0xe679, 
+0xe9d0, 0x2b82, 0x151a, 0xca9f, 0xdb68, 0x1f4a, 0x271c, 0x0e2a, 0xfb32, 0xd1b2, 
+0xc8ff, 0x2382, 0x6380, 0x0a52, 0xa118, 0xccbf, 0x2ddc, 0x33fd, 0x0964, 0xf2a4, 
+0xdd81, 0xe092, 0x1a00, 0x325c, 0xf5e3, 0xd6a1, 0x0b6c, 0x1c75, 0xe4f8, 0xe07c, 
+0x2082, 0x2b3e, 0xf445, 0xdaa9, 0xea13, 0xff3c, 0x245c, 0x35c1, 0xf308, 0xab53, 
+0xdf59, 0x4698, 0x3f3b, 0xe7f7, 0xca84, 0xed4d, 0x0c3f, 0x1e94, 0x1c2d, 0xf06f, 
+0xd4df, 0xff34, 0x23d8, 0x001e, 0xe3f1, 0x0b15, 0x2113, 0xf3fd, 0xd768, 0xf9a0, 
+0x1d31, 0x1c6e, 0x0797, 0xe3a0, 0xce6c, 0xfd7b, 0x422a, 0x2c4c, 0xd364, 0xbf42, 
+0x0278, 0x303e, 0x1c51, 0xf737, 0xe25a, 0xe75f, 0x0a8f, 0x22ab, 0x05f4, 0xe3f9, 
+0xf8c4, 0x1705, 0x0162, 0xe49f, 0xfb8b, 0x1e2b, 0x13ac, 0xf044, 0xe07b, 0xf01a, 
+0x1567, 0x2cbf, 0x0b75, 0xd01b, 0xd206, 0x1563, 0x38d7, 0x0f2e, 0xdb32, 0xdc30, 
+0x023b, 0x1e44, 0x16eb, 0xf5f7, 0xe425, 0xfa33, 0x14d5, 0x0968, 0xeff2, 0xf762, 
+0x1137, 0x0e59, 0xf13a, 0xe651, 0xff41, 0x1d60, 0x18fd, 0xf1e6, 0xd75f, 0xf097, 
+0x20ec, 0x27fa, 0xfba4, 0xd5b8, 0xe68e, 0x1657, 0x2518, 0x04f6, 0xe5a3, 0xe976, 
+0x0578, 0x18fa, 0x0a92, 0xec0a, 0xef2a, 0x111f, 0x12f4, 0xeec3, 0xe95e, 0x0d3a, 
+0x18fd, 0xff72, 0xeefc, 0xf114, 0xfaaa, 0x14ee, 0x21db, 0xf56e, 0xcb49, 0xf621, 
+0x3323, 0x1947, 0xe017, 0xe7e9, 0x0819, 0x0707, 0x084c, 0x0f57, 0xf152, 0xdf92, 
+0x104a, 0x28eb, 0xedcc, 0xd4ad, 0x1415, 0x296d, 0xed9a, 0xdf57, 0x0cc2, 0x0d95, 
+0xf7b5, 0x0deb, 0x0b34, 0xd713, 0xea08, 0x38d6, 0x216d, 0xc727, 0xdc32, 0x2cd2, 
+0x1822, 0xe2d5, 0xfeb3, 0x106c, 0xe6e5, 0xf81e, 0x2fe8, 0x01af, 0xc180, 0x037a, 
+0x42d8, 0xf88d, 0xc344, 0x0a4f, 0x2c4e, 0xf19d, 0xebeb, 0x162c, 0xf9e9, 0xde93, 
+0x1b56, 0x2c60, 0xd8aa, 0xce3e, 0x2a41, 0x2eeb, 0xdab1, 0xde32, 0x1c32, 0x0aba, 
+0xeabe, 0x1008, 0x136d, 0xda2f, 0xec3b, 0x31dd, 0x1130, 0xca79, 0xf5b8, 0x3423, 
+0x0274, 0xd27d, 0x035e, 0x1e68, 0xf641, 0xf904, 0x1691, 0xef7d, 0xd57a, 0x1c3b, 
+0x3c23, 0xe881, 0xc274, 0x0af5, 0x2962, 0xfa34, 0xf676, 0x0f71, 0xefcc, 0xe01f, 
+0x19e7, 0x276f, 0xe694, 0xe134, 0x1c3a, 0x0e8b, 0xd8e7, 0xfa81, 0x2f8b, 0x07c5, 
+0xd904, 0xf6fa, 0x0ca5, 0xf9a2, 0x0dc7, 0x2623, 0xec54, 0xbe23, 0x02b6, 0x4296, 
+0x10cd, 0xda61, 0xf11c, 0x0103, 0xf41c, 0x10b4, 0x2a03, 0xf63c, 0xce1a, 0xfdbd, 
+0x1fb4, 0xfc51, 0xf727, 0x1c8a, 0x04ff, 0xcf41, 0xec05, 0x2913, 0x1ce8, 0xf70c, 
+0xf744, 0xede8, 0xdd77, 0x0d99, 0x43f1, 0x119c, 0xc14f, 0xd60e, 0x17cb, 0x1e19, 
+0x0d4e, 0x0c95, 0xeed1, 0xcdf4, 0xf7a5, 0x331f, 0x1cd0, 0xeb17, 0xf082, 0xfb19, 
+0xe899, 0xfdeb, 0x323c, 0x2036, 0xdad3, 0xd134, 0xfd03, 0x1345, 0x1c10, 0x2239, 
+0xf656, 0xbc22, 0xdc3f, 0x3392, 0x3d59, 0xfd77, 0xdb4d, 0xe23f, 0xedbe, 0x0f7e, 
+0x35cc, 0x1947, 0xd5dc, 0xd1bf, 0x035d, 0x16fc, 0x1174, 0x1675, 0x0249, 0xd2d4, 
+0xd851, 0x184d, 0x32fe, 0x0f91, 0xee14, 0xe1e6, 0xdf9b, 0x016b, 0x3668, 0x2b2b, 
+0xe20c, 0xc554, 0xf257, 0x1c05, 0x1fc5, 0x14f0, 0xf891, 0xd41c, 0xdf83, 0x1865, 
+0x2de1, 0x0b16, 0xed58, 0xea0c, 0xea79, 0xfbd9, 0x22af, 0x2732, 0xf62f, 0xd389, 
+0xe7d9, 0x0b39, 0x1cdc, 0x1de3, 0x038a, 0xd809, 0xd5f7, 0x0b55, 0x305e, 0x1910, 
+0xf02e, 0xe089, 0xe7c7, 0x0195, 0x2265, 0x21da, 0xf743, 0xd8f2, 0xe978, 0x09a1, 
+0x190a, 0x17c5, 0x045a, 0xe46d, 0xdd06, 0xffb2, 0x2293, 0x1cfe, 0xfd4d, 0xe4f9, 
+0xe310, 0xfaf1, 0x1d22, 0x2376, 0x0113, 0xde3a, 0xe21b, 0x0204, 0x1ba1, 0x1bd6, 
+0x0333, 0xe563, 0xe104, 0xfd51, 0x1bc1, 0x1ccf, 0x0285, 0xe757, 0xe35e, 0xfaf2, 
+0x185d, 0x1d46, 0x06b7, 0xec13, 0xe108, 0xef6e, 0x121d, 0x2a17, 0x16a6, 0xe32c, 
+0xc9a9, 0xf070, 0x2f48, 0x3788, 0xfa4e, 0xc32a, 0xd9c2, 0x1fa1, 0x36fe, 0x07fa, 
+0xd9e4, 0xe577, 0x0e5e, 0x1755, 0xfb53, 0xed71, 0x0540, 0x19e0, 0x0301, 0xdc97, 
+0xe391, 0x1937, 0x367c, 0x0bc9, 0xca4c, 0xc96b, 0x105d, 0x461f, 0x2416, 0xd481, 
+0xbc97, 0xf8b7, 0x39af, 0x2ec9, 0xecc6, 0xcb50, 0xeee3, 0x1ffe, 0x1e8e, 0xf700, 
+0xe66a, 0xff58, 0x149f, 0x02e5, 0xe792, 0xf2d8, 0x1a4d, 0x225a, 0xf642, 0xce7f, 
+0xe6a6, 0x25e2, 0x38f5, 0x01d0, 0xc50f, 0xd243, 0x19bd, 0x3fc6, 0x14f0, 0xd2d7, 
+0xcdb6, 0x069a, 0x2ffe, 0x1847, 0xe6f8, 0xdf0a, 0x0337, 0x1a90, 0x067a, 0xeb5b, 
+0xf541, 0x143b, 0x14f2, 0xf092, 0xdc02, 0xfb91, 0x28a3, 0x2274, 0xeaa8, 0xc9e7, 
+0xef48, 0x2d01, 0x322e, 0xf6d2, 0xc7cb, 0xe13b, 0x1fda, 0x3217, 0x0458, 0xd690, 
+0xe2bf, 0x11c4, 0x21d5, 0x0291, 0xe5c8, 0xf3a9, 0x12ba, 0x11aa, 0xf22b, 0xe627, 
+0x03ec, 0x219a, 0x1036, 0xe2f2, 0xd93f, 0x059c, 0x2ed6, 0x1b75, 0xe227, 0xce55, 
+0xfb19, 0x2de0, 0x2477, 0xed08, 0xd148, 0xf307, 0x21d4, 0x2002, 0xf543, 0xdeac, 
+0xf7f9, 0x18a9, 0x11d6, 0xf0ef, 0xe8e4, 0x05ea, 0x1ba5, 0x0727, 0xe448, 0xe748, 
+0x100e, 0x265e, 0x07fc, 0xdbae, 0xde78, 0x0efa, 0x2ce0, 0x0f94, 0xddf1, 0xd9ea, 
+0x0797, 0x28f6, 0x12eb, 0xe60c, 0xdf46, 0x0469, 0x1fbb, 0x0ced, 0xe9f6, 0xe95f, 
+0x09fe, 0x1ab9, 0x02cb, 0xe5a4, 0xef2a, 0x1327, 0x1d7b, 0xfd07, 0xde3d, 0xed9c, 
+0x17e5, 0x22e7, 0xfe3a, 0xdb38, 0xe9b9, 0x161a, 0x2416, 0x0175, 0xde3d, 0xe9de, 
+0x1294, 0x1fc9, 0x00ea, 0xe2a7, 0xeee2, 0x1298, 0x1a7d, 0xfc1d, 0xe3bb, 0xf47a, 
+0x1642, 0x185e, 0xf727, 0xe1af, 0xf709, 0x19c3, 0x18e7, 0xf50d, 0xe010, 0xf75b, 
+0x1a9c, 0x18d8, 0xf4c5, 0xe0c9, 0xf865, 0x1a1c, 0x16d5, 0xf3a6, 0xe257, 0xfaf2, 
+0x1a44, 0x14d5, 0xf34f, 0xe4b6, 0xfc77, 0x17d5, 0x0ff8, 0xf133, 0xe8b7, 0x0344, 
+0x1a37, 0x0ad5, 0xe95e, 0xe61a, 0x08a5, 0x227e, 0x0e33, 0xe4a7, 0xdd70, 0x03b0, 
+0x25f4, 0x17b2, 0xec0a, 0xdb4e, 0xf898, 0x1ba3, 0x18f6, 0xf973, 0xe87f, 0xf77a, 
+0x0b93, 0x096c, 0xfb0e, 0xfb03, 0x0896, 0x0940, 0xf51d, 0xe904, 0xfdc7, 0x1dda, 
+0x1bf9, 0xf29b, 0xd37f, 0xea1b, 0x1f37, 0x3175, 0x07eb, 0xd3f7, 0xd46b, 0x077d, 
+0x2eeb, 0x1e67, 0xeeae, 0xd8c7, 0xef85, 0x1119, 0x18d3, 0x088e, 0xf953, 0xf5ad, 
+0xf556, 0xf63d, 0x0234, 0x167a, 0x19a1, 0xfbf9, 0xd873, 0xdd4b, 0x0f06, 0x3748, 
+0x21e6, 0xe181, 0xc032, 0xe79a, 0x2bec, 0x3e76, 0x0b1b, 0xce41, 0xcb23, 0xff96, 
+0x2d79, 0x26d1, 0xfcc7, 0xdf8a, 0xe525, 0xfd83, 0x10f1, 0x16d7, 0x0f50, 0xfaea, 
+0xe3f1, 0xe20f, 0x0158, 0x27d9, 0x2866, 0xf96f, 0xcb34, 0xd563, 0x11d6, 0x3d25, 
+0x2424, 0xe254, 0xc2c9, 0xe7cd, 0x248d, 0x34f5, 0x0c42, 0xdcd0, 0xd827, 0xfa65, 
+0x19eb, 0x1b50, 0x0721, 0xf396, 0xeb9c, 0xefde, 0x0016, 0x1594, 0x1cc1, 0x0658, 
+0xe22b, 0xd852, 0xfb3e, 0x2923, 0x2c78, 0xfc87, 0xcdb5, 0xd69c, 0x0e3c, 0x3527, 
+0x201f, 0xe993, 0xcf9e, 0xeb21, 0x183f, 0x25ea, 0x0c93, 0xed4d, 0xe5f9, 0xf548, 
+0x07fb, 0x117c, 0x0ff2, 0x0398, 0xf08c, 0xe628, 0xf489, 0x143b, 0x2419, 0x0ccf, 
+0xe2cc, 0xd5a6, 0xf861, 0x2615, 0x2a1b, 0xfeb4, 0xd543, 0xdc53, 0x09b4, 0x2901, 
+0x19ff, 0xf24a, 0xde86, 0xeec4, 0x0b7b, 0x1733, 0x0d0a, 0xfc24, 0xf1bb, 0xf110, 
+0xfa03, 0x0a0f, 0x15d4, 0x0e21, 0xf435, 0xe17e, 0xee90, 0x1225, 0x2527, 0x0efa, 
+0xe61f, 0xd916, 0xf7b8, 0x1f50, 0x2326, 0x0099, 0xe01e, 0xe473, 0x0491, 0x1b37, 
+0x1360, 0xfb17, 0xecd9, 0xf20d, 0x0051, 0x0aec, 0x0d4a, 0x073d, 0xfa5a, 0xeeb8, 
+0xf165, 0x0516, 0x17dc, 0x12da, 0xf71b, 0xe213, 0xed85, 0x0eef, 0x20c8, 0x0e09, 
+0xebcc, 0xe0d4, 0xf848, 0x1637, 0x19d6, 0x026b, 0xec09, 0xed00, 0xff9b, 0x0e5a, 
+0x0d6b, 0x026c, 0xf865, 0xf4da, 0xf888, 0x025a, 0x0cbb, 0x0d53, 0xff96, 0xeefa, 
+0xee80, 0x021c, 0x15d6, 0x126a, 0xf9c1, 0xe724, 0xf017, 0x0aa1, 0x18b6, 0x0b4e, 
+0xf2d7, 0xea91, 0xf957, 0x0cac, 0x1061, 0x03f4, 0xf6ad, 0xf476, 0xfbdf, 0x0489, 
+0x08b1, 0x06df, 0xffcf, 0xf766, 0xf537, 0xfddf, 0x0ad4, 0x0e15, 0x01da, 0xf205, 
+0xf0a0, 0x0082, 0x1066, 0x0e41, 0xfc71, 0xef1b, 0xf4ad, 0x05cd, 0x0f32, 0x07ed, 
+0xf9c8, 0xf401, 0xfa93, 0x04af, 0x088c, 0x04a7, 0xfe15, 0xf9f1, 0xfa64, 0xff1e, 
+0x0539, 0x078c, 0x02af, 0xfa1a, 0xf69d, 0xfd09, 0x075b, 0x0a3d, 0x01f2, 0xf761, 
+0xf642, 0xffa7, 0x08f3, 0x0830, 0xff05, 0xf7db, 0xf9bc, 0x0174, 0x068b, 0x04b2, 
+0xfeff, 0xfb39, 0xfc1a, 000000, 0x0371, 0x03d7, 0x00fe, 0xfd37, 0xfbe0, 0xfe78, 
+0x02af, 0x044a, 0x0180, 0xfd43, 0xfc00, 0xfed1, 0x02aa, 0x0346, 0x00dd, 0xfde0, 
+0xfbfe, 0x0114, 0x0987, 0x04bc, 0xf49d, 0xf23a, 0x06ab, 0x162e, 0x0544, 0xe76b, 
+0xea25, 0x1015, 0x2474, 0x0431, 0xd7d3, 0xe1ec, 0x1923, 0x2df5, 0x01cd, 0xd386, 
+0xe3d9, 0x1b9d, 0x2c62, 0xfeb8, 0xd31a, 0xe6ba, 0x1dbd, 0x2abb, 0xfbab, 0xd2ed, 
+0xe9ab, 0x1fa7, 0x28ef, 0xf8b3, 0xd2f5, 0xeca5, 0x2160, 0x26fd, 0xf5d7, 0xd334, 
+0xefa1, 0x22e5, 0x24ea, 0xf31b, 0xd3a9, 0xf29f, 0x2435, 0x22b6, 0xf07e, 0xd44e, 
+0xf59b, 0x2551, 0x2067, 0xee08, 0xd527, 0xf88e, 0x2639, 0x1e00, 0xebb6, 0xd62d, 
+0xfb77, 0x26eb, 0x1b85, 0xe98b, 0xd75f, 0xfe51, 0x276b, 0x18f9, 0xe78e, 0xd8b9, 
+0x011a, 0x27b6, 0x1660, 0xe5bb, 0xda3a, 0x03cc, 0x27cf, 0x13bd, 0xe415, 0xdbdf, 
+0x066a, 0x27b7, 0x1117, 0xe29e, 0xdda5, 0x08ec, 0x276e, 0x0e6d, 0xe154, 0xdf89, 
+0x0b52, 0x26f6, 0x0bc7, 0xe039, 0xe185, 0x0d96, 0x2653, 0x0924, 0xdf4e, 0xe399, 
+0x0fb9, 0x2584, 0x068b, 0xde93, 0xe5c0, 0x11b8, 0x248e, 0x03fd, 0xde08, 0xe7f8, 
+0x1390, 0x2372, 0x0180, 0xddaa, 0xea3c, 0x1544, 0x2231, 0xff12, 0xdd7a, 0xec89, 
+0x16cf, 0x20d0, 0xfcb9, 0xdd77, 0xeedb, 0x1831, 0x1f52, 0xfa77, 0xdd9f, 0xf132, 
+0x1969, 0x1db7, 0xf850, 0xddf1, 0xf385, 0x1a75, 0x1c06, 0xf645, 0xde6b, 0xf5d7, 
+0x1b5b, 0x1a3f, 0xf457, 0xdf0d, 0xf820, 0x1c13, 0x1867, 0xf288, 0xdfd2, 0xfa5f, 
+0x1ca1, 0x167f, 0xf0db, 0xe0ba, 0xfc92, 0x1d06, 0x148b, 0xef50, 0xe1c1, 0xfeb5, 
+0x1d43, 0x1290, 0xede9, 0xe2e6, 0x00c6, 0x1d58, 0x108e, 0xeca7, 0xe426, 0x02c4, 
+0x1d45, 0x0e8a, 0xeb8a, 0xe57f, 0x04a9, 0x1d0e, 0x0c87, 0xea92, 0xe6ec, 0x0677, 
+0x1cb2, 0x0a87, 0xe9be, 0xe86e, 0x082a, 0x1c34, 0x088b, 0xe912, 0xe9fe, 0x09c1, 
+0x1b95, 0x069c, 0xe88c, 0xeb9c, 0x0b3a, 0x1ad9, 0x04b6, 0xe82a, 0xed43, 0x0c96, 
+0x1a00, 0x02df, 0xe7eb, 0xeef3, 0x0dd0, 0x190d, 0x0116, 0xe7d0, 0xf0a8, 0x0eec, 
+0x1804, 0xff61, 0xe7d8, 0xf25d, 0x0fe6, 0x16e3, 0xfdc0, 0xe800, 0xf412, 0x10bf, 
+0x15b1, 0xfc36, 0xe848, 0xf5c5, 0x1176, 0x146e, 0xfac2, 0xe8ad, 0xf771, 0x120d, 
+0x1320, 0xf969, 0xe92e, 0xf913, 0x1282, 0x11c4, 0xf828, 0xe9cb, 0xfaac, 0x12d8, 
+0x1062, 0xf703, 0xea7e, 0xfc38, 0x130e, 0x0efa, 0xf5fb, 0xeb49, 0xfdb5, 0x1325, 
+0x0d8e, 0xf50e, 0xec26, 0xff20, 0x131e, 0x0c21, 0xf43f, 0xed15, 0x007a, 0x12fa, 
+0x0ab6, 0xf38d, 0xee15, 0x01be, 0x12bd, 0x094f, 0xf2f9, 0xef22, 0x02ef, 0x1265, 
+0x07f0, 0xf283, 0xf037, 0x0408, 0x11f6, 0x0699, 0xf226, 0xf156, 0x050a, 0x1170, 
+0x054b, 0xf1e8, 0xf27a, 0x05f4, 0x10d8, 0x040c, 0xf1c5, 0xf3a3, 0x06c2, 0x102c, 
+0x02da, 0xf1bc, 0xf4cc, 0x0779, 0x0f71, 0x01b7, 0xf1cc, 0xf5f5, 0x0815, 0x0ea7, 
+0x00a8, 0xf1f4, 0xf719, 0x0899, 0x0dd2, 0xffab, 0xf233, 0xf839, 0x0902, 0x0cf4, 
+0xfec0, 0xf288, 0xf950, 0x0952, 0x0c0e, 0xfdec, 0xf2ee, 0xfa5d, 0x0989, 0x0b23, 
+0xfd2d, 0xf368, 0xfb62, 0x09a7, 0x0a35, 0xfc85, 0xf3f1, 0xfc58, 0x09af, 0x0946, 
+0xfbf2, 0xf488, 0xfd3f, 0x09a1, 0x0859, 0xfb77, 0xf52c, 0xfe17, 0x097d, 0x076f, 
+0xfb14, 0xf5d8, 0xfede, 0x0945, 0x068a, 0xfac6, 0xf68d, 0xff93, 0x08fb, 0x05ad, 
+0xfa8e, 0xf747, 0x0034, 0x08a1, 0x04da, 0xfa6f, 0xf805, 0x00c2, 0x0836, 0x0410, 
+0xfa63, 0xf8c6, 0x013c, 0x07bf, 0x0354, 0xfa6c, 0xf985, 0x01a1, 0x073b, 0x02a4, 
+0xfa8a, 0xfa43, 0x01f1, 0x06af, 0x0204, 0xfab9, 0xfafc, 0x022c, 0x0619, 0x0175, 
+0xfafa, 0xfbae, 0x0252, 0x057f, 0x00f6, 0xfb4b, 0xfc5a, 0x0263, 0x04e0, 0x008b, 
+0xfbaa, 0xfcfa, 0x0262, 0x0440, 0x0032, 0xfc16, 0xfd90, 0x024b, 0x03a0, 0xffec, 
+0xfc8c, 0xfe19, 0x0225, 0x0301, 0xffb9, 0xfd0c, 0xfe93, 0x01ea, 0x0267, 0xff9c, 
+0xfd95, 0xfefe, 0x01a0, 0x01d3, 0xff90, 0xfe22, 0xff5a, 0x0147, 0x0145, 0xff99, 
+0xfeb3, 0xffa1, 0x00e0, 0x00c3, 0xffb6, 0xff46, 0xffd9, 0x006d, 0x004b, 0xffe5, 
+0xffda, 0xfffc, 000000, 0xfffe, 000000, 0xffff, 000000, 0xffff, 0xffff, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 000000, 
+000000 };

Added: freeswitch/trunk/src/mod/endpoints/mod_iax/frame.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/src/mod/endpoints/mod_iax/frame.h	Thu May  8 19:25:36 2008
@@ -0,0 +1,134 @@
+/*
+ * libiax: An implementation of the Inter-Asterisk eXchange protocol
+ *
+ * Asterisk internal frame definitions.
+ * 
+ * Copyright (C) 1999, Mark Spencer
+ *
+ * Mark Spencer <markster at linux-support.net>
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU Lesser General Public License.  Other components of
+ * Asterisk are distributed under The GNU General Public License
+ * only.
+ */
+
+#ifndef _LIBIAX_FRAME_H
+#define _LIBIAX_FRAME_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+/* Frame types */
+#define AST_FRAME_DTMF		1		/* A DTMF digit, subclass is the digit */
+#define AST_FRAME_VOICE		2		/* Voice data, subclass is AST_FORMAT_* */
+#define AST_FRAME_VIDEO		3		/* Video frame, maybe?? :) */
+#define AST_FRAME_CONTROL	4		/* A control frame, subclass is AST_CONTROL_* */
+#define AST_FRAME_NULL		5		/* An empty, useless frame */
+#define AST_FRAME_IAX		6		/* Inter Aterisk Exchange private frame type */
+#define AST_FRAME_TEXT		7		/* Text messages */
+#define AST_FRAME_IMAGE		8		/* Image Frames */
+#define AST_FRAME_HTML		9		/* HTML Frames */
+#define AST_FRAME_CNG           10		/* Comfort Noise frame (subclass is level of CNG in -dBov) */
+
+/* HTML subclasses */
+#define AST_HTML_URL		1		/* Sending a URL */
+#define AST_HTML_DATA		2		/* Data frame */
+#define AST_HTML_BEGIN		4		/* Beginning frame */
+#define AST_HTML_END		8		/* End frame */
+#define AST_HTML_LDCOMPLETE	16		/* Load is complete */
+#define AST_HTML_NOSUPPORT	17		/* Peer is unable to support HTML */
+#define AST_HTML_LINKURL	18		/* Send URL and track */
+#define AST_HTML_UNLINK		19		/* Request no more linkage */
+#define AST_HTML_LINKREJECT	20		/* Reject LINKURL */
+
+/* Data formats for capabilities and frames alike */
+/*! G.723.1 compression */
+#define AST_FORMAT_G723_1       (1 << 0)
+	/*! GSM compression */
+#define AST_FORMAT_GSM          (1 << 1)
+	/*! Raw mu-law data (G.711) */
+#define AST_FORMAT_ULAW         (1 << 2)
+	/*! Raw A-law data (G.711) */
+#define AST_FORMAT_ALAW         (1 << 3)
+	/*! ADPCM (G.726, 32kbps) */
+#define AST_FORMAT_G726         (1 << 4)
+	/*! ADPCM (IMA) */
+#define AST_FORMAT_ADPCM        (1 << 5)
+	/*! Raw 16-bit Signed Linear (8000 Hz) PCM */
+#define AST_FORMAT_SLINEAR      (1 << 6)
+	/*! LPC10, 180 samples/frame */
+#define AST_FORMAT_LPC10        (1 << 7)
+	/*! G.729A audio */
+#define AST_FORMAT_G729A        (1 << 8)
+	/*! SpeeX Free Compression */
+#define AST_FORMAT_SPEEX        (1 << 9)
+	/*! iLBC Free Compression */
+#define AST_FORMAT_ILBC         (1 << 10)
+	/*! Maximum audio format */
+#define AST_FORMAT_MAX_AUDIO    (1 << 15)
+	/*! JPEG Images */
+#define AST_FORMAT_JPEG         (1 << 16)
+	/*! PNG Images */
+#define AST_FORMAT_PNG          (1 << 17)
+	/*! H.261 Video */
+#define AST_FORMAT_H261         (1 << 18)
+	/*! H.263 Video */
+#define AST_FORMAT_H263         (1 << 19)
+	/*! Max one */
+#define AST_FORMAT_MAX_VIDEO    (1 << 24)
+
+/* Control frame types */
+#define AST_CONTROL_HANGUP		1			/* Other end has hungup */
+#define AST_CONTROL_RING		2			/* Local ring */
+#define AST_CONTROL_RINGING 	3			/* Remote end is ringing */
+#define AST_CONTROL_ANSWER		4			/* Remote end has answered */
+#define AST_CONTROL_BUSY		5			/* Remote end is busy */
+#define AST_CONTROL_TAKEOFFHOOK 6			/* Make it go off hook */
+#define AST_CONTROL_OFFHOOK		7			/* Line is off hook */
+#define AST_CONTROL_CONGESTION	8			/* Congestion (circuits busy) */
+#define AST_CONTROL_FLASH		9			/* Flash hook */
+#define AST_CONTROL_WINK		10			/* Wink */
+#define AST_CONTROL_OPTION		11			/* Set an option */
+
+#define AST_FRIENDLY_OFFSET		64			/* Reserved header space */
+
+struct ast_frame {
+        /*! Kind of frame */
+        int frametype;
+        /*! Subclass, frame dependent */
+        int subclass;
+        /*! Length of data */
+        int datalen;
+        /*! Number of 8khz samples in this frame */
+        int samples;
+        /*! Was the data malloc'd?  i.e. should we free it when we discard the f
+rame? */
+        int mallocd;
+        /*! How far into "data" the data really starts */
+        int offset;
+        /*! Optional source of frame for debugging */
+        char *src;
+        /*! Pointer to actual data */
+        void *data;
+        /*! Next/Prev for linking stand alone frames */
+        struct ast_frame *prev;
+       /*! Next/Prev for linking stand alone frames */
+        struct ast_frame *next;
+                                                                /* Unused except
+ if debugging is turned on, but left
+                                                                   in the struct
+ so that it can be turned on without
+                                                                   requiring a r
+ecompile of the whole thing */
+};
+
+
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+
+#endif

Added: freeswitch/trunk/src/mod/endpoints/mod_iax/iax-client.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/src/mod/endpoints/mod_iax/iax-client.h	Thu May  8 19:25:36 2008
@@ -0,0 +1,244 @@
+/*
+ * Asterisk -- A telephony toolkit for Linux.
+ *
+ * Implementation of Inter-Asterisk eXchange
+ * 
+ * Copyright (C) 1999, Mark Spencer
+ *
+ * Mark Spencer <markster at linux-support.net>
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU Lesser General Public License (LGPL)
+ */
+ 
+#ifndef _ASTERISK_IAX_CLIENT_H
+#define _ASTERISK_IAX_CLIENT_H
+
+#ifdef WIN32_TIME_GET_TIME
+#include <Mmsystem.h>
+#endif
+
+#if defined(_MSC_VER)
+/* disable zero-sized array in struct/union warning */
+#pragma warning(disable:4200)
+#endif
+
+#if !defined(LINUX) && !defined(NETBSD)
+#define socklen_t int
+#endif
+
+#include "frame.h"
+#include "iax2.h"
+#include "iax2-parser.h"
+
+#define MAXSTRLEN 80
+
+#define IAX_AUTHMETHOD_PLAINTEXT 	IAX_AUTH_PLAINTEXT
+#define IAX_AUTHMETHOD_MD5 			IAX_AUTH_MD5
+
+extern char iax_errstr[];
+
+struct iax_session;
+
+
+#define IAX_EVENT_CONNECT 0			/* Connect a new call */
+#define IAX_EVENT_ACCEPT  1			/* Accept a call */
+#define IAX_EVENT_HANGUP  2			/* Hang up a call */
+#define IAX_EVENT_REJECT  3			/* Rejected call */
+#define IAX_EVENT_VOICE   4			/* Voice Data */
+#define IAX_EVENT_DTMF    5			/* A DTMF Tone */
+#define IAX_EVENT_TIMEOUT 6			/* Connection timeout...  session will be
+									   a pointer to free()'d memory! */
+#define IAX_EVENT_LAGRQ   7			/* Lag request -- Internal use only */
+#define IAX_EVENT_LAGRP   8			/* Lag Measurement.  See event.lag */
+#define IAX_EVENT_RINGA	  9			/* Announce we/they are ringing */
+#define IAX_EVENT_PING	  10		/* Ping -- internal use only */
+#define IAX_EVENT_PONG	  11		/* Pong -- internal use only */
+#define IAX_EVENT_BUSY	  12		/* Report a line busy */
+#define IAX_EVENT_ANSWER  13		/* Answer the line */
+
+#define IAX_EVENT_IMAGE   14		/* Send/Receive an image */
+#define IAX_EVENT_AUTHRQ  15		/* Authentication request */
+#define IAX_EVENT_AUTHRP  16		/* Authentication reply */
+
+#define IAX_EVENT_REGREQ  17		/* Registration request */
+#define IAX_EVENT_REGACK  18		/* Registration reply */
+#define IAX_EVENT_URL	  19		/* URL received */
+#define IAX_EVENT_LDCOMPLETE 20		/* URL loading complete */
+
+#define IAX_EVENT_TRANSFER	21		/* Transfer has taken place */
+
+#define IAX_EVENT_DPREQ		22		/* Dialplan request */
+#define IAX_EVENT_DPREP		23		/* Dialplan reply */
+#define IAX_EVENT_DIAL		24		/* Dial on a TBD call */
+
+#define IAX_EVENT_QUELCH	25		/* Quelch Audio */
+#define IAX_EVENT_UNQUELCH	26		/* Unquelch Audio */
+
+#define IAX_EVENT_UNLINK	27		/* Unlink */
+#define IAX_EVENT_LINKREJECT	28		/* Link Rejection */
+#define IAX_EVENT_TEXT		29		/* Text Frame :-) */
+#define IAX_EVENT_REGREJ  30		/* Registration reply */
+#define IAX_EVENT_LINKURL	31		/* Unlink */
+#define IAX_EVENT_CNG	32		/* Comfort-noise (almost silence) */
+#define IAX_EVENT_POKE   33
+
+/* moved from iax.c to support attended transfer */
+#define IAX_EVENT_REREQUEST	999
+#define IAX_EVENT_TXREPLY	1000
+#define IAX_EVENT_TXREJECT	1001
+#define IAX_EVENT_TXACCEPT  1002
+#define IAX_EVENT_TXREADY	1003
+
+#define IAX_SCHEDULE_FUZZ 0			/* ms of fuzz to drop */
+
+#ifdef WIN32
+#if defined(_MSC_VER)
+typedef int (__stdcall *sendto_t)(SOCKET, const char *, int, int, const struct sockaddr *, int);
+typedef int (__stdcall *recvfrom_t)(SOCKET, char *, int, int, struct sockaddr *, int *);
+#else
+typedef int PASCAL (*sendto_t)(SOCKET, const char *, int, int, const struct sockaddr *, int);
+typedef int PASCAL (*recvfrom_t)(SOCKET, char *buf, int len, int flags, struct sockaddr *from, int *fromlen);
+#endif
+#else
+typedef int (*sendto_t)(int, const void *, size_t, int, const struct sockaddr *, socklen_t);
+typedef int (*recvfrom_t)(int s, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen);
+#endif
+
+struct iax_event {
+	int etype;						/* Type of event */
+	int subclass;					/* Subclass data (event specific) */
+	time_in_ms_t ts;				/* Timestamp */
+	struct iax_session *session;	/* Applicable session */
+	int datalen;					/* Length of raw data */
+	struct iax_ies ies;				/* IE's for IAX2 frames */
+	unsigned char data[];			/* Raw data if applicable */
+};
+
+#if defined(__cplusplus)
+extern "C"
+{
+#endif
+
+/* All functions return 0 on success and -1 on failure unless otherwise
+   specified */
+
+/* Called to initialize IAX structures and sockets.  Returns actual
+   portnumber (which it will try preferred portno first, but if not
+   take what it can get */
+extern int iax_init(char *ip, int preferredportno);
+
+extern int iax_shutdown(void);
+
+/* Get filedescriptor for IAX to use with select or gtk_input_add */
+extern int iax_get_fd(void);
+
+/* Find out how many milliseconds until the next scheduled event */
+extern time_in_ms_t iax_time_to_next_event(void);
+
+/* Generate a new IAX session */
+extern struct iax_session *iax_session_new(void);
+
+/* Return exactly one iax event (if there is one pending).  If blocking is
+   non-zero, IAX will block until some event is received */
+extern struct iax_event *iax_get_event(int blocking);
+
+
+extern int iax_auth_reply(struct iax_session *session, char *password, 
+						char *challenge, int methods);
+
+/* Free an event */
+extern void iax_event_free(struct iax_event *event);
+
+struct sockaddr_in;
+
+/* Front ends for sending events */
+extern int iax_send_dtmf(struct iax_session *session, char digit);
+extern int iax_send_voice(struct iax_session *session, int format, unsigned char *data, int datalen, int samples);
+extern int iax_send_cng(struct iax_session *session, int level, unsigned char *data, int datalen);
+extern int iax_send_image(struct iax_session *session, int format, unsigned char *data, int datalen);
+extern int iax_send_url(struct iax_session *session, char *url, int link);
+extern int iax_send_text(struct iax_session *session, char *text);
+extern int iax_send_ping(struct iax_session *session);
+extern int iax_load_complete(struct iax_session *session);
+extern int iax_reject(struct iax_session *session, const char *reason);
+int iax_reject_registration(struct iax_session *session, char *reason);
+int iax_ack_registration(struct iax_session *session);
+int iax_auth_registration(struct iax_session *session);
+extern int iax_busy(struct iax_session *session);
+extern int iax_congestion(struct iax_session *session);
+extern int iax_hangup(struct iax_session *session, char *byemsg);
+extern int iax_call(struct iax_session *session, const char *cidnum, const char *cidname, char *ich, char *lang, int wait, int format, int capability);
+extern int iax_accept(struct iax_session *session, int format);
+extern int iax_answer(struct iax_session *session);
+extern int iax_sendurl(struct iax_session *session, char *url);
+extern int iax_send_unlink(struct iax_session *session);
+extern int iax_send_link_reject(struct iax_session *session);
+extern int iax_ring_announce(struct iax_session *session);
+extern struct sockaddr_in iax_get_peer_addr(struct iax_session *session);
+extern int iax_register(struct iax_session *session, char *hostname, char *peer, char *secret, int refresh);
+extern int iax_lag_request(struct iax_session *session);
+extern int iax_dial(struct iax_session *session, char *number);	/* Dial on a TBD call */
+extern int iax_dialplan_request(struct iax_session *session, char *number);	/* Request dialplan status for number */
+extern int iax_quelch(struct iax_session *session);
+extern int iax_unquelch(struct iax_session * session);
+extern int iax_transfer(struct iax_session *session, char *number);  
+extern int iax_quelch_moh(struct iax_session *session, int MOH);
+
+extern void iax_destroy(struct iax_session  * session);
+
+extern void iax_enable_debug(void);
+extern void iax_disable_debug(void);
+
+/* For attended transfer, application create a new session,
+ * make a call on the new session.
+ * On answer of the new session, call iax_setup_transfer and wait for
+ * IAX_EVENT_TXREADY when both sides are completed succefully or
+ * IAX_EVENT_TXREJECT for either side.
+ * If there are music on hold the it will be stopped by this library.
+ */
+extern int iax_setup_transfer(struct iax_session *s0, struct iax_session *s1);
+
+struct iax_netstat {
+	time_in_ms_t jitter;
+	int losspct;
+	int losscnt;
+	int packets;
+	time_in_ms_t delay;
+	int dropped;
+	int ooo;
+};
+/* fills in rtt, and an iax_netstat structure for each of local/remote directions of call */
+extern int iax_get_netstats(struct iax_session *s, time_in_ms_t *rtt, struct iax_netstat *local, struct iax_netstat *remote);
+
+
+extern void iax_set_private(struct iax_session *s, void *pvt);
+extern void *iax_get_private(struct iax_session *s);
+extern void iax_set_sendto(struct iax_session *s, sendto_t sendto);
+
+/* to use application networking instead of internal, set call this instead of iax_init,
+ * and pass in sendto and recvfrom replacements.  blocking reads may not be implemented */
+extern void iax_set_networking(sendto_t st, recvfrom_t rf);
+
+/* destroy an iax session */
+extern void iax_session_destroy(struct iax_session **session);
+
+/* Handle externally received frames */
+struct iax_event *iax_net_process(unsigned char *buf, int len, struct sockaddr_in *sin);
+extern unsigned int iax_session_get_capability(struct iax_session *s);
+extern char iax_pref_codec_add(struct iax_session *session, unsigned int format);
+extern void iax_pref_codec_del(struct iax_session *session, unsigned int format);
+extern int iax_pref_codec_get(struct iax_session *session, unsigned int *array, int len);
+
+/* Fine tune jitterbuffer */
+extern void iax_set_jb_target_extra( long value );
+
+extern char *iax_get_peer_ip(struct iax_session *session);
+extern char *iax_event_get_apparent_ip(struct iax_event *event);
+extern void iax_set_samplerate(struct iax_session *session, unsigned short samplemask);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* _ASTERISK_IAX_CLIENT_H */

Added: freeswitch/trunk/src/mod/endpoints/mod_iax/iax-mutex.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/src/mod/endpoints/mod_iax/iax-mutex.c	Thu May  8 19:25:36 2008
@@ -0,0 +1,124 @@
+/* 
+ * Simple 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. 
+ *
+ */
+
+#define _XOPEN_SOURCE 600
+#include <stdlib.h>
+#include "iax-mutex.h"
+
+
+#ifdef WIN32
+#define _WIN32_WINNT 0x0400
+#include <windows.h>
+struct mutex {
+	CRITICAL_SECTION mutex;
+};
+
+#else
+
+#include <pthread.h>
+struct mutex {
+	pthread_mutex_t mutex;
+};
+
+#endif
+
+
+mutex_status_t iax_mutex_create(mutex_t **mutex)
+{
+	mutex_status_t status = MUTEX_FAILURE;
+#ifndef WIN32
+	pthread_mutexattr_t attr;
+#endif
+	mutex_t *check = NULL;
+
+	check = (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 = MUTEX_SUCCESS;
+
+done:
+	return status;
+}
+
+mutex_status_t iax_mutex_destroy(mutex_t *mutex)
+{
+#ifdef WIN32
+	DeleteCriticalSection(&mutex->mutex);
+#else
+	if (pthread_mutex_destroy(&mutex->mutex))
+		return MUTEX_FAILURE;
+#endif
+	free(mutex);
+	return MUTEX_SUCCESS;
+}
+
+mutex_status_t iax_mutex_lock(mutex_t *mutex)
+{
+#ifdef WIN32
+	EnterCriticalSection(&mutex->mutex);
+#else
+	if (pthread_mutex_lock(&mutex->mutex))
+		return MUTEX_FAILURE;
+#endif
+	return MUTEX_SUCCESS;
+}
+
+mutex_status_t iax_mutex_trylock(mutex_t *mutex)
+{
+#ifdef WIN32
+	if (!TryEnterCriticalSection(&mutex->mutex))
+		return MUTEX_FAILURE;
+#else
+	if (pthread_mutex_trylock(&mutex->mutex))
+		return MUTEX_FAILURE;
+#endif
+	return MUTEX_SUCCESS;
+}
+
+mutex_status_t iax_mutex_unlock(mutex_t *mutex)
+{
+#ifdef WIN32
+	LeaveCriticalSection(&mutex->mutex);
+#else
+	if (pthread_mutex_unlock(&mutex->mutex))
+		return MUTEX_FAILURE;
+#endif
+	return MUTEX_SUCCESS;
+}

Added: freeswitch/trunk/src/mod/endpoints/mod_iax/iax-mutex.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/src/mod/endpoints/mod_iax/iax-mutex.h	Thu May  8 19:25:36 2008
@@ -0,0 +1,37 @@
+/* 
+ * Simple 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 _SIMPLE_ABSTRACT_MUTEX_H
+#define _SIMPLE_ABSTRACT_MUTEX_H
+
+typedef struct mutex mutex_t;
+
+typedef enum mutex_status {
+	MUTEX_SUCCESS,
+	MUTEX_FAILURE
+} mutex_status_t;
+
+mutex_status_t iax_mutex_create(mutex_t **mutex);
+mutex_status_t iax_mutex_destroy(mutex_t *mutex);
+mutex_status_t iax_mutex_lock(mutex_t *mutex);
+mutex_status_t iax_mutex_trylock(mutex_t *mutex);
+mutex_status_t iax_mutex_unlock(mutex_t *mutex);
+
+#endif

Added: freeswitch/trunk/src/mod/endpoints/mod_iax/iax.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/src/mod/endpoints/mod_iax/iax.c	Thu May  8 19:25:36 2008
@@ -0,0 +1,3366 @@
+ /*
+ * libiax: An implementation of Inter-Asterisk eXchange
+ *
+ * Copyright (C) 2001, Linux Support Services, Inc.
+ *
+ * Mark Spencer <markster at linux-support.net>
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU Lesser (Library) General Public License
+ */
+ 
+#ifdef	WIN32
+#undef __STRICT_ANSI__ //for strdup with ms
+
+#include <string.h>
+#include <process.h>
+#include <windows.h>
+#include <winsock.h>
+#include <time.h>
+#include <stdlib.h>
+#include <malloc.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <io.h>
+#include <errno.h>
+#include <limits.h>
+
+
+#define	snprintf _snprintf
+
+#if defined(_MSC_VER)
+#define	close		_close
+#define inline __inline
+#define strdup _strdup
+#endif
+
+void gettimeofday(struct timeval *tv, void /*struct timezone*/ *tz);
+#include "winpoop.h"
+
+#else
+
+#define _BSD_SOURCE 1
+#include <netdb.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <sys/time.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/select.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <time.h>
+       
+#endif
+
+#include "iax2.h"
+#include "iax-client.h"
+#include "md5.h"
+
+#ifdef NEWJB
+#include "jitterbuf.h"
+#endif
+#include "iax-mutex.h"
+/*
+	work around jitter-buffer shrinking in asterisk:
+	channels/chan_iax2.c:schedule_delivery() shrinks jitter buffer by 2.
+	this causes frames timestamped 1ms apart to ( sometimes ) be delivered 
+	out of order, and results in garbled audio. our temporary fix is to increase
+	the minimum number of ( timestamped ) milliseconds between frames to 3 ( 2 + 1 ).
+*/
+#define IAX_MIN_TIMESTAMP_INCREMENT 3
+
+/* Define socket options for IAX2 sockets, based on platform
+ * availability of flags */
+#ifdef WIN32
+ #define IAX_SOCKOPTS 0
+#else
+ #ifdef LINUX
+ #define IAX_SOCKOPTS MSG_DONTWAIT | MSG_NOSIGNAL
+ #else
+ #define IAX_SOCKOPTS MSG_DONTWAIT
+ #endif
+#endif
+
+
+
+#ifdef SNOM_HACK
+/* The snom phone seems to improperly execute memset in some cases */
+#include "../../snom_phonecore2/include/snom_memset.h"
+#endif
+
+/* Voice TS Prediction causes libiax2 to clean up the timestamps on
+ * outgoing frames.  It works best with either continuous voice, or
+ * callers who call iax_send_cng to indicate DTX for silence */
+#define USE_VOICE_TS_PREDICTION
+
+/* Define Voice Smoothing to try to make some judgements and adjust timestamps
+   on incoming packets to what they "ought to be" */
+
+#define VOICE_SMOOTHING
+#undef VOICE_SMOOTHING
+
+/* Define Drop Whole Frames to make IAX shrink its jitter buffer by dropping entire
+   frames rather than simply delivering them faster.  Dropping encoded frames, 
+   before they're decoded, usually leads to better results than dropping 
+   decoded frames. */
+
+#define DROP_WHOLE_FRAMES
+
+#define MIN_RETRY_TIME 10
+#define MAX_RETRY_TIME 4000
+#define MEMORY_SIZE 1000
+
+#define TRANSFER_NONE  0
+#define TRANSFER_BEGIN 1
+#define TRANSFER_READY 2
+#define TRANSFER_REL   3
+
+#ifndef NEWJB
+/* No more than 4 seconds of jitter buffer */
+static int max_jitterbuffer = 4000;
+/* No more than 50 extra milliseconds of jitterbuffer than needed */
+static int max_extra_jitterbuffer = 50;
+/* To use or not to use the jitterbuffer */
+static int iax_use_jitterbuffer = 1;
+
+/* Dropcount (in per-MEMORY_SIZE) usually percent */
+static int iax_dropcount = 3;
+#endif
+
+/* UDP Socket (file descriptor) */
+static int netfd = -1;
+
+/* Max timeouts */
+static int maxretries = 10;
+
+/* configurable jitterbuffer options */
+static long jb_target_extra = -1; 
+
+static int do_shutdown = 0;
+
+/* external global networking replacements */
+static sendto_t	  iax_sendto = (sendto_t) sendto;
+static recvfrom_t iax_recvfrom = (recvfrom_t) recvfrom;
+
+/* ping interval (seconds) */
+static int ping_time = 10;
+static void send_ping(void *session);
+
+struct iax_session {
+	/* Private data */
+	void *pvt;
+	/* session-local Sendto function */
+	sendto_t sendto;
+	/* Is voice quelched (e.g. hold) */
+	int quelch;
+	/* Codec Pref Order */
+	char codec_order[32];
+	/* Codec Pref Order Index*/
+	int codec_order_len;
+	/* Last received voice format */
+	int voiceformat;
+	/* Last transmitted voice format */
+	int svoiceformat;
+	/* Per session capability */
+	int capability;
+	/* Last received timestamp */
+	time_in_ms_t last_ts;
+	/* Last transmitted timestamp */
+	time_in_ms_t lastsent;
+	/* Last transmitted voice timestamp */
+	unsigned int lastvoicets;
+	/* Next predicted voice ts */
+	time_in_ms_t nextpred;
+	/* True if the last voice we transmitted was not silence/CNG */
+	int notsilenttx;
+	/* Our last measured ping time */
+	time_in_ms_t pingtime;
+	/* Address of peer */
+	struct sockaddr_in peeraddr;
+	/* Our call number */
+	int callno;
+	/* Peer's call number */
+	int peercallno;
+	/* Our next outgoing sequence number */
+	unsigned char oseqno;
+	/* Next sequence number they have not yet acknowledged */
+	unsigned char rseqno;
+	/* Our last received incoming sequence number */
+	unsigned char iseqno;
+	/* Last acknowledged sequence number */
+	unsigned char aseqno;
+	/* Peer supported formats */
+	int peerformats;
+	/* Time value that we base our transmission on */
+	time_in_ms_t offset;
+	/* Time value we base our delivery on */
+	time_in_ms_t rxcore;
+	/* History of lags */
+	int history[MEMORY_SIZE];
+	/* Current base jitterbuffer */
+	int jitterbuffer;
+	/* Informational jitter */
+	int jitter;
+	/* Measured lag */
+	int lag;
+	/* Current link state */
+	int state;
+	/* Peer name */
+	char peer[MAXSTRLEN];
+	/* Default Context */
+	char context[MAXSTRLEN];
+	/* Caller ID if available */
+	char callerid[MAXSTRLEN];
+	/* DNID */
+	char dnid[MAXSTRLEN];
+	/* Requested Extension */
+	char exten[MAXSTRLEN];
+	/* Expected Username */
+	char username[MAXSTRLEN];
+	/* Expected Secret */
+	char secret[MAXSTRLEN];
+	/* permitted authentication methods */
+	char methods[MAXSTRLEN];
+	/* MD5 challenge */
+	char challenge[12];
+#ifdef VOICE_SMOOTHING
+	unsigned int lastts;
+#endif
+	/* Refresh if applicable */
+	int refresh;
+
+	/* ping scheduler id */
+	int pingid;
+	
+	/* Transfer stuff */
+	struct sockaddr_in transfer;
+	int transferring;
+	int transfercallno;
+	int transferid;
+	int transferpeer;	/* for attended transfer */
+	int transfer_moh;	/* for music on hold while performing attended transfer */
+
+#ifdef NEWJB
+	jitterbuf *jb;
+#endif
+	struct iax_netstat remote_netstats;
+
+	unsigned short samplemask;
+	/* For linking if there are multiple connections */
+	struct iax_session *next;
+};
+
+char iax_errstr[256];
+
+static void destroy_session(struct iax_session *session);
+
+#define IAXERROR snprintf(iax_errstr, sizeof(iax_errstr), 
+
+#ifdef DEBUG_SUPPORT
+
+#ifdef DEBUG_DEFAULT
+static int debug = 1;
+#else
+static int debug = 0;
+#endif
+
+void iax_enable_debug(void)
+{
+	debug = 1;
+}
+
+void iax_disable_debug(void)
+{
+	debug = 0;
+}
+
+/* This is a little strange, but to debug you call DEBU(G "Hello World!\n"); */ 
+#ifdef WIN32
+#define G __FILE__, __LINE__, __FUNCTION__, 
+#else
+#define G __FILE__, __LINE__, (const char *)__func__, 
+#endif
+
+#define DEBU __debug 
+static int __debug(char *file, int lineno, const char *func, char *fmt, ...) 
+{
+	va_list args;
+	va_start(args, fmt);
+	if (debug) {
+		fprintf(stderr, "%s line %d in %s: ", file, lineno, func);
+		vfprintf(stderr, fmt, args);
+	}
+	va_end(args);
+	return 0;
+}
+
+#else /* No debug support */
+
+#ifdef	WIN32
+#define	DEBU
+#else
+#define DEBU(...) (void)(0)
+#endif
+#define G
+#endif
+
+typedef void (*sched_func)(void *);
+
+struct iax_sched {
+	/* These are scheduled things to be delivered */
+	time_in_ms_t when;
+	/* If event is non-NULL then we're delivering an event */
+	struct iax_event *event;
+	/* If frame is non-NULL then we're transmitting a frame */
+	struct iax_frame *frame;
+	/* If func is non-NULL then we should call it */
+	sched_func func;
+	/* and pass it this argument */
+	void *arg;
+	/* Easy linking */
+	struct iax_sched *next;
+};
+
+static mutex_t *sched_mutex = NULL;
+static mutex_t *session_mutex = NULL;
+static struct iax_sched *schedq = NULL;
+static struct iax_session *sessions = NULL;
+static int callnums = 1;
+static int transfer_id = 1;		/* for attended transfer */
+static int time_init = 0;
+
+static void init_time(void)
+{
+#ifdef WIN32_TIME_GET_TIME
+	timeBeginPeriod(1);
+#endif
+	time_init = 1;
+}
+
+static void time_end(void)
+{
+#ifdef WIN32_TIME_GET_TIME
+	timeEndPeriod(1);
+#endif
+	time_init = 0;
+}
+
+static time_in_ms_t current_time_in_ms(void)
+{
+#ifdef WIN32_TIME_GET_TIME
+	return timeGetTime();
+#else
+	struct timeval tv;
+	gettimeofday(&tv, NULL);
+	return ((tv.tv_sec * 1000) + (tv.tv_usec / 1000));
+#endif
+}
+
+void iax_set_private(struct iax_session *s, void *ptr)
+{
+	s->pvt = ptr;
+}
+
+void *iax_get_private(struct iax_session *s)
+{
+	return s->pvt;
+}
+
+void iax_set_sendto(struct iax_session *s, sendto_t ptr)
+{
+	s->sendto = ptr;
+}
+
+
+unsigned int iax_session_get_capability(struct iax_session *s)
+{
+	return s->capability;
+}
+
+
+static int inaddrcmp(struct sockaddr_in *sin1, struct sockaddr_in *sin2)
+{
+	return (sin1->sin_addr.s_addr != sin2->sin_addr.s_addr) || (sin1->sin_port != sin2->sin_port);
+}
+
+static int iax_sched_add(struct iax_event *event, struct iax_frame *frame, sched_func func, void *arg, time_in_ms_t ms)
+{
+
+	/* Schedule event to be delivered to the client
+	   in ms milliseconds from now, or a reliable frame to be retransmitted */
+	struct iax_sched *sched, *cur, *prev = NULL;
+	
+	if (!event && !frame && !func) {
+		DEBU(G "No event, no frame, no func?  what are we scheduling?\n");
+		return -1;
+	}
+	
+
+	sched = (struct iax_sched*)malloc(sizeof(struct iax_sched));
+	if (sched) {
+        memset(sched, 0, sizeof(struct iax_sched));
+		sched->when = current_time_in_ms() + ms;
+		sched->event = event;
+		sched->frame = frame;
+		sched->func = func;
+		sched->arg = arg;
+		/* Put it in the list, in order */
+		iax_mutex_lock(sched_mutex);
+		cur = schedq;
+		while(cur && cur->when <= sched->when) {
+			prev = cur;
+			cur = cur->next;
+		}
+		sched->next = cur;
+		if (prev) {
+			prev->next = sched;
+		} else {
+			schedq = sched;
+		}
+		iax_mutex_unlock(sched_mutex);
+		return 0;
+	} else {
+		DEBU(G "Out of memory!\n");
+		return -1;
+	}
+}
+
+static int iax_sched_del(struct iax_event *event, struct iax_frame *frame, sched_func func, void *arg, int all)
+{
+	struct iax_sched *cur, *tmp, *prev = NULL;
+	int ret = 0;
+
+	iax_mutex_lock(sched_mutex);
+	cur = schedq;
+	while (cur) {
+		if (cur->event == event && cur->frame == frame && cur->func == func && cur->arg == arg) {
+			if (prev)
+				prev->next = cur->next;
+			else
+				schedq = cur->next;
+			tmp = cur;
+			cur = cur->next;	
+			free(tmp);
+			if (!all) {
+				ret = -1;
+				goto done;
+			}
+		} else {
+			prev = cur;
+			cur = cur->next;
+		}
+	}
+ done:
+	iax_mutex_unlock(sched_mutex);
+
+	return 0;
+
+}
+
+
+time_in_ms_t iax_time_to_next_event(void)
+{
+	struct iax_sched *cur = NULL;
+	time_in_ms_t minimum = 999999999;
+	
+	iax_mutex_lock(sched_mutex);
+	cur = schedq;
+
+	/* If there are no pending events, we don't need to timeout */
+	if (!cur) {
+		iax_mutex_unlock(sched_mutex);
+		return -1;
+	}
+	while(cur) {
+		if (cur->when < minimum) {
+			minimum = cur->when;
+		}
+		cur = cur->next;
+	}
+	iax_mutex_unlock(sched_mutex);
+
+	if (minimum <= 0) {
+		return -1;
+	}
+
+
+
+	return minimum - current_time_in_ms();
+}
+
+struct iax_session *iax_session_new(void)
+{
+	struct iax_session *s;
+	s = (struct iax_session *)malloc(sizeof(struct iax_session));
+	if (s) {
+		memset(s, 0, sizeof(struct iax_session));
+		/* Initialize important fields */
+		s->voiceformat = -1;
+		s->svoiceformat = -1;
+		/* Default pingtime to 30 ms */
+		s->pingtime = 30;
+		/* XXX Not quite right -- make sure it's not in use, but that won't matter
+	           unless you've had at least 65k calls.  XXX */
+		s->callno = callnums++;
+		if (callnums > 32767)
+			callnums = 1;
+		s->peercallno = 0;
+		s->transferpeer = 0;		/* for attended transfer */
+
+		s->sendto = iax_sendto;
+		s->pingid = -1;
+#ifdef NEWJB
+		s->jb = jb_new();
+		{
+			jb_conf jbconf;
+			jbconf.max_jitterbuf = 0;
+			jbconf.resync_threshold = 1000;
+			jbconf.max_contig_interp = 0;
+			jbconf.target_extra = jb_target_extra;
+			jb_setconf(s->jb, &jbconf);
+		}
+#endif
+		iax_mutex_lock(session_mutex);
+		s->next = sessions;
+		sessions = s;
+		iax_mutex_unlock(session_mutex);
+	}
+	return s;
+}
+
+static int iax_session_valid(struct iax_session *session)
+{
+	/* Return -1 on a valid iax session pointer, 0 on a failure */
+	struct iax_session *cur;
+
+	iax_mutex_lock(session_mutex);
+	cur = sessions;
+	while(cur) {
+		if (session == cur) {
+			iax_mutex_unlock(session_mutex);
+			return -1;
+		}
+		cur = cur->next;
+	}
+	iax_mutex_unlock(session_mutex);
+
+	return 0;
+}
+
+int iax_get_netstats(struct iax_session *session, time_in_ms_t *rtt, struct iax_netstat *local, struct iax_netstat *remote) {
+
+  if(!iax_session_valid(session)) return -1;
+
+  *rtt = session->pingtime;
+
+  *remote = session->remote_netstats;
+
+#ifdef NEWJB
+  {
+      jb_info stats;
+      jb_getinfo(session->jb, &stats);
+
+      local->jitter = stats.jitter;
+      /* XXX: should be short-term loss pct.. */
+      if(stats.frames_in == 0) stats.frames_in = 1;
+      local->losspct = stats.losspct/1000;
+      local->losscnt = stats.frames_lost;
+      local->packets = stats.frames_in;
+      local->delay = stats.current - stats.min;
+      local->dropped = stats.frames_dropped;
+      local->ooo = stats.frames_ooo;
+  }
+#endif
+  return 0;
+}
+
+static time_in_ms_t calc_timestamp(struct iax_session *session, time_in_ms_t ts, struct ast_frame *f)
+{
+	time_in_ms_t ms;
+	time_in_ms_t time_in_ms;
+	int voice = 0;
+	int genuine = 0;
+	
+	if (f && f->frametype == AST_FRAME_VOICE) {
+		voice = 1;
+	} else if (!f || f->frametype == AST_FRAME_IAX) {
+		genuine = 1;
+	}
+	
+	/* If this is the first packet we're sending, get our
+	   offset now. */
+	if (!session->offset) {
+		session->offset = current_time_in_ms();
+	}
+	/* If the timestamp is specified, just use their specified
+	   timestamp no matter what.  Usually this is done for
+	   special cases.  */
+	if (ts) {
+		return ts;
+	}
+	/* Otherwise calculate the timestamp from the current time */
+	time_in_ms = current_time_in_ms();
+
+
+	/* Calculate the number of milliseconds since we sent the first packet */
+	ms = time_in_ms - session->offset;
+
+	if (ms < 0) {
+		ms = 0;
+	}
+
+	if(voice) {
+#ifdef USE_VOICE_TS_PREDICTION
+
+		/* If we haven't most recently sent silence, and we're
+		 * close in time, use predicted time */
+		if(session->notsilenttx && iax_abs(ms - session->nextpred) <= 240) {
+		    /* Adjust our txcore, keeping voice and non-voice
+		     * synchronized */
+			session->offset += (int)(ms - session->nextpred)/10;
+		    
+		    if(!session->nextpred) {
+				session->nextpred = ms; 
+			}
+		    ms = session->nextpred; 
+		} else {
+		    /* in this case, just use the actual time, since
+		     * we're either way off (shouldn't happen), or we're
+		     * ending a silent period -- and seed the next predicted
+		     * time.  Also, round ms to the next multiple of
+		     * frame size (so our silent periods are multiples
+		     * of frame size too) */
+		    time_in_ms_t diff = ms % (f->samples / 8);
+		    if(diff)
+			ms += f->samples/8 - diff;
+		    session->nextpred = ms; 
+		}
+#else
+		if(ms <= session->lastsent)
+			ms = session->lastsent + 3;
+#endif
+		session->notsilenttx = 1;
+	} else {
+		/* On a dataframe, use last value + 3 (to accomodate jitter buffer shrinking) 
+		   if appropriate unless it's a genuine frame */
+		if (genuine) {
+			if (ms <= session->lastsent)
+				ms = session->lastsent + 3;
+		} else if (iax_abs(ms - session->lastsent) <= 240) {
+			ms = session->lastsent + 3;
+		}
+	      
+	}
+
+	/* Record the last sent packet for future reference */
+	/* unless an AST_FRAME_IAX */
+	if (!genuine)
+		session->lastsent = ms;
+
+#ifdef USE_VOICE_TS_PREDICTION
+	/* set next predicted ts based on 8khz samples */
+	if(voice)
+	    session->nextpred = session->nextpred + f->samples / 8;
+#endif
+
+	return ms;
+}
+
+#ifdef NEWJB
+static unsigned char get_n_bits_at(unsigned char *data, int n, int bit)
+{
+	int byte = bit / 8;       /* byte containing first bit */
+	int rem = 8 - (bit % 8);  /* remaining bits in first byte */
+	unsigned char ret = 0;
+	
+	if (n <= 0 || n > 8)
+		return 0;
+
+	if (rem < n) {
+		ret = (data[byte] << (n - rem));
+		ret |= (data[byte + 1] >> (8 - n + rem));
+	} else {
+		ret = (data[byte] >> (rem - n));
+	}
+
+	return (ret & (0xff >> (8 - n)));
+}
+
+static int speex_get_wb_sz_at(unsigned char *data, int len, int bit)
+{
+	static int SpeexWBSubModeSz[] = {
+		0, 36, 112, 192,
+		352, 0, 0, 0 };
+	int off = bit;
+	unsigned char c;
+
+	/* skip up to two wideband frames */
+	if (((len * 8 - off) >= 5) && 
+		get_n_bits_at(data, 1, off)) {
+		c = get_n_bits_at(data, 3, off + 1);
+		off += SpeexWBSubModeSz[c];
+
+		if (((len * 8 - off) >= 5) && 
+			get_n_bits_at(data, 1, off)) {
+			c = get_n_bits_at(data, 3, off + 1);
+			off += SpeexWBSubModeSz[c];
+
+			if (((len * 8 - off) >= 5) && 
+				get_n_bits_at(data, 1, off)) {
+				/* too many in a row */
+				DEBU(G "\tCORRUPT too many wideband streams in a row\n");
+				return -1;
+			}
+		}
+
+	}
+	return off - bit;
+}
+
+static int speex_get_samples(unsigned char *data, int len)
+{
+	static int SpeexSubModeSz[] = {
+		0, 43, 119, 160, 
+		220, 300, 364, 492, 
+		79, 0, 0, 0,
+		0, 0, 0, 0 };
+	static int SpeexInBandSz[] = { 
+		1, 1, 4, 4,
+		4, 4, 4, 4,
+		8, 8, 16, 16,
+		32, 32, 64, 64 };
+	int bit = 0;
+	int cnt = 0;
+	int off = 0;
+	unsigned char c;
+
+	DEBU(G "speex_get_samples(%d)\n", len);
+	while ((len * 8 - bit) >= 5) {
+		/* skip wideband frames */
+		off = speex_get_wb_sz_at(data, len, bit);
+		if (off < 0)  {
+			DEBU(G "\tERROR reading wideband frames\n");
+			break;
+		}
+		bit += off;
+
+		if ((len * 8 - bit) < 5) {
+			DEBU(G "\tERROR not enough bits left after wb\n");
+			break;
+		}
+
+		/* get control bits */
+		c = get_n_bits_at(data, 5, bit);
+		DEBU(G "\tCONTROL: %d at %d\n", c, bit);
+		bit += 5;
+
+		if (c == 15) { 
+			DEBU(G "\tTERMINATOR\n");
+			break;
+		} else if (c == 14) {
+			/* in-band signal; next 4 bits contain signal id */
+			c = get_n_bits_at(data, 4, bit);
+			bit += 4;
+			DEBU(G "\tIN-BAND %d bits\n", SpeexInBandSz[c]);
+			bit += SpeexInBandSz[c];
+		} else if (c == 13) {
+			/* user in-band; next 5 bits contain msg len */
+			c = get_n_bits_at(data, 5, bit);
+			bit += 5;
+			DEBU(G "\tUSER-BAND %d bytes\n", c);
+			bit += c * 8;
+		} else if (c > 8) {
+			DEBU(G "\tUNKNOWN sub-mode %d\n", c);
+			break;
+		} else {
+			/* skip number bits for submode (less the 5 control bits) */
+			DEBU(G "\tSUBMODE %d %d bits\n", c, SpeexSubModeSz[c]);
+			bit += SpeexSubModeSz[c] - 5;
+
+			cnt += 160; /* new frame */
+		}
+	}
+	DEBU(G "\tSAMPLES: %d\n", cnt);
+	return cnt;
+}
+
+static inline int get_interp_len(int format)
+{
+	return (format == AST_FORMAT_ILBC) ? 30 : 20;
+}
+
+static int get_sample_cnt(struct iax_event *e)
+{
+	int cnt = 0;
+
+	/*
+	 * In the case of zero length frames, do not return a cnt of 0
+	 */
+	if ( e->datalen == 0 ) {
+		return get_interp_len( e->subclass ) * 8;
+	}
+
+	switch (e->subclass) {
+	  case AST_FORMAT_SPEEX:
+	    cnt = speex_get_samples(e->data, e->datalen);
+	    break;
+	  case AST_FORMAT_G723_1:
+	    cnt = 240;		/* FIXME Not always the case */
+	    break;
+	  case AST_FORMAT_ILBC:
+	    cnt = 240 * (e->datalen / 50);
+	    break;
+	  case AST_FORMAT_GSM:
+	    cnt = 160 * (e->datalen / 33);
+	    break;
+	  case AST_FORMAT_G729A:
+	    cnt = 160 * (e->datalen / 20);
+	    break;
+	  case AST_FORMAT_SLINEAR:
+	    cnt = e->datalen / 2;
+	    break;
+	  case AST_FORMAT_LPC10:
+	    cnt = 22 * 8 + (((char *)(e->data))[7] & 0x1) * 8;
+	    break;
+	  case AST_FORMAT_ULAW:
+	  case AST_FORMAT_ALAW:
+	    cnt = e->datalen;
+	    break;
+	  case AST_FORMAT_ADPCM:
+	  case AST_FORMAT_G726:
+	    cnt = e->datalen * 2;
+	    break;
+	  default:
+	    return 0;
+	}
+	return cnt;
+}
+#endif
+
+static int iax_xmit_frame(struct iax_frame *f)
+{
+	/* Send the frame raw */
+#ifdef DEBUG_SUPPORT
+	struct ast_iax2_full_hdr *h = (f->data);
+	if (ntohs(h->scallno) & IAX_FLAG_FULL)
+		iax_showframe(f, NULL, 0, f->transfer ? 
+						&(f->session->transfer) :
+					&(f->session->peeraddr), f->datalen - sizeof(struct ast_iax2_full_hdr));
+#endif
+
+	return f->session->sendto(netfd, (const char *) f->data, f->datalen,
+		IAX_SOCKOPTS,
+					f->transfer ? 
+						(struct sockaddr *)&(f->session->transfer) :
+					(struct sockaddr *)&(f->session->peeraddr), sizeof(f->session->peeraddr));
+}
+
+static int iax_reliable_xmit(struct iax_frame *f)
+{
+	struct iax_frame *fc;
+	struct ast_iax2_full_hdr *fh;
+	fh = (struct ast_iax2_full_hdr *) f->data;
+	if (!fh->type) {
+		DEBU(G "Asked to reliably transmit a non-packet.  Crashing.\n");
+		*((char *)0)=0;
+	}
+	fc = (struct iax_frame *)malloc(sizeof(struct iax_frame));
+	if (fc) {
+		/* Make a copy of the frame */
+		memcpy(fc, f, sizeof(struct iax_frame));
+		/* And a copy of the data if applicable */
+		if (!fc->data || !fc->datalen) {
+			IAXERROR "No frame data?");
+			DEBU(G "No frame data?\n");
+			return -1;
+		} else {
+			fc->data = (char *)malloc(fc->datalen);
+			if (!fc->data) {
+				DEBU(G "Out of memory\n");
+				IAXERROR "Out of memory\n");
+				return -1;
+			}
+			memcpy(fc->data, f->data, f->datalen);
+			iax_sched_add(NULL, fc, NULL, NULL, fc->retrytime);
+			return iax_xmit_frame(fc);
+		}
+	} else
+		return -1;
+}
+
+void iax_set_networking(sendto_t st, recvfrom_t rf)
+{
+
+	init_time();
+	iax_sendto = st;
+	iax_recvfrom = rf;
+}
+
+int __iax_shutdown(void)
+{
+	struct iax_sched *sp, *fp;
+
+	/* Hangup Calls */
+	if (sessions) {
+		struct iax_session *sp = NULL, *fp = NULL;
+		iax_mutex_lock(session_mutex); 
+		for(sp = sessions; sp ;) {
+			iax_hangup(sp, "System Shutdown");
+			fp = sp;
+			sp = sp->next;
+			destroy_session(fp);
+		}
+		iax_mutex_unlock(session_mutex); 
+	}
+
+	/* Clear Scheduler */
+	iax_mutex_lock(sched_mutex);
+	for(sp = schedq; sp ;) {
+		fp = sp;
+		sp = sp->next;
+		free(fp);
+	}
+	iax_mutex_unlock(sched_mutex);
+	
+	if (netfd > -1) {
+		shutdown(netfd, 2);
+		close(netfd);
+	}
+
+	time_end();
+
+	iax_mutex_destroy(sched_mutex);
+	iax_mutex_destroy(session_mutex);
+
+	return 0;
+}
+
+int iax_shutdown(void)
+{
+	return do_shutdown++;
+}
+
+void iax_set_jb_target_extra( long value )
+{
+	/* store in jb_target_extra, a static global */
+	jb_target_extra = value ;
+}
+
+int iax_init(char *ip, int preferredportno)
+{
+	int portno = preferredportno;
+	struct sockaddr_in sin;
+	unsigned int sinlen;
+	int flags;
+
+	init_time();
+
+	iax_mutex_create(&sched_mutex);
+	iax_mutex_create(&session_mutex);
+
+	if(iax_recvfrom == (recvfrom_t) recvfrom) {
+	    if (netfd > -1) {
+		    /* Sokay, just don't do anything */
+		    DEBU(G "Already initialized.");
+		    return 0;
+	    }
+	    netfd = (int)socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
+	    if (netfd < 0) {
+		    DEBU(G "Unable to allocate UDP socket\n");
+		    IAXERROR "Unable to allocate UDP socket\n");
+		    return -1;
+	    }
+	    
+	    if (preferredportno == 0) preferredportno = IAX_DEFAULT_PORTNO;
+		if (preferredportno < 0)  preferredportno = 0;
+
+		sin.sin_family = AF_INET;
+		sin.sin_addr.s_addr = 0;
+		sin.sin_port = htons((short)preferredportno);
+		if (bind(netfd, (struct sockaddr *) &sin, sizeof(sin)) < 0) 
+		{
+#if defined(WIN32)  ||  defined(_WIN32_WCE)
+			if (WSAGetLastError() == WSAEADDRINUSE)
+#else
+			if (errno == EADDRINUSE)
+#endif
+			{
+				/*the port is already in use, so bind to a free port chosen by the IP stack*/
+				DEBU(G "Unable to bind to preferred port - port is in use. Trying to bind to a free one");
+				sin.sin_port = htons((short)0);
+				if (bind(netfd, (struct sockaddr *) &sin, sizeof(sin)) < 0)
+				{
+					IAXERROR "Unable to bind UDP socket\n");
+					return -1;
+				}
+			} else
+			{
+				IAXERROR "Unable to bind UDP socket\n");
+				return -1;
+			}
+		}
+		sinlen = sizeof(sin);
+	    if (getsockname(netfd, (struct sockaddr *) &sin, &sinlen) < 0) {
+		    close(netfd);
+		    netfd = -1;
+		    DEBU(G "Unable to figure out what I'm bound to.");
+		    IAXERROR "Unable to determine bound port number.");
+	    }
+#ifdef	WIN32
+	    flags = 1;
+	    if (ioctlsocket(netfd,FIONBIO,(unsigned long *) &flags)) {
+		    closesocket(netfd);
+		    netfd = -1;
+		    DEBU(G "Unable to set non-blocking mode.");
+		    IAXERROR "Unable to set non-blocking mode.");
+	    }
+	    
+#else
+	    if ((flags = fcntl(netfd, F_GETFL)) < 0) {
+		    close(netfd);
+		    netfd = -1;
+		    DEBU(G "Unable to retrieve socket flags.");
+		    IAXERROR "Unable to retrieve socket flags.");
+	    }
+	    if (fcntl(netfd, F_SETFL, flags | O_NONBLOCK) < 0) {
+		    close(netfd);
+		    netfd = -1;
+		    DEBU(G "Unable to set non-blocking mode.");
+		    IAXERROR "Unable to set non-blocking mode.");
+	    }
+#endif
+	    portno = ntohs(sin.sin_port);
+	}
+	srand((unsigned int)time(NULL));
+	callnums = rand() % 32767 + 1;
+	transfer_id = rand() % 32767 + 1;
+	DEBU(G "Started on port %d\n", portno);
+	return portno;	
+}
+
+
+
+static void convert_reply(char *out, unsigned char *in)
+{
+	int x;
+	for (x=0;x<16;x++)
+		out += sprintf(out, "%2.2x", (int)in[x]);
+}
+
+static unsigned char compress_subclass(int subclass)
+{
+	int x;
+	int power=-1;
+	/* If it's 128 or smaller, just return it */
+	if (subclass < IAX_FLAG_SC_LOG)
+		return subclass;
+	/* Otherwise find its power */
+	for (x = 0; x < IAX_MAX_SHIFT; x++) {
+		if (subclass & (1 << x)) {
+			if (power > -1) {
+				DEBU(G "Can't compress subclass %d\n", subclass);
+				return 0;
+			} else
+				power = x;
+		}
+	}
+	return power | IAX_FLAG_SC_LOG;
+}
+
+static int iax_send(struct iax_session *pvt, struct ast_frame *f, time_in_ms_t ts, int seqno, int now, int transfer, int final) 
+{
+	/* Queue a packet for delivery on a given private structure.  Use "ts" for
+	   timestamp, or calculate if ts is 0.  Send immediately without retransmission
+	   or delayed, with retransmission */
+	struct ast_iax2_full_hdr *fh;
+	struct ast_iax2_mini_hdr *mh;
+	unsigned char	buf[5120];
+	struct iax_frame *fr;
+	int res;
+	int sendmini=0;
+	time_in_ms_t lastsent;
+	time_in_ms_t fts;
+	
+	if (!pvt) {
+		IAXERROR "No private structure for packet?\n");
+		return -1;
+	}
+	
+	/* this must come before the next call to calc_timestamp() since
+	 calc_timestamp() will change lastsent to the returned value */
+	lastsent = pvt->lastsent;
+
+	/* Calculate actual timestamp */
+	fts = calc_timestamp(pvt, ts, f);
+
+	if (((fts & 0xFFFF0000L) == (lastsent & 0xFFFF0000L))
+		/* High two bits are the same on timestamp, or sending on a trunk */ &&
+	    (f->frametype == AST_FRAME_VOICE) 
+		/* is a voice frame */ &&
+		(f->subclass == pvt->svoiceformat) 
+		/* is the same type */ ) {
+			/* Force immediate rather than delayed transmission */
+			now = 1;
+			/* Mark that mini-style frame is appropriate */
+			sendmini = 1;
+	}
+	/* Allocate an iax_frame */
+	if (now) {
+		fr = (struct iax_frame *) buf;
+	} else
+		fr = iax_frame_new(DIRECTION_OUTGRESS, f->datalen);
+	if (!fr) {
+		IAXERROR "Out of memory\n");
+		return -1;
+	}
+	/* Copy our prospective frame into our immediate or retransmitted wrapper */
+	iax_frame_wrap(fr, f);
+
+	fr->ts = fts;
+	if (!fr->ts) {
+		IAXERROR "timestamp is 0?\n");
+		if (!now)
+			iax_frame_free(fr);
+		return -1;
+	}
+
+	fr->callno = pvt->callno;
+	fr->transfer = transfer;
+	fr->final = final;
+	fr->session = pvt;
+	if (!sendmini) {
+		/* We need a full frame */
+		if (seqno > -1)
+			fr->oseqno = seqno;
+		else
+			fr->oseqno = pvt->oseqno++;
+		fr->iseqno = pvt->iseqno;
+		fh = (struct ast_iax2_full_hdr *)(((char *)fr->af.data) - sizeof(struct ast_iax2_full_hdr));
+		fh->scallno = htons(fr->callno | IAX_FLAG_FULL);
+		fh->ts = htonl((long)(fr->ts));
+		fh->oseqno = fr->oseqno;
+		if (transfer) {
+			fh->iseqno = 0;
+		} else
+			fh->iseqno = fr->iseqno;
+		/* Keep track of the last thing we've acknowledged */
+		pvt->aseqno = fr->iseqno;
+		fh->type = fr->af.frametype & 0xFF;
+		fh->csub = compress_subclass(fr->af.subclass);
+		if (transfer) {
+			fr->dcallno = pvt->transfercallno;
+		} else
+			fr->dcallno = pvt->peercallno;
+		fh->dcallno = htons(fr->dcallno);
+		fr->datalen = fr->af.datalen + sizeof(struct ast_iax2_full_hdr);
+		fr->data = fh;
+		fr->retries = maxretries;
+		/* Retry after 2x the ping time has passed */
+		fr->retrytime = pvt->pingtime * 2;
+		if (fr->retrytime < MIN_RETRY_TIME)
+			fr->retrytime = MIN_RETRY_TIME;
+		if (fr->retrytime > MAX_RETRY_TIME)
+			fr->retrytime = MAX_RETRY_TIME;
+		/* Acks' don't get retried */
+		if ((f->frametype == AST_FRAME_IAX) && (f->subclass == IAX_COMMAND_ACK))
+			fr->retries = -1;
+		if (f->frametype == AST_FRAME_VOICE) {
+			pvt->svoiceformat = f->subclass;
+		}
+		if (now) {
+			res = iax_xmit_frame(fr);
+		} else
+			res = iax_reliable_xmit(fr);
+	} else {
+		/* Mini-frames have no sequence number */
+		fr->oseqno = -1;
+		fr->iseqno = -1;
+		/* Mini frame will do */
+		mh = (struct ast_iax2_mini_hdr *)(((char *)fr->af.data) - sizeof(struct ast_iax2_mini_hdr));
+		mh->callno = htons(fr->callno);
+		mh->ts = htons((short)(fr->ts & 0xFFFF));
+		fr->datalen = fr->af.datalen + sizeof(struct ast_iax2_mini_hdr);
+		fr->data = mh;
+		fr->retries = -1;
+		res = iax_xmit_frame(fr);
+	}
+	if( !now && fr!=NULL )
+	        iax_frame_free( fr ); 
+	return res;
+}
+
+#if 0
+static int iax_predestroy(struct iax_session *pvt)
+{
+	if (!pvt) {
+		return -1;
+	}
+	if (!pvt->alreadygone) {
+		/* No more pings or lagrq's */
+		if (pvt->pingid > -1)
+			ast_sched_del(sched, pvt->pingid);
+		if (pvt->lagid > -1)
+			ast_sched_del(sched, pvt->lagid);
+		if (pvt->autoid > -1)
+			ast_sched_del(sched, pvt->autoid);
+		if (pvt->initid > -1)
+			ast_sched_del(sched, pvt->initid);
+		pvt->pingid = -1;
+		pvt->lagid = -1;
+		pvt->autoid = -1;
+		pvt->initid = -1;
+		pvt->alreadygone = 1;
+	}
+	return 0;
+}
+#endif
+
+static int __send_command(struct iax_session *i, char type, int command, time_in_ms_t ts, unsigned char *data, int datalen, int seqno, 
+		int now, int transfer, int final, int samples)
+{
+	struct ast_frame f;
+	f.frametype = type;
+	f.subclass = command;
+	f.datalen = datalen;
+	f.samples = samples;
+	f.mallocd = 0;
+	f.offset = 0;
+#ifdef __GNUC__
+	f.src = (char *) __FUNCTION__;
+#else
+	f.src = (char *) __FILE__;
+#endif
+	f.data = data;
+	return iax_send(i, &f, ts, seqno, now, transfer, final);
+}
+
+static int send_command(struct iax_session *i, char type, int command, time_in_ms_t ts, unsigned char *data, int datalen, int seqno)
+{
+	return __send_command(i, type, command, ts, data, datalen, seqno, 0, 0, 0, 0);
+}
+
+static int send_command_final(struct iax_session *i, char type, int command, unsigned int ts, unsigned char *data, int datalen, int seqno)
+{
+#if 0
+	/* It is assumed that the callno has already been locked */
+	iax_predestroy(i);
+#endif	
+	int r;
+	r = __send_command(i, type, command, ts, data, datalen, seqno, 0, 0, 1, 0);
+	if (r >= 0) {
+		iax_mutex_lock(session_mutex); 
+		destroy_session(i);
+		iax_mutex_unlock(session_mutex);
+	}
+	return r;
+}
+
+static int send_command_immediate(struct iax_session *i, char type, int command, unsigned int ts, unsigned char *data, int datalen, int seqno)
+{
+	return __send_command(i, type, command, ts, data, datalen, seqno, 1, 0, 0, 0);
+}
+
+static int send_command_transfer(struct iax_session *i, char type, int command, unsigned int ts, unsigned char *data, int datalen)
+{
+	return __send_command(i, type, command, ts, data, datalen, 0, 0, 1, 0, 0);
+}
+
+static int send_command_samples(struct iax_session *i, char type, int command, unsigned int ts, unsigned char *data, int datalen, int seqno, int samples)
+{
+	return __send_command(i, type, command, ts, data, datalen, seqno, 0, 0, 0, samples);
+}
+
+
+int iax_transfer(struct iax_session *session, char *number)
+{	
+	static int res;				//Return Code
+	struct iax_ie_data ied;			//IE Data Structure (Stuff To Send)
+
+	// Clear The Memory Used For IE Buffer
+	memset(&ied, 0, sizeof(ied));
+	
+	// Copy The Transfer Destination Into The IE Structure
+	iax_ie_append_str(&ied, IAX_IE_CALLED_NUMBER, (unsigned char *) number);
+	
+	// Send The Transfer Command - Asterisk Will Handle The Rest!			
+	res = send_command(session, AST_FRAME_IAX, IAX_COMMAND_TRANSFER, 0, ied.buf, ied.pos, -1);
+	
+	// Return Success
+	return 0;	
+}
+
+static void stop_transfer(struct iax_session *session)
+{
+	struct iax_sched *sch;
+
+	iax_mutex_lock(sched_mutex);
+	sch = schedq;
+	while(sch) {
+		if (sch->frame && (sch->frame->session == session))
+					sch->frame->retries = -1;
+		sch = sch->next;
+	}
+	iax_mutex_unlock(sched_mutex);
+}	/* stop_transfer */
+
+static void complete_transfer(struct iax_session *session, int peercallno, int xfr2peer, int preserveSeq)
+{
+	session->peercallno = peercallno;
+	/* Change from transfer to session now */
+	if (xfr2peer) {
+		memcpy(&session->peeraddr, &session->transfer, sizeof(session->peeraddr));
+		memset(&session->transfer, 0, sizeof(session->transfer));
+		session->transferring = TRANSFER_NONE;
+		session->transferpeer = 0;
+		session->transfer_moh = 0;
+		/* Force retransmission of a real voice packet, and reset all timing */
+		session->svoiceformat = -1;
+		session->voiceformat = 0;
+	}
+	session->rxcore = session->offset = 0;
+	memset(&session->history, 0, sizeof(session->history));
+#ifdef NEWJB
+	{ /* Reset jitterbuffer */
+	    jb_frame frame;
+	    while(jb_getall(session->jb,&frame) == JB_OK) 
+		iax_event_free(frame.data);
+	
+	    jb_reset(session->jb);
+	}
+#endif
+	session->jitterbuffer = 0;
+	session->jitter = 0;
+	session->lag = 0;
+
+	if (! preserveSeq)
+	{
+		/* Reset sequence numbers */
+		session->aseqno = 0;
+		session->oseqno = 0;
+		session->iseqno = 0;
+	}
+
+	session->lastsent = 0;
+	session->last_ts = 0;
+	session->lastvoicets = 0;
+	session->pingtime = 30;
+	/* We have to dump anything we were going to (re)transmit now that we've been
+	   transferred since they're all invalid and for the old host. */
+	stop_transfer(session);
+}	/* complete_transfer */
+
+int iax_setup_transfer(struct iax_session *org_session, struct iax_session *new_session)
+{
+	int res;
+	struct iax_ie_data ied0;
+	struct iax_ie_data ied1;
+
+	struct iax_session *s0 = org_session;
+	struct iax_session *s1 = new_session;
+
+	memset(&ied0, 0, sizeof(ied0));
+	memset(&ied1, 0, sizeof(ied1));
+
+	/* reversed setup */
+	iax_ie_append_addr(&ied0, IAX_IE_APPARENT_ADDR, &s1->peeraddr);
+	iax_ie_append_short(&ied0, IAX_IE_CALLNO, s1->peercallno);
+	iax_ie_append_int(&ied0, IAX_IE_TRANSFERID, transfer_id);
+
+	iax_ie_append_addr(&ied1, IAX_IE_APPARENT_ADDR, &s0->peeraddr);
+	iax_ie_append_short(&ied1, IAX_IE_CALLNO, s0->peercallno);
+	iax_ie_append_int(&ied1, IAX_IE_TRANSFERID, transfer_id);
+
+	s0->transfer = s1->peeraddr;
+	s1->transfer = s0->peeraddr;
+
+	s0->transferid = transfer_id;
+	s1->transferid = transfer_id;
+
+	s0->transfercallno = s0->peercallno;
+	s1->transfercallno = s1->peercallno;
+
+	s0->transferring = TRANSFER_BEGIN;
+	s1->transferring = TRANSFER_BEGIN;
+
+	s0->transferpeer = s1->callno;
+	s1->transferpeer = s0->callno;
+
+	transfer_id++;
+
+	if (transfer_id > 32767)
+		transfer_id = 1;
+
+	res = send_command(s0, AST_FRAME_IAX, IAX_COMMAND_TXREQ, 0, ied0.buf, ied0.pos, -1);
+	if (res < 0) {
+		return -1;
+	}
+
+	res = send_command(s1, AST_FRAME_IAX, IAX_COMMAND_TXREQ, 0, ied1.buf, ied1.pos, -1);
+	if (res < 0) {
+		return -1;
+	}
+
+	return 0;
+}
+
+static int iax_finish_transfer(struct iax_session *s, short new_peer)
+{
+	int res;
+	struct iax_ie_data ied;
+
+	memset(&ied, 0, sizeof(ied));
+
+	iax_ie_append_short(&ied, IAX_IE_CALLNO, new_peer);
+
+	res = send_command(s, AST_FRAME_IAX, IAX_COMMAND_TXREL, 0, ied.buf, ied.pos, -1);
+
+	complete_transfer(s, new_peer, 0, 1);
+
+	return res;
+
+}
+
+static struct iax_session *iax_find_session2(short callno)
+{
+	struct iax_session *cur;
+
+	iax_mutex_lock(session_mutex); 
+	cur = sessions;
+	while(cur) {
+		if (callno == cur->callno && callno != 0)  {
+			iax_mutex_unlock(session_mutex); 
+			return cur;
+		}
+		cur = cur->next;
+	}
+	iax_mutex_unlock(session_mutex); 
+
+	return NULL;
+}
+
+static int iax_handle_txready(struct iax_session *s)
+{
+	struct iax_session *s0, *s1;
+	short	s0_org_peer, s1_org_peer;
+
+	if (s->transfer_moh) {
+		s->transfer_moh = 0;
+		iax_unquelch(s);
+	}
+
+	complete_transfer(s, s->peercallno, 0, 1);
+
+	s->transferring = TRANSFER_REL;
+
+	s0 = s;
+	s1 = iax_find_session2(s0->transferpeer);
+
+	if (s1 != NULL &&
+	    s1->callno == s0->transferpeer &&
+		 s0->transferring == TRANSFER_REL &&
+		 s1->transferring == TRANSFER_REL) {
+
+		s0_org_peer = s0->peercallno;
+		s1_org_peer = s1->peercallno;
+
+		iax_finish_transfer(s0, s1_org_peer);
+		iax_finish_transfer(s1, s0_org_peer);
+		return 1;
+	}
+
+	return 0;
+}
+
+static void iax_handle_txreject(struct iax_session *s)
+{
+	struct iax_session *s0, *s1;
+
+	s0 = s;
+	s1 = iax_find_session2(s0->transferpeer);
+	if (s1 != NULL &&
+		 s0->transferpeer == s1->callno &&
+		 s1->transferring) {
+		if (s1->transfer_moh) {
+			s1->transfer_moh = 0;
+			send_command_immediate(s1, AST_FRAME_IAX, IAX_COMMAND_UNQUELCH, 0, NULL, 0, s1->iseqno);
+		}
+	}
+	if (s0->transfer_moh) {
+		s0->transfer_moh = 0;
+		send_command_immediate(s0, AST_FRAME_IAX, IAX_COMMAND_UNQUELCH, 0, NULL, 0, s0->iseqno);
+	}
+
+	memset(&s->transfer, 0, sizeof(s->transfer));
+	s->transferring = TRANSFER_NONE;
+	s->transferpeer = 0;
+	s->transfer_moh = 0;
+}
+
+static void destroy_session(struct iax_session *session)
+{
+	struct iax_session *cur, *prev=NULL;
+	struct iax_sched *curs, *prevs=NULL, *nexts=NULL;
+	int    loop_cnt=0;
+
+	iax_mutex_lock(sched_mutex);
+	curs = schedq;
+	while(curs) {
+		nexts = curs->next;
+		if (curs->frame && curs->frame->session == session) {
+			/* Just mark these frames as if they've been sent */
+			curs->frame->retries = -1;
+		} else if (curs->event && curs->event->session == session) {
+			if (prevs)
+				prevs->next = nexts;
+			else
+				schedq = nexts;
+			if (curs->event)
+				iax_event_free(curs->event);
+			free(curs);
+		} else {
+			prevs = curs;
+		}
+		curs = nexts;
+		loop_cnt++;
+	}
+	iax_mutex_unlock(sched_mutex);
+	
+
+	cur = sessions;
+	while(cur) {
+		if (cur == session) {
+			if (prev)
+				prev->next = session->next;
+			else
+				sessions = session->next;
+#ifdef NEWJB
+			{
+			    jb_frame frame;
+			    while(jb_getall(session->jb,&frame) == JB_OK) 
+				iax_event_free(frame.data);
+		   	
+			    jb_destroy(session->jb);
+			}
+#endif
+			free(session);
+			return;
+		}
+		prev = cur;
+		cur = cur->next;
+	}
+}
+
+static int iax_send_lagrp(struct iax_session *session, time_in_ms_t ts);
+static int iax_send_pong(struct iax_session *session, time_in_ms_t ts);
+
+static struct iax_event *handle_event(struct iax_event *event)
+{
+	/* We have a candidate event to be delievered.  Be sure
+	   the session still exists. */
+	if (event) {
+		if (iax_session_valid(event->session)) {
+			/* Lag requests are never actually sent to the client, but
+			   other than that are handled as normal packets */
+			switch(event->etype) {
+				/* the user on the outside may need to look at the session so we will not free 
+				   it here anymore we will test for hangup event in iax_event_free and do it
+				   there.
+				 */
+			case IAX_EVENT_REJECT:
+			case IAX_EVENT_HANGUP:
+				return event;
+			case IAX_EVENT_LAGRQ:
+				event->etype = IAX_EVENT_LAGRP;
+				iax_send_lagrp(event->session, event->ts);
+				iax_event_free(event);
+				break;
+			case IAX_EVENT_PING:
+				event->etype = IAX_EVENT_PONG;
+				iax_send_pong(event->session, event->ts);
+				iax_event_free(event);
+				break;
+			case IAX_EVENT_POKE:
+				event->etype = IAX_EVENT_PONG;
+				iax_send_pong(event->session, event->ts);
+				iax_destroy(event->session);
+				iax_event_free(event);
+				break;         
+			default:
+				return event;
+			}
+		} else 
+			iax_event_free(event);
+	}
+	return NULL;
+}
+
+static int iax2_vnak(struct iax_session *session)
+{
+	return send_command_immediate(session, AST_FRAME_IAX, IAX_COMMAND_VNAK, 0, NULL, 0, session->iseqno);
+}
+
+int iax_send_dtmf(struct iax_session *session, char digit)
+{
+	return send_command(session, AST_FRAME_DTMF, digit, 0, NULL, 0, -1);
+}
+
+int iax_send_voice(struct iax_session *session, int format, unsigned char *data, int datalen, int samples)
+{
+	/* Send a (possibly compressed) voice frame */
+	if (!session->quelch)
+		return send_command_samples(session, AST_FRAME_VOICE, format, 0, data, datalen, -1, samples);
+	return 0;
+}
+
+int iax_send_cng(struct iax_session *session, int level, unsigned char *data, int datalen)
+{    
+	session->notsilenttx = 0;
+	return send_command(session, AST_FRAME_CNG, level, 0, data, datalen, -1);
+}
+
+int iax_send_image(struct iax_session *session, int format, unsigned char *data, int datalen)
+{
+	/* Send an image frame */
+	return send_command(session, AST_FRAME_IMAGE, format, 0, data, datalen, -1);
+}
+
+int iax_register(struct iax_session *session, char *server, char *peer, char *secret, int refresh)
+{
+	/* Send a registration request */
+	char tmp[256];
+	char *p;
+	int res;
+	int portno = IAX_DEFAULT_PORTNO;
+	struct iax_ie_data ied;
+	struct hostent *hp;
+	
+	tmp[255] = '\0';
+	strncpy(tmp, server, sizeof(tmp) - 1);
+	p = strchr(tmp, ':');
+	if (p) {
+		*p = '\0';
+		portno = atoi(p+1);
+	}
+	
+	memset(&ied, 0, sizeof(ied));
+	if (secret)
+		strncpy(session->secret, secret, sizeof(session->secret) - 1);
+	else
+		strcpy(session->secret, "");
+
+	/* Connect first */
+	hp = gethostbyname(tmp);
+	if (!hp) {
+		snprintf(iax_errstr, sizeof(iax_errstr), "Invalid hostname: %s", tmp);
+		return -1;
+	}
+	memcpy(&session->peeraddr.sin_addr, hp->h_addr, sizeof(session->peeraddr.sin_addr));
+	session->peeraddr.sin_port = htons(portno);
+	session->peeraddr.sin_family = AF_INET;
+	strncpy(session->username, peer, sizeof(session->username) - 1);
+	session->refresh = refresh;
+	iax_ie_append_str(&ied, IAX_IE_USERNAME, (unsigned char *) peer);
+	iax_ie_append_short(&ied, IAX_IE_REFRESH, refresh);
+	res = send_command(session, AST_FRAME_IAX, IAX_COMMAND_REGREQ, 0, ied.buf, ied.pos, -1);
+	return res;
+}
+
+int iax_reject_registration(struct iax_session *session, char *reason)
+{
+	struct iax_ie_data ied;
+	memset(&ied, 0, sizeof(ied));
+	iax_ie_append_str(&ied, IAX_IE_CAUSE, reason ? (unsigned char *) reason : (unsigned char *) "Unspecified");
+	return send_command_final(session, AST_FRAME_IAX, IAX_COMMAND_REGREJ, 0, ied.buf, ied.pos, -1);
+}
+
+int iax_ack_registration(struct iax_session *session)
+{
+	return send_command_final(session, AST_FRAME_IAX, IAX_COMMAND_REGACK, 0, NULL, 0, -1);
+}
+
+int iax_auth_registration(struct iax_session *session)
+{
+	return send_command_final(session, AST_FRAME_IAX, IAX_COMMAND_REGAUTH, 0, NULL, 0, -1);
+}
+
+int iax_reject(struct iax_session *session, const char *reason)
+{
+	struct iax_ie_data ied;
+	memset(&ied, 0, sizeof(ied));
+	iax_ie_append_str(&ied, IAX_IE_CAUSE, reason ? (unsigned char *) reason : (unsigned char *) "Unspecified");
+	return send_command_final(session, AST_FRAME_IAX, IAX_COMMAND_REJECT, 0, ied.buf, ied.pos, -1);
+}
+
+int iax_hangup(struct iax_session *session, char *byemsg)
+{
+	struct iax_ie_data ied;
+	iax_sched_del(NULL, NULL, send_ping, (void *) session, 1);
+	memset(&ied, 0, sizeof(ied));
+	iax_ie_append_str(&ied, IAX_IE_CAUSE, byemsg ? (unsigned char *) byemsg : (unsigned char *) "Normal clearing");
+	return send_command_final(session, AST_FRAME_IAX, IAX_COMMAND_HANGUP, 0, ied.buf, ied.pos, -1);
+}
+
+int iax_sendurl(struct iax_session *session, char *url)
+{
+	return send_command(session, AST_FRAME_HTML, AST_HTML_URL, 0, (unsigned char *) url, (int)strlen(url), -1);
+}
+
+int iax_ring_announce(struct iax_session *session)
+{
+	return send_command(session, AST_FRAME_CONTROL, AST_CONTROL_RINGING, 0, NULL, 0, -1);
+}
+
+int iax_lag_request(struct iax_session *session)
+{
+	return send_command(session, AST_FRAME_IAX, IAX_COMMAND_LAGRQ, 0, NULL, 0, -1);
+}
+
+int iax_busy(struct iax_session *session)
+{
+	return send_command(session, AST_FRAME_CONTROL, AST_CONTROL_BUSY, 0, NULL, 0, -1);
+}
+
+int iax_congestion(struct iax_session *session)
+{
+	return send_command(session, AST_FRAME_CONTROL, AST_CONTROL_CONGESTION, 0, NULL, 0, -1);
+}
+
+
+int iax_accept(struct iax_session *session, int format)
+{
+	struct iax_ie_data ied;
+	memset(&ied, 0, sizeof(ied));
+	iax_ie_append_int(&ied, IAX_IE_FORMAT, format);
+	return send_command(session, AST_FRAME_IAX, IAX_COMMAND_ACCEPT, 0, ied.buf, ied.pos, -1);
+}
+
+int iax_answer(struct iax_session *session)
+{
+	return send_command(session, AST_FRAME_CONTROL, AST_CONTROL_ANSWER, 0, NULL, 0, -1);
+}
+
+int iax_load_complete(struct iax_session *session)
+{
+	return send_command(session, AST_FRAME_HTML, AST_HTML_LDCOMPLETE, 0, NULL, 0, -1);
+}
+
+int iax_send_url(struct iax_session *session, char *url, int link)
+{
+	return send_command(session, AST_FRAME_HTML, link ? AST_HTML_LINKURL : AST_HTML_URL, 0, (unsigned char *) url, (int)strlen(url), -1);
+}
+
+int iax_send_text(struct iax_session *session, char *text)
+{
+	return send_command(session, AST_FRAME_TEXT, 0, 0, (unsigned char *) text, (int)strlen(text) + 1, -1);
+}
+
+int iax_send_unlink(struct iax_session *session)
+{
+	return send_command(session, AST_FRAME_HTML, AST_HTML_UNLINK, 0, NULL, 0, -1);
+}
+
+int iax_send_link_reject(struct iax_session *session)
+{
+	return send_command(session, AST_FRAME_HTML, AST_HTML_LINKREJECT, 0, NULL, 0, -1);
+}
+
+static int iax_send_pong(struct iax_session *session, time_in_ms_t ts)
+{
+        struct iax_ie_data ied;
+
+        memset(&ied, 0, sizeof(ied));
+#ifdef NEWJB
+	{
+	    jb_info stats;
+	    jb_getinfo(session->jb, &stats);
+
+	    iax_ie_append_int(&ied,IAX_IE_RR_JITTER, (int)stats.jitter);
+	    /* XXX: should be short-term loss pct.. */
+	    if(stats.frames_in == 0) stats.frames_in = 1;
+	    iax_ie_append_int(&ied,IAX_IE_RR_LOSS, 
+		((0xff & (stats.losspct/1000)) << 24 | (stats.frames_lost & 0x00ffffff)));
+	    iax_ie_append_int(&ied,IAX_IE_RR_PKTS, stats.frames_in);
+	    iax_ie_append_short(&ied,IAX_IE_RR_DELAY, (unsigned short)(stats.current - stats.min));
+	    iax_ie_append_int(&ied,IAX_IE_RR_DROPPED, stats.frames_dropped);
+	    iax_ie_append_int(&ied,IAX_IE_RR_OOO, stats.frames_ooo);
+	}
+#else
+	    iax_ie_append_int(&ied,IAX_IE_RR_JITTER, session->jitter);
+	    /* don't know, don't send! iax_ie_append_int(&ied,IAX_IE_RR_LOSS, 0); */
+	    /* don't know, don't send! iax_ie_append_int(&ied,IAX_IE_RR_PKTS, stats.frames_in); */
+	    /* don't know, don't send! iax_ie_append_short(&ied,IAX_IE_RR_DELAY, stats.current - stats.min); */
+#endif
+
+	return send_command(session, AST_FRAME_IAX, IAX_COMMAND_PONG, ts, ied.buf, ied.pos, -1);
+}
+
+/* external API; deprecated since we send pings ourselves now (finally) */
+int iax_send_ping(struct iax_session *session)
+{
+	return send_command(session, AST_FRAME_IAX, IAX_COMMAND_PING, 0, NULL, 0, -1);
+}
+
+/* scheduled ping sender; sends ping, then reschedules */
+static void send_ping(void *s)
+{
+	struct iax_session *session = (struct iax_session *)s;
+
+	/* important, eh? */
+	if(!iax_session_valid(session)) return;
+
+	send_command(session, AST_FRAME_IAX, IAX_COMMAND_PING, 0, NULL, 0, -1);
+	session->pingid = iax_sched_add(NULL,NULL, send_ping, (void *)session, ping_time * 1000);
+	return;
+}
+
+static int iax_send_lagrp(struct iax_session *session, time_in_ms_t ts)
+{
+	return send_command(session, AST_FRAME_IAX, IAX_COMMAND_LAGRP, ts, NULL, 0, -1);
+}
+
+static int iax_send_txcnt(struct iax_session *session)
+{
+	struct iax_ie_data ied;
+	memset(&ied, 0, sizeof(ied));
+	iax_ie_append_int(&ied, IAX_IE_TRANSFERID, session->transferid);
+	return send_command_transfer(session, AST_FRAME_IAX, IAX_COMMAND_TXCNT, 0, ied.buf, ied.pos);
+}
+
+static int iax_send_txrej(struct iax_session *session)
+{
+	struct iax_ie_data ied;
+	memset(&ied, 0, sizeof(ied));
+	iax_ie_append_int(&ied, IAX_IE_TRANSFERID, session->transferid);
+	return send_command_transfer(session, AST_FRAME_IAX, IAX_COMMAND_TXREJ, 0, ied.buf, ied.pos);
+}
+
+static int iax_send_txaccept(struct iax_session *session)
+{
+	struct iax_ie_data ied;
+	memset(&ied, 0, sizeof(ied));
+	iax_ie_append_int(&ied, IAX_IE_TRANSFERID, session->transferid);
+	return send_command_transfer(session, AST_FRAME_IAX, IAX_COMMAND_TXACC, 0, ied.buf, ied.pos);
+}
+
+static int iax_send_txready(struct iax_session *session)
+{
+	struct iax_ie_data ied;
+	memset(&ied, 0, sizeof(ied));
+	/* see asterisk chan_iax2.c */
+	iax_ie_append_short(&ied, IAX_IE_CALLNO, session->callno);
+	return send_command(session, AST_FRAME_IAX, IAX_COMMAND_TXREADY, 0, ied.buf, ied.pos, -1);
+}
+
+int iax_auth_reply(struct iax_session *session, char *password, char *challenge, int methods)
+{
+	char reply[16];
+	struct MD5Context md5;
+	char realreply[256];
+	struct iax_ie_data ied;
+	memset(&ied, 0, sizeof(ied));
+	if ((methods & IAX_AUTH_MD5) && challenge) {
+		MD5Init(&md5);
+		MD5Update(&md5, (const unsigned char *) challenge, (unsigned int)strlen(challenge));
+		MD5Update(&md5, (const unsigned char *) password, (unsigned int)strlen(password));
+		MD5Final((unsigned char *) reply, &md5);
+		memset(realreply, 0, sizeof(realreply));
+		convert_reply(realreply, (unsigned char *) reply);
+		iax_ie_append_str(&ied, IAX_IE_MD5_RESULT, (unsigned char *) realreply);
+	} else {
+		iax_ie_append_str(&ied, IAX_IE_PASSWORD, (unsigned char *) password);
+	}
+	return send_command(session, AST_FRAME_IAX, IAX_COMMAND_AUTHREP, 0, ied.buf, ied.pos, -1);
+}
+
+static int iax_regauth_reply(struct iax_session *session, char *password, char *challenge, int methods)
+{
+	char reply[16];
+	struct MD5Context md5;
+	char realreply[256];
+	struct iax_ie_data ied;
+	memset(&ied, 0, sizeof(ied));
+	iax_ie_append_str(&ied, IAX_IE_USERNAME, (unsigned char *) session->username);
+	iax_ie_append_short(&ied, IAX_IE_REFRESH, session->refresh);
+	if ((methods & IAX_AUTHMETHOD_MD5) && challenge) {
+		MD5Init(&md5);
+		MD5Update(&md5, (const unsigned char *) challenge, (unsigned int)strlen(challenge));
+		MD5Update(&md5, (const unsigned char *) password, (unsigned int)strlen(password));
+		MD5Final((unsigned char *) reply, &md5);
+		memset(realreply, 0, sizeof(realreply));
+		convert_reply(realreply, (unsigned char *) reply);
+		iax_ie_append_str(&ied, IAX_IE_MD5_RESULT, (unsigned char *) realreply);
+	} else {
+		iax_ie_append_str(&ied, IAX_IE_PASSWORD, (unsigned char *) password);
+	}
+	return send_command(session, AST_FRAME_IAX, IAX_COMMAND_REGREQ, 0, ied.buf, ied.pos, -1);
+}
+
+
+int iax_dial(struct iax_session *session, char *number)
+{
+	struct iax_ie_data ied;
+	memset(&ied, 0, sizeof(ied));
+	iax_ie_append_str(&ied, IAX_IE_CALLED_NUMBER, (unsigned char *) number);
+	return send_command(session, AST_FRAME_IAX, IAX_COMMAND_DIAL, 0, ied.buf, ied.pos, -1);
+}
+
+int iax_quelch(struct iax_session *session)
+{
+	return send_command(session, AST_FRAME_IAX, IAX_COMMAND_QUELCH, 0, NULL, 0, -1);
+}
+
+int iax_unquelch(struct iax_session *session)
+{
+	return send_command(session, AST_FRAME_IAX, IAX_COMMAND_UNQUELCH, 0, NULL, 0, -1);
+}
+
+int iax_dialplan_request(struct iax_session *session, char *number)
+{
+	struct iax_ie_data ied;
+	memset(&ied, 0, sizeof(ied));
+	iax_ie_append_str(&ied, IAX_IE_CALLED_NUMBER, (unsigned char *) number);
+	return send_command(session, AST_FRAME_IAX, IAX_COMMAND_DPREQ, 0, ied.buf, ied.pos, -1);
+}
+
+static inline int which_bit(unsigned int i)
+{
+    char x;
+    for(x = 0; x < 32; x++) {
+        if ((1 << x) == i) {
+            return x + 1;
+        }
+    }
+    return 0;
+}
+
+char iax_pref_codec_add(struct iax_session *session, unsigned int format)
+{
+	int diff = (int) 'A';
+	session->codec_order[session->codec_order_len++] = (which_bit(format)) + diff;
+	session->codec_order[session->codec_order_len] = '\0';
+	return session->codec_order[session->codec_order_len-1];
+}
+
+
+void iax_pref_codec_del(struct iax_session *session, unsigned int format)
+{
+	int diff = (int) 'A';
+	size_t x;
+	char old[32];
+	char remove = which_bit(format) + diff;
+
+	strncpy(old, session->codec_order, sizeof(old));
+	session->codec_order_len = 0;
+
+	for (x = 0; x < strlen(old) ; x++) {
+		if (old[x] != remove) {
+			session->codec_order[session->codec_order_len++] = old[x];
+		}
+	}
+	session->codec_order[session->codec_order_len] = '\0';
+}
+
+int iax_pref_codec_get(struct iax_session *session, unsigned int *array, int len)
+{
+	int diff = (int) 'A';
+	int x;
+	
+	for (x = 0; x < session->codec_order_len && x < len; x++) {
+		array[x] = (1 << (session->codec_order[x] - diff - 1));
+	}
+
+	return x;
+}
+
+void iax_set_samplerate(struct iax_session *session, unsigned short samplemask)
+{
+	session->samplemask = samplemask;
+}
+
+
+int iax_call(struct iax_session *session, const char *cidnum, const char *cidname, char *ich, char *lang, int wait, int formats, int capabilities)
+{
+	char tmp[256]="";
+	char *part1, *part2;
+	int res;
+	int portno;
+	char *username, *hostname, *secret, *context, *exten, *dnid;
+	struct iax_ie_data ied;
+	struct hostent *hp;
+	/* We start by parsing up the temporary variable which is of the form of:
+	   [user@]peer[:portno][/exten[@context]] */
+	if (!ich) {
+		IAXERROR "Invalid IAX Call Handle\n");
+		DEBU(G "Invalid IAX Call Handle\n");
+		return -1;
+	}
+	memset(&ied, 0, sizeof(ied));
+	strncpy(tmp, ich, sizeof(tmp) - 1);	
+
+	iax_ie_append_short(&ied, IAX_IE_VERSION, IAX_PROTO_VERSION);
+    if (session->samplemask) {
+		iax_ie_append_short(&ied, IAX_IE_SAMPLINGRATE, session->samplemask);
+	}
+	if (cidnum)
+		iax_ie_append_str(&ied, IAX_IE_CALLING_NUMBER, (unsigned char *) cidnum);
+	if (cidname)
+		iax_ie_append_str(&ied, IAX_IE_CALLING_NAME, (unsigned char *) cidname);
+
+	if (session->codec_order_len) {
+		iax_ie_append_str(&ied, IAX_IE_CODEC_PREFS, (unsigned char *) session->codec_order);
+	}
+
+	session->capability = capabilities;
+	session->pingid = iax_sched_add(NULL,NULL, send_ping, (void *)session, 2 * 1000);
+
+	/* XXX We should have a preferred format XXX */
+	iax_ie_append_int(&ied, IAX_IE_FORMAT, formats);
+	iax_ie_append_int(&ied, IAX_IE_CAPABILITY, capabilities);
+	if (lang)
+		iax_ie_append_str(&ied, IAX_IE_LANGUAGE, (unsigned char *) lang);
+	
+	/* Part 1 is [user[:password]@]peer[:port] */
+	part1 = strtok(tmp, "/");
+
+	/* Part 2 is exten[@context] if it is anything all */
+	part2 = strtok(NULL, "/");
+	
+	if (strchr(part1, '@')) {
+		username = strtok(part1, "@");
+		hostname = strtok(NULL, "@");
+	} else {
+		username = NULL;
+		hostname = part1;
+	}
+	
+	if (username && strchr(username, ':')) {
+		username = strtok(username, ":");
+		secret = strtok(NULL, ":");
+	} else
+		secret = NULL;
+
+	if(username)
+	  strncpy(session->username, username, sizeof(session->username) - 1);
+
+	if(secret)
+	  strncpy(session->secret, secret, sizeof(session->secret) - 1);
+	
+	if (strchr(hostname, ':')) {
+		strtok(hostname, ":");
+		portno = atoi(strtok(NULL, ":"));
+	} else {
+		portno = IAX_DEFAULT_PORTNO;
+	}
+	if (part2) {
+		exten = strtok(part2, "@");
+		dnid = exten;
+		context = strtok(NULL, "@");
+	} else {
+		exten = NULL;
+		dnid = NULL;
+		context = NULL;
+	}
+	if (username)
+		iax_ie_append_str(&ied, IAX_IE_USERNAME, (unsigned char *) username);
+	if (exten && strlen(exten))
+		iax_ie_append_str(&ied, IAX_IE_CALLED_NUMBER, (unsigned char *) exten);
+	if (dnid && strlen(dnid))
+		iax_ie_append_str(&ied, IAX_IE_DNID, (unsigned char *) dnid);
+	if (context && strlen(context))
+		iax_ie_append_str(&ied, IAX_IE_CALLED_CONTEXT, (unsigned char *) context);
+
+	/* Setup host connection */
+	hp = gethostbyname(hostname);
+	if (!hp) {
+		snprintf(iax_errstr, sizeof(iax_errstr), "Invalid hostname: %s", hostname);
+		return -1;
+	}
+	memcpy(&session->peeraddr.sin_addr, hp->h_addr, sizeof(session->peeraddr.sin_addr));
+	session->peeraddr.sin_port = htons(portno);
+	session->peeraddr.sin_family = AF_INET;
+	res = send_command(session, AST_FRAME_IAX, IAX_COMMAND_NEW, 0, ied.buf, ied.pos, -1);
+	if (res < 0)
+		return res;
+	if (wait) {
+		DEBU(G "Waiting not yet implemented\n");
+		return -1;
+	}
+	return res;
+}
+
+static time_in_ms_t calc_rxstamp(struct iax_session *session)
+{
+	time_in_ms_t time_in_ms;
+
+	time_in_ms = current_time_in_ms();
+
+	if (!session->rxcore) {
+		session->rxcore = time_in_ms;
+	}
+
+	return time_in_ms - session->rxcore;
+}
+
+#ifdef notdef_cruft
+static int match(struct sockaddr_in *sin, short callno, short dcallno, struct iax_session *cur)
+{
+	if ((cur->peeraddr.sin_addr.s_addr == sin->sin_addr.s_addr) &&
+		(cur->peeraddr.sin_port == sin->sin_port)) {
+		/* This is the main host */
+		if ((cur->peercallno == callno) || 
+			((dcallno == cur->callno) && !cur->peercallno)) {
+			/* That's us.  Be sure we keep track of the peer call number */
+			cur->peercallno = callno;
+			return 1;
+		}
+	}
+	if ((cur->transfer.sin_addr.s_addr == sin->sin_addr.s_addr) &&
+	    (cur->transfer.sin_port == sin->sin_port) && (cur->transferring)) {
+		/* We're transferring */
+		if (dcallno == cur->callno)
+			return 1;
+	}
+	return 0;
+}
+#endif
+
+/* splitted match into 2 passes otherwise causing problem of matching
+   up the wrong session using the dcallno and the peercallno because
+   during a transfer (2 IAX channels on the same client/system) the
+   same peercallno (from two different asterisks) exist in more than
+	one session.
+ */
+static int forward_match(struct sockaddr_in *sin, short callno, short dcallno, struct iax_session *cur)
+{
+	if ((cur->transfer.sin_addr.s_addr == sin->sin_addr.s_addr) &&
+		(cur->transfer.sin_port == sin->sin_port) && (cur->transferring)) {
+		/* We're transferring */
+		if (dcallno == cur->callno)
+		{
+			return 1;
+		}
+	}
+
+	if ((cur->peeraddr.sin_addr.s_addr == sin->sin_addr.s_addr) &&
+		(cur->peeraddr.sin_port == sin->sin_port)) {
+		if (dcallno == cur->callno && dcallno != 0)  {
+					/* That's us.  Be sure we keep track of the peer call number */
+			if (cur->peercallno == 0) {
+				cur->peercallno = callno;
+			}
+			return 1;
+		}
+	}
+
+	return 0;
+}
+
+static int reverse_match(struct sockaddr_in *sin, short callno, struct iax_session *cur)
+{
+	if ((cur->transfer.sin_addr.s_addr == sin->sin_addr.s_addr) &&
+		(cur->transfer.sin_port == sin->sin_port) && (cur->transferring)) {
+		/* We're transferring */
+		if (callno == cur->peercallno)  {
+			return 1;
+		}
+	}
+	if ((cur->peeraddr.sin_addr.s_addr == sin->sin_addr.s_addr) &&
+		(cur->peeraddr.sin_port == sin->sin_port)) {
+		if (callno == cur->peercallno)  {
+			return 1;
+		}
+	}
+
+	return 0;
+}
+
+static struct iax_session *iax_find_session(struct sockaddr_in *sin, 
+											short callno, 
+											short dcallno,
+											int makenew)
+{
+	struct iax_session *cur;
+
+	iax_mutex_lock(session_mutex); 
+	cur = sessions;
+	while(cur) {
+		if (forward_match(sin, callno, dcallno, cur)) {
+			iax_mutex_unlock(session_mutex); 
+			return cur;
+		}
+		cur = cur->next;
+	}
+
+	cur = sessions;
+	while(cur) {
+		if (reverse_match(sin, callno, cur)) {
+			iax_mutex_unlock(session_mutex); 
+			return cur;
+		}
+		cur = cur->next;
+	}
+
+	iax_mutex_unlock(session_mutex); 
+
+	if (makenew && !dcallno) {
+		cur = iax_session_new();
+		cur->peercallno = callno;
+		cur->peeraddr.sin_addr.s_addr = sin->sin_addr.s_addr;
+		cur->peeraddr.sin_port = sin->sin_port;
+		cur->peeraddr.sin_family = AF_INET;
+		cur->pingid = iax_sched_add(NULL,NULL, send_ping, (void *)cur, 2 * 1000);
+		DEBU(G "Making new session, peer callno %d, our callno %d\n", callno, cur->callno);
+	} else {
+		DEBU(G "No session, peer = %d, us = %d\n", callno, dcallno);
+	}
+
+	return cur;	
+}
+
+#ifdef EXTREME_DEBUG
+static int display_time(int ms)
+{
+	static int oldms = -1;
+	if (oldms < 0) {
+		DEBU(G "First measure\n");
+		oldms = ms;
+		return 0;
+	}
+	DEBU(G "Time from last frame is %d ms\n", ms - oldms);
+	oldms = ms;
+	return 0;
+}
+#endif
+
+#define FUDGE 1
+
+#ifdef NEWJB
+/* From chan_iax2/steve davies:  need to get permission from steve or digium, I guess */
+static time_in_ms_t unwrap_timestamp(time_in_ms_t ts, time_in_ms_t last)
+{
+        time_in_ms_t x;
+
+        if ( (ts & 0xFFFF0000) == (last & 0xFFFF0000) ) {
+                x = ts - last;
+                if (x < -50000) {
+                        /* Sudden big jump backwards in timestamp:
+                           What likely happened here is that miniframe timestamp has circled but we haven't
+                           gotten the update from the main packet.  We'll just pretend that we did, and
+                           update the timestamp appropriately. */
+                        ts = ( (last & 0xFFFF0000) + 0x10000) | (ts & 0xFFFF);
+                                DEBU(G "schedule_delivery: pushed forward timestamp\n");
+                }
+                if (x > 50000) {
+                        /* Sudden apparent big jump forwards in timestamp:
+                           What's likely happened is this is an old miniframe belonging to the previous
+                           top-16-bit timestamp that has turned up out of order.
+                           Adjust the timestamp appropriately. */
+                        ts = ( (last & 0xFFFF0000) - 0x10000) | (ts & 0xFFFF);
+                                DEBU(G "schedule_delivery: pushed back timestamp\n");
+                }
+        }
+	return ts;
+}
+#endif
+
+
+static struct iax_event *schedule_delivery(struct iax_event *e, time_in_ms_t ts, int updatehistory)
+{
+	/* 
+	 * This is the core of the IAX jitterbuffer delivery mechanism: 
+	 * Dynamically adjust the jitterbuffer and decide how time_in_ms_t to wait
+	 * before delivering the packet.
+	 */
+#ifndef NEWJB
+	int ms, x;
+	int drops[MEMORY_SIZE];
+	int min, max=0, maxone=0, y, z, match;
+#endif
+
+#ifdef EXTREME_DEBUG	
+	DEBU(G "[%p] We are at %d, packet is for %d\n", e->session, calc_rxstamp(e->session), ts);
+#endif
+	
+#ifdef VOICE_SMOOTHING
+	if (e->etype == IAX_EVENT_VOICE) {
+		/* Smooth voices if we know enough about the format */
+		switch(e->event.voice.format) {
+		case AST_FORMAT_GSM:
+			/* GSM frames are 20 ms long, although there could be periods of 
+			   silence.  If the time is < 50 ms, assume it ought to be 20 ms */
+			if (ts - e->session->lastts < 50)  
+				ts = e->session->lastts + 20;
+#ifdef EXTREME_DEBUG
+			display_time(ts);
+#endif
+			break;
+		default:
+			/* Can't do anything */
+		}
+		e->session->lastts = ts;
+	}
+#endif
+
+#ifdef NEWJB
+	{
+	    int type = JB_TYPE_CONTROL;
+	    int len = 0;
+
+	    if(e->etype == IAX_EVENT_VOICE) {
+	      type = JB_TYPE_VOICE;
+	      len = get_sample_cnt(e) / 8;
+	    } else if(e->etype == IAX_EVENT_CNG) {
+	      type = JB_TYPE_SILENCE;	
+	    }
+
+	    /* unwrap timestamp */
+	    ts = unwrap_timestamp(ts,e->session->last_ts);
+
+	    /* move forward last_ts if it's greater.  We do this _after_ unwrapping, because
+	     * asterisk _still_ has cases where it doesn't send full frames when it ought to */
+	    if(ts > e->session->last_ts) {
+		e->session->last_ts = ts;		
+	    }
+
+
+	    /* insert into jitterbuffer */
+	    /* TODO: Perhaps we could act immediately if it's not droppable and late */
+	    if(jb_put(e->session->jb, e, type, len, ts, calc_rxstamp(e->session)) == JB_DROP) {
+		  iax_event_free(e);
+	    }
+
+	}
+#else
+	
+	/* How many ms from now should this packet be delivered? (remember
+	   this can be a negative number, too */
+	ms = (int)(calc_rxstamp(e->session) - ts);
+
+	/*  
+	   Drop voice frame if timestamp is way off 
+	   if ((e->etype == IAX_EVENT_VOICE) && ((ms > 65536) || (ms < -65536))) {
+	   DEBU(G "Dropping a voice packet with odd ts (ts = %d; ms = %d)\n", ts, ms);
+	   free(e);
+	   return NULL;
+	   }
+	*/
+
+	/* Adjust if voice frame timestamp is off by a step */
+	if (ms > 32768) {
+		/* What likely happened here is that our counter has circled but we haven't
+		   gotten the update from the main packet.  We'll just pretend that we did, and
+		   update the timestamp appropriately. */
+		ms -= 65536;
+	}
+	if (ms < -32768) {
+		/* We got this packet out of order.  Lets add 65536 to it to bring it into our new
+		   time frame */
+		ms += 65536;
+	}
+
+#if 0	
+	printf("rxstamp is %d, timestamp is %d, ms is %d\n", calc_rxstamp(e->session), ts, ms);
+#endif
+	/* Rotate history queue.  Leading 0's are irrelevant. */
+	if (updatehistory) {
+	    for (x=0; x < MEMORY_SIZE - 1; x++) 
+		    e->session->history[x] = e->session->history[x+1];
+	    
+	    /* Add new entry for this time */
+	    e->session->history[x] = ms;
+	}
+	
+	/* We have to find the maximum and minimum time delay we've had to deliver. */
+	min = e->session->history[0];
+	for (z=0;z < iax_dropcount + 1; z++) {
+		/* We drop the top iax_dropcount entries.  iax_dropcount represents
+		   a tradeoff between quality of voice and latency.  3% drop seems to
+		   be unnoticable to the client and can significantly improve latency.  
+		   We add one more to our droplist, but that's the one we actually use, 
+		   and don't drop.  */
+		max = -99999999;
+		for (x=0;x<MEMORY_SIZE;x++) {
+			if (max < e->session->history[x]) {
+				/* New candidate value.  Make sure we haven't dropped it. */
+				match=0;
+				for(y=0;!match && (y<z); y++) 
+					match |= (drops[y] == x);
+				/* If there is no match, this is our new maximum */
+				if (!match) {
+					max = e->session->history[x];
+					maxone = x;
+				}
+			}
+			if (!z) {
+				/* First pass, calcualte our minimum, too */
+				if (min > e->session->history[x])
+					min = e->session->history[x];
+			}
+		}
+		drops[z] = maxone;
+	}
+	/* Again, just for reference.  The "jitter buffer" is the max.  The difference
+	   is the perceived jitter correction. */
+	e->session->jitter = max - min;
+	
+	/* If the jitter buffer is substantially too large, shrink it, slowly enough
+	   that the client won't notice ;-) . */
+	if (max < e->session->jitterbuffer - max_extra_jitterbuffer) {
+#ifdef EXTREME_DEBUG
+		DEBU(G "Shrinking jitterbuffer (target = %d, current = %d...\n", max, e->session->jitterbuffer);
+#endif
+		e->session->jitterbuffer -= 1;
+	}
+		
+	/* Keep the jitter buffer from becoming unreasonably large */
+	if (max > min + max_jitterbuffer) {
+		DEBU(G "Constraining jitter buffer (min = %d, max = %d)...\n", min, max);
+		max = min + max_jitterbuffer;
+	}
+	
+	/* If the jitter buffer is too small, we immediately grow our buffer to
+	   accomodate */
+	if (max > e->session->jitterbuffer)
+		e->session->jitterbuffer = max;
+	
+	/* Start with our jitter buffer delay, and subtract the lateness (or earliness).
+	   Remember these times are all relative to the first packet, so their absolute
+	   values are really irrelevant. */
+	ms = e->session->jitterbuffer - ms - IAX_SCHEDULE_FUZZ;
+	
+	/* If the jitterbuffer is disabled, always deliver immediately */
+	if (!iax_use_jitterbuffer)
+		ms = 0;
+	
+	if (ms < 1) {
+#ifdef EXTREME_DEBUG
+		DEBU(G "Calculated delay is only %d\n", ms);
+#endif
+		if ((ms > -4) || (e->etype != IAX_EVENT_VOICE)) {
+			/* Return the event immediately if it's it's less than 3 milliseconds
+			   too late, or if it's not voice (believe me, you don't want to
+			   just drop a hangup frame because it's late, or a ping, or some such.
+			   That kinda ruins retransmissions too ;-) */
+			/* Queue for immediate delivery */
+			iax_sched_add(e, NULL, NULL, NULL, 0);
+			return NULL;
+			//return e;
+		}
+		DEBU(G "(not so) Silently dropping a packet (ms = %d)\n", ms);
+		/* Silently discard this as if it were to be delivered */
+		free(e);
+		return NULL;
+	}
+	/* We need this to be delivered in the future, so we use our scheduler */
+	iax_sched_add(e, NULL, NULL, NULL, ms);
+#ifdef EXTREME_DEBUG
+	DEBU(G "Delivering packet in %d ms\n", ms);
+#endif
+#endif /* NEWJB */
+	return NULL;
+	
+}
+
+static int uncompress_subclass(unsigned char csub)
+{
+	/* If the SC_LOG flag is set, return 2^csub otherwise csub */
+	if (csub & IAX_FLAG_SC_LOG)
+		return 1 << (csub & ~IAX_FLAG_SC_LOG & IAX_MAX_SHIFT);
+	else
+		return csub;
+}
+
+static inline char *extract(char *src, char *string)
+{
+	/* Extract and duplicate what we need from a string */
+	char *s, *t;
+	s = strstr(src, string);
+	if (s) {
+		s += strlen(string);
+		s = strdup(s);
+		/* End at ; */
+		t = strchr(s, ';');
+		if (t) {
+			*t = '\0';
+		}
+	}
+	return s;
+		
+}
+
+static struct iax_event *iax_header_to_event(struct iax_session *session,
+											 struct ast_iax2_full_hdr *fh,
+											 int datalen, struct sockaddr_in *sin)
+{
+	struct iax_event *e;
+	struct iax_sched *sch;
+	unsigned int ts;
+	int subclass = uncompress_subclass(fh->csub);
+	time_in_ms_t nowts;
+	int updatehistory = 1;
+	ts = ntohl(fh->ts);
+	/* don't run last_ts backwards; i.e. for retransmits and the like */
+	if (ts > session->last_ts &&
+	    (fh->type == AST_FRAME_IAX && 
+	     subclass != IAX_COMMAND_ACK &&
+	     subclass != IAX_COMMAND_PONG &&
+	     subclass != IAX_COMMAND_LAGRP)) {
+	    session->last_ts = ts;
+	}
+
+
+#ifdef DEBUG_SUPPORT
+	iax_showframe(NULL, fh, 1, sin, datalen);
+#endif
+
+	/* Get things going with it, timestamp wise, if we
+	   haven't already. */
+
+		/* Handle implicit ACKing unless this is an INVAL, and only if this is 
+		   from the real peer, not the transfer peer */
+		if (!inaddrcmp(sin, &session->peeraddr) && 
+			(((subclass != IAX_COMMAND_INVAL)) ||
+			(fh->type != AST_FRAME_IAX))) {
+			unsigned char x;
+			/* XXX This code is not very efficient.  Surely there is a better way which still
+			       properly handles boundary conditions? XXX */
+			/* First we have to qualify that the ACKed value is within our window */
+			for (x=session->rseqno; x != session->oseqno; x++)
+				if (fh->iseqno == x)
+					break;
+			if ((x != session->oseqno) || (session->oseqno == fh->iseqno)) {
+				/* The acknowledgement is within our window.  Time to acknowledge everything
+				   that it says to */
+				for (x=session->rseqno; x != fh->iseqno; x++) {
+					/* Ack the packet with the given timestamp */
+					DEBU(G "Cancelling transmission of packet %d\n", x);
+					iax_mutex_lock(sched_mutex);
+					sch = schedq;
+					while(sch) {
+						if (sch->frame && (sch->frame->session == session) && 
+						    (sch->frame->oseqno == x)) 
+							sch->frame->retries = -1;
+						sch = sch->next;
+					}
+					iax_mutex_unlock(sched_mutex);
+				}
+				/* Note how much we've received acknowledgement for */
+				session->rseqno = fh->iseqno;
+			} else
+				DEBU(G "Received iseqno %d not within window %d->%d\n", fh->iseqno, session->rseqno, session->oseqno);
+		}
+
+	/* Check where we are */
+		if ((ntohs(fh->dcallno) & IAX_FLAG_RETRANS) || (fh->type != AST_FRAME_VOICE))
+			updatehistory = 0;
+		if ((session->iseqno != fh->oseqno) &&
+			(session->iseqno ||
+			   ((subclass != IAX_COMMAND_TXREADY) &&
+			    (subclass != IAX_COMMAND_TXREL) &&
+				(subclass != IAX_COMMAND_TXCNT) &&
+				(subclass != IAX_COMMAND_TXACC)) ||
+			  (fh->type != AST_FRAME_IAX))) {
+			if (
+			 ((subclass != IAX_COMMAND_ACK) &&
+			  (subclass != IAX_COMMAND_INVAL) &&
+			  (subclass != IAX_COMMAND_TXREADY) &&
+			  (subclass != IAX_COMMAND_TXREL) &&
+			  (subclass != IAX_COMMAND_TXCNT) &&
+			  (subclass != IAX_COMMAND_TXACC) &&
+			  (subclass != IAX_COMMAND_VNAK)) ||
+			  (fh->type != AST_FRAME_IAX)) {
+			 	/* If it's not an ACK packet, it's out of order. */
+				DEBU(G "Packet arrived out of order (expecting %d, got %d) (frametype = %d, subclass = %d)\n", 
+					session->iseqno, fh->oseqno, fh->type, subclass);
+				if (session->iseqno > fh->oseqno) {
+					/* If we've already seen it, ack it XXX There's a border condition here XXX */
+					if ((fh->type != AST_FRAME_IAX) || 
+							((subclass != IAX_COMMAND_ACK) && (subclass != IAX_COMMAND_INVAL))) {
+						DEBU(G "Acking anyway\n");
+						/* XXX Maybe we should handle its ack to us, but then again, it's probably outdated anyway, and if
+						   we have anything to send, we'll retransmit and get an ACK back anyway XXX */
+						send_command_immediate(session, AST_FRAME_IAX, IAX_COMMAND_ACK, ts, NULL, 0,fh->iseqno);
+					}
+				} else {
+					/* Send a VNAK requesting retransmission */
+					iax2_vnak(session);
+				}
+				return NULL;
+			}
+		} else {
+			/* Increment unless it's an ACK or VNAK */
+			if (((subclass != IAX_COMMAND_ACK) &&
+			    (subclass != IAX_COMMAND_INVAL) &&
+			    (subclass != IAX_COMMAND_TXCNT) &&
+			    (subclass != IAX_COMMAND_TXACC) &&
+				(subclass != IAX_COMMAND_VNAK)) ||
+			    (fh->type != AST_FRAME_IAX))
+				session->iseqno++;
+		}
+			
+	e = (struct iax_event *)malloc(sizeof(struct iax_event) + datalen + 1);
+
+	if (e) {
+		memset(e, 0, sizeof(struct iax_event) + datalen);
+		/* Set etype to some unknown value so do not inavertently
+		   sending IAX_EVENT_CONNECT event, which is 0 to application.
+		 */
+		e->etype = -1;
+		e->session = session;
+		switch(fh->type) {
+		case AST_FRAME_DTMF:
+			e->etype = IAX_EVENT_DTMF;
+			e->subclass = subclass;
+			/* 
+			 We want the DTMF event deliver immediately so all I/O can be
+			 terminate quickly in an IVR system.
+			e = schedule_delivery(e, ts, updatehistory); */
+			break;
+		case AST_FRAME_VOICE:
+			e->etype = IAX_EVENT_VOICE;
+			e->subclass = subclass;
+			session->voiceformat = subclass;
+			if (datalen) {
+				memcpy(e->data, fh->iedata, datalen);
+				e->datalen = datalen;
+			}
+			e = schedule_delivery(e, ts, updatehistory);
+			break;
+		case AST_FRAME_CNG:
+			e->etype = IAX_EVENT_CNG;
+			e->subclass = subclass;
+                        if (datalen) {
+                                memcpy(e->data, fh->iedata, datalen);
+                                e->datalen = datalen;
+                        }
+                        e = schedule_delivery(e, ts, updatehistory);
+                        break;
+		case AST_FRAME_IAX:
+			/* Parse IE's */
+			if (datalen) {
+				memcpy(e->data, fh->iedata, datalen);
+				e->datalen = datalen;
+			}
+			if (iax_parse_ies(&e->ies, e->data, e->datalen)) {
+				IAXERROR "Unable to parse IE's");
+				free(e);
+				e = NULL;
+				break;
+			}
+			switch(subclass) {
+			case IAX_COMMAND_NEW:
+				/* This is a new, incoming call */
+				/* save the capability for validation */
+				session->capability = e->ies.capability;
+				if (e->ies.codec_prefs) {
+					strncpy(session->codec_order, e->ies.codec_prefs, sizeof(session->codec_order));
+					session->codec_order_len = (int)strlen(session->codec_order);
+				}
+				e->etype = IAX_EVENT_CONNECT;
+				e = schedule_delivery(e, ts, updatehistory);
+				break;
+			case IAX_COMMAND_AUTHREQ:
+				/* This is a request for a call */
+				e->etype = IAX_EVENT_AUTHRQ;
+				if (strlen(session->username) && !strcmp(e->ies.username, session->username) &&
+					strlen(session->secret)) {
+						/* Hey, we already know this one */
+						iax_auth_reply(session, session->secret, e->ies.challenge, e->ies.authmethods);
+						free(e);
+						e = NULL;
+						break;
+				}
+				e = schedule_delivery(e, ts, updatehistory);
+				break;
+			case IAX_COMMAND_HANGUP:
+				e->etype = IAX_EVENT_HANGUP;
+				e = schedule_delivery(e, ts, updatehistory);
+				break;
+			case IAX_COMMAND_INVAL:
+				e->etype = IAX_EVENT_HANGUP;
+				e = schedule_delivery(e, ts, updatehistory);
+				break;
+			case IAX_COMMAND_REJECT:
+				e->etype = IAX_EVENT_REJECT;
+				e = schedule_delivery(e, ts, updatehistory);
+				break;
+			case IAX_COMMAND_ACK:
+				free(e);
+				e = NULL;
+				break;
+			case IAX_COMMAND_LAGRQ:
+				/* Pass this atime_in_ms_t for later handling */
+				e->etype = IAX_EVENT_LAGRQ;
+				e->ts = ts;
+				e = schedule_delivery(e, ts, updatehistory);
+				break;
+			case IAX_COMMAND_POKE:
+				e->etype = IAX_EVENT_POKE;
+				e->ts = ts;
+				break;
+			case IAX_COMMAND_PING:
+				/* PINGS and PONGS don't get scheduled; */
+				e->etype = IAX_EVENT_PING;
+				e->ts = ts;
+				break;
+			case IAX_COMMAND_PONG:
+				e->etype = IAX_EVENT_PONG;
+				/* track weighted average of ping time */
+				session->pingtime = ((2 * session->pingtime) + (calc_timestamp(session,0,NULL) - ts)) / 3;
+				session->remote_netstats.jitter = e->ies.rr_jitter;
+				session->remote_netstats.losspct = e->ies.rr_loss >> 24;;
+				session->remote_netstats.losscnt = e->ies.rr_loss & 0xffffff;
+				session->remote_netstats.packets = e->ies.rr_pkts;
+				session->remote_netstats.delay = e->ies.rr_delay;
+				session->remote_netstats.dropped = e->ies.rr_dropped;
+				session->remote_netstats.ooo = e->ies.rr_ooo;
+				break;
+			case IAX_COMMAND_ACCEPT:
+				if (e->ies.format & session->capability) {
+					e->etype = IAX_EVENT_ACCEPT;
+				}
+				else {
+					struct iax_ie_data ied;
+					/* Although this should not happen, we added this to make sure
+					   the negotiation protocol is enforced.
+						For lack of event to notify the application we use the defined
+						REJECT event.
+					 */
+					memset(&ied, 0, sizeof(ied));
+					iax_ie_append_str(&ied, IAX_IE_CAUSE, (unsigned char *) "Unable to negotiate codec");
+					send_command_final(session, AST_FRAME_IAX, IAX_COMMAND_REJECT, 0, ied.buf, ied.pos, -1);
+					e->etype = IAX_EVENT_REJECT;
+				}
+				e = schedule_delivery(e, ts, updatehistory);
+				break;
+			case IAX_COMMAND_REGREQ:
+				e->etype = IAX_EVENT_REGREQ;
+				e = schedule_delivery(e, ts, updatehistory);
+				break;
+			case IAX_COMMAND_REGREL:
+				e->etype = IAX_EVENT_REGREQ;
+				e = schedule_delivery(e, ts, updatehistory);
+				break;
+			case IAX_COMMAND_REGACK:
+				e->etype = IAX_EVENT_REGACK;
+				e = schedule_delivery(e, ts, updatehistory);
+				break;
+			case IAX_COMMAND_REGAUTH:
+				iax_regauth_reply(session, session->secret, e->ies.challenge, e->ies.authmethods);
+				free(e);
+				e = NULL;
+				break;
+			case IAX_COMMAND_REGREJ:
+				e->etype = IAX_EVENT_REGREJ;
+				e = schedule_delivery(e, ts, updatehistory);
+				break;
+			case IAX_COMMAND_LAGRP:
+				e->etype = IAX_EVENT_LAGRP;
+				nowts = calc_timestamp(session, 0, NULL);
+				e->ts = nowts - ts;
+				e->subclass = session->jitter;
+				/* Can't call schedule_delivery since timestamp is non-normal */
+				break;;
+			case IAX_COMMAND_TXREQ:
+				/* added check for defensive programming
+				 * - in case the asterisk server
+				 * or another client does not send the
+				 *  apparent transfer address
+				 */
+				if (e->ies.apparent_addr != NULL) {
+				    /* so a full voice frame is sent on the 
+				       next voice output */
+				    session->svoiceformat = -1;	
+				    session->transfer = *e->ies.apparent_addr;
+				    session->transfer.sin_family = AF_INET;
+				    session->transfercallno = e->ies.callno;
+				    session->transferring = TRANSFER_BEGIN;
+				    session->transferid = e->ies.transferid;
+				    iax_send_txcnt(session);
+				}
+				free(e);
+				e = NULL;
+				break;
+			case IAX_COMMAND_DPREP:
+				/* Received dialplan reply */
+				e->etype = IAX_EVENT_DPREP;
+				/* Return immediately, makes no sense to schedule */
+				break;
+			case IAX_COMMAND_TXCNT:
+				if (session->transferring)  {
+					session->transfer = *sin;
+					iax_send_txaccept(session);
+				}
+				free(e);
+				e = NULL;
+				break;
+			case IAX_COMMAND_TXACC:
+				if (session->transferring) {
+					stop_transfer(session);
+					session->transferring = TRANSFER_READY;
+					iax_send_txready(session);
+				}
+				free(e);
+				e = NULL;
+				break;
+			case IAX_COMMAND_TXREL:
+				/* Release the transfer */
+			   send_command_immediate(session, AST_FRAME_IAX, IAX_COMMAND_ACK, fh->ts, NULL, 0, fh->iseqno);
+				if (session->transferring) {
+					complete_transfer(session, e->ies.callno, 1, 0);
+				}
+				else {
+					complete_transfer(session, session->peercallno, 0, 1);
+				}
+				e->etype = IAX_EVENT_TRANSFER;
+				/* notify that asterisk no longer sitting between peers */
+				e = schedule_delivery(e, ts, updatehistory);
+				break;
+			case IAX_COMMAND_QUELCH:
+				e->etype = IAX_EVENT_QUELCH;
+				session->quelch = 1;
+				break;
+			case IAX_COMMAND_UNQUELCH:
+				e->etype = IAX_EVENT_UNQUELCH;
+				session->quelch = 0;
+				break;
+			case IAX_COMMAND_TXREJ:
+				e->etype = IAX_EVENT_TXREJECT;
+				iax_handle_txreject(session);
+				break;
+
+			case IAX_COMMAND_TXREADY:
+				send_command_immediate(session, AST_FRAME_IAX, IAX_COMMAND_ACK, ts, NULL, 0, fh->iseqno);
+				if (iax_handle_txready(session)) {
+					e->etype = IAX_EVENT_TXREADY;
+				}
+				else {
+					free(e);
+					e = NULL;
+				}
+				break;
+			default:
+				DEBU(G "Don't know what to do with IAX command %d\n", subclass);
+				free(e);
+				e = NULL;
+			}
+			break;
+		case AST_FRAME_CONTROL:
+			switch(subclass) {
+			case AST_CONTROL_ANSWER:
+				e->etype = IAX_EVENT_ANSWER;
+				e = schedule_delivery(e, ts, updatehistory);
+				break;
+			case AST_CONTROL_CONGESTION:
+			case AST_CONTROL_BUSY:
+				e->etype = IAX_EVENT_BUSY;
+				e = schedule_delivery(e, ts, updatehistory);
+				break;
+			case AST_CONTROL_RINGING:
+				e->etype = IAX_EVENT_RINGA;
+				e = schedule_delivery(e, ts, updatehistory);
+				break;
+			default:
+				DEBU(G "Don't know what to do with AST control %d\n", subclass);
+				free(e);
+				return NULL;
+			}
+			break;
+		case AST_FRAME_IMAGE:
+			e->etype = IAX_EVENT_IMAGE;
+			e->subclass = subclass;
+			if (datalen) {
+				memcpy(e->data, fh->iedata, datalen);
+			}
+			e = schedule_delivery(e, ts, updatehistory);
+			break;
+
+		case AST_FRAME_TEXT:
+			e->etype = IAX_EVENT_TEXT;
+			if (datalen) {
+				memcpy(e->data, fh->iedata, datalen);
+			}
+			e = schedule_delivery(e, ts, updatehistory);
+			break;
+
+		case AST_FRAME_HTML:
+			switch(fh->csub) {
+			case AST_HTML_LINKURL:
+				e->etype = IAX_EVENT_LINKURL;
+				/* Fall through */
+			case AST_HTML_URL:
+				if (e->etype == -1)
+					e->etype = IAX_EVENT_URL;
+				e->