summaryrefslogtreecommitdiff
path: root/channels
diff options
context:
space:
mode:
authorJoshua Colp <jcolp@digium.com>2017-08-04 12:57:58 -0500
committerGerrit Code Review <gerrit2@gerrit.digium.api>2017-08-04 12:57:58 -0500
commit1f01106cfc273ea51fda4985cbd2bc3f33eee21e (patch)
tree75e5bf833b744910659f6d981ded406a973b4827 /channels
parent38c8080cdd174e6d101be7aa4c0acd68e4761683 (diff)
parent4c0798e91dff59682c16e269a87a181ea198a64e (diff)
Merge "chan_sip: Add dialplan function SIP_HEADERS"
Diffstat (limited to 'channels')
-rw-r--r--channels/chan_sip.c121
1 files changed, 120 insertions, 1 deletions
diff --git a/channels/chan_sip.c b/channels/chan_sip.c
index beaa3de0b..941a1e96d 100644
--- a/channels/chan_sip.c
+++ b/channels/chan_sip.c
@@ -380,6 +380,37 @@
<para>Please observe that contents of the SDP (an attachment to the
SIP request) can't be accessed with this function.</para>
</description>
+ <see-also>
+ <ref type="function">SIP_HEADERS</ref>
+ </see-also>
+ </function>
+ <function name="SIP_HEADERS" language="en_US">
+ <synopsis>
+ Gets the list of SIP header names from an incoming INVITE message.
+ </synopsis>
+ <syntax>
+ <parameter name="prefix">
+ <para>If specified, only the headers matching the given prefix are returned.</para>
+ </parameter>
+ </syntax>
+ <description>
+ <para>Returns a comma-separated list of header names (without values) from the
+ INVITE message that originated the current channel. Multiple headers with the
+ same name are included in the list only once. The returned list can be iterated
+ over using the functions POP() and SIP_HEADER().</para>
+ <para>For example, <literal>${SIP_HEADERS(Co)}</literal> might return
+ <literal>Contact,Content-Length,Content-Type</literal>. As a practical example,
+ you may use <literal>${SIP_HEADERS(X-)}</literal> to enumerate optional extended
+ headers.</para>
+ <para>This function does not access headers from the incoming SIP REFER message;
+ see the documentation of the function SIP_HEADER for how to access them.</para>
+ <para>Please observe that contents of the SDP (an attachment to the
+ SIP request) can't be accessed with this function.</para>
+ </description>
+ <see-also>
+ <ref type="function">SIP_HEADER</ref>
+ <ref type="function">POP</ref>
+ </see-also>
</function>
<function name="SIPPEER" language="en_US">
<synopsis>
@@ -22995,6 +23026,7 @@ static int func_header_read(struct ast_channel *chan, const char *function, char
{
struct sip_pvt *p;
const char *content = NULL;
+ char *mutable_data = ast_strdupa(data);
AST_DECLARE_APP_ARGS(args,
AST_APP_ARG(header);
AST_APP_ARG(number);
@@ -23018,7 +23050,7 @@ static int func_header_read(struct ast_channel *chan, const char *function, char
return -1;
}
- AST_STANDARD_APP_ARGS(args, data);
+ AST_STANDARD_APP_ARGS(args, mutable_data);
if (!args.number) {
number = 1;
} else {
@@ -23054,6 +23086,91 @@ static struct ast_custom_function sip_header_function = {
.read = func_header_read,
};
+/*! \brief Read unique list of SIP headers (dialplan function) */
+static int func_headers_read2(struct ast_channel *chan, const char *function, char *data, struct ast_str **buf, ssize_t maxlen)
+{
+ int i;
+ struct sip_pvt *pvt;
+ char *mutable_data = ast_strdupa(data);
+ struct ast_str *token = ast_str_alloca(100);
+ AST_DECLARE_APP_ARGS(args,
+ AST_APP_ARG(pattern);
+ );
+
+ if (!chan) {
+ return -1;
+ }
+
+ ast_channel_lock(chan);
+
+ if (!IS_SIP_TECH(ast_channel_tech(chan))) {
+ ast_log(LOG_WARNING, "This function can only be used on SIP channels.\n");
+ ast_channel_unlock(chan);
+ return -1;
+ }
+
+ pvt = ast_channel_tech_pvt(chan);
+ if (!pvt) {
+ ast_channel_unlock(chan);
+ return -1;
+ }
+
+ AST_STANDARD_APP_ARGS(args, mutable_data);
+ if (!args.pattern || strcmp(args.pattern, "*") == 0) {
+ args.pattern = "";
+ }
+
+ for (i = 0; i < pvt->initreq.headers; i++) {
+ const char *header = REQ_OFFSET_TO_STR(&pvt->initreq, header[i]);
+ if (ast_begins_with(header, args.pattern)) {
+ int hdrlen = strcspn(header, " \t:,"); /* Comma will break our logic, and illegal per RFC. */
+ const char *term = ast_skip_blanks(header + hdrlen);
+ if (hdrlen > 0 && *term == ':') { /* Header is malformed otherwise! */
+ const char *s = NULL;
+
+ /* Return short headers in full form always. */
+ if (hdrlen == 1) {
+ char short_hdr[2] = { header[0], '\0' };
+ s = find_full_alias(short_hdr, NULL);
+ }
+ if (s) {
+ /* Short header was found and expanded. */
+ ast_str_set(&token, -1, "%s,", s);
+ } else {
+ /* Return the header as is, whether 1-character or not. */
+ ast_str_set(&token, -1, "%.*s,", hdrlen, header);
+ }
+
+ /* Has the same header been already added? */
+ s = ast_str_buffer(*buf);
+ while ((s = strstr(s, ast_str_buffer(token))) != NULL) {
+ /* Found suffix, but is it the full token? */
+ if (s == ast_str_buffer(*buf) || s[-1] == ',')
+ break;
+ /* Only suffix matched, go on with the search after the comma. */
+ s += hdrlen + 1;
+ }
+
+ /* s is null iff not broken from the loop, hence header not yet added. */
+ if (s == NULL) {
+ ast_str_append(buf, maxlen, "%s", ast_str_buffer(token));
+ }
+ }
+ }
+ }
+
+ ast_str_truncate(*buf, -1); /* Trim the last comma. Safe if empty. */
+
+ ast_channel_unlock(chan);
+ return 0;
+}
+
+static struct ast_custom_function sip_headers_function = {
+ .name = "SIP_HEADERS",
+ .read2 = func_headers_read2,
+};
+
+
/*! \brief Dial plan function to check if domain is local */
static int func_check_sipdomain(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
{
@@ -35201,6 +35318,7 @@ static int load_module(void)
/* Register dialplan functions */
ast_custom_function_register(&sip_header_function);
+ ast_custom_function_register(&sip_headers_function);
ast_custom_function_register(&sippeer_function);
ast_custom_function_register(&checksipdomain_function);
@@ -35301,6 +35419,7 @@ static int unload_module(void)
/* Unregister dial plan functions */
ast_custom_function_unregister(&sippeer_function);
+ ast_custom_function_unregister(&sip_headers_function);
ast_custom_function_unregister(&sip_header_function);
ast_custom_function_unregister(&checksipdomain_function);