Add a massive set of changes for converting to use the ast_debug() macro.
[asterisk/asterisk.git] / apps / app_voicemail.c
index c968548..675d966 100644 (file)
  * \brief Comedian Mail - Voicemail System
  *
  * \author Mark Spencer <markster@digium.com>
  * \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
  * 
  * \par See also
  * \arg \ref Config_vm
+ * \note For information about voicemail IMAP storage, read doc/imapstorage.txt
  * \ingroup applications
  * \ingroup applications
- * \note This module requires res_adsi to load.
+ * \note This module requires res_adsi to load. This needs to be optional
+ * during compilation.
+ *
+ *
+ *
+ * \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_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>
 /*** 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>
+               <conflict>IMAP_STORAGE</conflict>
                <defaultenabled>no</defaultenabled>
        </member>
        <member name="IMAP_STORAGE" displayname="Storage of Voicemail using IMAP4">
                <depend>imap_tk</depend>
                <defaultenabled>no</defaultenabled>
        </member>
        <member name="IMAP_STORAGE" displayname="Storage of Voicemail using IMAP4">
                <depend>imap_tk</depend>
+               <conflict>ODBC_STORAGE</conflict>
                <use>ssl</use>
                <defaultenabled>no</defaultenabled>
        </member>
                <use>ssl</use>
                <defaultenabled>no</defaultenabled>
        </member>
@@ -58,6 +76,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include <sys/mman.h>
 #include <time.h>
 #include <dirent.h>
 #include <sys/mman.h>
 #include <time.h>
 #include <dirent.h>
+
 #ifdef IMAP_STORAGE
 #include <ctype.h>
 #include <signal.h>
 #ifdef IMAP_STORAGE
 #include <ctype.h>
 #include <signal.h>
@@ -66,6 +85,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "imap4r1.h"
 #include "linkage.h"
 #endif
 #include "imap4r1.h"
 #include "linkage.h"
 #endif
+
 #include "asterisk/lock.h"
 #include "asterisk/file.h"
 #include "asterisk/logger.h"
 #include "asterisk/lock.h"
 #include "asterisk/file.h"
 #include "asterisk/logger.h"
@@ -84,14 +104,13 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/utils.h"
 #include "asterisk/stringfields.h"
 #include "asterisk/smdi.h"
 #include "asterisk/utils.h"
 #include "asterisk/stringfields.h"
 #include "asterisk/smdi.h"
+#include "asterisk/event.h"
+
 #ifdef ODBC_STORAGE
 #include "asterisk/res_odbc.h"
 #endif
 
 #ifdef IMAP_STORAGE
 #ifdef ODBC_STORAGE
 #include "asterisk/res_odbc.h"
 #endif
 
 #ifdef IMAP_STORAGE
-AST_MUTEX_DEFINE_STATIC(imaptemp_lock);
-static char imaptemp[1024];
-
 static char imapserver[48];
 static char imapport[8];
 static char imapflags[128];
 static char imapserver[48];
 static char imapport[8];
 static char imapflags[128];
@@ -106,13 +125,13 @@ static char delimiter = '\0';
 struct vm_state;
 struct ast_vm_user;
 
 struct vm_state;
 struct ast_vm_user;
 
-static int init_mailstream (struct vm_state *vms, int box);
-static void write_file (char *filename, char *buffer, unsigned long len);
-/*static void status (MAILSTREAM *stream); */ /* No need for this. */
-static void display_body (BODY *body, char *pfx, long i);
-static char *get_header_by_tag(char *header, char *tag);
+/* 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 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);
 static void vm_imap_delete(int msgnum, struct vm_state *vms);
-static char *get_user_by_mailbox(char *mailbox);
+static char *get_user_by_mailbox(char *mailbox, char *buf, size_t len);
 static struct vm_state *get_vm_state_by_imapuser(char *user, int interactive);
 static struct vm_state *get_vm_state_by_mailbox(const char *mailbox, int interactive);
 static void vmstate_insert(struct vm_state *vms);
 static struct vm_state *get_vm_state_by_imapuser(char *user, int interactive);
 static struct vm_state *get_vm_state_by_mailbox(const char *mailbox, int interactive);
 static void vmstate_insert(struct vm_state *vms);
@@ -127,13 +146,16 @@ 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 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 int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu,int box);
+
+
+
 struct vmstate {
        struct vm_state *vms;
 struct vmstate {
        struct vm_state *vms;
-       struct vmstate *next;
+       AST_LIST_ENTRY(vmstate) list;
 };
 };
-AST_MUTEX_DEFINE_STATIC(vmstate_lock);
-static struct vmstate *vmstates = NULL;
+
+static AST_LIST_HEAD_STATIC(vmstates, vmstate);
+
 #endif
 
 #define SMDI_MWI_WAIT_TIMEOUT 1000 /* 1 second */
 #endif
 
 #define SMDI_MWI_WAIT_TIMEOUT 1000 /* 1 second */
@@ -189,7 +211,6 @@ enum {
        OPT_UNAVAIL_GREETING = (1 << 2),
        OPT_RECORDGAIN =       (1 << 3),
        OPT_PREPEND_MAILBOX =  (1 << 4),
        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;
 
        OPT_AUTOPLAY =         (1 << 6),
 } vm_option_flags;
 
@@ -206,7 +227,6 @@ AST_APP_OPTIONS(vm_app_options, {
        AST_APP_OPTION('u', OPT_UNAVAIL_GREETING),
        AST_APP_OPTION_ARG('g', OPT_RECORDGAIN, OPT_ARG_RECORDGAIN),
        AST_APP_OPTION('p', OPT_PREPEND_MAILBOX),
        AST_APP_OPTION('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),
 });
 
        AST_APP_OPTION_ARG('a', OPT_AUTOPLAY, OPT_ARG_PLAYFOLDER),
 });
 
@@ -292,7 +312,8 @@ struct baseio {
        unsigned char iobuf[BASEMAXINLINE];
 };
 
        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 */
 struct ast_vm_user {
        char context[AST_MAX_CONTEXT];   /*!< Voicemail context */
        char mailbox[AST_MAX_EXTENSION]; /*!< Mailbox id, unique within vm context */
@@ -314,13 +335,14 @@ struct ast_vm_user {
        int maxmsg;                      /*!< Maximum number of msgs per folder for this mailbox */
        int maxsecs;                     /*!< Maximum number of seconds per message for this mailbox */
 #ifdef IMAP_STORAGE
        int maxmsg;                      /*!< Maximum number of msgs per folder for this mailbox */
        int maxsecs;                     /*!< Maximum number of seconds per message for this mailbox */
 #ifdef IMAP_STORAGE
-       char imapuser[80];      /* IMAP server login */
-       char imappassword[80];  /* IMAP server password if authpassword not defined */
+       char imapuser[80];               /*!< IMAP server login */
+       char imappassword[80];           /*!< IMAP server password if authpassword not defined */
 #endif
 #endif
-       double volgain;         /*!< Volume gain for voicemails sent via email */
+       double volgain;                  /*!< Volume gain for voicemails sent via email */
        AST_LIST_ENTRY(ast_vm_user) list;
 };
 
        AST_LIST_ENTRY(ast_vm_user) list;
 };
 
