mbox-mail.c revision bf9402875418faf11825cf11fbe06326b6086e3d
2e37d45867d081db150ab78dad303b9077aea24fTimo Sirainen/* Copyright (c) 2003-2009 Dovecot authors, see the included COPYING file */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include "lib.h"
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen#include "ioloop.h"
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include "istream.h"
0536ccb51d41e3078c3a9fa33e509fb4b2420f95Timo Sirainen#include "hex-binary.h"
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include "index-mail.h"
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include "mbox-storage.h"
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include "mbox-file.h"
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include "mbox-lock.h"
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen#include "mbox-sync-private.h"
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen#include "istream-raw-mbox.h"
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include "istream-header-filter.h"
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen#include <fcntl.h>
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include <unistd.h>
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include <sys/stat.h>
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenstatic void mbox_prepare_resync(struct index_mail *mail)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen struct mbox_transaction_context *t =
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen (struct mbox_transaction_context *)mail->trans;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen struct mbox_mailbox *mbox = (struct mbox_mailbox *)mail->ibox;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen if (mbox->mbox_lock_type == F_RDLCK) {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (mbox->mbox_lock_id == t->mbox_lock_id)
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen t->mbox_lock_id = 0;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen (void)mbox_unlock(mbox, mbox->mbox_lock_id);
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen i_assert(mbox->mbox_lock_type == F_UNLCK);
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen }
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen}
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainenstatic int mbox_mail_seek(struct index_mail *mail)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
2c25e1360d4b5cc55eda969a3a7204d950de5a8fTimo Sirainen struct mbox_transaction_context *t =
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen (struct mbox_transaction_context *)mail->trans;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen struct mbox_mailbox *mbox = (struct mbox_mailbox *)mail->ibox;
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen enum mbox_sync_flags sync_flags = 0;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen int ret, try;
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen bool deleted;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (mail->mail.mail.expunged || mbox->syncing)
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen return -1;
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen if (mail->mail.mail.lookup_abort != MAIL_LOOKUP_ABORT_NEVER)
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen return mail_set_aborted(&mail->mail.mail);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (mbox->mbox_stream != NULL &&
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen istream_raw_mbox_is_corrupted(mbox->mbox_stream)) {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen /* clear the corruption by forcing a full resync */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen sync_flags |= MBOX_SYNC_UNDIRTY | MBOX_SYNC_FORCE_SYNC;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen for (try = 0; try < 2; try++) {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if ((sync_flags & MBOX_SYNC_FORCE_SYNC) != 0) {
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen /* dirty offsets are broken. make sure we can sync. */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen mbox_prepare_resync(mail);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (mbox->mbox_lock_type == F_UNLCK) {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen sync_flags |= MBOX_SYNC_LOCK_READING;
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen if (mbox_sync(mbox, sync_flags) < 0)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return -1;
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen t->mbox_lock_id = mbox->mbox_lock_id;
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen i_assert(t->mbox_lock_id != 0);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen /* refresh index file after mbox has been locked to
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen make sure we get only up-to-date mbox offsets. */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (mail_index_refresh(mbox->ibox.index) < 0) {
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen mail_storage_set_index_error(&mbox->ibox);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen return -1;
af81f402ddc897c74c1e85abd02879612ce44882Timo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen i_assert(mbox->mbox_lock_type != F_UNLCK);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen } else if (t->mbox_lock_id == 0) {
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen /* file is already locked by another transaction, but
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen we must keep it locked for the entire transaction,
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen so increase the lock counter. */
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen if (mbox_lock(mbox, mbox->mbox_lock_type,
9e095dd6a77097356aca8216356d4d71ef1bea45Timo Sirainen &t->mbox_lock_id) < 0)
9e095dd6a77097356aca8216356d4d71ef1bea45Timo Sirainen i_unreached();
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen }
9e095dd6a77097356aca8216356d4d71ef1bea45Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (mbox_file_open_stream(mbox) < 0)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return -1;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen ret = mbox_file_seek(mbox, mail->trans->trans_view,
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen mail->mail.mail.seq, &deleted);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (ret > 0) {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen /* success */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen break;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (ret < 0) {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (deleted)
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen mail_set_expunged(&mail->mail.mail);
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen return -1;
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen }
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen /* we'll need to re-sync it completely */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen sync_flags |= MBOX_SYNC_UNDIRTY | MBOX_SYNC_FORCE_SYNC;
b3142c8e513bc78da821fa70f479016148fa95e5Timo Sirainen }
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen if (ret == 0) {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen mail_storage_set_critical(&mbox->storage->storage,
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen "Losing sync for mail uid=%u in mbox file %s",
b3142c8e513bc78da821fa70f479016148fa95e5Timo Sirainen mail->mail.mail.uid, mbox->ibox.box.path);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen }
67c24901ac5e1521e38a91efc452faeb3e2135a1Timo Sirainen return 0;
67c24901ac5e1521e38a91efc452faeb3e2135a1Timo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenstatic int mbox_mail_get_received_date(struct mail *_mail, time_t *date_r)
67c24901ac5e1521e38a91efc452faeb3e2135a1Timo Sirainen{
67c24901ac5e1521e38a91efc452faeb3e2135a1Timo Sirainen struct index_mail *mail = (struct index_mail *)_mail;
67c24901ac5e1521e38a91efc452faeb3e2135a1Timo Sirainen struct index_mail_data *data = &mail->data;
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen struct mbox_mailbox *mbox = (struct mbox_mailbox *)mail->ibox;
67c24901ac5e1521e38a91efc452faeb3e2135a1Timo Sirainen
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen if (index_mail_get_received_date(_mail, date_r) == 0)
67c24901ac5e1521e38a91efc452faeb3e2135a1Timo Sirainen return 0;
67c24901ac5e1521e38a91efc452faeb3e2135a1Timo Sirainen
67c24901ac5e1521e38a91efc452faeb3e2135a1Timo Sirainen if (mbox_mail_seek(mail) < 0)
67c24901ac5e1521e38a91efc452faeb3e2135a1Timo Sirainen return -1;
67c24901ac5e1521e38a91efc452faeb3e2135a1Timo Sirainen data->received_date =
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen istream_raw_mbox_get_received_time(mbox->mbox_stream);
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen if (data->received_date == (time_t)-1) {
67c24901ac5e1521e38a91efc452faeb3e2135a1Timo Sirainen /* it's broken and conflicts with our "not found"
67c24901ac5e1521e38a91efc452faeb3e2135a1Timo Sirainen return value. change it. */
67c24901ac5e1521e38a91efc452faeb3e2135a1Timo Sirainen data->received_date = 0;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
e11a64ffc7f08b4cb05bcc27668d154d33d0c2e0Timo Sirainen *date_r = data->received_date;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen return 0;
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen}
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainenstatic int mbox_mail_get_save_date(struct mail *_mail, time_t *date_r)
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen{
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen struct index_mail *mail = (struct index_mail *)_mail;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen struct index_mail_data *data = &mail->data;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen if (index_mail_get_save_date(_mail, date_r) == 0)
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen return 0;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen /* no way to know this. save the current time into cache and use
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen that from now on. this works only as long as the index files
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen are permanent */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen data->save_date = ioloop_time;
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen *date_r = data->save_date;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return 0;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
b3142c8e513bc78da821fa70f479016148fa95e5Timo Sirainen
b3142c8e513bc78da821fa70f479016148fa95e5Timo Sirainenstatic bool
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenmbox_mail_get_md5_header(struct index_mail *mail, const char **value_r)
b3142c8e513bc78da821fa70f479016148fa95e5Timo Sirainen{
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen static uint8_t empty_md5[16] =
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen struct mbox_mailbox *mbox = (struct mbox_mailbox *)mail->ibox;
b3142c8e513bc78da821fa70f479016148fa95e5Timo Sirainen const void *ext_data;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (mail->data.guid != NULL)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return mail->data.guid;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen mail_index_lookup_ext(mail->trans->trans_view, mail->mail.mail.seq,
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen mbox->md5hdr_ext_idx, &ext_data, NULL);
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen if (ext_data != NULL && memcmp(ext_data, empty_md5, 16) != 0) {
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen mail->data.guid = p_strdup(mail->data_pool,
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen binary_to_hex(ext_data, 16));
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen *value_r = mail->data.guid;
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen return TRUE;
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen } else {
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen return FALSE;
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen }
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen}
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainenstatic int
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainenmbox_mail_get_special(struct mail *_mail, enum mail_fetch_field field,
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen const char **value_r)
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen{
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen struct index_mail *mail = (struct index_mail *)_mail;
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen struct mbox_mailbox *mbox = (struct mbox_mailbox *)mail->ibox;
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen switch (field) {
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen case MAIL_FETCH_FROM_ENVELOPE:
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen if (mbox_mail_seek(mail) < 0)
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen return -1;
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen *value_r = istream_raw_mbox_get_sender(mbox->mbox_stream);
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen return 0;
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen case MAIL_FETCH_GUID:
7d207b1e77a7b5e3fda640e353acfc86d261fedfTimo Sirainen case MAIL_FETCH_HEADER_MD5:
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen if (mbox_mail_get_md5_header(mail, value_r))
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return 0;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen /* i guess in theory the empty_md5 is valid and can happen,
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen but it's almost guaranteed that it means the MD5 sum is
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen missing. recalculate it. */
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen mbox->mbox_save_md5 = TRUE;
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen mbox_prepare_resync(mail);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (mbox_sync(mbox, MBOX_SYNC_FORCE_SYNC) < 0)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return -1;
fe363b433b8038a69b55169da9dca27892ad7d18Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen if (!mbox_mail_get_md5_header(mail, value_r)) {
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen i_error("mbox resyncing didn't save header MD5 values");
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return -1;
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen }
03f5c621d06d6b6d77a145196c9633a7aa64dc78Timo Sirainen return 0;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen default:
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen break;
e11a64ffc7f08b4cb05bcc27668d154d33d0c2e0Timo Sirainen }
e11a64ffc7f08b4cb05bcc27668d154d33d0c2e0Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return index_mail_get_special(_mail, field, value_r);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenstatic bool
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainenmbox_mail_get_next_offset(struct index_mail *mail, uoff_t *next_offset_r)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen struct mbox_mailbox *mbox = (struct mbox_mailbox *)mail->ibox;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen struct mail_index_view *view;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen const struct mail_index_header *hdr;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen uint32_t seq;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen int trailer_size;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen int ret = 1;
fe363b433b8038a69b55169da9dca27892ad7d18Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen hdr = mail_index_get_header(mail->trans->trans_view);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen if (mail->mail.mail.seq > hdr->messages_count) {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen /* we're appending a new message */
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen return 0;
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen /* We can't really trust trans_view. The next message may already be
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen expunged from it. Also hdr.messages_count may be incorrect there.
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen So refresh the index to get the latest changes and get the next
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen message's offset using a new view. */
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen i_assert(mbox->mbox_lock_type != F_UNLCK);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (mbox_sync_header_refresh(mbox) < 0)
da2aa032ccfa8e7e4a4380ef738014549f4d2c2dTimo Sirainen return -1;
9511a40d933181045343110c8101b75887062aaeTimo Sirainen
9511a40d933181045343110c8101b75887062aaeTimo Sirainen view = mail_index_view_open(mail->ibox->index);
03f5c621d06d6b6d77a145196c9633a7aa64dc78Timo Sirainen hdr = mail_index_get_header(view);
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen if (!mail_index_lookup_seq(view, mail->mail.mail.uid, &seq))
411d6baa37f31d90730e90c4a28c43e1974bbe58Timo Sirainen i_panic("Message unexpectedly expunged from index");
03f5c621d06d6b6d77a145196c9633a7aa64dc78Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (seq == hdr->messages_count) {
/* last message, use the synced mbox size */
trailer_size =
mbox->storage->storage.set->mail_save_crlf ? 2 : 1;
*next_offset_r = mbox->mbox_hdr.sync_size - trailer_size;
} else {
if (mbox_file_lookup_offset(mbox, view, seq + 1,
next_offset_r) <= 0)
ret = -1;
}
mail_index_view_close(&view);
return ret;
}
static int mbox_mail_get_physical_size(struct mail *_mail, uoff_t *size_r)
{
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 *input;
struct message_size hdr_size;
uoff_t old_offset, body_offset, body_size, next_offset;
if (index_mail_get_physical_size(_mail, size_r) == 0)
return 0;
/* we want to return the header size as seen by mail_get_stream(). */
old_offset = data->stream == NULL ? 0 : data->stream->v_offset;
if (mail_get_stream(_mail, &hdr_size, NULL, &input) < 0)
return -1;
/* our header size varies, so don't do any caching */
body_offset = istream_raw_mbox_get_body_offset(mbox->mbox_stream);
if (body_offset == (uoff_t)-1) {
mail_storage_set_critical(_mail->box->storage,
"Couldn't get mbox size");
return -1;
}
/* use the next message's offset to avoid reading through the entire
message body to find out its size */
if (mbox_mail_get_next_offset(mail, &next_offset) > 0)
body_size = next_offset - body_offset;
else
body_size = (uoff_t)-1;
/* verify that the calculated body size is correct */
body_size = istream_raw_mbox_get_body_size(mbox->mbox_stream,
body_size);
data->physical_size = hdr_size.physical_size + body_size;
*size_r = data->physical_size;
i_stream_seek(input, old_offset);
return 0;
}
static int mbox_mail_init_stream(struct index_mail *mail)
{
struct mbox_mailbox *mbox = (struct mbox_mailbox *)mail->ibox;
struct istream *raw_stream;
uoff_t hdr_offset, next_offset;
int ret;
if (mbox_mail_seek(mail) < 0)
return -1;
ret = mbox_mail_get_next_offset(mail, &next_offset);
if (ret < 0) {
if (mbox_mail_seek(mail) < 0)
return -1;
ret = mbox_mail_get_next_offset(mail, &next_offset);
if (ret < 0) {
i_warning("mbox %s: Can't find next message offset "
"for uid=%u",
mbox->ibox.box.path, mail->mail.mail.uid);
}
}
if (ret <= 0)
next_offset = (uoff_t)-1;
raw_stream = mbox->mbox_stream;
hdr_offset = istream_raw_mbox_get_header_offset(raw_stream);
i_stream_seek(raw_stream, hdr_offset);
if (next_offset != (uoff_t)-1)
istream_raw_mbox_set_next_offset(raw_stream, next_offset);
raw_stream = i_stream_create_limit(raw_stream, (uoff_t)-1);
mail->data.stream =
i_stream_create_header_filter(raw_stream,
HEADER_FILTER_EXCLUDE | HEADER_FILTER_NO_CR,
mbox_hide_headers, mbox_hide_headers_count,
null_header_filter_callback, NULL);
i_stream_unref(&raw_stream);
return 0;
}
static int mbox_mail_get_stream(struct mail *_mail,
struct message_size *hdr_size,
struct message_size *body_size,
struct istream **stream_r)
{
struct index_mail *mail = (struct index_mail *)_mail;
if (mail->data.stream == NULL) {
if (mbox_mail_init_stream(mail) < 0)
return -1;
}
return index_mail_init_stream(mail, hdr_size, body_size, stream_r);
}
static void mbox_mail_set_seq(struct mail *_mail, uint32_t seq)
{
struct index_mail *mail = (struct index_mail *)_mail;
index_mail_set_seq(_mail, seq);
mail->data.dont_cache_fetch_fields |= MAIL_FETCH_PHYSICAL_SIZE;
}
static bool mbox_mail_set_uid(struct mail *_mail, uint32_t uid)
{
struct index_mail *mail = (struct index_mail *)_mail;
bool ret;
ret = index_mail_set_uid(_mail, uid);
mail->data.dont_cache_fetch_fields |= MAIL_FETCH_PHYSICAL_SIZE;
return ret;
}
struct mail_vfuncs mbox_mail_vfuncs = {
index_mail_close,
index_mail_free,
mbox_mail_set_seq,
mbox_mail_set_uid,
index_mail_set_uid_cache_updates,
index_mail_get_flags,
index_mail_get_keywords,
index_mail_get_keyword_indexes,
index_mail_get_modseq,
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_update_modseq,
index_mail_update_uid,
NULL,
index_mail_expunge,
index_mail_set_cache_corrupted,
index_mail_get_index_mail
};