summaryrefslogtreecommitdiff
path: root/res/res_pjsip_mwi.c
diff options
context:
space:
mode:
Diffstat (limited to 'res/res_pjsip_mwi.c')
-rw-r--r--res/res_pjsip_mwi.c189
1 files changed, 145 insertions, 44 deletions
diff --git a/res/res_pjsip_mwi.c b/res/res_pjsip_mwi.c
index be38b44c1..f9bfc1904 100644
--- a/res/res_pjsip_mwi.c
+++ b/res/res_pjsip_mwi.c
@@ -42,6 +42,8 @@
struct mwi_subscription;
static struct ao2_container *unsolicited_mwi;
+static char *default_voicemail_extension;
+
#define STASIS_BUCKETS 13
#define MWI_BUCKETS 53
@@ -326,11 +328,30 @@ static int get_message_count(void *obj, void *arg, int flags)
return 0;
}
+static void set_voicemail_extension(pj_pool_t *pool, pjsip_sip_uri *local_uri,
+ struct ast_sip_message_accumulator *counter, const char *voicemail_extension)
+{
+ pjsip_sip_uri *account_uri;
+ const char *vm_exten;
+
+ if (ast_strlen_zero(voicemail_extension)) {
+ vm_exten = default_voicemail_extension;
+ } else {
+ vm_exten = voicemail_extension;
+ }
+
+ if (!ast_strlen_zero(vm_exten)) {
+ account_uri = pjsip_uri_clone(pool, local_uri);
+ pj_strdup2(pool, &account_uri->user, vm_exten);
+ pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR, account_uri, counter->message_account, sizeof(counter->message_account));
+ }
+}
+
struct unsolicited_mwi_data {
struct mwi_subscription *sub;
struct ast_sip_endpoint *endpoint;
pjsip_evsub_state state;
- const struct ast_sip_body *body;
+ struct ast_sip_message_accumulator *counter;
};
static int send_unsolicited_mwi_notify_to_contact(void *obj, void *arg, int flags)
@@ -339,27 +360,50 @@ static int send_unsolicited_mwi_notify_to_contact(void *obj, void *arg, int flag
struct mwi_subscription *sub = mwi_data->sub;
struct ast_sip_endpoint *endpoint = mwi_data->endpoint;
pjsip_evsub_state state = mwi_data->state;
- const struct ast_sip_body *body = mwi_data->body;
struct ast_sip_contact *contact = obj;
const char *state_name;
pjsip_tx_data *tdata;
pjsip_sub_state_hdr *sub_state;
pjsip_event_hdr *event;
+ pjsip_from_hdr *from;
+ pjsip_sip_uri *from_uri;
const pjsip_hdr *allow_events = pjsip_evsub_get_allow_events_hdr(NULL);
+ struct ast_sip_body body;
+ struct ast_str *body_text;
+ struct ast_sip_body_data body_data = {
+ .body_type = AST_SIP_MESSAGE_ACCUMULATOR,
+ .body_data = mwi_data->counter,
+ };
if (ast_sip_create_request("NOTIFY", NULL, endpoint, NULL, contact, &tdata)) {
ast_log(LOG_WARNING, "Unable to create unsolicited NOTIFY request to endpoint %s URI %s\n", sub->id, contact->uri);
return 0;
}
- if (!ast_strlen_zero(endpoint->subscription.mwi.fromuser)) {
- pjsip_fromto_hdr *from = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_FROM, NULL);
- pjsip_name_addr *from_name_addr = (pjsip_name_addr *) from->uri;
- pjsip_sip_uri *from_uri = pjsip_uri_get_uri(from_name_addr->uri);
+ body.type = MWI_TYPE;
+ body.subtype = MWI_SUBTYPE;
+ body_text = ast_str_create(64);
+ if (!body_text) {
+ return 0;
+ }
+ from = PJSIP_MSG_FROM_HDR(tdata->msg);
+ from_uri = pjsip_uri_get_uri(from->uri);
+
+ if (!ast_strlen_zero(endpoint->subscription.mwi.fromuser)) {
pj_strdup2(tdata->pool, &from_uri->user, endpoint->subscription.mwi.fromuser);
}
+ set_voicemail_extension(tdata->pool, from_uri, mwi_data->counter, endpoint->subscription.mwi.voicemail_extension);
+
+ if (ast_sip_pubsub_generate_body_content(body.type, body.subtype, &body_data, &body_text)) {
+ ast_log(LOG_WARNING, "Unable to generate SIP MWI NOTIFY body.\n");
+ ast_free(body_text);
+ return 0;
+ }
+
+ body.body_text = ast_str_buffer(body_text);
+
switch (state) {
case PJSIP_EVSUB_STATE_ACTIVE:
state_name = "active";
@@ -379,12 +423,54 @@ static int send_unsolicited_mwi_notify_to_contact(void *obj, void *arg, int flag
pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr *) event);
pjsip_msg_add_hdr(tdata->msg, pjsip_hdr_shallow_clone(tdata->pool, allow_events));
- ast_sip_add_body(tdata, body);
+ ast_sip_add_body(tdata, &body);
ast_sip_send_request(tdata, NULL, endpoint, NULL, NULL);
+ ast_free(body_text);
+
return 0;
}
+static struct ast_sip_aor *find_aor_for_resource(struct ast_sip_endpoint *endpoint, const char *resource)
+{
+ struct ast_sip_aor *aor;
+ char *aor_name;
+ char *aors_copy;
+
+ /* Direct match */
+ if ((aor = ast_sip_location_retrieve_aor(resource))) {
+ return aor;
+ }
+
+ if (!endpoint) {
+ return NULL;
+ }
+
+ /*
+ * This may be a subscribe to the voicemail_extension. If so,
+ * look for an aor belonging to this endpoint that has a matching
+ * voicemail_extension.
+ */
+ aors_copy = ast_strdupa(endpoint->aors);
+ while ((aor_name = ast_strip(strsep(&aors_copy, ",")))) {
+ struct ast_sip_aor *check_aor = ast_sip_location_retrieve_aor(aor_name);
+
+ if (!check_aor) {
+ continue;
+ }
+
+ if (!ast_strlen_zero(check_aor->voicemail_extension)
+ && !strcasecmp(check_aor->voicemail_extension, resource)) {
+ ast_debug(1, "Found an aor (%s) that matches voicemail_extension %s\n", aor_name, resource);
+ return check_aor;
+ }
+
+ ao2_ref(check_aor, -1);
+ }
+
+ return NULL;
+}
+
static void send_unsolicited_mwi_notify(struct mwi_subscription *sub,
struct ast_sip_message_accumulator *counter)
{
@@ -392,12 +478,6 @@ static void send_unsolicited_mwi_notify(struct mwi_subscription *sub,
"endpoint", sub->id), ao2_cleanup);
char *endpoint_aors;
char *aor_name;
- struct ast_sip_body body;
- struct ast_str *body_text;
- struct ast_sip_body_data body_data = {
- .body_type = AST_SIP_MESSAGE_ACCUMULATOR,
- .body_data = counter,
- };
if (!endpoint) {
ast_log(LOG_WARNING, "Unable to send unsolicited MWI to %s because endpoint does not exist\n",
@@ -410,23 +490,6 @@ static void send_unsolicited_mwi_notify(struct mwi_subscription *sub,
return;
}
- body.type = MWI_TYPE;
- body.subtype = MWI_SUBTYPE;
-
- body_text = ast_str_create(64);
-
- if (!body_text) {
- return;
- }
-
- if (ast_sip_pubsub_generate_body_content(body.type, body.subtype, &body_data, &body_text)) {
- ast_log(LOG_WARNING, "Unable to generate SIP MWI NOTIFY body.\n");
- ast_free(body_text);
- return;
- }
-
- body.body_text = ast_str_buffer(body_text);
-
endpoint_aors = ast_strdupa(endpoint->aors);
ast_debug(5, "Sending unsolicited MWI NOTIFY to endpoint %s, new messages: %d, old messages: %d\n",
@@ -438,7 +501,7 @@ static void send_unsolicited_mwi_notify(struct mwi_subscription *sub,
struct unsolicited_mwi_data mwi_data = {
.sub = sub,
.endpoint = endpoint,
- .body = &body,
+ .counter = counter,
};
if (!aor) {
@@ -454,8 +517,6 @@ static void send_unsolicited_mwi_notify(struct mwi_subscription *sub,
ao2_callback(contacts, OBJ_NODATA, send_unsolicited_mwi_notify_to_contact, &mwi_data);
}
-
- ast_free(body_text);
}
static void send_mwi_notify(struct mwi_subscription *sub)
@@ -463,16 +524,30 @@ static void send_mwi_notify(struct mwi_subscription *sub)
struct ast_sip_message_accumulator counter = {
.old_msgs = 0,
.new_msgs = 0,
+ .message_account[0] = '\0',
};
struct ast_sip_body_data data = {
.body_type = AST_SIP_MESSAGE_ACCUMULATOR,
.body_data = &counter,
};
+ const char *resource = ast_sip_subscription_get_resource_name(sub->sip_sub);
ao2_callback(sub->stasis_subs, OBJ_NODATA, get_message_count, &counter);
if (sub->is_solicited) {
+ struct ast_sip_endpoint *endpoint = ast_sip_subscription_get_endpoint(sub->sip_sub);
+ struct ast_sip_aor *aor = find_aor_for_resource(endpoint, resource);
+ pjsip_dialog *dlg = ast_sip_subscription_get_dialog(sub->sip_sub);
+ pjsip_sip_uri *sip_uri = ast_sip_subscription_get_sip_uri(sub->sip_sub);
+
+ if (aor && dlg && sip_uri) {
+ set_voicemail_extension(dlg->pool, sip_uri, &counter, aor->voicemail_extension);
+ }
+
+ ao2_cleanup(aor);
+ ao2_cleanup(endpoint);
ast_sip_subscription_notify(sub->sip_sub, &data, 0);
+
return;
}
@@ -565,7 +640,12 @@ static int endpoint_receives_unsolicited_mwi_for_mailbox(struct ast_sip_endpoint
mwi_stasis = ao2_find(mwi_sub->stasis_subs, mailbox, OBJ_SEARCH_KEY);
if (mwi_stasis) {
- ret = 1;
+ if (endpoint->subscription.mwi.subscribe_replaces_unsolicited) {
+ unsubscribe_stasis(mwi_stasis, NULL, 0);
+ ao2_unlink(mwi_sub->stasis_subs, mwi_stasis);
+ } else {
+ ret = 1;
+ }
ao2_cleanup(mwi_stasis);
}
}
@@ -670,14 +750,9 @@ static struct mwi_subscription *mwi_subscribe_single(
struct ast_sip_aor *aor;
struct mwi_subscription *sub;
- aor = ast_sip_location_retrieve_aor(name);
+ aor = find_aor_for_resource(endpoint, name);
if (!aor) {
- /*! I suppose it's possible for the AOR to disappear on us
- * between accepting the subscription and sending the first
- * NOTIFY...
- */
- ast_log(LOG_WARNING, "Unable to locate aor %s. MWI subscription failed.\n",
- name);
+ ast_log(LOG_WARNING, "Unable to locate aor %s. MWI subscription failed.\n", name);
return NULL;
}
@@ -716,10 +791,9 @@ static int mwi_new_subscribe(struct ast_sip_endpoint *endpoint,
return 200;
}
- aor = ast_sip_location_retrieve_aor(resource);
+ aor = find_aor_for_resource(endpoint, resource);
if (!aor) {
- ast_debug(1, "Unable to locate aor %s. MWI subscription failed.\n",
- resource);
+ ast_debug(1, "Unable to locate aor %s. MWI subscription failed.\n", resource);
return 404;
}
@@ -771,6 +845,8 @@ static void *mwi_get_notify_data(struct ast_sip_subscription *sub)
struct ast_sip_message_accumulator *counter;
struct mwi_subscription *mwi_sub;
struct ast_datastore *mwi_datastore;
+ struct ast_sip_aor *aor;
+ struct ast_sip_endpoint *endpoint = ast_sip_subscription_get_endpoint(sub);
mwi_datastore = ast_sip_subscription_get_datastore(sub, MWI_DATASTORE);
if (!mwi_datastore) {
@@ -784,6 +860,17 @@ static void *mwi_get_notify_data(struct ast_sip_subscription *sub)
return NULL;
}
+ if ((aor = find_aor_for_resource(endpoint, ast_sip_subscription_get_resource_name(sub)))) {
+ pjsip_dialog *dlg = ast_sip_subscription_get_dialog(sub);
+ pjsip_sip_uri *sip_uri = ast_sip_subscription_get_sip_uri(sub);
+
+ if (dlg && sip_uri) {
+ set_voicemail_extension(dlg->pool, sip_uri, counter, aor->voicemail_extension);
+ }
+ ao2_ref(aor, -1);
+ }
+ ao2_cleanup(endpoint);
+
ao2_callback(mwi_sub->stasis_subs, OBJ_NODATA, get_message_count, counter);
ao2_cleanup(mwi_datastore);
return counter;
@@ -1084,6 +1171,16 @@ static void mwi_startup_event_cb(void *data, struct stasis_subscription *sub, st
stasis_unsubscribe(sub);
}
+static void global_loaded(const char *object_type)
+{
+ ast_free(default_voicemail_extension);
+ default_voicemail_extension = ast_sip_get_default_voicemail_extension();
+}
+
+static struct ast_sorcery_observer global_observer = {
+ .loaded = global_loaded,
+};
+
static int reload(void)
{
create_mwi_subscriptions();
@@ -1106,6 +1203,8 @@ static int load_module(void)
create_mwi_subscriptions();
ast_sorcery_observer_add(ast_sip_get_sorcery(), "contact", &mwi_contact_observer);
+ ast_sorcery_observer_add(ast_sip_get_sorcery(), "global", &global_observer);
+ ast_sorcery_reload_object(ast_sip_get_sorcery(), "global");
if (ast_test_flag(&ast_options, AST_OPT_FLAG_FULLY_BOOTED)) {
ast_sip_push_task(NULL, send_initial_notify_all, NULL);
@@ -1120,8 +1219,10 @@ static int unload_module(void)
{
ao2_callback(unsolicited_mwi, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, unsubscribe, NULL);
ao2_ref(unsolicited_mwi, -1);
+ ast_sorcery_observer_remove(ast_sip_get_sorcery(), "global", &global_observer);
ast_sorcery_observer_remove(ast_sip_get_sorcery(), "contact", &mwi_contact_observer);
ast_sip_unregister_subscription_handler(&mwi_handler);
+ ast_free(default_voicemail_extension);
return 0;
}