diff --git a/Makefile b/Makefile
index cd2a4a1457cdf269c32255bce0a57334f62d92b0..9edd35c6a38f6eb665bdfdc8824bf6780ae5931d 100755
--- a/Makefile
+++ b/Makefile
@@ -13,6 +13,34 @@
 
 .EXPORT_ALL_VARIABLES:
 
+# Pentium Pro Optimize
+#PROC=i686
+# Pentium Optimize
+#PROC=i586
+#PROC=k6
+#PROC=ppc
+PROC=$(shell uname -m)
+
+######### More GSM codec optimization
+######### Uncomment to enable MMXTM optimizations for x86 architecture CPU's
+######### which support MMX instructions.  This should be newer pentiums,
+######### ppro's, etc, as well as the AMD K6 and K7.  
+K6OPT  = #-DK6OPT
+
+#Tell gcc to optimize the asterisk's code
+OPTIMIZE=-O6
+
+#Include debug symbols in the executables (-g) and profiling info (-pg)
+DEBUG=-g #-pg
+
+# Optional debugging parameters
+DEBUG_THREADS = #-DDO_CRASH -DDEBUG_THREADS
+
+# Uncomment next one to enable ast_frame tracing (for debugging)
+TRACE_FRAMES = #-DTRACE_FRAMES
+
+# Where to install asterisk after compiling
+# Default -> leave empty
 INSTALL_PREFIX=
 
 ASTLIBDIR=$(INSTALL_PREFIX)/usr/lib/asterisk
@@ -30,18 +58,9 @@ ASTVARRUNDIR=$(INSTALL_PREFIX)/var/run
 MODULES_DIR=$(ASTLIBDIR)/modules
 AGI_DIR=$(ASTVARLIBDIR)/agi-bin
 
-# Pentium Pro Optimize
-#PROC=i686
-# Pentium Optimize
-#PROC=i586
-#PROC=k6
-#PROC=ppc
-PROC=$(shell uname -m)
-
-DEBUG=-g #-pg
 INCLUDE=-Iinclude -I../include
 CFLAGS=-pipe  -Wall -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations $(DEBUG) $(INCLUDE) -D_REENTRANT -D_GNU_SOURCE #-DMAKE_VALGRIND_HAPPY
