rge overhaul to voicemail imap support. Allows support for more imap servers,
authorMatt O'Gorman <mogorman@digium.com>
Tue, 7 Nov 2006 18:50:58 +0000 (18:50 +0000)
committerMatt O'Gorman <mogorman@digium.com>
Tue, 7 Nov 2006 18:50:58 +0000 (18:50 +0000)
also a better implementation of several parts of the original work.
patch provided by 8033 with major upgrades. minor differences from 1.4 patch do to
changes in app_voicemail

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@47278 65c4cc65-6c06-0410-ace0-fbb531ad65f3

apps/app_voicemail.c

index e6efb09..2468f75 100644 (file)
@@ -89,25 +89,26 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #endif
 
 #ifdef IMAP_STORAGE
-AST_MUTEX_DEFINE_STATIC(curhstusr_lock);
-static char *curhst = NULL;    /* currently connected host */
-static char *curusr = NULL;    /* current login user */
-
-static char temp[1024];
+AST_MUTEX_DEFINE_STATIC(imaptemp_lock);
+static char imaptemp[1024];
 
 static char imapserver[48];
 static char imapport[8];
 static char imapflags[128];
+static char imapfolder[64];
 static char authuser[32];
 static char authpassword[42];
+
 static int expungeonhangup = 1;
+AST_MUTEX_DEFINE_STATIC(delimiter_lock);
 static char delimiter = '\0';
 
 struct vm_state;
+struct ast_vm_user;
 
-static int init_mailstream (struct vm_state *vms);
+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);
+/*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);
 static void vm_imap_delete(int msgnum, struct vm_state *vms);
@@ -124,6 +125,9 @@ static int save_body(BODY *body, struct vm_state *vms, char *section, char *form
 static int make_gsm_file(char *dest, char *imapuser, char *dir, int num);
 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 int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu,int box);
 struct vmstate {
        struct vm_state *vms;
        struct vmstate *next;
@@ -309,6 +313,7 @@ struct ast_vm_user {
        int maxmsg;                      /*!< Maximum number of msgs per folder for this mailbox */
 #ifdef IMAP_STORAGE
        char imapuser[80];      /* IMAP server login */
+       char imappassword[80];  /* IMAP server password if authpassword not defined */
 #endif
        double volgain;         /*!< Volume gain for voicemails sent via email */
        AST_LIST_ENTRY(ast_vm_user) list;
@@ -356,7 +361,8 @@ static int play_record_review(struct ast_channel *chan, char *playfile, char *re
 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);
-#ifndef ODBC_STORAGE
+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);
@@ -366,7 +372,7 @@ static char odbc_database[80];
 static char odbc_table[80];
 #define RETRIEVE(a,b) retrieve_file(a,b)
 #define DISPOSE(a,b) remove_file(a,b)
-#define STORE(a,b,c,d) store_file(a,b,c,d)
+#define STORE(a,b,c,d,e,f,g,h,i) store_file(a,b,c,d)
 #define EXISTS(a,b,c,d) (message_exists(a,b))
 #define RENAME(a,b,c,d,e,f,g,h) (rename_file(a,b,c,d,e,f))
 #define COPY(a,b,c,d,e,f,g,h) (copy_file(a,b,c,d,e,f))
@@ -375,7 +381,7 @@ static char odbc_table[80];
 #ifdef IMAP_STORAGE
 #define RETRIEVE(a,b)
 #define DISPOSE(a,b)
-#define STORE(a,b,c,d)
+#define STORE(a,b,c,d,e,f,g,h,i) (imap_store_file(a,b,c,d,e,f,g,h,i))
 #define EXISTS(a,b,c,d) (ast_fileexists(c,NULL,d) > 0)
 #define RENAME(a,b,c,d,e,f,g,h) (rename_file(g,h));
 #define COPY(a,b,c,d,e,f,g,h) (copy_file(g,h));
@@ -384,7 +390,7 @@ static char odbc_table[80];
 #else
 #define RETRIEVE(a,b)
 #define DISPOSE(a,b)
-#define STORE(a,b,c,d)
+#define STORE(a,b,c,d,e,f,g,h,i)
 #define EXISTS(a,b,c,d) (ast_fileexists(c,NULL,d) > 0)
 #define RENAME(a,b,c,d,e,f,g,h) (rename_file(g,h));
 #define COPY(a,b,c,d,e,f,g,h) (copy_file(g,h));
