diff -ur --exclude=CVS libiax2/src/frame.h /home/stevek/work/hms/iaxclient/lib/libiax2/src/frame.h
--- libiax2/src/frame.h	2003-04-16 23:54:42.000000000 -0400
+++ /home/stevek/work/hms/iaxclient/lib/libiax2/src/frame.h	2004-10-27 11:33:45.000000000 -0400
@@ -30,6 +30,7 @@
 #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 */
diff -ur --exclude=CVS libiax2/src/iax2-parser.c /home/stevek/work/hms/iaxclient/lib/libiax2/src/iax2-parser.c
--- libiax2/src/iax2-parser.c	2004-04-12 10:24:51.000000000 -0400
+++ /home/stevek/work/hms/iaxclient/lib/libiax2/src/iax2-parser.c	2004-12-03 12:03:38.000000000 -0500
@@ -20,19 +20,40 @@
 #include <netinet/in.h>
 #include <arpa/inet.h>
 #endif
-#include <string.h>
-#include "frame.h"
+
+#ifndef _MSC_VER
 #include <unistd.h>
+#endif
+
+#include <string.h>
 #include <stdlib.h>
 #include <stdio.h>
+
+#include "frame.h"
 #include "iax2.h"
 #include "iax2-parser.h"
 
-
 static int frames = 0;
 static int iframes = 0;
 static int oframes = 0;
 
+#ifdef ALIGN32
+static unsigned int get_uint32(unsigned char *p)
+{
+  return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
+}
+
+static unsigned short get_uint16(unsigned char *p)
+{
+  return (p[0] << 8) | p[1] ;
+}
+
+#else
+#define get_uint32(p) (*((unsigned int *)(p)))
+#define get_uint16(p) (*((unsigned short *)(p)))
+#endif
+
+
 static void internaloutput(const char *str)
 {
 	printf(str);
@@ -69,7 +90,7 @@
 static void dump_int(char *output, int maxlen, void *value, int len)
 {
 	if (len == sizeof(unsigned int))
-		snprintf(output, maxlen, "%ld", (long)ntohl(*((unsigned int *)value)));
+		snprintf(output, maxlen, "%ld", (unsigned long)ntohl(get_uint32(value)));
 	else
 		snprintf(output, maxlen, "Invalid INT");
 }
@@ -77,7 +98,7 @@
 static void dump_short(char *output, int maxlen, void *value, int len)
 {
 	if (len == sizeof(unsigned short))
-		snprintf(output, maxlen, "%d", ntohs(*((unsigned short *)value)));
+		snprintf(output, maxlen, "%d", ntohs(get_uint16(value)));
 	else
 		snprintf(output, maxlen, "Invalid SHORT");
 }
@@ -402,14 +423,14 @@
 				snprintf(tmp, sizeof(tmp), "Expecting capability to be %d bytes long but was %d\n", sizeof(unsigned int), len);
 				errorf(tmp);
 			} else
-				ies->capability = ntohl(*((unsigned int *)(data + 2)));
+				ies->capability = ntohl(get_uint32(data+2));
 			break;
 		case IAX_IE_FORMAT:
 			if (len != sizeof(unsigned int)) {
 				snprintf(tmp, sizeof(tmp), "Expecting format to be %d bytes long but was %d\n", sizeof(unsigned int), len);
 				errorf(tmp);
 			} else
-				ies->format = ntohl(*((unsigned int *)(data + 2)));
+				ies->format = ntohl(get_uint32(data+2));
 			break;
 		case IAX_IE_LANGUAGE:
 			ies->language = data + 2;
@@ -419,14 +440,14 @@
 				snprintf(tmp, sizeof(tmp),  "Expecting version to be %d bytes long but was %d\n", sizeof(unsigned short), len);
 				errorf(tmp);
 			} else
-				ies->version = ntohs(*((unsigned short *)(data + 2)));
+				ies->version = ntohs(get_uint16(data+2));
 			break;
 		case IAX_IE_ADSICPE:
 			if (len != sizeof(unsigned short)) {
 				snprintf(tmp, sizeof(tmp), "Expecting adsicpe to be %d bytes long but was %d\n", sizeof(unsigned short), len);
 				errorf(tmp);
 			} else
