static int maildir_mail_get_fname(struct maildir_mailbox *mbox, struct mail *mail, const char **fname_r) { enum maildir_uidlist_rec_flag flags; struct mail_index_view *view; uint32_t seq; bool exists; int ret; ret = maildir_sync_lookup(mbox, mail->uid, &flags, fname_r); if (ret != 0) return ret; /* file exists in index file, but not in dovecot-uidlist anymore. */ mail_set_expunged(mail); /* one reason this could happen is if we delayed opening dovecot-uidlist and we're trying to open a mail that got recently expunged. Let's test this theory first: */ mail_index_refresh(mbox->box.index); view = mail_index_view_open(mbox->box.index); exists = mail_index_lookup_seq(view, mail->uid, &seq); mail_index_view_close(&view); if (exists) { /* the message still exists in index. this means there's some kind of a desync, which doesn't get fixed if cur/ mtime is the same as in index. fix this by forcing a resync. */ (void)maildir_storage_sync_force(mbox, mail->uid); } return 0; }
static void maildir_mail_remove_sizes_from_filename(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; char wrong_key; if (mbox->storage->set->maildir_broken_filename_sizes) { /* never try to fix sizes in maildir filenames */ return; } if (maildir_sync_lookup(mbox, mail->uid, &flags, &fname) <= 0) return; if (strchr(fname, MAILDIR_EXTRA_SEP) == NULL) return; if (field == MAIL_FETCH_VIRTUAL_SIZE && maildir_filename_get_size(fname, MAILDIR_EXTRA_VIRTUAL_SIZE, &size)) { wrong_key = 'W'; } else if (field == MAIL_FETCH_PHYSICAL_SIZE && maildir_filename_get_size(fname, MAILDIR_EXTRA_FILE_SIZE, &size)) { wrong_key = 'S'; } else { /* the broken size isn't in filename */ return; } (void)maildir_file_do(mbox, mail->uid, do_fix_size, &wrong_key); }
static void maildir_mail_remove_sizes_from_filename(struct mail *mail, enum mail_fetch_field field) { struct maildir_mailbox *mbox = (struct maildir_mailbox *)mail->box; struct mail_private *pmail = (struct mail_private *)mail; enum maildir_uidlist_rec_flag flags; const char *fname; uoff_t size; struct maildir_size_fix_ctx ctx; if (mbox->storage->set->maildir_broken_filename_sizes) { /* never try to fix sizes in maildir filenames */ return; } if (maildir_sync_lookup(mbox, mail->uid, &flags, &fname) <= 0) return; if (strchr(fname, MAILDIR_EXTRA_SEP) == NULL) return; memset(&ctx, 0, sizeof(ctx)); ctx.physical_size = (uoff_t)-1; if (field == MAIL_FETCH_VIRTUAL_SIZE && maildir_filename_get_size(fname, MAILDIR_EXTRA_VIRTUAL_SIZE, &size)) { ctx.wrong_key = 'W'; } else if (field == MAIL_FETCH_PHYSICAL_SIZE && maildir_filename_get_size(fname, MAILDIR_EXTRA_FILE_SIZE, &size)) { ctx.wrong_key = 'S'; } else { /* the broken size isn't in filename */ return; } if (pmail->v.istream_opened != NULL) { /* the mail could be e.g. compressed. get the physical size the slow way by actually reading the mail. */ struct istream *input; const struct stat *stp; if (mail_get_stream(mail, NULL, NULL, &input) < 0) return; if (i_stream_stat(input, TRUE, &stp) < 0) return; ctx.physical_size = stp->st_size; } (void)maildir_file_do(mbox, mail->uid, do_fix_size, &ctx); }
static int maildir_file_do_try(struct maildir_mailbox *mbox, uint32_t uid, maildir_file_do_func *callback, void *context) { const char *path, *fname; enum maildir_uidlist_rec_flag flags; bool have_flags; int ret; ret = maildir_sync_lookup(mbox, uid, &flags, &fname); if (ret <= 0) return ret == 0 ? -2 : -1; if ((flags & MAILDIR_UIDLIST_REC_FLAG_NONSYNCED) != 0) { /* let's see if we can guess the filename based on index */ fname = maildir_filename_guess(mbox, uid, fname, &flags, &have_flags); } /* make a copy, just in case callback refreshes uidlist and the pointer becomes invalid. */ fname = t_strdup(fname); ret = 0; if ((flags & MAILDIR_UIDLIST_REC_FLAG_NEW_DIR) != 0) { /* probably in new/ dir */ path = t_strconcat(mailbox_get_path(&mbox->box), "/new/", fname, NULL); ret = callback(mbox, path, context); } if (ret == 0) { path = t_strconcat(mailbox_get_path(&mbox->box), "/cur/", fname, NULL); ret = callback(mbox, path, context); } if (ret > 0 && (flags & MAILDIR_UIDLIST_REC_FLAG_NONSYNCED) != 0) { /* file was found. make sure we remember its latest name. */ maildir_uidlist_update_fname(mbox->uidlist, fname); } else if (ret == 0 && (flags & MAILDIR_UIDLIST_REC_FLAG_NONSYNCED) == 0) { /* file wasn't found. mark this message nonsynced, so we can retry the lookup by guessing the flags */ maildir_uidlist_add_flags(mbox->uidlist, fname, MAILDIR_UIDLIST_REC_FLAG_NONSYNCED); } return ret; }