<p>Joshua Colp <strong>merged</strong> this change.</p><p><a href="https://gerrit.asterisk.org/6119">View Change</a></p><div style="white-space:pre-wrap">Approvals:
  Richard Mudgett: Looks good to me, but someone else must approve
  Joshua Colp: Looks good to me, approved; Approved for Submit

</div><pre style="font-family: monospace,monospace; white-space: pre-wrap;">chan_sip: Add dialplan function SIP_HEADERS<br><br>Syntax: SIP_HEADERS([prefix])<br><br>If the argument is specified, only the headers matching the given prefix<br>are returned.<br><br>The function returns a comma-separated list of SIP header names from an<br>incoming INVITE message. Multiple headers with the same name are included<br>in the list only once. The returned list can be iterated over using the<br>functions POP() and SIP_HEADER().<br><br>For example, '${SIP_HEADERS(Co)}' might return the string<br>'Contact,Content-Length,Content-Type'.<br><br>Practical use is rather '${SIP_HEADERS(X-)}' to enumerate optional<br>extended headers sent by a peer.<br><br>ASTERISK-27163<br><br>Change-Id: I2076d3893d03a2f82429f393b5b46db6cf68a267<br>---<br>M CHANGES<br>M channels/chan_sip.c<br>2 files changed, 129 insertions(+), 2 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">diff --git a/CHANGES b/CHANGES<br>index 71166ef..4f5225a 100644<br>--- a/CHANGES<br>+++ b/CHANGES<br>@@ -9,6 +9,14 @@<br> ==============================================================================<br> <br> ------------------------------------------------------------------------------<br>+--- Functionality changes from Asterisk 15 to Asterisk 16 --------------------<br>+------------------------------------------------------------------------------<br>+<br>+chan_sip<br>+------------------<br>+ * New function SIP_HEADERS() enumerates all headers in the incoming INVITE.<br>+<br>+------------------------------------------------------------------------------<br> --- Functionality changes from Asterisk 14 to Asterisk 15 --------------------<br> ------------------------------------------------------------------------------<br> <br>@@ -1539,7 +1547,7 @@<br> ------------------<br>  * New CLI commands have been added: "pjsip show identif(y|ies)", which lists<br>    all configured PJSIP identify objects<br>-   <br>+<br> ------------------------------------------------------------------------------<br> --- Functionality changes from Asterisk 12 to Asterisk 13 --------------------<br> ------------------------------------------------------------------------------<br>diff --git a/channels/chan_sip.c b/channels/chan_sip.c<br>index beaa3de..941a1e9 100644<br>--- a/channels/chan_sip.c<br>+++ b/channels/chan_sip.c<br>@@ -380,6 +380,37 @@<br>                    <para>Please observe that contents of the SDP (an attachment to the<br>                     SIP request) can't be accessed with this function.</para><br>           </description><br>+         <see-also><br>+                     <ref type="function">SIP_HEADERS</ref><br>+         </see-also><br>+    </function><br>+    <function name="SIP_HEADERS" language="en_US"><br>+             <synopsis><br>+                     Gets the list of SIP header names from an incoming INVITE message.<br>+           </synopsis><br>+            <syntax><br>+                       <parameter name="prefix"><br>+                            <para>If specified, only the headers matching the given prefix are returned.</para><br>+                      </parameter><br>+           </syntax><br>+              <description><br>+                  <para>Returns a comma-separated list of header names (without values) from the<br>+                 INVITE message that originated the current channel. Multiple headers with the<br>+                        same name are included in the list only once. The returned list can be iterated<br>+                      over using the functions POP() and SIP_HEADER().</para><br>+                        <para>For example, <literal>${SIP_HEADERS(Co)}</literal> might return<br>+                      <literal>Contact,Content-Length,Content-Type</literal>. As a practical example,<br>+                  you may use <literal>${SIP_HEADERS(X-)}</literal> to enumerate optional extended<br>+                 headers.</para><br>+                        <para>This function does not access headers from the incoming SIP REFER message;<br>+                       see the documentation of the function SIP_HEADER for how to access them.</para><br>+                        <para>Please observe that contents of the SDP (an attachment to the<br>+                    SIP request) can't be accessed with this function.</para><br>+          </description><br>+         <see-also><br>+                     <ref type="function">SIP_HEADER</ref><br>+                  <ref type="function">POP</ref><br>+         </see-also><br>     </function><br>     <function name="SIPPEER" language="en_US"><br>          <synopsis><br>@@ -22995,6 +23026,7 @@<br> {<br>         struct sip_pvt *p;<br>    const char *content = NULL;<br>+  char *mutable_data = ast_strdupa(data);<br>       AST_DECLARE_APP_ARGS(args,<br>            AST_APP_ARG(header);<br>          AST_APP_ARG(number);<br>@@ -23018,7 +23050,7 @@<br>                 return -1;<br>    }<br> <br>- AST_STANDARD_APP_ARGS(args, data);<br>+   AST_STANDARD_APP_ARGS(args, mutable_data);<br>    if (!args.number) {<br>           number = 1;<br>   } else {<br>@@ -23053,6 +23085,91 @@<br>    .name = "SIP_HEADER",<br>       .read = func_header_read,<br> };<br>+<br>+/*! \brief Read unique list of SIP headers (dialplan function) */<br>+static int func_headers_read2(struct ast_channel *chan, const char *function, char *data, struct ast_str **buf, ssize_t maxlen)<br>+{<br>+  int i;<br>+       struct sip_pvt *pvt;<br>+ char *mutable_data = ast_strdupa(data);<br>+      struct ast_str *token = ast_str_alloca(100);<br>+ AST_DECLARE_APP_ARGS(args,<br>+           AST_APP_ARG(pattern);<br>+        );<br>+<br>+        if (!chan) {<br>+         return -1;<br>+   }<br>+<br>+ ast_channel_lock(chan);<br>+<br>+   if (!IS_SIP_TECH(ast_channel_tech(chan))) {<br>+          ast_log(LOG_WARNING, "This function can only be used on SIP channels.\n");<br>+         ast_channel_unlock(chan);<br>+            return -1;<br>+   }<br>+<br>+ pvt = ast_channel_tech_pvt(chan);<br>+    if (!pvt) {<br>+          ast_channel_unlock(chan);<br>+            return -1;<br>+   }<br>+<br>+ AST_STANDARD_APP_ARGS(args, mutable_data);<br>+   if (!args.pattern || strcmp(args.pattern, "*") == 0) {<br>+             args.pattern = "";<br>+ }<br>+<br>+ for (i = 0; i < pvt->initreq.headers; i++) {<br>+           const char *header = REQ_OFFSET_TO_STR(&pvt->initreq, header[i]);<br>+             if (ast_begins_with(header, args.pattern)) {<br>+                 int hdrlen = strcspn(header, " \t:,");  /* Comma will break our logic, and illegal per RFC. */<br>+                     const char *term = ast_skip_blanks(header + hdrlen);<br>+                 if (hdrlen > 0 && *term == ':') {  /* Header is malformed otherwise! */<br>+                           const char *s = NULL;<br>+<br>+                             /* Return short headers in full form always. */<br>+                              if (hdrlen == 1) {<br>+                                   char short_hdr[2] = { header[0], '\0' };<br>+                                     s = find_full_alias(short_hdr, NULL);<br>+                                }<br>+                            if (s) {<br>+                                     /* Short header was found and expanded. */<br>+                                   ast_str_set(&token, -1, "%s,", s);<br>+                             } else {<br>+                                     /* Return the header as is, whether 1-character or not. */<br>+                                   ast_str_set(&token, -1, "%.*s,", hdrlen, header);<br>+                              }<br>+<br>+                         /* Has the same header been already added? */<br>+                                s = ast_str_buffer(*buf);<br>+                            while ((s = strstr(s, ast_str_buffer(token))) != NULL) {<br>+                                     /* Found suffix, but is it the full token? */<br>+                                        if (s == ast_str_buffer(*buf) || s[-1] == ',')<br>+                                               break;<br>+                                       /* Only suffix matched, go on with the search after the comma. */<br>+                                    s += hdrlen + 1;<br>+                             }<br>+<br>+                         /* s is null iff not broken from the loop, hence header not yet added. */<br>+                            if (s == NULL) {<br>+                                     ast_str_append(buf, maxlen, "%s", ast_str_buffer(token));<br>+                          }<br>+                    }<br>+            }<br>+    }<br>+<br>+ ast_str_truncate(*buf, -1);  /* Trim the last comma. Safe if empty. */<br>+<br>+    ast_channel_unlock(chan);<br>+    return 0;<br>+}<br>+<br>+static struct ast_custom_function sip_headers_function = {<br>+        .name = "SIP_HEADERS",<br>+     .read2 = func_headers_read2,<br>+};<br>+<br> <br> /*! \brief  Dial plan function to check if domain is local */<br> static int func_check_sipdomain(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)<br>@@ -35201,6 +35318,7 @@<br> <br>   /* Register dialplan functions */<br>     ast_custom_function_register(&sip_header_function);<br>+      ast_custom_function_register(&sip_headers_function);<br>      ast_custom_function_register(&sippeer_function);<br>  ast_custom_function_register(&checksipdomain_function);<br> <br>@@ -35301,6 +35419,7 @@<br> <br>    /* Unregister dial plan functions */<br>  ast_custom_function_unregister(&sippeer_function);<br>+       ast_custom_function_unregister(&sip_headers_function);<br>    ast_custom_function_unregister(&sip_header_function);<br>     ast_custom_function_unregister(&checksipdomain_function);<br> <br></pre><p>To view, visit <a href="https://gerrit.asterisk.org/6119">change 6119</a>. To unsubscribe, 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/6119"/><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-MessageType: merged </div>
<div style="display:none"> Gerrit-Change-Id: I2076d3893d03a2f82429f393b5b46db6cf68a267 </div>
<div style="display:none"> Gerrit-Change-Number: 6119 </div>
<div style="display:none"> Gerrit-PatchSet: 6 </div>
<div style="display:none"> Gerrit-Owner: Kirill Katsnelson <kkm@smartaction.com> </div>
<div style="display:none"> Gerrit-Reviewer: Jenkins2 </div>
<div style="display:none"> Gerrit-Reviewer: Joshua Colp <jcolp@digium.com> </div>
<div style="display:none"> Gerrit-Reviewer: Kirill Katsnelson <kkm@smartaction.com> </div>
<div style="display:none"> Gerrit-Reviewer: Richard Mudgett <rmudgett@digium.com> </div>
<div style="display:none"> Gerrit-Reviewer: Sean Bright <sean.bright@gmail.com> </div>