Add a massive set of changes for converting to use the ast_debug() macro.
[asterisk/asterisk.git] / apps / app_voicemail.c
index 5cb03c8..675d966 100644 (file)
@@ -41,7 +41,7 @@ c-client (http://www.washington.edu/imap/
  */
 
 /*** MODULEINFO
-       <depend>res_adsi</depend>
+       <depend>res_smdi</depend>
  ***/
 
 /*** MAKEOPTS
@@ -104,6 +104,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/utils.h"
 #include "asterisk/stringfields.h"
 #include "asterisk/smdi.h"
+#include "asterisk/event.h"
 
 #ifdef ODBC_STORAGE
 #include "asterisk/res_odbc.h"
@@ -210,7 +211,6 @@ enum {
        OPT_UNAVAIL_GREETING = (1 << 2),
        OPT_RECORDGAIN =       (1 << 3),
        OPT_PREPEND_MAILBOX =  (1 << 4),
-       OPT_PRIORITY_JUMP =    (1 << 5),
        OPT_AUTOPLAY =         (1 << 6),
 } vm_option_flags;
 
@@ -227,7 +227,6 @@ AST_APP_OPTIONS(vm_app_options, {
        AST_APP_OPTION('u', OPT_UNAVAIL_GREETING),
        AST_APP_OPTION_ARG('g', OPT_RECORDGAIN, OPT_ARG_RECORDGAIN),
        AST_APP_OPTION('p', OPT_PREPEND_MAILBOX),
-       AST_APP_OPTION('j', OPT_PRIORITY_JUMP),
        AST_APP_OPTION_ARG('a', OPT_AUTOPLAY, OPT_ARG_PLAYFOLDER),
 });
 
@@ -313,7 +312,8 @@ struct baseio {
        unsigned char iobuf[BASEMAXINLINE];
 };
 
-/*! Structure for linked list of users */
+/*! Structure for linked list of users 
+ * Use ast_vm_user_destroy() to free one of these structures. */
 struct ast_vm_user {
        char context[AST_MAX_CONTEXT];   /*!< Voicemail context */
        char mailbox[AST_MAX_EXTENSION]; /*!< Mailbox id, unique within vm context */
@@ -455,9 +455,7 @@ static char *descrip_vm =
        "           message. The units are whole-number decibels (dB).\n"
        "    s    - Skip the playback of instructions for leaving a message to the\n"
        "           calling party.\n"
-       "    u    - Play the 'unavailble greeting.\n"
-       "    j    - Jump to priority n+101 if the mailbox is not found or some other\n"
-       "           error occurs.\n";
+       "    u    - Play the 'unavailable greeting.\n";
 
 static char *synopsis_vmain = "Check Voicemail messages";
 
@@ -487,8 +485,7 @@ static char *descrip_vm_box_exists =
        "    VMBOXEXISTSSTATUS - This will contain the status of the execution of the\n"
        "                        MailboxExists application. Possible values include:\n"
        "                        SUCCESS | FAILED\n\n"
-       "  Options:\n"
-       "    j - Jump to priority n+101 if the mailbox is found.\n";
+       "  Options: (none)\n";
 
 static char *synopsis_vmauthenticate = "Authenticate with Voicemail passwords";
 
@@ -528,6 +525,42 @@ static int maxgreet;
 static int skipms;
 static int maxlogins;
 
+/*! Poll mailboxes for changes since there is something external to
+ *  app_voicemail that may change them. */
+static unsigned int poll_mailboxes;
+
+/*! Polling frequency */
+static unsigned int poll_freq;
+/*! By default, poll every 30 seconds */
+#define DEFAULT_POLL_FREQ 30
+
+AST_MUTEX_DEFINE_STATIC(poll_lock);
+static ast_cond_t poll_cond = PTHREAD_COND_INITIALIZER;
+static pthread_t poll_thread = AST_PTHREADT_NULL;
+static unsigned char poll_thread_run;
+
+/*! Subscription to ... MWI event subscriptions */
+static struct ast_event_sub *mwi_sub_sub;
+/*! Subscription to ... MWI event un-subscriptions */
+static struct ast_event_sub *mwi_unsub_sub;
+
+/*!
+ * \brief An MWI subscription
+ *
+ * This is so we can keep track of which mailboxes are subscribed to.
+ * This way, we know which mailboxes to poll when the pollmailboxes
+ * option is being used.
+ */
+struct mwi_sub {
+       AST_RWLIST_ENTRY(mwi_sub) entry;
+       int old_new;
+       int old_old;
+       uint32_t uniqueid;
+       char mailbox[1];
+};
+
+static AST_RWLIST_HEAD_STATIC(mwi_subs, mwi_sub);
+
 /* custom password sounds */
 static char vm_password[80] = "vm-password";
 static char vm_newpassword[80] = "vm-newpassword";
@@ -755,7 +788,7 @@ static struct ast_vm_user *find_user_realtime(struct ast_vm_user *ivm, const cha
                        ast_variables_destroy(var);
                } else { 
                        if (!ivm) 
-                               free(retval);
+                               ast_free(retval);
                        retval = NULL;
                }       
        } 
@@ -839,7 +872,7 @@ static void vm_change_password(struct ast_vm_user *vmu, const char *newpassword)
                                        ast_log(LOG_WARNING, "Failed to get category structure.\n");
                                        break;
                                }
-                               ast_variable_update(cat, vmu->mailbox, new, NULL);
+                               ast_variable_update(cat, vmu->mailbox, new, NULL, 0);
                        }
                }
                /* save the results */
@@ -852,26 +885,22 @@ static void vm_change_password(struct ast_vm_user *vmu, const char *newpassword)
        /* check users.conf and update the password stored for the mailbox*/
        /* if no vmsecret entry exists create one. */
        if ((cfg = ast_config_load_with_comments("users.conf"))) {
-               if (option_debug > 3)
-                       ast_log(LOG_DEBUG, "we are looking for %s\n", vmu->mailbox);
+               ast_debug(4, "we are looking for %s\n", vmu->mailbox);
                while ((category = ast_category_browse(cfg, category))) {
-                       if (option_debug > 3)
-                               ast_log(LOG_DEBUG, "users.conf: %s\n", category);
+                       ast_debug(4, "users.conf: %s\n", category);
                        if (!strcasecmp(category, vmu->mailbox)) {
                                if (!(tmp = ast_variable_retrieve(cfg, category, "vmsecret"))) {
-                                       if (option_debug > 3)
-                                               ast_log(LOG_DEBUG, "looks like we need to make vmsecret!\n");
+                                       ast_debug(3, "looks like we need to make vmsecret!\n");
                                        var = ast_variable_new("vmsecret", newpassword);
                                } 
                                new = alloca(strlen(newpassword)+1);
                                sprintf(new, "%s", newpassword);
                                if (!(cat = ast_category_get(cfg, category))) {
-                                       if (option_debug > 3)
-                                               ast_log(LOG_DEBUG, "failed to get category!\n");
+                                       ast_debug(4, "failed to get category!\n");
                                        break;
                                }
                                if (!var)               
-                                       ast_variable_update(cat, "vmsecret", new, NULL);
+                                       ast_variable_update(cat, "vmsecret", new, NULL, 0);
                                else
                                        ast_variable_append(cat, var);
                        }
@@ -920,8 +949,7 @@ static void vm_imap_delete(int msgnum, struct vm_state *vms)
                ast_log(LOG_WARNING, "msgnum %d, mailbox message %lu is zero.\n",msgnum,messageNum);
                return;
        }
-       if(option_debug > 2)
-               ast_log(LOG_DEBUG, "deleting msgnum %d, which is mailbox message %lu\n",msgnum,messageNum);
+       ast_debug(3, "deleting msgnum %d, which is mailbox message %lu\n",msgnum,messageNum);
        /* delete message */
        sprintf (arg,"%lu",messageNum);
        mail_setflag (vms->mailstream,arg,"\\DELETED");
@@ -939,7 +967,7 @@ static int make_file(char *dest, int len, char *dir, int num)
  * \param context String. Ignored if is null or empty string.
  * \param ext     String. Ignored if is null or empty string.
  * \param folder  String. Ignored if is null or empty string. 
- * \return 0 on failure, 1 on success.
+ * \return -1 on failure, 0 on success.
  */
 static int create_dirpath(char *dest, int len, const char *context, const char *ext, const char *folder)
 {
@@ -949,24 +977,24 @@ static int create_dirpath(char *dest, int len, const char *context, const char *
                make_dir(dest, len, context, "", "");
                if (mkdir(dest, mode) && errno != EEXIST) {
                        ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dest, strerror(errno));
-                       return 0;
+                       return -1;
                }
        }
        if (!ast_strlen_zero(ext)) {
                make_dir(dest, len, context, ext, "");
                if (mkdir(dest, mode) && errno != EEXIST) {
                        ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dest, strerror(errno));
-                       return 0;
+                       return -1;
                }
        }
        if (!ast_strlen_zero(folder)) {
                make_dir(dest, len, context, ext, folder);
                if (mkdir(dest, mode) && errno != EEXIST) {
                        ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dest, strerror(errno));
-                       return 0;
+                       return -1;
                }
        }
