diff options
Diffstat (limited to 'apps')
-rw-r--r-- | apps/app_voicemail.c | 7109 |
1 files changed, 3498 insertions, 3611 deletions
diff --git a/apps/app_voicemail.c b/apps/app_voicemail.c index 2f7bd55f0..a74201c98 100644 --- a/apps/app_voicemail.c +++ b/apps/app_voicemail.c @@ -140,19 +140,16 @@ struct ast_vm_user; static int init_mailstream(struct vm_state *vms, int box); static void write_file(char *filename, char *buffer, unsigned long len); static char *get_header_by_tag(char *header, char *tag, char *buf, size_t len); -static void vm_imap_delete(int msgnum, struct vm_state *vms); +static void vm_imap_delete(int msgnum, struct ast_vm_user *vmu); static char *get_user_by_mailbox(char *mailbox, char *buf, size_t len); static struct vm_state *get_vm_state_by_imapuser(char *user, int interactive); static struct vm_state *get_vm_state_by_mailbox(const char *mailbox, int interactive); -static 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); @@ -160,7 +157,7 @@ static int imap_store_file(char *dir, char *mailboxuser, char *mailboxcontext, i static void update_messages_by_imapuser(const char *user, unsigned long number); static int imap_remove_file (char *dir, int msgnum); -static int imap_retrieve_file (char *dir, int msgnum, const char *mailbox, char *context); +static int imap_retrieve_file (const char *dir, const int msgnum, const char *mailbox, const char *context); static int imap_delete_old_greeting (char *dir, struct vm_state *vms); static void check_quota(struct vm_state *vms, char *mailbox); static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box); @@ -444,17 +441,16 @@ static char odbc_table[80]; #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,c,d) (imap_retrieve_file(a,b,c,d )) #define DISPOSE(a,b) (imap_remove_file(a,b)) #define STORE(a,b,c,d,e,f,g,h,i) (imap_store_file(a,b,c,d,e,f,g,h,i)) #define EXISTS(a,b,c,d) (ast_fileexists(c, NULL, d) > 0) +#define RETRIEVE(a,b,c,d) imap_retrieve_file(a,b,c,d) #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,c,d) #define DISPOSE(a,b) @@ -462,7 +458,7 @@ static char odbc_table[80]; #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 @@ -1044,40 +1040,35 @@ 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) +/*! + * \brief Creates a file system path expression for a folder within the voicemail data folder and the appropriate context. + * \param dest The variable to hold the output generated path expression. This buffer should be of size PATH_MAX. + * \param len The length of the path string that was written out. + * + * The path is constructed as + * VM_SPOOL_DIRcontext/ext/folder + * + * \return zero on success, -1 on error. + */ +static int make_file(char *dest, const int len, const char *dir, const int num) { - int res; - if ((res = ast_mkdir(dir, 01777))) { - ast_log(LOG_WARNING, "ast_mkdir '%s' failed: %s\n", dir, strerror(res)); - 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; + } } - ast_debug(3, "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 @@ -1101,623 +1092,1908 @@ static int create_dirpath(char *dest, int len, const char *context, const char * return 0; } -/*! \brief Lock file path - only return failure if ast_lock_path returns 'timeout', - not if the path does not exist or any other reason -*/ -static int vm_lock_path(const char *path) +static const char *mbox(int id) { - switch (ast_lock_path(path)) { - case AST_LOCK_TIMEOUT: - return -1; - default: - return 0; + static const char *msgs[] = { +#ifdef IMAP_STORAGE + imapfolder, +#else + "INBOX", +#endif + "Old", + "Work", + "Family", + "Friends", + "Cust1", + "Cust2", + "Cust3", + "Cust4", + "Cust5", + "Deleted", + "Urgent" + }; + return (id >= 0 && id < (sizeof(msgs)/sizeof(msgs[0]))) ? msgs[id] : "Unknown"; +} + +static void free_user(struct ast_vm_user *vmu) +{ + if (ast_test_flag(vmu, VM_ALLOCED)) + ast_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; + } + ast_debug(3, "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_greeting (const char *dir, const int msgnum, struct ast_vm_user *vmu) +{ + struct vm_state *vms_p; + char *file, *filename; + char *attachment; + int ret = 0, i; + BODY *body; -#ifdef ODBC_STORAGE -struct generic_prepare_struct { - char *sql; - int argc; - char **argv; -}; + /* This function is only used for retrieval of IMAP greetings + * regular messages are not retrieved this way, nor are greetings + * if they are stored locally*/ + if (msgnum > -1 || !imapgreetings) { + return 0; + } else { + file = strrchr(ast_strdupa(dir), '/'); + if (file) + *file++ = '\0'; + else { + ast_debug (1, "Failed to procure file name from directory passed.\n"); + return -1; + } + } -static SQLHSTMT generic_prepare(struct odbc_obj *obj, void *data) + /* check if someone is accessing this box right now... */ + if (!(vms_p = get_vm_state_by_mailbox(vmu->mailbox, 1)) ||!(vms_p = get_vm_state_by_mailbox(vmu->mailbox, 0))) { + ast_log(LOG_ERROR, "Voicemail state not found!\n"); + return -1; + } + + ret = init_mailstream(vms_p, GREETINGS_FOLDER); + if (!vms_p->mailstream) { + ast_log(LOG_ERROR, "IMAP mailstream is NULL\n"); + return -1; + } + + /*XXX Yuck, this could probably be done a lot better */ + for (i = 0; i < vms_p->mailstream->nmsgs; i++) { + mail_fetchstructure(vms_p->mailstream, i + 1, &body); + /* We have the body, now we extract the file name of the first attachment. */ + if (body->nested.part && body->nested.part->next && body->nested.part->next->body.parameter->value) { + attachment = ast_strdupa(body->nested.part->next->body.parameter->value); + } else { + ast_log(LOG_ERROR, "There is no file attached to this IMAP message.\n"); + return -1; + } + filename = strsep(&attachment, "."); + if (!strcmp(filename, file)) { + ast_copy_string(vms_p->fn, dir, sizeof(vms_p->fn)); + vms_p->msgArray[vms_p->curmsg] = i + 1; + save_body(body, vms_p, "2", attachment); + return 0; + } + } + + return -1; +} + +static int imap_retrieve_file(const char *dir, const int msgnum, const char *mailbox, const char *context) { - struct generic_prepare_struct *gps = data; - int res, i; - SQLHSTMT stmt; + BODY *body; + char *header_content; + char *attachedfilefmt; + char buf[80]; + struct vm_state *vms; + char text_file[PATH_MAX]; + FILE *text_file_ptr; + int res = 0; + struct ast_vm_user *vmu; - res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt); - if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { - ast_log(LOG_WARNING, "SQL Alloc Handle failed!\n"); - return NULL; + if (!(vmu = find_user(NULL, context, mailbox))) { + ast_log(LOG_WARNING, "Couldn't find user with mailbox %s@%s\n", mailbox, context); + return -1; } - res = SQLPrepare(stmt, (unsigned char *)gps->sql, SQL_NTS); - if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { - ast_log(LOG_WARNING, "SQL Prepare failed![%s]\n", gps->sql); - SQLFreeHandle(SQL_HANDLE_STMT, stmt); - return NULL; + + if (msgnum < 0) { + if (imapgreetings) { + res = imap_retrieve_greeting(dir, msgnum, vmu); + goto exit; + } else { + res = 0; + goto exit; + } + } + + /* 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); + res = -1; + goto exit; + } + + 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) { + res = 0; + goto exit; + } + + 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"); + res = -1; + goto exit; + } + + /* 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]); + res = -1; + goto exit; + } + + 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"); + res = -1; + goto exit; } - for (i = 0; i < gps->argc; i++) - SQLBindParameter(stmt, i + 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(gps->argv[i]), 0, gps->argv[i], 0, NULL); + + /* 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"); + res = -1; + goto exit; + } + + 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]"); - return stmt; + get_header_by_tag(header_content, "X-Asterisk-VM-Caller-ID-Num:", buf, sizeof(buf)); + fprintf(text_file_ptr, "callerid=\"%s\" ", S_OR(buf, "")); + get_header_by_tag(header_content, "X-Asterisk-VM-Caller-ID-Name:", buf, sizeof(buf)); + fprintf(text_file_ptr, "<%s>\n", S_OR(buf, "")); + get_header_by_tag(header_content, "X-Asterisk-VM-Context:", buf, sizeof(buf)); + fprintf(text_file_ptr, "context=%s\n", S_OR(buf, "")); + get_header_by_tag(header_content, "X-Asterisk-VM-Orig-time:", buf, sizeof(buf)); + fprintf(text_file_ptr, "origtime=%s\n", S_OR(buf, "")); + get_header_by_tag(header_content, "X-Asterisk-VM-Duration:", buf, sizeof(buf)); + fprintf(text_file_ptr, "duration=%s\n", S_OR(buf, "")); + get_header_by_tag(header_content, "X-Asterisk-VM-Category:", buf, sizeof(buf)); + fprintf(text_file_ptr, "category=%s\n", S_OR(buf, "")); + fclose(text_file_ptr); + +exit: + free_user(vmu); + return res; } -static int retrieve_file(char *dir, int msgnum) +static int folder_int(const char *folder) { - int x = 0; - int res; - int fd = -1; - size_t fdlen = 0; - void *fdm = MAP_FAILED; - SQLSMALLINT colcount = 0; - SQLHSTMT stmt; - char sql[PATH_MAX]; - char fmt[80] = ""; - char *c; - char coltitle[256]; - SQLSMALLINT collen; - SQLSMALLINT datatype; - SQLSMALLINT decimaldigits; - SQLSMALLINT nullable; - SQLULEN colsize; - SQLLEN colsize2; - FILE *f = NULL; - char rowdata[80]; + /*assume a NULL folder means INBOX*/ + if (!folder) + return 0; + if (!strcasecmp(folder, imapfolder)) + 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 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 full_fn[PATH_MAX]; - char msgnums[80]; - char *argv[] = { dir, msgnums }; - struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv }; + char mailbox[256]; + char *stringp; + FILE *p = NULL; + char tmp[80] = "/tmp/astmail-XXXXXX"; + long len; + void *buf; + int tempcopy = 0; + STRING str; + + /* Attach only the first format */ + fmt = ast_strdupa(fmt); + stringp = fmt; + strsep(&stringp, "|"); - struct odbc_obj *obj; - obj = ast_odbc_request_obj(odbc_database, 0); - if (obj) { - ast_copy_string(fmt, vmfmts, sizeof(fmt)); - c = strchr(fmt, '|'); - if (c) - *c = '\0'; - if (!strcasecmp(fmt, "wav49")) - strcpy(fmt, "WAV"); - snprintf(msgnums, sizeof(msgnums), "%d", msgnum); - if (msgnum > -1) - make_file(fn, sizeof(fn), dir, msgnum); - else - ast_copy_string(fn, dir, sizeof(fn)); - snprintf(full_fn, sizeof(full_fn), "%s.txt", fn); - - if (!(f = fopen(full_fn, "w+"))) { - ast_log(LOG_WARNING, "Failed to open/create '%s'\n", full_fn); - goto yuck; + if (!ast_strlen_zero(vmu->serveremail)) + myserveremail = vmu->serveremail; + + if (msgnum > -1) + make_file(fn, sizeof(fn), dir, msgnum); + else + ast_copy_string (fn, dir, sizeof(fn)); + + 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"; + ast_debug(3, "Storing file '%s', format '%s'\n", fn, fmt); + + /* Make a temporary file instead of piping directly to sendmail, in case the mail + command hangs. */ + if (!(p = vm_mkftemp(tmp))) { + ast_log(LOG_WARNING, "Unable to store '%s' (can't create temporary file)\n", fn); + if (tempcopy) + *(vmu->email) = '\0'; + return -1; + } + + if (msgnum < 0 && imapgreetings) { + init_mailstream(vms, GREETINGS_FOLDER); + imap_delete_old_greeting(fn, vms); + } + + make_email_file(p, myserveremail, vmu, msgnum, vmu->context, vmu->mailbox, S_OR(chan->cid.cid_num, NULL), S_OR(chan->cid.cid_name, NULL), fn, fmt, duration, 1, chan, NULL, 1); + /* read mail file to memory */ + len = ftell(p); + rewind(p); + if (!(buf = ast_malloc(len + 1))) { + ast_log(LOG_ERROR, "Can't allocate %ld bytes to read message\n", len + 1); + fclose(p); + if (tempcopy) + *(vmu->email) = '\0'; + return -1; + } + fread(buf, len, 1, p); + ((char *)buf)[len] = '\0'; + INIT(&str, mail_string, buf, len); + init_mailstream(vms, NEW_FOLDER); + imap_mailbox_name(mailbox, sizeof(mailbox), vms, NEW_FOLDER, 1); + if (!mail_append(vms->mailstream, mailbox, &str)) + ast_log(LOG_ERROR, "Error while sending the message to %s\n", mailbox); + fclose(p); + unlink(tmp); + ast_free(buf); + ast_debug(3, "%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; } - - snprintf(full_fn, sizeof(full_fn), "%s.%s", fn, fmt); - snprintf(sql, sizeof(sql), "SELECT * FROM %s WHERE dir=? AND msgnum=?", odbc_table); - stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps); - if (!stmt) { - ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql); - ast_odbc_release_obj(obj); - goto yuck; + } + + /* No IMAP account available */ + if (vmu->imapuser[0] == '\0') { + ast_log(LOG_WARNING, "IMAP user not set for mailbox %s\n", vmu->mailbox); + free_user(vmu); + return -1; + } + + /* check if someone is accessing this box right now... */ + vms_p = get_vm_state_by_imapuser(vmu->imapuser, 1); + if (!vms_p) { + vms_p = get_vm_state_by_mailbox(mailbox, 1); + } + if (vms_p) { + ast_debug(3, "Returning before search - user is logged in\n"); + if (fold == 0) { /* INBOX */ + return vms_p->newmessages; } - res = SQLFetch(stmt); - if (res == SQL_NO_DATA) { - SQLFreeHandle (SQL_HANDLE_STMT, stmt); - ast_odbc_release_obj(obj); - goto yuck; - } else if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { - ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql); - SQLFreeHandle (SQL_HANDLE_STMT, stmt); - ast_odbc_release_obj(obj); - goto yuck; + if (fold == 1) { /* Old messages */ + return vms_p->oldmessages; } - fd = open(full_fn, O_RDWR | O_CREAT | O_TRUNC, VOICEMAIL_FILE_MODE); - if (fd < 0) { - ast_log(LOG_WARNING, "Failed to write '%s': %s\n", full_fn, strerror(errno)); - SQLFreeHandle (SQL_HANDLE_STMT, stmt); - ast_odbc_release_obj(obj); - goto yuck; + } + + /* 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) { + ast_debug(3, "Adding new vmstate for %s\n", vmu->imapuser); + if (!(vms_p = ast_calloc(1, sizeof(*vms_p)))) { + return -1; } - res = SQLNumResultCols(stmt, &colcount); - if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { - ast_log(LOG_WARNING, "SQL Column Count error!\n[%s]\n\n", sql); - SQLFreeHandle (SQL_HANDLE_STMT, stmt); - ast_odbc_release_obj(obj); - goto yuck; + 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 */ + ast_debug(3, "Copied %s to %s\n", vmu->imapuser, vms_p->imapuser); + vms_p->updated = 1; + /* set mailbox to INBOX! */ + ast_copy_string(vms_p->curbox, mbox(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, "Houston we have a problem - 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; } - if (f) - fprintf(f, "[message]\n"); - for (x = 0; x < colcount; x++) { - rowdata[0] = '\0'; - collen = sizeof(coltitle); - res = SQLDescribeCol(stmt, x + 1, (unsigned char *)coltitle, sizeof(coltitle), &collen, - &datatype, &colsize, &decimaldigits, &nullable); - if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { - ast_log(LOG_WARNING, "SQL Describe Column error!\n[%s]\n\n", sql); - SQLFreeHandle (SQL_HANDLE_STMT, stmt); - ast_odbc_release_obj(obj); - goto yuck; - } - if (!strcasecmp(coltitle, "recording")) { - off_t offset; - res = SQLGetData(stmt, x + 1, SQL_BINARY, rowdata, 0, &colsize2); - fdlen = colsize2; - if (fd > -1) { - char tmp[1] = ""; - lseek(fd, fdlen - 1, SEEK_SET); - if (write(fd, tmp, 1) != 1) { - close(fd); - fd = -1; - continue; - } - /* Read out in small chunks */ - for (offset = 0; offset < colsize2; offset += CHUNKSIZE) { - if ((fdm = mmap(NULL, CHUNKSIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, offset)) == MAP_FAILED) { - ast_log(LOG_WARNING, "Could not mmap the output file: %s (%d)\n", strerror(errno), errno); - SQLFreeHandle(SQL_HANDLE_STMT, stmt); - ast_odbc_release_obj(obj); - goto yuck; - } else { - res = SQLGetData(stmt, x + 1, SQL_BINARY, fdm, CHUNKSIZE, NULL); - munmap(fdm, CHUNKSIZE); - if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { - ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql); - unlink(full_fn); - SQLFreeHandle(SQL_HANDLE_STMT, stmt); - ast_odbc_release_obj(obj); - goto yuck; - } - } - } - truncate(full_fn, fdlen); - } - } else { - SQLLEN ind; - res = SQLGetData(stmt, x + 1, SQL_CHAR, rowdata, sizeof(rowdata), &ind); - if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { - SQLINTEGER nativeerror = 0; - SQLSMALLINT diagbytes = 0; - unsigned char state[10], diagnostic[256]; - SQLGetDiagRec(SQL_HANDLE_STMT, stmt, 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes); - ast_log(LOG_WARNING, "SQL Get Data error: %s: %s!\n[%s]\n\n", state, diagnostic, sql); - SQLFreeHandle (SQL_HANDLE_STMT, stmt); - ast_odbc_release_obj(obj); - goto yuck; + /* 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; + + ast_debug(3, "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; } - if (strcasecmp(coltitle, "msgnum") && strcasecmp(coltitle, "dir") && f) - fprintf(f, "%s=%s\n", coltitle, rowdata); } } - SQLFreeHandle (SQL_HANDLE_STMT, stmt); - ast_odbc_release_obj(obj); - } else - ast_log(LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database); -yuck: - if (f) - fclose(f); - if (fd > -1) - close(fd); - return x - 1; + return 0; + } + if (context) { + *context = '\0'; + mailboxnc = tmp; + context++; + } else { + context = "default"; + mailboxnc = (char *)mailbox_context; + } + if (newmsgs) { + if ((*newmsgs = messagecount(context, mailboxnc, imapfolder)) < 0) + return -1; + } + if (oldmsgs) { + if ((*oldmsgs = messagecount(context, mailboxnc, "Old")) < 0) + return -1; + } + return 0; } -static int remove_file(char *dir, int msgnum) +/** +* \brief Determines if the given folder has messages. +* \param mailbox The @ delimited string for user@context. If no context is found, uses 'default' for the context. +* \param folder the folder to look in +* +* This function is used when the mailbox is stored in an IMAP back end. +* This invokes the messagecount(). Here we are interested in the presence of messages (> 0) only, not the actual count. +* \return 1 if the folder has one or more messages. zero otherwise. +*/ + +static int has_voicemail(const char *mailbox, const char *folder) { - char fn[PATH_MAX]; - char full_fn[PATH_MAX]; - char msgnums[80]; + 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; +} + +/*! +* \brief Copies a message from one mailbox to another. +* \param chan +* \param vmu +* \param imbox +* \param msgnum +* \param duration +* \param recip +* \param fmt +* \param dir +* +* This works with IMAP storage based mailboxes. +* +* \return zero on success, -1 on error. +*/ +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 (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); - if (ast_check_realtime("voicemail_data")) { - ast_destroy_realtime("voicemail_data", "filename", fn, NULL); + if (box == OLD_FOLDER) { + ast_copy_string(vms->curbox, mbox(NEW_FOLDER), sizeof(vms->curbox)); + } else { + ast_copy_string(vms->curbox, mbox(box), sizeof(vms->curbox)); + } + + if (box == NEW_FOLDER) { + ast_copy_string(vms->vmbox, "vm-INBOX", sizeof(vms->vmbox)); + } else { + snprintf(vms->vmbox, sizeof(vms->vmbox), "vm-%s", mbox(box)); + } + + /* 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 == NEW_FOLDER || box == OLD_FOLDER) + snprintf(spec, len, "%s%s", tmp, use_folder? imapfolder: "INBOX"); + else if (box == GREETINGS_FOLDER) + snprintf(spec, len, "%s%s", tmp, greetingfolder); + else { /* Other folders such as Friends, Family, etc... */ + if (!ast_strlen_zero(imapparentfolder)) { + /* imapparentfolder would typically be set to INBOX */ + snprintf(spec, len, "%s%s%c%s", tmp, imapparentfolder, delimiter, mbox(box)); + } else { + snprintf(spec, len, "%s%s", tmp, mbox(box)); + } } - 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) +static int init_mailstream(struct vm_state *vms, int box) { - int x = 0; - int res; - SQLHSTMT stmt; - char sql[PATH_MAX]; - char rowdata[20]; - char *argv[] = { dir }; - struct generic_prepare_struct gps = { .sql = sql, .argc = 1, .argv = argv }; + 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? */ - struct odbc_obj *obj; - obj = ast_odbc_request_obj(odbc_database, 0); - if (obj) { - snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir=?", odbc_table); - stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps); - if (!stmt) { - ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql); - ast_odbc_release_obj(obj); - goto yuck; + 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; } - res = SQLFetch(stmt); - if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { - ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql); - SQLFreeHandle (SQL_HANDLE_STMT, stmt); - ast_odbc_release_obj(obj); - goto yuck; + 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, urgent = 0; + + /* If Urgent, then look at INBOX */ + if (box == 11) { + box = NEW_FOLDER; + urgent = 1; + } + + ast_copy_string(vms->imapuser,vmu->imapuser, sizeof(vms->imapuser)); + ast_debug(3,"Before init_mailstream, user is %s\n",vmu->imapuser); + + if ((ret = init_mailstream(vms, box)) || !vms->mailstream) { + ast_log(LOG_ERROR, "Could not initialize mailstream\n"); + return -1; + } + + create_dirpath(vms->curdir, sizeof(vms->curdir), vmu->context, vms->username, vms->curbox); + + /* Check Quota */ + if (box == 0) { + ast_debug(3, "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 = NEW_FOLDER, check for new, if box = OLD_FOLDER, check for read */ + if (box == NEW_FOLDER && urgent == 1) { + pgm->unseen = 1; + pgm->seen = 0; + pgm->flagged = 1; + pgm->unflagged = 0; + } else if (box == NEW_FOLDER && urgent == 0) { + pgm->unseen = 1; + pgm->seen = 0; + pgm->flagged = 0; + pgm->unflagged = 1; + } else if (box == OLD_FOLDER) { + pgm->seen = 1; + pgm->unseen = 0; + } + + ast_debug(3,"Before mail_search_full, user is %s\n",vmu->imapuser); + + vms->vmArrayIndex = 0; + 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; + ast_log(LOG_NOTICE, "The name of the file I'm writing is %s\n", filename); + + output = fopen (filename, "w"); + fwrite (buffer, len, 1, output); + fclose (output); +} + +static void update_messages_by_imapuser(const char *user, unsigned long number) +{ + struct vmstate *vlist = NULL; + + AST_LIST_LOCK(&vmstates); + AST_LIST_TRAVERSE(&vmstates, vlist, list) { + if (!vlist->vms) { + ast_debug(3, "error: vms is NULL for %s\n", user); + continue; } - res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL); - if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { - ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql); - SQLFreeHandle (SQL_HANDLE_STMT, stmt); - ast_odbc_release_obj(obj); - goto yuck; + if (!vlist->vms->imapuser) { + ast_debug(3, "error: imapuser is NULL for %s\n", user); + continue; } - if (sscanf(rowdata, "%d", &x) != 1) - ast_log(LOG_WARNING, "Failed to read message count!\n"); - SQLFreeHandle (SQL_HANDLE_STMT, stmt); - ast_odbc_release_obj(obj); - } else - ast_log(LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database); -yuck: - return x - 1; + ast_debug(3, "saving mailbox message number %lu as message %d. Interactive set to %d\n", number, vlist->vms->vmArrayIndex, vlist->vms->interactive); + vlist->vms->msgArray[vlist->vms->vmArrayIndex++] = number; + } + AST_LIST_UNLOCK(&vmstates); } -static int message_exists(char *dir, int msgnum) +void mm_searched(MAILSTREAM *stream, unsigned long number) { - int x = 0; - int res; - SQLHSTMT stmt; - char sql[PATH_MAX]; - char rowdata[20]; - char msgnums[20]; - char *argv[] = { dir, msgnums }; - struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv }; + char *mailbox = stream->mailbox, buf[1024] = "", *user; - struct odbc_obj *obj; - obj = ast_odbc_request_obj(odbc_database, 0); - if (obj) { - snprintf(msgnums, sizeof(msgnums), "%d", msgnum); - snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir=? AND msgnum=?", odbc_table); - stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps); - if (!stmt) { - ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql); - ast_odbc_release_obj(obj); - goto yuck; - } - res = SQLFetch(stmt); - if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { - ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql); - SQLFreeHandle (SQL_HANDLE_STMT, stmt); - ast_odbc_release_obj(obj); - goto yuck; + if (!(user = get_user_by_mailbox(mailbox, buf, sizeof(buf)))) + return; + + update_messages_by_imapuser(user, number); +} + +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! */ + ast_debug(4, "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! */ + ast_debug(4, "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! */ + ast_debug(4, "Entering FLAGS callback for message %ld\n", number); + if (number == 0) return; + set_update(stream); +} + + +void mm_notify(MAILSTREAM * stream, char *string, long errflg) +{ + ast_debug(5, "Entering NOTIFY callback, errflag is %ld, string is %s\n", errflg, string); + mm_log (string, errflg); +} + + +void mm_list(MAILSTREAM * stream, int delim, char *mailbox, long attributes) +{ + if (delimiter == '\0') { + delimiter = delim; + } + + ast_debug(5, "Delimiter set to %c and mailbox %s\n",delim, mailbox); + if (attributes & LATT_NOINFERIORS) + ast_debug(5, "no inferiors\n"); + if (attributes & LATT_NOSELECT) + ast_debug(5, "no select\n"); + if (attributes & LATT_MARKED) + ast_debug(5, "marked\n"); + if (attributes & LATT_UNMARKED) + ast_debug(5, "unmarked\n"); +} + + +void mm_lsub(MAILSTREAM * stream, int delimiter, char *mailbox, long attributes) +{ + ast_debug(5, "Delimiter set to %c and mailbox %s\n",delimiter, mailbox); + if (attributes & LATT_NOINFERIORS) + ast_debug(5, "no inferiors\n"); + if (attributes & LATT_NOSELECT) + ast_debug(5, "no select\n"); + if (attributes & LATT_MARKED) + ast_debug(5, "marked\n"); + if (attributes & LATT_UNMARKED) + ast_debug(5, "unmarked\n"); +} + + +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: + ast_debug(1,"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; + + ast_debug(4, "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; + } } - res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL); - if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { - ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql); - SQLFreeHandle (SQL_HANDLE_STMT, stmt); - ast_odbc_release_obj(obj); - goto yuck; + if (!vmu) { + if ((vmu = find_user_realtime_imapuser(mb->user))) { + ast_copy_string(pwd, vmu->imappassword, MAILTMPLEN); + free_user(vmu); + } } - if (sscanf(rowdata, "%d", &x) != 1) - ast_log(LOG_WARNING, "Failed to read message count!\n"); - SQLFreeHandle (SQL_HANDLE_STMT, stmt); - ast_odbc_release_obj(obj); - } else - ast_log(LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database); -yuck: - return x; + } } -static int count_messages(struct ast_vm_user *vmu, char *dir) + +void mm_critical(MAILSTREAM * stream) { - return last_message_index(vmu, dir) + 1; } -static void delete_file(char *sdir, int smsg) + +void mm_nocritical(MAILSTREAM * stream) { - SQLHSTMT stmt; - char sql[PATH_MAX]; - char msgnums[20]; - char *argv[] = { sdir, msgnums }; - struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv }; +} - struct odbc_obj *obj; - obj = ast_odbc_request_obj(odbc_database, 0); - if (obj) { - snprintf(msgnums, sizeof(msgnums), "%d", smsg); - snprintf(sql, sizeof(sql), "DELETE FROM %s WHERE dir=? AND msgnum=?", odbc_table); - stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps); - if (!stmt) - ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql); - else - SQLFreeHandle (SQL_HANDLE_STMT, stmt); - ast_odbc_release_obj(obj); - } else - ast_log(LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database); - return; + +long mm_diskerror(MAILSTREAM * stream, long errcode, long serious) +{ + kill (getpid (), SIGSTOP); + return NIL; } -static void copy_file(char *sdir, int smsg, char *ddir, int dmsg, char *dmailboxuser, char *dmailboxcontext) + +void mm_fatal(char *string) { - SQLHSTMT stmt; - char sql[512]; - char msgnums[20]; - char msgnumd[20]; - struct odbc_obj *obj; - char *argv[] = { ddir, msgnumd, dmailboxuser, dmailboxcontext, sdir, msgnums }; - struct generic_prepare_struct gps = { .sql = sql, .argc = 6, .argv = argv }; + ast_log(LOG_ERROR, "IMAP access FATAL error: %s\n", string); +} - delete_file(ddir, dmsg); - obj = ast_odbc_request_obj(odbc_database, 0); - if (obj) { - snprintf(msgnums, sizeof(msgnums), "%d", smsg); - snprintf(msgnumd, sizeof(msgnumd), "%d", dmsg); - snprintf(sql, sizeof(sql), "INSERT INTO %s (dir, msgnum, context, macrocontext, callerid, origtime, duration, recording, mailboxuser, mailboxcontext) SELECT ?,?,context,macrocontext,callerid,origtime,duration,recording,?,? FROM %s WHERE dir=? AND msgnum=?", odbc_table, odbc_table); - stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps); - if (!stmt) - ast_log(LOG_WARNING, "SQL Execute error!\n[%s] (You probably don't have MySQL 4.1 or later installed)\n\n", sql); - else - SQLFreeHandle(SQL_HANDLE_STMT, stmt); - ast_odbc_release_obj(obj); - } else - ast_log(LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database); - return; +/* C-client callback to handle quota */ +static void mm_parsequota(MAILSTREAM *stream, unsigned char *msg, QUOTALIST *pquota) +{ + struct vm_state *vms; + char *mailbox = stream->mailbox, *user; + char buf[1024] = ""; + unsigned long usage = 0, limit = 0; + + while (pquota) { + usage = pquota->usage; + limit = pquota->limit; + pquota = pquota->next; + } + + if (!(user = get_user_by_mailbox(mailbox, buf, sizeof(buf))) || !(vms = get_vm_state_by_imapuser(user, 2))) { + ast_log(LOG_ERROR, "No state found.\n"); + return; + } + + ast_debug(3, "User %s usage is %lu, limit is %lu\n", user, usage, limit); + + vms->quota_usage = usage; + vms->quota_limit = limit; } -struct insert_cb_struct { - char *dir; - char *msgnum; - void *recording; - size_t recordinglen; - SQLLEN indlen; - const char *context; - const char *macrocontext; - const char *callerid; - const char *origtime; - const char *duration; - char *mailboxuser; - char *mailboxcontext; - const char *category; - char *sql; -}; +static char *get_header_by_tag(char *header, char *tag, char *buf, size_t len) +{ + char *start, *eol_pnt; + int taglen; + + if (ast_strlen_zero(header) || ast_strlen_zero(tag)) + return NULL; + + taglen = strlen(tag) + 1; + if (taglen < 1) + return NULL; + + if (!(start = strstr(header, tag))) + return NULL; + + /* Since we can be called multiple times we should clear our buffer */ + memset(buf, 0, len); -static SQLHSTMT insert_cb(struct odbc_obj *obj, void *vd) + ast_copy_string(buf, start+taglen, len); + if ((eol_pnt = strchr(buf,'\r')) || (eol_pnt = strchr(buf,'\n'))) + *eol_pnt = '\0'; + return buf; +} + +static char *get_user_by_mailbox(char *mailbox, char *buf, size_t len) { - struct insert_cb_struct *d = vd; - int res; - SQLHSTMT stmt; + char *start, *quote, *eol_pnt; - res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt); - if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { - ast_log(LOG_WARNING, "SQL Alloc Handle failed!\n"); + if (ast_strlen_zero(mailbox)) return NULL; - } - res = SQLPrepare(stmt, (unsigned char *)d->sql, SQL_NTS); - if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { - ast_log(LOG_WARNING, "SQL Prepare failed![%s]\n", d->sql); - SQLFreeHandle(SQL_HANDLE_STMT, stmt); + if (!(start = strstr(mailbox, "/user="))) return NULL; - } - SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(d->dir), 0, (void *)d->dir, 0, NULL); - SQLBindParameter(stmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(d->msgnum), 0, (void *)d->msgnum, 0, NULL); - SQLBindParameter(stmt, 3, SQL_PARAM_INPUT, SQL_C_BINARY, SQL_LONGVARBINARY, d->recordinglen, 0, (void *)d->recording, 0, &d->indlen); - SQLBindParameter(stmt, 4, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(d->context), 0, (void *)d->context, 0, NULL); - SQLBindParameter(stmt, 5, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(d->macrocontext), 0, (void *)d->macrocontext, 0, NULL); - SQLBindParameter(stmt, 6, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(d->callerid), 0, (void *)d->callerid, 0, NULL); - SQLBindParameter(stmt, 7, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(d->origtime), 0, (void *)d->origtime, 0, NULL); - SQLBindParameter(stmt, 8, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(d->duration), 0, (void *)d->duration, 0, NULL); - SQLBindParameter(stmt, 9, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(d->mailboxuser), 0, (void *)d->mailboxuser, 0, NULL); - SQLBindParameter(stmt, 10, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(d->mailboxcontext), 0, (void *)d->mailboxcontext, 0, NULL); - if (!ast_strlen_zero(d->category)) { - SQLBindParameter(stmt, 11, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(d->category), 0, (void *)d->category, 0, NULL); + ast_copy_string(buf, start+6, len); + + if (!(quote = strchr(buf, '\"'))) { + if (!(eol_pnt = strchr(buf, '/'))) + eol_pnt = strchr(buf,'}'); + *eol_pnt = '\0'; + return buf; + } else { + eol_pnt = strchr(buf+1,'\"'); + *eol_pnt = '\0'; + return buf+1; } +} + +static struct vm_state *create_vm_state_from_user(struct ast_vm_user *vmu) +{ + struct vm_state *vms_p; - return stmt; + 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 int store_file(char *dir, char *mailboxuser, char *mailboxcontext, int msgnum) +static struct vm_state *get_vm_state_by_imapuser(char *user, int interactive) { - int x = 0; - int fd = -1; - void *fdm = MAP_FAILED; - size_t fdlen = -1; - SQLHSTMT stmt; - char sql[PATH_MAX]; - char msgnums[20]; - char fn[PATH_MAX]; - char full_fn[PATH_MAX]; - char fmt[80] = ""; - char *c; - struct insert_cb_struct d = { - .dir = dir, - .msgnum = msgnums, - .context = "", - .macrocontext = "", - .callerid = "", - .origtime = "", - .duration = "", - .mailboxuser = mailboxuser, - .mailboxcontext = mailboxcontext, - .category = "", - .sql = sql - }; - struct ast_config *cfg = NULL; - struct odbc_obj *obj; - struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE }; + struct vmstate *vlist = NULL; - delete_file(dir, msgnum); - obj = ast_odbc_request_obj(odbc_database, 0); - if (obj) { - ast_copy_string(fmt, vmfmts, sizeof(fmt)); - c = strchr(fmt, '|'); - if (c) - *c = '\0'; - if (!strcasecmp(fmt, "wav49")) - strcpy(fmt, "WAV"); - snprintf(msgnums, sizeof(msgnums), "%d", msgnum); - if (msgnum > -1) - make_file(fn, sizeof(fn), dir, msgnum); - else - ast_copy_string(fn, dir, sizeof(fn)); - snprintf(full_fn, sizeof(full_fn), "%s.txt", fn); - cfg = ast_config_load(full_fn, config_flags); - snprintf(full_fn, sizeof(full_fn), "%s.%s", fn, fmt); - fd = open(full_fn, O_RDWR); - if (fd < 0) { - ast_log(LOG_WARNING, "Open of sound file '%s' failed: %s\n", full_fn, strerror(errno)); - ast_odbc_release_obj(obj); - goto yuck; + AST_LIST_LOCK(&vmstates); + AST_LIST_TRAVERSE(&vmstates, vlist, list) { + if (!vlist->vms) { + ast_debug(3, "error: vms is NULL for %s\n", user); + continue; } - if (cfg) { - d.context = ast_variable_retrieve(cfg, "message", "context"); - if (!d.context) d.context = ""; - d.macrocontext = ast_variable_retrieve(cfg, "message", "macrocontext"); - if (!d.macrocontext) d.macrocontext = ""; - d.callerid = ast_variable_retrieve(cfg, "message", "callerid"); - if (!d.callerid) d.callerid = ""; - d.origtime = ast_variable_retrieve(cfg, "message", "origtime"); - if (!d.origtime) d.origtime = ""; - d.duration = ast_variable_retrieve(cfg, "message", "duration"); - if (!d.duration) d.duration = ""; - d.category = ast_variable_retrieve(cfg, "message", "category"); - if (!d.category) d.category = ""; - } - fdlen = lseek(fd, 0, SEEK_END); - lseek(fd, 0, SEEK_SET); - printf("Length is %zd\n", fdlen); - fdm = mmap(NULL, fdlen, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); - if (fdm == MAP_FAILED) { - ast_log(LOG_WARNING, "Memory map failed!\n"); - ast_odbc_release_obj(obj); - goto yuck; - } - d.recording = fdm; - d.recordinglen = d.indlen = fdlen; /* SQL_LEN_DATA_AT_EXEC(fdlen); */ - if (!ast_strlen_zero(d.category)) - snprintf(sql, sizeof(sql), "INSERT INTO %s (dir,msgnum,recording,context,macrocontext,callerid,origtime,duration,mailboxuser,mailboxcontext,category) VALUES (?,?,?,?,?,?,?,?,?,?,?)", odbc_table); - else - snprintf(sql, sizeof(sql), "INSERT INTO %s (dir,msgnum,recording,context,macrocontext,callerid,origtime,duration,mailboxuser,mailboxcontext) VALUES (?,?,?,?,?,?,?,?,?,?)", odbc_table); - stmt = ast_odbc_prepare_and_execute(obj, insert_cb, &d); - if (stmt) { - SQLFreeHandle(SQL_HANDLE_STMT, stmt); + if (!vlist->vms->imapuser) { + ast_debug(3, "error: imapuser is NULL for %s\n", user); + continue; } - ast_odbc_release_obj(obj); - } else - ast_log(LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database); -yuck: - if (cfg) - ast_config_destroy(cfg); - if (fdm != MAP_FAILED) - munmap(fdm, fdlen); - if (fd > -1) - close(fd); - return x; + + if (!strcmp(vlist->vms->imapuser, user) && (interactive == 2 || vlist->vms->interactive == interactive)) { + AST_LIST_UNLOCK(&vmstates); + return vlist->vms; + } + } + AST_LIST_UNLOCK(&vmstates); + + ast_debug(3, "%s not found in vmstates\n", user); + + return NULL; } -static void rename_file(char *sdir, int smsg, char *mailboxuser, char *mailboxcontext, char *ddir, int dmsg) +static struct vm_state *get_vm_state_by_mailbox(const char *mailbox, int interactive) { - SQLHSTMT stmt; - char sql[PATH_MAX]; - char msgnums[20]; - char msgnumd[20]; - struct odbc_obj *obj; - char *argv[] = { ddir, msgnumd, mailboxuser, mailboxcontext, sdir, msgnums }; - struct generic_prepare_struct gps = { .sql = sql, .argc = 6, .argv = argv }; - delete_file(ddir, dmsg); - obj = ast_odbc_request_obj(odbc_database, 0); - if (obj) { - snprintf(msgnums, sizeof(msgnums), "%d", smsg); - snprintf(msgnumd, sizeof(msgnumd), "%d", dmsg); - snprintf(sql, sizeof(sql), "UPDATE %s SET dir=?, msgnum=?, mailboxuser=?, mailboxcontext=? WHERE dir=? AND msgnum=?", odbc_table); - stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps); - if (!stmt) - ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql); - else - SQLFreeHandle(SQL_HANDLE_STMT, stmt); - ast_odbc_release_obj(obj); - } else - ast_log(LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database); - return; + struct vmstate *vlist = NULL; + + AST_LIST_LOCK(&vmstates); + AST_LIST_TRAVERSE(&vmstates, vlist, list) { + if (!vlist->vms) { + ast_debug(3, "error: vms is NULL for %s\n", mailbox); + continue; + } + if (!vlist->vms->username) { + ast_debug(3, "error: username is NULL for %s\n", mailbox); + continue; + } + + ast_debug(3, "comparing mailbox %s (i=%d) to vmstate mailbox %s (i=%d)\n", mailbox, interactive, vlist->vms->username, vlist->vms->interactive); + + if (!strcmp(vlist->vms->username,mailbox) && vlist->vms->interactive == interactive) { + ast_debug(3, "Found it!\n"); + AST_LIST_UNLOCK(&vmstates); + return vlist->vms; + } + } + AST_LIST_UNLOCK(&vmstates); + + ast_debug(3, "%s not found in vmstates\n", mailbox); + + return NULL; } -#else -#ifndef IMAP_STORAGE -static int count_messages(struct ast_vm_user *vmu, char *dir) +static void vmstate_insert(struct vm_state *vms) { - /* Find all .txt files - even if they are not in sequence from 0000 */ + struct vmstate *v; + struct vm_state *altvms; - int vmcount = 0; - DIR *vmdir = NULL; - struct dirent *vment = NULL; + /* 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) { + ast_debug(3, "Duplicate mailbox %s, copying message info...\n",vms->username); + vms->newmessages = altvms->newmessages; + vms->oldmessages = altvms->oldmessages; + 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; */ + } + } - if (vm_lock_path(dir)) - return ERROR_LOCK_PATH; + if (!(v = ast_calloc(1, sizeof(*v)))) + return; + + v->vms = vms; + + ast_debug(3, "Inserting vm_state for user:%s, mailbox %s\n",vms->imapuser,vms->username); - if ((vmdir = opendir(dir))) { - while ((vment = readdir(vmdir))) { - if (strlen(vment->d_name) > 7 && !strncmp(vment->d_name + 7, ".txt", 4)) - vmcount++; + AST_LIST_LOCK(&vmstates); + AST_LIST_INSERT_TAIL(&vmstates, v, list); + AST_LIST_UNLOCK(&vmstates); +} + +static void vmstate_delete(struct vm_state *vms) +{ + struct vmstate *vc = NULL; + struct vm_state *altvms = NULL; + + /* If interactive, we should copy pertinent info + back to the persistent state (to make update immediate) */ + if (vms->interactive == 1 && (altvms = vms->persist_vms)) { + ast_debug(3, "Duplicate mailbox %s, copying message info...\n", vms->username); + altvms->newmessages = vms->newmessages; + altvms->oldmessages = vms->oldmessages; + altvms->updated = 1; + } + + ast_debug(3, "Removing vm_state for user:%s, mailbox %s\n", vms->imapuser, vms->username); + + AST_LIST_LOCK(&vmstates); + AST_LIST_TRAVERSE_SAFE_BEGIN(&vmstates, vc, list) { + if (vc->vms == vms) { + AST_LIST_REMOVE_CURRENT(list); + break; } - closedir(vmdir); } - ast_unlock_path(dir); + AST_LIST_TRAVERSE_SAFE_END + AST_LIST_UNLOCK(&vmstates); - return vmcount; + if (vc) { + ast_mutex_destroy(&vc->vms->lock); + ast_free(vc); + } + else + ast_log(LOG_ERROR, "No vmstate found for user:%s, mailbox %s\n", vms->imapuser, vms->username); } -static void rename_file(char *sfn, char *dfn) +static void set_update(MAILSTREAM * stream) { - char stxt[PATH_MAX]; - char dtxt[PATH_MAX]; - ast_filerename(sfn, dfn, NULL); - snprintf(stxt, sizeof(stxt), "%s.txt", sfn); - snprintf(dtxt, sizeof(dtxt), "%s.txt", dfn); - if (ast_check_realtime("voicemail_data")) { - ast_update_realtime("voicemail_data", "filename", sfn, "filename", dfn, NULL); + struct vm_state *vms; + char *mailbox = stream->mailbox, *user; + char buf[1024] = ""; + + if (!(user = get_user_by_mailbox(mailbox, buf, sizeof(buf))) || !(vms = get_vm_state_by_imapuser(user, 0))) { + if (user && option_debug > 2) + ast_log(LOG_WARNING, "User %s mailbox not found for update.\n", user); + return; } - rename(stxt, dtxt); + + ast_debug(3, "User %s mailbox set for update.\n", user); + + vms->updated = 1; /* Set updated flag since mailbox changed */ } -#endif -#ifndef IMAP_STORAGE -/*! \brief - * A negative return value indicates an error. - * \note Should always be called with a lock already set on dir. - */ -static int last_message_index(struct ast_vm_user *vmu, char *dir) +static void init_vm_state(struct vm_state *vms) { int x; - unsigned char map[MAXMSGLIMIT] = ""; - DIR *msgdir; - struct dirent *msgdirent; - int msgdirint; - - /* Reading the entire directory into a file map scales better than - * doing a stat repeatedly on a predicted sequence. I suspect this - * is partially due to stat(2) internally doing a readdir(2) itself to - * find each file. */ - msgdir = opendir(dir); - while ((msgdirent = readdir(msgdir))) { - if (sscanf(msgdirent->d_name, "msg%d", &msgdirint) == 1 && msgdirint < MAXMSGLIMIT) - map[msgdirint] = 1; - } - closedir(msgdir); - - for (x = 0; x < vmu->maxmsg; x++) { - if (map[x] == 0) - break; + vms->vmArrayIndex = 0; + for (x = 0; x < 256; x++) { + vms->msgArray[x] = 0; } + ast_mutex_init(&vms->lock); +} - return x - 1; +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; +} +/*! +* \brief Get delimiter via mm_list callback +* \param stream +* +* Determines the delimiter character that is used by the underlying IMAP based mail store. +*/ +static void get_mailbox_delimiter(MAILSTREAM *stream) { + char tmp[50]; + snprintf(tmp, sizeof(tmp), "{%s}", imapserver); + mail_list(stream, tmp, "*"); +} + +/*! +* \brief Check Quota for user +* \param vms a pointer to a vm_state struct, will use the mailstream property of this. +* \param mailbox the mailbox to check the quota for. +* +* Calls imap_getquotaroot, which will populate its results into the vm_state vms input structure. +*/ +static void check_quota(struct vm_state *vms, char *mailbox) { + mail_parameters(NULL, SET_QUOTA, (void *) mm_parsequota); + ast_debug(3, "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 */ + + /*! \brief Lock file path + only return failure if ast_lock_path returns 'timeout', + not if the path does not exist or any other reason + */ + static int vm_lock_path(const char *path) + { + switch (ast_lock_path(path)) { + case AST_LOCK_TIMEOUT: + return -1; + default: + return 0; + } + } + + +#ifdef ODBC_STORAGE + struct generic_prepare_struct { + char *sql; + int argc; + char **argv; + }; + + static SQLHSTMT generic_prepare(struct odbc_obj *obj, void *data) + { + struct generic_prepare_struct *gps = data; + int res, i; + SQLHSTMT stmt; + + res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt); + if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { + ast_log(LOG_WARNING, "SQL Alloc Handle failed!\n"); + return NULL; + } + res = SQLPrepare(stmt, (unsigned char *)gps->sql, SQL_NTS); + if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { + ast_log(LOG_WARNING, "SQL Prepare failed![%s]\n", gps->sql); + SQLFreeHandle(SQL_HANDLE_STMT, stmt); + return NULL; + } + for (i = 0; i < gps->argc; i++) + SQLBindParameter(stmt, i + 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(gps->argv[i]), 0, gps->argv[i], 0, NULL); + + return stmt; + } + + static int retrieve_file(char *dir, int msgnum) + { + int x = 0; + int res; + int fd = -1; + size_t fdlen = 0; + void *fdm = MAP_FAILED; + SQLSMALLINT colcount = 0; + SQLHSTMT stmt; + char sql[PATH_MAX]; + char fmt[80] = ""; + char *c; + char coltitle[256]; + SQLSMALLINT collen; + SQLSMALLINT datatype; + SQLSMALLINT decimaldigits; + SQLSMALLINT nullable; + SQLULEN colsize; + SQLLEN colsize2; + FILE *f = NULL; + char rowdata[80]; + char fn[PATH_MAX]; + char full_fn[PATH_MAX]; + char msgnums[80]; + char *argv[] = { dir, msgnums }; + struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv }; + + struct odbc_obj *obj; + obj = ast_odbc_request_obj(odbc_database, 0); + if (obj) { + ast_copy_string(fmt, vmfmts, sizeof(fmt)); + c = strchr(fmt, '|'); + if (c) + *c = '\0'; + if (!strcasecmp(fmt, "wav49")) + strcpy(fmt, "WAV"); + snprintf(msgnums, sizeof(msgnums), "%d", msgnum); + if (msgnum > -1) + make_file(fn, sizeof(fn), dir, msgnum); + else + ast_copy_string(fn, dir, sizeof(fn)); + snprintf(full_fn, sizeof(full_fn), "%s.txt", fn); + + if (!(f = fopen(full_fn, "w+"))) { + ast_log(LOG_WARNING, "Failed to open/create '%s'\n", full_fn); + goto yuck; + } + + snprintf(full_fn, sizeof(full_fn), "%s.%s", fn, fmt); + snprintf(sql, sizeof(sql), "SELECT * FROM %s WHERE dir=? AND msgnum=?", odbc_table); + stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps); + if (!stmt) { + ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql); + ast_odbc_release_obj(obj); + goto yuck; + } + res = SQLFetch(stmt); + if (res == SQL_NO_DATA) { + SQLFreeHandle (SQL_HANDLE_STMT, stmt); + ast_odbc_release_obj(obj); + goto yuck; + } else if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { + ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql); + SQLFreeHandle (SQL_HANDLE_STMT, stmt); + ast_odbc_release_obj(obj); + goto yuck; + } + fd = open(full_fn, O_RDWR | O_CREAT | O_TRUNC, VOICEMAIL_FILE_MODE); + if (fd < 0) { + ast_log(LOG_WARNING, "Failed to write '%s': %s\n", full_fn, strerror(errno)); + SQLFreeHandle (SQL_HANDLE_STMT, stmt); + ast_odbc_release_obj(obj); + goto yuck; + } + res = SQLNumResultCols(stmt, &colcount); + if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { + ast_log(LOG_WARNING, "SQL Column Count error!\n[%s]\n\n", sql); + SQLFreeHandle (SQL_HANDLE_STMT, stmt); + ast_odbc_release_obj(obj); + goto yuck; + } + if (f) + fprintf(f, "[message]\n"); + for (x = 0; x < colcount; x++) { + rowdata[0] = '\0'; + collen = sizeof(coltitle); + res = SQLDescribeCol(stmt, x + 1, (unsigned char *)coltitle, sizeof(coltitle), &collen, + &datatype, &colsize, &decimaldigits, &nullable); + if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { + ast_log(LOG_WARNING, "SQL Describe Column error!\n[%s]\n\n", sql); + SQLFreeHandle (SQL_HANDLE_STMT, stmt); + ast_odbc_release_obj(obj); + goto yuck; + } + if (!strcasecmp(coltitle, "recording")) { + off_t offset; + res = SQLGetData(stmt, x + 1, SQL_BINARY, rowdata, 0, &colsize2); + fdlen = colsize2; + if (fd > -1) { + char tmp[1] = ""; + lseek(fd, fdlen - 1, SEEK_SET); + if (write(fd, tmp, 1) != 1) { + close(fd); + fd = -1; + continue; + } + /* Read out in small chunks */ + for (offset = 0; offset < colsize2; offset += CHUNKSIZE) { + if ((fdm = mmap(NULL, CHUNKSIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, offset)) == MAP_FAILED) { + ast_log(LOG_WARNING, "Could not mmap the output file: %s (%d)\n", strerror(errno), errno); + SQLFreeHandle(SQL_HANDLE_STMT, stmt); + ast_odbc_release_obj(obj); + goto yuck; + } else { + res = SQLGetData(stmt, x + 1, SQL_BINARY, fdm, CHUNKSIZE, NULL); + munmap(fdm, CHUNKSIZE); + if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { + ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql); + unlink(full_fn); + SQLFreeHandle(SQL_HANDLE_STMT, stmt); + ast_odbc_release_obj(obj); + goto yuck; + } + } + } + truncate(full_fn, fdlen); + } + } else { + SQLLEN ind; + res = SQLGetData(stmt, x + 1, SQL_CHAR, rowdata, sizeof(rowdata), &ind); + if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { + SQLINTEGER nativeerror = 0; + SQLSMALLINT diagbytes = 0; + unsigned char state[10], diagnostic[256]; + SQLGetDiagRec(SQL_HANDLE_STMT, stmt, 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes); + ast_log(LOG_WARNING, "SQL Get Data error: %s: %s!\n[%s]\n\n", state, diagnostic, sql); + SQLFreeHandle (SQL_HANDLE_STMT, stmt); + ast_odbc_release_obj(obj); + goto yuck; + } + if (strcasecmp(coltitle, "msgnum") && strcasecmp(coltitle, "dir") && f) + fprintf(f, "%s=%s\n", coltitle, rowdata); + } + } + SQLFreeHandle (SQL_HANDLE_STMT, stmt); + ast_odbc_release_obj(obj); + } else + ast_log(LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database); + yuck: + if (f) + fclose(f); + if (fd > -1) + close(fd); + return x - 1; + } + + /*! + * \brief Determines the highest message number in use for a given user and mailbox folder. + * \param vmu + * \param dir the folder the mailbox folder to look for messages. Used to construct the SQL where clause. + * + * This method is used when mailboxes are stored in an ODBC back end. + * Typical use to set the msgnum would be to take the value returned from this method and add one to it. + * + * \return the value of zero or greaterto indicate the last message index in use, -1 to indicate none. + */ + static int last_message_index(struct ast_vm_user *vmu, char *dir) + { + int x = 0; + int res; + SQLHSTMT stmt; + char sql[PATH_MAX]; + char rowdata[20]; + char *argv[] = { dir }; + struct generic_prepare_struct gps = { .sql = sql, .argc = 1, .argv = argv }; + + struct odbc_obj *obj; + obj = ast_odbc_request_obj(odbc_database, 0); + if (obj) { + snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir=?", odbc_table); + stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps); + if (!stmt) { + ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql); + ast_odbc_release_obj(obj); + goto yuck; + } + res = SQLFetch(stmt); + if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { + ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql); + SQLFreeHandle (SQL_HANDLE_STMT, stmt); + ast_odbc_release_obj(obj); + goto yuck; + } + res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL); + if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { + ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql); + SQLFreeHandle (SQL_HANDLE_STMT, stmt); + ast_odbc_release_obj(obj); + goto yuck; + } + if (sscanf(rowdata, "%d", &x) != 1) + ast_log(LOG_WARNING, "Failed to read message count!\n"); + SQLFreeHandle (SQL_HANDLE_STMT, stmt); + ast_odbc_release_obj(obj); + } else + ast_log(LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database); + yuck: + return x - 1; + } + + static int message_exists(char *dir, int msgnum) + { + int x = 0; + int res; + SQLHSTMT stmt; + char sql[PATH_MAX]; + char rowdata[20]; + char msgnums[20]; + char *argv[] = { dir, msgnums }; + struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv }; + + struct odbc_obj *obj; + obj = ast_odbc_request_obj(odbc_database, 0); + if (obj) { + snprintf(msgnums, sizeof(msgnums), "%d", msgnum); + snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir=? AND msgnum=?", odbc_table); + stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps); + if (!stmt) { + ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql); + ast_odbc_release_obj(obj); + goto yuck; + } + res = SQLFetch(stmt); + if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { + ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql); + SQLFreeHandle (SQL_HANDLE_STMT, stmt); + ast_odbc_release_obj(obj); + goto yuck; + } + res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL); + if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { + ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql); + SQLFreeHandle (SQL_HANDLE_STMT, stmt); + ast_odbc_release_obj(obj); + goto yuck; + } + if (sscanf(rowdata, "%d", &x) != 1) + ast_log(LOG_WARNING, "Failed to read message count!\n"); + SQLFreeHandle (SQL_HANDLE_STMT, stmt); + ast_odbc_release_obj(obj); + } else + ast_log(LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database); + yuck: + return x; + } + + static int count_messages(struct ast_vm_user *vmu, char *dir) + { + return last_message_index(vmu, dir) + 1; + } + + static void delete_file(char *sdir, int smsg) + { + SQLHSTMT stmt; + char sql[PATH_MAX]; + char msgnums[20]; + char *argv[] = { sdir, msgnums }; + struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv }; + + struct odbc_obj *obj; + obj = ast_odbc_request_obj(odbc_database, 0); + if (obj) { + snprintf(msgnums, sizeof(msgnums), "%d", smsg); + snprintf(sql, sizeof(sql), "DELETE FROM %s WHERE dir=? AND msgnum=?", odbc_table); + stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps); + if (!stmt) + ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql); + else + SQLFreeHandle (SQL_HANDLE_STMT, stmt); + ast_odbc_release_obj(obj); + } else + ast_log(LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database); + return; + } + + static void copy_file(char *sdir, int smsg, char *ddir, int dmsg, char *dmailboxuser, char *dmailboxcontext) + { + SQLHSTMT stmt; + char sql[512]; + char msgnums[20]; + char msgnumd[20]; + struct odbc_obj *obj; + char *argv[] = { ddir, msgnumd, dmailboxuser, dmailboxcontext, sdir, msgnums }; + struct generic_prepare_struct gps = { .sql = sql, .argc = 6, .argv = argv }; + + delete_file(ddir, dmsg); + obj = ast_odbc_request_obj(odbc_database, 0); + if (obj) { + snprintf(msgnums, sizeof(msgnums), "%d", smsg); + snprintf(msgnumd, sizeof(msgnumd), "%d", dmsg); + snprintf(sql, sizeof(sql), "INSERT INTO %s (dir, msgnum, context, macrocontext, callerid, origtime, duration, recording, mailboxuser, mailboxcontext) SELECT ?,?,context,macrocontext,callerid,origtime,duration,recording,?,? FROM %s WHERE dir=? AND msgnum=?", odbc_table, odbc_table); + stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps); + if (!stmt) + ast_log(LOG_WARNING, "SQL Execute error!\n[%s] (You probably don't have MySQL 4.1 or later installed)\n\n", sql); + else + SQLFreeHandle(SQL_HANDLE_STMT, stmt); + ast_odbc_release_obj(obj); + } else + ast_log(LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database); + return; + } + + struct insert_cb_struct { + char *dir; + char *msgnum; + void *recording; + size_t recordinglen; + SQLLEN indlen; + const char *context; + const char *macrocontext; + const char *callerid; + const char *origtime; + const char *duration; + char *mailboxuser; + char *mailboxcontext; + const char *category; + char *sql; + }; + + static SQLHSTMT insert_cb(struct odbc_obj *obj, void *vd) + { + struct insert_cb_struct *d = vd; + int res; + SQLHSTMT stmt; + + res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt); + if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { + ast_log(LOG_WARNING, "SQL Alloc Handle failed!\n"); + return NULL; + } + + res = SQLPrepare(stmt, (unsigned char *)d->sql, SQL_NTS); + if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { + ast_log(LOG_WARNING, "SQL Prepare failed![%s]\n", d->sql); + SQLFreeHandle(SQL_HANDLE_STMT, stmt); + return NULL; + } + + SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(d->dir), 0, (void *)d->dir, 0, NULL); + SQLBindParameter(stmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(d->msgnum), 0, (void *)d->msgnum, 0, NULL); + SQLBindParameter(stmt, 3, SQL_PARAM_INPUT, SQL_C_BINARY, SQL_LONGVARBINARY, d->recordinglen, 0, (void *)d->recording, 0, &d->indlen); + SQLBindParameter(stmt, 4, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(d->context), 0, (void *)d->context, 0, NULL); + SQLBindParameter(stmt, 5, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(d->macrocontext), 0, (void *)d->macrocontext, 0, NULL); + SQLBindParameter(stmt, 6, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(d->callerid), 0, (void *)d->callerid, 0, NULL); + SQLBindParameter(stmt, 7, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(d->origtime), 0, (void *)d->origtime, 0, NULL); + SQLBindParameter(stmt, 8, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(d->duration), 0, (void *)d->duration, 0, NULL); + SQLBindParameter(stmt, 9, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(d->mailboxuser), 0, (void *)d->mailboxuser, 0, NULL); + SQLBindParameter(stmt, 10, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(d->mailboxcontext), 0, (void *)d->mailboxcontext, 0, NULL); + if (!ast_strlen_zero(d->category)) { + SQLBindParameter(stmt, 11, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(d->category), 0, (void *)d->category, 0, NULL); + } + + return stmt; + } + + static int store_file(char *dir, char *mailboxuser, char *mailboxcontext, int msgnum) + { + int x = 0; + int fd = -1; + void *fdm = MAP_FAILED; + size_t fdlen = -1; + SQLHSTMT stmt; + char sql[PATH_MAX]; + char msgnums[20]; + char fn[PATH_MAX]; + char full_fn[PATH_MAX]; + char fmt[80] = ""; + char *c; + struct insert_cb_struct d = { + .dir = dir, + .msgnum = msgnums, + .context = "", + .macrocontext = "", + .callerid = "", + .origtime = "", + .duration = "", + .mailboxuser = mailboxuser, + .mailboxcontext = mailboxcontext, + .category = "", + .sql = sql + }; + struct ast_config *cfg = NULL; + struct odbc_obj *obj; + struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE }; + + delete_file(dir, msgnum); + obj = ast_odbc_request_obj(odbc_database, 0); + if (obj) { + ast_copy_string(fmt, vmfmts, sizeof(fmt)); + c = strchr(fmt, '|'); + if (c) + *c = '\0'; + if (!strcasecmp(fmt, "wav49")) + strcpy(fmt, "WAV"); + snprintf(msgnums, sizeof(msgnums), "%d", msgnum); + if (msgnum > -1) + make_file(fn, sizeof(fn), dir, msgnum); + else + ast_copy_string(fn, dir, sizeof(fn)); + snprintf(full_fn, sizeof(full_fn), "%s.txt", fn); + cfg = ast_config_load(full_fn, config_flags); + snprintf(full_fn, sizeof(full_fn), "%s.%s", fn, fmt); + fd = open(full_fn, O_RDWR); + if (fd < 0) { + ast_log(LOG_WARNING, "Open of sound file '%s' failed: %s\n", full_fn, strerror(errno)); + ast_odbc_release_obj(obj); + goto yuck; + } + if (cfg) { + d.context = ast_variable_retrieve(cfg, "message", "context"); + if (!d.context) d.context = ""; + d.macrocontext = ast_variable_retrieve(cfg, "message", "macrocontext"); + if (!d.macrocontext) d.macrocontext = ""; + d.callerid = ast_variable_retrieve(cfg, "message", "callerid"); + if (!d.callerid) d.callerid = ""; + d.origtime = ast_variable_retrieve(cfg, "message", "origtime"); + if (!d.origtime) d.origtime = ""; + d.duration = ast_variable_retrieve(cfg, "message", "duration"); + if (!d.duration) d.duration = ""; + d.category = ast_variable_retrieve(cfg, "message", "category"); + if (!d.category) d.category = ""; + } + fdlen = lseek(fd, 0, SEEK_END); + lseek(fd, 0, SEEK_SET); + printf("Length is %zd\n", fdlen); + fdm = mmap(NULL, fdlen, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (fdm == MAP_FAILED) { + ast_log(LOG_WARNING, "Memory map failed!\n"); + ast_odbc_release_obj(obj); + goto yuck; + } + d.recording = fdm; + d.recordinglen = d.indlen = fdlen; /* SQL_LEN_DATA_AT_EXEC(fdlen); */ + if (!ast_strlen_zero(d.category)) + snprintf(sql, sizeof(sql), "INSERT INTO %s (dir,msgnum,recording,context,macrocontext,callerid,origtime,duration,mailboxuser,mailboxcontext,category) VALUES (?,?,?,?,?,?,?,?,?,?,?)", odbc_table); + else + snprintf(sql, sizeof(sql), "INSERT INTO %s (dir,msgnum,recording,context,macrocontext,callerid,origtime,duration,mailboxuser,mailboxcontext) VALUES (?,?,?,?,?,?,?,?,?,?)", odbc_table); + stmt = ast_odbc_prepare_and_execute(obj, insert_cb, &d); + if (stmt) { + SQLFreeHandle(SQL_HANDLE_STMT, stmt); + } + ast_odbc_release_obj(obj); + } else + ast_log(LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database); + yuck: + if (cfg) + ast_config_destroy(cfg); + if (fdm != MAP_FAILED) + munmap(fdm, fdlen); + if (fd > -1) + close(fd); + return x; + } + + static void rename_file(char *sdir, int smsg, char *mailboxuser, char *mailboxcontext, char *ddir, int dmsg) + { + SQLHSTMT stmt; + char sql[PATH_MAX]; + char msgnums[20]; + char msgnumd[20]; + struct odbc_obj *obj; + char *argv[] = { ddir, msgnumd, mailboxuser, mailboxcontext, sdir, msgnums }; + struct generic_prepare_struct gps = { .sql = sql, .argc = 6, .argv = argv }; + + delete_file(ddir, dmsg); + obj = ast_odbc_request_obj(odbc_database, 0); + if (obj) { + snprintf(msgnums, sizeof(msgnums), "%d", smsg); + snprintf(msgnumd, sizeof(msgnumd), "%d", dmsg); + snprintf(sql, sizeof(sql), "UPDATE %s SET dir=?, msgnum=?, mailboxuser=?, mailboxcontext=? WHERE dir=? AND msgnum=?", odbc_table); + stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps); + if (!stmt) + ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql); + else + SQLFreeHandle(SQL_HANDLE_STMT, stmt); + ast_odbc_release_obj(obj); + } else + ast_log(LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database); + return; + } + +#else +#ifndef IMAP_STORAGE + static int count_messages(struct ast_vm_user *vmu, char *dir) + { + /* Find all .txt files - even if they are not in sequence from 0000 */ + + int vmcount = 0; + DIR *vmdir = NULL; + struct dirent *vment = NULL; + + if (vm_lock_path(dir)) + return ERROR_LOCK_PATH; + + if ((vmdir = opendir(dir))) { + while ((vment = readdir(vmdir))) { + if (strlen(vment->d_name) > 7 && !strncmp(vment->d_name + 7, ".txt", 4)) + vmcount++; + } + closedir(vmdir); + } + ast_unlock_path(dir); + + return vmcount; + } + + static void rename_file(char *sfn, char *dfn) + { + char stxt[PATH_MAX]; + char dtxt[PATH_MAX]; + ast_filerename(sfn, dfn, NULL); + snprintf(stxt, sizeof(stxt), "%s.txt", sfn); + snprintf(dtxt, sizeof(dtxt), "%s.txt", dfn); + if (ast_check_realtime("voicemail_data")) { + ast_update_realtime("voicemail_data", "filename", sfn, "filename", dfn, NULL); + } + rename(stxt, dtxt); + } +#endif + +#ifndef IMAP_STORAGE + /*! \brief + * A negative return value indicates an error. + * \note Should always be called with a lock already set on dir. + */ + static int last_message_index(struct ast_vm_user *vmu, char *dir) + { + int x; + unsigned char map[MAXMSGLIMIT] = ""; + DIR *msgdir; + struct dirent *msgdirent; + int msgdirint; + + /* Reading the entire directory into a file map scales better than + * doing a stat repeatedly on a predicted sequence. I suspect this + * is partially due to stat(2) internally doing a readdir(2) itself to + * find each file. */ + msgdir = opendir(dir); + while ((msgdirent = readdir(msgdir))) { + if (sscanf(msgdirent->d_name, "msg%d", &msgdirint) == 1 && msgdirint < MAXMSGLIMIT) + map[msgdirint] = 1; + } + closedir(msgdir); + + for (x = 0; x < vmu->maxmsg; x++) { + if (map[x] == 0) + break; + } + + return x - 1; + } +#if (defined(IMAP_STORAGE) || defined(ODBC_STORAGE)) + /*! + * \brief Removes a voicemail message file. + * \param dir the path to the message file. + * \param msgnum the unique number for the message within the mailbox. + * + * Removes the message content file and the information file. + * This method is used by the DISPOSE macro when mailboxes are stored in an ODBC back end. + * Typical use is to clean up after a RETRIEVE operation. + * Note that this does not remove the message from the mailbox folders, to do that we would use delete_file(). + * \return zero on success, -1 on error. + */ + 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 + #endif /* #ifndef IMAP_STORAGE */ #endif /* #else of #ifdef ODBC_STORAGE */ @@ -1813,6 +3089,15 @@ static void copy_plain_file(char *frompath, char *topath) ast_variables_destroy(var); } +#if (!defined(ODBC_STORAGE) && !defined(IMAP_STORAGE)) +/*! +* \brief Removes the voicemail sound and information file. +* \param file The path to the sound file. This will be the the folder and message index, without the extension. +* +* This is used by the DELETE macro when voicemails are stored on the file system. +* +* \return zero on success, -1 on error. +*/ static int vm_delete(char *file) { char *txt; @@ -1821,8 +3106,8 @@ static int vm_delete(char *file) txtsize = (strlen(file) + 5) * sizeof(char); txt = alloca(txtsize); /* Sprintf here would safe because we alloca'd exactly the right length, - * but trying to eliminate all sprintf's anyhow - */ + * but trying to eliminate all sprintf's anyhow + */ if (ast_check_realtime("voicemail_data")) { ast_destroy_realtime("voicemail_data", "filename", file, NULL); } @@ -1830,7 +3115,7 @@ static int vm_delete(char *file) unlink(txt); return ast_filedelete(file, NULL); } - +#endif static int inbuf(struct baseio *bio, FILE *fi) { int l; @@ -1973,9 +3258,9 @@ static char *quote(const char *from, char *to, size_t len) } /*! \brief - * fill in *tm for current time according to the proper timezone, if any. - * Return tm so it can be used as a function argument. - */ +* fill in *tm for current time according to the proper timezone, if any. +* Return tm so it can be used as a function argument. +*/ static const struct ast_tm *vmu_tm(const struct ast_vm_user *vmu, struct ast_tm *tm) { const struct vm_zone *z = NULL; @@ -1995,22 +3280,6 @@ static const struct ast_tm *vmu_tm(const struct ast_vm_user *vmu, struct ast_tm return tm; } -/*! \brief 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]; @@ -2113,6 +3382,8 @@ static void make_email_file(FILE *p, char *srcemail, struct ast_vm_user *vmu, in fprintf(p, "X-Asterisk-VM-Duration: %d" ENDL, duration); if (!ast_strlen_zero(category)) { fprintf(p, "X-Asterisk-VM-Category: %s" ENDL, category); + } else { + fprintf(p, "X-Asterisk-VM-Category: " ENDL); } fprintf(p, "X-Asterisk-VM-Message-Type: %s" ENDL, msgnum > -1 ? "Message" : greeting_attachment); fprintf(p, "X-Asterisk-VM-Orig-date: %s" ENDL, date); @@ -2219,7 +3490,7 @@ static int sendmail(char *srcemail, struct ast_vm_user *vmu, int msgnum, char *c format = "WAV"; ast_debug(3, "Attaching file '%s', format '%s', uservm is '%d', global is %d\n", attach, format, attach_user_voicemail, ast_test_flag((&globalflags), VM_ATTACH)); /* Make a temporary file instead of piping directly to sendmail, in case the mail - command hangs */ + command hangs */ if ((p = vm_mkftemp(tmp)) == NULL) { ast_log(LOG_WARNING, "Unable to launch '%s' (can't create temporary file)\n", mailcmd); return -1; @@ -2377,77 +3648,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)) - return; - - ast_free(vmu); -} - static void free_zone(struct vm_zone *z) { ast_free(z); } -static const char *mbox(int id) -{ - static const char *msgs[] = { -#ifdef IMAP_STORAGE - imapfolder, -#else - "INBOX", -#endif - "Old", - "Work", - "Family", - "Friends", - "Cust1", - "Cust2", - "Cust3", - "Cust4", - "Cust5", - "Deleted", - }; - 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; -#ifdef IMAP_STORAGE - if (!strcasecmp(folder, imapfolder)) -#else - if (!strcasecmp(folder, "INBOX")) -#endif - 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 if (!strcasecmp(folder, "Deleted")) - return 10; - 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) @@ -2600,2715 +3805,2012 @@ static int has_voicemail(const char *mailbox, const char *folder) #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; - - /* Attach only the first format */ - fmt = ast_strdupa(fmt); - stringp = fmt; - strsep(&stringp, "|"); +#endif +#ifndef IMAP_STORAGE + /* copy message only used by file storage */ + static int copy_message(struct ast_channel *chan, struct ast_vm_user *vmu, int imbox, int msgnum, long duration, struct ast_vm_user *recip, char *fmt, char *dir) + { + char fromdir[PATH_MAX], todir[PATH_MAX], frompath[PATH_MAX], topath[PATH_MAX]; + const char *frombox = mbox(imbox); + int recipmsgnum; - if (!ast_strlen_zero(vmu->serveremail)) - myserveremail = vmu->serveremail; + ast_log(LOG_NOTICE, "Copying message from %s@%s to %s@%s\n", vmu->mailbox, vmu->context, recip->mailbox, recip->context); - if (msgnum > -1) - make_file(fn, sizeof(fn), dir, msgnum); - else - ast_copy_string (fn, dir, sizeof(fn)); - - 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; - } + create_dirpath(todir, sizeof(todir), recip->context, recip->mailbox, "INBOX"); + + if (!dir) + make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, frombox); + else + ast_copy_string(fromdir, dir, sizeof(fromdir)); - if (!strcmp(fmt, "wav49")) - fmt = "WAV"; - ast_debug(3, "Storing file '%s', format '%s'\n", fn, fmt); + make_file(frompath, sizeof(frompath), fromdir, msgnum); + make_dir(todir, sizeof(todir), recip->context, recip->mailbox, "INBOX"); - /* Make a temporary file instead of piping directly to sendmail, in case the mail - command hangs. */ - if (!(p = vm_mkftemp(tmp))) { - ast_log(LOG_WARNING, "Unable to store '%s' (can't create temporary file)\n", fn); - if (tempcopy) - *(vmu->email) = '\0'; - return -1; - } + if (vm_lock_path(todir)) + return ERROR_LOCK_PATH; - if (msgnum < 0 && imapgreetings) { - init_mailstream(vms, GREETINGS_FOLDER); - imap_delete_old_greeting(fn, vms); + recipmsgnum = last_message_index(recip, todir) + 1; + if (recipmsgnum < recip->maxmsg) { + make_file(topath, sizeof(topath), todir, recipmsgnum); + COPY(fromdir, msgnum, todir, recipmsgnum, recip->mailbox, recip->context, frompath, topath); + } else { + ast_log(LOG_ERROR, "Recipient mailbox %s@%s is full\n", recip->mailbox, recip->context); + } + ast_unlock_path(todir); + notify_new_message(chan, recip, NULL, recipmsgnum, duration, fmt, S_OR(chan->cid.cid_num, NULL), S_OR(chan->cid.cid_name, NULL)); + + return 0; } - - make_email_file(p, myserveremail, vmu, msgnum, vmu->context, vmu->mailbox, S_OR(chan->cid.cid_num, NULL), S_OR(chan->cid.cid_name, NULL), fn, fmt, duration, 1, chan, NULL, 1); - /* read mail file to memory */ - len = ftell(p); - rewind(p); - if (!(buf = ast_malloc(len + 1))) { - ast_log(LOG_ERROR, "Can't allocate %ld bytes to read message\n", len + 1); - fclose(p); - if (tempcopy) - *(vmu->email) = '\0'; - return -1; +#endif +#if !(defined(IMAP_STORAGE) || defined(ODBC_STORAGE)) + static int messagecount(const char *context, const char *mailbox, const char *folder) + { + return __has_voicemail(context, mailbox, folder, 0); } - fread(buf, len, 1, p); - ((char *)buf)[len] = '\0'; - INIT(&str, mail_string, buf, len); - init_mailstream(vms, NEW_FOLDER); - imap_mailbox_name(mailbox, sizeof(mailbox), vms, NEW_FOLDER, 1); - if (!mail_append(vms->mailstream, mailbox, &str)) - ast_log(LOG_ERROR, "Error while sending the message to %s\n", mailbox); - fclose(p); - unlink(tmp); - ast_free(buf); - ast_debug(3, "%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; + static int __has_voicemail(const char *context, const char *mailbox, const char *folder, int shortcircuit) + { + DIR *dir; + struct dirent *de; + char fn[256]; + int ret = 0; - 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; + /* If no mailbox, return immediately */ + 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; - } - } - - /* No IMAP account available */ - if (vmu->imapuser[0] == '\0') { - ast_log(LOG_WARNING, "IMAP user not set for mailbox %s\n", vmu->mailbox); - free_user(vmu); - return -1; - } + if (ast_strlen_zero(folder)) + folder = "INBOX"; + if (ast_strlen_zero(context)) + context = "default"; - /* 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) { - ast_debug(3, "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; - } - } + snprintf(fn, sizeof(fn), "%s%s/%s/%s", VM_SPOOL_DIR, context, mailbox, folder); - /* 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 (!(dir = opendir(fn))) + return 0; - if (!vms_p) { - ast_debug(3, "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 */ - ast_debug(3, "Copied %s to %s\n", vmu->imapuser, vms_p->imapuser); - vms_p->updated = 1; - /* set mailbox to INBOX! */ - ast_copy_string(vms_p->curbox, mbox(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, "Houston we have a problem - 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; + while ((de = readdir(dir))) { + if (!strncasecmp(de->d_name, "msg", 3)) { + if (shortcircuit) { + ret = 1; + break; + } else if (!strncasecmp(de->d_name + 8, "txt", 3)) + ret++; + } } - 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; + closedir(dir); - ast_debug(3, "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; + return ret; } - if (context) { - *context = '\0'; - mailboxnc = tmp; - context++; - } else { - context = "default"; - mailboxnc = (char *)mailbox_context; - } - if (newmsgs) { - if ((*newmsgs = messagecount(context, mailboxnc, imapfolder)) < 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, ',')) { + + static int has_voicemail(const char *mailbox, const char *folder) + { + char tmp[256], *tmp2 = tmp, *mbox, *context; + ast_copy_string(tmp, mailbox, sizeof(tmp)); while ((mbox = strsep(&tmp2, ","))) { - if (!ast_strlen_zero(mbox)) { - if (has_voicemail(mbox, folder)) - return 1; - } + if ((context = strchr(mbox, '@'))) + *context++ = '\0'; + else + context = "default"; + if (__has_voicemail(context, mbox, folder, 1)) + 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 999,999,999 messages... */ - 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 */ -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) -{ - char fromdir[PATH_MAX], todir[PATH_MAX], frompath[PATH_MAX], topath[PATH_MAX]; - const char *frombox = mbox(imbox); - int recipmsgnum; - - ast_log(LOG_NOTICE, "Copying message from %s@%s to %s@%s\n", vmu->mailbox, vmu->context, recip->mailbox, recip->context); - - create_dirpath(todir, sizeof(todir), recip->context, recip->mailbox, "INBOX"); - - if (!dir) - make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, frombox); - else - ast_copy_string(fromdir, dir, sizeof(fromdir)); - - make_file(frompath, sizeof(frompath), fromdir, msgnum); - make_dir(todir, sizeof(todir), recip->context, recip->mailbox, "INBOX"); - - if (vm_lock_path(todir)) - return ERROR_LOCK_PATH; - - recipmsgnum = last_message_index(recip, todir) + 1; - if (recipmsgnum < recip->maxmsg) { - make_file(topath, sizeof(topath), todir, recipmsgnum); - COPY(fromdir, msgnum, todir, recipmsgnum, recip->mailbox, recip->context, frompath, topath); - } else { - ast_log(LOG_ERROR, "Recipient mailbox %s@%s is full\n", recip->mailbox, recip->context); } - ast_unlock_path(todir); - notify_new_message(chan, recip, NULL, recipmsgnum, duration, fmt, S_OR(chan->cid.cid_num, NULL), S_OR(chan->cid.cid_name, NULL)); - - return 0; -} -#endif -#if !(defined(IMAP_STORAGE) || defined(ODBC_STORAGE)) -static int messagecount(const char *context, const char *mailbox, const char *folder) -{ - return __has_voicemail(context, mailbox, folder, 0); -} -static int __has_voicemail(const char *context, const char *mailbox, const char *folder, int shortcircuit) -{ - DIR *dir; - struct dirent *de; - char fn[256]; - int ret = 0; + static int inboxcount(const char *mailbox, int *newmsgs, int *oldmsgs) + { + char tmp[256]; + char *context; - /* If no mailbox, return immediately */ - if (ast_strlen_zero(mailbox)) - return 0; + /* If no mailbox, return immediately */ + if (ast_strlen_zero(mailbox)) + return 0; - if (ast_strlen_zero(folder)) - folder = "INBOX"; - if (ast_strlen_zero(context)) - context = "default"; + if (newmsgs) + *newmsgs = 0; + if (oldmsgs) + *oldmsgs = 0; - snprintf(fn, sizeof(fn), "%s%s/%s/%s", VM_SPOOL_DIR, context, mailbox, folder); + if (strchr(mailbox, ',')) { + int tmpnew, tmpold; + char *mb, *cur; - if (!(dir = opendir(fn))) - return 0; - - while ((de = readdir(dir))) { - if (!strncasecmp(de->d_name, "msg", 3)) { - if (shortcircuit) { - ret = 1; - break; - } else if (!strncasecmp(de->d_name + 8, "txt", 3)) - ret++; + ast_copy_string(tmp, mailbox, 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; } - } - - closedir(dir); - - return ret; -} - -static int has_voicemail(const char *mailbox, const char *folder) -{ - char tmp[256], *tmp2 = tmp, *mbox, *context; - ast_copy_string(tmp, mailbox, sizeof(tmp)); - while ((mbox = strsep(&tmp2, ","))) { - if ((context = strchr(mbox, '@'))) + ast_copy_string(tmp, mailbox, sizeof(tmp)); + + if ((context = strchr(tmp, '@'))) *context++ = '\0'; else context = "default"; - if (__has_voicemail(context, mbox, folder, 1)) - return 1; - } - return 0; -} + if (newmsgs) + *newmsgs = __has_voicemail(context, tmp, "INBOX", 0); + if (oldmsgs) + *oldmsgs = __has_voicemail(context, tmp, "Old", 0); -static int inboxcount(const char *mailbox, int *newmsgs, int *oldmsgs) -{ - char tmp[256]; - char *context; - - /* If no mailbox, return immediately */ - if (ast_strlen_zero(mailbox)) - return 0; - - if (newmsgs) - *newmsgs = 0; - if (oldmsgs) - *oldmsgs = 0; - - if (strchr(mailbox, ',')) { - int tmpnew, tmpold; - char *mb, *cur; - - ast_copy_string(tmp, mailbox, 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; } - ast_copy_string(tmp, mailbox, sizeof(tmp)); - - if ((context = strchr(tmp, '@'))) - *context++ = '\0'; - else - context = "default"; - - if (newmsgs) - *newmsgs = __has_voicemail(context, tmp, "INBOX", 0); - if (oldmsgs) - *oldmsgs = __has_voicemail(context, tmp, "Old", 0); - - return 0; -} - #endif -static void run_externnotify(char *context, char *extension) -{ - char arguments[255]; - char ext_context[256] = ""; - int newvoicemails = 0, oldvoicemails = 0; - struct ast_smdi_mwi_message *mwi_msg; - - if (!ast_strlen_zero(context)) - snprintf(ext_context, sizeof(ext_context), "%s@%s", extension, context); - else - ast_copy_string(ext_context, extension, sizeof(ext_context)); + static void run_externnotify(char *context, char *extension) + { + char arguments[255]; + char ext_context[256] = ""; + int newvoicemails = 0, oldvoicemails = 0; + struct ast_smdi_mwi_message *mwi_msg; - if (smdi_iface) { - if (ast_app_has_voicemail(ext_context, NULL)) - ast_smdi_mwi_set(smdi_iface, extension); + if (!ast_strlen_zero(context)) + snprintf(ext_context, sizeof(ext_context), "%s@%s", extension, context); else - ast_smdi_mwi_unset(smdi_iface, extension); - - if ((mwi_msg = ast_smdi_mwi_message_wait_station(smdi_iface, SMDI_MWI_WAIT_TIMEOUT, extension))) { - ast_log(LOG_ERROR, "Error executing SMDI MWI change for %s\n", extension); - if (!strncmp(mwi_msg->cause, "INV", 3)) - ast_log(LOG_ERROR, "Invalid MWI extension: %s\n", mwi_msg->fwd_st); - else if (!strncmp(mwi_msg->cause, "BLK", 3)) - ast_log(LOG_WARNING, "MWI light was already on or off for %s\n", mwi_msg->fwd_st); - ast_log(LOG_WARNING, "The switch reported '%s'\n", mwi_msg->cause); - ASTOBJ_UNREF(mwi_msg, ast_smdi_mwi_message_destroy); - } else { - ast_debug(1, "Successfully executed SMDI MWI change for %s\n", extension); + ast_copy_string(ext_context, extension, sizeof(ext_context)); + + if (smdi_iface) { + if (ast_app_has_voicemail(ext_context, NULL)) + ast_smdi_mwi_set(smdi_iface, extension); + else + ast_smdi_mwi_unset(smdi_iface, extension); + + if ((mwi_msg = ast_smdi_mwi_message_wait_station(smdi_iface, SMDI_MWI_WAIT_TIMEOUT, extension))) { + ast_log(LOG_ERROR, "Error executing SMDI MWI change for %s\n", extension); + if (!strncmp(mwi_msg->cause, "INV", 3)) + ast_log(LOG_ERROR, "Invalid MWI extension: %s\n", mwi_msg->fwd_st); + else if (!strncmp(mwi_msg->cause, "BLK", 3)) + ast_log(LOG_WARNING, "MWI light was already on or off for %s\n", mwi_msg->fwd_st); + ast_log(LOG_WARNING, "The switch reported '%s'\n", mwi_msg->cause); + ASTOBJ_UNREF(mwi_msg, ast_smdi_mwi_message_destroy); + } else { + ast_debug(1, "Successfully executed SMDI MWI change for %s\n", extension); + } } - } - if (!ast_strlen_zero(externnotify)) { - if (inboxcount(ext_context, &newvoicemails, &oldvoicemails)) { - ast_log(LOG_ERROR, "Problem in calculating number of voicemail messages available for extension %s\n", extension); - } else { - snprintf(arguments, sizeof(arguments), "%s %s %s %d&", externnotify, context, extension, newvoicemails); - ast_debug(1, "Executing %s\n", arguments); - ast_safe_system(arguments); + if (!ast_strlen_zero(externnotify)) { + if (inboxcount(ext_context, &newvoicemails, &oldvoicemails)) { + ast_log(LOG_ERROR, "Problem in calculating number of voicemail messages available for extension %s\n", extension); + } else { + snprintf(arguments, sizeof(arguments), "%s %s %s %d&", externnotify, context, extension, newvoicemails); + ast_debug(1, "Executing %s\n", arguments); + ast_safe_system(arguments); + } } } -} -struct leave_vm_options { - unsigned int flags; - signed char record_gain; - char *exitcontext; -}; + struct leave_vm_options { + unsigned int flags; + signed char record_gain; + char *exitcontext; + }; -static int leave_voicemail(struct ast_channel *chan, char *ext, struct leave_vm_options *options) -{ + static int leave_voicemail(struct ast_channel *chan, char *ext, struct leave_vm_options *options) + { #ifdef IMAP_STORAGE - int newmsgs, oldmsgs; - struct vm_state *vms = NULL; + int newmsgs, oldmsgs; #endif - char txtfile[PATH_MAX], tmptxtfile[PATH_MAX]; - char callerid[256]; - FILE *txt; - char date[256]; - int txtdes; - int res = 0; - int msgnum; - int duration = 0; - int ausemacro = 0; - int ousemacro = 0; - int ouseexten = 0; - int rtmsgid = 0; - char tmpid[16]; - char tmpdur[16]; - char priority[16]; - char origtime[16]; - char dir[PATH_MAX], tmpdir[PATH_MAX]; - char fn[PATH_MAX]; - char prefile[PATH_MAX] = ""; - char tempfile[PATH_MAX] = ""; - char ext_context[256] = ""; - char fmt[80]; - char *context; - char ecodes[17] = "#"; - char tmp[1024] = "", *tmpptr; - struct ast_vm_user *vmu; - struct ast_vm_user svm; - const char *category = NULL, *code, *alldtmf = "0123456789ABCD*#"; - - ast_copy_string(tmp, ext, sizeof(tmp)); - ext = tmp; - if ((context = strchr(tmp, '@'))) { - *context++ = '\0'; - tmpptr = strchr(context, '&'); - } else { - tmpptr = strchr(ext, '&'); - } + char txtfile[PATH_MAX], tmptxtfile[PATH_MAX]; + struct vm_state *vms = NULL; + char callerid[256]; + FILE *txt; + char date[256]; + int txtdes; + int res = 0; + int msgnum; + int duration = 0; + int ausemacro = 0; + int ousemacro = 0; + int ouseexten = 0; + int rtmsgid = 0; + char tmpid[16]; + char tmpdur[16]; + char priority[16]; + char origtime[16]; + char dir[PATH_MAX], tmpdir[PATH_MAX]; + char fn[PATH_MAX]; + char prefile[PATH_MAX] = ""; + char tempfile[PATH_MAX] = ""; + char ext_context[256] = ""; + char fmt[80]; + char *context; + char ecodes[17] = "#"; + char tmp[1024] = "", *tmpptr; + struct ast_vm_user *vmu; + struct ast_vm_user svm; + const char *category = NULL, *code, *alldtmf = "0123456789ABCD*#"; + + ast_copy_string(tmp, ext, sizeof(tmp)); + ext = tmp; + if ((context = strchr(tmp, '@'))) { + *context++ = '\0'; + tmpptr = strchr(context, '&'); + } else { + tmpptr = strchr(ext, '&'); + } - if (tmpptr) - *tmpptr++ = '\0'; + if (tmpptr) + *tmpptr++ = '\0'; - category = pbx_builtin_getvar_helper(chan, "VM_CATEGORY"); + category = pbx_builtin_getvar_helper(chan, "VM_CATEGORY"); - ast_debug(3, "Before find_user\n"); - if (!(vmu = find_user(&svm, context, ext))) { - ast_log(LOG_WARNING, "No entry in voicemail config file for '%s'\n", ext); - pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED"); - return res; - } - /* Setup pre-file if appropriate */ - if (strcmp(vmu->context, "default")) - snprintf(ext_context, sizeof(ext_context), "%s@%s", ext, vmu->context); - else - ast_copy_string(ext_context, vmu->mailbox, sizeof(ext_context)); - if (ast_test_flag(options, OPT_BUSY_GREETING)) { - snprintf(prefile, sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, ext); - } else if (ast_test_flag(options, OPT_UNAVAIL_GREETING)) { - snprintf(prefile, sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, ext); - } - snprintf(tempfile, sizeof(tempfile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, ext); - if ((res = create_dirpath(tmpdir, sizeof(tmpdir), vmu->context, ext, "tmp"))) { - ast_log(LOG_WARNING, "Failed to make directory (%s)\n", tempfile); - return -1; - } - RETRIEVE(tempfile, -1, ext, context); - if (ast_fileexists(tempfile, NULL, NULL) > 0) - ast_copy_string(prefile, tempfile, sizeof(prefile)); - DISPOSE(tempfile, -1); - /* It's easier just to try to make it than to check for its existence */ - create_dirpath(dir, sizeof(dir), vmu->context, ext, "INBOX"); + ast_debug(3, "Before find_user\n"); + if (!(vmu = find_user(&svm, context, ext))) { + ast_log(LOG_WARNING, "No entry in voicemail config file for '%s'\n", ext); + pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED"); + return res; + } + /* Setup pre-file if appropriate */ + if (strcmp(vmu->context, "default")) + snprintf(ext_context, sizeof(ext_context), "%s@%s", ext, vmu->context); + else + ast_copy_string(ext_context, vmu->mailbox, sizeof(ext_context)); + if (ast_test_flag(options, OPT_BUSY_GREETING)) { + snprintf(prefile, sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, ext); + } else if (ast_test_flag(options, OPT_UNAVAIL_GREETING)) { + snprintf(prefile, sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, ext); + } + snprintf(tempfile, sizeof(tempfile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, ext); + if ((res = create_dirpath(tmpdir, sizeof(tmpdir), vmu->context, ext, "tmp"))) { + ast_log(LOG_WARNING, "Failed to make directory (%s)\n", tempfile); + return -1; + } + RETRIEVE(tempfile, -1, vmu->mailbox, vmu->context); + if (ast_fileexists(tempfile, NULL, NULL) > 0) + ast_copy_string(prefile, tempfile, sizeof(prefile)); + DISPOSE(tempfile, -1); + /* It's easier just to try to make it than to check for its existence */ + create_dirpath(dir, sizeof(dir), vmu->context, ext, "INBOX"); - /* Check current or macro-calling context for special extensions */ - if (ast_test_flag(vmu, VM_OPERATOR)) { - if (!ast_strlen_zero(vmu->exit)) { - if (ast_exists_extension(chan, vmu->exit, "o", 1, chan->cid.cid_num)) { + /* Check current or macro-calling context for special extensions */ + if (ast_test_flag(vmu, VM_OPERATOR)) { + if (!ast_strlen_zero(vmu->exit)) { + if (ast_exists_extension(chan, vmu->exit, "o", 1, chan->cid.cid_num)) { + strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1); + ouseexten = 1; + } + } else if (ast_exists_extension(chan, chan->context, "o", 1, chan->cid.cid_num)) { strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1); ouseexten = 1; + } else if (!ast_strlen_zero(chan->macrocontext) && ast_exists_extension(chan, chan->macrocontext, "o", 1, chan->cid.cid_num)) { + strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1); + ousemacro = 1; } - } else if (ast_exists_extension(chan, chan->context, "o", 1, chan->cid.cid_num)) { - strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1); - ouseexten = 1; - } else if (!ast_strlen_zero(chan->macrocontext) && ast_exists_extension(chan, chan->macrocontext, "o", 1, chan->cid.cid_num)) { - strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1); - ousemacro = 1; } - } - if (!ast_strlen_zero(vmu->exit)) { - if (ast_exists_extension(chan, vmu->exit, "a", 1, chan->cid.cid_num)) + if (!ast_strlen_zero(vmu->exit)) { + if (ast_exists_extension(chan, vmu->exit, "a", 1, chan->cid.cid_num)) + strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1); + } else if (ast_exists_extension(chan, chan->context, "a", 1, chan->cid.cid_num)) strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1); - } else if (ast_exists_extension(chan, chan->context, "a", 1, chan->cid.cid_num)) - strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1); - else if (!ast_strlen_zero(chan->macrocontext) && ast_exists_extension(chan, chan->macrocontext, "a", 1, chan->cid.cid_num)) { - strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1); - ausemacro = 1; - } - - if (ast_test_flag(options, OPT_DTMFEXIT)) { - for (code = alldtmf; *code; code++) { - char e[2] = ""; - e[0] = *code; - if (strchr(ecodes, e[0]) == NULL && ast_canmatch_extension(chan, chan->context, e, 1, chan->cid.cid_num)) - strncat(ecodes, e, sizeof(ecodes) - strlen(ecodes) - 1); + else if (!ast_strlen_zero(chan->macrocontext) && ast_exists_extension(chan, chan->macrocontext, "a", 1, chan->cid.cid_num)) { + strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1); + ausemacro = 1; } - } - /* Play the beginning intro if desired */ - if (!ast_strlen_zero(prefile)) { - res = play_greeting(chan, vmu, prefile, ecodes); - if (res == -2) { - /* The file did not exist */ - ast_debug(1, "%s doesn't exist, doing what we can\n", prefile); - res = invent_message(chan, vmu, ext, ast_test_flag(options, OPT_BUSY_GREETING), ecodes); + if (ast_test_flag(options, OPT_DTMFEXIT)) { + for (code = alldtmf; *code; code++) { + char e[2] = ""; + e[0] = *code; + if (strchr(ecodes, e[0]) == NULL && ast_canmatch_extension(chan, chan->context, e, 1, chan->cid.cid_num)) + strncat(ecodes, e, sizeof(ecodes) - strlen(ecodes) - 1); + } } - if (res < 0) { - ast_debug(1, "Hang up during prefile playback\n"); - free_user(vmu); - pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED"); - return -1; + + /* Play the beginning intro if desired */ + if (!ast_strlen_zero(prefile)) { + res = play_greeting(chan, vmu, prefile, ecodes); + if (res == -2) { + /* The file did not exist */ + ast_debug(1, "%s doesn't exist, doing what we can\n", prefile); + res = invent_message(chan, vmu, ext, ast_test_flag(options, OPT_BUSY_GREETING), ecodes); + } + if (res < 0) { + ast_debug(1, "Hang up during prefile playback\n"); + free_user(vmu); + pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED"); + return -1; + } } - } - if (res == '#') { - /* On a '#' we skip the instructions */ - ast_set_flag(options, OPT_SILENT); - res = 0; - } - if (!res && !ast_test_flag(options, OPT_SILENT)) { - res = ast_stream_and_wait(chan, INTRO, ecodes); if (res == '#') { + /* On a '#' we skip the instructions */ ast_set_flag(options, OPT_SILENT); res = 0; } - } - if (res > 0) - ast_stopstream(chan); - /* Check for a '*' here in case the caller wants to escape from voicemail to something - other than the operator -- an automated attendant or mailbox login for example */ - if (res == '*') { - chan->exten[0] = 'a'; - chan->exten[1] = '\0'; - if (!ast_strlen_zero(vmu->exit)) { - ast_copy_string(chan->context, vmu->exit, sizeof(chan->context)); - } else if (ausemacro && !ast_strlen_zero(chan->macrocontext)) { - ast_copy_string(chan->context, chan->macrocontext, sizeof(chan->context)); + if (!res && !ast_test_flag(options, OPT_SILENT)) { + res = ast_stream_and_wait(chan, INTRO, ecodes); + if (res == '#') { + ast_set_flag(options, OPT_SILENT); + res = 0; + } } - chan->priority = 0; - free_user(vmu); - pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT"); - return 0; - } - - /* Check for a '0' here */ - if (ast_test_flag(vmu, VM_OPERATOR) && res == '0') { - transfer: - if (ouseexten || ousemacro) { - chan->exten[0] = 'o'; + if (res > 0) + ast_stopstream(chan); + /* Check for a '*' here in case the caller wants to escape from voicemail to something + other than the operator -- an automated attendant or mailbox login for example */ + if (res == '*') { + chan->exten[0] = 'a'; chan->exten[1] = '\0'; if (!ast_strlen_zero(vmu->exit)) { ast_copy_string(chan->context, vmu->exit, sizeof(chan->context)); - } else if (ousemacro && !ast_strlen_zero(chan->macrocontext)) { + } else if (ausemacro && !ast_strlen_zero(chan->macrocontext)) { ast_copy_string(chan->context, chan->macrocontext, sizeof(chan->context)); } - ast_play_and_wait(chan, "transfer"); chan->priority = 0; free_user(vmu); pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT"); + return 0; } - return 0; - } - /* Allow all other digits to exit Voicemail and return to the dialplan */ - if (ast_test_flag(options, OPT_DTMFEXIT) && res > 0) { - if (!ast_strlen_zero(options->exitcontext)) - ast_copy_string(chan->context, options->exitcontext, sizeof(chan->context)); - free_user(vmu); - pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT"); - return res; - } - - if (res < 0) { - free_user(vmu); - pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED"); - return -1; - } - /* The meat of recording the message... All the announcements and beeps have been played*/ - ast_copy_string(fmt, vmfmts, sizeof(fmt)); - if (!ast_strlen_zero(fmt)) { - msgnum = 0; - -#ifdef IMAP_STORAGE - /* Is ext a mailbox? */ - /* must open stream for this user to get info! */ - res = inboxcount(ext_context, &newmsgs, &oldmsgs); - if (res < 0) { - ast_log(LOG_NOTICE, "Can not leave voicemail, unable to count messages\n"); - return -1; - } - if (!(vms = get_vm_state_by_mailbox(ext, 0))) { - /* It is possible under certain circumstances that inboxcount did not - * create a vm_state when it was needed. This is a catchall which will - * rarely be used. - */ - if (!(vms = ast_calloc(1, sizeof(*vms)))) { - ast_log(LOG_ERROR, "Couldn't allocate necessary space\n"); - return -1; + /* Check for a '0' here */ + if (ast_test_flag(vmu, VM_OPERATOR) && res == '0') { + transfer: + if (ouseexten || ousemacro) { + chan->exten[0] = 'o'; + chan->exten[1] = '\0'; + if (!ast_strlen_zero(vmu->exit)) { + ast_copy_string(chan->context, vmu->exit, sizeof(chan->context)); + } else if (ousemacro && !ast_strlen_zero(chan->macrocontext)) { + ast_copy_string(chan->context, chan->macrocontext, sizeof(chan->context)); + } + ast_play_and_wait(chan, "transfer"); + chan->priority = 0; + free_user(vmu); + pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT"); } - ast_copy_string(vms->imapuser, vmu->imapuser, sizeof(vms->imapuser)); - ast_copy_string(vms->username, ext, sizeof(vms->username)); - vms->mailstream = NIL; - ast_debug(3, "Copied %s to %s\n", vmu->imapuser, vms->imapuser); - vms->updated = 1; - ast_copy_string(vms->curbox, mbox(0), sizeof(vms->curbox)); - init_vm_state(vms); - vmstate_insert(vms); - vms = get_vm_state_by_mailbox(ext, 0); - } - vms->newmessages++; - - /* here is a big difference! We add one to it later */ - msgnum = newmsgs + oldmsgs; - ast_debug(3, "Messagecount set to %d\n", msgnum); - snprintf(fn, sizeof(fn), "%s/imap/msg%s%04d", VM_SPOOL_DIR, vmu->mailbox, msgnum); - /* set variable for compatibility */ - pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", "IMAP_STORAGE"); - - /* Check if mailbox is full */ - check_quota(vms, imapfolder); - if (vms->quota_limit && vms->quota_usage >= vms->quota_limit) { - ast_debug(1, "*** QUOTA EXCEEDED!! %u >= %u\n", vms->quota_usage, vms->quota_limit); - ast_play_and_wait(chan, "vm-mailboxfull"); - return -1; - } - - /* Check if we have exceeded maxmsg */ - if (msgnum >= vmu->maxmsg) { - ast_log(LOG_WARNING, "Unable to leave message since we will exceed the maximum number of messages allowed (%u > %u)\n", msgnum, vmu->maxmsg); - ast_play_and_wait(chan, "vm-mailboxfull"); - return -1; + return 0; } -#else - if (count_messages(vmu, dir) >= vmu->maxmsg) { - res = ast_streamfile(chan, "vm-mailboxfull", chan->language); - if (!res) - res = ast_waitstream(chan, ""); - ast_log(LOG_WARNING, "No more messages possible\n"); - pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED"); - goto leave_vm_out; + /* Allow all other digits to exit Voicemail and return to the dialplan */ + if (ast_test_flag(options, OPT_DTMFEXIT) && res > 0) { + if (!ast_strlen_zero(options->exitcontext)) + ast_copy_string(chan->context, options->exitcontext, sizeof(chan->context)); + free_user(vmu); + pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT"); + return res; } -#endif - snprintf(tmptxtfile, sizeof(tmptxtfile), "%s/XXXXXX", tmpdir); - txtdes = mkstemp(tmptxtfile); - chmod(tmptxtfile, VOICEMAIL_FILE_MODE & ~my_umask); - if (txtdes < 0) { - res = ast_streamfile(chan, "vm-mailboxfull", chan->language); - if (!res) - res = ast_waitstream(chan, ""); - ast_log(LOG_ERROR, "Unable to create message file: %s\n", strerror(errno)); + if (res < 0) { + free_user(vmu); pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED"); - goto leave_vm_out; + return -1; } + /* The meat of recording the message... All the announcements and beeps have been played*/ + ast_copy_string(fmt, vmfmts, sizeof(fmt)); + if (!ast_strlen_zero(fmt)) { + msgnum = 0; - /* Now play the beep once we have the message number for our next message. */ - if (res >= 0) { - /* Unless we're *really* silent, try to send the beep */ - res = ast_stream_and_wait(chan, "beep", ""); - } - - /* Store information in real-time storage */ - if (ast_check_realtime("voicemail_data")) { - snprintf(priority, sizeof(priority), "%d", chan->priority); - snprintf(origtime, sizeof(origtime), "%ld", (long)time(NULL)); - get_date(date, sizeof(date)); - rtmsgid = ast_store_realtime("voicemail_data", "origmailbox", ext, "context", chan->context, "macrocontext", chan->macrocontext, "exten", chan->exten, "priority", priority, "callerchan", chan->name, "callerid", ast_callerid_merge(callerid, sizeof(callerid), chan->cid.cid_name, chan->cid.cid_num, "Unknown"), "origdate", date, "origtime", origtime, "category", category ? category : "", NULL); - } - - /* Store information */ - txt = fdopen(txtdes, "w+"); - if (txt) { - get_date(date, sizeof(date)); - fprintf(txt, - ";\n" - "; Message Information file\n" - ";\n" - "[message]\n" - "origmailbox=%s\n" - "context=%s\n" - "macrocontext=%s\n" - "exten=%s\n" - "priority=%d\n" - "callerchan=%s\n" - "callerid=%s\n" - "origdate=%s\n" - "origtime=%ld\n" - "category=%s\n", - ext, - chan->context, - chan->macrocontext, - chan->exten, - chan->priority, - chan->name, - ast_callerid_merge(callerid, sizeof(callerid), S_OR(chan->cid.cid_name, NULL), S_OR(chan->cid.cid_num, NULL), "Unknown"), - date, (long)time(NULL), - category ? category : ""); - } else - ast_log(LOG_WARNING, "Error opening text file for output\n"); #ifdef IMAP_STORAGE - res = play_record_review(chan, NULL, tmptxtfile, vmu->maxsecs, fmt, 1, vmu, &duration, NULL, options->record_gain, vms); + /* Is ext a mailbox? */ + /* must open stream for this user to get info! */ + res = inboxcount(ext_context, &newmsgs, &oldmsgs); + if (res < 0) { + ast_log(LOG_NOTICE, "Can not leave voicemail, unable to count messages\n"); + return -1; + } + if (!(vms = get_vm_state_by_mailbox(ext, 0))) { + /* It is possible under certain circumstances that inboxcount did not + * create a vm_state when it was needed. This is a catchall which will + * rarely be used. + */ + if (!(vms = create_vm_state_from_user(vmu))) { + ast_log(LOG_ERROR, "Couldn't allocate necessary space\n"); + return -1; + } + } + vms->newmessages++; + + /* here is a big difference! We add one to it later */ + msgnum = newmsgs + oldmsgs; + ast_debug(3, "Messagecount set to %d\n", msgnum); + snprintf(fn, sizeof(fn), "%s/imap/msg%s%04d", VM_SPOOL_DIR, vmu->mailbox, msgnum); + /* set variable for compatibility */ + pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", "IMAP_STORAGE"); + + /* Check if mailbox is full */ + check_quota(vms, imapfolder); + if (vms->quota_limit && vms->quota_usage >= vms->quota_limit) { + ast_debug(1, "*** QUOTA EXCEEDED!! %u >= %u\n", vms->quota_usage, vms->quota_limit); + ast_play_and_wait(chan, "vm-mailboxfull"); + return -1; + } + + /* Check if we have exceeded maxmsg */ + if (msgnum >= vmu->maxmsg) { + ast_log(LOG_WARNING, "Unable to leave message since we will exceed the maximum number of messages allowed (%u > %u)\n", msgnum, vmu->maxmsg); + ast_play_and_wait(chan, "vm-mailboxfull"); + return -1; + } #else - res = play_record_review(chan, NULL, tmptxtfile, vmu->maxsecs, fmt, 1, vmu, &duration, NULL, options->record_gain, NULL); + if (count_messages(vmu, dir) >= vmu->maxmsg) { + res = ast_streamfile(chan, "vm-mailboxfull", chan->language); + if (!res) + res = ast_waitstream(chan, ""); + ast_log(LOG_WARNING, "No more messages possible\n"); + pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED"); + goto leave_vm_out; + } + #endif + snprintf(tmptxtfile, sizeof(tmptxtfile), "%s/XXXXXX", tmpdir); + txtdes = mkstemp(tmptxtfile); + chmod(tmptxtfile, VOICEMAIL_FILE_MODE & ~my_umask); + if (txtdes < 0) { + res = ast_streamfile(chan, "vm-mailboxfull", chan->language); + if (!res) + res = ast_waitstream(chan, ""); + ast_log(LOG_ERROR, "Unable to create message file: %s\n", strerror(errno)); + pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED"); + goto leave_vm_out; + } - if (txt) { - if (duration < vmminsecs) { - fclose(txt); - ast_verb(3, "Recording was %d seconds long but needs to be at least %d - abandoning\n", duration, vmminsecs); - ast_filedelete(tmptxtfile, NULL); - unlink(tmptxtfile); - if (ast_check_realtime("voicemail_data")) { - snprintf(tmpid, sizeof(tmpid), "%d", rtmsgid); - ast_destroy_realtime("voicemail_data", "id", tmpid, NULL); - } - } else { - fprintf(txt, "duration=%d\n", duration); - fclose(txt); - if (vm_lock_path(dir)) { - ast_log(LOG_ERROR, "Couldn't lock directory %s. Voicemail will be lost.\n", dir); - /* Delete files */ + /* Now play the beep once we have the message number for our next message. */ + if (res >= 0) { + /* Unless we're *really* silent, try to send the beep */ + res = ast_stream_and_wait(chan, "beep", ""); + } + + /* Store information in real-time storage */ + if (ast_check_realtime("voicemail_data")) { + snprintf(priority, sizeof(priority), "%d", chan->priority); + snprintf(origtime, sizeof(origtime), "%ld", (long)time(NULL)); + get_date(date, sizeof(date)); + rtmsgid = ast_store_realtime("voicemail_data", "origmailbox", ext, "context", chan->context, "macrocontext", chan->macrocontext, "exten", chan->exten, "priority", priority, "callerchan", chan->name, "callerid", ast_callerid_merge(callerid, sizeof(callerid), chan->cid.cid_name, chan->cid.cid_num, "Unknown"), "origdate", date, "origtime", origtime, "category", category ? category : "", NULL); + } + + /* Store information */ + txt = fdopen(txtdes, "w+"); + if (txt) { + get_date(date, sizeof(date)); + fprintf(txt, + ";\n" + "; Message Information file\n" + ";\n" + "[message]\n" + "origmailbox=%s\n" + "context=%s\n" + "macrocontext=%s\n" + "exten=%s\n" + "priority=%d\n" + "callerchan=%s\n" + "callerid=%s\n" + "origdate=%s\n" + "origtime=%ld\n" + "category=%s\n", + ext, + chan->context, + chan->macrocontext, + chan->exten, + chan->priority, + chan->name, + ast_callerid_merge(callerid, sizeof(callerid), S_OR(chan->cid.cid_name, NULL), S_OR(chan->cid.cid_num, NULL), "Unknown"), + date, (long)time(NULL), + category ? category : ""); + } else + ast_log(LOG_WARNING, "Error opening text file for output\n"); + res = play_record_review(chan, NULL, tmptxtfile, vmu->maxsecs, fmt, 1, vmu, &duration, NULL, options->record_gain, vms); + + if (txt) { + if (duration < vmminsecs) { + fclose(txt); + ast_verb(3, "Recording was %d seconds long but needs to be at least %d - abandoning\n", duration, vmminsecs); ast_filedelete(tmptxtfile, NULL); unlink(tmptxtfile); - } else if (ast_fileexists(tmptxtfile, NULL, NULL) <= 0) { - ast_debug(1, "The recorded media file is gone, so we should remove the .txt file too!\n"); - unlink(tmptxtfile); - ast_unlock_path(dir); if (ast_check_realtime("voicemail_data")) { snprintf(tmpid, sizeof(tmpid), "%d", rtmsgid); ast_destroy_realtime("voicemail_data", "id", tmpid, NULL); } } else { + fprintf(txt, "duration=%d\n", duration); + fclose(txt); + if (vm_lock_path(dir)) { + ast_log(LOG_ERROR, "Couldn't lock directory %s. Voicemail will be lost.\n", dir); + /* Delete files */ + ast_filedelete(tmptxtfile, NULL); + unlink(tmptxtfile); + } else if (ast_fileexists(tmptxtfile, NULL, NULL) <= 0) { + ast_debug(1, "The recorded media file is gone, so we should remove the .txt file too!\n"); + unlink(tmptxtfile); + ast_unlock_path(dir); + if (ast_check_realtime("voicemail_data")) { + snprintf(tmpid, sizeof(tmpid), "%d", rtmsgid); + ast_destroy_realtime("voicemail_data", "id", tmpid, NULL); + } + } else { #ifndef IMAP_STORAGE - msgnum = last_message_index(vmu, dir) + 1; + msgnum = last_message_index(vmu, dir) + 1; #endif - make_file(fn, sizeof(fn), dir, msgnum); + make_file(fn, sizeof(fn), dir, msgnum); - /* assign a variable with the name of the voicemail file */ + /* assign a variable with the name of the voicemail file */ #ifndef IMAP_STORAGE - pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", fn); + pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", fn); #else - pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", "IMAP_STORAGE"); + pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", "IMAP_STORAGE"); #endif - snprintf(txtfile, sizeof(txtfile), "%s.txt", fn); - ast_filerename(tmptxtfile, fn, NULL); - rename(tmptxtfile, txtfile); + snprintf(txtfile, sizeof(txtfile), "%s.txt", fn); + ast_filerename(tmptxtfile, fn, NULL); + rename(tmptxtfile, txtfile); - /* Properly set permissions on voicemail text descriptor file. - Unfortunately mkstemp() makes this file 0600 on most unix systems. */ - if (chmod(txtfile, VOICEMAIL_FILE_MODE) < 0) - ast_log(LOG_ERROR, "Couldn't set permissions on voicemail text file %s: %s", txtfile, strerror(errno)); - - ast_unlock_path(dir); - if (ast_check_realtime("voicemail_data")) { - snprintf(tmpid, sizeof(tmpid), "%d", rtmsgid); - snprintf(tmpdur, sizeof(tmpdur), "%d", duration); - ast_update_realtime("voicemail_data", "id", tmpid, "filename", fn, "duration", tmpdur, NULL); - } - /* We must store the file first, before copying the message, because - * ODBC storage does the entire copy with SQL. - */ - if (ast_fileexists(fn, NULL, NULL) > 0) { - STORE(dir, vmu->mailbox, vmu->context, msgnum, chan, vmu, fmt, duration, vms); - } + /* Properly set permissions on voicemail text descriptor file. + Unfortunately mkstemp() makes this file 0600 on most unix systems. */ + if (chmod(txtfile, VOICEMAIL_FILE_MODE) < 0) + ast_log(LOG_ERROR, "Couldn't set permissions on voicemail text file %s: %s", txtfile, strerror(errno)); - /* Are there to be more recipients of this message? */ - while (tmpptr) { - struct ast_vm_user recipu, *recip; - char *exten, *context; - - exten = strsep(&tmpptr, "&"); - context = strchr(exten, '@'); - if (context) { - *context = '\0'; - context++; + ast_unlock_path(dir); + if (ast_check_realtime("voicemail_data")) { + snprintf(tmpid, sizeof(tmpid), "%d", rtmsgid); + snprintf(tmpdur, sizeof(tmpdur), "%d", duration); + ast_update_realtime("voicemail_data", "id", tmpid, "filename", fn, "duration", tmpdur, NULL); } - if ((recip = find_user(&recipu, context, exten))) { - copy_message(chan, vmu, 0, msgnum, duration, recip, fmt, dir); - free_user(recip); + /* We must store the file first, before copying the message, because + * ODBC storage does the entire copy with SQL. + */ + if (ast_fileexists(fn, NULL, NULL) > 0) { + STORE(dir, vmu->mailbox, vmu->context, msgnum, chan, vmu, fmt, duration, vms); } - } - /* Notification and disposal needs to happen after the copy, though. */ - if (ast_fileexists(fn, NULL, NULL)) { + + /* Are there to be more recipients of this message? */ + while (tmpptr) { + struct ast_vm_user recipu, *recip; + char *exten, *context; + + exten = strsep(&tmpptr, "&"); + context = strchr(exten, '@'); + if (context) { + *context = '\0'; + context++; + } + if ((recip = find_user(&recipu, context, exten))) { + copy_message(chan, vmu, 0, msgnum, duration, recip, fmt, dir); + free_user(recip); + } + } + /* Notification and disposal needs to happen after the copy, though. */ + if (ast_fileexists(fn, NULL, NULL)) { #ifdef IMAP_STORAGE - notify_new_message(chan, vmu, vms, msgnum, duration, fmt, S_OR(chan->cid.cid_num, NULL), S_OR(chan->cid.cid_name, NULL)); + notify_new_message(chan, vmu, vms, msgnum, duration, fmt, S_OR(chan->cid.cid_num, NULL), S_OR(chan->cid.cid_name, NULL)); #else - notify_new_message(chan, vmu, NULL, msgnum, duration, fmt, S_OR(chan->cid.cid_num, NULL), S_OR(chan->cid.cid_name, NULL)); + notify_new_message(chan, vmu, NULL, msgnum, duration, fmt, S_OR(chan->cid.cid_num, NULL), S_OR(chan->cid.cid_name, NULL)); #endif - DISPOSE(dir, msgnum); + DISPOSE(dir, msgnum); + } } } } - } - if (res == '0') { - goto transfer; - } else if (res > 0) - res = 0; + if (res == '0') { + goto transfer; + } else if (res > 0) + res = 0; - if (duration < vmminsecs) - /* XXX We should really give a prompt too short/option start again, with leave_vm_out called only after a timeout XXX */ - pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED"); - else - pbx_builtin_setvar_helper(chan, "VMSTATUS", "SUCCESS"); - } else - ast_log(LOG_WARNING, "No format for saving voicemail?\n"); -leave_vm_out: - free_user(vmu); - - return res; -} + if (duration < vmminsecs) + /* XXX We should really give a prompt too short/option start again, with leave_vm_out called only after a timeout XXX */ + pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED"); + else + pbx_builtin_setvar_helper(chan, "VMSTATUS", "SUCCESS"); + } else + ast_log(LOG_WARNING, "No format for saving voicemail?\n"); + leave_vm_out: + free_user(vmu); + + return res; + } #ifndef IMAP_STORAGE -static int resequence_mailbox(struct ast_vm_user *vmu, char *dir) -{ - /* we know max messages, so stop process when number is hit */ + static int resequence_mailbox(struct ast_vm_user *vmu, char *dir) + { + /* we know max messages, so stop process when number is hit */ - int x, dest; - char sfn[PATH_MAX]; - char dfn[PATH_MAX]; + int x, dest; + char sfn[PATH_MAX]; + char dfn[PATH_MAX]; - if (vm_lock_path(dir)) - return ERROR_LOCK_PATH; + if (vm_lock_path(dir)) + return ERROR_LOCK_PATH; - for (x = 0, dest = 0; x < vmu->maxmsg; x++) { - make_file(sfn, sizeof(sfn), dir, x); - if (EXISTS(dir, x, sfn, NULL)) { - - if (x != dest) { - make_file(dfn, sizeof(dfn), dir, dest); - RENAME(dir, x, vmu->mailbox, vmu->context, dir, dest, sfn, dfn); + for (x = 0, dest = 0; x < vmu->maxmsg; x++) { + make_file(sfn, sizeof(sfn), dir, x); + if (EXISTS(dir, x, sfn, NULL)) { + + if (x != dest) { + make_file(dfn, sizeof(dfn), dir, dest); + RENAME(dir, x, vmu->mailbox, vmu->context, dir, dest, sfn, dfn); + } + + dest++; } - - dest++; } - } - ast_unlock_path(dir); + ast_unlock_path(dir); - return 0; -} + return 0; + } #endif -static int say_and_wait(struct ast_channel *chan, int num, const char *language) -{ - int d; - d = ast_say_number(chan, num, AST_DIGIT_ANY, language, NULL); - return d; -} + static int say_and_wait(struct ast_channel *chan, int num, const char *language) + { + int d; + d = ast_say_number(chan, num, AST_DIGIT_ANY, language, NULL); + return d; + } -static int save_to_folder(struct ast_vm_user *vmu, struct vm_state *vms, int msg, int box) -{ + static int save_to_folder(struct ast_vm_user *vmu, struct vm_state *vms, int msg, int box) + { #ifdef IMAP_STORAGE - /* we must use mbox(x) folder names, and copy the message there */ - /* simple. huh? */ - long res; - char sequence[10]; - char mailbox[256]; - - /* 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]); - /* Create the folder if it don't exist */ - imap_mailbox_name(mailbox, sizeof(mailbox), vms, box, 1); /* Get the full mailbox name */ - ast_debug(5, "Checking if folder exists: %s\n",mailbox); - if (mail_create(vms->mailstream, mailbox) == NIL) - ast_debug(5, "Folder exists.\n"); - else - ast_log(LOG_NOTICE, "Folder %s created!\n",mbox(box)); - - ast_debug(3, "Copying sequence %s to mailbox %s\n", sequence, mbox(box)); - res = mail_copy(vms->mailstream, sequence, (char *)mbox(box)); - if (res == 1) return 0; - return 1; + /* we must use mbox(x) folder names, and copy the message there */ + /* simple. huh? */ + char sequence[10]; + char mailbox[256]; + /* get the real IMAP message number for this message */ + snprintf(sequence, sizeof(sequence), "%ld", vms->msgArray[msg]); + + ast_debug(3, "Copying sequence %s to mailbox %s\n", sequence, mbox(box)); + if (box == OLD_FOLDER) { + mail_setflag(vms->mailstream, sequence, "\\Seen"); + } else if (box == NEW_FOLDER) { + mail_clearflag(vms->mailstream, sequence, "\\Seen"); + } + if (!strcasecmp(mbox(NEW_FOLDER), vms->curbox) && (box == NEW_FOLDER || box == OLD_FOLDER)) + return 0; + /* Create the folder if it don't exist */ + imap_mailbox_name(mailbox, sizeof(mailbox), vms, box, 1); /* Get the full mailbox name */ + ast_debug(5, "Checking if folder exists: %s\n",mailbox); + if (mail_create(vms->mailstream, mailbox) == NIL) + ast_debug(5, "Folder exists.\n"); + else + ast_log(LOG_NOTICE, "Folder %s created!\n",mbox(box)); + return !mail_copy(vms->mailstream, sequence, (char *)mbox(box)); #else - char *dir = vms->curdir; - char *username = vms->username; - char *context = vmu->context; - char sfn[PATH_MAX]; - char dfn[PATH_MAX]; - char ddir[PATH_MAX]; - const char *dbox = mbox(box); - int x, i; - create_dirpath(ddir, sizeof(ddir), context, username, dbox); - - if (vm_lock_path(ddir)) - return ERROR_LOCK_PATH; - - x = last_message_index(vmu, ddir) + 1; - - if (box == 10 && x >= vmu->maxdeletedmsg) { /* "Deleted" folder*/ - x--; - for (i = 1; i <= x; i++) { - /* Push files down a "slot". The oldest file (msg0000) will be deleted. */ - make_file(sfn, sizeof(sfn), ddir, i); - make_file(dfn, sizeof(dfn), ddir, i - 1); - if (EXISTS(ddir, i, sfn, NULL)) { - RENAME(ddir, i, vmu->mailbox, vmu->context, ddir, i - 1, sfn, dfn); - } else - break; + char *dir = vms->curdir; + char *username = vms->username; + char *context = vmu->context; + char sfn[PATH_MAX]; + char dfn[PATH_MAX]; + char ddir[PATH_MAX]; + const char *dbox = mbox(box); + int x, i; + create_dirpath(ddir, sizeof(ddir), context, username, dbox); + + if (vm_lock_path(ddir)) + return ERROR_LOCK_PATH; + + x = last_message_index(vmu, ddir) + 1; + + if (box == 10 && x >= vmu->maxdeletedmsg) { /* "Deleted" folder*/ + x--; + for (i = 1; i <= x; i++) { + /* Push files down a "slot". The oldest file (msg0000) will be deleted. */ + make_file(sfn, sizeof(sfn), ddir, i); + make_file(dfn, sizeof(dfn), ddir, i - 1); + if (EXISTS(ddir, i, sfn, NULL)) { + RENAME(ddir, i, vmu->mailbox, vmu->context, ddir, i - 1, sfn, dfn); + } else + break; + } + } else { + if (x >= vmu->maxmsg) { + ast_unlock_path(ddir); + return ERROR_MAILBOX_FULL; + } } - } else { - if (x >= vmu->maxmsg) { - ast_unlock_path(ddir); - return ERROR_MAILBOX_FULL; + make_file(sfn, sizeof(sfn), dir, msg); + make_file(dfn, sizeof(dfn), ddir, x); + if (strcmp(sfn, dfn)) { + COPY(dir, msg, ddir, x, username, context, sfn, dfn); } - } - make_file(sfn, sizeof(sfn), dir, msg); - make_file(dfn, sizeof(dfn), ddir, x); - if (strcmp(sfn, dfn)) { - COPY(dir, msg, ddir, x, username, context, sfn, dfn); - } - ast_unlock_path(ddir); + ast_unlock_path(ddir); #endif - return 0; -} + return 0; + } -static int adsi_logo(unsigned char *buf) -{ - int bytes = 0; - bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, "Comedian Mail", ""); - bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, "(C)2002-2006 Digium, Inc.", ""); - return bytes; -} + static int adsi_logo(unsigned char *buf) + { + int bytes = 0; + bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, "Comedian Mail", ""); + bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, "(C)2002-2006 Digium, Inc.", ""); + return bytes; + } -static int adsi_load_vmail(struct ast_channel *chan, int *useadsi) -{ - unsigned char buf[256]; - int bytes = 0; - int x; - char num[5]; + static int adsi_load_vmail(struct ast_channel *chan, int *useadsi) + { + unsigned char buf[256]; + int bytes = 0; + int x; + char num[5]; - *useadsi = 0; - bytes += ast_adsi_data_mode(buf + bytes); - ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY); + *useadsi = 0; + bytes += ast_adsi_data_mode(buf + bytes); + ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY); - bytes = 0; - bytes += adsi_logo(buf); - bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", ""); + bytes = 0; + bytes += adsi_logo(buf); + bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", ""); #ifdef DISPLAY - bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " .", ""); + bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " .", ""); #endif - bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1); - bytes += ast_adsi_data_mode(buf + bytes); - ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY); - - if (ast_adsi_begin_download(chan, addesc, adsifdn, adsisec, adsiver)) { - bytes = 0; - bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Cancelled.", ""); - bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", ""); bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1); - bytes += ast_adsi_voice_mode(buf + bytes, 0); + bytes += ast_adsi_data_mode(buf + bytes); ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY); - return 0; - } + + if (ast_adsi_begin_download(chan, addesc, adsifdn, adsisec, adsiver)) { + bytes = 0; + bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Cancelled.", ""); + bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", ""); + bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1); + bytes += ast_adsi_voice_mode(buf + bytes, 0); + ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY); + return 0; + } #ifdef DISPLAY - /* Add a dot */ - bytes = 0; - bytes += ast_adsi_logo(buf); - bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", ""); - bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ..", ""); - bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1); - ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY); + /* Add a dot */ + bytes = 0; + bytes += ast_adsi_logo(buf); + bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", ""); + bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ..", ""); + bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1); + ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY); #endif - bytes = 0; - bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 0, "Listen", "Listen", "1", 1); - bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 1, "Folder", "Folder", "2", 1); - bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 2, "Advanced", "Advnced", "3", 1); - bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Options", "Options", "0", 1); - bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 4, "Help", "Help", "*", 1); - bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 5, "Exit", "Exit", "#", 1); - ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD); + bytes = 0; + bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 0, "Listen", "Listen", "1", 1); + bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 1, "Folder", "Folder", "2", 1); + bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 2, "Advanced", "Advnced", "3", 1); + bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Options", "Options", "0", 1); + bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 4, "Help", "Help", "*", 1); + bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 5, "Exit", "Exit", "#", 1); + ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD); #ifdef DISPLAY - /* Add another dot */ - bytes = 0; - bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ...", ""); - bytes += ast_adsi_voice_mode(buf + bytes, 0); + /* Add another dot */ + bytes = 0; + bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ...", ""); + bytes += ast_adsi_voice_mode(buf + bytes, 0); - bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1); - ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY); + bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1); + ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY); #endif - bytes = 0; - /* These buttons we load but don't use yet */ - bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 6, "Previous", "Prev", "4", 1); - bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 8, "Repeat", "Repeat", "5", 1); - bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 7, "Delete", "Delete", "7", 1); - bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 9, "Next", "Next", "6", 1); - bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 10, "Save", "Save", "9", 1); - bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 11, "Undelete", "Restore", "7", 1); - ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD); + bytes = 0; + /* These buttons we load but don't use yet */ + bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 6, "Previous", "Prev", "4", 1); + bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 8, "Repeat", "Repeat", "5", 1); + bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 7, "Delete", "Delete", "7", 1); + bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 9, "Next", "Next", "6", 1); + bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 10, "Save", "Save", "9", 1); + bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 11, "Undelete", "Restore", "7", 1); + ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD); #ifdef DISPLAY - /* Add another dot */ - bytes = 0; - bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ....", ""); - bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1); - ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY); + /* Add another dot */ + bytes = 0; + bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ....", ""); + bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1); + ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY); #endif - bytes = 0; - for (x = 0; x < 5; x++) { - snprintf(num, sizeof(num), "%d", x); - bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + x, mbox(x), mbox(x), num, 1); - } - bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + 5, "Cancel", "Cancel", "#", 1); - ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD); + bytes = 0; + for (x = 0; x < 5; x++) { + snprintf(num, sizeof(num), "%d", x); + bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + x, mbox(x), mbox(x), num, 1); + } + bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + 5, "Cancel", "Cancel", "#", 1); + ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD); #ifdef DISPLAY - /* Add another dot */ - bytes = 0; - bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " .....", ""); - bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1); - ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY); + /* Add another dot */ + bytes = 0; + bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " .....", ""); + bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1); + ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY); #endif - if (ast_adsi_end_download(chan)) { + if (ast_adsi_end_download(chan)) { + bytes = 0; + bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Download Unsuccessful.", ""); + bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", ""); + bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1); + bytes += ast_adsi_voice_mode(buf + bytes, 0); + ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY); + return 0; + } bytes = 0; - bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Download Unsuccessful.", ""); - bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", ""); - bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1); + bytes += ast_adsi_download_disconnect(buf + bytes); bytes += ast_adsi_voice_mode(buf + bytes, 0); - ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY); - return 0; - } - bytes = 0; - bytes += ast_adsi_download_disconnect(buf + bytes); - bytes += ast_adsi_voice_mode(buf + bytes, 0); - ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD); + ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD); - ast_debug(1, "Done downloading scripts...\n"); + ast_debug(1, "Done downloading scripts...\n"); #ifdef DISPLAY - /* Add last dot */ - bytes = 0; - bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, " ......", ""); - bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1); + /* Add last dot */ + bytes = 0; + bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, " ......", ""); + bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1); #endif - ast_debug(1, "Restarting session...\n"); + ast_debug(1, "Restarting session...\n"); - bytes = 0; - /* Load the session now */ - if (ast_adsi_load_session(chan, adsifdn, adsiver, 1) == 1) { - *useadsi = 1; - bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Scripts Loaded!", ""); - } else - bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Failed!", ""); + bytes = 0; + /* Load the session now */ + if (ast_adsi_load_session(chan, adsifdn, adsiver, 1) == 1) { + *useadsi = 1; + bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Scripts Loaded!", ""); + } else + bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Failed!", ""); - ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY); - return 0; -} + ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY); + return 0; + } -static void adsi_begin(struct ast_channel *chan, int *useadsi) -{ - int x; - if (!ast_adsi_available(chan)) - return; - x = ast_adsi_load_session(chan, adsifdn, adsiver, 1); - if (x < 0) - return; - if (!x) { - if (adsi_load_vmail(chan, useadsi)) { - ast_log(LOG_WARNING, "Unable to upload voicemail scripts\n"); + static void adsi_begin(struct ast_channel *chan, int *useadsi) + { + int x; + if (!ast_adsi_available(chan)) return; - } - } else - *useadsi = 1; -} + x = ast_adsi_load_session(chan, adsifdn, adsiver, 1); + if (x < 0) + return; + if (!x) { + if (adsi_load_vmail(chan, useadsi)) { + ast_log(LOG_WARNING, "Unable to upload voicemail scripts\n"); + return; + } + } else + *useadsi = 1; + } -static void adsi_login(struct ast_channel *chan) -{ - unsigned char buf[256]; - int bytes = 0; - unsigned char keys[8]; - int x; - if (!ast_adsi_available(chan)) - return; + static void adsi_login(struct ast_channel *chan) + { + unsigned char buf[256]; + int bytes = 0; + unsigned char keys[8]; + int x; + if (!ast_adsi_available(chan)) + return; - for (x = 0; x < 8; x++) - keys[x] = 0; - /* Set one key for next */ - keys[3] = ADSI_KEY_APPS + 3; + for (x = 0; x < 8; x++) + keys[x] = 0; + /* Set one key for next */ + keys[3] = ADSI_KEY_APPS + 3; - bytes += adsi_logo(buf + bytes); - bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, " ", ""); - bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, " ", ""); - bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1); - bytes += ast_adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Mailbox: ******", ""); - bytes += ast_adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 1, 1, ADSI_JUST_LEFT); - bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Enter", "Enter", "#", 1); - bytes += ast_adsi_set_keys(buf + bytes, keys); - bytes += ast_adsi_voice_mode(buf + bytes, 0); - ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY); -} + bytes += adsi_logo(buf + bytes); + bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, " ", ""); + bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, " ", ""); + bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1); + bytes += ast_adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Mailbox: ******", ""); + bytes += ast_adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 1, 1, ADSI_JUST_LEFT); + bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Enter", "Enter", "#", 1); + bytes += ast_adsi_set_keys(buf + bytes, keys); + bytes += ast_adsi_voice_mode(buf + bytes, 0); + ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY); + } -static void adsi_password(struct ast_channel *chan) -{ - unsigned char buf[256]; - int bytes = 0; - unsigned char keys[8]; - int x; - if (!ast_adsi_available(chan)) - return; + static void adsi_password(struct ast_channel *chan) + { + unsigned char buf[256]; + int bytes = 0; + unsigned char keys[8]; + int x; + if (!ast_adsi_available(chan)) + return; - for (x = 0; x < 8; x++) - keys[x] = 0; - /* Set one key for next */ - keys[3] = ADSI_KEY_APPS + 3; + for (x = 0; x < 8; x++) + keys[x] = 0; + /* Set one key for next */ + keys[3] = ADSI_KEY_APPS + 3; - bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1); - bytes += ast_adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Password: ******", ""); - bytes += ast_adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 0, 1, ADSI_JUST_LEFT); - bytes += ast_adsi_set_keys(buf + bytes, keys); - bytes += ast_adsi_voice_mode(buf + bytes, 0); - ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY); -} + bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1); + bytes += ast_adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Password: ******", ""); + bytes += ast_adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 0, 1, ADSI_JUST_LEFT); + bytes += ast_adsi_set_keys(buf + bytes, keys); + bytes += ast_adsi_voice_mode(buf + bytes, 0); + ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY); + } -static void adsi_folders(struct ast_channel *chan, int start, char *label) -{ - unsigned char buf[256]; - int bytes = 0; - unsigned char keys[8]; - int x, y; + static void adsi_folders(struct ast_channel *chan, int start, char *label) + { + unsigned char buf[256]; + int bytes = 0; + unsigned char keys[8]; + int x, y; - if (!ast_adsi_available(chan)) - return; + if (!ast_adsi_available(chan)) + return; - for (x = 0; x < 5; x++) { - y = ADSI_KEY_APPS + 12 + start + x; - if (y > ADSI_KEY_APPS + 12 + 4) - y = 0; - keys[x] = ADSI_KEY_SKT | y; - } - keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 17); - keys[6] = 0; - keys[7] = 0; + for (x = 0; x < 5; x++) { + y = ADSI_KEY_APPS + 12 + start + x; + if (y > ADSI_KEY_APPS + 12 + 4) + y = 0; + keys[x] = ADSI_KEY_SKT | y; + } + keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 17); + keys[6] = 0; + keys[7] = 0; - bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, label, ""); - bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, " ", ""); - bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1); - bytes += ast_adsi_set_keys(buf + bytes, keys); - bytes += ast_adsi_voice_mode(buf + bytes, 0); + bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, label, ""); + bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, " ", ""); + bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1); + bytes += ast_adsi_set_keys(buf + bytes, keys); + bytes += ast_adsi_voice_mode(buf + bytes, 0); - ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY); -} + ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY); + } -static void adsi_message(struct ast_channel *chan, struct vm_state *vms) -{ - int bytes = 0; - unsigned char buf[256]; - char buf1[256], buf2[256]; - char fn2[PATH_MAX]; + static void adsi_message(struct ast_channel *chan, struct vm_state *vms) + { + int bytes = 0; + unsigned char buf[256]; + char buf1[256], buf2[256]; + char fn2[PATH_MAX]; - char cid[256] = ""; - char *val; - char *name, *num; - char datetime[21] = ""; - FILE *f; + char cid[256] = ""; + char *val; + char *name, *num; + char datetime[21] = ""; + FILE *f; - unsigned char keys[8]; + unsigned char keys[8]; - int x; + int x; - if (!ast_adsi_available(chan)) - return; + if (!ast_adsi_available(chan)) + return; - /* Retrieve important info */ - snprintf(fn2, sizeof(fn2), "%s.txt", vms->fn); - f = fopen(fn2, "r"); - if (f) { - while (!feof(f)) { - fgets((char *)buf, sizeof(buf), f); - if (!feof(f)) { - char *stringp = NULL; - stringp = (char *)buf; - strsep(&stringp, "="); - val = strsep(&stringp, "="); - if (!ast_strlen_zero(val)) { - if (!strcmp((char *)buf, "callerid")) - ast_copy_string(cid, val, sizeof(cid)); - if (!strcmp((char *)buf, "origdate")) - ast_copy_string(datetime, val, sizeof(datetime)); + /* Retrieve important info */ + snprintf(fn2, sizeof(fn2), "%s.txt", vms->fn); + f = fopen(fn2, "r"); + if (f) { + while (!feof(f)) { + fgets((char *)buf, sizeof(buf), f); + if (!feof(f)) { + char *stringp = NULL; + stringp = (char *)buf; + strsep(&stringp, "="); + val = strsep(&stringp, "="); + if (!ast_strlen_zero(val)) { + if (!strcmp((char *)buf, "callerid")) + ast_copy_string(cid, val, sizeof(cid)); + if (!strcmp((char *)buf, "origdate")) + ast_copy_string(datetime, val, sizeof(datetime)); + } } } + fclose(f); } - fclose(f); - } - /* New meaning for keys */ - for (x = 0; x < 5; x++) - keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x); - keys[6] = 0x0; - keys[7] = 0x0; + /* New meaning for keys */ + for (x = 0; x < 5; x++) + keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x); + keys[6] = 0x0; + keys[7] = 0x0; - if (!vms->curmsg) { - /* No prev key, provide "Folder" instead */ - keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1); - } - if (vms->curmsg >= vms->lastmsg) { - /* If last message ... */ - if (vms->curmsg) { - /* but not only message, provide "Folder" instead */ - keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1); - bytes += ast_adsi_voice_mode(buf + bytes, 0); + if (!vms->curmsg) { + /* No prev key, provide "Folder" instead */ + keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1); + } + if (vms->curmsg >= vms->lastmsg) { + /* If last message ... */ + if (vms->curmsg) { + /* but not only message, provide "Folder" instead */ + keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1); + bytes += ast_adsi_voice_mode(buf + bytes, 0); - } else { - /* Otherwise if only message, leave blank */ - keys[3] = 1; + } else { + /* Otherwise if only message, leave blank */ + keys[3] = 1; + } } - } - if (!ast_strlen_zero(cid)) { - ast_callerid_parse(cid, &name, &num); - if (!name) - name = num; - } else - name = "Unknown Caller"; + if (!ast_strlen_zero(cid)) { + ast_callerid_parse(cid, &name, &num); + if (!name) + name = num; + } else + name = "Unknown Caller"; - /* If deleted, show "undeleted" */ + /* If deleted, show "undeleted" */ - if (vms->deleted[vms->curmsg]) - keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11); + if (vms->deleted[vms->curmsg]) + keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11); - /* Except "Exit" */ - keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5); - snprintf(buf1, sizeof(buf1), "%s%s", vms->curbox, - strcasecmp(vms->curbox, "INBOX") ? " Messages" : ""); - snprintf(buf2, sizeof(buf2), "Message %d of %d", vms->curmsg + 1, vms->lastmsg + 1); + /* Except "Exit" */ + keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5); + snprintf(buf1, sizeof(buf1), "%s%s", vms->curbox, + strcasecmp(vms->curbox, "INBOX") ? " Messages" : ""); + snprintf(buf2, sizeof(buf2), "Message %d of %d", vms->curmsg + 1, vms->lastmsg + 1); - bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, ""); - bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, ""); - bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, name, ""); - bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, datetime, ""); - bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1); - bytes += ast_adsi_set_keys(buf + bytes, keys); - bytes += ast_adsi_voice_mode(buf + bytes, 0); + bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, ""); + bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, ""); + bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, name, ""); + bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, datetime, ""); + bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1); + bytes += ast_adsi_set_keys(buf + bytes, keys); + bytes += ast_adsi_voice_mode(buf + bytes, 0); - ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY); -} + ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY); + } -static void adsi_delete(struct ast_channel *chan, struct vm_state *vms) -{ - int bytes = 0; - unsigned char buf[256]; - unsigned char keys[8]; + static void adsi_delete(struct ast_channel *chan, struct vm_state *vms) + { + int bytes = 0; + unsigned char buf[256]; + unsigned char keys[8]; - int x; + int x; - if (!ast_adsi_available(chan)) - return; + if (!ast_adsi_available(chan)) + return; - /* New meaning for keys */ - for (x = 0; x < 5; x++) - keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x); + /* New meaning for keys */ + for (x = 0; x < 5; x++) + keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x); - keys[6] = 0x0; - keys[7] = 0x0; + keys[6] = 0x0; + keys[7] = 0x0; - if (!vms->curmsg) { - /* No prev key, provide "Folder" instead */ - keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1); - } - if (vms->curmsg >= vms->lastmsg) { - /* If last message ... */ - if (vms->curmsg) { - /* but not only message, provide "Folder" instead */ - keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1); - } else { - /* Otherwise if only message, leave blank */ - keys[3] = 1; + if (!vms->curmsg) { + /* No prev key, provide "Folder" instead */ + keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1); + } + if (vms->curmsg >= vms->lastmsg) { + /* If last message ... */ + if (vms->curmsg) { + /* but not only message, provide "Folder" instead */ + keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1); + } else { + /* Otherwise if only message, leave blank */ + keys[3] = 1; + } } - } - /* If deleted, show "undeleted" */ - if (vms->deleted[vms->curmsg]) - keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11); + /* If deleted, show "undeleted" */ + if (vms->deleted[vms->curmsg]) + keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11); - /* Except "Exit" */ - keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5); - bytes += ast_adsi_set_keys(buf + bytes, keys); - bytes += ast_adsi_voice_mode(buf + bytes, 0); + /* Except "Exit" */ + keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5); + bytes += ast_adsi_set_keys(buf + bytes, keys); + bytes += ast_adsi_voice_mode(buf + bytes, 0); - ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY); -} + ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY); + } -static void adsi_status(struct ast_channel *chan, struct vm_state *vms) -{ - unsigned char buf[256] = ""; - char buf1[256] = "", buf2[256] = ""; - int bytes = 0; - unsigned char keys[8]; - int x; + static void adsi_status(struct ast_channel *chan, struct vm_state *vms) + { + unsigned char buf[256] = ""; + char buf1[256] = "", buf2[256] = ""; + int bytes = 0; + unsigned char keys[8]; + int x; - char *newm = (vms->newmessages == 1) ? "message" : "messages"; - char *oldm = (vms->oldmessages == 1) ? "message" : "messages"; - if (!ast_adsi_available(chan)) - return; - if (vms->newmessages) { - snprintf(buf1, sizeof(buf1), "You have %d new", vms->newmessages); - if (vms->oldmessages) { - strncat(buf1, " and", sizeof(buf1) - strlen(buf1) - 1); - snprintf(buf2, sizeof(buf2), "%d old %s.", vms->oldmessages, oldm); + char *newm = (vms->newmessages == 1) ? "message" : "messages"; + char *oldm = (vms->oldmessages == 1) ? "message" : "messages"; + if (!ast_adsi_available(chan)) + return; + if (vms->newmessages) { + snprintf(buf1, sizeof(buf1), "You have %d new", vms->newmessages); + if (vms->oldmessages) { + strncat(buf1, " and", sizeof(buf1) - strlen(buf1) - 1); + snprintf(buf2, sizeof(buf2), "%d old %s.", vms->oldmessages, oldm); + } else { + snprintf(buf2, sizeof(buf2), "%s.", newm); + } + } else if (vms->oldmessages) { + snprintf(buf1, sizeof(buf1), "You have %d old", vms->oldmessages); + snprintf(buf2, sizeof(buf2), "%s.", oldm); } else { - snprintf(buf2, sizeof(buf2), "%s.", newm); + strcpy(buf1, "You have no messages."); + buf2[0] = ' '; + buf2[1] = '\0'; } - } else if (vms->oldmessages) { - snprintf(buf1, sizeof(buf1), "You have %d old", vms->oldmessages); - snprintf(buf2, sizeof(buf2), "%s.", oldm); - } else { - strcpy(buf1, "You have no messages."); - buf2[0] = ' '; - buf2[1] = '\0'; - } - bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, ""); - bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, ""); - bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1); + bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, ""); + bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, ""); + bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1); - for (x = 0; x < 6; x++) - keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x); - keys[6] = 0; - keys[7] = 0; + for (x = 0; x < 6; x++) + keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x); + keys[6] = 0; + keys[7] = 0; - /* Don't let them listen if there are none */ - if (vms->lastmsg < 0) - keys[0] = 1; - bytes += ast_adsi_set_keys(buf + bytes, keys); + /* Don't let them listen if there are none */ + if (vms->lastmsg < 0) + keys[0] = 1; + bytes += ast_adsi_set_keys(buf + bytes, keys); - bytes += ast_adsi_voice_mode(buf + bytes, 0); + bytes += ast_adsi_voice_mode(buf + bytes, 0); - ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY); -} + ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY); + } -static void adsi_status2(struct ast_channel *chan, struct vm_state *vms) -{ - unsigned char buf[256] = ""; - char buf1[256] = "", buf2[256] = ""; - int bytes = 0; - unsigned char keys[8]; - int x; + static void adsi_status2(struct ast_channel *chan, struct vm_state *vms) + { + unsigned char buf[256] = ""; + char buf1[256] = "", buf2[256] = ""; + int bytes = 0; + unsigned char keys[8]; + int x; - char *mess = (vms->lastmsg == 0) ? "message" : "messages"; + char *mess = (vms->lastmsg == 0) ? "message" : "messages"; - if (!ast_adsi_available(chan)) - return; + if (!ast_adsi_available(chan)) + return; - /* Original command keys */ - for (x = 0; x < 6; x++) - keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x); + /* Original command keys */ + for (x = 0; x < 6; x++) + keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x); - keys[6] = 0; - keys[7] = 0; + keys[6] = 0; + keys[7] = 0; - if ((vms->lastmsg + 1) < 1) - keys[0] = 0; + if ((vms->lastmsg + 1) < 1) + keys[0] = 0; - snprintf(buf1, sizeof(buf1), "%s%s has", vms->curbox, - strcasecmp(vms->curbox, "INBOX") ? " folder" : ""); + snprintf(buf1, sizeof(buf1), "%s%s has", vms->curbox, + strcasecmp(vms->curbox, "INBOX") ? " folder" : ""); - if (vms->lastmsg + 1) - snprintf(buf2, sizeof(buf2), "%d %s.", vms->lastmsg + 1, mess); - else - strcpy(buf2, "no messages."); - bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, ""); - bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, ""); - bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, "", ""); - bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1); - bytes += ast_adsi_set_keys(buf + bytes, keys); + if (vms->lastmsg + 1) + snprintf(buf2, sizeof(buf2), "%d %s.", vms->lastmsg + 1, mess); + else + strcpy(buf2, "no messages."); + bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, ""); + bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, ""); + bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, "", ""); + bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1); + bytes += ast_adsi_set_keys(buf + bytes, keys); - bytes += ast_adsi_voice_mode(buf + bytes, 0); + bytes += ast_adsi_voice_mode(buf + bytes, 0); - ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY); - -} + ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY); + + } -/* -static void adsi_clear(struct ast_channel *chan) -{ - char buf[256]; - int bytes = 0; - if (!ast_adsi_available(chan)) - return; - bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1); - bytes += ast_adsi_voice_mode(buf + bytes, 0); + /* + static void adsi_clear(struct ast_channel *chan) + { + char buf[256]; + int bytes = 0; + if (!ast_adsi_available(chan)) + return; + bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1); + bytes += ast_adsi_voice_mode(buf + bytes, 0); - ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY); -} -*/ + ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY); + } + */ -static void adsi_goodbye(struct ast_channel *chan) -{ - unsigned char buf[256]; - int bytes = 0; + static void adsi_goodbye(struct ast_channel *chan) + { + unsigned char buf[256]; + int bytes = 0; - if (!ast_adsi_available(chan)) - return; - bytes += adsi_logo(buf + bytes); - bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, " ", ""); - bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Goodbye", ""); - bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1); - bytes += ast_adsi_voice_mode(buf + bytes, 0); + if (!ast_adsi_available(chan)) + return; + bytes += adsi_logo(buf + bytes); + bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, " ", ""); + bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Goodbye", ""); + bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1); + bytes += ast_adsi_voice_mode(buf + bytes, 0); - ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY); -} + ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY); + } -/*!\brief get_folder: Folder menu - * Plays "press 1 for INBOX messages" etc. - * Should possibly be internationalized - */ -static int get_folder(struct ast_channel *chan, int start) -{ - int x; - int d; - char fn[PATH_MAX]; - d = ast_play_and_wait(chan, "vm-press"); /* "Press" */ - if (d) - return d; - for (x = start; x < 5; x++) { /* For all folders */ - if ((d = ast_say_number(chan, x, AST_DIGIT_ANY, chan->language, NULL))) - return d; - d = ast_play_and_wait(chan, "vm-for"); /* "for" */ - if (d) - return d; - snprintf(fn, sizeof(fn), "vm-%s", mbox(x)); /* Folder name */ - d = vm_play_folder_name(chan, fn); + /*!\brief get_folder: Folder menu + * Plays "press 1 for INBOX messages" etc. + * Should possibly be internationalized + */ + static int get_folder(struct ast_channel *chan, int start) + { + int x; + int d; + char fn[PATH_MAX]; + d = ast_play_and_wait(chan, "vm-press"); /* "Press" */ if (d) return d; - d = ast_waitfordigit(chan, 500); + for (x = start; x < 5; x++) { /* For all folders */ + if ((d = ast_say_number(chan, x, AST_DIGIT_ANY, chan->language, NULL))) + return d; + d = ast_play_and_wait(chan, "vm-for"); /* "for" */ + if (d) + return d; + snprintf(fn, sizeof(fn), "vm-%s", mbox(x)); /* Folder name */ + d = vm_play_folder_name(chan, fn); + if (d) + return d; + d = ast_waitfordigit(chan, 500); + if (d) + return d; + } + d = ast_play_and_wait(chan, "vm-tocancel"); /* "or pound to cancel" */ if (d) return d; - } - d = ast_play_and_wait(chan, "vm-tocancel"); /* "or pound to cancel" */ - if (d) + d = ast_waitfordigit(chan, 4000); return d; - d = ast_waitfordigit(chan, 4000); - return d; -} - -static int get_folder2(struct ast_channel *chan, char *fn, int start) -{ - int res = 0; - res = ast_play_and_wait(chan, fn); /* Folder name */ - while (((res < '0') || (res > '9')) && - (res != '#') && (res >= 0)) { - res = get_folder(chan, 0); } - return res; -} -static int vm_forwardoptions(struct ast_channel *chan, struct ast_vm_user *vmu, char *curdir, int curmsg, char *vmfmts, - char *context, signed char record_gain, long *duration, struct vm_state *vms) -{ - int cmd = 0; - int retries = 0, prepend_duration = 0, already_recorded = 0; - signed char zero_gain = 0; - struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE }; - struct ast_config *msg_cfg; - const char *duration_str; - char msgfile[PATH_MAX], backup[PATH_MAX]; - char textfile[PATH_MAX]; - - /* Must always populate duration correctly */ - make_file(msgfile, sizeof(msgfile), curdir, curmsg); - strcpy(textfile, msgfile); - strcpy(backup, msgfile); - strncat(textfile, ".txt", sizeof(textfile) - strlen(textfile) - 1); - strncat(backup, "-bak", sizeof(backup) - strlen(backup) - 1); - - if ((msg_cfg = ast_config_load(textfile, config_flags)) && (duration_str = ast_variable_retrieve(msg_cfg, "message", "duration"))) { - *duration = atoi(duration_str); - } else { - *duration = 0; + static int get_folder2(struct ast_channel *chan, char *fn, int start) + { + int res = 0; + res = ast_play_and_wait(chan, fn); /* Folder name */ + while (((res < '0') || (res > '9')) && + (res != '#') && (res >= 0)) { + res = get_folder(chan, 0); + } + return res; } - while ((cmd >= 0) && (cmd != 't') && (cmd != '*')) { - if (cmd) - retries = 0; - switch (cmd) { - case '1': - /* prepend a message to the current message, update the metadata and return */ - prepend_duration = 0; - - /* if we can't read the message metadata, stop now */ - if (!msg_cfg) { - cmd = 0; - break; - } - - /* Back up the original file, so we can retry the prepend */ - if (already_recorded) - ast_filecopy(backup, msgfile, NULL); - else - ast_filecopy(msgfile, backup, NULL); - already_recorded = 1; + static int vm_forwardoptions(struct ast_channel *chan, struct ast_vm_user *vmu, char *curdir, int curmsg, char *vmfmts, + char *context, signed char record_gain, long *duration, struct vm_state *vms) + { + int cmd = 0; + int retries = 0, prepend_duration = 0, already_recorded = 0; + signed char zero_gain = 0; + struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE }; + struct ast_config *msg_cfg; + const char *duration_str; + char msgfile[PATH_MAX], backup[PATH_MAX]; + char textfile[PATH_MAX]; + + /* Must always populate duration correctly */ + make_file(msgfile, sizeof(msgfile), curdir, curmsg); + strcpy(textfile, msgfile); + strcpy(backup, msgfile); + strncat(textfile, ".txt", sizeof(textfile) - strlen(textfile) - 1); + strncat(backup, "-bak", sizeof(backup) - strlen(backup) - 1); + + if ((msg_cfg = ast_config_load(textfile, config_flags)) && (duration_str = ast_variable_retrieve(msg_cfg, "message", "duration"))) { + *duration = atoi(duration_str); + } else { + *duration = 0; + } - if (record_gain) - ast_channel_setoption(chan, AST_OPTION_RXGAIN, &record_gain, sizeof(record_gain), 0); + while ((cmd >= 0) && (cmd != 't') && (cmd != '*')) { + if (cmd) + retries = 0; + switch (cmd) { + case '1': + /* prepend a message to the current message, update the metadata and return */ + prepend_duration = 0; - cmd = ast_play_and_prepend(chan, NULL, msgfile, 0, vmfmts, &prepend_duration, 1, silencethreshold, maxsilence); - if (record_gain) - ast_channel_setoption(chan, AST_OPTION_RXGAIN, &zero_gain, sizeof(zero_gain), 0); + /* if we can't read the message metadata, stop now */ + if (!msg_cfg) { + cmd = 0; + break; + } - if (prepend_duration) { - struct ast_category *msg_cat; - /* need enough space for a maximum-length message duration */ - char duration_str[12]; - - prepend_duration += *duration; - msg_cat = ast_category_get(msg_cfg, "message"); - snprintf(duration_str, sizeof(duration_str), "%d", prepend_duration); - if (!ast_variable_update(msg_cat, "duration", duration_str, NULL, 0)) { - config_text_file_save(textfile, msg_cfg, "app_voicemail"); - STORE(curdir, vmu->mailbox, context, curmsg, chan, vmu, vmfmts, prepend_duration, vms); + /* Back up the original file, so we can retry the prepend */ + if (already_recorded) + ast_filecopy(backup, msgfile, NULL); + else + ast_filecopy(msgfile, backup, NULL); + already_recorded = 1; + + if (record_gain) + ast_channel_setoption(chan, AST_OPTION_RXGAIN, &record_gain, sizeof(record_gain), 0); + + cmd = ast_play_and_prepend(chan, NULL, msgfile, 0, vmfmts, &prepend_duration, 1, silencethreshold, maxsilence); + if (record_gain) + ast_channel_setoption(chan, AST_OPTION_RXGAIN, &zero_gain, sizeof(zero_gain), 0); + + if (prepend_duration) { + struct ast_category *msg_cat; + /* need enough space for a maximum-length message duration */ + char duration_str[12]; + + prepend_duration += *duration; + msg_cat = ast_category_get(msg_cfg, "message"); + snprintf(duration_str, sizeof(duration_str), "%d", prepend_duration); + if (!ast_variable_update(msg_cat, "duration", duration_str, NULL, 0)) { + config_text_file_save(textfile, msg_cfg, "app_voicemail"); + STORE(curdir, vmu->mailbox, context, curmsg, chan, vmu, vmfmts, prepend_duration, vms); + } } - } - break; - case '2': - cmd = 't'; - break; - case '*': - cmd = '*'; - break; - default: - cmd = ast_play_and_wait(chan, "vm-forwardoptions"); - /* "Press 1 to prepend a message or 2 to forward the message without prepending" */ - if (!cmd) - cmd = ast_play_and_wait(chan, "vm-starmain"); - /* "press star to return to the main menu" */ - if (!cmd) - cmd = ast_waitfordigit(chan, 6000); - if (!cmd) - retries++; - if (retries > 3) + break; + case '2': cmd = 't'; + break; + case '*': + cmd = '*'; + break; + default: + cmd = ast_play_and_wait(chan, "vm-forwardoptions"); + /* "Press 1 to prepend a message or 2 to forward the message without prepending" */ + if (!cmd) + cmd = ast_play_and_wait(chan, "vm-starmain"); + /* "press star to return to the main menu" */ + if (!cmd) + cmd = ast_waitfordigit(chan, 6000); + if (!cmd) + retries++; + if (retries > 3) + cmd = 't'; + } } - } - if (msg_cfg) - ast_config_destroy(msg_cfg); - if (already_recorded) - ast_filedelete(backup, NULL); - if (prepend_duration) - *duration = prepend_duration; + if (msg_cfg) + ast_config_destroy(msg_cfg); + if (already_recorded) + ast_filedelete(backup, NULL); + if (prepend_duration) + *duration = prepend_duration; - if (cmd == 't' || cmd == 'S') - cmd = 0; - return cmd; -} + if (cmd == 't' || cmd == 'S') + cmd = 0; + return cmd; + } -static void queue_mwi_event(const char *mbox, int new, int old) -{ - struct ast_event *event; - char *mailbox, *context; + static void queue_mwi_event(const char *mbox, int new, int old) + { + struct ast_event *event; + char *mailbox, *context; - /* Strip off @default */ - context = mailbox = ast_strdupa(mbox); - strsep(&context, "@"); - if (ast_strlen_zero(context)) - context = "default"; + /* Strip off @default */ + context = mailbox = ast_strdupa(mbox); + strsep(&context, "@"); + if (ast_strlen_zero(context)) + context = "default"; - if (!(event = ast_event_new(AST_EVENT_MWI, - AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, mailbox, - AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, context, - AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_UINT, new, - AST_EVENT_IE_OLDMSGS, AST_EVENT_IE_PLTYPE_UINT, old, - AST_EVENT_IE_END))) { - return; - } + if (!(event = ast_event_new(AST_EVENT_MWI, + AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, mailbox, + AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, context, + AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_UINT, new, + AST_EVENT_IE_OLDMSGS, AST_EVENT_IE_PLTYPE_UINT, old, + AST_EVENT_IE_END))) { + return; + } - ast_event_queue_and_cache(event, - AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, - AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, - AST_EVENT_IE_END); -} + ast_event_queue_and_cache(event, + AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, + AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, + AST_EVENT_IE_END); + } -static int notify_new_message(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int msgnum, long duration, char *fmt, char *cidnum, char *cidname) -{ - char todir[PATH_MAX], fn[PATH_MAX], ext_context[PATH_MAX], *stringp; - int newmsgs = 0, oldmsgs = 0; - const char *category = pbx_builtin_getvar_helper(chan, "VM_CATEGORY"); - char *myserveremail = serveremail; + static int notify_new_message(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int msgnum, long duration, char *fmt, char *cidnum, char *cidname) + { + char todir[PATH_MAX], fn[PATH_MAX], ext_context[PATH_MAX], *stringp; + int newmsgs = 0, oldmsgs = 0; + const char *category = pbx_builtin_getvar_helper(chan, "VM_CATEGORY"); + char *myserveremail = serveremail; - make_dir(todir, sizeof(todir), vmu->context, vmu->mailbox, "INBOX"); - make_file(fn, sizeof(fn), todir, msgnum); - snprintf(ext_context, sizeof(ext_context), "%s@%s", vmu->mailbox, vmu->context); + make_dir(todir, sizeof(todir), vmu->context, vmu->mailbox, "INBOX"); + make_file(fn, sizeof(fn), todir, msgnum); + snprintf(ext_context, sizeof(ext_context), "%s@%s", vmu->mailbox, vmu->context); - if (!ast_strlen_zero(vmu->attachfmt)) { - if (strstr(fmt, vmu->attachfmt)) - fmt = vmu->attachfmt; - else - ast_log(LOG_WARNING, "Attachment format '%s' is not one of the recorded formats '%s'. Falling back to default format for '%s@%s'.\n", vmu->attachfmt, fmt, vmu->mailbox, vmu->context); - } + if (!ast_strlen_zero(vmu->attachfmt)) { + if (strstr(fmt, vmu->attachfmt)) + fmt = vmu->attachfmt; + else + ast_log(LOG_WARNING, "Attachment format '%s' is not one of the recorded formats '%s'. Falling back to default format for '%s@%s'.\n", vmu->attachfmt, fmt, vmu->mailbox, vmu->context); + } - /* Attach only the first format */ - fmt = ast_strdupa(fmt); - stringp = fmt; - strsep(&stringp, "|"); + /* Attach only the first format */ + fmt = ast_strdupa(fmt); + stringp = fmt; + strsep(&stringp, "|"); - if (!ast_strlen_zero(vmu->serveremail)) - myserveremail = vmu->serveremail; + if (!ast_strlen_zero(vmu->serveremail)) + myserveremail = vmu->serveremail; - if (!ast_strlen_zero(vmu->email)) { - int attach_user_voicemail = ast_test_flag(vmu, VM_ATTACH); - if (!attach_user_voicemail) - attach_user_voicemail = ast_test_flag((&globalflags), VM_ATTACH); + if (!ast_strlen_zero(vmu->email)) { + int attach_user_voicemail = ast_test_flag(vmu, VM_ATTACH); + if (!attach_user_voicemail) + attach_user_voicemail = ast_test_flag((&globalflags), VM_ATTACH); - if (attach_user_voicemail) - RETRIEVE(todir, msgnum, vmu->mailbox, vmu->context); + if (attach_user_voicemail) + RETRIEVE(todir, msgnum, vmu->mailbox, vmu->context); - /* XXX possible imap issue, should category be NULL XXX */ - sendmail(myserveremail, vmu, msgnum, vmu->context, vmu->mailbox, cidnum, cidname, fn, fmt, duration, attach_user_voicemail, chan, category); + /* XXX possible imap issue, should category be NULL XXX */ + sendmail(myserveremail, vmu, msgnum, vmu->context, vmu->mailbox, cidnum, cidname, fn, fmt, duration, attach_user_voicemail, chan, category); - if (attach_user_voicemail) - DISPOSE(todir, msgnum); - } + if (attach_user_voicemail) + DISPOSE(todir, msgnum); + } - if (!ast_strlen_zero(vmu->pager)) - sendpage(myserveremail, vmu->pager, msgnum, vmu->context, vmu->mailbox, cidnum, cidname, duration, vmu, category); + if (!ast_strlen_zero(vmu->pager)) + sendpage(myserveremail, vmu->pager, msgnum, vmu->context, vmu->mailbox, cidnum, cidname, duration, vmu, category); - if (ast_test_flag(vmu, VM_DELETE)) - DELETE(todir, msgnum, fn); + if (ast_test_flag(vmu, VM_DELETE)) + DELETE(todir, msgnum, fn, vmu); - /* Leave voicemail for someone */ - if (ast_app_has_voicemail(ext_context, NULL)) - ast_app_inboxcount(ext_context, &newmsgs, &oldmsgs); + /* Leave voicemail for someone */ + if (ast_app_has_voicemail(ext_context, NULL)) + ast_app_inboxcount(ext_context, &newmsgs, &oldmsgs); - queue_mwi_event(ext_context, newmsgs, oldmsgs); + queue_mwi_event(ext_context, newmsgs, oldmsgs); - manager_event(EVENT_FLAG_CALL, "MessageWaiting", "Mailbox: %s@%s\r\nWaiting: %d\r\nNew: %d\r\nOld: %d\r\n", vmu->mailbox, vmu->context, ast_app_has_voicemail(ext_context, NULL), newmsgs, oldmsgs); - run_externnotify(vmu->context, vmu->mailbox); + manager_event(EVENT_FLAG_CALL, "MessageWaiting", "Mailbox: %s@%s\r\nWaiting: %d\r\nNew: %d\r\nOld: %d\r\n", vmu->mailbox, vmu->context, ast_app_has_voicemail(ext_context, NULL), newmsgs, oldmsgs); + run_externnotify(vmu->context, vmu->mailbox); -#ifdef IMAP_STORAGE - DELETE(todir, msgnum, fn); /* Delete the file, but not the IMAP message */ - if (ast_test_flag(vmu, VM_DELETE)) { /* Delete the IMAP message if delete = yes */ - IMAP_DELETE(vms->curdir, vms->curmsg, vms->fn, vms); - vms->newmessages--; /* Fix new message count */ + return 0; } -#endif - return 0; -} -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) -{ + 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; + int todircount = 0; + struct vm_state *dstvms; #endif - char username[70] = ""; - char fn[PATH_MAX]; /* for playback of name greeting */ - char ecodes[16] = "#"; - int res = 0, cmd = 0; - struct ast_vm_user *receiver = NULL, *vmtmp; - AST_LIST_HEAD_NOLOCK_STATIC(extensions, ast_vm_user); - char *stringp; - const char *s; - int saved_messages = 0, found = 0; - int valid_extensions = 0; - char *dir; - int curmsg; - - if (vms == NULL) return -1; - dir = vms->curdir; - curmsg = vms->curmsg; - - while (!res && !valid_extensions) { - int use_directory = 0; - if (ast_test_flag((&globalflags), VM_DIRECFORWARD)) { - int done = 0; - int retries = 0; - cmd = 0; - while ((cmd >= 0) && !done) { - if (cmd) - retries = 0; - switch (cmd) { - case '1': - use_directory = 0; - done = 1; - break; - case '2': - use_directory = 1; - done = 1; - break; - case '*': - cmd = 't'; - done = 1; - break; - default: - /* Press 1 to enter an extension press 2 to use the directory */ - cmd = ast_play_and_wait(chan, "vm-forward"); - if (!cmd) - cmd = ast_waitfordigit(chan, 3000); - if (!cmd) - retries++; - if (retries > 3) { + char username[70] = ""; + char fn[PATH_MAX]; /* for playback of name greeting */ + char ecodes[16] = "#"; + int res = 0, cmd = 0; + struct ast_vm_user *receiver = NULL, *vmtmp; + AST_LIST_HEAD_NOLOCK_STATIC(extensions, ast_vm_user); + char *stringp; + const char *s; + int saved_messages = 0, found = 0; + int valid_extensions = 0; + char *dir; + int curmsg; + + if (vms == NULL) return -1; + dir = vms->curdir; + curmsg = vms->curmsg; + + while (!res && !valid_extensions) { + int use_directory = 0; + if (ast_test_flag((&globalflags), VM_DIRECFORWARD)) { + int done = 0; + int retries = 0; + cmd = 0; + while ((cmd >= 0) && !done) { + if (cmd) + retries = 0; + switch (cmd) { + case '1': + use_directory = 0; + done = 1; + break; + case '2': + use_directory = 1; + done = 1; + break; + case '*': cmd = 't'; done = 1; + break; + default: + /* Press 1 to enter an extension press 2 to use the directory */ + cmd = ast_play_and_wait(chan, "vm-forward"); + if (!cmd) + cmd = ast_waitfordigit(chan, 3000); + if (!cmd) + retries++; + if (retries > 3) { + cmd = 't'; + done = 1; + } + } - } + if (cmd < 0 || cmd == 't') + break; } - if (cmd < 0 || cmd == 't') - break; - } - - if (use_directory) { - /* use app_directory */ - - char old_context[sizeof(chan->context)]; - char old_exten[sizeof(chan->exten)]; - int old_priority; - struct ast_app* app; - - app = pbx_findapp("Directory"); - if (app) { - char vmcontext[256]; - /* make backup copies */ - memcpy(old_context, chan->context, sizeof(chan->context)); - memcpy(old_exten, chan->exten, sizeof(chan->exten)); - old_priority = chan->priority; + if (use_directory) { + /* use app_directory */ - /* call the the Directory, changes the channel */ - snprintf(vmcontext, sizeof(vmcontext), "%s||v", context ? context : "default"); - res = pbx_exec(chan, app, vmcontext); - - ast_copy_string(username, chan->exten, sizeof(username)); - - /* restore the old context, exten, and priority */ - memcpy(chan->context, old_context, sizeof(chan->context)); - memcpy(chan->exten, old_exten, sizeof(chan->exten)); - chan->priority = old_priority; + char old_context[sizeof(chan->context)]; + char old_exten[sizeof(chan->exten)]; + int old_priority; + struct ast_app* app; + + app = pbx_findapp("Directory"); + if (app) { + char vmcontext[256]; + /* make backup copies */ + memcpy(old_context, chan->context, sizeof(chan->context)); + memcpy(old_exten, chan->exten, sizeof(chan->exten)); + old_priority = chan->priority; + + /* call the the Directory, changes the channel */ + snprintf(vmcontext, sizeof(vmcontext), "%s||v", context ? context : "default"); + res = pbx_exec(chan, app, vmcontext); + + ast_copy_string(username, chan->exten, sizeof(username)); + + /* restore the old context, exten, and priority */ + memcpy(chan->context, old_context, sizeof(chan->context)); + memcpy(chan->exten, old_exten, sizeof(chan->exten)); + chan->priority = old_priority; + + } else { + ast_log(LOG_WARNING, "Could not find the Directory application, disabling directory_forward\n"); + ast_clear_flag((&globalflags), VM_DIRECFORWARD); + } } else { - ast_log(LOG_WARNING, "Could not find the Directory application, disabling directory_forward\n"); - ast_clear_flag((&globalflags), VM_DIRECFORWARD); - } - } else { - /* Ask for an extension */ - res = ast_streamfile(chan, "vm-extension", chan->language); /* "extension" */ - if (res) - break; - if ((res = ast_readstring(chan, username, sizeof(username) - 1, 2000, 10000, "#") < 0)) - break; - } - - /* start all over if no username */ - if (ast_strlen_zero(username)) - continue; - stringp = username; - s = strsep(&stringp, "*"); - /* start optimistic */ - valid_extensions = 1; - while (s) { - /* Don't forward to ourselves but allow leaving a message for ourselves (flag == 1). find_user is going to malloc since we have a NULL as first argument */ - if ((flag == 1 || strcmp(s, sender->mailbox)) && (receiver = find_user(NULL, context, s))) { - AST_LIST_INSERT_HEAD(&extensions, receiver, list); - found++; - } else { - valid_extensions = 0; - break; + /* Ask for an extension */ + res = ast_streamfile(chan, "vm-extension", chan->language); /* "extension" */ + if (res) + break; + if ((res = ast_readstring(chan, username, sizeof(username) - 1, 2000, 10000, "#") < 0)) + break; } + + /* start all over if no username */ + if (ast_strlen_zero(username)) + continue; + stringp = username; + s = strsep(&stringp, "*"); + /* start optimistic */ + valid_extensions = 1; + while (s) { + /* Don't forward to ourselves but allow leaving a message for ourselves (flag == 1). find_user is going to malloc since we have a NULL as first argument */ + if ((flag == 1 || strcmp(s, sender->mailbox)) && (receiver = find_user(NULL, context, s))) { + AST_LIST_INSERT_HEAD(&extensions, receiver, list); + found++; + } else { + valid_extensions = 0; + break; + } - /* play name if available, else play extension number */ - snprintf(fn, sizeof(fn), "%s%s/%s/greet", VM_SPOOL_DIR, receiver->context, s); - RETRIEVE(fn, -1, s, receiver->context); - if (ast_fileexists(fn, NULL, NULL) > 0) { - res = ast_stream_and_wait(chan, fn, ecodes); - if (res) { + /* play name if available, else play extension number */ + snprintf(fn, sizeof(fn), "%s%s/%s/greet", VM_SPOOL_DIR, receiver->context, s); + RETRIEVE(fn, -1, s, receiver->context); + if (ast_fileexists(fn, NULL, NULL) > 0) { + res = ast_stream_and_wait(chan, fn, ecodes); + if (res) { + DISPOSE(fn, -1); + return res; + } + } else { + /* Dispose just in case */ DISPOSE(fn, -1); - return res; + res = ast_say_digit_str(chan, s, ecodes, chan->language); } - } else { - /* Dispose just in case */ - DISPOSE(fn, -1); - res = ast_say_digit_str(chan, s, ecodes, chan->language); - } - s = strsep(&stringp, "*"); + s = strsep(&stringp, "*"); + } + /* break from the loop of reading the extensions */ + if (valid_extensions) + break; + /* "I am sorry, that's not a valid extension. Please try again." */ + res = ast_play_and_wait(chan, "pbx-invalid"); } - /* break from the loop of reading the extensions */ - if (valid_extensions) - break; - /* "I am sorry, that's not a valid extension. Please try again." */ - res = ast_play_and_wait(chan, "pbx-invalid"); - } - /* check if we're clear to proceed */ - if (AST_LIST_EMPTY(&extensions) || !valid_extensions) - return res; - if (flag==1) { - struct leave_vm_options leave_options; - char mailbox[AST_MAX_EXTENSION * 2 + 2]; - /* Make sure that context doesn't get set as a literal "(null)" (or else find_user won't find it) */ - if (context) - snprintf(mailbox, sizeof(mailbox), "%s@%s", username, context); - else - ast_copy_string(mailbox, username, sizeof(mailbox)); - - /* Send VoiceMail */ - memset(&leave_options, 0, sizeof(leave_options)); - leave_options.record_gain = record_gain; - cmd = leave_voicemail(chan, mailbox, &leave_options); - } else { - /* Forward VoiceMail */ - long duration = 0; - char origmsgfile[PATH_MAX], msgfile[PATH_MAX]; - struct vm_state vmstmp; - memcpy(&vmstmp, vms, sizeof(vmstmp)); - - make_file(origmsgfile, sizeof(origmsgfile), dir, curmsg); - create_dirpath(vmstmp.curdir, sizeof(vmstmp.curdir), sender->context, vmstmp.username, "tmp"); - make_file(msgfile, sizeof(msgfile), vmstmp.curdir, curmsg); - - RETRIEVE(dir, curmsg, sender->mailbox, context); + /* check if we're clear to proceed */ + if (AST_LIST_EMPTY(&extensions) || !valid_extensions) + return res; + if (flag==1) { + struct leave_vm_options leave_options; + char mailbox[AST_MAX_EXTENSION * 2 + 2]; + /* Make sure that context doesn't get set as a literal "(null)" (or else find_user won't find it) */ + if (context) + snprintf(mailbox, sizeof(mailbox), "%s@%s", username, context); + else + ast_copy_string(mailbox, username, sizeof(mailbox)); - /* Alter a surrogate file, only */ - copy_plain_file(origmsgfile, msgfile); + /* Send VoiceMail */ + memset(&leave_options, 0, sizeof(leave_options)); + leave_options.record_gain = record_gain; + cmd = leave_voicemail(chan, mailbox, &leave_options); + } else { + /* Forward VoiceMail */ + long duration = 0; + char origmsgfile[PATH_MAX], msgfile[PATH_MAX]; + struct vm_state vmstmp; + memcpy(&vmstmp, vms, sizeof(vmstmp)); + + make_file(origmsgfile, sizeof(origmsgfile), dir, curmsg); + create_dirpath(vmstmp.curdir, sizeof(vmstmp.curdir), sender->context, vmstmp.username, "tmp"); + make_file(msgfile, sizeof(msgfile), vmstmp.curdir, curmsg); + + RETRIEVE(dir, curmsg, sender->mailbox, sender->context); + + /* Alter a surrogate file, only */ + copy_plain_file(origmsgfile, msgfile); - cmd = vm_forwardoptions(chan, sender, vmstmp.curdir, curmsg, vmfmts, S_OR(context, "default"), record_gain, &duration, &vmstmp); - if (!cmd) { - AST_LIST_TRAVERSE_SAFE_BEGIN(&extensions, vmtmp, list) { + cmd = vm_forwardoptions(chan, sender, vmstmp.curdir, curmsg, vmfmts, S_OR(context, "default"), record_gain, &duration, &vmstmp); + if (!cmd) { + AST_LIST_TRAVERSE_SAFE_BEGIN(&extensions, vmtmp, list) { #ifdef IMAP_STORAGE - char *myserveremail = serveremail; - int attach_user_voicemail; - char buf[1024] = ""; - - /* Need to get message content */ - ast_debug(3, "Before mail_fetchheaders, curmsg is: %d, imap messages is %lu\n", vms->curmsg, vms->msgArray[vms->curmsg]); - if (!vms->msgArray[vms->curmsg]) { - ast_log(LOG_WARNING, "Trying to access unknown message\n"); - return -1; - } - - /* This will only work for new messages... */ - 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 */ - if ((temp = get_header_by_tag(header_content, "X-Asterisk-VM-Duration:", buf, sizeof(buf)))) - duration = atoi(temp); - else - duration = 0; - - /* Attach only the first format */ - if ((fmt = ast_strdupa(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"; - ast_debug(3, "**** format set to %s, vmfmts set to %s\n", fmt, vmfmts); - 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); - - ast_debug(3, "Before mail_fetchstructure, message number is %ld, filename is:%s\n", vms->msgArray[vms->curmsg], vms->fn); - 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); - } - if (dstvms) { - init_mailstream(dstvms, 0); - if (!dstvms->mailstream) { - ast_log(LOG_ERROR, "IMAP mailstream for %s is NULL\n", vmtmp->mailbox); + char *myserveremail = serveremail; + int attach_user_voicemail; + /* get destination mailbox */ + dstvms = get_vm_state_by_mailbox(vmtmp->mailbox, 0); + if (!dstvms) { + 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(vmstmp.curdir, vmtmp->mailbox, vmtmp->context, dstvms->curmsg, chan, vmtmp, fmt, duration, dstvms); + run_externnotify(vmtmp->context, vmtmp->mailbox); + } } else { - STORE(todir, vmtmp->mailbox, vmtmp->context, dstvms->curmsg, chan, vmtmp, fmt, duration, dstvms); - run_externnotify(vmtmp->context, vmtmp->mailbox); + ast_log(LOG_ERROR, "Could not find state information for mailbox %s\n", vmtmp->mailbox); } - } else { - ast_log(LOG_ERROR, "Could not find state information for mailbox %s\n", vmtmp->mailbox); - } - - if (!ast_strlen_zero(vmtmp->serveremail)) - myserveremail = vmtmp->serveremail; - 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); - + if (!ast_strlen_zero(vmtmp->serveremail)) + myserveremail = vmtmp->serveremail; + 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); #else - copy_message(chan, sender, -1, curmsg, duration, vmtmp, fmt, vmstmp.curdir); + copy_message(chan, sender, -1, curmsg, duration, vmtmp, fmt, vmstmp.curdir); #endif - saved_messages++; - AST_LIST_REMOVE_CURRENT(list); - free_user(vmtmp); - if (res) - break; + saved_messages++; + AST_LIST_REMOVE_CURRENT(list); + free_user(vmtmp); + if (res) + break; + } + AST_LIST_TRAVERSE_SAFE_END; + if (saved_messages > 0) { + /* give confirmation that the message was saved */ + /* commented out since we can't forward batches yet + if (saved_messages == 1) + res = ast_play_and_wait(chan, "vm-message"); + else + res = ast_play_and_wait(chan, "vm-messages"); + if (!res) + res = ast_play_and_wait(chan, "vm-saved"); */ + res = ast_play_and_wait(chan, "vm-msgsaved"); + } } - AST_LIST_TRAVERSE_SAFE_END; - if (saved_messages > 0) { - /* give confirmation that the message was saved */ - /* commented out since we can't forward batches yet - if (saved_messages == 1) - res = ast_play_and_wait(chan, "vm-message"); - else - res = ast_play_and_wait(chan, "vm-messages"); - if (!res) - res = ast_play_and_wait(chan, "vm-saved"); */ - res = ast_play_and_wait(chan, "vm-msgsaved"); - } + /* Remove surrogate file */ + DISPOSE(dir, curmsg); } - /* Remove surrogate file */ - vm_delete(msgfile); + /* If anything failed above, we still have this list to free */ + while ((vmtmp = AST_LIST_REMOVE_HEAD(&extensions, list))) + free_user(vmtmp); + return res ? res : cmd; } - /* If anything failed above, we still have this list to free */ - while ((vmtmp = AST_LIST_REMOVE_HEAD(&extensions, list))) - free_user(vmtmp); - return res ? res : cmd; -} + static int wait_file2(struct ast_channel *chan, struct vm_state *vms, char *file) + { + int res; + if ((res = ast_stream_and_wait(chan, file, AST_DIGIT_ANY)) < 0) + ast_log(LOG_WARNING, "Unable to play message %s\n", file); + return res; + } -static int wait_file2(struct ast_channel *chan, struct vm_state *vms, char *file) -{ - int res; - if ((res = ast_stream_and_wait(chan, file, AST_DIGIT_ANY)) < 0) - ast_log(LOG_WARNING, "Unable to play message %s\n", file); - return res; -} + static int wait_file(struct ast_channel *chan, struct vm_state *vms, char *file) + { + return ast_control_streamfile(chan, file, listen_control_forward_key, listen_control_reverse_key, listen_control_stop_key, listen_control_pause_key, listen_control_restart_key, skipms, NULL); + } -static int wait_file(struct ast_channel *chan, struct vm_state *vms, char *file) -{ - return ast_control_streamfile(chan, file, listen_control_forward_key, listen_control_reverse_key, listen_control_stop_key, listen_control_pause_key, listen_control_restart_key, skipms, NULL); -} + static int play_message_category(struct ast_channel *chan, const char *category) + { + int res = 0; -static int play_message_category(struct ast_channel *chan, const char *category) -{ - int res = 0; + if (!ast_strlen_zero(category)) + res = ast_play_and_wait(chan, category); - if (!ast_strlen_zero(category)) - res = ast_play_and_wait(chan, category); + if (res) { + ast_log(LOG_WARNING, "No sound file for category '%s' was found.\n", category); + res = 0; + } - if (res) { - ast_log(LOG_WARNING, "No sound file for category '%s' was found.\n", category); - res = 0; + return res; } - return res; -} + static int play_message_datetime(struct ast_channel *chan, struct ast_vm_user *vmu, const char *origtime, const char *filename) + { + int res = 0; + struct vm_zone *the_zone = NULL; + time_t t; -static int play_message_datetime(struct ast_channel *chan, struct ast_vm_user *vmu, const char *origtime, const char *filename) -{ - int res = 0; - struct vm_zone *the_zone = NULL; - time_t t; - - if (ast_get_time_t(origtime, &t, 0, NULL)) { - ast_log(LOG_WARNING, "Couldn't find origtime in %s\n", filename); - return 0; - } + if (ast_get_time_t(origtime, &t, 0, NULL)) { + ast_log(LOG_WARNING, "Couldn't find origtime in %s\n", filename); + return 0; + } - /* Does this user have a timezone specified? */ - if (!ast_strlen_zero(vmu->zonetag)) { - /* Find the zone in the list */ - struct vm_zone *z; - AST_LIST_LOCK(&zones); - AST_LIST_TRAVERSE(&zones, z, list) { - if (!strcmp(z->name, vmu->zonetag)) { - the_zone = z; - break; + /* Does this user have a timezone specified? */ + if (!ast_strlen_zero(vmu->zonetag)) { + /* Find the zone in the list */ + struct vm_zone *z; + AST_LIST_LOCK(&zones); + AST_LIST_TRAVERSE(&zones, z, list) { + if (!strcmp(z->name, vmu->zonetag)) { + the_zone = z; + break; + } } + AST_LIST_UNLOCK(&zones); } - AST_LIST_UNLOCK(&zones); - } -/* No internal variable parsing for now, so we'll comment it out for the time being */ + /* No internal variable parsing for now, so we'll comment it out for the time being */ #if 0 - /* Set the DIFF_* variables */ - ast_localtime(&t, &time_now, NULL); - tv_now = ast_tvnow(); - ast_localtime(&tv_now, &time_then, NULL); - - /* Day difference */ - if (time_now.tm_year == time_then.tm_year) - snprintf(temp, sizeof(temp), "%d", time_now.tm_yday); - else - snprintf(temp, sizeof(temp), "%d", (time_now.tm_year - time_then.tm_year) * 365 + (time_now.tm_yday - time_then.tm_yday)); - pbx_builtin_setvar_helper(chan, "DIFF_DAY", temp); + /* Set the DIFF_* variables */ + ast_localtime(&t, &time_now, NULL); + tv_now = ast_tvnow(); + ast_localtime(&tv_now, &time_then, NULL); + + /* Day difference */ + if (time_now.tm_year == time_then.tm_year) + snprintf(temp, sizeof(temp), "%d", time_now.tm_yday); + else + snprintf(temp, sizeof(temp), "%d", (time_now.tm_year - time_then.tm_year) * 365 + (time_now.tm_yday - time_then.tm_yday)); + pbx_builtin_setvar_helper(chan, "DIFF_DAY", temp); - /* Can't think of how other diffs might be helpful, but I'm sure somebody will think of something. */ + /* Can't think of how other diffs might be helpful, but I'm sure somebody will think of something. */ #endif - if (the_zone) - res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, the_zone->msg_format, the_zone->timezone); - else if (!strcasecmp(chan->language, "pl")) /* POLISH syntax */ - res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' Q HM", NULL); - else if (!strcasecmp(chan->language, "se")) /* SWEDISH syntax */ - res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' dB 'digits/at' k 'and' M", NULL); - else if (!strcasecmp(chan->language, "no")) /* NORWEGIAN syntax */ - res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' Q 'digits/at' HM", NULL); - else if (!strcasecmp(chan->language, "de")) /* GERMAN syntax */ - res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' Q 'digits/at' HM", NULL); - else if (!strcasecmp(chan->language, "nl")) /* DUTCH syntax */ - res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q 'digits/nl-om' HM", NULL); - else if (!strcasecmp(chan->language, "it")) /* ITALIAN syntax */ - res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q 'digits/at' 'digits/hours' k 'digits/e' M 'digits/minutes'", NULL); - else if (!strcasecmp(chan->language, "gr")) - res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q H 'digits/kai' M ", NULL); - else if (!strcasecmp(chan->language, "pt_BR")) - res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' Ad 'digits/pt-de' B 'digits/pt-de' Y 'digits/pt-as' HM ", NULL); - else if (!strcasecmp(chan->language, "tw")) /* CHINESE (Taiwan) syntax */ - res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "qR 'vm-received'", NULL); - else - res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q 'digits/at' IMp", NULL); + if (the_zone) { + res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, the_zone->msg_format, the_zone->timezone); + } + else if (!strcasecmp(chan->language,"pl")) /* POLISH syntax */ + res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' Q HM", NULL); + else if (!strcasecmp(chan->language, "se")) /* SWEDISH syntax */ + res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' dB 'digits/at' k 'and' M", NULL); + else if (!strcasecmp(chan->language, "no")) /* NORWEGIAN syntax */ + res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' Q 'digits/at' HM", NULL); + else if (!strcasecmp(chan->language, "de")) /* GERMAN syntax */ + res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' Q 'digits/at' HM", NULL); + else if (!strcasecmp(chan->language, "nl")) /* DUTCH syntax */ + res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q 'digits/nl-om' HM", NULL); + else if (!strcasecmp(chan->language, "it")) /* ITALIAN syntax */ + res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q 'digits/at' 'digits/hours' k 'digits/e' M 'digits/minutes'", NULL); + else if (!strcasecmp(chan->language, "gr")) + res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q H 'digits/kai' M ", NULL); + else if (!strcasecmp(chan->language, "pt_BR")) + res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' Ad 'digits/pt-de' B 'digits/pt-de' Y 'digits/pt-as' HM ", NULL); + else if (!strcasecmp(chan->language, "tw")) /* CHINESE (Taiwan) syntax */ + res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "qR 'vm-received'", NULL); + else { + res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q 'digits/at' IMp", NULL); + } #if 0 - pbx_builtin_setvar_helper(chan, "DIFF_DAY", NULL); + pbx_builtin_setvar_helper(chan, "DIFF_DAY", NULL); #endif - return res; -} + return res; + } -static int play_message_callerid(struct ast_channel *chan, struct vm_state *vms, char *cid, const char *context, int callback) -{ - int res = 0; - int i; - char *callerid, *name; - char prefile[PATH_MAX] = ""; - + static int play_message_callerid(struct ast_channel *chan, struct vm_state *vms, char *cid, const char *context, int callback) + { + int res = 0; + int i; + char *callerid, *name; + char prefile[PATH_MAX] = ""; + - /* If voicemail cid is not enabled, or we didn't get cid or context from - * the attribute file, leave now. - * - * TODO Still need to change this so that if this function is called by the - * message envelope (and someone is explicitly requesting to hear the CID), - * it does not check to see if CID is enabled in the config file. - */ - if ((cid == NULL)||(context == NULL)) - return res; + /* If voicemail cid is not enabled, or we didn't get cid or context from + * the attribute file, leave now. + * + * TODO Still need to change this so that if this function is called by the + * message envelope (and someone is explicitly requesting to hear the CID), + * it does not check to see if CID is enabled in the config file. + */ + if ((cid == NULL)||(context == NULL)) + return res; - /* Strip off caller ID number from name */ - ast_debug(1, "VM-CID: composite caller ID received: %s, context: %s\n", cid, context); - ast_callerid_parse(cid, &name, &callerid); - if ((!ast_strlen_zero(callerid)) && strcmp(callerid, "Unknown")) { - /* Check for internal contexts and only */ - /* say extension when the call didn't come from an internal context in the list */ - for (i = 0 ; i < MAX_NUM_CID_CONTEXTS ; i++) { - ast_debug(1, "VM-CID: comparing internalcontext: %s\n", cidinternalcontexts[i]); - if ((strcmp(cidinternalcontexts[i], context) == 0)) - break; - } - if (i != MAX_NUM_CID_CONTEXTS) { /* internal context? */ - if (!res) { - snprintf(prefile, sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, context, callerid); - if (!ast_strlen_zero(prefile)) { - /* See if we can find a recorded name for this person instead of their extension number */ - if (ast_fileexists(prefile, NULL, NULL) > 0) { - ast_verb(3, "Playing envelope info: CID number '%s' matches mailbox number, playing recorded name\n", callerid); - if (!callback) - res = wait_file2(chan, vms, "vm-from"); - res = ast_stream_and_wait(chan, prefile, ""); - } else { - ast_verb(3, "Playing envelope info: message from '%s'\n", callerid); - /* Say "from extension" as one saying to sound smoother */ - if (!callback) - res = wait_file2(chan, vms, "vm-from-extension"); - res = ast_say_digit_str(chan, callerid, "", chan->language); + /* Strip off caller ID number from name */ + ast_debug(1, "VM-CID: composite caller ID received: %s, context: %s\n", cid, context); + ast_callerid_parse(cid, &name, &callerid); + if ((!ast_strlen_zero(callerid)) && strcmp(callerid, "Unknown")) { + /* Check for internal contexts and only */ + /* say extension when the call didn't come from an internal context in the list */ + for (i = 0 ; i < MAX_NUM_CID_CONTEXTS ; i++) { + ast_debug(1, "VM-CID: comparing internalcontext: %s\n", cidinternalcontexts[i]); + if ((strcmp(cidinternalcontexts[i], context) == 0)) + break; + } + if (i != MAX_NUM_CID_CONTEXTS) { /* internal context? */ + if (!res) { + snprintf(prefile, sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, context, callerid); + if (!ast_strlen_zero(prefile)) { + /* See if we can find a recorded name for this person instead of their extension number */ + if (ast_fileexists(prefile, NULL, NULL) > 0) { + ast_verb(3, "Playing envelope info: CID number '%s' matches mailbox number, playing recorded name\n", callerid); + if (!callback) + res = wait_file2(chan, vms, "vm-from"); + res = ast_stream_and_wait(chan, prefile, ""); + } else { + ast_verb(3, "Playing envelope info: message from '%s'\n", callerid); + /* Say "from extension" as one saying to sound smoother */ + if (!callback) + res = wait_file2(chan, vms, "vm-from-extension"); + res = ast_say_digit_str(chan, callerid, "", chan->language); + } } } + } else if (!res) { + ast_debug(1, "VM-CID: Numeric caller id: (%s)\n", callerid); + /* Since this is all nicely figured out, why not say "from phone number" in this case? */ + if (!callback) + res = wait_file2(chan, vms, "vm-from-phonenumber"); + res = ast_say_digit_str(chan, callerid, AST_DIGIT_ANY, chan->language); } - } else if (!res) { - ast_debug(1, "VM-CID: Numeric caller id: (%s)\n", callerid); - /* Since this is all nicely figured out, why not say "from phone number" in this case? */ - if (!callback) - res = wait_file2(chan, vms, "vm-from-phonenumber"); - res = ast_say_digit_str(chan, callerid, AST_DIGIT_ANY, chan->language); + } else { + /* Number unknown */ + ast_debug(1, "VM-CID: From an unknown number\n"); + /* Say "from an unknown caller" as one phrase - it is already recorded by "the voice" anyhow */ + res = wait_file2(chan, vms, "vm-unknown-caller"); } - } else { - /* Number unknown */ - ast_debug(1, "VM-CID: From an unknown number\n"); - /* Say "from an unknown caller" as one phrase - it is already recorded by "the voice" anyhow */ - res = wait_file2(chan, vms, "vm-unknown-caller"); + return res; } - return res; -} -static int play_message_duration(struct ast_channel *chan, struct vm_state *vms, const char *duration, int minduration) -{ - int res = 0; - int durationm; - int durations; - /* Verify that we have a duration for the message */ - if (duration == NULL) - return res; + static int play_message_duration(struct ast_channel *chan, struct vm_state *vms, const char *duration, int minduration) + { + int res = 0; + int durationm; + int durations; + /* Verify that we have a duration for the message */ + if (duration == NULL) + return res; - /* Convert from seconds to minutes */ - durations = atoi(duration); - durationm = durations / 60; + /* Convert from seconds to minutes */ + durations = atoi(duration); + durationm = durations / 60; - ast_debug(1, "VM-Duration: duration is: %d seconds converted to: %d minutes\n", durations, durationm); + ast_debug(1, "VM-Duration: duration is: %d seconds converted to: %d minutes\n", durations, durationm); - if ((!res) && (durationm >= minduration)) { - res = wait_file2(chan, vms, "vm-duration"); + if ((!res) && (durationm >= minduration)) { + res = wait_file2(chan, vms, "vm-duration"); - /* POLISH syntax */ - if (!strcasecmp(chan->language, "pl")) { - div_t num = div(durationm, 10); + /* POLISH syntax */ + if (!strcasecmp(chan->language, "pl")) { + div_t num = div(durationm, 10); - if (durationm == 1) { - res = ast_play_and_wait(chan, "digits/1z"); - res = res ? res : ast_play_and_wait(chan, "vm-minute-ta"); - } else if (num.rem > 1 && num.rem < 5 && num.quot != 1) { - if (num.rem == 2) { - if (!num.quot) { - res = ast_play_and_wait(chan, "digits/2-ie"); + if (durationm == 1) { + res = ast_play_and_wait(chan, "digits/1z"); + res = res ? res : ast_play_and_wait(chan, "vm-minute-ta"); + } else if (num.rem > 1 && num.rem < 5 && num.quot != 1) { + if (num.rem == 2) { + if (!num.quot) { + res = ast_play_and_wait(chan, "digits/2-ie"); + } else { + res = say_and_wait(chan, durationm - 2 , chan->language); + res = res ? res : ast_play_and_wait(chan, "digits/2-ie"); + } } else { - res = say_and_wait(chan, durationm - 2 , chan->language); - res = res ? res : ast_play_and_wait(chan, "digits/2-ie"); + res = say_and_wait(chan, durationm, chan->language); } + res = res ? res : ast_play_and_wait(chan, "vm-minute-ty"); } else { res = say_and_wait(chan, durationm, chan->language); + res = res ? res : ast_play_and_wait(chan, "vm-minute-t"); } - res = res ? res : ast_play_and_wait(chan, "vm-minute-ty"); + /* DEFAULT syntax */ } else { - res = say_and_wait(chan, durationm, chan->language); - res = res ? res : ast_play_and_wait(chan, "vm-minute-t"); + res = ast_say_number(chan, durationm, AST_DIGIT_ANY, chan->language, NULL); + res = wait_file2(chan, vms, "vm-minutes"); } - /* DEFAULT syntax */ - } else { - res = ast_say_number(chan, durationm, AST_DIGIT_ANY, chan->language, NULL); - res = wait_file2(chan, vms, "vm-minutes"); - } - } - 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], cidN[256]; - char context[256]; - char origtime[32]; - char duration[16]; - char category[32]; - char todir[PATH_MAX]; - int res = 0; - char *attachedfilefmt; - char *temp; - char buf[1024]; - - vms->starting = 0; - ast_debug(3, "Before mail_fetchheaders, curmsg is: %d, imap messages is %lu\n", vms->curmsg, vms->msgArray[vms->curmsg]); - - if (!vms->msgArray[vms->curmsg]) { - ast_log(LOG_WARNING, "Trying to access unknown message\n"); - return -1; - } - - /* 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, NULL); } + return res; } - /* Get info from headers!! */ - if ((temp = get_header_by_tag(header_content, "X-Asterisk-VM-Caller-ID-Name:", buf, sizeof(buf)))) - ast_copy_string(cidN, temp, sizeof(cidN)); - else - cidN[0] = '\0'; - - if ((temp = get_header_by_tag(header_content, "X-Asterisk-VM-Caller-ID-Num:", buf, sizeof(buf)))) - snprintf(cid, sizeof(cid), "\"%s\" <%s>", cidN, temp); - else - cid[0] = '\0'; - - if ((temp = get_header_by_tag(header_content, "X-Asterisk-VM-Context:", buf, sizeof(buf)))) - ast_copy_string(context, temp, sizeof(context)); - else - context[0] = '\0'; - - if ((temp = get_header_by_tag(header_content, "X-Asterisk-VM-Orig-time:", buf, sizeof(buf)))) - ast_copy_string(origtime, temp, sizeof(origtime)); - else - origtime[0] = '\0'; - - if ((temp = get_header_by_tag(header_content, "X-Asterisk-VM-Duration:", buf, sizeof(buf)))) - ast_copy_string(duration, temp, sizeof(duration)); - else - duration[0] = '\0'; - - if ((temp = get_header_by_tag(header_content, "X-Asterisk-VM-Category:", buf, sizeof(buf)))) - ast_copy_string(category, temp, sizeof(category)); - else - category[0] = '\0'; - - 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); - - res = 0; + static int play_message(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms) + { + int res = 0; + char filename[256], *cid; + const char *origtime, *context, *category, *duration; + struct ast_config *msg_cfg; + struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE }; - 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; - char filename[256], *cid; - const char *origtime, *context, *category, *duration; - struct ast_config *msg_cfg; - struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE }; - - vms->starting = 0; - make_file(vms->fn, sizeof(vms->fn), vms->curdir, vms->curmsg); - 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) { - /* POLISH syntax */ - if (!strcasecmp(chan->language, "pl")) { - if (vms->curmsg && (vms->curmsg != vms->lastmsg)) { - int ten, one; - char nextmsg[256]; - ten = (vms->curmsg + 1) / 10; - one = (vms->curmsg + 1) % 10; - - if (vms->curmsg < 20) { - snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", vms->curmsg + 1); - res = wait_file2(chan, vms, nextmsg); - } else { - snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", ten * 10); - res = wait_file2(chan, vms, nextmsg); - if (one > 0) { - if (!res) { - snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", one); - res = wait_file2(chan, vms, nextmsg); + vms->starting = 0; + make_file(vms->fn, sizeof(vms->fn), vms->curdir, vms->curmsg); + 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) { + /* POLISH syntax */ + if (!strcasecmp(chan->language, "pl")) { + if (vms->curmsg && (vms->curmsg != vms->lastmsg)) { + int ten, one; + char nextmsg[256]; + ten = (vms->curmsg + 1) / 10; + one = (vms->curmsg + 1) % 10; + + if (vms->curmsg < 20) { + snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", vms->curmsg + 1); + res = wait_file2(chan, vms, nextmsg); + } else { + snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", ten * 10); + res = wait_file2(chan, vms, nextmsg); + if (one > 0) { + if (!res) { + snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", one); + res = wait_file2(chan, vms, nextmsg); + } } } } - } - if (!res) - res = wait_file2(chan, vms, "vm-message"); - } else { - if (!strcasecmp(chan->language, "se")) /* SWEDISH syntax */ - res = wait_file2(chan, vms, "vm-meddelandet"); /* "message" */ - else /* DEFAULT syntax */ - res = wait_file2(chan, vms, "vm-message"); - if (vms->curmsg && (vms->curmsg != vms->lastmsg)) { if (!res) - res = ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY, chan->language, NULL); + res = wait_file2(chan, vms, "vm-message"); + } else { + if (!strcasecmp(chan->language, "se")) /* SWEDISH syntax */ + res = wait_file2(chan, vms, "vm-meddelandet"); /* "message" */ + else /* DEFAULT syntax */ { + res = wait_file2(chan, vms, "vm-message"); + } + if (vms->curmsg && (vms->curmsg != vms->lastmsg)) { + if (!res) { + res = ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY, chan->language, NULL); + } + } } } - } - - /* 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, vmu->mailbox, vmu->context); - msg_cfg = ast_config_load(filename, config_flags); - if (!msg_cfg) { - ast_log(LOG_WARNING, "No message attribute file?!! (%s)\n", filename); - return 0; - } - - if (!(origtime = ast_variable_retrieve(msg_cfg, "message", "origtime"))) { - ast_log(LOG_WARNING, "No origtime?!\n"); - DISPOSE(vms->curdir, vms->curmsg); - ast_config_destroy(msg_cfg); - return 0; - } - - cid = ast_strdupa(ast_variable_retrieve(msg_cfg, "message", "callerid")); - duration = ast_variable_retrieve(msg_cfg, "message", "duration"); - category = ast_variable_retrieve(msg_cfg, "message", "category"); - - 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"); - if (!res) - res = play_message_category(chan, category); - if ((!res) && (ast_test_flag(vmu, VM_ENVELOPE))) - res = play_message_datetime(chan, vmu, origtime, filename); - if ((!res) && (ast_test_flag(vmu, VM_SAYCID))) - res = play_message_callerid(chan, vms, cid, context, 0); - if ((!res) && (ast_test_flag(vmu, VM_SAYDURATION))) - 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); - if (!res) { - make_file(vms->fn, sizeof(vms->fn), vms->curdir, vms->curmsg); - vms->heard[vms->curmsg] = 1; - if ((res = wait_file(chan, vms, vms->fn)) < 0) { - ast_log(LOG_WARNING, "Playback of message %s failed\n", vms->fn); - res = 0; + /* 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, vmu->mailbox, vmu->context); + msg_cfg = ast_config_load(filename, config_flags); + if (!msg_cfg) { + ast_log(LOG_WARNING, "No message attribute file?!! (%s)\n", filename); + return 0; } - } - 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 == OLD_FOLDER) { - ast_copy_string(vms->curbox, mbox(NEW_FOLDER), sizeof(vms->curbox)); - } else { - ast_copy_string(vms->curbox, mbox(box), sizeof(vms->curbox)); - } - - if (box == NEW_FOLDER) { - ast_copy_string(vms->vmbox, "vm-INBOX", sizeof(vms->vmbox)); - } else { - snprintf(vms->vmbox, sizeof(vms->vmbox), "vm-%s", mbox(box)); - } - - /* 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 == NEW_FOLDER || box == OLD_FOLDER) - snprintf(spec, len, "%s%s", tmp, use_folder? imapfolder: "INBOX"); - else if (box == GREETINGS_FOLDER) - snprintf(spec, len, "%s%s", tmp, greetingfolder); - else /* Other folders such as Friends, Family, etc... */ - if (!ast_strlen_zero(imapparentfolder)) { - /* imapparentfolder would typically be set to INBOX */ - snprintf(spec, len, "%s%s%c%s", tmp, imapparentfolder, delimiter, mbox(box)); - } else { - snprintf(spec, len, "%s%s", tmp, mbox(box)); + if (!(origtime = ast_variable_retrieve(msg_cfg, "message", "origtime"))) { + ast_log(LOG_WARNING, "No origtime?!\n"); + DISPOSE(vms->curdir, vms->curmsg); + ast_config_destroy(msg_cfg); + return 0; } -} -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; - } - ast_debug(3, "vm_state user is:%s\n", vms->imapuser); - if (vms->mailstream == NIL || !vms->mailstream) { - ast_debug(1, "mailstream not set.\n"); - } else { - stream = vms->mailstream; - } - /* debug = T; user wants protocol telemetry? */ - debug = NIL; /* NO protocol telemetry? */ + cid = ast_strdupa(ast_variable_retrieve(msg_cfg, "message", "callerid")); + duration = ast_variable_retrieve(msg_cfg, "message", "duration"); + category = ast_variable_retrieve(msg_cfg, "message", "category"); - 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 mailbox to get mailstream so we can get 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; + 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"); + if (!res) { + res = play_message_category(chan, category); } - } - /* Now connect to the target folder */ - imap_mailbox_name(tmp, sizeof(tmp), vms, box, 1); - ast_debug(3, "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)); - ast_debug(3, "Before init_mailstream, user is %s\n", vmu->imapuser); - - if ((ret = init_mailstream(vms, box)) || !vms->mailstream) { - ast_log(LOG_ERROR, "Could not initialize mailstream\n"); - return -1; - } - - /* Check Quota */ - if (box == 0) { - ast_debug(3, "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 ((!res) && (ast_test_flag(vmu, VM_ENVELOPE))) + res = play_message_datetime(chan, vmu, origtime, filename); + if ((!res) && (ast_test_flag(vmu, VM_SAYCID))) + res = play_message_callerid(chan, vms, cid, context, 0); + if ((!res) && (ast_test_flag(vmu, VM_SAYDURATION))) + 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); - /* if box = NEW_FOLDER, check for new, if box = OLD_FOLDER, check for read */ - if (box == NEW_FOLDER) { - pgm->unseen = 1; - pgm->seen = 0; - } else if (box == OLD_FOLDER) { - pgm->seen = 1; - pgm->unseen = 0; + if (!res) { + make_file(vms->fn, sizeof(vms->fn), vms->curdir, vms->curmsg); + vms->heard[vms->curmsg] = 1; + if ((res = wait_file(chan, vms, vms->fn)) < 0) { + ast_log(LOG_WARNING, "Playback of message %s failed\n", vms->fn); + res = 0; + } + } + DISPOSE(vms->curdir, vms->curmsg); + return res; } - ast_debug(3, "Before mail_search_full, user is %s\n", vmu->imapuser); - - vms->vmArrayIndex = 0; - mail_search_full (vms->mailstream, NULL, pgm, NIL); - vms->lastmsg = vms->vmArrayIndex - 1; - mail_free_searchpgm(&pgm); - - return 0; -} - +#ifdef IMAP_STORAGE static int imap_remove_file(char *dir, int msgnum) { char fn[PATH_MAX]; char full_fn[PATH_MAX]; - char msgnums[80]; if (msgnum > -1) { - snprintf(msgnums, sizeof(msgnums), "%d", msgnum); make_file(fn, sizeof(fn), dir, msgnum); } else ast_copy_string(fn, dir, sizeof(fn)); if ((msgnum < 0 && imapgreetings) || msgnum > -1) { - ast_filedelete(fn, NULL); + ast_filedelete(fn, NULL); snprintf(full_fn, sizeof(full_fn), "%s.txt", fn); unlink(full_fn); } return 0; } -static int imap_retrieve_file (char *dir, int msgnum, const char *mailbox, char *context) -{ - struct ast_vm_user *vmu; - struct vm_state *vms_p; - char *file, *filename; - char *attachment; - int ret = 0, i; - BODY *body; - - /* This function is only used for retrieval of IMAP greetings - * regular messages are not retrieved this way, nor are greetings - * if they are stored locally*/ - if (msgnum > -1 || !imapgreetings) { - return 0; - } else { - file = strrchr(ast_strdupa(dir), '/'); - if (file) - *file++ = '\0'; - else { - ast_debug(1, "Failed to procure file name from directory passed.\n"); - return -1; - } - } - /* We have to get the user before we can open the stream! */ - /* ast_log(LOG_DEBUG, "Before find_user, context is %s and mailbox is %s\n", context, mailbox); */ - vmu = find_user(NULL, context, mailbox); - if (!vmu) { - ast_log(LOG_ERROR, "Couldn't find mailbox %s in context %s\n", mailbox, context); - return -1; - } else { - /* No IMAP account available */ - if (vmu->imapuser[0] == '\0') { - ast_log(LOG_WARNING, "IMAP user not set for mailbox %s\n", vmu->mailbox); - free_user(vmu); - return -1; - } - } - - /* check if someone is accessing this box right now... */ - vms_p = get_vm_state_by_mailbox(mailbox, 0); - if (!vms_p) { - ast_log(LOG_ERROR, "Voicemail state not found!\n"); - return -1; - } - - ret = init_mailstream(vms_p, GREETINGS_FOLDER); - if (!vms_p->mailstream) { - ast_log(LOG_ERROR, "IMAP mailstream is NULL\n"); - free_user(vmu); - return -1; - } - - for (i = 0; i < vms_p->mailstream->nmsgs; i++) { - mail_fetchstructure(vms_p->mailstream, i + 1, &body); - /* We have the body, now we extract the file name of the first attachment. */ - if (body->nested.part && body->nested.part->next && body->nested.part->next->body.parameter->value) { - attachment = ast_strdupa(body->nested.part->next->body.parameter->value); - } else { - ast_log(LOG_ERROR, "There is no file attached to this IMAP message.\n"); - return -1; - } - filename = strsep(&attachment, "."); - if (!strcmp(filename, file)) { - ast_copy_string(vms_p->fn, dir, sizeof(vms_p->fn)); - vms_p->msgArray[vms_p->curmsg] = i + 1; - save_body(body, vms_p, "2", attachment); - free_user(vmu); - return 0; - } - } - - free_user(vmu); - return -1; -} - static int imap_delete_old_greeting (char *dir, struct vm_state *vms) { char *file, *filename; @@ -5346,6 +5848,7 @@ static int imap_delete_old_greeting (char *dir, struct vm_state *vms) } #else +#ifndef IMAP_STORAGE static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box) { int res = 0; @@ -5394,6 +5897,7 @@ static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box) return 0; } #endif +#endif static int close_mailbox(struct vm_state *vms, struct ast_vm_user *vmu) { @@ -5446,7 +5950,7 @@ static int close_mailbox(struct vm_state *vms, struct ast_vm_user *vmu) cause RENAME() will overwrite files, but will keep duplicate records in RT-storage */ make_file(vms->fn, sizeof(vms->fn), vms->curdir, x); if (EXISTS(vms->curdir, x, vms->fn, NULL)) - DELETE(vms->curdir, x, vms->fn); + DELETE(vms->curdir, x, vms->fn, vmu); } } @@ -5455,7 +5959,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 @@ -5463,7 +5967,7 @@ static int close_mailbox(struct vm_state *vms, struct ast_vm_user *vmu) for (x = 0; x < vmu->maxmsg; x++) { if (vms->deleted[x]) { ast_debug(3, "IMAP delete of %d\n", x); - IMAP_DELETE(vms->curdir, x, vms->fn, vms); + DELETE(vms->curdir, x, vms->fn, vmu); } } } @@ -6572,11 +7076,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; } @@ -6586,22 +7086,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; } @@ -6635,27 +7127,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); @@ -6753,23 +7233,15 @@ static int vm_tempgreeting(struct ast_channel *chan, struct ast_vm_user *vmu, st retries = 0; RETRIEVE(prefile, -1, vmu->mailbox, vmu->context); if (ast_fileexists(prefile, NULL, NULL) <= 0) { -#ifndef IMAP_STORAGE - play_record_review(chan, "vm-rec-temp", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, NULL); -#else play_record_review(chan, "vm-rec-temp", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms); -#endif cmd = 't'; } else { switch (cmd) { case '1': -#ifndef IMAP_STORAGE - cmd = play_record_review(chan, "vm-rec-temp", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, NULL); -#else cmd = play_record_review(chan, "vm-rec-temp", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms); -#endif break; case '2': - DELETE(prefile, -1, prefile); + DELETE(prefile, -1, prefile, vmu); ast_play_and_wait(chan, "vm-tempremoved"); cmd = 't'; break; @@ -7186,7 +7658,6 @@ static int vm_execmain(struct ast_channel *chan, void *data) /* Set language from config to override channel language */ if (!ast_strlen_zero(vmu->language)) ast_string_field_set(chan, language, vmu->language); - create_dirpath(vms.curdir, sizeof(vms.curdir), vmu->context, vms.username, ""); /* Retrieve old and new message counts */ ast_debug(1, "Before open_mailbox\n"); res = open_mailbox(&vms, vmu, OLD_FOLDER); @@ -7478,12 +7949,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; @@ -7495,7 +7964,7 @@ static int vm_execmain(struct ast_channel *chan, void *data) snprintf(vms.fn, sizeof(vms.fn), "vm-%s", mbox(box)); if (!cmd) { cmd = ast_play_and_wait(chan, "vm-message"); - if (!cmd) + if (!cmd) cmd = say_and_wait(chan, vms.curmsg + 1, chan->language); if (!cmd) cmd = ast_play_and_wait(chan, "vm-savedto"); @@ -9059,62 +9528,16 @@ 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], cidN[256], cid[256], contextS[256]; - char *header_content, *temp; - char buf[1024]; -#else - char *cid; - struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE }; -#endif char filename[PATH_MAX]; struct ast_config *msg_cfg = NULL; const char *origtime, *context; char *name, *num; int retries = 0; + char *cid; + struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE, }; vms->starting = 0; -#ifdef IMAP_STORAGE - /* START HERE */ - - /* get the message info!! */ - ast_debug(3, "Before mail_fetchheaders, curmsg is: %d, imap messages is %lu\n", vms->curmsg, vms->msgArray[vms->curmsg]); - - if (!vms->msgArray[vms->curmsg]) { - ast_log(LOG_WARNING, "Trying to access unknown message\n"); - return -1; - } - - /* This will only work for new messages... */ - if (!(header_content = mail_fetchheader(vms->mailstream, vms->msgArray[vms->curmsg])) || ast_strlen_zero(header_content)) { - ast_log(LOG_ERROR, "Could not fetch header for message number %ld\n", vms->msgArray[vms->curmsg]); - return -1; - } - - /* Get info from headers!! */ - if ((temp = get_header_by_tag(header_content, "X-Asterisk-VM-Caller-ID-Name:", buf, sizeof(buf)))) - ast_copy_string(cidN, temp, sizeof(cidN)); - else - cidN[0] = '\0'; - - if ((temp = get_header_by_tag(header_content, "X-Asterisk-VM-Caller-ID-Num:", buf, sizeof(buf)))) - snprintf(cid, sizeof(cid), "\"%s\" <%s>", cidN, temp); - else if ((temp = get_header_by_tag(header_content, "X-Asterisk-VM-Context:", buf, sizeof(buf)))) - ast_copy_string(contextS, temp, sizeof(contextS)); - else - contextS[0] = '\0'; - - context = &contextS[0]; - if ((temp = get_header_by_tag(header_content, "X-Asterisk-VM-Orig-time:", buf, sizeof(buf)))) - ast_copy_string(origtimeS, temp, sizeof(origtimeS)); - else - origtimeS[0] = '\0'; - - 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 */ @@ -9139,7 +9562,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) @@ -9442,7 +9864,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'; } } @@ -9487,541 +9909,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); -} - -static void update_messages_by_imapuser(const char *user, unsigned long number) -{ - struct vmstate *vlist = NULL; - - AST_LIST_LOCK(&vmstates); - AST_LIST_TRAVERSE(&vmstates, vlist, list) { - if (!vlist->vms) { - ast_debug(3, "error: vms is NULL for %s\n", user); - continue; - } - if (!vlist->vms->imapuser) { - ast_debug(3, "error: imapuser is NULL for %s\n", user); - continue; - } - ast_debug(3, "saving mailbox message number %lu as message %d. Interactive set to %d\n", number, vlist->vms->vmArrayIndex, vlist->vms->interactive); - vlist->vms->msgArray[vlist->vms->vmArrayIndex++] = number; - } - AST_LIST_UNLOCK(&vmstates); -} - -void mm_searched(MAILSTREAM *stream, unsigned long number) -{ - char *mailbox = stream->mailbox, buf[1024] = "", *user; - - if (!(user = get_user_by_mailbox(mailbox, buf, sizeof(buf)))) - return; - - update_messages_by_imapuser(user, number); -} - -static struct ast_vm_user *find_user_realtime_imapuser(const char *imapuser) -{ - struct ast_variable *var; - struct ast_vm_user *vmu; - - vmu = ast_calloc(1, sizeof *vmu); - if (!vmu) - return NULL; - ast_set_flag(vmu, VM_ALLOCED); - populate_defaults(vmu); - - var = ast_load_realtime("voicemail", "imapuser", imapuser, NULL); - if (var) { - apply_options_full(vmu, var); - ast_variables_destroy(var); - return vmu; - } else { - ast_free(vmu); - return NULL; - } -} - -/* Interfaces to C-client */ - -void mm_exists(MAILSTREAM * stream, unsigned long number) -{ - /* mail_ping will callback here if new mail! */ - ast_debug(4, "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! */ - ast_debug(4, "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! */ - ast_debug(4, "Entering FLAGS callback for message %ld\n", number); - if (number == 0) return; - set_update(stream); -} - - -void mm_notify(MAILSTREAM * stream, char *string, long errflg) -{ - ast_debug(5, "Entering NOTIFY callback, errflag is %ld, string is %s\n", errflg, string); - mm_log (string, errflg); -} - - -void mm_list(MAILSTREAM * stream, int delim, char *mailbox, long attributes) -{ - if (delimiter == '\0') { - delimiter = delim; - } - - ast_debug(5, "Delimiter set to %c and mailbox %s\n", delim, mailbox); - if (attributes & LATT_NOINFERIORS) - ast_debug(5, "no inferiors\n"); - if (attributes & LATT_NOSELECT) - ast_debug(5, "no select\n"); - if (attributes & LATT_MARKED) - ast_debug(5, "marked\n"); - if (attributes & LATT_UNMARKED) - ast_debug(5, "unmarked\n"); -} - - -void mm_lsub(MAILSTREAM * stream, int delimiter, char *mailbox, long attributes) -{ - ast_debug(5, "Delimiter set to %c and mailbox %s\n", delimiter, mailbox); - if (attributes & LATT_NOINFERIORS) - ast_debug(5, "no inferiors\n"); - if (attributes & LATT_NOSELECT) - ast_debug(5, "no select\n"); - if (attributes & LATT_MARKED) - ast_debug(5, "marked\n"); - if (attributes & LATT_UNMARKED) - ast_debug(5, "unmarked\n"); -} - - -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: - ast_debug(1, "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; - - ast_debug(4, "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 = stream->mailbox, *user; - char buf[1024] = ""; - unsigned long usage = 0, limit = 0; - - while (pquota) { - usage = pquota->usage; - limit = pquota->limit; - pquota = pquota->next; - } - - if (!(user = get_user_by_mailbox(mailbox, buf, sizeof(buf))) || !(vms = get_vm_state_by_imapuser(user, 2))) { - ast_log(LOG_ERROR, "No state found.\n"); - return; - } - - ast_debug(3, "User %s usage is %lu, limit is %lu\n", user, usage, limit); - - vms->quota_usage = usage; - vms->quota_limit = limit; -} - -static char *get_header_by_tag(char *header, char *tag, char *buf, size_t len) -{ - char *start, *eol_pnt; - int taglen; - - if (ast_strlen_zero(header) || ast_strlen_zero(tag)) - return NULL; - - taglen = strlen(tag) + 1; - if (taglen < 1) - return NULL; - - if (!(start = strstr(header, tag))) - return NULL; - - /* Since we can be called multiple times we should clear our buffer */ - memset(buf, 0, len); - - ast_copy_string(buf, start+taglen, len); - if ((eol_pnt = strchr(buf, '\r')) || (eol_pnt = strchr(buf, '\n'))) - *eol_pnt = '\0'; - return buf; -} - -static char *get_user_by_mailbox(char *mailbox, char *buf, size_t len) -{ - char *start, *quote, *eol_pnt; - - if (ast_strlen_zero(mailbox)) - return NULL; - - if (!(start = strstr(mailbox, "/user="))) - return NULL; - - ast_copy_string(buf, start + 6, len); - - if (!(quote = strchr(buf, '\"'))) { - if (!(eol_pnt = strchr(buf, '/'))) - eol_pnt = strchr(buf, '}'); - *eol_pnt = '\0'; - return buf; - } else { - eol_pnt = strchr(buf + 1, '\"'); - *eol_pnt = '\0'; - return buf + 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_LIST_LOCK(&vmstates); - AST_LIST_TRAVERSE(&vmstates, vlist, list) { - if (!vlist->vms) { - ast_debug(3, "error: vms is NULL for %s\n", user); - continue; - } - if (!vlist->vms->imapuser) { - ast_debug(3, "error: imapuser is NULL for %s\n", user); - continue; - } - - if (!strcmp(vlist->vms->imapuser, user) && (interactive == 2 || vlist->vms->interactive == interactive)) { - AST_LIST_UNLOCK(&vmstates); - return vlist->vms; - } - } - AST_LIST_UNLOCK(&vmstates); - - ast_debug(3, "%s not found in vmstates\n", user); - - return NULL; -} - -static struct vm_state *get_vm_state_by_mailbox(const char *mailbox, int interactive) -{ - - struct vmstate *vlist = NULL; - - AST_LIST_LOCK(&vmstates); - AST_LIST_TRAVERSE(&vmstates, vlist, list) { - if (!vlist->vms) { - ast_debug(3, "error: vms is NULL for %s\n", mailbox); - continue; - } - if (!vlist->vms->username) { - ast_debug(3, "error: username is NULL for %s\n", mailbox); - continue; - } - - ast_debug(3, "comparing mailbox %s (i=%d) to vmstate mailbox %s (i=%d)\n", mailbox, interactive, vlist->vms->username, vlist->vms->interactive); - - if (!strcmp(vlist->vms->username, mailbox) && vlist->vms->interactive == interactive) { - ast_debug(3, "Found it!\n"); - AST_LIST_UNLOCK(&vmstates); - return vlist->vms; - } - } - AST_LIST_UNLOCK(&vmstates); - - ast_debug(3, "%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) { - ast_debug(3, "Duplicate mailbox %s, copying message info...\n", vms->username); - vms->newmessages = altvms->newmessages; - vms->oldmessages = altvms->oldmessages; - ast_debug(3, "check_msgArray before memcpy\n"); - check_msgArray(vms); - /* memcpy(vms->msgArray, altvms->msgArray, sizeof(long) * 256); */ - copy_msgArray(vms, altvms); - ast_debug(3, "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; */ - } - } - - if (!(v = ast_calloc(1, sizeof(*v)))) - return; - - v->vms = vms; - - ast_debug(3, "Inserting vm_state for user:%s, mailbox %s\n", vms->imapuser, vms->username); - - AST_LIST_LOCK(&vmstates); - AST_LIST_INSERT_TAIL(&vmstates, v, list); - AST_LIST_UNLOCK(&vmstates); -} - -static void vmstate_delete(struct vm_state *vms) -{ - struct vmstate *vc = NULL; - struct vm_state *altvms = NULL; - - /* If interactive, we should copy pertinent info - back to the persistent state (to make update immediate) */ - if (vms->interactive == 1 && (altvms = vms->persist_vms)) { - ast_debug(3, "Duplicate mailbox %s, copying message info...\n", vms->username); - altvms->newmessages = vms->newmessages; - altvms->oldmessages = vms->oldmessages; - altvms->updated = 1; - } - - ast_debug(3, "Removing vm_state for user:%s, mailbox %s\n", vms->imapuser, vms->username); - - AST_LIST_LOCK(&vmstates); - AST_LIST_TRAVERSE_SAFE_BEGIN(&vmstates, vc, list) { - if (vc->vms == vms) { - AST_LIST_REMOVE_CURRENT(list); - break; - } - } - AST_LIST_TRAVERSE_SAFE_END - AST_LIST_UNLOCK(&vmstates); - - if (vc) { - ast_mutex_destroy(&vc->vms->lock); - ast_free(vc); - } - else - ast_log(LOG_ERROR, "No vmstate found for user:%s, mailbox %s\n", vms->imapuser, vms->username); -} - -static void set_update(MAILSTREAM * stream) -{ - struct vm_state *vms; - char *mailbox = stream->mailbox, *user; - char buf[1024] = ""; - - if (!(user = get_user_by_mailbox(mailbox, buf, sizeof(buf))) || !(vms = get_vm_state_by_imapuser(user, 0))) { - if (user && option_debug > 2) - ast_log(LOG_WARNING, "User %s mailbox not found for update.\n", user); - return; - } - - ast_debug(3, "User %s mailbox set for update.\n", user); - - vms->updated = 1; /* Set updated flag since mailbox changed */ -} - -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) { - ast_debug(1, "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_debug(1, 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); - ast_debug(3, "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)" */ |