Merge in ast_strftime branch, which changes timestamps to be accurate to the microsec...
[asterisk/asterisk.git] / apps / app_voicemail.c
index 13dc0dd..4c051dc 100644 (file)
  * \brief Comedian Mail - Voicemail System
  *
  * \author Mark Spencer <markster@digium.com>
+ *
+ * \extref Unixodbc - http://www.unixodbc.org
+ * \extref A source distribution of University of Washington's IMAP
+c-client (http://www.washington.edu/imap/
  * 
  * \par See also
  * \arg \ref Config_vm
  *
  *
  *
- * \note  This file is now almost impossible to work with, due to all #ifdefs.
+ * \note  This file is now almost impossible to work with, due to all \#ifdefs.
  *        Feels like the database code before realtime. Someone - please come up
  *        with a plan to clean this up.
  */
 
 /*** MODULEINFO
-       <depend>res_adsi</depend>
+       <depend>res_smdi</depend>
  ***/
 
 /*** MAKEOPTS
 <category name="MENUSELECT_OPTS_app_voicemail" displayname="Voicemail Build Options" positive_output="yes" remove_on_change="apps/app_voicemail.o">
        <member name="ODBC_STORAGE" displayname="Storage of Voicemail using ODBC">
                <depend>unixodbc</depend>
+               <depend>ltdl</depend>
                <conflict>IMAP_STORAGE</conflict>
                <defaultenabled>no</defaultenabled>
        </member>
@@ -77,10 +82,16 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include <ctype.h>
 #include <signal.h>
 #include <pwd.h>
+#ifdef USE_SYSTEM_IMAP
+#include <imap/c-client.h>
+#include <imap/imap4r1.h>
+#include <imap/linkage.h>
+#else
 #include "c-client.h"
 #include "imap4r1.h"
 #include "linkage.h"
 #endif
+#endif
 
 #include "asterisk/lock.h"
 #include "asterisk/file.h"
@@ -100,6 +111,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"
@@ -110,10 +122,12 @@ static char imapserver[48];
 static char imapport[8];
 static char imapflags[128];
 static char imapfolder[64];
+static char greetingfolder[64];
 static char authuser[32];
 static char authpassword[42];
 
 static int expungeonhangup = 1;
+static int imapgreetings = 0;
 AST_MUTEX_DEFINE_STATIC(delimiter_lock);
 static char delimiter = '\0';
 
@@ -122,7 +136,7 @@ struct ast_vm_user;
 
 /* Forward declarations for IMAP */
 static int init_mailstream(struct vm_state *vms, int box);
-static void write_file char *filename, char *buffer, unsigned long len);
+static void write_file(char *filename, char *buffer, unsigned long len);
 static void display_body(BODY *body, char *pfx, long i);
 static char *get_header_by_tag(char *header, char *tag, char *buf, size_t len);
 static void vm_imap_delete(int msgnum, struct vm_state *vms);
@@ -141,9 +155,11 @@ static void get_mailbox_delimiter(MAILSTREAM *stream);
 static void mm_parsequota (MAILSTREAM *stream, unsigned char *msg, QUOTALIST *pquota);
 static void imap_mailbox_name(char *spec, struct vm_state *vms, int box, int target);
 static int imap_store_file(char *dir, char *mailboxuser, char *mailboxcontext, int msgnum, struct ast_channel *chan, struct ast_vm_user *vmu, char *fmt, int duration, struct vm_state *vms);
+static void update_messages_by_imapuser(const char *user, unsigned long number);
 
-
-
+static int imap_remove_file (char *dir, int msgnum);
+static int imap_retrieve_file (char *dir, int msgnum, char *mailbox, char *context);
+static int imap_delete_old_greeting (char *dir, struct vm_state *vms);
 struct vmstate {
        struct vm_state *vms;
        AST_LIST_ENTRY(vmstate) list;
@@ -164,6 +180,16 @@ static AST_LIST_HEAD_STATIC(vmstates, vmstate);
 #define VOICEMAIL_CONFIG "voicemail.conf"
 #define ASTERISK_USERNAME "asterisk"
 
+/* Define fast-forward, pause, restart, and reverse keys
+   while listening to a voicemail message - these are
+   strings, not characters */
+#define DEFAULT_LISTEN_CONTROL_FORWARD_KEY "#"
+#define DEFAULT_LISTEN_CONTROL_REVERSE_KEY "*"
+#define DEFAULT_LISTEN_CONTROL_PAUSE_KEY "0"
+#define DEFAULT_LISTEN_CONTROL_RESTART_KEY "2"
+#define DEFAULT_LISTEN_CONTROL_STOP_KEY "13456789"
+#define VALID_DTMF "1234567890*#" /* Yes ABCD are valid dtmf but what phones have those? */
+
 /* Default mail command to mail voicemail. Change it with the
     mailcmd= command in voicemail.conf */
 #define SENDMAIL "/usr/sbin/sendmail -t"
@@ -201,12 +227,20 @@ static AST_LIST_HEAD_STATIC(vmstates, vmstate);
 
 
 enum {
+       NEW_FOLDER,
+       OLD_FOLDER,
+       WORK_FOLDER,
+       FAMILY_FOLDER,
+       FRIENDS_FOLDER,
+       GREETINGS_FOLDER
+} vm_box;
+
+enum {
        OPT_SILENT =           (1 << 0),
        OPT_BUSY_GREETING =    (1 << 1),
        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;
 
@@ -223,7 +257,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),
 });
 
@@ -243,6 +276,7 @@ static int load_config(void);
        \arg \b gr    - Greek
        \arg \b no    - Norwegian
        \arg \b se    - Swedish
+       \arg \b tw    - Chinese (Taiwan)
 
 German requires the following additional soundfile:
 \arg \b 1F     einE (feminine)
@@ -295,6 +329,15 @@ For vm_intro_it:
 \arg \b vm-vecchio     old
 \arg \b vm-vecchi      old plural
 
+Chinese (Taiwan) requires the following additional soundfile:
+\arg \b vm-tong                A class-word for call (tong1)
+\arg \b vm-ri          A class-word for day (ri4)
+\arg \b vm-you         You (ni3)
+\arg \b vm-haveno   Have no (mei2 you3)
+\arg \b vm-have            Have (you3)
+\arg \b vm-listen   To listen (yao4 ting1)
+
+
 \note Don't use vm-INBOX or vm-Old, because they are the name of the INBOX and Old folders,
 spelled among others when you have to change folder. For the above reasons, vm-INBOX
 and vm-Old are spelled plural, to make them sound more as folder name than an adjective.
@@ -309,7 +352,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 */
@@ -326,7 +370,7 @@ struct ast_vm_user {
        char uniqueid[20];               /*!< Unique integer identifier */
        char exit[80];
        char attachfmt[20];              /*!< Attachment format */
-       unsigned int flags;              /*!< VM_ flags */      
+       uint64_t flags;              /*!< VM_ flags */  
        int saydurationm;
        int maxmsg;                      /*!< Maximum number of msgs per folder for this mailbox */
        int maxsecs;                     /*!< Maximum number of seconds per message for this mailbox */
@@ -379,7 +423,7 @@ struct vm_state {
 #ifdef ODBC_STORAGE
 static char odbc_database[80];
 static char odbc_table[80];
-#define RETRIEVE(a,b) retrieve_file(a,b)
+#define RETRIEVE(a,b,c,d) retrieve_file(a,b)
 #define DISPOSE(a,b) remove_file(a,b)
 #define STORE(a,b,c,d,e,f,g,h,i) store_file(a,b,c,d)
 #define EXISTS(a,b,c,d) (message_exists(a,b))
@@ -388,8 +432,8 @@ static char odbc_table[80];
 #define DELETE(a,b,c) (delete_file(a,b))
 #else
 #ifdef IMAP_STORAGE
-#define RETRIEVE(a,b)
-#define DISPOSE(a,b)
+#define RETRIEVE(a,b,c,d) (imap_retrieve_file(a,b,c,d ))
+#define DISPOSE(a,b) (imap_remove_file(a,b))
 #define STORE(a,b,c,d,e,f,g,h,i) (imap_store_file(a,b,c,d,e,f,g,h,i))
 #define EXISTS(a,b,c,d) (ast_fileexists(c,NULL,d) > 0)
 #define RENAME(a,b,c,d,e,f,g,h) (rename_file(g,h));
@@ -397,7 +441,7 @@ static char odbc_table[80];
 #define IMAP_DELETE(a,b,c,d) (vm_imap_delete(b,d))
 #define DELETE(a,b,c) (vm_delete(c))
 #else
-#define RETRIEVE(a,b)
+#define RETRIEVE(a,b,c,d)
 #define DISPOSE(a,b)
 #define STORE(a,b,c,d,e,f,g,h,i)
 #define EXISTS(a,b,c,d) (ast_fileexists(c,NULL,d) > 0)
@@ -415,12 +459,14 @@ static char ext_pass_cmd[128];
 #define PWDCHANGE_EXTERNAL (1 << 2)
 static int pwdchange = PWDCHANGE_INTERNAL;
 
-#if ODBC_STORAGE
+#ifdef ODBC_STORAGE
 #define tdesc "Comedian Mail (Voicemail System) with ODBC Storage"
-#elif IMAP_STORAGE
-#define tdesc "Comedian Mail (Voicemail System) with IMAP Storage"
 #else
-#define tdesc "Comedian Mail (Voicemail System)"
+# ifdef IMAP_STORAGE
+# define tdesc "Comedian Mail (Voicemail System) with IMAP Storage"
+# else
+# define tdesc "Comedian Mail (Voicemail System)"
+# endif
 #endif
 
 static char userscontext[AST_MAX_EXTENSION] = "default";
@@ -449,9 +495,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";
 
@@ -481,8 +525,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";
 
@@ -522,6 +565,49 @@ 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 audio control prompts for voicemail playback */
+static char listen_control_forward_key[12];
+static char listen_control_reverse_key[12];
+static char listen_control_pause_key[12];
+static char listen_control_restart_key[12];
+static char listen_control_stop_key[12];
+
 /* custom password sounds */
 static char vm_password[80] = "vm-password";
 static char vm_newpassword[80] = "vm-newpassword";
@@ -533,9 +619,9 @@ static struct ast_flags globalflags = {0};
 
 static int saydurationminfo;
 
-static char dialcontext[AST_MAX_CONTEXT];
-static char callcontext[AST_MAX_CONTEXT];
-static char exitcontext[AST_MAX_CONTEXT];
+static char dialcontext[AST_MAX_CONTEXT] = "";
+static char callcontext[AST_MAX_CONTEXT] = "";
+static char exitcontext[AST_MAX_CONTEXT] = "";
 
 static char cidinternalcontexts[MAX_NUM_CID_CONTEXTS][64];
 
@@ -566,6 +652,7 @@ static int vm_play_folder_name(struct ast_channel *chan, char *mbox);
 static int notify_new_message(struct ast_channel *chan, struct ast_vm_user *vmu, int msgnum, long duration, char *fmt, char *cidnum, char *cidname);
 static void make_email_file(FILE *p, char *srcemail, struct ast_vm_user *vmu, int msgnum, char *context, char *mailbox, char *cidnum, char *cidname, char *attach, char *format, int duration, int attach_user_voicemail, struct ast_channel *chan, const char *category, int imap);
 static void apply_options(struct ast_vm_user *vmu, const char *options);
+static int is_valid_dtmf(const char *key);
 
 #if !(defined(ODBC_STORAGE) || defined(IMAP_STORAGE))
 static int __has_voicemail(const char *context, const char *mailbox, const char *folder, int shortcircuit);
@@ -578,12 +665,9 @@ static void populate_defaults(struct ast_vm_user *vmu)
        ast_copy_flags(vmu, (&globalflags), AST_FLAGS_ALL);     
        if (saydurationminfo)
                vmu->saydurationm = saydurationminfo;
-       if (callcontext)
-               ast_copy_string(vmu->callback, callcontext, sizeof(vmu->callback));
-       if (dialcontext)
-               ast_copy_string(vmu->dialout, dialcontext, sizeof(vmu->dialout));
-       if (exitcontext)
-               ast_copy_string(vmu->exit, exitcontext, sizeof(vmu->exit));
+       ast_copy_string(vmu->callback, callcontext, sizeof(vmu->callback));
+       ast_copy_string(vmu->dialout, dialcontext, sizeof(vmu->dialout));
+       ast_copy_string(vmu->exit, exitcontext, sizeof(vmu->exit));
        if (vmmaxsecs)
                vmu->maxsecs = vmmaxsecs;
        if (maxmsg)
@@ -727,6 +811,21 @@ static void apply_options_full(struct ast_vm_user *retval, struct ast_variable *
        } 
 }
 
+static int is_valid_dtmf(const char *key)
+{
+       int i;
+       char *local_key = ast_strdupa(key);
+
+       for(i = 0; i < strlen(key); ++i) {
+               if(!strchr(VALID_DTMF, *local_key)) {
+                       ast_log(LOG_WARNING, "Invalid DTMF key \"%c\" used in voicemail configuration file\n", *local_key);
+                       return 0;
+               }
+               local_key++;
+       }
+       return 1;
+}
+
 static struct ast_vm_user *find_user_realtime(struct ast_vm_user *ivm, const char *context, const char *mailbox)
 {
        struct ast_variable *var;
@@ -749,7 +848,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;
                }       
        } 
