mbox-mail.c revision e6aa82aeb50948cb47a45a1b61a9c16d6a162388
183bea41fa640dc8117f3eb45ff935cd81377a84Timo Sirainen/* Copyright (c) 2003-2011 Dovecot authors, see the included COPYING file */
d22301419109ed4a38351715e6760011421dadecTimo Sirainenstatic void mbox_prepare_resync(struct mail *mail)
d22301419109ed4a38351715e6760011421dadecTimo Sirainen (struct mbox_transaction_context *)mail->transaction;
d22301419109ed4a38351715e6760011421dadecTimo Sirainen struct mbox_mailbox *mbox = (struct mbox_mailbox *)mail->box;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainenstatic int mbox_mail_seek(struct index_mail *mail)
af1f4b17a92ca7b2661737e65c7849df289d3070Timo Sirainen (struct mbox_transaction_context *)mail->trans;
d22301419109ed4a38351715e6760011421dadecTimo Sirainen struct mbox_mailbox *mbox = (struct mbox_mailbox *)_mail->box;
d22301419109ed4a38351715e6760011421dadecTimo Sirainen if (_mail->lookup_abort != MAIL_LOOKUP_ABORT_NEVER)
b12a6d0e54318273acf0d0fb8b3f4c29f67b62b0Timo Sirainen istream_raw_mbox_is_corrupted(mbox->mbox_stream)) {
b12a6d0e54318273acf0d0fb8b3f4c29f67b62b0Timo Sirainen /* clear the corruption by forcing a full resync */
b12a6d0e54318273acf0d0fb8b3f4c29f67b62b0Timo Sirainen sync_flags |= MBOX_SYNC_UNDIRTY | MBOX_SYNC_FORCE_SYNC;
73247459cf41eb1e5ae5bc61354db46d3b05ee75Timo Sirainen if ((sync_flags & MBOX_SYNC_FORCE_SYNC) != 0) {
73247459cf41eb1e5ae5bc61354db46d3b05ee75Timo Sirainen /* dirty offsets are broken. make sure we can sync. */
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen /* refresh index file after mbox has been locked to
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen make sure we get only up-to-date mbox offsets. */
d22301419109ed4a38351715e6760011421dadecTimo Sirainen if (mail_index_refresh(mbox->box.index) < 0) {
73247459cf41eb1e5ae5bc61354db46d3b05ee75Timo Sirainen } else if (t->mbox_lock_id == 0) {
73247459cf41eb1e5ae5bc61354db46d3b05ee75Timo Sirainen /* file is already locked by another transaction, but
73247459cf41eb1e5ae5bc61354db46d3b05ee75Timo Sirainen we must keep it locked for the entire transaction,
73247459cf41eb1e5ae5bc61354db46d3b05ee75Timo Sirainen so increase the lock counter. */
cd83124e5d070a016c590bb0b1096d7828c7b6adTimo Sirainen ret = mbox_file_seek(mbox, _mail->transaction->view,
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen /* success */
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen /* we'll need to re-sync it completely */
6060b7c8edf8fce73470d0df6a2479b69b01c537Timo Sirainen sync_flags |= MBOX_SYNC_UNDIRTY | MBOX_SYNC_FORCE_SYNC;
ccc895c0358108d2304239063e940b7d75f364abTimo Sirainen mail_storage_set_critical(&mbox->storage->storage,
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen "Losing sync for mail uid=%u in mbox file %s",
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainenstatic int mbox_mail_get_received_date(struct mail *_mail, time_t *date_r)
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen struct index_mail *mail = (struct index_mail *)_mail;
d22301419109ed4a38351715e6760011421dadecTimo Sirainen struct mbox_mailbox *mbox = (struct mbox_mailbox *)_mail->box;
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen if (index_mail_get_received_date(_mail, date_r) == 0)
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen istream_raw_mbox_get_received_time(mbox->mbox_stream);
345212e8f61ebf14ff4f80df26df9e655eb5121eTimo Sirainen /* it's broken and conflicts with our "not found"
345212e8f61ebf14ff4f80df26df9e655eb5121eTimo Sirainen return value. change it. */
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainenstatic int mbox_mail_get_save_date(struct mail *_mail, time_t *date_r)
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen struct index_mail *mail = (struct index_mail *)_mail;
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen if (index_mail_get_save_date(_mail, date_r) == 0)
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen /* no way to know this. save the current time into cache and use
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen that from now on. this works only as long as the index files
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen are permanent */
5daa12cc1c862eec4f63df42227812d3514da2ccTimo Sirainenmbox_mail_get_md5_header(struct index_mail *mail, const char **value_r)
5daa12cc1c862eec4f63df42227812d3514da2ccTimo Sirainen { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
d22301419109ed4a38351715e6760011421dadecTimo Sirainen struct mbox_mailbox *mbox = (struct mbox_mailbox *)mail->mail.mail.box;
cd83124e5d070a016c590bb0b1096d7828c7b6adTimo Sirainen mail_index_lookup_ext(mail->mail.mail.transaction->view,
5daa12cc1c862eec4f63df42227812d3514da2ccTimo Sirainen if (ext_data != NULL && memcmp(ext_data, empty_md5, 16) != 0) {
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainenmbox_mail_get_special(struct mail *_mail, enum mail_fetch_field field,
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen const char **value_r)
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen struct index_mail *mail = (struct index_mail *)_mail;
d22301419109ed4a38351715e6760011421dadecTimo Sirainen struct mbox_mailbox *mbox = (struct mbox_mailbox *)_mail->box;
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen *value_r = istream_raw_mbox_get_sender(mbox->mbox_stream);
ea5f188fc29dfaa0c4071e6413e16e1d04263722Timo Sirainen /* i guess in theory the empty_md5 is valid and can happen,
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen but it's almost guaranteed that it means the MD5 sum is
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen missing. recalculate it. */
cbcde6379f1b0b27bdefc4b11eec93ad69e459d4Timo Sirainen offset = mbox->mbox_lock_type == F_UNLCK ? 0 :
cbcde6379f1b0b27bdefc4b11eec93ad69e459d4Timo Sirainen istream_raw_mbox_get_start_offset(mbox->mbox_stream);
cbcde6379f1b0b27bdefc4b11eec93ad69e459d4Timo Sirainen i_error("mbox %s sync lost during MD5 syncing",
5daa12cc1c862eec4f63df42227812d3514da2ccTimo Sirainen if (!mbox_mail_get_md5_header(mail, value_r)) {
e48c10b9db945fd72e2315e3ec343174fa55c7c7Timo Sirainen i_error("mbox %s resyncing didn't save header MD5 values",
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen return index_mail_get_special(_mail, field, value_r);
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainenmbox_mail_get_next_offset(struct index_mail *mail, uoff_t *next_offset_r)
d22301419109ed4a38351715e6760011421dadecTimo Sirainen struct mbox_mailbox *mbox = (struct mbox_mailbox *)mail->mail.mail.box;
cd83124e5d070a016c590bb0b1096d7828c7b6adTimo Sirainen hdr = mail_index_get_header(mail->mail.mail.transaction->view);
54d42552005111841ab45ec9ca7559075fabd5dfTimo Sirainen if (mail->mail.mail.seq > hdr->messages_count) {
54d42552005111841ab45ec9ca7559075fabd5dfTimo Sirainen /* we're appending a new message */
54d42552005111841ab45ec9ca7559075fabd5dfTimo Sirainen /* We can't really trust trans_view. The next message may already be
8ed8c821ba8aab0b4ed0375f87d48737ef0e0d8eTimo Sirainen expunged from it. Also hdr.messages_count may be incorrect there.
690bafa70767e3f6e98bbfd62ad4a26be2387ea9Timo Sirainen So refresh the index to get the latest changes and get the next
690bafa70767e3f6e98bbfd62ad4a26be2387ea9Timo Sirainen message's offset using a new view. */
d22301419109ed4a38351715e6760011421dadecTimo Sirainen view = mail_index_view_open(mail->mail.mail.box->index);
54d42552005111841ab45ec9ca7559075fabd5dfTimo Sirainen if (!mail_index_lookup_seq(view, mail->mail.mail.uid, &seq))
54d42552005111841ab45ec9ca7559075fabd5dfTimo Sirainen i_panic("Message unexpectedly expunged from index");
54d42552005111841ab45ec9ca7559075fabd5dfTimo Sirainen /* last message, use the synced mbox size */
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen mbox->storage->storage.set->mail_save_crlf ? 2 : 1;
690bafa70767e3f6e98bbfd62ad4a26be2387ea9Timo Sirainen *next_offset_r = mbox->mbox_hdr.sync_size - trailer_size;
5abb33fdc94c081ccd3213bf7d0fa9d0367b4bfdTimo Sirainen if (mbox_file_lookup_offset(mbox, view, seq + 1,
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainenstatic int mbox_mail_get_physical_size(struct mail *_mail, uoff_t *size_r)
d67fde1a8ebc1d85704c5986d8f93aae97eccef3Timo Sirainen struct index_mail *mail = (struct index_mail *)_mail;
d22301419109ed4a38351715e6760011421dadecTimo Sirainen struct mbox_mailbox *mbox = (struct mbox_mailbox *)_mail->box;
a5c8dc283ef673fcdae158513b8032e74b45f59aTimo Sirainen uoff_t old_offset, body_offset, body_size, next_offset;
aa215ab623706463cea1d047f975ffe51d3f0c05Timo Sirainen if (index_mail_get_physical_size(_mail, size_r) == 0)
aa215ab623706463cea1d047f975ffe51d3f0c05Timo Sirainen /* we want to return the header size as seen by mail_get_stream(). */
a5c8dc283ef673fcdae158513b8032e74b45f59aTimo Sirainen old_offset = data->stream == NULL ? 0 : data->stream->v_offset;
aa215ab623706463cea1d047f975ffe51d3f0c05Timo Sirainen if (mail_get_stream(_mail, &hdr_size, NULL, &input) < 0)
d67fde1a8ebc1d85704c5986d8f93aae97eccef3Timo Sirainen /* our header size varies, so don't do any caching */
aa215ab623706463cea1d047f975ffe51d3f0c05Timo Sirainen body_offset = istream_raw_mbox_get_body_offset(mbox->mbox_stream);
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen mail_storage_set_critical(_mail->box->storage,
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen "Couldn't get mbox size");
1b5366b2234892f8930a29351da06b193e385150Timo Sirainen /* use the next message's offset to avoid reading through the entire
1b5366b2234892f8930a29351da06b193e385150Timo Sirainen message body to find out its size */
5abb33fdc94c081ccd3213bf7d0fa9d0367b4bfdTimo Sirainen if (mbox_mail_get_next_offset(mail, &next_offset) > 0)
1b5366b2234892f8930a29351da06b193e385150Timo Sirainen /* verify that the calculated body size is correct */
aa215ab623706463cea1d047f975ffe51d3f0c05Timo Sirainen body_size = istream_raw_mbox_get_body_size(mbox->mbox_stream,
aa215ab623706463cea1d047f975ffe51d3f0c05Timo Sirainen data->physical_size = hdr_size.physical_size + body_size;
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainenstatic int mbox_mail_init_stream(struct index_mail *mail)
d22301419109ed4a38351715e6760011421dadecTimo Sirainen struct mbox_mailbox *mbox = (struct mbox_mailbox *)mail->mail.mail.box;
5abb33fdc94c081ccd3213bf7d0fa9d0367b4bfdTimo Sirainen ret = mbox_mail_get_next_offset(mail, &next_offset);
5abb33fdc94c081ccd3213bf7d0fa9d0367b4bfdTimo Sirainen ret = mbox_mail_get_next_offset(mail, &next_offset);
f480b30abdddf6f1beb8a2c5b1ce4bf8999400dbTimo Sirainen i_warning("mbox %s: Can't find next message offset "
f480b30abdddf6f1beb8a2c5b1ce4bf8999400dbTimo Sirainen "for uid=%u",
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen hdr_offset = istream_raw_mbox_get_header_offset(raw_stream);
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen istream_raw_mbox_set_next_offset(raw_stream, next_offset);
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen raw_stream = i_stream_create_limit(raw_stream, (uoff_t)-1);
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainenstatic int mbox_mail_get_stream(struct mail *_mail,
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen struct index_mail *mail = (struct index_mail *)_mail;
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen return index_mail_init_stream(mail, hdr_size, body_size, stream_r);
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainenstatic void mbox_mail_set_seq(struct mail *_mail, uint32_t seq)
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen struct index_mail *mail = (struct index_mail *)_mail;
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen mail->data.dont_cache_fetch_fields |= MAIL_FETCH_PHYSICAL_SIZE;
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainenstatic bool mbox_mail_set_uid(struct mail *_mail, uint32_t uid)
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen struct index_mail *mail = (struct index_mail *)_mail;