+/*! Voicemail time zones */
 struct vm_zone {
        AST_LIST_ENTRY(vm_zone) list;
        char name[80];
 struct vm_zone {
        AST_LIST_ENTRY(vm_zone) list;
        char name[80];
@@ -328,6 +350,7 @@ struct vm_zone {
        char msg_format[512];
 };
 
        char msg_format[512];
 };
 
+/*! Voicemail mailbox state */
 struct vm_state {
        char curbox[80];
        char username[80];
 struct vm_state {
        char curbox[80];
        char username[80];
@@ -344,30 +367,18 @@ struct vm_state {
        int starting;
        int repeats;
 #ifdef IMAP_STORAGE
        int starting;
        int repeats;
 #ifdef IMAP_STORAGE
-       int updated; /* decremented on each mail check until 1 -allows delay */
+       int updated;                         /*!< decremented on each mail check until 1 -allows delay */
        long msgArray[256];
        MAILSTREAM *mailstream;
        int vmArrayIndex;
        long msgArray[256];
        MAILSTREAM *mailstream;
        int vmArrayIndex;
-       char imapuser[80]; /* IMAP server login */
+       char imapuser[80];                   /*!< IMAP server login */
        int interactive;
        unsigned int quota_limit;
        unsigned int quota_usage;
        struct vm_state *persist_vms;
 #endif
 };
        int interactive;
        unsigned int quota_limit;
        unsigned int quota_usage;
        struct vm_state *persist_vms;
 #endif
 };
-static int advanced_options(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int msg, int option, signed char record_gain);
-static int dialout(struct ast_channel *chan, struct ast_vm_user *vmu, char *num, char *outgoing_context);
-static int play_record_review(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime,
-                       char *fmt, int outsidecaller, struct ast_vm_user *vmu, int *duration, const char *unlockdir,
-                       signed char record_gain, struct vm_state *vms);
-static int vm_tempgreeting(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain);
-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);
-#if !(defined(ODBC_STORAGE) || defined(IMAP_STORAGE))
-static int __has_voicemail(const char *context, const char *mailbox, const char *folder, int shortcircuit);
-#endif
-static void apply_options(struct ast_vm_user *vmu, const char *options);
+
 
 #ifdef ODBC_STORAGE
 static char odbc_database[80];
 
 #ifdef ODBC_STORAGE
 static char odbc_database[80];
@@ -408,89 +419,85 @@ static char ext_pass_cmd[128];
 #define PWDCHANGE_EXTERNAL (1 << 2)
 static int pwdchange = PWDCHANGE_INTERNAL;
 
 #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"
 #define tdesc "Comedian Mail (Voicemail System) with ODBC Storage"
-#elif IMAP_STORAGE
-#define tdesc "Comedian Mail (Voicemail System) with IMAP Storage"
 #else
 #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";
 
 static char *addesc = "Comedian Mail";
 
 #endif
 
 static char userscontext[AST_MAX_EXTENSION] = "default";
 
 static char *addesc = "Comedian Mail";
 
-static char *synopsis_vm =
-"Leave a Voicemail message";
+static char *synopsis_vm = "Leave a Voicemail message";
 
 static char *descrip_vm =
 
 static char *descrip_vm =
-"  VoiceMail(mailbox[@context][&mailbox[@context]][...][|options]): This\n"
-"application allows the calling party to leave a message for the specified\n"
-"list of mailboxes. When multiple mailboxes are specified, the greeting will\n"
-"be taken from the first mailbox specified. Dialplan execution will stop if the\n"
-"specified mailbox does not exist.\n"
-"  The Voicemail application will exit if any of the following DTMF digits are\n"
-"received:\n"
-"    0 - Jump to the 'o' extension in the current dialplan context.\n"
-"    * - Jump to the 'a' extension in the current dialplan context.\n"
-"  This application will set the following channel variable upon completion:\n"
-"    VMSTATUS - This indicates the status of the execution of the VoiceMail\n"
-"               application. The possible values are:\n"
-"               SUCCESS | USEREXIT | FAILED\n\n"
-"  Options:\n"
-"    b    - Play the 'busy' greeting to the calling party.\n"
-"    g(#) - Use the specified amount of gain when recording the voicemail\n"
-"           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";
-
-static char *synopsis_vmain =
-"Check Voicemail messages";
+       "  VoiceMail(mailbox[@context][&mailbox[@context]][...][|options]): This\n"
+       "application allows the calling party to leave a message for the specified\n"
+       "list of mailboxes. When multiple mailboxes are specified, the greeting will\n"
+       "be taken from the first mailbox specified. Dialplan execution will stop if the\n"
+       "specified mailbox does not exist.\n"
+       "  The Voicemail application will exit if any of the following DTMF digits are\n"
+       "received:\n"
+       "    0 - Jump to the 'o' extension in the current dialplan context.\n"
+       "    * - Jump to the 'a' extension in the current dialplan context.\n"
+       "  This application will set the following channel variable upon completion:\n"
+       "    VMSTATUS - This indicates the status of the execution of the VoiceMail\n"
+       "               application. The possible values are:\n"
+       "               SUCCESS | USEREXIT | FAILED\n\n"
+       "  Options:\n"
+       "    b    - Play the 'busy' greeting to the calling party.\n"
+       "    g(#) - Use the specified amount of gain when recording the voicemail\n"
+       "           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 'unavailable greeting.\n";
+
+static char *synopsis_vmain = "Check Voicemail messages";
 
 static char *descrip_vmain =
 
 static char *descrip_vmain =
-"  VoiceMailMain([mailbox][@context][|options]): This application allows the\n"
-"calling party to check voicemail messages. A specific mailbox, and optional\n"
-"corresponding context, may be specified. If a mailbox is not provided, the\n"
-"calling party will be prompted to enter one. If a context is not specified,\n"
-"the 'default' context will be used.\n\n"
-"  Options:\n"
-"    p    - Consider the mailbox parameter as a prefix to the mailbox that\n"
-"           is entered by the caller.\n"
-"    g(#) - Use the specified amount of gain when recording a voicemail\n"
-"           message. The units are whole-number decibels (dB).\n"
-"    s    - Skip checking the passcode for the mailbox.\n"
-"    a(#) - Skip folder prompt and go directly to folder specified.\n"
-"           Defaults to INBOX\n";
+       "  VoiceMailMain([mailbox][@context][|options]): This application allows the\n"
+       "calling party to check voicemail messages. A specific mailbox, and optional\n"
+       "corresponding context, may be specified. If a mailbox is not provided, the\n"
+       "calling party will be prompted to enter one. If a context is not specified,\n"
+       "the 'default' context will be used.\n\n"
+       "  Options:\n"
+       "    p    - Consider the mailbox parameter as a prefix to the mailbox that\n"
+       "           is entered by the caller.\n"
+       "    g(#) - Use the specified amount of gain when recording a voicemail\n"
+       "           message. The units are whole-number decibels (dB).\n"
+       "    s    - Skip checking the passcode for the mailbox.\n"
+       "    a(#) - Skip folder prompt and go directly to folder specified.\n"
+       "           Defaults to INBOX\n";
 
 static char *synopsis_vm_box_exists =
 "Check to see if Voicemail mailbox exists";
 
 static char *descrip_vm_box_exists =
 
 static char *synopsis_vm_box_exists =
 "Check to see if Voicemail mailbox exists";
 
 static char *descrip_vm_box_exists =
-"  MailboxExists(mailbox[@context][|options]): Check to see if the specified\n"
-"mailbox exists. If no voicemail context is specified, the 'default' context\n"
-"will be used.\n"
-"  This application will set the following channel variable upon completion:\n"
-"    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";
-
-static char *synopsis_vmauthenticate =
-"Authenticate with Voicemail passwords";
+       "  MailboxExists(mailbox[@context][|options]): Check to see if the specified\n"
+       "mailbox exists. If no voicemail context is specified, the 'default' context\n"
+       "will be used.\n"
+       "  This application will set the following channel variable upon completion:\n"
+       "    VMBOXEXISTSSTATUS - This will contain the status of the execution of the\n"
+       "                        MailboxExists application. Possible values include:\n"
+       "                        SUCCESS | FAILED\n\n"
+       "  Options: (none)\n";
+
+static char *synopsis_vmauthenticate = "Authenticate with Voicemail passwords";
 
 static char *descrip_vmauthenticate =
 
 static char *descrip_vmauthenticate =
-"  VMAuthenticate([mailbox][@context][|options]): This application behaves the\n"
-"same way as the Authenticate application, but the passwords are taken from\n"
-"voicemail.conf.\n"
-"  If the mailbox is specified, only that mailbox's password will be considered\n"
-"valid. If the mailbox is not specified, the channel variable AUTH_MAILBOX will\n"
-"be set with the authenticated mailbox.\n\n"
-"  Options:\n"
-"    s - Skip playing the initial prompts.\n";
+       "  VMAuthenticate([mailbox][@context][|options]): This application behaves the\n"
+       "same way as the Authenticate application, but the passwords are taken from\n"
+       "voicemail.conf.\n"
+       "  If the mailbox is specified, only that mailbox's password will be considered\n"
+       "valid. If the mailbox is not specified, the channel variable AUTH_MAILBOX will\n"
+       "be set with the authenticated mailbox.\n\n"
+       "  Options:\n"
+       "    s - Skip playing the initial prompts.\n";
 
 /* Leave a message */
 static char *app = "VoiceMail";
 
 /* Leave a message */
 static char *app = "VoiceMail";
@@ -518,6 +525,42 @@ static int maxgreet;
 static int skipms;
 static int maxlogins;
 
 static int skipms;
 static int maxlogins;
 
+/*! Poll mailboxes for changes since there is something external to
+ *  app_voicemail that may change them. */
+static unsigned int poll_mailboxes;
+
+/*! Polling frequency */
+static unsigned int poll_freq;
+/*! By default, poll every 30 seconds */
+#define DEFAULT_POLL_FREQ 30
+
+AST_MUTEX_DEFINE_STATIC(poll_lock);
+static ast_cond_t poll_cond = PTHREAD_COND_INITIALIZER;
+static pthread_t poll_thread = AST_PTHREADT_NULL;
+static unsigned char poll_thread_run;
+
+/*! Subscription to ... MWI event subscriptions */
+static struct ast_event_sub *mwi_sub_sub;
+/*! Subscription to ... MWI event un-subscriptions */
+static struct ast_event_sub *mwi_unsub_sub;
+
+/*!
+ * \brief An MWI subscription
+ *
+ * This is so we can keep track of which mailboxes are subscribed to.
+ * This way, we know which mailboxes to poll when the pollmailboxes
+ * option is being used.
+ */
+struct mwi_sub {
+       AST_RWLIST_ENTRY(mwi_sub) entry;
+       int old_new;
+       int old_old;
+       uint32_t uniqueid;
+       char mailbox[1];
+};
+
+static AST_RWLIST_HEAD_STATIC(mwi_subs, mwi_sub);
+
 /* custom password sounds */
 static char vm_password[80] = "vm-password";
 static char vm_newpassword[80] = "vm-newpassword";
 /* custom password sounds */
 static char vm_password[80] = "vm-password";
 static char vm_newpassword[80] = "vm-newpassword";
@@ -550,6 +593,24 @@ static unsigned char adsisec[4] = "\x9B\xDB\xF7\xAC";
 static int adsiver = 1;
 static char emaildateformat[32] = "%A, %B %d, %Y at %r";
 
 static int adsiver = 1;
 static char emaildateformat[32] = "%A, %B %d, %Y at %r";
 
+/* Forward declarations - generic */
+static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu,int box);
+static int advanced_options(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int msg, int option, signed char record_gain);
+static int dialout(struct ast_channel *chan, struct ast_vm_user *vmu, char *num, char *outgoing_context);
+static int play_record_review(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime,
+                       char *fmt, int outsidecaller, struct ast_vm_user *vmu, int *duration, const char *unlockdir,
+                       signed char record_gain, struct vm_state *vms);
+static int vm_tempgreeting(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain);
+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);
+
+#if !(defined(ODBC_STORAGE) || defined(IMAP_STORAGE))
+static int __has_voicemail(const char *context, const char *mailbox, const char *folder, int shortcircuit);
+#endif
+
+
 
 static void populate_defaults(struct ast_vm_user *vmu)
 {
 
 static void populate_defaults(struct ast_vm_user *vmu)
 {
@@ -678,13 +739,11 @@ static void apply_options_full(struct ast_vm_user *retval, struct ast_variable *
        struct ast_variable *tmp;
        tmp = var;
        while (tmp) {
        struct ast_variable *tmp;
        tmp = var;
        while (tmp) {
-               ast_log(LOG_DEBUG, "Name: %s Value: %s\n", tmp->name, tmp->value);
-               if (!strcasecmp(tmp->name, "password") || !strcasecmp(tmp->name, "secret")) {
+               if (!strcasecmp(tmp->name, "vmsecret")) {
                        ast_copy_string(retval->password, tmp->value, sizeof(retval->password));
                        ast_copy_string(retval->password, tmp->value, sizeof(retval->password));
-               } else if  (!strcasecmp(tmp->name, "secret")) {
-                       /* dont let secret override vmpassword */
-                       if ((strlen(retval->password) == 0))
-                               ast_copy_string(retval->password, tmp->value, sizeof(retval->password));        
+               } else if (!strcasecmp(tmp->name, "secret") || !strcasecmp(tmp->name, "password")) { /* don't overwrite vmsecret if it exists */
+                       if (ast_strlen_zero(retval->password))
+                               ast_copy_string(retval->password, tmp->value, sizeof(retval->password));
                } else if (!strcasecmp(tmp->name, "uniqueid")) {
                        ast_copy_string(retval->uniqueid, tmp->value, sizeof(retval->uniqueid));
                } else if (!strcasecmp(tmp->name, "pager")) {
                } else if (!strcasecmp(tmp->name, "uniqueid")) {
                        ast_copy_string(retval->uniqueid, tmp->value, sizeof(retval->uniqueid));
                } else if (!strcasecmp(tmp->name, "pager")) {
@@ -695,6 +754,12 @@ static void apply_options_full(struct ast_vm_user *retval, struct ast_variable *
                        ast_copy_string(retval->fullname, tmp->value, sizeof(retval->fullname));
                } else if (!strcasecmp(tmp->name, "context")) {
                        ast_copy_string(retval->context, tmp->value, sizeof(retval->context));
                        ast_copy_string(retval->fullname, tmp->value, sizeof(retval->fullname));
                } else if (!strcasecmp(tmp->name, "context")) {
                        ast_copy_string(retval->context, tmp->value, sizeof(retval->context));
+#ifdef IMAP_STORAGE
+               } else if (!strcasecmp(tmp->name, "imapuser")) {
+                       ast_copy_string(retval->imapuser, tmp->value, sizeof(retval->imapuser));
+               } else if (!strcasecmp(tmp->name, "imappassword")) {
+                       ast_copy_string(retval->imappassword, tmp->value, sizeof(retval->imappassword));
+#endif
                } else
                        apply_option(retval, tmp->name, tmp->value);
                tmp = tmp->next;
                } else
                        apply_option(retval, tmp->name, tmp->value);
                tmp = tmp->next;
@@ -723,7 +788,7 @@ static struct ast_vm_user *find_user_realtime(struct ast_vm_user *ivm, const cha
                        ast_variables_destroy(var);
                } else { 
                        if (!ivm) 
                        ast_variables_destroy(var);
                } else { 
                        if (!ivm) 
-                               free(retval);
+                               ast_free(retval);
                        retval = NULL;
                }       
        } 
                        retval = NULL;
                }       
        } 
@@ -784,7 +849,6 @@ static void vm_change_password(struct ast_vm_user *vmu, const char *newpassword)
        struct ast_category *cat=NULL;
        char *category=NULL, *value=NULL, *new=NULL;
        const char *tmp=NULL;
        struct ast_category *cat=NULL;
        char *category=NULL, *value=NULL, *new=NULL;
        const char *tmp=NULL;
-       int len;
                                        
        if (!change_password_realtime(vmu, newpassword))
                return;
                                        
        if (!change_password_realtime(vmu, newpassword))
                return;
@@ -793,8 +857,7 @@ static void vm_change_password(struct ast_vm_user *vmu, const char *newpassword)
        if ((cfg = ast_config_load_with_comments(VOICEMAIL_CONFIG))) {
                while ((category = ast_category_browse(cfg, category))) {
                        if (!strcasecmp(category, vmu->context)) {
        if ((cfg = ast_config_load_with_comments(VOICEMAIL_CONFIG))) {
                while ((category = ast_category_browse(cfg, category))) {
                        if (!strcasecmp(category, vmu->context)) {
-                               tmp = ast_variable_retrieve(cfg, category, vmu->mailbox);
-                               if (!tmp) {
+                               if (!(tmp = ast_variable_retrieve(cfg, category, vmu->mailbox))) {
                                        ast_log(LOG_WARNING, "We could not find the mailbox.\n");
                                        break;
                                }
                                        ast_log(LOG_WARNING, "We could not find the mailbox.\n");
                                        break;
                                }
@@ -803,51 +866,41 @@ static void vm_change_password(struct ast_vm_user *vmu, const char *newpassword)
                                        ast_log(LOG_WARNING, "variable has bad format.\n");
                                        break;
                                }
                                        ast_log(LOG_WARNING, "variable has bad format.\n");
                                        break;
                                }
-                               len  = (strlen(value) + strlen(newpassword));
-                               
-                               if (!(new = ast_calloc(1,len))) {
-                                       ast_log(LOG_WARNING, "Memory Allocation Failed.\n");
-                                       break;
-                               }
+                               new = alloca((strlen(value)+strlen(newpassword)+1));
                                sprintf(new,"%s%s", newpassword, value);
                                sprintf(new,"%s%s", newpassword, value);
-       
                                if (!(cat = ast_category_get(cfg, category))) {
                                        ast_log(LOG_WARNING, "Failed to get category structure.\n");
                                        break;
                                }
                                if (!(cat = ast_category_get(cfg, category))) {
                                        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 */
                reset_user_pw(vmu->context, vmu->mailbox, newpassword);
                ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
                config_text_file_save(VOICEMAIL_CONFIG, cfg, "AppVoicemail");
                        }
                }
                /* save the results */
                reset_user_pw(vmu->context, vmu->mailbox, newpassword);
                ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
                config_text_file_save(VOICEMAIL_CONFIG, cfg, "AppVoicemail");
-               if (new)
-                       free(new);
        }
        category = NULL;
        var = NULL;
        /* check users.conf and update the password stored for the mailbox*/
        }
        category = NULL;
        var = NULL;
        /* check users.conf and update the password stored for the mailbox*/
-       /* if no vmpassword entry exists create one. */
+       /* if no vmsecret entry exists create one. */
        if ((cfg = ast_config_load_with_comments("users.conf"))) {
        if ((cfg = ast_config_load_with_comments("users.conf"))) {
-               ast_log(LOG_WARNING, "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))) {
                while ((category = ast_category_browse(cfg, category))) {
-                       ast_log(LOG_WARNING, "users.conf: %s\n", category);
+                       ast_debug(4, "users.conf: %s\n", category);
                        if (!strcasecmp(category, vmu->mailbox)) {
                        if (!strcasecmp(category, vmu->mailbox)) {
-                               if (!(tmp = ast_variable_retrieve(cfg, category, "vmpassword"))) {
-                                       ast_log(LOG_WARNING, "looks like we need to make vmpassword!\n");
-                                       var = ast_variable_new("vmpassword", newpassword);
-                               } 
-                               if (!(new = ast_calloc(1,strlen(newpassword)))) {
-                                       ast_log(LOG_WARNING, "Memory Allocation Failed.\n");
-                                       break;
+                               if (!(tmp = ast_variable_retrieve(cfg, category, "vmsecret"))) {
+                                       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))) {
                                sprintf(new, "%s", newpassword);
                                if (!(cat = ast_category_get(cfg, category))) {
-                                       ast_log(LOG_WARNING, "failed to get category!\n");
+                                       ast_debug(4, "failed to get category!\n");
+                                       break;
                                }
                                if (!var)               
                                }
                                if (!var)               
-                                       ast_variable_update(cat, "vmpassword", new, NULL);
+                                       ast_variable_update(cat, "vmsecret", new, NULL, 0);
                                else
                                        ast_variable_append(cat, var);
                        }
                                else
                                        ast_variable_append(cat, var);
                        }
@@ -856,10 +909,7 @@ static void vm_change_password(struct ast_vm_user *vmu, const char *newpassword)
                reset_user_pw(vmu->context, vmu->mailbox, newpassword); 
                ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
                config_text_file_save("users.conf", cfg, "AppVoicemail");
                reset_user_pw(vmu->context, vmu->mailbox, newpassword); 
                ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
                config_text_file_save("users.conf", cfg, "AppVoicemail");
-               if (new) 
-                       free(new);
        }
        }
-
 }
 
 static void vm_change_password_shell(struct ast_vm_user *vmu, char *newpassword)
 }
 
 static void vm_change_password_shell(struct ast_vm_user *vmu, char *newpassword)
@@ -899,8 +949,7 @@ static void vm_imap_delete(int msgnum, struct vm_state *vms)
                ast_log(LOG_WARNING, "msgnum %d, mailbox message %lu is zero.\n",msgnum,messageNum);
                return;
        }
                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");
        /* delete message */
        sprintf (arg,"%lu",messageNum);
        mail_setflag (vms->mailstream,arg,"\\DELETED");
@@ -918,7 +967,7 @@ static int make_file(char *dest, int len, char *dir, int num)
  * \param context String. Ignored if is null or empty string.
  * \param ext     String. Ignored if is null or empty string.
  * \param folder  String. Ignored if is null or empty string. 
  * \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)
 {
  */
 static int create_dirpath(char *dest, int len, const char *context, const char *ext, const char *folder)
 {
@@ -928,27 +977,28 @@ static int create_dirpath(char *dest, int len, const char *context, const char *
                make_dir(dest, len, context, "", "");
                if (mkdir(dest, mode) && errno != EEXIST) {
                        ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dest, strerror(errno));
                make_dir(dest, len, context, "", "");
                if (mkdir(dest, mode) && errno != EEXIST) {
                        ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dest, strerror(errno));
-                       return 0;
+                       return -1;
                }
        }
        if (!ast_strlen_zero(ext)) {
                make_dir(dest, len, context, ext, "");
                if (mkdir(dest, mode) && errno != EEXIST) {
                        ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dest, strerror(errno));
                }
        }
        if (!ast_strlen_zero(ext)) {
                make_dir(dest, len, context, ext, "");
                if (mkdir(dest, mode) && errno != EEXIST) {
                        ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dest, strerror(errno));
-                       return 0;
+                       return -1;
                }
        }
        if (!ast_strlen_zero(folder)) {
                make_dir(dest, len, context, ext, folder);
                if (mkdir(dest, mode) && errno != EEXIST) {
                        ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dest, strerror(errno));
                }
        }
        if (!ast_strlen_zero(folder)) {
                make_dir(dest, len, context, ext, folder);
                if (mkdir(dest, mode) && errno != EEXIST) {
                        ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dest, strerror(errno));
-                       return 0;
+                       return -1;
                }
        }
                }
        }
-       return 1;
+       return 0;
 }
 
 }
 
-/* only return failure if ast_lock_path returns 'timeout',
+/*! \brief Lock file path
+    only return failure if ast_lock_path returns 'timeout',
    not if the path does not exist or any other reason
 */
 static int vm_lock_path(const char *path)
    not if the path does not exist or any other reason
 */
 static int vm_lock_path(const char *path)
@@ -969,7 +1019,7 @@ static int retrieve_file(char *dir, int msgnum)
        int res;
        int fd=-1;
        size_t fdlen = 0;
        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];
        SQLSMALLINT colcount=0;
        SQLHSTMT stmt;
        char sql[PATH_MAX];
@@ -1074,7 +1124,7 @@ static int retrieve_file(char *dir, int msgnum)
                        }
                        if (!strcasecmp(coltitle, "recording")) {
                                off_t offset;
                        }
                        if (!strcasecmp(coltitle, "recording")) {
                                off_t offset;
-                               res = SQLGetData(stmt, x + 1, SQL_BINARY, NULL, 0, &colsize2);
+                               res = SQLGetData(stmt, x + 1, SQL_BINARY, rowdata, 0, &colsize2);
                                fdlen = colsize2;
                                if (fd > -1) {
                                        char tmp[1]="";
                                fdlen = colsize2;
                                if (fd > -1) {
                                        char tmp[1]="";
@@ -1086,15 +1136,14 @@ static int retrieve_file(char *dir, int msgnum)
                                        }
                                        /* Read out in small chunks */
                                        for (offset = 0; offset < colsize2; offset += CHUNKSIZE) {
                                        }
                                        /* Read out in small chunks */
                                        for (offset = 0; offset < colsize2; offset += CHUNKSIZE) {
-                                               /* +1 because SQLGetData likes null-terminating binary data */
-                                               if ((fdm = mmap(NULL, CHUNKSIZE + 1, 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);
                                                        goto yuck;
                                                } else {
                                                        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);
                                                        goto yuck;
                                                } else {
-                                                       res = SQLGetData(stmt, x + 1, SQL_BINARY, fdm, CHUNKSIZE + 1, NULL);
-                                                       munmap(fdm, 0);
+                                                       res = SQLGetData(stmt, x + 1, SQL_BINARY, fdm, CHUNKSIZE, NULL);
+                                                       munmap(fdm, CHUNKSIZE);
                                                        if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
                                                                ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
                                                                unlink(full_fn);
                                                        if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
                                                                ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
                                                                unlink(full_fn);
@@ -1142,6 +1191,9 @@ static int remove_file(char *dir, int msgnum)
        } else
                ast_copy_string(fn, dir, sizeof(fn));
        ast_filedelete(fn, NULL);       
        } 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;
        snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
        unlink(full_fn);
        return 0;
@@ -1365,10 +1417,10 @@ static int store_file(char *dir, char *mailboxuser, char *mailboxcontext, int ms
        int x = 0;
        int res;
        int fd = -1;
        int x = 0;
        int res;
        int fd = -1;
-       void *fdm=NULL;
+       void *fdm = MAP_FAILED;
        size_t fdlen = -1;
        SQLHSTMT stmt;
        size_t fdlen = -1;
        SQLHSTMT stmt;
-       SQLINTEGER len;
+       SQLLEN len;
        char sql[PATH_MAX];
        char msgnums[20];
        char fn[PATH_MAX];
        char sql[PATH_MAX];
        char msgnums[20];
        char fn[PATH_MAX];
@@ -1421,7 +1473,7 @@ static int store_file(char *dir, char *mailboxuser, char *mailboxcontext, int ms
                lseek(fd, 0, SEEK_SET);
                printf("Length is %zd\n", fdlen);
                fdm = mmap(NULL, fdlen, PROT_READ | PROT_WRITE, MAP_SHARED,fd, 0);
                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;
                        ast_log(LOG_WARNING, "Memory map failed!\n");
                        ast_odbc_release_obj(obj);
                        goto yuck;
@@ -1470,7 +1522,7 @@ static int store_file(char *dir, char *mailboxuser, char *mailboxcontext, int ms
 yuck:  
        if (cfg)
                ast_config_destroy(cfg);
 yuck:  
        if (cfg)
                ast_config_destroy(cfg);
-       if (fdm)
+       if (fdm != MAP_FAILED)
                munmap(fdm, fdlen);
        if (fd > -1)
                close(fd);
                munmap(fdm, fdlen);
        if (fd > -1)
                close(fd);
@@ -1558,6 +1610,9 @@ static void rename_file(char *sfn, char *dfn)
        ast_filerename(sfn,dfn,NULL);
        snprintf(stxt, sizeof(stxt), "%s.txt", sfn);
        snprintf(dtxt, sizeof(dtxt), "%s.txt", dfn);
        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);
 }
 
        rename(stxt, dtxt);
 }
 
@@ -1614,13 +1669,47 @@ static int copy(char *infile, char *outfile)
 static void copy_file(char *frompath, char *topath)
 {
        char frompath2[PATH_MAX], topath2[PATH_MAX];
 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);
        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);
        copy(frompath2, topath2);
+       ast_variables_destroy(var);
 }
 #endif
 }
 #endif
-/*
+
+/*! \brief
  * A negative return value indicates an error.
  * \note Should always be called with a lock already set on dir.
  */
  * A negative return value indicates an error.
  * \note Should always be called with a lock already set on dir.
  */
