<p>Joshua C. Colp <strong>merged</strong> this change.</p><p><a href="https://gerrit.asterisk.org/10801">View Change</a></p><div style="white-space:pre-wrap">Approvals:
  Sean Bright: Looks good to me, but someone else must approve
  Joshua C. Colp: Looks good to me, approved; Approved for Submit

</div><pre style="font-family: monospace,monospace; white-space: pre-wrap;">app_voicemail:  Add Mailbox Aliases<br><br>You can now define an "aliases" context in voicemail.conf<br>whose entries point to actual mailboxes.  These can be used anywhere<br>the mailbox is specified.<br><br>Example:<br>[general]<br>aliasescontext = myaliases<br><br>[default]<br>1234 = yadayada<br><br>[myaliases]<br>4321@devices = 1234@default<br><br>Now you can use 4321@devices to refer to the 1234@default mailbox.<br><br>This can be useful to provide channel drivers with constant<br>mailbox specifications such as <extension>@devices leaving<br>app_voicemail to control exactly which mailbox the alias points to.<br>Now, only voicemail has to be reloaded to make changes instead of<br>individual channel drivers which are usually more expensive to<br>reload.<br><br>Change-Id: I395b9205c91523a334fe971be0d1de4522067b04<br>---<br>M CHANGES<br>M apps/app_voicemail.c<br>M configs/samples/voicemail.conf.sample<br>3 files changed, 288 insertions(+), 45 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/CHANGES b/CHANGES</span><br><span>index 3459b47..23612fb 100644</span><br><span>--- a/CHANGES</span><br><span>+++ b/CHANGES</span><br><span>@@ -93,6 +93,12 @@</span><br><span>    The previous behavior has been restored so both channels receive the</span><br><span>    channel variable when one of these features is invoked.</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+app_voicemail</span><br><span style="color: hsl(120, 100%, 40%);">+------------------</span><br><span style="color: hsl(120, 100%, 40%);">+ * You can now specify a special context with the "aliasescontext" parameter</span><br><span style="color: hsl(120, 100%, 40%);">+   in voicemail.conf which will allow you to create aliases for physical</span><br><span style="color: hsl(120, 100%, 40%);">+   mailboxes.</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> ------------------------------------------------------------------------------</span><br><span> --- Functionality changes from Asterisk 16.0.0 to Asterisk 16.1.0 ------------</span><br><span> ------------------------------------------------------------------------------</span><br><span>diff --git a/apps/app_voicemail.c b/apps/app_voicemail.c</span><br><span>index d132e2b..3223af6 100644</span><br><span>--- a/apps/app_voicemail.c</span><br><span>+++ b/apps/app_voicemail.c</span><br><span>@@ -999,6 +999,7 @@</span><br><span> static int maxlogins;</span><br><span> static int minpassword;</span><br><span> static int passwordlocation;</span><br><span style="color: hsl(120, 100%, 40%);">+static char aliasescontext[MAX_VM_CONTEXT_LEN];</span><br><span> </span><br><span> /*! Poll mailboxes for changes since there is something external to</span><br><span>  *  app_voicemail that may change them. */</span><br><span>@@ -1051,6 +1052,27 @@</span><br><span> </span><br><span> static AST_RWLIST_HEAD_STATIC(mwi_subs, mwi_sub);</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+struct alias_mailbox_mapping {</span><br><span style="color: hsl(120, 100%, 40%);">+ char *alias;</span><br><span style="color: hsl(120, 100%, 40%);">+  char *mailbox;</span><br><span style="color: hsl(120, 100%, 40%);">+        char buf[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%);">+struct mailbox_alias_mapping {</span><br><span style="color: hsl(120, 100%, 40%);">+    char *alias;</span><br><span style="color: hsl(120, 100%, 40%);">+  char *mailbox;</span><br><span style="color: hsl(120, 100%, 40%);">+        char buf[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%);">+#define MAPPING_BUCKETS 511</span><br><span style="color: hsl(120, 100%, 40%);">+static struct ao2_container *alias_mailbox_mappings;</span><br><span style="color: hsl(120, 100%, 40%);">+AO2_STRING_FIELD_HASH_FN(alias_mailbox_mapping, alias);</span><br><span style="color: hsl(120, 100%, 40%);">+AO2_STRING_FIELD_CMP_FN(alias_mailbox_mapping, alias);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static struct ao2_container *mailbox_alias_mappings;</span><br><span style="color: hsl(120, 100%, 40%);">+AO2_STRING_FIELD_HASH_FN(mailbox_alias_mapping, mailbox);</span><br><span style="color: hsl(120, 100%, 40%);">+AO2_STRING_FIELD_CMP_FN(mailbox_alias_mapping, mailbox);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /* custom audio control prompts for voicemail playback */</span><br><span> static char listen_control_forward_key[12];</span><br><span> static char listen_control_reverse_key[12];</span><br><span>@@ -1765,9 +1787,31 @@</span><br><span>                    ast_set2_flag(vmu, !ivm, VM_ALLOCED);</span><br><span>                        AST_LIST_NEXT(vmu, list) = NULL;</span><br><span>             }</span><br><span style="color: hsl(0, 100%, 40%);">-       } else</span><br><span style="color: hsl(0, 100%, 40%);">-          vmu = find_user_realtime(ivm, context, mailbox);</span><br><span style="color: hsl(120, 100%, 40%);">+      }</span><br><span>    AST_LIST_UNLOCK(&users);</span><br><span style="color: hsl(120, 100%, 40%);">+  if (!vmu) {</span><br><span style="color: hsl(120, 100%, 40%);">+           vmu = find_user_realtime(ivm, context, mailbox);</span><br><span style="color: hsl(120, 100%, 40%);">+      }</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!vmu && !ast_strlen_zero(aliasescontext)) {</span><br><span style="color: hsl(120, 100%, 40%);">+               struct alias_mailbox_mapping *mapping;</span><br><span style="color: hsl(120, 100%, 40%);">+                char *search_string = ast_alloca(MAX_VM_MAILBOX_LEN);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+               snprintf(search_string, MAX_VM_MAILBOX_LEN, "%s%s%s",</span><br><span style="color: hsl(120, 100%, 40%);">+                       mailbox,</span><br><span style="color: hsl(120, 100%, 40%);">+                      ast_strlen_zero(context) ? "" : "@",</span><br><span style="color: hsl(120, 100%, 40%);">+                      S_OR(context, ""));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+               mapping = ao2_find(alias_mailbox_mappings, search_string, OBJ_SEARCH_KEY);</span><br><span style="color: hsl(120, 100%, 40%);">+            if (mapping) {</span><br><span style="color: hsl(120, 100%, 40%);">+                        char *search_mailbox = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+                  char *search_context = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                        separate_mailbox(ast_strdupa(mapping->mailbox), &search_mailbox, &search_context);</span><br><span style="color: hsl(120, 100%, 40%);">+                 ao2_ref(mapping, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+                 vmu = find_user(ivm, search_mailbox, search_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%);">+</span><br><span>  return vmu;</span><br><span> }</span><br><span> </span><br><span>@@ -6056,6 +6100,9 @@</span><br><span>         struct dirent *de;</span><br><span>   char fn[256];</span><br><span>        int ret = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+  struct alias_mailbox_mapping *mapping;</span><br><span style="color: hsl(120, 100%, 40%);">+        char *c;</span><br><span style="color: hsl(120, 100%, 40%);">+      char *m;</span><br><span> </span><br><span>         /* If no mailbox, return immediately */</span><br><span>      if (ast_strlen_zero(mailbox))</span><br><span>@@ -6066,7 +6113,21 @@</span><br><span>       if (ast_strlen_zero(context))</span><br><span>                context = "default";</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-      snprintf(fn, sizeof(fn), "%s%s/%s/%s", VM_SPOOL_DIR, context, mailbox, folder);</span><br><span style="color: hsl(120, 100%, 40%);">+     c = (char *)context;</span><br><span style="color: hsl(120, 100%, 40%);">+  m = (char *)mailbox;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        if (!ast_strlen_zero(aliasescontext)) {</span><br><span style="color: hsl(120, 100%, 40%);">+               char tmp[MAX_VM_MAILBOX_LEN];</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+               snprintf(tmp, MAX_VM_MAILBOX_LEN, "%s@%s", mailbox, context);</span><br><span style="color: hsl(120, 100%, 40%);">+               mapping = ao2_find(alias_mailbox_mappings, tmp, OBJ_SEARCH_KEY);</span><br><span style="color: hsl(120, 100%, 40%);">+              if (mapping) {</span><br><span style="color: hsl(120, 100%, 40%);">+                        separate_mailbox(ast_strdupa(mapping->mailbox), &m, &c);</span><br><span style="color: hsl(120, 100%, 40%);">+                   ao2_ref(mapping, -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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   snprintf(fn, sizeof(fn), "%s%s/%s/%s", VM_SPOOL_DIR, c, m, folder);</span><br><span> </span><br><span>    if (!(dir = opendir(fn)))</span><br><span>            return 0;</span><br><span>@@ -8096,7 +8157,24 @@</span><br><span>           return;</span><br><span>      }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ ast_debug(3, "Queueing event for mailbox %s  New: %d   Old: %d\n", box, new + urgent, old);</span><br><span>        ast_publish_mwi_state_channel(mailbox, context, new + urgent, old, channel_id);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!ast_strlen_zero(aliasescontext)) {</span><br><span style="color: hsl(120, 100%, 40%);">+               struct ao2_iterator *aliases;</span><br><span style="color: hsl(120, 100%, 40%);">+         struct mailbox_alias_mapping *mapping;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+              aliases = ao2_find(mailbox_alias_mappings, box, OBJ_SEARCH_KEY | OBJ_MULTIPLE);</span><br><span style="color: hsl(120, 100%, 40%);">+               while ((mapping = ao2_iterator_next(aliases))) {</span><br><span style="color: hsl(120, 100%, 40%);">+                      mailbox = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+                       context = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+                       ast_debug(3, "Found alias mapping: %s -> %s\n", mapping->alias, box);</span><br><span style="color: hsl(120, 100%, 40%);">+                 separate_mailbox(ast_strdupa(mapping->alias), &mailbox, &context);</span><br><span style="color: hsl(120, 100%, 40%);">+                 ast_publish_mwi_state_channel(mailbox, context, new + urgent, old, channel_id);</span><br><span style="color: hsl(120, 100%, 40%);">+                       ao2_ref(mapping, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+         }</span><br><span style="color: hsl(120, 100%, 40%);">+             ao2_iterator_destroy(aliases);</span><br><span style="color: hsl(120, 100%, 40%);">+        }</span><br><span> }</span><br><span> </span><br><span> /*!</span><br><span>@@ -13000,6 +13078,46 @@</span><br><span>         return res;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+/*! \brief Show a list of voicemail zones in the CLI */</span><br><span style="color: hsl(120, 100%, 40%);">+static char *handle_voicemail_show_aliases(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        struct ao2_iterator aliases;</span><br><span style="color: hsl(120, 100%, 40%);">+  struct alias_mailbox_mapping *mapping;</span><br><span style="color: hsl(120, 100%, 40%);">+#define ALIASES_OUTPUT_FORMAT "%-32s %-32s\n"</span><br><span style="color: hsl(120, 100%, 40%);">+       char *res = CLI_SUCCESS;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    switch (cmd) {</span><br><span style="color: hsl(120, 100%, 40%);">+        case CLI_INIT:</span><br><span style="color: hsl(120, 100%, 40%);">+                e->command = "voicemail show aliases";</span><br><span style="color: hsl(120, 100%, 40%);">+           e->usage =</span><br><span style="color: hsl(120, 100%, 40%);">+                 "Usage: voicemail show aliases\n"</span><br><span style="color: hsl(120, 100%, 40%);">+                   "       Lists mailbox aliases\n";</span><br><span style="color: hsl(120, 100%, 40%);">+           return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  case CLI_GENERATE:</span><br><span style="color: hsl(120, 100%, 40%);">+            return NULL;</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 (a->argc != 3)</span><br><span style="color: hsl(120, 100%, 40%);">+          return CLI_SHOWUSAGE;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       if (ast_strlen_zero(aliasescontext)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                ast_cli(a->fd, "Aliases are not enabled\n");</span><br><span style="color: hsl(120, 100%, 40%);">+             return res;</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_cli(a->fd, "Aliases context: %s\n", aliasescontext);</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_cli(a->fd, ALIASES_OUTPUT_FORMAT, "Alias", "Mailbox");</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   aliases = ao2_iterator_init(alias_mailbox_mappings, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+       while ((mapping = ao2_iterator_next(&aliases))) {</span><br><span style="color: hsl(120, 100%, 40%);">+         ast_cli(a->fd, ALIASES_OUTPUT_FORMAT, mapping->alias, mapping->mailbox);</span><br><span style="color: hsl(120, 100%, 40%);">+             ao2_ref(mapping, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+     ao2_iterator_destroy(&aliases);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return res;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /*! \brief Reload voicemail configuration from the CLI */</span><br><span> static char *handle_voicemail_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)</span><br><span> {</span><br><span>@@ -13026,6 +13144,7 @@</span><br><span> static struct ast_cli_entry cli_voicemail[] = {</span><br><span>    AST_CLI_DEFINE(handle_voicemail_show_users, "List defined voicemail boxes"),</span><br><span>       AST_CLI_DEFINE(handle_voicemail_show_zones, "List zone message formats"),</span><br><span style="color: hsl(120, 100%, 40%);">+   AST_CLI_DEFINE(handle_voicemail_show_aliases, "List mailbox aliases"),</span><br><span>     AST_CLI_DEFINE(handle_voicemail_reload, "Reload voicemail configuration"),</span><br><span> };</span><br><span> </span><br><span>@@ -13244,7 +13363,6 @@</span><br><span>     if (stasis_message_type(msg) != stasis_subscription_change_type()) {</span><br><span>                 return;</span><br><span>      }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span>    change = stasis_message_data(msg);</span><br><span>   if (change->topic == ast_mwi_topic_all()) {</span><br><span>               return;</span><br><span>@@ -13662,11 +13780,98 @@</span><br><span> }</span><br><span> #endif</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+static struct alias_mailbox_mapping *alias_mailbox_mapping_create(const char *alias, const char *mailbox)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  struct alias_mailbox_mapping *mapping;</span><br><span style="color: hsl(120, 100%, 40%);">+        size_t from_len = strlen(alias) + 1;</span><br><span style="color: hsl(120, 100%, 40%);">+  size_t to_len = strlen(mailbox) + 1;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        mapping = ao2_alloc(sizeof(*mapping) + from_len + to_len, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+      if (!mapping) {</span><br><span style="color: hsl(120, 100%, 40%);">+               return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+     mapping->alias = mapping->buf;</span><br><span style="color: hsl(120, 100%, 40%);">+  mapping->mailbox = mapping->buf + from_len;</span><br><span style="color: hsl(120, 100%, 40%);">+     strcpy(mapping->alias, alias); /* Safe */</span><br><span style="color: hsl(120, 100%, 40%);">+  strcpy(mapping->mailbox, mailbox); /* Safe */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    return mapping;</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 load_aliases(struct ast_config *cfg)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     struct ast_variable *var;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (ast_strlen_zero(aliasescontext)) {</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%);">+     var = ast_variable_browse(cfg, aliasescontext);</span><br><span style="color: hsl(120, 100%, 40%);">+       while (var) {</span><br><span style="color: hsl(120, 100%, 40%);">+         struct alias_mailbox_mapping *mapping = alias_mailbox_mapping_create(var->name, var->value);</span><br><span style="color: hsl(120, 100%, 40%);">+            if (mapping) {</span><br><span style="color: hsl(120, 100%, 40%);">+                        ao2_link(alias_mailbox_mappings, mapping);</span><br><span style="color: hsl(120, 100%, 40%);">+                    ao2_link(mailbox_alias_mappings, mapping);</span><br><span style="color: hsl(120, 100%, 40%);">+                    ao2_ref(mapping, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+         }</span><br><span style="color: hsl(120, 100%, 40%);">+             var = var->next;</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 load_zonemessages(struct ast_config *cfg)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      struct ast_variable *var;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   var = ast_variable_browse(cfg, "zonemessages");</span><br><span style="color: hsl(120, 100%, 40%);">+     while (var) {</span><br><span style="color: hsl(120, 100%, 40%);">+         struct vm_zone *z;</span><br><span style="color: hsl(120, 100%, 40%);">+            char *msg_format, *tzone;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           z = ast_malloc(sizeof(*z));</span><br><span style="color: hsl(120, 100%, 40%);">+           if (!z) {</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%);">+           msg_format = ast_strdupa(var->value);</span><br><span style="color: hsl(120, 100%, 40%);">+              tzone = strsep(&msg_format, "|,");</span><br><span style="color: hsl(120, 100%, 40%);">+              if (msg_format) {</span><br><span style="color: hsl(120, 100%, 40%);">+                     ast_copy_string(z->name, var->name, sizeof(z->name));</span><br><span style="color: hsl(120, 100%, 40%);">+                        ast_copy_string(z->timezone, tzone, sizeof(z->timezone));</span><br><span style="color: hsl(120, 100%, 40%);">+                       ast_copy_string(z->msg_format, msg_format, sizeof(z->msg_format));</span><br><span style="color: hsl(120, 100%, 40%);">+                      AST_LIST_LOCK(&zones);</span><br><span style="color: hsl(120, 100%, 40%);">+                    AST_LIST_INSERT_HEAD(&zones, z, list);</span><br><span style="color: hsl(120, 100%, 40%);">+                    AST_LIST_UNLOCK(&zones);</span><br><span style="color: hsl(120, 100%, 40%);">+          } else {</span><br><span style="color: hsl(120, 100%, 40%);">+                      ast_log(AST_LOG_WARNING, "Invalid timezone definition at line %d\n", var->lineno);</span><br><span style="color: hsl(120, 100%, 40%);">+                       ast_free(z);</span><br><span style="color: hsl(120, 100%, 40%);">+          }</span><br><span style="color: hsl(120, 100%, 40%);">+             var = var->next;</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 load_users(struct ast_config *cfg)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     struct ast_variable *var;</span><br><span style="color: hsl(120, 100%, 40%);">+     char *cat = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   while ((cat = ast_category_browse(cfg, cat))) {</span><br><span style="color: hsl(120, 100%, 40%);">+               if (strcasecmp(cat, "general") == 0</span><br><span style="color: hsl(120, 100%, 40%);">+                 || strcasecmp(cat, aliasescontext) == 0</span><br><span style="color: hsl(120, 100%, 40%);">+                       || strcasecmp(cat, "zonemessages") == 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                  continue;</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%);">+           var = ast_variable_browse(cfg, cat);</span><br><span style="color: hsl(120, 100%, 40%);">+          while (var) {</span><br><span style="color: hsl(120, 100%, 40%);">+                 append_mailbox(cat, var->name, var->value);</span><br><span style="color: hsl(120, 100%, 40%);">+                     var = var->next;</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%);">+</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>         char *cat;</span><br><span style="color: hsl(0, 100%, 40%);">-      struct ast_variable *var;</span><br><span>    const char *val;</span><br><span>     char *q, *stringp, *tmp;</span><br><span>     int x;</span><br><span>@@ -13695,6 +13900,10 @@</span><br><span>    /* Free all the zones structure */</span><br><span>   free_vm_zones();</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+  /* Remove all aliases */</span><br><span style="color: hsl(120, 100%, 40%);">+      ao2_callback(alias_mailbox_mappings, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+     ao2_callback(mailbox_alias_mappings, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>  AST_LIST_LOCK(&users);</span><br><span> </span><br><span>       memset(ext_pass_cmd, 0, sizeof(ext_pass_cmd));</span><br><span>@@ -13706,6 +13915,11 @@</span><br><span>            if (!(val = ast_variable_retrieve(cfg, "general", "userscontext")))</span><br><span>                      val = "default";</span><br><span>           ast_copy_string(userscontext, val, sizeof(userscontext));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           aliasescontext[0] = '\0';</span><br><span style="color: hsl(120, 100%, 40%);">+             val = ast_variable_retrieve(cfg, "general", "aliasescontext");</span><br><span style="color: hsl(120, 100%, 40%);">+            ast_copy_string(aliasescontext, S_OR(val, ""), sizeof(aliasescontext));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>          /* Attach voice message to mail message ? */</span><br><span>                 if (!(val = ast_variable_retrieve(cfg, "general", "attach")))</span><br><span>                    val = "yes";</span><br><span>@@ -14307,45 +14521,16 @@</span><br><span>           }</span><br><span> </span><br><span>                /* load mailboxes from voicemail.conf */</span><br><span style="color: hsl(0, 100%, 40%);">-                cat = ast_category_browse(cfg, NULL);</span><br><span style="color: hsl(0, 100%, 40%);">-           while (cat) {</span><br><span style="color: hsl(0, 100%, 40%);">-                   if (strcasecmp(cat, "general")) {</span><br><span style="color: hsl(0, 100%, 40%);">-                             var = ast_variable_browse(cfg, cat);</span><br><span style="color: hsl(0, 100%, 40%);">-                            if (strcasecmp(cat, "zonemessages")) {</span><br><span style="color: hsl(0, 100%, 40%);">-                                        /* Process mailboxes in this context */</span><br><span style="color: hsl(0, 100%, 40%);">-                                 while (var) {</span><br><span style="color: hsl(0, 100%, 40%);">-                                           append_mailbox(cat, var->name, var->value);</span><br><span style="color: hsl(0, 100%, 40%);">-                                               var = var->next;</span><br><span style="color: hsl(0, 100%, 40%);">-                                     }</span><br><span style="color: hsl(0, 100%, 40%);">-                               } else {</span><br><span style="color: hsl(0, 100%, 40%);">-                                        /* Timezones in this context */</span><br><span style="color: hsl(0, 100%, 40%);">-                                 while (var) {</span><br><span style="color: hsl(0, 100%, 40%);">-                                           struct vm_zone *z;</span><br><span style="color: hsl(0, 100%, 40%);">-                                              if ((z = ast_malloc(sizeof(*z)))) {</span><br><span style="color: hsl(0, 100%, 40%);">-                                                     char *msg_format, *tzone;</span><br><span style="color: hsl(0, 100%, 40%);">-                                                       msg_format = ast_strdupa(var->value);</span><br><span style="color: hsl(0, 100%, 40%);">-                                                        tzone = strsep(&msg_format, "|,");</span><br><span style="color: hsl(0, 100%, 40%);">-                                                        if (msg_format) {</span><br><span style="color: hsl(0, 100%, 40%);">-                                                               ast_copy_string(z->name, var->name, sizeof(z->name));</span><br><span style="color: hsl(0, 100%, 40%);">-                                                          ast_copy_string(z->timezone, tzone, sizeof(z->timezone));</span><br><span style="color: hsl(0, 100%, 40%);">-                                                         ast_copy_string(z->msg_format, msg_format, sizeof(z->msg_format));</span><br><span style="color: hsl(0, 100%, 40%);">-                                                                AST_LIST_LOCK(&zones);</span><br><span style="color: hsl(0, 100%, 40%);">-                                                              AST_LIST_INSERT_HEAD(&zones, z, list);</span><br><span style="color: hsl(0, 100%, 40%);">-                                                              AST_LIST_UNLOCK(&zones);</span><br><span style="color: hsl(0, 100%, 40%);">-                                                    } else {</span><br><span style="color: hsl(0, 100%, 40%);">-                                                                ast_log(AST_LOG_WARNING, "Invalid timezone definition at line %d\n", var->lineno);</span><br><span style="color: hsl(0, 100%, 40%);">-                                                         ast_free(z);</span><br><span style="color: hsl(0, 100%, 40%);">-                                                    }</span><br><span style="color: hsl(0, 100%, 40%);">-                                               } else {</span><br><span style="color: hsl(0, 100%, 40%);">-                                                        AST_LIST_UNLOCK(&users);</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%);">-                                               var = var->next;</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%);">-                       cat = ast_category_browse(cfg, cat);</span><br><span style="color: hsl(0, 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%);">+             * Aliases must be loaded before users or the aliases won't be notified</span><br><span style="color: hsl(120, 100%, 40%);">+            * if there's existing voicemail in the user mailbox.</span><br><span style="color: hsl(120, 100%, 40%);">+              */</span><br><span style="color: hsl(120, 100%, 40%);">+           load_aliases(cfg);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+          load_zonemessages(cfg);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+             load_users(cfg);</span><br><span> </span><br><span>                 AST_LIST_UNLOCK(&users);</span><br><span> </span><br><span>@@ -15096,6 +15281,16 @@</span><br><span>  return res;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+static void print_mappings(void *v_obj, void *where, ao2_prnt_fn *prnt)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      struct alias_mailbox_mapping *mapping = v_obj;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      if (!mapping) {</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%);">+     prnt(where, "Alias: %s Mailbox: %s", mapping->alias, mapping->mailbox);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /*!</span><br><span>  * \brief Load the module</span><br><span>  *</span><br><span>@@ -15122,6 +15317,38 @@</span><br><span>            return AST_MODULE_LOAD_DECLINE;</span><br><span>      }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ alias_mailbox_mappings = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0, MAPPING_BUCKETS,</span><br><span style="color: hsl(120, 100%, 40%);">+               alias_mailbox_mapping_hash_fn, NULL, alias_mailbox_mapping_cmp_fn);</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!alias_mailbox_mappings) {</span><br><span style="color: hsl(120, 100%, 40%);">+                ast_log(LOG_ERROR, "Unable to create alias_mailbox_mappings container\n");</span><br><span style="color: hsl(120, 100%, 40%);">+          ao2_cleanup(inprocess_container);</span><br><span style="color: hsl(120, 100%, 40%);">+             return AST_MODULE_LOAD_DECLINE;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+     res = ao2_container_register("voicemail_alias_mailbox_mappings", alias_mailbox_mappings, print_mappings);</span><br><span style="color: hsl(120, 100%, 40%);">+   if (res) {</span><br><span style="color: hsl(120, 100%, 40%);">+            ast_log(LOG_ERROR, "Unable to register alias_mailbox_mappings container\n");</span><br><span style="color: hsl(120, 100%, 40%);">+                ao2_cleanup(inprocess_container);</span><br><span style="color: hsl(120, 100%, 40%);">+             ao2_cleanup(alias_mailbox_mappings);</span><br><span style="color: hsl(120, 100%, 40%);">+          return AST_MODULE_LOAD_DECLINE;</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%);">+   mailbox_alias_mappings = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0, MAPPING_BUCKETS,</span><br><span style="color: hsl(120, 100%, 40%);">+               mailbox_alias_mapping_hash_fn, NULL, mailbox_alias_mapping_cmp_fn);</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!mailbox_alias_mappings) {</span><br><span style="color: hsl(120, 100%, 40%);">+                ast_log(LOG_ERROR, "Unable to create mailbox_alias_mappings container\n");</span><br><span style="color: hsl(120, 100%, 40%);">+          ao2_cleanup(inprocess_container);</span><br><span style="color: hsl(120, 100%, 40%);">+             ao2_cleanup(alias_mailbox_mappings);</span><br><span style="color: hsl(120, 100%, 40%);">+          return AST_MODULE_LOAD_DECLINE;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+     res = ao2_container_register("voicemail_mailbox_alias_mappings", mailbox_alias_mappings, print_mappings);</span><br><span style="color: hsl(120, 100%, 40%);">+   if (res) {</span><br><span style="color: hsl(120, 100%, 40%);">+            ast_log(LOG_ERROR, "Unable to register mailbox_alias_mappings container\n");</span><br><span style="color: hsl(120, 100%, 40%);">+                ao2_cleanup(inprocess_container);</span><br><span style="color: hsl(120, 100%, 40%);">+             ao2_cleanup(alias_mailbox_mappings);</span><br><span style="color: hsl(120, 100%, 40%);">+          ao2_cleanup(mailbox_alias_mappings);</span><br><span style="color: hsl(120, 100%, 40%);">+          return AST_MODULE_LOAD_DECLINE;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 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>diff --git a/configs/samples/voicemail.conf.sample b/configs/samples/voicemail.conf.sample</span><br><span>index e4130d3..30054b5 100644</span><br><span>--- a/configs/samples/voicemail.conf.sample</span><br><span>+++ b/configs/samples/voicemail.conf.sample</span><br><span>@@ -73,6 +73,10 @@</span><br><span> ;</span><br><span> ;userscontext=default</span><br><span> ;</span><br><span style="color: hsl(120, 100%, 40%);">+; Aliases allow a mailbox to be referenced by an alias.  The aliases are</span><br><span style="color: hsl(120, 100%, 40%);">+; specified in the special context named here.  There is no default.</span><br><span style="color: hsl(120, 100%, 40%);">+;aliasescontext=myaliases</span><br><span style="color: hsl(120, 100%, 40%);">+;</span><br><span> ; If you need to have an external program, i.e. /usr/bin/myapp</span><br><span> ; called when a voicemail is left, delivered, or your voicemailbox</span><br><span> ; is checked, uncomment this.</span><br><span>@@ -233,7 +237,6 @@</span><br><span>                          ; Default: no</span><br><span> </span><br><span> ; -----------------------------------------------------------------------------</span><br><span style="color: hsl(0, 100%, 40%);">-;</span><br><span> </span><br><span> ; Each mailbox is listed in the form <mailbox>=<password>,<name>,<email>,<pager_email>,<options></span><br><span> ; If email is specified, a message will be sent when a voicemail is received, to</span><br><span>@@ -451,6 +454,13 @@</span><br><span> ;4110 => 3443,Rob Flynn,rflynn@blueridge.net</span><br><span> ;4235 => 1234,Jim Holmes,jim@astricon.ips,,Tz=european</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+;</span><br><span style="color: hsl(120, 100%, 40%);">+; Aliases allow alternate references to mailboxes.  See the "aliasescontext"</span><br><span style="color: hsl(120, 100%, 40%);">+; parameter in the "general" section.</span><br><span style="color: hsl(120, 100%, 40%);">+;</span><br><span style="color: hsl(120, 100%, 40%);">+[myaliases]</span><br><span style="color: hsl(120, 100%, 40%);">+1234@devices => 1234@default</span><br><span style="color: hsl(120, 100%, 40%);">+;6200@devices => 4200@default</span><br><span> </span><br><span> ;</span><br><span> ; Mailboxes may be organized into multiple contexts for</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.asterisk.org/10801">change 10801</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/10801"/><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: I395b9205c91523a334fe971be0d1de4522067b04 </div>
<div style="display:none"> Gerrit-Change-Number: 10801 </div>
<div style="display:none"> Gerrit-PatchSet: 8 </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: Friendly Automation (1000185) </div>
<div style="display:none"> Gerrit-Reviewer: Joshua C. Colp <jcolp@digium.com> </div>
<div style="display:none"> Gerrit-Reviewer: Sean Bright <sean.bright@gmail.com> </div>