--- channels/chan_sip.c.orig	2010-10-06 15:31:23.000000000 +0200
+++ channels/chan_sip.c	2010-10-06 15:32:50.000000000 +0200
@@ -864,21 +864,22 @@
 
 /*! \brief T38 States for a call */
 enum t38state {
-        T38_DISABLED = 0,                /*!< Not enabled */
-        T38_LOCAL_REINVITE,              /*!< Offered from local - REINVITE */
-        T38_PEER_DIRECT,                 /*!< Offered from peer */
-        T38_PEER_REINVITE,               /*!< Offered from peer - REINVITE */
-        T38_ENABLED                      /*!< Negotiated (enabled) */
+		T38_DISABLED = 0,              /*!< Not enabled */
+		T38_LOCAL_DIRECT,              /*!< Offered from local */
+		T38_LOCAL_REINVITE,            /*!< Offered from local - REINVITE */
+		T38_PEER_DIRECT,               /*!< Offered from peer */
+		T38_PEER_REINVITE,             /*!< Offered from peer - REINVITE */
+		T38_ENABLED                    /*!< Negotiated (enabled) */
 };
 
 /*! \brief T.38 channel settings (at some point we need to make this alloc'ed */
 struct t38properties {
-	struct ast_flags t38support;	/*!< Flag for udptl, rtp or tcp support for this session */
-	int capability;			/*!< Our T38 capability */
-	int peercapability;		/*!< Peers T38 capability */
-	int jointcapability;		/*!< Supported T38 capability at both ends */
-	enum t38state state;		/*!< T.38 state */
-	unsigned int direct:1;          /*!< Whether the T38 came from the initial invite or not */
+	struct ast_flags t38support;       /*!< Flag for udptl, rtp or tcp support for this session */
+	int capability;                    /*!< Our T38 capability */
+	int peercapability;	               /*!< Peers T38 capability */
+	int jointcapability;               /*!< Supported T38 capability at both ends */
+	enum t38state state;               /*!< T.38 state */
+	unsigned int only:1;               /*!< This is a T38 only call (no audio codecs, so do not forward voice frames) */
 };
 
 /*! \brief Parameters to know status of transfer */
@@ -3248,6 +3249,13 @@
 		} else if (!strcasecmp(ast_var_name(current), "SIPTRANSFER_REPLACES")) {
 			/* We're replacing a call. */
 			p->options->replaces = ast_var_value(current);
+		} else if (!strcasecmp(ast_var_name(current), "T38CALL")) {
+			p->t38.state = T38_ENABLED;
+			p->t38.only = 1;
+			if (option_debug > 2) {
+				ast_log(LOG_DEBUG,"T38 Only call!\n");
+				ast_log(LOG_DEBUG,"T38 State change to %d on channel %s\n", p->t38.state, ast->name);
+			}
 		}
 	}
 	
@@ -3275,7 +3283,7 @@
 		p->jointnoncodeccapability = p->noncodeccapability;
 
 		/* If there are no audio formats left to offer, punt */
