maildir-mail.c revision b12b6da6f084212d42421a28ae329eae79751c42
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen/* Copyright (c) 2003-2011 Dovecot authors, see the included COPYING file */
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen#include "lib.h"
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen#include "istream.h"
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen#include "nfs-workarounds.h"
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen#include "index-mail.h"
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen#include "maildir-storage.h"
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen#include "maildir-filename.h"
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen#include "maildir-uidlist.h"
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen#include "maildir-sync.h"
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen#include <stdio.h>
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen#include <stdlib.h>
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen#include <fcntl.h>
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen#include <unistd.h>
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen#include <sys/stat.h>
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainenstruct maildir_open_context {
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen int fd;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen char *path;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen};
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainenstatic int
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainendo_open(struct maildir_mailbox *mbox, const char *path,
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen struct maildir_open_context *ctx)
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen{
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen ctx->fd = nfs_safe_open(path, O_RDONLY);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen if (ctx->fd != -1) {
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen ctx->path = i_strdup(path);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen return 1;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen }
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen if (errno == ENOENT)
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen return 0;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen if (errno == EACCES) {
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen mail_storage_set_critical(&mbox->storage->storage, "%s",
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen mail_error_eacces_msg("open", path));
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen } else {
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen mail_storage_set_critical(&mbox->storage->storage,
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen "open(%s) failed: %m", path);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen }
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen return -1;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen}
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainenstatic int
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainendo_stat(struct maildir_mailbox *mbox, const char *path, struct stat *st)
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen{
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen if (stat(path, st) == 0)
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen return 1;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen if (errno == ENOENT)
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen return 0;
c649139f889c02154fc9a153728b81619edb5663Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen if (errno == EACCES) {
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen mail_storage_set_critical(&mbox->storage->storage, "%s",
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen mail_error_eacces_msg("stat", path));
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen } else {
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen mail_storage_set_critical(&mbox->storage->storage,
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen "stat(%s) failed: %m", path);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen }
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen return -1;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen}
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainenstatic struct istream *
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainenmaildir_open_mail(struct maildir_mailbox *mbox, struct mail *mail,
c649139f889c02154fc9a153728b81619edb5663Timo Sirainen bool *deleted_r)
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen{
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen struct istream *input;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen const char *path;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen struct maildir_open_context ctx;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen *deleted_r = FALSE;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen ctx.fd = -1;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen ctx.path = NULL;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen mail->transaction->stats.open_lookup_count++;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen if (!mail->saving) {
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen if (maildir_file_do(mbox, mail->uid, do_open, &ctx) < 0)
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen return NULL;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen } else {
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen path = maildir_save_file_get_path(mail->transaction, mail->seq);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen if (do_open(mbox, path, &ctx) <= 0)
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen return NULL;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen }
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen if (ctx.fd == -1) {
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen *deleted_r = TRUE;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen return NULL;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen }
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen input = i_stream_create_fd(ctx.fd, 0, TRUE);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen if (input->stream_errno == EISDIR) {
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen i_stream_destroy(&input);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen if (maildir_lose_unexpected_dir(&mbox->storage->storage,
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen ctx.path) >= 0)
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen *deleted_r = TRUE;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen } else {
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen i_stream_set_name(input, ctx.path);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen index_mail_set_read_buffer_size(mail, input);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen }
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen i_free(ctx.path);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen return input;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen}
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainenstatic int maildir_mail_stat(struct mail *mail, struct stat *st)
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen{
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen struct maildir_mailbox *mbox = (struct maildir_mailbox *)mail->box;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen struct index_mail *imail = (struct index_mail *)mail;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen const struct stat *stp;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen const char *path;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen int ret;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen if (mail->lookup_abort == MAIL_LOOKUP_ABORT_NOT_IN_CACHE)
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen return mail_set_aborted(mail);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen if (imail->data.access_part != 0 &&
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen imail->data.stream == NULL) {
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen /* we're going to open the mail anyway */
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen struct istream *input;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen (void)mail_get_stream(mail, NULL, NULL, &input);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen }
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen if (imail->data.stream != NULL) {
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen mail->transaction->stats.fstat_lookup_count++;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen stp = i_stream_stat(imail->data.stream, FALSE);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen if (stp == NULL)
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen return -1;
c649139f889c02154fc9a153728b81619edb5663Timo Sirainen *st = *stp;
c649139f889c02154fc9a153728b81619edb5663Timo Sirainen } else if (!mail->saving) {
c649139f889c02154fc9a153728b81619edb5663Timo Sirainen mail->transaction->stats.stat_lookup_count++;
c649139f889c02154fc9a153728b81619edb5663Timo Sirainen ret = maildir_file_do(mbox, mail->uid, do_stat, st);
c649139f889c02154fc9a153728b81619edb5663Timo Sirainen if (ret <= 0) {
c649139f889c02154fc9a153728b81619edb5663Timo Sirainen if (ret == 0)
c649139f889c02154fc9a153728b81619edb5663Timo Sirainen mail_set_expunged(mail);
c649139f889c02154fc9a153728b81619edb5663Timo Sirainen return -1;
c649139f889c02154fc9a153728b81619edb5663Timo Sirainen }
c649139f889c02154fc9a153728b81619edb5663Timo Sirainen } else {
c649139f889c02154fc9a153728b81619edb5663Timo Sirainen mail->transaction->stats.stat_lookup_count++;
c649139f889c02154fc9a153728b81619edb5663Timo Sirainen path = maildir_save_file_get_path(mail->transaction, mail->seq);
c649139f889c02154fc9a153728b81619edb5663Timo Sirainen if (stat(path, st) < 0) {
c649139f889c02154fc9a153728b81619edb5663Timo Sirainen mail_storage_set_critical(mail->box->storage,
c649139f889c02154fc9a153728b81619edb5663Timo Sirainen "stat(%s) failed: %m", path);
c649139f889c02154fc9a153728b81619edb5663Timo Sirainen return -1;
c649139f889c02154fc9a153728b81619edb5663Timo Sirainen }
c649139f889c02154fc9a153728b81619edb5663Timo Sirainen }
c649139f889c02154fc9a153728b81619edb5663Timo Sirainen return 0;
c649139f889c02154fc9a153728b81619edb5663Timo Sirainen}
c649139f889c02154fc9a153728b81619edb5663Timo Sirainen
c649139f889c02154fc9a153728b81619edb5663Timo Sirainenstatic int maildir_mail_get_received_date(struct mail *_mail, time_t *date_r)
c649139f889c02154fc9a153728b81619edb5663Timo Sirainen{
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen struct index_mail *mail = (struct index_mail *)_mail;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen struct index_mail_data *data = &mail->data;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen struct stat st;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen if (index_mail_get_received_date(_mail, date_r) == 0)
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen return 0;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen if (maildir_mail_stat(_mail, &st) < 0)
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen return -1;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen *date_r = data->received_date = st.st_mtime;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen return 0;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen}
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainenstatic int maildir_mail_get_save_date(struct mail *_mail, time_t *date_r)
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen{
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen struct index_mail *mail = (struct index_mail *)_mail;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen struct index_mail_data *data = &mail->data;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen struct stat st;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen if (index_mail_get_save_date(_mail, date_r) == 0)
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen return 0;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen if (maildir_mail_stat(_mail, &st) < 0)
c649139f889c02154fc9a153728b81619edb5663Timo Sirainen return -1;
c649139f889c02154fc9a153728b81619edb5663Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen *date_r = data->save_date = st.st_ctime;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen return 0;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen}
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainenstatic int
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainenmaildir_mail_get_fname(struct maildir_mailbox *mbox, struct mail *mail,
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen const char **fname_r)
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen{
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen enum maildir_uidlist_rec_flag flags;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen struct mail_index_view *view;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen uint32_t seq;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen bool exists;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen int ret;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen ret = maildir_sync_lookup(mbox, mail->uid, &flags, fname_r);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen if (ret != 0)
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen return ret;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen /* file exists in index file, but not in dovecot-uidlist anymore. */
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen mail_set_expunged(mail);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen /* one reason this could happen is if we delayed opening
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen dovecot-uidlist and we're trying to open a mail that got recently
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen expunged. Let's test this theory first: */
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen (void)mail_index_refresh(mbox->box.index);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen view = mail_index_view_open(mbox->box.index);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen exists = mail_index_lookup_seq(view, mail->uid, &seq);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen mail_index_view_close(&view);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen if (exists) {
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen /* the message still exists in index. this means there's some
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen kind of a desync, which doesn't get fixed if cur/ mtime is
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen the same as in index. fix this by forcing a resync. */
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen (void)maildir_storage_sync_force(mbox, mail->uid);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen }
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen return 0;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen}
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainenstatic int maildir_get_pop3_state(struct index_mail *mail)
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen{
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen struct mailbox *box = mail->mail.mail.box;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen struct index_mailbox_context *ibox = INDEX_STORAGE_CONTEXT(box);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen const struct mail_cache_field *fields;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen unsigned int i, count, psize_idx, vsize_idx;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen enum mail_cache_decision_type dec, vsize_dec;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen enum mail_fetch_field allowed_pop3_fields;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen bool not_pop3_only = FALSE;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen if (mail->pop3_state_set)
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen return mail->pop3_state;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen /* if this mail itself has non-pop3 fields we know we're not
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen pop3-only */
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen allowed_pop3_fields = MAIL_FETCH_FLAGS | MAIL_FETCH_STREAM_HEADER |
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen MAIL_FETCH_STREAM_BODY | MAIL_FETCH_UIDL_FILE_NAME |
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen MAIL_FETCH_VIRTUAL_SIZE;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen if (mail->data.wanted_headers != NULL ||
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen (mail->data.wanted_fields & ~allowed_pop3_fields) != 0)
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen not_pop3_only = TRUE;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen /* get vsize decisions */
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen psize_idx = ibox->cache_fields[MAIL_CACHE_PHYSICAL_FULL_SIZE].idx;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen vsize_idx = ibox->cache_fields[MAIL_CACHE_VIRTUAL_FULL_SIZE].idx;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen if (not_pop3_only) {
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen vsize_dec = mail_cache_field_get_decision(box->cache,
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen vsize_idx);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen vsize_dec &= ~MAIL_CACHE_DECISION_FORCED;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen } else {
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen /* also check if there are any non-[pv]size cached fields */
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen vsize_dec = MAIL_CACHE_DECISION_NO;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen fields = mail_cache_register_get_list(box->cache,
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen pool_datastack_create(),
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen &count);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen for (i = 0; i < count; i++) {
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen dec = fields[i].decision & ~MAIL_CACHE_DECISION_FORCED;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen if (fields[i].idx == vsize_idx)
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen vsize_dec = dec;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen else if (dec != MAIL_CACHE_DECISION_NO &&
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen fields[i].idx != psize_idx)
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen not_pop3_only = TRUE;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen }
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen }
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen if (!not_pop3_only) {
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen /* either nothing is cached, or only vsize is cached. */
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen mail->pop3_state = 1;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen } else if (vsize_dec != MAIL_CACHE_DECISION_YES &&
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen (box->flags & MAILBOX_FLAG_POP3_SESSION) == 0) {
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen /* if virtual size isn't cached permanently,
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen POP3 isn't being used */
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen mail->pop3_state = -1;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen } else {
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen /* possibly a mixed pop3/imap */
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen mail->pop3_state = 0;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen }
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen mail->pop3_state_set = TRUE;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen return mail->pop3_state;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen}
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainenstatic int maildir_quick_size_lookup(struct index_mail *mail, bool vsize,
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen uoff_t *size_r)
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen{
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen struct mail *_mail = &mail->mail.mail;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen struct maildir_mailbox *mbox = (struct maildir_mailbox *)_mail->box;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen enum maildir_uidlist_rec_ext_key key;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen const char *path, *fname, *value;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen if (!_mail->saving) {
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen if (maildir_mail_get_fname(mbox, _mail, &fname) <= 0)
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen return -1;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen } else {
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen path = maildir_save_file_get_path(_mail->transaction,
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen _mail->seq);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen fname = strrchr(path, '/');
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen fname = fname != NULL ? fname + 1 : path;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen }
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen /* size can be included in filename */
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen if (maildir_filename_get_size(fname,
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen vsize ? MAILDIR_EXTRA_VIRTUAL_SIZE :
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen MAILDIR_EXTRA_FILE_SIZE,
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen size_r))
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen return 1;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen /* size can be included in uidlist entry */
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen if (!_mail->saving) {
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen key = vsize ? MAILDIR_UIDLIST_REC_EXT_VSIZE :
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen MAILDIR_UIDLIST_REC_EXT_PSIZE;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen value = maildir_uidlist_lookup_ext(mbox->uidlist, _mail->uid,
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen key);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen if (value != NULL && str_to_uoff(value, size_r) == 0)
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen return 1;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen }
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen return 0;
c649139f889c02154fc9a153728b81619edb5663Timo Sirainen}
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainenstatic void
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainenmaildir_handle_size_caching(struct index_mail *mail, bool quick_check,
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen bool vsize)
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen{
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen struct mailbox *box = mail->mail.mail.box;
c649139f889c02154fc9a153728b81619edb5663Timo Sirainen struct maildir_mailbox *mbox = (struct maildir_mailbox *)box;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen enum mail_fetch_field field;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen uoff_t size;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen int pop3_state;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen field = vsize ? MAIL_FETCH_VIRTUAL_SIZE : MAIL_FETCH_PHYSICAL_SIZE;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen if ((mail->data.dont_cache_fetch_fields & field) != 0)
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen return;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen if (quick_check && maildir_quick_size_lookup(mail, vsize, &size) > 0) {
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen /* already in filename / uidlist. don't add it anywhere,
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen including to the uidlist if it's already in filename.
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen do some extra checks here to catch potential cache bugs. */
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen if (vsize && mail->data.virtual_size != size) {
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen mail_cache_set_corrupted(box->cache,
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen "Corrupted virtual size for uid=%u: "
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen "%"PRIuUOFF_T" != %"PRIuUOFF_T,
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen mail->mail.mail.uid,
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen mail->data.virtual_size, size);
c649139f889c02154fc9a153728b81619edb5663Timo Sirainen mail->data.virtual_size = size;
c649139f889c02154fc9a153728b81619edb5663Timo Sirainen } else if (!vsize && mail->data.physical_size != size) {
c649139f889c02154fc9a153728b81619edb5663Timo Sirainen mail_cache_set_corrupted(box->cache,
c649139f889c02154fc9a153728b81619edb5663Timo Sirainen "Corrupted physical size for uid=%u: "
c649139f889c02154fc9a153728b81619edb5663Timo Sirainen "%"PRIuUOFF_T" != %"PRIuUOFF_T,
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen mail->mail.mail.uid,
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen mail->data.physical_size, size);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen mail->data.physical_size = size;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen }
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen mail->data.dont_cache_fetch_fields |= field;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen return;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen }
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen /* 1 = pop3-only, 0 = mixed, -1 = no pop3 */
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen pop3_state = maildir_get_pop3_state(mail);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen if (pop3_state >= 0 && mail->mail.mail.uid != 0) {
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen /* if size is wanted permanently, store it to uidlist
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen so that in case cache file gets lost we can get it quickly */
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen mail->data.dont_cache_fetch_fields |= field;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen size = vsize ? mail->data.virtual_size :
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen mail->data.physical_size;
c649139f889c02154fc9a153728b81619edb5663Timo Sirainen maildir_uidlist_set_ext(mbox->uidlist, mail->mail.mail.uid,
c649139f889c02154fc9a153728b81619edb5663Timo Sirainen vsize ? MAILDIR_UIDLIST_REC_EXT_VSIZE :
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen MAILDIR_UIDLIST_REC_EXT_PSIZE,
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen dec2str(size));
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen }
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen}
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainenstatic int maildir_mail_get_virtual_size(struct mail *_mail, uoff_t *size_r)
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen{
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen struct maildir_mailbox *mbox = (struct maildir_mailbox *)_mail->box;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen struct index_mail *mail = (struct index_mail *)_mail;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen struct index_mail_data *data = &mail->data;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen struct message_size hdr_size, body_size;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen struct istream *input;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen uoff_t old_offset;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen if (maildir_uidlist_is_read(mbox->uidlist) ||
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen (_mail->box->flags & MAILBOX_FLAG_POP3_SESSION) != 0) {
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen /* try to get the size from uidlist. this is especially useful
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen with pop3 to avoid unnecessarily opening the cache file. */
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen if (maildir_quick_size_lookup(mail, TRUE,
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen &data->virtual_size) < 0)
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen return -1;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen }
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen if (data->virtual_size == (uoff_t)-1) {
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen if (index_mail_get_cached_virtual_size(mail, size_r)) {
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen i_assert(mail->data.virtual_size != (uoff_t)-1);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen maildir_handle_size_caching(mail, TRUE, TRUE);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen return 0;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen }
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen if (maildir_quick_size_lookup(mail, TRUE,
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen &data->virtual_size) < 0)
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen return -1;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen }
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen if (data->virtual_size != (uoff_t)-1) {
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen data->dont_cache_fetch_fields |= MAIL_FETCH_VIRTUAL_SIZE;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen *size_r = data->virtual_size;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen return 0;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen }
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen /* fallback to reading the file */
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen old_offset = data->stream == NULL ? 0 : data->stream->v_offset;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen if (mail_get_stream(_mail, &hdr_size, &body_size, &input) < 0)
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen return -1;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen i_stream_seek(data->stream, old_offset);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen maildir_handle_size_caching(mail, FALSE, TRUE);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen *size_r = data->virtual_size;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen return 0;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen}
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainenstatic int maildir_mail_get_physical_size(struct mail *_mail, uoff_t *size_r)
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen{
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen struct index_mail *mail = (struct index_mail *)_mail;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen struct maildir_mailbox *mbox = (struct maildir_mailbox *)_mail->box;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen struct index_mail_data *data = &mail->data;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen struct stat st;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen const char *path;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen int ret;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen if (maildir_uidlist_is_read(mbox->uidlist) ||
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen (_mail->box->flags & MAILBOX_FLAG_POP3_SESSION) != 0) {
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen /* try to get the size from uidlist (see virtual size above) */
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen if (maildir_quick_size_lookup(mail, FALSE,
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen &data->physical_size) < 0)
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen return -1;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen }
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen if (data->physical_size == (uoff_t)-1) {
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen if (index_mail_get_physical_size(_mail, size_r) == 0) {
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen i_assert(mail->data.physical_size != (uoff_t)-1);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen maildir_handle_size_caching(mail, TRUE, FALSE);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen return 0;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen }
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen if (maildir_quick_size_lookup(mail, FALSE,
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen &data->physical_size) < 0)
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen return -1;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen }
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen if (data->physical_size != (uoff_t)-1) {
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen data->dont_cache_fetch_fields |= MAIL_FETCH_PHYSICAL_SIZE;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen *size_r = data->physical_size;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen return 0;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen }
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen if (!_mail->saving) {
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen ret = maildir_file_do(mbox, _mail->uid, do_stat, &st);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen if (ret <= 0) {
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen if (ret == 0)
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen mail_set_expunged(_mail);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen return -1;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen }
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen } else {
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen /* saved mail which hasn't been committed yet */
c649139f889c02154fc9a153728b81619edb5663Timo Sirainen path = maildir_save_file_get_path(_mail->transaction,
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen _mail->seq);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen if (stat(path, &st) < 0) {
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen mail_storage_set_critical(_mail->box->storage,
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen "stat(%s) failed: %m", path);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen return -1;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen }
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen }
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen data->physical_size = st.st_size;
c649139f889c02154fc9a153728b81619edb5663Timo Sirainen maildir_handle_size_caching(mail, FALSE, FALSE);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen *size_r = st.st_size;
c649139f889c02154fc9a153728b81619edb5663Timo Sirainen return 0;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen}
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainenstatic int
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainenmaildir_mail_get_special(struct mail *_mail, enum mail_fetch_field field,
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen const char **value_r)
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen{
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen struct index_mail *mail = (struct index_mail *)_mail;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen struct maildir_mailbox *mbox = (struct maildir_mailbox *)_mail->box;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen const char *path, *fname = NULL, *end, *guid, *uidl, *order;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen switch (field) {
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen case MAIL_FETCH_GUID:
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen /* use GUID from uidlist if it exists */
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen i_assert(!_mail->saving);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen /* first make sure that we have a refreshed uidlist */
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen if (maildir_mail_get_fname(mbox, _mail, &fname) <= 0)
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen return -1;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen guid = maildir_uidlist_lookup_ext(mbox->uidlist, _mail->uid,
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen MAILDIR_UIDLIST_REC_EXT_GUID);
c649139f889c02154fc9a153728b81619edb5663Timo Sirainen if (guid != NULL) {
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen if (*guid != '\0') {
*value_r = p_strdup(mail->data_pool, guid);
return 0;
}
mail_storage_set_critical(_mail->box->storage,
"Maildir %s: Corrupted dovecot-uidlist: "
"UID %u had empty GUID, clearing it",
mailbox_get_path(_mail->box), _mail->uid);
maildir_uidlist_set_ext(mbox->uidlist, _mail->uid,
MAILDIR_UIDLIST_REC_EXT_GUID, NULL);
}
/* default to base filename: */
case MAIL_FETCH_UIDL_FILE_NAME:
if (mail->data.guid != NULL) {
*value_r = mail->data.guid;
return 0;
}
if (fname != NULL) {
/* we came here from MAIL_FETCH_GUID,
avoid a second lookup */
} else if (!_mail->saving) {
if (maildir_mail_get_fname(mbox, _mail, &fname) <= 0)
return -1;
} else {
path = maildir_save_file_get_path(_mail->transaction,
_mail->seq);
fname = strrchr(path, '/');
fname = fname != NULL ? fname + 1 : path;
}
end = strchr(fname, MAILDIR_INFO_SEP);
mail->data.guid = end == NULL ?
p_strdup(mail->data_pool, fname) :
p_strdup_until(mail->data_pool, fname, end);
*value_r = mail->data.guid;
return 0;
case MAIL_FETCH_UIDL_BACKEND:
uidl = maildir_uidlist_lookup_ext(mbox->uidlist, _mail->uid,
MAILDIR_UIDLIST_REC_EXT_POP3_UIDL);
if (uidl == NULL) {
/* use the default */
*value_r = "";
} else if (*uidl == '\0') {
/* special optimization case: use the base file name */
return maildir_mail_get_special(_mail,
MAIL_FETCH_UIDL_FILE_NAME, value_r);
} else {
*value_r = p_strdup(mail->data_pool, uidl);
}
return 0;
case MAIL_FETCH_POP3_ORDER:
order = maildir_uidlist_lookup_ext(mbox->uidlist, _mail->uid,
MAILDIR_UIDLIST_REC_EXT_POP3_ORDER);
if (order == NULL) {
*value_r = "";
} else {
*value_r = p_strdup(mail->data_pool, order);
}
return 0;
default:
return index_mail_get_special(_mail, field, value_r);
}
}
static int
maildir_mail_get_stream(struct mail *_mail, bool get_body ATTR_UNUSED,
struct message_size *hdr_size,
struct message_size *body_size,
struct istream **stream_r)
{
struct index_mail *mail = (struct index_mail *)_mail;
struct maildir_mailbox *mbox = (struct maildir_mailbox *)_mail->box;
struct index_mail_data *data = &mail->data;
bool deleted;
if (data->stream == NULL) {
data->stream = maildir_open_mail(mbox, _mail, &deleted);
if (data->stream == NULL) {
if (deleted)
mail_set_expunged(_mail);
return -1;
}
if (mail->mail.v.istream_opened != NULL) {
if (mail->mail.v.istream_opened(_mail,
&data->stream) < 0)
return -1;
}
}
return index_mail_init_stream(mail, hdr_size, body_size, stream_r);
}
static void maildir_update_pop3_uidl(struct mail *_mail, const char *uidl)
{
struct maildir_mailbox *mbox = (struct maildir_mailbox *)_mail->box;
const char *fname;
if (maildir_mail_get_special(_mail, MAIL_FETCH_UIDL_FILE_NAME,
&fname) == 0 &&
strcmp(uidl, fname) == 0) {
/* special case optimization: empty UIDL means the same
as base filename */
uidl = "";
}
maildir_uidlist_set_ext(mbox->uidlist, _mail->uid,
MAILDIR_UIDLIST_REC_EXT_POP3_UIDL, uidl);
}
static void maildir_mail_remove_sizes_from_uidlist(struct mail *mail)
{
struct maildir_mailbox *mbox = (struct maildir_mailbox *)mail->box;
if (maildir_uidlist_lookup_ext(mbox->uidlist, mail->uid,
MAILDIR_UIDLIST_REC_EXT_VSIZE) != NULL) {
maildir_uidlist_set_ext(mbox->uidlist, mail->uid,
MAILDIR_UIDLIST_REC_EXT_VSIZE, NULL);
}
if (maildir_uidlist_lookup_ext(mbox->uidlist, mail->uid,
MAILDIR_UIDLIST_REC_EXT_PSIZE) != NULL) {
maildir_uidlist_set_ext(mbox->uidlist, mail->uid,
MAILDIR_UIDLIST_REC_EXT_PSIZE, NULL);
}
}
static int
do_fix_size(struct maildir_mailbox *mbox, const char *path,
const char *wrong_key_p)
{
const char *fname, *newpath, *extra, *info, *dir;
fname = strrchr(path, '/');
i_assert(fname != NULL);
dir = t_strdup_until(path, fname++);
extra = strchr(fname, MAILDIR_EXTRA_SEP);
i_assert(extra != NULL);
info = strchr(fname, MAILDIR_INFO_SEP);
if (info == NULL) info = "";
newpath = t_strdup_printf("%s/%s%s", dir,
t_strdup_until(fname, extra), info);
if (rename(path, newpath) == 0) {
mail_storage_set_critical(mbox->box.storage,
"Maildir filename has wrong %c value, "
"renamed the file from %s to %s",
*wrong_key_p, path, newpath);
return 1;
}
if (errno == ENOENT)
return 0;
mail_storage_set_critical(&mbox->storage->storage,
"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 (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_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,
maildir_mail_get_special,
index_mail_get_real_mail,
index_mail_update_flags,
index_mail_update_keywords,
index_mail_update_modseq,
maildir_update_pop3_uidl,
index_mail_expunge,
maildir_mail_set_cache_corrupted,
index_mail_opened
};