@@ -833,7 +932,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 */
@@ -846,26 +945,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);
                        }
@@ -893,8 +988,9 @@ static int make_dir(char *dest, int len, const char *context, const char *ext, c
 #ifdef IMAP_STORAGE
 static int make_gsm_file(char *dest, char *imapuser, char *dir, int num)
 {
-       if (mkdir(dir, 01777) && (errno != EEXIST)) {
-               ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dir, strerror(errno));
+       int res;
+       if ((res = ast_mkdir(dir, 01777))) {
+               ast_log(LOG_WARNING, "ast_mkdir '%s' failed: %s\n", dir, strerror(res));
                return sprintf(dest, "%s/msg%04d", dir, num);
        }
        /* return sprintf(dest, "%s/s/msg%04d", dir, imapuser, num); */
@@ -914,8 +1010,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");
@@ -933,34 +1028,19 @@ 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)
 {
        mode_t  mode = VOICEMAIL_DIR_MODE;
+       int res;
 
-       if (!ast_strlen_zero(context)) {
-               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;
-               }
-       }
-       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;
-               }
-       }
-       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;
-               }
+       make_dir(dest, len, context, ext, folder);
+       if ((res = ast_mkdir(dest, mode))) {
+               ast_log(LOG_WARNING, "ast_mkdir '%s' failed: %s\n", dest, strerror(res));
+               return -1;
        }
-       return 1;
+       return 0;
 }
 
 /*! \brief Lock file path
@@ -985,7 +1065,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];
@@ -1102,7 +1182,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);
@@ -1157,6 +1237,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;
@@ -1380,10 +1463,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];
@@ -1436,7 +1519,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;
@@ -1485,7 +1568,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);
@@ -1573,6 +1656,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);
 }
 
@@ -1629,10 +1715,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
 
@@ -1667,6 +1786,8 @@ static int last_message_index(struct ast_vm_user *vmu, char *dir)
        return x - 1;
 }
 
+#endif
+
 static int vm_delete(char *file)
 {
        char *txt;
@@ -1677,13 +1798,14 @@ 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);
 }
 
-
-#endif
 static int inbuf(struct baseio *bio, FILE *fi)
 {
        int l;
@@ -1842,10 +1964,10 @@ static char *quote(const char *from, char *to, size_t len)
  * fill in *tm for current time according to the proper timezone, if any.
  * Return tm so it can be used as a function argument.
  */
-static const struct tm *vmu_tm(const struct ast_vm_user *vmu, struct tm *tm)
+static const struct ast_tm *vmu_tm(const struct ast_vm_user *vmu, struct ast_tm *tm)
 {
        const struct vm_zone *z = NULL;
-       time_t t = time(NULL);
+       struct timeval t = ast_tvnow();
 
        /* Does this user have a timezone specified? */
        if (!ast_strlen_zero(vmu->zonetag)) {
@@ -1885,25 +2007,37 @@ static void make_email_file(FILE *p, char *srcemail, struct ast_vm_user *vmu, in
        char fname[256];
        char dur[256];
        char tmpcmd[256];
-       struct tm tm;
+       struct ast_tm tm;
        char *passdata2;
        size_t len_passdata;
+       char *greeting_attachment;
+
+#ifdef IMAP_STORAGE
+#define ENDL "\r\n"
+#else
+#define ENDL "\n"
+#endif
 
        gethostname(host, sizeof(host)-1);
        if (strchr(srcemail, '@'))
                ast_copy_string(who, srcemail, sizeof(who));
        else 
                snprintf(who, sizeof(who), "%s@%s", srcemail, host);
+       
+       greeting_attachment = strrchr(ast_strdupa(attach), '/');
+       if (greeting_attachment)
+               *greeting_attachment++ = '\0';
+
        snprintf(dur, sizeof(dur), "%d:%02d", duration / 60, duration % 60);
-       strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", vmu_tm(vmu, &tm));
-       fprintf(p, "Date: %s\r\n", date);
+       ast_strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", vmu_tm(vmu, &tm));
+       fprintf(p, "Date: %s" ENDL, date);
 
        /* Set date format for voicemail mail */
-       strftime(date, sizeof(date), emaildateformat, &tm);
+       ast_strftime(date, sizeof(date), emaildateformat, &tm);
 
        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))) {
@@ -1912,27 +2046,27 @@ static void make_email_file(FILE *p, char *srcemail, struct ast_vm_user *vmu, in
                                pbx_substitute_variables_helper(ast, fromstring, passdata, vmlen);
                                len_passdata = strlen(passdata) * 2 + 3;
                                passdata2 = alloca(len_passdata);
-                               fprintf(p, "From: %s <%s>\r\n", quote(passdata, passdata2, len_passdata), who);
+                               fprintf(p, "From: %s <%s>" ENDL, quote(passdata, passdata2, len_passdata), who);
                        } else
                                ast_log(LOG_WARNING, "Cannot allocate workspace for variable substitution\n");
                        ast_channel_free(ast);
                } else
                        ast_log(LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
        } else
-               fprintf(p, "From: Asterisk PBX <%s>\r\n", who);
+               fprintf(p, "From: Asterisk PBX <%s>" ENDL, who);
        len_passdata = strlen(vmu->fullname) * 2 + 3;
        passdata2 = alloca(len_passdata);
-       fprintf(p, "To: %s <%s>\r\n", quote(vmu->fullname, passdata2, len_passdata), vmu->email);
+       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))) {
                                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, emailsubject, passdata, vmlen);
-                               fprintf(p, "Subject: %s\r\n", passdata);
+                               fprintf(p, "Subject: %s" ENDL, passdata);
                        } else
                                ast_log(LOG_WARNING, "Cannot allocate workspace for variable substitution\n");
                        ast_channel_free(ast);
