virtual-mail.c revision 6564208826b0f46a00f010d1b5711d85944c3c88
1d940afbc02516d8c3d016780e1223a779844a1ePhil Carmody/* Copyright (c) 2008-2010 Dovecot authors, see the included COPYING file */
1d940afbc02516d8c3d016780e1223a779844a1ePhil Carmody
1d940afbc02516d8c3d016780e1223a779844a1ePhil Carmody#include "lib.h"
1d940afbc02516d8c3d016780e1223a779844a1ePhil Carmody#include "array.h"
1d940afbc02516d8c3d016780e1223a779844a1ePhil Carmody#include "index-mail.h"
1d940afbc02516d8c3d016780e1223a779844a1ePhil Carmody#include "virtual-storage.h"
1d940afbc02516d8c3d016780e1223a779844a1ePhil Carmody#include "virtual-transaction.h"
1d940afbc02516d8c3d016780e1223a779844a1ePhil Carmody
1d940afbc02516d8c3d016780e1223a779844a1ePhil Carmodystruct virtual_mail {
1d940afbc02516d8c3d016780e1223a779844a1ePhil Carmody struct index_mail imail;
1d940afbc02516d8c3d016780e1223a779844a1ePhil Carmody
1d940afbc02516d8c3d016780e1223a779844a1ePhil Carmody enum mail_fetch_field wanted_fields;
1d940afbc02516d8c3d016780e1223a779844a1ePhil Carmody struct mailbox_header_lookup_ctx *wanted_headers;
1d940afbc02516d8c3d016780e1223a779844a1ePhil Carmody
1d940afbc02516d8c3d016780e1223a779844a1ePhil Carmody /* currently active mail */
1d940afbc02516d8c3d016780e1223a779844a1ePhil Carmody struct mail *backend_mail;
1d940afbc02516d8c3d016780e1223a779844a1ePhil Carmody /* all allocated mails */
1d940afbc02516d8c3d016780e1223a779844a1ePhil Carmody ARRAY_DEFINE(backend_mails, struct mail *);
1d940afbc02516d8c3d016780e1223a779844a1ePhil Carmody
1d940afbc02516d8c3d016780e1223a779844a1ePhil Carmody /* mail is lost if backend_mail doesn't point to correct mail */
1d940afbc02516d8c3d016780e1223a779844a1ePhil Carmody unsigned int lost:1;
1d940afbc02516d8c3d016780e1223a779844a1ePhil Carmody};
1d940afbc02516d8c3d016780e1223a779844a1ePhil Carmody
1d940afbc02516d8c3d016780e1223a779844a1ePhil Carmodystruct mail *
1d940afbc02516d8c3d016780e1223a779844a1ePhil Carmodyvirtual_mail_alloc(struct mailbox_transaction_context *t,
1d940afbc02516d8c3d016780e1223a779844a1ePhil Carmody enum mail_fetch_field wanted_fields,
1d940afbc02516d8c3d016780e1223a779844a1ePhil Carmody struct mailbox_header_lookup_ctx *wanted_headers)
1d940afbc02516d8c3d016780e1223a779844a1ePhil Carmody{
1d940afbc02516d8c3d016780e1223a779844a1ePhil Carmody struct virtual_mailbox *mbox = (struct virtual_mailbox *)t->box;
1d940afbc02516d8c3d016780e1223a779844a1ePhil Carmody struct virtual_mail *vmail;
1d940afbc02516d8c3d016780e1223a779844a1ePhil Carmody pool_t pool;
1d940afbc02516d8c3d016780e1223a779844a1ePhil Carmody
1d940afbc02516d8c3d016780e1223a779844a1ePhil Carmody pool = pool_alloconly_create("vmail", 1024);
1d940afbc02516d8c3d016780e1223a779844a1ePhil Carmody vmail = p_new(pool, struct virtual_mail, 1);
1d940afbc02516d8c3d016780e1223a779844a1ePhil Carmody vmail->imail.mail.pool = pool;
1d940afbc02516d8c3d016780e1223a779844a1ePhil Carmody vmail->imail.mail.v = virtual_mail_vfuncs;
1d940afbc02516d8c3d016780e1223a779844a1ePhil Carmody vmail->imail.mail.mail.box = t->box;
1d940afbc02516d8c3d016780e1223a779844a1ePhil Carmody vmail->imail.mail.mail.transaction = t;
1d940afbc02516d8c3d016780e1223a779844a1ePhil Carmody array_create(&vmail->imail.mail.module_contexts, pool,
1d940afbc02516d8c3d016780e1223a779844a1ePhil Carmody sizeof(void *), 5);
1d940afbc02516d8c3d016780e1223a779844a1ePhil Carmody
1d940afbc02516d8c3d016780e1223a779844a1ePhil Carmody vmail->imail.data_pool =
1d940afbc02516d8c3d016780e1223a779844a1ePhil Carmody pool_alloconly_create("virtual index_mail", 512);
1d940afbc02516d8c3d016780e1223a779844a1ePhil Carmody vmail->imail.ibox = INDEX_STORAGE_CONTEXT(t->box);
1d940afbc02516d8c3d016780e1223a779844a1ePhil Carmody vmail->imail.trans = (struct index_transaction_context *)t;
1d940afbc02516d8c3d016780e1223a779844a1ePhil Carmody
1d940afbc02516d8c3d016780e1223a779844a1ePhil Carmody vmail->wanted_fields = wanted_fields;
1d940afbc02516d8c3d016780e1223a779844a1ePhil Carmody if (wanted_headers != NULL) {
1d940afbc02516d8c3d016780e1223a779844a1ePhil Carmody vmail->wanted_headers = wanted_headers;
1d940afbc02516d8c3d016780e1223a779844a1ePhil Carmody mailbox_header_lookup_ref(wanted_headers);
1d940afbc02516d8c3d016780e1223a779844a1ePhil Carmody }
1d940afbc02516d8c3d016780e1223a779844a1ePhil Carmody
1d940afbc02516d8c3d016780e1223a779844a1ePhil Carmody i_array_init(&vmail->backend_mails, array_count(&mbox->backend_boxes));
1d940afbc02516d8c3d016780e1223a779844a1ePhil Carmody return &vmail->imail.mail.mail;
1d940afbc02516d8c3d016780e1223a779844a1ePhil Carmody}
1d940afbc02516d8c3d016780e1223a779844a1ePhil Carmody
1d940afbc02516d8c3d016780e1223a779844a1ePhil Carmodystatic void virtual_mail_free(struct mail *mail)
1d940afbc02516d8c3d016780e1223a779844a1ePhil Carmody{
1d940afbc02516d8c3d016780e1223a779844a1ePhil Carmody struct virtual_mail *vmail = (struct virtual_mail *)mail;
1d940afbc02516d8c3d016780e1223a779844a1ePhil Carmody struct mail **mails;
1d940afbc02516d8c3d016780e1223a779844a1ePhil Carmody unsigned int i, count;
1d940afbc02516d8c3d016780e1223a779844a1ePhil Carmody
1d940afbc02516d8c3d016780e1223a779844a1ePhil Carmody mails = array_get_modifiable(&vmail->backend_mails, &count);
1d940afbc02516d8c3d016780e1223a779844a1ePhil Carmody for (i = 0; i < count; i++)
1d940afbc02516d8c3d016780e1223a779844a1ePhil Carmody mail_free(&mails[i]);
1d940afbc02516d8c3d016780e1223a779844a1ePhil Carmody array_free(&vmail->backend_mails);
1d940afbc02516d8c3d016780e1223a779844a1ePhil Carmody
1d940afbc02516d8c3d016780e1223a779844a1ePhil Carmody if (vmail->wanted_headers != NULL)
1d940afbc02516d8c3d016780e1223a779844a1ePhil Carmody mailbox_header_lookup_unref(&vmail->wanted_headers);
1d940afbc02516d8c3d016780e1223a779844a1ePhil Carmody
1d940afbc02516d8c3d016780e1223a779844a1ePhil Carmody pool_unref(&vmail->imail.data_pool);
1d940afbc02516d8c3d016780e1223a779844a1ePhil Carmody pool_unref(&vmail->imail.mail.pool);
1d940afbc02516d8c3d016780e1223a779844a1ePhil Carmody}
1d940afbc02516d8c3d016780e1223a779844a1ePhil Carmody
1d940afbc02516d8c3d016780e1223a779844a1ePhil Carmodystatic struct mail *
1d940afbc02516d8c3d016780e1223a779844a1ePhil Carmodybackend_mail_find(struct virtual_mail *vmail, struct mailbox *box)
1d940afbc02516d8c3d016780e1223a779844a1ePhil Carmody{
1d940afbc02516d8c3d016780e1223a779844a1ePhil Carmody struct mail *const *mails;
1d940afbc02516d8c3d016780e1223a779844a1ePhil Carmody unsigned int i, count;
1d940afbc02516d8c3d016780e1223a779844a1ePhil Carmody
1d940afbc02516d8c3d016780e1223a779844a1ePhil Carmody mails = array_get(&vmail->backend_mails, &count);
1d940afbc02516d8c3d016780e1223a779844a1ePhil Carmody for (i = 0; i < count; i++) {
1d940afbc02516d8c3d016780e1223a779844a1ePhil Carmody if (mails[i]->box == box)
1d940afbc02516d8c3d016780e1223a779844a1ePhil Carmody return mails[i];
1d940afbc02516d8c3d016780e1223a779844a1ePhil Carmody }
1d940afbc02516d8c3d016780e1223a779844a1ePhil Carmody return NULL;
1d940afbc02516d8c3d016780e1223a779844a1ePhil Carmody}
1d940afbc02516d8c3d016780e1223a779844a1ePhil Carmody
1d940afbc02516d8c3d016780e1223a779844a1ePhil Carmodystruct mail *
1d940afbc02516d8c3d016780e1223a779844a1ePhil Carmodyvirtual_mail_set_backend_mail(struct mail *mail,
1d940afbc02516d8c3d016780e1223a779844a1ePhil Carmody struct virtual_backend_box *bbox)
1d940afbc02516d8c3d016780e1223a779844a1ePhil Carmody{
1d940afbc02516d8c3d016780e1223a779844a1ePhil Carmody struct virtual_mail *vmail = (struct virtual_mail *)mail;
1d940afbc02516d8c3d016780e1223a779844a1ePhil Carmody struct mailbox_transaction_context *backend_trans;
8bec19723b39071a1794e76dec35d151473cae5fPhil Carmody struct mailbox_header_lookup_ctx *backend_headers;
8bec19723b39071a1794e76dec35d151473cae5fPhil Carmody
8bec19723b39071a1794e76dec35d151473cae5fPhil Carmody backend_trans = virtual_transaction_get(mail->transaction, bbox->box);
8bec19723b39071a1794e76dec35d151473cae5fPhil Carmody
8bec19723b39071a1794e76dec35d151473cae5fPhil Carmody backend_headers = vmail->wanted_headers == NULL ? NULL :
8bec19723b39071a1794e76dec35d151473cae5fPhil Carmody mailbox_header_lookup_init(bbox->box,
8bec19723b39071a1794e76dec35d151473cae5fPhil Carmody vmail->wanted_headers->headers);
8bec19723b39071a1794e76dec35d151473cae5fPhil Carmody vmail->backend_mail = mail_alloc(backend_trans, vmail->wanted_fields,
8bec19723b39071a1794e76dec35d151473cae5fPhil Carmody backend_headers);
8bec19723b39071a1794e76dec35d151473cae5fPhil Carmody if (backend_headers != NULL)
8bec19723b39071a1794e76dec35d151473cae5fPhil Carmody mailbox_header_lookup_unref(&backend_headers);
8bec19723b39071a1794e76dec35d151473cae5fPhil Carmody array_append(&vmail->backend_mails, &vmail->backend_mail, 1);
8bec19723b39071a1794e76dec35d151473cae5fPhil Carmody return vmail->backend_mail;
8bec19723b39071a1794e76dec35d151473cae5fPhil Carmody}
8bec19723b39071a1794e76dec35d151473cae5fPhil Carmody
8bec19723b39071a1794e76dec35d151473cae5fPhil Carmodystatic void virtual_mail_set_seq(struct mail *mail, uint32_t seq)
8bec19723b39071a1794e76dec35d151473cae5fPhil Carmody{
8bec19723b39071a1794e76dec35d151473cae5fPhil Carmody struct virtual_mail *vmail = (struct virtual_mail *)mail;
8bec19723b39071a1794e76dec35d151473cae5fPhil Carmody struct virtual_mailbox *mbox = (struct virtual_mailbox *)mail->box;
8bec19723b39071a1794e76dec35d151473cae5fPhil Carmody struct virtual_backend_box *bbox;
8bec19723b39071a1794e76dec35d151473cae5fPhil Carmody const struct virtual_mail_index_record *vrec;
8bec19723b39071a1794e76dec35d151473cae5fPhil Carmody const void *data;
8bec19723b39071a1794e76dec35d151473cae5fPhil Carmody bool expunged;
1d940afbc02516d8c3d016780e1223a779844a1ePhil Carmody
mail_index_lookup_ext(mail->box->view, seq, mbox->virtual_ext_id,
&data, &expunged);
vrec = data;
bbox = virtual_backend_box_lookup(mbox, vrec->mailbox_id);
vmail->backend_mail = backend_mail_find(vmail, bbox->box);
if (vmail->backend_mail == NULL)
virtual_mail_set_backend_mail(mail, bbox);
vmail->lost = !mail_set_uid(vmail->backend_mail, vrec->real_uid);
memset(&vmail->imail.data, 0, sizeof(vmail->imail.data));
p_clear(vmail->imail.data_pool);
vmail->imail.data.seq = seq;
mail->seq = seq;
mail_index_lookup_uid(mail->box->view, seq, &mail->uid);
if (!vmail->lost) {
mail->expunged = vmail->backend_mail->expunged;
mail->has_nuls = vmail->backend_mail->has_nuls;
mail->has_no_nuls = vmail->backend_mail->has_no_nuls;
} else {
mail->expunged = TRUE;
mail->has_nuls = FALSE;
mail->has_no_nuls = FALSE;
}
}
static bool virtual_mail_set_uid(struct mail *mail, uint32_t uid)
{
uint32_t seq;
if (!mail_index_lookup_seq(mail->box->view, uid, &seq))
return FALSE;
virtual_mail_set_seq(mail, seq);
return TRUE;
}
static void virtual_mail_set_uid_cache_updates(struct mail *mail, bool set)
{
struct virtual_mail *vmail = (struct virtual_mail *)mail;
struct mail_private *p = (struct mail_private *)vmail->backend_mail;
p->v.set_uid_cache_updates(vmail->backend_mail, set);
}
static int virtual_mail_handle_lost(struct virtual_mail *vmail)
{
if (!vmail->lost)
return 0;
mail_set_expunged(&vmail->imail.mail.mail);
return -1;
}
static int
virtual_mail_get_parts(struct mail *mail, struct message_part **parts_r)
{
struct virtual_mail *vmail = (struct virtual_mail *)mail;
if (virtual_mail_handle_lost(vmail) < 0)
return -1;
if (mail_get_parts(vmail->backend_mail, parts_r) < 0) {
virtual_box_copy_error(mail->box, vmail->backend_mail->box);
return -1;
}
return 0;
}
static int
virtual_mail_get_date(struct mail *mail, time_t *date_r, int *timezone_r)
{
struct virtual_mail *vmail = (struct virtual_mail *)mail;
int tz;
if (timezone_r == NULL)
timezone_r = &tz;
if (virtual_mail_handle_lost(vmail) < 0)
return -1;
if (mail_get_date(vmail->backend_mail, date_r, timezone_r) < 0) {
virtual_box_copy_error(mail->box, vmail->backend_mail->box);
return -1;
}
return 0;
}
static int virtual_mail_get_received_date(struct mail *mail, time_t *date_r)
{
struct virtual_mail *vmail = (struct virtual_mail *)mail;
if (virtual_mail_handle_lost(vmail) < 0)
return -1;
if (mail_get_received_date(vmail->backend_mail, date_r) < 0) {
virtual_box_copy_error(mail->box, vmail->backend_mail->box);
return -1;
}
return 0;
}
static int virtual_mail_get_save_date(struct mail *mail, time_t *date_r)
{
struct virtual_mail *vmail = (struct virtual_mail *)mail;
if (virtual_mail_handle_lost(vmail) < 0)
return -1;
if (mail_get_save_date(vmail->backend_mail, date_r) < 0) {
virtual_box_copy_error(mail->box, vmail->backend_mail->box);
return -1;
}
return 0;
}
static int virtual_mail_get_virtual_mail_size(struct mail *mail, uoff_t *size_r)
{
struct virtual_mail *vmail = (struct virtual_mail *)mail;
if (virtual_mail_handle_lost(vmail) < 0)
return -1;
if (mail_get_virtual_size(vmail->backend_mail, size_r) < 0) {
virtual_box_copy_error(mail->box, vmail->backend_mail->box);
return -1;
}
return 0;
}
static int virtual_mail_get_physical_size(struct mail *mail, uoff_t *size_r)
{
struct virtual_mail *vmail = (struct virtual_mail *)mail;
if (virtual_mail_handle_lost(vmail) < 0)
return -1;
if (mail_get_physical_size(vmail->backend_mail, size_r) < 0) {
virtual_box_copy_error(mail->box, vmail->backend_mail->box);
return -1;
}
return 0;
}
static int
virtual_mail_get_first_header(struct mail *mail, const char *field,
bool decode_to_utf8, const char **value_r)
{
struct virtual_mail *vmail = (struct virtual_mail *)mail;
struct mail_private *p = (struct mail_private *)vmail->backend_mail;
if (virtual_mail_handle_lost(vmail) < 0)
return -1;
if (p->v.get_first_header(vmail->backend_mail, field,
decode_to_utf8, value_r) < 0) {
virtual_box_copy_error(mail->box, vmail->backend_mail->box);
return -1;
}
return 0;
}
static int
virtual_mail_get_headers(struct mail *mail, const char *field,
bool decode_to_utf8, const char *const **value_r)
{
struct virtual_mail *vmail = (struct virtual_mail *)mail;
struct mail_private *p = (struct mail_private *)vmail->backend_mail;
if (virtual_mail_handle_lost(vmail) < 0)
return -1;
if (p->v.get_headers(vmail->backend_mail, field,
decode_to_utf8, value_r) < 0) {
virtual_box_copy_error(mail->box, vmail->backend_mail->box);
return -1;
}
return 0;
}
static int
virtual_mail_get_header_stream(struct mail *mail,
struct mailbox_header_lookup_ctx *headers,
struct istream **stream_r)
{
struct virtual_mail *vmail = (struct virtual_mail *)mail;
struct mailbox_header_lookup_ctx *backend_headers;
int ret;
if (virtual_mail_handle_lost(vmail) < 0)
return -1;
backend_headers = mailbox_header_lookup_init(vmail->backend_mail->box,
headers->headers);
ret = mail_get_header_stream(vmail->backend_mail, backend_headers,
stream_r);
mailbox_header_lookup_unref(&backend_headers);
if (ret < 0) {
virtual_box_copy_error(mail->box, vmail->backend_mail->box);
return -1;
}
return 0;
}
static int
virtual_mail_get_stream(struct mail *mail, struct message_size *hdr_size,
struct message_size *body_size,
struct istream **stream_r)
{
struct virtual_mail *vmail = (struct virtual_mail *)mail;
if (virtual_mail_handle_lost(vmail) < 0)
return -1;
if (mail_get_stream(vmail->backend_mail, hdr_size, body_size,
stream_r) < 0) {
virtual_box_copy_error(mail->box, vmail->backend_mail->box);
return -1;
}
return 0;
}
static int
virtual_mail_get_special(struct mail *mail, enum mail_fetch_field field,
const char **value_r)
{
struct virtual_mail *vmail = (struct virtual_mail *)mail;
struct mailbox *box = vmail->backend_mail->box;
if (virtual_mail_handle_lost(vmail) < 0)
return -1;
if (mail_get_special(vmail->backend_mail, field, value_r) < 0) {
virtual_box_copy_error(mail->box, box);
return -1;
}
return 0;
}
static struct mail *virtual_mail_get_real_mail(struct mail *mail)
{
struct virtual_mail *vmail = (struct virtual_mail *)mail;
return mail_get_real_mail(vmail->backend_mail);
}
static void virtual_mail_update_pop3_uidl(struct mail *mail, const char *uidl)
{
struct virtual_mail *vmail = (struct virtual_mail *)mail;
mail_update_pop3_uidl(vmail->backend_mail, uidl);
}
static void virtual_mail_expunge(struct mail *mail)
{
struct virtual_mail *vmail = (struct virtual_mail *)mail;
if (virtual_mail_handle_lost(vmail) < 0)
return;
mail_expunge(vmail->backend_mail);
}
static void
virtual_mail_set_cache_corrupted(struct mail *mail, enum mail_fetch_field field)
{
struct virtual_mail *vmail = (struct virtual_mail *)mail;
if (virtual_mail_handle_lost(vmail) < 0)
return;
mail_set_cache_corrupted(vmail->backend_mail, field);
}
struct mail_vfuncs virtual_mail_vfuncs = {
NULL,
virtual_mail_free,
virtual_mail_set_seq,
virtual_mail_set_uid,
virtual_mail_set_uid_cache_updates,
index_mail_get_flags,
index_mail_get_keywords,
index_mail_get_keyword_indexes,
index_mail_get_modseq,
virtual_mail_get_parts,
virtual_mail_get_date,
virtual_mail_get_received_date,
virtual_mail_get_save_date,
virtual_mail_get_virtual_mail_size,
virtual_mail_get_physical_size,
virtual_mail_get_first_header,
virtual_mail_get_headers,
virtual_mail_get_header_stream,
virtual_mail_get_stream,
virtual_mail_get_special,
virtual_mail_get_real_mail,
index_mail_update_flags,
index_mail_update_keywords,
index_mail_update_modseq,
virtual_mail_update_pop3_uidl,
virtual_mail_expunge,
virtual_mail_set_cache_corrupted,
NULL
};