--- chan_sip.c_orig	2008-07-08 02:04:27.000000000 +0900
+++ chan_sip.c	2008-07-08 02:13:22.000000000 +0900
@@ -715,7 +715,7 @@
 /*--- Various flags for the flags field in the pvt structure */
 #define SIP_ALREADYGONE		(1 << 0)	/*!< Whether or not we've already been destroyed by our peer */
 #define SIP_NEEDDESTROY		(1 << 1)	/*!< if we need to be destroyed by the monitor thread */
-#define SIP_NOVIDEO		(1 << 2)	/*!< Didn't get video in invite, don't offer */
+#define SIP_DEFER_BYE_ON_TRANSFER	(1 << 2)	/*!< Do not hangup at first ast_hangup */
 #define SIP_RINGING		(1 << 3)	/*!< Have sent 180 ringing */
 #define SIP_PROGRESS_SENT	(1 << 4)	/*!< Have sent 183 message progress */
 #define SIP_NEEDREINVITE	(1 << 5)	/*!< Do we need to send another reinvite? */
@@ -728,12 +728,13 @@
 #define SIP_USECLIENTCODE	(1 << 12)	/*!< Trust X-ClientCode info message */
 #define SIP_OUTGOING		(1 << 13)	/*!< Direction of the last transaction in this dialog */
 #define SIP_FREE_BIT		(1 << 14)	/*!< ---- */
-#define SIP_DEFER_BYE_ON_TRANSFER	(1 << 15)	/*!< Do not hangup at first ast_hangup */
-#define SIP_DTMF		(3 << 16)	/*!< DTMF Support: four settings, uses two bits */
-#define SIP_DTMF_RFC2833	(0 << 16)	/*!< DTMF Support: RTP DTMF - "rfc2833" */
-#define SIP_DTMF_INBAND		(1 << 16)	/*!< DTMF Support: Inband audio, only for ULAW/ALAW - "inband" */
-#define SIP_DTMF_INFO		(2 << 16)	/*!< DTMF Support: SIP Info messages - "info" */
-#define SIP_DTMF_AUTO		(3 << 16)	/*!< DTMF Support: AUTO switch between rfc2833 and in-band DTMF */
+#define SIP_DTMF		(7 << 15)	/*!< DTMF Support: four settings, uses two bits */
+#define SIP_DTMF_RFC2833	(0 << 15)	/*!< DTMF Support: RTP DTMF - "rfc2833" */
+#define SIP_DTMF_INBAND		(1 << 15)	/*!< DTMF Support: Inband audio, only for ULAW/ALAW - "inband" */
+#define SIP_DTMF_INFO		(2 << 15)	/*!< DTMF Support: SIP Info messages - "info DTMF-RELAY" */
+#define SIP_DTMF_AUTO		(3 << 15)	/*!< DTMF Support: AUTO switch between rfc2833 and in-band DTMF */
+#define SIP_DTMF_SHORTINFO	(4 << 15)	/*!< DTMF Support: SIP Info messages - "info application/dtmf" */
+#define SIP_DTMF_INFO2		(5 << 15)	/*!< DTMF Support: SIP Info messages - "info telephone-event" */
 /* NAT settings */
 #define SIP_NAT			(3 << 18)	/*!< four settings, uses two bits */
 #define SIP_NAT_NEVER		(0 << 18)	/*!< No nat support */
@@ -954,6 +955,7 @@
 	int lastinvite;				/*!< Last Cseq of invite */
 	int lastnoninvite;                      /*!< Last Cseq of non-invite */
 	struct ast_flags flags[2];		/*!< SIP_ flags */
+	char novideo;				/*!< Didn't get video in invite, don't offer */			
 	int timer_t1;				/*!< SIP timer T1, ms rtt */
 	unsigned int sipoptions;		/*!< Supported SIP options on the other end */
 	struct ast_codec_pref prefs;		/*!< codec prefs */
@@ -1510,7 +1512,7 @@
 static int add_header_contentLength(struct sip_request *req, int len);
 static int add_line(struct sip_request *req, const char *line);
 static int add_text(struct sip_request *req, const char *text);
-static int add_digit(struct sip_request *req, char digit, unsigned int duration);
+static int add_digit(struct sip_request *req, char digit, unsigned int duration, int mode);
 static int add_vidupdate(struct sip_request *req);
 static void add_route(struct sip_request *req, struct sip_route *route);
 static int copy_header(struct sip_request *req, const struct sip_request *orig, const char *field);
