diff options
author | Joshua Colp <jcolp@digium.com> | 2017-08-04 12:57:58 -0500 |
---|---|---|
committer | Gerrit Code Review <gerrit2@gerrit.digium.api> | 2017-08-04 12:57:58 -0500 |
commit | 1f01106cfc273ea51fda4985cbd2bc3f33eee21e (patch) | |
tree | 75e5bf833b744910659f6d981ded406a973b4827 /channels | |
parent | 38c8080cdd174e6d101be7aa4c0acd68e4761683 (diff) | |
parent | 4c0798e91dff59682c16e269a87a181ea198a64e (diff) |
Merge "chan_sip: Add dialplan function SIP_HEADERS"
Diffstat (limited to 'channels')
-rw-r--r-- | channels/chan_sip.c | 121 |
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); |