|
|
|
|
@ -214,6 +214,16 @@ static char *descrip_vm_box_exists =
|
|
|
|
|
" MailboxExists(mailbox[@context]): Conditionally branches to priority n+101\n"
|
|
|
|
|
"if the specified voice mailbox exists.\n";
|
|
|
|
|
|
|
|
|
|
static char *synopsis_vmauthenticate =
|
|
|
|
|
"Authenticate off voicemail passwords";
|
|
|
|
|
|
|
|
|
|
static char *descrip_vmauthenticate =
|
|
|
|
|
" VMAuthenticate([mailbox][@context]): Behaves identically to the Authenticate\n"
|
|
|
|
|
"application, with the exception that the passwords are taken from\n"
|
|
|
|
|
"voicemail.conf.\n"
|
|
|
|
|
" If the mailbox is specified, only that mailbox's password will be considered\n"
|
|
|
|
|
"valid. If the mailbox is not specified, the channel variable AUTH_MAILBOX will\n"
|
|
|
|
|
"be set with the authenticated mailbox.\n";
|
|
|
|
|
|
|
|
|
|
/* Leave a message */
|
|
|
|
|
static char *app = "VoiceMail";
|
|
|
|
|
@ -222,6 +232,7 @@ static char *app = "VoiceMail";
|
|
|
|
|
static char *app2 = "VoiceMailMain";
|
|
|
|
|
|
|
|
|
|
static char *app3 = "MailboxExists";
|
|
|
|
|
static char *app4 = "VMAuthenticate";
|
|
|
|
|
|
|
|
|
|
AST_MUTEX_DEFINE_STATIC(vmlock);
|
|
|
|
|
struct ast_vm_user *users;
|
|
|
|
|
@ -3249,72 +3260,11 @@ static int vm_browse_messages_pt(struct ast_channel *chan, struct vm_state *vms,
|
|
|
|
|
return cmd;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int vm_execmain(struct ast_channel *chan, void *data)
|
|
|
|
|
static int vm_authenticate(struct ast_channel *chan, char *mailbox, int mailbox_size, struct ast_vm_user *res_vmu, const char *context, const char *prefix, int skipuser, int maxlogins)
|
|
|
|
|
{
|
|
|
|
|
/* XXX This is, admittedly, some pretty horrendus code. For some
|
|
|
|
|
reason it just seemed a lot easier to do with GOTO's. I feel
|
|
|
|
|
like I'm back in my GWBASIC days. XXX */
|
|
|
|
|
int res=-1;
|
|
|
|
|
int valid = 0;
|
|
|
|
|
int prefix = 0;
|
|
|
|
|
int cmd=0;
|
|
|
|
|
struct localuser *u;
|
|
|
|
|
char prefixstr[80] ="";
|
|
|
|
|
char empty[80] = "";
|
|
|
|
|
char ext_context[256]="";
|
|
|
|
|
int box;
|
|
|
|
|
int useadsi = 0;
|
|
|
|
|
int skipuser = 0;
|
|
|
|
|
char tmp[256], *ext;
|
|
|
|
|
char fmtc[256] = "";
|
|
|
|
|
char password[80];
|
|
|
|
|
struct vm_state vms;
|
|
|
|
|
int logretries = 0;
|
|
|
|
|
struct ast_vm_user *vmu = NULL, vmus;
|
|
|
|
|
char *context=NULL;
|
|
|
|
|
int silentexit = 0;
|
|
|
|
|
char *passptr;
|
|
|
|
|
|
|
|
|
|
LOCAL_USER_ADD(u);
|
|
|
|
|
memset(&vms, 0, sizeof(vms));
|
|
|
|
|
memset(&vmus, 0, sizeof(vmus));
|
|
|
|
|
strncpy(fmtc, vmfmts, sizeof(fmtc) - 1);
|
|
|
|
|
if (chan->_state != AST_STATE_UP)
|
|
|
|
|
ast_answer(chan);
|
|
|
|
|
|
|
|
|
|
if (data && !ast_strlen_zero(data)) {
|
|
|
|
|
strncpy(tmp, data, sizeof(tmp) - 1);
|
|
|
|
|
ext = tmp;
|
|
|
|
|
|
|
|
|
|
switch (*ext) {
|
|
|
|
|
case 's':
|
|
|
|
|
/* We should skip the user's password */
|
|
|
|
|
valid++;
|
|
|
|
|
ext++;
|
|
|
|
|
break;
|
|
|
|
|
case 'p':
|
|
|
|
|
/* We should prefix the mailbox with the supplied data */
|
|
|
|
|
prefix++;
|
|
|
|
|
ext++;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
context = strchr(ext, '@');
|
|
|
|
|
if (context) {
|
|
|
|
|
*context = '\0';
|
|
|
|
|
context++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (prefix)
|
|
|
|
|
strncpy(prefixstr, ext, sizeof(prefixstr) - 1);
|
|
|
|
|
else
|
|
|
|
|
strncpy(vms.username, ext, sizeof(vms.username) - 1);
|
|
|
|
|
if (!ast_strlen_zero(vms.username) && (vmu = find_user(&vmus, context ,vms.username)))
|
|
|
|
|
skipuser++;
|
|
|
|
|
else
|
|
|
|
|
valid = 0;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
int useadsi, valid=0, logretries=0;
|
|
|
|
|
char password[AST_MAX_EXTENSION]="", *passptr;
|
|
|
|
|
struct ast_vm_user vmus, *vmu = NULL;
|
|
|
|
|
|
|
|
|
|
/* If ADSI is supported, setup login screen */
|
|
|
|
|
adsi_begin(chan, &useadsi);
|
|
|
|
|
@ -3322,49 +3272,48 @@ static int vm_execmain(struct ast_channel *chan, void *data)
|
|
|
|
|
adsi_login(chan);
|
|
|
|
|
if (!skipuser && ast_streamfile(chan, "vm-login", chan->language)) {
|
|
|
|
|
ast_log(LOG_WARNING, "Couldn't stream login file\n");
|
|
|
|
|
goto out;
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Authenticate them and get their mailbox/password */
|
|
|
|
|
|
|
|
|
|
while (!valid && (logretries < maxlogins)) {
|
|
|
|
|
/* Prompt for, and read in the username */
|
|
|
|
|
if (!skipuser && ast_readstring(chan, vms.username, sizeof(vms.username) - 1, 2000, 10000, "#") < 0) {
|
|
|
|
|
if (!skipuser && ast_readstring(chan, mailbox, mailbox_size - 1, 2000, 10000, "#") < 0) {
|
|
|
|
|
ast_log(LOG_WARNING, "Couldn't read username\n");
|
|
|
|
|
goto out;
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
if (ast_strlen_zero(vms.username)) {
|
|
|
|
|
if (ast_strlen_zero(mailbox)) {
|
|
|
|
|
if (chan->cid.cid_num) {
|
|
|
|
|
strncpy(vms.username, chan->cid.cid_num, sizeof(vms.username) - 1);
|
|
|
|
|
strncpy(mailbox, chan->cid.cid_num, mailbox_size);
|
|
|
|
|
} else {
|
|
|
|
|
if (option_verbose > 2)
|
|
|
|
|
ast_verbose(VERBOSE_PREFIX_3 "Username not entered\n");
|
|
|
|
|
res = 0;
|
|
|
|
|
goto out;
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (useadsi)
|
|
|
|
|
adsi_password(chan);
|
|
|
|
|
if (!skipuser)
|
|
|
|
|
vmu = find_user(&vmus, context, vms.username);
|
|
|
|
|
vmu = find_user(&vmus, context, mailbox);
|
|
|
|
|
if (vmu && (vmu->password[0] == '\0' || (vmu->password[0] == '-' && vmu->password[1] == '\0'))) {
|
|
|
|
|
/* saved password is blank, so don't bother asking */
|
|
|
|
|
password[0] = '\0';
|
|
|
|
|
} else {
|
|
|
|
|
if (ast_streamfile(chan, "vm-password", chan->language)) {
|
|
|
|
|
ast_log(LOG_WARNING, "Unable to stream password file\n");
|
|
|
|
|
goto out;
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
if (ast_readstring(chan, password, sizeof(password) - 1, 2000, 10000, "#") < 0) {
|
|
|
|
|
ast_log(LOG_WARNING, "Unable to read password\n");
|
|
|
|
|
goto out;
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (prefix) {
|
|
|
|
|
char fullusername[80] = "";
|
|
|
|
|
strncpy(fullusername, prefixstr, sizeof(fullusername) - 1);
|
|
|
|
|
strncat(fullusername, vms.username, sizeof(fullusername) - 1);
|
|
|
|
|
strncpy(vms.username, fullusername, sizeof(vms.username) - 1);
|
|
|
|
|
strncpy(fullusername, prefix, sizeof(fullusername) - 1);
|
|
|
|
|
strncat(fullusername, mailbox, sizeof(fullusername) - 1 - strlen(fullusername));
|
|
|
|
|
strncpy(mailbox, fullusername, mailbox_size - 1);
|
|
|
|
|
}
|
|
|
|
|
if (vmu) {
|
|
|
|
|
passptr = vmu->password;
|
|
|
|
|
@ -3374,9 +3323,9 @@ static int vm_execmain(struct ast_channel *chan, void *data)
|
|
|
|
|
valid++;
|
|
|
|
|
else {
|
|
|
|
|
if (option_verbose > 2)
|
|
|
|
|
ast_verbose( VERBOSE_PREFIX_3 "Incorrect password '%s' for user '%s' (context = %s)\n", password, vms.username, context ? context : "<any>");
|
|
|
|
|
ast_verbose( VERBOSE_PREFIX_3 "Incorrect password '%s' for user '%s' (context = %s)\n", password, mailbox, context ? context : "<any>");
|
|
|
|
|
if (prefix)
|
|
|
|
|
strncpy(vms.username, empty, sizeof(vms.username) -1);
|
|
|
|
|
strncpy(mailbox, "", mailbox_size -1);
|
|
|
|
|
}
|
|
|
|
|
logretries++;
|
|
|
|
|
if (!valid) {
|
|
|
|
|
@ -3394,11 +3343,92 @@ static int vm_execmain(struct ast_channel *chan, void *data)
|
|
|
|
|
}
|
|
|
|
|
if (!valid && (logretries >= maxlogins)) {
|
|
|
|
|
ast_stopstream(chan);
|
|
|
|
|
res = ast_play_and_wait(chan, "vm-goodbye");
|
|
|
|
|
if (res > 0)
|
|
|
|
|
res = 0;
|
|
|
|
|
ast_play_and_wait(chan, "vm-goodbye");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
if (!skipuser) {
|
|
|
|
|
memcpy(res_vmu, vmu, sizeof(struct ast_vm_user));
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int vm_execmain(struct ast_channel *chan, void *data)
|
|
|
|
|
{
|
|
|
|
|
/* XXX This is, admittedly, some pretty horrendus code. For some
|
|
|
|
|
reason it just seemed a lot easier to do with GOTO's. I feel
|
|
|
|
|
like I'm back in my GWBASIC days. XXX */
|
|
|
|
|
int res=-1;
|
|
|
|
|
int valid = 0;
|
|
|
|
|
int prefix = 0;
|
|
|
|
|
int cmd=0;
|
|
|
|
|
struct localuser *u;
|
|
|
|
|
char prefixstr[80] ="";
|
|
|
|
|
char ext_context[256]="";
|
|
|
|
|
int box;
|
|
|
|
|
int useadsi = 0;
|
|
|
|
|
int skipuser = 0;
|
|
|
|
|
char tmp[256], *ext;
|
|
|
|
|
char fmtc[256] = "";
|
|
|
|
|
struct vm_state vms;
|
|
|
|
|
struct ast_vm_user *vmu = NULL, vmus;
|
|
|
|
|
char *context=NULL;
|
|
|
|
|
int silentexit = 0;
|
|
|
|
|
|
|
|
|
|
LOCAL_USER_ADD(u);
|
|
|
|
|
memset(&vms, 0, sizeof(vms));
|
|
|
|
|
memset(&vmus, 0, sizeof(vmus));
|
|
|
|
|
strncpy(fmtc, vmfmts, sizeof(fmtc) - 1);
|
|
|
|
|
if (chan->_state != AST_STATE_UP)
|
|
|
|
|
ast_answer(chan);
|
|
|
|
|
|
|
|
|
|
if (data && !ast_strlen_zero(data)) {
|
|
|
|
|
strncpy(tmp, data, sizeof(tmp) - 1);
|
|
|
|
|
ext = tmp;
|
|
|
|
|
|
|
|
|
|
switch (*ext) {
|
|
|
|
|
case 's':
|
|
|
|
|
/* We should skip the user's password */
|
|
|
|
|
valid++;
|
|
|
|
|
ext++;
|
|
|
|
|
break;
|
|
|
|
|
case 'p':
|
|
|
|
|
/* We should prefix the mailbox with the supplied data */
|
|
|
|
|
prefix++;
|
|
|
|
|
ext++;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
context = strchr(ext, '@');
|
|
|
|
|
if (context) {
|
|
|
|
|
*context = '\0';
|
|
|
|
|
context++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (prefix)
|
|
|
|
|
strncpy(prefixstr, ext, sizeof(prefixstr) - 1);
|
|
|
|
|
else
|
|
|
|
|
strncpy(vms.username, ext, sizeof(vms.username) - 1);
|
|
|
|
|
if (!ast_strlen_zero(vms.username) && (vmu = find_user(&vmus, context ,vms.username)))
|
|
|
|
|
skipuser++;
|
|
|
|
|
else
|
|
|
|
|
valid = 0;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
res = vm_authenticate(chan, vms.username, sizeof(vms.username), &vmus, context, prefixstr, skipuser, maxlogins);
|
|
|
|
|
|
|
|
|
|
if (!res) {
|
|
|
|
|
valid = 1;
|
|
|
|
|
if (!skipuser) {
|
|
|
|
|
vmu = &vmus;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
res = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* If ADSI is supported, setup login screen */
|
|
|
|
|
adsi_begin(chan, &useadsi);
|
|
|
|
|
|
|
|
|
|
if (valid) {
|
|
|
|
|
/* Set language from config to override channel language */
|
|
|
|
|
if (vmu->language && !ast_strlen_zero(vmu->language))
|
|
|
|
|
@ -3861,6 +3891,33 @@ static int vm_box_exists(struct ast_channel *chan, void *data) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int vmauthenticate(struct ast_channel *chan, void *data) {
|
|
|
|
|
struct localuser *u;
|
|
|
|
|
char *s = data, *user=NULL, *context=NULL, mailbox[AST_MAX_EXTENSION];
|
|
|
|
|
struct ast_vm_user vmus;
|
|
|
|
|
|
|
|
|
|
if (s) {
|
|
|
|
|
s = ast_strdupa(s);
|
|
|
|
|
if (!s) {
|
|
|
|
|
ast_log(LOG_ERROR, "Out of memory\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
user = strsep(&s, "@");
|
|
|
|
|
context = strsep(&s, "");
|
|
|
|
|
}
|
|
|
|
|
LOCAL_USER_ADD(u);
|
|
|
|
|
|
|
|
|
|
if (!vm_authenticate(chan, mailbox, sizeof(mailbox), &vmus, context, NULL, 0, 3)) {
|
|
|
|
|
pbx_builtin_setvar_helper(chan, "AUTH_MAILBOX", mailbox);
|
|
|
|
|
pbx_builtin_setvar_helper(chan, "AUTH_CONTEXT", vmus.context);
|
|
|
|
|
LOCAL_USER_REMOVE(u);
|
|
|
|
|
return 0;
|
|
|
|
|
} else {
|
|
|
|
|
LOCAL_USER_REMOVE(u);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static char show_voicemail_users_help[] =
|
|
|
|
|
"Usage: show voicemail users [for <context>]\n"
|
|
|
|
|
" Lists all mailboxes currently set up\n";
|
|
|
|
|
@ -4371,6 +4428,7 @@ int unload_module(void)
|
|
|
|
|
res = ast_unregister_application(app);
|
|
|
|
|
res |= ast_unregister_application(app2);
|
|
|
|
|
res |= ast_unregister_application(app3);
|
|
|
|
|
res |= ast_unregister_application(app4);
|
|
|
|
|
ast_cli_unregister(&show_voicemail_users_cli);
|
|
|
|
|
ast_cli_unregister(&show_voicemail_zones_cli);
|
|
|
|
|
return res;
|
|
|
|
|
@ -4382,6 +4440,7 @@ int load_module(void)
|
|
|
|
|
res = ast_register_application(app, vm_exec, synopsis_vm, descrip_vm);
|
|
|
|
|
res |= ast_register_application(app2, vm_execmain, synopsis_vmain, descrip_vmain);
|
|
|
|
|
res |= ast_register_application(app3, vm_box_exists, synopsis_vm_box_exists, descrip_vm_box_exists);
|
|
|
|
|
res |= ast_register_application(app4, vmauthenticate, synopsis_vmauthenticate, descrip_vmauthenticate);
|
|
|
|
|
if (res)
|
|
|
|
|
return(res);
|
|
|
|
|
|
|
|
|
|
|