From 1d6b192ce0262db43b91bf736f15cd2d7f39082a Mon Sep 17 00:00:00 2001
From: Olle Johansson <oej@edvina.net>
Date: Wed, 19 Dec 2007 08:57:45 +0000
Subject: [PATCH] Adding the ability to specify the To: header in an outbound
 INVITE by adding an exclamation mark to the dial string.

This patch also exists for 1.4 in the fixtoheader-1.4 branch
and has been in production for quite some time.



git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@93897 65c4cc65-6c06-0410-ace0-fbb531ad65f3
---
 CHANGES                 |  2 ++
 channels/chan_sip.c     | 61 +++++++++++++++++++++++++++++++++--------
 configs/sip.conf.sample | 42 ++++++++++++++++++++--------
 3 files changed, 83 insertions(+), 22 deletions(-)

diff --git a/CHANGES b/CHANGES
index 91a6c3f3b6..0ccb9a0cbe 100644
--- a/CHANGES
+++ b/CHANGES
@@ -109,6 +109,8 @@ SIP changes
   * New settings for timer T1 and timer B on a global level or per device. This makes it 
     possible to force timeout faster on non-responsive SIP servers. These settings are
     considered advanced, so don't use them unless you have a problem.
+  * Added a dial string option to be able to set the To: header in an INVITE to any
+    SIP uri.
 
 IAX2 changes
 ------------
