static unsigned int index_storage_count_pvt_unseen(struct mailbox *box)
{
	const struct mail_index_record *pvt_rec;
	uint32_t shared_seq, pvt_seq, shared_count, pvt_count;
	uint32_t shared_uid;
	unsigned int unseen_count = 0;

	/* we can't trust private index to be up to date. we'll need to go
	   through the shared index and for each existing mail lookup its
	   private flags. if a mail doesn't exist in private index then its
	   flags are 0. */
	shared_count = mail_index_view_get_messages_count(box->view);
	pvt_count = mail_index_view_get_messages_count(box->view_pvt);
	shared_seq = pvt_seq = 1;
	while (shared_seq <= shared_count && pvt_seq <= pvt_count) {
		mail_index_lookup_uid(box->view, shared_seq, &shared_uid);
		pvt_rec = mail_index_lookup(box->view_pvt, pvt_seq);

		if (shared_uid == pvt_rec->uid) {
			if ((pvt_rec->flags & MAIL_SEEN) == 0)
				unseen_count++;
			shared_seq++; pvt_seq++;
		} else if (shared_uid < pvt_rec->uid) {
			shared_seq++;
		} else {
			pvt_seq++;
		}
	}
	unseen_count += (shared_count+1) - shared_seq;
	return unseen_count;
}
static int sync_pvt_expunges(struct index_mailbox_sync_pvt_context *ctx)
{
	uint32_t seq_shared, seq_pvt, count_shared, count_pvt;
	uint32_t uid_shared, uid_pvt;

	count_shared = mail_index_view_get_messages_count(ctx->view_shared);
	count_pvt = mail_index_view_get_messages_count(ctx->view_pvt);
	seq_shared = seq_pvt = 1;
	while (seq_pvt <= count_pvt && seq_shared <= count_shared) {
		mail_index_lookup_uid(ctx->view_pvt, seq_pvt, &uid_pvt);
		mail_index_lookup_uid(ctx->view_shared, seq_shared, &uid_shared);
		if (uid_pvt == uid_shared) {
			seq_pvt++;
			seq_shared++;
		} else if (uid_pvt < uid_shared) {
			/* message expunged */
			mail_index_expunge(ctx->trans_pvt, seq_pvt);
			seq_pvt++;
		} else {
			mail_storage_set_critical(ctx->box->storage,
				"%s: Message UID=%u unexpectedly inserted to mailbox",
				ctx->box->index_pvt->filepath, uid_shared);
			return -1;
		}
	}
	return 0;
}
static uint32_t index_storage_find_first_pvt_unseen_seq(struct mailbox *box)
{
	const struct mail_index_header *pvt_hdr;
	const struct mail_index_record *pvt_rec;
	uint32_t pvt_seq, pvt_count, shared_seq, seq2;

	pvt_count = mail_index_view_get_messages_count(box->view_pvt);
	mail_index_lookup_first(box->view_pvt, 0, MAIL_SEEN, &pvt_seq);
	if (pvt_seq == 0)
		pvt_seq = pvt_count+1;
	for (; pvt_seq <= pvt_count; pvt_seq++) {
		pvt_rec = mail_index_lookup(box->view_pvt, pvt_seq);
		if ((pvt_rec->flags & MAIL_SEEN) == 0 &&
		    mail_index_lookup_seq(box->view, pvt_rec->uid, &shared_seq))
			return shared_seq;
	}
	/* if shared index has any messages that don't exist in private index,
	   the first of them is the first unseen message */
	pvt_hdr = mail_index_get_header(box->view_pvt);
	if (mail_index_lookup_seq_range(box->view,
					pvt_hdr->next_uid, (uint32_t)-1,
					&shared_seq, &seq2))
		return shared_seq;
	return 0;
}
Example #4
0
static void view_lookup_uid(struct mail_index_view *view, uint32_t seq,
			    uint32_t *uid_r)
{
	i_assert(seq > 0 && seq <= mail_index_view_get_messages_count(view));

	*uid_r = MAIL_INDEX_REC_AT_SEQ(view->map, seq)->uid;
}
struct mailbox_sync_context *
index_mailbox_sync_init(struct mailbox *box, enum mailbox_sync_flags flags,
			bool failed)
{
        struct index_mailbox_sync_context *ctx;
	struct index_mailbox_sync_pvt_context *pvt_ctx;
	enum mail_index_view_sync_flags sync_flags = 0;

	ctx = i_new(struct index_mailbox_sync_context, 1);
	ctx->ctx.box = box;
	ctx->ctx.flags = flags;

	if (failed) {
		ctx->failed = TRUE;
		return &ctx->ctx;
	}

	if ((flags & MAILBOX_SYNC_FLAG_NO_EXPUNGES) != 0)
		sync_flags |= MAIL_INDEX_VIEW_SYNC_FLAG_NOEXPUNGES;

	if ((flags & MAILBOX_SYNC_FLAG_FIX_INCONSISTENT) != 0) {
		sync_flags |= MAIL_INDEX_VIEW_SYNC_FLAG_FIX_INCONSISTENT;
		ctx->messages_count = 0;
	} else {
		ctx->messages_count =
			mail_index_view_get_messages_count(box->view);
	}

	if ((flags & MAILBOX_SYNC_FLAG_FAST) != 0) {
		/* we most likely did a fast sync. refresh the index anyway in
		   case there were some new changes. */
		(void)mail_index_refresh(box->index);
	}
	ctx->sync_ctx = mail_index_view_sync_begin(box->view, sync_flags);
	if ((flags & MAILBOX_SYNC_FLAG_NO_EXPUNGES) == 0) {
		mail_index_view_sync_get_expunges(ctx->sync_ctx,
						  &ctx->expunges);
		ctx->expunge_pos = array_count(ctx->expunges);
	}
	index_view_sync_recs_get(ctx);
	index_sync_search_results_expunge(ctx);

	/* sync private index if needed. it doesn't use box->view, so it
	   doesn't matter if it's called at _sync_init() or _sync_deinit().
	   however we also need to know if any private flags have changed
	   since last sync, so we need to call it before _sync_next() calls. */
	if (index_mailbox_sync_pvt_init(box, FALSE, &pvt_ctx) > 0) {
		(void)index_mailbox_sync_pvt_view(pvt_ctx, &ctx->flag_updates,
						  &ctx->hidden_updates);
		index_mailbox_sync_pvt_deinit(&pvt_ctx);

	}
	index_view_sync_cleanup_updates(ctx);
	return &ctx->ctx;
}
Example #6
0
void index_pop3_uidl_update_exists_finish(struct mailbox_transaction_context *trans)
{
	struct mail_index_view *view;
	struct mailbox_index_pop3_uidl uidl;
	const void *data;
	size_t size;
	bool seen_all_msgs;

	if (trans->highest_pop3_uidl_uid == 0)
		return;

	/* First check that we actually looked at UIDL for all messages.
	   Otherwise we can't say for sure if the newest messages had UIDLs. */
	if (trans->prev_pop3_uidl_tracking_seq !=
	    mail_index_view_get_messages_count(trans->view))
		return;

	/* Just to be sure: Refresh the index and check again. POP3 keeps
	   transactions open for duration of the entire session. Maybe another
	   process already added new mails (and already updated this header).
	   This check is racy, but normally UIDLs aren't added after migration
	   so it's a bit questionable if it's even worth having this check in
	   there. */
	view = mail_index_view_open(trans->box->index);
	seen_all_msgs = mail_index_refresh(trans->box->index) == 0 &&
		trans->prev_pop3_uidl_tracking_seq ==
		mail_index_view_get_messages_count(view);
	mail_index_view_close(&view);
	if (!seen_all_msgs)
		return;

	/* check if we have already the same header */
	mail_index_get_header_ext(trans->view, trans->box->pop3_uidl_hdr_ext_id,
				  &data, &size);
	if (size >= sizeof(uidl)) {
		memcpy(&uidl, data, size);
		if (trans->highest_pop3_uidl_uid == uidl.max_uid_with_pop3_uidl)
			return;
	}
	index_pop3_uidl_set_max_uid(trans->box, trans->itrans,
				    trans->highest_pop3_uidl_uid);
}
Example #7
0
static void imapc_sync_expunge_eom(struct imapc_sync_context *ctx)
{
	struct imapc_mailbox *mbox = ctx->mbox;
	uint32_t lseq, uid, msg_count;

	if (mbox->sync_next_lseq == 0)
		return;

	/* if we haven't seen FETCH reply for some messages at the end of
	   mailbox they've been externally expunged. */
	msg_count = mail_index_view_get_messages_count(ctx->sync_view);
	for (lseq = mbox->sync_next_lseq; lseq <= msg_count; lseq++) {
		mail_index_lookup_uid(ctx->sync_view, lseq, &uid);
		if (uid >= mbox->sync_uid_next) {
			/* another process already added new messages to index
			   that our IMAP connection hasn't seen yet */
			break;
		}
		mail_index_expunge(ctx->trans, lseq);
	}

	mbox->sync_next_lseq = 0;
	mbox->sync_next_rseq = 0;
}
static int mailbox_list_index_parse_records(struct mailbox_list_index *ilist,
					    struct mail_index_view *view,
					    const char **error_r)
{
	struct mailbox_list_index_node *node;
	const struct mail_index_record *rec;
	const struct mailbox_list_index_record *irec;
	const void *data;
	bool expunged;
	uint32_t seq, uid, count;

	*error_r = NULL;

	count = mail_index_view_get_messages_count(view);
	for (seq = 1; seq <= count; seq++) {
		node = p_new(ilist->mailbox_pool,
			     struct mailbox_list_index_node, 1);
		rec = mail_index_lookup(view, seq);
		node->uid = rec->uid;
		node->flags = rec->flags;

		mail_index_lookup_ext(view, seq, ilist->ext_id,
				      &data, &expunged);
		if (data == NULL) {
			*error_r = "Missing list extension data";
			return -1;
		}
		irec = data;

		node->name_id = irec->name_id;
		node->name = hash_table_lookup(ilist->mailbox_names,
					       POINTER_CAST(irec->name_id));
		if (node->name == NULL) {
			*error_r = "name_id not in index header";
			if (ilist->has_backing_store)
				return -1;
			/* generate a new name and use it */
			mailbox_list_index_generate_name(ilist, node);
		}
		hash_table_insert(ilist->mailbox_hash,
				  POINTER_CAST(node->uid), node);
	}

	/* do a second scan to create the actual mailbox tree hierarchy.
	   this is needed because the parent_uid may be smaller or higher than
	   the current node's uid */
	for (seq = 1; seq <= count; seq++) {
		mail_index_lookup_uid(view, seq, &uid);
		mail_index_lookup_ext(view, seq, ilist->ext_id,
				      &data, &expunged);
		irec = data;

		node = mailbox_list_index_lookup_uid(ilist, uid);
		i_assert(node != NULL);

		if (irec->parent_uid != 0) {
			/* node should have a parent */
			node->parent = mailbox_list_index_lookup_uid(ilist,
							irec->parent_uid);
			if (node->parent != NULL) {
				node->next = node->parent->children;
				node->parent->children = node;
				continue;
			}
			*error_r = "parent_uid points to nonexistent record";
			if (ilist->has_backing_store)
				return -1;
			/* just place it under the root */
		}
		node->next = ilist->mailbox_tree;
		ilist->mailbox_tree = node;
	}
	return *error_r == NULL ? 0 : -1;
}
Example #9
0
unsigned int mdbox_map_get_messages_count(struct mdbox_map *map)
{
	return mail_index_view_get_messages_count(map->view);
}
Example #10
0
static const struct mail_index_record *
view_lookup_full(struct mail_index_view *view, uint32_t seq,
		 struct mail_index_map **map_r, bool *expunged_r)
{
	static struct mail_index_record broken_rec;
	struct mail_index_map *map;
	const struct mail_index_record *rec, *head_rec;

