bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2003-2018 Dovecot authors, see the included COPYING file */
d22301419109ed4a38351715e6760011421dadecTimo Sirainenstatic void mbox_prepare_resync(struct mail *mail)
c150beda11da6fbbb1a936829550945d5e884f68Josef 'Jeff' Sipek struct mbox_transaction_context *t = MBOX_TRANSCTX(mail->transaction);
c150beda11da6fbbb1a936829550945d5e884f68Josef 'Jeff' Sipek struct mbox_mailbox *mbox = MBOX_MAILBOX(mail->box);
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainenstatic int mbox_mail_seek(struct index_mail *mail)
c150beda11da6fbbb1a936829550945d5e884f68Josef 'Jeff' Sipek struct mbox_transaction_context *t = MBOX_TRANSCTX(_mail->transaction);
c150beda11da6fbbb1a936829550945d5e884f68Josef 'Jeff' Sipek struct mbox_mailbox *mbox = MBOX_MAILBOX(_mail->box);
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo 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) {
86c6b2546b0bbfce326583f14d05f59674a6d861Timo Sirainen } else if (t->read_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;
d4002fe1f64d25a792f76fb102ef7dc519cd4e24Martti Rannanjärvi mail_set_critical(_mail, "mbox: Losing sync");
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainenstatic int mbox_mail_get_received_date(struct mail *_mail, time_t *date_r)
87490012895b4f371635ded00add04c9107dcfefJosef 'Jeff' Sipek struct index_mail *mail = INDEX_MAIL(_mail);
c150beda11da6fbbb1a936829550945d5e884f68Josef 'Jeff' Sipek struct mbox_mailbox *mbox = 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)
87490012895b4f371635ded00add04c9107dcfefJosef 'Jeff' Sipek struct index_mail *mail = 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 };
c150beda11da6fbbb1a936829550945d5e884f68Josef 'Jeff' Sipek struct mbox_mailbox *mbox = MBOX_MAILBOX(_mail->box);
fc22ecbb03396eda9270472446a6065a986a43e0Timo Sirainen mail_index_lookup_ext(_mail->transaction->view, _mail->seq,
5daa12cc1c862eec4f63df42227812d3514da2ccTimo Sirainen if (ext_data != NULL && memcmp(ext_data, empty_md5, 16) != 0) {
5f44975ec6c5755dd74bcd4c47a123a7242ecab3Timo Sirainen mail->data.guid = p_strdup(mail->mail.data_pool,
fc22ecbb03396eda9270472446a6065a986a43e0Timo Sirainen } else if (mail_index_is_expunged(_mail->transaction->view, _mail->seq)) {
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainenmbox_mail_get_special(struct mail *_mail, enum mail_fetch_field field,
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen const char **value_r)
87490012895b4f371635ded00add04c9107dcfefJosef 'Jeff' Sipek struct index_mail *mail = INDEX_MAIL(_mail);
c150beda11da6fbbb1a936829550945d5e884f68Josef 'Jeff' Sipek struct mbox_mailbox *mbox = MBOX_MAILBOX(_mail->box);
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen *value_r = istream_raw_mbox_get_sender(mbox->mbox_stream);
fc22ecbb03396eda9270472446a6065a986a43e0Timo Sirainen if ((ret = mbox_mail_get_md5_header(mail, value_r)) != 0)
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. */
36f4f01d56ec9156ab75bc2047a8388192df3178Timo Sirainen offset = istream_raw_mbox_get_start_offset(mbox->mbox_stream);
cbcde6379f1b0b27bdefc4b11eec93ad69e459d4Timo Sirainen i_error("mbox %s sync lost during MD5 syncing",
fc22ecbb03396eda9270472446a6065a986a43e0Timo Sirainen if ((ret = mbox_mail_get_md5_header(mail, value_r)) == 0) {
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)
c150beda11da6fbbb1a936829550945d5e884f68Josef 'Jeff' Sipek struct mbox_mailbox *mbox = 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");
767cd7e92a46ca7c0dc4823936750b2bf2eb99e3Timo Sirainen if (mbox_file_lookup_offset(mbox, view, seq + 1,
767cd7e92a46ca7c0dc4823936750b2bf2eb99e3Timo Sirainen } else if (mail->mail.mail.box->input != NULL) {
767cd7e92a46ca7c0dc4823936750b2bf2eb99e3Timo Sirainen /* opened the mailbox as input stream. we can't trust the
767cd7e92a46ca7c0dc4823936750b2bf2eb99e3Timo Sirainen sync_size, since it's wrong with compressed mailboxes */
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;
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainenstatic int mbox_mail_get_physical_size(struct mail *_mail, uoff_t *size_r)
87490012895b4f371635ded00add04c9107dcfefJosef 'Jeff' Sipek struct index_mail *mail = INDEX_MAIL(_mail);
c150beda11da6fbbb1a936829550945d5e884f68Josef 'Jeff' Sipek struct mbox_mailbox *mbox = 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 */
3063bd8ff05d3d8cd33156f4366b36890e501436Timo Sirainen if (istream_raw_mbox_get_body_offset(mbox->mbox_stream, &body_offset) < 0) {
d4002fe1f64d25a792f76fb102ef7dc519cd4e24Martti Rannanjärvi mail_set_critical(_mail, "mbox: Couldn't get body offset");
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 */
3063bd8ff05d3d8cd33156f4366b36890e501436Timo Sirainen if (istream_raw_mbox_get_body_size(mbox->mbox_stream,
d4002fe1f64d25a792f76fb102ef7dc519cd4e24Martti Rannanjärvi mail_set_critical(_mail, "mbox: Couldn't get body size");
aa215ab623706463cea1d047f975ffe51d3f0c05Timo Sirainen data->physical_size = hdr_size.physical_size + body_size;
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainenstatic int mbox_mail_init_stream(struct index_mail *mail)
c150beda11da6fbbb1a936829550945d5e884f68Josef 'Jeff' Sipek struct mbox_mailbox *mbox = 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 "
3063bd8ff05d3d8cd33156f4366b36890e501436Timo Sirainen if (istream_raw_mbox_get_header_offset(raw_stream, &hdr_offset) < 0) {
d4002fe1f64d25a792f76fb102ef7dc519cd4e24Martti Rannanjärvi "mbox: Couldn't get header offset");
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);
6df0ab0c1ab91f06b6418cb30eff44405a1b8f02Timo Sirainenstatic int mbox_mail_get_stream(struct mail *_mail, bool get_body ATTR_UNUSED,
87490012895b4f371635ded00add04c9107dcfefJosef 'Jeff' Sipek struct index_mail *mail = INDEX_MAIL(_mail);
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen return index_mail_init_stream(mail, hdr_size, body_size, stream_r);
7631f16156aca373004953fe6b01a7f343fb47e0Timo Sirainenstatic void mbox_mail_set_seq(struct mail *_mail, uint32_t seq, bool saving)
87490012895b4f371635ded00add04c9107dcfefJosef 'Jeff' Sipek struct index_mail *mail = 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)
87490012895b4f371635ded00add04c9107dcfefJosef 'Jeff' Sipek struct index_mail *mail = INDEX_MAIL(_mail);