@@ -1940,105 +2074,108 @@ static void make_email_file(FILE *p, char *srcemail, struct ast_vm_user *vmu, in
                        ast_log(LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
        } else  if (!ast_strlen_zero(emailtitle)) {
                fprintf(p, emailtitle, msgnum + 1, mailbox) ;
-               fprintf(p,"\r\n") ;
+               fprintf(p, ENDL) ;
        } else if (ast_test_flag((&globalflags), VM_PBXSKIP))
-               fprintf(p, "Subject: New message %d in mailbox %s\r\n", msgnum + 1, mailbox);
+               fprintf(p, "Subject: New message %d in mailbox %s" ENDL, msgnum + 1, mailbox);
        else
-               fprintf(p, "Subject: [PBX]: New message %d in mailbox %s\r\n", msgnum + 1, mailbox);
-       fprintf(p, "Message-ID: <Asterisk-%d-%d-%s-%d@%s>\r\n", msgnum, (unsigned int)ast_random(), mailbox, getpid(), host);
+               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 + 1, (unsigned int)ast_random(), mailbox, getpid(), host);
        if(imap) {
                /* additional information needed for IMAP searching */
-               fprintf(p, "X-Asterisk-VM-Message-Num: %d\r\n", msgnum + 1);
-               /* fprintf(p, "X-Asterisk-VM-Orig-Mailbox: %s\r\n", ext); */
-               fprintf(p, "X-Asterisk-VM-Server-Name: %s\r\n", fromstring);
-               fprintf(p, "X-Asterisk-VM-Context: %s\r\n", context);
-               fprintf(p, "X-Asterisk-VM-Extension: %s\r\n", mailbox);
-               fprintf(p, "X-Asterisk-VM-Priority: %d\r\n", chan->priority);
-               fprintf(p, "X-Asterisk-VM-Caller-channel: %s\r\n", chan->name);
-               fprintf(p, "X-Asterisk-VM-Caller-ID-Num: %s\r\n", cidnum);
-               fprintf(p, "X-Asterisk-VM-Caller-ID-Name: %s\r\n", cidname);
-               fprintf(p, "X-Asterisk-VM-Duration: %d\r\n", duration);
-               if (!ast_strlen_zero(category))
-                       fprintf(p, "X-Asterisk-VM-Category: %s\r\n", category);
-               fprintf(p, "X-Asterisk-VM-Orig-date: %s\r\n", date);
-               fprintf(p, "X-Asterisk-VM-Orig-time: %ld\r\n", (long)time(NULL));
+               fprintf(p, "X-Asterisk-VM-Message-Num: %d" ENDL, msgnum + 1);
+               /* fprintf(p, "X-Asterisk-VM-Orig-Mailbox: %s" ENDL, ext); */
+               fprintf(p, "X-Asterisk-VM-Server-Name: %s" ENDL, fromstring);
+               fprintf(p, "X-Asterisk-VM-Context: %s" ENDL, context);
+               fprintf(p, "X-Asterisk-VM-Extension: %s" ENDL, mailbox);
+               fprintf(p, "X-Asterisk-VM-Priority: %d" ENDL, chan->priority);
+               fprintf(p, "X-Asterisk-VM-Caller-channel: %s" ENDL, chan->name);
+               fprintf(p, "X-Asterisk-VM-Caller-ID-Num: %s" ENDL, cidnum);
+               fprintf(p, "X-Asterisk-VM-Caller-ID-Name: %s" ENDL, cidname);
+               fprintf(p, "X-Asterisk-VM-Duration: %d" ENDL, duration);
+               if (!ast_strlen_zero(category)) 
+                       fprintf(p, "X-Asterisk-VM-Category: %s" ENDL, category);
+               fprintf(p, "X-Asterisk-VM-Message-Type: %s\n", msgnum > -1 ? "Message" : greeting_attachment);
+               fprintf(p, "X-Asterisk-VM-Orig-date: %s" ENDL, date);
+               fprintf(p, "X-Asterisk-VM-Orig-time: %ld" ENDL, (long)time(NULL));
        }
        if (!ast_strlen_zero(cidnum))
-               fprintf(p, "X-Asterisk-CallerID: %s\r\n", cidnum);
+               fprintf(p, "X-Asterisk-CallerID: %s" ENDL, cidnum);
        if (!ast_strlen_zero(cidname))
-               fprintf(p, "X-Asterisk-CallerIDName: %s\r\n", cidname);
-       fprintf(p, "MIME-Version: 1.0\r\n");
+               fprintf(p, "X-Asterisk-CallerIDName: %s" ENDL, cidname);
+       fprintf(p, "MIME-Version: 1.0" ENDL);
        if (attach_user_voicemail) {
                /* Something unique. */
-               snprintf(bound, sizeof(bound), "voicemail_%d%s%d%d", msgnum, mailbox, getpid(), (unsigned int)ast_random());
-
-               fprintf(p, "Content-Type: multipart/mixed; boundary=\"%s\"\r\n\r\n\r\n", bound);
+               snprintf(bound, sizeof(bound), "----voicemail_%d%s%d%d", msgnum + 1, mailbox, getpid(), (unsigned int)ast_random());
 
-               fprintf(p, "--%s\r\n", bound);
+               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\r\nContent-Transfer-Encoding: 8bit\r\n\r\n", charset);
+       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))) {
                                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, emailbody, passdata, vmlen);
-                               fprintf(p, "%s\r\n", passdata);
+                               fprintf(p, "%s" ENDL, passdata);
                        } else
                                ast_log(LOG_WARNING, "Cannot allocate workspace for variable substitution\n");
                        ast_channel_free(ast);
                } else
                        ast_log(LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
-       } else {
-               fprintf(p, "Dear %s:\r\n\r\n\tJust wanted to let you know you were just left a %s long message (number %d)\r\n"
+       } else if (msgnum > -1){
+               fprintf(p, "Dear %s:" ENDL ENDL "\tJust wanted to let you know you were just left a %s long message (number %d)" ENDL
 
-               "in mailbox %s from %s, on %s so you might\r\n"
-               "want to check it when you get a chance.  Thanks!\r\n\r\n\t\t\t\t--Asterisk\r\n\r\n", vmu->fullname, 
+               "in mailbox %s from %s, on %s so you might" ENDL
+               "want to check it when you get a chance.  Thanks!" ENDL ENDL "\t\t\t\t--Asterisk" ENDL ENDL, vmu->fullname, 
                dur, msgnum + 1, mailbox, (cidname ? cidname : (cidnum ? cidnum : "an unknown caller")), date);
+       } else {
+               fprintf(p, "This message is to let you know that your greeting was changed on %s." ENDL
+                               "Please do not delete this message, lest your greeting vanish with it." ENDL ENDL, date);
        }
        if (attach_user_voicemail) {
                /* Eww. We want formats to tell us their own MIME type */
                char *ctype = (!strcasecmp(format, "ogg")) ? "application/" : "audio/x-";
                char tmpdir[256], newtmp[256];
-               int tmpfd;
+               int tmpfd = -1;
        
-               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);
                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);
-               }
-               fprintf(p, "--%s\r\n", bound);
-               fprintf(p, "Content-Type: %s%s; name=\"msg%04d.%s\"\r\n", ctype, format, msgnum, format);
-               fprintf(p, "Content-Transfer-Encoding: base64\r\n");
-               fprintf(p, "Content-Description: Voicemail sound attachment.\r\n");
-               fprintf(p, "Content-Disposition: attachment; filename=\"msg%04d.%s\"\r\n\r\n", msgnum, format);
+                       create_dirpath(tmpdir, sizeof(tmpdir), vmu->context, vmu->mailbox, "tmp");
+                       snprintf(newtmp, sizeof(newtmp), "%s/XXXXXX", tmpdir);
+                       tmpfd = mkstemp(newtmp);
+                       ast_debug(3, "newtmp: %s\n", newtmp);
+                       if (tmpfd > -1) {
+                               snprintf(tmpcmd, sizeof(tmpcmd), "sox -v %.4f %s.%s %s.%s", vmu->volgain, attach, format, newtmp, format);
+                               ast_safe_system(tmpcmd);
+                               attach = newtmp;
+                               ast_debug(3, "VOLGAIN: Stored at: %s.%s - Level: %.4f - Mailbox: %s\n", attach, format, vmu->volgain, mailbox);
+                       }
+               }
+               fprintf(p, "--%s" ENDL, bound);
+               if (msgnum > -1)
+                       fprintf(p, "Content-Type: %s%s; name=\"msg%04d.%s\"" ENDL, ctype, format, msgnum + 1, format);
+               else
+                       fprintf(p, "Content-Type: %s%s; name=\"%s.%s\"" ENDL, ctype, format, greeting_attachment, format);
+               fprintf(p, "Content-Transfer-Encoding: base64" ENDL);
+               fprintf(p, "Content-Description: Voicemail sound attachment." ENDL);
+               if (msgnum > -1)
+                       fprintf(p, "Content-Disposition: attachment; filename=\"msg%04d.%s\"" ENDL ENDL, msgnum + 1, format);
+               else
+                       fprintf(p, "Content-Disposition: attachment; filename=\"%s.%s\"" ENDL ENDL, greeting_attachment, 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\r\n", bound);
-                       fprintf(p, "Content-Type: audio/x-gsm; name=\"msg%04d.%s\"\r\n", msgnum, format);
-                       fprintf(p, "Content-Transfer-Encoding: base64\r\n");
-                       fprintf(p, "Content-Description: Voicemail sound attachment.\r\n");
-                       fprintf(p, "Content-Disposition: attachment; filename=\"msg%04d.gsm\"\r\n\r\n", msgnum);
-                       snprintf(fname, sizeof(fname), "%s.gsm", attach);
-                       base_encode(fname, p);
-               }
-               fprintf(p, "\r\n\r\n--%s--\r\n.\r\n", bound);
-               if (tmpfd > -1)
+               fprintf(p, ENDL "--%s--" ENDL "." ENDL, bound);
+               if (tmpfd > -1) {
+                       unlink(fname);
                        close(tmpfd);
-               unlink(newtmp);
+                       unlink(newtmp);
+               }
        }
+#undef ENDL
 }
 
 static int sendmail(char *srcemail, struct ast_vm_user *vmu, int msgnum, char *context, char *mailbox, char *cidnum, char *cidname, char *attach, char *format, int duration, int attach_user_voicemail, struct ast_channel *chan, const char *category)
@@ -2053,8 +2190,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 %lld\n", attach, format, attach_user_voicemail, (unsigned long long)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) {
@@ -2065,8 +2201,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;
 }
@@ -2079,7 +2214,7 @@ static int sendpage(char *srcemail, char *pager, int msgnum, char *context, char
        char dur[PATH_MAX];
        char tmp[80] = "/tmp/astmail-XXXXXX";
        char tmp2[PATH_MAX];
-       struct tm tm;
+       struct ast_tm tm;
        FILE *p;
 
        if ((p = vm_mkftemp(tmp)) == NULL) {
@@ -2092,12 +2227,12 @@ static int sendpage(char *srcemail, char *pager, int msgnum, char *context, char
        else 
                snprintf(who, sizeof(who), "%s@%s", srcemail, host);
        snprintf(dur, sizeof(dur), "%d:%02d", duration / 60, duration % 60);
-       strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", vmu_tm(vmu, &tm));
+       ast_strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", vmu_tm(vmu, &tm));
        fprintf(p, "Date: %s\n", date);
 
        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))) {
@@ -2115,7 +2250,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))) {
@@ -2131,19 +2266,17 @@ static int sendpage(char *srcemail, char *pager, int msgnum, char *context, char
        } else
                fprintf(p, "Subject: New VM\n\n");
 
-       strftime(date, sizeof(date), "%A, %B %d, %Y at %r", &tm);
+       ast_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");
@@ -2154,18 +2287,16 @@ 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;
 }
 
 static int get_date(char *s, int len)
 {
-       struct tm tm;
-       time_t t;
-       t = time(0);
-       localtime_r(&t,&tm);
-       return strftime(s, len, "%a %b %e %r %Z %Y", &tm);
+       struct ast_tm tm;
+       struct timeval t = ast_tvnow();
+       ast_localtime(&t, &tm, NULL);
+       return ast_strftime(s, len, "%a %b %e %r %Z %Y", &tm);
 }
 
 static int invent_message(struct ast_channel *chan, char *context, char *ext, int busy, char *ecodes)