-		if (!(p->jointcapability & AST_FORMAT_AUDIO_MASK)) {
+		if (!(p->jointcapability & AST_FORMAT_AUDIO_MASK) && !p->t38.only) {
 			ast_log(LOG_WARNING, "No audio format found to offer. Cancelling call to %s\n", p->username);
 			res = -1;
 		} else {
@@ -4003,7 +4011,7 @@
 						transmit_provisional_response(p, "183 Session Progress", &p->initreq, 1);
 						ast_set_flag(&p->flags[0], SIP_PROGRESS_SENT);
 					}
-				} else if (p->t38.state == T38_ENABLED && !p->t38.direct) {
+				} else if (p->t38.state == T38_ENABLED && p->t38.only) {
 					/* drop frame, can't sent VOICE frames while in T.38 mode */
 				} else {
 					p->lastrtptx = time(NULL);
@@ -4045,6 +4053,8 @@
 				if (ast_test_flag(&p->flags[1], SIP_PAGE2_T38SUPPORT) && p->t38.state == T38_DISABLED) {
 					if (!p->pendinginvite) {
 						p->t38.state = T38_LOCAL_REINVITE;
+						if (option_debug > 2)
+							ast_log(LOG_DEBUG, "T38 state changed to %d on channel %s\n", p->t38.state, p->owner ? p->owner->name : "<none>" );
 						transmit_reinvite_with_t38_sdp(p);
 					}
 				} else if (p->t38.state == T38_ENABLED) {
@@ -4326,12 +4336,28 @@
 	} else if (i->capability)	{	/* Our configured capability for this peer */
 		what = i->capability;
 		video = i->capability & AST_FORMAT_VIDEO_MASK;
+	} else if (i->t38.jointcapability && !i->jointcapability && !i->capability) {
+		/* On T38 Only calls we must set a native format to fool channel.c
+		   But we must also set the proper channel variable to inform the new channel
+		   and so that users can choose not to playback audio on T38 Only calls */
+		ast_log(LOG_DEBUG, "*** T.38 Only call, setting native formats anyway. \n");
+		if (global_capability) {
+			what = global_capability;	/* Use global capability support */
+		} else { 
+			what = AST_FORMAT_ULAW;		/* We must have a codec so if none is defined fallback to ulaw */
+		}
+		video = 0;
+		pbx_builtin_setvar_helper(tmp, "_T38CALL", "1");
+		i->t38.state = T38_ENABLED; /* T38 Only Offered so no need to negotiate, just enable it */
+		i->t38.only = 1;
+		if (option_debug > 2)
+			ast_log(LOG_DEBUG, "T38 state changed to %d on channel %s\n", i->t38.state, tmp->name ? tmp->name : "<none>" );
 	} else {
 		what = global_capability;	/* Global codec support */
 		video = global_capability & AST_FORMAT_VIDEO_MASK;
 	}
 
-	/* Set the native formats for audio  and merge in video */
+	/* Set the native formats for audio and merge in video */
 	tmp->nativeformats = ast_codec_choose(&i->prefs, what, 1) | video;
 	if (option_debug > 2) {
 		char buf[SIPBUFSIZE];
@@ -4692,9 +4718,9 @@
 				if (option_debug > 2)
 					ast_log(LOG_DEBUG, "Sending reinvite on SIP (%s) for T.38 negotiation.\n",ast->name);
 				p->t38.state = T38_LOCAL_REINVITE;
-				transmit_reinvite_with_t38_sdp(p);
-				if (option_debug > 1)
+				if (option_debug > 2)
 					ast_log(LOG_DEBUG, "T38 state changed to %d on channel %s\n", p->t38.state, ast->name);
+				transmit_reinvite_with_t38_sdp(p);
 			}
 		} else if (!ast_test_flag(&p->flags[0], SIP_PENDINGBYE)) {
 			if (option_debug > 2)
@@ -5597,14 +5623,13 @@
 			
 			if (p->owner && p->lastinvite) {
 				if (p->t38.state != T38_LOCAL_REINVITE) {
-					p->t38.state = T38_PEER_REINVITE; /* T38 Offered in re-invite from remote party */
-					if (option_debug > 1)
+					p->t38.state = T38_ENABLED; /* T38 Offered in re-invite from remote party */
+					if (option_debug > 2)
 						ast_log(LOG_DEBUG, "T38 state changed to %d on channel %s\n", p->t38.state, p->owner ? p->owner->name : "<none>" );
 				}
 			} else {
 				p->t38.state = T38_PEER_DIRECT; /* T38 Offered directly from peer in first invite */
-				p->t38.direct = 1;
-				if (option_debug > 1)
+				if (option_debug > 2)
 					ast_log(LOG_DEBUG, "T38 state changed to %d on channel %s\n", p->t38.state, p->owner ? p->owner->name : "<none>");
 			}
 
@@ -5732,8 +5757,12 @@
 			/* Do NOT Change current setting */
 			return -1;
 		} else {
-			if (option_debug > 2)
-				ast_log(LOG_DEBUG, "Have T.38 but no audio codecs, accepting offer anyway\n");
+			p->t38.state = T38_ENABLED;
+			p->t38.only = 1;			
+			if (option_debug > 2) {
+				ast_log(LOG_DEBUG, "Detected a T38 Only call!\n");
+				ast_log(LOG_DEBUG, "T38 state changed to %d on channel %s\n", p->t38.state, p->owner ? p->owner->name : "<none>" );
+			}
 		}
 	}
 
@@ -7034,7 +7063,7 @@
 		dest.sin_port = sin.sin_port;
 	}
 