@@ -1661,6 +1750,9 @@ static int vm_delete(char *file)
        /* Sprintf here would safe because we alloca'd exactly the right length,
         * but trying to eliminate all sprintf's anyhow
         */
        /* 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);
        snprintf(txt, txtsize, "%s.txt", file);
        unlink(txt);
        return ast_filedelete(file, NULL);
@@ -1701,14 +1793,14 @@ static int inchar(struct baseio *bio, FILE *fi)
 
 static int ochar(struct baseio *bio, int c, FILE *so)
 {
 
 static int ochar(struct baseio *bio, int c, FILE *so)
 {
-       if (bio->linelength>=BASELINELEN) {
-               if (fputs(eol,so)==EOF)
+       if (bio->linelength >= BASELINELEN) {
+               if (fputs(eol,so) == EOF)
                        return -1;
 
                bio->linelength= 0;
        }
 
                        return -1;
 
                bio->linelength= 0;
        }
 
-       if (putc(((unsigned char)c),so)==EOF)
+       if (putc(((unsigned char)c),so) == EOF)
                return -1;
 
        bio->linelength++;
                return -1;
 
        bio->linelength++;
@@ -1731,24 +1823,24 @@ static int base_encode(char *filename, FILE *so)
                return -1;
        }
 
                return -1;
        }
 
-       for (i= 0;i<9;i++) {
+       for (i= 0; i<9; i++) {
                dtable[i]= 'A'+i;
                dtable[i+9]= 'J'+i;
                dtable[26+i]= 'a'+i;
                dtable[26+i+9]= 'j'+i;
        }
                dtable[i]= 'A'+i;
                dtable[i+9]= 'J'+i;
                dtable[26+i]= 'a'+i;
                dtable[26+i+9]= 'j'+i;
        }
-       for (i= 0;i<8;i++) {
+       for (i= 0; i<8; i++) {
                dtable[i+18]= 'S'+i;
                dtable[26+i+18]= 's'+i;
        }
                dtable[i+18]= 'S'+i;
                dtable[26+i+18]= 's'+i;
        }
-       for (i= 0;i<10;i++) {
+       for (i= 0; i<10; i++) {
                dtable[52+i]= '0'+i;
        }
        dtable[62]= '+';
        dtable[63]= '/';
 
        while (!hiteof){
                dtable[52+i]= '0'+i;
        }
        dtable[62]= '+';
        dtable[63]= '/';
 
        while (!hiteof){
-               unsigned char igroup[3],ogroup[4];
+               unsigned char igroup[3], ogroup[4];
                int c,n;
 
                igroup[0]= igroup[1]= igroup[2]= 0;
                int c,n;
 
                igroup[0]= igroup[1]= igroup[2]= 0;
@@ -1764,8 +1856,8 @@ static int base_encode(char *filename, FILE *so)
 
                if (n> 0) {
                        ogroup[0]= dtable[igroup[0]>>2];
 
                if (n> 0) {
                        ogroup[0]= dtable[igroup[0]>>2];
-                       ogroup[1]= dtable[((igroup[0]&3)<<4)|(igroup[1]>>4)];
-                       ogroup[2]= dtable[((igroup[1]&0xF)<<2)|(igroup[2]>>6)];
+                       ogroup[1]= dtable[((igroup[0]&3)<<4) | (igroup[1]>>4)];
+                       ogroup[2]= dtable[((igroup[1]&0xF)<<2) | (igroup[2]>>6)];
                        ogroup[3]= dtable[igroup[2]&0x3F];
 
                        if (n<3) {
                        ogroup[3]= dtable[igroup[2]&0x3F];
 
                        if (n<3) {
@@ -1780,7 +1872,7 @@ static int base_encode(char *filename, FILE *so)
                }
        }
 
                }
        }
 
-       if (fputs(eol,so)==EOF)
+       if (fputs(eol,so) == EOF)
                return 0;
 
        fclose(fi);
                return 0;
 
        fclose(fi);
@@ -1821,7 +1913,8 @@ static char *quote(const char *from, char *to, size_t len)
        *ptr = '\0';
        return to;
 }
        *ptr = '\0';
        return to;
 }
-/*
+
+/*! \brief
  * fill in *tm for current time according to the proper timezone, if any.
  * Return tm so it can be used as a function argument.
  */
  * fill in *tm for current time according to the proper timezone, if any.
  * Return tm so it can be used as a function argument.
  */
@@ -1844,7 +1937,7 @@ static const struct tm *vmu_tm(const struct ast_vm_user *vmu, struct tm *tm)
        return tm;
 }
 
        return tm;
 }
 
-/* same as mkstemp, but return a FILE * */
+/*! \brief same as mkstemp, but return a FILE * */
 static FILE *vm_mkftemp(char *template)
 {
        FILE *p = NULL;
 static FILE *vm_mkftemp(char *template)
 {
        FILE *p = NULL;
@@ -1871,116 +1964,120 @@ static void make_email_file(FILE *p, char *srcemail, struct ast_vm_user *vmu, in
        struct tm tm;
        char *passdata2;
        size_t len_passdata;
        struct tm tm;
        char *passdata2;
        size_t len_passdata;
+#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));
 
        gethostname(host, sizeof(host)-1);
        if (strchr(srcemail, '@'))
                ast_copy_string(who, srcemail, sizeof(who));
-       else {
+       else 
                snprintf(who, sizeof(who), "%s@%s", srcemail, host);
                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));
        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);
+       fprintf(p, "Date: %s" ENDL, date);
 
        /* Set date format for voicemail mail */
        strftime(date, sizeof(date), emaildateformat, &tm);
 
 
        /* Set date format for voicemail mail */
        strftime(date, sizeof(date), emaildateformat, &tm);
 
-       if (*fromstring) {
+       if (!ast_strlen_zero(fromstring)) {
                struct ast_channel *ast;
                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))) {
                                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, fromstring, passdata, vmlen);
                        char *passdata;
                        int vmlen = strlen(fromstring)*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, fromstring, passdata, vmlen);
-                               len_passdata = strlen(passdata) * 2 + 1;
+                               len_passdata = strlen(passdata) * 2 + 3;
                                passdata2 = alloca(len_passdata);
                                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
                        } 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);
-       len_passdata = strlen(vmu->fullname) * 2 + 1;
+               fprintf(p, "From: Asterisk PBX <%s>" ENDL, who);
+       len_passdata = strlen(vmu->fullname) * 2 + 3;
        passdata2 = alloca(len_passdata);
        passdata2 = alloca(len_passdata);
-       fprintf(p, "To: %s <%s>\r\n", quote(vmu->fullname, passdata2, len_passdata), vmu->email);
-       if (emailsubject) {
+       fprintf(p, "To: %s <%s>" ENDL, quote(vmu->fullname, passdata2, len_passdata), vmu->email);
+       if (!ast_strlen_zero(emailsubject)) {
                struct ast_channel *ast;
                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;
                        char *passdata;
-                       int vmlen = strlen(emailsubject)*3 + 200;
+                       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);
                        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);
                } else
                        ast_log(LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
                        } 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  if (*emailtitle) {
+       } else  if (!ast_strlen_zero(emailtitle)) {
                fprintf(p, emailtitle, msgnum + 1, mailbox) ;
                fprintf(p, emailtitle, msgnum + 1, mailbox) ;
-               fprintf(p,"\r\n") ;
+               fprintf(p, ENDL) ;
        } else if (ast_test_flag((&globalflags), VM_PBXSKIP))
        } 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
        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 */
        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);
+               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))
                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-Category: %s" ENDL, category);
+               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))
        }
        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))
        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. */
        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 (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);
                        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 {
                        } 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"
+               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);
        }
        if (attach_user_voicemail) {
                dur, msgnum + 1, mailbox, (cidname ? cidname : (cidnum ? cidnum : "an unknown caller")), date);
        }
        if (attach_user_voicemail) {
@@ -1992,36 +2089,28 @@ static void make_email_file(FILE *p, char *srcemail, struct ast_vm_user *vmu, in
                create_dirpath(tmpdir, sizeof(tmpdir), vmu->context, vmu->mailbox, "tmp");
                snprintf(newtmp, sizeof(newtmp), "%s/XXXXXX", tmpdir);
                tmpfd = mkstemp(newtmp);
                create_dirpath(tmpdir, sizeof(tmpdir), vmu->context, vmu->mailbox, "tmp");
                snprintf(newtmp, sizeof(newtmp), "%s/XXXXXX", tmpdir);
                tmpfd = mkstemp(newtmp);
-               ast_log(LOG_DEBUG, "newtmp: %s\n", newtmp);
+               ast_debug(3, "newtmp: %s\n", newtmp);
                if (vmu->volgain < -.001 || vmu->volgain > .001) {
                        snprintf(tmpcmd, sizeof(tmpcmd), "sox -v %.4f %s.%s %s.%s", vmu->volgain, attach, format, newtmp, format);
                        ast_safe_system(tmpcmd);
                        attach = newtmp;
                if (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;
-                       ast_log(LOG_DEBUG, "VOLGAIN: Stored at: %s.%s - Level: %.4f - Mailbox: %s\n", attach, format, vmu->volgain, mailbox);
+                       ast_debug(3, "VOLGAIN: Stored at: %s.%s - Level: %.4f - Mailbox: %s\n", attach, format, vmu->volgain, mailbox);
                }
                }
-               fprintf(p, "--%s\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);
+               fprintf(p, "--%s" ENDL, bound);
+               fprintf(p, "Content-Type: %s%s; name=\"msg%04d.%s\"" ENDL, ctype, format, msgnum + 1, format);
+               fprintf(p, "Content-Transfer-Encoding: base64" ENDL);
+               fprintf(p, "Content-Description: Voicemail sound attachment." ENDL);
+               fprintf(p, "Content-Disposition: attachment; filename=\"msg%04d.%s\"" ENDL ENDL, msgnum + 1, format);
                snprintf(fname, sizeof(fname), "%s.%s", attach, format);
                base_encode(fname, p);
                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);
+               fprintf(p, ENDL "--%s--" ENDL "." ENDL, bound);
                if (tmpfd > -1)
                        close(tmpfd);
                unlink(newtmp);
        }
                if (tmpfd > -1)
                        close(tmpfd);
                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)
 {
        FILE *p=NULL;
 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)
 {
        FILE *p=NULL;
@@ -2034,7 +2123,7 @@ static int sendmail(char *srcemail, struct ast_vm_user *vmu, int msgnum, char *c
        }
        if (!strcmp(format, "wav49"))
                format = "WAV";
        }
        if (!strcmp(format, "wav49"))
                format = "WAV";
-       ast_log(LOG_DEBUG, "Attaching file '%s', format '%s', uservm is '%d', global is %d\n", attach, format, attach_user_voicemail, ast_test_flag((&globalflags), VM_ATTACH));
+       ast_debug(3, "Attaching file '%s', format '%s', uservm is '%d', global is %d\n", attach, format, attach_user_voicemail, ast_test_flag((&globalflags), VM_ATTACH));
        /* Make a temporary file instead of piping directly to sendmail, in case the mail
           command hangs */
        if ((p = vm_mkftemp(tmp)) == NULL) {
        /* Make a temporary file instead of piping directly to sendmail, in case the mail
           command hangs */
        if ((p = vm_mkftemp(tmp)) == NULL) {
@@ -2045,8 +2134,7 @@ static int sendmail(char *srcemail, struct ast_vm_user *vmu, int msgnum, char *c
                fclose(p);
                snprintf(tmp2, sizeof(tmp2), "( %s < %s ; rm -f %s ) &", mailcmd, tmp, tmp);
                ast_safe_system(tmp2);
                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;
 }
        }
        return 0;
 }
@@ -2065,73 +2153,74 @@ static int sendpage(char *srcemail, char *pager, int msgnum, char *context, char
        if ((p = vm_mkftemp(tmp)) == NULL) {
                ast_log(LOG_WARNING, "Unable to launch '%s' (can't create temporary file)\n", mailcmd);
                return -1;
        if ((p = vm_mkftemp(tmp)) == NULL) {
                ast_log(LOG_WARNING, "Unable to launch '%s' (can't create temporary file)\n", mailcmd);
                return -1;
-       } else {
-               gethostname(host, sizeof(host)-1);
-               if (strchr(srcemail, '@'))
-                       ast_copy_string(who, srcemail, sizeof(who));
-               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));
-               fprintf(p, "Date: %s\n", date);
-
-               if (*pagerfromstring) {
-                       struct ast_channel *ast;
-                       if ((ast = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, 0))) {
-                               char *passdata;
-                               int vmlen = strlen(fromstring)*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, pagerfromstring, passdata, vmlen);
-                                       fprintf(p, "From: %s <%s>\n", 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>\n", who);
-               fprintf(p, "To: %s\n", pager);
-               if (pagersubject) {
-                       struct ast_channel *ast;
-                       if ((ast = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, 0))) {
-                               char *passdata;
-                               int vmlen = strlen(pagersubject) * 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, pagersubject, passdata, vmlen);
-                                       fprintf(p, "Subject: %s\n\n", 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");
+       }
+       gethostname(host, sizeof(host)-1);
+       if (strchr(srcemail, '@'))
+               ast_copy_string(who, srcemail, sizeof(who));
+       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));
+       fprintf(p, "Date: %s\n", date);
+
+       if (*pagerfromstring) {
+               struct ast_channel *ast;
+               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))) {
+                               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, pagerfromstring, passdata, vmlen);
+                               fprintf(p, "From: %s <%s>\n", 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>\n", who);
+       fprintf(p, "To: %s\n", pager);
+       if (pagersubject) {
+               struct ast_channel *ast;
+               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))) {
+                               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, pagersubject, passdata, vmlen);
+                               fprintf(p, "Subject: %s\n\n", passdata);
+                       } else
+                               ast_log(LOG_WARNING, "Cannot allocate workspace for variable substitution\n");
+                       ast_channel_free(ast);
                } else
                } else
-                       fprintf(p, "Subject: New VM\n\n");
-               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))) {
-                               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");
+                       ast_log(LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
+       } else
+               fprintf(p, "Subject: New VM\n\n");
+
+       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, 0))) {
+                       char *passdata;
+                       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);
                        ast_channel_free(ast);
-                       } else ast_log(LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
-               } else {
-                       fprintf(p, "New %s long msg in box %s\n"
-                                       "from %s, on %s", dur, mailbox, (cidname ? cidname : (cidnum ? cidnum : "unknown")), date);
-               }
-               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);
+               } else
+                       ast_log(LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
+       } else {
+               fprintf(p, "New %s long msg in box %s\n"
+                               "from %s, on %s", dur, mailbox, (cidname ? cidname : (cidnum ? cidnum : "unknown")), date);
        }
        }
+       fclose(p);
+       snprintf(tmp2, sizeof(tmp2), "( %s < %s ; rm -f %s ) &", mailcmd, tmp, tmp);
+       ast_safe_system(tmp2);
+       ast_debug(1, "Sent page to %s with command '%s'\n", pager, mailcmd);
        return 0;
 }
 
        return 0;
 }
 
@@ -2152,7 +2241,7 @@ static int invent_message(struct ast_channel *chan, char *context, char *ext, in
 
        snprintf(fn, sizeof(fn), "%s%s/%s/greet", VM_SPOOL_DIR, context, ext);
 
 
        snprintf(fn, sizeof(fn), "%s%s/%s/greet", VM_SPOOL_DIR, context, ext);
 
-       if (!(res = create_dirpath(dest, sizeof(dest), context, ext, "greet"))) {
+       if ((res = create_dirpath(dest, sizeof(dest), context, ext, "greet"))) {
                ast_log(LOG_WARNING, "Failed to make directory(%s)\n", fn);
                return -1;
        }
                ast_log(LOG_WARNING, "Failed to make directory(%s)\n", fn);
                return -1;
        }
@@ -2180,13 +2269,15 @@ static int invent_message(struct ast_channel *chan, char *context, char *ext, in
 
 static void free_user(struct ast_vm_user *vmu)
 {
 
 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)
 {
 }
 
 static void free_zone(struct vm_zone *z)
 {
-       free(z);
+       ast_free(z);
 }
 
 static const char *mbox(int id)
 }
 
 static const char *mbox(int id)
@@ -2423,34 +2514,34 @@ static int imap_store_file(char *dir, char *mailboxuser, char *mailboxcontext, i
 
        if (!strcmp(fmt, "wav49"))
                fmt = "WAV";
 
        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 */
        /* Make a temporary file instead of piping directly to sendmail, in case the mail
           command hangs */
-       if ((p = vm_mkftemp(tmp)) == NULL) {
+       if (!(p = vm_mkftemp(tmp))) {
                ast_log(LOG_WARNING, "Unable to store '%s' (can't create temporary file)\n", fn);
                return -1;
                ast_log(LOG_WARNING, "Unable to store '%s' (can't create temporary file)\n", fn);
                return -1;
-       } else {
-               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);
-               /* read mail file to memory */          
-               len = ftell(p);
-               rewind(p);
-               if((buf = ast_malloc(len+1)) == NIL) {
-                       ast_log(LOG_ERROR, "Can't allocate %ld bytes to read message\n", len+1);
-                       return -1;
-               }
-               fread(buf, len, 1, p);
-               ((char *)buf)[len] = '\0';
-               INIT(&str, mail_string, buf, len);
-               imap_mailbox_name(mailbox, vms, 0, 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);
        }
        }
+       
+       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);
+       /* read mail file to memory */          
+       len = ftell(p);
+       rewind(p);
+       if (!(buf = ast_malloc(len+1))) {
+               ast_log(LOG_ERROR, "Can't allocate %ld bytes to read message\n", len+1);
+               return -1;
+       }
+       fread(buf, len, 1, p);
+       ((char *)buf)[len] = '\0';
+       INIT(&str, mail_string, buf, len);
+       init_mailstream(vms, 0);
+       imap_mailbox_name(mailbox, vms, 0, 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);
+       ast_debug(3, "%s stored\n", fn);
        return 0;
 
 }
        return 0;
 
 }