-				ies->adsicpe = ntohs(*((unsigned short *)(data + 2)));
+				ies->adsicpe = ntohs(get_uint16(data+2));
 			break;
 		case IAX_IE_DNID:
 			ies->dnid = data + 2;
@@ -439,7 +460,7 @@
 				snprintf(tmp, sizeof(tmp), "Expecting authmethods to be %d bytes long but was %d\n", sizeof(unsigned short), len);
 				errorf(tmp);
 			} else
-				ies->authmethods = ntohs(*((unsigned short *)(data + 2)));
+				ies->authmethods = ntohs(get_uint16(data+2));
 			break;
 		case IAX_IE_CHALLENGE:
 			ies->challenge = data + 2;
@@ -451,14 +472,15 @@
 			ies->rsa_result = data + 2;
 			break;
 		case IAX_IE_APPARENT_ADDR:
-			ies->apparent_addr = ((struct sockaddr_in *)(data + 2));
+			/* XXX need to check alignment? */
+			ies->apparent_addr = ((struct sockaddr_in *)(data+2));
 			break;
 		case IAX_IE_REFRESH:
 			if (len != sizeof(unsigned short)) {
 				snprintf(tmp, sizeof(tmp),  "Expecting refresh to be %d bytes long but was %d\n", sizeof(unsigned short), len);
 				errorf(tmp);
 			} else
-				ies->refresh = ntohs(*((unsigned short *)(data + 2)));
+				ies->refresh = ntohs(get_uint16(data+2));
 			break;
 		case IAX_IE_DPSTATUS:
 			if (len != sizeof(unsigned short)) {
@@ -472,7 +494,7 @@
 				snprintf(tmp, sizeof(tmp),  "Expecting callno to be %d bytes long but was %d\n", sizeof(unsigned short), len);
 				errorf(tmp);
 			} else
-				ies->callno = ntohs(*((unsigned short *)(data + 2)));
+				ies->callno = ntohs(get_uint16(data+2));
 			break;
 		case IAX_IE_CAUSE:
 			ies->cause = data + 2;
@@ -490,7 +512,7 @@
 				snprintf(tmp, sizeof(tmp), "Expecting msgcount to be %d bytes long but was %d\n", sizeof(unsigned short), len);
 				errorf(tmp);
 			} else
-				ies->msgcount = ntohs(*((unsigned short *)(data + 2)));	
+				ies->msgcount = ntohs(get_uint16(data+2));
 			break;
 		case IAX_IE_AUTOANSWER:
 			ies->autoanswer = 1;
@@ -503,14 +525,14 @@
 				snprintf(tmp, sizeof(tmp), "Expecting transferid to be %d bytes long but was %d\n", sizeof(unsigned int), len);
 				errorf(tmp);
 			} else
-				ies->transferid = ntohl(*((unsigned int *)(data + 2)));
+				ies->transferid = ntohl(get_uint32(data+2));
 			break;
 		case IAX_IE_DATETIME:
 			if (len != sizeof(unsigned int)) {
 				snprintf(tmp, sizeof(tmp), "Expecting date/time to be %d bytes long but was %d\n", sizeof(unsigned int), len);
 				errorf(tmp);
 			} else
-				ies->datetime = ntohl(*((unsigned int *)(data + 2)));
+				ies->datetime = ntohl(get_uint32(data+2));
 			break;
 		default:
 			snprintf(tmp, sizeof(tmp), "Ignoring unknown information element '%s' (%d) of length %d\n", iax_ie2str(ie), ie, len);
diff -ur --exclude=CVS libiax2/src/iax.c /home/stevek/work/hms/iaxclient/lib/libiax2/src/iax.c
--- libiax2/src/iax.c	2004-10-01 12:42:48.000000000 -0400
+++ /home/stevek/work/hms/iaxclient/lib/libiax2/src/iax.c	2004-12-03 14:20:31.000000000 -0500
@@ -23,7 +23,14 @@
 #include <fcntl.h>
 #include <io.h>
 #include <errno.h>
