diff --git a/CHANGES b/CHANGES index 5c254a8791..398e0842f0 100644 --- a/CHANGES +++ b/CHANGES @@ -18,6 +18,11 @@ pbx_config extensions.conf. Variables are processed in the order they are found and duplicate variables overwrite the previous value. +chan_pjsip +------------------ + * New dialplan function PJSIP_PARSE_URI added to parse an URI and return + a specified part of the URI. + res_pjsip ------------------ * New options 'trust_connected_line' and 'send_connected_line' have been diff --git a/channels/chan_pjsip.c b/channels/chan_pjsip.c index 5bbd0257d6..062fb7ccc3 100644 --- a/channels/chan_pjsip.c +++ b/channels/chan_pjsip.c @@ -2774,6 +2774,11 @@ static struct ast_custom_function chan_pjsip_dial_contacts_function = { .read = pjsip_acf_dial_contacts_read, }; +static struct ast_custom_function chan_pjsip_parse_uri_function = { + .name = "PJSIP_PARSE_URI", + .read = pjsip_acf_parse_uri_read, +}; + static struct ast_custom_function media_offer_function = { .name = "PJSIP_MEDIA_OFFER", .read = pjsip_acf_media_offer_read, @@ -2825,6 +2830,11 @@ static int load_module(void) goto end; } + if (ast_custom_function_register(&chan_pjsip_parse_uri_function)) { + ast_log(LOG_ERROR, "Unable to register PJSIP_PARSE_URI dialplan function\n"); + goto end; + } + if (ast_custom_function_register(&media_offer_function)) { ast_log(LOG_WARNING, "Unable to register PJSIP_MEDIA_OFFER dialplan function\n"); goto end; @@ -2897,6 +2907,7 @@ end: ast_custom_function_unregister(&dtmf_mode_function); ast_custom_function_unregister(&media_offer_function); ast_custom_function_unregister(&chan_pjsip_dial_contacts_function); + ast_custom_function_unregister(&chan_pjsip_parse_uri_function); ast_custom_function_unregister(&session_refresh_function); ast_channel_unregister(&chan_pjsip_tech); ast_rtp_glue_unregister(&chan_pjsip_rtp_glue); @@ -2921,6 +2932,7 @@ static int unload_module(void) ast_custom_function_unregister(&dtmf_mode_function); ast_custom_function_unregister(&media_offer_function); ast_custom_function_unregister(&chan_pjsip_dial_contacts_function); + ast_custom_function_unregister(&chan_pjsip_parse_uri_function); ast_custom_function_unregister(&session_refresh_function); ast_channel_unregister(&chan_pjsip_tech); diff --git a/channels/pjsip/dialplan_functions.c b/channels/pjsip/dialplan_functions.c index b7a74607cc..c6971c89ee 100644 --- a/channels/pjsip/dialplan_functions.c +++ b/channels/pjsip/dialplan_functions.c @@ -121,6 +121,60 @@ PJSIP_MEDIA_OFFER + + + Parse an uri and return a type part of the URI. + + + + URI to parse + + + The type parameter specifies which URI part to read + + + Display name. + + + URI scheme. + + + User part. + + + Password part. + + + Host part. + + + Port number, or zero. + + + User parameter. + + + Method parameter. + + + Transport parameter. + + + TTL param, or -1. + + + Loose routing param, or zero. + + + Maddr param. + + + + + + Parse an URI and return a specified part of the URI. + + @@ -987,6 +1041,127 @@ int pjsip_acf_dial_contacts_read(struct ast_channel *chan, const char *cmd, char return 0; } +/*! \brief Struct used to push PJSIP_PARSE_URI function arguments to task processor */ +struct parse_uri_args { + const char *uri; + const char *type; + char *buf; + size_t buflen; + int ret; +}; + +/*! \internal \brief Taskprocessor callback that handles the PJSIP_PARSE_URI on a PJSIP thread */ +static int parse_uri_cb(void *data) +{ + struct parse_uri_args *args = data; + pj_pool_t *pool; + pjsip_name_addr *uri; + pjsip_sip_uri *sip_uri; + pj_str_t tmp; + + args->ret = 0; + + pool = pjsip_endpt_create_pool(ast_sip_get_pjsip_endpoint(), "ParseUri", 128, 128); + if (!pool) { + ast_log(LOG_ERROR, "Failed to allocate ParseUri endpoint pool.\n"); + args->ret = -1; + return 0; + } + + pj_strdup2_with_null(pool, &tmp, args->uri); + uri = (pjsip_name_addr *)pjsip_parse_uri(pool, tmp.ptr, tmp.slen, PJSIP_PARSE_URI_AS_NAMEADDR); + if (!uri) { + ast_log(LOG_WARNING, "Failed to parse URI '%s'\n", args->uri); + pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool); + args->ret = -1; + return 0; + } + + if (!strcmp(args->type, "scheme")) { + ast_copy_pj_str(args->buf, pjsip_uri_get_scheme(uri), args->buflen); + pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool); + return 0; + } else if (!strcmp(args->type, "display")) { + ast_copy_pj_str(args->buf, &uri->display, args->buflen); + pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool); + return 0; + } + + sip_uri = pjsip_uri_get_uri(uri); + if (!sip_uri) { + ast_log(LOG_ERROR, "Failed to get an URI object for '%s'\n", args->uri); + pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool); + args->ret = -1; + return 0; + } + + if (!strcmp(args->type, "user")) { + ast_copy_pj_str(args->buf, &sip_uri->user, args->buflen); + } else if (!strcmp(args->type, "passwd")) { + ast_copy_pj_str(args->buf, &sip_uri->passwd, args->buflen); + } else if (!strcmp(args->type, "host")) { + ast_copy_pj_str(args->buf, &sip_uri->host, args->buflen); + } else if (!strcmp(args->type, "port")) { + snprintf(args->buf, args->buflen, "%d", sip_uri->port); + } else if (!strcmp(args->type, "user_param")) { + ast_copy_pj_str(args->buf, &sip_uri->user_param, args->buflen); + } else if (!strcmp(args->type, "method_param")) { + ast_copy_pj_str(args->buf, &sip_uri->method_param, args->buflen); + } else if (!strcmp(args->type, "transport_param")) { + ast_copy_pj_str(args->buf, &sip_uri->transport_param, args->buflen); + } else if (!strcmp(args->type, "ttl_param")) { + snprintf(args->buf, args->buflen, "%d", sip_uri->ttl_param); + } else if (!strcmp(args->type, "lr_param")) { + snprintf(args->buf, args->buflen, "%d", sip_uri->lr_param); + } else if (!strcmp(args->type, "maddr_param")) { + ast_copy_pj_str(args->buf, &sip_uri->maddr_param, args->buflen); + } else { + ast_log(AST_LOG_WARNING, "Unknown type part '%s' specified\n", args->type); + pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool); + args->ret = -1; + return 0; + } + + pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool); + + return 0; +} + +int pjsip_acf_parse_uri_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen) +{ + struct parse_uri_args func_args = { 0, }; + + AST_DECLARE_APP_ARGS(args, + AST_APP_ARG(uri_str); + AST_APP_ARG(type); + ); + + AST_STANDARD_APP_ARGS(args, data); + + if (ast_strlen_zero(args.uri_str)) { + ast_log(LOG_WARNING, "An URI must be specified when using the '%s' dialplan function\n", cmd); + return -1; + } + + if (ast_strlen_zero(args.type)) { + ast_log(LOG_WARNING, "A type part of the URI must be specified when using the '%s' dialplan function\n", cmd); + return -1; + } + + memset(buf, 0, buflen); + + func_args.uri = args.uri_str; + func_args.type = args.type; + func_args.buf = buf; + func_args.buflen = buflen; + if (ast_sip_push_task_wait_serializer(NULL, parse_uri_cb, &func_args)) { + ast_log(LOG_WARNING, "Unable to parse URI: failed to push task\n"); + return -1; + } + + return func_args.ret; +} + static int media_offer_read_av(struct ast_sip_session *session, char *buf, size_t len, enum ast_media_type media_type) { diff --git a/channels/pjsip/include/dialplan_functions.h b/channels/pjsip/include/dialplan_functions.h index 731e91d139..a9332a24ca 100644 --- a/channels/pjsip/include/dialplan_functions.h +++ b/channels/pjsip/include/dialplan_functions.h @@ -110,4 +110,17 @@ int pjsip_acf_session_refresh_write(struct ast_channel *chan, const char *cmd, c */ int pjsip_acf_dial_contacts_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len); +/*! + * \brief PJSIP_PARSE_URI function read callback + * \param chan The channel the function is called on + * \param cmd The name of the function + * \param data Arguments passed to the function + * \param buf Out buffer that should be populated with the data + * \param len Size of the buffer + * + * \retval 0 on success + * \retval -1 on failure + */ +int pjsip_acf_parse_uri_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len); + #endif /* _PJSIP_DIALPLAN_FUNCTIONS */ \ No newline at end of file