<p>N A has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.asterisk.org/c/asterisk/+/16569">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">chan_sip: Add custom SIP tag capabilities<br><br>Some SIP environments require the addition of custom<br>SIP tags into certain headers (e.g. From) and also<br>require placement either before or after the "tag"<br>tag. This is especially common with SS7 trunking<br>over SIP.<br><br>This adds the ability to add custom tags to headers,<br>read tags from headers, and define the placement<br>of custom-injected tags within the From header, since<br>many carriers require that they be inside the closing<br>angle bracket.<br><br>Also adds built-in support for the outgoing OLI tag,<br>disabled by default.<br><br>ASTERISK-29681 #close<br><br>Change-Id: I1e99a220295c03275827050147622a6c1f5a4be9<br>---<br>M channels/chan_sip.c<br>M channels/sip/include/sip.h<br>M configs/samples/sip.conf.sample<br>3 files changed, 286 insertions(+), 2 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.asterisk.org:29418/asterisk refs/changes/69/16569/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/channels/chan_sip.c b/channels/chan_sip.c</span><br><span>index 23b8fa6..97f367a 100644</span><br><span>--- a/channels/chan_sip.c</span><br><span>+++ b/channels/chan_sip.c</span><br><span>@@ -311,6 +311,21 @@</span><br><span> <para>Changes the dtmfmode for a SIP call.</para></span><br><span> </description></span><br><span> </application></span><br><span style="color: hsl(120, 100%, 40%);">+ <application name="SIPAddTag" language="en_US"></span><br><span style="color: hsl(120, 100%, 40%);">+ <synopsis></span><br><span style="color: hsl(120, 100%, 40%);">+ Add a SIP tag to the From header in the outbound call.</span><br><span style="color: hsl(120, 100%, 40%);">+ </synopsis></span><br><span style="color: hsl(120, 100%, 40%);">+ <syntax argsep=":"></span><br><span style="color: hsl(120, 100%, 40%);">+ <parameter name="Tag" required="true" /></span><br><span style="color: hsl(120, 100%, 40%);">+ <parameter name="Content" required="true" /></span><br><span style="color: hsl(120, 100%, 40%);">+ </syntax></span><br><span style="color: hsl(120, 100%, 40%);">+ <description></span><br><span style="color: hsl(120, 100%, 40%);">+ <para>Adds a tag to a SIP call placed with DIAL.</para></span><br><span style="color: hsl(120, 100%, 40%);">+ <para>Use this with care. Adding the wrong tags may</span><br><span style="color: hsl(120, 100%, 40%);">+ jeopardize the SIP dialog.</para></span><br><span style="color: hsl(120, 100%, 40%);">+ <para>Always returns <literal>0</literal>.</para></span><br><span style="color: hsl(120, 100%, 40%);">+ </description></span><br><span style="color: hsl(120, 100%, 40%);">+ </application></span><br><span> <application name="SIPAddHeader" language="en_US"></span><br><span> <synopsis></span><br><span> Add a SIP header to the outbound call.</span><br><span>@@ -367,6 +382,42 @@</span><br><span> application is only available if TEST_FRAMEWORK is defined.</para></span><br><span> </description></span><br><span> </application></span><br><span style="color: hsl(120, 100%, 40%);">+ <function name="SIP_TAG" language="en_US"></span><br><span style="color: hsl(120, 100%, 40%);">+ <synopsis></span><br><span style="color: hsl(120, 100%, 40%);">+ Gets the specified SIP tag from the specified SIP header from an incoming INVITE message.</span><br><span style="color: hsl(120, 100%, 40%);">+ </synopsis></span><br><span style="color: hsl(120, 100%, 40%);">+ <syntax></span><br><span style="color: hsl(120, 100%, 40%);">+ <parameter name="tag" required="true" /></span><br><span style="color: hsl(120, 100%, 40%);">+ <parameter name="name" required="true" /></span><br><span style="color: hsl(120, 100%, 40%);">+ <parameter name="number"></span><br><span style="color: hsl(120, 100%, 40%);">+ <para>If not specified, defaults to <literal>1</literal>.</para></span><br><span style="color: hsl(120, 100%, 40%);">+ </parameter></span><br><span style="color: hsl(120, 100%, 40%);">+ </syntax></span><br><span style="color: hsl(120, 100%, 40%);">+ <description></span><br><span style="color: hsl(120, 100%, 40%);">+ <para>This function returns the value of a SIP tag in a specified header.</para></span><br><span style="color: hsl(120, 100%, 40%);">+ <para>Since there are several headers (such as Via) which can occur multiple</span><br><span style="color: hsl(120, 100%, 40%);">+ times, SIP_HEADER takes an optional second argument to specify which header with</span><br><span style="color: hsl(120, 100%, 40%);">+ that name to retrieve. Headers start at offset <literal>1</literal>.</para></span><br><span style="color: hsl(120, 100%, 40%);">+ <para>This function does not access headers from the REFER message if the call</span><br><span style="color: hsl(120, 100%, 40%);">+ was transferred. To obtain the REFER headers, set the dialplan variable</span><br><span style="color: hsl(120, 100%, 40%);">+ <variable>GET_TRANSFERRER_DATA</variable> to the prefix of the headers of the</span><br><span style="color: hsl(120, 100%, 40%);">+ REFER message that you need to access; for example, <literal>X-</literal> to</span><br><span style="color: hsl(120, 100%, 40%);">+ get all headers starting with <literal>X-</literal>. The variable must be set</span><br><span style="color: hsl(120, 100%, 40%);">+ before a call to the application that starts the channel that may eventually</span><br><span style="color: hsl(120, 100%, 40%);">+ transfer back into the dialplan, and must be inherited by that channel, so prefix</span><br><span style="color: hsl(120, 100%, 40%);">+ it with the <literal>_</literal> or <literal>__</literal> when setting (or</span><br><span style="color: hsl(120, 100%, 40%);">+ set it in the pre-dial handler executed on the new channel). To get all headers</span><br><span style="color: hsl(120, 100%, 40%);">+ of the REFER message, set the value to <literal>*</literal>. Headers</span><br><span style="color: hsl(120, 100%, 40%);">+ are returned in the form of a dialplan hash TRANSFER_DATA, and can be accessed</span><br><span style="color: hsl(120, 100%, 40%);">+ with the functions <variable>HASHKEYS(TRANSFER_DATA)</variable> and, e. g.,</span><br><span style="color: hsl(120, 100%, 40%);">+ <variable>HASH(TRANSFER_DATA,X-That-Special-Header)</variable>.</para></span><br><span style="color: hsl(120, 100%, 40%);">+ <para>Please also note that contents of the SDP (an attachment to the</span><br><span style="color: hsl(120, 100%, 40%);">+ SIP request) can't be accessed with this function.</para></span><br><span style="color: hsl(120, 100%, 40%);">+ </description></span><br><span style="color: hsl(120, 100%, 40%);">+ <see-also></span><br><span style="color: hsl(120, 100%, 40%);">+ <ref type="function">SIP_HEADERS</ref></span><br><span style="color: hsl(120, 100%, 40%);">+ </see-also></span><br><span style="color: hsl(120, 100%, 40%);">+ </function></span><br><span> <function name="SIP_HEADER" language="en_US"></span><br><span> <synopsis></span><br><span> Gets the specified SIP header from an incoming INVITE message.</span><br><span>@@ -1384,6 +1435,7 @@</span><br><span> static char *sip_cli_notify(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);</span><br><span> static char *sip_set_history(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);</span><br><span> static int sip_dtmfmode(struct ast_channel *chan, const char *data);</span><br><span style="color: hsl(120, 100%, 40%);">+static int sip_addtag(struct ast_channel *chan, const char *data);</span><br><span> static int sip_addheader(struct ast_channel *chan, const char *data);</span><br><span> static int sip_do_reload(enum channelreloadreason reason);</span><br><span> static char *sip_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);</span><br><span>@@ -6484,6 +6536,9 @@</span><br><span> } else if (!p->options->addsipheaders && !strncmp(ast_var_name(current), "SIPADDHEADER", strlen("SIPADDHEADER"))) {</span><br><span> /* Check whether there is a variable with a name starting with SIPADDHEADER */</span><br><span> p->options->addsipheaders = 1;</span><br><span style="color: hsl(120, 100%, 40%);">+ } else if (!p->options->addsiptags && !strncmp(ast_var_name(current), "SIPADDTAG", strlen("SIPADDTAG"))) {</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Check whether there is a variable with a name starting with SIPADDTAG */</span><br><span style="color: hsl(120, 100%, 40%);">+ p->options->addsiptags = 1;</span><br><span> } else if (!strcmp(ast_var_name(current), "SIPFROMDOMAIN")) {</span><br><span> ast_string_field_set(p, fromdomain, ast_var_value(current));</span><br><span> } else if (!strcmp(ast_var_name(current), "SIPTRANSFER")) {</span><br><span>@@ -14518,9 +14573,85 @@</span><br><span> ourport = (p->fromdomainport && (p->fromdomainport != STANDARD_SIP_PORT)) ? p->fromdomainport : ast_sockaddr_port(&p->ourip);</span><br><span> </span><br><span> if (!sip_standard_port(p->socket.type, ourport)) {</span><br><span style="color: hsl(0, 100%, 40%);">- ret = ast_str_set(&from, 0, "<sip:%s@%s:%d>;tag=%s", tmp_l, d, ourport, p->tag);</span><br><span style="color: hsl(120, 100%, 40%);">+ ret = ast_str_set(&from, 0, "<sip:%s@%s:%d", tmp_l, d, ourport);</span><br><span> } else {</span><br><span style="color: hsl(0, 100%, 40%);">- ret = ast_str_set(&from, 0, "<sip:%s@%s>;tag=%s", tmp_l, d, p->tag);</span><br><span style="color: hsl(120, 100%, 40%);">+ ret = ast_str_set(&from, 0, "<sip:%s@%s", tmp_l, d);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (ret != AST_DYNSTR_BUILD_FAILED) {</span><br><span style="color: hsl(120, 100%, 40%);">+ /* The normal way is <sip:NUMBER@IP>;tag=SOMETHING;isup-oli=0;noa=1 (draft-haluska-dispatch-isup-oli-01)</span><br><span style="color: hsl(120, 100%, 40%);">+ * Some carriers/Sonus/Genband/SS7 use <sip:NUMBER@IP;isup-oli=OLI;noa=1>;tag=SOMETHING instead (SIP-I/T)</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!sip_cfg.from_tags_inside) {</span><br><span style="color: hsl(120, 100%, 40%);">+ /* typically, tag should come before custom tags, but if we're doing it carrier-style, it still comes last */</span><br><span style="color: hsl(120, 100%, 40%);">+ ret = ast_str_append(&from, 0, ">;tag=%s", p->tag);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Add custom tags now */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (ret != AST_DYNSTR_BUILD_FAILED && p->owner && sip_cfg.send_oli) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_debug(3, "Detected ANI2/OLI %d on channel %s\n", ast_channel_caller(p->owner)->ani2, ast_channel_name(p->owner));</span><br><span style="color: hsl(120, 100%, 40%);">+ ret = ast_str_append(&from, 0, ";isup-oli=%d", ast_channel_caller(p->owner)->ani2);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ if (ret != AST_DYNSTR_BUILD_FAILED && p->owner && p->options && p->options->addsiptags) {</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_channel *chan = p->owner; /* The owner channel */</span><br><span style="color: hsl(120, 100%, 40%);">+ struct varshead *headp;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_channel_lock(chan);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ headp = ast_channel_varshead(chan);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!headp) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_log(LOG_WARNING, "No Headp for the channel...ooops!\n");</span><br><span style="color: hsl(120, 100%, 40%);">+ } else {</span><br><span style="color: hsl(120, 100%, 40%);">+ const struct ast_var_t *current;</span><br><span style="color: hsl(120, 100%, 40%);">+ AST_LIST_TRAVERSE(headp, current, entries) {</span><br><span style="color: hsl(120, 100%, 40%);">+ /* SIPADDTAG: Add SIP tag to From header in outgoing call */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!strncmp(ast_var_name(current), "SIPADDTAG", strlen("SIPADDTAG"))) {</span><br><span style="color: hsl(120, 100%, 40%);">+ char *content, *end;</span><br><span style="color: hsl(120, 100%, 40%);">+ const char *tag = ast_var_value(current);</span><br><span style="color: hsl(120, 100%, 40%);">+ char *headdup = ast_malloc(sizeof(tag));</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!headdup) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_log(LOG_ERROR, "Couldn't allocate tag\n");</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_copy_string(headdup, tag, strlen(tag) + 1);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Strip off the starting " (if it's there) */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (*headdup == '"') {</span><br><span style="color: hsl(120, 100%, 40%);">+ headdup++;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ if ((content = strchr(headdup, ':'))) {</span><br><span style="color: hsl(120, 100%, 40%);">+ *content = '\0';</span><br><span style="color: hsl(120, 100%, 40%);">+ content++;</span><br><span style="color: hsl(120, 100%, 40%);">+ content = ast_skip_blanks(content); /* Skip white space */</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Strip the ending " (if it's there) */</span><br><span style="color: hsl(120, 100%, 40%);">+ end = content + strlen(content) -1;</span><br><span style="color: hsl(120, 100%, 40%);">+ if (*end == '"') {</span><br><span style="color: hsl(120, 100%, 40%);">+ *end = '\0';</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ if (sipdebug) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_debug(3, "Adding SIP tag \"%s\" to %s header with content: %s\n", headdup, "From", content);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ ret = ast_str_append(&from, 0, ";%s=%s", headdup, content);</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_free(headdup);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (ret == AST_DYNSTR_BUILD_FAILED) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_log(LOG_WARNING, "Appending failed, aborting custom SIP tags\n");</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ } else {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_debug(1, "Nothing to do for tag %s\n", headdup);</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_free(headdup);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_channel_unlock(chan);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Now, finish it off, if needed */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (ret != AST_DYNSTR_BUILD_FAILED && sip_cfg.from_tags_inside) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ret = ast_str_append(&from, 0, ">;tag=%s", p->tag);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span> }</span><br><span> if (ret == AST_DYNSTR_BUILD_FAILED) {</span><br><span> /* We don't have an escape path from here... */</span><br><span>@@ -21936,6 +22067,8 @@</span><br><span> ast_cli(a->fd, " Send RPID: %s\n", AST_CLI_YESNO(ast_test_flag(&global_flags[0], SIP_SENDRPID)));</span><br><span> ast_cli(a->fd, " Legacy userfield parse: %s\n", AST_CLI_YESNO(sip_cfg.legacy_useroption_parsing));</span><br><span> ast_cli(a->fd, " Send Diversion: %s\n", AST_CLI_YESNO(sip_cfg.send_diversion));</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_cli(a->fd, " Send OLI: %s\n", AST_CLI_YESNO(sip_cfg.send_oli));</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_cli(a->fd, " From Tags Inside: %s\n", AST_CLI_YESNO(sip_cfg.from_tags_inside));</span><br><span> ast_cli(a->fd, " Caller ID: %s\n", default_callerid);</span><br><span> if ((default_fromdomainport) && (default_fromdomainport != STANDARD_SIP_PORT)) {</span><br><span> ast_cli(a->fd, " From: Domain: %s:%d\n", default_fromdomain, default_fromdomainport);</span><br><span>@@ -23246,6 +23379,93 @@</span><br><span> return 0;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+/*! \brief Read SIP tags from header (dialplan function) */</span><br><span style="color: hsl(120, 100%, 40%);">+static int func_tag_read(struct ast_channel *chan, const char *function, char *data, char *buf, size_t len)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct sip_pvt *p;</span><br><span style="color: hsl(120, 100%, 40%);">+ const char *content = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ char *mutable_data = ast_strdupa(data);</span><br><span style="color: hsl(120, 100%, 40%);">+ AST_DECLARE_APP_ARGS(args,</span><br><span style="color: hsl(120, 100%, 40%);">+ AST_APP_ARG(tag);</span><br><span style="color: hsl(120, 100%, 40%);">+ AST_APP_ARG(header);</span><br><span style="color: hsl(120, 100%, 40%);">+ AST_APP_ARG(number);</span><br><span style="color: hsl(120, 100%, 40%);">+ );</span><br><span style="color: hsl(120, 100%, 40%);">+ int i, number, start = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ char *tagname = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ char *tagfull = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ char *tagvalue = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!chan) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_log(LOG_WARNING, "No channel was provided to %s function.\n", function);</span><br><span style="color: hsl(120, 100%, 40%);">+ return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (ast_strlen_zero(data)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_log(LOG_WARNING, "This function requires a header name.\n");</span><br><span style="color: hsl(120, 100%, 40%);">+ return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_channel_lock(chan);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!IS_SIP_TECH(ast_channel_tech(chan))) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_log(LOG_WARNING, "This function can only be used on SIP channels.\n");</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_channel_unlock(chan);</span><br><span style="color: hsl(120, 100%, 40%);">+ return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ AST_STANDARD_APP_ARGS(args, mutable_data);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!args.number) {</span><br><span style="color: hsl(120, 100%, 40%);">+ number = 1;</span><br><span style="color: hsl(120, 100%, 40%);">+ } else {</span><br><span style="color: hsl(120, 100%, 40%);">+ sscanf(args.number, "%30d", &number);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (number < 1)</span><br><span style="color: hsl(120, 100%, 40%);">+ number = 1;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ p = ast_channel_tech_pvt(chan);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* If there is no private structure, this channel is no longer alive */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!p) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_channel_unlock(chan);</span><br><span style="color: hsl(120, 100%, 40%);">+ return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ for (i = 0; i < number; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+ content = __get_header(&p->initreq, args.header, &start);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (ast_strlen_zero(content)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_channel_unlock(chan);</span><br><span style="color: hsl(120, 100%, 40%);">+ return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ tagname = ast_strdupa(args.tag);</span><br><span style="color: hsl(120, 100%, 40%);">+ tagfull = ast_strdupa(content);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* discard the first match, because it's not a tag. */</span><br><span style="color: hsl(120, 100%, 40%);">+ tagvalue = strsep(&tagfull, ";");</span><br><span style="color: hsl(120, 100%, 40%);">+ while (tagvalue && (tagvalue = strsep(&tagfull, ";"))) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_debug(3, "%s: Looking for %s, found: %s\n", function, tagname, tagvalue);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!strncmp(tagname, tagvalue, strlen(tagname))) {</span><br><span style="color: hsl(120, 100%, 40%);">+ /* we found our tag */</span><br><span style="color: hsl(120, 100%, 40%);">+ const char *result = strchr(tagvalue, '=') + 1;</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!result) {</span><br><span style="color: hsl(120, 100%, 40%);">+ continue;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_copy_string(buf, result, len);</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_channel_unlock(chan);</span><br><span style="color: hsl(120, 100%, 40%);">+ return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_channel_unlock(chan);</span><br><span style="color: hsl(120, 100%, 40%);">+ return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static struct ast_custom_function sip_tag_function = {</span><br><span style="color: hsl(120, 100%, 40%);">+ .name = "SIP_TAG",</span><br><span style="color: hsl(120, 100%, 40%);">+ .read = func_tag_read,</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /*! \brief Read SIP header (dialplan function) */</span><br><span> static int func_header_read(struct ast_channel *chan, const char *function, char *data, char *buf, size_t len)</span><br><span> {</span><br><span>@@ -32669,6 +32889,8 @@</span><br><span> sip_cfg.regextenonqualify = DEFAULT_REGEXTENONQUALIFY;</span><br><span> sip_cfg.legacy_useroption_parsing = DEFAULT_LEGACY_USEROPTION_PARSING;</span><br><span> sip_cfg.send_diversion = DEFAULT_SEND_DIVERSION;</span><br><span style="color: hsl(120, 100%, 40%);">+ sip_cfg.send_oli = DEFAULT_SEND_OLI;</span><br><span style="color: hsl(120, 100%, 40%);">+ sip_cfg.from_tags_inside = DEFAULT_FROM_TAGS_INSIDE;</span><br><span> sip_cfg.notifyringing = DEFAULT_NOTIFYRINGING;</span><br><span> sip_cfg.notifycid = DEFAULT_NOTIFYCID;</span><br><span> sip_cfg.notifyhold = FALSE; /*!< Keep track of hold status for a peer */</span><br><span>@@ -32996,6 +33218,10 @@</span><br><span> sip_cfg.legacy_useroption_parsing = ast_true(v->value);</span><br><span> } else if (!strcasecmp(v->name, "send_diversion")) {</span><br><span> sip_cfg.send_diversion = ast_true(v->value);</span><br><span style="color: hsl(120, 100%, 40%);">+ } else if (!strcasecmp(v->name, "send_oli")) {</span><br><span style="color: hsl(120, 100%, 40%);">+ sip_cfg.send_oli = ast_true(v->value);</span><br><span style="color: hsl(120, 100%, 40%);">+ } else if (!strcasecmp(v->name, "from_tags_inside")) {</span><br><span style="color: hsl(120, 100%, 40%);">+ sip_cfg.from_tags_inside = ast_true(v->value);</span><br><span> } else if (!strcasecmp(v->name, "callerid")) {</span><br><span> ast_copy_string(default_callerid, v->value, sizeof(default_callerid));</span><br><span> } else if (!strcasecmp(v->name, "mwi_from")) {</span><br><span>@@ -34018,6 +34244,7 @@</span><br><span> };</span><br><span> </span><br><span> static char *app_dtmfmode = "SIPDtmfMode";</span><br><span style="color: hsl(120, 100%, 40%);">+static char *app_sipaddtag = "SIPAddTag";</span><br><span> static char *app_sipaddheader = "SIPAddHeader";</span><br><span> static char *app_sipremoveheader = "SIPRemoveHeader";</span><br><span> #ifdef TEST_FRAMEWORK</span><br><span>@@ -34078,6 +34305,46 @@</span><br><span> return 0;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+/*! \brief Add a SIP tag to the From header in an outbound INVITE */</span><br><span style="color: hsl(120, 100%, 40%);">+static int sip_addtag(struct ast_channel *chan, const char *data)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ int no = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ int ok = FALSE;</span><br><span style="color: hsl(120, 100%, 40%);">+ char varbuf[30];</span><br><span style="color: hsl(120, 100%, 40%);">+ const char *inbuf = data;</span><br><span style="color: hsl(120, 100%, 40%);">+ char *subbuf;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (ast_strlen_zero(inbuf)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_log(LOG_WARNING, "This application requires the argument: Tag\n");</span><br><span style="color: hsl(120, 100%, 40%);">+ return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_channel_lock(chan);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Check for headers */</span><br><span style="color: hsl(120, 100%, 40%);">+ while (!ok && no <= 99) {</span><br><span style="color: hsl(120, 100%, 40%);">+ no++;</span><br><span style="color: hsl(120, 100%, 40%);">+ snprintf(varbuf, sizeof(varbuf), "__SIPADDTAG%.2d", no);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Compare without the leading underscores */</span><br><span style="color: hsl(120, 100%, 40%);">+ if ((pbx_builtin_getvar_helper(chan, (const char *) varbuf + 2) == (const char *) NULL)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ok = TRUE;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ if (ok) {</span><br><span style="color: hsl(120, 100%, 40%);">+ size_t len = strlen(inbuf);</span><br><span style="color: hsl(120, 100%, 40%);">+ subbuf = ast_alloca(len + 1);</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_get_encoded_str(inbuf, subbuf, len + 1);</span><br><span style="color: hsl(120, 100%, 40%);">+ pbx_builtin_setvar_helper(chan, varbuf, subbuf);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (sipdebug) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_debug(1, "SIP Tag added \"%s\" as %s\n", inbuf, varbuf);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ } else {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_log(LOG_WARNING, "Too many SIP tags added, max 150\n");</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_channel_unlock(chan);</span><br><span style="color: hsl(120, 100%, 40%);">+ return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /*! \brief Add a SIP header to an outbound INVITE */</span><br><span> static int sip_addheader(struct ast_channel *chan, const char *data)</span><br><span> {</span><br><span>@@ -35618,6 +35885,7 @@</span><br><span> </span><br><span> /* Register dialplan applications */</span><br><span> ast_register_application_xml(app_dtmfmode, sip_dtmfmode);</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_register_application_xml(app_sipaddtag, sip_addtag);</span><br><span> ast_register_application_xml(app_sipaddheader, sip_addheader);</span><br><span> ast_register_application_xml(app_sipremoveheader, sip_removeheader);</span><br><span> #ifdef TEST_FRAMEWORK</span><br><span>@@ -35625,6 +35893,7 @@</span><br><span> #endif</span><br><span> </span><br><span> /* Register dialplan functions */</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_custom_function_register(&sip_tag_function);</span><br><span> ast_custom_function_register(&sip_header_function);</span><br><span> ast_custom_function_register(&sip_headers_function);</span><br><span> ast_custom_function_register(&sippeer_function);</span><br><span>@@ -35737,10 +36006,12 @@</span><br><span> ast_custom_function_unregister(&sippeer_function);</span><br><span> ast_custom_function_unregister(&sip_headers_function);</span><br><span> ast_custom_function_unregister(&sip_header_function);</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_custom_function_unregister(&sip_tag_function);</span><br><span> ast_custom_function_unregister(&checksipdomain_function);</span><br><span> </span><br><span> /* Unregister dial plan applications */</span><br><span> ast_unregister_application(app_dtmfmode);</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_unregister_application(app_sipaddtag);</span><br><span> ast_unregister_application(app_sipaddheader);</span><br><span> ast_unregister_application(app_sipremoveheader);</span><br><span> #ifdef TEST_FRAMEWORK</span><br><span>diff --git a/channels/sip/include/sip.h b/channels/sip/include/sip.h</span><br><span>index 18db352..a9116e2 100644</span><br><span>--- a/channels/sip/include/sip.h</span><br><span>+++ b/channels/sip/include/sip.h</span><br><span>@@ -226,6 +226,8 @@</span><br><span> #define DEFAULT_REGEXTENONQUALIFY FALSE</span><br><span> #define DEFAULT_LEGACY_USEROPTION_PARSING FALSE</span><br><span> #define DEFAULT_SEND_DIVERSION TRUE</span><br><span style="color: hsl(120, 100%, 40%);">+#define DEFAULT_SEND_OLI FALSE</span><br><span style="color: hsl(120, 100%, 40%);">+#define DEFAULT_FROM_TAGS_INSIDE FALSE</span><br><span> #define DEFAULT_T1MIN 100 /*!< 100 MS for minimal roundtrip time */</span><br><span> #define DEFAULT_MAX_CALL_BITRATE (384) /*!< Max bitrate for video */</span><br><span> #ifndef DEFAULT_USERAGENT</span><br><span>@@ -759,6 +761,8 @@</span><br><span> int regextenonqualify; /*!< Whether to add/remove regexten when qualifying peers */</span><br><span> int legacy_useroption_parsing; /*!< Whether to strip useroptions in URI via semicolons */</span><br><span> int send_diversion; /*!< Whether to Send SIP Diversion headers */</span><br><span style="color: hsl(120, 100%, 40%);">+ int send_oli; /*!< Whether to Send ANI2/OLI */</span><br><span style="color: hsl(120, 100%, 40%);">+ int from_tags_inside; /*!< Whether to place OLI inside the arrows or leave outside */</span><br><span> int matchexternaddrlocally; /*!< Match externaddr/externhost setting against localnet setting */</span><br><span> char regcontext[AST_MAX_CONTEXT]; /*!< Context for auto-extensions */</span><br><span> char messagecontext[AST_MAX_CONTEXT]; /*!< Default context for out of dialog msgs. */</span><br><span>@@ -853,6 +857,7 @@</span><br><span> /*! \brief Parameters to the transmit_invite function */</span><br><span> struct sip_invite_param {</span><br><span> int addsipheaders; /*!< Add extra SIP headers */</span><br><span style="color: hsl(120, 100%, 40%);">+ int addsiptags; /*!< Add extra SIP tags to From header */</span><br><span> const char *uri_options; /*!< URI options to add to the URI */</span><br><span> const char *vxml_url; /*!< VXML url for Cisco phones */</span><br><span> char *auth; /*!< Authentication */</span><br><span>diff --git a/configs/samples/sip.conf.sample b/configs/samples/sip.conf.sample</span><br><span>index 4947754..0e0c277 100644</span><br><span>--- a/configs/samples/sip.conf.sample</span><br><span>+++ b/configs/samples/sip.conf.sample</span><br><span>@@ -542,6 +542,14 @@</span><br><span> ; is disabled, Asterisk won't send Diversion headers unless</span><br><span> ; they are added manually.</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+;send_oli=no ; Default "no" ; Asterisk can pass ANI2 or Originating Line Information (OLI)</span><br><span style="color: hsl(120, 100%, 40%);">+ ; if desired. This will appear as isup-oli in the From header.</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+;from_tags_inside=no ; Default "no" ; Some carriers expect isup-oli and other carrier tags to be </span><br><span style="color: hsl(120, 100%, 40%);">+ ; inside the arrow brackets rather than outside. This option </span><br><span style="color: hsl(120, 100%, 40%);">+ ; allows for compatability with these carriers. Custom SIP tags</span><br><span style="color: hsl(120, 100%, 40%);">+ ; in the from header may be set using the SipAddTag application.</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> ; The shrinkcallerid function removes '(', ' ', ')', non-trailing '.', and '-' not</span><br><span> ; in square brackets. For example, the caller id value 555.5555 becomes 5555555</span><br><span> ; when this option is enabled. Disabling this option results in no modification</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.asterisk.org/c/asterisk/+/16569">change 16569</a>. To unsubscribe, or for help writing mail filters, visit <a href="https://gerrit.asterisk.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.asterisk.org/c/asterisk/+/16569"/><meta itemprop="name" content="View Change"/></div></div>
<div style="display:none"> Gerrit-Project: asterisk </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-Change-Id: I1e99a220295c03275827050147622a6c1f5a4be9 </div>
<div style="display:none"> Gerrit-Change-Number: 16569 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: N A <mail@interlinked.x10host.com> </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>