-#include <winpoop.h>
+
+#define	snprintf _snprintf
+
+#if defined(_MSC_VER)
+#define	close		_close
+#endif
+
+void gettimeofday(struct timeval *tv, struct timezone *tz);
 
 #else
 
@@ -45,15 +52,13 @@
 
 #ifndef MACOSX
 #include <malloc.h>
+#ifndef SOLARIS
 #include <error.h>
 #endif
-
 #endif
 
+#endif
 
-#include "frame.h" 
-#include "iax2.h"
-#include "iax2-parser.h"
 #include "iax-client.h"
 #include "md5.h"
 
@@ -73,10 +78,14 @@
 #else
 #ifdef MACOSX
 #define IAX_SOCKOPTS MSG_DONTWAIT
+#else
+#ifdef SOLARIS
+#define IAX_SOCKOPTS MSG_DONTWAIT
 #else  /* Linux and others */
 #define IAX_SOCKOPTS MSG_DONTWAIT | MSG_NOSIGNAL
 #endif
 #endif
+#endif
 
 
 #ifdef SNOM_HACK
@@ -84,11 +93,10 @@
 #include "../../snom_phonecore2/include/snom_memset.h"
 #endif
 
-#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
+/* 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" */
@@ -110,6 +118,7 @@
 #define TRANSFER_NONE  0
 #define TRANSFER_BEGIN 1
 #define TRANSFER_READY 2
+#define TRANSFER_REL   3
 
 /* No more than 4 seconds of jitter buffer */
 static int max_jitterbuffer = 4000;
@@ -138,6 +147,8 @@
 	int voiceformat;
 	/* Last transmitted voice format */
 	int svoiceformat;
+	/* Per session capability */
+	int capability;
 	/* Last received timestamp */
 	unsigned int last_ts;
 	/* Last transmitted timestamp */
@@ -146,6 +157,8 @@
 	unsigned int lastvoicets;
 	/* Next predicted voice ts */
 	unsigned int nextpred;
+	/* True if the last voice we transmitted was not silence/CNG */
+	int notsilenttx;
 	/* Our last measured ping time */
 	unsigned int pingtime;
 	/* Address of peer */
@@ -207,23 +220,15 @@
 	int transferring;
 	int transfercallno;
 	int transferid;
-	
+	int transferpeer;	/* for attended transfer */
+	int transfer_moh;	/* for music on hold while performing attended transfer */
+
 	/* For linking if there are multiple connections */
 	struct iax_session *next;
 };
 
-#ifdef	WIN32
-
-void gettimeofday(struct timeval *tv, struct timezone *tz);
-
-#define	snprintf _snprintf
-
-#endif
-
 char iax_errstr[256];
 
-static int sformats = 0;
-
 #define IAXERROR snprintf(iax_errstr, sizeof(iax_errstr), 
 
 #ifdef DEBUG_SUPPORT
@@ -325,6 +330,7 @@
 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 inaddrcmp(struct sockaddr_in *sin1, struct sockaddr_in *sin2)
 {
@@ -417,6 +423,7 @@
 		if (callnums > 32767)
 			callnums = 1;
 		s->peercallno = 0;
+		s->transferpeer = 0;		/* for attended transfer */
 		s->next = sessions;
 		s->sendto = sendto;
 		sessions = s;
@@ -436,6 +443,18 @@
 	return 0;
 }
 
+static void add_ms(struct timeval *tv, int ms) {
+  tv->tv_usec += ms * 1000;
+  if(tv->tv_usec > 1000000) {
+      tv->tv_usec -= 1000000;
+      tv->tv_sec++;
+  }
+  if(tv->tv_usec < 0) {
+      tv->tv_usec += 1000000;
+      tv->tv_sec--;
+  }
+}
+
 static int calc_timestamp(struct iax_session *session, unsigned int ts, struct ast_frame *f)
 {
 	int ms;
@@ -474,12 +493,34 @@
 		ms = 0;
 
 	if(voice) {
-		if(abs(ms - session->nextpred) <= 240) {
+#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 && abs(ms - session->nextpred) <= 240) {
+		    /* Adjust our txcore, keeping voice and non-voice
+		     * synchronized */
+		    add_ms(&session->offset, (int)(ms - session->nextpred)/10);
+		    
 		    if(!session->nextpred)		
 			session->nextpred = f->samples; 
 		    ms = session->nextpred; 
-		} else
-		    session->nextpred = ms;
+		} 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) */
+		    int 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 */
@@ -493,11 +534,15 @@
 	}
 
 	/* Record the last sent packet for future reference */