@@ -2467,16 +2558,19 @@ static int inboxcount(const char *mailbox, int *newmsgs, int *oldmsgs)
        char *mailboxnc; 
        char *context;
        int ret = 0;
        char *mailboxnc; 
        char *context;
        int ret = 0;
+
        if (newmsgs)
                *newmsgs = 0;
        if (newmsgs)
                *newmsgs = 0;
+
        if (oldmsgs)
                *oldmsgs = 0;
  
        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))
                return 0;
        /* If no mailbox, return immediately */
        if (ast_strlen_zero(mailbox))
                return 0;
+
        if (strchr(mailbox, ',')) {
                int tmpnew, tmpold;
                ast_copy_string(tmp, mailbox, sizeof(tmp));
        if (strchr(mailbox, ',')) {
                int tmpnew, tmpold;
                ast_copy_string(tmp, mailbox, sizeof(tmp));
@@ -2496,9 +2590,10 @@ static int inboxcount(const char *mailbox, int *newmsgs, int *oldmsgs)
                }
                return 0;
        }
                }
                return 0;
        }
+
        ast_copy_string(tmp, mailbox, sizeof(tmp));
        ast_copy_string(tmp, mailbox, sizeof(tmp));
-       context = strchr(tmp, '@');
-       if (context) {
+
+       if ((context = strchr(tmp, '@'))) {
                *context = '\0';
                mailboxnc = tmp;
                context++;
                *context = '\0';
                mailboxnc = tmp;
                context++;
@@ -2508,92 +2603,85 @@ static int inboxcount(const char *mailbox, int *newmsgs, int *oldmsgs)
        }
  
        /* We have to get the user before we can open the stream! */
        }
  
        /* 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, mailboxnc);
-       if (!vmu) {
-               ast_log (LOG_ERROR,"Couldn't find mailbox %s in context %s\n",mailboxnc,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);
-                       return -1;
-               }
+       /*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;
+       }
+       
+       /* 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... */
        }
  
        /* check if someone is accessing this box right now... */
-       vms_p = get_vm_state_by_imapuser(vmu->imapuser,1);
-       if (!vms_p) {
-               vms_p = get_vm_state_by_mailbox(mailboxnc,1);
-       }
-       if (vms_p) {
-               if(option_debug > 2)
-                       ast_log (LOG_DEBUG,"Returning before search - user is logged in\n");
+       if ((vms_p = get_vm_state_by_imapuser(vmu->imapuser, 1)) || (vms_p = get_vm_state_by_mailbox(mailboxnc, 1))) {
+               ast_debug(3,"Returning before search - user is logged in\n");
                *newmsgs = vms_p->newmessages;
                *oldmsgs = vms_p->oldmessages;
                *newmsgs = vms_p->newmessages;
                *oldmsgs = vms_p->oldmessages;
+               free_user(vmu);
                return 0;
        }
  
        /* add one if not there... */
                return 0;
        }
  
        /* add one if not there... */
-       vms_p = get_vm_state_by_imapuser(vmu->imapuser,0);
-       if (!vms_p) {
-               vms_p = get_vm_state_by_mailbox(mailboxnc,0);
-       }
-       if (!vms_p) {
-               if(option_debug > 2)
-                       ast_log (LOG_DEBUG,"Adding new vmstate for %s\n",vmu->imapuser);
-               vms_p = (struct vm_state *)malloc(sizeof(struct vm_state));
+       if (!(vms_p = get_vm_state_by_imapuser(vmu->imapuser, 0)) && !(vms_p = get_vm_state_by_mailbox(mailboxnc, 0))) {
+               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 */
                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);
-               vms_p->updated = 1;
-               vms_p->interactive = 0;
-               /* set mailbox to INBOX! */
+               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));
                init_vm_state(vms_p);
                vmstate_insert(vms_p);
        }
                ast_copy_string(vms_p->curbox, mbox(0), sizeof(vms_p->curbox));
                init_vm_state(vms_p);
                vmstate_insert(vms_p);
        }
-       if (!vms_p->mailstream)
-               ret = init_mailstream(vms_p, 0);
-       if (!vms_p->mailstream) {
+
+       /* If no mailstream exists yet and even after attempting to initialize it fails, bail out */
+       ret = init_mailstream(vms_p, 0);
+       if (!vms_p->mailstream) {
                ast_log (LOG_ERROR,"Houston we have a problem - IMAP mailstream is NULL\n");
                ast_log (LOG_ERROR,"Houston we have a problem - IMAP mailstream is NULL\n");
-               return -1;
-       }
-       if (newmsgs && ret==0 && vms_p->updated==1 ) {
-               pgm = mail_newsearchpgm ();
-               hdr = mail_newsearchheader ("X-Asterisk-VM-Extension", (char *)mailboxnc);
-               pgm->header = hdr;
-               pgm->unseen = 1;
-               pgm->seen = 0;
-               pgm->undeleted = 1;
-               pgm->deleted = 0;
-               vms_p->vmArrayIndex = 0;
-       
-               mail_search_full (vms_p->mailstream, NULL, pgm, NIL);
-               *newmsgs = vms_p->vmArrayIndex;
-               vms_p->newmessages = vms_p->vmArrayIndex;
-               mail_free_searchpgm(&pgm);
-       }
-       if (oldmsgs && ret==0 && vms_p->updated==1 ) {
-               pgm = mail_newsearchpgm ();
-               hdr = mail_newsearchheader ("X-Asterisk-VM-Extension", (char *)mailboxnc);
-               pgm->header = hdr;
-               pgm->unseen = 0;
-               pgm->seen = 1;
-               pgm->deleted = 0;
-               pgm->undeleted = 1;
-               vms_p->vmArrayIndex = 0;
-       
-               mail_search_full (vms_p->mailstream, NULL, pgm, NIL);
-               *oldmsgs = vms_p->vmArrayIndex;
-               vms_p->oldmessages = vms_p->vmArrayIndex;
-               mail_free_searchpgm(&pgm);
-       }
+               free_user(vmu);
+               return -1;
+       }
+
+       if (!ret && vms_p->updated == 1) {
+               if (newmsgs) {
+                       pgm = mail_newsearchpgm();
+                       hdr = mail_newsearchheader("X-Asterisk-VM-Extension", (char *)mailboxnc);
+                       pgm->header = hdr;
+                       pgm->unseen = 1;
+                       pgm->seen = 0;
+                       pgm->undeleted = 1;
+                       pgm->deleted = 0;
+                       vms_p->vmArrayIndex = 0;
+                       mail_search_full(vms_p->mailstream, NULL, pgm, NIL);
+                       *newmsgs = vms_p->vmArrayIndex;
+                       vms_p->newmessages = vms_p->vmArrayIndex;
+                       mail_free_searchpgm(&pgm);
+               }
+               if (oldmsgs) {
+                       pgm = mail_newsearchpgm ();
+                       hdr = mail_newsearchheader ("X-Asterisk-VM-Extension", (char *)mailboxnc);
+                       pgm->header = hdr;
+                       pgm->unseen = 0;
+                       pgm->seen = 1;
+                       pgm->undeleted = 1;
+                       pgm->deleted = 0;
+                       vms_p->vmArrayIndex = 0;
+                       mail_search_full(vms_p->mailstream, NULL, pgm, NIL);
+                       *oldmsgs = vms_p->vmArrayIndex;
+                       vms_p->oldmessages = vms_p->vmArrayIndex;
+                       mail_free_searchpgm(&pgm);
+               }
+       }
+
        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 */
        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 */
@@ -2604,6 +2692,8 @@ static int inboxcount(const char *mailbox, int *newmsgs, int *oldmsgs)
                *newmsgs = vms_p->newmessages;
                *oldmsgs = vms_p->oldmessages;
        }
                *newmsgs = vms_p->newmessages;
                *oldmsgs = vms_p->oldmessages;
        }
+
+       free_user(vmu);
        return 0;
  }
 
        return 0;
  }
 
@@ -2682,17 +2772,21 @@ static int __has_voicemail(const char *context, const char *mailbox, const char
        struct dirent *de;
        char fn[256];
        int ret = 0;
        struct dirent *de;
        char fn[256];
        int ret = 0;
-       if (!folder)
-               folder = "INBOX";
+
        /* If no mailbox, return immediately */
        if (ast_strlen_zero(mailbox))
                return 0;
        /* If no mailbox, return immediately */
        if (ast_strlen_zero(mailbox))
                return 0;
-       if (!context)
+
+       if (ast_strlen_zero(folder))
+               folder = "INBOX";
+       if (ast_strlen_zero(context))
                context = "default";
                context = "default";
+
        snprintf(fn, sizeof(fn), "%s%s/%s/%s", VM_SPOOL_DIR, context, mailbox, folder);
        snprintf(fn, sizeof(fn), "%s%s/%s/%s", VM_SPOOL_DIR, context, mailbox, folder);
-       dir = opendir(fn);
-       if (!dir)
+
+       if (!(dir = opendir(fn)))
                return 0;
                return 0;
+
        while ((de = readdir(dir))) {
                if (!strncasecmp(de->d_name, "msg", 3)) {
                        if (shortcircuit) {
        while ((de = readdir(dir))) {
                if (!strncasecmp(de->d_name, "msg", 3)) {
                        if (shortcircuit) {
@@ -2702,7 +2796,9 @@ static int __has_voicemail(const char *context, const char *mailbox, const char
                                ret++;
                }
        }
                                ret++;
                }
        }
+
        closedir(dir);
        closedir(dir);
+
        return ret;
 }
 
        return ret;
 }
 
@@ -2728,13 +2824,15 @@ static int inboxcount(const char *mailbox, int *newmsgs, int *oldmsgs)
        char tmp[256];
        char *context;
 
        char tmp[256];
        char *context;
 
+       /* If no mailbox, return immediately */
+       if (ast_strlen_zero(mailbox))
+               return 0;
+
        if (newmsgs)
                *newmsgs = 0;
        if (oldmsgs)
                *oldmsgs = 0;
        if (newmsgs)
                *newmsgs = 0;
        if (oldmsgs)
                *oldmsgs = 0;
-       /* If no mailbox, return immediately */
-       if (ast_strlen_zero(mailbox))
-               return 0;
+
        if (strchr(mailbox, ',')) {
                int tmpnew, tmpold;
                char *mb, *cur;
        if (strchr(mailbox, ',')) {
                int tmpnew, tmpold;
                char *mb, *cur;
@@ -2755,17 +2853,19 @@ static int inboxcount(const char *mailbox, int *newmsgs, int *oldmsgs)
                }
                return 0;
        }
                }
                return 0;
        }
+
        ast_copy_string(tmp, mailbox, sizeof(tmp));
        ast_copy_string(tmp, mailbox, sizeof(tmp));
-       context = strchr(tmp, '@');
-       if (context) {
-               *context = '\0';
-               context++;
-       } else
+       
+       if ((context = strchr(tmp, '@')))
+               *context++ = '\0';
+       else
                context = "default";
                context = "default";
+
        if (newmsgs)
                *newmsgs = __has_voicemail(context, tmp, "INBOX", 0);
        if (oldmsgs)
                *oldmsgs = __has_voicemail(context, tmp, "Old", 0);
        if (newmsgs)
                *newmsgs = __has_voicemail(context, tmp, "INBOX", 0);
        if (oldmsgs)
                *oldmsgs = __has_voicemail(context, tmp, "Old", 0);
+
        return 0;
 }
 
        return 0;
 }
 
@@ -2783,7 +2883,7 @@ static void run_externnotify(char *context, char *extension)
        else
                ast_copy_string(ext_context, extension, sizeof(ext_context));
 
        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
                if (ast_app_has_voicemail(ext_context, NULL)) 
                        ast_smdi_mwi_set(smdi_iface, extension);
                else
@@ -2798,16 +2898,16 @@ 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 {
                        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 (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);
                }
        }
                        ast_safe_system(arguments);
                }
        }