-       return 1;
+       return 0;
 }
 
 /*! \brief Lock file path
@@ -991,7 +1019,7 @@ static int retrieve_file(char *dir, int msgnum)
        int res;
        int fd=-1;
        size_t fdlen = 0;
-       void *fdm=NULL;
+       void *fdm = MAP_FAILED;
        SQLSMALLINT colcount=0;
        SQLHSTMT stmt;
        char sql[PATH_MAX];
@@ -1108,7 +1136,7 @@ static int retrieve_file(char *dir, int msgnum)
                                        }
                                        /* Read out in small chunks */
                                        for (offset = 0; offset < colsize2; offset += CHUNKSIZE) {
-                                               if ((fdm = mmap(NULL, CHUNKSIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, offset)) == (void *)-1) {
+                                               if ((fdm = mmap(NULL, CHUNKSIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, offset)) == MAP_FAILED) {
                                                        ast_log(LOG_WARNING, "Could not mmap the output file: %s (%d)\n", strerror(errno), errno);
                                                        SQLFreeHandle(SQL_HANDLE_STMT, stmt);
                                                        ast_odbc_release_obj(obj);
@@ -1163,6 +1191,9 @@ static int remove_file(char *dir, int msgnum)
        } else
                ast_copy_string(fn, dir, sizeof(fn));
        ast_filedelete(fn, NULL);       
+       if (ast_check_realtime("voicemail_data")) {
+               ast_destroy_realtime("voicemail_data", "filename", fn, NULL);
+       }
        snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
        unlink(full_fn);
        return 0;
@@ -1386,10 +1417,10 @@ static int store_file(char *dir, char *mailboxuser, char *mailboxcontext, int ms
        int x = 0;
        int res;
        int fd = -1;
-       void *fdm=NULL;
+       void *fdm = MAP_FAILED;
        size_t fdlen = -1;
        SQLHSTMT stmt;
-       SQLINTEGER len;
+       SQLLEN len;
        char sql[PATH_MAX];
        char msgnums[20];
        char fn[PATH_MAX];
@@ -1442,7 +1473,7 @@ static int store_file(char *dir, char *mailboxuser, char *mailboxcontext, int ms
                lseek(fd, 0, SEEK_SET);
                printf("Length is %zd\n", fdlen);
                fdm = mmap(NULL, fdlen, PROT_READ | PROT_WRITE, MAP_SHARED,fd, 0);
-               if (!fdm) {
+               if (fdm == MAP_FAILED) {
                        ast_log(LOG_WARNING, "Memory map failed!\n");
                        ast_odbc_release_obj(obj);
                        goto yuck;
@@ -1491,7 +1522,7 @@ static int store_file(char *dir, char *mailboxuser, char *mailboxcontext, int ms
 yuck:  
        if (cfg)
                ast_config_destroy(cfg);
-       if (fdm)
+       if (fdm != MAP_FAILED)
                munmap(fdm, fdlen);
        if (fd > -1)
                close(fd);
@@ -1579,6 +1610,9 @@ static void rename_file(char *sfn, char *dfn)
        ast_filerename(sfn,dfn,NULL);
        snprintf(stxt, sizeof(stxt), "%s.txt", sfn);
        snprintf(dtxt, sizeof(dtxt), "%s.txt", dfn);
+       if (ast_check_realtime("voicemail_data")) {
+               ast_update_realtime("voicemail_data", "filename", sfn, "filename", dfn, NULL);
+       }
        rename(stxt, dtxt);
 }
 
@@ -1635,10 +1669,43 @@ static int copy(char *infile, char *outfile)
 static void copy_file(char *frompath, char *topath)
 {
        char frompath2[PATH_MAX], topath2[PATH_MAX];
+       struct ast_variable *tmp,*var = NULL;
+       char *origmailbox = NULL, *context = NULL, *macrocontext = NULL, *exten = NULL, *priority = NULL, *callerchan = NULL, *callerid = NULL, *origdate = NULL, *origtime = NULL, *category = NULL, *duration = NULL;
        ast_filecopy(frompath, topath, NULL);
        snprintf(frompath2, sizeof(frompath2), "%s.txt", frompath);
        snprintf(topath2, sizeof(topath2), "%s.txt", topath);
+       if (ast_check_realtime("voicemail_data")) {
+               var = ast_load_realtime("voicemail_data", "filename", frompath, NULL);
+               /* This cycle converts ast_variable linked list, to va_list list of arguments, may be there is a better way to do it? */
+               for (tmp = var; tmp; tmp = tmp->next) {
+                       if (!strcasecmp(tmp->name, "origmailbox")) {
+                               origmailbox = tmp->value;
+                       } else if (!strcasecmp(tmp->name, "context")) {
+                               context = tmp->value;
+                       } else if (!strcasecmp(tmp->name, "macrocontext")) {
+                               macrocontext = tmp->value;
+                       } else if (!strcasecmp(tmp->name, "exten")) {
+                               exten = tmp->value;
+                       } else if (!strcasecmp(tmp->name, "priority")) {
+                               priority = tmp->value;
+                       } else if (!strcasecmp(tmp->name, "callerchan")) {
+                               callerchan = tmp->value;
+                       } else if (!strcasecmp(tmp->name, "callerid")) {
+                               callerid = tmp->value;
+                       } else if (!strcasecmp(tmp->name, "origdate")) {
+                               origdate = tmp->value;
+                       } else if (!strcasecmp(tmp->name, "origtime")) {
+                               origtime = tmp->value;
+                       } else if (!strcasecmp(tmp->name, "category")) {
+                               category = tmp->value;
+                       } else if (!strcasecmp(tmp->name, "duration")) {
+                               duration = tmp->value;
+                       }
+               }
+               ast_store_realtime("voicemail_data", "filename", topath, "origmailbox", origmailbox, "context", context, "macrocontext", macrocontext, "exten", exten, "priority", priority, "callerchan", callerchan, "callerid", callerid, "origdate", origdate, "origtime", origtime, "category", category, "duration", duration, NULL);
+       }
        copy(frompath2, topath2);
+       ast_variables_destroy(var);
 }
 #endif
 
@@ -1683,6 +1750,9 @@ static int vm_delete(char *file)
        /* Sprintf here would safe because we alloca'd exactly the right length,
         * but trying to eliminate all sprintf's anyhow
         */
+       if (ast_check_realtime("voicemail_data")) {
+               ast_destroy_realtime("voicemail_data", "filename", file, NULL);
+       }
        snprintf(txt, txtsize, "%s.txt", file);
        unlink(txt);
        return ast_filedelete(file, NULL);
@@ -1914,7 +1984,7 @@ static void make_email_file(FILE *p, char *srcemail, struct ast_vm_user *vmu, in
 
        if (!ast_strlen_zero(fromstring)) {
                struct ast_channel *ast;
-               if ((ast = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, 0))) {
+               if ((ast = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, 0))) {
                        char *passdata;
                        int vmlen = strlen(fromstring)*3 + 200;
                        if ((passdata = alloca(vmlen))) {
@@ -1936,7 +2006,7 @@ static void make_email_file(FILE *p, char *srcemail, struct ast_vm_user *vmu, in
        fprintf(p, "To: %s <%s>" ENDL, quote(vmu->fullname, passdata2, len_passdata), vmu->email);
        if (!ast_strlen_zero(emailsubject)) {
                struct ast_channel *ast;
-               if ((ast = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, 0))) {
+               if ((ast = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, 0))) {
                        char *passdata;
                        int vmlen = strlen(emailsubject) * 3 + 200;
                        if ((passdata = alloca(vmlen))) {
@@ -1956,7 +2026,7 @@ static void make_email_file(FILE *p, char *srcemail, struct ast_vm_user *vmu, in
                fprintf(p, "Subject: New message %d in mailbox %s" ENDL, msgnum + 1, mailbox);
        else
                fprintf(p, "Subject: [PBX]: New message %d in mailbox %s" ENDL, msgnum + 1, mailbox);
-       fprintf(p, "Message-ID: <Asterisk-%d-%d-%s-%d@%s>" ENDL, msgnum, (unsigned int)ast_random(), mailbox, getpid(), host);
+       fprintf(p, "Message-ID: <Asterisk-%d-%d-%s-%d@%s>" ENDL, msgnum + 1, (unsigned int)ast_random(), mailbox, getpid(), host);
        if(imap) {
                /* additional information needed for IMAP searching */
                fprintf(p, "X-Asterisk-VM-Message-Num: %d" ENDL, msgnum + 1);
@@ -1981,16 +2051,16 @@ static void make_email_file(FILE *p, char *srcemail, struct ast_vm_user *vmu, in
        fprintf(p, "MIME-Version: 1.0" ENDL);
        if (attach_user_voicemail) {
                /* Something unique. */
-               snprintf(bound, sizeof(bound), "voicemail_%d%s%d%d", msgnum + 1, mailbox, getpid(), (unsigned int)ast_random());
-
-               fprintf(p, "Content-Type: multipart/mixed; boundary=\"%s\"" ENDL ENDL ENDL, bound);
+               snprintf(bound, sizeof(bound), "----voicemail_%d%s%d%d", msgnum + 1, mailbox, getpid(), (unsigned int)ast_random());
 
+               fprintf(p, "Content-Type: multipart/mixed; boundary=\"%s\"" ENDL, bound);
+               fprintf(p, ENDL ENDL "This is a multi-part message in MIME format." ENDL ENDL);
                fprintf(p, "--%s" ENDL, bound);
        }
        fprintf(p, "Content-Type: text/plain; charset=%s" ENDL "Content-Transfer-Encoding: 8bit" ENDL ENDL, charset);
        if (emailbody) {
                struct ast_channel *ast;
-               if ((ast = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, 0))) {
+               if ((ast = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, 0))) {
                        char *passdata;
                        int vmlen = strlen(emailbody)*3 + 200;
                        if ((passdata = alloca(vmlen))) {
@@ -2019,14 +2089,12 @@ static void make_email_file(FILE *p, char *srcemail, struct ast_vm_user *vmu, in
                create_dirpath(tmpdir, sizeof(tmpdir), vmu->context, vmu->mailbox, "tmp");
                snprintf(newtmp, sizeof(newtmp), "%s/XXXXXX", tmpdir);
                tmpfd = mkstemp(newtmp);
-               if (option_debug > 2)
-                       ast_log(LOG_DEBUG, "newtmp: %s\n", newtmp);
+               ast_debug(3, "newtmp: %s\n", newtmp);
                if (vmu->volgain < -.001 || vmu->volgain > .001) {
                        snprintf(tmpcmd, sizeof(tmpcmd), "sox -v %.4f %s.%s %s.%s", vmu->volgain, attach, format, newtmp, format);
                        ast_safe_system(tmpcmd);
                        attach = newtmp;
-                       if (option_debug > 2)
-                               ast_log(LOG_DEBUG, "VOLGAIN: Stored at: %s.%s - Level: %.4f - Mailbox: %s\n", attach, format, vmu->volgain, mailbox);
+                       ast_debug(3, "VOLGAIN: Stored at: %s.%s - Level: %.4f - Mailbox: %s\n", attach, format, vmu->volgain, mailbox);
                }
                fprintf(p, "--%s" ENDL, bound);
                fprintf(p, "Content-Type: %s%s; name=\"msg%04d.%s\"" ENDL, ctype, format, msgnum + 1, format);
@@ -2035,17 +2103,7 @@ static void make_email_file(FILE *p, char *srcemail, struct ast_vm_user *vmu, in
                fprintf(p, "Content-Disposition: attachment; filename=\"msg%04d.%s\"" ENDL ENDL, msgnum + 1, format);
                snprintf(fname, sizeof(fname), "%s.%s", attach, format);
                base_encode(fname, p);
-               /* only attach if necessary */
-               if (imap && !strcmp(format, "gsm")) {
-                       fprintf(p, "--%s" ENDL, bound);
-                       fprintf(p, "Content-Type: audio/x-gsm; name=\"msg%04d.%s\"" ENDL, msgnum + 1, format);
-                       fprintf(p, "Content-Transfer-Encoding: base64" ENDL);
-                       fprintf(p, "Content-Description: Voicemail sound attachment." ENDL);
-                       fprintf(p, "Content-Disposition: attachment; filename=\"msg%04d.gsm\"" ENDL ENDL, msgnum + 1);
-                       snprintf(fname, sizeof(fname), "%s.gsm", attach);
-                       base_encode(fname, p);
-               }
-               fprintf(p, ENDL ENDL "--%s--" ENDL "." ENDL, bound);
+               fprintf(p, ENDL "--%s--" ENDL "." ENDL, bound);
                if (tmpfd > -1)
                        close(tmpfd);
                unlink(newtmp);
@@ -2065,8 +2123,7 @@ static int sendmail(char *srcemail, struct ast_vm_user *vmu, int msgnum, char *c
        }
        if (!strcmp(format, "wav49"))
                format = "WAV";
-       if (option_debug > 2)
-               ast_log(LOG_DEBUG, "Attaching file '%s', format '%s', uservm is '%d', global is %d\n", attach, format, attach_user_voicemail, ast_test_flag((&globalflags), VM_ATTACH));
+       ast_debug(3, "Attaching file '%s', format '%s', uservm is '%d', global is %d\n", attach, format, attach_user_voicemail, ast_test_flag((&globalflags), VM_ATTACH));
        /* Make a temporary file instead of piping directly to sendmail, in case the mail
           command hangs */
        if ((p = vm_mkftemp(tmp)) == NULL) {
@@ -2077,8 +2134,7 @@ static int sendmail(char *srcemail, struct ast_vm_user *vmu, int msgnum, char *c
                fclose(p);
                snprintf(tmp2, sizeof(tmp2), "( %s < %s ; rm -f %s ) &", mailcmd, tmp, tmp);
                ast_safe_system(tmp2);
-               if (option_debug)
-                       ast_log(LOG_DEBUG, "Sent mail to %s with command '%s'\n", vmu->email, mailcmd);
+               ast_debug(1, "Sent mail to %s with command '%s'\n", vmu->email, mailcmd);
        }
        return 0;
 }
@@ -2109,7 +2165,7 @@ static int sendpage(char *srcemail, char *pager, int msgnum, char *context, char
 
        if (*pagerfromstring) {
                struct ast_channel *ast;
-               if ((ast = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, 0))) {
+               if ((ast = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, 0))) {
                        char *passdata;
                        int vmlen = strlen(fromstring)*3 + 200;
                        if ((passdata = alloca(vmlen))) {
@@ -2127,7 +2183,7 @@ static int sendpage(char *srcemail, char *pager, int msgnum, char *context, char
        fprintf(p, "To: %s\n", pager);
        if (pagersubject) {
                struct ast_channel *ast;
-               if ((ast = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, 0))) {
+               if ((ast = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, 0))) {
                        char *passdata;
                        int vmlen = strlen(pagersubject) * 3 + 200;
                        if ((passdata = alloca(vmlen))) {
@@ -2146,16 +2202,14 @@ static int sendpage(char *srcemail, char *pager, int msgnum, char *context, char
        strftime(date, sizeof(date), "%A, %B %d, %Y at %r", &tm);
        if (pagerbody) {
                struct ast_channel *ast;
-               if ((ast = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, 0))) {
+               if ((ast = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, 0))) {
                        char *passdata;
-                       int vmlen = strlen(pagerbody)*3 + 200;
-                       if ((passdata = alloca(vmlen))) {
-                               memset(passdata, 0, vmlen);
-                               prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, cidnum, cidname, dur, date, passdata, vmlen, category);
-                               pbx_substitute_variables_helper(ast, pagerbody, passdata, vmlen);
-                               fprintf(p, "%s\n", passdata);
-                       } else
-                               ast_log(LOG_WARNING, "Cannot allocate workspace for variable substitution\n");
+                       int vmlen = strlen(pagerbody) * 3 + 200;
+                       passdata = alloca(vmlen);
+                       memset(passdata, 0, vmlen);
+                       prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, cidnum, cidname, dur, date, passdata, vmlen, category);
+                       pbx_substitute_variables_helper(ast, pagerbody, passdata, vmlen);
+                       fprintf(p, "%s\n", passdata);
                        ast_channel_free(ast);
                } else
                        ast_log(LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
@@ -2166,8 +2220,7 @@ static int sendpage(char *srcemail, char *pager, int msgnum, char *context, char
        fclose(p);
        snprintf(tmp2, sizeof(tmp2), "( %s < %s ; rm -f %s ) &", mailcmd, tmp, tmp);
        ast_safe_system(tmp2);
-       if (option_debug)
-               ast_log(LOG_DEBUG, "Sent page to %s with command '%s'\n", pager, mailcmd);
+       ast_debug(1, "Sent page to %s with command '%s'\n", pager, mailcmd);
        return 0;
 }
 
@@ -2188,7 +2241,7 @@ static int invent_message(struct ast_channel *chan, char *context, char *ext, in
 
        snprintf(fn, sizeof(fn), "%s%s/%s/greet", VM_SPOOL_DIR, context, ext);
 
-       if (!(res = create_dirpath(dest, sizeof(dest), context, ext, "greet"))) {
+       if ((res = create_dirpath(dest, sizeof(dest), context, ext, "greet"))) {
                ast_log(LOG_WARNING, "Failed to make directory(%s)\n", fn);
                return -1;
        }
@@ -2216,13 +2269,15 @@ static int invent_message(struct ast_channel *chan, char *context, char *ext, in
 
 static void free_user(struct ast_vm_user *vmu)
 {
-       if (ast_test_flag(vmu, VM_ALLOCED))
-               free(vmu);
+       if (!ast_test_flag(vmu, VM_ALLOCED))
+               return;
+
+       ast_free(vmu);
 }
 
 static void free_zone(struct vm_zone *z)
 {
-       free(z);
+       ast_free(z);
 }
 
 static const char *mbox(int id)
@@ -2459,8 +2514,7 @@ static int imap_store_file(char *dir, char *mailboxuser, char *mailboxcontext, i
 
        if (!strcmp(fmt, "wav49"))
                fmt = "WAV";
-       if(option_debug > 2)
-               ast_log(LOG_DEBUG, "Storing file '%s', format '%s'\n", fn, fmt);
+       ast_debug(3, "Storing file '%s', format '%s'\n", fn, fmt);
 
        /* Make a temporary file instead of piping directly to sendmail, in case the mail
           command hangs */
@@ -2487,8 +2541,7 @@ static int imap_store_file(char *dir, char *mailboxuser, char *mailboxcontext, i
        fclose(p);
        unlink(tmp);
        ast_free(buf);
-       if(option_debug > 2)
-               ast_log(LOG_DEBUG, "%s stored\n", fn);
+       ast_debug(3, "%s stored\n", fn);
        return 0;
 
 }
@@ -2512,8 +2565,7 @@ static int inboxcount(const char *mailbox, int *newmsgs, int *oldmsgs)
        if (oldmsgs)
                *oldmsgs = 0;
  
-       if(option_debug > 2)
-               ast_log (LOG_DEBUG,"Mailbox is set to %s\n",mailbox);
+        ast_debug(3,"Mailbox is set to %s\n",mailbox);
 
        /* If no mailbox, return immediately */
        if (ast_strlen_zero(mailbox))
@@ -2551,7 +2603,7 @@ static int inboxcount(const char *mailbox, int *newmsgs, int *oldmsgs)
        }
  
        /* We have to get the user before we can open the stream! */
-       /*ast_log (LOG_DEBUG,"Before find_user, context is %s and mailbox is %s\n",context,mailbox); */
+       /*ast_debug(1,"Before find_user, context is %s and mailbox is %s\n",context,mailbox); */
        if (!(vmu = find_user(NULL, context, mailboxnc))) {
                ast_log(LOG_ERROR, "Couldn't find mailbox %s in context %s\n", mailboxnc, context);
                return -1;
@@ -2560,29 +2612,30 @@ static int inboxcount(const char *mailbox, int *newmsgs, int *oldmsgs)
        /* No IMAP account available */
        if (vmu->imapuser[0] == '\0') {
                ast_log (LOG_WARNING,"IMAP user not set for mailbox %s\n",vmu->mailbox);
+               free_user(vmu);
                return -1;
        }
  
        /* check if someone is accessing this box right now... */
        if ((vms_p = get_vm_state_by_imapuser(vmu->imapuser, 1)) || (vms_p = get_vm_state_by_mailbox(mailboxnc, 1))) {
-               if(option_debug > 2)
-                       ast_log (LOG_DEBUG,"Returning before search - user is logged in\n");
+               ast_debug(3,"Returning before search - user is logged in\n");
                *newmsgs = vms_p->newmessages;
                *oldmsgs = vms_p->oldmessages;
+               free_user(vmu);
                return 0;
        }
  
        /* add one if not there... */
        if (!(vms_p = get_vm_state_by_imapuser(vmu->imapuser, 0)) && !(vms_p = get_vm_state_by_mailbox(mailboxnc, 0))) {
-               if(option_debug > 2)
-                       ast_log (LOG_DEBUG,"Adding new vmstate for %s\n",vmu->imapuser);
-               if (!(vms_p = ast_calloc(1, sizeof(*vms_p))))
+               ast_debug(3,"Adding new vmstate for %s\n",vmu->imapuser);
+               if (!(vms_p = ast_calloc(1, sizeof(*vms_p)))) {
+                       free_user(vmu);
                        return -1;
+               }
                ast_copy_string(vms_p->imapuser,vmu->imapuser, sizeof(vms_p->imapuser));
                ast_copy_string(vms_p->username, mailboxnc, sizeof(vms_p->username)); /* save for access from interactive entry point */
                vms_p->mailstream = NIL; /* save for access from interactive entry point */
-               if(option_debug > 2)
-                       ast_log (LOG_DEBUG,"Copied %s to %s\n",vmu->imapuser,vms_p->imapuser);
+               ast_debug(3,"Copied %s to %s\n",vmu->imapuser,vms_p->imapuser);
                vms_p->updated = 1;
                /* set mailbox to INBOX! */
                ast_copy_string(vms_p->curbox, mbox(0), sizeof(vms_p->curbox));
@@ -2594,6 +2647,7 @@ static int inboxcount(const char *mailbox, int *newmsgs, int *oldmsgs)
        ret = init_mailstream(vms_p, 0);
        if (!vms_p->mailstream) {
                ast_log (LOG_ERROR,"Houston we have a problem - IMAP mailstream is NULL\n");
+               free_user(vmu);
                return -1;
        }
 
@@ -2639,6 +2693,7 @@ static int inboxcount(const char *mailbox, int *newmsgs, int *oldmsgs)
                *oldmsgs = vms_p->oldmessages;
        }
 
+       free_user(vmu);
        return 0;
  }
 
@@ -2843,8 +2898,7 @@ static void run_externnotify(char *context, char *extension)
                        ast_log(LOG_WARNING, "The switch reported '%s'\n", mwi_msg->cause);
                        ASTOBJ_UNREF(mwi_msg, ast_smdi_mwi_message_destroy);
                } else {
-                       if (option_debug)
-                               ast_log(LOG_DEBUG, "Successfully executed SMDI MWI change for %s on %s\n", extension, smdi_iface->name);
+                       ast_debug(1, "Successfully executed SMDI MWI change for %s on %s\n", extension, smdi_iface->name);
                }
        }
 
@@ -2853,8 +2907,7 @@ static void run_externnotify(char *context, char *extension)
                        ast_log(LOG_ERROR, "Problem in calculating number of voicemail messages available for extension %s\n", extension);
                } else {
                        snprintf(arguments, sizeof(arguments), "%s %s %s %d&", externnotify, context, extension, newvoicemails);
-                       if (option_debug)
-                               ast_log(LOG_DEBUG, "Executing %s\n", arguments);
+                       ast_debug(1, "Executing %s\n", arguments);
                        ast_safe_system(arguments);
                }
        }
@@ -2882,6 +2935,11 @@ static int leave_voicemail(struct ast_channel *chan, char *ext, struct leave_vm_
        int ausemacro = 0;
        int ousemacro = 0;
        int ouseexten = 0;
+       int rtmsgid = 0;
+       char tmpid[16];
+       char tmpdur[16];
+       char priority[16];
+       char origtime[16];
        char dir[PATH_MAX], tmpdir[PATH_MAX];
        char dest[PATH_MAX];
        char fn[PATH_MAX];
@@ -2891,7 +2949,7 @@ static int leave_voicemail(struct ast_channel *chan, char *ext, struct leave_vm_
        char fmt[80];
        char *context;
        char ecodes[16] = "#";
-       char tmp[256] = "", *tmpptr;
+       char tmp[1024] = "", *tmpptr;
        struct ast_vm_user *vmu;
        struct ast_vm_user svm;
        const char *category = NULL;
@@ -2910,12 +2968,9 @@ static int leave_voicemail(struct ast_channel *chan, char *ext, struct leave_vm_
 
        category = pbx_builtin_getvar_helper(chan, "VM_CATEGORY");
 
-       if(option_debug > 2)
-               ast_log(LOG_DEBUG, "Before find_user\n");
+       ast_debug(3, "Before find_user\n");
        if (!(vmu = find_user(&svm, context, ext))) {
                ast_log(LOG_WARNING, "No entry in voicemail config file for '%s'\n", ext);
-               if (ast_test_flag(options, OPT_PRIORITY_JUMP) || ast_opt_priority_jumping)
-                       ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101);
                pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
                return res;
        }
@@ -2932,7 +2987,7 @@ static int leave_voicemail(struct ast_channel *chan, char *ext, struct leave_vm_
                snprintf(prefile, sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, ext);
        }
        snprintf(tempfile, sizeof(tempfile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, ext);
-       if (!(res = create_dirpath(dest, sizeof(dest), vmu->context, ext, "temp"))) {
+       if ((res = create_dirpath(dest, sizeof(dest), vmu->context, ext, "temp"))) {
                ast_log(LOG_WARNING, "Failed to make directory (%s)\n", tempfile);
                return -1;
        }
@@ -2978,14 +3033,12 @@ static int leave_voicemail(struct ast_channel *chan, char *ext, struct leave_vm_
                        if (ast_streamfile(chan, prefile, chan->language) > -1) 
                                res = ast_waitstream(chan, ecodes);
                } else {
-                       if (option_debug)
-                               ast_log(LOG_DEBUG, "%s doesn't exist, doing what we can\n", prefile);
+                       ast_debug(1, "%s doesn't exist, doing what we can\n", prefile);
                        res = invent_message(chan, vmu->context, ext, ast_test_flag(options, OPT_BUSY_GREETING), ecodes);
                }
                DISPOSE(prefile, -1);
                if (res < 0) {
-                       if (option_debug)
-                               ast_log(LOG_DEBUG, "Hang up during prefile playback\n");
+                       ast_debug(1, "Hang up during prefile playback\n");
                        free_user(vmu);
                        pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
                        return -1;
@@ -3054,12 +3107,11 @@ static int leave_voicemail(struct ast_channel *chan, char *ext, struct leave_vm_
                /* must open stream for this user to get info! */
                vms = get_vm_state_by_mailbox(ext,0);
                if (vms) {
-                       if(option_debug > 2)
-                               ast_log(LOG_DEBUG, "Using vm_state, interactive set to %d.\n",vms->interactive);
+                       ast_debug(3, "Using vm_state, interactive set to %d.\n",vms->interactive);
                        newmsgs = vms->newmessages++;
                        oldmsgs = vms->oldmessages;
                } else {
-                       res = inboxcount(ext, &newmsgs, &oldmsgs);
+                       res = inboxcount(ext_context, &newmsgs, &oldmsgs);
                        if(res < 0) {
                                ast_log(LOG_NOTICE,"Can not leave voicemail, unable to count messages\n");
                                return -1;
@@ -3068,23 +3120,20 @@ static int leave_voicemail(struct ast_channel *chan, char *ext, struct leave_vm_
                }
                /* here is a big difference! We add one to it later */
                msgnum = newmsgs + oldmsgs;
-               if(option_debug > 2)
-                       ast_log(LOG_DEBUG, "Messagecount set to %d\n",msgnum);
+               ast_debug(3, "Messagecount set to %d\n",msgnum);
                snprintf(fn, sizeof(fn), "%s/imap/msg%s%04d", VM_SPOOL_DIR, vmu->mailbox, msgnum);
                /* set variable for compatibility */
                pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", "IMAP_STORAGE");
 
                /* Check if mailbox is full */
                if (vms->quota_limit && vms->quota_usage >= vms->quota_limit) {
-                       if (option_debug)
-                               ast_log(LOG_DEBUG, "*** QUOTA EXCEEDED!! %u >= %u\n", vms->quota_usage, vms->quota_limit);
+                       ast_debug(1, "*** QUOTA EXCEEDED!! %u >= %u\n", vms->quota_usage, vms->quota_limit);
                        ast_play_and_wait(chan, "vm-mailboxfull");
                        return -1;
                }
                /* here is a big difference! We add one to it later */
                msgnum = newmsgs + oldmsgs;
-               if(option_debug > 2)
-                       ast_log(LOG_DEBUG, "Messagecount set to %d\n",msgnum);
+               ast_debug(3, "Messagecount set to %d\n",msgnum);
 
 #else
                if (count_messages(vmu, dir) >= vmu->maxmsg) {
@@ -3114,6 +3163,14 @@ static int leave_voicemail(struct ast_channel *chan, char *ext, struct leave_vm_
                        res = ast_stream_and_wait(chan, "beep", "");
                }
                                
+               /* Store information in real-time storage */
+               if (ast_check_realtime("voicemail_data")) {
+                       snprintf(priority, sizeof(priority), "%d", chan->priority);
+                       snprintf(origtime, sizeof(origtime), "%ld", (long)time(NULL));
+                       get_date(date, sizeof(date));
+                       rtmsgid = ast_store_realtime("voicemail_data", "origmailbox", ext, "context", chan->context, "macrocontext", chan->macrocontext, "exten", chan->exten, "priority", priority, "callerchan", chan->name, "callerid", ast_callerid_merge(callerid, sizeof(callerid), chan->cid.cid_name, chan->cid.cid_num, "Unknown"), "origdate", date, "origtime", origtime, "category", category ? category : "", NULL);
+               }
+
                /* Store information */
                txt = fdopen(txtdes, "w+");
                if (txt) {
@@ -3156,6 +3213,10 @@ static int leave_voicemail(struct ast_channel *chan, char *ext, struct leave_vm_
                                        ast_verbose( VERBOSE_PREFIX_3 "Recording was %d seconds long but needs to be at least %d - abandoning\n", duration, vmminsecs);
                                ast_filedelete(tmptxtfile, NULL);
                                unlink(tmptxtfile);
+                               if (ast_check_realtime("voicemail_data")) {
+                                       snprintf(tmpid, sizeof(tmpid), "%d", rtmsgid);
+                                       ast_destroy_realtime("voicemail_data", "id", tmpid, NULL);
+                               }
                        } else {
                                fprintf(txt, "duration=%d\n", duration);
                                fclose(txt);
@@ -3165,10 +3226,13 @@ static int leave_voicemail(struct ast_channel *chan, char *ext, struct leave_vm_
                                        ast_filedelete(tmptxtfile, NULL);
                                        unlink(tmptxtfile);
                                } else if (ast_fileexists(tmptxtfile, NULL, NULL) <= 0) {
-                                       if (option_debug) 
-                                               ast_log(LOG_DEBUG, "The recorded media file is gone, so we should remove the .txt file too!\n");
+                                       ast_debug(1, "The recorded media file is gone, so we should remove the .txt file too!\n");
                                        unlink(tmptxtfile);
                                        ast_unlock_path(dir);
+                                       if (ast_check_realtime("voicemail_data")) {
+                                               snprintf(tmpid, sizeof(tmpid), "%d", rtmsgid);
+                                               ast_destroy_realtime("voicemail_data", "id", tmpid, NULL);
+                                       }
                                } else {
                                        msgnum = last_message_index(vmu, dir) + 1;
                                        make_file(fn, sizeof(fn), dir, msgnum);
@@ -3185,6 +3249,11 @@ static int leave_voicemail(struct ast_channel *chan, char *ext, struct leave_vm_
                                        rename(tmptxtfile, txtfile);
 
                                        ast_unlock_path(dir);
+                                       if (ast_check_realtime("voicemail_data")) {
+                                               snprintf(tmpid, sizeof(tmpid), "%d", rtmsgid);
+                                               snprintf(tmpdur, sizeof(tmpdur), "%d", duration);
+                                               ast_update_realtime("voicemail_data", "id", tmpid, "filename", fn, "duration", tmpdur, NULL);
+                                       }
 #ifndef IMAP_STORAGE
                                        /* Are there to be more recipients of this message? */
                                        while (tmpptr) {
@@ -3280,8 +3349,7 @@ static int save_to_folder(struct ast_vm_user *vmu, struct vm_state *vms, int msg
        /* get the real IMAP message number for this message */
        sprintf(sequence,"%ld",vms->msgArray[msg]);
        imap_mailbox_name(dbox, vms, box, 1);
-       if (option_debug > 2)
-               ast_log(LOG_DEBUG, "Copying sequence %s to mailbox %s\n",sequence,dbox);
+       ast_debug(3, "Copying sequence %s to mailbox %s\n",sequence,dbox);
        res = mail_copy(vms->mailstream, sequence, dbox);
        if (res == 1) return 0;
        return 1;
@@ -3430,8 +3498,7 @@ static int adsi_load_vmail(struct ast_channel *chan, int *useadsi)
        bytes += ast_adsi_voice_mode(buf + bytes, 0);
        ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
 
-       if (option_debug)
-               ast_log(LOG_DEBUG, "Done downloading scripts...\n");
+       ast_debug(1, "Done downloading scripts...\n");
 
 #ifdef DISPLAY
        /* Add last dot */
@@ -3439,8 +3506,7 @@ static int adsi_load_vmail(struct ast_channel *chan, int *useadsi)
        bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "   ......", "");
        bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
 #endif
-       if (option_debug)
-               ast_log(LOG_DEBUG, "Restarting session...\n");
+       ast_debug(1, "Restarting session...\n");
 
        bytes = 0;
        /* Load the session now */
@@ -3899,7 +3965,7 @@ static int vm_forwardoptions(struct ast_channel *chan, struct ast_vm_user *vmu,
                                *duration += prepend_duration;
                                msg_cat = ast_category_get(msg_cfg, "message");
                                snprintf(duration_str, 11, "%ld", *duration);
-                               if (!ast_variable_update(msg_cat, "duration", duration_str, NULL)) {
+                               if (!ast_variable_update(msg_cat, "duration", duration_str, NULL, 0)) {
                                        config_text_file_save(textfile, msg_cfg, "app_voicemail");
                                        STORE(curdir, vmu->mailbox, context, curmsg, chan, vmu, vmfmts, *duration, vms);
                                }
@@ -3934,6 +4000,29 @@ static int vm_forwardoptions(struct ast_channel *chan, struct ast_vm_user *vmu,
        return cmd;
 }
 
+static void queue_mwi_event(const char *mbox, int new, int old)
+{
+       struct ast_event *event;
+       char *mailbox;
+
+       /* Strip off @default */
+       mailbox = ast_strdupa(mbox);
+       if (strstr(mailbox, "@default"))
+               mailbox = strsep(&mailbox, "@");
+
+       if (!(event = ast_event_new(AST_EVENT_MWI,
+                       AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, mailbox,
+                       AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_UINT, new,
+                       AST_EVENT_IE_OLDMSGS, AST_EVENT_IE_PLTYPE_UINT, old,
+                       AST_EVENT_IE_END))) {
+               return;
+       }
+
+       ast_event_queue_and_cache(event,
+               AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR,
+               AST_EVENT_IE_END);
+}
+
 static int notify_new_message(struct ast_channel *chan, struct ast_vm_user *vmu, int msgnum, long duration, char *fmt, char *cidnum, char *cidname)
 {
        char todir[PATH_MAX], fn[PATH_MAX], ext_context[PATH_MAX], *stringp;
@@ -3982,6 +4071,8 @@ static int notify_new_message(struct ast_channel *chan, struct ast_vm_user *vmu,
        if (ast_app_has_voicemail(ext_context, NULL)) 
                ast_app_inboxcount(ext_context, &newmsgs, &oldmsgs);
 
+       queue_mwi_event(ext_context, newmsgs, oldmsgs);
+
        manager_event(EVENT_FLAG_CALL, "MessageWaiting", "Mailbox: %s@%s\r\nWaiting: %d\r\nNew: %d\r\nOld: %d\r\n", vmu->mailbox, vmu->context, ast_app_has_voicemail(ext_context, NULL), newmsgs, oldmsgs);
        run_externnotify(vmu->context, vmu->mailbox);
        return 0;
@@ -4144,8 +4235,7 @@ static int forward_message(struct ast_channel *chan, char *context, struct vm_st
                        AST_LIST_TRAVERSE_SAFE_BEGIN(&extensions, vmtmp, list) {
 #ifdef IMAP_STORAGE
                                /* Need to get message content */
-                               if(option_debug > 2)
-                                       ast_log (LOG_DEBUG,"Before mail_fetchheaders, curmsg is: %d, imap messages is %lu\n",vms->curmsg, vms->msgArray[vms->curmsg]);
+                               ast_debug(3,"Before mail_fetchheaders, curmsg is: %d, imap messages is %lu\n",vms->curmsg, vms->msgArray[vms->curmsg]);
                                if (!vms->msgArray[vms->curmsg]) {
                                        ast_log (LOG_WARNING,"Trying to access unknown message\n");
                                        return -1;
@@ -4174,14 +4264,12 @@ static int forward_message(struct ast_channel *chan, char *context, struct vm_st
                                }
                                if (!strcasecmp(fmt, "wav49"))
                                        fmt = "WAV";
-                               if (option_debug > 2)
-                                       ast_log (LOG_DEBUG,"**** format set to %s, vmfmts set to %s\n",fmt,vmfmts);
+                               ast_debug(3,"**** format set to %s, vmfmts set to %s\n",fmt,vmfmts);
                                /* ast_copy_string(fmt, vmfmts, sizeof(fmt));*/
                                /* if (!ast_strlen_zero(fmt)) { */
                                snprintf(todir, sizeof(todir), "%s%s/%s/tmp", VM_SPOOL_DIR, vmtmp->context, vmtmp->mailbox);
                                make_gsm_file(vms->fn, vms->imapuser, todir, vms->curmsg);
-                               if (option_debug > 2)
-                                       ast_log (LOG_DEBUG,"Before mail_fetchstructure, message number is %ld, filename is:%s\n",vms->msgArray[vms->curmsg], vms->fn);
+                               ast_debug(3,"Before mail_fetchstructure, message number is %ld, filename is:%s\n",vms->msgArray[vms->curmsg], vms->fn);
                                /*mail_fetchstructure (mailstream, vmArray[0], &body); */
                                mail_fetchstructure (vms->mailstream, vms->msgArray[vms->curmsg], &body);
                                save_body(body,vms,"3","gsm");
@@ -4219,6 +4307,10 @@ static int forward_message(struct ast_channel *chan, char *context, struct vm_st
                        }       
                }
        }
+
+       /* If anything failed above, we still have this list to free */
+       while ((vmtmp = AST_LIST_REMOVE_HEAD(&extensions, list)))
+               free_user(vmtmp);
        return res ? res : cmd;
 }
 
@@ -4232,7 +4324,7 @@ static int wait_file2(struct ast_channel *chan, struct vm_state *vms, char *file
 
 static int wait_file(struct ast_channel *chan, struct vm_state *vms, char *file) 
 {
-       return ast_control_streamfile(chan, file, "#", "*", "1456789", "0", "2", skipms);
+       return ast_control_streamfile(chan, file, "#", "*", "1456789", "0", "2", skipms, NULL);
 }
 
 static int play_message_category(struct ast_channel *chan, const char *category)
@@ -4334,15 +4426,13 @@ static int play_message_callerid(struct ast_channel *chan, struct vm_state *vms,
                return res;
 
        /* Strip off caller ID number from name */
-       if (option_debug)
-               ast_log(LOG_DEBUG, "VM-CID: composite caller ID received: %s, context: %s\n", cid, context);
+       ast_debug(1, "VM-CID: composite caller ID received: %s, context: %s\n", cid, context);
        ast_callerid_parse(cid, &name, &callerid);
        if ((!ast_strlen_zero(callerid)) && strcmp(callerid, "Unknown")) {
                /* Check for internal contexts and only */
                /* say extension when the call didn't come from an internal context in the list */
                for (i = 0 ; i < MAX_NUM_CID_CONTEXTS ; i++){
-                       if (option_debug)
-                               ast_log(LOG_DEBUG, "VM-CID: comparing internalcontext: %s\n", cidinternalcontexts[i]);
+                       ast_debug(1, "VM-CID: comparing internalcontext: %s\n", cidinternalcontexts[i]);
                        if ((strcmp(cidinternalcontexts[i], context) == 0))
                                break;
                }
@@ -4370,8 +4460,7 @@ static int play_message_callerid(struct ast_channel *chan, struct vm_state *vms,
                }
 
                else if (!res) {
-                       if (option_debug)
-                               ast_log(LOG_DEBUG, "VM-CID: Numeric caller id: (%s)\n", callerid);
+                       ast_debug(1, "VM-CID: Numeric caller id: (%s)\n", callerid);
                        /* BB: Since this is all nicely figured out, why not say "from phone number" in this case" */
                        if (!callback)
                                res = wait_file2(chan, vms, "vm-from-phonenumber");
@@ -4379,8 +4468,7 @@ static int play_message_callerid(struct ast_channel *chan, struct vm_state *vms,
                }
        } else {
                /* Number unknown */
-               if (option_debug)
-                       ast_log(LOG_DEBUG, "VM-CID: From an unknown number\n");
+               ast_debug(1, "VM-CID: From an unknown number\n");
                /* Say "from an unknown caller" as one phrase - it is already recorded by "the voice" anyhow */
                res = wait_file2(chan, vms, "vm-unknown-caller");
        }
@@ -4400,8 +4488,7 @@ static int play_message_duration(struct ast_channel *chan, struct vm_state *vms,
        durations=atoi(duration);
        durationm=(durations / 60);
 
-       if (option_debug)
-               ast_log(LOG_DEBUG, "VM-Duration: duration is: %d seconds converted to: %d minutes\n", durations, durationm);
+       ast_debug(1, "VM-Duration: duration is: %d seconds converted to: %d minutes\n", durations, durationm);
 
        if ((!res) && (durationm >= minduration)) {
                res = wait_file2(chan, vms, "vm-duration");
@@ -4450,12 +4537,12 @@ static int play_message(struct ast_channel *chan, struct ast_vm_user *vmu, struc
        char category[32];
        char todir[PATH_MAX];
        int res = 0;
+       char *attachedfilefmt;
        char *temp;
        char buf[1024];
 
        vms->starting = 0; 
-       if(option_debug > 2)
-               ast_log (LOG_DEBUG,"Before mail_fetchheaders, curmsg is: %d, imap messages is %lu\n",vms->curmsg, vms->msgArray[vms->curmsg]);
+       ast_debug(3,"Before mail_fetchheaders, curmsg is: %d, imap messages is %lu\n",vms->curmsg, vms->msgArray[vms->curmsg]);
 
        if (!vms->msgArray[vms->curmsg]) {
                ast_log (LOG_WARNING,"Trying to access unknown message\n");
@@ -4473,7 +4560,23 @@ static int play_message(struct ast_channel *chan, struct ast_vm_user *vmu, struc
        make_gsm_file(vms->fn, vms->imapuser, todir, vms->curmsg);
 
        mail_fetchstructure (vms->mailstream,vms->msgArray[vms->curmsg],&body);
-       save_body(body,vms,"3","gsm");
+       
+       /* We have the body, now we extract the file name of the first attachment. */
+       if (body->nested.part->next && body->nested.part->next->body.parameter->value) {
+               attachedfilefmt = ast_strdupa(body->nested.part->next->body.parameter->value);
+       } else {
+               ast_log(LOG_ERROR, "There is no file attached to this IMAP message.\n");
+               return -1;
+       }
+       
+       /* Find the format of the attached file */
+
+       strsep(&attachedfilefmt, ".");
+       if (!attachedfilefmt) {
+               ast_log(LOG_ERROR, "File format could not be obtained from IMAP message attachment\n");
+               return -1;
+       }
+       save_body(body, vms, "2", attachedfilefmt);
 
        adsi_message(chan, vms);
        if (!vms->curmsg)
@@ -4665,7 +4768,7 @@ static void imap_mailbox_name(char *spec, struct vm_state *vms, int box, int use
 
        /* Add authentication user if present */
        if (!ast_strlen_zero(authuser))
-               ast_build_string(&t, &left, "/%s", authuser);
+               ast_build_string(&t, &left, "/authuser=%s", authuser);
 
        /* Add flags if present */
        if (!ast_strlen_zero(imapflags))
@@ -4690,11 +4793,9 @@ static int init_mailstream(struct vm_state *vms, int box)
                ast_log (LOG_ERROR,"vm_state is NULL!\n");
                return -1;
        }
-       if(option_debug > 2)
-               ast_log (LOG_DEBUG,"vm_state user is:%s\n",vms->imapuser);
+       ast_debug(3,"vm_state user is:%s\n",vms->imapuser);
        if (vms->mailstream == NIL || !vms->mailstream) {
-               if (option_debug)
-                       ast_log (LOG_DEBUG,"mailstream not set.\n");
+               ast_debug(1,"mailstream not set.\n");
        } else {
                stream = vms->mailstream;
        }
@@ -4720,8 +4821,7 @@ static int init_mailstream(struct vm_state *vms, int box)
        }
        /* Now connect to the target folder */
        imap_mailbox_name(tmp, vms, box, 1);
-       if(option_debug > 2)
-               ast_log (LOG_DEBUG,"Before mail_open, server: %s, box:%d\n", tmp, box);
+       ast_debug(3,"Before mail_open, server: %s, box:%d\n", tmp, box);
        vms->mailstream = mail_open(stream, tmp, debug ? OP_DEBUG : NIL);
        if (vms->mailstream == NIL) {
                return -1;
@@ -4738,9 +4838,7 @@ static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box)
        char dbox[256];
 
        ast_copy_string(vms->imapuser,vmu->imapuser, sizeof(vms->imapuser));
-
-       if(option_debug > 2)
-               ast_log(LOG_DEBUG,"Before init_mailstream, user is %s\n",vmu->imapuser);
+       ast_debug(3,"Before init_mailstream, user is %s\n",vmu->imapuser);
 
        if ((ret = init_mailstream(vms, box)) || !vms->mailstream) {
                ast_log (LOG_ERROR,"Could not initialize mailstream\n");
@@ -4769,8 +4867,7 @@ static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box)
                pgm->unseen = 0;
        }
 
-       if(option_debug > 2)
-               ast_log(LOG_DEBUG,"Before mail_search_full, user is %s\n",vmu->imapuser);
+       ast_debug(3,"Before mail_search_full, user is %s\n",vmu->imapuser);
 
        vms->vmArrayIndex = 0;
        mail_search_full (vms->mailstream, NULL, pgm, NIL);
@@ -4866,6 +4963,12 @@ static int close_mailbox(struct vm_state *vms, struct ast_vm_user *vmu)
                                vms->heard[x] = 0;
                                --x;
                        } 
+               } else if (vms->deleted[x] && ast_check_realtime("voicemail_data")) {
+                       /* If realtime storage enabled - we should explicitly delete this message,
+                       cause RENAME() will overwrite files, but will keep duplicate records in RT-storage */
+                       make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
+                       if (EXISTS(vms->curdir, x, vms->fn, NULL))
+                               DELETE(vms->curdir, x, vms->fn);
                } 
        } 
 
@@ -4878,11 +4981,12 @@ static int close_mailbox(struct vm_state *vms, struct ast_vm_user *vmu)
        }
        ast_unlock_path(vms->curdir);
 #else
-       for (x=0;x < vmu->maxmsg;x++) { 
-               if (vms->deleted[x]) { 
-                       if(option_debug > 2)
-                               ast_log(LOG_DEBUG,"IMAP delete of %d\n",x);
-                       IMAP_DELETE(vms->curdir, x, vms->fn, vms);
+       if (vms->deleted) {
+               for (x=0;x < vmu->maxmsg;x++) { 
+                       if (vms->deleted[x]) { 
+                               ast_debug(3,"IMAP delete of %d\n",x);
+                               IMAP_DELETE(vms->curdir, x, vms->fn, vms);
+                       }
                }
        }
 #endif
@@ -4940,7 +5044,7 @@ static int vm_play_folder_name(struct ast_channel *chan, char *mbox)
 {
        int cmd;
 
-       if (!strcasecmp(chan->language, "it") || !strcasecmp(chan->language, "es") || !strcasecmp(chan->language, "fr") || !strcasecmp(chan->language, "pt") || !strcasecmp(chan->language, "pt_BR")) { /* Italian, Spanish, French or Portuguese syntax */
+       if (!strcasecmp(chan->language, "it") || !strcasecmp(chan->language, "es") || !strcasecmp(chan->language, "pt") || !strcasecmp(chan->language, "pt_BR")) { /* Italian, Spanish, French or Portuguese syntax */
                cmd = ast_play_and_wait(chan, "vm-messages"); /* "messages */
                return cmd ? cmd : ast_play_and_wait(chan, mbox);
        } else if (!strcasecmp(chan->language, "gr")){
@@ -5413,14 +5517,14 @@ static int vm_intro_fr(struct ast_channel *chan,struct vm_state *vms)
                }
                if (!res && vms->oldmessages) {
                        res = say_and_wait(chan, vms->oldmessages, chan->language);
+                       if (!res)
+                               res = ast_play_and_wait(chan, "vm-Old");
                        if (!res) {
                                if (vms->oldmessages == 1)
                                        res = ast_play_and_wait(chan, "vm-message");
                                else
                                        res = ast_play_and_wait(chan, "vm-messages");
                        }
-                       if (!res)
-                               res = ast_play_and_wait(chan, "vm-Old");
                }
                if (!res) {
                        if (!vms->oldmessages && !vms->newmessages) {
@@ -5824,15 +5928,18 @@ static int vm_newuser(struct ast_channel *chan, struct ast_vm_user *vmu, struct
        if ((pwdchange & PWDCHANGE_EXTERNAL) && !ast_strlen_zero(ext_pass_cmd))
                vm_change_password_shell(vmu, newpassword);
 
-       if (option_debug)
-               ast_log(LOG_DEBUG,"User %s set password to %s of length %d\n",vms->username,newpassword,(int)strlen(newpassword));
+       ast_debug(1,"User %s set password to %s of length %d\n",vms->username,newpassword,(int)strlen(newpassword));
        cmd = ast_play_and_wait(chan, vm_passchanged);
 
        /* If forcename is set, have the user record their name */      
        if (ast_test_flag(vmu, VM_FORCENAME)) {
                snprintf(prefile,sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, vmu->context, vms->username);
                if (ast_fileexists(prefile, NULL, NULL) < 1) {
+#ifndef IMAP_STORAGE
                        cmd = play_record_review(chan, "vm-rec-name", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, NULL);
+#else
+                       cmd = play_record_review(chan, "vm-rec-name", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms);
+#endif
                        if (cmd < 0 || cmd == 't' || cmd == '#')
                                return cmd;
                }
@@ -5842,14 +5949,22 @@ static int vm_newuser(struct ast_channel *chan, struct ast_vm_user *vmu, struct
        if (ast_test_flag(vmu, VM_FORCEGREET)) {
                snprintf(prefile,sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, vms->username);
                if (ast_fileexists(prefile, NULL, NULL) < 1) {
+#ifndef IMAP_STORAGE
                        cmd = play_record_review(chan, "vm-rec-unv", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, NULL);
+#else
+                       cmd = play_record_review(chan, "vm-rec-unv", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms);
+#endif
                        if (cmd < 0 || cmd == 't' || cmd == '#')
                                return cmd;
                }
 
                snprintf(prefile,sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, vms->username);
                if (ast_fileexists(prefile, NULL, NULL) < 1) {
+#ifndef IMAP_STORAGE
                        cmd = play_record_review(chan, "vm-rec-busy", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, NULL);
+#else
+                       cmd = play_record_review(chan, "vm-rec-busy", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms);
+#endif
                        if (cmd < 0 || cmd == 't' || cmd == '#')
                                return cmd;
                }
@@ -5884,15 +5999,27 @@ static int vm_options(struct ast_channel *chan, struct ast_vm_user *vmu, struct
                switch (cmd) {
                case '1':
                        snprintf(prefile,sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, vms->username);
+#ifndef IMAP_STORAGE
                        cmd = play_record_review(chan,"vm-rec-unv",prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, NULL);
+#else
+                       cmd = play_record_review(chan,"vm-rec-unv",prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms);
+#endif
                        break;
                case '2': 
                        snprintf(prefile,sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, vms->username);
+#ifndef IMAP_STORAGE
                        cmd = play_record_review(chan,"vm-rec-busy",prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, NULL);
+#else
+                       cmd = play_record_review(chan,"vm-rec-busy",prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms);
+#endif
                        break;
                case '3': 
                        snprintf(prefile,sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, vmu->context, vms->username);
+#ifndef IMAP_STORAGE
                        cmd = play_record_review(chan,"vm-rec-name",prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, NULL);
+#else
+                       cmd = play_record_review(chan,"vm-rec-name",prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms);
+#endif
                        break;
                case '4': 
                        cmd = vm_tempgreeting(chan, vmu, vms, fmtc, record_gain);
@@ -5935,8 +6062,7 @@ static int vm_options(struct ast_channel *chan, struct ast_vm_user *vmu, struct
                        if ((pwdchange & PWDCHANGE_EXTERNAL) && !ast_strlen_zero(ext_pass_cmd))
                                vm_change_password_shell(vmu, newpassword);
 
-                       if (option_debug)
-                               ast_log(LOG_DEBUG,"User %s set password to %s of length %d\n",vms->username,newpassword,(int)strlen(newpassword));
+                       ast_debug(1,"User %s set password to %s of length %d\n",vms->username,newpassword,(int)strlen(newpassword));
                        cmd = ast_play_and_wait(chan, vm_passchanged);
                        break;
                case '*': 
@@ -5978,7 +6104,7 @@ static int vm_tempgreeting(struct ast_channel *chan, struct ast_vm_user *vmu, st
        }
 
        snprintf(prefile, sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
-       if (!(res = create_dirpath(dest, sizeof(dest), vmu->context, vms->username, "temp"))) {
+       if ((res = create_dirpath(dest, sizeof(dest), vmu->context, vms->username, "temp"))) {
                ast_log(LOG_WARNING, "Failed to create directory (%s).\n", prefile);
                return -1;
        }
@@ -5987,12 +6113,20 @@ static int vm_tempgreeting(struct ast_channel *chan, struct ast_vm_user *vmu, st
                        retries = 0;
                RETRIEVE(prefile, -1);
                if (ast_fileexists(prefile, NULL, NULL) <= 0) {
+#ifndef IMAP_STORAGE
                        play_record_review(chan, "vm-rec-temp", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, NULL);
+#else
+                       play_record_review(chan, "vm-rec-temp", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms);
+#endif
                        cmd = 't';      
                } else {
                        switch (cmd) {
                        case '1':
+#ifndef IMAP_STORAGE
                                cmd = play_record_review(chan, "vm-rec-temp", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, NULL);
+#else
+                               cmd = play_record_review(chan, "vm-rec-temp", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms);
+#endif
                                break;
                        case '2':
                                DELETE(prefile, -1, prefile);
@@ -6187,8 +6321,7 @@ static int vm_authenticate(struct ast_channel *chan, char *mailbox, int mailbox_
                        ast_copy_string(mailbox, fullusername, mailbox_size);
                }
 
-               if (option_debug)
-                       ast_log(LOG_DEBUG, "Before find user for mailbox %s\n",mailbox);
+               ast_debug(1, "Before find user for mailbox %s\n",mailbox);
                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 */
@@ -6280,8 +6413,7 @@ static int vm_execmain(struct ast_channel *chan, void *data)
        memset(&vmus, 0, sizeof(vmus));
 
        if (chan->_state != AST_STATE_UP) {
-               if (option_debug)
-                       ast_log(LOG_DEBUG, "Before ast_answer\n");
+               ast_debug(1, "Before ast_answer\n");
                ast_answer(chan);
        }
 
@@ -6363,8 +6495,7 @@ static int vm_execmain(struct ast_channel *chan, void *data)
        if (!valid)
                res = vm_authenticate(chan, vms.username, sizeof(vms.username), &vmus, context, prefixstr, skipuser, maxlogins, 0);
 
-       if (option_debug)
-               ast_log(LOG_DEBUG, "After vm_authenticate\n");
+       ast_debug(1, "After vm_authenticate\n");
        if (!res) {
                valid = 1;
                if (!skipuser)
@@ -6399,21 +6530,18 @@ static int vm_execmain(struct ast_channel *chan, void *data)
        create_dirpath(vms.curdir, sizeof(vms.curdir), vmu->context, vms.username, "");
 #endif
        /* Retrieve old and new message counts */
-       if (option_debug)
-               ast_log(LOG_DEBUG, "Before open_mailbox\n");
+       ast_debug(1, "Before open_mailbox\n");
        res = open_mailbox(&vms, vmu, 1);
        if (res == ERROR_LOCK_PATH)
                goto out;
        vms.oldmessages = vms.lastmsg + 1;
-       if (option_debug)
-               ast_log(LOG_DEBUG, "Number of old messages: %d\n",vms.oldmessages);
+       ast_debug(1, "Number of old messages: %d\n",vms.oldmessages);
        /* Start in INBOX */
        res = open_mailbox(&vms, vmu, 0);
        if (res == ERROR_LOCK_PATH)
                goto out;
        vms.newmessages = vms.lastmsg + 1;
-       if (option_debug)
-               ast_log(LOG_DEBUG, "Number of new messages: %d\n",vms.newmessages);
+       ast_debug(1, "Number of new messages: %d\n",vms.newmessages);
                
        /* Select proper mailbox FIRST!! */
        if (play_auto) {
@@ -6457,11 +6585,9 @@ static int vm_execmain(struct ast_channel *chan, void *data)
                }
        }
 #ifdef IMAP_STORAGE
-               if(option_debug > 2)
-                       ast_log(LOG_DEBUG, "Checking quotas: comparing %u to %u\n",vms.quota_usage,vms.quota_limit);
+               ast_debug(3, "Checking quotas: comparing %u to %u\n",vms.quota_usage,vms.quota_limit);
                if (vms.quota_limit && vms.quota_usage >= vms.quota_limit) {
-                       if (option_debug)
-                               ast_log(LOG_DEBUG, "*** QUOTA EXCEEDED!!\n");
+                       ast_debug(1, "*** QUOTA EXCEEDED!!\n");
                        cmd = ast_play_and_wait(chan, "vm-mailboxfull");
                }
 #endif
@@ -6612,7 +6738,7 @@ static int vm_execmain(struct ast_channel *chan, void *data)
                        }
                        break;
                case '4':
-                       if (vms.curmsg) {
+                       if (vms.curmsg > 0) {
                                vms.curmsg--;
                                cmd = play_message(chan, vmu, &vms);
                        } else {
@@ -6628,21 +6754,24 @@ static int vm_execmain(struct ast_channel *chan, void *data)
                        }
                        break;
                case '7':
-                       vms.deleted[vms.curmsg] = !vms.deleted[vms.curmsg];
-                       if (useadsi)
-                               adsi_delete(chan, &vms);
-                       if (vms.deleted[vms.curmsg]) 
-                               cmd = ast_play_and_wait(chan, "vm-deleted");
-                       else
-                               cmd = ast_play_and_wait(chan, "vm-undeleted");
-                       if (ast_test_flag((&globalflags), VM_SKIPAFTERCMD)) {
-                               if (vms.curmsg < vms.lastmsg) {
-                                       vms.curmsg++;
-                                       cmd = play_message(chan, vmu, &vms);
-                               } else {
-                                       cmd = ast_play_and_wait(chan, "vm-nomore");
+                       if (vms.curmsg >= 0 && vms.curmsg <= vms.lastmsg) {
+                               vms.deleted[vms.curmsg] = !vms.deleted[vms.curmsg];
+                               if (useadsi)
+                                       adsi_delete(chan, &vms);
+                               if (vms.deleted[vms.curmsg]) 
+                                       cmd = ast_play_and_wait(chan, "vm-deleted");
+                               else
+                                       cmd = ast_play_and_wait(chan, "vm-undeleted");
+                               if (ast_test_flag((&globalflags), VM_SKIPAFTERCMD)) {
+                                       if (vms.curmsg < vms.lastmsg) {
+                                               vms.curmsg++;
+                                               cmd = play_message(chan, vmu, &vms);
+                                       } else {
+                                               cmd = ast_play_and_wait(chan, "vm-nomore");
+                                       }
                                }
-                       }
+                       } else /* Delete not valid if we haven't selected a message */
+                               cmd = 0;
 #ifdef IMAP_STORAGE
                        deleted = 1;
 #endif
@@ -6755,14 +6884,16 @@ out:
        if (vmu)
                close_mailbox(&vms, vmu);
        if (valid) {
+               int new = 0, old = 0;
                snprintf(ext_context, sizeof(ext_context), "%s@%s", vms.username, vmu->context);
                manager_event(EVENT_FLAG_CALL, "MessageWaiting", "Mailbox: %s\r\nWaiting: %d\r\n", ext_context, has_voicemail(ext_context, NULL));
                run_externnotify(vmu->context, vmu->mailbox);
+               ast_app_inboxcount(ext_context, &new, &old);
+               queue_mwi_event(ext_context, new, old);
        }
 #ifdef IMAP_STORAGE
        /* expunge message - use UID Expunge if supported on IMAP server*/
-       if(option_debug > 2)
-               ast_log(LOG_DEBUG, "*** Checking if we can expunge, deleted set to %d, expungeonhangup set to %d\n",deleted,expungeonhangup);
+       ast_debug(3, "*** Checking if we can expunge, deleted set to %d, expungeonhangup set to %d\n",deleted,expungeonhangup);
        if (vmu && deleted == 1 && expungeonhangup == 1) {
 #ifdef HAVE_IMAP_TK2006
                if (LEVELUIDPLUS (vms.mailstream)) {
@@ -6814,7 +6945,7 @@ static int vm_exec(struct ast_channel *chan, void *data)
                                ast_module_user_remove(u);
                                return -1;
                        }
-                       ast_copy_flags(&leave_options, &flags, OPT_SILENT | OPT_BUSY_GREETING | OPT_UNAVAIL_GREETING | OPT_PRIORITY_JUMP);
+                       ast_copy_flags(&leave_options, &flags, OPT_SILENT | OPT_BUSY_GREETING | OPT_UNAVAIL_GREETING);
                        if (ast_test_flag(&flags, OPT_RECORDGAIN)) {
                                int gain;
 
@@ -6845,10 +6976,6 @@ static int vm_exec(struct ast_channel *chan, void *data)
 
        if (res == ERROR_LOCK_PATH) {
                ast_log(LOG_ERROR, "Could not leave voicemail. The path is already locked.\n");
-               /*Send the call to n+101 priority, where n is the current priority*/
-               if (ast_test_flag(&leave_options, OPT_PRIORITY_JUMP) || ast_opt_priority_jumping)
-                       if (ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101))
-                               ast_log(LOG_WARNING, "Extension %s, priority %d doesn't exist.\n", chan->exten, chan->priority + 101);
                pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
                res = 0;
        }
@@ -6861,20 +6988,25 @@ static int vm_exec(struct ast_channel *chan, void *data)
 static struct ast_vm_user *find_or_create(char *context, char *mbox)
 {
        struct ast_vm_user *vmu;
+
        AST_LIST_TRAVERSE(&users, vmu, list) {
                if (ast_test_flag((&globalflags), VM_SEARCH) && !strcasecmp(mbox, vmu->mailbox))
                        break;
                if (context && (!strcasecmp(context, vmu->context)) && (!strcasecmp(mbox, vmu->mailbox)))
                        break;
        }
+
+       if (vmu)
+               return vmu;
+       
+       if (!(vmu = ast_calloc(1, sizeof(*vmu))))
+               return NULL;
+       
+       ast_copy_string(vmu->context, context, sizeof(vmu->context));
+       ast_copy_string(vmu->mailbox, mbox, sizeof(vmu->mailbox));
+
+       AST_LIST_INSERT_TAIL(&users, vmu, list);
        
-       if (!vmu) {
-               if ((vmu = ast_calloc(1, sizeof(*vmu)))) {
-                       ast_copy_string(vmu->context, context, sizeof(vmu->context));
-                       ast_copy_string(vmu->mailbox, mbox, sizeof(vmu->mailbox));
-                       AST_LIST_INSERT_TAIL(&users, vmu, list);
-               }
-       }
        return vmu;
 }
 
@@ -6885,24 +7017,36 @@ static int append_mailbox(char *context, char *mbox, char *data)
        char *stringp;
        char *s;
        struct ast_vm_user *vmu;
+       char *mailbox_full;
+       int new = 0, old = 0;
 
        tmp = ast_strdupa(data);
 
-       if ((vmu = find_or_create(context, mbox))) {
-               populate_defaults(vmu);
-
-               stringp = tmp;
-               if ((s = strsep(&stringp, ","))) 
-                       ast_copy_string(vmu->password, s, sizeof(vmu->password));
-               if (stringp && (s = strsep(&stringp, ","))) 
-                       ast_copy_string(vmu->fullname, s, sizeof(vmu->fullname));
-               if (stringp && (s = strsep(&stringp, ","))) 
-                       ast_copy_string(vmu->email, s, sizeof(vmu->email));
-               if (stringp && (s = strsep(&stringp, ","))) 
-                       ast_copy_string(vmu->pager, s, sizeof(vmu->pager));
-               if (stringp && (s = strsep(&stringp, ","))) 
-                       apply_options(vmu, s);
-       }
+       if (!(vmu = find_or_create(context, mbox)))
+               return -1;
+       
+       populate_defaults(vmu);
+
+       stringp = tmp;
+       if ((s = strsep(&stringp, ","))) 
+               ast_copy_string(vmu->password, s, sizeof(vmu->password));
+       if (stringp && (s = strsep(&stringp, ","))) 
+               ast_copy_string(vmu->fullname, s, sizeof(vmu->fullname));
+       if (stringp && (s = strsep(&stringp, ","))) 
+               ast_copy_string(vmu->email, s, sizeof(vmu->email));
+       if (stringp && (s = strsep(&stringp, ","))) 
+               ast_copy_string(vmu->pager, s, sizeof(vmu->pager));
+       if (stringp && (s = strsep(&stringp, ","))) 
+               apply_options(vmu, s);
+
+       mailbox_full = alloca(strlen(mbox) + strlen(context) + 1);
+       strcpy(mailbox_full, mbox);
+       strcat(mailbox_full, "@");
+       strcat(mailbox_full, context);
+
+       inboxcount(mailbox_full, &new, &old);
+       queue_mwi_event(mailbox_full, new, old);
+
        return 0;
 }
 
@@ -6911,7 +7055,6 @@ static int vm_box_exists(struct ast_channel *chan, void *data)
        struct ast_module_user *u;
        struct ast_vm_user svm;
        char *context, *box;
-       int priority_jump = 0;
        AST_DECLARE_APP_ARGS(args,
                AST_APP_ARG(mbox);
                AST_APP_ARG(options);
@@ -6935,8 +7078,6 @@ static int vm_box_exists(struct ast_channel *chan, void *data)
        AST_STANDARD_APP_ARGS(args, box);
 
        if (args.options) {
-               if (strchr(args.options, 'j'))
-                       priority_jump = 1;
        }
 
        if ((context = strchr(args.mbox, '@'))) {
@@ -6946,9 +7087,6 @@ static int vm_box_exists(struct ast_channel *chan, void *data)
 
        if (find_user(&svm, context, args.mbox)) {
                pbx_builtin_setvar_helper(chan, "VMBOXEXISTSSTATUS", "SUCCESS");
-               if (priority_jump || ast_opt_priority_jumping)
-                       if (ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101)) 
-                               ast_log(LOG_WARNING, "VM box %s@%s exists, but extension %s, priority %d doesn't exist\n", box, context, chan->exten, chan->priority + 101);
        } else
                pbx_builtin_setvar_helper(chan, "VMBOXEXISTSSTATUS", "FAILED");
        ast_module_user_remove(u);
@@ -7027,16 +7165,61 @@ static const char voicemail_show_zones_help[] =
 "Usage: voicemail show zones\n"
 "       Lists zone message formats\n";
 
+static int show_users_realtime(int fd, const char *context)
+{
+       struct ast_config *cfg;
+       const char *cat = NULL;
+
+       if (!(cfg = ast_load_realtime_multientry("voicemail", 
+               "context", context, NULL))) {
+               return RESULT_FAILURE;
+       }
+
+       ast_cli(fd, "\n"
+                   "=============================================================\n"
+                   "=== Configured Voicemail Users ==============================\n"
+                   "=============================================================\n"
+                   "===\n");
+
+       while ((cat = ast_category_browse(cfg, cat))) {
+               struct ast_variable *var = NULL;
+               ast_cli(fd, "=== Mailbox ...\n"
+                           "===\n");
+               for (var = ast_variable_browse(cfg, cat); var; var = var->next)
+                       ast_cli(fd, "=== ==> %s: %s\n", var->name, var->value);
+               ast_cli(fd, "===\n"
+                           "=== ---------------------------------------------------------\n"
+                           "===\n");
+       }
+
+       ast_cli(fd, "=============================================================\n"
+                   "\n");
+
+       return RESULT_SUCCESS;
+}
+
 /*! \brief Show a list of voicemail users in the CLI */
 static int handle_voicemail_show_users(int fd, int argc, char *argv[])
 {
        struct ast_vm_user *vmu;
        char *output_format = "%-10s %-5s %-25s %-10s %6s\n";
+       const char *context = NULL;
 
        if ((argc < 3) || (argc > 5) || (argc == 4))
                return RESULT_SHOWUSAGE;
-       if ((argc == 5) && strcmp(argv[3],"for"))
-               return RESULT_SHOWUSAGE;
+       if (argc == 5) {
+               if (strcmp(argv[3],"for"))
+                       return RESULT_SHOWUSAGE;
+               context = argv[4];
+       }
+
+       if (ast_check_realtime("voicemail")) {
+               if (!context) {
+                       ast_cli(fd, "You must specify a specific context to show users from realtime!\n");
+                       return RESULT_SHOWUSAGE;
+               }
+               return show_users_realtime(fd, context);
+       }
 
        AST_LIST_LOCK(&users);
        if (AST_LIST_EMPTY(&users)) {
@@ -7049,13 +7232,13 @@ static int handle_voicemail_show_users(int fd, int argc, char *argv[])
        else {
                int count = 0;
                AST_LIST_TRAVERSE(&users, vmu, list) {
-                       if (!strcmp(argv[4],vmu->context))
+                       if (!strcmp(context, vmu->context))
                                count++;
                }
                if (count) {
                        ast_cli(fd, output_format, "Context", "Mbox", "User", "Zone", "NewMsg");
                } else {
-                       ast_cli(fd, "No such voicemail context \"%s\"\n", argv[4]);
+                       ast_cli(fd, "No such voicemail context \"%s\"\n", context);
                        AST_LIST_UNLOCK(&users);
                        return RESULT_FAILURE;
                }
@@ -7064,7 +7247,7 @@ static int handle_voicemail_show_users(int fd, int argc, char *argv[])
                int newmsgs = 0, oldmsgs = 0;
                char count[12], tmp[256] = "";
 
-               if ((argc == 3) || ((argc == 5) && !strcmp(argv[4],vmu->context))) {
+               if ((argc == 3) || ((argc == 5) && !strcmp(context, vmu->context))) {
                        snprintf(tmp, sizeof(tmp), "%s@%s", vmu->mailbox, ast_strlen_zero(vmu->context) ? "default" : vmu->context);
                        inboxcount(tmp, &newmsgs, &oldmsgs);
                        snprintf(count,sizeof(count),"%d",newmsgs);
@@ -7134,6 +7317,227 @@ static struct ast_cli_entry cli_voicemail[] = {
        voicemail_show_zones_help, NULL, NULL },
 };
 
+static void poll_subscribed_mailboxes(void)
+{
+       struct mwi_sub *mwi_sub;
+
+       AST_RWLIST_RDLOCK(&mwi_subs);
+       AST_RWLIST_TRAVERSE(&mwi_subs, mwi_sub, entry) {
+               int new = 0, old = 0;
+
+               if (ast_strlen_zero(mwi_sub->mailbox))
+                       continue;
+
+               inboxcount(mwi_sub->mailbox, &new, &old);
+
+               if (new != mwi_sub->old_new || old != mwi_sub->old_old) {
+                       mwi_sub->old_new = new;
+                       mwi_sub->old_old = old;
+                       queue_mwi_event(mwi_sub->mailbox, new, old);
+               }
+       }
+       AST_RWLIST_UNLOCK(&mwi_subs);
+}
+
+static void *mb_poll_thread(void *data)
+{
+       while (poll_thread_run) {
+               struct timespec ts = { 0, };
+               struct timeval tv;
+
+               tv = ast_tvadd(ast_tvnow(), ast_samp2tv(poll_freq, 1));
+               ts.tv_sec = tv.tv_sec;
+               ts.tv_nsec = tv.tv_usec * 1000;
+
+               ast_mutex_lock(&poll_lock);
+               ast_cond_timedwait(&poll_cond, &poll_lock, &ts);
+               ast_mutex_unlock(&poll_lock);
+
+               if (!poll_thread_run)
+                       break;
+
+               poll_subscribed_mailboxes();
+       }
+
+       return NULL;
+}
+
+static void mwi_sub_destroy(struct mwi_sub *mwi_sub)
+{
+       free(mwi_sub);
+}
+
+static void mwi_unsub_event_cb(const struct ast_event *event, void *userdata)
+{
+       uint32_t uniqueid;
+       struct mwi_sub *mwi_sub;
+
+       if (ast_event_get_type(event) != AST_EVENT_UNSUB)
+               return;
+
+       if (ast_event_get_ie_uint(event, AST_EVENT_IE_EVENTTYPE) != AST_EVENT_MWI)
+               return;
+
+       uniqueid = ast_event_get_ie_uint(event, AST_EVENT_IE_UNIQUEID);
+
+       AST_RWLIST_WRLOCK(&mwi_subs);
+       AST_RWLIST_TRAVERSE_SAFE_BEGIN(&mwi_subs, mwi_sub, entry) {
+               if (mwi_sub->uniqueid == uniqueid) {
+                       AST_LIST_REMOVE_CURRENT(&mwi_subs, entry);
+                       break;
+               }
+       }
+       AST_RWLIST_TRAVERSE_SAFE_END
+       AST_RWLIST_UNLOCK(&mwi_subs);
+
+       if (mwi_sub)
+               mwi_sub_destroy(mwi_sub);
+}
+
+static void mwi_sub_event_cb(const struct ast_event *event, void *userdata)
+{
+       const char *mailbox;
+       uint32_t uniqueid;
+       unsigned int len;
+       struct mwi_sub *mwi_sub;
+
+       if (ast_event_get_type(event) != AST_EVENT_SUB)
+               return;
+
+       if (ast_event_get_ie_uint(event, AST_EVENT_IE_EVENTTYPE) != AST_EVENT_MWI)
+               return;
+
+       mailbox = ast_event_get_ie_str(event, AST_EVENT_IE_MAILBOX);
+       uniqueid = ast_event_get_ie_uint(event, AST_EVENT_IE_UNIQUEID);
+
+       len = sizeof(*mwi_sub);
+       if (!ast_strlen_zero(mailbox))
+               len += strlen(mailbox);
+
+       if (!(mwi_sub = ast_calloc(1, len)))
+               return;
+
+       mwi_sub->uniqueid = uniqueid;
+       if (!ast_strlen_zero(mailbox))
+               strcpy(mwi_sub->mailbox, mailbox);
+
+       AST_RWLIST_WRLOCK(&mwi_subs);
+       AST_RWLIST_INSERT_TAIL(&mwi_subs, mwi_sub, entry);
+       AST_RWLIST_UNLOCK(&mwi_subs);
+}
+
+static void start_poll_thread(void)
+{
+       pthread_attr_t attr;
+
+       mwi_sub_sub = ast_event_subscribe(AST_EVENT_SUB, mwi_sub_event_cb, NULL,
+               AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, AST_EVENT_MWI,
+               AST_EVENT_IE_END);
+
+       mwi_unsub_sub = ast_event_subscribe(AST_EVENT_UNSUB, mwi_unsub_event_cb, NULL,
+               AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, AST_EVENT_MWI,
+               AST_EVENT_IE_END);
+
+       if (mwi_sub_sub)
+               ast_event_report_subs(mwi_sub_sub);
+
+       poll_thread_run = 1;
+
+       pthread_attr_init(&attr);
+       ast_pthread_create(&poll_thread, &attr, mb_poll_thread, NULL);
+       pthread_attr_destroy(&attr);
+}
+
+static void stop_poll_thread(void)
+{
+       poll_thread_run = 0;
+
+       if (mwi_sub_sub) {
+               ast_event_unsubscribe(mwi_sub_sub);
+               mwi_sub_sub = NULL;
+       }
+
+       if (mwi_unsub_sub) {
+               ast_event_unsubscribe(mwi_unsub_sub);
+               mwi_unsub_sub = NULL;
+       }
+
+       ast_mutex_lock(&poll_lock);
+       ast_cond_signal(&poll_cond);
+       ast_mutex_unlock(&poll_lock);
+
+       pthread_join(poll_thread, NULL);
+
+       poll_thread = AST_PTHREADT_NULL;
+}
+
+/*! \brief Manager list voicemail users command */
+static int manager_list_voicemail_users(struct mansession *s, const struct message *m)
+{
+       struct ast_vm_user *vmu = NULL;
+       const char *id = astman_get_header(m, "ActionID");
+       char actionid[128] = "";
+
+       if (!ast_strlen_zero(id))
+               snprintf(actionid, sizeof(actionid), "ActionID: %s\r\n", id);
+
+       AST_LIST_LOCK(&users);
+
+       if (AST_LIST_EMPTY(&users)) {
+               astman_send_ack(s, m, "There are no voicemail users currently defined.");
+               AST_LIST_UNLOCK(&users);
+               return RESULT_SUCCESS;
+       }
+       
+       astman_send_ack(s, m, "Voicemail user list will follow\r\n");
+       
+       AST_LIST_TRAVERSE(&users, vmu, list) {
+               char dirname[256];
+               
+               make_dir(dirname, sizeof(dirname), vmu->context, vmu->mailbox, "INBOX");
+               astman_append(s,
+                             "%s"
+                             "Event: VoicemailUserEntry\r\n"
+                             "VMContext: %s\r\n"
+                             "VoiceMailbox: %s\r\n"
+                             "Fullname: %s\r\n"
+                             "Email: %s\r\n"
+                             "Pager: %s\r\n"
+                             "ServerEmail: %s\r\n"
+                             "MailCommand: %s\r\n"
+                             "Language: %s\r\n"
+                             "TimeZone: %s\r\n"
+                             "Callback: %s\r\n"
+                             "Dialout: %s\r\n"
+                             "UniqueID: %s\r\n"
+                             "ExitContext: %s\r\n"
+                             "SayDurationMinimum: %d\r\n"
+                             "AttachmentFormat: %s\r\n"
+                             "VolumeGain: %.2lf\r\n"
+                             "MaxMessageCount: %d\r\n"
+                             "MaxMessageLength: %d\r\n"
+                             "NewMessageCount: %d\r\n"
+#ifdef IMAP_STORAGE
+                             "IMAPUser: %s\r\n"
+#endif
+                             "\r\n",
+                             actionid, vmu->context, vmu->mailbox, vmu->fullname, vmu->email,
+                             vmu->pager, vmu->serveremail, vmu->mailcmd, vmu->language,
+                             vmu->zonetag, vmu->callback, vmu->dialout, vmu->uniqueid,
+                             vmu->exit, vmu->saydurationm, vmu->attachfmt, vmu->volgain,
+                             vmu->maxmsg, vmu->maxsecs, count_messages(vmu, dirname)
+#ifdef IMAP_STORAGE
+                             , vmu->imapuser
+#endif
+                       );
+       }               
+       astman_append(s, "Event: VoicemailUserEntryComplete\r\n%s\r\n", actionid);
+
+       AST_LIST_UNLOCK(&users);
+
+       return RESULT_SUCCESS;
+}
+
 static int load_config(void)
 {
        struct ast_vm_user *cur;
@@ -7141,51 +7545,9 @@ static int load_config(void)
        struct ast_config *cfg, *ucfg;
        char *cat;
        struct ast_variable *var;
-       const char *notifystr = NULL;
-       const char *smdistr = NULL;
-       const char *astattach;
-       const char *astsearch;
-       const char *astsaycid;
-       const char *send_voicemail;
-#ifdef IMAP_STORAGE
-       const char *imap_server;
-       const char *imap_port;
-       const char *imap_flags;
-       const char *imap_folder;
-       const char *auth_user;
-       const char *auth_password;
-       const char *expunge_on_hangup;
-#endif
-       const char *astcallop;
-       const char *astreview;
-       const char *asttempgreetwarn;
-       const char *astskipcmd;
-       const char *asthearenv;
-       const char *astsaydurationinfo;
-       const char *astsaydurationminfo;
-       const char *silencestr;
-       const char *maxmsgstr;
-       const char *astdirfwd;
-       const char *thresholdstr;
-       const char *fmt;
-       const char *astemail;
-       const char *ucontext;
-       const char *astmailcmd = SENDMAIL;
-       const char *astforcename;
-       const char *astforcegreet;
+       const char *val;
        const char *s;
-       char *q,*stringp;
-       const char *dialoutcxt = NULL;
-       const char *callbackcxt = NULL; 
-       const char *exitcxt = NULL;     
-       const char *extpc;
-       const char *emaildateformatstr;
-       const char *volgainstr;
-       const char *vm_paswd;
-       const char *vm_newpasswd;
-       const char *vm_passchange;
-       const char *vm_reenterpass;
-       const char *vm_mism;
+       char *q, *stringp;
        int x;
        int tmpadsi[4];
 
@@ -7207,99 +7569,99 @@ static int load_config(void)
        if (cfg) {
                /* General settings */
 
-               if (!(ucontext = ast_variable_retrieve(cfg, "general", "userscontext")))
-                       ucontext = "default";
-               ast_copy_string(userscontext, ucontext, sizeof(userscontext));
+               if (!(val = ast_variable_retrieve(cfg, "general", "userscontext")))
+                       val = "default";
+               ast_copy_string(userscontext, val, sizeof(userscontext));
                /* Attach voice message to mail message ? */
-               if (!(astattach = ast_variable_retrieve(cfg, "general", "attach"))) 
-                       astattach = "yes";
-               ast_set2_flag((&globalflags), ast_true(astattach), VM_ATTACH);  
+               if (!(val = ast_variable_retrieve(cfg, "general", "attach"))) 
+                       val = "yes";
+               ast_set2_flag((&globalflags), ast_true(val), VM_ATTACH);        
 
-               if (!(astsearch = ast_variable_retrieve(cfg, "general", "searchcontexts")))
-                       astsearch = "no";
-               ast_set2_flag((&globalflags), ast_true(astsearch), VM_SEARCH);
+               if (!(val = ast_variable_retrieve(cfg, "general", "searchcontexts")))
+                       val = "no";
+               ast_set2_flag((&globalflags), ast_true(val), VM_SEARCH);
 
                volgain = 0.0;
-               if ((volgainstr = ast_variable_retrieve(cfg, "general", "volgain")))
-                       sscanf(volgainstr, "%lf", &volgain);
+               if ((val = ast_variable_retrieve(cfg, "general", "volgain")))
+                       sscanf(val, "%lf", &volgain);
 
 #ifdef ODBC_STORAGE
                strcpy(odbc_database, "asterisk");
-               if ((thresholdstr = ast_variable_retrieve(cfg, "general", "odbcstorage"))) {
-                       ast_copy_string(odbc_database, thresholdstr, sizeof(odbc_database));
+               if ((val = ast_variable_retrieve(cfg, "general", "odbcstorage"))) {
+                       ast_copy_string(odbc_database, val, sizeof(odbc_database));
                }
                strcpy(odbc_table, "voicemessages");
-               if ((thresholdstr = ast_variable_retrieve(cfg, "general", "odbctable"))) {
-                       ast_copy_string(odbc_table, thresholdstr, sizeof(odbc_table));
+               if ((val = ast_variable_retrieve(cfg, "general", "odbctable"))) {
+                       ast_copy_string(odbc_table, val, sizeof(odbc_table));
                }
 #endif         
                /* Mail command */
                strcpy(mailcmd, SENDMAIL);
-               if ((astmailcmd = ast_variable_retrieve(cfg, "general", "mailcmd")))
-                       ast_copy_string(mailcmd, astmailcmd, sizeof(mailcmd)); /* User setting */
+               if ((val = ast_variable_retrieve(cfg, "general", "mailcmd")))
+                       ast_copy_string(mailcmd, val, sizeof(mailcmd)); /* User setting */
 
                maxsilence = 0;
-               if ((silencestr = ast_variable_retrieve(cfg, "general", "maxsilence"))) {
-                       maxsilence = atoi(silencestr);
+               if ((val = ast_variable_retrieve(cfg, "general", "maxsilence"))) {
+                       maxsilence = atoi(val);
                        if (maxsilence > 0)
                                maxsilence *= 1000;
                }
                
-               if (!(maxmsgstr = ast_variable_retrieve(cfg, "general", "maxmsg"))) {
+               if (!(val = ast_variable_retrieve(cfg, "general", "maxmsg"))) {
                        maxmsg = MAXMSG;
                } else {
-                       maxmsg = atoi(maxmsgstr);
+                       maxmsg = atoi(val);
                        if (maxmsg <= 0) {
-                               ast_log(LOG_WARNING, "Invalid number of messages per folder '%s'. Using default value %i\n", maxmsgstr, MAXMSG);
+                               ast_log(LOG_WARNING, "Invalid number of messages per folder '%s'. Using default value %i\n", val, MAXMSG);
                                maxmsg = MAXMSG;
                        } else if (maxmsg > MAXMSGLIMIT) {
-                               ast_log(LOG_WARNING, "Maximum number of messages per folder is %i. Cannot accept value '%s'\n", MAXMSGLIMIT, maxmsgstr);
+                               ast_log(LOG_WARNING, "Maximum number of messages per folder is %i. Cannot accept value '%s'\n", MAXMSGLIMIT, val);
                                maxmsg = MAXMSGLIMIT;
                        }
                }
 
                /* Load date format config for voicemail mail */
-               if ((emaildateformatstr = ast_variable_retrieve(cfg, "general", "emaildateformat"))) {
-                       ast_copy_string(emaildateformat, emaildateformatstr, sizeof(emaildateformat));
+               if ((val = ast_variable_retrieve(cfg, "general", "emaildateformat"))) {
+                       ast_copy_string(emaildateformat, val, sizeof(emaildateformat));
                }
 
                /* External password changing command */
-               if ((extpc = ast_variable_retrieve(cfg, "general", "externpass"))) {
-                       ast_copy_string(ext_pass_cmd,extpc,sizeof(ext_pass_cmd));
+               if ((val = ast_variable_retrieve(cfg, "general", "externpass"))) {
+                       ast_copy_string(ext_pass_cmd,val,sizeof(ext_pass_cmd));
                        pwdchange = PWDCHANGE_EXTERNAL;
-               } else if ((extpc = ast_variable_retrieve(cfg, "general", "externpassnotify"))) {
-                       ast_copy_string(ext_pass_cmd,extpc,sizeof(ext_pass_cmd));
+               } else if ((val = ast_variable_retrieve(cfg, "general", "externpassnotify"))) {
+                       ast_copy_string(ext_pass_cmd,val,sizeof(ext_pass_cmd));
                        pwdchange = PWDCHANGE_EXTERNAL | PWDCHANGE_INTERNAL;
                }
 
 #ifdef IMAP_STORAGE
                /* IMAP server address */
-               if ((imap_server = ast_variable_retrieve(cfg, "general", "imapserver"))) {
-                       ast_copy_string(imapserver, imap_server, sizeof(imapserver));
+               if ((val = ast_variable_retrieve(cfg, "general", "imapserver"))) {
+                       ast_copy_string(imapserver, val, sizeof(imapserver));
                } else {
                        ast_copy_string(imapserver,"localhost", sizeof(imapserver));
                }
                /* IMAP server port */
-               if ((imap_port = ast_variable_retrieve(cfg, "general", "imapport"))) {
-                       ast_copy_string(imapport, imap_port, sizeof(imapport));
+               if ((val = ast_variable_retrieve(cfg, "general", "imapport"))) {
+                       ast_copy_string(imapport, val, sizeof(imapport));
                } else {
                        ast_copy_string(imapport,"143", sizeof(imapport));
                }
                /* IMAP server flags */
-               if ((imap_flags = ast_variable_retrieve(cfg, "general", "imapflags"))) {
-                       ast_copy_string(imapflags, imap_flags, sizeof(imapflags));
+               if ((val = ast_variable_retrieve(cfg, "general", "imapflags"))) {
+                       ast_copy_string(imapflags, val, sizeof(imapflags));
                }
                /* IMAP server master username */
-               if ((auth_user = ast_variable_retrieve(cfg, "general", "authuser"))) {
-                       ast_copy_string(authuser, auth_user, sizeof(authuser));
+               if ((val = ast_variable_retrieve(cfg, "general", "authuser"))) {
+                       ast_copy_string(authuser, val, sizeof(authuser));
                }
                /* IMAP server master password */
-               if ((auth_password = ast_variable_retrieve(cfg, "general", "authpassword"))) {
-                       ast_copy_string(authpassword, auth_password, sizeof(authpassword));
+               if ((val = ast_variable_retrieve(cfg, "general", "authpassword"))) {
+                       ast_copy_string(authpassword, val, sizeof(authpassword));
                }
                /* Expunge on exit */
-               if ((expunge_on_hangup = ast_variable_retrieve(cfg, "general", "expungeonhangup"))) {
-                       if(ast_false(expunge_on_hangup))
+               if ((val = ast_variable_retrieve(cfg, "general", "expungeonhangup"))) {
+                       if(ast_false(val))
                                expungeonhangup = 0;
                        else
                                expungeonhangup = 1;
@@ -7307,48 +7669,44 @@ static int load_config(void)
                        expungeonhangup = 1;
                }
                /* IMAP voicemail folder */
-               if ((imap_folder = ast_variable_retrieve(cfg, "general", "imapfolder"))) {
-                       ast_copy_string(imapfolder, imap_folder, sizeof(imapfolder));
+               if ((val = ast_variable_retrieve(cfg, "general", "imapfolder"))) {
+                       ast_copy_string(imapfolder, val, sizeof(imapfolder));
                } else {
                        ast_copy_string(imapfolder,"INBOX", sizeof(imapfolder));
                }
 #endif
                /* External voicemail notify application */
-               if ((notifystr = ast_variable_retrieve(cfg, "general", "externnotify"))) {
-                       ast_copy_string(externnotify, notifystr, sizeof(externnotify));
-                       if (option_debug)
-                               ast_log(LOG_DEBUG, "found externnotify: %s\n", externnotify);
+               if ((val = ast_variable_retrieve(cfg, "general", "externnotify"))) {
+                       ast_copy_string(externnotify, val, sizeof(externnotify));
+                       ast_debug(1, "found externnotify: %s\n", externnotify);
                } else {
                        externnotify[0] = '\0';
                }
 
                /* SMDI voicemail notification */
                if ((s = ast_variable_retrieve(cfg, "general", "smdienable")) && ast_true(s)) {
-                       if (option_debug)
-                               ast_log(LOG_DEBUG, "Enabled SMDI voicemail notification\n");
-                       if ((smdistr = ast_variable_retrieve(cfg, "general", "smdiport"))) {
-                               smdi_iface = ast_smdi_interface_find(smdistr);
+                       ast_debug(1, "Enabled SMDI voicemail notification\n");
+                       if ((val = ast_variable_retrieve(cfg, "general", "smdiport"))) {
+                               smdi_iface = ast_smdi_interface_find(val);
                        } else {
-                               if (option_debug)
-                                       ast_log(LOG_DEBUG, "No SMDI interface set, trying default (/dev/ttyS0)\n");
+                               ast_debug(1, "No SMDI interface set, trying default (/dev/ttyS0)\n");
                                smdi_iface = ast_smdi_interface_find("/dev/ttyS0");
                        }
                        if (!smdi_iface) {
                                ast_log(LOG_ERROR, "No valid SMDI interface specfied, disabling SMDI voicemail notification\n");
                        } else {
-                               if (option_debug)
-                                       ast_log(LOG_DEBUG, "Using SMDI port %s\n", smdi_iface->name);
+                               ast_debug(1, "Using SMDI port %s\n", smdi_iface->name);
                        }
                }
 
                /* Silence treshold */
                silencethreshold = 256;
-               if ((thresholdstr = ast_variable_retrieve(cfg, "general", "silencethreshold")))
-                       silencethreshold = atoi(thresholdstr);
+               if ((val = ast_variable_retrieve(cfg, "general", "silencethreshold")))
+                       silencethreshold = atoi(val);
                
-               if (!(astemail = ast_variable_retrieve(cfg, "general", "serveremail"))) 
-                       astemail = ASTERISK_USERNAME;
-               ast_copy_string(serveremail, astemail, sizeof(serveremail));
+               if (!(val = ast_variable_retrieve(cfg, "general", "serveremail"))) 
+                       val = ASTERISK_USERNAME;
+               ast_copy_string(serveremail, val, sizeof(serveremail));
                
                vmmaxsecs = 0;
                if ((s = ast_variable_retrieve(cfg, "general", "maxsecs"))) {
@@ -7394,10 +7752,10 @@ static int load_config(void)
                        }
                }
 
-               fmt = ast_variable_retrieve(cfg, "general", "format");
-               if (!fmt)
-                       fmt = "wav";    
-               ast_copy_string(vmfmts, fmt, sizeof(vmfmts));
+               val = ast_variable_retrieve(cfg, "general", "format");
+               if (!val)
+                       val = "wav";    
+               ast_copy_string(vmfmts, val, sizeof(vmfmts));
 
                skipms = 3000;
                if ((s = ast_variable_retrieve(cfg, "general", "maxgreet"))) {
@@ -7426,18 +7784,17 @@ static int load_config(void)
                }
 
                /* Force new user to record name ? */
-               if (!(astforcename = ast_variable_retrieve(cfg, "general", "forcename"))) 
-                       astforcename = "no";
-               ast_set2_flag((&globalflags), ast_true(astforcename), VM_FORCENAME);
+               if (!(val = ast_variable_retrieve(cfg, "general", "forcename"))) 
+                       val = "no";
+               ast_set2_flag((&globalflags), ast_true(val), VM_FORCENAME);
 
                /* Force new user to record greetings ? */
-               if (!(astforcegreet = ast_variable_retrieve(cfg, "general", "forcegreetings"))) 
-                       astforcegreet = "no";
-               ast_set2_flag((&globalflags), ast_true(astforcegreet), VM_FORCEGREET);
+               if (!(val = ast_variable_retrieve(cfg, "general", "forcegreetings"))) 
+                       val = "no";
+               ast_set2_flag((&globalflags), ast_true(val), VM_FORCEGREET);
 
                if ((s = ast_variable_retrieve(cfg, "general", "cidinternalcontexts"))){
-                       if (option_debug)
-                               ast_log(LOG_DEBUG,"VM_CID Internal context string: %s\n",s);
+                       ast_debug(1,"VM_CID Internal context string: %s\n",s);
                        stringp = ast_strdupa(s);
                        for (x = 0 ; x < MAX_NUM_CID_CONTEXTS ; x++){
                                if (!ast_strlen_zero(stringp)) {
@@ -7445,121 +7802,121 @@ static int load_config(void)
                                        while ((*q == ' ')||(*q == '\t')) /* Eat white space between contexts */
                                                q++;
                                        ast_copy_string(cidinternalcontexts[x], q, sizeof(cidinternalcontexts[x]));
-                                       if (option_debug)
-                                               ast_log(LOG_DEBUG,"VM_CID Internal context %d: %s\n", x, cidinternalcontexts[x]);
+                                       ast_debug(1,"VM_CID Internal context %d: %s\n", x, cidinternalcontexts[x]);
                                } else {
                                        cidinternalcontexts[x][0] = '\0';
                                }
                        }
                }
-               if (!(astreview = ast_variable_retrieve(cfg, "general", "review"))){
-                       if (option_debug)
-                               ast_log(LOG_DEBUG,"VM Review Option disabled globally\n");
-                       astreview = "no";
+               if (!(val = ast_variable_retrieve(cfg, "general", "review"))){
+                       ast_debug(1,"VM Review Option disabled globally\n");
+                       val = "no";
                }
-               ast_set2_flag((&globalflags), ast_true(astreview), VM_REVIEW);  
+               ast_set2_flag((&globalflags), ast_true(val), VM_REVIEW);        
 
                /*Temporary greeting reminder */
-               if (!(asttempgreetwarn = ast_variable_retrieve(cfg, "general", "tempgreetwarn"))) {
-                       if (option_debug)
-                               ast_log(LOG_DEBUG, "VM Temporary Greeting Reminder Option disabled globally\n");
-                       asttempgreetwarn = "no";
+               if (!(val = ast_variable_retrieve(cfg, "general", "tempgreetwarn"))) {
+                       ast_debug(1, "VM Temporary Greeting Reminder Option disabled globally\n");
+                       val = "no";
                } else {
-                       if (option_debug)
-                               ast_log(LOG_DEBUG, "VM Temporary Greeting Reminder Option enabled globally\n");
+                       ast_debug(1, "VM Temporary Greeting Reminder Option enabled globally\n");
                }
-               ast_set2_flag((&globalflags), ast_true(asttempgreetwarn), VM_TEMPGREETWARN);
+               ast_set2_flag((&globalflags), ast_true(val), VM_TEMPGREETWARN);
 
-               if (!(astcallop = ast_variable_retrieve(cfg, "general", "operator"))){
-                       if (option_debug)
-                               ast_log(LOG_DEBUG,"VM Operator break disabled globally\n");
-                       astcallop = "no";
+               if (!(val = ast_variable_retrieve(cfg, "general", "operator"))){
+                       ast_debug(1,"VM Operator break disabled globally\n");
+                       val = "no";
                }
-               ast_set2_flag((&globalflags), ast_true(astcallop), VM_OPERATOR);        
+               ast_set2_flag((&globalflags), ast_true(val), VM_OPERATOR);      
 
-               if (!(astsaycid = ast_variable_retrieve(cfg, "general", "saycid"))) {
-                       if (option_debug)
-                               ast_log(LOG_DEBUG,"VM CID Info before msg disabled globally\n");
-                       astsaycid = "no";
+               if (!(val = ast_variable_retrieve(cfg, "general", "saycid"))) {
+                       ast_debug(1,"VM CID Info before msg disabled globally\n");
+                       val = "no";
                } 
-               ast_set2_flag((&globalflags), ast_true(astsaycid), VM_SAYCID);  
+               ast_set2_flag((&globalflags), ast_true(val), VM_SAYCID);        
 
-               if (!(send_voicemail = ast_variable_retrieve(cfg,"general", "sendvoicemail"))){
-                       if (option_debug)
-                               ast_log(LOG_DEBUG,"Send Voicemail msg disabled globally\n");
-                       send_voicemail = "no";
+               if (!(val = ast_variable_retrieve(cfg,"general", "sendvoicemail"))){
+                       ast_debug(1,"Send Voicemail msg disabled globally\n");
+                       val = "no";
                }
-               ast_set2_flag((&globalflags), ast_true(send_voicemail), VM_SVMAIL);
+               ast_set2_flag((&globalflags), ast_true(val), VM_SVMAIL);
        
-               if (!(asthearenv = ast_variable_retrieve(cfg, "general", "envelope"))) {
-                       if (option_debug)
-                               ast_log(LOG_DEBUG,"ENVELOPE before msg enabled globally\n");
-                       asthearenv = "yes";
+               if (!(val = ast_variable_retrieve(cfg, "general", "envelope"))) {
+                       ast_debug(1,"ENVELOPE before msg enabled globally\n");
+                       val = "yes";
                }
-               ast_set2_flag((&globalflags), ast_true(asthearenv), VM_ENVELOPE);       
+               ast_set2_flag((&globalflags), ast_true(val), VM_ENVELOPE);      
 
-               if (!(astsaydurationinfo = ast_variable_retrieve(cfg, "general", "sayduration"))) {
-                       if (option_debug)
-                               ast_log(LOG_DEBUG,"Duration info before msg enabled globally\n");
-                       astsaydurationinfo = "yes";
+               if (!(val = ast_variable_retrieve(cfg, "general", "sayduration"))) {
+                       ast_debug(1,"Duration info before msg enabled globally\n");
+                       val = "yes";
                }
-               ast_set2_flag((&globalflags), ast_true(astsaydurationinfo), VM_SAYDURATION);    
+               ast_set2_flag((&globalflags), ast_true(val), VM_SAYDURATION);   
 
                saydurationminfo = 2;
-               if ((astsaydurationminfo = ast_variable_retrieve(cfg, "general", "saydurationm"))) {
-                       if (sscanf(astsaydurationminfo, "%d", &x) == 1) {
+               if ((val = ast_variable_retrieve(cfg, "general", "saydurationm"))) {
+                       if (sscanf(val, "%d", &x) == 1) {
                                saydurationminfo = x;
                        } else {
                                ast_log(LOG_WARNING, "Invalid min duration for say duration\n");
                        }
                }
 
-               if (!(astskipcmd = ast_variable_retrieve(cfg, "general", "nextaftercmd"))) {
-                       if (option_debug)
-                               ast_log(LOG_DEBUG,"We are not going to skip to the next msg after save/delete\n");
-                       astskipcmd = "no";
+               if (!(val = ast_variable_retrieve(cfg, "general", "nextaftercmd"))) {
+                       ast_debug(1,"We are not going to skip to the next msg after save/delete\n");
+                       val = "no";
                }
-               ast_set2_flag((&globalflags), ast_true(astskipcmd), VM_SKIPAFTERCMD);
+               ast_set2_flag((&globalflags), ast_true(val), VM_SKIPAFTERCMD);
 
-               if ((dialoutcxt = ast_variable_retrieve(cfg, "general", "dialout"))) {
-                       ast_copy_string(dialcontext, dialoutcxt, sizeof(dialcontext));
-                       if (option_debug)
-                               ast_log(LOG_DEBUG, "found dialout context: %s\n", dialcontext);
+               if ((val = ast_variable_retrieve(cfg, "general", "dialout"))) {
+                       ast_copy_string(dialcontext, val, sizeof(dialcontext));
+                       ast_debug(1, "found dialout context: %s\n", dialcontext);
                } else {
                        dialcontext[0] = '\0';  
                }
                
-               if ((callbackcxt = ast_variable_retrieve(cfg, "general", "callback"))) {
-                       ast_copy_string(callcontext, callbackcxt, sizeof(callcontext));
-                       if (option_debug)
-                               ast_log(LOG_DEBUG, "found callback context: %s\n", callcontext);
+               if ((val = ast_variable_retrieve(cfg, "general", "callback"))) {
+                       ast_copy_string(callcontext, val, sizeof(callcontext));
+                       ast_debug(1, "found callback context: %s\n", callcontext);
                } else {
                        callcontext[0] = '\0';
                }
 
-               if ((exitcxt = ast_variable_retrieve(cfg, "general", "exitcontext"))) {
-                       ast_copy_string(exitcontext, exitcxt, sizeof(exitcontext));
-                       if (option_debug)
-                               ast_log(LOG_DEBUG, "found operator context: %s\n", exitcontext);
+               if ((val = ast_variable_retrieve(cfg, "general", "exitcontext"))) {
+                       ast_copy_string(exitcontext, val, sizeof(exitcontext));
+                       ast_debug(1, "found operator context: %s\n", exitcontext);
                } else {
                        exitcontext[0] = '\0';
                }
                
                /* load password sounds configuration */
-               if ((vm_paswd = ast_variable_retrieve(cfg, "general", "vm-password")))
-                       ast_copy_string(vm_password, vm_paswd, sizeof(vm_password));
-               if ((vm_newpasswd = ast_variable_retrieve(cfg, "general", "vm-newpassword")))
-                       ast_copy_string(vm_newpassword, vm_newpasswd, sizeof(vm_newpassword));
-               if ((vm_passchange = ast_variable_retrieve(cfg, "general", "vm-passchanged")))
-                       ast_copy_string(vm_passchanged, vm_passchange, sizeof(vm_passchanged));
-               if ((vm_reenterpass = ast_variable_retrieve(cfg, "general", "vm-reenterpassword")))
-                       ast_copy_string(vm_reenterpassword, vm_reenterpass, sizeof(vm_reenterpassword));
-               if ((vm_mism = ast_variable_retrieve(cfg, "general", "vm-mismatch")))
-                       ast_copy_string(vm_mismatch, vm_mism, sizeof(vm_mismatch));
-
-               if (!(astdirfwd = ast_variable_retrieve(cfg, "general", "usedirectory"))) 
-                       astdirfwd = "no";
-               ast_set2_flag((&globalflags), ast_true(astdirfwd), VM_DIRECFORWARD);    
+               if ((val = ast_variable_retrieve(cfg, "general", "vm-password")))
+                       ast_copy_string(vm_password, val, sizeof(vm_password));
+               if ((val = ast_variable_retrieve(cfg, "general", "vm-newpassword")))
+                       ast_copy_string(vm_newpassword, val, sizeof(vm_newpassword));
+               if ((val = ast_variable_retrieve(cfg, "general", "vm-passchanged")))
+                       ast_copy_string(vm_passchanged, val, sizeof(vm_passchanged));
+               if ((val = ast_variable_retrieve(cfg, "general", "vm-reenterpassword")))
+                       ast_copy_string(vm_reenterpassword, val, sizeof(vm_reenterpassword));
+               if ((val = ast_variable_retrieve(cfg, "general", "vm-mismatch")))
+                       ast_copy_string(vm_mismatch, val, sizeof(vm_mismatch));
+
+               if (!(val = ast_variable_retrieve(cfg, "general", "usedirectory"))) 
+                       val = "no";
+               ast_set2_flag((&globalflags), ast_true(val), VM_DIRECFORWARD);  
+
+               poll_freq = DEFAULT_POLL_FREQ;
+               if ((val = ast_variable_retrieve(cfg, "general", "pollfreq"))) {
+                       if (sscanf(val, "%u", &poll_freq) != 1) {
+                               poll_freq = DEFAULT_POLL_FREQ;
+                               ast_log(LOG_ERROR, "'%s' is not a valid value for the pollfreq option!\n", val);
+                       }
+               }
+
+               poll_mailboxes = 0;
+               if ((val = ast_variable_retrieve(cfg, "general", "pollmailboxes")))
+                       poll_mailboxes = ast_true(val);
+
                if ((ucfg = ast_config_load("users.conf"))) {   
                        for (cat = ast_category_browse(ucfg, NULL); cat ; cat = ast_category_browse(ucfg, cat)) {
                                if (!ast_true(ast_config_option(ucfg, cat, "hasvoicemail")))
@@ -7599,10 +7956,9 @@ static int load_config(void)
                                                                AST_LIST_UNLOCK(&zones);
                                                        } else {
                                                                ast_log(LOG_WARNING, "Invalid timezone definition at line %d\n", var->lineno);
-                                                               free(z);
+                                                               ast_free(z);
                                                        }
                                                } else {
-                                                       free(z);
                                                        AST_LIST_UNLOCK(&users);
                                                        ast_config_destroy(cfg);
                                                        return -1;
@@ -7613,24 +7969,24 @@ static int load_config(void)
                        }
                        cat = ast_category_browse(cfg, cat);
                }
-               memset(fromstring,0,sizeof(fromstring));
+               memset(fromstring, 0, sizeof(fromstring));
                memset(pagerfromstring,0,sizeof(pagerfromstring));
                memset(emailtitle,0,sizeof(emailtitle));
                strcpy(charset, "ISO-8859-1");
                if (emailbody) {
-                       free(emailbody);
+                       ast_free(emailbody);
                        emailbody = NULL;
                }
                if (emailsubject) {
-                       free(emailsubject);
+                       ast_free(emailsubject);
                        emailsubject = NULL;
                }
                if (pagerbody) {
-                       free(pagerbody);
+                       ast_free(pagerbody);
                        pagerbody = NULL;
                }
                if (pagersubject) {
-                       free(pagersubject);
+                       ast_free(pagersubject);
                        pagersubject = NULL;
                }
                if ((s = ast_variable_retrieve(cfg, "general", "pbxskip")))
@@ -7719,56 +8075,67 @@ static int load_config(void)
                }
                AST_LIST_UNLOCK(&users);
                ast_config_destroy(cfg);
+
+               if (poll_mailboxes && poll_thread == AST_PTHREADT_NULL)
+                       start_poll_thread();
+               if (!poll_mailboxes && poll_thread != AST_PTHREADT_NULL)
+                       stop_poll_thread();;
+
                return 0;
        } else {
                AST_LIST_UNLOCK(&users);
-               ast_log(LOG_WARNING, "Failed to load configuration file. Module not activated.\n");
+               ast_log(LOG_WARNING, "Failed to load configuration file.\n");
                return 0;
        }
 }
 
 static int reload(void)
 {
-       return(load_config());
+       return load_config();
 }
 
 static int unload_module(void)
 {
        int res;
-       
+
        res = ast_unregister_application(app);
        res |= ast_unregister_application(app2);
        res |= ast_unregister_application(app3);
        res |= ast_unregister_application(app4);
        res |= ast_custom_function_unregister(&mailbox_exists_acf);
+       res |= ast_manager_unregister("VoicemailUsersList");
        ast_cli_unregister_multiple(cli_voicemail, sizeof(cli_voicemail) / sizeof(struct ast_cli_entry));
        ast_uninstall_vm_functions();
        
        ast_module_user_hangup_all();
 
+       if (poll_thread != AST_PTHREADT_NULL)
+               stop_poll_thread();
+
        return res;
 }
 
 static int load_module(void)
 {
        int res;
+
+       /* compute the location of the voicemail spool directory */
+       snprintf(VM_SPOOL_DIR, sizeof(VM_SPOOL_DIR), "%s/voicemail/", ast_config_AST_SPOOL_DIR);
+
+       if ((res = load_config()))
+               return res;
+
        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);
        res |= ast_custom_function_register(&mailbox_exists_acf);
+       res |= ast_manager_register("VoicemailUsersList", EVENT_FLAG_CALL, manager_list_voicemail_users, "List All Voicemail User Information");
        if (res)
-               return(res);
-
-       if ((res=load_config())) {
-               return(res);
-       }
+               return res;
 
        ast_cli_register_multiple(cli_voicemail, sizeof(cli_voicemail) / sizeof(struct ast_cli_entry));
 
-       /* compute the location of the voicemail spool directory */
-       snprintf(VM_SPOOL_DIR, sizeof(VM_SPOOL_DIR), "%s/voicemail/", ast_config_AST_SPOOL_DIR);
-
        ast_install_vm_functions(has_voicemail, inboxcount, messagecount);
 
        return res;
@@ -7854,8 +8221,7 @@ static int advanced_options(struct ast_channel *chan, struct ast_vm_user *vmu, s
        /* START HERE */
 
        /* get the message info!! */
-       if(option_debug > 2)
-               ast_log(LOG_DEBUG, "Before mail_fetchheaders, curmsg is: %d, imap messages is %lu\n", vms->curmsg, vms->msgArray[vms->curmsg]);
+       ast_debug(3, "Before mail_fetchheaders, curmsg is: %d, imap messages is %lu\n", vms->curmsg, vms->msgArray[vms->curmsg]);
 
        if (!vms->msgArray[vms->curmsg]) {
                ast_log(LOG_WARNING, "Trying to access unknown message\n");
@@ -8032,7 +8398,8 @@ static int advanced_options(struct ast_channel *chan, struct ast_vm_user *vmu, s
                        ast_config_destroy(msg_cfg);
                        return res;
                } else {
-                       if (find_user(NULL, vmu->context, num)) {
+                       struct ast_vm_user vmu2;
+                       if (find_user(&vmu2, vmu->context, num)) {
                                struct leave_vm_options leave_options;
                                char mailbox[AST_MAX_EXTENSION * 2 + 2];
                                snprintf(mailbox, sizeof(mailbox), "%s@%s", num, vmu->context);
@@ -8086,6 +8453,7 @@ static int play_record_review(struct ast_channel *chan, char *playfile, char *re
        int recorded = 0;
        int message_exists = 0;
        signed char zero_gain = 0;
+       char tempfile[PATH_MAX];
        char *acceptdtmf = "#";
        char *canceldtmf = "";
 
@@ -8097,6 +8465,11 @@ static int play_record_review(struct ast_channel *chan, char *playfile, char *re
                return -1;
        }
 
+       if (!outsidecaller)
+               snprintf(tempfile, sizeof(tempfile), "%s.tmp", recordfile);
+       else
+               ast_copy_string(tempfile, recordfile, sizeof(tempfile));
+
        cmd = '3';  /* Want to start by recording */
 
        while ((cmd >= 0) && (cmd != 't')) {
@@ -8110,9 +8483,13 @@ static int play_record_review(struct ast_channel *chan, char *playfile, char *re
                                /* Otherwise 1 is to save the existing message */
                                if (option_verbose > 2)
                                        ast_verbose(VERBOSE_PREFIX_3 "Saving message as is\n");
+                               if (!outsidecaller)
+                                       ast_filerename(tempfile, recordfile, NULL);
                                ast_stream_and_wait(chan, "vm-msgsaved", "");
-                               STORE(recordfile, vmu->mailbox, vmu->context, -1, chan, vmu, fmt, *duration, vms);
-                               DISPOSE(recordfile, -1);
+                               if (!outsidecaller) {
+                                       STORE(recordfile, vmu->mailbox, vmu->context, -1, chan, vmu, fmt, *duration, vms);
+                                       DISPOSE(recordfile, -1);
+                               }
                                cmd = 't';
                                return res;
                        }
@@ -8120,7 +8497,7 @@ static int play_record_review(struct ast_channel *chan, char *playfile, char *re
                        /* Review */
                        if (option_verbose > 2)
                                ast_verbose(VERBOSE_PREFIX_3 "Reviewing the message\n");
-                       cmd = ast_stream_and_wait(chan, recordfile, AST_DIGIT_ANY);
+                       cmd = ast_stream_and_wait(chan, tempfile, AST_DIGIT_ANY);
                        break;
                case '3':
                        message_exists = 0;
@@ -8142,11 +8519,15 @@ static int play_record_review(struct ast_channel *chan, char *playfile, char *re
                                ast_channel_setoption(chan, AST_OPTION_RXGAIN, &record_gain, sizeof(record_gain), 0);
                        if (ast_test_flag(vmu, VM_OPERATOR))
                                canceldtmf = "0";
-                       cmd = ast_play_and_record_full(chan, playfile, recordfile, maxtime, fmt, duration, silencethreshold, maxsilence, unlockdir, acceptdtmf, canceldtmf);
+                       cmd = ast_play_and_record_full(chan, playfile, tempfile, maxtime, fmt, duration, silencethreshold, maxsilence, unlockdir, acceptdtmf, canceldtmf);
                        if (record_gain)
                                ast_channel_setoption(chan, AST_OPTION_RXGAIN, &zero_gain, sizeof(zero_gain), 0);
                        if (cmd == -1) {
-                       /* User has hung up, no options to give */
+                               /* User has hung up, no options to give */
+                               if (!outsidecaller) {
+                                       /* user was recording a greeting and they hung up, so let's delete the recording. */
+                                       vm_delete(tempfile);
+                               }
                                return cmd;
                        }
                        if (cmd == '0') {
@@ -8160,14 +8541,14 @@ static int play_record_review(struct ast_channel *chan, char *playfile, char *re
                                if (option_verbose > 2)
                                        ast_verbose(VERBOSE_PREFIX_3 "Message too short\n");
                                cmd = ast_play_and_wait(chan, "vm-tooshort");
-                               cmd = vm_delete(recordfile);
+                               cmd = vm_delete(tempfile);
                                break;
                        }
                        else if (vmu->review && (cmd == 2 && *duration < (maxsilence + 3))) {
                                /* Message is all silence */
                                if (option_verbose > 2)
                                        ast_verbose(VERBOSE_PREFIX_3 "Nothing recorded\n");
-                               cmd = vm_delete(recordfile);
+                               cmd = vm_delete(tempfile);
                                cmd = ast_play_and_wait(chan, "vm-nothingrecorded");
                                if (!cmd)
                                        cmd = ast_play_and_wait(chan, "vm-speakup");
@@ -8196,7 +8577,7 @@ static int play_record_review(struct ast_channel *chan, char *playfile, char *re
                case '*':
                        /* Cancel recording, delete message, offer to take another message*/
                        cmd = ast_play_and_wait(chan, "vm-deleted");
-                       cmd = vm_delete(recordfile);
+                       cmd = vm_delete(tempfile);
                        if (outsidecaller) {
                                res = vm_exec(chan, NULL);
                                return res;
@@ -8288,8 +8669,7 @@ void mm_searched(MAILSTREAM *stream, unsigned long number)
                return;
        }
        
-       if(option_debug > 2)
-               ast_log(LOG_DEBUG, "saving mailbox message number %lu as message %d. Interactive set to %d\n", number, vms->vmArrayIndex, vms->interactive);
+       ast_debug(3, "saving mailbox message number %lu as message %d. Interactive set to %d\n", number, vms->vmArrayIndex, vms->interactive);
 
        vms->msgArray[vms->vmArrayIndex++] = number;
 }
@@ -8478,7 +8858,7 @@ static struct ast_vm_user *find_user_realtime_imapuser(const char *imapuser)
                ast_variables_destroy(var);
                return vmu;
        } else {
-               free(vmu);
+               ast_free(vmu);
                return NULL;
        }
 }
@@ -8488,8 +8868,7 @@ static struct ast_vm_user *find_user_realtime_imapuser(const char *imapuser)
 void mm_exists(MAILSTREAM * stream, unsigned long number)
 {
        /* mail_ping will callback here if new mail! */
-       if(option_debug > 3)
-               ast_log (LOG_DEBUG, "Entering EXISTS callback for message %ld\n", number);
+       ast_debug(4, "Entering EXISTS callback for message %ld\n", number);
        if (number == 0) return;
        set_update(stream);
 }
@@ -8498,8 +8877,7 @@ void mm_exists(MAILSTREAM * stream, unsigned long number)
 void mm_expunged(MAILSTREAM * stream, unsigned long number)
 {
        /* mail_ping will callback here if expunged mail! */
-       if(option_debug > 3)
-               ast_log (LOG_DEBUG, "Entering EXPUNGE callback for message %ld\n", number);
+       ast_debug(4, "Entering EXPUNGE callback for message %ld\n", number);
        if (number == 0) return;
        set_update(stream);
 }
@@ -8508,8 +8886,7 @@ void mm_expunged(MAILSTREAM * stream, unsigned long number)
 void mm_flags(MAILSTREAM * stream, unsigned long number)
 {
        /* mail_ping will callback here if read mail! */
-       if(option_debug > 3)
-               ast_log (LOG_DEBUG, "Entering FLAGS callback for message %ld\n", number);
+       ast_debug(4, "Entering FLAGS callback for message %ld\n", number);
        if (number == 0) return;
        set_update(stream);
 }
@@ -8528,33 +8905,30 @@ void mm_list(MAILSTREAM * stream, int delim, char *mailbox, long attributes)
                delimiter = delim;
                ast_mutex_unlock(&delimiter_lock);
        }
-       if (option_debug > 4) {
-               ast_log(LOG_DEBUG, "Delimiter set to %c and mailbox %s\n",delim, mailbox);
-               if (attributes & LATT_NOINFERIORS)
-                       ast_log(LOG_DEBUG, "no inferiors\n");
-               if (attributes & LATT_NOSELECT)
-                       ast_log(LOG_DEBUG, "no select\n");
-               if (attributes & LATT_MARKED)
-                       ast_log(LOG_DEBUG, "marked\n");
-               if (attributes & LATT_UNMARKED)
-                       ast_log(LOG_DEBUG, "unmarked\n");
-       }
+
+       ast_debug(5, "Delimiter set to %c and mailbox %s\n",delim, mailbox);
+       if (attributes & LATT_NOINFERIORS)
+               ast_debug(5, "no inferiors\n");
+       if (attributes & LATT_NOSELECT)
+               ast_debug(5, "no select\n");
+       if (attributes & LATT_MARKED)
+               ast_debug(5, "marked\n");
+       if (attributes & LATT_UNMARKED)
+               ast_debug(5, "unmarked\n");
 }
 
 
 void mm_lsub(MAILSTREAM * stream, int delimiter, char *mailbox, long attributes)
 {
-       if (option_debug > 4) {
-               ast_log(LOG_DEBUG, "Delimiter set to %c and mailbox %s\n",delimiter, mailbox);
-               if (attributes & LATT_NOINFERIORS)
-                       ast_log(LOG_DEBUG, "no inferiors\n");
-               if (attributes & LATT_NOSELECT)
-                       ast_log(LOG_DEBUG, "no select\n");
-               if (attributes & LATT_MARKED)
-                       ast_log(LOG_DEBUG, "marked\n");
-               if (attributes & LATT_UNMARKED)
-                       ast_log(LOG_DEBUG, "unmarked\n");
-       }
+       ast_debug(5, "Delimiter set to %c and mailbox %s\n",delimiter, mailbox);
+       if (attributes & LATT_NOINFERIORS)
+               ast_debug(5, "no inferiors\n");
+       if (attributes & LATT_NOSELECT)
+               ast_debug(5, "no select\n");
+       if (attributes & LATT_MARKED)
+               ast_debug(5, "marked\n");
+       if (attributes & LATT_UNMARKED)
+               ast_debug(5, "unmarked\n");
 }
 
 
@@ -8579,8 +8953,7 @@ void mm_log(char *string, long errflg)
 {
        switch ((short) errflg) {
                case NIL:
-                       if(option_debug)
-                               ast_log(LOG_DEBUG,"IMAP Info: %s\n", string);
+                       ast_debug(1,"IMAP Info: %s\n", string);
                        break;
                case PARSE:
                case WARN:
@@ -8603,8 +8976,7 @@ void mm_login(NETMBX * mb, char *user, char *pwd, long trial)
 {
        struct ast_vm_user *vmu;
 
-       if(option_debug > 3)
-               ast_log(LOG_DEBUG, "Entering callback mm_login\n");
+       ast_debug(4, "Entering callback mm_login\n");
 
        ast_copy_string(user, mb->user, MAILTMPLEN);
 
@@ -8669,8 +9041,7 @@ static void mm_parsequota(MAILSTREAM *stream, unsigned char *msg, QUOTALIST *pqu
                return;
        }
 
-       if (option_debug > 2)
-               ast_log(LOG_DEBUG, "User %s usage is %lu, limit is %lu\n", user, usage, limit);
+       ast_debug(3, "User %s usage is %lu, limit is %lu\n", user, usage, limit);
 
        vms->quota_usage = usage;
        vms->quota_limit = limit;
@@ -8730,13 +9101,11 @@ static struct vm_state *get_vm_state_by_imapuser(char *user, int interactive)
 
        AST_LIST_TRAVERSE(&vmstates, vlist, list) {
                if (!vlist->vms) {
-                       if (option_debug > 2)
-                               ast_log(LOG_DEBUG, "error: vms is NULL for %s\n", user);
+                       ast_debug(3, "error: vms is NULL for %s\n", user);
                        continue;
                }
                if (!vlist->vms->imapuser) {
-                       if (option_debug > 2)
-                               ast_log(LOG_DEBUG, "error: imapuser is NULL for %s\n", user);
+                       ast_debug(3, "error: imapuser is NULL for %s\n", user);
                        continue;
                }
 
@@ -8746,8 +9115,7 @@ static struct vm_state *get_vm_state_by_imapuser(char *user, int interactive)
                        return vlist->vms;
        }
 
-       if(option_debug > 2)
-               ast_log(LOG_DEBUG, "%s not found in vmstates\n", user);
+       ast_debug(3, "%s not found in vmstates\n", user);
 
        return NULL;
 }
@@ -8758,28 +9126,23 @@ static struct vm_state *get_vm_state_by_mailbox(const char *mailbox, int interac
 
        AST_LIST_TRAVERSE(&vmstates, vlist, list) {
                if (!vlist->vms) {
-                       if (option_debug > 2)
-                               ast_log(LOG_DEBUG, "error: vms is NULL for %s\n", mailbox);
+                       ast_debug(3, "error: vms is NULL for %s\n", mailbox);
                        continue;
                }
                if (!vlist->vms->username) {
-                       if (option_debug > 2)
-                               ast_log(LOG_DEBUG, "error: username is NULL for %s\n", mailbox);
+                       ast_debug(3, "error: username is NULL for %s\n", mailbox);
                        continue;
                }
 
-               if (option_debug > 2)
-                       ast_log(LOG_DEBUG, "comparing mailbox %s (i=%d) to vmstate mailbox %s (i=%d)\n", mailbox, interactive, vlist->vms->username, vlist->vms->interactive);
+               ast_debug(3, "comparing mailbox %s (i=%d) to vmstate mailbox %s (i=%d)\n", mailbox, interactive, vlist->vms->username, vlist->vms->interactive);
                
                if (!strcmp(vlist->vms->username,mailbox) && vlist->vms->interactive == interactive) {
-                       if(option_debug > 2)
-                               ast_log(LOG_DEBUG, "Found it!\n");
+                       ast_debug(3, "Found it!\n");
                        return vlist->vms;
                }
        }
 
-       if (option_debug > 2)
-               ast_log(LOG_DEBUG, "%s not found in vmstates\n", mailbox);
+       ast_debug(3, "%s not found in vmstates\n", mailbox);
 
        return NULL;
 }
@@ -8795,17 +9158,14 @@ static void vmstate_insert(struct vm_state *vms)
        if (vms->interactive == 1) {
                altvms = get_vm_state_by_mailbox(vms->username,0);
                if (altvms) {
-                       if(option_debug > 2)
-                               ast_log(LOG_DEBUG, "Duplicate mailbox %s, copying message info...\n",vms->username);
+                       ast_debug(3, "Duplicate mailbox %s, copying message info...\n",vms->username);
                        vms->newmessages = altvms->newmessages;
                        vms->oldmessages = altvms->oldmessages;
-                       if(option_debug > 2)
-                               ast_log(LOG_DEBUG, "check_msgArray before memcpy\n");
+                       ast_debug(3, "check_msgArray before memcpy\n");
                        check_msgArray(vms);
                        /* memcpy(vms->msgArray, altvms->msgArray, sizeof(long)*256); */
                        copy_msgArray(vms, altvms);
-                       if(option_debug > 2)
-                               ast_log(LOG_DEBUG, "check_msgArray after memcpy\n");
+                       ast_debug(3, "check_msgArray after memcpy\n");
                        check_msgArray(vms);
                        vms->vmArrayIndex = altvms->vmArrayIndex;
                        vms->lastmsg = altvms->lastmsg;
@@ -8820,9 +9180,10 @@ static void vmstate_insert(struct vm_state *vms)
 
        if (!(v = ast_calloc(1, sizeof(*v))))
                return;
+       
+       v->vms = vms;
 
-       if(option_debug > 2)
-               ast_log(LOG_DEBUG, "Inserting vm_state for user:%s, mailbox %s\n",vms->imapuser,vms->username);
+       ast_debug(3, "Inserting vm_state for user:%s, mailbox %s\n",vms->imapuser,vms->username);
 
        AST_LIST_LOCK(&vmstates);
        AST_LIST_INSERT_TAIL(&vmstates, v, list);
@@ -8837,15 +9198,13 @@ static void vmstate_delete(struct vm_state *vms)
        /* If interactive, we should copy pertinent info
           back to the persistent state (to make update immediate) */
        if (vms->interactive == 1 && (altvms = vms->persist_vms)) {
-               if(option_debug > 2)
-                       ast_log(LOG_DEBUG, "Duplicate mailbox %s, copying message info...\n", vms->username);
+               ast_debug(3, "Duplicate mailbox %s, copying message info...\n", vms->username);
                altvms->newmessages = vms->newmessages;
                altvms->oldmessages = vms->oldmessages;
                altvms->updated = 2;
        }
        
-       if (option_debug > 2)
-               ast_log(LOG_DEBUG, "Removing vm_state for user:%s, mailbox %s\n", vms->imapuser, vms->username);
+       ast_debug(3, "Removing vm_state for user:%s, mailbox %s\n", vms->imapuser, vms->username);
        
        AST_LIST_LOCK(&vmstates);
        AST_LIST_TRAVERSE_SAFE_BEGIN(&vmstates, vc, list) {
@@ -8858,7 +9217,7 @@ static void vmstate_delete(struct vm_state *vms)
        AST_LIST_UNLOCK(&vmstates);
        
        if (vc)
-               free(vc);
+               ast_free(vc);
        else
                ast_log(LOG_ERROR, "No vmstate found for user:%s, mailbox %s\n", vms->imapuser, vms->username);
 }
@@ -8875,8 +9234,7 @@ static void set_update(MAILSTREAM * stream)
                return;
        }
 
-       if (option_debug > 2)
-               ast_log(LOG_DEBUG, "User %s mailbox set for update.\n", user);
+       ast_debug(3, "User %s mailbox set for update.\n", user);
        
        vms->updated = 2; /* Set updated flag since mailbox changed */
 }
@@ -8895,8 +9253,7 @@ static void check_msgArray(struct vm_state *vms)
        int x;
        for (x = 0; x<256; x++) {
                if (vms->msgArray[x]!=0) {
-                       if(option_debug)
-                               ast_log (LOG_DEBUG, "Item %d set to %ld\n",x,vms->msgArray[x]);
+                       ast_debug(1, "Item %d set to %ld\n",x,vms->msgArray[x]);
                }
        }
 }
@@ -8923,7 +9280,7 @@ static int save_body(BODY *body, struct vm_state *vms, char *section, char *form
        body_content = mail_fetchbody (vms->mailstream, vms->msgArray[vms->curmsg], section, &len);
        if (body_content != NIL) {
                sprintf(filename,"%s.%s", vms->fn, format);
-               /* ast_log (LOG_DEBUG,body_content); */
+               /* ast_debug(1,body_content); */
                body_decoded = rfc822_base64 ((unsigned char *)body_content, len, &newlen);
                write_file (filename, (char *) body_decoded, newlen);
        }