-	session->lastsent = ms;
+	/* 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;
 }
@@ -616,6 +661,7 @@
 	portno = ntohs(sin.sin_port);
 	srand(time(NULL));
 	callnums = rand() % 32767 + 1;
+	transfer_id = rand() % 32767 + 1;
 	DEBU(G "Started on port %d\n", portno);
 	return portno;	
 }
@@ -656,19 +702,13 @@
 	   or delayed, with retransmission */
 	struct ast_iax2_full_hdr *fh;
 	struct ast_iax2_mini_hdr *mh;
-        struct {
-                struct iax_frame fr2;
-                unsigned char buffer[4096];             /* Buffer -- must preceed fr2 */
-        } buf;
+	unsigned char	buf[5120];
 	struct iax_frame *fr;
 	int res;
 	int sendmini=0;
 	unsigned int lastsent;
 	unsigned int fts;
 	
-	/* Shut up GCC */
-	buf.buffer[0] = 0;
-	
 	if (!pvt) {
 		IAXERROR "No private structure for packet?\n");
 		return -1;
@@ -694,7 +734,7 @@
 	}
 	/* Allocate an iax_frame */
 	if (now) {
-		fr = &buf.fr2;
+		fr = (struct iax_frame *) buf;
 	} else
 		fr = iax_frame_new(DIRECTION_OUTGRESS, f->datalen);
 	if (!fr) {
@@ -711,6 +751,7 @@
 			iax_frame_free(fr);
 		return -1;
 	}
+
 	fr->callno = pvt->callno;
 	fr->transfer = transfer;
 	fr->final = final;
@@ -830,7 +871,10 @@
 	/* It is assumed that the callno has already been locked */
 	iax_predestroy(i);
 #endif	
-	return __send_command(i, type, command, ts, data, datalen, seqno, 0, 0, 1, 0);
+	int r;
+	r = __send_command(i, type, command, ts, data, datalen, seqno, 0, 0, 1, 0);
+	if (r >= 0) destroy_session(i);
+	return r;
 }
 
 static int send_command_immediate(struct iax_session *i, char type, int command, unsigned int ts, char *data, int datalen, int seqno)
@@ -867,33 +911,197 @@
 	return 0;	
 }
 
-int try_transfer(struct iax_session *session, struct iax_ies *ies)
+static void stop_transfer(struct iax_session *session)
+{
+	struct iax_sched *sch;
+
+	sch = schedq;
+	while(sch) {
+		if (sch->frame && (sch->frame->session == session))
+					sch->frame->retries = -1;
+		sch = sch->next;
+	}
+}	/* 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;
+	}
+
+	memset(&session->rxcore, 0, sizeof(session->rxcore));
+	memset(&session->offset, 0, sizeof(session->offset));
+	memset(&session->history, 0, sizeof(session->history));
+	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 newcall = 0;
-	char newip[256] = "";
+	int res;
 	struct iax_ie_data ied;
-	struct sockaddr_in new;
-	
+
 	memset(&ied, 0, sizeof(ied));
-	if (ies->apparent_addr)
-		memcpy(&new, ies->apparent_addr, sizeof(new));
-	if (ies->callno)
-		newcall = ies->callno;
-	if (!newcall || !new.sin_addr.s_addr || !new.sin_port) {
-		return -1;
+
+	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 = sessions;
+
+	while(cur) {
+		if (callno == cur->callno && callno != 0)  {
+			return cur;
+		}
+		cur = cur->next;
+	}
+
+	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;
 	}
-	session->transfercallno = newcall;
-	memcpy(&session->transfer, &new, sizeof(session->transfer));
-	inet_aton(newip, &session->transfer.sin_addr);
-	session->transfer.sin_family = AF_INET;
-	session->transferring = TRANSFER_BEGIN;
-	session->transferid = ies->transferid;
-	if (ies->transferid)
-		iax_ie_append_int(&ied, IAX_IE_TRANSFERID, ies->transferid);
-	send_command_transfer(session, AST_FRAME_IAX, IAX_COMMAND_TXCNT, 0, ied.buf, ied.pos);
-	return 0; 
+
+	return 0;
 }
 
+static void iax_handle_txreject(struct iax_session *s)
+{
+	struct iax_session *s0, *s1;
+
+	complete_transfer(s, s->peercallno, 0, 1);
+	s->svoiceformat = -1;
+
+	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);
+	}
+}
 
 static void destroy_session(struct iax_session *session)
 {
@@ -990,6 +1198,12 @@
 	return 0;
 }
 
+int iax_send_cng(struct iax_session *session, int level, 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, char *data, int datalen)
 {
 	/* Send an image frame */