-        snprintf(owner, sizeof(owner), "o=root %d %d IN IP4 %s\r\n", p->sessionid, p->sessionversion, ast_inet_ntoa(dest.sin_addr));
+	snprintf(owner, sizeof(owner), "o=root %d %d IN IP4 %s\r\n", p->sessionid, p->sessionversion, ast_inet_ntoa(dest.sin_addr));
 	snprintf(connection, sizeof(connection), "c=IN IP4 %s\r\n", ast_inet_ntoa(dest.sin_addr));
 
 	if (ast_test_flag(&p->flags[1], SIP_PAGE2_CALL_ONHOLD) == SIP_PAGE2_CALL_ONHOLD_ONEDIR)
@@ -7202,11 +7231,10 @@
 		}
 
 		if (debug) {
-			ast_log(LOG_DEBUG, "T.38 UDPTL is at %s port %d\n", ast_inet_ntoa(p->ourip), ntohs(udptlsin.sin_port));
-			ast_log(LOG_DEBUG, "Our T38 capability (%d), peer T38 capability (%d), joint capability (%d)\n",
-				p->t38.capability,
-				p->t38.peercapability,
-				p->t38.jointcapability);
+			ast_log(LOG_DEBUG, "T38 UDPTL is currently at %s port %d\n", ast_inet_ntoa(p->ourip), ntohs(udptlsin.sin_port));
+			if (p->udptlredirip.sin_addr.s_addr)
+				ast_log(LOG_DEBUG, "T38 UDPTL will be sent to %s port %d\n", ast_inet_ntoa(udptldest.sin_addr), ntohs(udptldest.sin_port));
+			ast_log(LOG_DEBUG, "Our T38 capability (%d), peer T38 capability (%d), joint capability (%d)\n", p->t38.capability,	p->t38.peercapability, p->t38.jointcapability);
 		}
 
 		ast_build_string(&m_modem_next, &m_modem_left, "m=image %d udptl t38\r\n", ntohs(udptldest.sin_port));
@@ -7243,7 +7271,7 @@
 		add_content(resp, m_audio);
 		add_content(resp, a_audio);
 		add_content(resp, hold);
-	} else if (p->offered_media[SDP_AUDIO].offered) {
+	} else if (p->offered_media[SDP_AUDIO].offered && !p->t38.only) {
 		snprintf(dummy_answer, sizeof(dummy_answer), "m=audio 0 RTP/AVP %s\r\n", p->offered_media[SDP_AUDIO].text);
 		add_content(resp, dummy_answer);
 	}
@@ -7329,9 +7357,16 @@
 			ast_rtp_codec_setpref(p->rtp, &p->prefs);
 		}
 		try_suggested_sip_codec(p);
-		if (p->t38.state == T38_PEER_DIRECT || p->t38.state == T38_ENABLED) {
+			if (option_debug > 2 )
+				ast_log(LOG_DEBUG,"T38 is in state %d on channel %s\n", p->t38.state, p->owner ? p->owner->name : "<none>");
+		if (p->t38.state != T38_DISABLED) {
+			if (p->t38.only)
+				add_sdp(&resp, p, 0, 1);
+			else
+				add_sdp(&resp, p, 1, 1);
 			p->t38.state = T38_ENABLED;
-			add_sdp(&resp, p, 1, 1);
+			if (option_debug > 2)
+				ast_log(LOG_DEBUG, "T38 state changed to %d on channel %s\n", p->t38.state, p->owner ? p->owner->name : "<none>" );
 		} else {
 			add_sdp(&resp, p, 1, 0);
 		}
@@ -7758,11 +7793,14 @@
 	}
 	if (sdp) {
 		memset(p->offered_media, 0, sizeof(p->offered_media));
-		if (p->udptl && p->t38.state == T38_LOCAL_REINVITE) {
-			ast_udptl_offered_from_local(p->udptl, 1);
+		if (p->udptl) {
 			if (option_debug)
 				ast_log(LOG_DEBUG, "T38 is in state %d on channel %s\n", p->t38.state, p->owner ? p->owner->name : "<none>");
-			add_sdp(&req, p, 0, 1);
+			ast_udptl_offered_from_local(p->udptl, 1);
+			if (p->t38.only)
+				add_sdp(&req, p, 0, 1);
+			else 
+				add_sdp(&req, p, 1, 1);
 		} else if (p->rtp) 
 			add_sdp(&req, p, 1, 0);
 	}
@@ -12920,7 +12958,7 @@
 			if (option_debug)
 				ast_log(LOG_DEBUG, "Sending pending reinvite on '%s'\n", p->callid);
 			/* Didn't get to reinvite yet, so do it now */
-			transmit_reinvite_with_sdp(p);
+				transmit_reinvite_with_sdp(p);
 			ast_clear_flag(&p->flags[0], SIP_NEEDREINVITE);
 		}
 	}
