maildir-mail.c revision f6f021c133f680cf3d559187524fd9abcbaae9b9
bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2003-2010 Dovecot authors, see the included COPYING file */
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen#include "lib.h"
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen#include "istream.h"
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen#include "index-mail.h"
ea5f188fc29dfaa0c4071e6413e16e1d04263722Timo Sirainen#include "maildir-storage.h"
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen#include "maildir-filename.h"
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen#include "maildir-uidlist.h"
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen#include "maildir-sync.h"
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen
63a61b7a739ae0f3f520215137d9c50f94d0f34fTimo Sirainen#include <stdlib.h>
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen#include <fcntl.h>
18565c69efcd7db003dbf27cf625ed822e889fb1Timo Sirainen#include <unistd.h>
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen#include <sys/stat.h>
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainenstruct maildir_open_context {
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen int fd;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen char *path;
d22301419109ed4a38351715e6760011421dadecTimo Sirainen};
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen
c150beda11da6fbbb1a936829550945d5e884f68Josef 'Jeff' Sipekstatic int
c150beda11da6fbbb1a936829550945d5e884f68Josef 'Jeff' Sipekdo_open(struct maildir_mailbox *mbox, const char *path,
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen struct maildir_open_context *ctx)
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen{
86c6b2546b0bbfce326583f14d05f59674a6d861Timo Sirainen ctx->fd = open(path, O_RDONLY);
86c6b2546b0bbfce326583f14d05f59674a6d861Timo Sirainen if (ctx->fd != -1) {
b66d803de86bfb411165b3465b0d9ef64ecfe2a1Timo Sirainen ctx->path = i_strdup(path);
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen return 1;
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen }
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen if (errno == ENOENT)
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen return 0;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen if (errno == EACCES) {
d22301419109ed4a38351715e6760011421dadecTimo Sirainen mail_storage_set_critical(&mbox->storage->storage, "%s",
c150beda11da6fbbb1a936829550945d5e884f68Josef 'Jeff' Sipek mail_error_eacces_msg("open", path));
c150beda11da6fbbb1a936829550945d5e884f68Josef 'Jeff' Sipek } else {
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen mail_storage_set_critical(&mbox->storage->storage,
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen "open(%s) failed: %m", path);
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen }
01cbf4ac5d44137ab434791be7f838d98d0fcf3bTimo Sirainen return -1;
d22301419109ed4a38351715e6760011421dadecTimo Sirainen}
4b41116563110d00330896a568eff1078c382827Timo Sirainen
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainenstatic int
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainendo_stat(struct maildir_mailbox *mbox, const char *path, struct stat *st)
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen{
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen if (stat(path, st) == 0)
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen return 1;
7204b8112e005ff81dcf628f7880ef1feed1effeTimo Sirainen if (errno == ENOENT)
ebe6df72f1309135f02b6a4d2aef1e81a073f91cTimo Sirainen return 0;
b12a6d0e54318273acf0d0fb8b3f4c29f67b62b0Timo Sirainen
b12a6d0e54318273acf0d0fb8b3f4c29f67b62b0Timo Sirainen if (errno == EACCES) {
b12a6d0e54318273acf0d0fb8b3f4c29f67b62b0Timo Sirainen mail_storage_set_critical(&mbox->storage->storage, "%s",
b12a6d0e54318273acf0d0fb8b3f4c29f67b62b0Timo Sirainen mail_error_eacces_msg("stat", path));
b12a6d0e54318273acf0d0fb8b3f4c29f67b62b0Timo Sirainen } else {
b12a6d0e54318273acf0d0fb8b3f4c29f67b62b0Timo Sirainen mail_storage_set_critical(&mbox->storage->storage,
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen "stat(%s) failed: %m", path);
73247459cf41eb1e5ae5bc61354db46d3b05ee75Timo Sirainen }
73247459cf41eb1e5ae5bc61354db46d3b05ee75Timo Sirainen return -1;
d22301419109ed4a38351715e6760011421dadecTimo Sirainen}
73247459cf41eb1e5ae5bc61354db46d3b05ee75Timo Sirainen
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainenstatic struct istream *
86c6b2546b0bbfce326583f14d05f59674a6d861Timo Sirainenmaildir_open_mail(struct maildir_mailbox *mbox, struct mail *mail,
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen bool *deleted_r)
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen{
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen struct mail_private *p = (struct mail_private *)mail;
86c6b2546b0bbfce326583f14d05f59674a6d861Timo Sirainen struct istream *input;
86c6b2546b0bbfce326583f14d05f59674a6d861Timo Sirainen const char *path;
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen struct maildir_open_context ctx;
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen *deleted_r = FALSE;
d22301419109ed4a38351715e6760011421dadecTimo Sirainen
1f1ee8db68d9ae1604350801cd8dc33ebe29fe8aTimo Sirainen ctx.fd = -1;
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen ctx.path = NULL;
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen p->stats_open_lookup_count++;
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen if (!mail->saving) {
86c6b2546b0bbfce326583f14d05f59674a6d861Timo Sirainen if (maildir_file_do(mbox, mail->uid, do_open, &ctx) < 0)
73247459cf41eb1e5ae5bc61354db46d3b05ee75Timo Sirainen return NULL;
73247459cf41eb1e5ae5bc61354db46d3b05ee75Timo Sirainen } else {
73247459cf41eb1e5ae5bc61354db46d3b05ee75Timo Sirainen path = maildir_save_file_get_path(mail->transaction, mail->seq);
73247459cf41eb1e5ae5bc61354db46d3b05ee75Timo Sirainen if (do_open(mbox, path, &ctx) <= 0)
86c6b2546b0bbfce326583f14d05f59674a6d861Timo Sirainen return NULL;
73247459cf41eb1e5ae5bc61354db46d3b05ee75Timo Sirainen }
d30da25fb6be1f1c667d93767c9194000194b618Timo Sirainen
d30da25fb6be1f1c667d93767c9194000194b618Timo Sirainen if (ctx.fd == -1) {
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen *deleted_r = TRUE;
597dce34068d603fb759b4dff404b34049213e51Timo Sirainen return NULL;
63a61b7a739ae0f3f520215137d9c50f94d0f34fTimo Sirainen }
cd83124e5d070a016c590bb0b1096d7828c7b6adTimo Sirainen
d22301419109ed4a38351715e6760011421dadecTimo Sirainen input = i_stream_create_fd(ctx.fd, 0, TRUE);
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen if (input->stream_errno == EISDIR) {
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen i_stream_destroy(&input);
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen if (maildir_lose_unexpected_dir(&mbox->storage->storage,
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen ctx.path) >= 0)
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen *deleted_r = TRUE;
4b41116563110d00330896a568eff1078c382827Timo Sirainen } else {
d22301419109ed4a38351715e6760011421dadecTimo Sirainen i_stream_set_name(input, ctx.path);
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen index_mail_set_read_buffer_size(mail, input);
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen }
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen i_free(ctx.path);
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen return input;
6060b7c8edf8fce73470d0df6a2479b69b01c537Timo Sirainen}
7f773564b94e6054a40d3785cb63c29f1e4d4deeTimo Sirainen
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainenstatic int maildir_mail_stat(struct mail *mail, struct stat *st)
d4002fe1f64d25a792f76fb102ef7dc519cd4e24Martti Rannanjärvi{
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen struct maildir_mailbox *mbox = (struct maildir_mailbox *)mail->box;
4b41116563110d00330896a568eff1078c382827Timo Sirainen struct index_mail *imail = (struct index_mail *)mail;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen const struct stat *stp;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen const char *path;
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen int ret;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
87490012895b4f371635ded00add04c9107dcfefJosef 'Jeff' Sipek if (mail->lookup_abort == MAIL_LOOKUP_ABORT_NOT_IN_CACHE)
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen return mail_set_aborted(mail);
c150beda11da6fbbb1a936829550945d5e884f68Josef 'Jeff' Sipek
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen if (imail->data.access_part != 0 && imail->data.stream == NULL) {
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen /* we're going to open the mail anyway */
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen struct istream *input;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
4b41116563110d00330896a568eff1078c382827Timo Sirainen (void)mail_get_stream(mail, NULL, NULL, &input);
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen }
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen if (imail->data.stream != NULL) {
345212e8f61ebf14ff4f80df26df9e655eb5121eTimo Sirainen imail->mail.stats_fstat_lookup_count++;
345212e8f61ebf14ff4f80df26df9e655eb5121eTimo Sirainen stp = i_stream_stat(imail->data.stream, FALSE);
345212e8f61ebf14ff4f80df26df9e655eb5121eTimo Sirainen if (stp == NULL)
345212e8f61ebf14ff4f80df26df9e655eb5121eTimo Sirainen return -1;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen *st = *stp;
345212e8f61ebf14ff4f80df26df9e655eb5121eTimo Sirainen } else if (!mail->saving) {
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen imail->mail.stats_stat_lookup_count++;
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen ret = maildir_file_do(mbox, mail->uid, do_stat, st);
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen if (ret <= 0) {
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen if (ret == 0)
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen mail_set_expunged(mail);
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen return -1;
87490012895b4f371635ded00add04c9107dcfefJosef 'Jeff' Sipek }
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen } else {
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen imail->mail.stats_stat_lookup_count++;
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen path = maildir_save_file_get_path(mail->transaction, mail->seq);
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen if (stat(path, st) < 0) {
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen mail_storage_set_critical(mail->box->storage,
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen "stat(%s) failed: %m", path);
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen return -1;
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen }
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen }
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen return 0;
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen}
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainenstatic int maildir_mail_get_received_date(struct mail *_mail, time_t *date_r)
915bb1572a406d30013ed3ee83fba7082a6d1baePhil Carmody{
5daa12cc1c862eec4f63df42227812d3514da2ccTimo Sirainen struct index_mail *mail = (struct index_mail *)_mail;
5daa12cc1c862eec4f63df42227812d3514da2ccTimo Sirainen struct index_mail_data *data = &mail->data;
fc22ecbb03396eda9270472446a6065a986a43e0Timo Sirainen struct stat st;
5daa12cc1c862eec4f63df42227812d3514da2ccTimo Sirainen
5daa12cc1c862eec4f63df42227812d3514da2ccTimo Sirainen if (index_mail_get_received_date(_mail, date_r) == 0)
c150beda11da6fbbb1a936829550945d5e884f68Josef 'Jeff' Sipek return 0;
5daa12cc1c862eec4f63df42227812d3514da2ccTimo Sirainen
5daa12cc1c862eec4f63df42227812d3514da2ccTimo Sirainen if (maildir_mail_stat(_mail, &st) < 0)
e6aa82aeb50948cb47a45a1b61a9c16d6a162388Timo Sirainen return -1;
e6aa82aeb50948cb47a45a1b61a9c16d6a162388Timo Sirainen
fc22ecbb03396eda9270472446a6065a986a43e0Timo Sirainen *date_r = data->received_date = st.st_mtime;
e6aa82aeb50948cb47a45a1b61a9c16d6a162388Timo Sirainen return 0;
bf9402875418faf11825cf11fbe06326b6086e3dTimo Sirainen}
fc22ecbb03396eda9270472446a6065a986a43e0Timo Sirainen
fc22ecbb03396eda9270472446a6065a986a43e0Timo Sirainenstatic int maildir_mail_get_save_date(struct mail *_mail, time_t *date_r)
5daa12cc1c862eec4f63df42227812d3514da2ccTimo Sirainen{
5f44975ec6c5755dd74bcd4c47a123a7242ecab3Timo Sirainen struct index_mail *mail = (struct index_mail *)_mail;
bf9402875418faf11825cf11fbe06326b6086e3dTimo Sirainen struct index_mail_data *data = &mail->data;
bf9402875418faf11825cf11fbe06326b6086e3dTimo Sirainen struct stat st;
fc22ecbb03396eda9270472446a6065a986a43e0Timo Sirainen
fc22ecbb03396eda9270472446a6065a986a43e0Timo Sirainen if (index_mail_get_save_date(_mail, date_r) == 0)
fc22ecbb03396eda9270472446a6065a986a43e0Timo Sirainen return 0;
fc22ecbb03396eda9270472446a6065a986a43e0Timo Sirainen
5daa12cc1c862eec4f63df42227812d3514da2ccTimo Sirainen if (maildir_mail_stat(_mail, &st) < 0)
fc22ecbb03396eda9270472446a6065a986a43e0Timo Sirainen return -1;
5daa12cc1c862eec4f63df42227812d3514da2ccTimo Sirainen
5daa12cc1c862eec4f63df42227812d3514da2ccTimo Sirainen *date_r = data->save_date = st.st_ctime;
5daa12cc1c862eec4f63df42227812d3514da2ccTimo Sirainen return 0;
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen}
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainenstatic int
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainenmaildir_mail_get_fname(struct maildir_mailbox *mbox, struct mail *mail,
87490012895b4f371635ded00add04c9107dcfefJosef 'Jeff' Sipek const char **fname_r)
c150beda11da6fbbb1a936829550945d5e884f68Josef 'Jeff' Sipek{
f140f88a5ab3e2194f214c11f9f418559e949c83Timo Sirainen enum maildir_uidlist_rec_flag flags;
36f4f01d56ec9156ab75bc2047a8388192df3178Timo Sirainen struct mail_index_view *view;
fc22ecbb03396eda9270472446a6065a986a43e0Timo Sirainen uint32_t seq;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen bool exists;
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen int ret;
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen
4b41116563110d00330896a568eff1078c382827Timo Sirainen ret = maildir_uidlist_lookup(mbox->uidlist, mail->uid, &flags, fname_r);
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen if (ret != 0)
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen return ret;
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen /* file exists in index file, but not in dovecot-uidlist anymore. */
ee3e01f75b1db691bf20dd4e2558965421b8f937Timo Sirainen mail_set_expunged(mail);
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen
fc22ecbb03396eda9270472446a6065a986a43e0Timo Sirainen /* one reason this could happen is if we delayed opening
fc22ecbb03396eda9270472446a6065a986a43e0Timo Sirainen dovecot-uidlist and we're trying to open a mail that got recently
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen expunged. Let's test this theory first: */
ea5f188fc29dfaa0c4071e6413e16e1d04263722Timo Sirainen (void)mail_index_refresh(mbox->box.index);
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen view = mail_index_view_open(mbox->box.index);
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen exists = mail_index_lookup_seq(view, mail->uid, &seq);
36f4f01d56ec9156ab75bc2047a8388192df3178Timo Sirainen mail_index_view_close(&view);
36f4f01d56ec9156ab75bc2047a8388192df3178Timo Sirainen
36f4f01d56ec9156ab75bc2047a8388192df3178Timo Sirainen if (exists) {
36f4f01d56ec9156ab75bc2047a8388192df3178Timo Sirainen /* the message still exists in index. this means there's some
36f4f01d56ec9156ab75bc2047a8388192df3178Timo Sirainen kind of a desync, which doesn't get fixed if cur/ mtime is
36f4f01d56ec9156ab75bc2047a8388192df3178Timo Sirainen the same as in index. fix this by forcing a resync. */
36f4f01d56ec9156ab75bc2047a8388192df3178Timo Sirainen (void)maildir_storage_sync_force(mbox, mail->uid);
36f4f01d56ec9156ab75bc2047a8388192df3178Timo Sirainen }
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen return 0;
f140f88a5ab3e2194f214c11f9f418559e949c83Timo Sirainen}
f140f88a5ab3e2194f214c11f9f418559e949c83Timo Sirainen
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainenstatic int maildir_get_pop3_state(struct index_mail *mail)
36f4f01d56ec9156ab75bc2047a8388192df3178Timo Sirainen{
cbcde6379f1b0b27bdefc4b11eec93ad69e459d4Timo Sirainen struct mailbox *box = mail->mail.mail.box;
cbcde6379f1b0b27bdefc4b11eec93ad69e459d4Timo Sirainen struct index_mailbox_context *ibox = INDEX_STORAGE_CONTEXT(box);
cbcde6379f1b0b27bdefc4b11eec93ad69e459d4Timo Sirainen const struct mail_cache_field *fields;
cbcde6379f1b0b27bdefc4b11eec93ad69e459d4Timo Sirainen unsigned int i, count, psize_idx, vsize_idx;
cbcde6379f1b0b27bdefc4b11eec93ad69e459d4Timo Sirainen enum mail_cache_decision_type dec, vsize_dec;
cbcde6379f1b0b27bdefc4b11eec93ad69e459d4Timo Sirainen enum mail_fetch_field allowed_pop3_fields;
f140f88a5ab3e2194f214c11f9f418559e949c83Timo Sirainen bool not_pop3_only = FALSE;
5daa12cc1c862eec4f63df42227812d3514da2ccTimo Sirainen
fc22ecbb03396eda9270472446a6065a986a43e0Timo Sirainen if (mail->pop3_state_set)
e48c10b9db945fd72e2315e3ec343174fa55c7c7Timo Sirainen return mail->pop3_state;
e48c10b9db945fd72e2315e3ec343174fa55c7c7Timo Sirainen
5daa12cc1c862eec4f63df42227812d3514da2ccTimo Sirainen /* if this mail itself has non-pop3 fields we know we're not
5daa12cc1c862eec4f63df42227812d3514da2ccTimo Sirainen pop3-only */
fc22ecbb03396eda9270472446a6065a986a43e0Timo Sirainen allowed_pop3_fields = MAIL_FETCH_FLAGS | MAIL_FETCH_STREAM_HEADER |
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen MAIL_FETCH_STREAM_BODY | MAIL_FETCH_UIDL_FILE_NAME |
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen MAIL_FETCH_VIRTUAL_SIZE;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen if (mail->wanted_headers != NULL ||
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen (mail->wanted_fields & ~allowed_pop3_fields) != 0)
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen not_pop3_only = TRUE;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
915bb1572a406d30013ed3ee83fba7082a6d1baePhil Carmody /* get vsize decisions */
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen psize_idx = ibox->cache_fields[MAIL_CACHE_PHYSICAL_FULL_SIZE].idx;
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen vsize_idx = ibox->cache_fields[MAIL_CACHE_VIRTUAL_FULL_SIZE].idx;
c150beda11da6fbbb1a936829550945d5e884f68Josef 'Jeff' Sipek if (not_pop3_only) {
54d42552005111841ab45ec9ca7559075fabd5dfTimo Sirainen vsize_dec = mail_cache_field_get_decision(box->cache,
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen vsize_idx);
54d42552005111841ab45ec9ca7559075fabd5dfTimo Sirainen vsize_dec &= ~MAIL_CACHE_DECISION_FORCED;
54d42552005111841ab45ec9ca7559075fabd5dfTimo Sirainen } else {
5abb33fdc94c081ccd3213bf7d0fa9d0367b4bfdTimo Sirainen /* also check if there are any non-[pv]size cached fields */
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen vsize_dec = MAIL_CACHE_DECISION_NO;
7bd301fdbfefe7cef3576d19ece29c75ebe53bafTimo Sirainen fields = mail_cache_register_get_list(box->cache,
7bd301fdbfefe7cef3576d19ece29c75ebe53bafTimo Sirainen pool_datastack_create(),
cd83124e5d070a016c590bb0b1096d7828c7b6adTimo Sirainen &count);
54d42552005111841ab45ec9ca7559075fabd5dfTimo Sirainen for (i = 0; i < count; i++) {
54d42552005111841ab45ec9ca7559075fabd5dfTimo Sirainen dec = fields[i].decision & ~MAIL_CACHE_DECISION_FORCED;
5abb33fdc94c081ccd3213bf7d0fa9d0367b4bfdTimo Sirainen if (fields[i].idx == vsize_idx)
54d42552005111841ab45ec9ca7559075fabd5dfTimo Sirainen vsize_dec = dec;
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen else if (dec != MAIL_CACHE_DECISION_NO &&
54d42552005111841ab45ec9ca7559075fabd5dfTimo Sirainen fields[i].idx != psize_idx)
8ed8c821ba8aab0b4ed0375f87d48737ef0e0d8eTimo Sirainen not_pop3_only = TRUE;
690bafa70767e3f6e98bbfd62ad4a26be2387ea9Timo Sirainen }
690bafa70767e3f6e98bbfd62ad4a26be2387ea9Timo Sirainen }
8ed8c821ba8aab0b4ed0375f87d48737ef0e0d8eTimo Sirainen
690bafa70767e3f6e98bbfd62ad4a26be2387ea9Timo Sirainen if (!not_pop3_only) {
690bafa70767e3f6e98bbfd62ad4a26be2387ea9Timo Sirainen /* either nothing is cached, or only vsize is cached. */
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen mail->pop3_state = 1;
d22301419109ed4a38351715e6760011421dadecTimo Sirainen } else if (vsize_dec != MAIL_CACHE_DECISION_YES &&
54d42552005111841ab45ec9ca7559075fabd5dfTimo Sirainen (box->flags & MAILBOX_FLAG_POP3_SESSION) == 0) {
54d42552005111841ab45ec9ca7559075fabd5dfTimo Sirainen /* if virtual size isn't cached permanently,
54d42552005111841ab45ec9ca7559075fabd5dfTimo Sirainen POP3 isn't being used */
54d42552005111841ab45ec9ca7559075fabd5dfTimo Sirainen mail->pop3_state = -1;
767cd7e92a46ca7c0dc4823936750b2bf2eb99e3Timo Sirainen } else {
767cd7e92a46ca7c0dc4823936750b2bf2eb99e3Timo Sirainen /* possibly a mixed pop3/imap */
767cd7e92a46ca7c0dc4823936750b2bf2eb99e3Timo Sirainen mail->pop3_state = 0;
767cd7e92a46ca7c0dc4823936750b2bf2eb99e3Timo Sirainen }
767cd7e92a46ca7c0dc4823936750b2bf2eb99e3Timo Sirainen mail->pop3_state_set = TRUE;
767cd7e92a46ca7c0dc4823936750b2bf2eb99e3Timo Sirainen return mail->pop3_state;
767cd7e92a46ca7c0dc4823936750b2bf2eb99e3Timo Sirainen}
767cd7e92a46ca7c0dc4823936750b2bf2eb99e3Timo Sirainen
767cd7e92a46ca7c0dc4823936750b2bf2eb99e3Timo Sirainenstatic int maildir_quick_size_lookup(struct index_mail *mail, bool vsize,
54d42552005111841ab45ec9ca7559075fabd5dfTimo Sirainen uoff_t *size_r)
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen{
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen struct mail *_mail = &mail->mail.mail;
690bafa70767e3f6e98bbfd62ad4a26be2387ea9Timo Sirainen struct maildir_mailbox *mbox = (struct maildir_mailbox *)_mail->box;
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen enum maildir_uidlist_rec_ext_key key;
54d42552005111841ab45ec9ca7559075fabd5dfTimo Sirainen const char *path, *fname, *value;
54d42552005111841ab45ec9ca7559075fabd5dfTimo Sirainen
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen if (!_mail->saving) {
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen if (maildir_mail_get_fname(mbox, _mail, &fname) <= 0)
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen return -1;
d67fde1a8ebc1d85704c5986d8f93aae97eccef3Timo Sirainen } else {
87490012895b4f371635ded00add04c9107dcfefJosef 'Jeff' Sipek path = maildir_save_file_get_path(_mail->transaction,
d67fde1a8ebc1d85704c5986d8f93aae97eccef3Timo Sirainen _mail->seq);
c150beda11da6fbbb1a936829550945d5e884f68Josef 'Jeff' Sipek fname = strrchr(path, '/');
aa215ab623706463cea1d047f975ffe51d3f0c05Timo Sirainen fname = fname != NULL ? fname + 1 : path;
aa215ab623706463cea1d047f975ffe51d3f0c05Timo Sirainen }
a5c8dc283ef673fcdae158513b8032e74b45f59aTimo Sirainen
d67fde1a8ebc1d85704c5986d8f93aae97eccef3Timo Sirainen /* size can be included in filename */
aa215ab623706463cea1d047f975ffe51d3f0c05Timo Sirainen if (maildir_filename_get_size(fname,
aa215ab623706463cea1d047f975ffe51d3f0c05Timo Sirainen vsize ? MAILDIR_EXTRA_VIRTUAL_SIZE :
aa215ab623706463cea1d047f975ffe51d3f0c05Timo Sirainen MAILDIR_EXTRA_FILE_SIZE,
aa215ab623706463cea1d047f975ffe51d3f0c05Timo Sirainen size_r))
a5c8dc283ef673fcdae158513b8032e74b45f59aTimo Sirainen return 1;
aa215ab623706463cea1d047f975ffe51d3f0c05Timo Sirainen
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen /* size can be included in uidlist entry */
a1808be0774cbcb28fec45341aabf803ec44bae5Timo Sirainen if (!_mail->saving) {
d67fde1a8ebc1d85704c5986d8f93aae97eccef3Timo Sirainen key = vsize ? MAILDIR_UIDLIST_REC_EXT_VSIZE :
3063bd8ff05d3d8cd33156f4366b36890e501436Timo Sirainen MAILDIR_UIDLIST_REC_EXT_PSIZE;
d4002fe1f64d25a792f76fb102ef7dc519cd4e24Martti Rannanjärvi value = maildir_uidlist_lookup_ext(mbox->uidlist, _mail->uid,
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen key);
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen if (value != NULL && str_to_uoff(value, size_r) == 0)
1b5366b2234892f8930a29351da06b193e385150Timo Sirainen return 1;
1b5366b2234892f8930a29351da06b193e385150Timo Sirainen }
1b5366b2234892f8930a29351da06b193e385150Timo Sirainen return 0;
5abb33fdc94c081ccd3213bf7d0fa9d0367b4bfdTimo Sirainen}
1b5366b2234892f8930a29351da06b193e385150Timo Sirainen
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainenstatic void
1b5366b2234892f8930a29351da06b193e385150Timo Sirainenmaildir_handle_size_caching(struct index_mail *mail, bool quick_check,
1b5366b2234892f8930a29351da06b193e385150Timo Sirainen bool vsize)
1b5366b2234892f8930a29351da06b193e385150Timo Sirainen{
3063bd8ff05d3d8cd33156f4366b36890e501436Timo Sirainen struct mailbox *box = mail->mail.mail.box;
3063bd8ff05d3d8cd33156f4366b36890e501436Timo Sirainen struct maildir_mailbox *mbox = (struct maildir_mailbox *)box;
d4002fe1f64d25a792f76fb102ef7dc519cd4e24Martti Rannanjärvi enum mail_fetch_field field;
3063bd8ff05d3d8cd33156f4366b36890e501436Timo Sirainen uoff_t size;
3063bd8ff05d3d8cd33156f4366b36890e501436Timo Sirainen int pop3_state;
d67fde1a8ebc1d85704c5986d8f93aae97eccef3Timo Sirainen
aa215ab623706463cea1d047f975ffe51d3f0c05Timo Sirainen field = vsize ? MAIL_FETCH_VIRTUAL_SIZE : MAIL_FETCH_PHYSICAL_SIZE;
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen if ((mail->data.dont_cache_fetch_fields & field) != 0)
a5c8dc283ef673fcdae158513b8032e74b45f59aTimo Sirainen return;
a5c8dc283ef673fcdae158513b8032e74b45f59aTimo Sirainen
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen if (quick_check && maildir_quick_size_lookup(mail, vsize, &size) > 0) {
d67fde1a8ebc1d85704c5986d8f93aae97eccef3Timo Sirainen /* already in filename / uidlist. don't add it anywhere,
d67fde1a8ebc1d85704c5986d8f93aae97eccef3Timo Sirainen including to the uidlist if it's already in filename.
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen do some extra checks here to catch potential cache bugs. */
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen if (vsize && mail->data.virtual_size != size) {
c150beda11da6fbbb1a936829550945d5e884f68Josef 'Jeff' Sipek mail_cache_set_corrupted(box->cache,
b2ecd50bb98c44816cb07c17aa17fae2b425f941Timo Sirainen "Corrupted virtual size for uid=%u: "
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen "%"PRIuUOFF_T" != %"PRIuUOFF_T,
5abb33fdc94c081ccd3213bf7d0fa9d0367b4bfdTimo Sirainen mail->mail.mail.uid,
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen mail->data.virtual_size, size);
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen mail->data.virtual_size = size;
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen } else if (!vsize && mail->data.physical_size != size) {
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen mail_cache_set_corrupted(box->cache,
5abb33fdc94c081ccd3213bf7d0fa9d0367b4bfdTimo Sirainen "Corrupted physical size for uid=%u: "
5abb33fdc94c081ccd3213bf7d0fa9d0367b4bfdTimo Sirainen "%"PRIuUOFF_T" != %"PRIuUOFF_T,
4b41116563110d00330896a568eff1078c382827Timo Sirainen mail->mail.mail.uid,
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen mail->data.physical_size, size);
5abb33fdc94c081ccd3213bf7d0fa9d0367b4bfdTimo Sirainen mail->data.physical_size = size;
5abb33fdc94c081ccd3213bf7d0fa9d0367b4bfdTimo Sirainen }
f480b30abdddf6f1beb8a2c5b1ce4bf8999400dbTimo Sirainen mail->data.dont_cache_fetch_fields |= field;
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen return;
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen }
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen /* 1 = pop3-only, 0 = mixed, -1 = no pop3 */
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen pop3_state = maildir_get_pop3_state(mail);
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen if (pop3_state >= 0 && mail->mail.mail.uid != 0) {
3063bd8ff05d3d8cd33156f4366b36890e501436Timo Sirainen /* if size is wanted permanently, store it to uidlist
d4002fe1f64d25a792f76fb102ef7dc519cd4e24Martti Rannanjärvi so that in case cache file gets lost we can get it quickly */
d4002fe1f64d25a792f76fb102ef7dc519cd4e24Martti Rannanjärvi mail->data.dont_cache_fetch_fields |= field;
3063bd8ff05d3d8cd33156f4366b36890e501436Timo Sirainen size = vsize ? mail->data.virtual_size :
3063bd8ff05d3d8cd33156f4366b36890e501436Timo Sirainen mail->data.physical_size;
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen maildir_uidlist_set_ext(mbox->uidlist, mail->mail.mail.uid,
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen vsize ? MAILDIR_UIDLIST_REC_EXT_VSIZE :
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen MAILDIR_UIDLIST_REC_EXT_PSIZE,
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen dec2str(size));
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen }
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen}
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainenstatic int maildir_mail_get_virtual_size(struct mail *_mail, uoff_t *size_r)
8f017a40470ef2f4b530000d947a8bce44350a5eTimo Sirainen{
59151b71059df1190acd75d8717ed04a7920c862Timo Sirainen struct index_mail *mail = (struct index_mail *)_mail;
677b75f90d81eafe742896d6570a2f63ce501d05Josef 'Jeff' Sipek struct index_mail_data *data = &mail->data;
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen struct message_size hdr_size, body_size;
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen struct istream *input;
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen uoff_t old_offset;
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen
6df0ab0c1ab91f06b6418cb30eff44405a1b8f02Timo Sirainen if (index_mail_get_cached_virtual_size(mail, size_r)) {
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen i_assert(mail->data.virtual_size != (uoff_t)-1);
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen maildir_handle_size_caching(mail, TRUE, TRUE);
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen return 0;
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen }
87490012895b4f371635ded00add04c9107dcfefJosef 'Jeff' Sipek
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen if (maildir_quick_size_lookup(mail, TRUE, &data->virtual_size) < 0)
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen return -1;
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen if (data->virtual_size != (uoff_t)-1) {
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen data->dont_cache_fetch_fields |= MAIL_FETCH_VIRTUAL_SIZE;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen *size_r = data->virtual_size;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen return 0;
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen }
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen /* fallback to reading the file */
7631f16156aca373004953fe6b01a7f343fb47e0Timo Sirainen old_offset = data->stream == NULL ? 0 : data->stream->v_offset;
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen if (mail_get_stream(_mail, &hdr_size, &body_size, &input) < 0)
87490012895b4f371635ded00add04c9107dcfefJosef 'Jeff' Sipek return -1;
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen i_stream_seek(data->stream, old_offset);
7631f16156aca373004953fe6b01a7f343fb47e0Timo Sirainen
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen maildir_handle_size_caching(mail, FALSE, TRUE);
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen *size_r = data->virtual_size;
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen return 0;
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen}
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen
87490012895b4f371635ded00add04c9107dcfefJosef 'Jeff' Sipekstatic int maildir_mail_get_physical_size(struct mail *_mail, uoff_t *size_r)
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen{
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen struct index_mail *mail = (struct index_mail *)_mail;
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen struct maildir_mailbox *mbox = (struct maildir_mailbox *)_mail->box;
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen struct index_mail_data *data = &mail->data;
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen struct stat st;
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen const char *path;
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen int ret;
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen
0d86aa0d47f7393c669c084b34c0537b193688adTimo Sirainen if (index_mail_get_physical_size(_mail, size_r) == 0) {
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen i_assert(mail->data.physical_size != (uoff_t)-1);
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen maildir_handle_size_caching(mail, TRUE, FALSE);
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen return 0;
aa247243412a49f9bdebf7255e131dc6ece4ed46Timo Sirainen }
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
421d30619384e72a27e2a5d13ff6525aff4d17feTimo Sirainen if (maildir_quick_size_lookup(mail, FALSE, &data->physical_size) < 0)
ecd69c4e8371853667e01b0c16d436ef7f7393e2Timo Sirainen return -1;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen if (data->physical_size != (uoff_t)-1) {
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen data->dont_cache_fetch_fields |= MAIL_FETCH_PHYSICAL_SIZE;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen *size_r = data->physical_size;
a757f31393b9d6fc7760a9dec8363404ab3ae576Timo Sirainen return 0;
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen }
f46885a5b78b15a8d2419f6e5d13b643bd85e41fTimo Sirainen
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen if (!_mail->saving) {
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen ret = maildir_file_do(mbox, _mail->uid, do_stat, &st);
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen if (ret <= 0) {
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen if (ret == 0)
d67fde1a8ebc1d85704c5986d8f93aae97eccef3Timo Sirainen mail_set_expunged(_mail);
d67fde1a8ebc1d85704c5986d8f93aae97eccef3Timo Sirainen return -1;
87460b08cb97b31cde640d4975a6aa2c1d0e7226Timo Sirainen }
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen } else {
87460b08cb97b31cde640d4975a6aa2c1d0e7226Timo Sirainen /* saved mail which hasn't been committed yet */
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen path = maildir_save_file_get_path(_mail->transaction,
306b3f41b05da642d87e7ca7a1496efce9f5902fTimo Sirainen _mail->seq);
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen if (stat(path, &st) < 0) {
21aaa6affb9f134112b75b5db737309fc35ef1cfMartti Rannanjärvi mail_storage_set_critical(_mail->box->storage,
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen "stat(%s) failed: %m", path);
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen return -1;
ad48319996942463675b53877092ab7e13a7a75aTimo Sirainen }
f46885a5b78b15a8d2419f6e5d13b643bd85e41fTimo Sirainen }
225e82df5dd1e765f4e52b80c954558f00e5a7dfTimo Sirainen
838e367716bbd5e44b4a1691db9cbf72af53e9f0Timo Sirainen data->physical_size = st.st_size;
6564208826b0f46a00f010d1b5711d85944c3c88Timo Sirainen maildir_handle_size_caching(mail, FALSE, FALSE);
6de6ec228a41275ddda972d4a554699ea75cd06dTimo Sirainen *size_r = st.st_size;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen return 0;
}
static int
maildir_mail_get_special(struct mail *_mail, enum mail_fetch_field field,
const char **value_r)
{
struct index_mail *mail = (struct index_mail *)_mail;
struct maildir_mailbox *mbox = (struct maildir_mailbox *)_mail->box;
const char *path, *fname = NULL, *end, *guid, *uidl;
switch (field) {
case MAIL_FETCH_GUID:
/* use GUID from uidlist if it exists */
i_assert(!_mail->saving);
/* first make sure that we have a refreshed uidlist */
if (maildir_mail_get_fname(mbox, _mail, &fname) <= 0)
return -1;
guid = maildir_uidlist_lookup_ext(mbox->uidlist, _mail->uid,
MAILDIR_UIDLIST_REC_EXT_GUID);
if (guid != NULL) {
*value_r = guid;
return 0;
}
/* 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 = uidl;
}
return 0;
default:
return index_mail_get_special(_mail, field, value_r);
}
}
static int maildir_mail_get_stream(struct mail *_mail,
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;
}
}
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_set_cache_corrupted(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;
int ret;
if (field == MAIL_FETCH_VIRTUAL_SIZE) {
/* make sure it gets removed from uidlist.
if it's in file name, we can't really do more than log it. */
ret = maildir_uidlist_lookup(mbox->uidlist, _mail->uid,
&flags, &fname);
if (ret <= 0)
return;
if (maildir_filename_get_size(fname, MAILDIR_EXTRA_VIRTUAL_SIZE,
&size)) {
const char *subdir =
(flags & MAILDIR_UIDLIST_REC_FLAG_NEW_DIR) != 0 ?
"new" : "cur";
mail_storage_set_critical(_mail->box->storage,
"Maildir filename has wrong W value: %s/%s/%s",
mbox->box.path, subdir, fname);
} else 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);
}
}
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_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
};