maildir-mail.c revision c60d1eda4df179d83d531647732d5e3e45064219
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen/* Copyright (c) 2003-2010 Dovecot authors, see the included COPYING file */
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "lib.h"
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen#include "istream.h"
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen#include "index-mail.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "maildir-storage.h"
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen#include "maildir-filename.h"
137ea7ca34005345aa2304a940149b7f3774d727Timo Sirainen#include "maildir-uidlist.h"
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen#include "maildir-sync.h"
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen#include <stdlib.h>
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen#include <fcntl.h>
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen#include <unistd.h>
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen#include <sys/stat.h>
137ea7ca34005345aa2304a940149b7f3774d727Timo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenstruct maildir_open_context {
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen int fd;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen char *path;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen};
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenstatic int
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainendo_open(struct maildir_mailbox *mbox, const char *path,
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen struct maildir_open_context *ctx)
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen{
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen ctx->fd = open(path, O_RDONLY);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen if (ctx->fd != -1) {
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen ctx->path = i_strdup(path);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen return 1;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen }
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen if (errno == ENOENT)
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen return 0;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen if (errno == EACCES) {
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen mail_storage_set_critical(&mbox->storage->storage, "%s",
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen mail_error_eacces_msg("open", path));
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen } else {
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen mail_storage_set_critical(&mbox->storage->storage,
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen "open(%s) failed: %m", path);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen }
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen return -1;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen}
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenstatic int
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainendo_stat(struct maildir_mailbox *mbox, const char *path, struct stat *st)
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen{
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen if (stat(path, st) == 0)
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen return 1;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen if (errno == ENOENT)
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen return 0;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen if (errno == EACCES) {
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen mail_storage_set_critical(&mbox->storage->storage, "%s",
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen mail_error_eacces_msg("stat", path));
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen } else {
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen mail_storage_set_critical(&mbox->storage->storage,
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen "stat(%s) failed: %m", path);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen }
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen return -1;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen}
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenstatic int
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenmaildir_rmdir_unexpected_dir(struct mail_storage *storage, const char *path)
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen{
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen if (rmdir(path) == 0) {
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen mail_storage_set_critical(storage,
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen "Maildir: rmdir()ed unwanted empty directory: %s",
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen path);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen return 0;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen } else {
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen mail_storage_set_critical(storage,
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen "Maildir: Found unwanted directory %s, "
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen "but rmdir() failed: %m", path);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen return -1;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen }
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen}
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenstatic struct istream *
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenmaildir_open_mail(struct maildir_mailbox *mbox, struct mail *mail,
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen bool *deleted_r)
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen{
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen struct mail_private *p = (struct mail_private *)mail;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen struct istream *input;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen const char *path;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen struct maildir_open_context ctx;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen *deleted_r = FALSE;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen ctx.fd = -1;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen ctx.path = NULL;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen p->stats_open_lookup_count++;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen if (!mail->saving) {
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen if (maildir_file_do(mbox, mail->uid, do_open, &ctx) < 0)
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen return NULL;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen } else {
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen path = maildir_save_file_get_path(mail->transaction, mail->seq);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen if (do_open(mbox, path, &ctx) <= 0)
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen return NULL;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen }
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen if (ctx.fd == -1) {
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen *deleted_r = TRUE;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen return NULL;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen }
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen input = i_stream_create_fd(ctx.fd, 0, TRUE);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen if (input->stream_errno == EISDIR) {
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen /* there's a directory in maildir. many installations seem to
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen have messed up something and causing "cur", "new" and "tmp"
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen directories to be created under the "cur" directory.
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen if the directory is empty, just get rid of it and log an
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen error */
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen i_stream_destroy(&input);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen if (maildir_rmdir_unexpected_dir(&mbox->storage->storage,
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen ctx.path) == 0)
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen *deleted_r = TRUE;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen } else {
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen i_stream_set_name(input, ctx.path);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen index_mail_set_read_buffer_size(mail, input);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen }
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen i_free(ctx.path);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen return input;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen}
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenstatic int maildir_mail_stat(struct mail *mail, struct stat *st)
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen{
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen struct maildir_mailbox *mbox = (struct maildir_mailbox *)mail->box;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen struct index_mail *imail = (struct index_mail *)mail;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen const struct stat *stp;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen const char *path;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen int ret;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen if (mail->lookup_abort == MAIL_LOOKUP_ABORT_NOT_IN_CACHE)
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen return mail_set_aborted(mail);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen if (imail->data.access_part != 0 && imail->data.stream == NULL) {
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen /* we're going to open the mail anyway */
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen struct istream *input;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen (void)mail_get_stream(mail, NULL, NULL, &input);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen }
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen if (imail->data.stream != NULL) {
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen imail->mail.stats_fstat_lookup_count++;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen stp = i_stream_stat(imail->data.stream, FALSE);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen if (stp == NULL)
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen return -1;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen *st = *stp;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen } else if (!mail->saving) {
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen imail->mail.stats_stat_lookup_count++;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen ret = maildir_file_do(mbox, mail->uid, do_stat, st);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen if (ret <= 0) {
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen if (ret == 0)
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen mail_set_expunged(mail);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen return -1;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen }
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen } else {
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen imail->mail.stats_stat_lookup_count++;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen path = maildir_save_file_get_path(mail->transaction, mail->seq);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen if (stat(path, st) < 0) {
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen mail_storage_set_critical(mail->box->storage,
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen "stat(%s) failed: %m", path);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen return -1;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen }
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen }
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen return 0;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen}
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenstatic int maildir_mail_get_received_date(struct mail *_mail, time_t *date_r)
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen{
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen struct index_mail *mail = (struct index_mail *)_mail;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct index_mail_data *data = &mail->data;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct stat st;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
16f816d3f3c32ae3351834253f52ddd0212bcbf3Timo Sirainen if (index_mail_get_received_date(_mail, date_r) == 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (maildir_mail_stat(_mail, &st) < 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen *date_r = data->received_date = st.st_mtime;
5fb3bff645380804c9db2510940c41db6b8fdb01Timo Sirainen return 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainenstatic int maildir_mail_get_save_date(struct mail *_mail, time_t *date_r)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct index_mail *mail = (struct index_mail *)_mail;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct index_mail_data *data = &mail->data;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct stat st;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (index_mail_get_save_date(_mail, date_r) == 0)
b66a7b7ab0db2c9ad425912d3f21a36fcf76d876Timo Sirainen return 0;
b66a7b7ab0db2c9ad425912d3f21a36fcf76d876Timo Sirainen
b66a7b7ab0db2c9ad425912d3f21a36fcf76d876Timo Sirainen if (maildir_mail_stat(_mail, &st) < 0)
b66a7b7ab0db2c9ad425912d3f21a36fcf76d876Timo Sirainen return -1;
b66a7b7ab0db2c9ad425912d3f21a36fcf76d876Timo Sirainen
b66a7b7ab0db2c9ad425912d3f21a36fcf76d876Timo Sirainen *date_r = data->save_date = st.st_ctime;
b66a7b7ab0db2c9ad425912d3f21a36fcf76d876Timo Sirainen return 0;
b66a7b7ab0db2c9ad425912d3f21a36fcf76d876Timo Sirainen}
d3eff05aaa4c2bc0a7580ee87a54f6693f4a8241Timo Sirainen
d3eff05aaa4c2bc0a7580ee87a54f6693f4a8241Timo Sirainenstatic int
d3eff05aaa4c2bc0a7580ee87a54f6693f4a8241Timo Sirainenmaildir_mail_get_fname(struct maildir_mailbox *mbox, struct mail *mail,
d3eff05aaa4c2bc0a7580ee87a54f6693f4a8241Timo Sirainen const char **fname_r)
d3eff05aaa4c2bc0a7580ee87a54f6693f4a8241Timo Sirainen{
d3eff05aaa4c2bc0a7580ee87a54f6693f4a8241Timo Sirainen enum maildir_uidlist_rec_flag flags;
d3eff05aaa4c2bc0a7580ee87a54f6693f4a8241Timo Sirainen struct mail_index_view *view;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen uint32_t seq;
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen bool exists;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen int ret;
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ret = maildir_uidlist_lookup(mbox->uidlist, mail->uid, &flags, fname_r);
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen if (ret != 0)
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen return ret;
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen /* file exists in index file, but not in dovecot-uidlist anymore. */
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen mail_set_expunged(mail);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* one reason this could happen is if we delayed opening
fd3d711f219fd6813492acbe051e04327f0ca0f0Timo Sirainen dovecot-uidlist and we're trying to open a mail that got recently
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen expunged. Let's test this theory first: */
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen (void)mail_index_refresh(mbox->box.index);
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen view = mail_index_view_open(mbox->box.index);
b35f7104715edee0cfac6d46ab0b342033867eb7Timo Sirainen exists = mail_index_lookup_seq(view, mail->uid, &seq);
fd3d711f219fd6813492acbe051e04327f0ca0f0Timo Sirainen mail_index_view_close(&view);
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen
b35f7104715edee0cfac6d46ab0b342033867eb7Timo Sirainen if (exists) {
fd3d711f219fd6813492acbe051e04327f0ca0f0Timo Sirainen /* the message still exists in index. this means there's some
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen kind of a desync, which doesn't get fixed if cur/ mtime is
fd3d711f219fd6813492acbe051e04327f0ca0f0Timo Sirainen the same as in index. fix this by forcing a resync. */
b92813e2f96d4b28f989528ed5dd6115da7d9bdbTimo Sirainen (void)maildir_storage_sync_force(mbox, mail->uid);
fd3d711f219fd6813492acbe051e04327f0ca0f0Timo Sirainen }
fd3d711f219fd6813492acbe051e04327f0ca0f0Timo Sirainen return 0;
e1ca7af110ea6eeb6303bdd8f07c172b11dff2faTimo Sirainen}
e1ca7af110ea6eeb6303bdd8f07c172b11dff2faTimo Sirainen
e1ca7af110ea6eeb6303bdd8f07c172b11dff2faTimo Sirainenstatic int maildir_get_pop3_state(struct index_mail *mail)
e1ca7af110ea6eeb6303bdd8f07c172b11dff2faTimo Sirainen{
e1ca7af110ea6eeb6303bdd8f07c172b11dff2faTimo Sirainen struct mailbox *box = mail->mail.mail.box;
e1ca7af110ea6eeb6303bdd8f07c172b11dff2faTimo Sirainen struct index_mailbox_context *ibox = INDEX_STORAGE_CONTEXT(box);
e1ca7af110ea6eeb6303bdd8f07c172b11dff2faTimo Sirainen const struct mail_cache_field *fields;
e1ca7af110ea6eeb6303bdd8f07c172b11dff2faTimo Sirainen unsigned int i, count, psize_idx, vsize_idx;
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen enum mail_cache_decision_type dec, vsize_dec;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen enum mail_fetch_field allowed_pop3_fields;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen bool not_pop3_only = FALSE;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen if (mail->pop3_state_set)
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen return mail->pop3_state;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen /* if this mail itself has non-pop3 fields we know we're not
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen pop3-only */
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen allowed_pop3_fields = MAIL_FETCH_FLAGS | MAIL_FETCH_STREAM_HEADER |
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen MAIL_FETCH_STREAM_BODY | MAIL_FETCH_UIDL_FILE_NAME |
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen MAIL_FETCH_VIRTUAL_SIZE;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen if (mail->wanted_headers != NULL ||
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen (mail->wanted_fields & ~allowed_pop3_fields) != 0)
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen not_pop3_only = TRUE;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen /* get vsize decisions */
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen psize_idx = ibox->cache_fields[MAIL_CACHE_PHYSICAL_FULL_SIZE].idx;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen vsize_idx = ibox->cache_fields[MAIL_CACHE_VIRTUAL_FULL_SIZE].idx;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen if (not_pop3_only) {
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen vsize_dec = mail_cache_field_get_decision(box->cache,
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen vsize_idx);
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen vsize_dec &= ~MAIL_CACHE_DECISION_FORCED;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen } else {
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen /* also check if there are any non-[pv]size cached fields */
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen vsize_dec = MAIL_CACHE_DECISION_NO;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen fields = mail_cache_register_get_list(box->cache,
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen pool_datastack_create(),
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen &count);
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen for (i = 0; i < count; i++) {
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen dec = fields[i].decision & ~MAIL_CACHE_DECISION_FORCED;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen if (fields[i].idx == vsize_idx)
e1ca7af110ea6eeb6303bdd8f07c172b11dff2faTimo Sirainen vsize_dec = dec;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen else if (dec != MAIL_CACHE_DECISION_NO &&
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen fields[i].idx != psize_idx)
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen not_pop3_only = TRUE;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen }
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen }
0db4290d60bfa00774f628276d38654c56abd68cTimo Sirainen
0db4290d60bfa00774f628276d38654c56abd68cTimo Sirainen if (!not_pop3_only) {
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen /* either nothing is cached, or only vsize is cached. */
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen mail->pop3_state = 1;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen } else if (vsize_dec != MAIL_CACHE_DECISION_YES &&
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen (box->flags & MAILBOX_FLAG_POP3_SESSION) == 0) {
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen /* if virtual size isn't cached permanently,
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen POP3 isn't being used */
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen mail->pop3_state = -1;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen } else {
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen /* possibly a mixed pop3/imap */
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen mail->pop3_state = 0;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen }
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen mail->pop3_state_set = TRUE;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen return mail->pop3_state;
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen}
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainenstatic int maildir_quick_size_lookup(struct index_mail *mail, bool vsize,
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen uoff_t *size_r)
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen{
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen struct mail *_mail = &mail->mail.mail;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen struct maildir_mailbox *mbox = (struct maildir_mailbox *)_mail->box;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen enum maildir_uidlist_rec_ext_key key;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen const char *path, *fname, *value;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen if (!_mail->saving) {
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen if (maildir_mail_get_fname(mbox, _mail, &fname) <= 0)
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen return -1;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen } else {
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen path = maildir_save_file_get_path(_mail->transaction,
e1ca7af110ea6eeb6303bdd8f07c172b11dff2faTimo Sirainen _mail->seq);
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen fname = strrchr(path, '/');
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen fname = fname != NULL ? fname + 1 : path;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen }
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen /* size can be included in filename */
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen if (maildir_filename_get_size(fname,
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen vsize ? MAILDIR_EXTRA_VIRTUAL_SIZE :
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen MAILDIR_EXTRA_FILE_SIZE,
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen size_r))
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen return 1;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen /* size can be included in uidlist entry */
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen if (!_mail->saving) {
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen key = vsize ? MAILDIR_UIDLIST_REC_EXT_VSIZE :
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen MAILDIR_UIDLIST_REC_EXT_PSIZE;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen value = maildir_uidlist_lookup_ext(mbox->uidlist, _mail->uid,
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen key);
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen if (value != NULL && str_to_uoff(value, size_r) == 0)
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen return 1;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen }
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen return 0;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen}
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainenstatic void
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainenmaildir_handle_size_caching(struct index_mail *mail, bool quick_check,
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen bool vsize)
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen{
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen struct mailbox *box = mail->mail.mail.box;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen struct maildir_mailbox *mbox = (struct maildir_mailbox *)box;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen enum mail_fetch_field field;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen uoff_t size;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen int pop3_state;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen field = vsize ? MAIL_FETCH_VIRTUAL_SIZE : MAIL_FETCH_PHYSICAL_SIZE;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen if ((mail->data.dont_cache_fetch_fields & field) != 0)
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen return;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen if (quick_check && maildir_quick_size_lookup(mail, vsize, &size) > 0) {
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen /* already in filename / uidlist. don't add it anywhere,
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen including to the uidlist if it's already in filename.
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen do some extra checks here to catch potential cache bugs. */
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen if (vsize && mail->data.virtual_size != size) {
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen mail_cache_set_corrupted(box->cache,
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen "Corrupted virtual size for uid=%u: "
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen "%"PRIuUOFF_T" != %"PRIuUOFF_T,
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen mail->mail.mail.uid,
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen mail->data.virtual_size, size);
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen mail->data.virtual_size = size;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen } else if (!vsize && mail->data.physical_size != size) {
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen mail_cache_set_corrupted(box->cache,
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen "Corrupted physical size for uid=%u: "
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen "%"PRIuUOFF_T" != %"PRIuUOFF_T,
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen mail->mail.mail.uid,
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen mail->data.physical_size, size);
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen mail->data.physical_size = size;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen }
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen mail->data.dont_cache_fetch_fields |= field;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen return;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen }
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen /* 1 = pop3-only, 0 = mixed, -1 = no pop3 */
e1ca7af110ea6eeb6303bdd8f07c172b11dff2faTimo Sirainen pop3_state = maildir_get_pop3_state(mail);
e1ca7af110ea6eeb6303bdd8f07c172b11dff2faTimo Sirainen if (pop3_state >= 0 && mail->mail.mail.uid != 0) {
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen /* if size is wanted permanently, store it to uidlist
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen so that in case cache file gets lost we can get it quickly */
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen mail->data.dont_cache_fetch_fields |= field;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen size = vsize ? mail->data.virtual_size :
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen mail->data.physical_size;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen maildir_uidlist_set_ext(mbox->uidlist, mail->mail.mail.uid,
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen vsize ? MAILDIR_UIDLIST_REC_EXT_VSIZE :
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen MAILDIR_UIDLIST_REC_EXT_PSIZE,
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen dec2str(size));
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen }
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen}
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainenstatic int maildir_mail_get_virtual_size(struct mail *_mail, uoff_t *size_r)
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen{
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen struct index_mail *mail = (struct index_mail *)_mail;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen struct index_mail_data *data = &mail->data;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen struct message_size hdr_size, body_size;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen struct istream *input;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen uoff_t old_offset;
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (index_mail_get_cached_virtual_size(mail, size_r)) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_assert(mail->data.virtual_size != (uoff_t)-1);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen maildir_handle_size_caching(mail, TRUE, TRUE);
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen return 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (maildir_quick_size_lookup(mail, TRUE, &data->virtual_size) < 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (data->virtual_size != (uoff_t)-1) {
8153fdec343e40e2a78f5c12353e89b994b28f74Timo 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
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen /* fallback to reading the file */
2cfe9983ce7a6280636ee12beccc2e865111967bTimo Sirainen old_offset = data->stream == NULL ? 0 : data->stream->v_offset;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (mail_get_stream(_mail, &hdr_size, &body_size, &input) < 0)
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen return -1;
b142deb9a831c89b1bb9129ada655f3e56b9d4ccTimo Sirainen i_stream_seek(data->stream, old_offset);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen maildir_handle_size_caching(mail, FALSE, TRUE);
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen *size_r = data->virtual_size;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
b92813e2f96d4b28f989528ed5dd6115da7d9bdbTimo Sirainen
b35f7104715edee0cfac6d46ab0b342033867eb7Timo Sirainenstatic int maildir_mail_get_physical_size(struct mail *_mail, uoff_t *size_r)
b142deb9a831c89b1bb9129ada655f3e56b9d4ccTimo Sirainen{
b142deb9a831c89b1bb9129ada655f3e56b9d4ccTimo Sirainen struct index_mail *mail = (struct index_mail *)_mail;
b142deb9a831c89b1bb9129ada655f3e56b9d4ccTimo Sirainen struct maildir_mailbox *mbox = (struct maildir_mailbox *)_mail->box;
b142deb9a831c89b1bb9129ada655f3e56b9d4ccTimo Sirainen struct index_mail_data *data = &mail->data;
b142deb9a831c89b1bb9129ada655f3e56b9d4ccTimo Sirainen struct stat st;
91dca97b367c54a139c268b56a0c67f564bd9197Timo Sirainen const char *path;
e1ca7af110ea6eeb6303bdd8f07c172b11dff2faTimo Sirainen int ret;
b142deb9a831c89b1bb9129ada655f3e56b9d4ccTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (index_mail_get_physical_size(_mail, size_r) == 0) {
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen i_assert(mail->data.physical_size != (uoff_t)-1);
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen maildir_handle_size_caching(mail, TRUE, FALSE);
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen return 0;
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen }
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen if (maildir_quick_size_lookup(mail, FALSE, &data->physical_size) < 0)
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen return -1;
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen if (data->physical_size != (uoff_t)-1) {
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen data->dont_cache_fetch_fields |= MAIL_FETCH_PHYSICAL_SIZE;
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen *size_r = data->physical_size;
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen return 0;
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen }
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen if (!_mail->saving) {
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen ret = maildir_file_do(mbox, _mail->uid, do_stat, &st);
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen if (ret <= 0) {
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen if (ret == 0)
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen mail_set_expunged(_mail);
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen return -1;
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen }
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen } else {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* saved mail which hasn't been committed yet */
b142deb9a831c89b1bb9129ada655f3e56b9d4ccTimo Sirainen path = maildir_save_file_get_path(_mail->transaction,
b142deb9a831c89b1bb9129ada655f3e56b9d4ccTimo Sirainen _mail->seq);
b142deb9a831c89b1bb9129ada655f3e56b9d4ccTimo Sirainen if (stat(path, &st) < 0) {
b142deb9a831c89b1bb9129ada655f3e56b9d4ccTimo Sirainen mail_storage_set_critical(_mail->box->storage,
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen "stat(%s) failed: %m", path);
b92813e2f96d4b28f989528ed5dd6115da7d9bdbTimo Sirainen return -1;
b92813e2f96d4b28f989528ed5dd6115da7d9bdbTimo Sirainen }
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen data->physical_size = st.st_size;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen maildir_handle_size_caching(mail, FALSE, FALSE);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen *size_r = st.st_size;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return 0;
b35f7104715edee0cfac6d46ab0b342033867eb7Timo Sirainen}
b35f7104715edee0cfac6d46ab0b342033867eb7Timo Sirainen
770cbd7d71f9e97256ecfcd8bfc134f7f048dafcTimo Sirainenstatic int
b92813e2f96d4b28f989528ed5dd6115da7d9bdbTimo Sirainenmaildir_mail_get_special(struct mail *_mail, enum mail_fetch_field field,
fd3d711f219fd6813492acbe051e04327f0ca0f0Timo Sirainen const char **value_r)
fd3d711f219fd6813492acbe051e04327f0ca0f0Timo Sirainen{
fd3d711f219fd6813492acbe051e04327f0ca0f0Timo Sirainen struct index_mail *mail = (struct index_mail *)_mail;
8153fdec343e40e2a78f5c12353e89b994b28f74Timo Sirainen struct maildir_mailbox *mbox = (struct maildir_mailbox *)_mail->box;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen const char *path, *fname, *end, *uidl;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen switch (field) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen case MAIL_FETCH_UIDL_FILE_NAME:
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen case MAIL_FETCH_GUID:
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen if (mail->data.guid != NULL) {
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen *value_r = mail->data.guid;
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen return 0;
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen }
6bf1543bb7af03324c04e8f9ac8e430f395989aeTimo Sirainen if (!_mail->saving) {
6bf1543bb7af03324c04e8f9ac8e430f395989aeTimo Sirainen if (maildir_mail_get_fname(mbox, _mail, &fname) <= 0)
6bf1543bb7af03324c04e8f9ac8e430f395989aeTimo Sirainen return -1;
6bf1543bb7af03324c04e8f9ac8e430f395989aeTimo Sirainen } else {
6bf1543bb7af03324c04e8f9ac8e430f395989aeTimo Sirainen path = maildir_save_file_get_path(_mail->transaction,
6bf1543bb7af03324c04e8f9ac8e430f395989aeTimo Sirainen _mail->seq);
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen fname = strrchr(path, '/');
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen fname = fname != NULL ? fname + 1 : path;
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen }
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen end = strchr(fname, MAILDIR_INFO_SEP);
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen mail->data.guid = end == NULL ?
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen p_strdup(mail->data_pool, fname) :
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen p_strdup_until(mail->data_pool, fname, end);
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen *value_r = mail->data.guid;
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen return 0;
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen case MAIL_FETCH_UIDL_BACKEND:
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen uidl = maildir_uidlist_lookup_ext(mbox->uidlist, _mail->uid,
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen MAILDIR_UIDLIST_REC_EXT_POP3_UIDL);
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen if (uidl == NULL) {
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen /* use the default */
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen *value_r = "";
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen } else if (*uidl == '\0') {
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen /* special optimization case: use the base file name */
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen return maildir_mail_get_special(_mail,
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen MAIL_FETCH_UIDL_FILE_NAME, value_r);
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen } else {
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen *value_r = uidl;
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen }
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen return 0;
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen default:
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen return index_mail_get_special(_mail, field, value_r);
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen }
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen}
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainenstatic int maildir_mail_get_stream(struct mail *_mail,
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen struct message_size *hdr_size,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct message_size *body_size,
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen struct istream **stream_r)
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen{
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen struct index_mail *mail = (struct index_mail *)_mail;
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen struct maildir_mailbox *mbox = (struct maildir_mailbox *)_mail->box;
659fe5d24825b160cae512538088020d97a60239Timo Sirainen struct index_mail_data *data = &mail->data;
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen bool deleted;
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen if (data->stream == NULL) {
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen data->stream = maildir_open_mail(mbox, _mail, &deleted);
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen if (data->stream == NULL) {
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen if (deleted)
659fe5d24825b160cae512538088020d97a60239Timo Sirainen mail_set_expunged(_mail);
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen return -1;
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen }
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen }
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen return index_mail_init_stream(mail, hdr_size, body_size, stream_r);
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen}
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainenstatic void maildir_update_pop3_uidl(struct mail *_mail, const char *uidl)
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen{
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen struct maildir_mailbox *mbox = (struct maildir_mailbox *)_mail->box;
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen const char *fname;
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen if (maildir_mail_get_special(_mail, MAIL_FETCH_UIDL_FILE_NAME,
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen &fname) == 0 &&
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen strcmp(uidl, fname) == 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* special case optimization: empty UIDL means the same
659fe5d24825b160cae512538088020d97a60239Timo Sirainen as base filename */
6f66e585998aa88a4b0ccad531d329a103325d57Timo Sirainen uidl = "";
6f66e585998aa88a4b0ccad531d329a103325d57Timo Sirainen }
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen
6f66e585998aa88a4b0ccad531d329a103325d57Timo Sirainen maildir_uidlist_set_ext(mbox->uidlist, _mail->uid,
659fe5d24825b160cae512538088020d97a60239Timo Sirainen MAILDIR_UIDLIST_REC_EXT_POP3_UIDL, uidl);
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen}
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainenstatic void maildir_mail_set_cache_corrupted(struct mail *_mail,
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen enum mail_fetch_field field)
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen{
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen struct maildir_mailbox *mbox = (struct maildir_mailbox *)_mail->box;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen enum maildir_uidlist_rec_flag flags;
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen const char *fname;
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen uoff_t size;
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen int ret;
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen
b35f7104715edee0cfac6d46ab0b342033867eb7Timo Sirainen if (field == MAIL_FETCH_VIRTUAL_SIZE) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* make sure it gets removed from uidlist.
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen if it's in file name, we can't really do more than log it. */
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen ret = maildir_uidlist_lookup(mbox->uidlist, _mail->uid,
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen &flags, &fname);
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen if (ret <= 0)
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen return;
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen if (maildir_filename_get_size(fname, MAILDIR_EXTRA_VIRTUAL_SIZE,
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen &size)) {
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen const char *subdir =
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen (flags & MAILDIR_UIDLIST_REC_FLAG_NEW_DIR) != 0 ?
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen "new" : "cur";
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen mail_storage_set_critical(_mail->box->storage,
b35f7104715edee0cfac6d46ab0b342033867eb7Timo Sirainen "Maildir filename has wrong W value: %s/%s/%s",
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mbox->box.path, subdir, fname);
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen } else if (maildir_uidlist_lookup_ext(mbox->uidlist, _mail->uid,
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen MAILDIR_UIDLIST_REC_EXT_VSIZE) != NULL) {
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen maildir_uidlist_set_ext(mbox->uidlist, _mail->uid,
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen MAILDIR_UIDLIST_REC_EXT_VSIZE,
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen NULL);
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen }
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen }
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen index_mail_set_cache_corrupted(_mail, field);
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen}
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainenstruct mail_vfuncs maildir_mail_vfuncs = {
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen index_mail_close,
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen index_mail_free,
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen index_mail_set_seq,
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen index_mail_set_uid,
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen index_mail_set_uid_cache_updates,
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen index_mail_get_flags,
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen index_mail_get_keywords,
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen index_mail_get_keyword_indexes,
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen index_mail_get_modseq,
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen index_mail_get_parts,
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen index_mail_get_date,
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen maildir_mail_get_received_date,
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen maildir_mail_get_save_date,
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen maildir_mail_get_virtual_size,
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen maildir_mail_get_physical_size,
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen index_mail_get_first_header,
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen index_mail_get_headers,
6f66e585998aa88a4b0ccad531d329a103325d57Timo Sirainen index_mail_get_header_stream,
6f66e585998aa88a4b0ccad531d329a103325d57Timo Sirainen maildir_mail_get_stream,
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen maildir_mail_get_special,
6f66e585998aa88a4b0ccad531d329a103325d57Timo Sirainen index_mail_get_real_mail,
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen index_mail_update_flags,
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen index_mail_update_keywords,
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen index_mail_update_modseq,
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen maildir_update_pop3_uidl,
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen index_mail_expunge,
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen maildir_mail_set_cache_corrupted
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen};
7fb7365a8fad104a17538a73c338ee3d3420e7b0Timo Sirainen