@@ -13078,7 +13116,7 @@
 			if (bridgepeer->tech == &sip_tech || bridgepeer->tech == &sip_tech_info) {
 				bridgepvt = (struct sip_pvt*)(bridgepeer->tech_pvt);
 				if (bridgepvt->udptl) {
-					if (p->t38.state == T38_PEER_REINVITE) {
+					if (p->t38.state == T38_PEER_REINVITE || ((p->t38.state == T38_ENABLED) && reinvite)) {
 						sip_handle_t38_reinvite(bridgepeer, p, 0);
 						ast_rtp_set_rtptimers_onhold(p->rtp);
 						if (p->vrtp)
@@ -13090,25 +13128,25 @@
 					ast_mutex_lock(&bridgepvt->lock);
 					bridgepvt->t38.state = T38_DISABLED;
 					ast_mutex_unlock(&bridgepvt->lock);
-					if (option_debug)
-						ast_log(LOG_DEBUG,"T38 state changed to %d on channel %s\n", bridgepvt->t38.state, bridgepeer->tech->type);
 					p->t38.state = T38_DISABLED;
-					if (option_debug > 1)
+					if (option_debug > 2) {
+						ast_log(LOG_DEBUG,"T38 state changed to %d on channel %s\n", bridgepvt->t38.state, bridgepeer->tech->type);
 						ast_log(LOG_DEBUG,"T38 state changed to %d on channel %s\n", p->t38.state, p->owner ? p->owner->name : "<none>");
+					}
 				}
 			} else {
 				/* Other side is not a SIP channel */
 				if (option_debug > 1)
 					ast_log(LOG_DEBUG, "Strange... The other side of the bridge is not a SIP channel\n");
 				p->t38.state = T38_DISABLED;
-				if (option_debug > 1)
+				if (option_debug > 2)
 					ast_log(LOG_DEBUG,"T38 state changed to %d on channel %s\n", p->t38.state, p->owner ? p->owner->name : "<none>");
 			}
 		}
-		if (p->t38.state == T38_LOCAL_REINVITE) {
+		if (p->t38.state == T38_LOCAL_REINVITE || p->t38.state == T38_LOCAL_DIRECT) {
 			/* If there was T38 reinvite and we are supposed to answer with 200 OK than this should set us to T38 negotiated mode */
 			p->t38.state = T38_ENABLED;
-			if (option_debug)
+			if (option_debug > 2)
 				ast_log(LOG_DEBUG, "T38 changed state to %d on channel %s\n", p->t38.state, p->owner ? p->owner->name : "<none>");
 		}
 
@@ -13201,6 +13239,8 @@
 		xmitres = transmit_request(p, SIP_ACK, seqno, XMIT_UNRELIABLE, FALSE);
 		if (reinvite && p->udptl) {
 			p->t38.state = T38_DISABLED;
+			if (option_debug > 2)
+				ast_log(LOG_DEBUG, "T38 state changed to %d on channel %s\n", p->t38.state, p->owner ? p->owner->name : "<none>" );
 			/* Try to reset RTP timers */
 			ast_rtp_set_rtptimers_onhold(p->rtp);
 			/* Trigger a reinvite back to audio */
@@ -15378,7 +15418,9 @@
 
 			transmit_response(p, "100 Trying", req);
 
-			if (p->t38.state == T38_PEER_REINVITE) {
+			if (p->t38.state == T38_PEER_REINVITE || 
+				p->t38.state == T38_LOCAL_REINVITE || 
+				((p->t38.state == T38_ENABLED) && reinvite)) {
 				struct ast_channel *bridgepeer = NULL;
 				struct sip_pvt *bridgepvt = NULL;
 				
@@ -15396,7 +15438,7 @@
 								ast_mutex_lock(&bridgepvt->lock);
 								bridgepvt->t38.state = T38_DISABLED;
 								ast_mutex_unlock(&bridgepvt->lock);
-								if (option_debug > 1)
+								if (option_debug > 2)
 									ast_log(LOG_DEBUG,"T38 state changed to %d on channel %s\n", bridgepvt->t38.state, bridgepeer->name);
 								if (ast_test_flag(req, SIP_PKT_IGNORE))
 									transmit_response(p, "488 Not acceptable here", req);
@@ -15409,7 +15451,7 @@
 							ast_set_flag(&p->flags[1], SIP_PAGE2_DIALOG_ESTABLISHED);
 							transmit_response_with_t38_sdp(p, "200 OK", req, XMIT_CRITICAL);
 							p->t38.state = T38_ENABLED;
-							if (option_debug)
+							if (option_debug > 2)
 								ast_log(LOG_DEBUG, "T38 state changed to %d on channel %s\n", p->t38.state, p->owner ? p->owner->name : "<none>");
 						}
 					} else {
@@ -15419,7 +15461,7 @@
 						else
 							transmit_response_reliable(p, "488 Not acceptable here", req);
 						p->t38.state = T38_DISABLED;
-						if (option_debug > 1)
+						if (option_debug > 2)
 							ast_log(LOG_DEBUG,"T38 state changed to %d on channel %s\n", p->t38.state, p->owner ? p->owner->name : "<none>");
 
 						if (!p->lastinvite) /* Only destroy if this is *not* a re-invite */
@@ -15430,7 +15472,7 @@
 					ast_set_flag(&p->flags[1], SIP_PAGE2_DIALOG_ESTABLISHED);
 					transmit_response_with_t38_sdp(p, "200 OK", req, XMIT_CRITICAL);
 					p->t38.state = T38_ENABLED;
-					if (option_debug)
+					if (option_debug > 2)
 						ast_log(LOG_DEBUG,"T38 state changed to %d on channel %s\n", p->t38.state, p->owner ? p->owner->name : "<none>");
 				}
 			} else if (p->t38.state == T38_DISABLED) { /* Channel doesn't have T38 offered or enabled */
@@ -19083,7 +19125,7 @@
 		}
 		pvt->t38.state = T38_ENABLED;
 		p->t38.state = T38_ENABLED;
-		if (option_debug > 1) {
+		if (option_debug > 2) {
 			ast_log(LOG_DEBUG, "T38 changed state to %d on channel %s\n", pvt->t38.state, pvt->owner ? pvt->owner->name : "<none>");
 			ast_log(LOG_DEBUG, "T38 changed state to %d on channel %s\n", p->t38.state, chan ? chan->name : "<none>");
 		}
@@ -19093,7 +19135,7 @@
 		return 0;
 	} else if (pvt->t38.state == T38_DISABLED) { /* The other side can not talk T.38 with us. We tell it to the the originating T.38 party with a 488 */
 		p->t38.state = T38_DISABLED;
-		if (option_debug > 1) {
+		if (option_debug > 2) {
 			ast_log(LOG_DEBUG, "T38 changed state to %d on channel %s\n", pvt->t38.state, pvt->owner ? pvt->owner->name : "<none>");
 			ast_log(LOG_DEBUG, "T38 changed state to %d on channel %s\n", p->t38.state, chan ? chan->name : "<none>");
 		}
@@ -19172,6 +19214,23 @@
 	if (!p) 
 		return -1;
 
+	/* If this is a local re-invite of an established T38 session, use sip_set_udptl_peer instead */
+	if (p->t38.state != T38_DISABLED) {
+		if (!p->t38.only) {
+			if (p->t38.state != T38_PEER_REINVITE) {
+				p->t38.state = T38_LOCAL_REINVITE;
+				if (option_debug > 2)
+					ast_log(LOG_DEBUG,"T38 state changed to %d on channel %s\n", p->t38.state, p->owner ? p->owner->name : "<none>");
+				}
+		} else {
+			ast_log(LOG_WARNING,"Call %s cannot re-invite because its a T38 Only call (not yet supported).\n", p->callid);
+			return 0;
+			/* Re-Invite on T38 Only calls might be made possible by calling "return sip_set_udptl_peer(chan, p->udptl);" 
+		   however the "p-udptl" then holds the wrong information so it would cause the peer to invite itself :-(
+		   If anyone can figure it out, please be my guest (ramonpeek)*/
+		}
+	}
+
 	/* Disable early RTP bridge  */
 	if (!ast_bridged_channel(chan) && !global_directrtpsetup) 	/* We are in early state */
 		return 0;
