Exemple #1
0
static void
dbox_sync_index_copy_from_old(struct dbox_sync_rebuild_context *ctx,
			      struct mail_index_view *view,
			      uint32_t old_seq, uint32_t new_seq)
{
	struct mail_index *index = mail_index_view_get_index(view);
	const struct mail_index_record *rec;
	ARRAY_TYPE(keyword_indexes) old_keywords;
	struct mail_keywords *kw;
	uint64_t modseq;

	/* copy flags */
	rec = mail_index_lookup(view, old_seq);
	mail_index_update_flags(ctx->trans, new_seq,
				MODIFY_REPLACE, rec->flags);

	/* copy keywords */
	t_array_init(&old_keywords, 32);
	mail_index_lookup_keywords(view, old_seq, &old_keywords);
	kw = mail_index_keywords_create_from_indexes(index, &old_keywords);
	mail_index_update_keywords(ctx->trans, new_seq, MODIFY_REPLACE, kw);
	mail_index_keywords_unref(&kw);

	/* copy modseq */
	modseq = mail_index_modseq_lookup(view, old_seq);
	mail_index_update_modseq(ctx->trans, new_seq, modseq);

	dbox_sync_index_copy_cache(ctx, view, old_seq, new_seq);
}
Exemple #2
0
void dbox_save_add_to_index(struct dbox_save_context *ctx)
{
	struct mail_save_data *mdata = &ctx->ctx.data;
	enum mail_flags save_flags;

	save_flags = mdata->flags & ~MAIL_RECENT;
	mail_index_append(ctx->trans, mdata->uid, &ctx->seq);
	mail_index_update_flags(ctx->trans, ctx->seq, MODIFY_REPLACE,
				save_flags);
	if (mdata->keywords != NULL) {
		mail_index_update_keywords(ctx->trans, ctx->seq,
					   MODIFY_REPLACE, mdata->keywords);
	}
	if (mdata->min_modseq != 0) {
		mail_index_update_modseq(ctx->trans, ctx->seq,
					 mdata->min_modseq);
	}
}
int maildir_sync_index(struct maildir_index_sync_context *ctx,
		       bool partial)
{
	struct maildir_mailbox *mbox = ctx->mbox;
	struct mail_index_view *view = ctx->view;
	struct mail_index_view *view2;
	struct maildir_uidlist_iter_ctx *iter;
	struct mail_index_transaction *trans = ctx->trans;
	const struct mail_index_header *hdr;
	struct mail_index_header empty_hdr;
	const struct mail_index_record *rec;
	uint32_t seq, seq2, uid, prev_uid;
        enum maildir_uidlist_rec_flag uflags;
	const char *filename;
	uint32_t uid_validity, next_uid, hdr_next_uid, first_recent_uid;
	uint32_t first_uid;
	unsigned int changes = 0;
	int ret = 0;
	time_t time_before_sync;
	guid_128_t expunged_guid_128;
	enum mail_flags private_flags_mask;
	bool expunged, full_rescan = FALSE;

	i_assert(!mbox->syncing_commit);

	first_uid = 1;
	hdr = mail_index_get_header(view);
	uid_validity = maildir_uidlist_get_uid_validity(mbox->uidlist);
	if (uid_validity != hdr->uid_validity &&
	    uid_validity != 0 && hdr->uid_validity != 0) {
		/* uidvalidity changed and index isn't being synced for the
		   first time, reset the index so we can add all messages as
		   new */
		i_warning("Maildir %s: UIDVALIDITY changed (%u -> %u)",
			  mailbox_get_path(&ctx->mbox->box),
			  hdr->uid_validity, uid_validity);
		mail_index_reset(trans);
		mailbox_recent_flags_reset(&mbox->box);

		first_uid = hdr->messages_count + 1;
		memset(&empty_hdr, 0, sizeof(empty_hdr));
		empty_hdr.next_uid = 1;
		hdr = &empty_hdr;
	}
	hdr_next_uid = hdr->next_uid;

	ctx->mbox->box.tmp_sync_view = view;
	private_flags_mask = mailbox_get_private_flags_mask(&mbox->box);
	time_before_sync = time(NULL);
	mbox->syncing_commit = TRUE;
	seq = prev_uid = 0; first_recent_uid = I_MAX(hdr->first_recent_uid, 1);
	i_array_init(&ctx->keywords, MAILDIR_MAX_KEYWORDS);
	i_array_init(&ctx->idx_keywords, MAILDIR_MAX_KEYWORDS);
	iter = maildir_uidlist_iter_init(mbox->uidlist);
	while (maildir_uidlist_iter_next(iter, &uid, &uflags, &filename)) {
		maildir_filename_flags_get(ctx->keywords_sync_ctx, filename,
					   &ctx->flags, &ctx->keywords);

		i_assert(uid > prev_uid);
		prev_uid = uid;

		/* the private flags are kept only in indexes. don't use them
		   at all even for newly seen mails */
		ctx->flags &= ~private_flags_mask;

	again:
		seq++;
		ctx->uid = uid;

		if (seq > hdr->messages_count) {
			if (uid < hdr_next_uid) {
				if (maildir_handle_uid_insertion(ctx, uflags,
								 filename,
								 uid) < 0)
					ret = -1;
				seq--;
				continue;
			}

			/* Trust uidlist recent flags only for newly added
			   messages. When saving/copying messages with flags
			   they're stored to cur/ and uidlist treats them
			   as non-recent. */
			if ((uflags & MAILDIR_UIDLIST_REC_FLAG_RECENT) == 0) {
				if (uid >= first_recent_uid)
					first_recent_uid = uid + 1;
			}

			hdr_next_uid = uid + 1;
			mail_index_append(trans, uid, &seq);
			mail_index_update_flags(trans, seq, MODIFY_REPLACE,
						ctx->flags);
			if (array_count(&ctx->keywords) > 0) {
				struct mail_keywords *kw;

				kw = mail_index_keywords_create_from_indexes(
					mbox->box.index, &ctx->keywords);
				mail_index_update_keywords(trans, seq,
							   MODIFY_REPLACE, kw);
				mail_index_keywords_unref(&kw);
			}
			continue;
		}

		rec = mail_index_lookup(view, seq);
		if (uid > rec->uid) {
			/* already expunged (no point in showing guid in the
			   expunge record anymore) */
			mail_index_expunge(ctx->trans, seq);
			goto again;
		}

		if (uid < rec->uid) {
			if (maildir_handle_uid_insertion(ctx, uflags,
							 filename, uid) < 0)
				ret = -1;
			seq--;
			continue;
		}

		index_sync_changes_read(ctx->sync_changes, ctx->uid, &expunged,
					expunged_guid_128);
		if (expunged) {
			if (!maildir_expunge_is_valid_guid(ctx, ctx->uid,
							   filename,
							   expunged_guid_128))
				continue;
			if (maildir_file_do(mbox, ctx->uid,
					    maildir_expunge, ctx) >= 0) {
				/* successful expunge */
				mail_index_expunge(ctx->trans, seq);
			}
			if ((++changes % MAILDIR_SLOW_MOVE_COUNT) == 0)
				maildir_sync_notify(ctx->maildir_sync_ctx);
			continue;
		}

		/* the private flags are stored only in indexes, keep them */
		ctx->flags |= rec->flags & private_flags_mask;

		if (index_sync_changes_have(ctx->sync_changes)) {
			/* apply flag changes to maildir */
			if (maildir_file_do(mbox, ctx->uid,
					    maildir_sync_flags, ctx) < 0)
				ctx->flags |= MAIL_INDEX_MAIL_FLAG_DIRTY;
			if ((++changes % MAILDIR_SLOW_MOVE_COUNT) == 0)
				maildir_sync_notify(ctx->maildir_sync_ctx);
		}

		if ((uflags & MAILDIR_UIDLIST_REC_FLAG_NONSYNCED) != 0) {
			/* partial syncing */
			if ((uflags & MAILDIR_UIDLIST_REC_FLAG_NEW_DIR) != 0) {
				/* we last saw this mail in new/, but it's
				   not there anymore. possibly expunged,
				   make sure. */
				full_rescan = TRUE;
			}
			continue;
		}

		if ((rec->flags & MAIL_INDEX_MAIL_FLAG_DIRTY) != 0) {
			/* we haven't been able to update maildir with this
			   record's flag changes. don't sync them. */
			continue;
		}

		if (ctx->flags != (rec->flags & MAIL_FLAGS_NONRECENT)) {
			mail_index_update_flags(trans, seq, MODIFY_REPLACE,
						ctx->flags);
		}

		maildir_sync_mail_keywords(ctx, seq);
	}
	maildir_uidlist_iter_deinit(&iter);

	if (!partial) {
		/* expunge the rest */
		for (seq++; seq <= hdr->messages_count; seq++)
			mail_index_expunge(ctx->trans, seq);
	}

	/* add \Recent flags. use updated view so it contains newly
	   appended messages. */
	view2 = mail_index_transaction_open_updated_view(trans);
	if (mail_index_lookup_seq_range(view2, first_recent_uid, (uint32_t)-1,
					&seq, &seq2) && seq2 >= first_uid) {
		if (seq < first_uid) {
			/* UIDVALIDITY changed, skip over the old messages */
			seq = first_uid;
		}
		mailbox_recent_flags_set_seqs(&mbox->box, view2, seq, seq2);
	}
	mail_index_view_close(&view2);

	if (ctx->uidlist_sync_ctx != NULL) {
		if (maildir_uidlist_sync_deinit(&ctx->uidlist_sync_ctx,
						TRUE) < 0)
			ret = -1;
	}

	if (mbox->box.v.sync_notify != NULL)
		mbox->box.v.sync_notify(&mbox->box, 0, 0);
	ctx->mbox->box.tmp_sync_view = NULL;

	/* check cur/ mtime later. if we came here from saving messages they
	   could still be moved to cur/ directory. */
	ctx->update_maildir_hdr_cur = TRUE;
	mbox->maildir_hdr.cur_check_time = time_before_sync;

	if (uid_validity == 0) {
		uid_validity = hdr->uid_validity != 0 ? hdr->uid_validity :
			maildir_get_uidvalidity_next(mbox->box.list);
		maildir_uidlist_set_uid_validity(mbox->uidlist, uid_validity);
	}
	maildir_uidlist_set_next_uid(mbox->uidlist, hdr_next_uid, FALSE);

	if (uid_validity != hdr->uid_validity) {
		mail_index_update_header(trans,
			offsetof(struct mail_index_header, uid_validity),
			&uid_validity, sizeof(uid_validity), TRUE);
	}
Exemple #4
0
struct maildir_filename *
maildir_save_add(struct mail_save_context *_ctx, const char *tmp_fname,
		 struct mail *src_mail)
{
	struct maildir_save_context *ctx = (struct maildir_save_context *)_ctx;
	struct mail_save_data *mdata = &_ctx->data;
	struct maildir_filename *mf;
	struct istream *input;
	unsigned int keyword_count;

	i_assert(*tmp_fname != '\0');

	/* allow caller to specify recent flag only when uid is specified
	   (we're replicating, converting, etc.). */
	if (mdata->uid == 0)
		mdata->flags |= MAIL_RECENT;
	else if ((mdata->flags & MAIL_RECENT) == 0 &&
		 ctx->last_nonrecent_uid < mdata->uid)
		ctx->last_nonrecent_uid = mdata->uid;

	/* now, we want to be able to rollback the whole append session,
	   so we'll just store the name of this temp file and move it later
	   into new/ or cur/. */
	/* @UNSAFE */
	keyword_count = mdata->keywords == NULL ? 0 : mdata->keywords->count;
	mf = p_malloc(ctx->pool, sizeof(*mf) +
		      sizeof(unsigned int) * keyword_count);
	mf->tmp_name = mf->dest_basename = p_strdup(ctx->pool, tmp_fname);
	mf->flags = mdata->flags;
	mf->size = (uoff_t)-1;
	mf->vsize = (uoff_t)-1;

	ctx->file_last = mf;
	i_assert(*ctx->files_tail == NULL);
	*ctx->files_tail = mf;
	ctx->files_tail = &mf->next;
	ctx->files_count++;

	if (mdata->keywords != NULL) {
		/* @UNSAFE */
		mf->keywords_count = keyword_count;
		memcpy(mf + 1, mdata->keywords->idx,
		       sizeof(unsigned int) * keyword_count);
		ctx->have_keywords = TRUE;
	}
	if (mdata->pop3_uidl != NULL)
		mf->pop3_uidl = p_strdup(ctx->pool, mdata->pop3_uidl);
	mf->pop3_order = mdata->pop3_order;

	/* insert into index */
	mail_index_append(ctx->trans, mdata->uid, &ctx->seq);
	mail_index_update_flags(ctx->trans, ctx->seq,
				MODIFY_REPLACE, mdata->flags & ~MAIL_RECENT);
	if (mdata->keywords != NULL) {
		mail_index_update_keywords(ctx->trans, ctx->seq,
					   MODIFY_REPLACE, mdata->keywords);
	}
	if (mdata->min_modseq != 0) {
		mail_index_update_modseq(ctx->trans, ctx->seq,
					 mdata->min_modseq);
	}

	if (ctx->first_seq == 0) {
		ctx->first_seq = ctx->seq;
		i_assert(ctx->files->next == NULL);
	}

	if (_ctx->dest_mail == NULL) {
		if (ctx->mail == NULL)
			ctx->mail = mail_alloc(_ctx->transaction, 0, NULL);
		_ctx->dest_mail = ctx->mail;
	}
	mail_set_seq_saving(_ctx->dest_mail, ctx->seq);

	if (ctx->input == NULL) {
		/* copying with hardlinking. */
		i_assert(src_mail != NULL);
		index_copy_cache_fields(_ctx, src_mail, ctx->seq);
		ctx->cur_dest_mail = NULL;
	} else {
		input = index_mail_cache_parse_init(_ctx->dest_mail,
						    ctx->input);
		i_stream_unref(&ctx->input);
		ctx->input = input;
		ctx->cur_dest_mail = _ctx->dest_mail;
	}
	return mf;
}