maildir-mail.c revision 236bedf76e31651ea9fca63fbdc25be673819526
2454dfa32c93c20a8522c6ed42fe057baaac9f9aStephan Bosch/* Copyright (c) 2003-2008 Dovecot authors, see the included COPYING file */
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainendo_open(struct maildir_mailbox *mbox, const char *path, int *fd)
4ee00532a265bdfb38539d811fcd12d51210ac35Timo Sirainen mail_storage_set_critical(&mbox->storage->storage,
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainendo_stat(struct maildir_mailbox *mbox, const char *path, struct stat *st)
6789ed17e7ca4021713507baf0dcf6979bb42e0cTimo Sirainen mail_storage_set_critical(&mbox->storage->storage,
67c25cb4af273aff7384d5028d459cc9afdf8712Timo Sirainenstatic struct istream *
67c25cb4af273aff7384d5028d459cc9afdf8712Timo Sirainenmaildir_open_mail(struct maildir_mailbox *mbox, struct mail *mail,
d244c6cadd5f077f5d0f1e00c3652d0108a2d908Timo Sirainen if (maildir_file_do(mbox, mail->uid, do_open, &fd) < 0)
67c25cb4af273aff7384d5028d459cc9afdf8712Timo Sirainen path = maildir_save_file_get_path(mail->transaction, mail->seq);
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen return i_stream_create_fd(fd, MAIL_READ_BLOCK_SIZE, TRUE);
fde0b1793a2842da00eaa105d5e13fec465f0443Timo Sirainenstatic int maildir_mail_stat(struct mail *mail, struct stat *st)
baf1148108b7d9739626b47cc57298c36929586aTimo Sirainen struct maildir_mailbox *mbox = (struct maildir_mailbox *)mail->box;
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen struct index_mail_data *data = &((struct index_mail *)mail)->data;
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen if (data->access_part != 0 && data->stream == NULL) {
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen /* we're going to open the mail anyway */
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen (void)mail_get_stream(mail, NULL, NULL, &input);
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Bosch mail_storage_set_critical(&mbox->storage->storage,
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen "fstat(maildir) failed: %m");
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen ret = maildir_file_do(mbox, mail->uid, do_stat, st);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen path = maildir_save_file_get_path(mail->transaction, mail->seq);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainenstatic int maildir_mail_get_received_date(struct mail *_mail, time_t *date_r)
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen struct index_mail *mail = (struct index_mail *)_mail;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen if (index_mail_get_received_date(_mail, date_r) == 0)
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainenstatic int maildir_mail_get_save_date(struct mail *_mail, time_t *date_r)
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen struct index_mail *mail = (struct index_mail *)_mail;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen if (index_mail_get_save_date(_mail, date_r) == 0)
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainenmaildir_mail_get_fname(struct maildir_mailbox *mbox, struct mail *mail,
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen const char **fname_r)
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen *fname_r = maildir_uidlist_lookup(mbox->uidlist, mail->uid, &flags);
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen /* file exists in index file, but not in dovecot-uidlist anymore. */
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen /* one reason this could happen is if we delayed opening
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen dovecot-uidlist and we're trying to open a mail that got recently
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen expunged. Let's test this theory first: */
e20e638805c4bd54e039891a3e92760b1dfa189aTimo Sirainen view = mail_index_view_open(mbox->ibox.index);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen exists = mail_index_lookup_seq(view, mail->uid, &seq);
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen /* the message still exists in index. this means there's some
e20e638805c4bd54e039891a3e92760b1dfa189aTimo Sirainen kind of a desync, which doesn't get fixed if cur/ mtime is
e20e638805c4bd54e039891a3e92760b1dfa189aTimo Sirainen the same as in index. fix this by forcing a resync. */
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen (void)maildir_storage_sync_force(mbox, mail->uid);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainenstatic int maildir_get_pop3_state(struct index_mail *mail)
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen /* if this mail itself has non-pop3 fields we know we're not
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen allowed_pop3_fields = MAIL_FETCH_FLAGS | MAIL_FETCH_STREAM_HEADER |
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen MAIL_FETCH_STREAM_BODY | MAIL_FETCH_UIDL_FILE_NAME |
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen (mail->wanted_fields & ~allowed_pop3_fields) != 0)
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen /* get vsize decisions */
905951e448e0d0f0778f43ce7673d0cac60b9b61Timo Sirainen psize_idx = mail->ibox->cache_fields[MAIL_CACHE_PHYSICAL_FULL_SIZE].idx;
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen vsize_idx = mail->ibox->cache_fields[MAIL_CACHE_VIRTUAL_FULL_SIZE].idx;
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen vsize_dec = mail_cache_field_get_decision(mail->ibox->cache,
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen /* also check if there are any non-[pv]size cached fields */
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen fields = mail_cache_register_get_list(mail->ibox->cache,
905951e448e0d0f0778f43ce7673d0cac60b9b61Timo Sirainen for (i = 0; i < count; i++) {
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen dec = fields[i].decision & ~MAIL_CACHE_DECISION_FORCED;
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen /* either nothing is cached, or only vsize is cached. */
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen } else if (vsize_dec != MAIL_CACHE_DECISION_YES &&
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen (mail->ibox->open_flags & MAILBOX_OPEN_POP3_SESSION) == 0) {
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen /* if virtual size isn't cached permanently,
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen POP3 isn't being used */
c4b376dd6e0c423006d7ac83a39253bcaf8e7c47Timo Sirainen /* possibly a mixed pop3/imap */
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainenstatic int maildir_quick_size_lookup(struct index_mail *mail, bool vsize,
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen struct maildir_mailbox *mbox = (struct maildir_mailbox *)mail->ibox;
4145aa5025b57ec64418e503c2a5a6bf5a02aec5Timo Sirainen if (!maildir_mail_get_fname(mbox, _mail, &fname))
0dab9cb35a976c49b28a11e28d5570f5191f1a7aMartti Rannanjärvi path = maildir_save_file_get_path(_mail->transaction,
4145aa5025b57ec64418e503c2a5a6bf5a02aec5Timo Sirainen /* size can be included in filename */
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen /* size can be included in uidlist entry */
4145aa5025b57ec64418e503c2a5a6bf5a02aec5Timo Sirainen value = maildir_uidlist_lookup_ext(mbox->uidlist, _mail->uid,
4145aa5025b57ec64418e503c2a5a6bf5a02aec5Timo Sirainen if (*p == '\0') {
cdc5c81463995a153c57c68c299e98cc3de0b287Timo Sirainenmaildir_handle_size_caching(struct index_mail *mail, bool quick_check,
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen struct maildir_mailbox *mbox = (struct maildir_mailbox *)mail->ibox;
4145aa5025b57ec64418e503c2a5a6bf5a02aec5Timo Sirainen field = vsize ? MAIL_FETCH_VIRTUAL_SIZE : MAIL_FETCH_PHYSICAL_SIZE;
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen if ((mail->data.dont_cache_fetch_fields & field) != 0)
4145aa5025b57ec64418e503c2a5a6bf5a02aec5Timo Sirainen if (quick_check && maildir_quick_size_lookup(mail, vsize, &size) > 0) {
4145aa5025b57ec64418e503c2a5a6bf5a02aec5Timo Sirainen /* already in filename / uidlist. don't add it anywhere,
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen including to the uidlist if it's already in filename.
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen do some extra checks here to catch potential cache bugs. */
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen if (vsize && mail->data.virtual_size != size) {
4145aa5025b57ec64418e503c2a5a6bf5a02aec5Timo Sirainen "Corrupted virtual size for uid=%u: "
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen } else if (!vsize && mail->data.physical_size != size) {
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen "Corrupted physical size for uid=%u: "
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen /* 1 = pop3-only, 0 = mixed, -1 = no pop3 */
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen if (pop3_state >= 0 && mail->mail.mail.uid != 0) {
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen /* if size is wanted permanently, store it to uidlist
4145aa5025b57ec64418e503c2a5a6bf5a02aec5Timo Sirainen so that in case cache file gets lost we can get it quickly */
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen maildir_uidlist_set_ext(mbox->uidlist, mail->mail.mail.uid,
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainenstatic int maildir_mail_get_virtual_size(struct mail *_mail, uoff_t *size_r)
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen struct index_mail *mail = (struct index_mail *)_mail;
4145aa5025b57ec64418e503c2a5a6bf5a02aec5Timo Sirainen if (index_mail_get_cached_virtual_size(mail, size_r)) {
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen i_assert(mail->data.virtual_size != (uoff_t)-1);
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen maildir_handle_size_caching(mail, TRUE, TRUE);
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen if (maildir_quick_size_lookup(mail, TRUE, &data->virtual_size) < 0)
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen data->dont_cache_fetch_fields |= MAIL_FETCH_VIRTUAL_SIZE;
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen /* fallback to reading the file */
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen old_offset = data->stream == NULL ? 0 : data->stream->v_offset;
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen if (mail_get_stream(_mail, &hdr_size, &body_size, &input) < 0)
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen maildir_handle_size_caching(mail, FALSE, TRUE);
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainenstatic int maildir_mail_get_physical_size(struct mail *_mail, uoff_t *size_r)
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen struct index_mail *mail = (struct index_mail *)_mail;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen struct maildir_mailbox *mbox = (struct maildir_mailbox *)mail->ibox;
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen if (index_mail_get_physical_size(_mail, size_r) == 0) {
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen i_assert(mail->data.physical_size != (uoff_t)-1);
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen maildir_handle_size_caching(mail, TRUE, FALSE);
a342a31752dd71ac444259ca57ad33ea6b79a572Timo Sirainen if (maildir_quick_size_lookup(mail, FALSE, &data->physical_size) < 0)
31a574fda352ef4f71dbff9c30e15e4744e132c0Timo Sirainen data->dont_cache_fetch_fields |= MAIL_FETCH_PHYSICAL_SIZE;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen ret = maildir_file_do(mbox, _mail->uid, do_stat, &st);
cee926660616568927461f1349420e41aa9e89e1Timo Sirainen /* saved mail which hasn't been committed yet */
cee926660616568927461f1349420e41aa9e89e1Timo Sirainen path = maildir_save_file_get_path(_mail->transaction,
cee926660616568927461f1349420e41aa9e89e1Timo Sirainen mail_storage_set_critical(_mail->box->storage,
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen maildir_handle_size_caching(mail, FALSE, FALSE);
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainenmaildir_mail_get_special(struct mail *_mail, enum mail_fetch_field field,
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen const char **value_r)
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen struct index_mail *mail = (struct index_mail *)_mail;
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen struct maildir_mailbox *mbox = (struct maildir_mailbox *)mail->ibox;
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen if (!maildir_mail_get_fname(mbox, _mail, &fname))
2412873209ff658bc4bd20123af2d6162464c4ffTimo Sirainen path = maildir_save_file_get_path(_mail->transaction,
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen *value_r = end == NULL ? fname : t_strdup_until(fname, end);
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen uidl = maildir_uidlist_lookup_ext(mbox->uidlist, _mail->uid,
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen return index_mail_get_special(_mail, field, value_r);
3ddbbe03fe74b3ee7b1dff4e08ec706d7880d052Timo Sirainenstatic int maildir_mail_get_stream(struct mail *_mail,
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen struct index_mail *mail = (struct index_mail *)_mail;
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen struct maildir_mailbox *mbox = (struct maildir_mailbox *)mail->ibox;
3ddbbe03fe74b3ee7b1dff4e08ec706d7880d052Timo Sirainen data->stream = maildir_open_mail(mbox, _mail, &deleted);
905627a760ce8bf4141b361f72858a99975ded3cTimo Sirainen return index_mail_init_stream(mail, hdr_size, body_size, stream_r);
905627a760ce8bf4141b361f72858a99975ded3cTimo Sirainenstatic void maildir_mail_set_cache_corrupted(struct mail *_mail,
905627a760ce8bf4141b361f72858a99975ded3cTimo Sirainen struct index_mail *mail = (struct index_mail *)_mail;
905627a760ce8bf4141b361f72858a99975ded3cTimo Sirainen struct maildir_mailbox *mbox = (struct maildir_mailbox *)mail->ibox;
704a96fa677763eef7ae62466e14e83a2f535427Timo Sirainen /* make sure it gets removed from uidlist.
704a96fa677763eef7ae62466e14e83a2f535427Timo Sirainen if it's in file name, we can't really do more than log it. */
704a96fa677763eef7ae62466e14e83a2f535427Timo Sirainen if (maildir_filename_get_size(fname, MAILDIR_EXTRA_VIRTUAL_SIZE,
704a96fa677763eef7ae62466e14e83a2f535427Timo Sirainen i_error("Maildir filename has wrong W value: %s/%s",
289bd999f282a307b05e6f8beef33155a50fb837Timo Sirainen } else if (maildir_uidlist_lookup_ext(mbox->uidlist, _mail->uid,