@@ -571,6 +577,8 @@ static void apply_option(struct ast_vm_user *vmu, const char *var, const char *v
 #ifdef IMAP_STORAGE
        } else if (!strcasecmp(var, "imapuser")) {
                ast_copy_string(vmu->imapuser, value, sizeof(vmu->imapuser));
+       } else if (!strcasecmp(var, "imappassword")) {
+               ast_copy_string(vmu->imappassword, value, sizeof(vmu->imappassword));
 #endif
        } else if (!strcasecmp(var, "delete") || !strcasecmp(var, "deletevoicemail")) {
                ast_set2_flag(vmu, ast_true(value), VM_DELETE); 
@@ -897,15 +905,12 @@ static int make_dir(char *dest, int len, const char *context, const char *ext, c
 #ifdef IMAP_STORAGE
 static int make_gsm_file(char *dest, char *imapuser, char *dir, int num)
 {
-       char gsmdir[256];
-
-       sprintf(gsmdir,"%s/%s",dir,imapuser);
-       if (mkdir(gsmdir, 01777) && (errno != EEXIST)) {
-               ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", gsmdir, strerror(errno));
+       if (mkdir(dir, 01777) && (errno != EEXIST)) {
+               ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dir, strerror(errno));
                return sprintf(dest, "%s/msg%04d", dir, num);
        }
        /* return sprintf(dest, "%s/s/msg%04d", dir, imapuser, num); */
-       return sprintf(dest, "%s/%s/msg%04d", dir, imapuser, num);
+       return sprintf(dest, "%s/msg%04d", dir, num);
 }
 
 static void vm_imap_delete(int msgnum, struct vm_state *vms)
@@ -1535,6 +1540,7 @@ yuck:
 }
 
 #else
+#ifndef IMAP_STORAGE
 static int count_messages(struct ast_vm_user *vmu, char *dir)
 {
        /* Find all .txt files - even if they are not in sequence from 0000 */
@@ -1626,7 +1632,7 @@ static void copy_file(char *frompath, char *topath)
        snprintf(topath2, sizeof(topath2), "%s.txt", topath);
        copy(frompath2, topath2);
 }
-
+#endif
 /*
  * A negative return value indicates an error.
  * \note Should always be called with a lock already set on dir.
@@ -1841,7 +1847,7 @@ static FILE *vm_mkftemp(char *template)
        FILE *p = NULL;
        int pfd = mkstemp(template);
        if (pfd > -1) {
-               p = fdopen(pfd, "w");
+               p = fdopen(pfd, "w+");
                if (!p) {
                        close(pfd);
                        pfd = -1;
@@ -1850,186 +1856,183 @@ static FILE *vm_mkftemp(char *template)
        return p;
 }
 
-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)
+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)
 {
-       FILE *p=NULL;
        char date[256];
        char host[MAXHOSTNAMELEN] = "";
        char who[256];
        char bound[256];
        char fname[256];
        char dur[256];
-       char tmp[80] = "/tmp/astmail-XXXXXX";
-       char tmp2[256];
        char tmpcmd[256];
        struct tm tm;
 
+       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\r\n", date);
+
+       /* Set date format for voicemail mail */
+       strftime(date, sizeof(date), emaildateformat, &tm);
+
+       if (*fromstring) {
+               struct ast_channel *ast;
+               if ((ast = ast_channel_alloc(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);
+                               fprintf(p, "From: %s <%s>\r\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>\r\n", who);
+       fprintf(p, "To: %s <%s>\r\n", vmu->fullname, vmu->email);
+       if (emailsubject) {
+               struct ast_channel *ast;
+               if ((ast = ast_channel_alloc(0))) {
+                       char *passdata;
+                       int vmlen = strlen(emailsubject)*3 + 200;
+                       if ((passdata = alloca(vmlen))) {
+                               memset(passdata, 0, vmlen);
+                               prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, cidnum, cidname, dur, date, passdata, vmlen, category);
+                               pbx_substitute_variables_helper(ast, emailsubject, passdata, vmlen);
+                               fprintf(p, "Subject: %s\r\n", passdata);
+                       } 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) {
+               fprintf(p, emailtitle, msgnum + 1, mailbox) ;
+               fprintf(p,"\r\n") ;
+       } else if (ast_test_flag((&globalflags), VM_PBXSKIP))
+               fprintf(p, "Subject: New message %d in mailbox %s\r\n", msgnum + 1, mailbox);
+       else
+               fprintf(p, "Subject: [PBX]: New message %d in mailbox %s\r\n", msgnum + 1, mailbox);
+       fprintf(p, "Message-ID: <Asterisk-%d-%d-%s-%d@%s>\r\n", msgnum, (unsigned int)ast_random(), mailbox, getpid(), host);
+       if(imap) {
+               /* additional information needed for IMAP searching */
+               fprintf(p, "X-Asterisk-VM-Message-Num: %d\r\n", msgnum + 1);
+               /* fprintf(p, "X-Asterisk-VM-Orig-Mailbox: %s\r\n", ext); */
+               fprintf(p, "X-Asterisk-VM-Server-Name: %s\r\n", fromstring);
+               fprintf(p, "X-Asterisk-VM-Context: %s\r\n", context);
+               fprintf(p, "X-Asterisk-VM-Extension: %s\r\n", mailbox);
+               fprintf(p, "X-Asterisk-VM-Priority: %d\r\n", chan->priority);
+               fprintf(p, "X-Asterisk-VM-Caller-channel: %s\r\n", chan->name);
+               fprintf(p, "X-Asterisk-VM-Caller-ID-Num: %s\r\n", cidnum);
+               fprintf(p, "X-Asterisk-VM-Caller-ID-Name: %s\r\n", cidname);
+               fprintf(p, "X-Asterisk-VM-Duration: %d\r\n", duration);
+               if (!ast_strlen_zero(category))
+                       fprintf(p, "X-Asterisk-VM-Category: %s\r\n", category);
+               fprintf(p, "X-Asterisk-VM-Orig-date: %s\r\n", date);
+               fprintf(p, "X-Asterisk-VM-Orig-time: %ld\r\n", (long)time(NULL));
+       }
+       if (!ast_strlen_zero(cidnum))
+               fprintf(p, "X-Asterisk-CallerID: %s\r\n", cidnum);
+       if (!ast_strlen_zero(cidname))
+               fprintf(p, "X-Asterisk-CallerIDName: %s\r\n", cidname);
+       fprintf(p, "MIME-Version: 1.0\r\n");
+       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);
+
+               fprintf(p, "--%s\r\n", bound);
+       }
+       fprintf(p, "Content-Type: text/plain; charset=%s\r\nContent-Transfer-Encoding: 8bit\r\n\r\n", charset);
+       if (emailbody) {
+               struct ast_channel *ast;
+               if ((ast = ast_channel_alloc(0))) {
+                       char *passdata;
+                       int vmlen = strlen(emailbody)*3 + 200;
+                       if ((passdata = alloca(vmlen))) {
+                               memset(passdata, 0, vmlen);
+                               prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, cidnum, cidname, dur, date, passdata, vmlen, category);
+                               pbx_substitute_variables_helper(ast, emailbody, passdata, vmlen);
+                               fprintf(p, "%s\r\n", passdata);
+                       } 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"
+
+               "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, 
+               dur, msgnum + 1, mailbox, (cidname ? cidname : (cidnum ? cidnum : "an unknown caller")), date);
+       }
+       if (attach_user_voicemail) {
+               /* Eww. We want formats to tell us their own MIME type */
+               char *ctype = (!strcasecmp(format, "ogg")) ? "application/" : "audio/x-";
+               char tmpdir[256], newtmp[256];
+               int tmpfd;
+       
+               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);
+               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);
+               }
+               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);
+               snprintf(fname, sizeof(fname), "%s.%s", attach, format);
+               base_encode(fname, p);
+               /* only attach if necessary */
+               if (imap && strcmp(format, "gsm")) {
+                       fprintf(p, "--%s\r\n", bound);
+                       fprintf(p, "Content-Type: audio/x-gsm; name=\"msg%04d.%s\"\r\n", msgnum, format);
+                       fprintf(p, "Content-Transfer-Encoding: base64\r\n");
+                       fprintf(p, "Content-Description: Voicemail sound attachment.\r\n");
+                       fprintf(p, "Content-Disposition: attachment; filename=\"msg%04d.gsm\"\r\n\r\n", msgnum);
+                       snprintf(fname, sizeof(fname), "%s.gsm", attach);
+                       base_encode(fname, p);
+               }
+               fprintf(p, "\r\n\r\n--%s--\r\n.\r\n", bound);
+               if (tmpfd > -1)
+                       close(tmpfd);
+               unlink(newtmp);
+       }
+}
+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;
+       char tmp[80] = "/tmp/astmail-XXXXXX";
+       char tmp2[256];
+
        if (vmu && ast_strlen_zero(vmu->email)) {
                ast_log(LOG_WARNING, "E-mail address missing for mailbox [%s].  E-mail will not be sent.\n", vmu->mailbox);
                return(0);
        }
        if (!strcmp(format, "wav49"))
                format = "WAV";
-       if (option_debug)
-               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_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));
        /* Make a temporary file instead of piping directly to sendmail, in case the mail
           command hangs */
        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);