@@ -1071,9 +1285,12 @@
 	return send_command(session, AST_FRAME_CONTROL, AST_CONTROL_BUSY, 0, NULL, 0, -1);
 }
 
-int iax_accept(struct iax_session *session)
+int iax_accept(struct iax_session *session, int format)
 {
-	return send_command(session, AST_FRAME_IAX, IAX_COMMAND_ACCEPT, 0, NULL, 0, -1);
+	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)
@@ -1149,7 +1366,8 @@
 {
 	struct iax_ie_data ied;
 	memset(&ied, 0, sizeof(ied));
-	iax_ie_append_int(&ied, IAX_IE_TRANSFERID, session->transferid);
+	/* 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);
 }
 
@@ -1197,10 +1415,6 @@
 	return send_command(session, AST_FRAME_IAX, IAX_COMMAND_REGREQ, 0, ied.buf, ied.pos, -1);
 }
 
-void iax_set_formats(int fmt)
-{
-	sformats = fmt;
-}
 
 int iax_dial(struct iax_session *session, char *number)
 {
@@ -1228,7 +1442,7 @@
 	return send_command(session, AST_FRAME_IAX, IAX_COMMAND_DPREQ, 0, ied.buf, ied.pos, -1);
 }
 
-int iax_call(struct iax_session *session, char *cidnum, char *cidname, char *ich, char *lang, int wait)
+int iax_call(struct iax_session *session, char *cidnum, char *cidname, char *ich, char *lang, int wait, int formats, int capabilities)
 {
 	char tmp[256]="";
 	char *part1, *part2;
@@ -1252,9 +1466,11 @@
 	if (cidname)
 		iax_ie_append_str(&ied, IAX_IE_CALLING_NAME, cidname);
 	
+	session->capability = capabilities;
+
 	/* XXX We should have a preferred format XXX */
-	iax_ie_append_int(&ied, IAX_IE_FORMAT, sformats);
-	iax_ie_append_int(&ied, IAX_IE_CAPABILITY, sformats);
+	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, lang);
 	
@@ -1363,6 +1579,56 @@
 	return 0;
 }
 
+/* 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,
@@ -1370,10 +1636,20 @@
 {
 	struct iax_session *cur = sessions;
 	while(cur) {
-		if (match(sin, callno, dcallno, cur))
+		if (forward_match(sin, callno, dcallno, cur)) {
 			return cur;
+		}
 		cur = cur->next;
 	}
+
+	cur = sessions;
+	while(cur) {
+		if (reverse_match(sin, callno, cur)) {
+			return cur;
+		}
+		cur = cur->next;
+	}
+
 	if (makenew && !dcallno) {
 		cur = iax_session_new();
 		cur->peercallno = callno;
@@ -1611,7 +1887,7 @@
 	/* don't run last_ts backwards; i.e. for retransmits and the like */
 	if (ts > session->last_ts) 
 	    session->last_ts = ts;
-	e = (struct iax_event *)malloc(sizeof(struct iax_event) + datalen + 1);
+
 
 #ifdef DEBUG_SUPPORT
 	iax_showframe(NULL, fh, 1, sin, datalen);
