Newer
Older
ast_log(AST_LOG_WARNING, "ast_mkdir '%s' failed: %s\n", dest, strerror(res));
Tilghman Lesher
committed
return -1;
static const char *mbox(struct ast_vm_user *vmu, int id)
Sean Bright
committed
{
#ifdef IMAP_STORAGE
if (vmu && id == 0) {
return vmu->imapfolder;
}
#endif
Sean Bright
committed
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);
}
Sean Bright
committed
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)
{
if (!vmu) {
return;
}
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);
snprintf (arg, sizeof(arg), "%lu", messageNum);
ast_mutex_lock(&vms->lock);
mail_setflag (vms->mailstream, arg, "\\DELETED");
mail_expunge(vms->mailstream);
ast_mutex_unlock(&vms->lock);
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
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 dest[PATH_MAX];
int ret = 0;
int curr_mbox;
/* 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");
ret = -1;
break;
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);
ret = 0;
break;
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;
int curr_mbox;
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;
Kevin P. Fleming
committed
}
/* 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]);
res = -1;
goto exit;
}
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]");
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
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 (!folder) {
}
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);
free_user(vmu);
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);
free_user(vmu);
/* 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 */
free_user(vmu);
return urgent ? vms_p->urgentmessages : vms_p->newmessages;
if (fold == 1) { /* Old messages */
free_user(vmu);
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");
free_user(vmu);
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"));
if (fold != OLD_FOLDER) {
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);
free_user(vmu);
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);
free_user(vmu);
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");
}
return -1;
}
return 0;
}
/*!
* \brief Gets the number of messages that exist in a mailbox folder.
Richard Mudgett
committed
* \param mailbox_id
* This method is used when IMAP backend is used.
* \return The number of messages in this mailbox folder (zero or more).
*/
Richard Mudgett
committed
static int messagecount(const char *mailbox_id, const char *folder)
Richard Mudgett
committed
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)
Tilghman Lesher
committed
{
char *myserveremail = serveremail;
char fn[PATH_MAX];
char introfn[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;
int ret; /* for better error checking */
char *imap_flags = NIL;
Richard Mudgett
committed
int msgcount;
Tilghman Lesher
committed
Richard Mudgett
committed
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");
imap_flags = "\\FLAGGED";
Tilghman Lesher
committed
}
/* Attach only the first format */
fmt = ast_strdupa(fmt);
stringp = fmt;
strsep(&stringp, "|");
Tilghman Lesher
committed
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';
Tilghman Lesher
committed
}
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);
Tilghman Lesher
committed
}
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;
}
Tilghman Lesher
committed
return -1;
}
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);
Tilghman Lesher
committed
}
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) {
Sean Bright
committed
if (ferror(p)) {
ast_log(LOG_ERROR, "Error while reading mail file: %s\n", tmp);
Sean Bright
committed
return -1;
}
}
((char *) buf)[len] = '\0';
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)
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) {
Matthew Jordan
committed
free_user(vmu);
Matthew Jordan
committed
free_user(vmu);
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 (!ast_strlen_zero(box)) {
if (has_voicemail(box, folder)) {
if ((context = strchr(tmp, '@'))) {
}
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);
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));
}
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;