@@ -2835,6 +2935,11 @@ static int leave_voicemail(struct ast_channel *chan, char *ext, struct leave_vm_
        int ausemacro = 0;
        int ousemacro = 0;
        int ouseexten = 0;
        int 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 dir[PATH_MAX], tmpdir[PATH_MAX];
        char dest[PATH_MAX];
        char fn[PATH_MAX];
@@ -2844,15 +2949,14 @@ static int leave_voicemail(struct ast_channel *chan, char *ext, struct leave_vm_
        char fmt[80];
        char *context;
        char ecodes[16] = "#";
        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;
 
        ast_copy_string(tmp, ext, sizeof(tmp));
        ext = tmp;
        struct ast_vm_user *vmu;
        struct ast_vm_user svm;
        const char *category = NULL;
 
        ast_copy_string(tmp, ext, sizeof(tmp));
        ext = tmp;
-       context = strchr(tmp, '@');
-       if (context) {
+       if ((context = strchr(tmp, '@'))) {
                *context++ = '\0';
                tmpptr = strchr(context, '&');
        } else {
                *context++ = '\0';
                tmpptr = strchr(context, '&');
        } else {
@@ -2864,12 +2968,9 @@ static int leave_voicemail(struct ast_channel *chan, char *ext, struct leave_vm_
 
        category = pbx_builtin_getvar_helper(chan, "VM_CATEGORY");
 
 
        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 (!(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;
        }
                pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
                return res;
        }
@@ -2886,7 +2987,7 @@ static int leave_voicemail(struct ast_channel *chan, char *ext, struct leave_vm_
                snprintf(prefile, sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, ext);
        }
        snprintf(tempfile, sizeof(tempfile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, ext);
                snprintf(prefile, sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, ext);
        }
        snprintf(tempfile, sizeof(tempfile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, ext);
-       if (!(res = create_dirpath(dest, sizeof(dest), vmu->context, ext, "temp"))) {
+       if ((res = create_dirpath(dest, sizeof(dest), vmu->context, ext, "temp"))) {
                ast_log(LOG_WARNING, "Failed to make directory (%s)\n", tempfile);
                return -1;
        }
                ast_log(LOG_WARNING, "Failed to make directory (%s)\n", tempfile);
                return -1;
        }
@@ -2932,14 +3033,12 @@ static int leave_voicemail(struct ast_channel *chan, char *ext, struct leave_vm_
                        if (ast_streamfile(chan, prefile, chan->language) > -1) 
                                res = ast_waitstream(chan, ecodes);
                } else {
                        if (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) {
                        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;
                        free_user(vmu);
                        pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
                        return -1;
@@ -3008,12 +3107,11 @@ static int leave_voicemail(struct ast_channel *chan, char *ext, struct leave_vm_
                /* must open stream for this user to get info! */
                vms = get_vm_state_by_mailbox(ext,0);
                if (vms) {
                /* must open stream for this user to get info! */
                vms = get_vm_state_by_mailbox(ext,0);
                if (vms) {
-                       if(option_debug > 2)
-                               ast_log(LOG_DEBUG, "Using vm_state, interactive set to %d.\n",vms->interactive);
+                       ast_debug(3, "Using vm_state, interactive set to %d.\n",vms->interactive);
                        newmsgs = vms->newmessages++;
                        oldmsgs = vms->oldmessages;
                } else {
                        newmsgs = vms->newmessages++;
                        oldmsgs = vms->oldmessages;
                } else {
-                       res = inboxcount(ext, &newmsgs, &oldmsgs);
+                       res = inboxcount(ext_context, &newmsgs, &oldmsgs);
                        if(res < 0) {
                                ast_log(LOG_NOTICE,"Can not leave voicemail, unable to count messages\n");
                                return -1;
                        if(res < 0) {
                                ast_log(LOG_NOTICE,"Can not leave voicemail, unable to count messages\n");
                                return -1;
@@ -3022,23 +3120,20 @@ static int leave_voicemail(struct ast_channel *chan, char *ext, struct leave_vm_
                }
                /* here is a big difference! We add one to it later */
                msgnum = newmsgs + oldmsgs;
                }
                /* 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) {
                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;
                        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) {
 
 #else
                if (count_messages(vmu, dir) >= vmu->maxmsg) {
@@ -3068,6 +3163,14 @@ static int leave_voicemail(struct ast_channel *chan, char *ext, struct leave_vm_
                        res = ast_stream_and_wait(chan, "beep", "");
                }
                                
                        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) {
                /* Store information */
                txt = fdopen(txtdes, "w+");
                if (txt) {
@@ -3110,6 +3213,10 @@ static int leave_voicemail(struct ast_channel *chan, char *ext, struct leave_vm_
                                        ast_verbose( VERBOSE_PREFIX_3 "Recording was %d seconds long but needs to be at least %d - abandoning\n", duration, vmminsecs);
                                ast_filedelete(tmptxtfile, NULL);
                                unlink(tmptxtfile);
                                        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);
                        } else {
                                fprintf(txt, "duration=%d\n", duration);
                                fclose(txt);
@@ -3119,10 +3226,13 @@ static int leave_voicemail(struct ast_channel *chan, char *ext, struct leave_vm_
                                        ast_filedelete(tmptxtfile, NULL);
                                        unlink(tmptxtfile);
                                } else if (ast_fileexists(tmptxtfile, NULL, NULL) <= 0) {
                                        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);
                                        unlink(tmptxtfile);
                                        ast_unlock_path(dir);
+                                       if (ast_check_realtime("voicemail_data")) {
+                                               snprintf(tmpid, sizeof(tmpid), "%d", rtmsgid);
+                                               ast_destroy_realtime("voicemail_data", "id", tmpid, NULL);
+                                       }
                                } else {
                                        msgnum = last_message_index(vmu, dir) + 1;
                                        make_file(fn, sizeof(fn), dir, msgnum);
                                } else {
                                        msgnum = last_message_index(vmu, dir) + 1;
                                        make_file(fn, sizeof(fn), dir, msgnum);
@@ -3139,6 +3249,11 @@ static int leave_voicemail(struct ast_channel *chan, char *ext, struct leave_vm_
                                        rename(tmptxtfile, txtfile);
 
                                        ast_unlock_path(dir);
                                        rename(tmptxtfile, txtfile);
 
                                        ast_unlock_path(dir);
+                                       if (ast_check_realtime("voicemail_data")) {
+                                               snprintf(tmpid, sizeof(tmpid), "%d", rtmsgid);
+                                               snprintf(tmpdur, sizeof(tmpdur), "%d", duration);
+                                               ast_update_realtime("voicemail_data", "id", tmpid, "filename", fn, "duration", tmpdur, NULL);
+                                       }
 #ifndef IMAP_STORAGE
                                        /* Are there to be more recipients of this message? */
                                        while (tmpptr) {
 #ifndef IMAP_STORAGE
                                        /* Are there to be more recipients of this message? */
                                        while (tmpptr) {
@@ -3234,8 +3349,7 @@ static int save_to_folder(struct ast_vm_user *vmu, struct vm_state *vms, int msg
        /* get the real IMAP message number for this message */
        sprintf(sequence,"%ld",vms->msgArray[msg]);
        imap_mailbox_name(dbox, vms, box, 1);
        /* 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;
        res = mail_copy(vms->mailstream, sequence, dbox);
        if (res == 1) return 0;
        return 1;
@@ -3384,8 +3498,7 @@ static int adsi_load_vmail(struct ast_channel *chan, int *useadsi)
        bytes += ast_adsi_voice_mode(buf + bytes, 0);
        ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
 
        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 */
 
 #ifdef DISPLAY
        /* Add last dot */
@@ -3393,8 +3506,7 @@ static int adsi_load_vmail(struct ast_channel *chan, int *useadsi)
        bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "   ......", "");
        bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
 #endif
        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 */
 
        bytes = 0;
        /* Load the session now */
@@ -3853,7 +3965,7 @@ static int vm_forwardoptions(struct ast_channel *chan, struct ast_vm_user *vmu,
                                *duration += prepend_duration;
                                msg_cat = ast_category_get(msg_cfg, "message");
                                snprintf(duration_str, 11, "%ld", *duration);
                                *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);
                                }
                                        config_text_file_save(textfile, msg_cfg, "app_voicemail");
                                        STORE(curdir, vmu->mailbox, context, curmsg, chan, vmu, vmfmts, *duration, vms);
                                }
@@ -3888,22 +4000,45 @@ static int vm_forwardoptions(struct ast_channel *chan, struct ast_vm_user *vmu,
        return cmd;
 }
 
        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;
        int newmsgs = 0, oldmsgs = 0;
        const char *category = pbx_builtin_getvar_helper(chan, "VM_CATEGORY");
 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;
        int newmsgs = 0, oldmsgs = 0;
        const char *category = pbx_builtin_getvar_helper(chan, "VM_CATEGORY");
+       char *myserveremail = serveremail;
 
        make_dir(todir, sizeof(todir), vmu->context, vmu->mailbox, "INBOX");
        make_file(fn, sizeof(fn), todir, msgnum);
        snprintf(ext_context, sizeof(ext_context), "%s@%s", vmu->mailbox, vmu->context);
 
        if (!ast_strlen_zero(vmu->attachfmt)) {
 
        make_dir(todir, sizeof(todir), vmu->context, vmu->mailbox, "INBOX");
        make_file(fn, sizeof(fn), todir, msgnum);
        snprintf(ext_context, sizeof(ext_context), "%s@%s", vmu->mailbox, vmu->context);
 
        if (!ast_strlen_zero(vmu->attachfmt)) {
-               if (strstr(fmt, vmu->attachfmt)) {
+               if (strstr(fmt, vmu->attachfmt))
                        fmt = vmu->attachfmt;
                        fmt = vmu->attachfmt;
-               } else {
+                else
                        ast_log(LOG_WARNING, "Attachment format '%s' is not one of the recorded formats '%s'.  Falling back to default format for '%s@%s'.\n", vmu->attachfmt, fmt, vmu->mailbox, vmu->context);
                        ast_log(LOG_WARNING, "Attachment format '%s' is not one of the recorded formats '%s'.  Falling back to default format for '%s@%s'.\n", vmu->attachfmt, fmt, vmu->mailbox, vmu->context);
-               }
        }
 
        /* Attach only the first format */
        }
 
        /* Attach only the first format */
@@ -3911,34 +4046,33 @@ static int notify_new_message(struct ast_channel *chan, struct ast_vm_user *vmu,
        stringp = fmt;
        strsep(&stringp, "|");
 
        stringp = fmt;
        strsep(&stringp, "|");
 
+       if (!ast_strlen_zero(vmu->serveremail))
+               myserveremail = vmu->serveremail;
+
        if (!ast_strlen_zero(vmu->email)) {
        if (!ast_strlen_zero(vmu->email)) {
-               int attach_user_voicemail = ast_test_flag((&globalflags), VM_ATTACH);
-               char *myserveremail = serveremail;
-               attach_user_voicemail = ast_test_flag(vmu, VM_ATTACH);
-               if (!ast_strlen_zero(vmu->serveremail))
-                       myserveremail = vmu->serveremail;
+               int attach_user_voicemail = ast_test_flag(vmu, VM_ATTACH);
+               if (!attach_user_voicemail)
+                       attach_user_voicemail = ast_test_flag((&globalflags), VM_ATTACH);
+
                /*XXX possible imap issue, should category be NULL XXX*/
                sendmail(myserveremail, vmu, msgnum, vmu->context, vmu->mailbox, cidnum, cidname, fn, fmt, duration, attach_user_voicemail, chan, category);
        }
 
                /*XXX possible imap issue, should category be NULL XXX*/
                sendmail(myserveremail, vmu, msgnum, vmu->context, vmu->mailbox, cidnum, cidname, fn, fmt, duration, attach_user_voicemail, chan, category);
        }
 
-       if (!ast_strlen_zero(vmu->pager)) {
-               char *myserveremail = serveremail;
-               if (!ast_strlen_zero(vmu->serveremail))
-                       myserveremail = vmu->serveremail;
+       if (!ast_strlen_zero(vmu->pager))
                sendpage(myserveremail, vmu->pager, msgnum, vmu->context, vmu->mailbox, cidnum, cidname, duration, vmu, category);
                sendpage(myserveremail, vmu->pager, msgnum, vmu->context, vmu->mailbox, cidnum, cidname, duration, vmu, category);
-       }
 
 
-       if (ast_test_flag(vmu, VM_DELETE)) {
+       if (ast_test_flag(vmu, VM_DELETE))
                DELETE(todir, msgnum, fn);
                DELETE(todir, msgnum, fn);
-       }
 
 #ifdef IMAP_STORAGE
        DELETE(todir, msgnum, fn);
 #endif
        /* Leave voicemail for someone */
 
 #ifdef IMAP_STORAGE
        DELETE(todir, msgnum, fn);
 #endif
        /* Leave voicemail for someone */
-       if (ast_app_has_voicemail(ext_context, NULL)) {
+       if (ast_app_has_voicemail(ext_context, NULL)) 
                ast_app_inboxcount(ext_context, &newmsgs, &oldmsgs);
                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;
        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;
@@ -4090,15 +4224,19 @@ static int forward_message(struct ast_channel *chan, char *context, struct vm_st
 
                /* Forward VoiceMail */
                long duration = 0;
 
                /* Forward VoiceMail */
                long duration = 0;
+#ifdef IMAP_STORAGE
+               char *myserveremail = serveremail;
+               char buf[1024] = "";
+               int attach_user_voicemail = ast_test_flag((&globalflags), VM_ATTACH);
+#endif
                RETRIEVE(dir, curmsg);
                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 */
                RETRIEVE(dir, curmsg);
                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]);
-                               if (vms->msgArray[vms->curmsg] == 0) {
+                               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;
                                }
                                        ast_log (LOG_WARNING,"Trying to access unknown message\n");
                                        return -1;
                                }
@@ -4111,15 +4249,13 @@ static int forward_message(struct ast_channel *chan, char *context, struct vm_st
                                        return -1;
                                }
                                /* Get header info needed by sendmail */
                                        return -1;
                                }
                                /* Get header info needed by sendmail */
-                               temp = get_header_by_tag(header_content, "X-Asterisk-VM-Duration:");
-                               if (temp)
+                               if ((temp = get_header_by_tag(header_content, "X-Asterisk-VM-Duration:", buf, sizeof(buf))))
                                        duration = atoi(temp);
                                else
                                        duration = 0;
                                        duration = atoi(temp);
                                else
                                        duration = 0;
+                               
                                /* Attach only the first format */
                                /* Attach only the first format */
-                               fmt = ast_strdupa(fmt);
-                               if (fmt) {
+                               if ((fmt = ast_strdupa(fmt))) {
                                        stringp = fmt;
                                        strsep(&stringp, "|");
                                } else {
                                        stringp = fmt;
                                        strsep(&stringp, "|");
                                } else {
@@ -4128,14 +4264,12 @@ static int forward_message(struct ast_channel *chan, char *context, struct vm_st
                                }
                                if (!strcasecmp(fmt, "wav49"))
                                        fmt = "WAV";
                                }
                                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);
                                /* 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");
                                /*mail_fetchstructure (mailstream, vmArray[0], &body); */
                                mail_fetchstructure (vms->mailstream, vms->msgArray[vms->curmsg], &body);
                                save_body(body,vms,"3","gsm");
@@ -4144,10 +4278,8 @@ static int forward_message(struct ast_channel *chan, char *context, struct vm_st
  
                                STORE(todir, vmtmp->mailbox, vmtmp->context, vms->curmsg, chan, vmtmp, fmt, duration, vms);
 
  
                                STORE(todir, vmtmp->mailbox, vmtmp->context, vms->curmsg, chan, vmtmp, fmt, duration, vms);
 
-                               char *myserveremail = serveremail;
                                if (!ast_strlen_zero(vmtmp->serveremail))
                                        myserveremail = vmtmp->serveremail;
                                if (!ast_strlen_zero(vmtmp->serveremail))
                                        myserveremail = vmtmp->serveremail;
-                               int attach_user_voicemail = ast_test_flag((&globalflags), VM_ATTACH);
                                attach_user_voicemail = ast_test_flag(vmtmp, VM_ATTACH);
                                /* NULL category for IMAP storage */
                                sendmail(myserveremail, vmtmp, todircount, vmtmp->context, vmtmp->mailbox, S_OR(chan->cid.cid_num, NULL), S_OR(chan->cid.cid_name, NULL), vms->fn, fmt, duration, attach_user_voicemail, chan, NULL);
                                attach_user_voicemail = ast_test_flag(vmtmp, VM_ATTACH);
                                /* NULL category for IMAP storage */
                                sendmail(myserveremail, vmtmp, todircount, vmtmp->context, vmtmp->mailbox, S_OR(chan->cid.cid_num, NULL), S_OR(chan->cid.cid_name, NULL), vms->fn, fmt, duration, attach_user_voicemail, chan, NULL);
@@ -4175,6 +4307,10 @@ static int forward_message(struct ast_channel *chan, char *context, struct vm_st
                        }       
                }
        }
                        }       
                }
        }
+
+       /* If anything failed above, we still have this list to free */
+       while ((vmtmp = AST_LIST_REMOVE_HEAD(&extensions, list)))
+               free_user(vmtmp);
        return res ? res : cmd;
 }
 
        return res ? res : cmd;
 }
 
@@ -4188,7 +4324,7 @@ static int wait_file2(struct ast_channel *chan, struct vm_state *vms, char *file
 
 static int wait_file(struct ast_channel *chan, struct vm_state *vms, char *file) 
 {
 
 static int wait_file(struct ast_channel *chan, struct vm_state *vms, char *file) 
 {
-       return ast_control_streamfile(chan, file, "#", "*", "1456789", "0", "2", skipms);
+       return ast_control_streamfile(chan, file, "#", "*", "1456789", "0", "2", skipms, NULL);
 }
 
 static int play_message_category(struct ast_channel *chan, const char *category)
 }
 
 static int play_message_category(struct ast_channel *chan, const char *category)
@@ -4290,15 +4426,13 @@ static int play_message_callerid(struct ast_channel *chan, struct vm_state *vms,
                return res;
 
        /* Strip off caller ID number from name */
                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++){
        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;
                }
                        if ((strcmp(cidinternalcontexts[i], context) == 0))
                                break;
                }
@@ -4325,9 +4459,8 @@ 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);
+               else if (!res) {
+                       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");
                        /* 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");
@@ -4335,8 +4468,7 @@ static int play_message_callerid(struct ast_channel *chan, struct vm_state *vms,
                }
        } else {
                /* Number unknown */
                }
        } 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");
        }
                /* Say "from an unknown caller" as one phrase - it is already recorded by "the voice" anyhow */
                res = wait_file2(chan, vms, "vm-unknown-caller");
        }
@@ -4356,8 +4488,7 @@ static int play_message_duration(struct ast_channel *chan, struct vm_state *vms,
        durations=atoi(duration);
        durationm=(durations / 60);
 
        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");
 
        if ((!res) && (durationm >= minduration)) {
                res = wait_file2(chan, vms, "vm-duration");
@@ -4406,12 +4537,14 @@ 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 category[32];
        char todir[PATH_MAX];
        int res = 0;
+       char *attachedfilefmt;
        char *temp;
        char *temp;
+       char buf[1024];
 
        vms->starting = 0; 
 
        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]);
-       if (vms->msgArray[vms->curmsg] == 0) {
+       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;
        }
                ast_log (LOG_WARNING,"Trying to access unknown message\n");
                return -1;
        }
@@ -4427,13 +4560,30 @@ 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);
        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)
                res = wait_file2(chan, vms, "vm-first");        /* "First" */
        else if (vms->curmsg == vms->lastmsg)
                res = wait_file2(chan, vms, "vm-last");         /* "last" */
 
        adsi_message(chan, vms);
        if (!vms->curmsg)
                res = wait_file2(chan, vms, "vm-first");        /* "First" */
        else if (vms->curmsg == vms->lastmsg)
                res = wait_file2(chan, vms, "vm-last");         /* "last" */
+
        if (!res) {
                res = wait_file2(chan, vms, "vm-message");      /* "message" */
                if (vms->curmsg && (vms->curmsg != vms->lastmsg)) {
        if (!res) {
                res = wait_file2(chan, vms, "vm-message");      /* "message" */
                if (vms->curmsg && (vms->curmsg != vms->lastmsg)) {
@@ -4443,37 +4593,27 @@ static int play_message(struct ast_channel *chan, struct ast_vm_user *vmu, struc
        }
 
        /* Get info from headers!! */
        }
 
        /* Get info from headers!! */
-       temp = get_header_by_tag(header_content, "X-Asterisk-VM-Caller-ID-Num:");
-
-       if (temp)
+       if ((temp = get_header_by_tag(header_content, "X-Asterisk-VM-Caller-ID-Num:", buf, sizeof(buf))))
                ast_copy_string(cid, temp, sizeof(cid)); 
        else 
                cid[0] = '\0';
                ast_copy_string(cid, temp, sizeof(cid)); 
        else 
                cid[0] = '\0';
-
-       temp = get_header_by_tag(header_content, "X-Asterisk-VM-Context:");
-
-       if (temp)
+       
+       if ((temp = get_header_by_tag(header_content, "X-Asterisk-VM-Context:", buf, sizeof(buf))))
                ast_copy_string(context, temp, sizeof(context)); 
        else
                context[0] = '\0';
 
                ast_copy_string(context, temp, sizeof(context)); 
        else
                context[0] = '\0';
 
-       temp = get_header_by_tag(header_content, "X-Asterisk-VM-Orig-time:");
-
-       if (temp)
+       if ((temp = get_header_by_tag(header_content, "X-Asterisk-VM-Orig-time:", buf, sizeof(buf))))
                ast_copy_string(origtime, temp, sizeof(origtime));
        else
                origtime[0] = '\0';
 
                ast_copy_string(origtime, temp, sizeof(origtime));
        else
                origtime[0] = '\0';
 
-       temp = get_header_by_tag(header_content, "X-Asterisk-VM-Duration:");
-
-       if (temp)
+       if ((temp = get_header_by_tag(header_content, "X-Asterisk-VM-Duration:", buf, sizeof(buf))))
                ast_copy_string(duration,temp, sizeof(duration));
        else
                duration[0] = '\0';
        
                ast_copy_string(duration,temp, sizeof(duration));
        else
                duration[0] = '\0';
        
-       temp = get_header_by_tag(header_content, "X-Asterisk-VM-Category:");
-       
-       if (temp)
+       if ((temp = get_header_by_tag(header_content, "X-Asterisk-VM-Category:", buf, sizeof(buf))))
                ast_copy_string(category,temp, sizeof(category));
        else
                category[0] = '\0';
                ast_copy_string(category,temp, sizeof(category));
        else
                category[0] = '\0';
@@ -4612,8 +4752,9 @@ static int play_message(struct ast_channel *chan, struct ast_vm_user *vmu, struc
 #ifdef IMAP_STORAGE
 static void imap_mailbox_name(char *spec, struct vm_state *vms, int box, int use_folder)
 {
 #ifdef IMAP_STORAGE
 static void imap_mailbox_name(char *spec, struct vm_state *vms, int box, int use_folder)
 {
-       char tmp[256];
-       
+       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 == 1) {
                ast_copy_string(vms->curbox, mbox(0), sizeof(vms->curbox));
                sprintf(vms->vmbox, "vm-%s", mbox(1));
@@ -4622,11 +4763,20 @@ static void imap_mailbox_name(char *spec, struct vm_state *vms, int box, int use
                snprintf(vms->vmbox, sizeof(vms->vmbox), "vm-%s", vms->curbox);
        }
 
                snprintf(vms->vmbox, sizeof(vms->vmbox), "vm-%s", vms->curbox);
        }
 
-       if (strlen(authuser) > 0) {
-               snprintf(tmp, sizeof(tmp), "{%s:%s/imap/authuser=%s/%s/user=%s}",imapserver,imapport,authuser,imapflags,vms->imapuser);
-       } else {
-               snprintf(tmp, sizeof(tmp), "{%s:%s/imap/%s/user=%s}",imapserver,imapport,imapflags,vms->imapuser);
-       }
+       /* Build up server information */
+       ast_build_string(&t, &left, "{%s:%s/imap", imapserver, imapport);
+
+       /* Add authentication user if present */
+       if (!ast_strlen_zero(authuser))
+               ast_build_string(&t, &left, "/authuser=%s", authuser);
+
+       /* Add flags if present */
+       if (!ast_strlen_zero(imapflags))
+               ast_build_string(&t, &left, "/%s", imapflags);
+
+       /* End with username */
+       ast_build_string(&t, &left, "/user=%s}", vms->imapuser);
+
        if(box == 0 || box == 1)
                sprintf(spec, "%s%s", tmp, use_folder? imapfolder: "INBOX");
        else
        if(box == 0 || box == 1)
                sprintf(spec, "%s%s", tmp, use_folder? imapfolder: "INBOX");
        else
@@ -4643,10 +4793,9 @@ static int init_mailstream(struct vm_state *vms, int box)
                ast_log (LOG_ERROR,"vm_state is NULL!\n");
                return -1;
        }
                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 (vms->mailstream == NIL || !vms->mailstream) {
-               ast_log (LOG_DEBUG,"mailstream not set.\n");
+               ast_debug(1,"mailstream not set.\n");
        } else {
                stream = vms->mailstream;
        }
        } else {
                stream = vms->mailstream;
        }
@@ -4658,22 +4807,22 @@ static int init_mailstream(struct vm_state *vms, int box)
 #include "linkage.c"
                /* Connect to INBOX first to get folders delimiter */
                imap_mailbox_name(tmp, vms, 0, 0);
 #include "linkage.c"
                /* Connect to INBOX first to get folders delimiter */
                imap_mailbox_name(tmp, vms, 0, 0);
-               stream = mail_open (stream, tmp, debug ? OP_DEBUG : NIL);
+               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);
                        return NIL;
                }
                get_mailbox_delimiter(stream);
                /* update delimiter in imapfolder */
                if (stream == NIL) {
                        ast_log (LOG_ERROR, "Can't connect to imap server %s\n", tmp);
                        return NIL;
                }
                get_mailbox_delimiter(stream);
                /* update delimiter in imapfolder */
-               for(cp = imapfolder; *cp; cp++)
+               for(cp = imapfolder; *cp; cp++) {
                        if(*cp == '/')
                                *cp = delimiter;
                        if(*cp == '/')
                                *cp = delimiter;
+               }
        }
        /* Now connect to the target folder */
        imap_mailbox_name(tmp, vms, box, 1);
        }
        /* 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);
-       vms->mailstream = mail_open (stream, tmp, debug ? OP_DEBUG : NIL);
+       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;
        } else {
        if (vms->mailstream == NIL) {
                return -1;
        } else {
@@ -4689,14 +4838,13 @@ 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));
        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);
-       ret = init_mailstream(vms, box);
-       if (ret != 0 || !vms->mailstream) {
+       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");
                return -1;
        }
                ast_log (LOG_ERROR,"Could not initialize mailstream\n");
                return -1;
        }
-
+       
        /* Check Quota (here for now to test) */
        mail_parameters(NULL, SET_QUOTA, (void *) mm_parsequota);
        imap_mailbox_name(dbox, vms, box, 1);
        /* Check Quota (here for now to test) */
        mail_parameters(NULL, SET_QUOTA, (void *) mm_parsequota);
        imap_mailbox_name(dbox, vms, box, 1);
