diff --git a/apps/app_voicemail.c b/apps/app_voicemail.c index c6e501c3b036a59869fcb24480ebdc535ded7fa8..c5afb32514ead2450fcad4b9989de009f9a280b5 100644 --- a/apps/app_voicemail.c +++ b/apps/app_voicemail.c @@ -1009,42 +1009,24 @@ 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 + * \brief A mailbox to be polled * - * 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; +struct poll_state { + int marked_used; 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); +#define POLL_LIST_BUCKETS 511 +static struct ao2_container *poll_list; +AO2_STRING_FIELD_HASH_FN(poll_state, mailbox); +AO2_STRING_FIELD_CMP_FN(poll_state, mailbox); /* custom audio control prompts for voicemail playback */ static char listen_control_forward_key[12]; @@ -1122,7 +1104,7 @@ static const char *substitute_escapes(const char *value); static int message_range_and_existence_check(struct vm_state *vms, const char *msg_ids [], size_t num_msgs, int *msg_nums, struct ast_vm_user *vmu); static void notify_new_state(struct ast_vm_user *vmu); static int append_vmu_info_astman(struct mansession *s, struct ast_vm_user *vmu, const char* event_name, const char* actionid); - +static int poll_mailbox(void *obj, void *arg, int flags); /*! * Place a message in the indicated folder @@ -12310,6 +12292,59 @@ static int add_message_id(struct ast_config *msg_cfg, char *dir, int msg, char * return 0; } +static void poll_state_dtor(void *obj) +{ + struct poll_state *poll_state = obj; + + ast_debug(3, "DTOR: Mailbox: %s New: %d Old: %d Urgent: %d Marked Used: %d\n", poll_state->mailbox, + poll_state->old_new, poll_state->old_old, poll_state->old_urgent, + poll_state->marked_used); +} + +static int mark_or_create_poll_state(struct ast_vm_user *vmu) +{ + size_t len; + struct poll_state *poll_state; + char *mailbox; + + if (ast_strlen_zero(vmu->mailbox)) { + ast_log(LOG_ERROR, "Mailbox can't be empty\n"); + return -1; + } + + len = sizeof(vmu->mailbox) + sizeof(vmu->context) + sizeof('@') + 1; + mailbox = ast_alloca(len); + len = snprintf(mailbox, len, "%s%s%s", + vmu->mailbox, + ast_strlen_zero(vmu->context) ? "" : "@", + vmu->context); + + len++; /* For NULL terminator */ + + poll_state = ao2_find(poll_list, mailbox, OBJ_SEARCH_KEY); + if (poll_state) { + poll_state->marked_used = 1; + ao2_ref(poll_state, -1); + return 0; + } + + poll_state = ao2_alloc_options(len + sizeof(*poll_state), poll_state_dtor, + AO2_ALLOC_OPT_LOCK_NOLOCK); + if (!poll_state) { + return -1; + } + strcpy(poll_state->mailbox, mailbox); /* Safe */ + poll_state->marked_used = 1; + + ao2_link_flags(poll_list, poll_state, OBJ_NOLOCK); + + poll_mailbox(poll_state, NULL, 0); + + ao2_ref(poll_state, -1); + + return 0; +} + static struct ast_vm_user *find_or_create(const char *context, const char *box) { struct ast_vm_user *vmu; @@ -12339,12 +12374,18 @@ static struct ast_vm_user *find_or_create(const char *context, const char *box) } } - if (!(vmu = ast_calloc(1, sizeof(*vmu)))) + if (!(vmu = ast_calloc(1, sizeof(*vmu)))) { return NULL; + } ast_copy_string(vmu->context, context, sizeof(vmu->context)); ast_copy_string(vmu->mailbox, box, sizeof(vmu->mailbox)); + if (mark_or_create_poll_state(vmu)) { + ast_free(vmu); + return NULL; + } + AST_LIST_INSERT_TAIL(&users, vmu, list); return vmu; @@ -12600,6 +12641,7 @@ AST_TEST_DEFINE(test_voicemail_vmuser) #endif free_user(vmu); + return res ? AST_TEST_FAIL : AST_TEST_PASS; } #endif @@ -13010,38 +13052,33 @@ 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_mailbox(void *obj, void *arg, int flags) { + struct poll_state *poll_state = obj; int new = 0, old = 0, urgent = 0; - inboxcount2(mwi_sub->mailbox, &urgent, &new, &old); + + inboxcount2(poll_state->mailbox, &urgent, &new, &old); + ast_debug(4, "Polled mailbox '%s' urgent: %d new: %d old: %d\n", + poll_state->mailbox, urgent, new, old); #ifdef IMAP_STORAGE if (imap_poll_logout) { - imap_logout(mwi_sub->mailbox); + imap_logout(poll_state->mailbox); } #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 != poll_state->old_urgent || new != poll_state->old_new || old != poll_state->old_old) { + ast_debug(4, "Notifying subscribers of mailbox '%s' urgent: %d new: %d old: %d\n", + poll_state->mailbox, urgent, new, old); + poll_state->old_urgent = urgent; + poll_state->old_new = new; + poll_state->old_old = old; + queue_mwi_event(NULL, poll_state->mailbox, urgent, new, old); + run_externnotify(NULL, poll_state->mailbox, 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) @@ -13061,18 +13098,13 @@ static void *mb_poll_thread(void *data) if (!poll_thread_run) break; - poll_subscribed_mailboxes(); + ast_debug(3, "Polling mailboxes\n"); + ao2_callback(poll_list, OBJ_NODATA | OBJ_MULTIPLE, poll_mailbox, NULL); } 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) { @@ -13108,155 +13140,22 @@ 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_mailboxes_cb(void *obj, void *arg, int flags) { - 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); - } - } - AST_RWLIST_TRAVERSE_SAFE_END - AST_RWLIST_UNLOCK(&mwi_subs); + struct poll_state *poll_state = obj; + imap_logout(poll_state->mailbox); - 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 */ - - if (!(mwi_sub = ast_calloc(1, len))) - return -1; - - mwi_sub->uniqueid = ast_strdup(p->uniqueid); - if (!ast_strlen_zero(p->mailbox)) - strcpy(mwi_sub->mailbox, p->mailbox); - - if (!ast_strlen_zero(p->context)) { - strcat(mwi_sub->mailbox, "@"); - strcat(mwi_sub->mailbox, p->context); - } - - 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); - return 0; -} - -static void mwi_unsub_event_cb(struct stasis_subscription_change *change) -{ - char *uniqueid = ast_strdup(change->uniqueid); - - if (!uniqueid) { - ast_log(LOG_ERROR, "Unable to allocate memory for uniqueid\n"); - return; - } - - if (ast_taskprocessor_push(mwi_subscription_tps, handle_unsubscribe, uniqueid) < 0) { - ast_free(uniqueid); - } -} - -static void mwi_sub_event_cb(struct stasis_subscription_change *change) -{ - struct mwi_sub_task *mwist; - char *context; - char *mailbox; - - mwist = ast_calloc(1, (sizeof(*mwist))); - if (!mwist) { - return; - } - - if (separate_mailbox(ast_strdupa(stasis_topic_name(change->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); - } -} - -static void mwi_event_cb(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg) -{ - 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; - } - - if (!strcmp(change->description, "Subscribe")) { - mwi_sub_event_cb(change); - } else if (!strcmp(change->description, "Unsubscribe")) { - mwi_unsub_event_cb(change); - } -} - -static int dump_cache(void *obj, void *arg, int flags) +static void imap_close_subscribed_mailboxes(void) { - struct stasis_message *msg = obj; - mwi_event_cb(NULL, NULL, msg); - return 0; + ao2_callback(poll_list, OBJ_NODATA | OBJ_MULTIPLE, imap_close_subscribed_mailboxes_cb, NULL); } +#endif 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); - } poll_thread_run = 1; @@ -13269,8 +13168,6 @@ 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); @@ -13401,38 +13298,50 @@ static int append_vmu_info_astman( } -static int manager_voicemail_refresh(struct mansession *s, const struct message *m) +struct refresh_data { + const char *context; + const char *mailbox; +}; + +static int refresh_match(void *obj, void *arg, int gflags) { - const char *context = astman_get_header(m, "Context"); - const char *mailbox = astman_get_header(m, "Mailbox"); - struct mwi_sub *mwi_sub; + struct poll_state *poll_state = obj; + struct refresh_data *data = arg; 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) - ) { - poll_subscribed_mailbox(mwi_sub); - } + if (!ast_strlen_zero(poll_state->mailbox)) { + if ( + /* First case: everything matches */ + (ast_strlen_zero(data->context) && ast_strlen_zero(data->mailbox)) || + /* Second case: match the mailbox only */ + (ast_strlen_zero(data->context) && !ast_strlen_zero(data->mailbox) && + (at = strchr(poll_state->mailbox, '@')) && + strncmp(data->mailbox, poll_state->mailbox, at - poll_state->mailbox) == 0) || + /* Third case: match the context only */ + (!ast_strlen_zero(data->context) && ast_strlen_zero(data->mailbox) && + (at = strchr(poll_state->mailbox, '@')) && + strcmp(data->context, at + 1) == 0) || + /* Final case: match an exact specified mailbox */ + (!ast_strlen_zero(data->context) && !ast_strlen_zero(data->mailbox) && + (at = strchr(poll_state->mailbox, '@')) && + strncmp(data->mailbox, poll_state->mailbox, at - poll_state->mailbox) == 0 && + strcmp(data->context, at + 1) == 0) + ) { + poll_mailbox(poll_state, NULL, 0); } } - AST_RWLIST_UNLOCK(&mwi_subs); + + return 0; +} + +static int manager_voicemail_refresh(struct mansession *s, const struct message *m) +{ + struct refresh_data data = { + .context = astman_get_header(m, "Context"), + .mailbox = astman_get_header(m, "Mailbox"), + }; + + ao2_callback(poll_list, OBJ_NODATA | OBJ_MULTIPLE, refresh_match, (void *)&data); astman_send_ack(s, m, "Refresh sent"); return RESULT_SUCCESS; } @@ -13643,6 +13552,26 @@ static int load_config_from_memory(int reload, struct ast_config *cfg, struct as } #endif +static int unmark_poll_state(void *obj, void*arg, int flags) +{ + struct poll_state *poll_state = obj; + + poll_state->marked_used = 0; + + return 0; +} + +static int unmarked_poll_state(void *obj, void*arg, int flags) +{ + struct poll_state *poll_state = obj; + + if (!poll_state->marked_used) { + return CMP_MATCH; + } + + return 0; +} + static int actual_load_config(int reload, struct ast_config *cfg, struct ast_config *ucfg) { struct ast_vm_user *current; @@ -13653,8 +13582,6 @@ static int actual_load_config(int reload, struct ast_config *cfg, struct ast_con int x; unsigned int tmpadsi[4]; char secretfn[PATH_MAX] = ""; - long tps_queue_low; - long tps_queue_high; #ifdef IMAP_STORAGE ast_copy_string(imapparentfolder, "\0", sizeof(imapparentfolder)); @@ -13670,6 +13597,17 @@ static int actual_load_config(int reload, struct ast_config *cfg, struct ast_con imap_close_subscribed_mailboxes(); #endif + if (poll_thread != AST_PTHREADT_NULL) { + stop_poll_thread(); + } + + /* + * Unmark all current poll states. As mailboxes are (re)loaded, + * the state will be marked as used. Any not marked after the + * (re)load, will be removed. + */ + ao2_callback(poll_list, OBJ_NODATA | OBJ_MULTIPLE, unmark_poll_state, NULL); + /* Free all the users structure */ free_vm_users(); @@ -14243,23 +14181,11 @@ static int actual_load_config(int reload, struct ast_config *cfg, struct ast_con pagerbody = ast_strdup(substitute_escapes(val)); } - tps_queue_high = AST_TASKPROCESSOR_HIGH_WATER_LEVEL; if ((val = ast_variable_retrieve(cfg, "general", "tps_queue_high"))) { - if (sscanf(val, "%30ld", &tps_queue_high) != 1 || tps_queue_high <= 0) { - ast_log(AST_LOG_WARNING, "Invalid the taskprocessor high water alert trigger level '%s'\n", val); - tps_queue_high = AST_TASKPROCESSOR_HIGH_WATER_LEVEL; - } + ast_log(LOG_NOTICE, "Parameter tps_queue_high is obsolete and will be ignored\n"); } - tps_queue_low = -1; if ((val = ast_variable_retrieve(cfg, "general", "tps_queue_low"))) { - if (sscanf(val, "%30ld", &tps_queue_low) != 1 || - tps_queue_low < -1 || tps_queue_high < tps_queue_low) { - ast_log(AST_LOG_WARNING, "Invalid the taskprocessor low water clear alert level '%s'\n", val); - tps_queue_low = -1; - } - } - if (ast_taskprocessor_alert_set_levels(mwi_subscription_tps, tps_queue_low, tps_queue_high)) { - ast_log(AST_LOG_WARNING, "Failed to set alert levels for voicemail taskprocessor.\n"); + ast_log(LOG_NOTICE, "Parameter tps_queue_low is obsolete and will be ignored\n"); } /* load mailboxes from users.conf */ @@ -14329,15 +14255,16 @@ static int actual_load_config(int reload, struct ast_config *cfg, struct ast_con } AST_LIST_UNLOCK(&users); + /* Remove any left over unmarked poll states */ + ao2_callback(poll_list, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, unmarked_poll_state, NULL); if (poll_mailboxes && poll_thread == AST_PTHREADT_NULL) start_poll_thread(); - if (!poll_mailboxes && poll_thread != AST_PTHREADT_NULL) - stop_poll_thread();; return 0; } else { AST_LIST_UNLOCK(&users); + ao2_callback(poll_list, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, unmarked_poll_state, NULL); ast_log(AST_LOG_WARNING, "Failed to load configuration file.\n"); return 0; } @@ -14558,7 +14485,6 @@ AST_TEST_DEFINE(test_voicemail_msgcount) { int i, j, res = AST_TEST_PASS, syserr; struct ast_vm_user *vmu; - struct ast_vm_user svm; struct vm_state vms; #ifdef IMAP_STORAGE struct ast_channel *chan = NULL; @@ -14611,9 +14537,11 @@ AST_TEST_DEFINE(test_voicemail_msgcount) } #endif - memset(&svm, 0, sizeof(svm)); - if (!(vmu = find_user(&svm, testcontext, testmailbox)) && - !(vmu = find_or_create(testcontext, testmailbox))) { + AST_LIST_LOCK(&users); + vmu = find_or_create(testcontext, testmailbox); + AST_LIST_UNLOCK(&users); + + if (!vmu) { ast_test_status_update(test, "Cannot create vmu structure\n"); ast_unreplace_sigchld(); #ifdef IMAP_STORAGE @@ -14641,8 +14569,8 @@ AST_TEST_DEFINE(test_voicemail_msgcount) #ifdef IMAP_STORAGE chan = ast_channel_unref(chan); #endif - free_user(vmu); - return AST_TEST_FAIL; + res = AST_TEST_FAIL; + break; } } @@ -14666,27 +14594,34 @@ AST_TEST_DEFINE(test_voicemail_msgcount) res = AST_TEST_FAIL; } } + if (res) { + break; + } new = old = urgent = 0; if (ast_app_inboxcount(testspec, &new, &old)) { ast_test_status_update(test, "inboxcount returned failure\n"); res = AST_TEST_FAIL; + break; } else if (old != expected_results[i][3 + 0] || new != expected_results[i][3 + 2]) { ast_test_status_update(test, "inboxcount(%s) returned old=%d (expected %d) and new=%d (expected %d)\n", testspec, old, expected_results[i][3 + 0], new, expected_results[i][3 + 2]); res = AST_TEST_FAIL; + break; } new = old = urgent = 0; if (ast_app_inboxcount2(testspec, &urgent, &new, &old)) { ast_test_status_update(test, "inboxcount2 returned failure\n"); res = AST_TEST_FAIL; + break; } else if (old != expected_results[i][6 + 0] || urgent != expected_results[i][6 + 1] || new != expected_results[i][6 + 2] ) { ast_test_status_update(test, "inboxcount2(%s) returned old=%d (expected %d), urgent=%d (expected %d), and new=%d (expected %d)\n", testspec, old, expected_results[i][6 + 0], urgent, expected_results[i][6 + 1], new, expected_results[i][6 + 2]); res = AST_TEST_FAIL; + break; } new = old = urgent = 0; @@ -14697,6 +14632,9 @@ AST_TEST_DEFINE(test_voicemail_msgcount) res = AST_TEST_FAIL; } } + if (res) { + break; + } } for (i = 0; i < 3; i++) { @@ -14725,7 +14663,9 @@ AST_TEST_DEFINE(test_voicemail_msgcount) syserr > 0 ? strerror(syserr) : "unable to fork()"); } - free_user(vmu); + /* restore config */ + load_config(0); /* this might say "Failed to load configuration file." */ + return res; } @@ -14776,15 +14716,13 @@ AST_TEST_DEFINE(test_voicemail_notify_endl) snprintf(attach, sizeof(attach), "%s/sounds/en/tt-weasels", ast_config_AST_DATA_DIR); snprintf(attach2, sizeof(attach2), "%s/sounds/en/tt-somethingwrong", ast_config_AST_DATA_DIR); - if (!(vmu = find_user(&vmus, testcontext, testmailbox)) && - !(vmu = find_or_create(testcontext, testmailbox))) { - ast_test_status_update(test, "Cannot create vmu structure\n"); - return AST_TEST_NOT_RUN; - } + AST_LIST_LOCK(&users); + vmu = find_or_create(testcontext, testmailbox); + AST_LIST_UNLOCK(&users); - if (vmu != &vmus && !(vmu = find_user(&vmus, testcontext, testmailbox))) { - ast_test_status_update(test, "Cannot find vmu structure?!!\n"); - return AST_TEST_NOT_RUN; + if (!vmu) { + ast_test_status_update(test, "Cannot create vmu structure\n"); + return AST_TEST_FAIL; } populate_defaults(vmu); @@ -14835,7 +14773,10 @@ AST_TEST_DEFINE(test_voicemail_notify_endl) } } fclose(file); - free_user(vmu); + + /* restore config */ + load_config(0); /* this might say "Failed to load configuration file." */ + return res; } @@ -14909,7 +14850,7 @@ AST_TEST_DEFINE(test_voicemail_load_config) #undef CHECK /* restore config */ - load_config(1); /* this might say "Failed to load configuration file." */ + load_config(0); /* this might say "Failed to load configuration file." */ cleanup: unlink(config_filename); @@ -14965,8 +14906,11 @@ AST_TEST_DEFINE(test_voicemail_vm_info) return AST_TEST_FAIL; } - if (!(vmu = find_user(NULL, testcontext, testmailbox)) && - !(vmu = find_or_create(testcontext, testmailbox))) { + AST_LIST_LOCK(&users); + vmu = find_or_create(testcontext, testmailbox); + AST_LIST_UNLOCK(&users); + + if (!vmu) { ast_test_status_update(test, "Cannot create vmu structure\n"); chan = ast_channel_unref(chan); return AST_TEST_FAIL; @@ -14996,7 +14940,10 @@ AST_TEST_DEFINE(test_voicemail_vm_info) } chan = ast_channel_unref(chan); - free_user(vmu); + + /* restore config */ + load_config(0); /* this might say "Failed to load configuration file." */ + return res; } #endif /* defined(TEST_FRAMEWORK) */ @@ -15062,10 +15009,13 @@ static int unload_module(void) #endif ao2_ref(inprocess_container, -1); - if (poll_thread != AST_PTHREADT_NULL) + if (poll_thread != AST_PTHREADT_NULL) { stop_poll_thread(); + } + + ao2_container_unregister("voicemail_poll_list"); + ao2_cleanup(poll_list); - mwi_subscription_tps = ast_taskprocessor_unreference(mwi_subscription_tps); ast_unload_realtime("voicemail"); ast_unload_realtime("voicemail_data"); @@ -15077,6 +15027,18 @@ static int unload_module(void) return res; } +static void print_poll_state(void *v_obj, void *where, ao2_prnt_fn *prnt) +{ + struct poll_state *poll_state = v_obj; + + if (!poll_state) { + return; + } + prnt(where, "Mailbox: %s New: %d Old: %d Urgent: %d Marked Used: %d", poll_state->mailbox, + poll_state->old_new, poll_state->old_old, poll_state->old_urgent, + poll_state->marked_used); +} + /*! * \brief Load the module * @@ -15101,13 +15063,23 @@ static int load_module(void) return AST_MODULE_LOAD_DECLINE; } + poll_list = ao2_container_alloc(POLL_LIST_BUCKETS, poll_state_hash_fn, poll_state_cmp_fn); + if (!poll_list) { + ast_log(LOG_ERROR, "Unable to create poll_list container\n"); + ao2_cleanup(inprocess_container); + return AST_MODULE_LOAD_DECLINE; + } + res = ao2_container_register("voicemail_poll_list", poll_list, print_poll_state); + if (res) { + ast_log(LOG_ERROR, "Unable to register poll_list container\n"); + ao2_cleanup(inprocess_container); + ao2_cleanup(poll_list); + return AST_MODULE_LOAD_DECLINE; + } + /* compute the location of the voicemail spool directory */ snprintf(VM_SPOOL_DIR, sizeof(VM_SPOOL_DIR), "%s/voicemail/", ast_config_AST_SPOOL_DIR); - if (!(mwi_subscription_tps = ast_taskprocessor_get("app_voicemail", 0))) { - ast_log(AST_LOG_WARNING, "failed to reference mwi subscription taskprocessor. MWI will not work\n"); - } - if ((res = load_config(0))) { unload_module(); return AST_MODULE_LOAD_DECLINE; diff --git a/configs/samples/voicemail.conf.sample b/configs/samples/voicemail.conf.sample index e4130d356f6faa9b8b821106d3b7a2415f87a2e0..43325a24942324f9a6305afa9664b8a0f80bab6e 100644 --- a/configs/samples/voicemail.conf.sample +++ b/configs/samples/voicemail.conf.sample @@ -387,17 +387,6 @@ sendvoicemail=yes ; Allow the user to compose and send a voicemail while inside ; defaults to being off ; backupdeleted=100 -; Asterisk Task Processor Queue Size -; On heavy loaded system you may need to increase 'app_voicemail' taskprocessor queue. -; If the taskprocessor queue size reached high water level, the alert is triggered. -; If the alert is set then some modules (for example pjsip) slow down its production -; until the alert is cleared. -; The alert is cleared when taskprocessor queue size drops to the low water clear level. -; The next options set taskprocessor queue levels for this module. -; tps_queue_high=500 ; Taskprocessor high water alert trigger level. -; tps_queue_low=450 ; Taskprocessor low water clear alert level. - ; The default is -1 for 90% of high water level. - [zonemessages] ; Users may be located in different timezones, or may have different ; message announcements for their introductory message when they enter