maildir-mail.c revision 89fb98e9eb7e95255a579c8e9d865383c2334a74
45312f52ff3a3d4c137447be4c7556500c2f8bf2Timo Sirainen/* Copyright (c) 2003-2008 Dovecot authors, see the included COPYING file */
2cfe9983ce7a6280636ee12beccc2e865111967bTimo Sirainendo_open(struct maildir_mailbox *mbox, const char *path, int *fd)
ccc895c0358108d2304239063e940b7d75f364abTimo Sirainen mail_storage_set_critical(&mbox->storage->storage,
2cfe9983ce7a6280636ee12beccc2e865111967bTimo Sirainendo_stat(struct maildir_mailbox *mbox, const char *path, struct stat *st)
ccc895c0358108d2304239063e940b7d75f364abTimo Sirainen mail_storage_set_critical(&mbox->storage->storage,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic struct istream *
b6a7e0a7899e7f5d60c23cdaa50e025e4c67d05fTimo Sirainenmaildir_open_mail(struct maildir_mailbox *mbox, struct mail *mail,
b6a7e0a7899e7f5d60c23cdaa50e025e4c67d05fTimo Sirainen if (maildir_file_do(mbox, mail->uid, do_open, &fd) < 0)
b6a7e0a7899e7f5d60c23cdaa50e025e4c67d05fTimo Sirainen path = maildir_save_file_get_path(mail->transaction, mail->seq);
2526d52441ef368215ab6bf04fd0356d3b09d235Timo Sirainen return i_stream_create_fd(fd, MAIL_READ_BLOCK_SIZE, TRUE);
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainenstatic int maildir_mail_stat(struct mail *mail, struct stat *st)
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen struct maildir_mailbox *mbox = (struct maildir_mailbox *)mail->box;
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen struct index_mail_data *data = &((struct index_mail *)mail)->data;
55773f17bccf6361d6599ffcbe072d7c9fe205bfTimo Sirainen if (data->access_part != 0 && data->stream == NULL) {
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen /* we're going to open the mail anyway */
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen (void)mail_get_stream(mail, NULL, NULL, &input);
ccc895c0358108d2304239063e940b7d75f364abTimo Sirainen mail_storage_set_critical(&mbox->storage->storage,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen "fstat(maildir) failed: %m");
e9d29ae46d435aee85514decfe6ee27399ebf794Timo Sirainen ret = maildir_file_do(mbox, mail->uid, do_stat, st);
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen path = maildir_save_file_get_path(mail->transaction, mail->seq);
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainenstatic int maildir_mail_get_received_date(struct mail *_mail, time_t *date_r)
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen struct index_mail *mail = (struct index_mail *)_mail;
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen if (index_mail_get_received_date(_mail, date_r) == 0)
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainenstatic int maildir_mail_get_save_date(struct mail *_mail, time_t *date_r)
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen struct index_mail *mail = (struct index_mail *)_mail;
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen if (index_mail_get_save_date(_mail, date_r) == 0)
3ec2c1f31631bb5ff86f5fc93a563c33e5cae90dTimo Sirainenmaildir_mail_get_fname(struct maildir_mailbox *mbox, struct mail *mail,
3ec2c1f31631bb5ff86f5fc93a563c33e5cae90dTimo Sirainen const char **fname_r)
3ec2c1f31631bb5ff86f5fc93a563c33e5cae90dTimo Sirainen *fname_r = maildir_uidlist_lookup(mbox->uidlist, mail->uid, &flags);
9334fbad0aabb2fed88f40b2205d0d6f80bdffa2Timo Sirainen /* file exists in index file, but not in dovecot-uidlist anymore. */
9334fbad0aabb2fed88f40b2205d0d6f80bdffa2Timo Sirainen /* one reason this could happen is if we delayed opening
9334fbad0aabb2fed88f40b2205d0d6f80bdffa2Timo Sirainen dovecot-uidlist and we're trying to open a mail that got recently
9334fbad0aabb2fed88f40b2205d0d6f80bdffa2Timo Sirainen expunged. Let's test this theory first: */
9334fbad0aabb2fed88f40b2205d0d6f80bdffa2Timo Sirainen view = mail_index_view_open(mbox->ibox.index);
9334fbad0aabb2fed88f40b2205d0d6f80bdffa2Timo Sirainen exists = mail_index_lookup_seq(view, mail->uid, &seq);
9334fbad0aabb2fed88f40b2205d0d6f80bdffa2Timo Sirainen /* the message still exists in index. this means there's some
9334fbad0aabb2fed88f40b2205d0d6f80bdffa2Timo Sirainen kind of a desync, which doesn't get fixed if cur/ mtime is
9334fbad0aabb2fed88f40b2205d0d6f80bdffa2Timo Sirainen the same as in index. fix this by forcing a resync. */
9334fbad0aabb2fed88f40b2205d0d6f80bdffa2Timo Sirainen (void)maildir_storage_sync_force(mbox, mail->uid);
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainenstatic int maildir_get_pop3_state(struct index_mail *mail)
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen /* if this mail itself has non-pop3 fields we know we're not
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen allowed_pop3_fields = MAIL_FETCH_FLAGS | MAIL_FETCH_STREAM_HEADER |
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen MAIL_FETCH_STREAM_BODY | MAIL_FETCH_UIDL_FILE_NAME |
8b58939517a381db55670089c0984da39fc0f099Timo Sirainen (mail->wanted_fields & ~allowed_pop3_fields) != 0)
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen /* get vsize decisions */
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen psize_idx = mail->ibox->cache_fields[MAIL_CACHE_PHYSICAL_FULL_SIZE].idx;
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen vsize_idx = mail->ibox->cache_fields[MAIL_CACHE_VIRTUAL_FULL_SIZE].idx;
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen vsize_dec = mail_cache_field_get_decision(mail->ibox->cache,
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen /* also check if there are any non-[pv]size cached fields */
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen fields = mail_cache_register_get_list(mail->ibox->cache,
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen for (i = 0; i < count; i++) {
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen dec = fields[i].decision & ~MAIL_CACHE_DECISION_FORCED;
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen /* either nothing is cached, or only vsize is cached. */
236bedf76e31651ea9fca63fbdc25be673819526Timo Sirainen } else if (vsize_dec != MAIL_CACHE_DECISION_YES &&
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen /* if virtual size isn't cached permanently,
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen POP3 isn't being used */
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen /* possibly a mixed pop3/imap */
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainenstatic int maildir_quick_size_lookup(struct index_mail *mail, bool vsize,
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen struct maildir_mailbox *mbox = (struct maildir_mailbox *)mail->ibox;
3ec2c1f31631bb5ff86f5fc93a563c33e5cae90dTimo Sirainen if (!maildir_mail_get_fname(mbox, _mail, &fname))
b142deb9a831c89b1bb9129ada655f3e56b9d4ccTimo Sirainen path = maildir_save_file_get_path(_mail->transaction,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* size can be included in filename */
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen /* size can be included in uidlist entry */
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen value = maildir_uidlist_lookup_ext(mbox->uidlist, _mail->uid,
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen if (*p == '\0') {
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainenmaildir_handle_size_caching(struct index_mail *mail, bool quick_check,
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen struct maildir_mailbox *mbox = (struct maildir_mailbox *)mail->ibox;
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen field = vsize ? MAIL_FETCH_VIRTUAL_SIZE : MAIL_FETCH_PHYSICAL_SIZE;
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen if ((mail->data.dont_cache_fetch_fields & field) != 0)
55b6e3105184ad6a2f987346380966f556300055Timo Sirainen if (quick_check && maildir_quick_size_lookup(mail, vsize, &size) > 0) {
7aeaf23f760d86aad525d831efcac9f860a55a39Timo Sirainen /* already in filename / uidlist. don't add it anywhere,
cf49fc07f541c0f74578ac6c3b334ddade143aa1Timo Sirainen including to the uidlist if it's already in filename.
cf49fc07f541c0f74578ac6c3b334ddade143aa1Timo Sirainen do some extra checks here to catch potential cache bugs. */
cf49fc07f541c0f74578ac6c3b334ddade143aa1Timo Sirainen if (vsize && mail->data.virtual_size != size) {
63aaafe7e6b201d6633f8c25610ecd30c9cda99cTimo Sirainen "Corrupted virtual size for uid=%u: "
cf49fc07f541c0f74578ac6c3b334ddade143aa1Timo Sirainen } else if (!vsize && mail->data.physical_size != size) {
63aaafe7e6b201d6633f8c25610ecd30c9cda99cTimo Sirainen "Corrupted physical size for uid=%u: "
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen /* 1 = pop3-only, 0 = mixed, -1 = no pop3 */
18065635d4e79dd96eb3b3215718abd12f6a6808Timo Sirainen if (pop3_state >= 0 && mail->mail.mail.uid != 0) {
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen /* if size is wanted permanently, store it to uidlist
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen so that in case cache file gets lost we can get it quickly */
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen maildir_uidlist_set_ext(mbox->uidlist, mail->mail.mail.uid,
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainenstatic int maildir_mail_get_virtual_size(struct mail *_mail, uoff_t *size_r)
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen struct index_mail *mail = (struct index_mail *)_mail;
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen if (index_mail_get_cached_virtual_size(mail, size_r)) {
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen i_assert(mail->data.virtual_size != (uoff_t)-1);
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen maildir_handle_size_caching(mail, TRUE, TRUE);
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen if (maildir_quick_size_lookup(mail, TRUE, &data->virtual_size) < 0)
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen data->dont_cache_fetch_fields |= MAIL_FETCH_VIRTUAL_SIZE;
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen /* fallback to reading the file */
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen old_offset = data->stream == NULL ? 0 : data->stream->v_offset;
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen if (mail_get_stream(_mail, &hdr_size, &body_size, &input) < 0)
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen maildir_handle_size_caching(mail, FALSE, TRUE);
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainenstatic int maildir_mail_get_physical_size(struct mail *_mail, uoff_t *size_r)
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen struct index_mail *mail = (struct index_mail *)_mail;
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen struct maildir_mailbox *mbox = (struct maildir_mailbox *)mail->ibox;
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen if (index_mail_get_physical_size(_mail, size_r) == 0) {
9fdd27b307347a06871ddab74b165122c878553cTimo Sirainen i_assert(mail->data.physical_size != (uoff_t)-1);
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen maildir_handle_size_caching(mail, TRUE, FALSE);
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen if (maildir_quick_size_lookup(mail, FALSE, &data->physical_size) < 0)
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen data->dont_cache_fetch_fields |= MAIL_FETCH_PHYSICAL_SIZE;
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen ret = maildir_file_do(mbox, _mail->uid, do_stat, &st);
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen /* saved mail which hasn't been committed yet */
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen path = maildir_save_file_get_path(_mail->transaction,
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen mail_storage_set_critical(_mail->box->storage,
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen maildir_handle_size_caching(mail, FALSE, FALSE);
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainenmaildir_mail_get_special(struct mail *_mail, enum mail_fetch_field field,
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen const char **value_r)
366d6311c9d5bac6613e3cd64619eb878adce9ecTimo Sirainen struct index_mail *mail = (struct index_mail *)_mail;
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen struct maildir_mailbox *mbox = (struct maildir_mailbox *)mail->ibox;
3ec2c1f31631bb5ff86f5fc93a563c33e5cae90dTimo Sirainen if (!maildir_mail_get_fname(mbox, _mail, &fname))
b142deb9a831c89b1bb9129ada655f3e56b9d4ccTimo Sirainen path = maildir_save_file_get_path(_mail->transaction,
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen *value_r = end == NULL ? fname : t_strdup_until(fname, end);
e76c494ad6535d3de314cc0d3ac7a44b06e53c4bTimo Sirainen uidl = maildir_uidlist_lookup_ext(mbox->uidlist, _mail->uid,
89fb98e9eb7e95255a579c8e9d865383c2334a74Timo Sirainen /* use the default */
89fb98e9eb7e95255a579c8e9d865383c2334a74Timo Sirainen /* special optimization case: use the base file name */
b19a1420da0618a10edf67c2cfd13c8c8633057aTimo Sirainen return index_mail_get_special(_mail, field, value_r);
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainenstatic int maildir_mail_get_stream(struct mail *_mail,
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen struct index_mail *mail = (struct index_mail *)_mail;
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen struct maildir_mailbox *mbox = (struct maildir_mailbox *)mail->ibox;
b6a7e0a7899e7f5d60c23cdaa50e025e4c67d05fTimo Sirainen data->stream = maildir_open_mail(mbox, _mail, &deleted);
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen return index_mail_init_stream(mail, hdr_size, body_size, stream_r);
8c9e48cd6de80da0fa32b9c0dee003472c9a7c0dTimo Sirainenstatic void maildir_mail_set_cache_corrupted(struct mail *_mail,
8c9e48cd6de80da0fa32b9c0dee003472c9a7c0dTimo Sirainen struct index_mail *mail = (struct index_mail *)_mail;
8c9e48cd6de80da0fa32b9c0dee003472c9a7c0dTimo Sirainen struct maildir_mailbox *mbox = (struct maildir_mailbox *)mail->ibox;
8c9e48cd6de80da0fa32b9c0dee003472c9a7c0dTimo Sirainen /* make sure it gets removed from uidlist.
8c9e48cd6de80da0fa32b9c0dee003472c9a7c0dTimo Sirainen if it's in file name, we can't really do more than log it. */
8c9e48cd6de80da0fa32b9c0dee003472c9a7c0dTimo Sirainen if (maildir_filename_get_size(fname, MAILDIR_EXTRA_VIRTUAL_SIZE,
e0645d5232900a5c574780ef0c0362a5b7581abaTimo Sirainen mail_storage_set_critical(_mail->box->storage,
e0645d5232900a5c574780ef0c0362a5b7581abaTimo Sirainen "Maildir filename has wrong W value: %s/%s",
0d16525a729011f4fced989a3da74d755ea49e6dTimo Sirainen } else if (maildir_uidlist_lookup_ext(mbox->uidlist, _mail->uid,