@@ -4705,7 +4853,7 @@ static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box)
        pgm = mail_newsearchpgm();
 
        /* Check IMAP folder for Asterisk messages only... */
        pgm = mail_newsearchpgm();
 
        /* Check IMAP folder for Asterisk messages only... */
-       hdr = mail_newsearchheader ("X-Asterisk-VM-Extension", vmu->mailbox);
+       hdr = mail_newsearchheader("X-Asterisk-VM-Extension", vmu->mailbox);
        pgm->header = hdr;
        pgm->deleted = 0;
        pgm->undeleted = 1;
        pgm->header = hdr;
        pgm->deleted = 0;
        pgm->undeleted = 1;
@@ -4719,15 +4867,13 @@ static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box)
                pgm->unseen = 0;
        }
 
                pgm->unseen = 0;
        }
 
+       ast_debug(3,"Before mail_search_full, user is %s\n",vmu->imapuser);
+
        vms->vmArrayIndex = 0;
        vms->vmArrayIndex = 0;
-       if(option_debug > 2)
-               ast_log(LOG_DEBUG,"Before mail_search_full, user is %s\n",vmu->imapuser);
        mail_search_full (vms->mailstream, NULL, pgm, NIL);
        mail_search_full (vms->mailstream, NULL, pgm, NIL);
-
-
        vms->lastmsg = vms->vmArrayIndex - 1;
        vms->lastmsg = vms->vmArrayIndex - 1;
-
        mail_free_searchpgm(&pgm);
        mail_free_searchpgm(&pgm);
+
        return 0;
 }
 #else
        return 0;
 }
 #else
@@ -4817,6 +4963,12 @@ static int close_mailbox(struct vm_state *vms, struct ast_vm_user *vmu)
                                vms->heard[x] = 0;
                                --x;
                        } 
                                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);
                } 
        } 
 
                } 
        } 
 
@@ -4829,11 +4981,12 @@ static int close_mailbox(struct vm_state *vms, struct ast_vm_user *vmu)
        }
        ast_unlock_path(vms->curdir);
 #else
        }
        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
                }
        }
 #endif
@@ -4891,7 +5044,7 @@ static int vm_play_folder_name(struct ast_channel *chan, char *mbox)
 {
        int cmd;
 
 {
        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")){
                cmd = ast_play_and_wait(chan, "vm-messages"); /* "messages */
                return cmd ? cmd : ast_play_and_wait(chan, mbox);
        } else if (!strcasecmp(chan->language, "gr")){
@@ -5364,14 +5517,14 @@ static int vm_intro_fr(struct ast_channel *chan,struct vm_state *vms)
                }
                if (!res && vms->oldmessages) {
                        res = say_and_wait(chan, vms->oldmessages, chan->language);
                }
                if (!res && 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) {
                                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) {
                }
                if (!res) {
                        if (!vms->oldmessages && !vms->newmessages) {
@@ -5775,28 +5928,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 ((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 = 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);
        }
 
        /* 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);
                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;
        }
 
        return cmd;
@@ -5828,15 +5999,27 @@ static int vm_options(struct ast_channel *chan, struct ast_vm_user *vmu, struct
                switch (cmd) {
                case '1':
                        snprintf(prefile,sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, vms->username);
                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);
                        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);
                        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);
                        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);
                        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);
                        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);
                        break;
                case '4': 
                        cmd = vm_tempgreeting(chan, vmu, vms, fmtc, record_gain);
@@ -5879,8 +6062,7 @@ static int vm_options(struct ast_channel *chan, struct ast_vm_user *vmu, struct
                        if ((pwdchange & PWDCHANGE_EXTERNAL) && !ast_strlen_zero(ext_pass_cmd))
                                vm_change_password_shell(vmu, newpassword);
 
                        if ((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 '*': 
                        cmd = ast_play_and_wait(chan, vm_passchanged);
                        break;
                case '*': 
@@ -5922,7 +6104,7 @@ static int vm_tempgreeting(struct ast_channel *chan, struct ast_vm_user *vmu, st
        }
 
        snprintf(prefile, sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
        }
 
        snprintf(prefile, sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
-       if (!(res = create_dirpath(dest, sizeof(dest), vmu->context, vms->username, "temp"))) {
+       if ((res = create_dirpath(dest, sizeof(dest), vmu->context, vms->username, "temp"))) {
                ast_log(LOG_WARNING, "Failed to create directory (%s).\n", prefile);
                return -1;
        }
                ast_log(LOG_WARNING, "Failed to create directory (%s).\n", prefile);
                return -1;
        }
@@ -5931,12 +6113,20 @@ static int vm_tempgreeting(struct ast_channel *chan, struct ast_vm_user *vmu, st
                        retries = 0;
                RETRIEVE(prefile, -1);
                if (ast_fileexists(prefile, NULL, NULL) <= 0) {
                        retries = 0;
                RETRIEVE(prefile, -1);
                if (ast_fileexists(prefile, NULL, NULL) <= 0) {
+#ifndef IMAP_STORAGE
                        play_record_review(chan, "vm-rec-temp", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, NULL);
                        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':
                        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);
                                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);
                                break;
                        case '2':
                                DELETE(prefile, -1, prefile);
@@ -6131,8 +6321,7 @@ static int vm_authenticate(struct ast_channel *chan, char *mailbox, int mailbox_
                        ast_copy_string(mailbox, fullusername, mailbox_size);
                }
 
                        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 */
                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 */
@@ -6224,8 +6413,7 @@ static int vm_execmain(struct ast_channel *chan, void *data)
        memset(&vmus, 0, sizeof(vmus));
 
        if (chan->_state != AST_STATE_UP) {
        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);
        }
 
                ast_answer(chan);
        }
 
@@ -6307,8 +6495,7 @@ static int vm_execmain(struct ast_channel *chan, void *data)
        if (!valid)
                res = vm_authenticate(chan, vms.username, sizeof(vms.username), &vmus, context, prefixstr, skipuser, maxlogins, 0);
 
        if (!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)
        if (!res) {
                valid = 1;
                if (!skipuser)
@@ -6343,21 +6530,18 @@ static int vm_execmain(struct ast_channel *chan, void *data)
        create_dirpath(vms.curdir, sizeof(vms.curdir), vmu->context, vms.username, "");
 #endif
        /* Retrieve old and new message counts */
        create_dirpath(vms.curdir, sizeof(vms.curdir), vmu->context, vms.username, "");
 #endif
        /* Retrieve old and new message counts */
-       if (option_debug)
-               ast_log(LOG_DEBUG, "Before open_mailbox\n");
+       ast_debug(1, "Before open_mailbox\n");
        res = open_mailbox(&vms, vmu, 1);
        if (res == ERROR_LOCK_PATH)
                goto out;
        vms.oldmessages = vms.lastmsg + 1;
        res = open_mailbox(&vms, vmu, 1);
        if (res == ERROR_LOCK_PATH)
                goto out;
        vms.oldmessages = vms.lastmsg + 1;
-       if (option_debug)
-               ast_log(LOG_DEBUG, "Number of old messages: %d\n",vms.oldmessages);
+       ast_debug(1, "Number of old messages: %d\n",vms.oldmessages);
        /* Start in INBOX */
        res = open_mailbox(&vms, vmu, 0);
        if (res == ERROR_LOCK_PATH)
                goto out;
        vms.newmessages = vms.lastmsg + 1;
        /* Start in INBOX */
        res = open_mailbox(&vms, vmu, 0);
        if (res == ERROR_LOCK_PATH)
                goto out;
        vms.newmessages = vms.lastmsg + 1;
-       if (option_debug)
-               ast_log(LOG_DEBUG, "Number of new messages: %d\n",vms.newmessages);
+       ast_debug(1, "Number of new messages: %d\n",vms.newmessages);
                
        /* Select proper mailbox FIRST!! */
        if (play_auto) {
                
        /* Select proper mailbox FIRST!! */
        if (play_auto) {
@@ -6401,10 +6585,9 @@ static int vm_execmain(struct ast_channel *chan, void *data)
                }
        }
 #ifdef IMAP_STORAGE
                }
        }
 #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 (vms.quota_limit && vms.quota_usage >= vms.quota_limit) {
-                       ast_log(LOG_DEBUG, "*** QUOTA EXCEEDED!!\n");
+                       ast_debug(1, "*** QUOTA EXCEEDED!!\n");
                        cmd = ast_play_and_wait(chan, "vm-mailboxfull");
                }
 #endif
                        cmd = ast_play_and_wait(chan, "vm-mailboxfull");
                }
 #endif
@@ -6555,7 +6738,7 @@ static int vm_execmain(struct ast_channel *chan, void *data)
                        }
                        break;
                case '4':
                        }
                        break;
                case '4':
-                       if (vms.curmsg) {
+                       if (vms.curmsg > 0) {
                                vms.curmsg--;
                                cmd = play_message(chan, vmu, &vms);
                        } else {
                                vms.curmsg--;
                                cmd = play_message(chan, vmu, &vms);
                        } else {
@@ -6571,21 +6754,24 @@ static int vm_execmain(struct ast_channel *chan, void *data)
                        }
                        break;
                case '7':
                        }
                        break;
                case '7':
-                       vms.deleted[vms.curmsg] = !vms.deleted[vms.curmsg];
-                       if (useadsi)
-                               adsi_delete(chan, &vms);
-                       if (vms.deleted[vms.curmsg]) 
-                               cmd = ast_play_and_wait(chan, "vm-deleted");
-                       else
-                               cmd = ast_play_and_wait(chan, "vm-undeleted");
-                       if (ast_test_flag((&globalflags), VM_SKIPAFTERCMD)) {
-                               if (vms.curmsg < vms.lastmsg) {
-                                       vms.curmsg++;
-                                       cmd = play_message(chan, vmu, &vms);
-                               } else {
-                                       cmd = ast_play_and_wait(chan, "vm-nomore");
+                       if (vms.curmsg >= 0 && vms.curmsg <= vms.lastmsg) {
+                               vms.deleted[vms.curmsg] = !vms.deleted[vms.curmsg];
+                               if (useadsi)
+                                       adsi_delete(chan, &vms);
+                               if (vms.deleted[vms.curmsg]) 
+                                       cmd = ast_play_and_wait(chan, "vm-deleted");
+                               else
+                                       cmd = ast_play_and_wait(chan, "vm-undeleted");
+                               if (ast_test_flag((&globalflags), VM_SKIPAFTERCMD)) {
+                                       if (vms.curmsg < vms.lastmsg) {
+                                               vms.curmsg++;
+                                               cmd = play_message(chan, vmu, &vms);
+                                       } else {
+                                               cmd = ast_play_and_wait(chan, "vm-nomore");
+                                       }
                                }
                                }
-                       }
+                       } else /* Delete not valid if we haven't selected a message */
+                               cmd = 0;
 #ifdef IMAP_STORAGE
                        deleted = 1;
 #endif
 #ifdef IMAP_STORAGE
                        deleted = 1;
 #endif
@@ -6698,14 +6884,16 @@ out:
        if (vmu)
                close_mailbox(&vms, vmu);
        if (valid) {
        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);
                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*/
        }
 #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)) {
        if (vmu && deleted == 1 && expungeonhangup == 1) {
 #ifdef HAVE_IMAP_TK2006
                if (LEVELUIDPLUS (vms.mailstream)) {
@@ -6757,7 +6945,7 @@ static int vm_exec(struct ast_channel *chan, void *data)
                                ast_module_user_remove(u);
                                return -1;
                        }
                                ast_module_user_remove(u);
                                return -1;
                        }
-                       ast_copy_flags(&leave_options, &flags, OPT_SILENT | OPT_BUSY_GREETING | OPT_UNAVAIL_GREETING | OPT_PRIORITY_JUMP);
+                       ast_copy_flags(&leave_options, &flags, OPT_SILENT | OPT_BUSY_GREETING | OPT_UNAVAIL_GREETING);
                        if (ast_test_flag(&flags, OPT_RECORDGAIN)) {
                                int gain;
 
                        if (ast_test_flag(&flags, OPT_RECORDGAIN)) {
                                int gain;
 
@@ -6788,10 +6976,6 @@ static int vm_exec(struct ast_channel *chan, void *data)
 
        if (res == ERROR_LOCK_PATH) {
                ast_log(LOG_ERROR, "Could not leave voicemail. The path is already locked.\n");
 
        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;
        }
                pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
                res = 0;
        }
@@ -6804,20 +6988,25 @@ static int vm_exec(struct ast_channel *chan, void *data)
 static struct ast_vm_user *find_or_create(char *context, char *mbox)
 {
        struct ast_vm_user *vmu;
 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;
        }
        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;
 }
 
        return vmu;
 }
 
@@ -6828,24 +7017,36 @@ static int append_mailbox(char *context, char *mbox, char *data)
        char *stringp;
        char *s;
        struct ast_vm_user *vmu;
        char *stringp;
        char *s;
        struct ast_vm_user *vmu;
+       char *mailbox_full;
+       int new = 0, old = 0;
 
        tmp = ast_strdupa(data);
 
 
        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;
 }
 
        return 0;
 }
 
@@ -6854,7 +7055,6 @@ static int vm_box_exists(struct ast_channel *chan, void *data)
        struct ast_module_user *u;
        struct ast_vm_user svm;
        char *context, *box;
        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);
        AST_DECLARE_APP_ARGS(args,
                AST_APP_ARG(mbox);
                AST_APP_ARG(options);
@@ -6878,8 +7078,6 @@ static int vm_box_exists(struct ast_channel *chan, void *data)
        AST_STANDARD_APP_ARGS(args, box);
 
        if (args.options) {
        AST_STANDARD_APP_ARGS(args, box);
 
        if (args.options) {
-               if (strchr(args.options, 'j'))
-                       priority_jump = 1;
        }
 
        if ((context = strchr(args.mbox, '@'))) {
        }
 
        if ((context = strchr(args.mbox, '@'))) {
@@ -6889,9 +7087,6 @@ static int vm_box_exists(struct ast_channel *chan, void *data)
 
        if (find_user(&svm, context, args.mbox)) {
                pbx_builtin_setvar_helper(chan, "VMBOXEXISTSSTATUS", "SUCCESS");
 
        if (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);
        } else
                pbx_builtin_setvar_helper(chan, "VMBOXEXISTSSTATUS", "FAILED");
        ast_module_user_remove(u);
@@ -6970,52 +7165,100 @@ static const char voicemail_show_zones_help[] =
 "Usage: voicemail show zones\n"
 "       Lists zone message formats\n";
 
 "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";
 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;
        }
                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;
 }
 
        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;
 static int handle_voicemail_show_zones(int fd, int argc, char *argv[])
 {
        struct vm_zone *zone;
@@ -7074,6 +7317,227 @@ static struct ast_cli_entry cli_voicemail[] = {
        voicemail_show_zones_help, NULL, NULL },
 };
 
        voicemail_show_zones_help, NULL, NULL },
 };
 
