Skip to content
Snippets Groups Projects
app_voicemail.c 523 KiB
Newer Older
  • Learn to ignore specific revisions
  • 		ast_log(AST_LOG_WARNING, "ast_mkdir '%s' failed: %s\n", dest, strerror(res));
    
    static const char *mbox(struct ast_vm_user *vmu, int id)
    
    #ifdef IMAP_STORAGE
    	if (vmu && id == 0) {
    		return vmu->imapfolder;
    	}
    #endif
    
    	return (id >= 0 && id < ARRAY_LEN(mailbox_folders)) ? mailbox_folders[id] : "Unknown";
    }
    
    
    static const char *vm_index_to_foldername(int id)
    {
    	return mbox(NULL, id);
    }
    
    
    
    static int get_folder_by_name(const char *name)
    {
    	size_t i;
    
    	for (i = 0; i < ARRAY_LEN(mailbox_folders); i++) {
    		if (strcasecmp(name, mailbox_folders[i]) == 0) {
    			return i;
    		}
    	}
    
    	return -1;
    
    static void free_user(struct ast_vm_user *vmu)
    {
    
    	ast_free(vmu->email);
    	vmu->email = NULL;
    	ast_free(vmu->emailbody);
    	vmu->emailbody = NULL;
    	ast_free(vmu->emailsubject);
    	vmu->emailsubject = NULL;
    
    	if (ast_test_flag(vmu, VM_ALLOCED)) {
    
    static int vm_allocate_dh(struct vm_state *vms, struct ast_vm_user *vmu, int count_msg) {
    
    	int arraysize = (vmu->maxmsg > count_msg ? vmu->maxmsg : count_msg);
    
    
    	/* remove old allocation */
    	if (vms->deleted) {
    		ast_free(vms->deleted);
    		vms->deleted = NULL;
    	}
    	if (vms->heard) {
    		ast_free(vms->heard);
    		vms->heard = NULL;
    	}
    	vms->dh_arraysize = 0;
    
    	if (arraysize > 0) {
    
    		if (!(vms->deleted = ast_calloc(arraysize, sizeof(int)))) {
    			return -1;
    		}
    		if (!(vms->heard = ast_calloc(arraysize, sizeof(int)))) {
    
    			ast_free(vms->deleted);
    			vms->deleted = NULL;
    
    			return -1;
    		}
    		vms->dh_arraysize = arraysize;
    	}
    
    	return 0;
    }
    
    
    /* 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(char *file, int msgnum, struct ast_vm_user *vmu)
    
    	char arg[10];
    	struct vm_state *vms;
    	unsigned long messageNum;
    
    	/* If greetings aren't stored in IMAP, just delete the file */
    	if (msgnum < 0 && !imapgreetings) {
    		ast_filedelete(file, NULL);
    
    	if (!(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 1)) && !(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 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;
    
    	if (msgnum < 0) {
    		imap_delete_old_greeting(file, vms);
    		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);
    
    	ast_debug(3, "deleting msgnum %d, which is mailbox message %lu\n", msgnum, messageNum);
    
    	/* delete message */
    
    	snprintf (arg, sizeof(arg), "%lu", messageNum);
    
    	ast_mutex_lock(&vms->lock);
    
    	mail_setflag (vms->mailstream, arg, "\\DELETED");
    
    	ast_mutex_unlock(&vms->lock);
    
    static void vm_imap_update_msg_id(char *dir, int msgnum, const char *msg_id, struct ast_vm_user *vmu, struct ast_config *msg_cfg, int folder)
    {
    	struct ast_channel *chan;
    	char *cid;
    	char *cid_name;
    	char *cid_num;
    	struct vm_state *vms;
    	const char *duration_str;
    	int duration = 0;
    
    	/*
    	 * First, get things initially set up. If any of this fails, then
    	 * back out before doing anything substantial
    	 */
    	vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 0);
    	if (!vms) {
    		return;
    	}
    
    	if (open_mailbox(vms, vmu, folder)) {
    		return;
    	}
    
    	chan = ast_dummy_channel_alloc();
    	if (!chan) {
    		close_mailbox(vms, vmu);
    		return;
    	}
    
    	/*
    	 * We need to make sure the new message we save has the same
    	 * callerid, flag, and duration as the original message
    	 */
    	cid = ast_strdupa(ast_variable_retrieve(msg_cfg, "message", "callerid"));
    
    	if (!ast_strlen_zero(cid)) {
    		ast_callerid_parse(cid, &cid_name, &cid_num);
    		ast_party_caller_init(ast_channel_caller(chan));
    		if (!ast_strlen_zero(cid_name)) {
    			ast_channel_caller(chan)->id.name.valid = 1;
    			ast_channel_caller(chan)->id.name.str = ast_strdup(cid_name);
    		}
    		if (!ast_strlen_zero(cid_num)) {
    			ast_channel_caller(chan)->id.number.valid = 1;
    			ast_channel_caller(chan)->id.number.str = ast_strdup(cid_num);
    		}
    	}
    
    	duration_str = ast_variable_retrieve(msg_cfg, "message", "duration");
    
    	if (!ast_strlen_zero(duration_str)) {
    		sscanf(duration_str, "%30d", &duration);
    	}
    
    	/*
    	 * IMAP messages cannot be altered once delivered. So we have to delete the
    	 * current message and then re-add it with the updated message ID.
    	 *
    	 * Furthermore, there currently is no atomic way to create a new message and to
    	 * store it in an arbitrary folder. So we have to save it to the INBOX and then
    	 * move to the appropriate folder.
    	 */
    	if (!imap_store_file(dir, vmu->mailbox, vmu->context, msgnum, chan, vmu, vmfmts,
    			duration, vms, ast_variable_retrieve(msg_cfg, "message", "flag"), msg_id)) {
    		if (folder != NEW_FOLDER) {
    			save_to_folder(vmu, vms, msgnum, folder, NULL, 1);
    		}
    		vm_imap_delete(dir, msgnum, vmu);
    	}
    	close_mailbox(vms, vmu);
    	ast_channel_unref(chan);
    }
    
    
    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;
    
    	/* 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");
    
    	/* check if someone is accessing this box right now... */
    
    	if (!(vms_p = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 1)) &&
    
    		!(vms_p = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 0))) {
    
    		/* Unlike when retrieving a message, it is reasonable not to be able to find a
    
    		* vm_state for a mailbox when trying to retrieve a greeting. Just create one,
    		* that's all we need to do.
    		*/
    		if (!(vms_p = create_vm_state_from_user(vmu))) {
    			ast_log(LOG_NOTICE, "Unable to create vm_state object!\n");
    			return -1;
    		}
    
    	/* Greetings will never have a prepended message */
    	*vms_p->introfn = '\0';
    
    
    	ast_mutex_lock(&vms_p->lock);
    
    
    	/* get the current mailbox so that we can point the mailstream back to it later */
    	curr_mbox = get_folder_by_name(vms_p->curbox);
    
    
    	if (init_mailstream(vms_p, GREETINGS_FOLDER) || !vms_p->mailstream) {
    		ast_log(AST_LOG_ERROR, "IMAP mailstream is NULL or can't init_mailstream\n");
    
    		ast_mutex_unlock(&vms_p->lock);
    
    		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(AST_LOG_ERROR, "There is no file attached to this IMAP message.\n");
    
    		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;
    
    			create_dirpath(dest, sizeof(dest), vmu->context, vms_p->username, "");
    
    			save_body(body, vms_p, "2", attachment, 0);
    
    	if (curr_mbox != -1) {
    		/* restore previous mbox stream */
    		if (init_mailstream(vms_p, curr_mbox) || !vms_p->mailstream) {
    			ast_log(AST_LOG_ERROR, "IMAP mailstream is NULL or can't init_mailstream\n");
    			ret = -1;
    		}
    	}
    	ast_mutex_unlock(&vms_p->lock);
    	return ret;
    
    }
    
    static int imap_retrieve_file(const char *dir, const int msgnum, const char *mailbox, const char *context)
    {
    	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;
    
    
    	if (!(vmu = find_user(NULL, context, mailbox))) {
    		ast_log(LOG_WARNING, "Couldn't find user with mailbox %s@%s\n", mailbox, context);
    		return -1;
    	}
    
    	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, vmu->context, 1)) && !(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 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;
    	}
    
    	/* Ensure we have the correct mailbox open and have a valid mailstream for it */
    	curr_mbox = get_folder_by_name(vms->curbox);
    	if (curr_mbox < 0) {
    		ast_debug(3, "Mailbox folder curbox not set, defaulting to Inbox\n");
    		curr_mbox = 0;
    	}
    	init_mailstream(vms, curr_mbox);
    	if (!vms->mailstream) {
    		ast_log(AST_LOG_ERROR, "IMAP mailstream for %s is NULL\n", vmu->mailbox);
    		res = -1;
    		goto exit;
    	}
    
    
    	make_file(vms->fn, sizeof(vms->fn), dir, msgnum);
    	snprintf(vms->introfn, sizeof(vms->introfn), "%sintro", vms->fn);
    
    	/* 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;
    
    	ast_debug(3, "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... */
    
    	ast_mutex_lock(&vms->lock);
    
    	header_content = mail_fetchheader (vms->mailstream, vms->msgArray[msgnum]);
    
    	ast_mutex_unlock(&vms->lock);
    
    	/* 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]);
    
    	ast_mutex_lock(&vms->lock);
    
    	mail_fetchstructure(vms->mailstream, vms->msgArray[msgnum], &body);
    
    	ast_mutex_unlock(&vms->lock);
    
    
    	/* 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;
    	}
    
    	/* 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, 0);
    	if (save_body(body, vms, "3", attachedfilefmt, 1)) {
    		*vms->introfn = '\0';
    	}
    
    	/* 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_ERROR, "Unable to open/create file %s: %s\n", text_file, strerror(errno));
    		goto exit;
    
    	}
    
    	fprintf(text_file_ptr, "%s\n", "[message]");
    
    
    	if (get_header_by_tag(header_content, "X-Asterisk-VM-Caller-ID-Name:", buf, sizeof(buf))) {
    		fprintf(text_file_ptr, "callerid=\"%s\" ", S_OR(buf, ""));
    	}
    	if (get_header_by_tag(header_content, "X-Asterisk-VM-Caller-ID-Num:", buf, sizeof(buf))) {
    		fprintf(text_file_ptr, "<%s>\n", S_OR(buf, ""));
    	}
    	if (get_header_by_tag(header_content, "X-Asterisk-VM-Context:", buf, sizeof(buf))) {
    		fprintf(text_file_ptr, "context=%s\n", S_OR(buf, ""));
    	}
    	if (get_header_by_tag(header_content, "X-Asterisk-VM-Orig-time:", buf, sizeof(buf))) {
    		fprintf(text_file_ptr, "origtime=%s\n", S_OR(buf, ""));
    	}
    	if (get_header_by_tag(header_content, "X-Asterisk-VM-Duration:", buf, sizeof(buf))) {
    		fprintf(text_file_ptr, "duration=%s\n", S_OR(buf, ""));
    	}
    	if (get_header_by_tag(header_content, "X-Asterisk-VM-Category:", buf, sizeof(buf))) {
    		fprintf(text_file_ptr, "category=%s\n", S_OR(buf, ""));
    	}
    	if (get_header_by_tag(header_content, "X-Asterisk-VM-Flag:", buf, sizeof(buf))) {
    		fprintf(text_file_ptr, "flag=%s\n", S_OR(buf, ""));
    	}
    	if (get_header_by_tag(header_content, "X-Asterisk-VM-Message-ID:", buf, sizeof(buf))) {
    		fprintf(text_file_ptr, "msg_id=%s\n", S_OR(buf, ""));
    	}
    
    	fclose(text_file_ptr);
    
    exit:
    	free_user(vmu);
    	return res;
    
    static int folder_int(const char *folder)
    
    	/*assume a NULL folder means INBOX*/
    
    	}
    	if (!strcasecmp(folder, imapfolder)) {
    
    	} else if (!strcasecmp(folder, "Old")) {
    
    	} else if (!strcasecmp(folder, "Work")) {
    
    	} else if (!strcasecmp(folder, "Family")) {
    
    	} else if (!strcasecmp(folder, "Friends")) {
    
    	} else if (!strcasecmp(folder, "Cust1")) {
    
    	} else if (!strcasecmp(folder, "Cust2")) {
    
    	} else if (!strcasecmp(folder, "Cust3")) {
    
    	} else if (!strcasecmp(folder, "Cust4")) {
    
    	} else if (!strcasecmp(folder, "Cust5")) {
    
    	} else if (!strcasecmp(folder, "Urgent")) {
    		return 11;
    	} else { /*assume they meant INBOX if folder is not found otherwise*/
    
    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);
    	int urgent = 0;
    
    	/* If URGENT, then look at INBOX */
    	if (fold == 11) {
    		fold = NEW_FOLDER;
    		urgent = 1;
    	}
    
    
    	if (ast_strlen_zero(mailbox))
    		return 0;
    
    	/* We have to get the user before we can open the stream! */
    
    	memset(&vmus, 0, sizeof(vmus));
    
    	vmu = find_user(&vmus, context, mailbox);
    	if (!vmu) {
    
    		ast_log(AST_LOG_WARNING, "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(AST_LOG_WARNING, "IMAP user not set for mailbox %s\n", vmu->mailbox);
    
    	/* No IMAP account available */
    	if (vmu->imapuser[0] == '\0') {
    		ast_log(AST_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);
    
    		vms_p = get_vm_state_by_mailbox(mailbox, context, 1);
    
    	}
    	if (vms_p) {
    		ast_debug(3, "Returning before search - user is logged in\n");
    		if (fold == 0) { /* INBOX */
    
    			return urgent ? vms_p->urgentmessages : vms_p->newmessages;
    
    		if (fold == 1) { /* Old messages */
    
    			return vms_p->oldmessages;
    
    	/* add one if not there... */
    
    	vms_p = get_vm_state_by_imapuser(vmu->imapuser, 0);
    
    		vms_p = get_vm_state_by_mailbox(mailbox, context, 0);
    
    		vms_p = create_vm_state_from_user(vmu);
    
    	}
    	ret = init_mailstream(vms_p, fold);
    	if (!vms_p->mailstream) {
    		ast_log(AST_LOG_ERROR, "Houston we have a problem - IMAP mailstream is NULL\n");
    
    		return -1;
    	}
    	if (ret == 0) {
    
    		ast_mutex_lock(&vms_p->lock);
    
    		pgm = mail_newsearchpgm ();
    
    		hdr = mail_newsearchheader ("X-Asterisk-VM-Extension", (char *)(!ast_strlen_zero(vmu->imapvmshareid) ? vmu->imapvmshareid : mailbox));
    
    		hdr->next = mail_newsearchheader("X-Asterisk-VM-Context", (char *) S_OR(context, "default"));
    
    		pgm->header = hdr;
    
    			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;
    		}
    		/* look for urgent messages */
    
    		if (fold == NEW_FOLDER) {
    			if (urgent) {
    				pgm->flagged = 1;
    				pgm->unflagged = 0;
    			} else {
    				pgm->flagged = 0;
    				pgm->unflagged = 1;
    			}
    
    		}
    		pgm->undeleted = 1;
    		pgm->deleted = 0;
    
    		vms_p->vmArrayIndex = 0;
    		mail_search_full (vms_p->mailstream, NULL, pgm, NIL);
    		if (fold == 0 && urgent == 0)
    			vms_p->newmessages = vms_p->vmArrayIndex;
    		if (fold == 1)
    			vms_p->oldmessages = vms_p->vmArrayIndex;
    		if (fold == 0 && urgent == 1)
    			vms_p->urgentmessages = vms_p->vmArrayIndex;
    		/*Freeing the searchpgm also frees the searchhdr*/
    		mail_free_searchpgm(&pgm);
    
    		ast_mutex_unlock(&vms_p->lock);
    
    		vms_p->updated = 0;
    		return vms_p->vmArrayIndex;
    
    	} else {
    		ast_mutex_lock(&vms_p->lock);
    
    		mail_ping(vms_p->mailstream);
    
    		ast_mutex_unlock(&vms_p->lock);
    
    static int imap_check_limits(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu, int msgnum)
    {
    	/* Check if mailbox is full */
    	check_quota(vms, vmu->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);
    
    		if (chan) {
    			ast_play_and_wait(chan, "vm-mailboxfull");
    		}
    
    	/* Check if we have exceeded maxmsg */
    
    	ast_debug(3, "Checking message number quota: mailbox has %d messages, maximum is set to %d, current messages %d\n", msgnum, vmu->maxmsg, inprocess_count(vmu->mailbox, vmu->context, 0));
    	if (msgnum >= vmu->maxmsg - inprocess_count(vmu->mailbox, vmu->context, +1)) {
    		ast_log(LOG_WARNING, "Unable to leave message since we will exceed the maximum number of messages allowed (%u >= %u)\n", msgnum, vmu->maxmsg);
    
    		if (chan) {
    			ast_play_and_wait(chan, "vm-mailboxfull");
    			pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
    		}
    
    /*!
     * \brief Gets the number of messages that exist in a mailbox folder.
    
     * This method is used when IMAP backend is used.
     * \return The number of messages in this mailbox folder (zero or more).
     */
    
    static int messagecount(const char *mailbox_id, const char *folder)
    
    	char *context;
    	char *mailbox;
    
    	if (ast_strlen_zero(mailbox_id)
    		|| separate_mailbox(ast_strdupa(mailbox_id), &mailbox, &context)) {
    		return 0;
    	}
    
    
    	if (ast_strlen_zero(folder) || !strcmp(folder, "INBOX")) {
    
    		return __messagecount(context, mailbox, "INBOX") + __messagecount(context, mailbox, "Urgent");
    	} else {
    		return __messagecount(context, mailbox, folder);
    	}
    }
    
    
    static int imap_store_file(const char *dir, const char *mailboxuser, const char *mailboxcontext, int msgnum, struct ast_channel *chan, struct ast_vm_user *vmu, char *fmt, int duration, struct vm_state *vms, const char *flag, const char *msg_id)
    
    	char *myserveremail = serveremail;
    	char fn[PATH_MAX];
    	char introfn[PATH_MAX];
    	char mailbox[256];
    	char *stringp;
    
    	char tmp[80] = "/tmp/astmail-XXXXXX";
    	long len;
    	void *buf;
    	int tempcopy = 0;
    	STRING str;
    	int ret; /* for better error checking */
    
    	int box = NEW_FOLDER;
    
    	snprintf(mailbox, sizeof(mailbox), "%s@%s", vmu->mailbox, vmu->context);
    	msgcount = messagecount(mailbox, "INBOX") + messagecount(mailbox, "Old");
    
    
    	/* Back out early if this is a greeting and we don't want to store greetings in IMAP */
    	if (msgnum < 0) {
    		if(!imapgreetings) {
    			return 0;
    		} else {
    			box = GREETINGS_FOLDER;
    		}
    	}
    
    	if (imap_check_limits(chan, vms, vmu, msgcount)) {
    		return -1;
    	}
    
    	/* Set urgent flag for IMAP message */
    	if (!ast_strlen_zero(flag) && !strcmp(flag, "Urgent")) {
    		ast_debug(3, "Setting message flag \\\\FLAGGED.\n");
    
    	/* Attach only the first format */
    	fmt = ast_strdupa(fmt);
    	stringp = fmt;
    	strsep(&stringp, "|");
    
    	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));
    
    	snprintf(introfn, sizeof(introfn), "%sintro", fn);
    	if (ast_fileexists(introfn, NULL, NULL) <= 0) {
    		*introfn = '\0';
    
    	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.
    		 */
    
    		vmu->email = ast_strdup(vmu->imapuser);
    
    	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(AST_LOG_WARNING, "Unable to store '%s' (can't create temporary file)\n", fn);
    
    		if (tempcopy) {
    			ast_free(vmu->email);
    			vmu->email = NULL;
    		}
    
    	if (msgnum < 0 && imapgreetings) {
    		if ((ret = init_mailstream(vms, GREETINGS_FOLDER))) {
    			ast_log(AST_LOG_WARNING, "Unable to open mailstream.\n");
    			return -1;
    
    		imap_delete_old_greeting(fn, vms);
    
    	make_email_file(p, myserveremail, vmu, msgnum, vmu->context, vmu->mailbox, "INBOX",
    
    		chan ? S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL) : NULL,
    		chan ? S_COR(ast_channel_caller(chan)->id.name.valid, ast_channel_caller(chan)->id.name.str, NULL) : NULL,
    
    		fn, introfn, fmt, duration, 1, chan, NULL, 1, flag, msg_id);
    
    	/* read mail file to memory */
    
    	len = ftell(p);
    	rewind(p);
    	if (!(buf = ast_malloc(len + 1))) {
    		ast_log(AST_LOG_ERROR, "Can't allocate %ld bytes to read message\n", len + 1);
    		fclose(p);
    		if (tempcopy)
    			*(vmu->email) = '\0';
    		return -1;
    	}
    
    	if (fread(buf, 1, len, p) != len) {
    
    			ast_log(LOG_ERROR, "Error while reading mail file: %s\n", tmp);
    
    	INIT(&str, mail_string, buf, len);
    
    	ret = init_mailstream(vms, box);
    
    		imap_mailbox_name(mailbox, sizeof(mailbox), vms, box, 1);
    
    		ast_mutex_lock(&vms->lock);
    
    		if(!mail_append_full(vms->mailstream, mailbox, imap_flags, NIL, &str))
    
    			ast_log(LOG_ERROR, "Error while sending the message to %s\n", mailbox);
    
    		ast_mutex_unlock(&vms->lock);
    
    		fclose(p);
    		unlink(tmp);
    		ast_free(buf);
    	} else {
    
    		ast_log(LOG_ERROR, "Could not initialize mailstream for %s\n", mailbox);
    
    		fclose(p);
    		unlink(tmp);
    		ast_free(buf);
    		return -1;
    	}
    	ast_debug(3, "%s stored\n", fn);
    
    	if (tempcopy)
    		*(vmu->email) = '\0';
    
    	inprocess_count(vmu->mailbox, vmu->context, -1);
    
     * \brief Gets the number of messages that exist in the inbox folder.
     * \param mailbox_context
     * \param newmsgs The variable that is updated with the count of new messages within this inbox.
     * \param oldmsgs The variable that is updated with the count of old messages within this inbox.
     * \param urgentmsgs The variable that is updated with the count of urgent messages within this inbox.
    
     * This method is used when IMAP backend is used.
     * Simultaneously determines the count of new,old, and urgent messages. The total messages would then be the sum of these three.
    
     * \return zero on success, -1 on error.
    
    
    static int inboxcount2(const char *mailbox_context, int *urgentmsgs, int *newmsgs, int *oldmsgs)
    
    	char tmp[PATH_MAX] = "";
    	char *mailboxnc;
    	char *context;
    	char *mb;
    	char *cur;
    	if (newmsgs)
    		*newmsgs = 0;
    	if (oldmsgs)
    		*oldmsgs = 0;
    	if (urgentmsgs)
    		*urgentmsgs = 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, tmpurgent;
    		ast_copy_string(tmp, mailbox_context, sizeof(tmp));
    		mb = tmp;
    		while ((cur = strsep(&mb, ", "))) {
    			if (!ast_strlen_zero(cur)) {
    				if (inboxcount2(cur, urgentmsgs ? &tmpurgent : NULL, newmsgs ? &tmpnew : NULL, oldmsgs ? &tmpold : NULL))
    					return -1;
    				else {
    					if (newmsgs)
    
    						*newmsgs += tmpnew;
    
    					if (oldmsgs)
    						*oldmsgs += tmpold;
    					if (urgentmsgs)
    						*urgentmsgs += tmpurgent;
    				}
    			}
    		}
    		return 0;
    	}
    	if (context) {
    		*context = '\0';
    		mailboxnc = tmp;
    		context++;
    	} else {
    		context = "default";
    
    		mailboxnc = (char *) mailbox_context;
    
    		struct ast_vm_user *vmu = find_user(NULL, context, mailboxnc);
    		if (!vmu) {
    			ast_log(AST_LOG_ERROR, "Couldn't find mailbox %s in context %s\n", mailboxnc, context);
    			return -1;
    		}
    
    		if ((*newmsgs = __messagecount(context, mailboxnc, vmu->imapfolder)) < 0) {
    
    		if ((*oldmsgs = __messagecount(context, mailboxnc, "Old")) < 0) {
    
    		if ((*urgentmsgs = __messagecount(context, mailboxnc, "Urgent")) < 0) {
    
     * \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 tmp[256], *tmp2, *box, *context;
    
    	ast_copy_string(tmp, mailbox, sizeof(tmp));
    	tmp2 = tmp;
    
    	if (strchr(tmp2, ',') || strchr(tmp2, '&')) {
    		while ((box = strsep(&tmp2, ",&"))) {
    
    				if (has_voicemail(box, folder)) {
    
    	if ((context = strchr(tmp, '@'))) {
    
    		*context++ = '\0';
    
    		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, char *flag, const char *dest_folder)
    
    	struct vm_state *sendvms = 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 (!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]);
    
    	ast_mutex_lock(&sendvms->lock);
    
    	if ((mail_copy(sendvms->mailstream, messagestring, (char *) mbox(vmu, imbox)) == T)) {
    
    		ast_mutex_unlock(&sendvms->lock);
    
    	}
    	ast_mutex_unlock(&sendvms->lock);
    
    	ast_log(LOG_WARNING, "Unable to copy message from mailbox %s to mailbox %s\n", vmu->mailbox, recip->mailbox);
    	return -1;
    
    static void imap_mailbox_name(char *spec, size_t len, struct vm_state *vms, int box, int use_folder)
    
    	char tmp[256], *t = tmp;
    	size_t left = sizeof(tmp);
    
    	if (box == OLD_FOLDER) {
    
    		ast_copy_string(vms->curbox, mbox(NULL, NEW_FOLDER), sizeof(vms->curbox));
    
    		ast_copy_string(vms->curbox, mbox(NULL, 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(NULL, box));
    
    	/* Build up server information */
    
    	ast_build_string(&t, &left, "{%s:%s/imap", S_OR(vms->imapserver, imapserver), S_OR(vms->imapport, 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_strlen_zero(vms->imapflags))) {
    		ast_build_string(&t, &left, "/%s", S_OR(vms->imapflags, imapflags));
    	}
    
    	/* End with username */
    
    	ast_build_string(&t, &left, "/user=%s}", vms->imapuser);
    
    #else
    	ast_build_string(&t, &left, "/user=%s/novalidate-cert}", vms->imapuser);
    #endif
    
    	if (box == NEW_FOLDER || box == OLD_FOLDER)
    
    		snprintf(spec, len, "%s%s", tmp, use_folder? vms->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(NULL, box));
    
    			snprintf(spec, len, "%s%s", tmp, mbox(NULL, box));
    
    		}
    	}
    }
    
    static int init_mailstream(struct vm_state *vms, int box)
    
    	MAILSTREAM *stream = NIL;