diff options
Diffstat (limited to 'res/res_pjsip_mwi.c')
-rw-r--r-- | res/res_pjsip_mwi.c | 189 |
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; } |