+static void poll_subscribed_mailboxes(void)
+{
+       struct mwi_sub *mwi_sub;
+
+       AST_RWLIST_RDLOCK(&mwi_subs);
+       AST_RWLIST_TRAVERSE(&mwi_subs, mwi_sub, entry) {
+               int new = 0, old = 0;
+
+               if (ast_strlen_zero(mwi_sub->mailbox))
+                       continue;
+
+               inboxcount(mwi_sub->mailbox, &new, &old);
+
+               if (new != mwi_sub->old_new || old != mwi_sub->old_old) {
+                       mwi_sub->old_new = new;
+                       mwi_sub->old_old = old;
+                       queue_mwi_event(mwi_sub->mailbox, new, old);
+               }
+       }
+       AST_RWLIST_UNLOCK(&mwi_subs);
+}
+
+static void *mb_poll_thread(void *data)
+{
+       while (poll_thread_run) {
+               struct timespec ts = { 0, };
+               struct timeval tv;
+
+               tv = ast_tvadd(ast_tvnow(), ast_samp2tv(poll_freq, 1));
+               ts.tv_sec = tv.tv_sec;
+               ts.tv_nsec = tv.tv_usec * 1000;
+
+               ast_mutex_lock(&poll_lock);
+               ast_cond_timedwait(&poll_cond, &poll_lock, &ts);
+               ast_mutex_unlock(&poll_lock);
+
+               if (!poll_thread_run)
+                       break;
+
+               poll_subscribed_mailboxes();
+       }
+
+       return NULL;
+}
+
+static void mwi_sub_destroy(struct mwi_sub *mwi_sub)
+{
+       free(mwi_sub);
+}
+
+static void mwi_unsub_event_cb(const struct ast_event *event, void *userdata)
+{
+       uint32_t uniqueid;
+       struct mwi_sub *mwi_sub;
+
+       if (ast_event_get_type(event) != AST_EVENT_UNSUB)
+               return;
+
+       if (ast_event_get_ie_uint(event, AST_EVENT_IE_EVENTTYPE) != AST_EVENT_MWI)
+               return;
+
+       uniqueid = ast_event_get_ie_uint(event, AST_EVENT_IE_UNIQUEID);
+
+       AST_RWLIST_WRLOCK(&mwi_subs);
+       AST_RWLIST_TRAVERSE_SAFE_BEGIN(&mwi_subs, mwi_sub, entry) {
+               if (mwi_sub->uniqueid == uniqueid) {
+                       AST_LIST_REMOVE_CURRENT(&mwi_subs, entry);
+                       break;
+               }
+       }
+       AST_RWLIST_TRAVERSE_SAFE_END
+       AST_RWLIST_UNLOCK(&mwi_subs);
+
+       if (mwi_sub)
+               mwi_sub_destroy(mwi_sub);
+}
+
+static void mwi_sub_event_cb(const struct ast_event *event, void *userdata)
+{
+       const char *mailbox;
+       uint32_t uniqueid;
+       unsigned int len;
+       struct mwi_sub *mwi_sub;
+
+       if (ast_event_get_type(event) != AST_EVENT_SUB)
+               return;
+
+       if (ast_event_get_ie_uint(event, AST_EVENT_IE_EVENTTYPE) != AST_EVENT_MWI)
+               return;
+
+       mailbox = ast_event_get_ie_str(event, AST_EVENT_IE_MAILBOX);
+       uniqueid = ast_event_get_ie_uint(event, AST_EVENT_IE_UNIQUEID);
+
+       len = sizeof(*mwi_sub);
+       if (!ast_strlen_zero(mailbox))
+               len += strlen(mailbox);
+
+       if (!(mwi_sub = ast_calloc(1, len)))
+               return;
+
+       mwi_sub->uniqueid = uniqueid;
+       if (!ast_strlen_zero(mailbox))
+               strcpy(mwi_sub->mailbox, mailbox);
+
+       AST_RWLIST_WRLOCK(&mwi_subs);
+       AST_RWLIST_INSERT_TAIL(&mwi_subs, mwi_sub, entry);
+       AST_RWLIST_UNLOCK(&mwi_subs);
+}
+
+static void start_poll_thread(void)
+{
+       pthread_attr_t attr;
+
+       mwi_sub_sub = ast_event_subscribe(AST_EVENT_SUB, mwi_sub_event_cb, NULL,
+               AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, AST_EVENT_MWI,
+               AST_EVENT_IE_END);
+
+       mwi_unsub_sub = ast_event_subscribe(AST_EVENT_UNSUB, mwi_unsub_event_cb, NULL,
+               AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, AST_EVENT_MWI,
+               AST_EVENT_IE_END);
+
+       if (mwi_sub_sub)
+               ast_event_report_subs(mwi_sub_sub);
+
+       poll_thread_run = 1;
+
+       pthread_attr_init(&attr);
+       ast_pthread_create(&poll_thread, &attr, mb_poll_thread, NULL);
+       pthread_attr_destroy(&attr);
+}
+
+static void stop_poll_thread(void)
+{
+       poll_thread_run = 0;
+
+       if (mwi_sub_sub) {
+               ast_event_unsubscribe(mwi_sub_sub);
+               mwi_sub_sub = NULL;
+       }
+
+       if (mwi_unsub_sub) {
+               ast_event_unsubscribe(mwi_unsub_sub);
+               mwi_unsub_sub = NULL;
+       }
+
+       ast_mutex_lock(&poll_lock);
+       ast_cond_signal(&poll_cond);
+       ast_mutex_unlock(&poll_lock);
+
+       pthread_join(poll_thread, NULL);
+
+       poll_thread = AST_PTHREADT_NULL;
+}
+
+/*! \brief Manager list voicemail users command */
+static int manager_list_voicemail_users(struct mansession *s, const struct message *m)
+{
+       struct ast_vm_user *vmu = NULL;
+       const char *id = astman_get_header(m, "ActionID");
+       char actionid[128] = "";
+
+       if (!ast_strlen_zero(id))
+               snprintf(actionid, sizeof(actionid), "ActionID: %s\r\n", id);
+
+       AST_LIST_LOCK(&users);
+
+       if (AST_LIST_EMPTY(&users)) {
+               astman_send_ack(s, m, "There are no voicemail users currently defined.");
+               AST_LIST_UNLOCK(&users);
+               return RESULT_SUCCESS;
+       }
+       
+       astman_send_ack(s, m, "Voicemail user list will follow\r\n");
+       
+       AST_LIST_TRAVERSE(&users, vmu, list) {
+               char dirname[256];
+               
+               make_dir(dirname, sizeof(dirname), vmu->context, vmu->mailbox, "INBOX");
+               astman_append(s,
+                             "%s"
+                             "Event: VoicemailUserEntry\r\n"
+                             "VMContext: %s\r\n"
+                             "VoiceMailbox: %s\r\n"
+                             "Fullname: %s\r\n"
+                             "Email: %s\r\n"
+                             "Pager: %s\r\n"
+                             "ServerEmail: %s\r\n"
+                             "MailCommand: %s\r\n"
+                             "Language: %s\r\n"
+                             "TimeZone: %s\r\n"
+                             "Callback: %s\r\n"
+                             "Dialout: %s\r\n"
+                             "UniqueID: %s\r\n"
+                             "ExitContext: %s\r\n"
+                             "SayDurationMinimum: %d\r\n"
+                             "AttachmentFormat: %s\r\n"
+                             "VolumeGain: %.2lf\r\n"
+                             "MaxMessageCount: %d\r\n"
+                             "MaxMessageLength: %d\r\n"
+                             "NewMessageCount: %d\r\n"
+#ifdef IMAP_STORAGE
+                             "IMAPUser: %s\r\n"
+#endif
+                             "\r\n",
+                             actionid, vmu->context, vmu->mailbox, vmu->fullname, vmu->email,
+                             vmu->pager, vmu->serveremail, vmu->mailcmd, vmu->language,
+                             vmu->zonetag, vmu->callback, vmu->dialout, vmu->uniqueid,
+                             vmu->exit, vmu->saydurationm, vmu->attachfmt, vmu->volgain,
+                             vmu->maxmsg, vmu->maxsecs, count_messages(vmu, dirname)
+#ifdef IMAP_STORAGE
+                             , vmu->imapuser
+#endif
+                       );
+       }               
+       astman_append(s, "Event: VoicemailUserEntryComplete\r\n%s\r\n", actionid);
+
+       AST_LIST_UNLOCK(&users);
+
+       return RESULT_SUCCESS;
+}
+
 static int load_config(void)
 {
        struct ast_vm_user *cur;
 static int load_config(void)
 {
        struct ast_vm_user *cur;
@@ -7081,51 +7545,9 @@ static int load_config(void)
        struct ast_config *cfg, *ucfg;
        char *cat;
        struct ast_variable *var;
        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;
        const char *s;
-       char *q,*stringp;
-       const char *dialoutcxt = NULL;
-       const char *callbackcxt = NULL; 
-       const char *exitcxt = NULL;     
-       const char *extpc;
-       const char *emaildateformatstr;
-       const char *volgainstr;
-       const char *vm_paswd;
-       const char *vm_newpasswd;
-       const char *vm_passchange;
-       const char *vm_reenterpass;
-       const char *vm_mism;
+       char *q, *stringp;
        int x;
        int tmpadsi[4];
 
        int x;
        int tmpadsi[4];
 
@@ -7147,99 +7569,99 @@ static int load_config(void)
        if (cfg) {
                /* General settings */
 
        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 ? */
                /* 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;
 
                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");
 
 #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");
                }
                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);
                }
 #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;
 
                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 (maxsilence > 0)
                                maxsilence *= 1000;
                }
                
-               if (!(maxmsgstr = ast_variable_retrieve(cfg, "general", "maxmsg"))) {
+               if (!(val = ast_variable_retrieve(cfg, "general", "maxmsg"))) {
                        maxmsg = MAXMSG;
                } else {
                        maxmsg = MAXMSG;
                } else {
-                       maxmsg = atoi(maxmsgstr);
+                       maxmsg = atoi(val);
                        if (maxmsg <= 0) {
                        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) {
                                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 */
                                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 */
                }
 
                /* 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;
                        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 */
                        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 */
                } 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 */
                } 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 */
                }
                /* 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 */
                }
                /* 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 */
                }
                /* 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;
                                expungeonhangup = 0;
                        else
                                expungeonhangup = 1;
@@ -7247,49 +7669,44 @@ static int load_config(void)
                        expungeonhangup = 1;
                }
                /* IMAP voicemail folder */
                        expungeonhangup = 1;
                }
                /* IMAP voicemail folder */
-               if ((imap_folder = ast_variable_retrieve(cfg, "general", "imapfolder"))) {
-                       ast_copy_string(imapfolder, imap_folder, sizeof(imapfolder));
+               if ((val = ast_variable_retrieve(cfg, "general", "imapfolder"))) {
+                       ast_copy_string(imapfolder, val, sizeof(imapfolder));
                } else {
                        ast_copy_string(imapfolder,"INBOX", sizeof(imapfolder));
                }
 #endif
                /* External voicemail notify application */
                } else {
                        ast_copy_string(imapfolder,"INBOX", sizeof(imapfolder));
                }
 #endif
                /* External voicemail notify application */
-               
-               if ((notifystr = ast_variable_retrieve(cfg, "general", "externnotify"))) {
-                       ast_copy_string(externnotify, notifystr, sizeof(externnotify));
-                       if (option_debug)
-                               ast_log(LOG_DEBUG, "found externnotify: %s\n", externnotify);
-                       if (!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';
                }
 
                } 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;
                /* 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"))) {
                
                vmmaxsecs = 0;
                if ((s = ast_variable_retrieve(cfg, "general", "maxsecs"))) {
@@ -7335,10 +7752,10 @@ static int load_config(void)
                        }
                }
 
                        }
                }
 
-               fmt = ast_variable_retrieve(cfg, "general", "format");
-               if (!fmt)
-                       fmt = "wav";    
-               ast_copy_string(vmfmts, fmt, sizeof(vmfmts));
+               val = ast_variable_retrieve(cfg, "general", "format");
+               if (!val)
+                       val = "wav";    
+               ast_copy_string(vmfmts, val, sizeof(vmfmts));
 
                skipms = 3000;
                if ((s = ast_variable_retrieve(cfg, "general", "maxgreet"))) {
 
                skipms = 3000;
                if ((s = ast_variable_retrieve(cfg, "general", "maxgreet"))) {
@@ -7367,18 +7784,17 @@ static int load_config(void)
                }
 
                /* Force new user to record name ? */
                }
 
                /* 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 ? */
 
                /* 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 ((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)) {
                        stringp = ast_strdupa(s);
                        for (x = 0 ; x < MAX_NUM_CID_CONTEXTS ; x++){
                                if (!ast_strlen_zero(stringp)) {
@@ -7386,121 +7802,121 @@ static int load_config(void)
                                        while ((*q == ' ')||(*q == '\t')) /* Eat white space between contexts */
                                                q++;
                                        ast_copy_string(cidinternalcontexts[x], q, sizeof(cidinternalcontexts[x]));
                                        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';
                                }
                        }
                }
                                } 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 */
 
                /*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 {
                } 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;
 
                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");
                        }
                }
 
                                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';  
                }
                
                } 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';
                }
 
                } 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 */
                } else {
                        exitcontext[0] = '\0';
                }
                
                /* load password sounds configuration */
-               if ((vm_paswd = ast_variable_retrieve(cfg, "general", "vm-password")))
-                       ast_copy_string(vm_password, vm_paswd, sizeof(vm_password));
-               if ((vm_newpasswd = ast_variable_retrieve(cfg, "general", "vm-newpassword")))
-                       ast_copy_string(vm_newpassword, vm_newpasswd, sizeof(vm_newpassword));
-               if ((vm_passchange = ast_variable_retrieve(cfg, "general", "vm-passchanged")))
-                       ast_copy_string(vm_passchanged, vm_passchange, sizeof(vm_passchanged));
-               if ((vm_reenterpass = ast_variable_retrieve(cfg, "general", "vm-reenterpassword")))
-                       ast_copy_string(vm_reenterpassword, vm_reenterpass, sizeof(vm_reenterpassword));
-               if ((vm_mism = ast_variable_retrieve(cfg, "general", "vm-mismatch")))
-                       ast_copy_string(vm_mismatch, vm_mism, sizeof(vm_mismatch));
-
-               if (!(astdirfwd = ast_variable_retrieve(cfg, "general", "usedirectory"))) 
-                       astdirfwd = "no";
-               ast_set2_flag((&globalflags), ast_true(astdirfwd), VM_DIRECFORWARD);    
+               if ((val = ast_variable_retrieve(cfg, "general", "vm-password")))
+                       ast_copy_string(vm_password, val, sizeof(vm_password));
+               if ((val = ast_variable_retrieve(cfg, "general", "vm-newpassword")))
+                       ast_copy_string(vm_newpassword, val, sizeof(vm_newpassword));
+               if ((val = ast_variable_retrieve(cfg, "general", "vm-passchanged")))
+                       ast_copy_string(vm_passchanged, val, sizeof(vm_passchanged));
+               if ((val = ast_variable_retrieve(cfg, "general", "vm-reenterpassword")))
+                       ast_copy_string(vm_reenterpassword, val, sizeof(vm_reenterpassword));
+               if ((val = ast_variable_retrieve(cfg, "general", "vm-mismatch")))
+                       ast_copy_string(vm_mismatch, val, sizeof(vm_mismatch));
+
+               if (!(val = ast_variable_retrieve(cfg, "general", "usedirectory"))) 
+                       val = "no";
+               ast_set2_flag((&globalflags), ast_true(val), VM_DIRECFORWARD);  
+
+               poll_freq = DEFAULT_POLL_FREQ;
+               if ((val = ast_variable_retrieve(cfg, "general", "pollfreq"))) {
+                       if (sscanf(val, "%u", &poll_freq) != 1) {
+                               poll_freq = DEFAULT_POLL_FREQ;
+                               ast_log(LOG_ERROR, "'%s' is not a valid value for the pollfreq option!\n", val);
+                       }
+               }
+
+               poll_mailboxes = 0;
+               if ((val = ast_variable_retrieve(cfg, "general", "pollmailboxes")))
+                       poll_mailboxes = ast_true(val);
+
                if ((ucfg = ast_config_load("users.conf"))) {   
                        for (cat = ast_category_browse(ucfg, NULL); cat ; cat = ast_category_browse(ucfg, cat)) {
                                if (!ast_true(ast_config_option(ucfg, cat, "hasvoicemail")))
                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")))
@@ -7540,10 +7956,9 @@ static int load_config(void)
                                                                AST_LIST_UNLOCK(&zones);
                                                        } else {
                                                                ast_log(LOG_WARNING, "Invalid timezone definition at line %d\n", var->lineno);
                                                                AST_LIST_UNLOCK(&zones);
                                                        } else {
                                                                ast_log(LOG_WARNING, "Invalid timezone definition at line %d\n", var->lineno);
-                                                               free(z);
+                                                               ast_free(z);
                                                        }
                                                } else {
                                                        }
                                                } else {
-                                                       free(z);
                                                        AST_LIST_UNLOCK(&users);
                                                        ast_config_destroy(cfg);
                                                        return -1;
                                                        AST_LIST_UNLOCK(&users);
                                                        ast_config_destroy(cfg);
                                                        return -1;
@@ -7554,24 +7969,24 @@ static int load_config(void)
                        }
                        cat = ast_category_browse(cfg, cat);
                }
                        }
                        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) {
                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) {
                        emailbody = NULL;
                }
                if (emailsubject) {
-                       free(emailsubject);
+                       ast_free(emailsubject);
                        emailsubject = NULL;
                }
                if (pagerbody) {
                        emailsubject = NULL;
                }
                if (pagerbody) {
-                       free(pagerbody);
+                       ast_free(pagerbody);
                        pagerbody = NULL;
                }
                if (pagersubject) {
                        pagerbody = NULL;
                }
                if (pagersubject) {
-                       free(pagersubject);
+                       ast_free(pagersubject);
                        pagersubject = NULL;
                }
                if ((s = ast_variable_retrieve(cfg, "general", "pbxskip")))
                        pagersubject = NULL;
                }
                if ((s = ast_variable_retrieve(cfg, "general", "pbxskip")))
