Add VMAuthenticate application (bug #2775)
authorMark Spencer <markster@digium.com>
Wed, 3 Nov 2004 15:06:44 +0000 (15:06 +0000)
committerMark Spencer <markster@digium.com>
Wed, 3 Nov 2004 15:06:44 +0000 (15:06 +0000)
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@4155 65c4cc65-6c06-0410-ace0-fbb531ad65f3

apps/app_voicemail.c

index 0d4cc37..cdfc57e 100755 (executable)
@@ -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);