<p>George Joseph <strong>merged</strong> this change.</p><p><a href="https://gerrit.asterisk.org/10720">View Change</a></p><div style="white-space:pre-wrap">Approvals:
  Joshua Colp: Looks good to me, but someone else must approve
  Benjamin Keith Ford: Looks good to me, but someone else must approve
  Matthew Fredrickson: Looks good to me, approved
  George Joseph: Approved for Submit

</div><pre style="font-family: monospace,monospace; white-space: pre-wrap;">Revert "app_voicemail: Remove need to subscribe to stasis"<br><br>This reverts commit 29115e23848cceee0e2763bc70e87cb311919cdd.<br><br>That commit closed a long standing hole which allowed subscriptions<br>to mailboxes that weren't configured in voicemail.conf.  This<br>caused an issue with FreePBX which depdended on that behavior.<br>The commit is being reverted until FreePBX can handle the new<br>behavior.<br><br>ASTERISK-28151<br>Reported by: Ronald Raikes<br><br>Change-Id: I57b7b85e75d7dd97c742b5c69d718a0f61260c15<br>---<br>M apps/app_voicemail.c<br>M configs/samples/voicemail.conf.sample<br>2 files changed, 282 insertions(+), 242 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/apps/app_voicemail.c b/apps/app_voicemail.c</span><br><span>index 595c2dc..13dedd3 100644</span><br><span>--- a/apps/app_voicemail.c</span><br><span>+++ b/apps/app_voicemail.c</span><br><span>@@ -1014,24 +1014,42 @@</span><br><span> static pthread_t poll_thread = AST_PTHREADT_NULL;</span><br><span> static unsigned char poll_thread_run;</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+/*! Subscription to MWI event subscription changes */</span><br><span style="color: hsl(120, 100%, 40%);">+static struct stasis_subscription *mwi_sub_sub;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /*!</span><br><span style="color: hsl(0, 100%, 40%);">- * \brief A mailbox to be polled</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief An MWI subscription</span><br><span>  *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This is so we can keep track of which mailboxes are subscribed to.</span><br><span>  * This way, we know which mailboxes to poll when the pollmailboxes</span><br><span>  * option is being used.</span><br><span>  */</span><br><span style="color: hsl(0, 100%, 40%);">-struct poll_state {</span><br><span style="color: hsl(0, 100%, 40%);">- int marked_used;</span><br><span style="color: hsl(120, 100%, 40%);">+struct mwi_sub {</span><br><span style="color: hsl(120, 100%, 40%);">+    AST_RWLIST_ENTRY(mwi_sub) entry;</span><br><span>     int old_urgent;</span><br><span>      int old_new;</span><br><span>         int old_old;</span><br><span style="color: hsl(120, 100%, 40%);">+  char *uniqueid;</span><br><span>      char mailbox[0];</span><br><span> };</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-#define POLL_LIST_BUCKETS 511</span><br><span style="color: hsl(0, 100%, 40%);">-static struct ao2_container *poll_list;</span><br><span style="color: hsl(0, 100%, 40%);">-AO2_STRING_FIELD_HASH_FN(poll_state, mailbox);</span><br><span style="color: hsl(0, 100%, 40%);">-AO2_STRING_FIELD_CMP_FN(poll_state, mailbox);</span><br><span style="color: hsl(120, 100%, 40%);">+struct mwi_sub_task {</span><br><span style="color: hsl(120, 100%, 40%);">+      const char *mailbox;</span><br><span style="color: hsl(120, 100%, 40%);">+  const char *context;</span><br><span style="color: hsl(120, 100%, 40%);">+  const char *uniqueid;</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void mwi_sub_task_dtor(struct mwi_sub_task *mwist)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     ast_free((void *) mwist->mailbox);</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_free((void *) mwist->context);</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_free((void *) mwist->uniqueid);</span><br><span style="color: hsl(120, 100%, 40%);">+        ast_free(mwist);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static struct ast_taskprocessor *mwi_subscription_tps;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static AST_RWLIST_HEAD_STATIC(mwi_subs, mwi_sub);</span><br><span> </span><br><span> /* custom audio control prompts for voicemail playback */</span><br><span> static char listen_control_forward_key[12];</span><br><span>@@ -1109,7 +1127,7 @@</span><br><span> 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);</span><br><span> static void notify_new_state(struct ast_vm_user *vmu);</span><br><span> static int append_vmu_info_astman(struct mansession *s, struct ast_vm_user *vmu, const char* event_name, const char* actionid);</span><br><span style="color: hsl(0, 100%, 40%);">-static int poll_mailbox(void *obj, void *arg, int flags);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> </span><br><span> /*!</span><br><span>  * Place a message in the indicated folder</span><br><span>@@ -12301,57 +12319,6 @@</span><br><span>       return 0;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-static void poll_state_dtor(void *obj)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-       struct poll_state *poll_state = obj;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-    ast_debug(3, "DTOR: Mailbox: %s New: %d  Old: %d  Urgent: %d  Marked Used: %d\n", poll_state->mailbox,</span><br><span style="color: hsl(0, 100%, 40%);">-             poll_state->old_new, poll_state->old_old, poll_state->old_urgent,</span><br><span style="color: hsl(0, 100%, 40%);">-              poll_state->marked_used);</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-static int mark_or_create_poll_state(struct ast_vm_user *vmu)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-     size_t len;</span><br><span style="color: hsl(0, 100%, 40%);">-     struct poll_state *poll_state;</span><br><span style="color: hsl(0, 100%, 40%);">-  char mailbox_full[MAX_VM_MAILBOX_LEN];</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-  if (ast_strlen_zero(vmu->mailbox)) {</span><br><span style="color: hsl(0, 100%, 40%);">-         ast_log(LOG_ERROR, "Mailbox can't be empty\n");</span><br><span style="color: hsl(0, 100%, 40%);">-           return -1;</span><br><span style="color: hsl(0, 100%, 40%);">-      }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       len = snprintf(mailbox_full, MAX_VM_MAILBOX_LEN, "%s%s%s",</span><br><span style="color: hsl(0, 100%, 40%);">-            vmu->mailbox,</span><br><span style="color: hsl(0, 100%, 40%);">-                ast_strlen_zero(vmu->context) ? "" : "@",</span><br><span style="color: hsl(0, 100%, 40%);">-                vmu->context);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       len++; /* For NULL terminator */</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-        poll_state = ao2_find(poll_list, mailbox_full, OBJ_SEARCH_KEY);</span><br><span style="color: hsl(0, 100%, 40%);">- if (poll_state) {</span><br><span style="color: hsl(0, 100%, 40%);">-               poll_state->marked_used = 1;</span><br><span style="color: hsl(0, 100%, 40%);">-         ao2_ref(poll_state, -1);</span><br><span style="color: hsl(0, 100%, 40%);">-                return 0;</span><br><span style="color: hsl(0, 100%, 40%);">-       }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       poll_state = ao2_alloc_options(len + sizeof(*poll_state), poll_state_dtor,</span><br><span style="color: hsl(0, 100%, 40%);">-              AO2_ALLOC_OPT_LOCK_NOLOCK);</span><br><span style="color: hsl(0, 100%, 40%);">-     if (!poll_state) {</span><br><span style="color: hsl(0, 100%, 40%);">-              return -1;</span><br><span style="color: hsl(0, 100%, 40%);">-      }</span><br><span style="color: hsl(0, 100%, 40%);">-       strcpy(poll_state->mailbox, mailbox_full); /* Safe */</span><br><span style="color: hsl(0, 100%, 40%);">-        poll_state->marked_used = 1;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- ao2_link_flags(poll_list, poll_state, OBJ_NOLOCK);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-      poll_mailbox(poll_state, NULL, 0);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-      ao2_ref(poll_state, -1);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-        return 0;</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span> static struct ast_vm_user *find_or_create(const char *context, const char *box)</span><br><span> {</span><br><span>   struct ast_vm_user *vmu;</span><br><span>@@ -12381,18 +12348,12 @@</span><br><span>                 }</span><br><span>    }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   if (!(vmu = ast_calloc(1, sizeof(*vmu)))) {</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!(vmu = ast_calloc(1, sizeof(*vmu))))</span><br><span>            return NULL;</span><br><span style="color: hsl(0, 100%, 40%);">-    }</span><br><span> </span><br><span>        ast_copy_string(vmu->context, context, sizeof(vmu->context));</span><br><span>  ast_copy_string(vmu->mailbox, box, sizeof(vmu->mailbox));</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-     if (mark_or_create_poll_state(vmu)) {</span><br><span style="color: hsl(0, 100%, 40%);">-           ast_free(vmu);</span><br><span style="color: hsl(0, 100%, 40%);">-          return NULL;</span><br><span style="color: hsl(0, 100%, 40%);">-    }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span>    AST_LIST_INSERT_TAIL(&users, vmu, list);</span><br><span> </span><br><span>     return vmu;</span><br><span>@@ -12648,7 +12609,6 @@</span><br><span> #endif</span><br><span> </span><br><span>  free_user(vmu);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span>      return res ? AST_TEST_FAIL : AST_TEST_PASS;</span><br><span> }</span><br><span> #endif</span><br><span>@@ -13059,33 +13019,38 @@</span><br><span>       AST_CLI_DEFINE(handle_voicemail_reload, "Reload voicemail configuration"),</span><br><span> };</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-static int poll_mailbox(void *obj, void *arg, int flags)</span><br><span style="color: hsl(120, 100%, 40%);">+static void poll_subscribed_mailbox(struct mwi_sub *mwi_sub)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-       struct poll_state *poll_state = obj;</span><br><span>         int new = 0, old = 0, urgent = 0;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-   inboxcount2(poll_state->mailbox, &urgent, &new, &old);</span><br><span style="color: hsl(0, 100%, 40%);">-   ast_debug(4, "Polled mailbox '%s' urgent: %d  new: %d  old: %d\n",</span><br><span style="color: hsl(0, 100%, 40%);">-            poll_state->mailbox, urgent, new, old);</span><br><span style="color: hsl(120, 100%, 40%);">+    inboxcount2(mwi_sub->mailbox, &urgent, &new, &old);</span><br><span> </span><br><span> #ifdef IMAP_STORAGE</span><br><span>        if (imap_poll_logout) {</span><br><span style="color: hsl(0, 100%, 40%);">-         imap_logout(poll_state->mailbox);</span><br><span style="color: hsl(120, 100%, 40%);">+          imap_logout(mwi_sub->mailbox);</span><br><span>    }</span><br><span> #endif</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- if (urgent != poll_state->old_urgent || new != poll_state->old_new || old != poll_state->old_old) {</span><br><span style="color: hsl(0, 100%, 40%);">-            ast_debug(4, "Notifying subscribers of mailbox '%s' urgent: %d  new: %d  old: %d\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                  poll_state->mailbox, urgent, new, old);</span><br><span style="color: hsl(0, 100%, 40%);">-              poll_state->old_urgent = urgent;</span><br><span style="color: hsl(0, 100%, 40%);">-             poll_state->old_new = new;</span><br><span style="color: hsl(0, 100%, 40%);">-           poll_state->old_old = old;</span><br><span style="color: hsl(0, 100%, 40%);">-           queue_mwi_event(NULL, poll_state->mailbox, urgent, new, old);</span><br><span style="color: hsl(0, 100%, 40%);">-                run_externnotify(NULL, poll_state->mailbox, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (urgent != mwi_sub->old_urgent || new != mwi_sub->old_new || old != mwi_sub->old_old) {</span><br><span style="color: hsl(120, 100%, 40%);">+           mwi_sub->old_urgent = urgent;</span><br><span style="color: hsl(120, 100%, 40%);">+              mwi_sub->old_new = new;</span><br><span style="color: hsl(120, 100%, 40%);">+            mwi_sub->old_old = old;</span><br><span style="color: hsl(120, 100%, 40%);">+            queue_mwi_event(NULL, mwi_sub->mailbox, urgent, new, old);</span><br><span style="color: hsl(120, 100%, 40%);">+         run_externnotify(NULL, mwi_sub->mailbox, NULL);</span><br><span>   }</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-        return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+static void poll_subscribed_mailboxes(void)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     struct mwi_sub *mwi_sub;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    AST_RWLIST_RDLOCK(&mwi_subs);</span><br><span style="color: hsl(120, 100%, 40%);">+     AST_RWLIST_TRAVERSE(&mwi_subs, mwi_sub, entry) {</span><br><span style="color: hsl(120, 100%, 40%);">+          if (!ast_strlen_zero(mwi_sub->mailbox)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                  poll_subscribed_mailbox(mwi_sub);</span><br><span style="color: hsl(120, 100%, 40%);">+             }</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+     AST_RWLIST_UNLOCK(&mwi_subs);</span><br><span> }</span><br><span> </span><br><span> static void *mb_poll_thread(void *data)</span><br><span>@@ -13105,13 +13070,18 @@</span><br><span>            if (!poll_thread_run)</span><br><span>                        break;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-              ast_debug(3, "Polling mailboxes\n");</span><br><span style="color: hsl(0, 100%, 40%);">-          ao2_callback(poll_list, OBJ_NODATA | OBJ_MULTIPLE, poll_mailbox, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+               poll_subscribed_mailboxes();</span><br><span>         }</span><br><span> </span><br><span>        return NULL;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+static void mwi_sub_destroy(struct mwi_sub *mwi_sub)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        ast_free(mwi_sub->uniqueid);</span><br><span style="color: hsl(120, 100%, 40%);">+       ast_free(mwi_sub);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> #ifdef IMAP_STORAGE</span><br><span> static void imap_logout(const char *mailbox_id)</span><br><span> {</span><br><span>@@ -13147,22 +13117,155 @@</span><br><span>  vmstate_delete(vms);</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-static int imap_close_subscribed_mailboxes_cb(void *obj, void *arg, int flags)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-    struct poll_state *poll_state = obj;</span><br><span style="color: hsl(0, 100%, 40%);">-    imap_logout(poll_state->mailbox);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-    return 0;</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span> static void imap_close_subscribed_mailboxes(void)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-    ao2_callback(poll_list, OBJ_NODATA | OBJ_MULTIPLE, imap_close_subscribed_mailboxes_cb, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+ struct mwi_sub *mwi_sub;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    AST_RWLIST_RDLOCK(&mwi_subs);</span><br><span style="color: hsl(120, 100%, 40%);">+     AST_RWLIST_TRAVERSE(&mwi_subs, mwi_sub, entry) {</span><br><span style="color: hsl(120, 100%, 40%);">+          if (!ast_strlen_zero(mwi_sub->mailbox)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                  imap_logout(mwi_sub->mailbox);</span><br><span style="color: hsl(120, 100%, 40%);">+             }</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+     AST_RWLIST_UNLOCK(&mwi_subs);</span><br><span> }</span><br><span> #endif</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+static int handle_unsubscribe(void *datap)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   struct mwi_sub *mwi_sub;</span><br><span style="color: hsl(120, 100%, 40%);">+      char *uniqueid = datap;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     AST_RWLIST_WRLOCK(&mwi_subs);</span><br><span style="color: hsl(120, 100%, 40%);">+     AST_RWLIST_TRAVERSE_SAFE_BEGIN(&mwi_subs, mwi_sub, entry) {</span><br><span style="color: hsl(120, 100%, 40%);">+               if (!strcmp(mwi_sub->uniqueid, uniqueid)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                        AST_LIST_REMOVE_CURRENT(entry);</span><br><span style="color: hsl(120, 100%, 40%);">+                       /* Don't break here since a duplicate uniqueid</span><br><span style="color: hsl(120, 100%, 40%);">+                     * may have been added as a result of a cache dump. */</span><br><span style="color: hsl(120, 100%, 40%);">+#ifdef IMAP_STORAGE</span><br><span style="color: hsl(120, 100%, 40%);">+                   imap_logout(mwi_sub->mailbox);</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span style="color: hsl(120, 100%, 40%);">+                     mwi_sub_destroy(mwi_sub);</span><br><span style="color: hsl(120, 100%, 40%);">+             }</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+     AST_RWLIST_TRAVERSE_SAFE_END</span><br><span style="color: hsl(120, 100%, 40%);">+  AST_RWLIST_UNLOCK(&mwi_subs);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   ast_free(uniqueid);</span><br><span style="color: hsl(120, 100%, 40%);">+   return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int handle_subscribe(void *datap)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   unsigned int len;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct mwi_sub *mwi_sub;</span><br><span style="color: hsl(120, 100%, 40%);">+      struct mwi_sub_task *p = datap;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     len = sizeof(*mwi_sub) + 1;</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!ast_strlen_zero(p->mailbox))</span><br><span style="color: hsl(120, 100%, 40%);">+          len += strlen(p->mailbox);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       if (!ast_strlen_zero(p->context))</span><br><span style="color: hsl(120, 100%, 40%);">+          len += strlen(p->context) + 1; /* Allow for seperator */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!(mwi_sub = ast_calloc(1, len)))</span><br><span style="color: hsl(120, 100%, 40%);">+          return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  mwi_sub->uniqueid = ast_strdup(p->uniqueid);</span><br><span style="color: hsl(120, 100%, 40%);">+    if (!ast_strlen_zero(p->mailbox))</span><br><span style="color: hsl(120, 100%, 40%);">+          strcpy(mwi_sub->mailbox, p->mailbox);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!ast_strlen_zero(p->context)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                strcat(mwi_sub->mailbox, "@");</span><br><span style="color: hsl(120, 100%, 40%);">+           strcat(mwi_sub->mailbox, p->context);</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   AST_RWLIST_WRLOCK(&mwi_subs);</span><br><span style="color: hsl(120, 100%, 40%);">+     AST_RWLIST_INSERT_TAIL(&mwi_subs, mwi_sub, entry);</span><br><span style="color: hsl(120, 100%, 40%);">+        AST_RWLIST_UNLOCK(&mwi_subs);</span><br><span style="color: hsl(120, 100%, 40%);">+     mwi_sub_task_dtor(p);</span><br><span style="color: hsl(120, 100%, 40%);">+ poll_subscribed_mailbox(mwi_sub);</span><br><span style="color: hsl(120, 100%, 40%);">+     return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void mwi_unsub_event_cb(struct stasis_subscription_change *change)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  char *uniqueid = ast_strdup(change->uniqueid);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!uniqueid) {</span><br><span style="color: hsl(120, 100%, 40%);">+              ast_log(LOG_ERROR, "Unable to allocate memory for uniqueid\n");</span><br><span style="color: hsl(120, 100%, 40%);">+             return;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (ast_taskprocessor_push(mwi_subscription_tps, handle_unsubscribe, uniqueid) < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+              ast_free(uniqueid);</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void mwi_sub_event_cb(struct stasis_subscription_change *change)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    struct mwi_sub_task *mwist;</span><br><span style="color: hsl(120, 100%, 40%);">+   char *context;</span><br><span style="color: hsl(120, 100%, 40%);">+        char *mailbox;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      mwist = ast_calloc(1, (sizeof(*mwist)));</span><br><span style="color: hsl(120, 100%, 40%);">+      if (!mwist) {</span><br><span style="color: hsl(120, 100%, 40%);">+         return;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (separate_mailbox(ast_strdupa(stasis_topic_name(change->topic)), &mailbox, &context)) {</span><br><span style="color: hsl(120, 100%, 40%);">+         ast_free(mwist);</span><br><span style="color: hsl(120, 100%, 40%);">+              return;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   mwist->mailbox = ast_strdup(mailbox);</span><br><span style="color: hsl(120, 100%, 40%);">+      mwist->context = ast_strdup(context);</span><br><span style="color: hsl(120, 100%, 40%);">+      mwist->uniqueid = ast_strdup(change->uniqueid);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       if (ast_taskprocessor_push(mwi_subscription_tps, handle_subscribe, mwist) < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+           mwi_sub_task_dtor(mwist);</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void mwi_event_cb(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      struct stasis_subscription_change *change;</span><br><span style="color: hsl(120, 100%, 40%);">+    /* Only looking for subscription change notices here */</span><br><span style="color: hsl(120, 100%, 40%);">+       if (stasis_message_type(msg) != stasis_subscription_change_type()) {</span><br><span style="color: hsl(120, 100%, 40%);">+          return;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   change = stasis_message_data(msg);</span><br><span style="color: hsl(120, 100%, 40%);">+    if (change->topic == ast_mwi_topic_all()) {</span><br><span style="color: hsl(120, 100%, 40%);">+                return;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!strcmp(change->description, "Subscribe")) {</span><br><span style="color: hsl(120, 100%, 40%);">+         mwi_sub_event_cb(change);</span><br><span style="color: hsl(120, 100%, 40%);">+     } else if (!strcmp(change->description, "Unsubscribe")) {</span><br><span style="color: hsl(120, 100%, 40%);">+                mwi_unsub_event_cb(change);</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int dump_cache(void *obj, void *arg, int flags)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     struct stasis_message *msg = obj;</span><br><span style="color: hsl(120, 100%, 40%);">+     mwi_event_cb(NULL, NULL, msg);</span><br><span style="color: hsl(120, 100%, 40%);">+        return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> static void start_poll_thread(void)</span><br><span> {</span><br><span>   int errcode;</span><br><span style="color: hsl(120, 100%, 40%);">+  mwi_sub_sub = stasis_subscribe(ast_mwi_topic_all(), mwi_event_cb, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    if (mwi_sub_sub) {</span><br><span style="color: hsl(120, 100%, 40%);">+            struct ao2_container *cached = stasis_cache_dump(ast_mwi_state_cache(), stasis_subscription_change_type());</span><br><span style="color: hsl(120, 100%, 40%);">+           if (cached) {</span><br><span style="color: hsl(120, 100%, 40%);">+                 ao2_callback(cached, OBJ_MULTIPLE | OBJ_NODATA, dump_cache, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+            }</span><br><span style="color: hsl(120, 100%, 40%);">+             ao2_cleanup(cached);</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span> </span><br><span>        poll_thread_run = 1;</span><br><span> </span><br><span>@@ -13175,6 +13278,8 @@</span><br><span> {</span><br><span>      poll_thread_run = 0;</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+      mwi_sub_sub = stasis_unsubscribe_and_join(mwi_sub_sub);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>    ast_mutex_lock(&poll_lock);</span><br><span>      ast_cond_signal(&poll_cond);</span><br><span>     ast_mutex_unlock(&poll_lock);</span><br><span>@@ -13305,50 +13410,38 @@</span><br><span> </span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-struct refresh_data {</span><br><span style="color: hsl(0, 100%, 40%);">- const char *context;</span><br><span style="color: hsl(0, 100%, 40%);">-    const char *mailbox;</span><br><span style="color: hsl(0, 100%, 40%);">-};</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-static int refresh_match(void *obj, void *arg, int gflags)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-       struct poll_state *poll_state = obj;</span><br><span style="color: hsl(0, 100%, 40%);">-    struct refresh_data *data = arg;</span><br><span style="color: hsl(0, 100%, 40%);">-        const char *at;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- if (!ast_strlen_zero(poll_state->mailbox)) {</span><br><span style="color: hsl(0, 100%, 40%);">-         if (</span><br><span style="color: hsl(0, 100%, 40%);">-                    /* First case: everything matches */</span><br><span style="color: hsl(0, 100%, 40%);">-                    (ast_strlen_zero(data->context) && ast_strlen_zero(data->mailbox)) ||</span><br><span style="color: hsl(0, 100%, 40%);">-                     /* Second case: match the mailbox only */</span><br><span style="color: hsl(0, 100%, 40%);">-                       (ast_strlen_zero(data->context) && !ast_strlen_zero(data->mailbox) &&</span><br><span style="color: hsl(0, 100%, 40%);">-                             (at = strchr(poll_state->mailbox, '@')) &&</span><br><span style="color: hsl(0, 100%, 40%);">-                           strncmp(data->mailbox, poll_state->mailbox, at - poll_state->mailbox) == 0) ||</span><br><span style="color: hsl(0, 100%, 40%);">-                 /* Third case: match the context only */</span><br><span style="color: hsl(0, 100%, 40%);">-                        (!ast_strlen_zero(data->context) && ast_strlen_zero(data->mailbox) &&</span><br><span style="color: hsl(0, 100%, 40%);">-                             (at = strchr(poll_state->mailbox, '@')) &&</span><br><span style="color: hsl(0, 100%, 40%);">-                           strcmp(data->context, at + 1) == 0) ||</span><br><span style="color: hsl(0, 100%, 40%);">-                       /* Final case: match an exact specified mailbox */</span><br><span style="color: hsl(0, 100%, 40%);">-                      (!ast_strlen_zero(data->context) && !ast_strlen_zero(data->mailbox) &&</span><br><span style="color: hsl(0, 100%, 40%);">-                            (at = strchr(poll_state->mailbox, '@')) &&</span><br><span style="color: hsl(0, 100%, 40%);">-                           strncmp(data->mailbox, poll_state->mailbox, at - poll_state->mailbox) == 0 &&</span><br><span style="color: hsl(0, 100%, 40%);">-                          strcmp(data->context, at + 1) == 0)</span><br><span style="color: hsl(0, 100%, 40%);">-          ) {</span><br><span style="color: hsl(0, 100%, 40%);">-                     poll_mailbox(poll_state, NULL, 0);</span><br><span style="color: hsl(0, 100%, 40%);">-              }</span><br><span style="color: hsl(0, 100%, 40%);">-       }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       return 0;</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span> static int manager_voicemail_refresh(struct mansession *s, const struct message *m)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-  struct refresh_data data = {</span><br><span style="color: hsl(0, 100%, 40%);">-            .context = astman_get_header(m, "Context"),</span><br><span style="color: hsl(0, 100%, 40%);">-           .mailbox = astman_get_header(m, "Mailbox"),</span><br><span style="color: hsl(0, 100%, 40%);">-   };</span><br><span style="color: hsl(120, 100%, 40%);">+    const char *context = astman_get_header(m, "Context");</span><br><span style="color: hsl(120, 100%, 40%);">+      const char *mailbox = astman_get_header(m, "Mailbox");</span><br><span style="color: hsl(120, 100%, 40%);">+      struct mwi_sub *mwi_sub;</span><br><span style="color: hsl(120, 100%, 40%);">+      const char *at;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-     ao2_callback(poll_list, OBJ_NODATA | OBJ_MULTIPLE, refresh_match, (void *)&data);</span><br><span style="color: hsl(120, 100%, 40%);">+ AST_RWLIST_RDLOCK(&mwi_subs);</span><br><span style="color: hsl(120, 100%, 40%);">+     AST_RWLIST_TRAVERSE(&mwi_subs, mwi_sub, entry) {</span><br><span style="color: hsl(120, 100%, 40%);">+          if (!ast_strlen_zero(mwi_sub->mailbox)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                  if (</span><br><span style="color: hsl(120, 100%, 40%);">+                          /* First case: everything matches */</span><br><span style="color: hsl(120, 100%, 40%);">+                          (ast_strlen_zero(context) && ast_strlen_zero(mailbox)) ||</span><br><span style="color: hsl(120, 100%, 40%);">+                             /* Second case: match the mailbox only */</span><br><span style="color: hsl(120, 100%, 40%);">+                             (ast_strlen_zero(context) && !ast_strlen_zero(mailbox) &&</span><br><span style="color: hsl(120, 100%, 40%);">+                                     (at = strchr(mwi_sub->mailbox, '@')) &&</span><br><span style="color: hsl(120, 100%, 40%);">+                                    strncmp(mailbox, mwi_sub->mailbox, at - mwi_sub->mailbox) == 0) ||</span><br><span style="color: hsl(120, 100%, 40%);">+                              /* Third case: match the context only */</span><br><span style="color: hsl(120, 100%, 40%);">+                              (!ast_strlen_zero(context) && ast_strlen_zero(mailbox) &&</span><br><span style="color: hsl(120, 100%, 40%);">+                                     (at = strchr(mwi_sub->mailbox, '@')) &&</span><br><span style="color: hsl(120, 100%, 40%);">+                                    strcmp(context, at + 1) == 0) ||</span><br><span style="color: hsl(120, 100%, 40%);">+                              /* Final case: match an exact specified mailbox */</span><br><span style="color: hsl(120, 100%, 40%);">+                            (!ast_strlen_zero(context) && !ast_strlen_zero(mailbox) &&</span><br><span style="color: hsl(120, 100%, 40%);">+                                    (at = strchr(mwi_sub->mailbox, '@')) &&</span><br><span style="color: hsl(120, 100%, 40%);">+                                    strncmp(mailbox, mwi_sub->mailbox, at - mwi_sub->mailbox) == 0 &&</span><br><span style="color: hsl(120, 100%, 40%);">+                                       strcmp(context, at + 1) == 0)</span><br><span style="color: hsl(120, 100%, 40%);">+                 ) {</span><br><span style="color: hsl(120, 100%, 40%);">+                           poll_subscribed_mailbox(mwi_sub);</span><br><span style="color: hsl(120, 100%, 40%);">+                     }</span><br><span style="color: hsl(120, 100%, 40%);">+             }</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+     AST_RWLIST_UNLOCK(&mwi_subs);</span><br><span>    astman_send_ack(s, m, "Refresh sent");</span><br><span>     return RESULT_SUCCESS;</span><br><span> }</span><br><span>@@ -13559,26 +13652,6 @@</span><br><span> }</span><br><span> #endif</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-static int unmark_poll_state(void *obj, void*arg, int flags)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-  struct poll_state *poll_state = obj;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-    poll_state->marked_used = 0;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- return 0;</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-static int unmarked_poll_state(void *obj, void*arg, int flags)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-       struct poll_state *poll_state = obj;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-    if (!poll_state->marked_used) {</span><br><span style="color: hsl(0, 100%, 40%);">-              return CMP_MATCH;</span><br><span style="color: hsl(0, 100%, 40%);">-       }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       return 0;</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span> static int actual_load_config(int reload, struct ast_config *cfg, struct ast_config *ucfg)</span><br><span> {</span><br><span>        struct ast_vm_user *current;</span><br><span>@@ -13589,6 +13662,8 @@</span><br><span>       int x;</span><br><span>       unsigned int tmpadsi[4];</span><br><span>     char secretfn[PATH_MAX] = "";</span><br><span style="color: hsl(120, 100%, 40%);">+       long tps_queue_low;</span><br><span style="color: hsl(120, 100%, 40%);">+   long tps_queue_high;</span><br><span> </span><br><span> #ifdef IMAP_STORAGE</span><br><span>      ast_copy_string(imapparentfolder, "\0", sizeof(imapparentfolder));</span><br><span>@@ -13604,17 +13679,6 @@</span><br><span>      imap_close_subscribed_mailboxes();</span><br><span> #endif</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-        if (poll_thread != AST_PTHREADT_NULL) {</span><br><span style="color: hsl(0, 100%, 40%);">-         stop_poll_thread();</span><br><span style="color: hsl(0, 100%, 40%);">-     }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       /*</span><br><span style="color: hsl(0, 100%, 40%);">-       * Unmark all current poll states.  As mailboxes are (re)loaded,</span><br><span style="color: hsl(0, 100%, 40%);">-         * the state will be marked as used.  Any not marked after the</span><br><span style="color: hsl(0, 100%, 40%);">-   * (re)load, will be removed.</span><br><span style="color: hsl(0, 100%, 40%);">-    */</span><br><span style="color: hsl(0, 100%, 40%);">-     ao2_callback(poll_list, OBJ_NODATA | OBJ_MULTIPLE, unmark_poll_state, NULL);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span>         /* Free all the users structure */</span><br><span>   free_vm_users();</span><br><span> </span><br><span>@@ -14188,11 +14252,23 @@</span><br><span>                     pagerbody = ast_strdup(substitute_escapes(val));</span><br><span>             }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+         tps_queue_high = AST_TASKPROCESSOR_HIGH_WATER_LEVEL;</span><br><span>                 if ((val = ast_variable_retrieve(cfg, "general", "tps_queue_high"))) {</span><br><span style="color: hsl(0, 100%, 40%);">-                      ast_log(LOG_NOTICE, "Parameter tps_queue_high is obsolete and will be ignored\n");</span><br><span style="color: hsl(120, 100%, 40%);">+                  if (sscanf(val, "%30ld", &tps_queue_high) != 1 || tps_queue_high <= 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                             ast_log(AST_LOG_WARNING, "Invalid the taskprocessor high water alert trigger level '%s'\n", val);</span><br><span style="color: hsl(120, 100%, 40%);">+                           tps_queue_high = AST_TASKPROCESSOR_HIGH_WATER_LEVEL;</span><br><span style="color: hsl(120, 100%, 40%);">+                  }</span><br><span>            }</span><br><span style="color: hsl(120, 100%, 40%);">+             tps_queue_low = -1;</span><br><span>          if ((val = ast_variable_retrieve(cfg, "general", "tps_queue_low"))) {</span><br><span style="color: hsl(0, 100%, 40%);">-                       ast_log(LOG_NOTICE, "Parameter tps_queue_low is obsolete and will be ignored\n");</span><br><span style="color: hsl(120, 100%, 40%);">+                   if (sscanf(val, "%30ld", &tps_queue_low) != 1 ||</span><br><span style="color: hsl(120, 100%, 40%);">+                                tps_queue_low < -1 || tps_queue_high < tps_queue_low) {</span><br><span style="color: hsl(120, 100%, 40%);">+                         ast_log(AST_LOG_WARNING, "Invalid the taskprocessor low water clear alert level '%s'\n", val);</span><br><span style="color: hsl(120, 100%, 40%);">+                              tps_queue_low = -1;</span><br><span style="color: hsl(120, 100%, 40%);">+                   }</span><br><span style="color: hsl(120, 100%, 40%);">+             }</span><br><span style="color: hsl(120, 100%, 40%);">+             if (ast_taskprocessor_alert_set_levels(mwi_subscription_tps, tps_queue_low, tps_queue_high)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                        ast_log(AST_LOG_WARNING, "Failed to set alert levels for voicemail taskprocessor.\n");</span><br><span>             }</span><br><span> </span><br><span>                /* load mailboxes from users.conf */</span><br><span>@@ -14262,16 +14338,15 @@</span><br><span>             }</span><br><span> </span><br><span>                AST_LIST_UNLOCK(&users);</span><br><span style="color: hsl(0, 100%, 40%);">-            /* Remove any left over unmarked poll states */</span><br><span style="color: hsl(0, 100%, 40%);">-         ao2_callback(poll_list, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, unmarked_poll_state, NULL);</span><br><span> </span><br><span>              if (poll_mailboxes && poll_thread == AST_PTHREADT_NULL)</span><br><span>                      start_poll_thread();</span><br><span style="color: hsl(120, 100%, 40%);">+          if (!poll_mailboxes && poll_thread != AST_PTHREADT_NULL)</span><br><span style="color: hsl(120, 100%, 40%);">+                      stop_poll_thread();;</span><br><span> </span><br><span>             return 0;</span><br><span>    } else {</span><br><span>             AST_LIST_UNLOCK(&users);</span><br><span style="color: hsl(0, 100%, 40%);">-            ao2_callback(poll_list, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, unmarked_poll_state, NULL);</span><br><span>          ast_log(AST_LOG_WARNING, "Failed to load configuration file.\n");</span><br><span>          return 0;</span><br><span>    }</span><br><span>@@ -14492,6 +14567,7 @@</span><br><span> {</span><br><span>     int i, j, res = AST_TEST_PASS, syserr;</span><br><span>       struct ast_vm_user *vmu;</span><br><span style="color: hsl(120, 100%, 40%);">+      struct ast_vm_user svm;</span><br><span>      struct vm_state vms;</span><br><span> #ifdef IMAP_STORAGE</span><br><span>  struct ast_channel *chan = NULL;</span><br><span>@@ -14544,11 +14620,9 @@</span><br><span>  }</span><br><span> #endif</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- AST_LIST_LOCK(&users);</span><br><span style="color: hsl(0, 100%, 40%);">-      vmu = find_or_create(testcontext, testmailbox);</span><br><span style="color: hsl(0, 100%, 40%);">- AST_LIST_UNLOCK(&users);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-    if (!vmu) {</span><br><span style="color: hsl(120, 100%, 40%);">+   memset(&svm, 0, sizeof(svm));</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!(vmu = find_user(&svm, testcontext, testmailbox)) &&</span><br><span style="color: hsl(120, 100%, 40%);">+         !(vmu = find_or_create(testcontext, testmailbox))) {</span><br><span>                 ast_test_status_update(test, "Cannot create vmu structure\n");</span><br><span>             ast_unreplace_sigchld();</span><br><span> #ifdef IMAP_STORAGE</span><br><span>@@ -14576,8 +14650,8 @@</span><br><span> #ifdef IMAP_STORAGE</span><br><span>                             chan = ast_channel_unref(chan);</span><br><span> #endif</span><br><span style="color: hsl(0, 100%, 40%);">-                               res = AST_TEST_FAIL;</span><br><span style="color: hsl(0, 100%, 40%);">-                            break;</span><br><span style="color: hsl(120, 100%, 40%);">+                                free_user(vmu);</span><br><span style="color: hsl(120, 100%, 40%);">+                               return AST_TEST_FAIL;</span><br><span>                        }</span><br><span>            }</span><br><span> </span><br><span>@@ -14601,34 +14675,27 @@</span><br><span>                            res = AST_TEST_FAIL;</span><br><span>                         }</span><br><span>            }</span><br><span style="color: hsl(0, 100%, 40%);">-               if (res) {</span><br><span style="color: hsl(0, 100%, 40%);">-                      break;</span><br><span style="color: hsl(0, 100%, 40%);">-          }</span><br><span> </span><br><span>                new = old = urgent = 0;</span><br><span>              if (ast_app_inboxcount(testspec, &new, &old)) {</span><br><span>                      ast_test_status_update(test, "inboxcount returned failure\n");</span><br><span>                     res = AST_TEST_FAIL;</span><br><span style="color: hsl(0, 100%, 40%);">-                    break;</span><br><span>               } else if (old != expected_results[i][3 + 0] || new != expected_results[i][3 + 2]) {</span><br><span>                         ast_test_status_update(test, "inboxcount(%s) returned old=%d (expected %d) and new=%d (expected %d)\n",</span><br><span>                            testspec, old, expected_results[i][3 + 0], new, expected_results[i][3 + 2]);</span><br><span>                         res = AST_TEST_FAIL;</span><br><span style="color: hsl(0, 100%, 40%);">-                    break;</span><br><span>               }</span><br><span> </span><br><span>                new = old = urgent = 0;</span><br><span>              if (ast_app_inboxcount2(testspec, &urgent, &new, &old)) {</span><br><span>                        ast_test_status_update(test, "inboxcount2 returned failure\n");</span><br><span>                    res = AST_TEST_FAIL;</span><br><span style="color: hsl(0, 100%, 40%);">-                    break;</span><br><span>               } else if (old != expected_results[i][6 + 0] ||</span><br><span>                              urgent != expected_results[i][6 + 1] ||</span><br><span>                                 new != expected_results[i][6 + 2]    ) {</span><br><span>                  ast_test_status_update(test, "inboxcount2(%s) returned old=%d (expected %d), urgent=%d (expected %d), and new=%d (expected %d)\n",</span><br><span>                                 testspec, old, expected_results[i][6 + 0], urgent, expected_results[i][6 + 1], new, expected_results[i][6 + 2]);</span><br><span>                     res = AST_TEST_FAIL;</span><br><span style="color: hsl(0, 100%, 40%);">-                    break;</span><br><span>               }</span><br><span> </span><br><span>                new = old = urgent = 0;</span><br><span>@@ -14639,9 +14706,6 @@</span><br><span>                            res = AST_TEST_FAIL;</span><br><span>                         }</span><br><span>            }</span><br><span style="color: hsl(0, 100%, 40%);">-               if (res) {</span><br><span style="color: hsl(0, 100%, 40%);">-                      break;</span><br><span style="color: hsl(0, 100%, 40%);">-          }</span><br><span>    }</span><br><span> </span><br><span>        for (i = 0; i < 3; i++) {</span><br><span>@@ -14670,9 +14734,7 @@</span><br><span>                       syserr > 0 ? strerror(syserr) : "unable to fork()");</span><br><span>    }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   /* restore config */</span><br><span style="color: hsl(0, 100%, 40%);">-    load_config(0); /* this might say "Failed to load configuration file." */</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(120, 100%, 40%);">+   free_user(vmu);</span><br><span>      return res;</span><br><span> }</span><br><span> </span><br><span>@@ -14723,13 +14785,15 @@</span><br><span>     snprintf(attach, sizeof(attach), "%s/sounds/en/tt-weasels", ast_config_AST_DATA_DIR);</span><br><span>      snprintf(attach2, sizeof(attach2), "%s/sounds/en/tt-somethingwrong", ast_config_AST_DATA_DIR);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-    AST_LIST_LOCK(&users);</span><br><span style="color: hsl(0, 100%, 40%);">-      vmu = find_or_create(testcontext, testmailbox);</span><br><span style="color: hsl(0, 100%, 40%);">- AST_LIST_UNLOCK(&users);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-    if (!vmu) {</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!(vmu = find_user(&vmus, testcontext, testmailbox)) &&</span><br><span style="color: hsl(120, 100%, 40%);">+                !(vmu = find_or_create(testcontext, testmailbox))) {</span><br><span>                 ast_test_status_update(test, "Cannot create vmu structure\n");</span><br><span style="color: hsl(0, 100%, 40%);">-                return AST_TEST_FAIL;</span><br><span style="color: hsl(120, 100%, 40%);">+         return AST_TEST_NOT_RUN;</span><br><span style="color: hsl(120, 100%, 40%);">+      }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (vmu != &vmus && !(vmu = find_user(&vmus, testcontext, testmailbox))) {</span><br><span style="color: hsl(120, 100%, 40%);">+            ast_test_status_update(test, "Cannot find vmu structure?!!\n");</span><br><span style="color: hsl(120, 100%, 40%);">+             return AST_TEST_NOT_RUN;</span><br><span>     }</span><br><span> </span><br><span>        populate_defaults(vmu);</span><br><span>@@ -14780,10 +14844,7 @@</span><br><span>           }</span><br><span>    }</span><br><span>    fclose(file);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-   /* restore config */</span><br><span style="color: hsl(0, 100%, 40%);">-    load_config(0); /* this might say "Failed to load configuration file." */</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(120, 100%, 40%);">+   free_user(vmu);</span><br><span>      return res;</span><br><span> }</span><br><span> </span><br><span>@@ -14857,7 +14918,7 @@</span><br><span> #undef CHECK</span><br><span> </span><br><span>   /* restore config */</span><br><span style="color: hsl(0, 100%, 40%);">-    load_config(0); /* this might say "Failed to load configuration file." */</span><br><span style="color: hsl(120, 100%, 40%);">+   load_config(1); /* this might say "Failed to load configuration file." */</span><br><span> </span><br><span> cleanup:</span><br><span>  unlink(config_filename);</span><br><span>@@ -14913,11 +14974,8 @@</span><br><span>          return AST_TEST_FAIL;</span><br><span>        }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   AST_LIST_LOCK(&users);</span><br><span style="color: hsl(0, 100%, 40%);">-      vmu = find_or_create(testcontext, testmailbox);</span><br><span style="color: hsl(0, 100%, 40%);">- AST_LIST_UNLOCK(&users);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-    if (!vmu) {</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!(vmu = find_user(NULL, testcontext, testmailbox)) &&</span><br><span style="color: hsl(120, 100%, 40%);">+                     !(vmu = find_or_create(testcontext, testmailbox))) {</span><br><span>                 ast_test_status_update(test, "Cannot create vmu structure\n");</span><br><span>             chan = ast_channel_unref(chan);</span><br><span>              return AST_TEST_FAIL;</span><br><span>@@ -14947,10 +15005,7 @@</span><br><span>     }</span><br><span> </span><br><span>        chan = ast_channel_unref(chan);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* restore config */</span><br><span style="color: hsl(0, 100%, 40%);">-    load_config(0); /* this might say "Failed to load configuration file." */</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(120, 100%, 40%);">+   free_user(vmu);</span><br><span>      return res;</span><br><span> }</span><br><span> #endif /* defined(TEST_FRAMEWORK) */</span><br><span>@@ -15016,13 +15071,10 @@</span><br><span> #endif</span><br><span>       ao2_ref(inprocess_container, -1);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   if (poll_thread != AST_PTHREADT_NULL) {</span><br><span style="color: hsl(120, 100%, 40%);">+       if (poll_thread != AST_PTHREADT_NULL)</span><br><span>                stop_poll_thread();</span><br><span style="color: hsl(0, 100%, 40%);">-     }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   ao2_container_unregister("voicemail_poll_list");</span><br><span style="color: hsl(0, 100%, 40%);">-      ao2_cleanup(poll_list);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(120, 100%, 40%);">+       mwi_subscription_tps = ast_taskprocessor_unreference(mwi_subscription_tps);</span><br><span>  ast_unload_realtime("voicemail");</span><br><span>  ast_unload_realtime("voicemail_data");</span><br><span> </span><br><span>@@ -15034,18 +15086,6 @@</span><br><span>      return res;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-static void print_poll_state(void *v_obj, void *where, ao2_prnt_fn *prnt)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-  struct poll_state *poll_state = v_obj;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-  if (!poll_state) {</span><br><span style="color: hsl(0, 100%, 40%);">-              return;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">-       prnt(where, "Mailbox: %s New: %d  Old: %d  Urgent: %d  Marked Used: %d", poll_state->mailbox,</span><br><span style="color: hsl(0, 100%, 40%);">-              poll_state->old_new, poll_state->old_old, poll_state->old_urgent,</span><br><span style="color: hsl(0, 100%, 40%);">-              poll_state->marked_used);</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span> /*!</span><br><span>  * \brief Load the module</span><br><span>  *</span><br><span>@@ -15072,24 +15112,13 @@</span><br><span>          return AST_MODULE_LOAD_DECLINE;</span><br><span>      }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   poll_list = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0, POLL_LIST_BUCKETS,</span><br><span style="color: hsl(0, 100%, 40%);">-            poll_state_hash_fn, NULL, poll_state_cmp_fn);</span><br><span style="color: hsl(0, 100%, 40%);">-   if (!poll_list) {</span><br><span style="color: hsl(0, 100%, 40%);">-               ast_log(LOG_ERROR, "Unable to create poll_list container\n");</span><br><span style="color: hsl(0, 100%, 40%);">-         ao2_cleanup(inprocess_container);</span><br><span style="color: hsl(0, 100%, 40%);">-               return AST_MODULE_LOAD_DECLINE;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">-       res = ao2_container_register("voicemail_poll_list", poll_list, print_poll_state);</span><br><span style="color: hsl(0, 100%, 40%);">-     if (res) {</span><br><span style="color: hsl(0, 100%, 40%);">-              ast_log(LOG_ERROR, "Unable to register poll_list container\n");</span><br><span style="color: hsl(0, 100%, 40%);">-               ao2_cleanup(inprocess_container);</span><br><span style="color: hsl(0, 100%, 40%);">-               ao2_cleanup(poll_list);</span><br><span style="color: hsl(0, 100%, 40%);">-         return AST_MODULE_LOAD_DECLINE;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span>    /* compute the location of the voicemail spool directory */</span><br><span>  snprintf(VM_SPOOL_DIR, sizeof(VM_SPOOL_DIR), "%s/voicemail/", ast_config_AST_SPOOL_DIR);</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+        if (!(mwi_subscription_tps = ast_taskprocessor_get("app_voicemail", 0))) {</span><br><span style="color: hsl(120, 100%, 40%);">+          ast_log(AST_LOG_WARNING, "failed to reference mwi subscription taskprocessor.  MWI will not work\n");</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>  if ((res = load_config(0))) {</span><br><span>                unload_module();</span><br><span>             return AST_MODULE_LOAD_DECLINE;</span><br><span>diff --git a/configs/samples/voicemail.conf.sample b/configs/samples/voicemail.conf.sample</span><br><span>index 43325a2..e4130d3 100644</span><br><span>--- a/configs/samples/voicemail.conf.sample</span><br><span>+++ b/configs/samples/voicemail.conf.sample</span><br><span>@@ -387,6 +387,17 @@</span><br><span> ; defaults to being off</span><br><span> ; backupdeleted=100</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+; Asterisk Task Processor Queue Size</span><br><span style="color: hsl(120, 100%, 40%);">+; On heavy loaded system you may need to increase 'app_voicemail' taskprocessor queue.</span><br><span style="color: hsl(120, 100%, 40%);">+; If the taskprocessor queue size reached high water level, the alert is triggered.</span><br><span style="color: hsl(120, 100%, 40%);">+; If the alert is set then some modules (for example pjsip) slow down its production</span><br><span style="color: hsl(120, 100%, 40%);">+; until the alert is cleared.</span><br><span style="color: hsl(120, 100%, 40%);">+; The alert is cleared when taskprocessor queue size drops to the low water clear level.</span><br><span style="color: hsl(120, 100%, 40%);">+; The next options set taskprocessor queue levels for this module.</span><br><span style="color: hsl(120, 100%, 40%);">+; tps_queue_high=500       ; Taskprocessor high water alert trigger level.</span><br><span style="color: hsl(120, 100%, 40%);">+; tps_queue_low=450    ; Taskprocessor low water clear alert level.</span><br><span style="color: hsl(120, 100%, 40%);">+                  ; The default is -1 for 90% of high water level.</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> [zonemessages]</span><br><span> ; Users may be located in different timezones, or may have different</span><br><span> ; message announcements for their introductory message when they enter</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.asterisk.org/10720">change 10720</a>. To unsubscribe, or for help writing mail filters, visit <a href="https://gerrit.asterisk.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.asterisk.org/10720"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: asterisk </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-MessageType: merged </div>
<div style="display:none"> Gerrit-Change-Id: I57b7b85e75d7dd97c742b5c69d718a0f61260c15 </div>
<div style="display:none"> Gerrit-Change-Number: 10720 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: George Joseph <gjoseph@digium.com> </div>
<div style="display:none"> Gerrit-Reviewer: Benjamin Keith Ford <bford@digium.com> </div>
<div style="display:none"> Gerrit-Reviewer: George Joseph <gjoseph@digium.com> </div>
<div style="display:none"> Gerrit-Reviewer: Jenkins2 (1000185) </div>
<div style="display:none"> Gerrit-Reviewer: Joshua Colp <jcolp@digium.com> </div>
<div style="display:none"> Gerrit-Reviewer: Matthew Fredrickson <creslin@digium.com> </div>