<p>Kirill Katsnelson has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.asterisk.org/6119">View Change</a></p><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_HEADER(Co)}' might return the string<br>'Contact,Content-Length,Content-Type'.<br><br>Practical use is rather '${SIP_HEADER(X-)}' to enumerate optional<br>extended headers sent by a peer.<br><br>ASTERISK-27163<br><br>Change-Id: I2076d3893d03a2f82429f393b5b46db6cf68a267<br>---<br>M channels/chan_sip.c<br>1 file changed, 109 insertions(+), 0 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.asterisk.org:29418/asterisk refs/changes/19/6119/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">diff --git a/channels/chan_sip.c b/channels/chan_sip.c<br>index f2daf2b..4d6d1a3 100644<br>--- a/channels/chan_sip.c<br>+++ b/channels/chan_sip.c<br>@@ -381,6 +381,32 @@<br>                         SIP request) can't be accessed with this function.</para><br>           </description><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_HEADER(Co)}</literal> might return<br>+                       <literal>Contact,Content-Length,Content-Type</literal>. As a practical example,<br>+                  you may use <literal>${SIP_HEADER(X-)}</literal> to enumerate optional extended<br>+                  headers.</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>                      Gets SIP peer information.<br>@@ -23054,6 +23080,87 @@<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>+ AST_DECLARE_APP_ARGS(args,<br>+           AST_APP_ARG(pattern);<br>+        );<br>+<br>+        SCOPED_CHANNELLOCK(chanlock, chan);<br>+<br>+       if (!chan) {<br>+         return -1;<br>+   }<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>+         return -1;<br>+   }<br>+<br>+ pvt = ast_channel_tech_pvt(chan);<br>+    if (!pvt) {<br>+          return -1;<br>+   }<br>+<br>+ AST_STANDARD_APP_ARGS(args, data);<br>+   if (!args.pattern) {<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>+                           struct ast_str *token = ast_str_alloca(100);<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>+    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> {<br>@@ -35201,6 +35308,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 +35409,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: newchange </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: 1 </div>
<div style="display:none"> Gerrit-Owner: Kirill Katsnelson <kkm@smartaction.com> </div>