struct mailbox_list_iterate_context *
mailbox_list_subscriptions_iter_init(struct mailbox_list *list,
				     const char *const *patterns,
				     enum mailbox_list_iter_flags flags)
{
	struct subscriptions_mailbox_list_iterate_context *ctx;
	pool_t pool;
	char sep = mail_namespace_get_sep(list->ns);

	pool = pool_alloconly_create("mailbox list subscriptions iter", 1024);
	ctx = p_new(pool, struct subscriptions_mailbox_list_iterate_context, 1);
	ctx->ctx.pool = pool;
	ctx->ctx.list = list;
	ctx->ctx.flags = flags;
	ctx->ctx.glob = imap_match_init_multiple(pool, patterns, TRUE, sep);
	array_create(&ctx->ctx.module_contexts, pool, sizeof(void *), 5);

	ctx->tree = mailbox_tree_init(sep);
	mailbox_list_subscriptions_fill(&ctx->ctx, ctx->tree, FALSE);

	ctx->info.ns = list->ns;
	/* the tree usually has only those entries we want to iterate through,
	   but there are also non-matching root entries (e.g. "LSUB foo/%" will
	   include the "foo"), which we'll drop with MAILBOX_MATCHED. */
	ctx->iter = mailbox_tree_iterate_init(ctx->tree, NULL, MAILBOX_MATCHED);
	return &ctx->ctx;
}
Esempio n. 2
0
static void
acl_mailbox_try_list_fast(struct acl_mailbox_list_iterate_context *ctx)
{
	struct acl_mailbox_list *alist = ACL_LIST_CONTEXT(ctx->ctx.list);
	struct acl_backend *backend = alist->rights.backend;
	const unsigned int *idxp;
	const struct acl_mask *acl_mask;
	struct acl_mailbox_list_context *nonowner_list_ctx;
	struct mail_namespace *ns = ctx->ctx.list->ns;
	struct mailbox_list_iter_update_context update_ctx;
	const char *name;
	int ret;

	if ((ctx->ctx.flags & (MAILBOX_LIST_ITER_RAW_LIST |
			       MAILBOX_LIST_ITER_SELECT_SUBSCRIBED)) != 0)
		return;

	if (ns->type == MAIL_NAMESPACE_TYPE_PUBLIC) {
		/* mailboxes in public namespace should all be listable to
		   someone. we don't benefit from fast listing. */
		return;
	}

	/* if this namespace's default rights contain LOOKUP, we'll need to
	   go through all mailboxes in any case. */
	idxp = alist->rights.acl_storage_right_idx + ACL_STORAGE_RIGHT_LOOKUP;
	if (acl_backend_get_default_rights(backend, &acl_mask) < 0 ||
	    acl_cache_mask_isset(acl_mask, *idxp))
		return;

	/* no LOOKUP right by default, we can optimize this */
	memset(&update_ctx, 0, sizeof(update_ctx));
	update_ctx.iter_ctx = &ctx->ctx;
	update_ctx.glob =
		imap_match_init(pool_datastack_create(), "*",
				(ns->flags & NAMESPACE_FLAG_INBOX_USER) != 0,
				ctx->sep);
	update_ctx.match_parents = TRUE;
	update_ctx.tree_ctx = mailbox_tree_init(ctx->sep);

	nonowner_list_ctx = acl_backend_nonowner_lookups_iter_init(backend);
	while ((ret = acl_backend_nonowner_lookups_iter_next(nonowner_list_ctx,
							     &name)) > 0) {
		T_BEGIN {
			const char *vname =
				mailbox_list_get_vname(ns->list, name);
			mailbox_list_iter_update(&update_ctx, vname);
		} T_END;
	}
	acl_backend_nonowner_lookups_iter_deinit(&nonowner_list_ctx);

	if (ret == 0)
		ctx->lookup_boxes = update_ctx.tree_ctx;
	else
		mailbox_tree_deinit(&update_ctx.tree_ctx);
}
struct mailbox_list_iterate_context *
maildir_list_iter_init(struct mailbox_list *_list, const char *const *patterns,
		       enum mailbox_list_iter_flags flags)
{
	struct maildir_mailbox_list *list =
		(struct maildir_mailbox_list *)_list;
	struct maildir_list_iterate_context *ctx;
	pool_t pool;
	char ns_sep = mail_namespace_get_sep(_list->ns);
	int ret;

	pool = pool_alloconly_create("mailbox list maildir iter", 1024);
	ctx = p_new(pool, struct maildir_list_iterate_context, 1);
	ctx->ctx.pool = pool;
	ctx->ctx.list = _list;
	ctx->ctx.flags = flags;
	ctx->ctx.glob = imap_match_init_multiple(pool, patterns, TRUE, ns_sep);
	array_create(&ctx->ctx.module_contexts, pool, sizeof(void *), 5);