@@ -2176,12 +2307,12 @@ 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, ""))) {
                ast_log(LOG_WARNING, "Failed to make directory(%s)\n", fn);
                return -1;
        }
 
-       RETRIEVE(fn, -1);
+       RETRIEVE(fn, -1, ext, context);
        if (ast_fileexists(fn, NULL, NULL) > 0) {
                res = ast_stream_and_wait(chan, fn, ecodes);
                if (res) {
@@ -2204,13 +2335,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)
@@ -2440,21 +2573,29 @@ static int imap_store_file(char *dir, char *mailboxuser, char *mailboxcontext, i
        if (!ast_strlen_zero(vmu->serveremail))
                myserveremail = vmu->serveremail;
 
-       make_file(fn, sizeof(fn), dir, msgnum);
-
+       if (msgnum > -1)
+               make_file(fn, sizeof(fn), dir, msgnum);
+       else
+               ast_copy_string (fn, dir, sizeof(fn));
+       
        if (ast_strlen_zero(vmu->email))
                ast_copy_string(vmu->email, vmu->imapuser, sizeof(vmu->email));
 
        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 */
        if (!(p = vm_mkftemp(tmp))) {
                ast_log(LOG_WARNING, "Unable to store '%s' (can't create temporary file)\n", fn);
                return -1;
+
+       }
+
+       if (msgnum < 0 && imapgreetings) {
+               init_mailstream(vms, GREETINGS_FOLDER);
+               imap_delete_old_greeting(fn, vms);
        }
        
        make_email_file(p, myserveremail, vmu, msgnum, vmu->context, vmu->mailbox, S_OR(chan->cid.cid_num, NULL), S_OR(chan->cid.cid_name, NULL), fn, fmt, duration, 1, chan, NULL, 1);
@@ -2468,14 +2609,14 @@ static int imap_store_file(char *dir, char *mailboxuser, char *mailboxcontext, i
        fread(buf, len, 1, p);
        ((char *)buf)[len] = '\0';
        INIT(&str, mail_string, buf, len);
-       imap_mailbox_name(mailbox, vms, 0, 1);
+       init_mailstream(vms, NEW_FOLDER);
+       imap_mailbox_name(mailbox, vms, NEW_FOLDER, 1);
        if(!mail_append(vms->mailstream, mailbox, &str))
                ast_log(LOG_ERROR, "Error while sending the message to %s\n", mailbox);
        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;
 
 }
@@ -2499,11 +2640,10 @@ 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))
+       if (ast_strlen_zero(mailbox)) 
                return 0;
 
        if (strchr(mailbox, ',')) {
@@ -2538,7 +2678,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;
@@ -2547,46 +2687,46 @@ 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));
+               ast_copy_string(vms_p->curbox, mbox(NEW_FOLDER), sizeof(vms_p->curbox));
                init_vm_state(vms_p);
                vmstate_insert(vms_p);
        }
 
        /* If no mailstream exists yet and even after attempting to initialize it fails, bail out */
-       if (!vms_p->mailstream) {
-               ret = init_mailstream(vms_p, 0);
-               if (!vms_p->mailstream) {
-                       ast_log (LOG_ERROR,"Houston we have a problem - IMAP mailstream is NULL\n");
-                       return -1;
-               }
+       ret = init_mailstream(vms_p, NEW_FOLDER);
+       if (!vms_p->mailstream) {
+               ast_log (LOG_ERROR,"Houston we have a problem - IMAP mailstream is NULL\n");
+               free_user(vmu);
+               return -1;
        }
 
-       if (!ret && vms_p->updated == 1) {
+       if (!ret && vms_p->updated > 0) {
                if (newmsgs) {
                        pgm = mail_newsearchpgm();
                        hdr = mail_newsearchheader("X-Asterisk-VM-Extension", (char *)mailboxnc);
@@ -2617,10 +2757,8 @@ static int inboxcount(const char *mailbox, int *newmsgs, int *oldmsgs)
                }
        }
 
-       if (vms_p->updated == 1) {  /* changes, so we did the searches above */
+       if (vms_p->updated > 1) {  /* changes, so we did the searches above */
                vms_p->updated = 0;
-       } else if (vms_p->updated > 1) {  /* decrement delay count */
-               vms_p->updated--;
        } else {  /* no changes, so don't search */
                mail_ping(vms_p->mailstream);
                /* Keep the old data */
@@ -2628,6 +2766,7 @@ static int inboxcount(const char *mailbox, int *newmsgs, int *oldmsgs)
                *oldmsgs = vms_p->oldmessages;
        }
 
+       free_user(vmu);
        return 0;
  }
 
@@ -2817,7 +2956,7 @@ static void run_externnotify(char *context, char *extension)
        else
                ast_copy_string(ext_context, extension, sizeof(ext_context));
 
-       if (!strcasecmp(externnotify, "smdi")) {
+       if (smdi_iface) {
                if (ast_app_has_voicemail(ext_context, NULL)) 
                        ast_smdi_mwi_set(smdi_iface, extension);
                else
@@ -2832,23 +2971,23 @@ 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);
                }
-       } else if (!ast_strlen_zero(externnotify)) {
+       }
+
+       if (!ast_strlen_zero(externnotify)) {
                if (inboxcount(ext_context, &newvoicemails, &oldvoicemails)) {
                        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);
                }
        }
 }
 
 struct leave_vm_options {
-       unsigned int flags;
+       uint64_t flags;
        signed char record_gain;
 };
 
@@ -2869,8 +3008,12 @@ 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];
        char prefile[PATH_MAX] = "";
        char tempfile[PATH_MAX] = "";
@@ -2878,7 +3021,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;
@@ -2897,12 +3040,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;
        }
@@ -2910,26 +3050,23 @@ static int leave_voicemail(struct ast_channel *chan, char *ext, struct leave_vm_
        if (strcmp(vmu->context, "default"))
                snprintf(ext_context, sizeof(ext_context), "%s@%s", ext, vmu->context);
        else
-               ast_copy_string(ext_context, vmu->context, sizeof(ext_context));
+               ast_copy_string(ext_context, vmu->mailbox, sizeof(ext_context));
        if (ast_test_flag(options, OPT_BUSY_GREETING)) {
-               res = create_dirpath(dest, sizeof(dest), vmu->context, ext, "busy");
                snprintf(prefile, sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, ext);
        } else if (ast_test_flag(options, OPT_UNAVAIL_GREETING)) {
-               res = create_dirpath(dest, sizeof(dest), vmu->context, ext, "unavail");
                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(tmpdir, sizeof(tmpdir), vmu->context, ext, "tmp"))) {
                ast_log(LOG_WARNING, "Failed to make directory (%s)\n", tempfile);
                return -1;
        }
-       RETRIEVE(tempfile, -1);
+       RETRIEVE(tempfile, -1, ext, context);
        if (ast_fileexists(tempfile, NULL, NULL) > 0)
                ast_copy_string(prefile, tempfile, sizeof(prefile));
        DISPOSE(tempfile, -1);
        /* It's easier just to try to make it than to check for its existence */
        create_dirpath(dir, sizeof(dir), vmu->context, ext, "INBOX");