	i_assert(seq > 0 && seq <= mail_index_view_get_messages_count(view));

	/* look up the record */
	rec = MAIL_INDEX_REC_AT_SEQ(view->map, seq);
	if (unlikely(rec->uid == 0)) {
		if (!view->inconsistent) {
			mail_index_set_error(view->index,
				"Corrupted Index file %s: Record [%u].uid=0",
				view->index->filepath, seq);
			(void)mail_index_fsck(view->index);
			view->inconsistent = TRUE;
		}

		/* we'll need to return something so the caller doesn't crash */
		*map_r = view->map;
		if (expunged_r != NULL)
			*expunged_r = TRUE;
		return &broken_rec;
	}
	if (view->map == view->index->map) {
		/* view's mapping is latest. we can use it directly. */
		*map_r = view->map;
		if (expunged_r != NULL)
			*expunged_r = FALSE;
		return rec;
	}

	/* look up the record from head mapping. it may contain some changes.

	   start looking up from the same sequence as in the old view.
	   if there are no expunges, it's there. otherwise it's somewhere
	   before (since records can't be inserted).

	   usually there are only a few expunges, so just going downwards from
	   our initial sequence position is probably faster than binary
	   search. */
	if (seq > view->index->map->hdr.messages_count)
		seq = view->index->map->hdr.messages_count;
	if (seq == 0) {
		/* everything is expunged from head. use the old record. */
		*map_r = view->map;
		if (expunged_r != NULL)
			*expunged_r = TRUE;
		return rec;
	}

	map = view->index->map;
	do {
		head_rec = MAIL_INDEX_REC_AT_SEQ(map, seq);
		if (head_rec->uid <= rec->uid)
			break;
	} while (--seq > 0);

	if (head_rec->uid == rec->uid) {
		/* found it. use it. reference the index mapping so that the
		   returned record doesn't get invalidated after next sync. */
		mail_index_view_ref_map(view, view->index->map);
		*map_r = view->index->map;
		if (expunged_r != NULL)
			*expunged_r = FALSE;
		return head_rec;
	} else {
		/* expuned from head. use the old record. */
		*map_r = view->map;
		if (expunged_r != NULL)
			*expunged_r = TRUE;
		return rec;
	}
}