Example #1
0
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;
}
Example #2
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);
}
Example #3
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;
	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);
}
Example #4
0
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;
}