-
-               /* Set date format for voicemail mail */
-               strftime(date, sizeof(date), emaildateformat, &tm);
-
-               if (*fromstring) {
-                       struct ast_channel *ast;
-                       if ((ast = ast_channel_alloc(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);
-                                       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 <%s>\n", vmu->fullname, vmu->email);
-
-               if (emailsubject) {
-                       struct ast_channel *ast;
-                       if ((ast = ast_channel_alloc(0))) {
-                               char *passdata;
-                               int vmlen = strlen(emailsubject)*3 + 200;
-                               if ((passdata = alloca(vmlen))) {
-                                       memset(passdata, 0, vmlen);
-                                       prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, cidnum, cidname, dur, date, passdata, vmlen, category);
-                                       pbx_substitute_variables_helper(ast, emailsubject, passdata, vmlen);
-                                       fprintf(p, "Subject: %s\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");
-               } else
-               if (*emailtitle) {
-                       fprintf(p, emailtitle, msgnum + 1, mailbox) ;
-                       fprintf(p,"\n") ;
-               } else if (ast_test_flag((&globalflags), VM_PBXSKIP))
-                       fprintf(p, "Subject: New message %d in mailbox %s\n", msgnum + 1, mailbox);
-               else
-                       fprintf(p, "Subject: [PBX]: New message %d in mailbox %s\n", msgnum + 1, mailbox);
-               fprintf(p, "Message-ID: <Asterisk-%d-%d-%s-%d@%s>\n", msgnum, (unsigned int)ast_random(), mailbox, getpid(), host);
-#ifdef IMAP_STORAGE
-               /* additional information needed for IMAP searching */
-               fprintf(p, "X-Asterisk-VM-Message-Num: %d\n", msgnum + 1);
-               /* fprintf(p, "X-Asterisk-VM-Orig-Mailbox: %s\n", ext); */
-               fprintf(p, "X-Asterisk-VM-Server-Name: %s\n", fromstring);
-               fprintf(p, "X-Asterisk-VM-Context: %s\n", context);
-               fprintf(p, "X-Asterisk-VM-Extension: %s\n", chan->exten);
-               fprintf(p, "X-Asterisk-VM-Priority: %d\n", chan->priority);
-               fprintf(p, "X-Asterisk-VM-Caller-channel: %s\n", chan->name);
-               fprintf(p, "X-Asterisk-VM-Caller-ID-Num: %s\n", cidnum);
-               fprintf(p, "X-Asterisk-VM-Caller-ID-Name: %s\n", cidname);
-               fprintf(p, "X-Asterisk-VM-Duration: %d\n", duration);
-               if (!ast_strlen_zero(category))
-                       fprintf(p, "X-Asterisk-VM-Category: %s\n", category);
-               fprintf(p, "X-Asterisk-VM-Orig-date: %s\n", date);
-               fprintf(p, "X-Asterisk-VM-Orig-time: %ld\n", (long)time(NULL));
-#endif
-               if (!ast_strlen_zero(cidnum))
-                       fprintf(p, "X-Asterisk-CallerID: %s\n", cidnum);
-               if (!ast_strlen_zero(cidname))
-                       fprintf(p, "X-Asterisk-CallerIDName: %s\n", cidname);
-               fprintf(p, "MIME-Version: 1.0\n");
-               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\"\n\n\n", bound);
-
-                       fprintf(p, "--%s\n", bound);
-               }
-               fprintf(p, "Content-Type: text/plain; charset=%s\nContent-Transfer-Encoding: 8bit\n\n", charset);
-               if (emailbody) {
-                       struct ast_channel *ast;
-                       if ((ast = ast_channel_alloc(0))) {
-                               char *passdata;
-                               int vmlen = strlen(emailbody)*3 + 200;
-                               if ((passdata = alloca(vmlen))) {
-                                       memset(passdata, 0, vmlen);
-                                       prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, cidnum, cidname, dur, date, passdata, vmlen, category);
-                                       pbx_substitute_variables_helper(ast, emailbody, passdata, vmlen);
-                                       fprintf(p, "%s\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");
-               } else {
-                       fprintf(p, "Dear %s:\n\n\tJust wanted to let you know you were just left a %s long message (number %d)\n"
-
-                       "in mailbox %s from %s, on %s so you might\n"
-                       "want to check it when you get a chance.  Thanks!\n\n\t\t\t\t--Asterisk\n\n", vmu->fullname, 
-                       dur, msgnum + 1, mailbox, (cidname ? cidname : (cidnum ? cidnum : "an unknown caller")), date);
-               }
-               if (attach_user_voicemail) {
-                       /* Eww. We want formats to tell us their own MIME type */
-                       char *ctype = (!strcasecmp(format, "ogg")) ?  "application/" : "audio/x-";
-                       char tmpdir[256], newtmp[256];
-                       int tmpfd;
-               
-                       create_dirpath(tmpdir, sizeof(tmpdir), vmu->context, vmu->mailbox, "tmp");
-                       snprintf(newtmp, sizeof(newtmp), "%s/XXXXXX", tmpdir);
-                       tmpfd = mkstemp(newtmp);
-                       if (option_debug)
-                               ast_log(LOG_DEBUG, "newtmp: %s\n", newtmp);
-                       if (vmu->volgain < -.001 || vmu->volgain > .001) {
-                               snprintf(tmpcmd, sizeof(tmpcmd), "sox -v %.4f %s.%s %s.%s", vmu->volgain, attach, format, newtmp, format);
-                               ast_safe_system(tmpcmd);
-                               attach = newtmp;
-                               if (option_debug)
-                                       ast_log(LOG_DEBUG, "VOLGAIN: Stored at: %s.%s - Level: %.4f - Mailbox: %s\n", attach, format, vmu->volgain, mailbox);
-                       }
-                       fprintf(p, "--%s\n", bound);
-                       fprintf(p, "Content-Type: %s%s; name=\"msg%04d.%s\"\n", ctype, format, msgnum, format);
-                       fprintf(p, "Content-Transfer-Encoding: base64\n");
-                       fprintf(p, "Content-Description: Voicemail sound attachment.\n");
-                       fprintf(p, "Content-Disposition: attachment; filename=\"msg%04d.%s\"\n\n", msgnum, format);
-
-                       snprintf(fname, sizeof(fname), "%s.%s", attach, format);
-                       base_encode(fname, p);
-#ifdef IMAP_STORAGE
-                       /* only attach if necessary */
-                       if (strcmp(format, "gsm")) {
-                               fprintf(p, "--%s\n", bound);
-                               fprintf(p, "Content-Type: audio/x-gsm; name=\"msg%04d.%s\"\n", msgnum, format);
-                               fprintf(p, "Content-Transfer-Encoding: base64\n");
-                               fprintf(p, "Content-Description: Voicemail sound attachment.\n");
-                               fprintf(p, "Content-Disposition: attachment; filename=\"msg%04d.gsm\"\n\n", msgnum);
-                               snprintf(fname, sizeof(fname), "%s.gsm", attach);
-                               base_encode(fname, p);
-                       }
-#endif
-                       fprintf(p, "\n\n--%s--\n.\n", bound);
-                       if (tmpfd > -1)
-                               close(tmpfd);
-                       unlink(newtmp);
-               }
+               make_email_file(p, srcemail, vmu, msgnum, context, mailbox, cidnum, cidname, attach, format, duration, attach_user_voicemail, chan, category, 0);
                fclose(p);
                snprintf(tmp2, sizeof(tmp2), "( %s < %s ; rm -f %s ) &", mailcmd, tmp, tmp);
                ast_safe_system(tmp2);
@@ -2123,7 +2126,6 @@ static int sendpage(char *srcemail, char *pager, int msgnum, char *context, char
        return 0;
 }
 
-#ifndef IMAP_STORAGE
 static int get_date(char *s, int len)
 {
        struct tm tm;
@@ -2132,7 +2134,6 @@ static int get_date(char *s, int len)
        localtime_r(&t,&tm);
        return strftime(s, len, "%a %b %e %r %Z %Y", &tm);
 }
-#endif
 
 static int invent_message(struct ast_channel *chan, char *context, char *ext, int busy, char *ecodes)
 {
@@ -2376,9 +2377,68 @@ static int has_voicemail(const char *mailbox, const char *folder)
                return 0;
 }
 
-#else
-#ifdef IMAP_STORAGE
-static int count_messages_imap(const char *mailbox, int *newmsgs, int *oldmsgs)
+#elif defined(IMAP_STORAGE)
+
+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)
+{
+       char *myserveremail = serveremail;
+       char fn[256];
+       char mailbox[256];
+       char *stringp;
+       FILE *p=NULL;
+       char tmp[80] = "/tmp/astmail-XXXXXX";
+       long len;
+       void *buf;
+       STRING str;
+       
+       /* Attach only the first format */
+       fmt = ast_strdupa(fmt);
+       stringp = fmt;
+       strsep(&stringp, "|");
+
+       if (!ast_strlen_zero(vmu->serveremail))
+               myserveremail = vmu->serveremail;
+
+       make_file(fn, sizeof(fn), dir, msgnum);
+
+       if (ast_strlen_zero(vmu->email))
+               ast_copy_string(vmu->email, vmu->imapuser, sizeof(vmu->email));
+
+       if (!strcmp(fmt, "wav49"))
+               fmt = "WAV";
+       if(option_debug > 2)
+               ast_log(LOG_DEBUG, "Storing file '%s', format '%s'\n", fn, fmt);
+       /* Make a temporary file instead of piping directly to sendmail, in case the mail
+          command hangs */
+       if ((p = vm_mkftemp(tmp)) == NULL) {
+               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, chan->cid.cid_num, chan->cid.cid_name, 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);
+       }
+       return 0;
+
+}
+
+static int inboxcount(const char *mailbox, int *newmsgs, int *oldmsgs)
 {
        SEARCHPGM *pgm;
        SEARCHHEADER *hdr;
@@ -2407,7 +2467,7 @@ static int count_messages_imap(const char *mailbox, int *newmsgs, int *oldmsgs)
                ret = 0;
                while((cur = strsep(&mb, ", "))) {
                        if (!ast_strlen_zero(cur)) {
-                               if (count_messages_imap(cur, newmsgs ? &tmpnew : NULL, oldmsgs ? &tmpold : NULL))
+                               if (inboxcount(cur, newmsgs ? &tmpnew : NULL, oldmsgs ? &tmpold : NULL))
                                        return -1;
                                else {
                                        if (newmsgs)
@@ -2467,7 +2527,7 @@ static int count_messages_imap(const char *mailbox, int *newmsgs, int *oldmsgs)
                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));
-               strcpy(vms_p->imapuser,vmu->imapuser);
+               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)
@@ -2480,7 +2540,7 @@ static int count_messages_imap(const char *mailbox, int *newmsgs, int *oldmsgs)
                vmstate_insert(vms_p);
        }
        if (!vms_p->mailstream)
-               ret = init_mailstream(vms_p);
+               ret = init_mailstream(vms_p, 0);
        if (!vms_p->mailstream) {
                ast_log (LOG_ERROR,"Houston we have a problem - IMAP mailstream is NULL\n");
                return -1;
@@ -2499,6 +2559,7 @@ static int count_messages_imap(const char *mailbox, int *newmsgs, int *oldmsgs)
                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 ();
@@ -2514,6 +2575,7 @@ static int count_messages_imap(const char *mailbox, int *newmsgs, int *oldmsgs)
                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;
@@ -2527,9 +2589,34 @@ static int count_messages_imap(const char *mailbox, int *newmsgs, int *oldmsgs)
        }
        return 0;
  }
