int acl_shared_namespaces_add(struct mail_namespace *ns)
{
	struct acl_user *auser = ACL_USER_CONTEXT(ns->user);
	struct acl_mailbox_list *alist = ACL_LIST_CONTEXT(ns->list);
	struct mail_storage *storage = mail_namespace_get_default_storage(ns);
	struct acl_lookup_dict_iter *iter;
	const char *name;

	i_assert(ns->type == MAIL_NAMESPACE_TYPE_SHARED);
	i_assert(strcmp(storage->name, MAIL_SHARED_STORAGE_NAME) == 0);

	if (ioloop_time < alist->last_shared_add_check + SHARED_NS_RETRY_SECS) {
		/* already added, don't bother rechecking */
		return 0;
	}
	alist->last_shared_add_check = ioloop_time;

	iter = acl_lookup_dict_iterate_visible_init(auser->acl_lookup_dict);
	while ((name = acl_lookup_dict_iterate_visible_next(iter)) != NULL) {
		T_BEGIN {
			acl_shared_namespace_add(ns, storage, name);
		} T_END;
	}
	return acl_lookup_dict_iterate_visible_deinit(&iter);
}
static int
index_storage_get_user_dict(struct mail_storage *err_storage,
			    struct mail_user *user, struct dict **dict_r)
{
	struct dict_settings dict_set;
	struct mail_namespace *ns;
	struct mail_storage *attr_storage;
	const char *error;

	if (user->_attr_dict != NULL) {
		*dict_r = user->_attr_dict;
		return 0;
	}
	if (user->attr_dict_failed) {
		mail_storage_set_internal_error(err_storage);
		return -1;
	}

	ns = mail_user_find_attribute_namespace(user);
	if (ns == NULL) {
		/* probably never happens? */
		mail_storage_set_error(err_storage, MAIL_ERROR_NOTPOSSIBLE,
			"Mailbox attributes not available for this mailbox");
		return -1;
	}
	attr_storage = mail_namespace_get_default_storage(ns);

	if (*attr_storage->set->mail_attribute_dict == '\0') {
		mail_storage_set_error(err_storage, MAIL_ERROR_NOTPOSSIBLE,
				       "Mailbox attributes not enabled");
		return -1;
	}

	memset(&dict_set, 0, sizeof(dict_set));
	dict_set.username = user->username;
	dict_set.base_dir = user->set->base_dir;
	if (dict_init(attr_storage->set->mail_attribute_dict, &dict_set,
		      &user->_attr_dict, &error) < 0) {
		mail_storage_set_critical(err_storage,
			"mail_attribute_dict: dict_init(%s) failed: %s",
			attr_storage->set->mail_attribute_dict, error);
		user->attr_dict_failed = TRUE;
		return -1;
	}
	*dict_r = user->_attr_dict;
	return 0;
}
static int
cmd_altmove_run(struct doveadm_mail_cmd_context *_ctx, struct mail_user *user)
{
	struct altmove_cmd_context *ctx = (struct altmove_cmd_context *)_ctx;
	const enum mailbox_list_iter_flags iter_flags =
		MAILBOX_LIST_ITER_NO_AUTO_BOXES |
		MAILBOX_LIST_ITER_RETURN_NO_FLAGS;
	struct doveadm_mailbox_list_iter *iter;
	const struct mailbox_info *info;
	struct mail_namespace *ns, *prev_ns = NULL;
	ARRAY(struct mail_storage *) purged_storages;
	struct mail_storage *const *storages, *ns_storage, *prev_storage = NULL;
	unsigned int i, count;
	int ret = 0;

	t_array_init(&purged_storages, 8);
	iter = doveadm_mailbox_list_iter_init(_ctx, user, _ctx->search_args,
					      iter_flags);
	while ((info = doveadm_mailbox_list_iter_next(iter)) != NULL) T_BEGIN {
		ns_storage = mail_namespace_get_default_storage(info->ns);
		if (ns_storage != prev_storage) {
			if (prev_storage != NULL) {
				if (ns_purge(_ctx, prev_ns, prev_storage) < 0)
					ret = -1;
				array_append(&purged_storages,
					     &prev_storage, 1);
			}
			prev_storage = ns_storage;
			prev_ns = info->ns;
		}
		if (cmd_altmove_box(_ctx, info, _ctx->search_args, ctx->reverse) < 0)
			ret = -1;
	} T_END;
	if (doveadm_mailbox_list_iter_deinit(&iter) < 0)
		ret = -1;

	if (prev_storage != NULL) {
		if (ns_purge(_ctx, prev_ns, prev_storage) < 0)
			ret = -1;
		array_append(&purged_storages, &prev_storage, 1);
	}

	/* make sure all private storages have been purged */
	storages = array_get(&purged_storages, &count);
	for (ns = user->namespaces; ns != NULL; ns = ns->next) {
		if (ns->type != MAIL_NAMESPACE_TYPE_PRIVATE)
			continue;

		ns_storage = mail_namespace_get_default_storage(ns);
		for (i = 0; i < count; i++) {
			if (ns_storage == storages[i])
				break;
		}
		if (i == count) {
			if (ns_purge(_ctx, ns, ns_storage) < 0)
				ret = -1;
			array_append(&purged_storages, &ns_storage, 1);
			storages = array_get(&purged_storages, &count);
		}
	}
	return ret;
}