@@ -1657,12 +1933,16 @@
 			updatehistory = 0;
 		if ((session->iseqno != fh->oseqno) &&
 			(session->iseqno ||
-				((subclass != IAX_COMMAND_TXCNT) &&
+			   ((subclass != IAX_COMMAND_TXREADY) &&
+			    (subclass != IAX_COMMAND_TXREL) &&
+				(subclass != IAX_COMMAND_TXCNT) &&
 				(subclass != IAX_COMMAND_TXACC)) ||
-				(subclass != AST_FRAME_IAX))) {
+			  (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)) ||
@@ -1696,14 +1976,23 @@
 				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;
-			e = schedule_delivery(e, ts, updatehistory);
+			/* 
+			 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;
@@ -1730,6 +2019,8 @@
 			switch(subclass) {
 			case IAX_COMMAND_NEW:
 				/* This is a new, incoming call */
+				/* save the capability for validation */
+				session->capability = e->ies.capability;
 				e->etype = IAX_EVENT_CONNECT;
 				e = schedule_delivery(e, ts, updatehistory);
 				break;
@@ -1759,6 +2050,7 @@
 				e = schedule_delivery(e, ts, updatehistory);
 				break;
 			case IAX_COMMAND_ACK:
+				free(e);
 				e = NULL;
 				break;
 			case IAX_COMMAND_LAGRQ:
@@ -1776,7 +2068,21 @@
 				e->etype = IAX_EVENT_PONG;
 				break;
 			case IAX_COMMAND_ACCEPT:
-				e->etype = IAX_EVENT_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, "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_REGACK:
@@ -1800,12 +2106,22 @@
 				/* Can't call schedule_delivery since timestamp is non-normal */
 				break;;
 			case IAX_COMMAND_TXREQ:
-				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);
+				/* 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;
@@ -1815,23 +2131,16 @@
 				/* Return immediately, makes no sense to schedule */
 				break;
 			case IAX_COMMAND_TXCNT:
-				/* Received a transfer connect.  Accept it if we're transferring */
-				e->etype = IAX_EVENT_TXACCEPT;
-				if (session->transferring) 
+				if (session->transferring)  {
+					session->transfer = *sin;
 					iax_send_txaccept(session);
+				}
 				free(e);
 				e = NULL;
 				break;
 			case IAX_COMMAND_TXACC:
-				e->etype = IAX_EVENT_TXREADY;
 				if (session->transferring) {
-					/* Cancel any more connect requests */
-					sch = schedq;
-					while(sch) {
-						if (sch->frame && sch->frame->transfer)
-								sch->frame->retries = -1;
-						sch = sch->next;
-					}
+					stop_transfer(session);
 					session->transferring = TRANSFER_READY;
 					iax_send_txready(session);
 				}
@@ -1840,36 +2149,14 @@
 				break;
 			case IAX_COMMAND_TXREL:
 				/* Release the transfer */
-				session->peercallno = e->ies.callno;
-				/* Change from transfer to session now */
-				memcpy(&session->peeraddr, &session->transfer, sizeof(session->peeraddr));
-				memset(&session->transfer, 0, sizeof(session->transfer));
-				session->transferring = TRANSFER_NONE;
-				/* Force retransmission of a real voice packet, and reset all timing */
-				session->svoiceformat = -1;
-				session->voiceformat = 0;
-				memset(&session->rxcore, 0, sizeof(session->rxcore));
-				memset(&session->offset, 0, sizeof(session->offset));
-				memset(&session->history, 0, sizeof(session->history));
-				session->jitterbuffer = 0;
-				session->jitter = 0;
-				session->lag = 0;
-				/* Reset sequence numbers */
-				session->oseqno = 0;
-				session->iseqno = 0;
-				session->lastsent = 0;
-				session->last_ts = 0;
-				session->lastvoicets = 0;
-				session->pingtime = 30;
-				e->etype = IAX_EVENT_TRANSFER;
-				/* 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. */
-				sch = schedq;
-				while(sch) {
-					if (sch->frame && (sch->frame->session == session))
-								sch->frame->retries = -1;
-					sch = sch->next;
+			   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;
 				break;
 			case IAX_COMMAND_QUELCH:
 				e->etype = IAX_EVENT_QUELCH;
@@ -1879,15 +2166,26 @@
 				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;
 			}
