summaryrefslogtreecommitdiff
path: root/res
diff options
context:
space:
mode:
authorGeorge Joseph <gjoseph@digium.com>2017-09-11 04:46:35 -0600
committerGeorge Joseph <gjoseph@digium.com>2017-09-13 09:22:13 -0500
commit35cc916e63b0c8b8181e6bbeb9b052a81af2e422 (patch)
treea8c2a81d7664aa219dfbd7bbb066e68f2d96ad2e /res
parentcadc96c04bf8350bd8052e8228d84550ed2c4899 (diff)
res_pjsip: Add handling for incoming unsolicited MWI NOTIFY
A new endpoint parameter "incoming_mwi_mailbox" allows Asterisk to receive unsolicited MWI NOTIFY requests and make them available to other modules via the stasis message bus. res_pjsip_pubsub has a new handler "pubsub_on_rx_mwi_notify_request" that parses a simple-message-summary body and, if endpoint->incoming_mwi_account is set, calls ast_publish_mwi_state with the voice-message counts from the message. Change-Id: I08bae3d16e77af48fcccc2c936acce8fc0ef0f3c
Diffstat (limited to 'res')
-rw-r--r--res/res_pjsip.c8
-rw-r--r--res/res_pjsip/pjsip_configuration.c4
-rw-r--r--res/res_pjsip_pubsub.c133
3 files changed, 145 insertions, 0 deletions
diff --git a/res/res_pjsip.c b/res/res_pjsip.c
index 0d46a157b..2986e1a5c 100644
--- a/res/res_pjsip.c
+++ b/res/res_pjsip.c
@@ -988,6 +988,14 @@
on Ringing when already INUSE.
</para></description>
</configOption>
+ <configOption name="incoming_mwi_mailbox">
+ <synopsis>Mailbox name to use when incoming MWI NOTIFYs are received</synopsis>
+ <description><para>
+ If an MWI NOTIFY is received <emphasis>from</emphasis> this endpoint,
+ this mailbox will be used when notifying other modules of MWI status
+ changes. If not set, incoming MWI NOTIFYs are ignored.
+ </para></description>
+ </configOption>
</configObject>
<configObject name="auth">
<synopsis>Authentication type</synopsis>
diff --git a/res/res_pjsip/pjsip_configuration.c b/res/res_pjsip/pjsip_configuration.c
index 4d3c61645..437476631 100644
--- a/res/res_pjsip/pjsip_configuration.c
+++ b/res/res_pjsip/pjsip_configuration.c
@@ -1958,6 +1958,7 @@ int ast_res_pjsip_initialize_configuration(void)
ast_sorcery_object_field_register(sip_sorcery, "endpoint", "allow_overlap", "yes", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, allow_overlap));
ast_sorcery_object_field_register(sip_sorcery, "endpoint", "refer_blind_progress", "yes", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, refer_blind_progress));
ast_sorcery_object_field_register(sip_sorcery, "endpoint", "notify_early_inuse_ringing", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, notify_early_inuse_ringing));
+ ast_sorcery_object_field_register(sip_sorcery, "endpoint", "incoming_mwi_mailbox", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, incoming_mwi_mailbox));
if (ast_sip_initialize_sorcery_transport()) {
ast_log(LOG_ERROR, "Failed to register SIP transport support with sorcery\n");
@@ -2121,6 +2122,9 @@ void *ast_sip_endpoint_alloc(const char *name)
ao2_cleanup(endpoint);
return NULL;
}
+
+ ast_string_field_init_extended(endpoint, incoming_mwi_mailbox);
+
if (!(endpoint->media.codecs = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) {
ao2_cleanup(endpoint);
return NULL;
diff --git a/res/res_pjsip_pubsub.c b/res/res_pjsip_pubsub.c
index 9f0eae241..81b25ac2e 100644
--- a/res/res_pjsip_pubsub.c
+++ b/res/res_pjsip_pubsub.c
@@ -31,6 +31,7 @@
#include <pjsip_simple.h>
#include <pjlib.h>
+#include "asterisk/app.h"
#include "asterisk/res_pjsip_pubsub.h"
#include "asterisk/module.h"
#include "asterisk/linkedlists.h"
@@ -3402,12 +3403,144 @@ end:
return res;
}
+struct simple_message_summary {
+ int messages_waiting;
+ int voice_messages_new;
+ int voice_messages_old;
+ int voice_messages_urgent_new;
+ int voice_messages_urgent_old;
+ char message_account[PJSIP_MAX_URL_SIZE];
+};
+
+static int parse_simple_message_summary(char *body,
+ struct simple_message_summary *summary)
+{
+ char *line;
+ char *buffer;
+ int found_counts = 0;
+
+ if (ast_strlen_zero(body) || !summary) {
+ return -1;
+ }
+
+ buffer = ast_strdupa(body);
+ memset(summary, 0, sizeof(*summary));
+
+ while ((line = ast_read_line_from_buffer(&buffer))) {
+ line = ast_str_to_lower(line);
+
+ if (sscanf(line, "voice-message: %d/%d (%d/%d)",
+ &summary->voice_messages_new, &summary->voice_messages_old,
+ &summary->voice_messages_urgent_new, &summary->voice_messages_urgent_old)) {
+ found_counts = 1;
+ } else {
+ sscanf(line, "message-account: %s", summary->message_account);
+ }
+ }
+
+ return !found_counts;
+}
+
+static pj_bool_t pubsub_on_rx_mwi_notify_request(pjsip_rx_data *rdata)
+{
+ RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
+ struct simple_message_summary summary;
+ const char *endpoint_name;
+ char *atsign;
+ char *context;
+ char *body;
+ char *mailbox;
+ int rc;
+
+ endpoint = ast_pjsip_rdata_get_endpoint(rdata);
+ if (!endpoint) {
+ ast_debug(1, "Incoming MWI: Endpoint not found in rdata (%p)\n", rdata);
+ rc = 404;
+ goto error;
+ }
+
+ endpoint_name = ast_sorcery_object_get_id(endpoint);
+ ast_debug(1, "Incoming MWI: Found endpoint: %s\n", endpoint_name);
+ if (ast_strlen_zero(endpoint->incoming_mwi_mailbox)) {
+ ast_debug(1, "Incoming MWI: No incoming mailbox specified for endpoint '%s'\n", endpoint_name);
+ ast_test_suite_event_notify("PUBSUB_NO_INCOMING_MWI_MAILBOX",
+ "Endpoint: %s", endpoint_name);
+ rc = 404;
+ goto error;
+ }
+
+ mailbox = ast_strdupa(endpoint->incoming_mwi_mailbox);
+ atsign = strchr(mailbox, '@');
+ if (!atsign) {
+ ast_debug(1, "Incoming MWI: No '@' found in endpoint %s's incoming mailbox '%s'. Can't parse context\n",
+ endpoint_name, endpoint->incoming_mwi_mailbox);
+ rc = 404;
+ goto error;
+ }
+
+ *atsign = '\0';
+ context = atsign + 1;
+
+ body = ast_alloca(rdata->msg_info.msg->body->len + 1);
+ rdata->msg_info.msg->body->print_body(rdata->msg_info.msg->body, body,
+ rdata->msg_info.msg->body->len + 1);
+
+ if (parse_simple_message_summary(body, &summary) != 0) {
+ ast_debug(1, "Incoming MWI: Endpoint: '%s' There was an issue getting message info from body '%s'\n",
+ ast_sorcery_object_get_id(endpoint), body);
+ rc = 404;
+ goto error;
+ }
+
+ if (ast_publish_mwi_state(mailbox, context,
+ summary.voice_messages_new, summary.voice_messages_old)) {
+ ast_log(LOG_ERROR, "Incoming MWI: Endpoint: '%s' Could not publish MWI to stasis. "
+ "Mailbox: %s Message-Account: %s Voice-Messages: %d/%d (%d/%d)\n",
+ endpoint_name, endpoint->incoming_mwi_mailbox, summary.message_account,
+ summary.voice_messages_new, summary.voice_messages_old,
+ summary.voice_messages_urgent_new, summary.voice_messages_urgent_old);
+ rc = 404;
+ } else {
+ ast_debug(1, "Incoming MWI: Endpoint: '%s' Mailbox: %s Message-Account: %s Voice-Messages: %d/%d (%d/%d)\n",
+ endpoint_name, endpoint->incoming_mwi_mailbox, summary.message_account,
+ summary.voice_messages_new, summary.voice_messages_old,
+ summary.voice_messages_urgent_new, summary.voice_messages_urgent_old);
+ ast_test_suite_event_notify("PUBSUB_INCOMING_MWI_PUBLISH",
+ "Endpoint: %s\r\n"
+ "Mailbox: %s\r\n"
+ "MessageAccount: %s\r\n"
+ "VoiceMessagesNew: %d\r\n"
+ "VoiceMessagesOld: %d\r\n"
+ "VoiceMessagesUrgentNew: %d\r\n"
+ "VoiceMessagesUrgentOld: %d",
+ endpoint_name, endpoint->incoming_mwi_mailbox, summary.message_account,
+ summary.voice_messages_new, summary.voice_messages_old,
+ summary.voice_messages_urgent_new, summary.voice_messages_urgent_old);
+ rc = 200;
+ }
+
+error:
+ pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, rc, NULL, NULL, NULL);
+ return PJ_TRUE;
+}
+
+static pj_bool_t pubsub_on_rx_notify_request(pjsip_rx_data *rdata)
+{
+ if (pj_stricmp2(&rdata->msg_info.msg->body->content_type.type, "application") == 0 &&
+ pj_stricmp2(&rdata->msg_info.msg->body->content_type.subtype, "simple-message-summary") == 0) {
+ return pubsub_on_rx_mwi_notify_request(rdata);
+ }
+ return PJ_FALSE;
+}
+
static pj_bool_t pubsub_on_rx_request(pjsip_rx_data *rdata)
{
if (!pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, pjsip_get_subscribe_method())) {
return pubsub_on_rx_subscribe_request(rdata);
} else if (!pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, &pjsip_publish_method)) {
return pubsub_on_rx_publish_request(rdata);
+ } else if (!pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, &pjsip_notify_method)) {
+ return pubsub_on_rx_notify_request(rdata);
}
return PJ_FALSE;