-       create_dirpath(tmpdir, sizeof(tmpdir), vmu->context, ext, "tmp");
 
        /* Check current or macro-calling context for special extensions */
        if (ast_test_flag(vmu, VM_OPERATOR)) {
@@ -2960,19 +3097,17 @@ static int leave_voicemail(struct ast_channel *chan, char *ext, struct leave_vm_
 
        /* Play the beginning intro if desired */
        if (!ast_strlen_zero(prefile)) {
-               RETRIEVE(prefile, -1);
+               RETRIEVE(prefile, -1, ext, context);
                if (ast_fileexists(prefile, NULL, NULL) > 0) {
                        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;
@@ -3039,39 +3174,45 @@ static int leave_voicemail(struct ast_channel *chan, char *ext, struct leave_vm_
 #ifdef IMAP_STORAGE
                /* Is ext a mailbox? */
                /* 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);
-                       newmsgs = vms->newmessages++;
-                       oldmsgs = vms->oldmessages;
-               } else {
-                       res = inboxcount(ext, &newmsgs, &oldmsgs);
-                       if(res < 0) {
-                               ast_log(LOG_NOTICE,"Can not leave voicemail, unable to count messages\n");
+               res = inboxcount(ext_context, &newmsgs, &oldmsgs);
+               if(res < 0) {
+                       ast_log(LOG_NOTICE,"Can not leave voicemail, unable to count messages\n");
+                       return -1;
+               }
+               if(!(vms = get_vm_state_by_mailbox(ext,0))) {
+               /*It is possible under certain circumstances that inboxcount did not create a vm_state when it was needed. This is a catchall which will
+                * rarely be used*/
+                       if (!(vms = ast_calloc(1, sizeof(*vms)))) {
+                               ast_log(LOG_ERROR, "Couldn't allocate necessary space\n");
                                return -1;
                        }
+                       ast_copy_string(vms->imapuser, vmu->imapuser, sizeof(vms->imapuser));
+                       ast_copy_string(vms->username, ext, sizeof(vms->username));
+                       vms->mailstream = NIL;
+                       ast_debug(3, "Copied %s to %s\n", vmu->imapuser, vms->imapuser);
+                       vms->updated=1;
+                       ast_copy_string(vms->curbox, mbox(0), sizeof(vms->curbox));
+                       init_vm_state(vms);
+                       vmstate_insert(vms);
                        vms = get_vm_state_by_mailbox(ext,0);
                }
+               vms->newmessages++;
+               
                /* 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) {
@@ -3101,6 +3242,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) {
@@ -3143,6 +3292,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);
@@ -3152,12 +3305,17 @@ 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 {
+#ifndef IMAP_STORAGE
                                        msgnum = last_message_index(vmu, dir) + 1;
+#endif
                                        make_file(fn, sizeof(fn), dir, msgnum);
 
                                        /* assign a variable with the name of the voicemail file */ 
@@ -3171,7 +3329,17 @@ static int leave_voicemail(struct ast_channel *chan, char *ext, struct leave_vm_
                                        ast_filerename(tmptxtfile, fn, NULL);
                                        rename(tmptxtfile, txtfile);
 
+                                       /* Properly set permissions on voicemail text descriptor file.
+                                          Unfortunately mkstemp() makes this file 0600 on most unix systems. */
+                                       if (chmod(txtfile, VOICEMAIL_FILE_MODE) < 0)
+                                               ast_log(LOG_ERROR, "Couldn't set permissions on voicemail text file %s: %s", txtfile, strerror(errno));
+
                                        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) {
@@ -3267,8 +3435,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;
@@ -3417,8 +3584,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 */
@@ -3426,8 +3592,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 */
@@ -3886,7 +4051,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);
                                }
@@ -3921,6 +4086,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;
@@ -3969,6 +4157,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;
@@ -3982,6 +4172,7 @@ static int forward_message(struct ast_channel *chan, char *context, struct vm_st
        char *temp;
        char todir[256];
        int todircount=0;
+       struct vm_state *dstvms;
 #endif
        char username[70]="";
        int res = 0, cmd = 0;
@@ -4125,14 +4316,13 @@ static int forward_message(struct ast_channel *chan, char *context, struct vm_st
                char buf[1024] = "";
                int attach_user_voicemail = ast_test_flag((&globalflags), VM_ATTACH);
 #endif
-               RETRIEVE(dir, curmsg);
+               RETRIEVE(dir, curmsg, sender->mailbox, context);
                cmd = vm_forwardoptions(chan, sender, dir, curmsg, vmfmts, S_OR(context, "default"), record_gain, &duration, vms);
                if (!cmd) {
                        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;
@@ -4161,21 +4351,31 @@ 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");
                                /* should not assume "fmt" here! */
                                save_body(body,vms,"2",fmt);
  
-                               STORE(todir, vmtmp->mailbox, vmtmp->context, vms->curmsg, chan, vmtmp, fmt, duration, vms);
+                               /* get destination mailbox */
+                               dstvms = get_vm_state_by_mailbox(vmtmp->mailbox,0);
+                               if (dstvms) {
+                                       init_mailstream(dstvms, 0);
+                                       if (!dstvms->mailstream) {
+                                               ast_log (LOG_ERROR,"IMAP mailstream for %s is NULL\n",vmtmp->mailbox);
+                                       } else {
+                                               STORE(todir, vmtmp->mailbox, vmtmp->context, dstvms->curmsg, chan, vmtmp, fmt, duration, dstvms);
+                                               run_externnotify(vmtmp->context, vmtmp->mailbox); 
+                                       }
+                               } else {
+                                       ast_log (LOG_ERROR,"Could not find state information for mailbox %s\n",vmtmp->mailbox);
+                               }
 
                                if (!ast_strlen_zero(vmtmp->serveremail))
                                        myserveremail = vmtmp->serveremail;
@@ -4206,6 +4406,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;
 }
 
@@ -4219,7 +4423,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, listen_control_forward_key, listen_control_reverse_key, listen_control_stop_key, listen_control_pause_key, listen_control_restart_key, skipms, NULL);
 }
 
 static int play_message_category(struct ast_channel *chan, const char *category)
@@ -4265,10 +4469,9 @@ static int play_message_datetime(struct ast_channel *chan, struct ast_vm_user *v
 /* No internal variable parsing for now, so we'll comment it out for the time being */
 #if 0
        /* Set the DIFF_* variables */
-       localtime_r(&t, &time_now);
+       ast_localtime(&t, &time_now, NULL);
        tv_now = ast_tvnow();
-       tnow = tv_now.tv_sec;
-       localtime_r(&tnow,&time_then);
+       ast_localtime(&tv_now, &time_then, NULL);
 
        /* Day difference */
        if (time_now.tm_year == time_then.tm_year)
@@ -4297,6 +4500,8 @@ static int play_message_datetime(struct ast_channel *chan, struct ast_vm_user *v
                res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q  H 'digits/kai' M ", NULL);
        else if (!strcasecmp(chan->language,"pt_BR"))
                res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' Ad 'digits/pt-de' B 'digits/pt-de' Y 'digits/pt-as' HM ", NULL);
+       else if (!strcasecmp(chan->language,"tw"))      /* CHINESE (Taiwan) syntax */
+               res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "qR 'vm-received'", NULL);               
        else
                res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q 'digits/at' IMp", NULL);
 #if 0
@@ -4321,15 +4526,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;
                }
@@ -4357,8 +4560,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");
@@ -4366,8 +4568,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");
        }
@@ -4387,8 +4588,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");
@@ -4437,12 +4637,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");
@@ -4460,7 +4660,24 @@ 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)
@@ -4589,7 +4806,7 @@ static int play_message(struct ast_channel *chan, struct ast_vm_user *vmu, struc
        /* Retrieve info from VM attribute file */
        make_file(vms->fn2, sizeof(vms->fn2), vms->curdir, vms->curmsg);
        snprintf(filename, sizeof(filename), "%s.txt", vms->fn2);
-       RETRIEVE(vms->curdir, vms->curmsg);
+       RETRIEVE(vms->curdir, vms->curmsg, vmu->mailbox, vmu->context);
        msg_cfg = ast_config_load(filename);
        if (!msg_cfg) {
                ast_log(LOG_WARNING, "No message attribute file?!! (%s)\n", filename);
@@ -4639,9 +4856,9 @@ static void imap_mailbox_name(char *spec, struct vm_state *vms, int box, int use
        char tmp[256], *t = tmp;
        size_t left = sizeof(tmp);
 
-       if (box == 1) {
-               ast_copy_string(vms->curbox, mbox(0), sizeof(vms->curbox));
-               sprintf(vms->vmbox, "vm-%s", mbox(1));
+       if (box == OLD_FOLDER) {
+               ast_copy_string(vms->curbox, mbox(NEW_FOLDER), sizeof(vms->curbox));
+               sprintf(vms->vmbox, "vm-%s", mbox(OLD_FOLDER));
        } else {
                ast_copy_string(vms->curbox, mbox(box), sizeof(vms->curbox));
                snprintf(vms->vmbox, sizeof(vms->vmbox), "vm-%s", vms->curbox);
@@ -4652,7 +4869,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))
@@ -4661,8 +4878,10 @@ static void imap_mailbox_name(char *spec, struct vm_state *vms, int box, int use
        /* End with username */
        ast_build_string(&t, &left, "/user=%s}", vms->imapuser);
 
-       if(box == 0 || box == 1)
+       if(box == NEW_FOLDER || box == OLD_FOLDER)
                sprintf(spec, "%s%s", tmp, use_folder? imapfolder: "INBOX");
+       else if (box == GREETINGS_FOLDER)
+               sprintf(spec, "%s%s", tmp, greetingfolder);
        else
                sprintf(spec, "%s%s%c%s", tmp, imapfolder, delimiter, mbox(box));
 }
@@ -4677,11 +4896,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;
        }
@@ -4690,9 +4907,13 @@ static int init_mailstream(struct vm_state *vms, int box)
 
        if (delimiter == '\0') {                /* did not probe the server yet */
                char *cp;
+#ifdef USE_SYSTEM_IMAP
+#include <imap/linkage.c>
+#else
 #include "linkage.c"
+#endif
                /* Connect to INBOX first to get folders delimiter */
-               imap_mailbox_name(tmp, vms, 0, 0);
+               imap_mailbox_name(tmp, vms, NEW_FOLDER, 0);
                stream = mail_open(stream, tmp, debug ? OP_DEBUG : NIL);
                if (stream == NIL) {
                        ast_log (LOG_ERROR, "Can't connect to imap server %s\n", tmp);
@@ -4707,8 +4928,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;
@@ -4725,9 +4945,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");
@@ -4747,17 +4965,16 @@ static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box)
        pgm->deleted = 0;
        pgm->undeleted = 1;
 
-       /* if box = 0, check for new, if box = 1, check for read */
-       if (box == 0) {
+       /* if box = NEW_FOLDER, check for new, if box = OLD_FOLDER, check for read */
+       if (box == NEW_FOLDER) {
                pgm->unseen = 1;
                pgm->seen = 0;
-       } else if (box == 1) {
+       } else if (box == OLD_FOLDER) {
                pgm->seen = 1;
                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);
@@ -4766,6 +4983,139 @@ static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box)
 
        return 0;
 }
+
+static int imap_remove_file(char *dir, int msgnum)
+{
+       char fn[PATH_MAX];
+       char full_fn[PATH_MAX];
+       char msgnums[80];
+       
+       if (msgnum > -1) {
+               snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
+               make_file(fn, sizeof(fn), dir, msgnum);
+       } else
+               ast_copy_string(fn, dir, sizeof(fn));
+       
+       if ((msgnum < 0 && imapgreetings) || msgnum > -1) {
+               ast_filedelete(fn, NULL);       
+               snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
+               unlink(full_fn);
+       }
+       return 0;
+}
+
+static int imap_retrieve_file (char *dir, int msgnum, char *mailbox, char *context)
+{
+       struct ast_vm_user *vmu;
+       struct vm_state *vms_p;
+       char *file, *filename;
+       char *attachment;
+       /*char *mb, *cur;*/
+       int ret = 0, i;
+       BODY *body;
+
+       /* This function is only used for retrieval of IMAP greetings
+        * regular messages are not retrieved this way, nor are greetings
+        * if they are stored locally*/
+       if (msgnum > -1 || !imapgreetings) {
+               return 0;
+       } else {
+               file = strrchr(ast_strdupa(dir), '/');
+               if (file)
+                       *file++ = '\0';
+               else {
+                       ast_debug (1, "Failed to procure file name from directory passed.\n");
+                       return -1;
+               }
+       }
+       /* 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); */
+       vmu = find_user(NULL, context, mailbox);
+       if (!vmu) {
+               ast_log (LOG_ERROR,"Couldn't find mailbox %s in context %s\n",mailbox,context);
+               return -1;
+       } else {
+               /* 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... */
+       vms_p = get_vm_state_by_mailbox(mailbox,0);
+       if (!vms_p) {
+               ast_log(LOG_ERROR, "Voicemail state not found!\n");
+               return -1;
+       }
+       
+       ret = init_mailstream(vms_p, GREETINGS_FOLDER);
+       if (!vms_p->mailstream) {
+               ast_log (LOG_ERROR,"IMAP mailstream is NULL\n");
+               free_user(vmu);
+               return -1;
+       }
+
+       for (i = 0; i < vms_p->mailstream->nmsgs; i++) {
+               mail_fetchstructure(vms_p->mailstream, i + 1, &body);
+               /* 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) {
+                       attachment = 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;
+               }
+               filename = strsep(&attachment, ".");
+               if (!strcmp(filename, file)) {
+                       ast_copy_string(vms_p->fn, dir, sizeof(vms_p->fn));
+                       vms_p->msgArray[vms_p->curmsg] = i + 1;
+                       save_body(body, vms_p, "2", attachment);
+                       free_user(vmu);
+                       return 0;
+               }
+       }
+
+       free_user(vmu);
+       return -1;
+}
+
+static int imap_delete_old_greeting (char *dir, struct vm_state *vms)
+{
+       char *file, *filename;
+       char *attachment;
+       char arg[10];
+       int i;
+       BODY* body;
+
+       
+       file = strrchr(ast_strdupa(dir), '/');
+       if (file)
+               *file++ = '\0';
+       else {
+               ast_log (LOG_ERROR, "Failed to procure file name from directory passed. You should never see this.\n");
+               return -1;
+       }
+       
+       for (i = 0; i < vms->mailstream->nmsgs; i++) {
+               mail_fetchstructure(vms->mailstream, i + 1, &body);
+               /* 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) {
+                       attachment = 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;
+               }
+               filename = strsep(&attachment, ".");
+               if (!strcmp(filename, file)) {
+                       sprintf (arg,"%d", i+1);
+                       mail_setflag (vms->mailstream,arg,"\\DELETED");
+               }
+       }
+       mail_expunge(vms->mailstream);
+       return 0;
+}
+
 #else
 static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu,int box)
 {
@@ -4853,6 +5203,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);
                } 
        } 
 
@@ -4865,11 +5221,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
@@ -4927,7 +5284,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")){
@@ -5400,14 +5757,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) {
@@ -5667,6 +6024,48 @@ static int vm_intro_ru(struct ast_channel *chan,struct vm_state *vms)
        return res;
 }
 
+/* CHINESE (Taiwan) syntax */
+static int vm_intro_tw(struct ast_channel *chan, struct vm_state *vms)
+{
+       int res;
+
+       /* Introduce messages they have */
+       res = ast_play_and_wait(chan, "vm-you");
+
+    if (!res && vms->newmessages) {
+        res = ast_play_and_wait(chan, "vm-have");
+        if (!res)
+            res = say_and_wait(chan, vms->newmessages, chan->language);
+        if (!res)
+            res = ast_play_and_wait(chan, "vm-tong");
+        if (!res)
+            res = ast_play_and_wait(chan, "vm-INBOX");
+        if (vms->oldmessages && !res)
+            res = ast_play_and_wait(chan, "vm-and");
+        else if (!res) 
+            res = ast_play_and_wait(chan, "vm-messages");
+
+    }
+    if (!res && vms->oldmessages) {
+        res = ast_play_and_wait(chan, "vm-have");
+        if (!res)
+            res = say_and_wait(chan, vms->oldmessages, chan->language);
+        if (!res)
+            res = ast_play_and_wait(chan, "vm-tong");
+        if (!res)
+            res = ast_play_and_wait(chan, "vm-Old");
+        if (!res)
+            res = ast_play_and_wait(chan, "vm-messages");
+    }
+    if (!res && !vms->oldmessages && !vms->newmessages) {
+        res = ast_play_and_wait(chan, "vm-haveno");
+        if (!res)
+            res = ast_play_and_wait(chan, "vm-messages");
+    }
+    return res;
+}
+
+
 
 static int vm_intro(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms)
 {
@@ -5706,12 +6105,14 @@ static int vm_intro(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm
                return vm_intro_no(chan, vms);
        } else if (!strcasecmp(chan->language, "ru")) { /* RUSSIAN syntax */
                return vm_intro_ru(chan, vms);
+       } else if (!strcasecmp(chan->language, "tw")) { /* CHINESE (Taiwan) syntax */
+               return vm_intro_tw(chan, vms);
        } else {                                        /* Default to ENGLISH */
                return vm_intro_en(chan, vms);
        }
 }
 
-static int vm_instructions(struct ast_channel *chan, struct vm_state *vms, int skipadvanced)
+static int vm_instructions_en(struct ast_channel *chan, struct vm_state *vms, int skipadvanced)
 {
        int res = 0;
        /* Play instructions and wait for new command */
@@ -5758,6 +6159,40 @@ static int vm_instructions(struct ast_channel *chan, struct vm_state *vms, int s
        return res;
 }
 
+static int vm_instructions_tw(struct ast_channel *chan, struct vm_state *vms, int skipadvanced)
+{
+       int res = 0;
+       /* Play instructions and wait for new command */
+       while (!res) {
+               if (vms->lastmsg > -1) {
+                       res = ast_play_and_wait(chan, "vm-listen");
+                       if (!res)
+                               res = vm_play_folder_name(chan, vms->vmbox);
+                       if (!res)
+                               res = ast_play_and_wait(chan, "press");
+                       if (!res)
+                               res = ast_play_and_wait(chan, "digits/1");
+               }
+               if (!res)
+                       res = ast_play_and_wait(chan, "vm-opts");
+               if (!res) {
+                       vms->starting = 0;
+                       return vm_instructions_en(chan,vms,skipadvanced);
+               }
+       }
+       return res;
+}
+
+static int vm_instructions(struct ast_channel *chan, struct vm_state *vms, int skipadvanced)
+{
+       if (vms->starting && !strcasecmp(chan->language, "tw")) { /* CHINESE (Taiwan) syntax */
+               return vm_instructions_tw(chan, vms, skipadvanced);
+       } else {                                        /* Default to ENGLISH */
+               return vm_instructions_en(chan, vms, skipadvanced);
+       }
+}
+
+
 static int vm_newuser(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
 {
        int cmd = 0;
@@ -5811,28 +6246,46 @@ 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);
-               cmd = play_record_review(chan,"vm-rec-name",prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, NULL);
-               if (cmd < 0 || cmd == 't' || cmd == '#')
-                       return cmd;
+               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;
+               }
        }
 
        /* If forcegreetings is set, have the user record their greetings */
        if (ast_test_flag(vmu, VM_FORCEGREET)) {
                snprintf(prefile,sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, vms->username);
-               cmd = play_record_review(chan,"vm-rec-unv",prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, NULL);
-               if (cmd < 0 || cmd == 't' || cmd == '#')
-                       return cmd;
+               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);
-               cmd = play_record_review(chan,"vm-rec-busy",prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, NULL);
-               if (cmd < 0 || cmd == 't' || cmd == '#')
-                       return cmd;
+               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;
+               }
        }
 
        return cmd;
@@ -5864,15 +6317,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);
@@ -5915,8 +6380,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 '*': 
@@ -5939,13 +6403,11 @@ static int vm_options(struct ast_channel *chan, struct ast_vm_user *vmu, struct
 
 static int vm_tempgreeting(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
 {
-       int res;
        int cmd = 0;
        int retries = 0;
        int duration = 0;
        char prefile[PATH_MAX] = "";
        unsigned char buf[256];
-       char dest[PATH_MAX];
        int bytes = 0;
 
        if (ast_adsi_available(chan)) {
@@ -5958,21 +6420,25 @@ 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"))) {
-               ast_log(LOG_WARNING, "Failed to create directory (%s).\n", prefile);
-               return -1;
-       }
        while((cmd >= 0) && (cmd != 't')) {
                if (cmd)
                        retries = 0;
-               RETRIEVE(prefile, -1);
+               RETRIEVE(prefile, -1, vmu->mailbox, vmu->context);
                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);
@@ -6108,6 +6574,27 @@ static int vm_browse_messages_pt(struct ast_channel *chan, struct vm_state *vms,
        return cmd;
 }
 
+/* Chinese (Taiwan)syntax */
+static int vm_browse_messages_tw(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
+{
+       int cmd=0;
+
+       if (vms->lastmsg > -1) {
+               cmd = play_message(chan, vmu, vms);
+       } else {
+               cmd = ast_play_and_wait(chan, "vm-you");
+               if (!cmd) 
+                       cmd = ast_play_and_wait(chan, "vm-haveno");
+               if (!cmd)
+                       cmd = ast_play_and_wait(chan, "vm-messages");
+               if (!cmd) {
+                       snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
+                       cmd = ast_play_and_wait(chan, vms->fn);
+               }
+       }
+       return cmd;
+}
+
 static int vm_browse_messages(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
 {
        if (!strcasecmp(chan->language, "es")) {        /* SPANISH */
@@ -6118,6 +6605,8 @@ static int vm_browse_messages(struct ast_channel *chan, struct vm_state *vms, st
                return vm_browse_messages_pt(chan, vms, vmu);
        } else if (!strcasecmp(chan->language, "gr")){
                return vm_browse_messages_gr(chan, vms, vmu);   /* GREEK */
+       } else if (!strcasecmp(chan->language, "tw")){
+               return vm_browse_messages_tw(chan, vms, vmu);   /* CHINESE (Taiwan) */
        } else {        /* Default to English syntax */
                return vm_browse_messages_en(chan, vms, vmu);
        }
@@ -6167,8 +6656,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 */
@@ -6234,7 +6722,6 @@ static int vm_execmain(struct ast_channel *chan, void *data)
        int res=-1;
        int cmd=0;
        int valid = 0;
-       struct ast_module_user *u;
        char prefixstr[80] ="";
        char ext_context[256]="";
        int box;
@@ -6251,7 +6738,6 @@ static int vm_execmain(struct ast_channel *chan, void *data)
 #ifdef IMAP_STORAGE
        int deleted = 0;
 #endif
-       u = ast_module_user_add(chan);
 
        /* Add the vm_state to the active list and keep it active */
        memset(&vms, 0, sizeof(vms));
@@ -6260,8 +6746,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);
        }
 
@@ -6278,16 +6763,13 @@ static int vm_execmain(struct ast_channel *chan, void *data)
                AST_STANDARD_APP_ARGS(args, parse);
 
                if (args.argc == 2) {
-                       if (ast_app_parse_options(vm_app_options, &flags, opts, args.argv1)) {
-                               ast_module_user_remove(u);
+                       if (ast_app_parse_options(vm_app_options, &flags, opts, args.argv1))
                                return -1;
-                       }
                        if (ast_test_flag(&flags, OPT_RECORDGAIN)) {
                                int gain;
-                               if (opts[OPT_ARG_RECORDGAIN]) {
+                               if (!ast_strlen_zero(opts[OPT_ARG_RECORDGAIN])) {
                                        if (sscanf(opts[OPT_ARG_RECORDGAIN], "%d", &gain) != 1) {
                                                ast_log(LOG_WARNING, "Invalid value '%s' provided for record gain option\n", opts[OPT_ARG_RECORDGAIN]);
-                                               ast_module_user_remove(u);
                                                return -1;
                                        } else {
                                                record_gain = (signed char) gain;
@@ -6343,8 +6825,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)
@@ -6358,7 +6839,7 @@ static int vm_execmain(struct ast_channel *chan, void *data)
 
 #ifdef IMAP_STORAGE
        vms.interactive = 1;
-       vms.updated = 2;
+       vms.updated = 1;
        vmstate_insert(&vms);
        init_vm_state(&vms);
 #endif
@@ -6379,21 +6860,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");
-       res = open_mailbox(&vms, vmu, 1);
+       ast_debug(1, "Before open_mailbox\n");
+       res = open_mailbox(&vms, vmu, OLD_FOLDER);
        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);
+       res = open_mailbox(&vms, vmu, NEW_FOLDER);
        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) {
@@ -6410,7 +6888,8 @@ static int vm_execmain(struct ast_channel *chan, void *data)
        } else {
                if (!vms.newmessages && vms.oldmessages) {
                        /* If we only have old messages start here */
-                       res = open_mailbox(&vms, vmu, 1);
+                       res = open_mailbox(&vms, vmu, OLD_FOLDER);
+                       play_folder = 1;
                        if (res == ERROR_LOCK_PATH)
                                goto out;
                }
@@ -6437,11 +6916,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
@@ -6476,6 +6953,7 @@ static int vm_execmain(struct ast_channel *chan, void *data)
                                res = open_mailbox(&vms, vmu, cmd);
                                if (res == ERROR_LOCK_PATH)
                                        goto out;
+                               play_folder = cmd;
                                cmd = 0;
                        }
                        if (useadsi)
@@ -6592,7 +7070,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 {
@@ -6608,21 +7086,34 @@ 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]) {
+                                       if (play_folder == 0)
+                                               vms.newmessages--;
+                                       else if (play_folder == 1)
+                                               vms.oldmessages--;
+                                       cmd = ast_play_and_wait(chan, "vm-deleted");
                                }
-                       }
+                               else {
+                                       if (play_folder == 0)
+                                               vms.newmessages++;
+                                       else if (play_folder == 1)
+                                               vms.oldmessages++;
+                                       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
@@ -6639,6 +7130,11 @@ static int vm_execmain(struct ast_channel *chan, void *data)
                                cmd = ast_play_and_wait(chan, "vm-nomore");
                        break;
                case '9':
+                       if (vms.curmsg < 0 || vms.curmsg > vms.lastmsg) {
+                               /* No message selected */
+                               cmd = 0;
+                               break;
+                       }
                        if (useadsi)
                                adsi_folders(chan, 1, "Save to folder...");
                        cmd = get_folder2(chan, "vm-savefolder", 1);
@@ -6735,14 +7231,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)) {
@@ -6761,7 +7259,6 @@ out:
                free(vms.deleted);
        if (vms.heard)
                free(vms.heard);
-       ast_module_user_remove(u);
 
        return res;
 }
@@ -6769,7 +7266,6 @@ out:
 static int vm_exec(struct ast_channel *chan, void *data)
 {
        int res = 0;
-       struct ast_module_user *u;
        char *tmp;
        struct leave_vm_options leave_options;
        struct ast_flags flags = { 0 };
@@ -6778,8 +7274,6 @@ static int vm_exec(struct ast_channel *chan, void *data)
                AST_APP_ARG(argv0);
                AST_APP_ARG(argv1);
        );
-
-       u = ast_module_user_add(chan);
        
        memset(&leave_options, 0, sizeof(leave_options));
 
@@ -6790,17 +7284,14 @@ static int vm_exec(struct ast_channel *chan, void *data)
                tmp = ast_strdupa(data);
                AST_STANDARD_APP_ARGS(args, tmp);
                if (args.argc == 2) {
-                       if (ast_app_parse_options(vm_app_options, &flags, opts, args.argv1)) {
-                               ast_module_user_remove(u);
+                       if (ast_app_parse_options(vm_app_options, &flags, opts, args.argv1))
                                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;
 
                                if (sscanf(opts[OPT_ARG_RECORDGAIN], "%d", &gain) != 1) {
                                        ast_log(LOG_WARNING, "Invalid value '%s' provided for record gain option\n", opts[OPT_ARG_RECORDGAIN]);
-                                       ast_module_user_remove(u);
                                        return -1;
                                } else {
                                        leave_options.record_gain = (signed char) gain;
@@ -6810,14 +7301,10 @@ static int vm_exec(struct ast_channel *chan, void *data)
        } else {
                char tmp[256];
                res = ast_app_getdata(chan, "vm-whichbox", tmp, sizeof(tmp) - 1, 0);
-               if (res < 0) {
-                       ast_module_user_remove(u);
+               if (res < 0)
                        return res;
-               }
-               if (ast_strlen_zero(tmp)) {
-                       ast_module_user_remove(u);
+               if (ast_strlen_zero(tmp))
                        return 0;
-               }
                args.argv0 = ast_strdupa(tmp);
        }
 
@@ -6825,15 +7312,9 @@ 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;
        }
-       
-       ast_module_user_remove(u);
 
        return res;
 }
@@ -6841,20 +7322,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;
 }
 
@@ -6865,33 +7351,43 @@ 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;
 }
 
 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);
@@ -6903,8 +7399,6 @@ static int vm_box_exists(struct ast_channel *chan, void *data)
                return -1;
        }
 
-       u = ast_module_user_add(chan);
-
        if (!dep_warning) {
                dep_warning = 1;
                ast_log(LOG_WARNING, "MailboxExists is deprecated.  Please use ${MAILBOX_EXISTS(%s)} instead.\n", (char *)data);
@@ -6915,8 +7409,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, '@'))) {
@@ -6926,12 +7418,9 @@ 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);
+
        return 0;
 }
 
