[asterisk-commits] res pjsip mwi: Add voicemail extension and mwi subscribe re... (asterisk[master])

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Mon Apr 4 15:31:22 CDT 2016


Joshua Colp has submitted this change and it was merged.

Change subject: res_pjsip_mwi:  Add voicemail extension and mwi_subscribe_replaces_unsolicited
......................................................................


res_pjsip_mwi:  Add voicemail extension and mwi_subscribe_replaces_unsolicited

res_pjsip_mwi was missing the chan_sip "vmexten" functionality which adds
the Message-Account header to the MWI NOTIFY.  Also, specifying mailboxes
on endpoints for unsolicited mwi and on aors for subscriptions required
that the admin know in advance which the client wanted.  If you specified
mailboxes on the endpoint, subscriptions were rejected even if you also
specified mailboxes on the aor.

Voicemail extension:
* Added a global default_voicemail_extension which defaults to "".
* Added voicemail_extension to both endpoint and aor.
* Added ast_sip_subscription_get_dialog for support.
* Added ast_sip_subscription_get_sip_uri for support.

When an unsolicited NOTIFY is constructed, the From header is parsed, the
voicemail extension from the endpoint is substituted for the user, and the
result placed in the Message-Account field in the body.

When a subscribed NOTIFY is constructed, the subscription dialog local uri
is parsed, the voicemail_extension from the aor (looked up from the
subscription resource name) is substituted for the user, and the result
placed in the Message-Account field in the body.

If no voicemail extension was defined, the Message-Account field is not added
to the NOTIFY body.

mwi_subscribe_replaces_unsolicited:
* Added mwi_subscribe_replaces_unsolicited to endpoint.

The previous behavior was to reject a subscribe if a previous internal
subscription for unsolicited MWI was found for the mailbox.  That remains the
default.  However, if there are mailboxes also set on the aor and the client
subscribes and mwi_subscribe_replaces_unsolicited is set, the existing internal
subscription is removed and replaced with the external subscription.  This
allows an admin to configure mailboxes on both the endpoint and aor and allows
the client to select which to use.

ASTERISK-25865 #close
Reported-by: Ross Beer

Change-Id: Ic15a9415091760539c7134a5ba3dc4a6a1217cea
---
M configs/samples/pjsip.conf.sample
A contrib/ast-db-manage/config/versions/1c688d9a003c_pjsip_voicemail_extension.py
M include/asterisk/res_pjsip.h
M include/asterisk/res_pjsip_body_generator_types.h
M include/asterisk/res_pjsip_pubsub.h
M res/res_pjsip.c
M res/res_pjsip/config_global.c
M res/res_pjsip/location.c
M res/res_pjsip/pjsip_configuration.c
M res/res_pjsip_mwi.c
M res/res_pjsip_mwi_body_generator.c
M res/res_pjsip_pubsub.c
M res/res_pjsip_pubsub.exports.in
13 files changed, 288 insertions(+), 92 deletions(-)

Approvals:
  Matt Jordan: Looks good to me, but someone else must approve
  Joshua Colp: Looks good to me, approved; Verified



diff --git a/configs/samples/pjsip.conf.sample b/configs/samples/pjsip.conf.sample
index faa9285..94d1792 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 0000000..781dca7
--- /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 b0ae2ce..2c26c25 100644
--- a/include/asterisk/res_pjsip.h
+++ b/include/asterisk/res_pjsip.h
@@ -312,6 +312,8 @@
 	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 @@
 	);
 	/* 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_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 @@
 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 a2cc043..aab1472 100644
--- a/include/asterisk/res_pjsip_body_generator_types.h
+++ b/include/asterisk/res_pjsip_body_generator_types.h
@@ -65,6 +65,8 @@
 	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 c9b66dc..84d86fb 100644
--- a/include/asterisk/res_pjsip_pubsub.h
+++ b/include/asterisk/res_pjsip_pubsub.h
@@ -339,6 +339,14 @@
 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 @@
 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 b9d6cb6..f4dc725 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 c0fede6..ad03379 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 @@
 		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_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 @@
 		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 4008aba..3145dac 100644
--- a/res/res_pjsip/location.c
+++ b/res/res_pjsip/location.c
@@ -35,6 +35,7 @@
 
 	ao2_cleanup(aor->permanent_contacts);
 	ast_string_field_free_memory(aor);
+	ast_free(aor->voicemail_extension);
 }
 
 /*! \brief Allocator for AOR */
@@ -433,6 +434,24 @@
 	const struct ast_sip_aor *aor = obj;
 
 	ast_sip_for_each_contact(aor, contact_to_var_list, 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;
 }
@@ -987,6 +1006,7 @@
 	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 b497f02..baa5063 100644
--- a/res/res_pjsip/pjsip_configuration.c
+++ b/res/res_pjsip/pjsip_configuration.c
@@ -1052,6 +1052,23 @@
 	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 @@
 	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 @@
 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 be38b44..bb8f004 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 @@
 	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,26 +360,49 @@
 	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:
@@ -379,8 +423,10 @@
 	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 @@
 				"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 @@
 		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 @@
 		struct unsolicited_mwi_data mwi_data = {
 			.sub = sub,
 			.endpoint = endpoint,
-			.body = &body,
+			.counter = counter,
 		};
 
 		if (!aor) {
@@ -454,8 +477,6 @@
 
 		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 @@
 	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 @@
 	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 @@
 
 		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 @@
 	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) {
@@ -782,6 +820,16 @@
 	if (!counter) {
 		ao2_cleanup(mwi_datastore);
 		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);
@@ -1084,6 +1132,16 @@
 	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 @@
 
 	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 @@
 {
 	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 e4b39d5..f46ce04 100644
--- a/res/res_pjsip_mwi_body_generator.c
+++ b/res/res_pjsip_mwi_body_generator.c
@@ -46,7 +46,7 @@
 	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 @@
 			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 57ca95d..141c2fc 100644
--- a/res/res_pjsip_pubsub.c
+++ b/res/res_pjsip_pubsub.c
@@ -1644,6 +1644,12 @@
 	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 @@
 	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 6616524..a75103b 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:
 		*;
 };

-- 
To view, visit https://gerrit.asterisk.org/2485
To unsubscribe, visit https://gerrit.asterisk.org/settings

Gerrit-MessageType: merged
Gerrit-Change-Id: Ic15a9415091760539c7134a5ba3dc4a6a1217cea
Gerrit-PatchSet: 3
Gerrit-Project: asterisk
Gerrit-Branch: master
Gerrit-Owner: George Joseph <george.joseph at fairview5.com>
Gerrit-Reviewer: Anonymous Coward #1000019
Gerrit-Reviewer: Joshua Colp <jcolp at digium.com>
Gerrit-Reviewer: Matt Jordan <mjordan at digium.com>



More information about the asterisk-commits mailing list