mirror of
https://github.com/asterisk/asterisk.git
synced 2025-09-29 18:19:30 +00:00
Merge "app_voicemail: Add Mailbox Aliases"
This commit is contained in:
6
CHANGES
6
CHANGES
@@ -93,6 +93,12 @@ Features
|
||||
The previous behavior has been restored so both channels receive the
|
||||
channel variable when one of these features is invoked.
|
||||
|
||||
app_voicemail
|
||||
------------------
|
||||
* You can now specify a special context with the "aliasescontext" parameter
|
||||
in voicemail.conf which will allow you to create aliases for physical
|
||||
mailboxes.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
--- Functionality changes from Asterisk 16.0.0 to Asterisk 16.1.0 ------------
|
||||
------------------------------------------------------------------------------
|
||||
|
@@ -999,6 +999,7 @@ static int skipms;
|
||||
static int maxlogins;
|
||||
static int minpassword;
|
||||
static int passwordlocation;
|
||||
static char aliasescontext[MAX_VM_CONTEXT_LEN];
|
||||
|
||||
/*! Poll mailboxes for changes since there is something external to
|
||||
* app_voicemail that may change them. */
|
||||
@@ -1051,6 +1052,27 @@ static struct ast_taskprocessor *mwi_subscription_tps;
|
||||
|
||||
static AST_RWLIST_HEAD_STATIC(mwi_subs, mwi_sub);
|
||||
|
||||
struct alias_mailbox_mapping {
|
||||
char *alias;
|
||||
char *mailbox;
|
||||
char buf[0];
|
||||
};
|
||||
|
||||
struct mailbox_alias_mapping {
|
||||
char *alias;
|
||||
char *mailbox;
|
||||
char buf[0];
|
||||
};
|
||||
|
||||
#define MAPPING_BUCKETS 511
|
||||
static struct ao2_container *alias_mailbox_mappings;
|
||||
AO2_STRING_FIELD_HASH_FN(alias_mailbox_mapping, alias);
|
||||
AO2_STRING_FIELD_CMP_FN(alias_mailbox_mapping, alias);
|
||||
|
||||
static struct ao2_container *mailbox_alias_mappings;
|
||||
AO2_STRING_FIELD_HASH_FN(mailbox_alias_mapping, mailbox);
|
||||
AO2_STRING_FIELD_CMP_FN(mailbox_alias_mapping, mailbox);
|
||||
|
||||
/* custom audio control prompts for voicemail playback */
|
||||
static char listen_control_forward_key[12];
|
||||
static char listen_control_reverse_key[12];
|
||||
@@ -1765,9 +1787,31 @@ static struct ast_vm_user *find_user(struct ast_vm_user *ivm, const char *contex
|
||||
ast_set2_flag(vmu, !ivm, VM_ALLOCED);
|
||||
AST_LIST_NEXT(vmu, list) = NULL;
|
||||
}
|
||||
} else
|
||||
vmu = find_user_realtime(ivm, context, mailbox);
|
||||
}
|
||||
AST_LIST_UNLOCK(&users);
|
||||
if (!vmu) {
|
||||
vmu = find_user_realtime(ivm, context, mailbox);
|
||||
}
|
||||
if (!vmu && !ast_strlen_zero(aliasescontext)) {
|
||||
struct alias_mailbox_mapping *mapping;
|
||||
char *search_string = ast_alloca(MAX_VM_MAILBOX_LEN);
|
||||
|
||||
snprintf(search_string, MAX_VM_MAILBOX_LEN, "%s%s%s",
|
||||
mailbox,
|
||||
ast_strlen_zero(context) ? "" : "@",
|
||||
S_OR(context, ""));
|
||||
|
||||
mapping = ao2_find(alias_mailbox_mappings, search_string, OBJ_SEARCH_KEY);
|
||||
if (mapping) {
|
||||
char *search_mailbox = NULL;
|
||||
char *search_context = NULL;
|
||||
|
||||
separate_mailbox(ast_strdupa(mapping->mailbox), &search_mailbox, &search_context);
|
||||
ao2_ref(mapping, -1);
|
||||
vmu = find_user(ivm, search_mailbox, search_context);
|
||||
}
|
||||
}
|
||||
|
||||
return vmu;
|
||||
}
|
||||
|
||||
@@ -6056,6 +6100,9 @@ static int __has_voicemail(const char *context, const char *mailbox, const char
|
||||
struct dirent *de;
|
||||
char fn[256];
|
||||
int ret = 0;
|
||||
struct alias_mailbox_mapping *mapping;
|
||||
char *c;
|
||||
char *m;
|
||||
|
||||
/* If no mailbox, return immediately */
|
||||
if (ast_strlen_zero(mailbox))
|
||||
@@ -6066,7 +6113,21 @@ static int __has_voicemail(const char *context, const char *mailbox, const char
|
||||
if (ast_strlen_zero(context))
|
||||
context = "default";
|
||||
|
||||
snprintf(fn, sizeof(fn), "%s%s/%s/%s", VM_SPOOL_DIR, context, mailbox, folder);
|
||||
c = (char *)context;
|
||||
m = (char *)mailbox;
|
||||
|
||||
if (!ast_strlen_zero(aliasescontext)) {
|
||||
char tmp[MAX_VM_MAILBOX_LEN];
|
||||
|
||||
snprintf(tmp, MAX_VM_MAILBOX_LEN, "%s@%s", mailbox, context);
|
||||
mapping = ao2_find(alias_mailbox_mappings, tmp, OBJ_SEARCH_KEY);
|
||||
if (mapping) {
|
||||
separate_mailbox(ast_strdupa(mapping->mailbox), &m, &c);
|
||||
ao2_ref(mapping, -1);
|
||||
}
|
||||
}
|
||||
|
||||
snprintf(fn, sizeof(fn), "%s%s/%s/%s", VM_SPOOL_DIR, c, m, folder);
|
||||
|
||||
if (!(dir = opendir(fn)))
|
||||
return 0;
|
||||
@@ -8096,7 +8157,24 @@ static void queue_mwi_event(const char *channel_id, const char *box, int urgent,
|
||||
return;
|
||||
}
|
||||
|
||||
ast_debug(3, "Queueing event for mailbox %s New: %d Old: %d\n", box, new + urgent, old);
|
||||
ast_publish_mwi_state_channel(mailbox, context, new + urgent, old, channel_id);
|
||||
|
||||
if (!ast_strlen_zero(aliasescontext)) {
|
||||
struct ao2_iterator *aliases;
|
||||
struct mailbox_alias_mapping *mapping;
|
||||
|
||||
aliases = ao2_find(mailbox_alias_mappings, box, OBJ_SEARCH_KEY | OBJ_MULTIPLE);
|
||||
while ((mapping = ao2_iterator_next(aliases))) {
|
||||
mailbox = NULL;
|
||||
context = NULL;
|
||||
ast_debug(3, "Found alias mapping: %s -> %s\n", mapping->alias, box);
|
||||
separate_mailbox(ast_strdupa(mapping->alias), &mailbox, &context);
|
||||
ast_publish_mwi_state_channel(mailbox, context, new + urgent, old, channel_id);
|
||||
ao2_ref(mapping, -1);
|
||||
}
|
||||
ao2_iterator_destroy(aliases);
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -13000,6 +13078,46 @@ static char *handle_voicemail_show_zones(struct ast_cli_entry *e, int cmd, struc
|
||||
return res;
|
||||
}
|
||||
|
||||
/*! \brief Show a list of voicemail zones in the CLI */
|
||||
static char *handle_voicemail_show_aliases(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
|
||||
{
|
||||
struct ao2_iterator aliases;
|
||||
struct alias_mailbox_mapping *mapping;
|
||||
#define ALIASES_OUTPUT_FORMAT "%-32s %-32s\n"
|
||||
char *res = CLI_SUCCESS;
|
||||
|
||||
switch (cmd) {
|
||||
case CLI_INIT:
|
||||
e->command = "voicemail show aliases";
|
||||
e->usage =
|
||||
"Usage: voicemail show aliases\n"
|
||||
" Lists mailbox aliases\n";
|
||||
return NULL;
|
||||
case CLI_GENERATE:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (a->argc != 3)
|
||||
return CLI_SHOWUSAGE;
|
||||
|
||||
if (ast_strlen_zero(aliasescontext)) {
|
||||
ast_cli(a->fd, "Aliases are not enabled\n");
|
||||
return res;
|
||||
}
|
||||
|
||||
ast_cli(a->fd, "Aliases context: %s\n", aliasescontext);
|
||||
ast_cli(a->fd, ALIASES_OUTPUT_FORMAT, "Alias", "Mailbox");
|
||||
|
||||
aliases = ao2_iterator_init(alias_mailbox_mappings, 0);
|
||||
while ((mapping = ao2_iterator_next(&aliases))) {
|
||||
ast_cli(a->fd, ALIASES_OUTPUT_FORMAT, mapping->alias, mapping->mailbox);
|
||||
ao2_ref(mapping, -1);
|
||||
}
|
||||
ao2_iterator_destroy(&aliases);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/*! \brief Reload voicemail configuration from the CLI */
|
||||
static char *handle_voicemail_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
|
||||
{
|
||||
@@ -13026,6 +13144,7 @@ static char *handle_voicemail_reload(struct ast_cli_entry *e, int cmd, struct as
|
||||
static struct ast_cli_entry cli_voicemail[] = {
|
||||
AST_CLI_DEFINE(handle_voicemail_show_users, "List defined voicemail boxes"),
|
||||
AST_CLI_DEFINE(handle_voicemail_show_zones, "List zone message formats"),
|
||||
AST_CLI_DEFINE(handle_voicemail_show_aliases, "List mailbox aliases"),
|
||||
AST_CLI_DEFINE(handle_voicemail_reload, "Reload voicemail configuration"),
|
||||
};
|
||||
|
||||
@@ -13244,7 +13363,6 @@ static void mwi_event_cb(void *userdata, struct stasis_subscription *sub, struct
|
||||
if (stasis_message_type(msg) != stasis_subscription_change_type()) {
|
||||
return;
|
||||
}
|
||||
|
||||
change = stasis_message_data(msg);
|
||||
if (change->topic == ast_mwi_topic_all()) {
|
||||
return;
|
||||
@@ -13662,11 +13780,98 @@ static int load_config_from_memory(int reload, struct ast_config *cfg, struct as
|
||||
}
|
||||
#endif
|
||||
|
||||
static struct alias_mailbox_mapping *alias_mailbox_mapping_create(const char *alias, const char *mailbox)
|
||||
{
|
||||
struct alias_mailbox_mapping *mapping;
|
||||
size_t from_len = strlen(alias) + 1;
|
||||
size_t to_len = strlen(mailbox) + 1;
|
||||
|
||||
mapping = ao2_alloc(sizeof(*mapping) + from_len + to_len, NULL);
|
||||
if (!mapping) {
|
||||
return NULL;
|
||||
}
|
||||
mapping->alias = mapping->buf;
|
||||
mapping->mailbox = mapping->buf + from_len;
|
||||
strcpy(mapping->alias, alias); /* Safe */
|
||||
strcpy(mapping->mailbox, mailbox); /* Safe */
|
||||
|
||||
return mapping;
|
||||
}
|
||||
|
||||
static void load_aliases(struct ast_config *cfg)
|
||||
{
|
||||
struct ast_variable *var;
|
||||
|
||||
if (ast_strlen_zero(aliasescontext)) {
|
||||
return;
|
||||
}
|
||||
var = ast_variable_browse(cfg, aliasescontext);
|
||||
while (var) {
|
||||
struct alias_mailbox_mapping *mapping = alias_mailbox_mapping_create(var->name, var->value);
|
||||
if (mapping) {
|
||||
ao2_link(alias_mailbox_mappings, mapping);
|
||||
ao2_link(mailbox_alias_mappings, mapping);
|
||||
ao2_ref(mapping, -1);
|
||||
}
|
||||
var = var->next;
|
||||
}
|
||||
}
|
||||
|
||||
static void load_zonemessages(struct ast_config *cfg)
|
||||
{
|
||||
struct ast_variable *var;
|
||||
|
||||
var = ast_variable_browse(cfg, "zonemessages");
|
||||
while (var) {
|
||||
struct vm_zone *z;
|
||||
char *msg_format, *tzone;
|
||||
|
||||
z = ast_malloc(sizeof(*z));
|
||||
if (!z) {
|
||||
return;
|
||||
}
|
||||
|
||||
msg_format = ast_strdupa(var->value);
|
||||
tzone = strsep(&msg_format, "|,");
|
||||
if (msg_format) {
|
||||
ast_copy_string(z->name, var->name, sizeof(z->name));
|
||||
ast_copy_string(z->timezone, tzone, sizeof(z->timezone));
|
||||
ast_copy_string(z->msg_format, msg_format, sizeof(z->msg_format));
|
||||
AST_LIST_LOCK(&zones);
|
||||
AST_LIST_INSERT_HEAD(&zones, z, list);
|
||||
AST_LIST_UNLOCK(&zones);
|
||||
} else {
|
||||
ast_log(AST_LOG_WARNING, "Invalid timezone definition at line %d\n", var->lineno);
|
||||
ast_free(z);
|
||||
}
|
||||
var = var->next;
|
||||
}
|
||||
}
|
||||
|
||||
static void load_users(struct ast_config *cfg)
|
||||
{
|
||||
struct ast_variable *var;
|
||||
char *cat = NULL;
|
||||
|
||||
while ((cat = ast_category_browse(cfg, cat))) {
|
||||
if (strcasecmp(cat, "general") == 0
|
||||
|| strcasecmp(cat, aliasescontext) == 0
|
||||
|| strcasecmp(cat, "zonemessages") == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
var = ast_variable_browse(cfg, cat);
|
||||
while (var) {
|
||||
append_mailbox(cat, var->name, var->value);
|
||||
var = var->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int actual_load_config(int reload, struct ast_config *cfg, struct ast_config *ucfg)
|
||||
{
|
||||
struct ast_vm_user *current;
|
||||
char *cat;
|
||||
struct ast_variable *var;
|
||||
const char *val;
|
||||
char *q, *stringp, *tmp;
|
||||
int x;
|
||||
@@ -13695,6 +13900,10 @@ static int actual_load_config(int reload, struct ast_config *cfg, struct ast_con
|
||||
/* Free all the zones structure */
|
||||
free_vm_zones();
|
||||
|
||||
/* Remove all aliases */
|
||||
ao2_callback(alias_mailbox_mappings, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL);
|
||||
ao2_callback(mailbox_alias_mappings, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL);
|
||||
|
||||
AST_LIST_LOCK(&users);
|
||||
|
||||
memset(ext_pass_cmd, 0, sizeof(ext_pass_cmd));
|
||||
@@ -13706,6 +13915,11 @@ static int actual_load_config(int reload, struct ast_config *cfg, struct ast_con
|
||||
if (!(val = ast_variable_retrieve(cfg, "general", "userscontext")))
|
||||
val = "default";
|
||||
ast_copy_string(userscontext, val, sizeof(userscontext));
|
||||
|
||||
aliasescontext[0] = '\0';
|
||||
val = ast_variable_retrieve(cfg, "general", "aliasescontext");
|
||||
ast_copy_string(aliasescontext, S_OR(val, ""), sizeof(aliasescontext));
|
||||
|
||||
/* Attach voice message to mail message ? */
|
||||
if (!(val = ast_variable_retrieve(cfg, "general", "attach")))
|
||||
val = "yes";
|
||||
@@ -14307,45 +14521,16 @@ static int actual_load_config(int reload, struct ast_config *cfg, struct ast_con
|
||||
}
|
||||
|
||||
/* load mailboxes from voicemail.conf */
|
||||
cat = ast_category_browse(cfg, NULL);
|
||||
while (cat) {
|
||||
if (strcasecmp(cat, "general")) {
|
||||
var = ast_variable_browse(cfg, cat);
|
||||
if (strcasecmp(cat, "zonemessages")) {
|
||||
/* Process mailboxes in this context */
|
||||
while (var) {
|
||||
append_mailbox(cat, var->name, var->value);
|
||||
var = var->next;
|
||||
}
|
||||
} else {
|
||||
/* Timezones in this context */
|
||||
while (var) {
|
||||
struct vm_zone *z;
|
||||
if ((z = ast_malloc(sizeof(*z)))) {
|
||||
char *msg_format, *tzone;
|
||||
msg_format = ast_strdupa(var->value);
|
||||
tzone = strsep(&msg_format, "|,");
|
||||
if (msg_format) {
|
||||
ast_copy_string(z->name, var->name, sizeof(z->name));
|
||||
ast_copy_string(z->timezone, tzone, sizeof(z->timezone));
|
||||
ast_copy_string(z->msg_format, msg_format, sizeof(z->msg_format));
|
||||
AST_LIST_LOCK(&zones);
|
||||
AST_LIST_INSERT_HEAD(&zones, z, list);
|
||||
AST_LIST_UNLOCK(&zones);
|
||||
} else {
|
||||
ast_log(AST_LOG_WARNING, "Invalid timezone definition at line %d\n", var->lineno);
|
||||
ast_free(z);
|
||||
}
|
||||
} else {
|
||||
AST_LIST_UNLOCK(&users);
|
||||
return -1;
|
||||
}
|
||||
var = var->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
cat = ast_category_browse(cfg, cat);
|
||||
}
|
||||
|
||||
/*
|
||||
* Aliases must be loaded before users or the aliases won't be notified
|
||||
* if there's existing voicemail in the user mailbox.
|
||||
*/
|
||||
load_aliases(cfg);
|
||||
|
||||
load_zonemessages(cfg);
|
||||
|
||||
load_users(cfg);
|
||||
|
||||
AST_LIST_UNLOCK(&users);
|
||||
|
||||
@@ -15096,6 +15281,16 @@ static int unload_module(void)
|
||||
return res;
|
||||
}
|
||||
|
||||
static void print_mappings(void *v_obj, void *where, ao2_prnt_fn *prnt)
|
||||
{
|
||||
struct alias_mailbox_mapping *mapping = v_obj;
|
||||
|
||||
if (!mapping) {
|
||||
return;
|
||||
}
|
||||
prnt(where, "Alias: %s Mailbox: %s", mapping->alias, mapping->mailbox);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Load the module
|
||||
*
|
||||
@@ -15122,6 +15317,38 @@ static int load_module(void)
|
||||
return AST_MODULE_LOAD_DECLINE;
|
||||
}
|
||||
|
||||
alias_mailbox_mappings = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0, MAPPING_BUCKETS,
|
||||
alias_mailbox_mapping_hash_fn, NULL, alias_mailbox_mapping_cmp_fn);
|
||||
if (!alias_mailbox_mappings) {
|
||||
ast_log(LOG_ERROR, "Unable to create alias_mailbox_mappings container\n");
|
||||
ao2_cleanup(inprocess_container);
|
||||
return AST_MODULE_LOAD_DECLINE;
|
||||
}
|
||||
res = ao2_container_register("voicemail_alias_mailbox_mappings", alias_mailbox_mappings, print_mappings);
|
||||
if (res) {
|
||||
ast_log(LOG_ERROR, "Unable to register alias_mailbox_mappings container\n");
|
||||
ao2_cleanup(inprocess_container);
|
||||
ao2_cleanup(alias_mailbox_mappings);
|
||||
return AST_MODULE_LOAD_DECLINE;
|
||||
}
|
||||
|
||||
mailbox_alias_mappings = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0, MAPPING_BUCKETS,
|
||||
mailbox_alias_mapping_hash_fn, NULL, mailbox_alias_mapping_cmp_fn);
|
||||
if (!mailbox_alias_mappings) {
|
||||
ast_log(LOG_ERROR, "Unable to create mailbox_alias_mappings container\n");
|
||||
ao2_cleanup(inprocess_container);
|
||||
ao2_cleanup(alias_mailbox_mappings);
|
||||
return AST_MODULE_LOAD_DECLINE;
|
||||
}
|
||||
res = ao2_container_register("voicemail_mailbox_alias_mappings", mailbox_alias_mappings, print_mappings);
|
||||
if (res) {
|
||||
ast_log(LOG_ERROR, "Unable to register mailbox_alias_mappings container\n");
|
||||
ao2_cleanup(inprocess_container);
|
||||
ao2_cleanup(alias_mailbox_mappings);
|
||||
ao2_cleanup(mailbox_alias_mappings);
|
||||
return AST_MODULE_LOAD_DECLINE;
|
||||
}
|
||||
|
||||
/* compute the location of the voicemail spool directory */
|
||||
snprintf(VM_SPOOL_DIR, sizeof(VM_SPOOL_DIR), "%s/voicemail/", ast_config_AST_SPOOL_DIR);
|
||||
|
||||
|
@@ -73,6 +73,10 @@ maxlogins=3
|
||||
;
|
||||
;userscontext=default
|
||||
;
|
||||
; Aliases allow a mailbox to be referenced by an alias. The aliases are
|
||||
; specified in the special context named here. There is no default.
|
||||
;aliasescontext=myaliases
|
||||
;
|
||||
; If you need to have an external program, i.e. /usr/bin/myapp
|
||||
; called when a voicemail is left, delivered, or your voicemailbox
|
||||
; is checked, uncomment this.
|
||||
@@ -233,7 +237,6 @@ pagerdateformat=%A, %B %d, %Y at %r
|
||||
; Default: no
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
;
|
||||
|
||||
; Each mailbox is listed in the form <mailbox>=<password>,<name>,<email>,<pager_email>,<options>
|
||||
; If email is specified, a message will be sent when a voicemail is received, to
|
||||
@@ -451,6 +454,13 @@ european=Europe/Copenhagen|'vm-received' a d b 'digits/at' HM
|
||||
;4110 => 3443,Rob Flynn,rflynn@blueridge.net
|
||||
;4235 => 1234,Jim Holmes,jim@astricon.ips,,Tz=european
|
||||
|
||||
;
|
||||
; Aliases allow alternate references to mailboxes. See the "aliasescontext"
|
||||
; parameter in the "general" section.
|
||||
;
|
||||
[myaliases]
|
||||
1234@devices => 1234@default
|
||||
;6200@devices => 4200@default
|
||||
|
||||
;
|
||||
; Mailboxes may be organized into multiple contexts for
|
||||
|
Reference in New Issue
Block a user