@@ -6961,14 +7450,11 @@ static struct ast_custom_function mailbox_exists_acf = {
 
 static int vmauthenticate(struct ast_channel *chan, void *data)
 {
-       struct ast_module_user *u;
        char *s = data, *user=NULL, *context=NULL, mailbox[AST_MAX_EXTENSION] = "";
        struct ast_vm_user vmus;
        char *options = NULL;
        int silent = 0, skipuser = 0;
        int res = -1;
-
-       u = ast_module_user_add(chan);
        
        if (s) {
                s = ast_strdupa(s);
@@ -6995,7 +7481,6 @@ static int vmauthenticate(struct ast_channel *chan, void *data)
                res = 0;
        }
 
-       ast_module_user_remove(u);
        return res;
 }
 
@@ -7007,52 +7492,100 @@ 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;
-       else if ((argc == 5) && strcmp(argv[3],"for")) return RESULT_SHOWUSAGE;
+       if ((argc < 3) || (argc > 5) || (argc == 4))
+               return RESULT_SHOWUSAGE;
+       if (argc == 5) {
+               if (strcmp(argv[3],"for"))
+                       return RESULT_SHOWUSAGE;
+               context = argv[4];
+       }
 
-       AST_LIST_LOCK(&users);
-       if (!AST_LIST_EMPTY(&users)) {
-               if (argc == 3)
-                       ast_cli(fd, output_format, "Context", "Mbox", "User", "Zone", "NewMsg");
-               else {
-                       int count = 0;
-                       AST_LIST_TRAVERSE(&users, vmu, list) {
-                               if (!strcmp(argv[4],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_LIST_UNLOCK(&users);
-                               return RESULT_FAILURE;
-                       }
+       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;
                }
-               AST_LIST_TRAVERSE(&users, vmu, list) {
-                       int newmsgs = 0, oldmsgs = 0;
-                       char count[12], tmp[256] = "";
+               return show_users_realtime(fd, context);
+       }
 
-                       if ((argc == 3) || ((argc == 5) && !strcmp(argv[4],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);
-                               ast_cli(fd, output_format, vmu->context, vmu->mailbox, vmu->fullname, vmu->zonetag, count);
-                       }
-               }
-       } else {
+       AST_LIST_LOCK(&users);
+       if (AST_LIST_EMPTY(&users)) {
                ast_cli(fd, "There are no voicemail users currently defined\n");
                AST_LIST_UNLOCK(&users);
                return RESULT_FAILURE;
        }
+       if (argc == 3)
+               ast_cli(fd, output_format, "Context", "Mbox", "User", "Zone", "NewMsg");
+       else {
+               int count = 0;
+               AST_LIST_TRAVERSE(&users, vmu, list) {
+                       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", context);
+                       AST_LIST_UNLOCK(&users);
+                       return RESULT_FAILURE;
+               }
+       }
+       AST_LIST_TRAVERSE(&users, vmu, list) {
+               int newmsgs = 0, oldmsgs = 0;
+               char count[12], tmp[256] = "";
+
+               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);
+                       ast_cli(fd, output_format, vmu->context, vmu->mailbox, vmu->fullname, vmu->zonetag, count);
+               }
+       }
        AST_LIST_UNLOCK(&users);
        return RESULT_SUCCESS;
 }
 
+/*! \brief Show a list of voicemail zones in the CLI */
 static int handle_voicemail_show_zones(int fd, int argc, char *argv[])
 {
        struct vm_zone *zone;
@@ -7111,6 +7644,235 @@ 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];
+
+#ifdef IMAP_STORAGE
+               int new, old;
+               inboxcount (vmu->mailbox, &new, &old);
+#endif
+               
+               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
+                                 "OldMessageCount: %d\r\n"
+                             "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, 
+#ifdef IMAP_STORAGE
+                                 new, old, vmu->imapuser
+#else
+                                 count_messages(vmu, dirname)
+#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;
@@ -7118,54 +7880,20 @@ 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;
+       const char *key;
+       char *q, *stringp;
        int x;
        int tmpadsi[4];
 
+       /* set audio control prompts */
+       strcpy(listen_control_forward_key,DEFAULT_LISTEN_CONTROL_FORWARD_KEY);
+       strcpy(listen_control_reverse_key,DEFAULT_LISTEN_CONTROL_REVERSE_KEY);
+       strcpy(listen_control_pause_key,DEFAULT_LISTEN_CONTROL_PAUSE_KEY);
+       strcpy(listen_control_restart_key,DEFAULT_LISTEN_CONTROL_RESTART_KEY);
+       strcpy(listen_control_stop_key,DEFAULT_LISTEN_CONTROL_STOP_KEY);
+       
        cfg = ast_config_load(VOICEMAIL_CONFIG);
 
        AST_LIST_LOCK(&users);
@@ -7184,99 +7912,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;
@@ -7284,49 +8012,55 @@ 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));
                }