-
-			if (session->aseqno != session->iseqno) {
-				send_command_immediate(session, AST_FRAME_IAX, IAX_COMMAND_ACK, ts, NULL, 0, fh->iseqno);
-			}
 			break;
 		case AST_FRAME_CONTROL:
 			switch(subclass) {
@@ -1967,7 +2265,7 @@
 		DEBU(G "Out of memory\n");
 	    
 	/* Already ack'd iax frames */
-	if ((fh->type != AST_FRAME_IAX) && (session->aseqno != session->iseqno)) {
+	if (session->aseqno != session->iseqno) {
 	    send_command_immediate(session, AST_FRAME_IAX, IAX_COMMAND_ACK, ts, NULL, 0, fh->iseqno);
 	}
 	return e;
@@ -2213,8 +2511,10 @@
 	if (session->quelch == 1)
 		return -1;
 		
-	if (MOH)
+	if (MOH) {
 		iax_ie_append(&ied, IAX_IE_MUSICONHOLD);
+		session->transfer_moh = 1;
+	}
 		
 	return send_command(session, AST_FRAME_IAX, IAX_COMMAND_QUELCH, 0, ied.buf, ied.pos, -1);		
 }
diff -ur --exclude=CVS libiax2/src/iax-client.h /home/stevek/work/hms/iaxclient/lib/libiax2/src/iax-client.h
--- libiax2/src/iax-client.h	2004-10-01 12:42:48.000000000 -0400
+++ /home/stevek/work/hms/iaxclient/lib/libiax2/src/iax-client.h	2004-11-08 12:49:28.000000000 -0500
@@ -14,6 +14,11 @@
 #ifndef _ASTERISK_IAX_CLIENT_H
 #define _ASTERISK_IAX_CLIENT_H
 
+#if defined(_MSC_VER)
+/* disable zero-sized array in struct/union warning */
+#pragma warning(disable:4200)
+#endif
+
 #ifndef LINUX
 #define socklen_t int
 #endif
@@ -72,10 +77,21 @@
 #define IAX_EVENT_REGREJ  30		/* Registration reply */
 #define IAX_EVENT_LINKURL	31		/* Unlink */
 
+/* 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);
+#else
 typedef int PASCAL (*sendto_t)(SOCKET, const char *, int, int, const struct sockaddr *, int);
+#endif
 #else
 typedef int (*sendto_t)(int, const void *, size_t, int, const struct sockaddr *, socklen_t);
 #endif
@@ -90,6 +106,11 @@
 	unsigned char data[0];			/* Raw data if applicable */
 };
 
+#if defined(__cplusplus)
+extern "C"
+{
+#endif
+
 /* All functions return 0 on success and -1 on failure unless otherwise
    specified */
 
@@ -115,27 +136,25 @@
 extern int iax_auth_reply(struct iax_session *session, char *password, 
 						char *challenge, int methods);
 
-/* Stop iax, hangup file descriptors, free memory, etc. */
-extern void iax_end(void);
-
 /* Free an event */
 extern void iax_event_free(struct iax_event *event);
 
 struct sockaddr_in;
 
 /* Front ends for sending events */
-extern void iax_set_formats(int fmt);
 extern int iax_send_dtmf(struct iax_session *session, char digit);
 extern int iax_send_voice(struct iax_session *session, int format, char *data, int datalen, int samples);
+extern int iax_send_cng(struct iax_session *session, int level, char *data, int datalen);
 extern int iax_send_image(struct iax_session *session, int format, 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, char *reason);
 extern int iax_busy(struct iax_session *session);
 extern int iax_hangup(struct iax_session *session, char *byemsg);
-extern int iax_call(struct iax_session *session, char *cidnum, char *cidname, char *ich, char *lang, int wait);
-extern int iax_accept(struct iax_session *session);
+extern int iax_call(struct iax_session *session, char *cidnum, 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);
@@ -156,6 +175,19 @@
 extern void iax_enable_debug(void);
 extern void iax_disable_debug(void);
 
+/* For attended trnasfer, 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);
+
+#if defined(__cplusplus)
+}
+#endif
+
 void iax_set_private(struct iax_session *s, void *pvt);
 void *iax_get_private(struct iax_session *s);
 void iax_set_sendto(struct iax_session *s, sendto_t sendto);