	ctx->tree_ctx = mailbox_tree_init(ns_sep);
	ctx->info.ns = _list->ns;
	ctx->prefix_char = strcmp(_list->name, MAILBOX_LIST_NAME_IMAPDIR) == 0 ?
		'\0' : list->sep;

	ctx->dir = _list->set.root_dir;

	if ((flags & MAILBOX_LIST_ITER_SELECT_SUBSCRIBED) != 0) {
		/* Listing only subscribed mailboxes.
		   Flags are set later if needed. */
		bool default_nonexistent =
			(flags & MAILBOX_LIST_ITER_RETURN_NO_FLAGS) == 0;

		mailbox_list_subscriptions_fill(&ctx->ctx, ctx->tree_ctx,
						default_nonexistent);
	}

	if ((flags & MAILBOX_LIST_ITER_SELECT_SUBSCRIBED) == 0 ||
	    (flags & MAILBOX_LIST_ITER_RETURN_NO_FLAGS) == 0) {
		/* Add/update mailbox list with flags */
		bool update_only =
			(flags & MAILBOX_LIST_ITER_SELECT_SUBSCRIBED) != 0;

		T_BEGIN {
			ret = maildir_fill_readdir(ctx, ctx->ctx.glob,
						   update_only);
		} T_END;
		if (ret < 0) {
			ctx->ctx.failed = TRUE;
			return &ctx->ctx;
		}
	}
Esempio n. 4
0
static struct mailbox_list *imapc_list_alloc(void)
{
	struct imapc_mailbox_list *list;
	pool_t pool;

	pool = pool_alloconly_create("imapc mailbox list", 1024);
	list = p_new(pool, struct imapc_mailbox_list, 1);
	list->list = imapc_mailbox_list;
	list->list.pool = pool;
	/* separator is set lazily */
	list->mailboxes = mailbox_tree_init('\0');
	mailbox_tree_set_parents_nonexistent(list->mailboxes);
	return &list->list;
}
int mailbox_list_subscriptions_refresh(struct mailbox_list *src_list,
				       struct mailbox_list *dest_list)
{
	struct subsfile_list_context *subsfile_ctx;
	struct stat st;
	enum mailbox_list_path_type type;
	const char *path, *name;
	char sep;
	int ret;

	/* src_list is subscriptions=yes, dest_list is subscriptions=no
	   (or the same as src_list) */
	i_assert((src_list->ns->flags & NAMESPACE_FLAG_SUBSCRIPTIONS) != 0);

	if (dest_list->subscriptions == NULL) {
		sep = mail_namespace_get_sep(src_list->ns);
		dest_list->subscriptions = mailbox_tree_init(sep);
	}

	type = src_list->set.control_dir != NULL ?
		MAILBOX_LIST_PATH_TYPE_CONTROL : MAILBOX_LIST_PATH_TYPE_DIR;
	if (!mailbox_list_get_root_path(src_list, type, &path) ||
	    src_list->set.subscription_fname == NULL) {
		/* no subscriptions (e.g. pop3c) */
		return 0;
	}
	path = t_strconcat(path, "/", src_list->set.subscription_fname, NULL);
	if (stat(path, &st) < 0) {
		if (errno == ENOENT) {
			/* no subscriptions */
			mailbox_tree_clear(dest_list->subscriptions);
			dest_list->subscriptions_mtime = 0;
			return 0;
		}
		mailbox_list_set_critical(dest_list, "stat(%s) failed: %m",
					  path);
		return -1;
	}
	if (st.st_mtime == dest_list->subscriptions_mtime &&
	    st.st_mtime < dest_list->subscriptions_read_time-1) {
		/* we're up to date */
		return 0;
	}

	mailbox_tree_clear(dest_list->subscriptions);
	dest_list->subscriptions_read_time = ioloop_time;

	subsfile_ctx = subsfile_list_init(dest_list, path);
	if (subsfile_list_fstat(subsfile_ctx, &st) == 0)
		dest_list->subscriptions_mtime = st.st_mtime;
	while ((name = subsfile_list_next(subsfile_ctx)) != NULL) T_BEGIN {
		T_BEGIN {
			ret = mailbox_list_subscription_fill_one(dest_list,
								 src_list, name);
		} T_END;
		if (ret < 0) {
			i_warning("Subscriptions file %s: "
				  "Removing invalid entry: %s",
				  path, name);
			(void)subsfile_set_subscribed(src_list, path,
				mailbox_list_get_temp_prefix(src_list),
				name, FALSE);

		}
	} T_END;

	if (subsfile_list_deinit(&subsfile_ctx) < 0) {
		dest_list->subscriptions_mtime = (time_t)-1;
		return -1;
	}
	return 0;
}