+               if ((val = ast_variable_retrieve(cfg, "general", "imapgreetings"))) {
+                       imapgreetings = ast_true(val);
+               } else {
+                       imapgreetings = 0;
+               }
+               if ((val = ast_variable_retrieve(cfg, "general", "greetingfolder"))) {
+                       ast_copy_string(greetingfolder, val, sizeof(greetingfolder));
+               } else {
+                       ast_copy_string(greetingfolder, imapfolder, sizeof(greetingfolder));
+               }
+
 #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 (!strcasecmp(externnotify, "smdi")) {
-                               if (option_debug)
-                                       ast_log(LOG_DEBUG, "Using SMDI for external voicemail notification\n");
-                               if ((smdistr = ast_variable_retrieve(cfg, "general", "smdiport"))) {
-                                       smdi_iface = ast_smdi_interface_find(smdistr);
-                               } else {
-                                       if (option_debug)
-                                               ast_log(LOG_DEBUG, "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 external voicemail notification\n");
-                                       externnotify[0] = '\0';
-                               } else {
-                                       if (option_debug)
-                                               ast_log(LOG_DEBUG, "Using SMDI port %s\n", smdi_iface->name);
-                               }
-                       }
+               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)) {
+                       ast_debug(1, "Enabled SMDI voicemail notification\n");
+                       if ((val = ast_variable_retrieve(cfg, "general", "smdiport"))) {
+                               smdi_iface = ast_smdi_interface_find(val);
+                       } else {
+                               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 {
+                               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"))) {
@@ -7372,10 +8106,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"))) {
@@ -7404,18 +8138,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)) {
@@ -7423,121 +8156,132 @@ 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));
+               /* load configurable audio prompts */
+               if ((key = ast_variable_retrieve(cfg, "general", "listen-control-forward-key")) && is_valid_dtmf(key))
+                       ast_copy_string(listen_control_forward_key, key, sizeof(listen_control_forward_key));
+               if ((key = ast_variable_retrieve(cfg, "general", "listen-control-reverse-key")) && is_valid_dtmf(key))
+                       ast_copy_string(listen_control_reverse_key, key, sizeof(listen_control_reverse_key));
+               if ((key = ast_variable_retrieve(cfg, "general", "listen-control-pause-key")) && is_valid_dtmf(key))
+                       ast_copy_string(listen_control_pause_key, key, sizeof(listen_control_pause_key));
+               if ((key = ast_variable_retrieve(cfg, "general", "listen-control-restart-key")) && is_valid_dtmf(key))
+                       ast_copy_string(listen_control_restart_key, key, sizeof(listen_control_restart_key));
+               if ((key = ast_variable_retrieve(cfg, "general", "listen-control-stop-key")) && is_valid_dtmf(key))
+                       ast_copy_string(listen_control_stop_key, key, sizeof(listen_control_stop_key));
+
+               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")))
@@ -7577,10 +8321,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;
@@ -7591,24 +8334,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")))
@@ -7697,32 +8440,40 @@ 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;
 }
