diff options
Diffstat (limited to 'apps')
-rw-r--r-- | apps/app_voicemail.c | 2776 |
1 files changed, 1223 insertions, 1553 deletions
diff --git a/apps/app_voicemail.c b/apps/app_voicemail.c index 09c90e588..61bdfc45a 100644 --- a/apps/app_voicemail.c +++ b/apps/app_voicemail.c @@ -127,19 +127,17 @@ 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 char *get_header_by_tag(char *header, char *tag); -static void vm_imap_delete(int msgnum, struct vm_state *vms); +static void vm_imap_delete(int msgnum, struct ast_vm_user *vmu); static char *get_user_by_mailbox(char *mailbox); 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 struct vm_state *create_vm_state_from_user(struct ast_vm_user *vmu, char *mailbox); +static struct vm_state *create_vm_state_from_user(struct ast_vm_user *vmu); static void vmstate_insert(struct vm_state *vms); static void vmstate_delete(struct vm_state *vms); static void set_update(MAILSTREAM * stream); static void init_vm_state(struct vm_state *vms); -static void check_msgArray(struct vm_state *vms); static void copy_msgArray(struct vm_state *dst, struct vm_state *src); static int save_body(BODY *body, struct vm_state *vms, char *section, char *format); -static int make_gsm_file(char *dest, size_t len, 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, size_t len, struct vm_state *vms, int box, int target); @@ -402,31 +400,30 @@ static void apply_options(struct ast_vm_user *vmu, const char *options); #ifdef ODBC_STORAGE static char odbc_database[80]; static char odbc_table[80]; -#define RETRIEVE(a,b) retrieve_file(a,b) +#define RETRIEVE(a,b,c) retrieve_file(a,b) #define DISPOSE(a,b) remove_file(a,b) #define STORE(a,b,c,d,e,f,g,h,i) store_file(a,b,c,d) #define EXISTS(a,b,c,d) (message_exists(a,b)) #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)) -#define DELETE(a,b,c) (delete_file(a,b)) +#define DELETE(a,b,c,d) (delete_file(a,b)) #else #ifdef IMAP_STORAGE -#define RETRIEVE(a,b) -#define DISPOSE(a,b) +#define RETRIEVE(a,b,c) imap_retrieve_file(a,b,c) +#define DISPOSE(a,b) remove_file(a,b) #define STORE(a,b,c,d,e,f,g,h,i) (imap_store_file(a,b,c,d,e,f,g,h,i)) #define EXISTS(a,b,c,d) (ast_fileexists(c,NULL,d) > 0) #define RENAME(a,b,c,d,e,f,g,h) (rename_file(g,h)); #define COPY(a,b,c,d,e,f,g,h) (copy_file(g,h)); -#define IMAP_DELETE(a,b,c,d) (vm_imap_delete(b,d)) -#define DELETE(a,b,c) (vm_delete(c)) +#define DELETE(a,b,c,d) (vm_imap_delete(b,d)) #else -#define RETRIEVE(a,b) +#define RETRIEVE(a,b,c) #define DISPOSE(a,b) #define STORE(a,b,c,d,e,f,g,h,i) #define EXISTS(a,b,c,d) (ast_fileexists(c,NULL,d) > 0) #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_plain_file(g,h)); -#define DELETE(a,b,c) (vm_delete(c)) +#define DELETE(a,b,c,d) (vm_delete(c)) #endif #endif @@ -898,40 +895,25 @@ static int make_dir(char *dest, int len, const char *context, const char *ext, c return snprintf(dest, len, "%s%s/%s/%s", VM_SPOOL_DIR, context, ext, folder); } -#ifdef IMAP_STORAGE -static int make_gsm_file(char *dest, size_t len, char *imapuser, char *dir, int num) +static int make_file(char *dest, const int len, const char *dir, const int num) { - if (mkdir(dir, 01777) && (errno != EEXIST)) { - ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dir, strerror(errno)); - return snprintf(dest, len, "%s/msg%04d", dir, num); - } return snprintf(dest, len, "%s/msg%04d", dir, num); } -static void vm_imap_delete(int msgnum, struct vm_state *vms) +/* same as mkstemp, but return a FILE * */ +static FILE *vm_mkftemp(char *template) { - unsigned long messageNum = 0; - char arg[10]; - - /* find real message number based on msgnum */ - /* this may be an index into vms->msgArray based on the msgnum. */ - - messageNum = vms->msgArray[msgnum]; - if (messageNum == 0) { - ast_log(LOG_WARNING, "msgnum %d, mailbox message %lu is zero.\n",msgnum,messageNum); - return; + FILE *p = NULL; + int pfd = mkstemp(template); + chmod(template, VOICEMAIL_FILE_MODE & ~my_umask); + if (pfd > -1) { + p = fdopen(pfd, "w+"); + if (!p) { + close(pfd); + pfd = -1; + } } - if (option_debug > 2) - ast_log(LOG_DEBUG, "deleting msgnum %d, which is mailbox message %lu\n",msgnum,messageNum); - /* delete message */ - snprintf (arg, sizeof(arg), "%lu",messageNum); - mail_setflag (vms->mailstream,arg,"\\DELETED"); -} - -#endif -static int make_file(char *dest, int len, char *dir, int num) -{ - return snprintf(dest, len, "%s/msg%04d", dir, num); + return p; } /*! \brief basically mkdir -p $dest/$context/$ext/$folder @@ -970,6 +952,1161 @@ static int create_dirpath(char *dest, int len, const char *context, const char * return 0; } +static const char *mbox(int id) +{ + static const char *msgs[] = { + "INBOX", + "Old", + "Work", + "Family", + "Friends", + "Cust1", + "Cust2", + "Cust3", + "Cust4", + "Cust5", + }; + return (id >= 0 && id < (sizeof(msgs)/sizeof(msgs[0]))) ? msgs[id] : "tmp"; +} + +static void free_user(struct ast_vm_user *vmu) +{ + if (ast_test_flag(vmu, VM_ALLOCED)) + free(vmu); +} + +/* All IMAP-specific functions should go in this block. This + * keeps them from being spread out all over the code */ +#ifdef IMAP_STORAGE +static void vm_imap_delete(int msgnum, struct ast_vm_user *vmu) +{ + char arg[10]; + struct vm_state *vms; + unsigned long messageNum; + + /* Greetings aren't stored in IMAP, so we can't delete them there */ + if (msgnum < 0) { + return; + } + + if (!(vms = get_vm_state_by_mailbox(vmu->mailbox, 1)) && !(vms = get_vm_state_by_mailbox(vmu->mailbox, 0))) { + ast_log(LOG_WARNING, "Couldn't find a vm_state for mailbox %s. Unable to set \\DELETED flag for message %d\n", vmu->mailbox, msgnum); + return; + } + + /* find real message number based on msgnum */ + /* this may be an index into vms->msgArray based on the msgnum. */ + messageNum = vms->msgArray[msgnum]; + if (messageNum == 0) { + 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); + /* delete message */ + snprintf (arg, sizeof(arg), "%lu",messageNum); + mail_setflag (vms->mailstream,arg,"\\DELETED"); +} + +static int imap_retrieve_file(const char *dir, const int msgnum, const struct ast_vm_user *vmu) +{ + BODY *body; + char *header_content; + char *attachedfilefmt; + const char *cid_num; + const char *cid_name; + const char *duration; + const char *context; + const char *category; + const char *origtime; + struct vm_state *vms; + char text_file[PATH_MAX]; + FILE *text_file_ptr; + + /* Greetings are not stored on the IMAP server, so we should not + * attempt to retrieve them. + */ + if (msgnum < 0) { + return 0; + } + + /* Before anything can happen, we need a vm_state so that we can + * actually access the imap server through the vms->mailstream + */ + if(!(vms = get_vm_state_by_mailbox(vmu->mailbox, 1)) && !(vms = get_vm_state_by_mailbox(vmu->mailbox, 0))) { + /* This should not happen. If it does, then I guess we'd + * need to create the vm_state, extract which mailbox to + * open, and then set up the msgArray so that the correct + * IMAP message could be accessed. If I have seen correctly + * though, the vms should be obtainable from the vmstates list + * and should have its msgArray properly set up. + */ + ast_log(LOG_ERROR, "Couldn't find a vm_state for mailbox %s!!! Oh no!\n", vmu->mailbox); + } + + make_file(vms->fn, sizeof(vms->fn), dir, msgnum); + + /* Don't try to retrieve a message from IMAP if it already is on the file system */ + if (ast_fileexists(vms->fn, NULL, NULL) > 0) { + return 0; + } + + if (option_debug > 2) + ast_log (LOG_DEBUG,"Before mail_fetchheaders, curmsg is: %d, imap messages is %lu\n", msgnum, vms->msgArray[msgnum]); + if (vms->msgArray[msgnum] == 0) { + ast_log (LOG_WARNING,"Trying to access unknown message\n"); + return -1; + } + + /* This will only work for new messages... */ + header_content = mail_fetchheader (vms->mailstream, vms->msgArray[msgnum]); + /* 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[msgnum]); + return -1; + } + + mail_fetchstructure (vms->mailstream,vms->msgArray[msgnum],&body); + + /* We have the body, now we extract the file name of the first attachment. */ + if (body->nested.part && 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); + + /* Get info from headers!! */ + snprintf(text_file, sizeof(text_file), "%s.%s", vms->fn, "txt"); + + if (!(text_file_ptr = fopen(text_file, "w"))) { + ast_log(LOG_WARNING, "Unable to open/create file %s: %s\n", text_file, strerror(errno)); + } + + fprintf(text_file_ptr, "%s\n", "[message]"); + + cid_num = get_header_by_tag(header_content, "X-Asterisk-VM-Caller-ID-Num:"); + cid_name = get_header_by_tag(header_content, "X-Asterisk-VM-Caller-ID-Name:"); + fprintf(text_file_ptr, "callerid=\"%s\" <%s>\n", S_OR(cid_name, ""), S_OR(cid_num, "")); + context = get_header_by_tag(header_content, "X-Asterisk-VM-Context:"); + fprintf(text_file_ptr, "context=%s\n", S_OR(context, "")); + origtime = get_header_by_tag(header_content, "X-Asterisk-VM-Orig-time:"); + fprintf(text_file_ptr, "origtime=%s\n", S_OR(origtime, "")); + duration = get_header_by_tag(header_content, "X-Asterisk-VM-Duration:"); + fprintf(text_file_ptr, "duration=%s\n", S_OR(origtime, "")); + category = get_header_by_tag(header_content, "X-Asterisk-VM-Category:"); + fprintf(text_file_ptr, "category=%s\n", S_OR(category, "")); + + fclose(text_file_ptr); + return 0; +} + +static int folder_int(const char *folder) +{ + /*assume a NULL folder means INBOX*/ + if (!folder) + return 0; + if (!strcasecmp(folder, "INBOX")) + return 0; + else if (!strcasecmp(folder, "Old")) + return 1; + else if (!strcasecmp(folder, "Work")) + return 2; + else if (!strcasecmp(folder, "Family")) + return 3; + else if (!strcasecmp(folder, "Friends")) + return 4; + else if (!strcasecmp(folder, "Cust1")) + return 5; + else if (!strcasecmp(folder, "Cust2")) + return 6; + else if (!strcasecmp(folder, "Cust3")) + return 7; + else if (!strcasecmp(folder, "Cust4")) + return 8; + else if (!strcasecmp(folder, "Cust5")) + return 9; + else /*assume they meant INBOX if folder is not found otherwise*/ + return 0; +} + +static int messagecount(const char *context, const char *mailbox, const char *folder) +{ + SEARCHPGM *pgm; + SEARCHHEADER *hdr; + + struct ast_vm_user *vmu, vmus; + struct vm_state *vms_p; + int ret = 0; + int fold = folder_int(folder); + + if (ast_strlen_zero(mailbox)) + return 0; + + /* 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(&vmus, context, mailbox); + if (!vmu) { + ast_log (LOG_ERROR,"Couldn't find mailbox %s in context %s\n",mailbox,context); + return -1; + } else { + /* No IMAP account available */ + if (vmu->imapuser[0] == '\0') { + ast_log (LOG_WARNING,"IMAP user not set for mailbox %s\n",vmu->mailbox); + return -1; + } + } + + /* 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(mailbox,1); + } + if (vms_p) { + if (option_debug > 2) + ast_log (LOG_DEBUG,"Returning before search - user is logged in\n"); + if (fold == 0) {/*INBOX*/ + return vms_p->newmessages; + } + if (fold == 1) {/*Old messages*/ + return vms_p->oldmessages; + } + } + + /* 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(mailbox,0); + } + + if (!vms_p) { + if (!(vms_p = create_vm_state_from_user(vmu))) { + ast_log(LOG_WARNING, "Unable to allocate space for new vm_state!\n"); + return -1; + } + } + ret = init_mailstream(vms_p, fold); + if (!vms_p->mailstream) { + ast_log (LOG_ERROR,"IMAP mailstream is NULL\n"); + return -1; + } + if (ret == 0) { + pgm = mail_newsearchpgm (); + hdr = mail_newsearchheader ("X-Asterisk-VM-Extension", (char *)mailbox); + pgm->header = hdr; + if (fold != 1) { + pgm->unseen = 1; + pgm->seen = 0; + } + /* In the special case where fold is 1 (old messages) we have to do things a bit + * differently. Old messages are stored in the INBOX but are marked as "seen" + */ + else { + 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); + if (fold == 0) + vms_p->newmessages = vms_p->vmArrayIndex; + if (fold == 1) + vms_p->oldmessages = vms_p->vmArrayIndex; + /*Freeing the searchpgm also frees the searchhdr*/ + mail_free_searchpgm(&pgm); + vms_p->updated = 0; + return vms_p->vmArrayIndex; + } else { + mail_ping(vms_p->mailstream); + } + return 0; +} + +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[PATH_MAX]; + char mailbox[256]; + char *stringp; + FILE *p=NULL; + char tmp[80] = "/tmp/astmail-XXXXXX"; + long len; + void *buf; + int tempcopy = 0; + STRING str; + + /*Greetings are not retrieved from IMAP, so there is no reason to attempt storing them there either*/ + if (msgnum < 0) + return 0; + + /* 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)) { + /*we need the vmu->email to be set when we call make_email_file, but if we keep it set, + * a duplicate e-mail will be created. So at the end of this function, we will revert back to an empty + * string if tempcopy is 1 + */ + ast_copy_string(vmu->email, vmu->imapuser, sizeof(vmu->email)); + tempcopy = 1; + } + + 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); + if (tempcopy) + *(vmu->email) = '\0'; + 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); + fclose(p); + 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, sizeof(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); + /* Using messagecount to populate the last place in the msgArray + * is less than optimal, but it's the only way given the current setup + */ + messagecount(vmu->context, vmu->mailbox, "INBOX"); + } + if (tempcopy) + *(vmu->email) = '\0'; + return 0; + +} + +static int inboxcount(const char *mailbox_context, int *newmsgs, int *oldmsgs) +{ + char tmp[PATH_MAX] = ""; + char *mailboxnc; + char *context; + char *mb; + char *cur; + if (newmsgs) + *newmsgs = 0; + if (oldmsgs) + *oldmsgs = 0; + + if (option_debug > 2) + ast_log (LOG_DEBUG,"Mailbox is set to %s\n",mailbox_context); + /* If no mailbox, return immediately */ + if (ast_strlen_zero(mailbox_context)) + return 0; + + ast_copy_string(tmp, mailbox_context, sizeof(tmp)); + context = strchr(tmp, '@'); + if (strchr(mailbox_context, ',')) { + int tmpnew, tmpold; + ast_copy_string(tmp, mailbox_context, sizeof(tmp)); + mb = tmp; + while ((cur = strsep(&mb, ", "))) { + if (!ast_strlen_zero(cur)) { + if (inboxcount(cur, newmsgs ? &tmpnew : NULL, oldmsgs ? &tmpold : NULL)) + return -1; + else { + if (newmsgs) + *newmsgs += tmpnew; + if (oldmsgs) + *oldmsgs += tmpold; + } + } + } + return 0; + } + if (context) { + *context = '\0'; + mailboxnc = tmp; + context++; + } else { + context = "default"; + mailboxnc = (char *)mailbox_context; + } + if (newmsgs) { + if ((*newmsgs = messagecount(context, mailboxnc, "INBOX")) < 0) + return -1; + } + if (oldmsgs) { + if ((*oldmsgs = messagecount(context, mailboxnc, "Old")) < 0) + return -1; + } + return 0; +} + + +static int has_voicemail(const char *mailbox, const char *folder) +{ + char tmp[256], *tmp2, *mbox, *context; + ast_copy_string(tmp, mailbox, sizeof(tmp)); + tmp2 = tmp; + if (strchr(tmp2, ',')) { + while ((mbox = strsep(&tmp2, ","))) { + if (!ast_strlen_zero(mbox)) { + if (has_voicemail(mbox, folder)) + return 1; + } + } + } + if ((context= strchr(tmp, '@'))) + *context++ = '\0'; + else + context = "default"; + return messagecount(context, tmp, folder) ? 1 : 0; +} + +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, char *dir) +{ + struct vm_state *sendvms = NULL, *destvms = NULL; + char messagestring[10]; /*I guess this could be a problem if someone has more than 999999999 messages...*/ + if (msgnum >= recip->maxmsg) { + ast_log(LOG_WARNING, "Unable to copy mail, mailbox %s is full\n", recip->mailbox); + return -1; + } + if (!(sendvms = get_vm_state_by_imapuser(vmu->imapuser, 0))) { + ast_log(LOG_ERROR, "Couldn't get vm_state for originator's mailbox!!\n"); + return -1; + } + if (!(destvms = get_vm_state_by_imapuser(recip->imapuser, 0))) { + ast_log(LOG_ERROR, "Couldn't get vm_state for destination mailbox!\n"); + return -1; + } + snprintf(messagestring, sizeof(messagestring), "%ld", sendvms->msgArray[msgnum]); + if ((mail_copy(sendvms->mailstream, messagestring, (char *) mbox(imbox)) == T)) + return 0; + ast_log(LOG_WARNING, "Unable to copy message from mailbox %s to mailbox %s\n", vmu->mailbox, recip->mailbox); + return -1; +} + +static void imap_mailbox_name(char *spec, size_t len, struct vm_state *vms, int box, int use_folder) +{ + char tmp[256], *t = tmp; + size_t left = sizeof(tmp); + + if (box == 1) { + ast_copy_string(vms->curbox, mbox(0), sizeof(vms->curbox)); + snprintf(vms->vmbox, sizeof(vms->vmbox), "vm-%s", mbox(1)); + } else { + ast_copy_string(vms->curbox, mbox(box), sizeof(vms->curbox)); + snprintf(vms->vmbox, sizeof(vms->vmbox), "vm-%s", vms->curbox); + } + + /* 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) + snprintf(spec, len, "%s%s", tmp, use_folder? imapfolder: "INBOX"); + else + snprintf(spec, len, "%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[256]; + + 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) { + if (option_debug) + 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; +#ifdef USE_SYSTEM_IMAP +#include <imap/linkage.c> +#elif defined(USE_SYSTEM_CCLIENT) +#include <c-client/linkage.c> +#else +#include "linkage.c" +#endif + /* Connect to INBOX first to get folders delimiter */ + imap_mailbox_name(tmp, sizeof(tmp), vms, 0, 1); + ast_mutex_lock(&vms->lock); + stream = mail_open (stream, tmp, debug ? OP_DEBUG : NIL); + ast_mutex_unlock(&vms->lock); + if (stream == NIL) { + ast_log (LOG_ERROR, "Can't connect to imap server %s\n", tmp); + return -1; + } + 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, sizeof(tmp), vms, box, 1); + if (option_debug > 2) + ast_log (LOG_DEBUG,"Before mail_open, server: %s, box:%d\n", tmp, box); + ast_mutex_lock(&vms->lock); + vms->mailstream = mail_open (stream, tmp, debug ? OP_DEBUG : NIL); + ast_mutex_unlock(&vms->lock); + 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; + + 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_log (LOG_ERROR,"Could not initialize mailstream\n"); + return -1; + } + + create_dirpath(vms->curdir, sizeof(vms->curdir), vmu->context, vms->username, vms->curbox); + + /* Check Quota */ + if (box == 0) { + if (option_debug > 2) + ast_log(LOG_DEBUG, "Mailbox name set to: %s, about to check quotas\n", mbox(box)); + check_quota(vms,(char *)mbox(box)); + } + + pgm = mail_newsearchpgm(); + + /* Check IMAP folder for Asterisk messages only... */ + hdr = mail_newsearchheader ("X-Asterisk-VM-Extension", vmu->mailbox); + pgm->header = hdr; + pgm->deleted = 0; + pgm->undeleted = 1; + + /* if box = 0, check for new, if box = 1, check for read */ + if (box == 0) { + pgm->unseen = 1; + pgm->seen = 0; + } else if (box == 1) { + pgm->seen = 1; + pgm->unseen = 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); + + vms->lastmsg = vms->vmArrayIndex - 1; + + mail_free_searchpgm(&pgm); + return 0; +} + +static void write_file(char *filename, char *buffer, unsigned long len) +{ + FILE *output; + + output = fopen (filename, "w"); + fwrite (buffer, len, 1, output); + fclose (output); +} + +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"); + } +} + +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 { + free(vmu); + return NULL; + } +} + +/* 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); + if (number == 0) return; + set_update(stream); +} + + +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); + if (number == 0) return; + set_update(stream); +} + + +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); + if (number == 0) return; + set_update(stream); +} + + +void mm_notify(MAILSTREAM * stream, char *string, long errflg) +{ + mm_log (string, errflg); +} + + +void mm_list(MAILSTREAM * stream, int delim, char *mailbox, long attributes) +{ + if (delimiter == '\0') { + delimiter = delim; + } + 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"); + } +} + + +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"); + } +} + + +void mm_status(MAILSTREAM * stream, char *mailbox, MAILSTATUS * status) +{ + ast_log (LOG_NOTICE," Mailbox %s", mailbox); + if (status->flags & SA_MESSAGES) + ast_log (LOG_NOTICE,", %lu messages", status->messages); + if (status->flags & SA_RECENT) + ast_log (LOG_NOTICE,", %lu recent", status->recent); + if (status->flags & SA_UNSEEN) + ast_log (LOG_NOTICE,", %lu unseen", status->unseen); + if (status->flags & SA_UIDVALIDITY) + ast_log (LOG_NOTICE,", %lu UID validity", status->uidvalidity); + if (status->flags & SA_UIDNEXT) + ast_log (LOG_NOTICE,", %lu next UID", status->uidnext); + ast_log (LOG_NOTICE,"\n"); +} + + +void mm_log(char *string, long errflg) +{ + switch ((short) errflg) { + case NIL: + if (option_debug) + ast_log(LOG_DEBUG,"IMAP Info: %s\n", string); + break; + case PARSE: + case WARN: + ast_log (LOG_WARNING,"IMAP Warning: %s\n", string); + break; + case ERROR: + ast_log (LOG_ERROR,"IMAP Error: %s\n", string); + break; + } +} + + +void mm_dlog(char *string) +{ + ast_log (LOG_NOTICE, "%s\n", string); +} + + +void mm_login(NETMBX * mb, char *user, char *pwd, long trial) +{ + struct ast_vm_user *vmu; + + if (option_debug > 3) + ast_log(LOG_DEBUG, "Entering callback mm_login\n"); + + ast_copy_string(user, mb->user, MAILTMPLEN); + + /* We should only do this when necessary */ + if (!ast_strlen_zero(authpassword)) { + ast_copy_string(pwd, authpassword, MAILTMPLEN); + } else { + AST_LIST_TRAVERSE(&users, vmu, list) { + if (!strcasecmp(mb->user, vmu->imapuser)) { + ast_copy_string(pwd, vmu->imappassword, MAILTMPLEN); + break; + } + } + if (!vmu) { + if ((vmu = find_user_realtime_imapuser(mb->user))) { + ast_copy_string(pwd, vmu->imappassword, MAILTMPLEN); + free_user(vmu); + } + } + } +} + + +void mm_critical(MAILSTREAM * stream) +{ +} + + +void mm_nocritical(MAILSTREAM * stream) +{ +} + + +long mm_diskerror(MAILSTREAM * stream, long errcode, long serious) +{ + kill (getpid (), SIGSTOP); + return NIL; +} + + +void mm_fatal(char *string) +{ + ast_log(LOG_ERROR,"IMAP access FATAL error: %s\n", string); +} + +/* C-client callback to handle quota */ +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; + + while (pquota) { + usage = pquota->usage; + limit = pquota->limit; + 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"); + } +} + +static char *get_header_by_tag(char *header, char *tag) +{ + char *start; + int taglen; + char *eol_pnt; + + if (!header || !tag) + return NULL; + + taglen = strlen(tag) + 1; + if (taglen < 1) + return NULL; + + start = strstr(header, tag); + if (!start) + return NULL; + + ast_mutex_lock(&imaptemp_lock); + ast_copy_string(imaptemp, start+taglen, sizeof(imaptemp)); + ast_mutex_unlock(&imaptemp_lock); + if ((eol_pnt = strchr(imaptemp,'\r')) || (eol_pnt = strchr(imaptemp,'\n'))) + *eol_pnt = '\0'; + return imaptemp; +} + +static char *get_user_by_mailbox(char *mailbox) +{ + char *start, *quote; + char *eol_pnt; + + if (!mailbox) + return NULL; + + start = strstr(mailbox,"/user="); + if (!start) + return NULL; + + ast_mutex_lock(&imaptemp_lock); + ast_copy_string(imaptemp, start+6, sizeof(imaptemp)); + ast_mutex_unlock(&imaptemp_lock); + + quote = strchr(imaptemp,'\"'); + if (!quote) { /* if username is not in quotes */ + eol_pnt = strchr(imaptemp,'/'); + if (!eol_pnt) { + eol_pnt = strchr(imaptemp,'}'); + } + *eol_pnt = '\0'; + return imaptemp; + } else { + eol_pnt = strchr(imaptemp+1,'\"'); + *eol_pnt = '\0'; + return imaptemp+1; + } +} + +static struct vm_state *create_vm_state_from_user(struct ast_vm_user *vmu) +{ + struct vm_state *vms_p; + + if (option_debug > 4) + ast_log(LOG_DEBUG,"Adding new vmstate for %s\n",vmu->imapuser); + if (!(vms_p = ast_calloc(1, sizeof(*vms_p)))) + return NULL; + ast_copy_string(vms_p->imapuser,vmu->imapuser, sizeof(vms_p->imapuser)); + ast_copy_string(vms_p->username, vmu->mailbox, 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 > 4) + ast_log(LOG_DEBUG,"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); + return vms_p; +} + +static struct vm_state *get_vm_state_by_imapuser(char *user, int interactive) +{ + struct vmstate *vlist = NULL; + + ast_mutex_lock(&vmstate_lock); + vlist = vmstates; + while (vlist) { + if (vlist->vms) { + if (vlist->vms->imapuser) { + if (!strcmp(vlist->vms->imapuser,user)) { + if (interactive == 2) { + ast_mutex_unlock(&vmstate_lock); + return vlist->vms; + } else if (vlist->vms->interactive == interactive) { + ast_mutex_unlock(&vmstate_lock); + return vlist->vms; + } + } + } else { + if (option_debug > 2) + ast_log(LOG_DEBUG, " error: imapuser is NULL for %s\n",user); + } + } else { + if (option_debug > 2) + ast_log(LOG_DEBUG, " error: vms is NULL for %s\n",user); + } + vlist = vlist->next; + } + ast_mutex_unlock(&vmstate_lock); + if (option_debug > 2) + ast_log(LOG_DEBUG, "%s not found in vmstates\n",user); + return NULL; +} + +static struct vm_state *get_vm_state_by_mailbox(const char *mailbox, int interactive) +{ + struct vmstate *vlist = NULL; + + ast_mutex_lock(&vmstate_lock); + vlist = vmstates; + if (option_debug > 2) + ast_log(LOG_DEBUG, "Mailbox set to %s\n",mailbox); + while (vlist) { + if (vlist->vms) { + if (vlist->vms->username) { + if (option_debug > 2) + ast_log(LOG_DEBUG, " comparing mailbox %s (i=%d) to vmstate mailbox %s (i=%d)\n",mailbox,interactive,vlist->vms->username,vlist->vms->interactive); + if (!strcmp(vlist->vms->username,mailbox) && vlist->vms->interactive == interactive) { + if (option_debug > 2) + ast_log(LOG_DEBUG, " Found it!\n"); + ast_mutex_unlock(&vmstate_lock); + return vlist->vms; + } + } else { + if (option_debug > 2) + ast_log(LOG_DEBUG, " error: username is NULL for %s\n",mailbox); + } + } else { + if (option_debug > 2) + ast_log(LOG_DEBUG, " error: vms is NULL for %s\n",mailbox); + } + vlist = vlist->next; + } + ast_mutex_unlock(&vmstate_lock); + if (option_debug > 2) + ast_log(LOG_DEBUG, "%s not found in vmstates\n",mailbox); + return NULL; +} + +static void vmstate_insert(struct vm_state *vms) +{ + struct vmstate *v; + struct vm_state *altvms; + + /* If interactive, it probably already exists, and we should + use the one we already have since it is more up to date. + We can compare the username to find the duplicate */ + if (vms->interactive == 1) { + altvms = get_vm_state_by_mailbox(vms->username,0); + if (altvms) { + if (option_debug > 2) + ast_log(LOG_DEBUG, "Duplicate mailbox %s, copying message info...\n",vms->username); + vms->newmessages = altvms->newmessages; + vms->oldmessages = altvms->oldmessages; + /* memcpy(vms->msgArray, altvms->msgArray, sizeof(long)*256); */ + copy_msgArray(vms, altvms); + vms->vmArrayIndex = altvms->vmArrayIndex; + vms->lastmsg = altvms->lastmsg; + vms->curmsg = altvms->curmsg; + /* get a pointer to the persistent store */ + vms->persist_vms = altvms; + /* Reuse the mailstream? */ + vms->mailstream = altvms->mailstream; + /* vms->mailstream = NIL; */ + } + } + + v = (struct vmstate *)malloc(sizeof(struct vmstate)); + if (!v) { + ast_log(LOG_ERROR, "Out of memory\n"); + } + if (option_debug > 2) + ast_log(LOG_DEBUG, "Inserting vm_state for user:%s, mailbox %s\n",vms->imapuser,vms->username); + ast_mutex_lock(&vmstate_lock); + v->vms = vms; + v->next = vmstates; + vmstates = v; + ast_mutex_unlock(&vmstate_lock); +} + +static void vmstate_delete(struct vm_state *vms) +{ + struct vmstate *vc, *vf = NULL, *vl = NULL; + struct vm_state *altvms; + + /* If interactive, we should copy pertainent info + back to the persistent state (to make update immediate) */ + if (vms->interactive == 1) { + altvms = vms->persist_vms; + if (altvms) { + if (option_debug > 2) + ast_log(LOG_DEBUG, "Duplicate mailbox %s, copying message info...\n",vms->username); + altvms->newmessages = vms->newmessages; + altvms->oldmessages = vms->oldmessages; + altvms->updated = 1; + } + } + + ast_mutex_lock(&vmstate_lock); + vc = vmstates; + if (option_debug > 2) + ast_log(LOG_DEBUG, "Removing vm_state for user:%s, mailbox %s\n",vms->imapuser,vms->username); + while (vc) { + if (vc->vms == vms) { + vf = vc; + if (vl) + vl->next = vc->next; + else + vmstates = vc->next; + break; + } + vl = vc; + vc = vc->next; + } + if (!vf) { + ast_log(LOG_ERROR, "No vmstate found for user:%s, mailbox %s\n",vms->imapuser,vms->username); + } else { + ast_mutex_destroy(&vf->vms->lock); + free(vf); + } + ast_mutex_unlock(&vmstate_lock); +} + +static void set_update(MAILSTREAM * stream) +{ + struct vm_state *vms; + char *mailbox; + char *user; + + mailbox = stream->mailbox; + user = get_user_by_mailbox(mailbox); + vms = get_vm_state_by_imapuser(user, 0); + if (vms) { + if (option_debug > 2) + ast_log (LOG_DEBUG, "User %s mailbox set for update.\n",user); + vms->updated = 1; /* set updated flag since mailbox changed */ + } else { + if (option_debug > 2) + ast_log (LOG_WARNING, "User %s mailbox not found for update.\n",user); + } +} + +static void init_vm_state(struct vm_state *vms) +{ + int x; + vms->vmArrayIndex = 0; + for (x = 0; x < 256; x++) { + vms->msgArray[x] = 0; + } + ast_mutex_init(&vms->lock); +} + +static void copy_msgArray(struct vm_state *dst, struct vm_state *src) +{ + int x; + for (x = 0; x<256; x++) { + dst->msgArray[x] = src->msgArray[x]; + } +} + +static int save_body(BODY *body, struct vm_state *vms, char *section, char *format) +{ + char *body_content; + char *body_decoded; + unsigned long len; + unsigned long newlen; + char filename[256]; + + if (!body || body == NIL) + return -1; + body_content = mail_fetchbody (vms->mailstream, vms->msgArray[vms->curmsg], section, &len); + if (body_content != NIL) { + snprintf(filename, sizeof(filename), "%s.%s", vms->fn, format); + /* ast_log (LOG_DEBUG,body_content); */ + body_decoded = rfc822_base64 ((unsigned char *)body_content, len, &newlen); + write_file (filename, (char *) body_decoded, newlen); + } + return 0; +} + +/* get delimiter via mm_list callback */ +static void get_mailbox_delimiter(MAILSTREAM *stream) { + char tmp[50]; + snprintf(tmp, sizeof(tmp), "{%s}", imapserver); + mail_list(stream, tmp, "*"); +} + +/* Check Quota for user */ +static void check_quota(struct vm_state *vms, char *mailbox) { + mail_parameters(NULL, SET_QUOTA, (void *) mm_parsequota); + if (option_debug > 2) + ast_log(LOG_DEBUG, "Mailbox name set to: %s, about to check quotas\n", mailbox); + if (vms && vms->mailstream != NULL) { + imap_getquotaroot(vms->mailstream, mailbox); + } else { + ast_log(LOG_WARNING,"Mailstream not available for mailbox: %s\n",mailbox); + } +} +#endif + /* only return failure if ast_lock_path returns 'timeout', not if the path does not exist or any other reason */ @@ -1171,23 +2308,6 @@ yuck: return x - 1; } -static int remove_file(char *dir, int msgnum) -{ - char fn[PATH_MAX]; - char full_fn[PATH_MAX]; - char msgnums[80]; - - if (msgnum > -1) { - snprintf(msgnums, sizeof(msgnums), "%d", msgnum); - make_file(fn, sizeof(fn), dir, msgnum); - } else - ast_copy_string(fn, dir, sizeof(fn)); - ast_filedelete(fn, NULL); - snprintf(full_fn, sizeof(full_fn), "%s.txt", fn); - unlink(full_fn); - return 0; -} - static int last_message_index(struct ast_vm_user *vmu, char *dir) { int x = 0; @@ -1571,6 +2691,24 @@ static int last_message_index(struct ast_vm_user *vmu, char *dir) } #endif #endif +#if (defined(IMAP_STORAGE) || defined(ODBC_STORAGE)) +static int remove_file(char *dir, int msgnum) +{ + char fn[PATH_MAX]; + char full_fn[PATH_MAX]; + char msgnums[80]; + + if (msgnum > -1) { + snprintf(msgnums, sizeof(msgnums), "%d", msgnum); + make_file(fn, sizeof(fn), dir, msgnum); + } else + ast_copy_string(fn, dir, sizeof(fn)); + ast_filedelete(fn, NULL); + snprintf(full_fn, sizeof(full_fn), "%s.txt", fn); + unlink(full_fn); + return 0; +} +#endif static int copy(char *infile, char *outfile) { @@ -1822,22 +2960,6 @@ static const struct tm *vmu_tm(const struct ast_vm_user *vmu, struct tm *tm) return tm; } -/* same as mkstemp, but return a FILE * */ -static FILE *vm_mkftemp(char *template) -{ - FILE *p = NULL; - int pfd = mkstemp(template); - chmod(template, VOICEMAIL_FILE_MODE & ~my_umask); - if (pfd > -1) { - p = fdopen(pfd, "w+"); - if (!p) { - close(pfd); - pfd = -1; - } - } - return p; -} - 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) { char date[256]; @@ -2157,7 +3279,7 @@ static int play_greeting(struct ast_channel *chan, struct ast_vm_user *vmu, char #ifdef ODBC_STORAGE int success = #endif - RETRIEVE(filename, -1); + RETRIEVE(filename, -1, vmu); if (ast_fileexists(filename, NULL, NULL) > 0) { res = ast_streamfile(chan, filename, chan->language); if (res > -1) @@ -2205,64 +3327,11 @@ static int invent_message(struct ast_channel *chan, struct ast_vm_user *vmu, cha return res; } -static void free_user(struct ast_vm_user *vmu) -{ - if (ast_test_flag(vmu, VM_ALLOCED)) - free(vmu); -} - static void free_zone(struct vm_zone *z) { free(z); } -static const char *mbox(int id) -{ - static const char *msgs[] = { - "INBOX", - "Old", - "Work", - "Family", - "Friends", - "Cust1", - "Cust2", - "Cust3", - "Cust4", - "Cust5", - }; - return (id >= 0 && id < (sizeof(msgs)/sizeof(msgs[0]))) ? msgs[id] : "tmp"; -} -#ifdef IMAP_STORAGE -static int folder_int(const char *folder) -{ - /*assume a NULL folder means INBOX*/ - if (!folder) - return 0; - if (!strcasecmp(folder, "INBOX")) - return 0; - else if (!strcasecmp(folder, "Old")) - return 1; - else if (!strcasecmp(folder, "Work")) - return 2; - else if (!strcasecmp(folder, "Family")) - return 3; - else if (!strcasecmp(folder, "Friends")) - return 4; - else if (!strcasecmp(folder, "Cust1")) - return 5; - else if (!strcasecmp(folder, "Cust2")) - return 6; - else if (!strcasecmp(folder, "Cust3")) - return 7; - else if (!strcasecmp(folder, "Cust4")) - return 8; - else if (!strcasecmp(folder, "Cust5")) - return 9; - else /*assume they meant INBOX if folder is not found otherwise*/ - return 0; -} -#endif - #ifdef ODBC_STORAGE /*! XXX \todo Fix this function to support multiple mailboxes in the intput string */ static int inboxcount(const char *mailbox, int *newmsgs, int *oldmsgs) @@ -2412,290 +3481,6 @@ static int has_voicemail(const char *mailbox, const char *folder) } return 0; } - -#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[PATH_MAX]; - char mailbox[256]; - char *stringp; - FILE *p=NULL; - char tmp[80] = "/tmp/astmail-XXXXXX"; - long len; - void *buf; - int tempcopy = 0; - STRING str; - - /*Greetings are not retrieved from IMAP, so there is no reason to attempt storing them there either*/ - if (msgnum < 0) - return 0; - - /* 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)) { - /*we need the vmu->email to be set when we call make_email_file, but if we keep it set, - * a duplicate e-mail will be created. So at the end of this function, we will revert back to an empty - * string if tempcopy is 1 - */ - ast_copy_string(vmu->email, vmu->imapuser, sizeof(vmu->email)); - tempcopy = 1; - } - - 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); - if (tempcopy) - *(vmu->email) = '\0'; - 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); - fclose(p); - 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, sizeof(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); - } - if (tempcopy) - *(vmu->email) = '\0'; - return 0; - -} - -static int messagecount(const char *context, const char *mailbox, const char *folder) -{ - SEARCHPGM *pgm; - SEARCHHEADER *hdr; - - struct ast_vm_user *vmu, vmus; - struct vm_state *vms_p; - int ret = 0; - int fold = folder_int(folder); - - if (ast_strlen_zero(mailbox)) - return 0; - - /* 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(&vmus, context, mailbox); - if (!vmu) { - ast_log (LOG_ERROR,"Couldn't find mailbox %s in context %s\n",mailbox,context); - return -1; - } else { - /* No IMAP account available */ - if (vmu->imapuser[0] == '\0') { - ast_log (LOG_WARNING,"IMAP user not set for mailbox %s\n",vmu->mailbox); - return -1; - } - } - - /* 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(mailbox,1); - } - if (vms_p) { - if (option_debug > 2) - ast_log (LOG_DEBUG,"Returning before search - user is logged in\n"); - if (fold == 0) {/*INBOX*/ - return vms_p->newmessages; - } - if (fold == 1) {/*Old messages*/ - return vms_p->oldmessages; - } - } - - /* 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(mailbox,0); - } - - if (!vms_p) { - if (option_debug > 2) - ast_log (LOG_DEBUG,"Adding new vmstate for %s\n",vmu->imapuser); - if (!(vms_p = ast_calloc(1, sizeof(*vms_p)))) { - return -1; - } - ast_copy_string(vms_p->imapuser,vmu->imapuser, sizeof(vms_p->imapuser)); - ast_copy_string(vms_p->username, mailbox, 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; - /* set mailbox to INBOX! */ - ast_copy_string(vms_p->curbox, mbox(fold), sizeof(vms_p->curbox)); - init_vm_state(vms_p); - vmstate_insert(vms_p); - } - ret = init_mailstream(vms_p, fold); - if (!vms_p->mailstream) { - ast_log (LOG_ERROR,"IMAP mailstream is NULL\n"); - return -1; - } - if (ret == 0) { - pgm = mail_newsearchpgm (); - hdr = mail_newsearchheader ("X-Asterisk-VM-Extension", (char *)mailbox); - pgm->header = hdr; - if (fold != 1) { - pgm->unseen = 1; - pgm->seen = 0; - } - /* In the special case where fold is 1 (old messages) we have to do things a bit - * differently. Old messages are stored in the INBOX but are marked as "seen" - */ - else { - 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); - if (fold == 0) - vms_p->newmessages = vms_p->vmArrayIndex; - if (fold == 1) - vms_p->oldmessages = vms_p->vmArrayIndex; - /*Freeing the searchpgm also frees the searchhdr*/ - mail_free_searchpgm(&pgm); - vms_p->updated = 0; - return vms_p->vmArrayIndex; - } else { - mail_ping(vms_p->mailstream); - } - return 0; -} -static int inboxcount(const char *mailbox_context, int *newmsgs, int *oldmsgs) -{ - char tmp[PATH_MAX] = ""; - char *mailboxnc; - char *context; - char *mb; - char *cur; - if (newmsgs) - *newmsgs = 0; - if (oldmsgs) - *oldmsgs = 0; - - if (option_debug > 2) - ast_log (LOG_DEBUG,"Mailbox is set to %s\n",mailbox_context); - /* If no mailbox, return immediately */ - if (ast_strlen_zero(mailbox_context)) - return 0; - - ast_copy_string(tmp, mailbox_context, sizeof(tmp)); - context = strchr(tmp, '@'); - if (strchr(mailbox_context, ',')) { - int tmpnew, tmpold; - ast_copy_string(tmp, mailbox_context, sizeof(tmp)); - mb = tmp; - while ((cur = strsep(&mb, ", "))) { - if (!ast_strlen_zero(cur)) { - if (inboxcount(cur, newmsgs ? &tmpnew : NULL, oldmsgs ? &tmpold : NULL)) - return -1; - else { - if (newmsgs) - *newmsgs += tmpnew; - if (oldmsgs) - *oldmsgs += tmpold; - } - } - } - return 0; - } - if (context) { - *context = '\0'; - mailboxnc = tmp; - context++; - } else { - context = "default"; - mailboxnc = (char *)mailbox_context; - } - if (newmsgs) { - if ((*newmsgs = messagecount(context, mailboxnc, "INBOX")) < 0) - return -1; - } - if (oldmsgs) { - if ((*oldmsgs = messagecount(context, mailboxnc, "Old")) < 0) - return -1; - } - return 0; -} - - -static int has_voicemail(const char *mailbox, const char *folder) -{ - char tmp[256], *tmp2, *mbox, *context; - ast_copy_string(tmp, mailbox, sizeof(tmp)); - tmp2 = tmp; - if (strchr(tmp2, ',')) { - while ((mbox = strsep(&tmp2, ","))) { - if (!ast_strlen_zero(mbox)) { - if (has_voicemail(mbox, folder)) - return 1; - } - } - } - if ((context= strchr(tmp, '@'))) - *context++ = '\0'; - else - context = "default"; - return messagecount(context, tmp, folder) ? 1 : 0; -} - -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, char *dir) -{ - struct vm_state *sendvms = NULL, *destvms = NULL; - char messagestring[10]; /*I guess this could be a problem if someone has more than 999999999 messages...*/ - if (msgnum >= recip->maxmsg) { - ast_log(LOG_WARNING, "Unable to copy mail, mailbox %s is full\n", recip->mailbox); - return -1; - } - if (!(sendvms = get_vm_state_by_imapuser(vmu->imapuser, 0))) { - ast_log(LOG_ERROR, "Couldn't get vm_state for originator's mailbox!!\n"); - return -1; - } - if (!(destvms = get_vm_state_by_imapuser(recip->imapuser, 0))) { - ast_log(LOG_ERROR, "Couldn't get vm_state for destination mailbox!\n"); - return -1; - } - snprintf(messagestring, sizeof(messagestring), "%ld", sendvms->msgArray[msgnum]); - if ((mail_copy(sendvms->mailstream, messagestring, (char *) mbox(imbox)) == T)) - return 0; - ast_log(LOG_WARNING, "Unable to copy message from mailbox %s to mailbox %s\n", vmu->mailbox, recip->mailbox); - return -1; -} - #endif #ifndef IMAP_STORAGE /* copy message only used by file storage */ @@ -2890,8 +3675,8 @@ static int leave_voicemail(struct ast_channel *chan, char *ext, struct leave_vm_ { #ifdef IMAP_STORAGE int newmsgs, oldmsgs; - struct vm_state *vms = NULL; #endif + struct vm_state *vms = NULL; char txtfile[PATH_MAX], tmptxtfile[PATH_MAX]; char callerid[256]; FILE *txt; @@ -2958,7 +3743,7 @@ static int leave_voicemail(struct ast_channel *chan, char *ext, struct leave_vm_ ast_log(LOG_WARNING, "Failed to make directory (%s)\n", tempfile); return -1; } - RETRIEVE(tempfile, -1); + RETRIEVE(tempfile, -1, vmu); if (ast_fileexists(tempfile, NULL, NULL) > 0) ast_copy_string(prefile, tempfile, sizeof(prefile)); DISPOSE(tempfile, -1); @@ -3079,20 +3864,10 @@ static int leave_voicemail(struct ast_channel *chan, char *ext, struct leave_vm_ if (!(vms = get_vm_state_by_mailbox(ext,0))) { /*It is possible under certain circumstances that inboxcount did not create a vm_state when it was needed. This is a catchall which will * rarely be used*/ - if (!(vms = ast_calloc(1, sizeof(*vms)))) { + if (!(vms = create_vm_state_from_user(vmu))) { ast_log(LOG_ERROR, "Couldn't allocate necessary space\n"); return -1; } - ast_copy_string(vms->imapuser, vmu->imapuser, sizeof(vms->imapuser)); - ast_copy_string(vms->username, ext, sizeof(vms->username)); - vms->mailstream = NIL; - if (option_debug > 2) - ast_log(LOG_DEBUG, "Copied %s to %s\n", vmu->imapuser, vms->imapuser); - vms->updated=1; - ast_copy_string(vms->curbox, mbox(0), sizeof(vms->curbox)); - init_vm_state(vms); - vmstate_insert(vms); - vms = get_vm_state_by_mailbox(ext,0); } vms->newmessages++; /* here is a big difference! We add one to it later */ @@ -3128,9 +3903,6 @@ static int leave_voicemail(struct ast_channel *chan, char *ext, struct leave_vm_ ast_play_and_wait(chan, "vm-mailboxfull"); return -1; } - /* here is a big difference! We add one to it later */ - if (option_debug > 2) - ast_log(LOG_DEBUG, "Messagecount set to %d\n",msgnum); #else if (count_messages(vmu, dir) >= vmu->maxmsg) { res = ast_streamfile(chan, "vm-mailboxfull", chan->language); @@ -3190,11 +3962,7 @@ static int leave_voicemail(struct ast_channel *chan, char *ext, struct leave_vm_ category ? category : ""); } else ast_log(LOG_WARNING, "Error opening text file for output\n"); -#ifdef IMAP_STORAGE res = play_record_review(chan, NULL, tmptxtfile, vmmaxmessage, fmt, 1, vmu, &duration, NULL, options->record_gain, vms); -#else - res = play_record_review(chan, NULL, tmptxtfile, vmmaxmessage, fmt, 1, vmu, &duration, NULL, options->record_gain, NULL); -#endif if (txt) { if (duration < vmminmessage) { @@ -3327,18 +4095,20 @@ 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? */ - long res; char sequence[10]; - - /* if save to Old folder, just leave in INBOX */ - if (box == 1) return 10; /* get the real IMAP message number for this message */ snprintf(sequence, sizeof(sequence), "%ld", vms->msgArray[msg]); if (option_debug > 2) ast_log(LOG_DEBUG, "Copying sequence %s to mailbox %s\n",sequence,(char *) mbox(box)); - res = mail_copy(vms->mailstream,sequence,(char *) mbox(box)); - if (res == 1) return 0; - return 1; + if (box == 1) { + mail_setflag(vms->mailstream, sequence, "\\Seen"); + } else if (box == 0) { + mail_clearflag(vms->mailstream, sequence, "\\Seen"); + } + if (!strcasecmp(mbox(0), vms->curbox) && (box == 0 || box == 1)) + return 0; + else + return !mail_copy(vms->mailstream,sequence,(char *) mbox(box)); #else char *dir = vms->curdir; char *username = vms->username; @@ -4039,7 +4809,7 @@ static int notify_new_message(struct ast_channel *chan, struct ast_vm_user *vmu, myserveremail = vmu->serveremail; if (attach_user_voicemail) - RETRIEVE(todir, msgnum); + RETRIEVE(todir, msgnum, vmu); /*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); @@ -4056,12 +4826,9 @@ static int notify_new_message(struct ast_channel *chan, struct ast_vm_user *vmu, } if (ast_test_flag(vmu, VM_DELETE)) { - DELETE(todir, msgnum, fn); + DELETE(todir, msgnum, fn, vmu); } -#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); @@ -4074,10 +4841,6 @@ static int notify_new_message(struct ast_channel *chan, struct ast_vm_user *vmu, static int forward_message(struct ast_channel *chan, char *context, struct vm_state *vms, struct ast_vm_user *sender, char *fmt, int flag, signed char record_gain) { #ifdef IMAP_STORAGE - BODY *body; - char *header_content; - char *temp; - char todir[256]; int todircount=0; struct vm_state *dstvms; #endif @@ -4230,7 +4993,7 @@ static int forward_message(struct ast_channel *chan, char *context, struct vm_st create_dirpath(vmstmp.curdir, sizeof(vmstmp.curdir), sender->context, vmstmp.username, "tmp"); make_file(msgfile, sizeof(msgfile), vmstmp.curdir, curmsg); - RETRIEVE(dir, curmsg); + RETRIEVE(dir, curmsg, sender); /* Alter a surrogate file, only */ copy_plain_file(origmsgfile, msgfile); @@ -4241,74 +5004,25 @@ static int forward_message(struct ast_channel *chan, char *context, struct vm_st #ifdef IMAP_STORAGE char *myserveremail; int attach_user_voicemail; - /* 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_log (LOG_WARNING,"Trying to access unknown message\n"); - 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]); - return -1; - } - /* Get header info needed by sendmail */ - temp = get_header_by_tag(header_content, "X-Asterisk-VM-Duration:"); - if (temp) - duration = atoi(temp); - else - duration = 0; - - /* Attach only the first format */ - fmt = ast_strdupa(fmt); - if (fmt) { - stringp = fmt; - strsep(&stringp, "|"); - } else { - ast_log (LOG_ERROR,"audio format not set. Default to WAV\n"); - 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_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, sizeof(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); - /*mail_fetchstructure (mailstream, vmArray[0], &body); */ - mail_fetchstructure (vms->mailstream, vms->msgArray[vms->curmsg], &body); - save_body(body,vms,"3","gsm"); - /* should not assume "fmt" here! */ - save_body(body,vms,"2",fmt); - /* get destination mailbox */ dstvms = get_vm_state_by_mailbox(vmtmp->mailbox,0); if (!dstvms) { - dstvms = create_vm_state_from_user(vmtmp, vmtmp->mailbox); + dstvms = create_vm_state_from_user(vmtmp); } if (dstvms) { init_mailstream(dstvms, 0); if (!dstvms->mailstream) { ast_log (LOG_ERROR,"IMAP mailstream for %s is NULL\n",vmtmp->mailbox); } else { - STORE(todir, vmtmp->mailbox, vmtmp->context, dstvms->curmsg, chan, vmtmp, fmt, duration, dstvms); + STORE(vmstmp.curdir, vmtmp->mailbox, vmtmp->context, dstvms->curmsg, chan, vmtmp, fmt, duration, dstvms); run_externnotify(vmtmp->context, vmtmp->mailbox); } } else { ast_log (LOG_ERROR,"Could not find state information for mailbox %s\n",vmtmp->mailbox); } - myserveremail = serveremail; if (!ast_strlen_zero(vmtmp->serveremail)) myserveremail = vmtmp->serveremail; - 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); @@ -4561,140 +5275,6 @@ static int play_message_duration(struct ast_channel *chan, struct vm_state *vms, return res; } -#ifdef IMAP_STORAGE -static int play_message(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms) -{ - BODY *body; - char *header_content; - char cid[256]; - char context[256]; - char origtime[32]; - char duration[16]; - char category[32]; - char todir[PATH_MAX]; - int res = 0; - char *attachedfilefmt; - char *temp; - - 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_log (LOG_WARNING,"Trying to access unknown message\n"); - 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]); - return -1; - } - snprintf(todir, sizeof(todir), "%s%s/%s/tmp", VM_SPOOL_DIR, vmu->context, vmu->mailbox); - make_gsm_file(vms->fn, sizeof(vms->fn), vms->imapuser, todir, vms->curmsg); - - mail_fetchstructure (vms->mailstream,vms->msgArray[vms->curmsg],&body); - - /* We have the body, now we extract the file name of the first attachment. */ - if (body->nested.part && 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" */ - if (!res) { - res = wait_file2(chan, vms, "vm-message"); /* "message" */ - if (vms->curmsg && (vms->curmsg != vms->lastmsg)) { - if (!res) - res = ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY, chan->language, (char *) NULL); - } - } - - /* Get info from headers!! */ - temp = get_header_by_tag(header_content, "X-Asterisk-VM-Caller-ID-Num:"); - - if (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) - 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) - ast_copy_string(origtime, temp, sizeof(origtime)); - else - origtime[0] = '\0'; - - temp = get_header_by_tag(header_content, "X-Asterisk-VM-Duration:"); - - if (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) - 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 */ - /* context = ast_variable_retrieve(msg_cfg, "message","macrocontext"); */ - if (res == '1') - res = 0; - - if ((!res) && !ast_strlen_zero(category)) { - res = play_message_category(chan, category); - } - - if ((!res) && (ast_test_flag(vmu, VM_ENVELOPE)) && origtime[0] != '\0') - res = play_message_datetime(chan, vmu, origtime, "IMAP_STORAGE"); - if ((!res) && (ast_test_flag(vmu, VM_SAYCID)) && cid[0] !='\0' && context[0] !='\0') - res = play_message_callerid(chan, vms, cid, context, 0); - - if ((!res) && (ast_test_flag(vmu, VM_SAYDURATION)) && duration[0] != '\0') - res = play_message_duration(chan, vms, duration, vmu->saydurationm); - - /* Allow pressing '1' to skip envelope / callerid */ - /* if (res == '1') - res = 0; - */ - /*ast_config_destroy(msg_cfg);*/ - res = 0; - - if (!res) { - vms->heard[vms->curmsg] = 1; - res = wait_file(chan, vms, vms->fn); - } - DISPOSE(vms->curdir, vms->curmsg); - DELETE(0, 0, vms->fn); - return res; -} -#else static int play_message(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms) { int res = 0; @@ -4749,7 +5329,7 @@ static int play_message(struct ast_channel *chan, struct ast_vm_user *vmu, struc /* Retrieve info from VM attribute file */ make_file(vms->fn2, sizeof(vms->fn2), vms->curdir, vms->curmsg); snprintf(filename, sizeof(filename), "%s.txt", vms->fn2); - RETRIEVE(vms->curdir, vms->curmsg); + RETRIEVE(vms->curdir, vms->curmsg, vmu); msg_cfg = ast_config_load(filename); if (!msg_cfg) { ast_log(LOG_WARNING, "No message attribute file?!! (%s)\n", filename); @@ -4794,152 +5374,8 @@ static int play_message(struct ast_channel *chan, struct ast_vm_user *vmu, struc DISPOSE(vms->curdir, vms->curmsg); return res; } -#endif - -#ifdef IMAP_STORAGE -static void imap_mailbox_name(char *spec, size_t len, struct vm_state *vms, int box, int use_folder) -{ - char tmp[256], *t = tmp; - size_t left = sizeof(tmp); - - if (box == 1) { - ast_copy_string(vms->curbox, mbox(0), sizeof(vms->curbox)); - snprintf(vms->vmbox, sizeof(vms->vmbox), "vm-%s", mbox(1)); - } else { - ast_copy_string(vms->curbox, mbox(box), sizeof(vms->curbox)); - snprintf(vms->vmbox, sizeof(vms->vmbox), "vm-%s", vms->curbox); - } - - /* 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) - snprintf(spec, len, "%s%s", tmp, use_folder? imapfolder: "INBOX"); - else - snprintf(spec, len, "%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[256]; - - 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) { - if (option_debug) - 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; -#ifdef USE_SYSTEM_IMAP -#include <imap/linkage.c> -#elif defined(USE_SYSTEM_CCLIENT) -#include <c-client/linkage.c> -#else -#include "linkage.c" -#endif - /* Connect to INBOX first to get folders delimiter */ - imap_mailbox_name(tmp, sizeof(tmp), vms, 0, 1); - ast_mutex_lock(&vms->lock); - stream = mail_open (stream, tmp, debug ? OP_DEBUG : NIL); - ast_mutex_unlock(&vms->lock); - if (stream == NIL) { - ast_log (LOG_ERROR, "Can't connect to imap server %s\n", tmp); - return -1; - } - 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, sizeof(tmp), vms, box, 1); - if (option_debug > 2) - ast_log (LOG_DEBUG,"Before mail_open, server: %s, box:%d\n", tmp, box); - ast_mutex_lock(&vms->lock); - vms->mailstream = mail_open (stream, tmp, debug ? OP_DEBUG : NIL); - ast_mutex_unlock(&vms->lock); - 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; - 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_log (LOG_ERROR,"Could not initialize mailstream\n"); - return -1; - } - - /* Check Quota */ - if (box == 0) { - if (option_debug > 2) - ast_log(LOG_DEBUG, "Mailbox name set to: %s, about to check quotas\n", mbox(box)); - check_quota(vms,(char *)mbox(box)); - } - - pgm = mail_newsearchpgm(); - - /* Check IMAP folder for Asterisk messages only... */ - hdr = mail_newsearchheader ("X-Asterisk-VM-Extension", vmu->mailbox); - pgm->header = hdr; - pgm->deleted = 0; - pgm->undeleted = 1; - - /* if box = 0, check for new, if box = 1, check for read */ - if (box == 0) { - pgm->unseen = 1; - pgm->seen = 0; - } else if (box == 1) { - pgm->seen = 1; - pgm->unseen = 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); - - - vms->lastmsg = vms->vmArrayIndex - 1; - - mail_free_searchpgm(&pgm); - return 0; -} -#else +#ifndef IMAP_STORAGE static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu,int box) { int res = 0; @@ -5028,7 +5464,7 @@ static int close_mailbox(struct vm_state *vms, struct ast_vm_user *vmu) for (x = vms->curmsg + 1; x <= nummsg; x++) { make_file(vms->fn, sizeof(vms->fn), vms->curdir, x); if (EXISTS(vms->curdir, x, vms->fn, NULL)) - DELETE(vms->curdir, x, vms->fn); + DELETE(vms->curdir, x, vms->fn, vmu); } ast_unlock_path(vms->curdir); #else @@ -5037,7 +5473,7 @@ static int close_mailbox(struct vm_state *vms, struct ast_vm_user *vmu) 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); + DELETE(vms->curdir, x, vms->fn, vmu); } } } @@ -6076,11 +6512,7 @@ static int vm_newuser(struct ast_channel *chan, struct ast_vm_user *vmu, struct if (ast_test_flag(vmu, VM_FORCENAME)) { snprintf(prefile,sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, vmu->context, vms->username); if (ast_fileexists(prefile, NULL, NULL) < 1) { -#ifndef IMAP_STORAGE - cmd = play_record_review(chan, "vm-rec-name", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, NULL); -#else cmd = play_record_review(chan, "vm-rec-name", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms); -#endif if (cmd < 0 || cmd == 't' || cmd == '#') return cmd; } @@ -6090,22 +6522,14 @@ static int vm_newuser(struct ast_channel *chan, struct ast_vm_user *vmu, struct if (ast_test_flag(vmu, VM_FORCEGREET)) { snprintf(prefile,sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, vms->username); if (ast_fileexists(prefile, NULL, NULL) < 1) { -#ifndef IMAP_STORAGE - cmd = play_record_review(chan, "vm-rec-unv", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, NULL); -#else cmd = play_record_review(chan, "vm-rec-unv", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms); -#endif if (cmd < 0 || cmd == 't' || cmd == '#') return cmd; } snprintf(prefile,sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, vms->username); if (ast_fileexists(prefile, NULL, NULL) < 1) { -#ifndef IMAP_STORAGE - cmd = play_record_review(chan, "vm-rec-busy", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, NULL); -#else cmd = play_record_review(chan, "vm-rec-busy", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms); -#endif if (cmd < 0 || cmd == 't' || cmd == '#') return cmd; } @@ -6140,27 +6564,15 @@ static int vm_options(struct ast_channel *chan, struct ast_vm_user *vmu, struct switch (cmd) { case '1': snprintf(prefile,sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, vms->username); -#ifndef IMAP_STORAGE - cmd = play_record_review(chan,"vm-rec-unv",prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, NULL); -#else cmd = play_record_review(chan,"vm-rec-unv",prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms); -#endif break; case '2': snprintf(prefile,sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, vms->username); -#ifndef IMAP_STORAGE - cmd = play_record_review(chan,"vm-rec-busy",prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, NULL); -#else cmd = play_record_review(chan,"vm-rec-busy",prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms); -#endif break; case '3': snprintf(prefile,sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, vmu->context, vms->username); -#ifndef IMAP_STORAGE - cmd = play_record_review(chan,"vm-rec-name",prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, NULL); -#else cmd = play_record_review(chan,"vm-rec-name",prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms); -#endif break; case '4': cmd = vm_tempgreeting(chan, vmu, vms, fmtc, record_gain); @@ -6257,25 +6669,17 @@ static int vm_tempgreeting(struct ast_channel *chan, struct ast_vm_user *vmu, st while ((cmd >= 0) && (cmd != 't')) { if (cmd) retries = 0; - RETRIEVE(prefile, -1); + RETRIEVE(prefile, -1, vmu); if (ast_fileexists(prefile, NULL, NULL) <= 0) { -#ifndef IMAP_STORAGE - play_record_review(chan, "vm-rec-temp", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, NULL); -#else play_record_review(chan, "vm-rec-temp", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms); -#endif cmd = 't'; } else { switch (cmd) { case '1': -#ifndef IMAP_STORAGE - cmd = play_record_review(chan, "vm-rec-temp", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, NULL); -#else cmd = play_record_review(chan, "vm-rec-temp", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms); -#endif break; case '2': - DELETE(prefile, -1, prefile); + DELETE(prefile, -1, prefile, vmu); ast_play_and_wait(chan, "vm-tempremoved"); cmd = 't'; break; @@ -6976,12 +7380,10 @@ static int vm_execmain(struct ast_channel *chan, void *data) if (cmd == ERROR_LOCK_PATH) { res = cmd; goto out; -#ifdef IMAP_STORAGE - } else if (cmd == 10) { - goto out; -#endif +#ifndef IMAP_STORAGE } else if (!cmd) { vms.deleted[vms.curmsg] = 1; +#endif } else { vms.deleted[vms.curmsg] = 0; vms.heard[vms.curmsg] = 0; @@ -8140,10 +8542,6 @@ static int dialout(struct ast_channel *chan, struct ast_vm_user *vmu, char *num, 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) { int res = 0; -#ifdef IMAP_STORAGE - char origtimeS[256],cidS[256],contextS[256]; - char *header_content,*temp; -#endif char filename[PATH_MAX]; struct ast_config *msg_cfg = NULL; const char *origtime, *context; @@ -8151,59 +8549,12 @@ static int advanced_options(struct ast_channel *chan, struct ast_vm_user *vmu, s int retries = 0; vms->starting = 0; -#ifdef IMAP_STORAGE - /* START HERE */ - /* get the message info!! */ - if (option_debug > 2) - ast_log (LOG_DEBUG,"Before mail_fetchheaders, curmsg is: %d, imap messages is %lu\n",vms->curmsg, vms->msgArray[vms->curmsg]); - if (vms->msgArray[vms->curmsg] == 0) { - ast_log (LOG_WARNING,"Trying to access unknown message\n"); - 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]); - 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)); - else - cidS[0] = '\0'; - - cid = &cidS[0]; - temp = get_header_by_tag(header_content, "X-Asterisk-VM-Context:"); - - if (temp) - 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) - ast_copy_string(origtimeS,temp, sizeof(origtimeS)); - else - origtimeS[0] = '\0'; - - origtime = &origtimeS[0]; - - ast_copy_string(filename, "IMAP_STORAGE", sizeof(filename)); -#else make_file(vms->fn, sizeof(vms->fn), vms->curdir, msg); /* Retrieve info from VM attribute file */ - make_file(vms->fn2, sizeof(vms->fn2), vms->curdir, vms->curmsg); snprintf(filename,sizeof(filename), "%s.txt", vms->fn2); - RETRIEVE(vms->curdir, vms->curmsg); + RETRIEVE(vms->curdir, vms->curmsg, vmu); msg_cfg = ast_config_load(filename); DISPOSE(vms->curdir, vms->curmsg); if (!msg_cfg) { @@ -8221,7 +8572,6 @@ static int advanced_options(struct ast_channel *chan, struct ast_vm_user *vmu, s context = ast_variable_retrieve(msg_cfg, "message", "context"); if (!strncasecmp("macro",context,5)) /* Macro names in contexts are useless for our needs */ context = ast_variable_retrieve(msg_cfg, "message","macrocontext"); -#endif switch (option) { case 3: if (!res) @@ -8538,7 +8888,7 @@ static int play_record_review(struct ast_channel *chan, char *playfile, char *re cmd = '0'; } else { ast_play_and_wait(chan, "vm-deleted"); - DELETE(recordfile, -1, recordfile); + DELETE(recordfile, -1, recordfile, vmu); cmd = '0'; } } @@ -8584,686 +8934,6 @@ static int play_record_review(struct ast_channel *chan, char *playfile, char *re return cmd; } -#ifdef IMAP_STORAGE - -static void write_file(char *filename, char *buffer, unsigned long len) -{ - FILE *output; - - output = fopen (filename, "w"); - fwrite (buffer, len, 1, output); - fclose (output); -} - -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"); - } -} - - -#if 0 /*No need for this. */ -/* MM status report - * Accepts: MAIL stream - */ -static void status(MAILSTREAM *stream) -{ - unsigned long i; - char *s, date[MAILTMPLEN]; - THREADER *thr; - AUTHENTICATOR *auth; - rfc822_date (date); - ast_log (LOG_NOTICE,"%s\n",date); - if (stream) { - if (stream->mailbox) - ast_log (LOG_NOTICE," %s mailbox: %s, %lu messages, %lu recent\n", - stream->dtb->name, stream->mailbox, stream->nmsgs,stream->recent); - else - ast_log (LOG_NOTICE,"No mailbox is open on this stream\n"); - if (stream->user_flags[0]) { - ast_log (LOG_NOTICE,"Keywords: %s\n", stream->user_flags[0]); - for (i = 1; i < NUSERFLAGS && stream->user_flags[i]; ++i) - ast_log (LOG_NOTICE," %s\n", stream->user_flags[i]); - } - if (!strcmp (stream->dtb->name, "imap")) { - if (LEVELIMAP4rev1 (stream)) - s = "IMAP4rev1 (RFC 3501)"; - else if (LEVEL1730 (stream)) - s = "IMAP4 (RFC 1730)"; - else if (LEVELIMAP2bis (stream)) - s = "IMAP2bis"; - else if (LEVEL1176 (stream)) - s = "IMAP2 (RFC 1176)"; - else - s = "IMAP2 (RFC 1064)"; - ast_log (LOG_NOTICE,"%s server %s\n", s, imap_host (stream)); - if (LEVELIMAP4 (stream)) { - if ((i = (imap_cap(stream)->auth))) { - s = ""; - ast_log (LOG_NOTICE,"Mutually-supported SASL mechanisms:\n"); - while ((auth = mail_lookup_auth (find_rightmost_bit (&i) + 1))) { - ast_log (LOG_NOTICE," %s\n", auth->name); - if (!strcmp (auth->name, "PLAIN")) - s = "\n [LOGIN will not be listed here if PLAIN is supported]\n"; - } - ast_log (LOG_NOTICE,s); - } - ast_log (LOG_NOTICE,"Supported standard extensions:\n"); - if (LEVELACL (stream)) - ast_log (LOG_NOTICE," Access Control lists (RFC 2086)\n"); - if (LEVELQUOTA (stream)) - ast_log (LOG_NOTICE," Quotas (RFC 2087)\n"); - if (LEVELLITERALPLUS (stream)) - ast_log (LOG_NOTICE," Non-synchronizing literals (RFC 2088)\n"); - if (LEVELIDLE (stream)) - ast_log (LOG_NOTICE," IDLE unsolicited update (RFC 2177)\n"); - if (LEVELMBX_REF (stream)) - ast_log (LOG_NOTICE," Mailbox referrals (RFC 2193)\n"); - if (LEVELLOG_REF (stream)) - ast_log (LOG_NOTICE," Login referrals (RFC 2221)\n"); - if (LEVELANONYMOUS (stream)) - ast_log (LOG_NOTICE," Anonymous access (RFC 2245)\n"); - if (LEVELNAMESPACE (stream)) - ast_log (LOG_NOTICE," Multiple namespaces (RFC 2342)\n"); - if (LEVELUIDPLUS (stream)) - ast_log (LOG_NOTICE," Extended UID behavior (RFC 2359)\n"); - if (LEVELSTARTTLS (stream)) - ast_log (LOG_NOTICE," Transport Layer Security (RFC 2595)\n"); - if (LEVELLOGINDISABLED (stream)) - ast_log (LOG_NOTICE," LOGIN command disabled (RFC 2595)\n"); - if (LEVELID (stream)) - ast_log (LOG_NOTICE," Implementation identity negotiation (RFC 2971)\n"); - if (LEVELCHILDREN (stream)) - ast_log (LOG_NOTICE," LIST children announcement (RFC 3348)\n"); - if (LEVELMULTIAPPEND (stream)) - ast_log (LOG_NOTICE," Atomic multiple APPEND (RFC 3502)\n"); - if (LEVELBINARY (stream)) - ast_log (LOG_NOTICE," Binary body content (RFC 3516)\n"); - ast_log (LOG_NOTICE,"Supported draft extensions:\n"); - if (LEVELUNSELECT (stream)) - ast_log (LOG_NOTICE," Mailbox unselect\n"); - if (LEVELSASLIR (stream)) - ast_log (LOG_NOTICE," SASL initial client response\n"); - if (LEVELSORT (stream)) - ast_log (LOG_NOTICE," Server-based sorting\n"); - if (LEVELTHREAD (stream)) { - ast_log (LOG_NOTICE," Server-based threading:\n"); - for (thr = imap_cap(stream)->threader; thr; thr = thr->next) - ast_log (LOG_NOTICE," %s\n", thr->name); - } - if (LEVELSCAN (stream)) - ast_log (LOG_NOTICE," Mailbox text scan\n"); - if ((i = imap_cap(stream)->extlevel)) { - ast_log (LOG_NOTICE,"Supported BODYSTRUCTURE extensions:\n"); - switch (i) { - case BODYEXTLOC: - ast_log (LOG_NOTICE," location\n"); - case BODYEXTLANG: - ast_log (LOG_NOTICE," language\n"); - case BODYEXTDSP: - ast_log (LOG_NOTICE," disposition\n"); - case BODYEXTMD5: - ast_log (LOG_NOTICE," MD5\n"); - } - } - }else - ast_log (LOG_NOTICE,"\n"); - } - } -} -#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 { - free(vmu); - return NULL; - } -} - -/* 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); - if (number == 0) return; - set_update(stream); -} - - -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); - if (number == 0) return; - set_update(stream); -} - - -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); - if (number == 0) return; - set_update(stream); -} - - -void mm_notify(MAILSTREAM * stream, char *string, long errflg) -{ - mm_log (string, errflg); -} - - -void mm_list(MAILSTREAM * stream, int delim, char *mailbox, long attributes) -{ - if (delimiter == '\0') { - delimiter = delim; - } - 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"); - } -} - - -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"); - } -} - - -void mm_status(MAILSTREAM * stream, char *mailbox, MAILSTATUS * status) -{ - ast_log (LOG_NOTICE," Mailbox %s", mailbox); - if (status->flags & SA_MESSAGES) - ast_log (LOG_NOTICE,", %lu messages", status->messages); - if (status->flags & SA_RECENT) - ast_log (LOG_NOTICE,", %lu recent", status->recent); - if (status->flags & SA_UNSEEN) - ast_log (LOG_NOTICE,", %lu unseen", status->unseen); - if (status->flags & SA_UIDVALIDITY) - ast_log (LOG_NOTICE,", %lu UID validity", status->uidvalidity); - if (status->flags & SA_UIDNEXT) - ast_log (LOG_NOTICE,", %lu next UID", status->uidnext); - ast_log (LOG_NOTICE,"\n"); -} - - -void mm_log(char *string, long errflg) -{ - switch ((short) errflg) { - case NIL: - if (option_debug) - ast_log(LOG_DEBUG,"IMAP Info: %s\n", string); - break; - case PARSE: - case WARN: - ast_log (LOG_WARNING,"IMAP Warning: %s\n", string); - break; - case ERROR: - ast_log (LOG_ERROR,"IMAP Error: %s\n", string); - break; - } -} - - -void mm_dlog(char *string) -{ - ast_log (LOG_NOTICE, "%s\n", string); -} - - -void mm_login(NETMBX * mb, char *user, char *pwd, long trial) -{ - struct ast_vm_user *vmu; - - if (option_debug > 3) - ast_log(LOG_DEBUG, "Entering callback mm_login\n"); - - ast_copy_string(user, mb->user, MAILTMPLEN); - - /* We should only do this when necessary */ - if (!ast_strlen_zero(authpassword)) { - ast_copy_string(pwd, authpassword, MAILTMPLEN); - } else { - AST_LIST_TRAVERSE(&users, vmu, list) { - if (!strcasecmp(mb->user, vmu->imapuser)) { - ast_copy_string(pwd, vmu->imappassword, MAILTMPLEN); - break; - } - } - if (!vmu) { - if ((vmu = find_user_realtime_imapuser(mb->user))) { - ast_copy_string(pwd, vmu->imappassword, MAILTMPLEN); - free_user(vmu); - } - } - } -} - - -void mm_critical(MAILSTREAM * stream) -{ -} - - -void mm_nocritical(MAILSTREAM * stream) -{ -} - - -long mm_diskerror(MAILSTREAM * stream, long errcode, long serious) -{ - kill (getpid (), SIGSTOP); - return NIL; -} - - -void mm_fatal(char *string) -{ - ast_log(LOG_ERROR,"IMAP access FATAL error: %s\n", string); -} - -/* C-client callback to handle quota */ -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; - - while (pquota) { - usage = pquota->usage; - limit = pquota->limit; - 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"); - } -} - -static char *get_header_by_tag(char *header, char *tag) -{ - char *start; - int taglen; - char *eol_pnt; - - if (!header || !tag) - return NULL; - - taglen = strlen(tag) + 1; - if (taglen < 1) - return NULL; - - start = strstr(header, tag); - if (!start) - return NULL; - - ast_mutex_lock(&imaptemp_lock); - ast_copy_string(imaptemp, start+taglen, sizeof(imaptemp)); - ast_mutex_unlock(&imaptemp_lock); - if ((eol_pnt = strchr(imaptemp,'\r')) || (eol_pnt = strchr(imaptemp,'\n'))) - *eol_pnt = '\0'; - return imaptemp; -} - -static char *get_user_by_mailbox(char *mailbox) -{ - char *start, *quote; - char *eol_pnt; - - if (!mailbox) - return NULL; - - start = strstr(mailbox,"/user="); - if (!start) - return NULL; - - ast_mutex_lock(&imaptemp_lock); - ast_copy_string(imaptemp, start+6, sizeof(imaptemp)); - ast_mutex_unlock(&imaptemp_lock); - - quote = strchr(imaptemp,'\"'); - if (!quote) { /* if username is not in quotes */ - eol_pnt = strchr(imaptemp,'/'); - if (!eol_pnt) { - eol_pnt = strchr(imaptemp,'}'); - } - *eol_pnt = '\0'; - return imaptemp; - } else { - eol_pnt = strchr(imaptemp+1,'\"'); - *eol_pnt = '\0'; - return imaptemp+1; - } -} - -static struct vm_state *create_vm_state_from_user(struct ast_vm_user *vmu, char *mailbox) -{ - struct vm_state *vms_p; - - if (option_debug > 4) - ast_log(LOG_DEBUG,"Adding new vmstate for %s\n",vmu->imapuser); - if (!(vms_p = ast_calloc(1, sizeof(*vms_p)))) - return NULL; - ast_copy_string(vms_p->imapuser,vmu->imapuser, sizeof(vms_p->imapuser)); - ast_copy_string(vms_p->username, mailbox, 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 > 4) - ast_log(LOG_DEBUG,"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); - return vms_p; -} - -static struct vm_state *get_vm_state_by_imapuser(char *user, int interactive) -{ - struct vmstate *vlist = NULL; - - ast_mutex_lock(&vmstate_lock); - vlist = vmstates; - while (vlist) { - if (vlist->vms) { - if (vlist->vms->imapuser) { - if (!strcmp(vlist->vms->imapuser,user)) { - if (interactive == 2) { - ast_mutex_unlock(&vmstate_lock); - return vlist->vms; - } else if (vlist->vms->interactive == interactive) { - ast_mutex_unlock(&vmstate_lock); - return vlist->vms; - } - } - } else { - if (option_debug > 2) - ast_log(LOG_DEBUG, " error: imapuser is NULL for %s\n",user); - } - } else { - if (option_debug > 2) - ast_log(LOG_DEBUG, " error: vms is NULL for %s\n",user); - } - vlist = vlist->next; - } - ast_mutex_unlock(&vmstate_lock); - if (option_debug > 2) - ast_log(LOG_DEBUG, "%s not found in vmstates\n",user); - return NULL; -} - -static struct vm_state *get_vm_state_by_mailbox(const char *mailbox, int interactive) -{ - struct vmstate *vlist = NULL; - - ast_mutex_lock(&vmstate_lock); - vlist = vmstates; - if (option_debug > 2) - ast_log(LOG_DEBUG, "Mailbox set to %s\n",mailbox); - while (vlist) { - if (vlist->vms) { - if (vlist->vms->username) { - if (option_debug > 2) - ast_log(LOG_DEBUG, " comparing mailbox %s (i=%d) to vmstate mailbox %s (i=%d)\n",mailbox,interactive,vlist->vms->username,vlist->vms->interactive); - if (!strcmp(vlist->vms->username,mailbox) && vlist->vms->interactive == interactive) { - if (option_debug > 2) - ast_log(LOG_DEBUG, " Found it!\n"); - ast_mutex_unlock(&vmstate_lock); - return vlist->vms; - } - } else { - if (option_debug > 2) - ast_log(LOG_DEBUG, " error: username is NULL for %s\n",mailbox); - } - } else { - if (option_debug > 2) - ast_log(LOG_DEBUG, " error: vms is NULL for %s\n",mailbox); - } - vlist = vlist->next; - } - ast_mutex_unlock(&vmstate_lock); - if (option_debug > 2) - ast_log(LOG_DEBUG, "%s not found in vmstates\n",mailbox); - return NULL; -} - -static void vmstate_insert(struct vm_state *vms) -{ - struct vmstate *v; - struct vm_state *altvms; - - /* If interactive, it probably already exists, and we should - use the one we already have since it is more up to date. - We can compare the username to find the duplicate */ - if (vms->interactive == 1) { - altvms = get_vm_state_by_mailbox(vms->username,0); - if (altvms) { - if (option_debug > 2) - ast_log(LOG_DEBUG, "Duplicate mailbox %s, copying message info...\n",vms->username); - vms->newmessages = altvms->newmessages; - vms->oldmessages = altvms->oldmessages; - if (option_debug > 2) - ast_log(LOG_DEBUG, "check_msgArray before memcpy\n"); - check_msgArray(vms); - /* memcpy(vms->msgArray, altvms->msgArray, sizeof(long)*256); */ - copy_msgArray(vms, altvms); - if (option_debug > 2) - ast_log(LOG_DEBUG, "check_msgArray after memcpy\n"); - check_msgArray(vms); - vms->vmArrayIndex = altvms->vmArrayIndex; - vms->lastmsg = altvms->lastmsg; - vms->curmsg = altvms->curmsg; - /* get a pointer to the persistent store */ - vms->persist_vms = altvms; - /* Reuse the mailstream? */ - vms->mailstream = altvms->mailstream; - /* vms->mailstream = NIL; */ - } - } - - v = (struct vmstate *)malloc(sizeof(struct vmstate)); - if (!v) { - ast_log(LOG_ERROR, "Out of memory\n"); - } - if (option_debug > 2) - ast_log(LOG_DEBUG, "Inserting vm_state for user:%s, mailbox %s\n",vms->imapuser,vms->username); - ast_mutex_lock(&vmstate_lock); - v->vms = vms; - v->next = vmstates; - vmstates = v; - ast_mutex_unlock(&vmstate_lock); -} - -static void vmstate_delete(struct vm_state *vms) -{ - struct vmstate *vc, *vf = NULL, *vl = NULL; - struct vm_state *altvms; - - /* If interactive, we should copy pertainent info - back to the persistent state (to make update immediate) */ - if (vms->interactive == 1) { - altvms = vms->persist_vms; - if (altvms) { - if (option_debug > 2) - ast_log(LOG_DEBUG, "Duplicate mailbox %s, copying message info...\n",vms->username); - altvms->newmessages = vms->newmessages; - altvms->oldmessages = vms->oldmessages; - altvms->updated = 1; - } - } - - ast_mutex_lock(&vmstate_lock); - vc = vmstates; - if (option_debug > 2) - ast_log(LOG_DEBUG, "Removing vm_state for user:%s, mailbox %s\n",vms->imapuser,vms->username); - while (vc) { - if (vc->vms == vms) { - vf = vc; - if (vl) - vl->next = vc->next; - else - vmstates = vc->next; - break; - } - vl = vc; - vc = vc->next; - } - if (!vf) { - ast_log(LOG_ERROR, "No vmstate found for user:%s, mailbox %s\n",vms->imapuser,vms->username); - } else { - ast_mutex_destroy(&vf->vms->lock); - free(vf); - } - ast_mutex_unlock(&vmstate_lock); -} - -static void set_update(MAILSTREAM * stream) -{ - struct vm_state *vms; - char *mailbox; - char *user; - - mailbox = stream->mailbox; - user = get_user_by_mailbox(mailbox); - vms = get_vm_state_by_imapuser(user, 0); - if (vms) { - if (option_debug > 2) - ast_log (LOG_DEBUG, "User %s mailbox set for update.\n",user); - vms->updated = 1; /* set updated flag since mailbox changed */ - } else { - if (option_debug > 2) - ast_log (LOG_WARNING, "User %s mailbox not found for update.\n",user); - } -} - -static void init_vm_state(struct vm_state *vms) -{ - int x; - vms->vmArrayIndex = 0; - for (x = 0; x < 256; x++) { - vms->msgArray[x] = 0; - } - ast_mutex_init(&vms->lock); -} - -static void check_msgArray(struct vm_state *vms) -{ - int x; - for (x = 0; x<256; x++) { - if (vms->msgArray[x]!=0) { - if (option_debug) - ast_log (LOG_DEBUG, "Item %d set to %ld\n",x,vms->msgArray[x]); - } - } -} - -static void copy_msgArray(struct vm_state *dst, struct vm_state *src) -{ - int x; - for (x = 0; x<256; x++) { - dst->msgArray[x] = src->msgArray[x]; - } -} - -static int save_body(BODY *body, struct vm_state *vms, char *section, char *format) -{ - char *body_content; - char *body_decoded; - unsigned long len; - unsigned long newlen; - char filename[256]; - - if (!body || body == NIL) - return -1; - body_content = mail_fetchbody (vms->mailstream, vms->msgArray[vms->curmsg], section, &len); - if (body_content != NIL) { - snprintf(filename, sizeof(filename), "%s.%s", vms->fn, format); - /* ast_log (LOG_DEBUG,body_content); */ - body_decoded = rfc822_base64 ((unsigned char *)body_content, len, &newlen); - write_file (filename, (char *) body_decoded, newlen); - } - return 0; -} - -/* get delimiter via mm_list callback */ -static void get_mailbox_delimiter(MAILSTREAM *stream) { - char tmp[50]; - snprintf(tmp, sizeof(tmp), "{%s}", imapserver); - mail_list(stream, tmp, "*"); -} - -/* Check Quota for user */ -static void check_quota(struct vm_state *vms, char *mailbox) { - mail_parameters(NULL, SET_QUOTA, (void *) mm_parsequota); - if (option_debug > 2) - ast_log(LOG_DEBUG, "Mailbox name set to: %s, about to check quotas\n", mailbox); - if (vms && vms->mailstream != NULL) { - imap_getquotaroot(vms->mailstream, mailbox); - } else { - ast_log(LOG_WARNING,"Mailstream not available for mailbox: %s\n",mailbox); - } -} - -#endif /* IMAP_STORAGE */ - /* This is a workaround so that menuselect displays a proper description * AST_MODULE_INFO(, , "Comedian Mail (Voicemail System)" */ |