<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>