@@ -7730,23 +8481,24 @@ static int unload_module(void)
 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;
@@ -7832,8 +8584,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");
@@ -7876,7 +8627,7 @@ static int advanced_options(struct ast_channel *chan, struct ast_vm_user *vmu, s
 
        make_file(vms->fn2, sizeof(vms->fn2), vms->curdir, vms->curmsg);
        snprintf(filename,sizeof(filename), "%s.txt", vms->fn2);
-       RETRIEVE(vms->curdir, vms->curmsg);
+       RETRIEVE(vms->curdir, vms->curmsg, vmu->mailbox, vmu->context);
        msg_cfg = ast_config_load(filename);
        DISPOSE(vms->curdir, vms->curmsg);
        if (!msg_cfg) {
@@ -8010,7 +8761,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);
@@ -8064,6 +8816,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 = "";
 
@@ -8075,6 +8828,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')) {
@@ -8088,9 +8846,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;
                        }
@@ -8098,7 +8860,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;
@@ -8120,11 +8882,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. */
+                                       ast_filedelete(tempfile, NULL);
+                               }               
                                return cmd;
                        }
                        if (cmd == '0') {
@@ -8138,14 +8904,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 = ast_filedelete(tempfile, NULL);
                                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 = ast_filedelete(tempfile, NULL);
                                cmd = ast_play_and_wait(chan, "vm-nothingrecorded");
                                if (!cmd)
                                        cmd = ast_play_and_wait(chan, "vm-speakup");
@@ -8174,7 +8940,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 = ast_filedelete(tempfile, NULL);
                        if (outsidecaller) {
                                res = vm_exec(chan, NULL);
                                return res;
@@ -8253,23 +9019,34 @@ static void write_file(char *filename, char *buffer, unsigned long len)
        fclose (output);
 }
 
+static void update_messages_by_imapuser(const char *user, unsigned long number)
+{
+       struct vmstate *vlist = NULL;
+
+       AST_LIST_LOCK(&vmstates);
+       AST_LIST_TRAVERSE(&vmstates, vlist, list) {
+               if (!vlist->vms) {
+                       ast_debug(3, "error: vms is NULL for %s\n", user);
+                       continue;
+               }
+               if (!vlist->vms->imapuser) {
+                       ast_debug(3, "error: imapuser is NULL for %s\n", user);
+                       continue;
+               }
+               ast_debug(3, "saving mailbox message number %lu as message %d. Interactive set to %d\n", number, vlist->vms->vmArrayIndex, vlist->vms->interactive);
+               vlist->vms->msgArray[vlist->vms->vmArrayIndex++] = number;
+       }
+       AST_LIST_UNLOCK(&vmstates);
+}
+
 void mm_searched(MAILSTREAM *stream, unsigned long number)
 {
-       struct vm_state *vms;
        char *mailbox = stream->mailbox, buf[1024] = "", *user;
 
        if (!(user = get_user_by_mailbox(mailbox, buf, sizeof(buf))))
                return;
 
-       if (!(vms = get_vm_state_by_imapuser(user, 2))) {
-               ast_log(LOG_ERROR, "No state found.\n");
-               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);
-
-       vms->msgArray[vms->vmArrayIndex++] = number;
+       update_messages_by_imapuser(user, number);
 }
 
 
@@ -8456,7 +9233,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;
        }
 }
@@ -8466,8 +9243,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);
 }
@@ -8476,8 +9252,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);
 }
@@ -8486,8 +9261,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);
 }
@@ -8506,33 +9280,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");
 }
 
 
@@ -8557,8 +9328,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:
@@ -8581,8 +9351,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);
 
@@ -8647,8 +9416,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;
@@ -8685,10 +9453,10 @@ static char *get_user_by_mailbox(char *mailbox, char *buf, size_t len)
        if (ast_strlen_zero(mailbox))
                return NULL;
 
-       if (!(start = strstr(mailbox, "user=")))
+       if (!(start = strstr(mailbox, "/user=")))
                return NULL;
 
-       ast_copy_string(buf, start+5, len);
+       ast_copy_string(buf, start+6, len);
 
        if (!(quote = strchr(buf, '\"'))) {
                if (!(eol_pnt = strchr(buf, '/')))
@@ -8706,58 +9474,56 @@ static struct vm_state *get_vm_state_by_imapuser(char *user, int interactive)
 {
        struct vmstate *vlist = NULL;
 
+       AST_LIST_LOCK(&vmstates);
        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;
                }
 
-               if (interactive == 2)
-                       return vlist->vms;
-               else if (vlist->vms->interactive == interactive)
+               if (!strcmp(vlist->vms->imapuser, user) && (interactive == 2 || vlist->vms->interactive == interactive)) {
+                       AST_LIST_UNLOCK(&vmstates);
                        return vlist->vms;
+               }
        }
+       AST_LIST_UNLOCK(&vmstates);
 
-       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;
 }
 
 static struct vm_state *get_vm_state_by_mailbox(const char *mailbox, int interactive)
-{ 
+{
+
        struct vmstate *vlist = NULL;
 
+       AST_LIST_LOCK(&vmstates);
        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");
+                       AST_LIST_UNLOCK(&vmstates);
                        return vlist->vms;
                }
        }
+       AST_LIST_UNLOCK(&vmstates);
 
-       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;
 }
@@ -8772,18 +9538,15 @@ static void vmstate_insert(struct vm_state *vms)
           We can compare the username to find the duplicate */
        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);
+               if (altvms) {   
+                       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;
@@ -8798,9 +9561,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);
@@ -8815,15 +9579,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;
+               altvms->updated = 1;
        }
        
-       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) {
@@ -8836,7 +9598,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);
 }
@@ -8853,10 +9615,9 @@ 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 */
+       vms->updated = 1; /* Set updated flag since mailbox changed */
 }
 
 static void init_vm_state(struct vm_state *vms) 
@@ -8873,8 +9634,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]);
                }
        }
 }
@@ -8901,7 +9661,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);
        }