@@ -3861,6 +3863,8 @@
 
 	ast_mutex_lock(&p->lock);
 	switch (ast_test_flag(&p->flags[0], SIP_DTMF)) {
+	case SIP_DTMF_INFO2:
+	case SIP_DTMF_SHORTINFO:
 	case SIP_DTMF_INFO:
 		transmit_info_with_digit(p, digit, duration);
 		break;
@@ -3972,7 +3976,7 @@
 		ast_moh_stop(ast);
 		break;
 	case AST_CONTROL_VIDUPDATE:	/* Request a video frame update */
-		if (p->vrtp && !ast_test_flag(&p->flags[0], SIP_NOVIDEO)) {
+		if (p->vrtp && !p->novideo) {
 			transmit_info_with_vidupdate(p);
 			/* ast_rtcp_send_h261fur(p->vrtp); */
 		} else
@@ -4028,8 +4032,10 @@
 		return NULL;
 	}
 	ast_mutex_lock(&i->lock);
+	if ((ast_test_flag(&i->flags[0], SIP_DTMF) == SIP_DTMF_INFO) || 
+		(ast_test_flag(&i->flags[0], SIP_DTMF) == SIP_DTMF_INFO2) || 
+		(ast_test_flag(&i->flags[0], SIP_DTMF) == SIP_DTMF_SHORTINFO))
 
-	if (ast_test_flag(&i->flags[0], SIP_DTMF) == SIP_DTMF_INFO)
 		tmp->tech = &sip_tech_info;
 	else
 		tmp->tech = &sip_tech;
@@ -5116,13 +5122,14 @@
 	vhp = hp;	/* Copy to video address as default too */
 	
 	iterator = req->sdp_start;
-	ast_set_flag(&p->flags[0], SIP_NOVIDEO);	
+	p->novideo = TRUE;
 
 
 	/* Find media streams in this SDP offer */
 	while ((m = get_sdp_iterate(&iterator, req, "m"))[0] != '\0') {
 		int x;
 		int audio = FALSE;
+		int video = FALSE;
 
 		numberofports = 1;
 		if ((sscanf(m, "audio %d/%d RTP/AVP %n", &x, &numberofports, &len) == 2) ||
@@ -5144,7 +5151,8 @@
 		} else if ((sscanf(m, "video %d/%d RTP/AVP %n", &x, &numberofports, &len) == 2) ||
 		    (sscanf(m, "video %d RTP/AVP %n", &x, &len) == 1)) {
 			/* If it is not audio - is it video ? */
-			ast_clear_flag(&p->flags[0], SIP_NOVIDEO);	
+			video = TRUE;
+			p->novideo = FALSE;
 			numberofmediastreams++;
 			vportno = x;
 			/* Scan through the RTP payload types specified in a "m=" line: */
@@ -6230,14 +6238,69 @@
 
 /*! \brief Add DTMF INFO tone to sip message */
 /* Always adds default duration 250 ms, regardless of what came in over the line */
-static int add_digit(struct sip_request *req, char digit, unsigned int duration)
+static int add_digit(struct sip_request *req, char digit, unsigned int duration, int mode)
 {
 	char tmp[256];
-
+	int event;
+	switch (mode){
+	case SIP_DTMF_INFO: //dtmf-relay
 	snprintf(tmp, sizeof(tmp), "Signal=%c\r\nDuration=%u\r\n", digit, duration);
 	add_header(req, "Content-Type", "application/dtmf-relay");
 	add_header_contentLength(req, strlen(tmp));
 	add_line(req, tmp);
+		break;
+	case SIP_DTMF_INFO2: // audio/telephone-event
+		switch(digit){
+		case '0': tmp[0]=0;break;
+		case '1': tmp[0]=1;break;
+		case '2': tmp[0]=2;break;
+		case '3': tmp[0]=3;break;
+		case '4': tmp[0]=4;break;
+		case '5': tmp[0]=5;break;
+		case '6': tmp[0]=6;break;
+		case '7': tmp[0]=7;break;
+		case '8': tmp[0]=8;break;
+		case '9': tmp[0]=9;break;
+		case '*': tmp[0]=10;break;
+		case '#': tmp[0]=11;break;
+		case 'A': tmp[0]=12;break;
+		case 'B': tmp[0]=13;break;
+		case 'C': tmp[0]=14;break;
+		case 'D': tmp[0]=15;break;
+		default:tmp[0]=16;
+		}
+		add_header(req, "Content-Type", "audio/telephone-event");
+		add_header_contentLength(req, 4);
+
+		if (!req->lines) {
+			/* Add extra empty return */
+			snprintf(req->data + req->len, sizeof(req->data) - req->len, "\r\n");
+			req->len += strlen(req->data + req->len);
+		}
+		req->line[req->lines] = req->data + req->len;
+		*req->line[req->lines] = tmp[0];
+		*(req->line[req->lines]+1) = 4;
+		*(req->line[req->lines]+2) = 0;
+		*(req->line[req->lines]+3) = 200; //Ignore duration and force it to 200ms.
+		
+		req->len += 4; 
+		req->lines++;	
+		break;
+	case SIP_DTMF_SHORTINFO: //application/dtmf 
+		if (digit == '*')
+			event = 10;
+		else if (digit == '#')
+			event = 11;
+		else if ((digit >= 'A') && (digit <= 'D'))
+			event = 12 + digit - 'A';
+		else
+			event = atoi(&digit);
+		snprintf(tmp, sizeof(tmp), "%d\r\n", event);
+		add_header(req, "Content-Type", "application/dtmf");
+		add_header_contentLength(req, strlen(tmp));
+		add_line(req, tmp);
+		break;
+	}
 	return 0;
 }
 
@@ -6537,7 +6600,7 @@
 
 	if (option_debug > 1) {
 		char codecbuf[SIPBUFSIZE];
-		ast_log(LOG_DEBUG, "** Our capability: %s Video flag: %s\n", ast_getformatname_multiple(codecbuf, sizeof(codecbuf), capability), ast_test_flag(&p->flags[0], SIP_NOVIDEO) ? "True" : "False");
+		ast_log(LOG_DEBUG, "** Our capability: %s Video flag: %s\n", ast_getformatname_multiple(codecbuf, sizeof(codecbuf), capability), p->novideo ? "True" : "False");
 		ast_log(LOG_DEBUG, "** Our prefcodec: %s \n", ast_getformatname_multiple(codecbuf, sizeof(codecbuf), p->prefcodec));
 	}
 	
@@ -6549,7 +6612,7 @@
 #endif
 
 	/* Check if we need video in this call */
-	if ((capability & AST_FORMAT_VIDEO_MASK) && !ast_test_flag(&p->flags[0], SIP_NOVIDEO)) {
+	if ((capability & AST_FORMAT_VIDEO_MASK) && !p->novideo) {
 		if (p->vrtp) {
 			needvideo = TRUE;
 			if (option_debug > 1)
@@ -7866,7 +7929,7 @@
 	struct sip_request req;
 
 	reqprep(&req, p, SIP_INFO, 0, 1);
-	add_digit(&req, digit, duration);
+	add_digit(&req, digit, duration, ast_test_flag(&p->flags[0], SIP_DTMF));
 	return send_request(p, &req, XMIT_RELIABLE, p->ocseq);
 }
 
@@ -10157,6 +10220,10 @@
 		return "rfc2833";
 	case SIP_DTMF_INFO:
 		return "info";
+	case SIP_DTMF_INFO2:
+		return "info_tel";		
+	case SIP_DTMF_SHORTINFO:
+		return "shortinfo";		
 	case SIP_DTMF_INBAND:
 		return "inband";
 	case SIP_DTMF_AUTO:
@@ -11223,6 +11290,112 @@
 	const char *c = get_header(req, "Content-Type");
 
 	/* Need to check the media/type */
+	if (!strcasecmp(c, "application/dtmf")){
+		unsigned int duration = 200;
+
+		/* Try getting the "signal=" part */
+		strcpy(buf, req->line[0]);
+		if (ast_strlen_zero(buf)){
+			ast_log(LOG_WARNING, "Unable to retrieve DTMF signal from INFO message from \n");
+			transmit_response(p, "200 OK", req); /* Should return error */
+			return;
+		} else {
+			event = atoi(buf);	
+		}
+	
+		if (!p->owner) {	/* not a PBX call */
+			transmit_response(p, "481 Call leg/transaction does not exist", req);
+			sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
+			return;
+		}
+
+		if (ast_strlen_zero(buf)) {
+			transmit_response(p, "200 OK", req);
+			return;
+		}
+
+		if (event == 16) {
+			/* send a FLASH event */
+			struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_FLASH, };
+			ast_queue_frame(p->owner, &f);
+			if (sipdebug)
+				ast_verbose("* dtmf event received: FLASH\n");
+		} else {
+			/* send a DTMF event */
+			struct ast_frame f = { AST_FRAME_DTMF, };
+			if (event < 10) {
+				f.subclass = '0' + event;
+			} else if (event < 11) {
+				f.subclass = '*';
+			} else if (event < 12) {
+				f.subclass = '#';
+			} else if (event < 16) {
+				f.subclass = 'A' + (event - 12);
+			}
+			f.len = duration;
+			ast_queue_frame(p->owner, &f);
+			if (sipdebug)
+				ast_verbose("* dtfm event received: %c\n", f.subclass);
+		}
+		transmit_response(p, "200 OK", req);
+		return;		
+
+	}else if (!strcasecmp(c, "audio/telephone-event")){
+		unsigned int duration = 200;
+		unsigned char xx=0;
+
+		/* Try getting the "signal=" part */
+		strcpy(buf, req->line[0]);
+		if (ast_strlen_zero(buf)){
+			ast_log(LOG_WARNING, "Unable to retrieve DTMF signal from INFO message from \n");
+			transmit_response(p, "200 OK", req); /* Should return error */
+			return;
+		} else {
+			event = (unsigned int) req->line[0][0];	
+			xx = (unsigned char) req->line[0][3];
+			duration = (unsigned int) xx;		
+		}
+	
+		if (!duration)
+			duration = 100; /* 100 ms */
+			
+		if (!p->owner) {	/* not a PBX call */
+			transmit_response(p, "481 Call leg/transaction does not exist", req);
+			sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
+			return;
+		}
+
+		if (ast_strlen_zero(buf)) {
+			transmit_response(p, "200 OK", req);
+			return;
+		}
+
+		if (event == 16) {
+			/* send a FLASH event */
+			struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_FLASH, };
+			ast_queue_frame(p->owner, &f);
+			if (sipdebug)
+				ast_verbose("* telephone-event received: FLASH\n");
+		} else {
+			/* send a DTMF event */
+			struct ast_frame f = { AST_FRAME_DTMF, };
+			if (event < 10) {
+				f.subclass = '0' + event;
+			} else if (event < 11) {
+				f.subclass = '*';
+			} else if (event < 12) {
+				f.subclass = '#';
+			} else if (event < 16) {
+				f.subclass = 'A' + (event - 12);
+			}
+			f.len = duration;
+			ast_queue_frame(p->owner, &f);
+			if (sipdebug)
+				ast_verbose("* telephone-event received: %c\n", f.subclass);
+		}
+		transmit_response(p, "200 OK", req);
+		return;		
+	}else 
 	if (!strcasecmp(c, "application/dtmf-relay") ||
 	    !strcasecmp(c, "application/vnd.nortelnetworks.digits")) {
 		unsigned int duration = 0;
@@ -16262,6 +16435,10 @@
 			ast_set_flag(&flags[0], SIP_DTMF_RFC2833);
 		else if (!strcasecmp(v->value, "info"))
 			ast_set_flag(&flags[0], SIP_DTMF_INFO);
+		else if (!strcasecmp(v->value, "info_tel"))
+			ast_set_flag(&flags[0], SIP_DTMF_INFO2);
+		else if (!strcasecmp(v->value, "shortinfo"))
+			ast_set_flag(&flags[0], SIP_DTMF_SHORTINFO);		
 		else if (!strcasecmp(v->value, "auto"))
 			ast_set_flag(&flags[0], SIP_DTMF_AUTO);
 		else {
@@ -17810,7 +17987,7 @@
 }
 
 static char *synopsis_dtmfmode = "Change the dtmfmode for a SIP call";
-static char *descrip_dtmfmode = "SIPDtmfMode(inband|info|rfc2833): Changes the dtmfmode for a SIP call\n";
+static char *descrip_dtmfmode = "SIPDtmfMode(inband|info|info_tel|shortinfo|rfc2833): Changes the dtmfmode for a SIP call\n";
 static char *app_dtmfmode = "SIPDtmfMode";
 
 static char *app_sipaddheader = "SIPAddHeader";
@@ -17852,6 +18029,14 @@
 		ast_clear_flag(&p->flags[0], SIP_DTMF);
 		ast_set_flag(&p->flags[0], SIP_DTMF_INFO);
 		p->jointnoncodeccapability &= ~AST_RTP_DTMF;
+	} else 	if (!strcasecmp(mode,"info_tel")) {
+		ast_clear_flag(&p->flags[0], SIP_DTMF);
+		ast_set_flag(&p->flags[0], SIP_DTMF_INFO2);
+		p->jointnoncodeccapability &= ~AST_RTP_DTMF;
+	} else 	if (!strcasecmp(mode,"shortinfo")) {
+		ast_clear_flag(&p->flags[0], SIP_DTMF);
+		ast_set_flag(&p->flags[0], SIP_DTMF_SHORTINFO);
+		p->jointnoncodeccapability &= ~AST_RTP_DTMF;			
 	} else if (!strcasecmp(mode,"rfc2833")) {
 		ast_clear_flag(&p->flags[0], SIP_DTMF);
 		ast_set_flag(&p->flags[0], SIP_DTMF_RFC2833);
