maildir-mail.c revision e0645d5232900a5c574780ef0c0362a5b7581aba
e59faf65ce864fe95dc00f5d52b8323cdbd0608aTimo Sirainen/* Copyright (c) 2003-2009 Dovecot authors, see the included COPYING file */
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainendo_open(struct maildir_mailbox *mbox, const char *path, int *fd)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen mail_storage_set_critical(&mbox->storage->storage,
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainendo_stat(struct maildir_mailbox *mbox, const char *path, struct stat *st)
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen mail_storage_set_critical(&mbox->storage->storage,
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainenstatic struct istream *
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainenmaildir_open_mail(struct maildir_mailbox *mbox, struct mail *mail,
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen if (maildir_file_do(mbox, mail->uid, do_open, &fd) < 0)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen path = maildir_save_file_get_path(mail->transaction, mail->seq);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen return i_stream_create_fd(fd, MAIL_READ_BLOCK_SIZE, TRUE);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainenstatic int maildir_mail_stat(struct mail *mail, struct stat *st)
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen struct maildir_mailbox *mbox = (struct maildir_mailbox *)mail->box;
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen struct index_mail_data *data = &((struct index_mail *)mail)->data;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if (data->access_part != 0 && data->stream == NULL) {
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen /* we're going to open the mail anyway */
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen (void)mail_get_stream(mail, NULL, NULL, &input);
798cfe56c9871262770384da1239162b3800cce1Timo Sirainen mail_storage_set_critical(&mbox->storage->storage,
798cfe56c9871262770384da1239162b3800cce1Timo Sirainen "fstat(maildir) failed: %m");
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen ret = maildir_file_do(mbox, mail->uid, do_stat, st);
47bb4a7615c85f212f061499f04f121d6d625387Timo Sirainen path = maildir_save_file_get_path(mail->transaction, mail->seq);
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainenstatic int maildir_mail_get_received_date(struct mail *_mail, time_t *date_r)
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen struct index_mail *mail = (struct index_mail *)_mail;
fc8d5f0ac909cca77840538e8beef98a8d40c21cTimo Sirainen if (index_mail_get_received_date(_mail, date_r) == 0)
3313a51ef9b245248d672c20f930c52a577a42f7Timo Sirainenstatic int maildir_mail_get_save_date(struct mail *_mail, time_t *date_r)
3313a51ef9b245248d672c20f930c52a577a42f7Timo Sirainen struct index_mail *mail = (struct index_mail *)_mail;
3313a51ef9b245248d672c20f930c52a577a42f7Timo Sirainen if (index_mail_get_save_date(_mail, date_r) == 0)
ce6b6093957885a74fd6e85c18801dbb727d61ecTimo Sirainenmaildir_mail_get_fname(struct maildir_mailbox *mbox, struct mail *mail,
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen const char **fname_r)
8eb94c5190ba09bb6f6f068eec7bf96750f08d1dTimo Sirainen *fname_r = maildir_uidlist_lookup(mbox->uidlist, mail->uid, &flags);
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen /* file exists in index file, but not in dovecot-uidlist anymore. */
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen /* one reason this could happen is if we delayed opening
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen dovecot-uidlist and we're trying to open a mail that got recently
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen expunged. Let's test this theory first: */
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen view = mail_index_view_open(mbox->ibox.index);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen exists = mail_index_lookup_seq(view, mail->uid, &seq);
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen /* the message still exists in index. this means there's some
ce6b6093957885a74fd6e85c18801dbb727d61ecTimo Sirainen kind of a desync, which doesn't get fixed if cur/ mtime is
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen the same as in index. fix this by forcing a resync. */
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen (void)maildir_storage_sync_force(mbox, mail->uid);
adc409a7ac9689d3baf811712ad5a5432cab2d87Timo Sirainenstatic int maildir_get_pop3_state(struct index_mail *mail)
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen /* if this mail itself has non-pop3 fields we know we're not
adc409a7ac9689d3baf811712ad5a5432cab2d87Timo Sirainen allowed_pop3_fields = MAIL_FETCH_FLAGS | MAIL_FETCH_STREAM_HEADER |
adc409a7ac9689d3baf811712ad5a5432cab2d87Timo Sirainen MAIL_FETCH_STREAM_BODY | MAIL_FETCH_UIDL_FILE_NAME |
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen (mail->wanted_fields & ~allowed_pop3_fields) != 0)
b44650b0f48a4b5f0dc240ed836833a00b643b9fTimo Sirainen /* get vsize decisions */
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen psize_idx = mail->ibox->cache_fields[MAIL_CACHE_PHYSICAL_FULL_SIZE].idx;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen vsize_idx = mail->ibox->cache_fields[MAIL_CACHE_VIRTUAL_FULL_SIZE].idx;
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen vsize_dec = mail_cache_field_get_decision(mail->ibox->cache,
47bb4a7615c85f212f061499f04f121d6d625387Timo Sirainen /* also check if there are any non-[pv]size cached fields */
47bb4a7615c85f212f061499f04f121d6d625387Timo Sirainen fields = mail_cache_register_get_list(mail->ibox->cache,
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen for (i = 0; i < count; i++) {
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen dec = fields[i].decision & ~MAIL_CACHE_DECISION_FORCED;
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen /* either nothing is cached, or only vsize is cached. */
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen } else if (vsize_dec != MAIL_CACHE_DECISION_YES &&
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen /* if virtual size isn't cached permanently,
b44650b0f48a4b5f0dc240ed836833a00b643b9fTimo Sirainen POP3 isn't being used */
137ea7ca34005345aa2304a940149b7f3774d727Timo Sirainen /* possibly a mixed pop3/imap */
938835576b218f6bb9498d829cef9514f8609c6fTimo Sirainenstatic int maildir_quick_size_lookup(struct index_mail *mail, bool vsize,
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen struct maildir_mailbox *mbox = (struct maildir_mailbox *)mail->ibox;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if (!maildir_mail_get_fname(mbox, _mail, &fname))
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen path = maildir_save_file_get_path(_mail->transaction,
e2a700d0628e395d64cbcef4b5b4510816bf51c4Timo Sirainen /* size can be included in filename */
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen /* size can be included in uidlist entry */
a8e132559a7ebe54c8269d79ce29fa3338c76199Timo Sirainen value = maildir_uidlist_lookup_ext(mbox->uidlist, _mail->uid,
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen if (*p == '\0') {
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainenmaildir_handle_size_caching(struct index_mail *mail, bool quick_check,
43358fffb1d9f3091fd94895e0ac4643c50e2388Timo Sirainen struct maildir_mailbox *mbox = (struct maildir_mailbox *)mail->ibox;
43358fffb1d9f3091fd94895e0ac4643c50e2388Timo Sirainen field = vsize ? MAIL_FETCH_VIRTUAL_SIZE : MAIL_FETCH_PHYSICAL_SIZE;
430c0b0c370bebeeceba2e206be76bc134742f41Timo Sirainen if ((mail->data.dont_cache_fetch_fields & field) != 0)
ce6b6093957885a74fd6e85c18801dbb727d61ecTimo Sirainen if (quick_check && maildir_quick_size_lookup(mail, vsize, &size) > 0) {
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen /* already in filename / uidlist. don't add it anywhere,
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen including to the uidlist if it's already in filename.
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen do some extra checks here to catch potential cache bugs. */
484e12acec34f16e5a8adc001e23ae48f1dda8c7Timo Sirainen if (vsize && mail->data.virtual_size != size) {
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen "Corrupted virtual size for uid=%u: "
484e12acec34f16e5a8adc001e23ae48f1dda8c7Timo Sirainen } else if (!vsize && mail->data.physical_size != size) {
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen "Corrupted physical size for uid=%u: "
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen /* 1 = pop3-only, 0 = mixed, -1 = no pop3 */
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen if (pop3_state >= 0 && mail->mail.mail.uid != 0) {
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen /* if size is wanted permanently, store it to uidlist
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen so that in case cache file gets lost we can get it quickly */
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen maildir_uidlist_set_ext(mbox->uidlist, mail->mail.mail.uid,
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainenstatic int maildir_mail_get_virtual_size(struct mail *_mail, uoff_t *size_r)
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen struct index_mail *mail = (struct index_mail *)_mail;
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen if (index_mail_get_cached_virtual_size(mail, size_r)) {
ce6b6093957885a74fd6e85c18801dbb727d61ecTimo Sirainen i_assert(mail->data.virtual_size != (uoff_t)-1);
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen maildir_handle_size_caching(mail, TRUE, TRUE);
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen if (maildir_quick_size_lookup(mail, TRUE, &data->virtual_size) < 0)
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen data->dont_cache_fetch_fields |= MAIL_FETCH_VIRTUAL_SIZE;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen /* fallback to reading the file */
6fabfb7bbfd88d0c1de66981e52850f26067623bTimo Sirainen old_offset = data->stream == NULL ? 0 : data->stream->v_offset;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if (mail_get_stream(_mail, &hdr_size, &body_size, &input) < 0)
6fabfb7bbfd88d0c1de66981e52850f26067623bTimo Sirainen maildir_handle_size_caching(mail, FALSE, TRUE);
0f39a57760d93cddbce3ca43096d78e0fe2f42fdTimo Sirainenstatic int maildir_mail_get_physical_size(struct mail *_mail, uoff_t *size_r)
3313a51ef9b245248d672c20f930c52a577a42f7Timo Sirainen struct index_mail *mail = (struct index_mail *)_mail;
3313a51ef9b245248d672c20f930c52a577a42f7Timo Sirainen struct maildir_mailbox *mbox = (struct maildir_mailbox *)mail->ibox;
0f39a57760d93cddbce3ca43096d78e0fe2f42fdTimo Sirainen if (index_mail_get_physical_size(_mail, size_r) == 0) {
0f39a57760d93cddbce3ca43096d78e0fe2f42fdTimo Sirainen i_assert(mail->data.physical_size != (uoff_t)-1);
0f39a57760d93cddbce3ca43096d78e0fe2f42fdTimo Sirainen maildir_handle_size_caching(mail, TRUE, FALSE);
0f39a57760d93cddbce3ca43096d78e0fe2f42fdTimo Sirainen if (maildir_quick_size_lookup(mail, FALSE, &data->physical_size) < 0)
798cfe56c9871262770384da1239162b3800cce1Timo Sirainen data->dont_cache_fetch_fields |= MAIL_FETCH_PHYSICAL_SIZE;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen ret = maildir_file_do(mbox, _mail->uid, do_stat, &st);
f0c01ca67be18ed9c8011a094db2773f8795a1ebTimo Sirainen /* saved mail which hasn't been committed yet */
f0c01ca67be18ed9c8011a094db2773f8795a1ebTimo Sirainen path = maildir_save_file_get_path(_mail->transaction,
f0c01ca67be18ed9c8011a094db2773f8795a1ebTimo Sirainen mail_storage_set_critical(_mail->box->storage,
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen maildir_handle_size_caching(mail, FALSE, FALSE);
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainenmaildir_mail_get_special(struct mail *_mail, enum mail_fetch_field field,
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen const char **value_r)
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen struct index_mail *mail = (struct index_mail *)_mail;
ce6b6093957885a74fd6e85c18801dbb727d61ecTimo Sirainen struct maildir_mailbox *mbox = (struct maildir_mailbox *)mail->ibox;
f0c01ca67be18ed9c8011a094db2773f8795a1ebTimo Sirainen if (!maildir_mail_get_fname(mbox, _mail, &fname))
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen path = maildir_save_file_get_path(_mail->transaction,
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen *value_r = end == NULL ? fname : t_strdup_until(fname, end);
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen uidl = maildir_uidlist_lookup_ext(mbox->uidlist, _mail->uid,
7cba14a4c3beb026a2862ee50d24c554fa713329Timo Sirainen /* use the default */
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen /* special optimization case: use the base file name */
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen return index_mail_get_special(_mail, field, value_r);
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainenstatic int maildir_mail_get_stream(struct mail *_mail,
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen struct index_mail *mail = (struct index_mail *)_mail;
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen struct maildir_mailbox *mbox = (struct maildir_mailbox *)mail->ibox;
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen data->stream = maildir_open_mail(mbox, _mail, &deleted);
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen return index_mail_init_stream(mail, hdr_size, body_size, stream_r);
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainenstatic void maildir_mail_set_cache_corrupted(struct mail *_mail,
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen struct index_mail *mail = (struct index_mail *)_mail;
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen struct maildir_mailbox *mbox = (struct maildir_mailbox *)mail->ibox;
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen /* make sure it gets removed from uidlist.
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen if it's in file name, we can't really do more than log it. */
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen if (maildir_filename_get_size(fname, MAILDIR_EXTRA_VIRTUAL_SIZE,
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen const char *subdir =
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen (flags & MAILDIR_UIDLIST_REC_FLAG_NEW_DIR) != 0 ?
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen mail_storage_set_critical(_mail->box->storage,
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen "Maildir filename has wrong W value: %s/%s/%s",
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen } else if (maildir_uidlist_lookup_ext(mbox->uidlist, _mail->uid,