diff options
-rw-r--r-- | configs/samples/pjsip.conf.sample | 28 | ||||
-rw-r--r-- | contrib/ast-db-manage/config/versions/1c688d9a003c_pjsip_voicemail_extension.py | 31 | ||||
-rw-r--r-- | include/asterisk/res_pjsip.h | 17 | ||||
-rw-r--r-- | include/asterisk/res_pjsip_body_generator_types.h | 2 | ||||
-rw-r--r-- | include/asterisk/res_pjsip_pubsub.h | 20 | ||||
-rw-r--r-- | res/res_pjsip.c | 12 | ||||
-rw-r--r-- | res/res_pjsip/config_global.c | 44 | ||||
-rw-r--r-- | res/res_pjsip/location.c | 20 | ||||
-rw-r--r-- | res/res_pjsip/pjsip_configuration.c | 20 | ||||
-rw-r--r-- | res/res_pjsip_mwi.c | 130 | ||||
-rw-r--r-- | res/res_pjsip_mwi_body_generator.c | 5 | ||||
-rw-r--r-- | res/res_pjsip_pubsub.c | 11 | ||||
-rw-r--r-- | res/res_pjsip_pubsub.exports.in | 40 |
13 files changed, 288 insertions, 92 deletions
diff --git a/configs/samples/pjsip.conf.sample b/configs/samples/pjsip.conf.sample index faa928598..94d179208 100644 --- a/configs/samples/pjsip.conf.sample +++ b/configs/samples/pjsip.conf.sample @@ -624,7 +624,14 @@ ; "username") ;redirect_method=user ; How redirects received from an endpoint are handled ; (default: "user") -;mailboxes= ; Mailbox es to be associated with (default: "") +;mailboxes= ; NOTIFY the endpoint when state changes for any of the specified mailboxes. + ; Asterisk will send unsolicited MWI NOTIFY messages to the endpoint when state + ; changes happen for any of the specified mailboxes. (default: "") +;voicemail_extension= ; The voicemail extension to send in the NOTIFY Message-Account header + ; (default: global/default_voicemail_extension) +;mwi_subscribe_replaces_unsolicited=no + ; An MWI subscribe will replace unsoliticed NOTIFYs + ; (default: "no") ;moh_suggest=default ; Default Music On Hold class (default: "default") ;moh_passthrough=yes ; Pass Music On Hold through using SIP re-invites with sendonly ; when placing on hold and sendrecv when taking off hold @@ -832,7 +839,11 @@ ;default_expiration=3600 ; Default expiration time in seconds for ; contacts that are dynamically bound to an AoR ; (default: "3600") -;mailboxes= ; Mailbox es to be associated with (default: "") +;mailboxes= ; Allow subscriptions for the specified mailbox(es) + ; This option applies when an external entity subscribes to an AoR + ; for Message Waiting Indications. (default: "") +;voicemail_extension= ; The voicemail extension to send in the NOTIFY Message-Account header + ; (default: global/default_voicemail_extension) ;maximum_expiration=7200 ; Maximum time to keep an AoR (default: "7200") ;max_contacts=0 ; Maximum number of contacts that can bind to an AoR (default: ; "0") @@ -904,10 +915,15 @@ ; startup that qualifies should be attempted on all ; contacts. If greater than the qualify_frequency ; for an aor, qualify_frequency will be used instead. -; If regcontext is specified, Asterisk will dynamically create and destroy a -; NoOp priority 1 extension for a given endpoint who registers or unregisters -; with us. The extension added is the name of the endpoint. -;regcontext=sipregistrations +;regcontext=sipregistrations ; If regcontext is specified, Asterisk will dynamically + ; create and destroy a NoOp priority 1 extension for a + ; given endpoint who registers or unregisters with us. + ; The extension added is the name of the endpoint. +;default_voicemail_extension=asterisk + ; The voicemail extension to send in the NOTIFY Message-Account header + ; if not set on endpoint or aor. + ; (default: "") + ; MODULE PROVIDING BELOW SECTION(S): res_pjsip_acl ;==========================ACL SECTION OPTIONS========================= diff --git a/contrib/ast-db-manage/config/versions/1c688d9a003c_pjsip_voicemail_extension.py b/contrib/ast-db-manage/config/versions/1c688d9a003c_pjsip_voicemail_extension.py new file mode 100644 index 000000000..781dca703 --- /dev/null +++ b/contrib/ast-db-manage/config/versions/1c688d9a003c_pjsip_voicemail_extension.py @@ -0,0 +1,31 @@ +"""pjsip voicemail extension + +Revision ID: 1c688d9a003c +Revises: 5813202e92be +Create Date: 2016-03-24 22:31:45.537895 + +""" + +# revision identifiers, used by Alembic. +revision = '1c688d9a003c' +down_revision = '5813202e92be' + +from alembic import op +import sqlalchemy as sa + + +def upgrade(): + op.add_column('ps_globals', sa.Column('default_voicemail_extension', sa.String(40))) + op.add_column('ps_aors', sa.Column('voicemail_extension', sa.String(40))) + op.add_column('ps_endpoints', sa.Column('voicemail_extension', sa.String(40))) + op.add_column('ps_endpoints', sa.Column('mwi_subscribe_replaces_unsolicited', sa.Integer)) + + +def downgrade(): + with op.batch_alter_table('ps_globals') as batch_op: + batch_op.drop_column('default_voicemail_extension') + with op.batch_alter_table('ps_aors') as batch_op: + batch_op.drop_column('voicemail_extension') + with op.batch_alter_table('ps_endpoints') as batch_op: + batch_op.drop_column('voicemail_extension') + batch_op.drop_column('mwi_subscribe_replaces_unsolicited') diff --git a/include/asterisk/res_pjsip.h b/include/asterisk/res_pjsip.h index b0ae2cefa..2c26c25da 100644 --- a/include/asterisk/res_pjsip.h +++ b/include/asterisk/res_pjsip.h @@ -312,6 +312,8 @@ struct ast_sip_aor { unsigned int support_path; /*! Qualify timeout. 0 is diabled. */ double qualify_timeout; + /* Voicemail extension to set in Message-Account */ + char *voicemail_extension; }; /*! @@ -466,6 +468,10 @@ struct ast_sip_mwi_configuration { ); /* Should mailbox states be combined into a single notification? */ unsigned int aggregate; + /* Should a subscribe replace unsolicited notifies? */ + unsigned int subscribe_replaces_unsolicited; + /* Voicemail extension to set in Message-Account */ + char *voicemail_extension; }; /*! @@ -2118,6 +2124,16 @@ char *ast_sip_get_regcontext(void); char *ast_sip_get_endpoint_identifier_order(void); /*! + * \brief Retrieve the default voicemail extension. + * \since 13.9.0 + * + * \note returned string needs to be de-allocated by caller. + * + * \retval the default voicemail extension + */ +char *ast_sip_get_default_voicemail_extension(void); + +/*! * \brief Retrieve the global default from user. * * This is the value placed in outbound requests' From header if there @@ -2265,4 +2281,5 @@ int ast_sip_set_tpselector_from_transport_name(const char *transport_name, pjsip void ast_sip_modify_id_header(pj_pool_t *pool, pjsip_fromto_hdr *id_hdr, const struct ast_party_id *id); + #endif /* _RES_PJSIP_H */ diff --git a/include/asterisk/res_pjsip_body_generator_types.h b/include/asterisk/res_pjsip_body_generator_types.h index a2cc04313..aab147238 100644 --- a/include/asterisk/res_pjsip_body_generator_types.h +++ b/include/asterisk/res_pjsip_body_generator_types.h @@ -65,6 +65,8 @@ struct ast_sip_message_accumulator { int old_msgs; /*! Number of new messages */ int new_msgs; + /*! Message-Account */ + char message_account[PJSIP_MAX_URL_SIZE]; }; #endif /* _RES_PJSIP_BODY_GENERATOR_TYPES_H */ diff --git a/include/asterisk/res_pjsip_pubsub.h b/include/asterisk/res_pjsip_pubsub.h index c9b66dce3..84d86fb9e 100644 --- a/include/asterisk/res_pjsip_pubsub.h +++ b/include/asterisk/res_pjsip_pubsub.h @@ -339,6 +339,14 @@ struct ast_sip_subscription_handler { struct ast_sip_subscription *ast_sip_create_subscription(const struct ast_sip_subscription_handler *handler, struct ast_sip_endpoint *endpoint, const char *resource); +/*! + * \brief Get the pjsip dialog that is associated with this subscription + * \since 13.9.0 + * + * \retval NULL Could not get dialog + * \retval non-NULL The dialog + */ +pjsip_dialog *ast_sip_subscription_get_dialog(struct ast_sip_subscription *sub); /*! * \brief Get the endpoint that is associated with this subscription @@ -379,6 +387,18 @@ struct ast_taskprocessor *ast_sip_subscription_get_serializer(struct ast_sip_sub int ast_sip_subscription_notify(struct ast_sip_subscription *sub, struct ast_sip_body_data *notify_data, int terminate); /*! + * \brief Retrieve the local sip uri for this subscription + * \since 13.9.0 + * + * This is the local sip URI of the subscribed resource. + * + * \param sub The subscription + * \retval NULL Could not get uri + * \retval non-NULL The local pjsip_sip_uri + */ +pjsip_sip_uri *ast_sip_subscription_get_sip_uri(struct ast_sip_subscription *sub); + +/*! * \brief Retrieve the local URI for this subscription * * This is the local URI of the subscribed resource. diff --git a/res/res_pjsip.c b/res/res_pjsip.c index b9d6cb6de..f4dc72549 100644 --- a/res/res_pjsip.c +++ b/res/res_pjsip.c @@ -302,6 +302,12 @@ configuration. </para></description> </configOption> + <configOption name="mwi_subscribe_replaces_unsolicited"> + <synopsis>An MWI subscribe will replace sending unsolicited NOTIFYs</synopsis> + </configOption> + <configOption name="voicemail_extension"> + <synopsis>The voicemail extension to send in the NOTIFY Message-Account header</synopsis> + </configOption> <configOption name="moh_suggest" default="default"> <synopsis>Default Music On Hold class</synopsis> </configOption> @@ -1138,6 +1144,9 @@ endpoint configuration section to enable unsolicited MWI NOTIFYs to the endpoint. </para></description> </configOption> + <configOption name="voicemail_extension"> + <synopsis>The voicemail extension to send in the NOTIFY Message-Account header</synopsis> + </configOption> <configOption name="maximum_expiration" default="7200"> <synopsis>Maximum time to keep an AoR</synopsis> <description><para> @@ -1302,6 +1311,9 @@ <configOption name="default_outbound_endpoint" default="default_outbound_endpoint"> <synopsis>Endpoint to use when sending an outbound request to a URI without a specified endpoint.</synopsis> </configOption> + <configOption name="default_voicemail_extension"> + <synopsis>The voicemail extension to send in the NOTIFY Message-Account header if not specified on endpoint or aor</synopsis> + </configOption> <configOption name="debug" default="no"> <synopsis>Enable/Disable SIP debug logging. Valid options include yes|no or a host address</synopsis> diff --git a/res/res_pjsip/config_global.c b/res/res_pjsip/config_global.c index c0fede64d..ad03379fd 100644 --- a/res/res_pjsip/config_global.c +++ b/res/res_pjsip/config_global.c @@ -37,6 +37,7 @@ #define DEFAULT_FROM_USER "asterisk" #define DEFAULT_REGCONTEXT "" #define DEFAULT_CONTACT_EXPIRATION_CHECK_INTERVAL 30 +#define DEFAULT_VOICEMAIL_EXTENSION "" static char default_useragent[256]; @@ -52,6 +53,8 @@ struct global_config { AST_STRING_FIELD(endpoint_identifier_order); /*! User name to place in From header if there is no better option */ AST_STRING_FIELD(default_from_user); + /*! Default voicemail extension */ + AST_STRING_FIELD(default_voicemail_extension); ); /* Value to put in Max-Forwards header */ unsigned int max_forwards; @@ -144,20 +147,35 @@ char *ast_sip_get_debug(void) char *ast_sip_get_regcontext(void) { - char *res; - struct global_config *cfg; + char *res; + struct global_config *cfg; - cfg = get_global_cfg(); - if (!cfg) { - return ast_strdup(DEFAULT_REGCONTEXT); - } + cfg = get_global_cfg(); + if (!cfg) { + return ast_strdup(DEFAULT_REGCONTEXT); + } - res = ast_strdup(cfg->regcontext); - ao2_ref(cfg, -1); + res = ast_strdup(cfg->regcontext); + ao2_ref(cfg, -1); - return res; + return res; } +char *ast_sip_get_default_voicemail_extension(void) +{ + char *res; + struct global_config *cfg; + + cfg = get_global_cfg(); + if (!cfg) { + return ast_strdup(DEFAULT_VOICEMAIL_EXTENSION); + } + + res = ast_strdup(cfg->default_voicemail_extension); + ao2_ref(cfg, -1); + + return res; +} char *ast_sip_get_endpoint_identifier_order(void) { @@ -347,12 +365,14 @@ int ast_sip_initialize_sorcery_global(void) OPT_UINT_T, 0, FLDSET(struct global_config, max_initial_qualify_time)); ast_sorcery_object_field_register(sorcery, "global", "default_from_user", DEFAULT_FROM_USER, OPT_STRINGFIELD_T, 0, STRFLDSET(struct global_config, default_from_user)); + ast_sorcery_object_field_register(sorcery, "global", "default_voicemail_extension", + DEFAULT_VOICEMAIL_EXTENSION, OPT_STRINGFIELD_T, 0, STRFLDSET(struct global_config, + default_voicemail_extension)); ast_sorcery_object_field_register(sorcery, "global", "regcontext", DEFAULT_REGCONTEXT, - OPT_STRINGFIELD_T, 0, STRFLDSET(struct global_config, regcontext)); + OPT_UINT_T, 0, FLDSET(struct global_config, contact_expiration_check_interval)); ast_sorcery_object_field_register(sorcery, "global", "contact_expiration_check_interval", __stringify(DEFAULT_CONTACT_EXPIRATION_CHECK_INTERVAL), - OPT_UINT_T, 0, FLDSET(struct global_config, contact_expiration_check_interval)); - + OPT_STRINGFIELD_T, 0, STRFLDSET(struct global_config, regcontext)); if (ast_sorcery_instance_observer_add(sorcery, &observer_callbacks_global)) { return -1; diff --git a/res/res_pjsip/location.c b/res/res_pjsip/location.c index 4008abad1..3145daca0 100644 --- a/res/res_pjsip/location.c +++ b/res/res_pjsip/location.c @@ -35,6 +35,7 @@ static void aor_destroy(void *obj) ao2_cleanup(aor->permanent_contacts); ast_string_field_free_memory(aor); + ast_free(aor->voicemail_extension); } /*! \brief Allocator for AOR */ @@ -437,6 +438,24 @@ static int contacts_to_var_list(const void *obj, struct ast_variable **fields) return 0; } +static int voicemail_extension_handler(const struct aco_option *opt, struct ast_variable *var, void *obj) +{ + struct ast_sip_aor *aor = obj; + + aor->voicemail_extension = ast_strdup(var->value); + + return aor->voicemail_extension ? 0 : -1; +} + +static int voicemail_extension_to_str(const void *obj, const intptr_t *args, char **buf) +{ + const struct ast_sip_aor *aor = obj; + + *buf = ast_strdup(aor->voicemail_extension); + + return 0; +} + int ast_sip_for_each_aor(const char *aors, ao2_callback_fn on_aor, void *arg) { char *copy, *name; @@ -987,6 +1006,7 @@ int ast_sip_initialize_sorcery_location(void) ast_sorcery_object_field_register(sorcery, "aor", "remove_existing", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_aor, remove_existing)); ast_sorcery_object_field_register_custom(sorcery, "aor", "contact", "", permanent_uri_handler, contacts_to_str, contacts_to_var_list, 0, 0); ast_sorcery_object_field_register(sorcery, "aor", "mailboxes", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_aor, mailboxes)); + ast_sorcery_object_field_register_custom(sorcery, "aor", "voicemail_extension", "", voicemail_extension_handler, voicemail_extension_to_str, NULL, 0, 0); ast_sorcery_object_field_register(sorcery, "aor", "outbound_proxy", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_aor, outbound_proxy)); ast_sorcery_object_field_register(sorcery, "aor", "support_path", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_aor, support_path)); diff --git a/res/res_pjsip/pjsip_configuration.c b/res/res_pjsip/pjsip_configuration.c index b497f02a2..baa5063e4 100644 --- a/res/res_pjsip/pjsip_configuration.c +++ b/res/res_pjsip/pjsip_configuration.c @@ -1052,6 +1052,23 @@ static int set_var_to_vl(const void *obj, struct ast_variable **fields) return 0; } +static int voicemail_extension_handler(const struct aco_option *opt, struct ast_variable *var, void *obj) +{ + struct ast_sip_endpoint *endpoint = obj; + + endpoint->subscription.mwi.voicemail_extension = ast_strdup(var->value); + + return endpoint->subscription.mwi.voicemail_extension ? 0 : -1; +} + +static int voicemail_extension_to_str(const void *obj, const intptr_t *args, char **buf) +{ + const struct ast_sip_endpoint *endpoint = obj; + + *buf = ast_strdup(endpoint->subscription.mwi.voicemail_extension); + + return 0; +} static void *sip_nat_hook_alloc(const char *name) { @@ -1647,7 +1664,9 @@ int ast_res_pjsip_initialize_configuration(void) ast_sorcery_object_field_register(sip_sorcery, "endpoint", "rpid_immediate", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, id.rpid_immediate)); ast_sorcery_object_field_register(sip_sorcery, "endpoint", "send_diversion", "yes", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, id.send_diversion)); ast_sorcery_object_field_register(sip_sorcery, "endpoint", "mailboxes", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, subscription.mwi.mailboxes)); + ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "voicemail_extension", "", voicemail_extension_handler, voicemail_extension_to_str, NULL, 0, 0); ast_sorcery_object_field_register(sip_sorcery, "endpoint", "aggregate_mwi", "yes", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, subscription.mwi.aggregate)); + ast_sorcery_object_field_register(sip_sorcery, "endpoint", "mwi_subscribe_replaces_unsolicited", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, subscription.mwi.subscribe_replaces_unsolicited)); ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "media_encryption", "no", media_encryption_handler, media_encryption_to_str, NULL, 0, 0); ast_sorcery_object_field_register(sip_sorcery, "endpoint", "use_avpf", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.rtp.use_avpf)); ast_sorcery_object_field_register(sip_sorcery, "endpoint", "force_avp", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.rtp.force_avp)); @@ -1799,6 +1818,7 @@ int ast_res_pjsip_reload_configuration(void) static void subscription_configuration_destroy(struct ast_sip_endpoint_subscription_configuration *subscription) { ast_string_field_free_memory(&subscription->mwi); + ast_free(subscription->mwi.voicemail_extension); } static void info_configuration_destroy(struct ast_sip_endpoint_info_configuration *info) diff --git a/res/res_pjsip_mwi.c b/res/res_pjsip_mwi.c index be38b44c1..bb8f004e3 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,9 +423,11 @@ 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; } @@ -392,12 +438,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 +450,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 +461,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 +477,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,6 +484,7 @@ 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, @@ -472,7 +494,17 @@ static void send_mwi_notify(struct mwi_subscription *sub) ao2_callback(sub->stasis_subs, OBJ_NODATA, get_message_count, &counter); if (sub->is_solicited) { + struct ast_sip_aor *aor = ast_sip_location_retrieve_aor(ast_sip_subscription_get_resource_name(sub->sip_sub)); + 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); ast_sip_subscription_notify(sub->sip_sub, &data, 0); + return; } @@ -565,7 +597,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); } } @@ -771,6 +808,7 @@ 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; mwi_datastore = ast_sip_subscription_get_datastore(sub, MWI_DATASTORE); if (!mwi_datastore) { @@ -784,6 +822,16 @@ static void *mwi_get_notify_data(struct ast_sip_subscription *sub) return NULL; } + if ((aor = ast_sip_location_retrieve_aor(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_callback(mwi_sub->stasis_subs, OBJ_NODATA, get_message_count, counter); ao2_cleanup(mwi_datastore); return counter; @@ -1084,6 +1132,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 +1164,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 +1180,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; } diff --git a/res/res_pjsip_mwi_body_generator.c b/res/res_pjsip_mwi_body_generator.c index e4b39d534..f46ce04e3 100644 --- a/res/res_pjsip_mwi_body_generator.c +++ b/res/res_pjsip_mwi_body_generator.c @@ -46,7 +46,7 @@ static void *mwi_allocate_body(void *data) if (!mwi_str) { return NULL; } - *mwi_str = ast_str_create(64); + *mwi_str = ast_str_create(128); if (!*mwi_str) { ast_free(mwi_str); return NULL; @@ -63,6 +63,9 @@ static int mwi_generate_body_content(void *body, void *data) counter->new_msgs ? "yes" : "no"); ast_str_append(mwi, 0, "Voice-Message: %d/%d (0/0)\r\n", counter->new_msgs, counter->old_msgs); + if (!ast_strlen_zero(counter->message_account)) { + ast_str_append(mwi, 0, "Message-Account: %s\r\n", counter->message_account); + } return 0; } diff --git a/res/res_pjsip_pubsub.c b/res/res_pjsip_pubsub.c index 57ca95d8c..141c2fcf4 100644 --- a/res/res_pjsip_pubsub.c +++ b/res/res_pjsip_pubsub.c @@ -1644,6 +1644,12 @@ struct ast_sip_subscription *ast_sip_create_subscription(const struct ast_sip_su return sub; } +pjsip_dialog *ast_sip_subscription_get_dialog(struct ast_sip_subscription *sub) +{ + ast_assert(sub->tree->dlg != NULL); + return sub->tree->dlg; +} + struct ast_sip_endpoint *ast_sip_subscription_get_endpoint(struct ast_sip_subscription *sub) { ast_assert(sub->tree->endpoint != NULL); @@ -2271,6 +2277,11 @@ int ast_sip_subscription_notify(struct ast_sip_subscription *sub, struct ast_sip return res; } +pjsip_sip_uri *ast_sip_subscription_get_sip_uri(struct ast_sip_subscription *sub) +{ + return sub->uri; +} + void ast_sip_subscription_get_local_uri(struct ast_sip_subscription *sub, char *buf, size_t size) { pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR, sub->uri, buf, size); diff --git a/res/res_pjsip_pubsub.exports.in b/res/res_pjsip_pubsub.exports.in index 661652489..a75103bb6 100644 --- a/res/res_pjsip_pubsub.exports.in +++ b/res/res_pjsip_pubsub.exports.in @@ -1,44 +1,6 @@ { global: - LINKER_SYMBOL_PREFIXast_sip_create_subscription; - LINKER_SYMBOL_PREFIXast_sip_subscription_get_endpoint; - LINKER_SYMBOL_PREFIXast_sip_subscription_get_serializer; - LINKER_SYMBOL_PREFIXast_sip_subscription_get_evsub; - LINKER_SYMBOL_PREFIXast_sip_subscription_get_dlg; - LINKER_SYMBOL_PREFIXast_sip_subscription_accept; - LINKER_SYMBOL_PREFIXast_sip_subscription_send_request; - LINKER_SYMBOL_PREFIXast_sip_subscription_alloc_datastore; - LINKER_SYMBOL_PREFIXast_sip_subscription_add_datastore; - LINKER_SYMBOL_PREFIXast_sip_subscription_get_datastore; - LINKER_SYMBOL_PREFIXast_sip_subscription_remove_datastore; - LINKER_SYMBOL_PREFIXast_sip_register_subscription_handler; - LINKER_SYMBOL_PREFIXast_sip_unregister_subscription_handler; - LINKER_SYMBOL_PREFIXast_sip_create_publication; - LINKER_SYMBOL_PREFIXast_sip_publication_get_endpoint; - LINKER_SYMBOL_PREFIXast_sip_publication_get_resource; - LINKER_SYMBOL_PREFIXast_sip_publication_get_event_configuration; - LINKER_SYMBOL_PREFIXast_sip_publication_create_response; - LINKER_SYMBOL_PREFIXast_sip_publication_send_response; - LINKER_SYMBOL_PREFIXast_sip_register_publish_handler; - LINKER_SYMBOL_PREFIXast_sip_unregister_publish_handler; - LINKER_SYMBOL_PREFIXast_sip_publication_add_datastore; - LINKER_SYMBOL_PREFIXast_sip_publication_get_datastore; - LINKER_SYMBOL_PREFIXast_sip_publication_remove_datastore; - LINKER_SYMBOL_PREFIXast_sip_publication_remove_datastore; - LINKER_SYMBOL_PREFIXast_sip_pubsub_register_body_generator; - LINKER_SYMBOL_PREFIXast_sip_pubsub_unregister_body_generator; - LINKER_SYMBOL_PREFIXast_sip_pubsub_register_body_supplement; - LINKER_SYMBOL_PREFIXast_sip_pubsub_unregister_body_supplement; - LINKER_SYMBOL_PREFIXast_sip_pubsub_generate_body_content; - LINKER_SYMBOL_PREFIXast_sip_subscription_get_body_type; - LINKER_SYMBOL_PREFIXast_sip_subscription_get_body_subtype; - LINKER_SYMBOL_PREFIXast_sip_subscription_get_resource_name; - LINKER_SYMBOL_PREFIXast_sip_subscription_notify; - LINKER_SYMBOL_PREFIXast_sip_subscription_get_local_uri; - LINKER_SYMBOL_PREFIXast_sip_subscription_get_remote_uri; - LINKER_SYMBOL_PREFIXast_sip_subscription_get_header; - LINKER_SYMBOL_PREFIXast_sip_subscription_is_terminated; - LINKER_SYMBOL_PREFIXast_sip_subscription_destroy; + LINKER_SYMBOL_PREFIXast_sip_*; local: *; }; |