-#CFLAGS+=-O6
+CFLAGS+=$(OPTIMIZE)
 CFLAGS+=$(shell if $(CC) -march=$(PROC) -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-march=$(PROC)"; fi)
 CFLAGS+=$(shell if uname -m | grep -q ppc; then echo "-fsigned-char"; fi)
 
@@ -62,10 +81,8 @@ CFLAGS+=-DASTCONFPATH=\"$(ASTCONFPATH)\"
 CFLAGS+=-DASTMODDIR=\"$(MODULES_DIR)\"
 CFLAGS+=-DASTAGIDIR=\"$(AGI_DIR)\"
 
-# Optional debugging parameters
-CFLAGS+= -DDO_CRASH -DDEBUG_THREADS
-# Uncomment next one to enable ast_frame tracing (for debugging)
-#CFLAGS+= -DTRACE_FRAMES
+CFLAGS+= $(DEBUG_THREADS)
+CFLAGS+= $(TRACE_FRAMES)
 CFLAGS+=# -fomit-frame-pointer 
 SUBDIRS=res channels pbx apps codecs formats agi cdr astman
 LIBS=-ldl -lpthread -lncurses -lm  #-lnjamd
@@ -311,3 +328,7 @@ config:
 	fi 
 
 	
+dont-optimize:
+	make OPTIMIZE= K6OPT= install
+
+valgrind: dont-optimize
diff --git a/apps/app_substring.c b/apps/app_substring.c
index 97f0fea0a2d4beec7f0611dc6523aa13972d0b33..4d3ccceb3231aeae9473a50fd7af3fa2e346b184 100755
--- a/apps/app_substring.c
+++ b/apps/app_substring.c
@@ -56,6 +56,7 @@ static int substring_exec(struct ast_channel *chan, void *data)
   char *count1, *count2;
   char *first, *second, *stringp;
   stringp=alloca(strlen(data)+1);
+  ast_log(LOG_WARNING, "The use of Substring application is deprecated. Please use ${variable:a:b} instead\n");
   strncpy(stringp,data,strlen(data)+1);
   if (strchr(stringp,'|')&&strchr(stringp,'=')) {
     int icount1,icount2;
diff --git a/channel.c b/channel.c
index 0a7eed39d554fef8e274551ea5c9779ea42bd18b..684adac62ca3e6709fcf1e740683391c9b40f5b3 100755
--- a/channel.c
+++ b/channel.c
@@ -347,7 +347,8 @@ int ast_queue_frame(struct ast_channel *chan, struct ast_frame *fin, int lock)
 		cur = cur->next;
 		qlen++;
 	}
-	if (qlen  > 128) {
+	/* Allow up to 96 voice frames outstanding, and up to 128 total frames */
+	if (((fin->frametype == AST_FRAME_VOICE) && (qlen > 96)) || (qlen  > 128)) {
 		if (fin->frametype != AST_FRAME_VOICE) {
 			ast_log(LOG_WARNING, "Exceptionally long queue length queuing to %s\n", chan->name);
 			CRASH;
diff --git a/channels/chan_iax.c b/channels/chan_iax.c
index 3cf6813ddde90d22048c6a5d7d952a727e2f78e7..894aa67c292c33350bb7b1b3f811d444a19a1760 100755
--- a/channels/chan_iax.c
+++ b/channels/chan_iax.c
@@ -3409,7 +3409,6 @@ static int socket_read(int *id, int fd, short events, void *cbdata)
 	char rel0[256];
 	char rel1[255];
 	char empty[32]="";		/* Safety measure */
-	fr.ts=0;	/* make Valgrind happy */
 	res = recvfrom(netsocket, buf, sizeof(buf), 0,(struct sockaddr *) &sin, &len);
 	if (res < 0) {
 		if (errno != ECONNREFUSED)
@@ -3473,6 +3472,7 @@ static int socket_read(int *id, int fd, short events, void *cbdata)
 			ast_log(LOG_DEBUG, "Received packet %d, (%d, %d)\n", ntohs(fh->seqno), f.frametype, f.subclass);
 		/* Check if it's out of order (and not an ACK or INVAL) */
 		fr.seqno = ntohs(fh->seqno);
+		fr.ts = ntohl(fh->ts);
 		if ((iaxs[fr.callno]->iseqno != fr.seqno) &&
 			(iaxs[fr.callno]->iseqno ||
 				((f.subclass != AST_IAX_COMMAND_TXCNT) &&
@@ -3525,7 +3525,6 @@ static int socket_read(int *id, int fd, short events, void *cbdata)
 			f.data = buf + sizeof(struct ast_iax_full_hdr);
 		else
 			f.data = empty;
-		fr.ts = ntohl(fh->ts);
 		/* Unless this is an ACK or INVAL frame, ack it */
 		if ((f.frametype != AST_FRAME_IAX) || 
 			 ((f.subclass != AST_IAX_COMMAND_ACK) && 
diff --git a/channels/chan_iax2.c b/channels/chan_iax2.c
index c58e24e3d4fdc567f8c270aa08fa60760c3fdeae..b1d2402ce7395f47dfe7c89124c77b8e173839c8 100755
--- a/channels/chan_iax2.c
+++ b/channels/chan_iax2.c
@@ -1786,6 +1786,7 @@ static int iax2_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags
 	struct ast_frame *f;
 	struct chan_iax2_pvt *p0 = c0->pvt->pvt;
 	struct chan_iax2_pvt *p1 = c1->pvt->pvt;
+	struct timeval waittimer = {0, 0}, tv;
 
 	/* Put them in native bridge mode */
 	p0->bridgecallno = p1->callno;
@@ -1814,13 +1815,18 @@ static int iax2_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags
 		
 		if ((p0->transferring == TRANSFER_RELEASED) && (p1->transferring == TRANSFER_RELEASED)) {
 			/* Call has been transferred.  We're no longer involved */
-			sleep(1);
-			c0->_softhangup |= AST_SOFTHANGUP_DEV;
-			c1->_softhangup |= AST_SOFTHANGUP_DEV;
-			*fo = NULL;
-			*rc = c0;
-			res = 0;
-			break;
+			gettimeofday(&tv, NULL);
+			if (!waittimer.tv_sec && !waittimer.tv_usec) {
+				waittimer.tv_sec = tv.tv_sec;
+				waittimer.tv_usec = tv.tv_usec;
+			} else if (tv.tv_sec - waittimer.tv_sec > IAX_LINGER_TIMEOUT) {
+				c0->_softhangup |= AST_SOFTHANGUP_DEV;
+				c1->_softhangup |= AST_SOFTHANGUP_DEV;
+				*fo = NULL;
+				*rc = c0;
+				res = 0;
+				break;
+			}
 		}
 		to = 1000;
 		who = ast_waitfor_n(cs, 2, &to);
@@ -2164,7 +2170,10 @@ static int iax2_send(struct chan_iax2_pvt *pvt, struct ast_frame *f, unsigned in
 		fh->scallno = htons(fr->callno | IAX_FLAG_FULL);
 		fh->ts = htonl(fr->ts);
 		fh->oseqno = fr->oseqno;
-		fh->iseqno = fr->iseqno;
+		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;
@@ -2206,6 +2215,7 @@ static int iax2_send(struct chan_iax2_pvt *pvt, struct ast_frame *f, unsigned in
 					ast_log(LOG_WARNING, "Out of trunk data space on call number %d, dropping\n", pvt->callno);
 				pvt->trunkerror = 1;
 			}
+			res = 0;
 		} else {
 			/* Mini-frames have no sequence number */
 			fr->oseqno = -1;
@@ -3355,146 +3365,6 @@ static int iax2_poke_peer_s(void *data)
 	return 0;
 }
 
-static int parse_ies(struct iax_ies *ies, unsigned char *data, int datalen)
-{
-	/* Parse data into information elements */
-	int len;
-	int ie;
-	memset(ies, 0, sizeof(struct iax_ies));
-	ies->msgcount = -1;
-	while(datalen >= 2) {
-		ie = data[0];
-		len = data[1];
-		if (len > datalen - 2) {
-			ast_log(LOG_WARNING, "Information element length exceeds message size\n");
-			return -1;
-		}
-		switch(ie) {
-		case IAX_IE_CALLED_NUMBER:
-			ies->called_number = data + 2;
-			break;
-		case IAX_IE_CALLING_NUMBER:
-			ies->calling_number = data + 2;
-			break;
-		case IAX_IE_CALLING_ANI:
-			ies->calling_ani = data + 2;
-			break;
-		case IAX_IE_CALLING_NAME:
-			ies->calling_name = data + 2;
-			break;
-		case IAX_IE_CALLED_CONTEXT:
-			ies->called_context = data + 2;
-			break;
-		case IAX_IE_USERNAME:
-			ies->username = data + 2;
-			break;
-		case IAX_IE_PASSWORD:
-			ies->password = data + 2;
-			break;
-		case IAX_IE_CAPABILITY:
-			if (len != sizeof(unsigned int)) 
-				ast_log(LOG_WARNING, "Expecting capability to be %d bytes long but was %d\n", sizeof(unsigned int), len);
-			else
-				ies->capability = ntohl(*((unsigned int *)(data + 2)));
-			break;
-		case IAX_IE_FORMAT:
-			if (len != sizeof(unsigned int)) 
-				ast_log(LOG_WARNING, "Expecting format to be %d bytes long but was %d\n", sizeof(unsigned int), len);
-			else
-				ies->format = ntohl(*((unsigned int *)(data + 2)));
-			break;
-		case IAX_IE_LANGUAGE:
-			ies->language = data + 2;
-			break;
-		case IAX_IE_VERSION:
-			if (len != sizeof(unsigned short)) 
-				ast_log(LOG_WARNING, "Expecting version to be %d bytes long but was %d\n", sizeof(unsigned short), len);
-			else
-				ies->version = ntohs(*((unsigned short *)(data + 2)));
-			break;
-		case IAX_IE_ADSICPE:
-			if (len != sizeof(unsigned short)) 
-				ast_log(LOG_WARNING, "Expecting adsicpe to be %d bytes long but was %d\n", sizeof(unsigned short), len);
-			else
-				ies->adsicpe = ntohs(*((unsigned short *)(data + 2)));
-			break;
-		case IAX_IE_DNID:
-			ies->dnid = data + 2;
-			break;
-		case IAX_IE_AUTHMETHODS:
-			if (len != sizeof(unsigned short)) 
-				ast_log(LOG_WARNING, "Expecting authmethods to be %d bytes long but was %d\n", sizeof(unsigned short), len);
-			else
-				ies->authmethods = ntohs(*((unsigned short *)(data + 2)));
-			break;
-		case IAX_IE_CHALLENGE:
-			ies->challenge = data + 2;
-			break;
-		case IAX_IE_MD5_RESULT:
-			ies->md5_result = data + 2;
-			break;
-		case IAX_IE_RSA_RESULT:
-			ies->rsa_result = data + 2;
-			break;
-		case IAX_IE_APPARENT_ADDR:
-			ies->apparent_addr = ((struct sockaddr_in *)(data + 2));
-			break;
-		case IAX_IE_REFRESH:
-			if (len != sizeof(unsigned short)) 
-				ast_log(LOG_WARNING, "Expecting refresh to be %d bytes long but was %d\n", sizeof(unsigned short), len);
-			else
-				ies->refresh = ntohs(*((unsigned short *)(data + 2)));
-			break;
-		case IAX_IE_DPSTATUS:
-			if (len != sizeof(unsigned short)) 
-				ast_log(LOG_WARNING, "Expecting dpstatus to be %d bytes long but was %d\n", sizeof(unsigned short), len);
-			else
-				ies->dpstatus = ntohs(*((unsigned short *)(data + 2)));
-			break;
-		case IAX_IE_CALLNO:
-			if (len != sizeof(unsigned short)) 
-				ast_log(LOG_WARNING, "Expecting callno to be %d bytes long but was %d\n", sizeof(unsigned short), len);
-			else
-				ies->callno = ntohs(*((unsigned short *)(data + 2)));
-			break;
-		case IAX_IE_CAUSE:
-			ies->cause = data + 2;
-			break;
-		case IAX_IE_IAX_UNKNOWN:
-			if (len == 1)
-				ies->iax_unknown = data[2];
-			else
-				ast_log(LOG_WARNING, "Expected single byte Unknown command, but was %d long\n", len);
-			break;
-		case IAX_IE_MSGCOUNT:
-			if (len != sizeof(unsigned short)) 
-				ast_log(LOG_WARNING, "Expecting msgcount to be %d bytes long but was %d\n", sizeof(unsigned short), len);
-			else
-				ies->msgcount = ntohs(*((unsigned short *)(data + 2)));	
-			break;
-		case IAX_IE_AUTOANSWER:
-			ies->autoanswer = 1;
-			break;
-		case IAX_IE_MUSICONHOLD:
-			ies->musiconhold = 1;
-			break;
-		default:
-			ast_log(LOG_NOTICE, "Ignoring unknown information element '%s' (%d) of length %d\n", iax_ie2str(ie), ie, len);
-		}
-		/* Overwrite information element with 0, to null terminate previous portion */
-		data[0] = 0;
-		datalen -= (len + 2);
-		data += (len + 2);
-	}
-	/* Null-terminate last field */
-	*data = '\0';
-	if (datalen) {
-		ast_log(LOG_WARNING, "Invalid information element contents, strange boundary\n");
-		return -1;
-	}
-	return 0;
-}
-
 static int send_trunk(struct iax2_peer *peer)
 {
 	int x;
@@ -3777,9 +3647,8 @@ static int socket_read(int *id, int fd, short events, void *cbdata)
 			ast_pthread_mutex_unlock(&iaxsl[fr.callno]);
 		return 1;
 	}
-	if (((f.subclass != IAX_COMMAND_TXCNT) &&
-	     (f.subclass != IAX_COMMAND_TXACC)) || (f.frametype != AST_FRAME_IAX))
-		iaxs[fr.callno]->peercallno = (short)(ntohs(mh->callno) & ~IAX_FLAG_FULL);
+	if (!memcmp(&sin, &iaxs[fr.callno]->addr, sizeof(sin)))
+		iaxs[fr.callno]->peercallno = (unsigned short)(ntohs(mh->callno) & ~IAX_FLAG_FULL);
 	if (ntohs(mh->callno) & IAX_FLAG_FULL) {
 		if (option_debug)
 			ast_log(LOG_DEBUG, "Received packet %d, (%d, %d)\n", fh->oseqno, f.frametype, f.subclass);
@@ -3840,9 +3709,11 @@ static int socket_read(int *id, int fd, short events, void *cbdata)
 		}
 		f.datalen = res - sizeof(struct ast_iax2_full_hdr);
 
-		/* Handle implicit ACKing unless this is an INVAL */
-		if (((f.subclass != IAX_COMMAND_INVAL)) ||
-			(f.frametype != AST_FRAME_IAX)) {
+		/* Handle implicit ACKing unless this is an INVAL, and only if this is 
+		   from the real peer, not the transfer peer */
+		if (!memcmp(&sin, &iaxs[fr.callno]->addr, sizeof(sin)) && 
+			(((f.subclass != IAX_COMMAND_INVAL)) ||
+			(f.frametype != 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 */
@@ -3883,10 +3754,18 @@ static int socket_read(int *id, int fd, short events, void *cbdata)
 			} else
 				ast_log(LOG_DEBUG, "Received iseqno %d not within window %d->%d\n", fr.iseqno, iaxs[fr.callno]->rseqno, iaxs[fr.callno]->oseqno);
 		}
+		if (memcmp(&sin, &iaxs[fr.callno]->addr, sizeof(sin)) && 
+			((f.frametype != AST_FRAME_IAX) || 
+			 ((f.subclass != IAX_COMMAND_TXACC) &&
+			  (f.subclass != IAX_COMMAND_TXCNT)))) {
+			/* Only messages we accept from a transfer host are TXACC and TXCNT */
+			ast_pthread_mutex_unlock(&iaxsl[fr.callno]);
+			return 1;
+		}
 
 		if (f.datalen) {
 			if (f.frametype == AST_FRAME_IAX) {
-				if (parse_ies(&ies, buf + sizeof(struct ast_iax2_full_hdr), f.datalen)) {
+				if (iax_parse_ies(&ies, buf + sizeof(struct ast_iax2_full_hdr), f.datalen)) {
 					ast_log(LOG_WARNING, "undecodable frame received\n");
 					ast_pthread_mutex_unlock(&iaxsl[fr.callno]);
 					return 1;
@@ -4385,6 +4264,8 @@ static int socket_read(int *id, int fd, short events, void *cbdata)
 					send_command_transfer(iaxs[fr.callno], AST_FRAME_IAX, IAX_COMMAND_TXACC, 0, NULL, 0);
 				break;
 			case IAX_COMMAND_TXREL:
+				/* Send ack immediately, rather than waiting until we've changed addresses */
+				send_command_immediate(iaxs[fr.callno], AST_FRAME_IAX, IAX_COMMAND_ACK, fr.ts, NULL, 0,fr.iseqno);
 				complete_transfer(fr.callno, &ies);
 				break;	
 			case IAX_COMMAND_DPREP:
diff --git a/channels/chan_sip.c b/channels/chan_sip.c
index ff47ba88ff16e4b2c8ec2a6ac87e147387ca9ca1..cb9bb6f568f9b84b5b4997fe76f5575f96f19cde 100755
--- a/channels/chan_sip.c
+++ b/channels/chan_sip.c
@@ -473,7 +473,7 @@ static void sip_prefs_free(void)
 
 static void sip_pref_remove(int format)
 {
-	struct sip_codec_pref *cur, *prev;
+	struct sip_codec_pref *cur, *prev=NULL;
 	cur = prefs;
 	while(cur) {
 		if (cur->codec == format) {
@@ -744,10 +744,9 @@ static int sip_hangup(struct ast_channel *ast)
 
 static int sip_answer(struct ast_channel *ast)
 {
-	int res = 0,fmt,capability;
+	int res = 0,fmt;
 	char *codec;
 	struct sip_pvt *p = ast->pvt->pvt;
-	struct sip_codec_pref *oldpref=NULL;
 
 	
 	if (ast->_state != AST_STATE_UP) {
@@ -759,10 +758,6 @@ static int sip_answer(struct ast_channel *ast)
 			ast_log(LOG_NOTICE, "Changing codec to '%s' for this call because of ${SIP_CODEC) variable\n",codec);
 			fmt=ast_getformatbyname(codec);
 			if (fmt) {
-				oldpref=prefs;
-				prefs=NULL;
-				sip_pref_append(fmt);
-				capability=p->capability;
 				p->capability=fmt;
 			} else ast_log(LOG_NOTICE, "Ignoring ${SIP_CODEC} variable because of unrecognized codec: %s\n",codec);
 		}
@@ -771,11 +766,6 @@ static int sip_answer(struct ast_channel *ast)
 		if (option_debug)
 			ast_log(LOG_DEBUG, "sip_answer(%s)\n", ast->name);
 		res = transmit_response_with_sdp(p, "200 OK", &p->initreq);
-		sip_prefs_free();
-		if (oldpref) {
-			prefs=oldpref;
-			p->capability=capability;
-		}
 	}
 	return res;
 }
diff --git a/channels/chan_zap.c b/channels/chan_zap.c
index 4d8e460b018a4e06a68c554e041da294baf02335..ac51aad3795e897606523b429cb46dd9449a47a1 100755
--- a/channels/chan_zap.c
+++ b/channels/chan_zap.c
@@ -2732,6 +2732,7 @@ static struct ast_frame *zt_handle_event(struct ast_channel *ast)
 								p->owner = p->subs[SUB_REAL].owner;
 								if (p->subs[SUB_REAL].owner && p->subs[SUB_REAL].owner->bridge)
 									ast_moh_stop(p->subs[SUB_REAL].owner->bridge);
+								zt_enable_ec(p);
 							}
 							
 						}
diff --git a/channels/iax2-parser.c b/channels/iax2-parser.c
index 6e27d6ffd604916de954b1a7c98fbcfb68a80732..f7020562b8472582d938e4393ee39291630c452a 100755
--- a/channels/iax2-parser.c
+++ b/channels/iax2-parser.c
@@ -342,3 +342,157 @@ void iax_set_error(void (*func)(const char *))
 {
 	errorf = func;
 }
+
+int iax_parse_ies(struct iax_ies *ies, unsigned char *data, int datalen)
+{
+	/* Parse data into information elements */
+	int len;
+	int ie;
+	char tmp[256];
+	memset(ies, 0, sizeof(struct iax_ies));
+	ies->msgcount = -1;
+	while(datalen >= 2) {
+		ie = data[0];
+		len = data[1];
+		if (len > datalen - 2) {
+			errorf("Information element length exceeds message size\n");
+			return -1;
+		}
+		switch(ie) {
+		case IAX_IE_CALLED_NUMBER:
+			ies->called_number = data + 2;
+			break;
+		case IAX_IE_CALLING_NUMBER:
+			ies->calling_number = data + 2;
+			break;
+		case IAX_IE_CALLING_ANI:
+			ies->calling_ani = data + 2;
+			break;
+		case IAX_IE_CALLING_NAME:
+			ies->calling_name = data + 2;
+			break;
+		case IAX_IE_CALLED_CONTEXT:
+			ies->called_context = data + 2;
+			break;
+		case IAX_IE_USERNAME:
+			ies->username = data + 2;
+			break;
+		case IAX_IE_PASSWORD:
+			ies->password = data + 2;
+			break;
+		case IAX_IE_CAPABILITY:
+			if (len != sizeof(unsigned int)) {
+				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)));
+			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)));
+			break;
+		case IAX_IE_LANGUAGE:
+			ies->language = data + 2;
+			break;
+		case IAX_IE_VERSION:
+			if (len != sizeof(unsigned short)) {
+				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)));
+			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)));
+			break;
+		case IAX_IE_DNID:
+			ies->dnid = data + 2;
+			break;
+		case IAX_IE_AUTHMETHODS:
+			if (len != sizeof(unsigned short))  {
+				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)));
+			break;
+		case IAX_IE_CHALLENGE:
+			ies->challenge = data + 2;
+			break;
+		case IAX_IE_MD5_RESULT:
+			ies->md5_result = data + 2;
+			break;
+		case IAX_IE_RSA_RESULT:
+			ies->rsa_result = data + 2;
+			break;
+		case IAX_IE_APPARENT_ADDR:
+			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)));
+			break;
+		case IAX_IE_DPSTATUS:
+			if (len != sizeof(unsigned short)) {
+				snprintf(tmp, sizeof(tmp),  "Expecting dpstatus to be %d bytes long but was %d\n", sizeof(unsigned short), len);
+				errorf(tmp);
+			} else
+				ies->dpstatus = ntohs(*((unsigned short *)(data + 2)));
+			break;
+		case IAX_IE_CALLNO:
+			if (len != sizeof(unsigned short)) {
+				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)));
+			break;
+		case IAX_IE_CAUSE:
+			ies->cause = data + 2;
+			break;
+		case IAX_IE_IAX_UNKNOWN:
+			if (len == 1)
+				ies->iax_unknown = data[2];
+			else {
+				snprintf(tmp, sizeof(tmp), "Expected single byte Unknown command, but was %d long\n", len);
+				errorf(tmp);
+			}
+			break;
+		case IAX_IE_MSGCOUNT:
+			if (len != sizeof(unsigned short)) {
+				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)));	
+			break;
+		case IAX_IE_AUTOANSWER:
+			ies->autoanswer = 1;
+			break;
+		case IAX_IE_MUSICONHOLD:
+			ies->musiconhold = 1;
+			break;
+		default:
+			snprintf(tmp, sizeof(tmp), "Ignoring unknown information element '%s' (%d) of length %d\n", iax_ie2str(ie), ie, len);
+			errorf(tmp);
+		}
+		/* Overwrite information element with 0, to null terminate previous portion */
+		data[0] = 0;
+		datalen -= (len + 2);
+		data += (len + 2);
+	}
+	/* Null-terminate last field */
+	*data = '\0';
+	if (datalen) {
+		errorf("Invalid information element contents, strange boundary\n");
+		return -1;
+	}
+	return 0;
+}
+
diff --git a/channels/iax2-parser.h b/channels/iax2-parser.h
index 903a44383724309a4fb4ae2c3bb8bfb91c46d93e..e34ca1ca7cbf86c873e6ca1d1bd8280bec40180b 100755
--- a/channels/iax2-parser.h
+++ b/channels/iax2-parser.h
@@ -106,5 +106,6 @@ extern int iax_ie_append_short(struct iax_ie_data *ied, unsigned char ie, unsign
 extern int iax_ie_append_str(struct iax_ie_data *ied, unsigned char ie, unsigned char *str);
 extern int iax_ie_append_byte(struct iax_ie_data *ied, unsigned char ie, unsigned char dat);
 extern int iax_ie_append(struct iax_ie_data *ied, unsigned char ie);
+extern int iax_parse_ies(struct iax_ies *ies, unsigned char *data, int datalen);
 
 #endif
diff --git a/channels/iax2.h b/channels/iax2.h
index e42591c2d5203ddeb2d5bb1191a734d7c9e0f907..88ffe0ca0881fe4365a020a290ebef5c98b49d00 100755
--- a/channels/iax2.h
+++ b/channels/iax2.h
@@ -66,6 +66,8 @@
 
 #define IAX_DEFAULT_REG_EXPIRE  60	/* By default require re-registration once per minute */
 
+#define IAX_LINGER_TIMEOUT		10 /* How long to wait before closing bridged call */
+
 #define IAX_DEFAULT_PORTNO		4569
 
 /* IAX Information elements */
diff --git a/codecs/gsm/Makefile b/codecs/gsm/Makefile
index 9e211f57598d95aab968bb543e3b5088223f7efa..721879da95df5372d94a628c8e37876e55a2679b 100755
--- a/codecs/gsm/Makefile
+++ b/codecs/gsm/Makefile
@@ -31,7 +31,7 @@ WAV49	= -DWAV49
 ######### manual page on gsm_option(3).
 
 #K6OPT	= -DK6OPT
-K6OPT	=
+#K6OPT	=
 ######### Define to enable MMXTM optimizations for x86 architecture CPU's
 ######### which support MMX instructions.  This should be newer pentiums,
 ######### ppro's, etc, as well as the AMD K6 and K7.  The compile will
@@ -54,7 +54,7 @@ PG =
 # CC		= /usr/lang/acc
 # CCFLAGS 	= -c -O
 
-CC		= gcc -ansi -pedantic -O6 -mpentium -fschedule-insns2  -fomit-frame-pointer 
+CC		= gcc -ansi -pedantic $(OPTIMIZE) -march=$(PROC) -fschedule-insns2  -fomit-frame-pointer 
 CCFLAGS 	+= -c -DNeedFunctionPrototypes=1 -finline-functions -funroll-loops
 
 LD 		= $(CC)
diff --git a/codecs/lpc10/Makefile b/codecs/lpc10/Makefile
index af5131d77862eee661ffbf5c4145034a584fbe67..61d87740c73b34d53050016d6799465537dc34cd 100755
--- a/codecs/lpc10/Makefile
+++ b/codecs/lpc10/Makefile
@@ -22,8 +22,9 @@ LIB_TARGET_DIR = .
 # 
 
 WARNINGS = -Wall -Wno-comment -Wno-error
-CFLAGS = -O6 -I$(LIB_TARGET_DIR) $(WARNINGS)
-CFLAGS+= $(shell if uname -m | grep -q 86; then echo "-mpentium" ; fi)
+CFLAGS = $(OPTIMIZE) -I$(LIB_TARGET_DIR) $(WARNINGS)
+#CFLAGS+= $(shell if uname -m | grep -q 86; then echo "-mpentium" ; fi)
+CFLAGS+= -march=$(PROC)
 
 LIB = $(LIB_TARGET_DIR)/liblpc10.a
 
diff --git a/configs/extensions.conf.sample b/configs/extensions.conf.sample
index 0499a3351cc2d30e7b9414331c7de9dad3a6c9eb..f7135ecf6b5f00a472f7055c6d2149b1c347a470 100755
--- a/configs/extensions.conf.sample
+++ b/configs/extensions.conf.sample
@@ -31,7 +31,7 @@ CONSOLE=Console/dsp				; Console interface for demo
 IAXINFO=guest					; IAXtel username/password
 ;IAXINFO=myuser:mypass
 TRUNK=Zap/g2					; Trunk interface
-;TRUNK=IAX/user:pass@provider
+;TRUNK=IAX2/user:pass@provider
 
 ;
 ; Any category other than "General" and "Globals" represent 
@@ -84,10 +84,10 @@ TRUNK=Zap/g2					; Trunk interface
 ; up, please go to www.gnophone.com or www.iaxtel.com
 ;
 [iaxtel700]
-exten => _91700NXXXXXX,1,Dial(IAX/${IAXINFO}@iaxtel.com/${EXTEN:1}@iaxtel)
+exten => _91700NXXXXXX,1,Dial(IAX2/${IAXINFO}@iaxtel.com/${EXTEN:1}@iaxtel)
 
 [iaxprovider]
-;switch => IAX/user:[key]@myserver/mycontext
+;switch => IAX2/user:[key]@myserver/mycontext
 
 [trunkint]
 ;
@@ -155,7 +155,7 @@ include => provider
 ; extensions that are not known here, for example with remote 
 ; IAX switching you transparently get access to the remote
 ; 
-; switch => IAX/user:password@bigserver/local
+; switch => IAX2/user:password@bigserver/local
 
 [macro-stdexten];
 ;
@@ -218,7 +218,7 @@ exten => i,1,Playback(invalid)		; "That's not valid, try again"
 ; Asterisk demo.
 ;
 exten => 500,1,Playback(demo-abouttotry); Let them know what's going on
-exten => 500,2,Dial(IAX/guest@misery.digium.com/s@default)	; Call the Asterisk demo
+exten => 500,2,Dial(IAX2/guest@misery.digium.com/s@default)	; Call the Asterisk demo
 exten => 500,3,Playback(demo-nogo)	; Couldn't connect to the demo site
 exten => 500,4,Goto(s,6)		; Return to the start over message.
 
diff --git a/frame.c b/frame.c
index 34ec9950251d7c0027b080dbccabef7266edb267..695c5573e1639e46a2cb5854a44c72c7a0255568 100755
--- a/frame.c
+++ b/frame.c
@@ -238,15 +238,37 @@ struct ast_frame *ast_frisolate(struct ast_frame *fr)
 
 struct ast_frame *ast_frdup(struct ast_frame *f)
 {
-	struct ast_frame *ret;
-	int p;
-	p = f->mallocd;
-	f->mallocd = 0;
-	/* Make frisolate think this is a 100% static frame, and make a duplicate */
-	ret = ast_frisolate(f);
-	/* Restore its true malloc status */
-	f->mallocd = p;
-	return ret;
+	struct ast_frame *out;
+	int len;
+	void *buf;
+	/* Start with standard stuff */
+	len = sizeof(struct ast_frame) + AST_FRIENDLY_OFFSET + f->datalen;
+	/* If we have a source, add space for it */
+	if (f->src && strlen(f->src))
+		len += strlen(f->src) + 1;
+	buf = malloc(len);
+	if (!buf)
+		return NULL;
+	out = buf;
+	/* Set us as having malloc'd header only, so it will eventually
+	   get freed. */
+	out->frametype = f->frametype;
+	out->subclass = f->subclass;
+	out->datalen = f->datalen;
+	out->samples = f->samples;
+	out->mallocd = AST_MALLOCD_HDR;
+	out->offset = AST_FRIENDLY_OFFSET;
+	out->data = buf + sizeof(struct ast_frame) + AST_FRIENDLY_OFFSET;
+	if (f->src && strlen(f->src)) {
+		out->src = out->data + f->datalen;
+		/* Must have space since we allocated for it */
+		strcpy(out->src, f->src);
+	} else
+		out->src = NULL;
+	out->prev = NULL;
+	out->next = NULL;
+	memcpy(out->data, f->data, out->datalen);	
+	return out;
 }
 
 struct ast_frame *ast_fr_fdread(int fd)
diff --git a/pbx.c b/pbx.c
index 63f251ed251d432a5ace9d02b5321b305cc73b60..1115580aa018e1fc4dcfc5ce36bb8b9e5c9f4bae 100755
--- a/pbx.c
+++ b/pbx.c
@@ -678,97 +678,125 @@ static struct ast_exten *pbx_find_extension(struct ast_channel *chan, char *cont
 
 static void pbx_substitute_variables_temp(struct ast_channel *c,char *cp3,char **cp4)
 {
-	int offset;
+	char *first,*second;
+	int offset,offset2;
 	struct ast_var_t *variables;
 	char *name, *num; /* for callerid name + num variables */
 	struct varshead *headp;
 	char pri[80];
         headp=&c->varshead;
         *cp4=NULL;
-	        		/* Now we have the variable name on cp3 */
-				if (!strcmp(cp3, "CALLERIDNUM")) {
-						char cid[256] = "";
-						if (c->callerid)
-							strncpy(cid, c->callerid, sizeof(cid) - 1);
-						ast_callerid_parse(cid, &name, &num);
-						if (num) {
-							ast_shrink_phone_number(num);
-							*cp4 = num;
-						} else
-							*cp4 = "";
-					} else if (!strcmp(cp3, "CALLERIDNAME")) {
-						char cid[256] = "";
-						if (c->callerid)
-							strncpy(cid, c->callerid, sizeof(cid) - 1);
-						ast_callerid_parse(cid, &name, &num);
-						if (name)
-							*cp4 = name;
-						else
-							*cp4 = "";
-	        			} else if (!strcmp(cp3, "CALLERID")) {
-						*cp4 = c->callerid;
-						if (!(*cp4))
-							*cp4 = "";
-					} else if (!strcmp(cp3, "EXTEN")) {
-						*cp4 = c->exten;
-					} else if (!strncmp(cp3, "EXTEN-", strlen("EXTEN-")) && 
-						/* XXX Remove me eventually */
-						(sscanf(cp3 + strlen("EXTEN-"), "%d", &offset) == 1)) {
-						if (offset < 0)
-							offset=0;
-						if (offset > strlen(c->exten))
-							offset = strlen(c->exten);
-						*cp4 = c->exten + offset;
-						ast_log(LOG_WARNING, "The use of 'EXTEN-foo' has been derprecated in favor of 'EXTEN:foo'\n");
-					} else if (!strncmp(cp3, "EXTEN:", strlen("EXTEN:")) && 
-						(sscanf(cp3 + strlen("EXTEN:"), "%d", &offset) == 1)) {
-						if (offset < 0)
-							offset=0;
-						if (offset > strlen(c->exten))
-							offset = strlen(c->exten);
-						*cp4 = c->exten + offset;
-					} else if (!strcmp(cp3, "RDNIS")) {
-						*cp4 = c->rdnis;
-						if (!(*cp4))
-							*cp4 = "";
-					} else if (!strcmp(cp3, "CONTEXT")) {
-						*cp4 = c->context;
-					} else if (!strcmp(cp3, "PRIORITY")) {
-						snprintf(pri, sizeof(pri), "%d", c->priority);
-						*cp4 = pri;
-					} else {
-		        		AST_LIST_TRAVERSE(headp,variables,entries) {
+        /* Now we have the variable name on cp3 */
+	if ((first=strchr(cp3,':'))) {
+		*first='\0';
+		offset=atoi(first+1);
+	 	if ((second=strchr(first+1,':'))) {
+			*second='\0';
+			offset2=atoi(second+1);
+		} else {
+			offset2=offset;
+			offset=0;
+		}
+		pbx_substitute_variables_temp(c,cp3,cp4);
+		if (!(*cp4)) return;
+		if (abs(offset)>strlen(*cp4)) {
+			if (offset>=0) offset=strlen(*cp4);
+			else offset=-strlen(*cp4);
+		}
+		if ((offset<0 && offset2>-offset) || (offset>=0 && offset+offset2>strlen(*cp4))) {
+			if (offset>=0) offset2=strlen(*cp4)-offset;
+			else offset2=strlen(*cp4)+offset;
+		}
+		if (offset>=0)
+			*cp4+=offset;
+		else
+			*cp4+=strlen(*cp4)+offset;
+		(*cp4)[offset2] = '\0';
+	} else if (!strcmp(cp3, "CALLERIDNUM")) {
+		char cid[256] = "";
+		if (c->callerid)
+			strncpy(cid, c->callerid, sizeof(cid) - 1);
+		ast_callerid_parse(cid, &name, &num);
+		if (num) {
+			ast_shrink_phone_number(num);
+			*cp4 = num;
+		} else
+			*cp4 = "";
+	} else if (!strcmp(cp3, "CALLERIDNAME")) {
+		char cid[256] = "";
+		if (c->callerid)
+			strncpy(cid, c->callerid, sizeof(cid) - 1);
+		ast_callerid_parse(cid, &name, &num);
+		if (name)
+			*cp4 = name;
+		else
+			*cp4 = "";
+	} else if (!strcmp(cp3, "CALLERID")) {
+		*cp4 = c->callerid;
+		if (!(*cp4))
+			*cp4 = "";
+	} else if (!strcmp(cp3, "EXTEN")) {
+		*cp4 = c->exten;
+	} else if (!strncmp(cp3, "EXTEN-", strlen("EXTEN-")) && 
+		/* XXX Remove me eventually */
+		(sscanf(cp3 + strlen("EXTEN-"), "%d", &offset) == 1)) {
+		if (offset < 0)
+			offset=0;
+		if (offset > strlen(c->exten))
+			offset = strlen(c->exten);
+		*cp4 = c->exten + offset;
+		ast_log(LOG_WARNING, "The use of 'EXTEN-foo' has been derprecated in favor of 'EXTEN:foo'\n");
 #if 0
-		        			ast_log(LOG_WARNING,"Comparing variable '%s' with '%s'\n",cp3,ast_var_name(variables));
+	} else if (!strncmp(cp3, "EXTEN:", strlen("EXTEN:")) && 
+		(sscanf(cp3 + strlen("EXTEN:"), "%d", &offset) == 1)) {
+		if (offset < 0)
+			offset=0;
+		if (offset > strlen(c->exten))
+			offset = strlen(c->exten);
+		*cp4 = c->exten + offset;
 #endif
-							if (strcasecmp(ast_var_name(variables),cp3)==0)
-								*cp4=ast_var_value(variables);
-						}
-						if (!(*cp4)) {
-							/* Try globals */
-			        		AST_LIST_TRAVERSE(&globals,variables,entries) {
+	} else if (!strcmp(cp3, "RDNIS")) {
+		*cp4 = c->rdnis;
+		if (!(*cp4))
+			*cp4 = "";
+	} else if (!strcmp(cp3, "CONTEXT")) {
+		*cp4 = c->context;
+	} else if (!strcmp(cp3, "PRIORITY")) {
+		snprintf(pri, sizeof(pri), "%d", c->priority);
+		*cp4 = pri;
+	} else {
+		AST_LIST_TRAVERSE(headp,variables,entries) {
 #if 0
-			        			ast_log(LOG_WARNING,"Comparing variable '%s' with '%s'\n",cp3,ast_var_name(variables));
+			ast_log(LOG_WARNING,"Comparing variable '%s' with '%s'\n",cp3,ast_var_name(variables));
 #endif
-								if (strcasecmp(ast_var_name(variables),cp3)==0)
-									*cp4=ast_var_value(variables);
-							}
-						}
-						if (!(*cp4)) {
-							int len=strlen(cp3);
-							int len_env=strlen("ENV(");
-							if (len > (len_env+1) && !strncasecmp(cp3,"ENV(",len_env) && !strcmp(cp3+len-1,")")) {
-								cp3[len-1]='\0';
-								*cp4=getenv(cp3+len_env);
-							}
-						}
-					}
+			if (strcasecmp(ast_var_name(variables),cp3)==0)
+				*cp4=ast_var_value(variables);
+		}
+		if (!(*cp4)) {
+			/* Try globals */
+			AST_LIST_TRAVERSE(&globals,variables,entries) {
+#if 0
+				ast_log(LOG_WARNING,"Comparing variable '%s' with '%s'\n",cp3,ast_var_name(variables));
+#endif
+				if (strcasecmp(ast_var_name(variables),cp3)==0)
+					*cp4=ast_var_value(variables);
+			}
+		}
+		if (!(*cp4)) {
+			int len=strlen(cp3);
+			int len_env=strlen("ENV(");
+			if (len > (len_env+1) && !strncasecmp(cp3,"ENV(",len_env) && !strcmp(cp3+len-1,")")) {
+				cp3[len-1]='\0';
+				*cp4=getenv(cp3+len_env);
+			}
+		}
+	}
 }
 
 static void pbx_substitute_variables_helper(struct ast_channel *c,char *cp1,char **ecp2,int count)
 {
 	char *cp4,*cp2;
-	char *tmp,*wherearewe,*finish,*ltmp,*lval,*nextvar;
+	char *tmp,*wherearewe,*finish=NULL,*ltmp,*lval,*nextvar;
 	int length,variables=0;
 
 	wherearewe=tmp=cp1;
diff --git a/pbx/pbx_config.c b/pbx/pbx_config.c
index ab2543895361619b9efa6289ee15bb0f7dadbb3e..f7b143dafb06def00e0252cbfd8cbb5040d09001 100755
--- a/pbx/pbx_config.c
+++ b/pbx/pbx_config.c
@@ -1512,8 +1512,12 @@ static int pbx_load_module(void)
 							appl = stringp;
 							if (!appl)
 								appl="";
-							if (!(start = strchr(appl, '(')))
-								appl = strsep(&stringp, ",");
+							if (!(start = strchr(appl, '('))) {
+								if (stringp)
+									appl = strsep(&stringp, ",");
+								else
+									appl = "";
+							}
 							if (start && (end = strrchr(appl, ')'))) {
 								*start = *end = '\0';
 								data = start + 1;
@@ -1525,7 +1529,10 @@ static int pbx_load_module(void)
 								data = strsep(&stringp, "\"");
 								stringp++;
 							} else {
-								data = strsep(&stringp, ",");
+								if (stringp)
+									data = strsep(&stringp, ",");
+								else
+									data = "";
 							}
 							cidmatch = strchr(ext, '/');
 							if (cidmatch) {
diff --git a/res/res_musiconhold.c b/res/res_musiconhold.c
index ab347f9d45bee312d56b5b26e5e516f552b9c5d6..dc1839d039ce3bad66bc005b42688bdc254ca654 100755
--- a/res/res_musiconhold.c
+++ b/res/res_musiconhold.c
@@ -221,8 +221,8 @@ static void *monmp3thread(void *data)
 			res = read(class->pseudofd, buf, sizeof(buf));
 		} else {
 			/* otherwise just sleep (unreliable) */
-			usleep(250000);
-			res = 2000;
+			usleep(100000);	/* Sleep 100 ms */
+			res = 800;		/* 800 samples */
 		}
 		if (!class->members)
 			continue;
@@ -328,7 +328,7 @@ static struct mohdata *mohalloc(struct mohclass *cl)
 static void moh_release(struct ast_channel *chan, void *data)
 {
 	struct mohdata *moh = data, *prev, *cur;
-	int oldrfmt, oldwfmt;
+	int oldwfmt;
 	ast_pthread_mutex_lock(&moh_lock);
 	/* Unlink */
 	prev = NULL;
@@ -350,8 +350,8 @@ static void moh_release(struct ast_channel *chan, void *data)
 	oldwfmt = moh->origwfmt;
 	free(moh);
 	if (chan) {
-		if (ast_set_write_format(chan, oldwfmt)) 
-			ast_log(LOG_WARNING, "Unable to restore channel '%s' to format %d/%d\n", chan->name, oldwfmt, oldrfmt);
+		if (oldwfmt && ast_set_write_format(chan, oldwfmt)) 
+			ast_log(LOG_WARNING, "Unable to restore channel '%s' to format %d\n", chan->name, oldwfmt);
 		if (option_verbose > 2)
 			ast_verbose(VERBOSE_PREFIX_3 "Stopped music on hold on %s\n", chan->name);
 	}