diff --git a/channels/chan_sip.c b/channels/chan_sip.c
index 023922fea1..96076ac20d 100644
--- a/channels/chan_sip.c
+++ b/channels/chan_sip.c
@@ -1053,6 +1053,7 @@ struct sip_pvt {
 		AST_STRING_FIELD(fromuser);	/*!< User to show in the user field */
 		AST_STRING_FIELD(fromname);	/*!< Name to show in the user field */
 		AST_STRING_FIELD(tohost);	/*!< Host we should put in the "to" field */
+		AST_STRING_FIELD(todnid);	/*!< DNID of this call (overrides host) */
 		AST_STRING_FIELD(language);	/*!< Default language for this call */
 		AST_STRING_FIELD(mohinterpret);	/*!< MOH class to use when put on hold */
 		AST_STRING_FIELD(mohsuggest);	/*!< MOH class to suggest when putting a peer on hold */
@@ -7839,17 +7840,30 @@ static void initreqprep(struct sip_request *req, struct sip_pvt *p, int sipmetho
 	if (p->options && p->options->uri_options)
 		ast_str_append(&invite, 0, ";%s", p->options->uri_options);
 	
+ 	/* This is the request URI, which is the next hop of the call
+ 		which may or may not be the destination of the call
+ 	*/
 	ast_string_field_set(p, uri, invite->str);
+  
+ 	if (!ast_strlen_zero(p->todnid)) {
+ 		/*! \todo Need to add back the VXML URL here at some point, possibly use build_string for all this junk */
+ 		if (!strchr(p->todnid, '@')) {
+ 			/* We have no domain in the dnid */
+ 			snprintf(to, sizeof(to), "<sip:%s@%s>%s%s", p->todnid, p->tohost, ast_strlen_zero(p->theirtag) ? "" : ";tag=", p->theirtag);
+ 		} else {
+ 			snprintf(to, sizeof(to), "<sip:%s>%s%s", p->todnid, ast_strlen_zero(p->theirtag) ? "" : ";tag=", p->theirtag);
+ 		}
+ 	} else {
+ 		if (sipmethod == SIP_NOTIFY && !ast_strlen_zero(p->theirtag)) { 
+ 			/* If this is a NOTIFY, use the From: tag in the subscribe (RFC 3265) */
+			snprintf(to, sizeof(to), "<%s%s>;tag=%s", (strncasecmp(p->uri, "sip:", 4) ? "" : "sip:"), p->uri, p->theirtag);
+ 		} else if (p->options && p->options->vxml_url) {
+ 			/* If there is a VXML URL append it to the SIP URL */
+ 			snprintf(to, sizeof(to), "<%s>;%s", p->uri, p->options->vxml_url);
+ 		} else 
+ 			snprintf(to, sizeof(to), "<%s>", p->uri);
+ 	}
 
-	if (sipmethod == SIP_NOTIFY && !ast_strlen_zero(p->theirtag)) { 
-		/* If this is a NOTIFY, use the From: tag in the subscribe (RFC 3265) */
-		snprintf(to, sizeof(to), "<%s%s>;tag=%s", (strncasecmp(p->uri, "sip:", 4) ? "" : "sip:"), p->uri, p->theirtag);
-	} else if (p->options && p->options->vxml_url) {
-		/* If there is a VXML URL append it to the SIP URL */
-		snprintf(to, sizeof(to), "<%s>;%s", p->uri, p->options->vxml_url);
-	} else 
-		snprintf(to, sizeof(to), "<%s>", p->uri);
-	
 	init_req(req, sipmethod, p->uri);
 	/* now tmp_n is available so reuse it to build the CSeq */
 	snprintf(tmp_n, sizeof(tmp_n), "%d %s", ++p->ocseq, sip_methods[sipmethod].text);
@@ -7858,6 +7872,7 @@ static void initreqprep(struct sip_request *req, struct sip_pvt *p, int sipmetho
 	add_header(req, "Max-Forwards", DEFAULT_MAX_FORWARDS);
 	/* SLD: FIXME?: do Route: here too?  I think not cos this is the first request.
 	 * OTOH, then we won't have anything in p->route anyway */
+
 	/* Build Remote Party-ID and From */
 	if (ast_test_flag(&p->flags[0], SIP_SENDRPID) && (sipmethod == SIP_INVITE)) {
 		build_rpid(p);
@@ -17304,7 +17319,13 @@ static int sip_devicestate(void *data)
 }
 
 /*! \brief PBX interface function -build SIP pvt structure 
-	SIP calls initiated by the PBX arrive here */
+	SIP calls initiated by the PBX arrive here 
+
+	SIP Dial string syntax
+		SIP/exten@host!dnid
+	or	SIP/host/exten!dnid
+	or	SIP/host!dnid
+*/
 static struct ast_channel *sip_request_call(const char *type, int format, void *data, int *cause)
 {
 	struct sip_pvt *p;
@@ -17312,6 +17333,7 @@ static struct ast_channel *sip_request_call(const char *type, int format, void *
 	char *ext, *host;
 	char tmp[256];
 	char *dest = data;
+	char *dnid;
 	int oldformat = format;
 
 	/* mask request with some set of allowed formats.
@@ -17344,7 +17366,18 @@ static struct ast_channel *sip_request_call(const char *type, int format, void *
 		return NULL;
 	}
 
+	/* Save the destination, the SIP dial string */
 	ast_copy_string(tmp, dest, sizeof(tmp));
+
+
+	/* Find DNID and take it away */
+	dnid = strchr(tmp, '!');
+	if (dnid != NULL) {
+		*dnid++ = '\0';
+		ast_string_field_set(p, todnid, dnid);
+	}
+
+	/* Find at sign - @ */
 	host = strchr(tmp, '@');
 	if (host) {
 		*host++ = '\0';
@@ -17356,6 +17389,11 @@ static struct ast_channel *sip_request_call(const char *type, int format, void *
 		host = tmp;
 	}
 
+	/* We now have 
+		host = peer name, DNS host name or DNS domain (for SRV) 
+		ext = extension (user part of URI)
+		dnid = destination of the call (applies to the To: header)
+	*/
 	if (create_addr(p, host)) {
 		*cause = AST_CAUSE_UNREGISTERED;
 		ast_debug(3, "Cant create SIP call - target device not registred\n");
@@ -17372,7 +17410,8 @@ static struct ast_channel *sip_request_call(const char *type, int format, void *
 	/* We have an extension to call, don't use the full contact here */
 	/* This to enable dialing registered peers with extension dialling,
 	   like SIP/peername/extension 	
-	   SIP/peername will still use the full contact */
+	   SIP/peername will still use the full contact 
+	 */
 	if (ext) {
 		ast_string_field_set(p, username, ext);
 		ast_string_field_set(p, fullcontact, NULL);
diff --git a/configs/sip.conf.sample b/configs/sip.conf.sample
index d8e25e6421..78ed4806f6 100644
--- a/configs/sip.conf.sample
+++ b/configs/sip.conf.sample
@@ -1,17 +1,37 @@
 ;
 ; SIP Configuration example for Asterisk
 ;
-; Syntax for specifying a SIP device in extensions.conf is
-; SIP/devicename where devicename is defined in a section below.
-;
-; You may also use 
-; SIP/username@domain to call any SIP user on the Internet
-; (Don't forget to enable DNS SRV records if you want to use this)
-; 
-; If you define a SIP proxy as a peer below, you may call
-; SIP/proxyhostname/user or SIP/user@proxyhostname 
-; where the proxyhostname is defined in a section below 
+; SIP dial strings
+;-----------------------------------------------------------
+; In the dialplan (extensions.conf) you can use several 
+; syntaxes for dialing SIP devices.
+;	SIP/devicename
+;	SIP/username@domain   (SIP uri)
+;	SIP/username@host:port
+;	SIP/devicename/extension
+;
+;
+; Devicename
+;      devicename is defined as a peer in a section below.
+;
+; username@domain
+; 	Call any SIP user on the Internet
+;	(Don't forget to enable DNS SRV records if you want to use this)
 ; 
+; devicename/extension
+; 	If you define a SIP proxy as a peer below, you may call
+; 	SIP/proxyhostname/user or SIP/user@proxyhostname 
+; 	where the proxyhostname is defined in a section below 
+;	This syntax also works with ATA's with FXO ports
+;
+; All of these dial strings specify the SIP request URI.
+; In addition, you can specify a specific To: header by adding an
+; exclamation mark after the dial string, like
+;
+; 	SIP/sales@mysipproxy!sales@edvina.net
+;
+; CLI Commands
+; -------------------------------------------------------------
 ; Useful CLI commands to check peers/users:
 ;   sip show peers		Show all SIP peers (including friends)
 ;   sip show users		Show all SIP users (including friends)
@@ -23,7 +43,7 @@
 ;				Active SIP peers will not be reconfigured
 ;
 
-; ** Deprecated options **
+; ** Deprecated configuration options **
 ; The "call-limit" configuation option is deprecated. It still works in
 ; this version of Asterisk, but will disappear in the next version.
 ; You are encouraged to use the dialplan groupcount functionality
-- 
GitLab