@@ -7660,56 +8075,67 @@ static int load_config(void)
                }
                AST_LIST_UNLOCK(&users);
                ast_config_destroy(cfg);
                }
                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);
                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 0;
        }
 }
 
 static int reload(void)
 {
-       return(load_config());
+       return load_config();
 }
 
 static int unload_module(void)
 {
        int res;
 }
 
 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_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();
 
        ast_cli_unregister_multiple(cli_voicemail, sizeof(cli_voicemail) / sizeof(struct ast_cli_entry));
        ast_uninstall_vm_functions();
        
        ast_module_user_hangup_all();
 
+       if (poll_thread != AST_PTHREADT_NULL)
+               stop_poll_thread();
+
        return res;
 }
 
 static int load_module(void)
 {
        int res;
        return res;
 }
 
 static int load_module(void)
 {
        int res;
+
+       /* compute the location of the voicemail spool directory */
+       snprintf(VM_SPOOL_DIR, sizeof(VM_SPOOL_DIR), "%s/voicemail/", ast_config_AST_SPOOL_DIR);
+
+       if ((res = load_config()))
+               return res;
+
        res = ast_register_application(app, vm_exec, synopsis_vm, descrip_vm);
        res |= ast_register_application(app2, vm_execmain, synopsis_vmain, descrip_vmain);
        res |= ast_register_application(app3, vm_box_exists, synopsis_vm_box_exists, descrip_vm_box_exists);
        res |= ast_register_application(app4, vmauthenticate, synopsis_vmauthenticate, descrip_vmauthenticate);
        res |= ast_custom_function_register(&mailbox_exists_acf);
        res = ast_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)
        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));
 
 
        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;
        ast_install_vm_functions(has_voicemail, inboxcount, messagecount);
 
        return res;
@@ -7780,8 +8206,9 @@ static int advanced_options(struct ast_channel *chan, struct ast_vm_user *vmu, s
 {
        int res = 0;
 #ifdef IMAP_STORAGE
 {
        int res = 0;
 #ifdef IMAP_STORAGE
-       char origtimeS[256],cidS[256],contextS[256];
-       char *header_content,*temp;
+       char origtimeS[256], cidS[256], contextS[256];
+       char *header_content, *temp;
+       char buf[1024];
 #endif
        char filename[PATH_MAX];
        struct ast_config *msg_cfg = NULL;
 #endif
        char filename[PATH_MAX];
        struct ast_config *msg_cfg = NULL;
@@ -7792,42 +8219,37 @@ static int advanced_options(struct ast_channel *chan, struct ast_vm_user *vmu, s
        vms->starting = 0; 
 #ifdef IMAP_STORAGE
        /* START HERE */
        vms->starting = 0; 
 #ifdef IMAP_STORAGE
        /* START HERE */
+
        /* get the message info!! */
        /* 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]);
-       if (vms->msgArray[vms->curmsg] == 0) {
-               ast_log (LOG_WARNING,"Trying to access unknown message\n");
+       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;
        }
 
        /* This will only work for new messages... */
                return -1;
        }
 
        /* This will only work for new messages... */
-       header_content = mail_fetchheader (vms->mailstream, vms->msgArray[vms->curmsg]);
-       /* empty string means no valid header */
-       if (ast_strlen_zero(header_content)) {
-               ast_log (LOG_ERROR,"Could not fetch header for message number %ld\n",vms->msgArray[vms->curmsg]);
+       if (!(header_content = mail_fetchheader(vms->mailstream, vms->msgArray[vms->curmsg])) || ast_strlen_zero(header_content)) {
+               ast_log(LOG_ERROR,"Could not fetch header for message number %ld\n", vms->msgArray[vms->curmsg]);
                return -1;
        }
                return -1;
        }
-
-       /* Get info from headers!! */
-       temp = get_header_by_tag(header_content, "X-Asterisk-VM-Caller-ID-Num:");
        
        
-       if (temp)
-               ast_copy_string(cidS,temp, sizeof(cidS));
+       /* Get info from headers!! */
+       if ((temp = get_header_by_tag(header_content, "X-Asterisk-VM-Caller-ID-Num:", buf, sizeof(buf))))
+               ast_copy_string(cidS, temp, sizeof(cidS));
        else
                cidS[0] = '\0';
        
        cid = &cidS[0];
        else
                cidS[0] = '\0';
        
        cid = &cidS[0];
-       temp = get_header_by_tag(header_content, "X-Asterisk-VM-Context:");
-       
-       if (temp)
+
+       if ((temp = get_header_by_tag(header_content, "X-Asterisk-VM-Context:", buf, sizeof(buf))))
                ast_copy_string(contextS,temp, sizeof(contextS));
        else
                contextS[0] = '\0';
        
        context = &contextS[0];
                ast_copy_string(contextS,temp, sizeof(contextS));
        else
                contextS[0] = '\0';
        
        context = &contextS[0];
-       temp = get_header_by_tag(header_content, "X-Asterisk-VM-Orig-time:");
-       
-       if (temp)
+
+       if ((temp = get_header_by_tag(header_content, "X-Asterisk-VM-Orig-time:", buf, sizeof(buf))))
                ast_copy_string(origtimeS,temp, sizeof(origtimeS));
        else
                origtimeS[0] = '\0';
                ast_copy_string(origtimeS,temp, sizeof(origtimeS));
        else
                origtimeS[0] = '\0';
@@ -7976,7 +8398,8 @@ static int advanced_options(struct ast_channel *chan, struct ast_vm_user *vmu, s
                        ast_config_destroy(msg_cfg);
                        return res;
                } else {
                        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);
                                struct leave_vm_options leave_options;
                                char mailbox[AST_MAX_EXTENSION * 2 + 2];
                                snprintf(mailbox, sizeof(mailbox), "%s@%s", num, vmu->context);
@@ -8030,6 +8453,7 @@ static int play_record_review(struct ast_channel *chan, char *playfile, char *re
        int recorded = 0;
        int message_exists = 0;
        signed char zero_gain = 0;
        int recorded = 0;
        int message_exists = 0;
        signed char zero_gain = 0;
+       char tempfile[PATH_MAX];
        char *acceptdtmf = "#";
        char *canceldtmf = "";
 
        char *acceptdtmf = "#";
        char *canceldtmf = "";
 
@@ -8041,6 +8465,11 @@ static int play_record_review(struct ast_channel *chan, char *playfile, char *re
                return -1;
        }
 
                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')) {
        cmd = '3';  /* Want to start by recording */
 
        while ((cmd >= 0) && (cmd != 't')) {
@@ -8054,9 +8483,13 @@ static int play_record_review(struct ast_channel *chan, char *playfile, char *re
                                /* Otherwise 1 is to save the existing message */
                                if (option_verbose > 2)
                                        ast_verbose(VERBOSE_PREFIX_3 "Saving message as is\n");
                                /* 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", "");
                                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;
                        }
                                cmd = 't';
                                return res;
                        }
@@ -8064,7 +8497,7 @@ static int play_record_review(struct ast_channel *chan, char *playfile, char *re
                        /* Review */
                        if (option_verbose > 2)
                                ast_verbose(VERBOSE_PREFIX_3 "Reviewing the message\n");
                        /* 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;
                        break;
                case '3':
                        message_exists = 0;
@@ -8086,11 +8519,15 @@ static int play_record_review(struct ast_channel *chan, char *playfile, char *re
                                ast_channel_setoption(chan, AST_OPTION_RXGAIN, &record_gain, sizeof(record_gain), 0);
                        if (ast_test_flag(vmu, VM_OPERATOR))
                                canceldtmf = "0";
                                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) {
                        if (record_gain)
                                ast_channel_setoption(chan, AST_OPTION_RXGAIN, &zero_gain, sizeof(zero_gain), 0);
                        if (cmd == -1) {
-                       /* User has hung up, no options to give */
+                               /* User has hung up, no options to give */
+                               if (!outsidecaller) {
+                                       /* user was recording a greeting and they hung up, so let's delete the recording. */
+                                       vm_delete(tempfile);
+                               }
                                return cmd;
                        }
                        if (cmd == '0') {
                                return cmd;
                        }
                        if (cmd == '0') {
@@ -8104,14 +8541,14 @@ static int play_record_review(struct ast_channel *chan, char *playfile, char *re
                                if (option_verbose > 2)
                                        ast_verbose(VERBOSE_PREFIX_3 "Message too short\n");
                                cmd = ast_play_and_wait(chan, "vm-tooshort");
                                if (option_verbose > 2)
                                        ast_verbose(VERBOSE_PREFIX_3 "Message too short\n");
                                cmd = ast_play_and_wait(chan, "vm-tooshort");
-                               cmd = vm_delete(recordfile);
+                               cmd = vm_delete(tempfile);
                                break;
                        }
                        else if (vmu->review && (cmd == 2 && *duration < (maxsilence + 3))) {
                                /* Message is all silence */
                                if (option_verbose > 2)
                                        ast_verbose(VERBOSE_PREFIX_3 "Nothing recorded\n");
                                break;
                        }
                        else if (vmu->review && (cmd == 2 && *duration < (maxsilence + 3))) {
                                /* Message is all silence */
                                if (option_verbose > 2)
                                        ast_verbose(VERBOSE_PREFIX_3 "Nothing recorded\n");
-                               cmd = vm_delete(recordfile);
+                               cmd = vm_delete(tempfile);
                                cmd = ast_play_and_wait(chan, "vm-nothingrecorded");
                                if (!cmd)
                                        cmd = ast_play_and_wait(chan, "vm-speakup");
                                cmd = ast_play_and_wait(chan, "vm-nothingrecorded");
                                if (!cmd)
                                        cmd = ast_play_and_wait(chan, "vm-speakup");
@@ -8140,7 +8577,7 @@ static int play_record_review(struct ast_channel *chan, char *playfile, char *re
                case '*':
                        /* Cancel recording, delete message, offer to take another message*/
                        cmd = ast_play_and_wait(chan, "vm-deleted");
                case '*':
                        /* Cancel recording, delete message, offer to take another message*/
                        cmd = ast_play_and_wait(chan, "vm-deleted");
-                       cmd = vm_delete(recordfile);
+                       cmd = vm_delete(tempfile);
                        if (outsidecaller) {
                                res = vm_exec(chan, NULL);
                                return res;
                        if (outsidecaller) {
                                res = vm_exec(chan, NULL);
                                return res;
@@ -8222,19 +8659,19 @@ static void write_file(char *filename, char *buffer, unsigned long len)
 void mm_searched(MAILSTREAM *stream, unsigned long number)
 {
        struct vm_state *vms;
 void mm_searched(MAILSTREAM *stream, unsigned long number)
 {
        struct vm_state *vms;
-       char *mailbox;
-       char *user;
-       mailbox = stream->mailbox;
-       user = get_user_by_mailbox(mailbox);
-       
-       vms = get_vm_state_by_imapuser(user,2);
-       if (vms) {
-               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;
-       } else {
-               ast_log (LOG_ERROR, "No state found.\n");
+       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;
        }
        }
+       
+       ast_debug(3, "saving mailbox message number %lu as message %d. Interactive set to %d\n", number, vms->vmArrayIndex, vms->interactive);
+
+       vms->msgArray[vms->vmArrayIndex++] = number;
 }
 
 
 }
 
 
@@ -8404,13 +8841,34 @@ static void status(MAILSTREAM *stream)
 }
 #endif
 
 }
 #endif
 
+static struct ast_vm_user *find_user_realtime_imapuser(const char *imapuser)
+{
+       struct ast_variable *var;
+       struct ast_vm_user *vmu;
+
+       vmu = ast_calloc(1, sizeof *vmu);
+       if (!vmu)
+               return NULL;
+       ast_set_flag(vmu, VM_ALLOCED);
+       populate_defaults(vmu);
+
+       var = ast_load_realtime("voicemail", "imapuser", imapuser, NULL);
+       if (var) {
+               apply_options_full(vmu, var);
+               ast_variables_destroy(var);
+               return vmu;
+       } else {
+               ast_free(vmu);
+               return NULL;
+       }
+}
+
 /* Interfaces to C-client */
 
 void mm_exists(MAILSTREAM * stream, unsigned long number)
 {
        /* mail_ping will callback here if new mail! */
 /* Interfaces to C-client */
 
 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);
 }
        if (number == 0) return;
        set_update(stream);
 }
@@ -8419,8 +8877,7 @@ void mm_exists(MAILSTREAM * stream, unsigned long number)
 void mm_expunged(MAILSTREAM * stream, unsigned long number)
 {
        /* mail_ping will callback here if expunged mail! */
 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);
 }
        if (number == 0) return;
        set_update(stream);
 }
@@ -8429,8 +8886,7 @@ void mm_expunged(MAILSTREAM * stream, unsigned long number)
 void mm_flags(MAILSTREAM * stream, unsigned long number)
 {
        /* mail_ping will callback here if read mail! */
 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);
 }
        if (number == 0) return;
        set_update(stream);
 }
@@ -8449,33 +8905,30 @@ void mm_list(MAILSTREAM * stream, int delim, char *mailbox, long attributes)
                delimiter = delim;
                ast_mutex_unlock(&delimiter_lock);
        }
                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)
 {
 }
 
 
 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");
 }
 
 
 }
 
 
@@ -8500,8 +8953,7 @@ void mm_log(char *string, long errflg)
 {
        switch ((short) errflg) {
                case NIL:
 {
        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:
                        break;
                case PARSE:
                case WARN:
@@ -8524,8 +8976,7 @@ void mm_login(NETMBX * mb, char *user, char *pwd, long trial)
 {
        struct ast_vm_user *vmu;
 
 {
        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);
 
 
        ast_copy_string(user, mb->user, MAILTMPLEN);
 
@@ -8539,6 +8990,12 @@ void mm_login(NETMBX * mb, char *user, char *pwd, long trial)
                                break;
                        }
                }
                                break;
                        }
                }
+               if (!vmu) {
+                       if ((vmu = find_user_realtime_imapuser(mb->user))) {
+                               ast_copy_string(pwd, vmu->imappassword, MAILTMPLEN);
+                               free_user(vmu);
+                       }
+               }
        }
 }
 
        }
 }
 
@@ -8569,10 +9026,9 @@ void mm_fatal(char *string)
 static void mm_parsequota(MAILSTREAM *stream, unsigned char *msg, QUOTALIST *pquota)
 {
        struct vm_state *vms;
 static void mm_parsequota(MAILSTREAM *stream, unsigned char *msg, QUOTALIST *pquota)
 {
        struct vm_state *vms;
-       char *mailbox;
-       char *user;
-       unsigned long usage = 0;
-       unsigned long limit = 0;
+       char *mailbox = stream->mailbox, *user;
+       char buf[1024] = "";
+       unsigned long usage = 0, limit = 0;
        
        while (pquota) {
                usage = pquota->usage;
        
        while (pquota) {
                usage = pquota->usage;
@@ -8580,72 +9036,62 @@ static void mm_parsequota(MAILSTREAM *stream, unsigned char *msg, QUOTALIST *pqu
                pquota = pquota->next;
        }
        
                pquota = pquota->next;
        }
        
-       mailbox = stream->mailbox;
-       user = get_user_by_mailbox(mailbox);
-       vms = get_vm_state_by_imapuser(user,2);
-       if (vms) {
-               if(option_debug > 2)
-                       ast_log (LOG_DEBUG, "User %s usage is %lu, limit is %lu\n",user,usage,limit);
-               vms->quota_usage = usage;
-               vms->quota_limit = limit;
-       } else {
-               ast_log (LOG_ERROR, "No state found.\n");
+       if (!(user = get_user_by_mailbox(mailbox, buf, sizeof(buf))) || !(vms = get_vm_state_by_imapuser(user, 2))) {
+               ast_log(LOG_ERROR, "No state found.\n");
+               return;
        }
        }
+
+       ast_debug(3, "User %s usage is %lu, limit is %lu\n", user, usage, limit);
+
+       vms->quota_usage = usage;
+       vms->quota_limit = limit;
 }
 
 }
 
-static char *get_header_by_tag(char *header, char *tag)
+static char *get_header_by_tag(char *header, char *tag, char *buf, size_t len)
 {
 {
-       char *start;
+       char *start, *eol_pnt;
        int taglen;
        int taglen;
-       char *eol_pnt;
 
 
-       if (!header || !tag)
+       if (ast_strlen_zero(header) || ast_strlen_zero(tag))
                return NULL;
 
        taglen = strlen(tag) + 1;
        if (taglen < 1)
                return NULL;
 
                return NULL;
 
        taglen = strlen(tag) + 1;
        if (taglen < 1)
                return NULL;
 
-       start = strstr(header, tag);
-       if (!start)
+       if (!(start = strs