From 005b6c8d50441ef6e3bed70c71807a5a8861bb45 Mon Sep 17 00:00:00 2001 From: Naveen Albert Date: Fri, 14 Oct 2022 22:24:00 +0000 Subject: [PATCH] res_pjsip_notify: Add option support for AMI. The PJSIP notify CLI commands allow for using "options" configured in pjsip_notify.conf. This allows these same options to be used in AMI actions as well. Additionally, as part of this improvement, some repetitive common code is refactored. ASTERISK-30263 #close Change-Id: Ie4496b322b63b61eaf9672183a959ab99a04b6b5 --- .../res_pjsip_notify_options.txt | 4 + res/res_pjsip_notify.c | 165 +++++++++++------- 2 files changed, 102 insertions(+), 67 deletions(-) create mode 100644 doc/CHANGES-staging/res_pjsip_notify_options.txt diff --git a/doc/CHANGES-staging/res_pjsip_notify_options.txt b/doc/CHANGES-staging/res_pjsip_notify_options.txt new file mode 100644 index 0000000000..0a500f67fa --- /dev/null +++ b/doc/CHANGES-staging/res_pjsip_notify_options.txt @@ -0,0 +1,4 @@ +Subject: res_pjsip_notify + +Allows using the config options in pjsip_notify.conf +from AMI actions as with the existing CLI commands. diff --git a/res/res_pjsip_notify.c b/res/res_pjsip_notify.c index 3ae9f625a8..3d88c18a88 100644 --- a/res/res_pjsip_notify.c +++ b/res/res_pjsip_notify.c @@ -52,11 +52,16 @@ Channel name to send the NOTIFY. Must be a PJSIP channel. - + + The config section name from pjsip_notify.conf to use. + One of Option or Variable must be specified. + + Appends variables as headers/content to the NOTIFY. If the variable is named Content, then the value will compose the body of the message if another variable sets Content-Type. name=value + One of Option or Variable must be specified. @@ -1071,6 +1076,47 @@ static struct ast_cli_entry cli_options[] = { AST_CLI_DEFINE(cli_notify, "Send a NOTIFY request to a SIP endpoint") }; +enum notify_type { + NOTIFY_ENDPOINT, + NOTIFY_URI, + NOTIFY_CHANNEL, +}; + +static void manager_send_response(struct mansession *s, const struct message *m, enum notify_type type, enum notify_result res, struct ast_variable *vars, const char *endpoint_name) +{ + switch (res) { + case INVALID_CHANNEL: + if (type == NOTIFY_CHANNEL) { + ast_variables_destroy(vars); + astman_send_error(s, m, "Channel not found"); + } else { + /* Shouldn't be possible. */ + ast_assert(0); + } + break; + case INVALID_ENDPOINT: + if (type == NOTIFY_ENDPOINT) { + ast_variables_destroy(vars); + astman_send_error_va(s, m, "Unable to retrieve endpoint %s", endpoint_name); + } else { + /* Shouldn't be possible. */ + ast_assert(0); + } + break; + case ALLOC_ERROR: + ast_variables_destroy(vars); + astman_send_error(s, m, "Unable to allocate NOTIFY task data"); + break; + case TASK_PUSH_ERROR: + /* Don't need to destroy vars since it is handled by cleanup in push_notify, push_notify_uri, etc. */ + astman_send_error(s, m, "Unable to push Notify task"); + break; + case SUCCESS: + astman_send_ack(s, m, "NOTIFY sent"); + break; + } +} + /*! * \internal * \brief Completes SIPNotify AMI command in Endpoint mode. @@ -1078,7 +1124,19 @@ static struct ast_cli_entry cli_options[] = { static void manager_notify_endpoint(struct mansession *s, const struct message *m, const char *endpoint_name) { - struct ast_variable *vars = astman_get_variables_order(m, ORDER_NATURAL); + RAII_VAR(struct notify_cfg *, cfg, NULL, ao2_cleanup); + RAII_VAR(struct notify_option *, option, NULL, ao2_cleanup); + struct ast_variable *vars = NULL; + enum notify_result res; + const char *option_name = astman_get_header(m, "Option"); + + if (!ast_strlen_zero(option_name) && (cfg = ao2_global_obj_ref(globals)) && !(option = notify_option_find(cfg->notify_options, option_name))) { + astman_send_error_va(s, m, "Unable to find notify type '%s'\n", option_name); + return; + } + if (!option) { + vars = astman_get_variables_order(m, ORDER_NATURAL); + } if (!strncasecmp(endpoint_name, "sip/", 4)) { endpoint_name += 4; @@ -1088,28 +1146,13 @@ static void manager_notify_endpoint(struct mansession *s, endpoint_name += 6; } - switch (push_notify(endpoint_name, vars, notify_ami_data_create)) { - case INVALID_CHANNEL: - /* Shouldn't be possible. */ - ast_assert(0); - break; - case INVALID_ENDPOINT: - ast_variables_destroy(vars); - astman_send_error_va(s, m, "Unable to retrieve endpoint %s", - endpoint_name); - break; - case ALLOC_ERROR: - ast_variables_destroy(vars); - astman_send_error(s, m, "Unable to allocate NOTIFY task data"); - break; - case TASK_PUSH_ERROR: - /* Don't need to destroy vars since it is handled by cleanup in push_notify */ - astman_send_error(s, m, "Unable to push NOTIFY task"); - break; - case SUCCESS: - astman_send_ack(s, m, "NOTIFY sent"); - break; + if (option) { + res = push_notify(endpoint_name, option, notify_cli_data_create); /* The CLI version happens to be suitable for options. */ + } else { + res = push_notify(endpoint_name, vars, notify_ami_data_create); } + + manager_send_response(s, m, NOTIFY_ENDPOINT, res, vars, endpoint_name); } /*! @@ -1119,29 +1162,27 @@ static void manager_notify_endpoint(struct mansession *s, static void manager_notify_uri(struct mansession *s, const struct message *m, const char *uri) { - struct ast_variable *vars = astman_get_variables_order(m, ORDER_NATURAL); + RAII_VAR(struct notify_cfg *, cfg, NULL, ao2_cleanup); + RAII_VAR(struct notify_option *, option, NULL, ao2_cleanup); + enum notify_result res; + const char *option_name = astman_get_header(m, "Option"); + struct ast_variable *vars = NULL; - switch (push_notify_uri(uri, vars, notify_ami_uri_data_create)) { - case INVALID_CHANNEL: - /* Shouldn't be possible. */ - ast_assert(0); - break; - case INVALID_ENDPOINT: - /* Shouldn't be possible. */ - ast_assert(0); - break; - case ALLOC_ERROR: - ast_variables_destroy(vars); - astman_send_error(s, m, "Unable to allocate NOTIFY task data"); - break; - case TASK_PUSH_ERROR: - /* Don't need to destroy vars since it is handled by cleanup in push_notify_uri */ - astman_send_error(s, m, "Unable to push Notify task"); - break; - case SUCCESS: - astman_send_ack(s, m, "NOTIFY sent"); - break; + if (!ast_strlen_zero(option_name) && (cfg = ao2_global_obj_ref(globals)) && !(option = notify_option_find(cfg->notify_options, option_name))) { + astman_send_error_va(s, m, "Unable to find notify type '%s'\n", option_name); + return; } + if (!option) { + vars = astman_get_variables_order(m, ORDER_NATURAL); + } + + if (option) { + res = push_notify_uri(uri, option, notify_cli_uri_data_create); + } else { + res = push_notify_uri(uri, vars, notify_ami_uri_data_create); + } + + manager_send_response(s, m, NOTIFY_URI, res, vars, NULL); } /*! @@ -1151,29 +1192,13 @@ static void manager_notify_uri(struct mansession *s, static void manager_notify_channel(struct mansession *s, const struct message *m, const char *channel) { - struct ast_variable *vars = astman_get_variables_order(m, ORDER_NATURAL); + enum notify_result res; + struct ast_variable *vars = NULL; - switch (push_notify_channel(channel, vars, notify_ami_channel_data_create)) { - case INVALID_CHANNEL: - ast_variables_destroy(vars); - astman_send_error(s, m, "Channel not found"); - break; - case INVALID_ENDPOINT: - /* Shouldn't be possible. */ - ast_assert(0); - break; - case ALLOC_ERROR: - ast_variables_destroy(vars); - astman_send_error(s, m, "Unable to allocate NOTIFY task data"); - break; - case TASK_PUSH_ERROR: - /* Don't need to destroy vars since it is handled by cleanup in push_notify_channel */ - astman_send_error(s, m, "Unable to push Notify task"); - break; - case SUCCESS: - astman_send_ack(s, m, "NOTIFY sent"); - break; - } + vars = astman_get_variables_order(m, ORDER_NATURAL); + res = push_notify_channel(channel, vars, notify_ami_channel_data_create); + + manager_send_response(s, m, NOTIFY_CHANNEL, res, vars, NULL); } /*! @@ -1185,6 +1210,8 @@ static int manager_notify(struct mansession *s, const struct message *m) const char *endpoint_name = astman_get_header(m, "Endpoint"); const char *uri = astman_get_header(m, "URI"); const char *channel = astman_get_header(m, "Channel"); + const char *variables = astman_get_header(m, "Variable"); + const char *option = astman_get_header(m, "Option"); int count = 0; if (!ast_strlen_zero(endpoint_name)) { @@ -1197,7 +1224,11 @@ static int manager_notify(struct mansession *s, const struct message *m) ++count; } - if (1 < count) { + if ((!ast_strlen_zero(option) && !ast_strlen_zero(variables)) || (ast_strlen_zero(option) && ast_strlen_zero(variables))) { + astman_send_error(s, m, + "PJSIPNotify requires either an Option or Variable(s)." + "You must use only one of them."); + } else if (1 < count) { astman_send_error(s, m, "PJSIPNotify requires either an endpoint name, a SIP URI, or a channel. " "You must use only one of them.");