@ -1016,43 +1016,8 @@ static ast_cond_t poll_cond = PTHREAD_COND_INITIALIZER;
static pthread_t poll_thread = AST_PTHREADT_NULL ;
static unsigned char poll_thread_run ;
/*! Subscription to MWI event subscription changes */
static struct stasis_subscription * mwi_sub_sub ;
/*!
* \ brief An MWI subscription
*
* This is so we can keep track of which mailboxes are subscribed to .
* This way , we know which mailboxes to poll when the pollmailboxes
* option is being used .
*/
struct mwi_sub {
AST_RWLIST_ENTRY ( mwi_sub ) entry ;
int old_urgent ;
int old_new ;
int old_old ;
char * uniqueid ;
char mailbox [ 0 ] ;
} ;
struct mwi_sub_task {
const char * mailbox ;
const char * context ;
const char * uniqueid ;
} ;
static void mwi_sub_task_dtor ( struct mwi_sub_task * mwist )
{
ast_free ( ( void * ) mwist - > mailbox ) ;
ast_free ( ( void * ) mwist - > context ) ;
ast_free ( ( void * ) mwist - > uniqueid ) ;
ast_free ( mwist ) ;
}
static struct ast_taskprocessor * mwi_subscription_tps ;
static AST_RWLIST_HEAD_STATIC ( mwi_subs , mwi_sub ) ;
struct alias_mailbox_mapping {
char * alias ;
char * mailbox ;
@ -6316,7 +6281,7 @@ static int inboxcount(const char *mailbox, int *newmsgs, int *oldmsgs)
return res ;
}
static void run_externnotify ( char * context , char * extension , const char * flag )
static void run_externnotify ( const char * context , const char * extension , const char * flag )
{
char arguments [ 255 ] ;
char ext_context [ 256 ] = " " ;
@ -13197,38 +13162,29 @@ static struct ast_cli_entry cli_voicemail[] = {
AST_CLI_DEFINE ( handle_voicemail_reload , " Reload voicemail configuration " ) ,
} ;
static void poll_subscribed_mailbox ( struct mwi_sub * mwi_sub )
static int poll_subscribed_mailbox ( struct ast_mwi_state * mwi_state , void * data )
{
int new = 0 , old = 0 , urgent = 0 ;
inboxcount2 ( mwi_sub - > mailbox , & urgent , & new , & old ) ;
if ( ! mwi_state ) {
/* This should only occur due to allocation failure of a default mwi state object */
return 0 ;
}
inboxcount2 ( mwi_state - > uniqueid , & urgent , & new , & old ) ;
# ifdef IMAP_STORAGE
if ( imap_poll_logout ) {
imap_logout ( mwi_sub - > mailbox ) ;
imap_logout ( mwi_s tate- > uniqueid ) ;
}
# endif
if ( urgent ! = mwi_sub - > old_urgent | | new ! = mwi_sub - > old_new | | old ! = mwi_sub - > old_old ) {
mwi_sub - > old_urgent = urgent ;
mwi_sub - > old_new = new ;
mwi_sub - > old_old = old ;
queue_mwi_event ( NULL , mwi_sub - > mailbox , urgent , new , old ) ;
run_externnotify ( NULL , mwi_sub - > mailbox , NULL ) ;
if ( urgent ! = mwi_state - > urgent_msgs | | new ! = mwi_state - > new_msgs | | old ! = mwi_state - > old_msgs ) {
queue_mwi_event ( NULL , mwi_state - > uniqueid , urgent , new , old ) ;
run_externnotify ( NULL , mwi_state - > uniqueid , NULL ) ;
}
}
static void poll_subscribed_mailboxes ( void )
{
struct mwi_sub * mwi_sub ;
AST_RWLIST_RDLOCK ( & mwi_subs ) ;
AST_RWLIST_TRAVERSE ( & mwi_subs , mwi_sub , entry ) {
if ( ! ast_strlen_zero ( mwi_sub - > mailbox ) ) {
poll_subscribed_mailbox ( mwi_sub ) ;
}
}
AST_RWLIST_UNLOCK ( & mwi_subs ) ;
return 0 ;
}
static void * mb_poll_thread ( void * data )
@ -13237,6 +13193,12 @@ static void *mb_poll_thread(void *data)
struct timespec ts = { 0 , } ;
struct timeval wait ;
ast_mwi_state_callback_subscribed ( poll_subscribed_mailbox , NULL ) ;
if ( ! poll_thread_run ) {
break ;
}
wait = ast_tvadd ( ast_tvnow ( ) , ast_samp2tv ( poll_freq , 1 ) ) ;
ts . tv_sec = wait . tv_sec ;
ts . tv_nsec = wait . tv_usec * 1000 ;
@ -13244,22 +13206,11 @@ static void *mb_poll_thread(void *data)
ast_mutex_lock ( & poll_lock ) ;
ast_cond_timedwait ( & poll_cond , & poll_lock , & ts ) ;
ast_mutex_unlock ( & poll_lock ) ;
if ( ! poll_thread_run )
break ;
poll_subscribed_mailboxes ( ) ;
}
return NULL ;
}
static void mwi_sub_destroy ( struct mwi_sub * mwi_sub )
{
ast_free ( mwi_sub - > uniqueid ) ;
ast_free ( mwi_sub ) ;
}
# ifdef IMAP_STORAGE
static void imap_logout ( const char * mailbox_id )
{
@ -13295,157 +13246,74 @@ static void imap_logout(const char *mailbox_id)
vmstate_delete ( vms ) ;
}
static void imap_close_subscribed_mailboxes ( void )
{
struct mwi_sub * mwi_sub ;
AST_RWLIST_RDLOCK ( & mwi_subs ) ;
AST_RWLIST_TRAVERSE ( & mwi_subs , mwi_sub , entry ) {
if ( ! ast_strlen_zero ( mwi_sub - > mailbox ) ) {
imap_logout ( mwi_sub - > mailbox ) ;
}
}
AST_RWLIST_UNLOCK ( & mwi_subs ) ;
}
# endif
static int handle_unsubscribe ( void * datap )
static int imap_close_subscribed_mailbox ( struct ast_mwi_state * mwi_state , void * data )
{
struct mwi_sub * mwi_sub ;
char * uniqueid = datap ;
AST_RWLIST_WRLOCK ( & mwi_subs ) ;
AST_RWLIST_TRAVERSE_SAFE_BEGIN ( & mwi_subs , mwi_sub , entry ) {
if ( ! strcmp ( mwi_sub - > uniqueid , uniqueid ) ) {
AST_LIST_REMOVE_CURRENT ( entry ) ;
/* Don't break here since a duplicate uniqueid
* may have been added as a result of a cache dump . */
# ifdef IMAP_STORAGE
imap_logout ( mwi_sub - > mailbox ) ;
# endif
mwi_sub_destroy ( mwi_sub ) ;
}
if ( mwi_state & & ! ast_strlen_zero ( mwi_state - > uniqueid ) ) {
imap_logout ( mwi_state - > uniqueid ) ;
}
AST_RWLIST_TRAVERSE_SAFE_END
AST_RWLIST_UNLOCK ( & mwi_subs ) ;
ast_free ( uniqueid ) ;
return 0 ;
}
static int handle_subscribe ( void * datap )
{
unsigned int len ;
struct mwi_sub * mwi_sub ;
struct mwi_sub_task * p = datap ;
len = sizeof ( * mwi_sub ) + 1 ;
if ( ! ast_strlen_zero ( p - > mailbox ) )
len + = strlen ( p - > mailbox ) ;
if ( ! ast_strlen_zero ( p - > context ) )
len + = strlen ( p - > context ) + 1 ; /* Allow for seperator */
# endif
if ( ! ( mwi_sub = ast_calloc ( 1 , len ) ) )
return - 1 ;
static int mwi_handle_unsubscribe2 ( void * data )
{
struct ast_mwi_state * mwi_state = data ;
mwi_sub - > uniqueid = ast_strdup ( p - > uniqueid ) ;
if ( ! ast_strlen_zero ( p - > mailbox ) )
strcpy ( mwi_sub - > mailbox , p - > mailbox ) ;
/*
* Go ahead and clear the implicit MWI publisher here to avoid a leak . If a backing
* configuration is available it ' ll re - initialize ( reset the cached state ) on its
* next publish .
*/
ast_delete_mwi_state_full ( mwi_state - > uniqueid , NULL , NULL ) ;
if ( ! ast_strlen_zero ( p - > context ) ) {
strcat ( mwi_sub - > mailbox , " @ " ) ;
strcat ( mwi_sub - > mailbox , p - > context ) ;
}
# ifdef IMAP_STORAGE
imap_close_subscribed_mailbox ( mwi_state , NULL ) ;
# endif
AST_RWLIST_WRLOCK ( & mwi_subs ) ;
AST_RWLIST_INSERT_TAIL ( & mwi_subs , mwi_sub , entry ) ;
AST_RWLIST_UNLOCK ( & mwi_subs ) ;
mwi_sub_task_dtor ( p ) ;
poll_subscribed_mailbox ( mwi_sub ) ;
ao2_ref ( mwi_state , - 1 ) ;
return 0 ;
}
static void mwi_ unsub_event_cb( struct stasis_subscription_change * change )
static void mwi_handle_unsubscribe ( const char * id , struct ast_mwi_subscriber * sub )
{
char * uniqueid = ast_strdup ( change - > uniqueid ) ;
if ( ! uniqueid ) {
ast_log ( LOG_ERROR , " Unable to allocate memory for uniqueid \n " ) ;
return ;
}
void * data = ast_mwi_subscriber_data ( sub ) ;
if ( ast_taskprocessor_push ( mwi_subscription_tps , handle_unsubscribe , uniqueid ) < 0 ) {
ast_free ( uniqueid ) ;
/* Don't bump data's reference. We'll just use the one returned above */
if ( ast_taskprocessor_push ( mwi_subscription_tps , mwi_handle_unsubscribe2 , data ) < 0 ) {
/* A reference was returned for data when retrieving, so remove it on error */
ao2_ref ( data , - 1 ) ;
}
}
static void mwi_sub_event_cb ( struct stasis_subscription_change * change )
static int mwi_handle_subscribe2 ( void * data )
{
struct mwi_sub_task * mwist ;
const char * topic ;
char * context ;
char * mailbox ;
mwist = ast_calloc ( 1 , ( sizeof ( * mwist ) ) ) ;
if ( ! mwist ) {
return ;
}
/* The topic name is prefixed with "mwi:all/" as this is a pool topic */
topic = stasis_topic_name ( change - > topic ) + 8 ;
if ( separate_mailbox ( ast_strdupa ( topic ) , & mailbox , & context ) ) {
ast_free ( mwist ) ;
return ;
}
mwist - > mailbox = ast_strdup ( mailbox ) ;
mwist - > context = ast_strdup ( context ) ;
mwist - > uniqueid = ast_strdup ( change - > uniqueid ) ;
if ( ast_taskprocessor_push ( mwi_subscription_tps , handle_subscribe , mwist ) < 0 ) {
mwi_sub_task_dtor ( mwist ) ;
}
poll_subscribed_mailbox ( data , NULL ) ;
ao2_ref ( data , - 1 ) ;
return 0 ;
}
static void mwi_ event_cb( void * userdata , struct stasis_subscription * sub , struct stasis_message * msg )
static void mwi_handle_subscribe ( const char * id , struct ast_mwi_subscriber * sub )
{
struct stasis_subscription_change * change ;
/* Only looking for subscription change notices here */
if ( stasis_message_type ( msg ) ! = stasis_subscription_change_type ( ) ) {
return ;
}
change = stasis_message_data ( msg ) ;
if ( change - > topic = = ast_mwi_topic_all ( ) ) {
return ;
}
void * data = ast_mwi_subscriber_data ( sub ) ;
if ( ! strcmp ( change - > description , " Subscribe " ) ) {
mwi_sub_event_cb ( change ) ;
} else if ( ! strcmp ( change - > description , " Unsubscribe " ) ) {
mwi_unsub_event_cb( change ) ;
/* Don't bump data's reference. We'll just use the one returned above */
if ( ast_taskprocessor_push ( mwi_subscription_tps , mwi_handle_subscribe2 , data ) < 0 ) {
/* A reference was returned for data when retrieving, so remove it on error */
ao2_ref ( data , - 1 ) ;
}
}
static int dump_cache ( void * obj , void * arg , int flags )
{
struct stasis_message * msg = obj ;
mwi_event_cb ( NULL , NULL , msg ) ;
return 0 ;
}
struct ast_mwi_observer mwi_observer = {
. on_subscribe = mwi_handle_subscribe ,
. on_unsubscribe = mwi_handle_unsubscribe ,
} ;
static void start_poll_thread ( void )
{
int errcode ;
mwi_sub_sub = stasis_subscribe ( ast_mwi_topic_all ( ) , mwi_event_cb , NULL ) ;
if ( mwi_sub_sub ) {
struct ao2_container * cached = stasis_cache_dump ( ast_mwi_state_cache ( ) , stasis_subscription_change_type ( ) ) ;
if ( cached ) {
ao2_callback ( cached , OBJ_MULTIPLE | OBJ_NODATA , dump_cache , NULL ) ;
}
ao2_cleanup ( cached ) ;
}
ast_mwi_add_observer ( & mwi_observer ) ;
poll_thread_run = 1 ;
@ -13458,15 +13326,14 @@ static void stop_poll_thread(void)
{
poll_thread_run = 0 ;
mwi_sub_sub = stasis_unsubscribe_and_join ( mwi_sub_sub ) ;
ast_mutex_lock ( & poll_lock ) ;
ast_cond_signal ( & poll_cond ) ;
ast_mutex_unlock ( & poll_lock ) ;
pthread_join ( poll_thread , NULL ) ;
poll_thread = AST_PTHREADT_NULL ;
ast_mwi_remove_observer ( & mwi_observer ) ;
}
/*!
@ -13590,38 +13457,40 @@ static int append_vmu_info_astman(
}
static int manager_ voicemail_refresh( struct mansession * s , const struct message * m )
static int manager_ match_mailbox( struct ast_mwi_state * mwi_state , void * data )
{
const char * context = astman_get_header ( m , " Context " ) ;
const char * mailbox = astman_get_header ( m , " Mailbox " ) ;
struct mwi_sub * mwi_sub ;
const char * context = astman_get_header ( data , " Context " ) ;
const char * mailbox = astman_get_header ( data , " Mailbox " ) ;
const char * at ;
AST_RWLIST_RDLOCK ( & mwi_subs ) ;
AST_RWLIST_TRAVERSE ( & mwi_subs , mwi_sub , entry ) {
if ( ! ast_strlen_zero ( mwi_sub - > mailbox ) ) {
if (
/* First case: everything matches */
( ast_strlen_zero ( context ) & & ast_strlen_zero ( mailbox ) ) | |
/* Second case: match the mailbox only */
( ast_strlen_zero ( context ) & & ! ast_strlen_zero ( mailbox ) & &
( at = strchr ( mwi_sub - > mailbox , ' @ ' ) ) & &
strncmp ( mailbox , mwi_sub - > mailbox , at - mwi_sub - > mailbox ) = = 0 ) | |
/* Third case: match the context only */
( ! ast_strlen_zero ( context ) & & ast_strlen_zero ( mailbox ) & &
( at = strchr ( mwi_sub - > mailbox , ' @ ' ) ) & &
strcmp ( context , at + 1 ) = = 0 ) | |
/* Final case: match an exact specified mailbox */
( ! ast_strlen_zero ( context ) & & ! ast_strlen_zero ( mailbox ) & &
( at = strchr ( mwi_sub - > mailbox , ' @ ' ) ) & &
strncmp ( mailbox , mwi_sub - > mailbox , at - mwi_sub - > mailbox ) = = 0 & &
strcmp ( context , at + 1 ) = = 0 )
if ( ! ast_strlen_zero ( mwi_state - > uniqueid ) ) {
if (
/* First case: everything matches */
( ast_strlen_zero ( context ) & & ast_strlen_zero ( mailbox ) ) | |
/* Second case: match the mailbox only */
( ast_strlen_zero ( context ) & & ! ast_strlen_zero ( mailbox ) & &
( at = strchr ( mwi_state - > uniqueid , ' @ ' ) ) & &
strncmp ( mailbox , mwi_state - > uniqueid , at - mwi_state - > uniqueid ) = = 0 ) | |
/* Third case: match the context only */
( ! ast_strlen_zero ( context ) & & ast_strlen_zero ( mailbox ) & &
( at = strchr ( mwi_state - > uniqueid , ' @ ' ) ) & &
strcmp ( context , at + 1 ) = = 0 ) | |
/* Final case: match an exact specified mailbox */
( ! ast_strlen_zero ( context ) & & ! ast_strlen_zero ( mailbox ) & &
( at = strchr ( mwi_state - > uniqueid , ' @ ' ) ) & &
strncmp ( mailbox , mwi_state - > uniqueid , at - mwi_state - > uniqueid ) = = 0 & &
strcmp ( context , at + 1 ) = = 0 )
) {
poll_subscribed_mailbox ( mwi_sub ) ;
}
poll_subscribed_mailbox ( mwi_state , NULL ) ;
}
}
AST_RWLIST_UNLOCK ( & mwi_subs ) ;
return 0 ;
}
static int manager_voicemail_refresh ( struct mansession * s , const struct message * m )
{
ast_mwi_state_callback_all ( manager_match_mailbox , ( void * ) m ) ;
astman_send_ack ( s , m , " Refresh sent " ) ;
return RESULT_SUCCESS ;
}
@ -13943,7 +13812,7 @@ static int actual_load_config(int reload, struct ast_config *cfg, struct ast_con
strcpy ( listen_control_stop_key , DEFAULT_LISTEN_CONTROL_STOP_KEY ) ;
# ifdef IMAP_STORAGE
imap_close_subscribed_mailboxes( ) ;
ast_mwi_state_callback_all( imap_close_subscribed_mailbox , NULL ) ;
# endif
/* Free all the users structure */
@ -15326,7 +15195,7 @@ static int unload_module(void)
ast_unload_realtime ( " voicemail_data " ) ;
# ifdef IMAP_STORAGE
imap_close_subscribed_mailboxes( ) ;
ast_mwi_state_callback_all( imap_close_subscribed_mailbox , NULL ) ;
# endif
free_vm_users ( ) ;
free_vm_zones ( ) ;