@ -40,7 +40,7 @@
# include "asterisk/app.h"
struct mwi_subscription ;
AO2_GLOBAL_OBJ_STATIC ( unsolicited_mwi ) ;
static struct ao2_container * unsolicited_mwi ;
# define STASIS_BUCKETS 13
# define MWI_BUCKETS 53
@ -297,7 +297,7 @@ static int mwi_sub_cmp(void *obj, void *arg, int flags)
static int get_message_count ( void * obj , void * arg , int flags )
{
RAII_VAR ( struct stasis_message * , msg , NULL , ao2_cleanup ) ;
struct stasis_message * msg ;
struct mwi_stasis_subscription * mwi_stasis = obj ;
struct ast_sip_message_accumulator * counter = arg ;
struct ast_mwi_state * mwi_state ;
@ -310,6 +310,9 @@ static int get_message_count(void *obj, void *arg, int flags)
mwi_state = stasis_message_data ( msg ) ;
counter - > old_msgs + = mwi_state - > old_msgs ;
counter - > new_msgs + = mwi_state - > new_msgs ;
ao2_ref ( msg , - 1 ) ;
return 0 ;
}
@ -479,22 +482,24 @@ static int unsubscribe_stasis(void *obj, void *arg, int flags)
static void mwi_subscription_shutdown ( struct ast_sip_subscription * sub )
{
struct mwi_subscription * mwi_sub ;
RAII_VAR ( struct ast_datastore * , mwi_datastore ,
ast_sip_subscription_get_datastore ( sub , MWI_DATASTORE ) , ao2_cleanup ) ;
struct ast_datastore * mwi_datastore ;
mwi_datastore = ast_sip_subscription_get_datastore ( sub , MWI_DATASTORE ) ;
if ( ! mwi_datastore ) {
return ;
}
mwi_sub = mwi_datastore - > data ;
ao2_callback ( mwi_sub - > stasis_subs , OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE , unsubscribe_stasis , NULL ) ;
ao2_ref ( mwi_datastore , - 1 ) ;
}
static struct ast_datastore_info mwi_ds_info = { } ;
static int add_mwi_datastore ( struct mwi_subscription * sub )
{
RAII_VAR ( struct ast_datastore * , mwi_datastore , NULL , ao2_cleanup ) ;
struct ast_datastore * mwi_datastore ;
mwi_datastore = ast_sip_subscription_alloc_datastore ( & mwi_ds_info , MWI_DATASTORE ) ;
if ( ! mwi_datastore ) {
@ -503,6 +508,7 @@ static int add_mwi_datastore(struct mwi_subscription *sub)
mwi_datastore - > data = sub ;
ast_sip_subscription_add_datastore ( sub - > sip_sub , mwi_datastore ) ;
ao2_ref ( mwi_datastore , - 1 ) ;
return 0 ;
}
@ -517,18 +523,12 @@ static int add_mwi_datastore(struct mwi_subscription *sub)
static int endpoint_receives_unsolicited_mwi_for_mailbox ( struct ast_sip_endpoint * endpoint ,
const char * mailbox )
{
struct ao2_container * unsolicited = ao2_global_obj_ref ( unsolicited_mwi ) ;
struct ao2_iterator * mwi_subs ;
struct mwi_subscription * mwi_sub ;
const char * endpoint_id = ast_sorcery_object_get_id ( endpoint ) ;
int ret = 0 ;
if ( ! unsolicited ) {
return 0 ;
}
mwi_subs = ao2_find ( unsolicited , endpoint_id , OBJ_SEARCH_KEY | OBJ_MULTIPLE ) ;
ao2_cleanup ( unsolicited ) ;
mwi_subs = ao2_find ( unsolicited_mwi , endpoint_id , OBJ_SEARCH_KEY | OBJ_MULTIPLE ) ;
if ( ! mwi_subs ) {
return 0 ;
@ -597,11 +597,15 @@ static int mwi_on_aor(void *obj, void *arg, int flags)
mailboxes = ast_strdupa ( aor - > mailboxes ) ;
while ( ( mailbox = strsep ( & mailboxes , " , " ) ) ) {
RAII_VAR ( struct mwi_stasis_subscription * , mwi_stasis_sub ,
mwi_stasis_subscription_alloc ( mailbox , sub ) , ao2_cleanup ) ;
if ( mwi_stasis_sub ) {
ao2_link ( sub - > stasis_subs , mwi_stasis_sub ) ;
struct mwi_stasis_subscription * mwi_stasis_sub ;
mwi_stasis_sub = mwi_stasis_subscription_alloc ( mailbox , sub ) ;
if ( ! mwi_stasis_sub ) {
continue ;
}
ao2_link ( sub - > stasis_subs , mwi_stasis_sub ) ;
ao2_ref ( mwi_stasis_sub , - 1 ) ;
}
return 0 ;
@ -768,9 +772,9 @@ static void mwi_to_ami(struct ast_sip_subscription *sub,
struct ast_str * * buf )
{
struct mwi_subscription * mwi_sub ;
RAII_VAR ( struct ast_datastore * , mwi_datastore ,
ast_sip_subscription_get_datastore ( sub , MWI_DATASTORE ) , ao2_cleanup ) ;
struct ast_datastore * mwi_datastore ;
mwi_datastore = ast_sip_subscription_get_datastore ( sub , MWI_DATASTORE ) ;
if ( ! mwi_datastore ) {
return ;
}
@ -781,6 +785,8 @@ static void mwi_to_ami(struct ast_sip_subscription *sub,
ast_str_append ( buf , 0 , " Mailboxes: " ) ;
mwi_subscription_mailboxes_str ( mwi_sub - > stasis_subs , buf ) ;
ast_str_append ( buf , 0 , " \r \n " ) ;
ao2_ref ( mwi_datastore , - 1 ) ;
}
static int serialized_notify ( void * userdata )
@ -840,14 +846,38 @@ static int create_mwi_subscriptions_for_endpoint(void *obj, void *arg, int flags
{
RAII_VAR ( struct mwi_subscription * , aggregate_sub , NULL , ao2_cleanup ) ;
struct ast_sip_endpoint * endpoint = obj ;
struct ao2_container * mwi_subscriptions = arg ;
char * mailboxes ;
char * mailbox ;
char * endpoint_aors , * aor_name , * mailboxes , * mailbox ;
struct ao2_container * contacts = NULL ;
if ( ast_strlen_zero ( endpoint - > subscription . mwi . mailboxes ) ) {
return 0 ;
}
endpoint_aors = ast_strdupa ( endpoint - > aors ) ;
while ( ( aor_name = strsep ( & endpoint_aors , " , " ) ) ) {
RAII_VAR ( struct ast_sip_aor * , aor , ast_sip_location_retrieve_aor ( aor_name ) , ao2_cleanup ) ;
if ( ! aor ) {
continue ;
}
contacts = ast_sip_location_retrieve_aor_contacts ( aor ) ;
if ( ! contacts | | ( ao2_container_count ( contacts ) = = 0 ) ) {
ao2_cleanup ( contacts ) ;
contacts = NULL ;
continue ;
}
break ;
}
if ( ! contacts ) {
return 0 ;
}
ao2_ref ( contacts , - 1 ) ;
if ( endpoint - > subscription . mwi . aggregate ) {
aggregate_sub = mwi_subscription_alloc ( endpoint , 0 , NULL ) ;
if ( ! aggregate_sub ) {
@ -859,18 +889,20 @@ static int create_mwi_subscriptions_for_endpoint(void *obj, void *arg, int flags
while ( ( mailbox = strsep ( & mailboxes , " , " ) ) ) {
struct mwi_subscription * sub = aggregate_sub ? :
mwi_subscription_alloc ( endpoint , 0 , NULL ) ;
RAII_VAR ( struct mwi_stasis_subscription * , mwi_stasis_sub ,
mwi_stasis_subscription_alloc ( mailbox , sub ) , ao2_cleanup ) ;
struct mwi_stasis_subscription * mwi_stasis_sub ;
mwi_stasis_sub = mwi_stasis_subscription_alloc ( mailbox , sub ) ;
if ( mwi_stasis_sub ) {
ao2_link ( sub - > stasis_subs , mwi_stasis_sub ) ;
ao2_ref ( mwi_stasis_sub , - 1 ) ;
}
if ( ! aggregate_sub ) {
ao2_link ( mwi_subscriptions , sub ) ;
ao2_ cleanup( sub ) ;
if ( ! aggregate_sub & & sub ) {
ao2_link _flags( unsolicited_mwi , sub , OBJ_NOLOCK ) ;
ao2_ ref( sub , - 1 ) ;
}
}
if ( aggregate_sub ) {
ao2_link ( mwi_subscriptions , aggregate_sub ) ;
ao2_link _flags( unsolicited_mwi , aggregate_sub , OBJ_NOLOCK ) ;
}
return 0 ;
}
@ -886,13 +918,11 @@ static int unsubscribe(void *obj, void *arg, int flags)
static void create_mwi_subscriptions ( void )
{
struct ao2_container * mwi_subscriptions = ao2_container_alloc ( MWI_BUCKETS , mwi_sub_hash , mwi_sub_cmp ) ;
RAII_VAR ( struct ao2_container * , old_mwi_subscriptions , ao2_global_obj_ref ( unsolicited_mwi ) , ao2_cleanup ) ;
RAII_VAR ( struct ao2_container * , endpoints , ast_sorcery_retrieve_by_fields (
ast_sip_get_sorcery ( ) , " endpoint " , AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL , NULL ) ,
ao2_cleanup ) ;
struct ao2_container * endpoints ;
if ( ! mwi_subscriptions ) {
endpoints = ast_sorcery_retrieve_by_fields ( ast_sip_get_sorcery ( ) , " endpoint " ,
AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL , NULL ) ;
if ( ! endpoints ) {
return ;
}
@ -902,12 +932,12 @@ static void create_mwi_subscriptions(void)
* and resubscribing , up - to - date mailbox state will be sent out to the endpoint when the
* new stasis subscription is established
*/
if ( old_mwi_subscriptions ) {
ao2_callback ( old_mwi_subscriptions , OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE , unsubscribe , NULL ) ;
}
ao2_ callback( endpoints , OBJ_NODATA , create_mwi_subscriptions_for_endpoint , mwi_subscriptions ) ;
ao2_global_obj_replace_unref ( unsolicited_mwi , mwi_subscriptions ) ;
ao2_ref ( mwi_subscription s, - 1 ) ;
ao2_lock ( unsolicited_mwi ) ;
ao2_callback ( uns olicite d_mwi, OBJ_NOLOCK | OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE , unsubscribe , NULL ) ;
ao2_callback ( endpoints , OBJ_NODATA , create_mwi_subscriptions_for_endpoint , NULL ) ;
ao2_ unlock( unsolicited_mwi ) ;
ao2_ref ( endpoint s, - 1 ) ;
}
/*! \brief Function called to send MWI NOTIFY on any unsolicited mailboxes relating to this AOR */
@ -927,40 +957,56 @@ static int send_contact_notify(void *obj, void *arg, int flags)
return 0 ;
}
/*! \brief Function called when a contact is created or updated */
static void mwi_contact_changed_observer ( const void * object )
/*! \brief Function called when a contact is updated */
static void mwi_contact_updated ( const void * object )
{
char * id = ast_strdupa ( ast_sorcery_object_get_id ( object ) ) , * aor = NULL ;
struct ao2_container * mwi_subscriptions = ao2_global_obj_ref ( unsolicited_mwi ) ;
if ( ! mwi_subscriptions ) {
aor = strsep ( & id , " ;@ " ) ;
ao2_callback ( unsolicited_mwi , OBJ_NODATA , send_contact_notify , aor ) ;
}
/*! \brief Function called when a contact is added */
static void mwi_contact_added ( const void * object )
{
const struct ast_sip_contact * contact = object ;
struct ao2_iterator * mwi_subs ;
struct mwi_subscription * mwi_sub ;
const char * endpoint_id = ast_sorcery_object_get_id ( contact - > endpoint ) ;
if ( ast_strlen_zero ( contact - > endpoint - > subscription . mwi . mailboxes ) ) {
return ;
}
aor = strsep ( & id , " ;@ " ) ;
ao2_lock ( unsolicited_mwi ) ;
mwi_subs = ao2_find ( unsolicited_mwi , endpoint_id , OBJ_SEARCH_KEY | OBJ_MULTIPLE | OBJ_NOLOCK | OBJ_UNLINK ) ;
if ( mwi_subs ) {
for ( ; ( mwi_sub = ao2_iterator_next ( mwi_subs ) ) ; ao2_cleanup ( mwi_sub ) ) {
unsubscribe ( mwi_sub , NULL , 0 ) ;
}
ao2_iterator_destroy ( mwi_subs ) ;
}
create_mwi_subscriptions_for_endpoint ( contact - > endpoint , NULL , 0 ) ;
ao2_callback ( mwi_subscriptions , OBJ_NODATA , send_contact_notify , aor ) ;
ao2_ref ( mwi_subscriptions , - 1 ) ;
ao2_unlock ( unsolicited_mwi ) ;
mwi_contact_updated ( object ) ;
}
/*! \brief Observer for contacts so unsolicited MWI is sent when a contact changes */
static const struct ast_sorcery_observer mwi_contact_observer = {
. created = mwi_contact_changed_observer ,
. updated = mwi_contact_changed_observer ,
. created = mwi_contact_ added ,
. updated = mwi_contact_ updated ,
} ;
/*! \brief Task invoked to send initial MWI NOTIFY for unsolicited */
static int send_initial_notify_all ( void * obj )
{
struct ao2_container * mwi_subscriptions = ao2_global_obj_ref ( unsolicited_mwi ) ;
if ( ! mwi_subscriptions ) {
return 0 ;
}
ao2_callback ( mwi_subscriptions , OBJ_NODATA , send_notify , NULL ) ;
ao2_ref ( mwi_subscriptions , - 1 ) ;
ao2_callback ( unsolicited_mwi , OBJ_NODATA , send_notify , NULL ) ;
return 0 ;
}
@ -1000,6 +1046,13 @@ static int load_module(void)
if ( ast_sip_register_subscription_handler ( & mwi_handler ) ) {
return AST_MODULE_LOAD_DECLINE ;
}
unsolicited_mwi = ao2_container_alloc ( MWI_BUCKETS , mwi_sub_hash , mwi_sub_cmp ) ;
if ( ! unsolicited_mwi ) {
ast_sip_unregister_subscription_handler ( & mwi_handler ) ;
return AST_MODULE_LOAD_DECLINE ;
}
create_mwi_subscriptions ( ) ;
ast_sorcery_observer_add ( ast_sip_get_sorcery ( ) , " contact " , & mwi_contact_observer ) ;
@ -1014,12 +1067,9 @@ static int load_module(void)
static int unload_module ( void )
{
RAII_VAR ( struct ao2_container * , mwi_subscriptions , ao2_global_obj_ref ( unsolicited_mwi ) , ao2_cleanup ) ;
if ( mwi_subscriptions ) {
ao2_callback ( mwi_subscriptions , OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE , unsubscribe , NULL ) ;
ao2_global_obj_release ( unsolicited_mwi ) ;
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 ( ) , " contact " , & mwi_contact_observer ) ;
}
ast_sip_unregister_subscription_handler ( & mwi_handler ) ;
return 0 ;
}