maildir-mail.c revision b12b6da6f084212d42421a28ae329eae79751c42
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen/* Copyright (c) 2003-2011 Dovecot authors, see the included COPYING file */
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainendo_open(struct maildir_mailbox *mbox, const char *path,
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen mail_storage_set_critical(&mbox->storage->storage, "%s",
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen mail_storage_set_critical(&mbox->storage->storage,
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainendo_stat(struct maildir_mailbox *mbox, const char *path, struct stat *st)
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen mail_storage_set_critical(&mbox->storage->storage, "%s",
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen mail_storage_set_critical(&mbox->storage->storage,
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainenstatic struct istream *
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainenmaildir_open_mail(struct maildir_mailbox *mbox, struct mail *mail,
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen if (maildir_file_do(mbox, mail->uid, do_open, &ctx) < 0)
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen path = maildir_save_file_get_path(mail->transaction, mail->seq);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen if (maildir_lose_unexpected_dir(&mbox->storage->storage,
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainenstatic int maildir_mail_stat(struct mail *mail, struct stat *st)
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen struct maildir_mailbox *mbox = (struct maildir_mailbox *)mail->box;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen struct index_mail *imail = (struct index_mail *)mail;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen if (mail->lookup_abort == MAIL_LOOKUP_ABORT_NOT_IN_CACHE)
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen /* we're going to open the mail anyway */
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen (void)mail_get_stream(mail, NULL, NULL, &input);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen mail->transaction->stats.fstat_lookup_count++;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen stp = i_stream_stat(imail->data.stream, FALSE);
c649139f889c02154fc9a153728b81619edb5663Timo Sirainen ret = maildir_file_do(mbox, mail->uid, do_stat, st);
c649139f889c02154fc9a153728b81619edb5663Timo Sirainen path = maildir_save_file_get_path(mail->transaction, mail->seq);
c649139f889c02154fc9a153728b81619edb5663Timo Sirainenstatic int maildir_mail_get_received_date(struct mail *_mail, time_t *date_r)
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen struct index_mail *mail = (struct index_mail *)_mail;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen if (index_mail_get_received_date(_mail, date_r) == 0)
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainenstatic int maildir_mail_get_save_date(struct mail *_mail, time_t *date_r)
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen struct index_mail *mail = (struct index_mail *)_mail;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen if (index_mail_get_save_date(_mail, date_r) == 0)
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainenmaildir_mail_get_fname(struct maildir_mailbox *mbox, struct mail *mail,
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen const char **fname_r)
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen ret = maildir_sync_lookup(mbox, mail->uid, &flags, fname_r);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen /* file exists in index file, but not in dovecot-uidlist anymore. */
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 exists = mail_index_lookup_seq(view, mail->uid, &seq);
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 Sirainenstatic int maildir_get_pop3_state(struct index_mail *mail)
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen struct index_mailbox_context *ibox = INDEX_STORAGE_CONTEXT(box);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen /* if this mail itself has non-pop3 fields we know we're not
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->data.wanted_fields & ~allowed_pop3_fields) != 0)
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 vsize_dec = mail_cache_field_get_decision(box->cache,
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen /* also check if there are any non-[pv]size cached fields */
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen fields = mail_cache_register_get_list(box->cache,
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen for (i = 0; i < count; i++) {
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen dec = fields[i].decision & ~MAIL_CACHE_DECISION_FORCED;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen /* either nothing is cached, or only vsize is cached. */
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 /* possibly a mixed pop3/imap */
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainenstatic int maildir_quick_size_lookup(struct index_mail *mail, bool vsize,
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen struct maildir_mailbox *mbox = (struct maildir_mailbox *)_mail->box;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen if (maildir_mail_get_fname(mbox, _mail, &fname) <= 0)
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen path = maildir_save_file_get_path(_mail->transaction,
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen /* size can be included in filename */
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen /* size can be included in uidlist entry */
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen value = maildir_uidlist_lookup_ext(mbox->uidlist, _mail->uid,
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen if (value != NULL && str_to_uoff(value, size_r) == 0)
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainenmaildir_handle_size_caching(struct index_mail *mail, bool quick_check,
c649139f889c02154fc9a153728b81619edb5663Timo Sirainen struct maildir_mailbox *mbox = (struct maildir_mailbox *)box;
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 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 "Corrupted virtual size for uid=%u: "
c649139f889c02154fc9a153728b81619edb5663Timo Sirainen } else if (!vsize && mail->data.physical_size != size) {
c649139f889c02154fc9a153728b81619edb5663Timo Sirainen "Corrupted physical size for uid=%u: "
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen /* 1 = pop3-only, 0 = mixed, -1 = no pop3 */
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 */
c649139f889c02154fc9a153728b81619edb5663Timo Sirainen maildir_uidlist_set_ext(mbox->uidlist, mail->mail.mail.uid,
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainenstatic int maildir_mail_get_virtual_size(struct mail *_mail, uoff_t *size_r)
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen struct maildir_mailbox *mbox = (struct maildir_mailbox *)_mail->box;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen struct index_mail *mail = (struct index_mail *)_mail;
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 (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 data->dont_cache_fetch_fields |= MAIL_FETCH_VIRTUAL_SIZE;
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 maildir_handle_size_caching(mail, FALSE, TRUE);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainenstatic int maildir_mail_get_physical_size(struct mail *_mail, uoff_t *size_r)
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen struct index_mail *mail = (struct index_mail *)_mail;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen struct maildir_mailbox *mbox = (struct maildir_mailbox *)_mail->box;
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 (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 data->dont_cache_fetch_fields |= MAIL_FETCH_PHYSICAL_SIZE;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen ret = maildir_file_do(mbox, _mail->uid, do_stat, &st);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen /* saved mail which hasn't been committed yet */
c649139f889c02154fc9a153728b81619edb5663Timo Sirainen path = maildir_save_file_get_path(_mail->transaction,
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen mail_storage_set_critical(_mail->box->storage,
c649139f889c02154fc9a153728b81619edb5663Timo Sirainen maildir_handle_size_caching(mail, FALSE, FALSE);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainenmaildir_mail_get_special(struct mail *_mail, enum mail_fetch_field field,
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen const char **value_r)
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 /* use GUID from uidlist if it exists */
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen /* first make sure that we have a refreshed uidlist */
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen if (maildir_mail_get_fname(mbox, _mail, &fname) <= 0)
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen guid = maildir_uidlist_lookup_ext(mbox->uidlist, _mail->uid,
case MAIL_FETCH_UIDL_BACKEND:
case MAIL_FETCH_POP3_ORDER:
bool deleted;
if (deleted)
const char *fname;
&fname) == 0 &&
const char *wrong_key_p)
const char *fname;
char wrong_key;
&size)) {
&size)) {