-#endif
-#endif
 
+static int has_voicemail(const char *mailbox, const char *folder)
+{
+       int newmsgs, oldmsgs;
+       
+       if(inboxcount(mailbox, &newmsgs, &oldmsgs))
+               return folder? oldmsgs: newmsgs;
+       else
+               return 0;
+}
+
+static int messagecount(const char *context, const char *mailbox, const char *folder)
+{
+       int newmsgs, oldmsgs;
+       char tmp[256]="";
+       
+       if (ast_strlen_zero(mailbox))
+               return 0;
+       sprintf(tmp,"%s@%s", mailbox, ast_strlen_zero(context)? "default": context);
+
+       if(inboxcount(tmp, &newmsgs, &oldmsgs))
+               return folder? oldmsgs: newmsgs;
+       else
+               return 0;
+}
+
+#endif
+#ifndef IMAP_STORAGE
 /* copy message only used by file storage */
 static int copy_message(struct ast_channel *chan, struct ast_vm_user *vmu, int imbox, int msgnum, long duration, struct ast_vm_user *recip, char *fmt)
 {
@@ -2561,9 +2648,8 @@ static int copy_message(struct ast_channel *chan, struct ast_vm_user *vmu, int i
        
        return 0;
 }
-
-#ifndef ODBC_STORAGE
-
+#endif
+#if !(defined(IMAP_STORAGE) || defined(ODBC_STORAGE))
 static int messagecount(const char *context, const char *mailbox, const char *folder)
 {
        return __has_voicemail(context, mailbox, folder, 0);
@@ -2716,14 +2802,13 @@ static int leave_voicemail(struct ast_channel *chan, char *ext, struct leave_vm_
 {
 #ifdef IMAP_STORAGE
        int newmsgs, oldmsgs;
-       struct vm_state *vms;
-#else
+       struct vm_state *vms = NULL;
+#endif
        char tmptxtfile[256], txtfile[256];
        char callerid[256];
        FILE *txt;
        char date[256];
        int txtdes;
-#endif
        int res = 0;
        int msgnum;
        int duration = 0;
@@ -2901,46 +2986,33 @@ static int leave_voicemail(struct ast_channel *chan, char *ext, struct leave_vm_
                        newmsgs = vms->newmessages++;
                        oldmsgs = vms->oldmessages;
                } else {
-                       res = count_messages_imap(ext, &newmsgs, &oldmsgs);
+                       res = inboxcount(ext, &newmsgs, &oldmsgs);
                        if(res < 0) {
                                ast_log(LOG_NOTICE,"Can not leave voicemail, unable to count messages\n");
                                return -1;
                        }
+                       vms = get_vm_state_by_mailbox(ext,0);
                }
                /* here is a big difference! We add one to it later */
                msgnum = newmsgs + oldmsgs;
-               ast_log(LOG_NOTICE, "Messagecount set to %d\n",msgnum);
+               if(option_debug > 2)
+                       ast_log(LOG_DEBUG, "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_usage >= vms->quota_limit) {
+               if (vms->quota_limit && vms->quota_usage >= vms->quota_limit) {
                        if (option_debug)
-                               ast_log(LOG_DEBUG, "*** QUOTA EXCEEDED!!\n");
+                               ast_log(LOG_DEBUG, "*** QUOTA EXCEEDED!! %u >= %u\n", vms->quota_usage, vms->quota_limit);
                        ast_play_and_wait(chan, "vm-mailboxfull");
                        return -1;
                }
+               /* here is a big difference! We add one to it later */
+               msgnum = newmsgs + oldmsgs;
+               if(option_debug > 2)
+                       ast_log(LOG_DEBUG, "Messagecount set to %d\n",msgnum);
 
-               /* play beep */
-               res = ast_streamfile(chan, "beep", chan->language);
-               if (!res)
-                       res = ast_waitstream(chan, "");
-               /* play_record_review does recording and verify */
-               if (option_debug)
-                       ast_log(LOG_DEBUG, "About to record message in file %s\n",fn);
-               res = play_record_review(chan, NULL, fn, vmmaxmessage, fmt, 1, vmu, &duration, dir, options->record_gain);
-               if (res == '0') {
-                       goto transfer;
-               }
-               if (res > 0) res = 0;
-
-               if (duration < vmminmessage) {
-                       if (option_verbose > 2) 
-                               ast_verbose( VERBOSE_PREFIX_3 "Recording was %d seconds long but needs to be at least %d - abandoning\n", duration, vmminmessage);
-                       goto leave_vm_out;
-               }
-               notify_new_message(chan, vmu, msgnum, duration, fmt, chan->cid.cid_num, chan->cid.cid_name);
 #else
                if (count_messages(vmu, dir) >= vmu->maxmsg) {
                        res = ast_streamfile(chan, "vm-mailboxfull", chan->language);
@@ -2951,6 +3023,7 @@ static int leave_voicemail(struct ast_channel *chan, char *ext, struct leave_vm_
                        goto leave_vm_out;
                }
 
+#endif
                snprintf(tmptxtfile, sizeof(tmptxtfile), "%s/XXXXXX", tmpdir);
                txtdes = mkstemp(tmptxtfile);
                if (txtdes < 0) {
@@ -3024,13 +3097,18 @@ static int leave_voicemail(struct ast_channel *chan, char *ext, struct leave_vm_
                                        make_file(fn, sizeof(fn), dir, msgnum);
 
                                        /* assign a variable with the name of the voicemail file */ 
+#ifndef IMAP_STORAGE
                                        pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", fn);
+#else
+                                       pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", "IMAP_STORAGE");
+#endif
 
                                        snprintf(txtfile, sizeof(txtfile), "%s.txt", fn);
                                        ast_filerename(tmptxtfile, fn, NULL);
                                        rename(tmptxtfile, txtfile);
 
                                        ast_unlock_path(dir);
+#ifndef IMAP_STORAGE
                                        /* Are there to be more recipients of this message? */
                                        while (tmpptr) {
                                                struct ast_vm_user recipu, *recip;
@@ -3047,15 +3125,15 @@ static int leave_voicemail(struct ast_channel *chan, char *ext, struct leave_vm_
                                                        free_user(recip);
                                                }
                                        }
+#endif
                                        if (ast_fileexists(fn, NULL, NULL)) {
-                                               STORE(dir, vmu->mailbox, vmu->context, msgnum);
+                                               STORE(dir, vmu->mailbox, vmu->context, msgnum, chan, vmu, fmt, duration, vms);
                                                notify_new_message(chan, vmu, msgnum, duration, fmt, chan->cid.cid_num, chan->cid.cid_name);
                                                DISPOSE(dir, msgnum);
                                        }
                                }
                        }
                }
-#endif
                if (res == '0') {
                        goto transfer;
                } else if (res > 0)
@@ -3116,7 +3194,7 @@ static int save_to_folder(struct ast_vm_user *vmu, struct vm_state *vms, int msg
 #ifdef IMAP_STORAGE
        /* we must use mbox(x) folder names, and copy the message there */
        /* simple. huh? */
-       char *dbox = mbox(box);
+       char dbox[256];
        long res;
        char sequence[10];
 
@@ -3124,9 +3202,10 @@ static int save_to_folder(struct ast_vm_user *vmu, struct vm_state *vms, int msg
        if (box == 1) return 10;
        /* 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);
-       res = mail_copy(vms->mailstream,sequence,dbox);
+       res = mail_copy(vms->mailstream, sequence, dbox);
        if (res == 1) return 0;
        return 1;
 #else
@@ -3747,13 +3826,8 @@ static int notify_new_message(struct ast_channel *chan, struct ast_vm_user *vmu,
        int newmsgs = 0, oldmsgs = 0;
        const char *category = pbx_builtin_getvar_helper(chan, "VM_CATEGORY");
 
-#ifdef IMAP_STORAGE
-       snprintf(todir, sizeof(todir), "%s/imap",VM_SPOOL_DIR);
-       sprintf(fn, "%s/msg%s%04d", todir, vmu->mailbox, msgnum);
-#else
        make_dir(todir, sizeof(todir), vmu->context, vmu->mailbox, "INBOX");
        make_file(fn, sizeof(fn), todir, msgnum);
-#endif
        snprintf(ext_context, sizeof(ext_context), "%s@%s", vmu->mailbox, vmu->context);
 
        if (!ast_strlen_zero(vmu->attachfmt)) {
@@ -3790,6 +3864,9 @@ static int notify_new_message(struct ast_channel *chan, struct ast_vm_user *vmu,
                DELETE(todir, msgnum, fn);
        }
 
+#ifdef IMAP_STORAGE
+       DELETE(todir, msgnum, fn);
+#endif
        /* Leave voicemail for someone */
        if (ast_app_has_voicemail(ext_context, NULL)) {
                ast_app_inboxcount(ext_context, &newmsgs, &oldmsgs);
@@ -3808,7 +3885,6 @@ static int forward_message(struct ast_channel *chan, char *context, struct vm_st
        char todir[256];
        int todircount=0;
        int duration;
-       char fn[256];
 #endif
        char username[70]="";
        int res = 0, cmd = 0;
@@ -3962,7 +4038,7 @@ static int forward_message(struct ast_channel *chan, char *context, struct vm_st
                                /* 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(header_content)) {
+                               if (ast_strlen_zero(header_content)) {
                                        ast_log (LOG_ERROR,"Could not fetch header for message number %ld\n",vms->msgArray[vms->curmsg]);
                                        return -1;
                                }
@@ -3988,7 +4064,7 @@ static int forward_message(struct ast_channel *chan, char *context, struct vm_st
                                        ast_log (LOG_DEBUG,"**** 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/imap", VM_SPOOL_DIR);
+                               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);
@@ -3998,14 +4074,15 @@ static int forward_message(struct ast_channel *chan, char *context, struct vm_st
                                /* should not assume "fmt" here! */
                                save_body(body,vms,"2",fmt);
  
+                               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;
                                int attach_user_voicemail = ast_test_flag((&globalflags), VM_ATTACH);
                                attach_user_voicemail = ast_test_flag(vmtmp, VM_ATTACH);
-                               sprintf(fn, "%s/%s/msg%04d", todir, vms->imapuser, vms->curmsg);
                                /* NULL category for IMAP storage */
-                               sendmail(myserveremail, vmtmp, todircount, vmtmp->context, vmtmp->mailbox, chan->cid.cid_num, chan->cid.cid_name, fn, fmt, duration, attach_user_voicemail, chan, NULL);
+                               sendmail(myserveremail, vmtmp, todircount, vmtmp->context, vmtmp->mailbox, chan->cid.cid_num, chan->cid.cid_name, vms->fn, fmt, duration, attach_user_voicemail, chan, NULL);
 #else
                                copy_message(chan, sender, 0, curmsg, 0, vmtmp, fmt);
 #endif
@@ -4273,11 +4350,11 @@ static int play_message(struct ast_channel *chan, struct ast_vm_user *vmu, struc
        /* 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(header_content)) {
+       if (ast_strlen_zero(header_content)) {
                ast_log (LOG_ERROR,"Could not fetch header for message number %ld\n",vms->msgArray[vms->curmsg]);
                return -1;
        }
-       snprintf(todir, sizeof(todir), "%s/imap", VM_SPOOL_DIR);
+       snprintf(todir, sizeof(todir), "%s%s/%s/tmp", VM_SPOOL_DIR, vmu->context, vmu->mailbox);
        make_gsm_file(vms->fn, vms->imapuser, todir, vms->curmsg);
 
        mail_fetchstructure (vms->mailstream,vms->msgArray[vms->curmsg],&body);
@@ -4296,43 +4373,43 @@ 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)
-               strcpy(cid,temp); 
+               ast_copy_string(cid, temp, sizeof(cid)); 
        else 
                cid[0] = '\0';
 
        temp = get_header_by_tag(header_content, "X-Asterisk-VM-Context:");
 
        if (temp)
-               strcpy(context,temp); 
+               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)
-               strcpy(origtime,temp);
+               ast_copy_string(origtime, temp, sizeof(origtime));
        else
                origtime[0] = '\0';
 
        temp = get_header_by_tag(header_content, "X-Asterisk-VM-Duration:");
 
        if (temp)
-               strcpy(duration,temp);
+               ast_copy_string(duration,temp, sizeof(duration));
        else
                duration[0] = '\0';
        
        temp = get_header_by_tag(header_content, "X-Asterisk-VM-Category:");
        
        if (temp)
-               strcpy(category,temp);
+               ast_copy_string(category,temp, sizeof(category));
        else
                category[0] = '\0';
 
-       /*if (!strncasecmp("macro",context,5))  Macro names in contexts are useless for our needs */
+       /*if (!strncasecmp("macro",context,5)) Macro names in contexts are useless for our needs */
        /*      context = ast_variable_retrieve(msg_cfg, "message","macrocontext"); */
        if (res == '1')
                res = 0;
@@ -4361,6 +4438,7 @@ static int play_message(struct ast_channel *chan, struct ast_vm_user *vmu, struc
                res = wait_file(chan, vms, vms->fn);
        }
        DISPOSE(vms->curdir, vms->curmsg);
+       DELETE(0, 0, vms->fn);
        return res;
 }
 #else
@@ -4463,13 +4541,10 @@ static int play_message(struct ast_channel *chan, struct ast_vm_user *vmu, struc
 #endif
 
 #ifdef IMAP_STORAGE
-static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu,int box)
+static void imap_mailbox_name(char *spec, struct vm_state *vms, int box, int use_folder)
 {
-       SEARCHPGM *pgm;
-       SEARCHHEADER *hdr;
-       int ret;
-
-       strcpy(vms->imapuser,vmu->imapuser);
+       char tmp[256];
+       
        if (box == 1) {
                ast_copy_string(vms->curbox, mbox(0), sizeof(vms->curbox));
                sprintf(vms->vmbox, "vm-%s", mbox(1));
@@ -4478,9 +4553,76 @@ static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu,int box)
                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);
+       }
+       if(box == 0 || box == 1)
+               sprintf(spec, "%s%s", tmp, use_folder? imapfolder: "INBOX");
+       else
+               sprintf(spec, "%s%s%c%s", tmp, imapfolder, delimiter, mbox(box));
+}
+
+static int init_mailstream(struct vm_state *vms, int box)
+{
+       MAILSTREAM *stream = NIL;
+       long debug;
+       char tmp[255];
+       
+       if (!vms) {
+               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);
+       if (vms->mailstream == NIL || !vms->mailstream) {
+               ast_log (LOG_DEBUG,"mailstream not set.\n");
+       } else {
+               stream = vms->mailstream;
+       }
+       /* debug = T;  user wants protocol telemetry? */
+       debug = NIL;  /* NO protocol telemetry? */
+
+       if (delimiter == '\0') {                /* did not probe the server yet */
+               char *cp;
+#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);
+               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++)
+                       if(*cp == '/')
+                               *cp = delimiter;
+       }
+       /* 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);
+       if (vms->mailstream == NIL) {
+               return -1;
+       } else {
+               return 0;
+       }
+}
+
+static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box)
+{
+       SEARCHPGM *pgm;
+       SEARCHHEADER *hdr;
+       int ret;
+       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);
+       ret = init_mailstream(vms, box);
        if (ret != 0) {
                ast_log (LOG_ERROR,"Could not initialize mailstream\n");
                return -1;
@@ -4488,7 +4630,8 @@ static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu,int box)
 
        /* Check Quota (here for now to test) */
        mail_parameters(NULL, SET_QUOTA, (void *) mm_parsequota);
-       imap_getquotaroot(vms->mailstream,"INBOX");
+       imap_mailbox_name(dbox, vms, box, 1);
+       imap_getquotaroot(vms->mailstream, dbox);
 
        pgm = mail_newsearchpgm();
 
@@ -4515,6 +4658,7 @@ static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu,int box)
 
        vms->lastmsg = vms->vmArrayIndex - 1;
 
+       mail_free_searchpgm(&pgm);
        return 0;
 }
 #else
@@ -5455,7 +5599,7 @@ static int vm_intro(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm
                return vm_intro_se(chan, vms);
        } else if (!strcasecmp(chan->language, "no")) { /* NORWEGIAN syntax */
                return vm_intro_no(chan, vms);
-       } else if (!strcasecmp(chan->language, "ru")) {   /* RUSSIAN syntax */
+       } else if (!strcasecmp(chan->language, "ru")) { /* RUSSIAN syntax */
                return vm_intro_ru(chan, vms);
        } else {                                        /* Default to ENGLISH */
                return vm_intro_en(chan, vms);
@@ -6181,7 +6325,7 @@ static int vm_execmain(struct ast_channel *chan, void *data)
 #ifdef IMAP_STORAGE
                if(option_debug > 2)
                        ast_log(LOG_DEBUG, "Checking quotas: comparing %u to %u\n",vms.quota_usage,vms.quota_limit);
-               if (vms.quota_usage >= vms.quota_limit) {
+               if (vms.quota_limit && vms.quota_usage >= vms.quota_limit) {
                        ast_log(LOG_DEBUG, "*** QUOTA EXCEEDED!!\n");
                        cmd = ast_play_and_wait(chan, "vm-mailboxfull");
                }
@@ -6483,7 +6627,7 @@ out:
        /* 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);
-       if (vmu && deleted == 1 && expungeonhangup == 1)  {
+       if (vmu && deleted == 1 && expungeonhangup == 1) {
 #ifdef HAVE_IMAP_TK2006
                if (LEVELUIDPLUS (vms.mailstream)) {
                        mail_expunge_full(vms.mailstream,NIL,EX_UID);
@@ -6877,6 +7021,7 @@ static int load_config(void)
        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;
@@ -6997,13 +7142,13 @@ static int load_config(void)
                if ((imap_server = ast_variable_retrieve(cfg, "general", "imapserver"))) {
                        ast_copy_string(imapserver, imap_server, sizeof(imapserver));
                } else {
-                       strcpy(imapserver,"localhost");
+                       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));
                } else {
-                       strcpy(imapport,"143");
+                       ast_copy_string(imapport,"143", sizeof(imapport));
                }
                /* IMAP server flags */
                if ((imap_flags = ast_variable_retrieve(cfg, "general", "imapflags"))) {
@@ -7019,13 +7164,19 @@ static int load_config(void)
                }
                /* Expunge on exit */
                if ((expunge_on_hangup = ast_variable_retrieve(cfg, "general", "expungeonhangup"))) {
-                       if(!ast_false(expunge_on_hangup))
+                       if(ast_false(expunge_on_hangup))
                                expungeonhangup = 0;
                        else
                                expungeonhangup = 1;
                } else {
                        expungeonhangup = 1;
                }
+               /* IMAP voicemail folder */
+               if ((imap_folder = ast_variable_retrieve(cfg, "general", "imapfolder"))) {
+                       ast_copy_string(imapfolder, imap_folder, sizeof(imapfolder));
+               } else {
+                       ast_copy_string(imapfolder,"INBOX", sizeof(imapfolder));
+               }
 #endif
                /* External voicemail notify application */
                
@@ -7525,7 +7676,7 @@ static int advanced_options(struct ast_channel *chan, struct ast_vm_user *vmu, s
        char *header_content,*temp;
 #endif
        char filename[256];
-       struct ast_config *msg_cfg;
+       struct ast_config *msg_cfg = NULL;
        const char *origtime, *context;
        char *cid, *name, *num;
        int retries = 0;
@@ -7549,11 +7700,11 @@ static int advanced_options(struct ast_channel *chan, struct ast_vm_user *vmu, s
                return -1;
        }
 
-       /* Get info from headers!!  */
+       /* Get info from headers!! */
        temp = get_header_by_tag(header_content, "X-Asterisk-VM-Caller-ID-Num:");
        
        if (temp)
-               strcpy(cidS,temp);
+               ast_copy_string(cidS,temp, sizeof(cidS));
        else
                cidS[0] = '\0';
        
@@ -7561,7 +7712,7 @@ static int advanced_options(struct ast_channel *chan, struct ast_vm_user *vmu, s
        temp = get_header_by_tag(header_content, "X-Asterisk-VM-Context:");
        
        if (temp)
-               strcpy(contextS,temp);
+               ast_copy_string(contextS,temp, sizeof(contextS));
        else
                contextS[0] = '\0';
        
@@ -7569,13 +7720,13 @@ static int advanced_options(struct ast_channel *chan, struct ast_vm_user *vmu, s
        temp = get_header_by_tag(header_content, "X-Asterisk-VM-Orig-time:");
        
        if (temp)
-               strcpy(origtimeS,temp);
+               ast_copy_string(origtimeS,temp, sizeof(origtimeS));
        else
                origtimeS[0] = '\0';
        
        origtime = &origtimeS[0];
        
-       strcpy(filename, "IMAP_STORAGE");
+       ast_copy_string(filename, "IMAP_STORAGE", sizeof(filename));
 #else
        make_file(vms->fn, sizeof(vms->fn), vms->curdir, msg);
 
@@ -7796,8 +7947,6 @@ static int play_record_review(struct ast_channel *chan, char *playfile, char *re
                                if (option_verbose > 2)
                                        ast_verbose(VERBOSE_PREFIX_3 "Saving message as is\n");
                                ast_stream_and_wait(chan, "vm-msgsaved", chan->language, "");
-                               STORE(recordfile, vmu->mailbox, vmu->context, -1);
-                               DISPOSE(recordfile, -1);
                                cmd = 't';
                                return res;
                        }
@@ -7950,52 +8099,6 @@ static int play_record_review(struct ast_channel *chan, char *playfile, char *re
 }
 
 #ifdef IMAP_STORAGE
-static int init_mailstream(struct vm_state *vms)
-{
-       MAILSTREAM *stream = NIL;
-       /* char *s; */
-       char mbox[255];
-       long debug;
-       
-       
-       
-       if (!vms) {
-               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);
-       if (vms->mailstream == NIL || !vms->mailstream) {
-               ast_log (LOG_DEBUG,"mailstream not set.\n");
-       } else {
-               stream = vms->mailstream;
-               /* return 0; */
-       }
-       ast_mutex_lock(&curhstusr_lock);
-       curusr = cpystr (vms->imapuser);
-       curhst = cpystr (mylocalhost ());
-       /* debug = T;  user wants protocol telemetry? */
-       debug = NIL;  /* NO protocol telemetry? */
-       if (strlen(authuser) > 0) {
-               snprintf(mbox, sizeof(mbox), "{%s:%s/imap/authuser=%s/%s/user=%s}%s",imapserver,imapport,authuser,imapflags,vms->imapuser,vms->curbox);
-       } else {
-               snprintf(mbox, sizeof(mbox), "{%s:%s/imap/%s/user=%s}%s",imapserver,imapport,imapflags,vms->imapuser,vms->curbox);
-       }
-       if(option_debug > 2)
-               ast_log (LOG_DEBUG,"Before mail_open, curusr: %s, mbox:%s\n",curusr,mbox);
-       ast_mutex_unlock(&curhstusr_lock);
-       vms->mailstream = mail_open (stream, mbox, debug ? OP_DEBUG : NIL);
-       if (vms->mailstream == NIL) {
-               return -1;
-       } else {
-               if (delimiter == '\0') {
-                       get_mailbox_delimiter(vms->mailstream);
-               }
-               /* status(vms->mailstream); */
-               return 0;
-       }
-}
 
 static void write_file(char *filename, char *buffer, unsigned long len)
 {
@@ -8080,6 +8183,7 @@ static void display_body(BODY *body, char *pfx, long i)
        }
 }
 
+#if 0 /*No need for this. */
 /* MM status report
  * Accepts: MAIL stream
  */
@@ -8188,7 +8292,7 @@ static void status(MAILSTREAM *stream)
                }
        }
 }
-
+#endif
 
 /* Interfaces to C-client */
 
@@ -8230,9 +8334,11 @@ void mm_notify(MAILSTREAM * stream, char *string, long errflg)
 
 void mm_list(MAILSTREAM * stream, int delim, char *mailbox, long attributes)
 {
-       if (delimiter)
+       if (delimiter == '\0') {
+               ast_mutex_lock(&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)
@@ -8300,25 +8406,29 @@ void mm_log(char *string, long errflg)
 
 void mm_dlog(char *string)
 {
-       ast_log(LOG_NOTICE,string);
+       ast_log (LOG_NOTICE, "%s\n", string);
 }
 
 
 void mm_login(NETMBX * mb, char *user, char *pwd, long trial)
 {
-       if (option_debug > 3)
+       struct ast_vm_user *vmu;
+
+       if(option_debug > 3)
                ast_log(LOG_DEBUG, "Entering callback mm_login\n");
-       ast_mutex_lock(&curhstusr_lock);
-       if (curhst)
-               fs_give((void **) &curhst);
-       curhst = (char *) fs_get(1 + strlen(mb->host));
-       strcpy(curhst, mb->host);
-       strcpy(user, S_OR(mb->user, curusr));
-       fs_give((void **) &curusr);
-       ast_mutex_unlock(&curhstusr_lock);
+       ast_copy_string(user, mb->user,sizeof(user));
+
        /* We should only do this when necessary */
-       if (!ast_strlen_zero(authpassword))
-               strcpy(pwd, authpassword);
+       if (!ast_strlen_zero(authpassword)) {
+               ast_copy_string(pwd, authpassword, sizeof(pwd));
+       } else {
+               AST_LIST_TRAVERSE(&users, vmu, list) {
+                       if(!strcasecmp(mb->user, vmu->imapuser)) {
+                               ast_copy_string(pwd, vmu->imappassword, sizeof(pwd));
+                               break;
+                       }
+               }
+       }
 }
 
 
@@ -8389,10 +8499,12 @@ static char *get_header_by_tag(char *header, char *tag)
        if (!start)
                return NULL;
 
-       ast_copy_string(temp, start+taglen, sizeof(temp));
-       eol_pnt = strchr(temp,'\n');
+       ast_mutex_lock(&imaptemp_lock);
+       ast_copy_string(imaptemp, start+taglen, sizeof(imaptemp));
+       ast_mutex_unlock(&imaptemp_lock);
+       eol_pnt = strchr(imaptemp,'\n');
        *eol_pnt = '\0';
-       return temp;
+       return imaptemp;
 }
 
 static char *get_user_by_mailbox(char *mailbox)
@@ -8407,20 +8519,22 @@ static char *get_user_by_mailbox(char *mailbox)
        if (!start)
                return NULL;
 
-       strcpy(temp,start+5);
+       ast_mutex_lock(&imaptemp_lock);
+       ast_copy_string(imaptemp, start+5, sizeof(imaptemp));
+       ast_mutex_unlock(&imaptemp_lock);
 
-       quote = strchr(temp,'\"');
+       quote = strchr(imaptemp,'\"');
        if (!quote) {  /* if username is not in quotes */
-               eol_pnt = strchr(temp,'/');
+               eol_pnt = strchr(imaptemp,'/');
                if (!eol_pnt) {
-                       eol_pnt = strchr(temp,'}');
+                       eol_pnt = strchr(imaptemp,'}');
                }
                *eol_pnt = '\0';
-               return temp;
+               return imaptemp;
        } else {
-               eol_pnt = strchr(temp+1,'\"');
+               eol_pnt = strchr(imaptemp+1,'\"');
                *eol_pnt = '\0';
-               return temp+1;
+               return imaptemp+1;
        }
 }
 
@@ -8515,8 +8629,8 @@ static void vmstate_insert(struct vm_state *vms)
                        /* get a pointer to the persistent store */
                        vms->persist_vms = altvms;
                        /* Reuse the mailstream? */
-                       /* vms->mailstream = altvms->mailstream; */
-                       vms->mailstream = NIL;
+                       vms->mailstream = altvms->mailstream;
+                       /* vms->mailstream = NIL; */
                }
        }
 
@@ -8596,9 +8710,9 @@ static void set_update(MAILSTREAM * stream)
 
 static void init_vm_state(struct vm_state *vms) 
 {
-       int x = 0;
+       int x;
        vms->vmArrayIndex = 0;
-       for (x; x<256; x++) {
+       for (x = 0; x < 256; x++) {
                vms->msgArray[x] = 0;
        }
 }
@@ -8637,7 +8751,7 @@ static int save_body(BODY *body, struct vm_state *vms, char *section, char *form
        if (body_content != NIL) {
                sprintf(filename,"%s.%s", vms->fn, format);
                /* ast_log (LOG_DEBUG,body_content); */
-               body_decoded = rfc822_base64 (body_content, len, &newlen);
+               body_decoded = rfc822_base64 ((unsigned char *)body_content, len, &newlen);
                write_file (filename, (char *) body_decoded, newlen);
        }
        return 0;
@@ -8645,7 +8759,9 @@ static int save_body(BODY *body, struct vm_state *vms, char *section, char *form
 
 /* get delimiter via mm_list callback */
 static void get_mailbox_delimiter(MAILSTREAM *stream) {
-       mail_list(stream, "", "*");
+       char tmp[50];
+       sprintf(tmp, "{%s}", imapserver);
+       mail_list(stream, tmp, "*");
 }
 
 #endif /* IMAP_STORAGE */