maildir-mail.c revision f567e9ad51a3b4f61580299f12b67e070fb16c5c
76b43e4417bab52e913da39b5f5bc2a130d3f149Timo Sirainen/* Copyright (c) 2003-2014 Dovecot authors, see the included COPYING file */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "lib.h"
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen#include "istream.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "nfs-workarounds.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "index-mail.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "maildir-storage.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "maildir-filename.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "maildir-uidlist.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "maildir-sync.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include <stdio.h>
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include <stdlib.h>
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include <fcntl.h>
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include <unistd.h>
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include <sys/stat.h>
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainenstruct maildir_open_context {
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen int fd;
213b139965e8bde6c8aff02ffd9fd39a74c887a9Timo Sirainen char *path;
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainen};
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic int
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainendo_open(struct maildir_mailbox *mbox, const char *path,
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen struct maildir_open_context *ctx)
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen{
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen ctx->fd = nfs_safe_open(path, O_RDONLY);
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen if (ctx->fd != -1) {
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen ctx->path = i_strdup(path);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return 1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (errno == ENOENT)
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen return 0;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen if (errno == EACCES) {
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen mail_storage_set_critical(&mbox->storage->storage, "%s",
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_error_eacces_msg("open", path));
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen } else {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_storage_set_critical(&mbox->storage->storage,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen "open(%s) failed: %m", path);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic int
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainendo_stat(struct maildir_mailbox *mbox, const char *path, struct stat *st)
7888a9d2008eab9985096c46e1da9ee985c22a2aTimo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (stat(path, st) == 0)
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainen return 1;
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainen if (errno == ENOENT)
213b139965e8bde6c8aff02ffd9fd39a74c887a9Timo Sirainen return 0;
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainen if (errno == EACCES) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_storage_set_critical(&mbox->storage->storage, "%s",
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_error_eacces_msg("stat", path));
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen } else {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_storage_set_critical(&mbox->storage->storage,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen "stat(%s) failed: %m", path);
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen }
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen return -1;
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen}
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainenstatic struct istream *
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainenmaildir_open_mail(struct maildir_mailbox *mbox, struct mail *mail,
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen bool *deleted_r)
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen{
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen struct istream *input;
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen const char *path;
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen struct maildir_open_context ctx;
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen *deleted_r = FALSE;
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ctx.fd = -1;
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen ctx.path = NULL;
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen mail->transaction->stats.open_lookup_count++;
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen if (!mail->saving) {
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen if (maildir_file_do(mbox, mail->uid, do_open, &ctx) < 0)
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen return NULL;
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen } else {
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen path = maildir_save_file_get_path(mail->transaction, mail->seq);
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen if (do_open(mbox, path, &ctx) <= 0)
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen return NULL;
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen }
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen if (ctx.fd == -1) {
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainen *deleted_r = TRUE;
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen return NULL;
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen input = i_stream_create_fd(ctx.fd, 0, TRUE);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (input->stream_errno == EISDIR) {
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen i_stream_destroy(&input);
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen if (maildir_lose_unexpected_dir(&mbox->storage->storage,
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen ctx.path) >= 0)
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen *deleted_r = TRUE;
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen } else {
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen i_stream_set_name(input, ctx.path);
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen index_mail_set_read_buffer_size(mail, input);
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen }
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen i_free(ctx.path);
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen return input;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen}
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic int maildir_mail_stat(struct mail *mail, struct stat *st_r)
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen{
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen struct maildir_mailbox *mbox = (struct maildir_mailbox *)mail->box;
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen struct index_mail *imail = (struct index_mail *)mail;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen const struct stat *stp;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen const char *path;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen int ret;
a050ca9def13949dbaa67bd6574a41c4f397ae26Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (mail->lookup_abort == MAIL_LOOKUP_ABORT_NOT_IN_CACHE) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_set_aborted(mail);
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen return -1;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen }
a050ca9def13949dbaa67bd6574a41c4f397ae26Timo Sirainen
a050ca9def13949dbaa67bd6574a41c4f397ae26Timo Sirainen if (imail->data.access_part != 0 &&
a050ca9def13949dbaa67bd6574a41c4f397ae26Timo Sirainen imail->data.stream == NULL) {
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen /* we're going to open the mail anyway */
a050ca9def13949dbaa67bd6574a41c4f397ae26Timo Sirainen struct istream *input;
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen
0d658231054332c3f4c04aab0422af649de89a8cTimo Sirainen (void)mail_get_stream(mail, NULL, NULL, &input);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen }
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (imail->data.stream != NULL) {
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen mail->transaction->stats.fstat_lookup_count++;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (i_stream_stat(imail->data.stream, FALSE, &stp) < 0)
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen return -1;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen *st_r = *stp;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen } else if (!mail->saving) {
f2786c07cbd4a7a0a6a46c3e06dc4545aaf2f278Timo Sirainen mail->transaction->stats.stat_lookup_count++;
0d658231054332c3f4c04aab0422af649de89a8cTimo Sirainen ret = maildir_file_do(mbox, mail->uid, do_stat, st_r);
0d658231054332c3f4c04aab0422af649de89a8cTimo Sirainen if (ret <= 0) {
0d658231054332c3f4c04aab0422af649de89a8cTimo Sirainen if (ret == 0)
0d658231054332c3f4c04aab0422af649de89a8cTimo Sirainen mail_set_expunged(mail);
0d658231054332c3f4c04aab0422af649de89a8cTimo Sirainen return -1;
f2786c07cbd4a7a0a6a46c3e06dc4545aaf2f278Timo Sirainen }
0d658231054332c3f4c04aab0422af649de89a8cTimo Sirainen } else {
45e62043058738e294f89504c319d852e25943ccTimo Sirainen mail->transaction->stats.stat_lookup_count++;
45e62043058738e294f89504c319d852e25943ccTimo Sirainen path = maildir_save_file_get_path(mail->transaction, mail->seq);
9df8c9225140d9d1df5ddf4c6c9da61662ae6c44Timo Sirainen if (stat(path, st_r) < 0) {
45e62043058738e294f89504c319d852e25943ccTimo Sirainen mail_storage_set_critical(mail->box->storage,
f2786c07cbd4a7a0a6a46c3e06dc4545aaf2f278Timo Sirainen "stat(%s) failed: %m", path);
9df8c9225140d9d1df5ddf4c6c9da61662ae6c44Timo Sirainen return -1;
9df8c9225140d9d1df5ddf4c6c9da61662ae6c44Timo Sirainen }
9df8c9225140d9d1df5ddf4c6c9da61662ae6c44Timo Sirainen }
9df8c9225140d9d1df5ddf4c6c9da61662ae6c44Timo Sirainen return 0;
9df8c9225140d9d1df5ddf4c6c9da61662ae6c44Timo Sirainen}
40ef82c46f6652412b068ebcdac7c3e74840a284Timo Sirainen
9df8c9225140d9d1df5ddf4c6c9da61662ae6c44Timo Sirainenstatic int maildir_mail_get_received_date(struct mail *_mail, time_t *date_r)
40ef82c46f6652412b068ebcdac7c3e74840a284Timo Sirainen{
95a284736b8b11319a3f575ba249ba2eb7dbac1bTimo Sirainen struct index_mail *mail = (struct index_mail *)_mail;
95a284736b8b11319a3f575ba249ba2eb7dbac1bTimo Sirainen struct index_mail_data *data = &mail->data;
95a284736b8b11319a3f575ba249ba2eb7dbac1bTimo Sirainen struct stat st;
95a284736b8b11319a3f575ba249ba2eb7dbac1bTimo Sirainen
95a284736b8b11319a3f575ba249ba2eb7dbac1bTimo Sirainen if (index_mail_get_received_date(_mail, date_r) == 0)
95a284736b8b11319a3f575ba249ba2eb7dbac1bTimo Sirainen return 0;
95a284736b8b11319a3f575ba249ba2eb7dbac1bTimo Sirainen
95a284736b8b11319a3f575ba249ba2eb7dbac1bTimo Sirainen if (maildir_mail_stat(_mail, &st) < 0)
8eeafcb306872435f3171e6acf5a9937aec3a175Timo Sirainen return -1;
be18b5067f9f787179f04c49168060165ed6be08Timo Sirainen
be18b5067f9f787179f04c49168060165ed6be08Timo Sirainen *date_r = data->received_date = st.st_mtime;
a4d209d480d453566d331e870b8d0c99af7716c8Timo Sirainen return 0;
a4d209d480d453566d331e870b8d0c99af7716c8Timo Sirainen}
a4d209d480d453566d331e870b8d0c99af7716c8Timo Sirainen
a4d209d480d453566d331e870b8d0c99af7716c8Timo Sirainenstatic int maildir_mail_get_save_date(struct mail *_mail, time_t *date_r)
a4d209d480d453566d331e870b8d0c99af7716c8Timo Sirainen{
a4d209d480d453566d331e870b8d0c99af7716c8Timo Sirainen struct index_mail *mail = (struct index_mail *)_mail;
a4d209d480d453566d331e870b8d0c99af7716c8Timo Sirainen struct index_mail_data *data = &mail->data;
a4d209d480d453566d331e870b8d0c99af7716c8Timo Sirainen struct stat st;
a4d209d480d453566d331e870b8d0c99af7716c8Timo Sirainen
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen if (index_mail_get_save_date(_mail, date_r) == 0)
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen return 0;
fc7b17677ac1a5fa3f7fe13d5ef7dcfea8d9b4a1Timo Sirainen
f537e7efaec891d6b3320ca94331d09ca8c4a4dbTimo Sirainen if (maildir_mail_stat(_mail, &st) < 0)
f537e7efaec891d6b3320ca94331d09ca8c4a4dbTimo Sirainen return -1;
f537e7efaec891d6b3320ca94331d09ca8c4a4dbTimo Sirainen
f537e7efaec891d6b3320ca94331d09ca8c4a4dbTimo Sirainen *date_r = data->save_date = st.st_ctime;
f537e7efaec891d6b3320ca94331d09ca8c4a4dbTimo Sirainen return 0;
f537e7efaec891d6b3320ca94331d09ca8c4a4dbTimo Sirainen}
f537e7efaec891d6b3320ca94331d09ca8c4a4dbTimo Sirainen
fc7b17677ac1a5fa3f7fe13d5ef7dcfea8d9b4a1Timo Sirainenstatic int
fc7b17677ac1a5fa3f7fe13d5ef7dcfea8d9b4a1Timo Sirainenmaildir_mail_get_fname(struct maildir_mailbox *mbox, struct mail *mail,
fc7b17677ac1a5fa3f7fe13d5ef7dcfea8d9b4a1Timo Sirainen const char **fname_r)
fc7b17677ac1a5fa3f7fe13d5ef7dcfea8d9b4a1Timo Sirainen{
fc7b17677ac1a5fa3f7fe13d5ef7dcfea8d9b4a1Timo Sirainen enum maildir_uidlist_rec_flag flags;
fc7b17677ac1a5fa3f7fe13d5ef7dcfea8d9b4a1Timo Sirainen struct mail_index_view *view;
fc7b17677ac1a5fa3f7fe13d5ef7dcfea8d9b4a1Timo Sirainen uint32_t seq;
fc7b17677ac1a5fa3f7fe13d5ef7dcfea8d9b4a1Timo Sirainen bool exists;
fc7b17677ac1a5fa3f7fe13d5ef7dcfea8d9b4a1Timo Sirainen int ret;
fc7b17677ac1a5fa3f7fe13d5ef7dcfea8d9b4a1Timo Sirainen
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen ret = maildir_sync_lookup(mbox, mail->uid, &flags, fname_r);
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen if (ret != 0)
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen return ret;
ccb77e2f63626ec46e5745ef4f38baa8e8e504fcTimo Sirainen
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen /* file exists in index file, but not in dovecot-uidlist anymore. */
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen mail_set_expunged(mail);
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen /* one reason this could happen is if we delayed opening
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen dovecot-uidlist and we're trying to open a mail that got recently
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen expunged. Let's test this theory first: */
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen mail_index_refresh(mbox->box.index);
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen view = mail_index_view_open(mbox->box.index);
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen exists = mail_index_lookup_seq(view, mail->uid, &seq);
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen mail_index_view_close(&view);
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen if (exists) {
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen /* the message still exists in index. this means there's some
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen kind of a desync, which doesn't get fixed if cur/ mtime is
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen the same as in index. fix this by forcing a resync. */
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen (void)maildir_storage_sync_force(mbox, mail->uid);
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen }
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen return 0;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen}
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainenstatic int maildir_get_pop3_state(struct index_mail *mail)
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen{
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen struct mailbox *box = mail->mail.mail.box;
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen struct index_mailbox_context *ibox = INDEX_STORAGE_CONTEXT(box);
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen const struct mail_cache_field *fields;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen unsigned int i, count, psize_idx, vsize_idx;
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen enum mail_cache_decision_type dec, vsize_dec;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen enum mail_fetch_field allowed_pop3_fields;
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen bool not_pop3_only = FALSE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen if (mail->pop3_state_set)
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen return mail->pop3_state;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen /* if this mail itself has non-pop3 fields we know we're not
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen pop3-only */
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen allowed_pop3_fields = MAIL_FETCH_FLAGS | MAIL_FETCH_STREAM_HEADER |
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen MAIL_FETCH_STREAM_BODY | MAIL_FETCH_UIDL_FILE_NAME |
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen MAIL_FETCH_VIRTUAL_SIZE;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen if (mail->data.wanted_headers != NULL ||
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen (mail->data.wanted_fields & ~allowed_pop3_fields) != 0)
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen not_pop3_only = TRUE;
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen /* get vsize decisions */
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen psize_idx = ibox->cache_fields[MAIL_CACHE_PHYSICAL_FULL_SIZE].idx;
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen vsize_idx = ibox->cache_fields[MAIL_CACHE_VIRTUAL_FULL_SIZE].idx;
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen if (not_pop3_only) {
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen vsize_dec = mail_cache_field_get_decision(box->cache,
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen vsize_idx);
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen vsize_dec &= ~MAIL_CACHE_DECISION_FORCED;
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen } else {
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen /* also check if there are any non-[pv]size cached fields */
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen vsize_dec = MAIL_CACHE_DECISION_NO;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen fields = mail_cache_register_get_list(box->cache,
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen pool_datastack_create(),
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen &count);
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen for (i = 0; i < count; i++) {
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen dec = fields[i].decision & ~MAIL_CACHE_DECISION_FORCED;
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen if (fields[i].idx == vsize_idx)
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen vsize_dec = dec;
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen else if (dec != MAIL_CACHE_DECISION_NO &&
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen fields[i].idx != psize_idx)
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen not_pop3_only = TRUE;
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen }
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen }
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen if (!not_pop3_only) {
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen /* either nothing is cached, or only vsize is cached. */
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen mail->pop3_state = 1;
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen } else if (vsize_dec != MAIL_CACHE_DECISION_YES &&
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen (box->flags & MAILBOX_FLAG_POP3_SESSION) == 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* if virtual size isn't cached permanently,
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen POP3 isn't being used */
f2786c07cbd4a7a0a6a46c3e06dc4545aaf2f278Timo Sirainen mail->pop3_state = -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen } else {
a050ca9def13949dbaa67bd6574a41c4f397ae26Timo Sirainen /* possibly a mixed pop3/imap */
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen mail->pop3_state = 0;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen }
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen mail->pop3_state_set = TRUE;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen return mail->pop3_state;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen}
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainenstatic int maildir_quick_size_lookup(struct index_mail *mail, bool vsize,
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen uoff_t *size_r)
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen{
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen struct mail *_mail = &mail->mail.mail;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen struct maildir_mailbox *mbox = (struct maildir_mailbox *)_mail->box;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen enum maildir_uidlist_rec_ext_key key;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen const char *path, *fname, *value;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (!_mail->saving) {
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen if (maildir_mail_get_fname(mbox, _mail, &fname) <= 0)
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen return -1;
527ed64bc924b4a13b570a8450f8be3efdf71879Timo Sirainen } else {
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen if (maildir_save_file_get_size(_mail->transaction, _mail->seq,
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainen vsize, size_r) == 0)
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen return 1;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen path = maildir_save_file_get_path(_mail->transaction,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen _mail->seq);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen fname = strrchr(path, '/');
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen fname = fname != NULL ? fname + 1 : path;
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
f2786c07cbd4a7a0a6a46c3e06dc4545aaf2f278Timo Sirainen /* size can be included in filename */
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen if (vsize || !mbox->storage->set->maildir_broken_filename_sizes) {
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen if (maildir_filename_get_size(fname,
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen vsize ? MAILDIR_EXTRA_VIRTUAL_SIZE :
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen MAILDIR_EXTRA_FILE_SIZE, size_r))
fadd878cd6098f5b873c21c121209a922679dae4Timo Sirainen return 1;
a050ca9def13949dbaa67bd6574a41c4f397ae26Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* size can be included in uidlist entry */
c680a6b35b459045e92814778908da5a93922107Timo Sirainen if (!_mail->saving) {
c680a6b35b459045e92814778908da5a93922107Timo Sirainen key = vsize ? MAILDIR_UIDLIST_REC_EXT_VSIZE :
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen MAILDIR_UIDLIST_REC_EXT_PSIZE;
c680a6b35b459045e92814778908da5a93922107Timo Sirainen value = maildir_uidlist_lookup_ext(mbox->uidlist, _mail->uid,
c680a6b35b459045e92814778908da5a93922107Timo Sirainen key);
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen if (value != NULL && str_to_uoff(value, size_r) == 0)
f537e7efaec891d6b3320ca94331d09ca8c4a4dbTimo Sirainen return 1;
c680a6b35b459045e92814778908da5a93922107Timo Sirainen }
c680a6b35b459045e92814778908da5a93922107Timo Sirainen return 0;
c680a6b35b459045e92814778908da5a93922107Timo Sirainen}
c680a6b35b459045e92814778908da5a93922107Timo Sirainen
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainenstatic void
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainenmaildir_handle_size_caching(struct index_mail *mail, bool quick_check,
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen bool vsize)
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen{
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen struct mailbox *box = mail->mail.mail.box;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen struct maildir_mailbox *mbox = (struct maildir_mailbox *)box;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen enum mail_fetch_field field;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen uoff_t size;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen int pop3_state;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen field = vsize ? MAIL_FETCH_VIRTUAL_SIZE : MAIL_FETCH_PHYSICAL_SIZE;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen if ((mail->data.dont_cache_fetch_fields & field) != 0)
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen return;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen if (quick_check && maildir_quick_size_lookup(mail, vsize, &size) > 0) {
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen /* already in filename / uidlist. don't add it anywhere,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen including to the uidlist if it's already in filename.
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen do some extra checks here to catch potential cache bugs. */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (vsize && mail->data.virtual_size != size) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_cache_set_corrupted(box->cache,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen "Corrupted virtual size for uid=%u: "
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen "%"PRIuUOFF_T" != %"PRIuUOFF_T,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail->mail.mail.uid,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail->data.virtual_size, size);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail->data.virtual_size = size;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen } else if (!vsize && mail->data.physical_size != size) {
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen mail_cache_set_corrupted(box->cache,
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen "Corrupted physical size for uid=%u: "
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen "%"PRIuUOFF_T" != %"PRIuUOFF_T,
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen mail->mail.mail.uid,
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen mail->data.physical_size, size);
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen mail->data.physical_size = size;
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen }
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen mail->data.dont_cache_fetch_fields |= field;
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen return;
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen }
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen /* 1 = pop3-only, 0 = mixed, -1 = no pop3 */
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen pop3_state = maildir_get_pop3_state(mail);
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen if (pop3_state >= 0 && mail->mail.mail.uid != 0) {
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen /* if size is wanted permanently, store it to uidlist
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen so that in case cache file gets lost we can get it quickly */
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen mail->data.dont_cache_fetch_fields |= field;
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen size = vsize ? mail->data.virtual_size :
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen mail->data.physical_size;
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen maildir_uidlist_set_ext(mbox->uidlist, mail->mail.mail.uid,
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen vsize ? MAILDIR_UIDLIST_REC_EXT_VSIZE :
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen MAILDIR_UIDLIST_REC_EXT_PSIZE,
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen dec2str(size));
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen }
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen}
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainenstatic int maildir_mail_get_virtual_size(struct mail *_mail, uoff_t *size_r)
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen{
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen struct maildir_mailbox *mbox = (struct maildir_mailbox *)_mail->box;
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen struct index_mail *mail = (struct index_mail *)_mail;
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen struct index_mail_data *data = &mail->data;
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen struct message_size hdr_size, body_size;
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen struct istream *input;
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen uoff_t old_offset;
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen if (maildir_uidlist_is_read(mbox->uidlist) ||
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen (_mail->box->flags & MAILBOX_FLAG_POP3_SESSION) != 0) {
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen /* try to get the size from uidlist. this is especially useful
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen with pop3 to avoid unnecessarily opening the cache file. */
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen if (maildir_quick_size_lookup(mail, TRUE,
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen &data->virtual_size) < 0)
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen return -1;
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen }
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen if (data->virtual_size == (uoff_t)-1) {
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen if (index_mail_get_cached_virtual_size(mail, size_r)) {
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen i_assert(mail->data.virtual_size != (uoff_t)-1);
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen maildir_handle_size_caching(mail, TRUE, TRUE);
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen return 0;
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen }
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen if (maildir_quick_size_lookup(mail, TRUE,
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen &data->virtual_size) < 0)
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen return -1;
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen }
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen if (data->virtual_size != (uoff_t)-1) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen data->dont_cache_fetch_fields |= MAIL_FETCH_VIRTUAL_SIZE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen *size_r = data->virtual_size;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* fallback to reading the file */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen old_offset = data->stream == NULL ? 0 : data->stream->v_offset;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (mail_get_stream(_mail, &hdr_size, &body_size, &input) < 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return -1;
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen i_stream_seek(data->stream, old_offset);
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen maildir_handle_size_caching(mail, FALSE, TRUE);
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen *size_r = data->virtual_size;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainenstatic int maildir_mail_get_physical_size(struct mail *_mail, uoff_t *size_r)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct index_mail *mail = (struct index_mail *)_mail;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct maildir_mailbox *mbox = (struct maildir_mailbox *)_mail->box;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct index_mail_data *data = &mail->data;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct stat st;
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen const char *path;
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen int ret;
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen
8bae533c96e129dca8ee7b494d7de5aeb4a043a2Timo Sirainen if (maildir_uidlist_is_read(mbox->uidlist) ||
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen (_mail->box->flags & MAILBOX_FLAG_POP3_SESSION) != 0) {
b5ac20e30146562322ceb7939f044d52d1e51184Timo Sirainen /* try to get the size from uidlist (see virtual size above) */
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen if (maildir_quick_size_lookup(mail, FALSE,
def1cf4b4d2d7bf8dd47258a46b5079682b99251Timo Sirainen &data->physical_size) < 0)
075912b4566a79c7bc59bf229c9f629ef7be0ea2Timo Sirainen return -1;
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen }
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen
b5ac20e30146562322ceb7939f044d52d1e51184Timo Sirainen if (data->physical_size == (uoff_t)-1) {
075912b4566a79c7bc59bf229c9f629ef7be0ea2Timo Sirainen if (index_mail_get_physical_size(_mail, size_r) == 0) {
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen i_assert(mail->data.physical_size != (uoff_t)-1);
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen maildir_handle_size_caching(mail, TRUE, FALSE);
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen return 0;
b5ac20e30146562322ceb7939f044d52d1e51184Timo Sirainen }
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen if (maildir_quick_size_lookup(mail, FALSE,
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen &data->physical_size) < 0)
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen return -1;
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen }
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen if (data->physical_size != (uoff_t)-1) {
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen data->dont_cache_fetch_fields |= MAIL_FETCH_PHYSICAL_SIZE;
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen *size_r = data->physical_size;
a5b331e18b220fac557480b569b85215a1b3bd8eTimo Sirainen return 0;
a5b331e18b220fac557480b569b85215a1b3bd8eTimo Sirainen }
a5b331e18b220fac557480b569b85215a1b3bd8eTimo Sirainen
a5b331e18b220fac557480b569b85215a1b3bd8eTimo Sirainen if (!_mail->saving) {
a5b331e18b220fac557480b569b85215a1b3bd8eTimo Sirainen ret = maildir_file_do(mbox, _mail->uid, do_stat, &st);
a5b331e18b220fac557480b569b85215a1b3bd8eTimo Sirainen if (ret <= 0) {
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen if (ret == 0)
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen mail_set_expunged(_mail);
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen return -1;
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen }
b5ac20e30146562322ceb7939f044d52d1e51184Timo Sirainen } else {
a5b331e18b220fac557480b569b85215a1b3bd8eTimo Sirainen /* saved mail which hasn't been committed yet */
a5b331e18b220fac557480b569b85215a1b3bd8eTimo Sirainen path = maildir_save_file_get_path(_mail->transaction,
a5b331e18b220fac557480b569b85215a1b3bd8eTimo Sirainen _mail->seq);
a5b331e18b220fac557480b569b85215a1b3bd8eTimo Sirainen if (stat(path, &st) < 0) {
a5b331e18b220fac557480b569b85215a1b3bd8eTimo Sirainen mail_storage_set_critical(_mail->box->storage,
a5b331e18b220fac557480b569b85215a1b3bd8eTimo Sirainen "stat(%s) failed: %m", path);
a5b331e18b220fac557480b569b85215a1b3bd8eTimo Sirainen return -1;
b5ac20e30146562322ceb7939f044d52d1e51184Timo Sirainen }
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen }
075912b4566a79c7bc59bf229c9f629ef7be0ea2Timo Sirainen
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen data->physical_size = st.st_size;
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen maildir_handle_size_caching(mail, FALSE, FALSE);
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen *size_r = st.st_size;
b5ac20e30146562322ceb7939f044d52d1e51184Timo Sirainen return 0;
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen}
075912b4566a79c7bc59bf229c9f629ef7be0ea2Timo Sirainen
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainenstatic int
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainenmaildir_mail_get_special(struct mail *_mail, enum mail_fetch_field field,
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen const char **value_r)
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen{
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen struct index_mail *mail = (struct index_mail *)_mail;
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen struct maildir_mailbox *mbox = (struct maildir_mailbox *)_mail->box;
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen const char *path, *fname = NULL, *end, *guid, *uidl, *order;
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen struct stat st;
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen switch (field) {
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen case MAIL_FETCH_GUID:
a5b331e18b220fac557480b569b85215a1b3bd8eTimo Sirainen /* use GUID from uidlist if it exists */
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen i_assert(!_mail->saving);
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen if (mail->data.guid != NULL) {
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen *value_r = mail->data.guid;
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen return 0;
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen }
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen /* first make sure that we have a refreshed uidlist */
075912b4566a79c7bc59bf229c9f629ef7be0ea2Timo Sirainen if (maildir_mail_get_fname(mbox, _mail, &fname) <= 0)
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen return -1;
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen guid = maildir_uidlist_lookup_ext(mbox->uidlist, _mail->uid,
b5ac20e30146562322ceb7939f044d52d1e51184Timo Sirainen MAILDIR_UIDLIST_REC_EXT_GUID);
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen if (guid != NULL) {
075912b4566a79c7bc59bf229c9f629ef7be0ea2Timo Sirainen if (*guid != '\0') {
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen *value_r = mail->data.guid =
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen p_strdup(mail->mail.data_pool, guid);
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen return 0;
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen }
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen mail_storage_set_critical(_mail->box->storage,
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen "Maildir %s: Corrupted dovecot-uidlist: "
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen "UID %u had empty GUID, clearing it",
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen mailbox_get_path(_mail->box), _mail->uid);
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen maildir_uidlist_unset_ext(mbox->uidlist, _mail->uid,
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen MAILDIR_UIDLIST_REC_EXT_GUID);
a5b331e18b220fac557480b569b85215a1b3bd8eTimo Sirainen }
a5b331e18b220fac557480b569b85215a1b3bd8eTimo Sirainen
a5b331e18b220fac557480b569b85215a1b3bd8eTimo Sirainen /* default to base filename: */
a5b331e18b220fac557480b569b85215a1b3bd8eTimo Sirainen if (maildir_mail_get_special(_mail, MAIL_FETCH_UIDL_FILE_NAME,
a5b331e18b220fac557480b569b85215a1b3bd8eTimo Sirainen value_r) < 0)
a5b331e18b220fac557480b569b85215a1b3bd8eTimo Sirainen return -1;
a5b331e18b220fac557480b569b85215a1b3bd8eTimo Sirainen mail->data.guid = mail->data.filename;
a5b331e18b220fac557480b569b85215a1b3bd8eTimo Sirainen return 0;
a5b331e18b220fac557480b569b85215a1b3bd8eTimo Sirainen case MAIL_FETCH_UIDL_FILE_NAME:
a5b331e18b220fac557480b569b85215a1b3bd8eTimo Sirainen if (mail->data.filename != NULL) {
a5b331e18b220fac557480b569b85215a1b3bd8eTimo Sirainen *value_r = mail->data.filename;
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen return 0;
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen }
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen if (fname != NULL) {
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen /* we came here from MAIL_FETCH_GUID,
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen avoid a second lookup */
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen } else if (!_mail->saving) {
b5ac20e30146562322ceb7939f044d52d1e51184Timo Sirainen if (maildir_mail_get_fname(mbox, _mail, &fname) <= 0)
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen return -1;
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen } else {
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen path = maildir_save_file_get_path(_mail->transaction,
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen _mail->seq);
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen fname = strrchr(path, '/');
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen fname = fname != NULL ? fname + 1 : path;
b5ac20e30146562322ceb7939f044d52d1e51184Timo Sirainen }
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen end = strchr(fname, MAILDIR_INFO_SEP);
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen mail->data.filename = end == NULL ?
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen p_strdup(mail->mail.data_pool, fname) :
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen p_strdup_until(mail->mail.data_pool, fname, end);
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen *value_r = mail->data.filename;
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen return 0;
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen case MAIL_FETCH_UIDL_BACKEND:
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen uidl = maildir_uidlist_lookup_ext(mbox->uidlist, _mail->uid,
a8012fea2a7315033bc467acbf46be8e7323318cTimo Sirainen MAILDIR_UIDLIST_REC_EXT_POP3_UIDL);
a8012fea2a7315033bc467acbf46be8e7323318cTimo Sirainen if (uidl == NULL) {
a8012fea2a7315033bc467acbf46be8e7323318cTimo Sirainen /* use the default */
834b90e1f426d1e3308670e09c050bcdea546eb8Timo Sirainen *value_r = "";
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen } else if (*uidl == '\0') {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* special optimization case: use the base file name */
0add8c99ca65e56dbf613595fc37c41aafff3f7fTimo Sirainen return maildir_mail_get_special(_mail,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen MAIL_FETCH_UIDL_FILE_NAME, value_r);
b5ac20e30146562322ceb7939f044d52d1e51184Timo Sirainen } else {
075912b4566a79c7bc59bf229c9f629ef7be0ea2Timo Sirainen *value_r = p_strdup(mail->mail.data_pool, uidl);
f1e1d821d93e4a1dc6ed8f23febde868b5d64cd5Timo Sirainen }
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen return 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen case MAIL_FETCH_POP3_ORDER:
f2786c07cbd4a7a0a6a46c3e06dc4545aaf2f278Timo Sirainen order = maildir_uidlist_lookup_ext(mbox->uidlist, _mail->uid,
f2786c07cbd4a7a0a6a46c3e06dc4545aaf2f278Timo Sirainen MAILDIR_UIDLIST_REC_EXT_POP3_ORDER);
f2786c07cbd4a7a0a6a46c3e06dc4545aaf2f278Timo Sirainen if (order == NULL) {
fadd878cd6098f5b873c21c121209a922679dae4Timo Sirainen *value_r = "";
fadd878cd6098f5b873c21c121209a922679dae4Timo Sirainen } else {
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen *value_r = p_strdup(mail->mail.data_pool, order);
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen }
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen return 0;
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen case MAIL_FETCH_REFCOUNT:
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen if (maildir_mail_stat(_mail, &st) < 0)
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen return -1;
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen *value_r = p_strdup_printf(mail->mail.data_pool, "%lu",
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen (unsigned long)st.st_nlink);
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen return 0;
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen default:
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen return index_mail_get_special(_mail, field, value_r);
f2786c07cbd4a7a0a6a46c3e06dc4545aaf2f278Timo Sirainen }
f2786c07cbd4a7a0a6a46c3e06dc4545aaf2f278Timo Sirainen}
f2786c07cbd4a7a0a6a46c3e06dc4545aaf2f278Timo Sirainen
fadd878cd6098f5b873c21c121209a922679dae4Timo Sirainenstatic int
b7cf555b699d73f2d71de0dabc088af6a7be3627Timo Sirainenmaildir_mail_get_stream(struct mail *_mail, bool get_body ATTR_UNUSED,
f1e1d821d93e4a1dc6ed8f23febde868b5d64cd5Timo Sirainen struct message_size *hdr_size,
f1e1d821d93e4a1dc6ed8f23febde868b5d64cd5Timo Sirainen struct message_size *body_size,
f1e1d821d93e4a1dc6ed8f23febde868b5d64cd5Timo Sirainen struct istream **stream_r)
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct index_mail *mail = (struct index_mail *)_mail;
f1e1d821d93e4a1dc6ed8f23febde868b5d64cd5Timo Sirainen struct maildir_mailbox *mbox = (struct maildir_mailbox *)_mail->box;
f1e1d821d93e4a1dc6ed8f23febde868b5d64cd5Timo Sirainen struct index_mail_data *data = &mail->data;
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainen bool deleted;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (data->stream == NULL) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen data->stream = maildir_open_mail(mbox, _mail, &deleted);
6eb30032b4a50c383dea4c9c74342d906de6ad36Timo Sirainen if (data->stream == NULL) {
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainen if (deleted)
1175f27441385a7011629f295f42708f9a3a4ffcTimo Sirainen mail_set_expunged(_mail);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return -1;
b5ac20e30146562322ceb7939f044d52d1e51184Timo Sirainen }
075912b4566a79c7bc59bf229c9f629ef7be0ea2Timo Sirainen if (mail->mail.v.istream_opened != NULL) {
075912b4566a79c7bc59bf229c9f629ef7be0ea2Timo Sirainen if (mail->mail.v.istream_opened(_mail,
44ff75ca53188056ff5a3e50428e3f2078800b3cTimo Sirainen &data->stream) < 0) {
1225a5a7ce39f1d5545d5ed3b84ecd4f72438d36Timo Sirainen i_stream_unref(&data->stream);
1225a5a7ce39f1d5545d5ed3b84ecd4f72438d36Timo Sirainen return -1;
b5ac20e30146562322ceb7939f044d52d1e51184Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
075912b4566a79c7bc59bf229c9f629ef7be0ea2Timo Sirainen return index_mail_init_stream(mail, hdr_size, body_size, stream_r);
6eb30032b4a50c383dea4c9c74342d906de6ad36Timo Sirainen}
1225a5a7ce39f1d5545d5ed3b84ecd4f72438d36Timo Sirainen
1225a5a7ce39f1d5545d5ed3b84ecd4f72438d36Timo Sirainenstatic void maildir_update_pop3_uidl(struct mail *_mail, const char *uidl)
b5ac20e30146562322ceb7939f044d52d1e51184Timo Sirainen{
6eb30032b4a50c383dea4c9c74342d906de6ad36Timo Sirainen struct maildir_mailbox *mbox = (struct maildir_mailbox *)_mail->box;
6eb30032b4a50c383dea4c9c74342d906de6ad36Timo Sirainen const char *fname;
6eb30032b4a50c383dea4c9c74342d906de6ad36Timo Sirainen
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen if (maildir_mail_get_special(_mail, MAIL_FETCH_UIDL_FILE_NAME,
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen &fname) == 0 &&
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen strcmp(uidl, fname) == 0) {
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen /* special case optimization: empty UIDL means the same
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen as base filename */
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen uidl = "";
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen }
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen _mail->transaction->nontransactional_changes = TRUE;
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen maildir_uidlist_set_ext(mbox->uidlist, _mail->uid,
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen MAILDIR_UIDLIST_REC_EXT_POP3_UIDL, uidl);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic void maildir_mail_remove_sizes_from_uidlist(struct mail *mail)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
5f78b33aa505b17e23cdf27b071a24e127b3db54Timo Sirainen struct maildir_mailbox *mbox = (struct maildir_mailbox *)mail->box;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (maildir_uidlist_lookup_ext(mbox->uidlist, mail->uid,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen MAILDIR_UIDLIST_REC_EXT_VSIZE) != NULL) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen maildir_uidlist_unset_ext(mbox->uidlist, mail->uid,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen MAILDIR_UIDLIST_REC_EXT_VSIZE);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (maildir_uidlist_lookup_ext(mbox->uidlist, mail->uid,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen MAILDIR_UIDLIST_REC_EXT_PSIZE) != NULL) {
5f78b33aa505b17e23cdf27b071a24e127b3db54Timo Sirainen maildir_uidlist_unset_ext(mbox->uidlist, mail->uid,
5f78b33aa505b17e23cdf27b071a24e127b3db54Timo Sirainen MAILDIR_UIDLIST_REC_EXT_PSIZE);
5f78b33aa505b17e23cdf27b071a24e127b3db54Timo Sirainen }
5f78b33aa505b17e23cdf27b071a24e127b3db54Timo Sirainen}
5f78b33aa505b17e23cdf27b071a24e127b3db54Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic int
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainendo_fix_size(struct maildir_mailbox *mbox, const char *path, char *wrong_key_p)
5f78b33aa505b17e23cdf27b071a24e127b3db54Timo Sirainen{
5f78b33aa505b17e23cdf27b071a24e127b3db54Timo Sirainen const char *fname, *newpath, *extra, *info, *dir;
5f78b33aa505b17e23cdf27b071a24e127b3db54Timo Sirainen struct stat st;
5f78b33aa505b17e23cdf27b071a24e127b3db54Timo Sirainen
5f78b33aa505b17e23cdf27b071a24e127b3db54Timo Sirainen fname = strrchr(path, '/');
5f78b33aa505b17e23cdf27b071a24e127b3db54Timo Sirainen i_assert(fname != NULL);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen dir = t_strdup_until(path, fname++);
8bae533c96e129dca8ee7b494d7de5aeb4a043a2Timo Sirainen
5f78b33aa505b17e23cdf27b071a24e127b3db54Timo Sirainen extra = strchr(fname, MAILDIR_EXTRA_SEP);
5f78b33aa505b17e23cdf27b071a24e127b3db54Timo Sirainen i_assert(extra != NULL);
5f78b33aa505b17e23cdf27b071a24e127b3db54Timo Sirainen info = strchr(fname, MAILDIR_INFO_SEP);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (info == NULL) info = "";
44ff75ca53188056ff5a3e50428e3f2078800b3cTimo Sirainen
44ff75ca53188056ff5a3e50428e3f2078800b3cTimo Sirainen if (stat(path, &st) < 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (errno == ENOENT)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return 0;
ccffbed92cb02c24fd717808a84138240bf1885bTimo Sirainen mail_storage_set_critical(&mbox->storage->storage,
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen "stat(%s) failed: %m", path);
ccffbed92cb02c24fd717808a84138240bf1885bTimo Sirainen return -1;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen }
ccffbed92cb02c24fd717808a84138240bf1885bTimo Sirainen
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen newpath = t_strdup_printf("%s/%s,S=%"PRIuUOFF_T"%s", dir,
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen t_strdup_until(fname, extra),
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen (uoff_t)st.st_size, info);
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen if (rename(path, newpath) == 0) {
ccffbed92cb02c24fd717808a84138240bf1885bTimo Sirainen mail_storage_set_critical(mbox->box.storage,
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen "Maildir filename has wrong %c value, "
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen "renamed the file from %s to %s",
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen *wrong_key_p, path, newpath);
ccffbed92cb02c24fd717808a84138240bf1885bTimo Sirainen return 1;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen }
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen if (errno == ENOENT)
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen return 0;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen mail_storage_set_critical(&mbox->storage->storage,
ccffbed92cb02c24fd717808a84138240bf1885bTimo Sirainen "rename(%s, %s) failed: %m", path, newpath);
return -1;
}
static void
maildir_mail_remove_sizes_from_filename(struct mail *mail,
enum mail_fetch_field field)
{
struct maildir_mailbox *mbox = (struct maildir_mailbox *)mail->box;
enum maildir_uidlist_rec_flag flags;
const char *fname;
uoff_t size;
char wrong_key;
if (mbox->storage->set->maildir_broken_filename_sizes) {
/* never try to fix sizes in maildir filenames */
return;
}
if (maildir_sync_lookup(mbox, mail->uid, &flags, &fname) <= 0)
return;
if (strchr(fname, MAILDIR_EXTRA_SEP) == NULL)
return;
if (field == MAIL_FETCH_VIRTUAL_SIZE &&
maildir_filename_get_size(fname, MAILDIR_EXTRA_VIRTUAL_SIZE,
&size)) {
wrong_key = 'W';
} else if (field == MAIL_FETCH_PHYSICAL_SIZE &&
maildir_filename_get_size(fname, MAILDIR_EXTRA_FILE_SIZE,
&size)) {
wrong_key = 'S';
} else {
/* the broken size isn't in filename */
return;
}
(void)maildir_file_do(mbox, mail->uid, do_fix_size, &wrong_key);
}
static void maildir_mail_set_cache_corrupted(struct mail *_mail,
enum mail_fetch_field field)
{
if (field == MAIL_FETCH_PHYSICAL_SIZE ||
field == MAIL_FETCH_VIRTUAL_SIZE) {
maildir_mail_remove_sizes_from_uidlist(_mail);
maildir_mail_remove_sizes_from_filename(_mail, field);
}
index_mail_set_cache_corrupted(_mail, field);
}
struct mail_vfuncs maildir_mail_vfuncs = {
index_mail_close,
index_mail_free,
index_mail_set_seq,
index_mail_set_uid,
index_mail_set_uid_cache_updates,
index_mail_prefetch,
index_mail_precache,
index_mail_add_temp_wanted_fields,
index_mail_get_flags,
index_mail_get_keywords,
index_mail_get_keyword_indexes,
index_mail_get_modseq,
index_mail_get_pvt_modseq,
index_mail_get_parts,
index_mail_get_date,
maildir_mail_get_received_date,
maildir_mail_get_save_date,
maildir_mail_get_virtual_size,
maildir_mail_get_physical_size,
index_mail_get_first_header,
index_mail_get_headers,
index_mail_get_header_stream,
maildir_mail_get_stream,
index_mail_get_binary_stream,
maildir_mail_get_special,
index_mail_get_real_mail,
index_mail_update_flags,
index_mail_update_keywords,
index_mail_update_modseq,
index_mail_update_pvt_modseq,
maildir_update_pop3_uidl,
index_mail_expunge,
maildir_mail_set_cache_corrupted,
index_mail_opened
};