mbox-mail.c revision 4b41116563110d00330896a568eff1078c382827
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen/* Copyright (C) 2003-2006 Timo Sirainen */
1d4f710106fb498750456724628da6063e012e6dTimo Sirainen
1d4f710106fb498750456724628da6063e012e6dTimo Sirainen#include "lib.h"
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen#include "ioloop.h"
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen#include "istream.h"
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen#include "index-mail.h"
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen#include "mbox-storage.h"
1d4f710106fb498750456724628da6063e012e6dTimo Sirainen#include "mbox-file.h"
1d4f710106fb498750456724628da6063e012e6dTimo Sirainen#include "mbox-lock.h"
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen#include "mbox-sync-private.h"
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen#include "istream-raw-mbox.h"
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen#include "istream-header-filter.h"
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen#include <fcntl.h>
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen#include <unistd.h>
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen#include <sys/stat.h>
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainenstatic void mbox_prepare_resync(struct index_mail *mail)
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen{
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen struct mbox_transaction_context *t =
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen (struct mbox_transaction_context *)mail->trans;
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen struct mbox_mailbox *mbox = (struct mbox_mailbox *)mail->ibox;
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen if (mbox->mbox_lock_type == F_RDLCK) {
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen if (mbox->mbox_lock_id == t->mbox_lock_id)
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen t->mbox_lock_id = 0;
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen (void)mbox_unlock(mbox, mbox->mbox_lock_id);
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen mbox->mbox_lock_id = 0;
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen i_assert(mbox->mbox_lock_type == F_UNLCK);
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen }
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen}
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainenstatic int mbox_mail_seek(struct index_mail *mail)
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen{
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen struct mbox_transaction_context *t =
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen (struct mbox_transaction_context *)mail->trans;
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen struct mbox_mailbox *mbox = (struct mbox_mailbox *)mail->ibox;
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen enum mbox_sync_flags sync_flags = 0;
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen int ret, try;
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen bool deleted;
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen if (mail->mail.mail.expunged || mbox->syncing)
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen return -1;
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen for (try = 0; try < 2; try++) {
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen if (mbox->mbox_lock_type == F_UNLCK) {
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen sync_flags |= MBOX_SYNC_LOCK_READING;
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen if (mbox_sync(mbox, sync_flags) < 0)
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen return -1;
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen /* refresh index file after mbox has been locked to
1d4f710106fb498750456724628da6063e012e6dTimo Sirainen make sure we get only up-to-date mbox offsets. */
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen if (mail_index_refresh(mbox->ibox.index) < 0) {
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen mail_storage_set_index_error(&mbox->ibox);
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen return -1;
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen }
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen i_assert(mbox->mbox_lock_type != F_UNLCK);
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen t->mbox_lock_id = mbox->mbox_lock_id;
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen } else if ((sync_flags & MBOX_SYNC_FORCE_SYNC) != 0) {
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen /* dirty offsets are broken and mbox is write-locked.
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen sync it to update offsets. */
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen if (mbox_sync(mbox, sync_flags) < 0)
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen return -1;
1d4f710106fb498750456724628da6063e012e6dTimo Sirainen }
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen if (mbox_file_open_stream(mbox) < 0)
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen return -1;
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen ret = mbox_file_seek(mbox, mail->trans->trans_view,
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen mail->mail.mail.seq, &deleted);
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen if (ret > 0) {
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen /* success */
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen break;
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen }
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen if (ret < 0) {
1d4f710106fb498750456724628da6063e012e6dTimo Sirainen if (deleted)
1d4f710106fb498750456724628da6063e012e6dTimo Sirainen mail->mail.mail.expunged = TRUE;
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen return -1;
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen }
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen /* we'll need to re-sync it completely */
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen mbox_prepare_resync(mail);
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen sync_flags |= MBOX_SYNC_UNDIRTY | MBOX_SYNC_FORCE_SYNC;
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen }
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen if (ret == 0) {
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen mail_storage_set_critical(&mbox->storage->storage,
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen "Losing sync for mail uid=%u in mbox file %s",
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen mail->mail.mail.uid, mbox->path);
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen }
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen return 0;
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen}
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainenstatic time_t mbox_mail_get_received_date(struct mail *_mail)
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen{
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen struct index_mail *mail = (struct index_mail *)_mail;
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen struct index_mail_data *data = &mail->data;
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen struct mbox_mailbox *mbox = (struct mbox_mailbox *)mail->ibox;
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen uint32_t t;
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen (void)index_mail_get_received_date(_mail);
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen if (data->received_date != (time_t)-1)
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen return data->received_date;
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen if (mbox_mail_seek(mail) < 0)
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen return (time_t)-1;
1d4f710106fb498750456724628da6063e012e6dTimo Sirainen data->received_date =
1d4f710106fb498750456724628da6063e012e6dTimo Sirainen istream_raw_mbox_get_received_time(mbox->mbox_stream);
if (data->received_date == (time_t)-1) {
/* it's broken and conflicts with our "not found"
return value. change it. */
data->received_date = 0;
}
t = data->received_date;
index_mail_cache_add(mail, MAIL_CACHE_RECEIVED_DATE, &t, sizeof(t));
return data->received_date;
}
static time_t mbox_mail_get_save_date(struct mail *_mail)
{
struct index_mail *mail = (struct index_mail *)_mail;
struct index_mail_data *data = &mail->data;
(void)index_mail_get_save_date(_mail);
if (data->save_date != (time_t)-1)
return data->save_date;
/* no way to know this. save the current time into cache and use
that from now on. this works only as long as the index files
are permanent */
data->save_date = ioloop_time;
index_mail_cache_add(mail, MAIL_CACHE_SAVE_DATE,
&data->save_date, sizeof(data->save_date));
return data->save_date;
}
static const char *
mbox_mail_get_special(struct mail *_mail, enum mail_fetch_field field)
{
#define EMPTY_MD5_SUM "00000000000000000000000000000000"
struct index_mail *mail = (struct index_mail *)_mail;
struct mbox_mailbox *mbox = (struct mbox_mailbox *)mail->ibox;
const char *value;
switch (field) {
case MAIL_FETCH_FROM_ENVELOPE:
if (mbox_mail_seek(mail) < 0)
return NULL;
return istream_raw_mbox_get_sender(mbox->mbox_stream);
case MAIL_FETCH_HEADER_MD5:
value = index_mail_get_special(_mail, field);
if (value != NULL && strcmp(value, EMPTY_MD5_SUM) != 0)
return value;
/* i guess in theory the EMPTY_MD5_SUM is valid and can happen,
but it's almost guaranteed that it means the MD5 sum is
missing. recalculate it. */
mbox->mbox_save_md5 = TRUE;
mbox_prepare_resync(mail);
if (mbox_sync(mbox, MBOX_SYNC_FORCE_SYNC) < 0)
return NULL;
break;
default:
break;
}
return index_mail_get_special(_mail, field);
}
static uoff_t mbox_mail_get_physical_size(struct mail *_mail)
{
struct index_mail *mail = (struct index_mail *)_mail;
struct index_mail_data *data = &mail->data;
struct mbox_mailbox *mbox = (struct mbox_mailbox *)mail->ibox;
struct istream *stream;
uoff_t hdr_offset, body_offset, body_size;
if (mbox_mail_seek(mail) < 0)
return (uoff_t)-1;
/* our header size varies, so don't do any caching */
stream = mbox->mbox_stream;
hdr_offset = istream_raw_mbox_get_header_offset(stream);
body_offset = istream_raw_mbox_get_body_offset(stream);
if (body_offset == (uoff_t)-1)
return (uoff_t)-1;
body_size = istream_raw_mbox_get_body_size(stream, (uoff_t)-1);
data->physical_size = (body_offset - hdr_offset) + body_size;
return data->physical_size;
}
static struct istream *mbox_mail_get_stream(struct mail *_mail,
struct message_size *hdr_size,
struct message_size *body_size)
{
struct index_mail *mail = (struct index_mail *)_mail;
struct index_mail_data *data = &mail->data;
struct mbox_mailbox *mbox = (struct mbox_mailbox *)mail->ibox;
struct istream *raw_stream;
uoff_t offset;
if (data->stream == NULL) {
if (mbox_mail_seek(mail) < 0)
return NULL;
raw_stream = mbox->mbox_stream;
offset = istream_raw_mbox_get_header_offset(raw_stream);
raw_stream = i_stream_create_limit(default_pool, raw_stream,
offset, (uoff_t)-1);
data->stream =
i_stream_create_header_filter(raw_stream,
HEADER_FILTER_EXCLUDE,
mbox_hide_headers, mbox_hide_headers_count,
null_header_filter_callback, NULL);
i_stream_unref(&raw_stream);
}
return index_mail_init_stream(mail, hdr_size, body_size);
}
struct mail_vfuncs mbox_mail_vfuncs = {
index_mail_free,
index_mail_set_seq,
index_mail_set_uid,
index_mail_get_flags,
index_mail_get_keywords,
index_mail_get_parts,
index_mail_get_date,
mbox_mail_get_received_date,
mbox_mail_get_save_date,
index_mail_get_virtual_size,
mbox_mail_get_physical_size,
index_mail_get_first_header,
index_mail_get_headers,
index_mail_get_header_stream,
mbox_mail_get_stream,
mbox_mail_get_special,
index_mail_update_flags,
index_mail_update_keywords,
index_mail_expunge
};