[dovecot-cvs] dovecot/src/plugins/acl Makefile.am, 1.4, 1.5 acl-api-private.h, 1.5, 1.6 acl-api.c, 1.6, 1.7 acl-api.h, 1.4, 1.5 acl-backend-vfile-acllist.c, NONE, 1.1 acl-backend-vfile.c, 1.18, 1.19 acl-backend-vfile.h, NONE, 1.1 acl-backend.c, 1.6, 1.7 acl-cache.c, 1.7, 1.8 acl-cache.h, 1.3, 1.4 acl-mailbox-list.c, 1.5, 1.6 acl-plugin.c, 1.5, 1.6 acl-storage.c, 1.6, 1.7

tss at dovecot.org tss at dovecot.org
Wed Apr 11 22:33:40 EEST 2007


Update of /var/lib/cvs/dovecot/src/plugins/acl
In directory talvi:/tmp/cvs-serv4498

Modified Files:
	Makefile.am acl-api-private.h acl-api.c acl-api.h 
	acl-backend-vfile.c acl-backend.c acl-cache.c acl-cache.h 
	acl-mailbox-list.c acl-plugin.c acl-storage.c 
Added Files:
	acl-backend-vfile-acllist.c acl-backend-vfile.h 
Log Message:
Create dovecot-acl-list file that lists all mailboxes where non-owner has
lookup right. Use the file when listing mailboxes in shared/public
namespace.



Index: Makefile.am
===================================================================
RCS file: /var/lib/cvs/dovecot/src/plugins/acl/Makefile.am,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -d -r1.4 -r1.5
--- Makefile.am	29 Mar 2007 11:51:09 -0000	1.4
+++ Makefile.am	11 Apr 2007 19:33:37 -0000	1.5
@@ -1,6 +1,7 @@
 AM_CPPFLAGS = \
 	-I$(top_srcdir)/src/lib \
 	-I$(top_srcdir)/src/lib-mail \
+	-I$(top_srcdir)/src/lib-imap \
 	-I$(top_srcdir)/src/lib-index \
 	-I$(top_srcdir)/src/lib-storage
 
@@ -13,6 +14,7 @@
 	acl-api.c \
 	acl-backend.c \
 	acl-backend-vfile.c \
+	acl-backend-vfile-acllist.c \
 	acl-cache.c \
 	acl-mailbox.c \
 	acl-mailbox-list.c \
@@ -22,6 +24,7 @@
 noinst_HEADERS = \
 	acl-api.h \
 	acl-api-private.h \
+	acl-backend-vfile.h \
 	acl-cache.h \
 	acl-plugin.h
 

Index: acl-api-private.h
===================================================================
RCS file: /var/lib/cvs/dovecot/src/plugins/acl/acl-api-private.h,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -d -r1.5 -r1.6
--- acl-api-private.h	11 Apr 2007 11:02:31 -0000	1.5
+++ acl-api-private.h	11 Apr 2007 19:33:37 -0000	1.6
@@ -8,6 +8,13 @@
 	int (*init)(struct acl_backend *backend, const char *data);
 	void (*deinit)(struct acl_backend *backend);
 
+	struct acl_mailbox_list_context *
+		(*nonowner_lookups_iter_init)(struct acl_backend *backend);
+	int (*nonowner_lookups_iter_next)(struct acl_mailbox_list_context *ctx,
+					  const char **name_r);
+	void (*nonowner_lookups_iter_deinit)
+		(struct acl_mailbox_list_context *ctx);
+
 	struct acl_object *(*object_init)(struct acl_backend *backend,
 					  struct mail_storage *storage,
 					  const char *name);
@@ -15,7 +22,7 @@
 
 	int (*object_refresh_cache)(struct acl_object *aclobj);
 	int (*object_update)(struct acl_object *aclobj,
-			     const struct acl_rights *rights);
+			     const struct acl_rights_update *rights);
 
 	struct acl_object_list_iter *
 		(*object_list_init)(struct acl_object *aclobj);
@@ -26,7 +33,7 @@
 
 struct acl_backend {
 	pool_t pool;
-	const char *username, *owner_username;
+	const char *username;
 	const char **groups;
 	unsigned int group_count;
 
@@ -38,9 +45,14 @@
 
 	struct acl_backend_vfuncs v;
 
+	unsigned int owner:1;
 	unsigned int debug:1;
 };
 
+struct acl_mailbox_list_context {
+	struct acl_backend *backend;
+};
+
 struct acl_object {
 	struct acl_backend *backend;
 	char *name;
@@ -48,6 +60,12 @@
 
 struct acl_object_list_iter {
 	struct acl_object *aclobj;
+
+	unsigned int idx;
+	unsigned int failed:1;
 };
 
+int acl_backend_get_default_rights(struct acl_backend *backend,
+				   const struct acl_mask **mask_r);
+
 #endif

Index: acl-api.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/plugins/acl/acl-api.c,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -d -r1.6 -r1.7
--- acl-api.c	11 Apr 2007 12:08:22 -0000	1.6
+++ acl-api.c	11 Apr 2007 19:33:37 -0000	1.7
@@ -20,23 +20,10 @@
 	aclobj->backend->v.object_deinit(aclobj);
 }
 
-static int acl_backend_get_default_rights(struct acl_backend *backend,
-					  const struct acl_mask **mask_r)
-{
-	if (backend->v.object_refresh_cache(backend->default_aclobj) < 0)
-		return -1;
-
-	*mask_r = acl_cache_get_my_rights(backend->cache, "");
-	if (*mask_r == NULL)
-		*mask_r = backend->default_aclmask;
-	return 0;
-}
-
 int acl_object_have_right(struct acl_object *aclobj, unsigned int right_idx)
 {
 	struct acl_backend *backend = aclobj->backend;
 	const struct acl_mask *have_mask;
-	unsigned int mask_idx;
 
 	if (*aclobj->name == '\0') {
 		/* we want to look up default rights */
@@ -55,10 +42,7 @@
 		}
 	}
 
-	mask_idx = right_idx / CHAR_BIT;
-	return mask_idx < have_mask->size &&
-		(have_mask->mask[mask_idx] &
-		 (1 << (right_idx % CHAR_BIT))) != 0;
+	return acl_cache_mask_isset(have_mask, right_idx);
 }
 
 int acl_object_get_my_rights(struct acl_object *aclobj, pool_t pool,
@@ -118,7 +102,7 @@
 }
 
 int acl_object_update(struct acl_object *aclobj,
-		      const struct acl_rights *rights)
+		      const struct acl_rights_update *rights)
 {
         return aclobj->backend->v.object_update(aclobj, rights);
 }
@@ -131,7 +115,10 @@
 int acl_object_list_next(struct acl_object_list_iter *iter,
                          struct acl_rights *rights_r)
 {
-        return iter->aclobj->backend->v.object_list_next(iter, rights_r);
+	if (iter->failed)
+		return -1;
+
+	return iter->aclobj->backend->v.object_list_next(iter, rights_r);
 }
 
 void acl_object_list_deinit(struct acl_object_list_iter **_iter)
@@ -141,3 +128,24 @@
 	*_iter = NULL;
         iter->aclobj->backend->v.object_list_deinit(iter);
 }
+
+struct acl_mailbox_list_context *
+acl_backend_nonowner_lookups_iter_init(struct acl_backend *backend)
+{
+	return backend->v.nonowner_lookups_iter_init(backend);
+}
+
+int acl_backend_nonowner_lookups_iter_next(struct acl_mailbox_list_context *ctx,
+					   const char **name_r)
+{
+	return ctx->backend->v.nonowner_lookups_iter_next(ctx, name_r);
+}
+
+void
+acl_backend_nonowner_lookups_iter_deinit(struct acl_mailbox_list_context **_ctx)
+{
+	struct acl_mailbox_list_context *ctx = *_ctx;
+
+	*_ctx = NULL;
+	ctx->backend->v.nonowner_lookups_iter_deinit(ctx);
+}

Index: acl-api.h
===================================================================
RCS file: /var/lib/cvs/dovecot/src/plugins/acl/acl-api.h,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -d -r1.4 -r1.5
--- acl-api.h	11 Apr 2007 12:08:50 -0000	1.4
+++ acl-api.h	11 Apr 2007 19:33:37 -0000	1.5
@@ -27,16 +27,19 @@
 /* Allow changing ACL state in this mailbox */
 #define MAIL_ACL_ADMIN		"admin"
 
+/* ACL identifiers in override order */
 enum acl_id_type {
 	/* Anyone's rights, including anonymous's.
 	   identifier name is ignored. */
 	ACL_ID_ANYONE,
-	/* Authenticate users' rights, overrides anyone's rights.
-	   identifier name is ignored. */
+	/* Authenticate users' rights. identifier name is ignored. */
 	ACL_ID_AUTHENTICATED,
-	/* Group's rights, overrides authenticated users' rights */
+	/* Group's rights */
 	ACL_ID_GROUP,
-	/* User's rights, overrides group's rights */
+	/* Owner's rights, used when user is the storage's owner.
+	   identifier name is ignored. */
+	ACL_ID_OWNER,
+	/* User's rights */
 	ACL_ID_USER,
 	/* Same as group's rights, but also overrides user's rights */
 	ACL_ID_GROUP_OVERRIDE,
@@ -63,8 +66,11 @@
 	const char *const *rights;
 	/* Negative rights assigned */
 	const char *const *neg_rights;
+};
+
+struct acl_rights_update {
+	struct acl_rights rights;
 
-	/* For set: */
 	enum acl_modify_mode modify_mode;
 	enum acl_modify_mode neg_modify_mode;
 };
@@ -75,10 +81,12 @@
 struct acl_backend *
 acl_backend_init(const char *data, struct mailbox_list *list,
 		 const char *acl_username, const char *const *groups,
-		 const char *owner_username);
+		 bool owner);
 void acl_backend_deinit(struct acl_backend **backend);
 /* Returns TRUE if user isn't anonymous. */
 bool acl_backend_user_is_authenticated(struct acl_backend *backend);
+/* Returns TRUE if user owns the storage. */
+bool acl_backend_user_is_owner(struct acl_backend *backend);
 /* Returns TRUE if given name matches the ACL user name. */
 bool acl_backend_user_name_equals(struct acl_backend *backend,
 				  const char *username);
@@ -89,6 +97,14 @@
 unsigned int acl_backend_lookup_right(struct acl_backend *backend,
 				      const char *right);
 
+/* List mailboxes that have lookup right to some non-owners. */
+struct acl_mailbox_list_context *
+acl_backend_nonowner_lookups_iter_init(struct acl_backend *backend);
+int acl_backend_nonowner_lookups_iter_next(struct acl_mailbox_list_context *ctx,
+					   const char **name_r);
+void
+acl_backend_nonowner_lookups_iter_deinit(struct acl_mailbox_list_context **ctx);
+
 struct acl_object *acl_object_init_from_name(struct acl_backend *backend,
 					     struct mail_storage *storage,
 					     const char *name);
@@ -103,7 +119,7 @@
 
 /* Update ACL of given object. */
 int acl_object_update(struct acl_object *aclobj,
-		      const struct acl_rights *rights);
+		      const struct acl_rights_update *rights);
 
 /* List all identifiers. */
 struct acl_object_list_iter *acl_object_list_init(struct acl_object *aclobj);

--- NEW FILE: acl-backend-vfile-acllist.c ---
/* Copyright (C) 2007 Timo Sirainen */

#include "lib.h"
#include "array.h"
#include "str.h"
#include "safe-mkstemp.h"
#include "istream.h"
#include "ostream.h"
#include "mail-namespace.h"
#include "mail-storage.h"
#include "acl-plugin.h"
#include "acl-cache.h"
#include "acl-backend-vfile.h"

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>

struct acl_mailbox_list_context_vfile {
	struct acl_mailbox_list_context ctx;

	unsigned int acllist_change_counter;
	unsigned int idx;
};

static void
acllist_clear(struct acl_backend_vfile *backend, uoff_t file_size)
{
	backend->acllist_change_counter++;
	if (backend->acllist_pool == NULL) {
		backend->acllist_pool =
			pool_alloconly_create("vfile acllist",
					      I_MAX(file_size / 2, 128));
		i_array_init(&backend->acllist, I_MAX(16, file_size / 60));
	} else {
		p_clear(backend->acllist_pool);
		array_clear(&backend->acllist);
	}
}

static int acl_backend_vfile_acllist_read(struct acl_backend_vfile *backend)
{
	struct acl_backend_vfile_acllist acllist;
	struct istream *input;
	struct stat st;
	const char *rootdir, *path, *line, *p;
	int fd, ret = 0;

	backend->acllist_last_check = ioloop_time;

	rootdir = mailbox_list_get_path(backend->backend.list, NULL,
					MAILBOX_LIST_PATH_TYPE_DIR);
	path = t_strdup_printf("%s/"ACLLIST_FILENAME, rootdir);

	if (backend->acllist_mtime != 0) {
		/* see if the file's mtime has changed */
		if (stat(path, &st) < 0) {
			if (errno == ENOENT)
				backend->acllist_mtime = 0;
			else
				i_error("stat(%s) failed: %m", path);
			return -1;
		}
		if (st.st_mtime == backend->acllist_mtime)
			return 0;
	}

	fd = open(path, O_RDONLY);
	if (fd == -1) {
		if (errno == ENOENT) {
			backend->acllist_mtime = 0;
			return -1;
		}
		i_error("open(%s) failed: %m", path);
		return -1;
	}
	if (fstat(fd, &st) < 0) {
		i_error("fstat(%s) failed: %m", path);
		(void)close(fd);
		return -1;
	}
	backend->acllist_mtime = st.st_mtime;
	acllist_clear(backend, st.st_size);

	input = i_stream_create_file(fd, default_pool, (size_t)-1, FALSE);
	while ((line = i_stream_read_next_line(input)) != NULL) {
		acllist.mtime = 0;
		for (p = line; *p >= '0' && *p <= '9'; p++)
			acllist.mtime = acllist.mtime * 10 + (*p - '0');

		if (p == line || *p != ' ' || p[1] == '\0') {
			i_error("Broken acllist file: %s", path);
			if (unlink(path) < 0 && errno != ENOENT)
				i_error("unlink(%s) failed: %m", path);
			return -1;
		}
		acllist.name = p_strdup(backend->acllist_pool, p + 1);
		array_append(&backend->acllist, &acllist, 1);
	}
	if (input->stream_errno != 0)
		ret = -1;
	i_stream_destroy(&input);

	if (close(fd) < 0)
		i_error("close(%s) failed: %m", path);
	return ret;
}

void acl_backend_vfile_acllist_refresh(struct acl_backend_vfile *backend)
{
	if (backend->acllist_last_check + backend->cache_secs > ioloop_time)
		return;

	if (acl_backend_vfile_acllist_read(backend) < 0) {
		acllist_clear(backend, 0);
		if (!backend->rebuilding_acllist)
			(void)acl_backend_vfile_acllist_rebuild(backend);
	}
}

static bool rights_has_lookup_changes(const struct acl_rights *rights)
{
	const char *const *p;

	if (rights->id_type == ACL_ID_OWNER) {
		/* ignore owner rights */
		return FALSE;
	}

	if (rights->rights == NULL)
		return FALSE;

	for (p = rights->rights; *p != NULL; p++) {
		if (strcmp(*p, MAIL_ACL_LOOKUP) == 0)
			return TRUE;
	}
	return FALSE;
}

static int
acllist_append(struct acl_backend_vfile *backend, struct ostream *output,
	       struct mail_storage *storage, const char *name)
{
	struct acl_object *aclobj;
	struct acl_object_list_iter *iter;
	struct acl_rights rights;
	struct acl_backend_vfile_acllist acllist;
	const char *line;
	int ret;

	acl_cache_flush(backend->backend.cache, name);
	aclobj = acl_object_init_from_name(&backend->backend, storage, name);

	iter = acl_object_list_init(aclobj);
	while ((ret = acl_object_list_next(iter, &rights)) > 0) {
		if (rights_has_lookup_changes(&rights))
			break;
	}
	acl_object_list_deinit(&iter);

	if (acl_backend_vfile_object_get_mtime(aclobj, &acllist.mtime) < 0)
		ret = -1;

	if (ret > 0) {
		acllist.name = p_strdup(backend->acllist_pool, name);
		array_append(&backend->acllist, &acllist, 1);

		t_push();
		line = t_strdup_printf("%s %s\n", dec2str(acllist.mtime), name);
		o_stream_send_str(output, line);
		t_pop();
	}
	acl_object_deinit(&aclobj);
	return ret < 0 ? -1 : 0;
}

int acl_backend_vfile_acllist_rebuild(struct acl_backend_vfile *backend)
{
	struct mailbox_list *list = backend->backend.list;
	struct mail_namespace *ns;
	struct mailbox_list_iterate_context *iter;
	struct mailbox_info *info;
	const char *rootdir, *acllist_path;
	struct ostream *output;
	struct stat st;
	string_t *path;
	mode_t mode;
	uid_t uid;
	gid_t gid;
	int fd, ret;

	ret = mailbox_list_get_permissions(list, NULL, &mode, &uid, &gid);
	if (ret <= 0) {
		/* Return success if the whole root directory was lost */
		return ret;
	}

	path = t_str_new(256);
	rootdir = mailbox_list_get_path(list, NULL,
					MAILBOX_LIST_PATH_TYPE_DIR);
	str_printfa(path, "%s/%s", rootdir, mailbox_list_get_temp_prefix(list));

	/* Build it into a temporary file and rename() over. There's no need
	   to use locking, because even if multiple processes are rebuilding
	   the file at the same time the result should be the same. */
	fd = safe_mkstemp(path, mode, uid, gid);
	if (fd == -1)
		return -1;
	output = o_stream_create_file(fd, default_pool, 0, FALSE);

	ret = 0;
	acllist_clear(backend, 0);
	ns = mailbox_list_get_namespace(list);

	backend->rebuilding_acllist = TRUE;
	iter = mailbox_list_iter_init(list, "*", MAILBOX_LIST_ITER_FAST_FLAGS |
				      MAILBOX_LIST_ITER_RAW_LIST);
	while ((info = mailbox_list_iter_next(iter)) != NULL) {
		if (acllist_append(backend, output, ns->storage,
				   info->name) < 0) {
			ret = -1;
			break;
		}
	}

	if (mailbox_list_iter_deinit(&iter) < 0)
		ret = -1;
	o_stream_destroy(&output);
	backend->rebuilding_acllist = FALSE;

	if (ret == 0) {
		if (fstat(fd, &st) < 0) {
			i_error("fstat(%s) failed: %m", str_c(path));
			ret = -1;
		}
	}
	if (close(fd) < 0) {
		i_error("close(%s) failed: %m", str_c(path));
		ret = -1;
	}

	if (ret == 0) {
		acllist_path = t_strdup_printf("%s/"ACLLIST_FILENAME, rootdir);
		if (rename(str_c(path), acllist_path) < 0) {
			i_error("rename(%s, %s) failed: %m",
				str_c(path), acllist_path);
			ret = -1;
		}
	}
	if (ret == 0) {
		backend->acllist_mtime = st.st_mtime;
		backend->acllist_last_check = ioloop_time;
	} else {
		acllist_clear(backend, 0);
		if (unlink(str_c(path)) < 0 && errno != ENOENT)
			i_error("unlink(%s) failed: %m", str_c(path));
	}
	return ret;
}

static const struct acl_backend_vfile_acllist *
acl_backend_vfile_acllist_find(struct acl_backend_vfile *backend,
			       const char *name)
{
	const struct acl_backend_vfile_acllist *acllist;
	unsigned int i, count;

	acllist = array_get(&backend->acllist, &count);
	for (i = 0; i < count; i++) {
		if (strcmp(acllist[i].name, name) == 0)
			return &acllist[i];
	}
	return NULL;
}

void acl_backend_vfile_acllist_verify(struct acl_backend_vfile *backend,
				      const char *name, time_t mtime)
{
	const struct acl_backend_vfile_acllist *acllist;

	acl_backend_vfile_acllist_refresh(backend);
	acllist = acl_backend_vfile_acllist_find(backend, name);
	if (acllist != NULL && acllist->mtime != mtime &&
	    !backend->rebuilding_acllist)
		(void)acl_backend_vfile_acllist_rebuild(backend);
}

struct acl_mailbox_list_context *
acl_backend_vfile_nonowner_iter_init(struct acl_backend *_backend)
{
	struct acl_backend_vfile *backend =
		(struct acl_backend_vfile *)_backend;
	struct acl_mailbox_list_context_vfile *ctx;

	acl_backend_vfile_acllist_refresh(backend);

	ctx = i_new(struct acl_mailbox_list_context_vfile, 1);
	ctx->ctx.backend = _backend;
	ctx->acllist_change_counter = backend->acllist_change_counter;
	return &ctx->ctx;
}

int acl_backend_vfile_nonowner_iter_next(struct acl_mailbox_list_context *_ctx,
					 const char **name_r)
{
	struct acl_mailbox_list_context_vfile *ctx =
		(struct acl_mailbox_list_context_vfile *)_ctx;
	struct acl_backend_vfile *backend =
		(struct acl_backend_vfile *)_ctx->backend;
	const struct acl_backend_vfile_acllist *acllist;
	unsigned int count;

	if (ctx->acllist_change_counter != backend->acllist_change_counter)
		return -1;

	acllist = array_get(&backend->acllist, &count);
	if (ctx->idx == count)
		return 0;

	*name_r = acllist[ctx->idx++].name;
	return 1;
}

void
acl_backend_vfile_nonowner_iter_deinit(struct acl_mailbox_list_context *ctx)
{
	i_free(ctx);
}

Index: acl-backend-vfile.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/plugins/acl/acl-backend-vfile.c,v
retrieving revision 1.18
retrieving revision 1.19
diff -u -d -r1.18 -r1.19
--- acl-backend-vfile.c	11 Apr 2007 19:31:29 -0000	1.18
+++ acl-backend-vfile.c	11 Apr 2007 19:33:37 -0000	1.19
@@ -1,4 +1,4 @@
-/* Copyright (C) 2006 Timo Sirainen */
+/* Copyright (C) 2006-2007 Timo Sirainen */
 
 #include "lib.h"
 #include "ioloop.h"
@@ -7,15 +7,13 @@
 #include "nfs-workarounds.h"
 #include "mail-storage-private.h"
 #include "acl-cache.h"
-#include "acl-api-private.h"
+#include "acl-backend-vfile.h"
 
 #include <stdlib.h>
 #include <fcntl.h>
 #include <unistd.h>
 #include <sys/stat.h>
 
-#define ACL_FILENAME "dovecot-acl"
-
 #define ACL_ESTALE_RETRY_COUNT NFS_ESTALE_RETRY_COUNT
 #define ACL_VFILE_DEFAULT_CACHE_SECS (60*5)
 
@@ -31,18 +29,6 @@
 	struct acl_vfile_validity global_validity, local_validity;
 };
 
-struct acl_backend_vfile {
-	struct acl_backend backend;
-	const char *global_dir;
-	unsigned int cache_secs;
-};
-
-struct acl_object_vfile {
-	struct acl_object aclobj;
-
-	char *global_path, *local_path;
-};
-
 struct acl_letter_map {
 	char letter;
 	const char *name;
@@ -148,6 +134,11 @@
 {
 	struct acl_object_vfile *aclobj = (struct acl_object_vfile *)_aclobj;
 
+	if (array_is_created(&aclobj->rights))
+		array_free(&aclobj->rights);
+	if (aclobj->rights_pool != NULL)
+		pool_unref(aclobj->rights_pool);
+
 	i_free(aclobj->local_path);
 	i_free(aclobj->global_path);
 	i_free(aclobj->aclobj.name);
@@ -155,11 +146,11 @@
 }
 
 static const char *const *
-acl_parse_rights(const char *acl, const char **error_r)
+acl_parse_rights(pool_t pool, const char *acl, const char **error_r)
 {
 	ARRAY_DEFINE(rights, const char *);
-	const char *const *names;
-	unsigned int i;
+	const char *const *names, **ret_rights;
+	unsigned int i, count;
 
 	/* parse IMAP ACL list */
 	while (*acl == ' ' || *acl == '\t')
@@ -180,29 +171,32 @@
 		array_append(&rights, &acl_letter_map[i].name, 1);
 	}
 
-	if (*acl == '\0') {
-		(void)array_append_space(&rights);
-		return array_idx(&rights, 0);
-	}
+	if (*acl != '\0') {
+		/* parse our own extended ACLs */
+		i_assert(*acl == ':');
 
-	/* parse our own extended ACLs */
-	i_assert(*acl == ':');
+		names = t_strsplit_spaces(acl, ", ");
+		for (; *names != NULL; names++) {
+			const char *name = p_strdup(pool, *names);
+			array_append(&rights, &name, 1);
+		}
+	}
 
-	names = t_strsplit_spaces(acl, ", ");
-	if (array_count(&rights) == 0)
-		return names;
-	
-	for (; *names != NULL; names++)
-		array_append(&rights, names, 1);
-	(void)array_append_space(&rights);
-	return array_idx(&rights, 0);
+	/* @UNSAFE */
+	count = array_count(&rights);
+	ret_rights = p_new(pool, const char *, count + 1);
+	if (count > 0) {
+		memcpy(ret_rights, array_idx(&rights, 0),
+		       sizeof(const char *) * count);
+	}
+	return ret_rights;
 }
 
 static int
-acl_object_vfile_parse_line(struct acl_object *aclobj, const char *path,
+acl_object_vfile_parse_line(struct acl_object_vfile *aclobj, const char *path,
 			    const char *line, unsigned int linenum)
 {
-	struct acl_rights rights;
+	struct acl_rights_update rights;
 	const char *p, *const *right_names, *error = NULL;
 
 	if (*line == '\0' || *line == '#')
@@ -220,35 +214,50 @@
 
 	memset(&rights, 0, sizeof(rights));
 
-	right_names = acl_parse_rights(p, &error);
+	right_names = acl_parse_rights(aclobj->rights_pool, p, &error);
 	if (*line != '-') {
 		rights.modify_mode = ACL_MODIFY_MODE_REPLACE;
-		rights.rights = right_names;
+		rights.rights.rights = right_names;
 	} else {
 		line++;
 		rights.neg_modify_mode = ACL_MODIFY_MODE_REPLACE;
-		rights.neg_rights = right_names;
+		rights.rights.neg_rights = right_names;
 	}
 
-	if (strncmp(line, "user=", 5) == 0) {
-		rights.id_type = ACL_ID_USER;
-		rights.identifier = line + 5;
-	} else if (strncmp(line, "group=", 6) == 0) {
-		rights.id_type = ACL_ID_GROUP;
-		rights.identifier = line + 6;
-	} else if (strncmp(line, "group-override=", 15) == 0) {
-		rights.id_type = ACL_ID_GROUP_OVERRIDE;
-		rights.identifier = line + 15;
-	} else if (strcmp(line, "owner") == 0) {
-		rights.id_type = ACL_ID_USER;
-		rights.identifier = aclobj->backend->owner_username;
-	} else if (strcmp(line, "authenticated") == 0) {
-		rights.id_type = ACL_ID_AUTHENTICATED;
-	} else if (strcmp(line, "anyone") == 0 ||
-		   strcmp(line, "anonymous") == 0) {
-		rights.id_type = ACL_ID_ANYONE;
-	} else {
+	switch (*line) {
+	case 'u':
+		if (strncmp(line, "user=", 5) == 0) {
+			rights.rights.id_type = ACL_ID_USER;
+			rights.rights.identifier = line + 5;
+			break;
+		}
+	case 'o':
+		if (strcmp(line, "owner") == 0) {
+			rights.rights.id_type = ACL_ID_OWNER;
+			break;
+		}
+	case 'g':
+		if (strncmp(line, "group=", 6) == 0) {
+			rights.rights.id_type = ACL_ID_GROUP;
+			rights.rights.identifier = line + 6;
+			break;
+		} else if (strncmp(line, "group-override=", 15) == 0) {
+			rights.rights.id_type = ACL_ID_GROUP_OVERRIDE;
+			rights.rights.identifier = line + 15;
+			break;
+		}
+	case 'a':
+		if (strcmp(line, "authenticated") == 0) {
+			rights.rights.id_type = ACL_ID_AUTHENTICATED;
+			break;
+		} else if (strcmp(line, "anyone") == 0 ||
+			   strcmp(line, "anonymous") == 0) {
+			rights.rights.id_type = ACL_ID_ANYONE;
+			break;
+		}
+	default:
 		error = t_strdup_printf("Unknown ID '%s'", line);
+		break;
 	}
 
 	if (error != NULL) {
@@ -257,14 +266,19 @@
 		return -1;
 	}
 
-	acl_cache_update(aclobj->backend->cache, aclobj->name, &rights);
+	rights.rights.identifier =
+		p_strdup(aclobj->rights_pool, rights.rights.identifier);
+	array_append(&aclobj->rights, &rights.rights, 1);
+
+	acl_cache_update(aclobj->aclobj.backend->cache,
+			 aclobj->aclobj.name, &rights);
 
 	t_pop();
 	return 0;
 }
 
 static int
-acl_backend_vfile_read(struct acl_object *aclobj, const char *path,
+acl_backend_vfile_read(struct acl_object_vfile *aclobj, const char *path,
 		       struct acl_vfile_validity *validity, bool try_retry,
 		       bool *is_dir_r)
 {
@@ -279,7 +293,7 @@
 	fd = nfs_safe_open(path, O_RDONLY);
 	if (fd == -1) {
 		if (errno == ENOENT) {
-			if (aclobj->backend->debug)
+			if (aclobj->aclobj.backend->debug)
 				i_info("acl vfile: file %s not found", path);
 
 			validity->last_size = 0;
@@ -308,11 +322,21 @@
 		return 0;
 	}
 
-	if (aclobj->backend->debug)
+	if (aclobj->aclobj.backend->debug)
 		i_info("acl vfile: reading file %s", path);
 
 	input = i_stream_create_file(fd, default_pool, 4096, FALSE);
 
+	if (!array_is_created(&aclobj->rights)) {
+		aclobj->rights_pool =
+			pool_alloconly_create("acl rights",
+					      I_MAX(256, st.st_size / 2));
+		i_array_init(&aclobj->rights, I_MAX(16, st.st_size / 40));
+	} else {
+		array_clear(&aclobj->rights);
+		p_clear(aclobj->rights_pool);
+	}
+
 	linenum = 1;
 	while ((line = i_stream_read_next_line(input)) != NULL) {
 		if (acl_object_vfile_parse_line(aclobj, path, line,
@@ -358,7 +382,8 @@
 }
 
 static int
-acl_backend_vfile_read_with_retry(struct acl_object *aclobj, const char *path,
+acl_backend_vfile_read_with_retry(struct acl_object_vfile *aclobj,
+				  const char *path,
 				  struct acl_vfile_validity *validity)
 {
 	unsigned int i;
@@ -427,11 +452,32 @@
 	return 1;
 }
 
+int acl_backend_vfile_object_get_mtime(struct acl_object *aclobj,
+				       time_t *mtime_r)
+{
+	struct acl_backend_vfile_validity *validity;
+
+	validity = acl_cache_get_validity(aclobj->backend->cache, aclobj->name);
+	if (validity == NULL)
+		return -1;
+
+	if (validity->local_validity.last_mtime != 0)
+		*mtime_r = validity->local_validity.last_mtime;
+	else if (validity->global_validity.last_mtime != 0)
+		*mtime_r = validity->global_validity.last_mtime;
+	else
+		*mtime_r = 0;
+	return 0;
+}
+
 static int acl_backend_vfile_object_refresh_cache(struct acl_object *_aclobj)
 {
 	struct acl_object_vfile *aclobj = (struct acl_object_vfile *)_aclobj;
+	struct acl_backend_vfile *backend =
+		(struct acl_backend_vfile *)_aclobj->backend;
 	struct acl_backend_vfile_validity *old_validity;
 	struct acl_backend_vfile_validity validity;
+	time_t mtime;
 	int ret;
 
 	old_validity = acl_cache_get_validity(_aclobj->backend->cache,
@@ -451,21 +497,25 @@
 	acl_cache_flush(_aclobj->backend->cache, _aclobj->name);
 
 	memset(&validity, 0, sizeof(validity));
-	if (acl_backend_vfile_read_with_retry(_aclobj, aclobj->global_path,
+	if (acl_backend_vfile_read_with_retry(aclobj, aclobj->global_path,
 					      &validity.global_validity) < 0)
 		return -1;
-	if (acl_backend_vfile_read_with_retry(_aclobj, aclobj->local_path,
+	if (acl_backend_vfile_read_with_retry(aclobj, aclobj->local_path,
 					      &validity.local_validity) < 0)
 		return -1;
 
 	acl_cache_set_validity(_aclobj->backend->cache,
 			       _aclobj->name, &validity);
+
+	if (acl_backend_vfile_object_get_mtime(_aclobj, &mtime) == 0)
+		acl_backend_vfile_acllist_verify(backend, _aclobj->name, mtime);
 	return 0;
 }
 
 static int
 acl_backend_vfile_object_update(struct acl_object *aclobj __attr_unused__,
-				const struct acl_rights *rights __attr_unused__)
+				const struct acl_rights_update *rights
+					__attr_unused__)
 {
 	/* FIXME */
 	return -1;
@@ -478,15 +528,27 @@
 
 	iter = i_new(struct acl_object_list_iter, 1);
 	iter->aclobj = aclobj;
+
+	if (aclobj->backend->v.object_refresh_cache(aclobj) < 0)
+		iter->failed = TRUE;
 	return iter;
 }
 
 static int
-acl_backend_vfile_object_list_next(struct acl_object_list_iter *iter
-				   	__attr_unused__,
-				   struct acl_rights *rights_r __attr_unused__)
+acl_backend_vfile_object_list_next(struct acl_object_list_iter *iter,
+				   struct acl_rights *rights_r)
 {
-	return -1;
+	struct acl_object_vfile *aclobj =
+		(struct acl_object_vfile *)iter->aclobj;
+	const struct acl_rights *rights;
+
+	if (!array_is_created(&aclobj->rights) ||
+	    iter->idx == array_count(&aclobj->rights))
+		return 0;
+
+	rights = array_idx(&aclobj->rights, iter->idx++);
+	*rights_r = *rights;
+	return 1;
 }
 
 static void
@@ -499,6 +561,9 @@
 	acl_backend_vfile_alloc,
 	acl_backend_vfile_init,
 	acl_backend_vfile_deinit,
+	acl_backend_vfile_nonowner_iter_init,
+	acl_backend_vfile_nonowner_iter_next,
+	acl_backend_vfile_nonowner_iter_deinit,
 	acl_backend_vfile_object_init,
 	acl_backend_vfile_object_deinit,
 	acl_backend_vfile_object_refresh_cache,

--- NEW FILE: acl-backend-vfile.h ---
#ifndef __ACL_BACKEND_VFILE_H
#define __ACL_BACKEND_VFILE_H

#include "acl-api-private.h"

#define ACL_FILENAME "dovecot-acl"
#define ACLLIST_FILENAME "dovecot-acl-list"

struct acl_object_vfile {
	struct acl_object aclobj;

	pool_t rights_pool;
	ARRAY_DEFINE(rights, struct acl_rights);

	char *global_path, *local_path;
};

struct acl_backend_vfile_acllist {
	time_t mtime;
	const char *name;
};

struct acl_backend_vfile {
	struct acl_backend backend;
	const char *global_dir;

	pool_t acllist_pool;
	ARRAY_DEFINE(acllist, struct acl_backend_vfile_acllist);

	time_t acllist_last_check;
	time_t acllist_mtime;
	unsigned int acllist_change_counter;

	unsigned int cache_secs;
	unsigned int rebuilding_acllist:1;
};

void acl_backend_vfile_acllist_refresh(struct acl_backend_vfile *backend);
int acl_backend_vfile_acllist_rebuild(struct acl_backend_vfile *backend);
void acl_backend_vfile_acllist_verify(struct acl_backend_vfile *backend,
				      const char *name, time_t mtime);

struct acl_mailbox_list_context *
acl_backend_vfile_nonowner_iter_init(struct acl_backend *backend);
int acl_backend_vfile_nonowner_iter_next(struct acl_mailbox_list_context *ctx,
					 const char **name_r);
void
acl_backend_vfile_nonowner_iter_deinit(struct acl_mailbox_list_context *ctx);

int acl_backend_vfile_object_get_mtime(struct acl_object *aclobj,
				       time_t *mtime_r);

#endif

Index: acl-backend.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/plugins/acl/acl-backend.c,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -d -r1.6 -r1.7
--- acl-backend.c	11 Apr 2007 11:02:31 -0000	1.6
+++ acl-backend.c	11 Apr 2007 19:33:37 -0000	1.7
@@ -28,18 +28,17 @@
 struct acl_backend *
 acl_backend_init(const char *data, struct mailbox_list *list,
 		 const char *acl_username, const char *const *groups,
-		 const char *owner_username)
+		 bool owner)
 {
 	struct acl_backend *backend;
 	unsigned int i, group_count;
-	bool storage_owner, debug;
+	bool debug;
 
 	debug = getenv("DEBUG") != NULL;
 	if (debug) {
 		i_info("acl: initializing backend with data: %s", data);
 		i_info("acl: acl username = %s", acl_username);
-		i_info("acl: owner username = %s",
-		       owner_username != NULL ? owner_username : "");
+		i_info("acl: owner = %d", owner);
 	}
 
 	group_count = strarray_length(groups);
@@ -56,8 +55,7 @@
 	backend->v = acl_backend_vfile;
 	backend->list = list;
 	backend->username = p_strdup(backend->pool, acl_username);
-	backend->owner_username = owner_username == NULL ? "" :
-		p_strdup(backend->pool, owner_username);
+	backend->owner = owner;
 
 	if (group_count > 0) {
 		backend->group_count = group_count;
@@ -72,11 +70,9 @@
 	if (acl_backend_vfile.init(backend, data) < 0)
 		i_fatal("acl: backend vfile init failed with data: %s", data);
 
-	storage_owner = owner_username != NULL &&
-		strcmp(acl_username, owner_username) == 0;
 	backend->default_aclmask =
 		acl_cache_mask_init(backend->cache, backend->pool,
-				    storage_owner ? owner_mailbox_rights :
+				    owner ? owner_mailbox_rights :
 				    non_owner_mailbox_rights);
 
 	backend->default_aclobj = acl_object_init_from_name(backend, NULL, "");
@@ -99,6 +95,11 @@
 	return backend->username != NULL;
 }
 
+bool acl_backend_user_is_owner(struct acl_backend *backend)
+{
+	return backend->owner;
+}
+
 bool acl_backend_user_name_equals(struct acl_backend *backend,
 				  const char *username)
 {
@@ -122,3 +123,15 @@
 {
 	return acl_cache_right_lookup(backend->cache, right);
 }
+
+int acl_backend_get_default_rights(struct acl_backend *backend,
+				   const struct acl_mask **mask_r)
+{
+	if (backend->v.object_refresh_cache(backend->default_aclobj) < 0)
+		return -1;
+
+	*mask_r = acl_cache_get_my_rights(backend->cache, "");
+	if (*mask_r == NULL)
+		*mask_r = backend->default_aclmask;
+	return 0;
+}

Index: acl-cache.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/plugins/acl/acl-cache.c,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -d -r1.7 -r1.8
--- acl-cache.c	10 Sep 2006 12:48:33 -0000	1.7
+++ acl-cache.c	11 Apr 2007 19:33:37 -0000	1.8
@@ -251,15 +251,15 @@
 static void
 acl_cache_update_rights(struct acl_cache *cache,
 			struct acl_object_cache *obj_cache,
-			const struct acl_rights *rights)
+			const struct acl_rights_update *rights)
 {
-	enum acl_id_type id_type = rights->id_type;
+	enum acl_id_type id_type = rights->rights.id_type;
 
 	acl_cache_update_rights_mask(cache, obj_cache, rights->modify_mode,
-				     rights->rights,
+				     rights->rights.rights,
 				     &obj_cache->my_rights[id_type]);
 	acl_cache_update_rights_mask(cache, obj_cache, rights->neg_modify_mode,
-				     rights->neg_rights,
+				     rights->rights.neg_rights,
 				     &obj_cache->my_neg_rights[id_type]);
 }
 
@@ -283,7 +283,7 @@
 }
 
 void acl_cache_update(struct acl_cache *cache, const char *objname,
-		      const struct acl_rights *rights)
+		      const struct acl_rights_update *rights)
 {
 	struct acl_object_cache *obj_cache;
 	bool created;
@@ -291,7 +291,7 @@
 	obj_cache = acl_cache_object_get(cache, objname, &created);
 	i_assert(obj_cache->my_current_rights != &negative_cache_entry);
 
-	switch (rights->id_type) {
+	switch (rights->rights.id_type) {
 	case ACL_ID_ANYONE:
 		acl_cache_update_rights(cache, obj_cache, rights);
 		break;
@@ -302,12 +302,16 @@
 	case ACL_ID_GROUP:
 	case ACL_ID_GROUP_OVERRIDE:
 		if (acl_backend_user_is_in_group(cache->backend,
-						 rights->identifier))
+						 rights->rights.identifier))
 			acl_cache_update_rights(cache, obj_cache, rights);
 		break;
 	case ACL_ID_USER:
 		if (acl_backend_user_name_equals(cache->backend,
-						 rights->identifier))
+						 rights->rights.identifier))
+			acl_cache_update_rights(cache, obj_cache, rights);
+		break;
+	case ACL_ID_OWNER:
+		if (acl_backend_user_is_owner(cache->backend))
 			acl_cache_update_rights(cache, obj_cache, rights);
 		break;
 	case ACL_ID_TYPE_COUNT:
@@ -402,3 +406,12 @@
 		acl_cache_my_current_rights_recalculate(obj_cache);
 	return obj_cache->my_current_rights;
 }
+
+bool acl_cache_mask_isset(const struct acl_mask *mask, unsigned int right_idx)
+{
+	unsigned int mask_idx;
+
+	mask_idx = right_idx / CHAR_BIT;
+	return mask_idx < mask->size &&
+		(mask->mask[mask_idx] & (1 << (right_idx % CHAR_BIT))) != 0;
+}

Index: acl-cache.h
===================================================================
RCS file: /var/lib/cvs/dovecot/src/plugins/acl/acl-cache.h,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -d -r1.3 -r1.4
--- acl-cache.h	30 May 2006 12:20:30 -0000	1.3
+++ acl-cache.h	11 Apr 2007 19:33:37 -0000	1.4
@@ -2,7 +2,7 @@
 #define __ACL_CACHE_H
 
 struct acl_backend;
-struct acl_rights;
+struct acl_rights_update;
 
 struct acl_mask {
 	pool_t pool;
@@ -34,7 +34,7 @@
 
 /* Update object ACLs. */
 void acl_cache_update(struct acl_cache *cache, const char *objname,
-		      const struct acl_rights *rights);
+		      const struct acl_rights_update *rights);
 /* Return ACL object validity, or NULL if object doesn't exit. */
 void *acl_cache_get_validity(struct acl_cache *cache, const char *objname);
 /* Update ACL object validity, creating the object if needed. */
@@ -51,4 +51,7 @@
 const struct acl_mask *
 acl_cache_get_my_rights(struct acl_cache *cache, const char *objname);
 
+/* Returns TRUE if given right index is set in mask. */
+bool acl_cache_mask_isset(const struct acl_mask *mask, unsigned int right_idx);
+
 #endif

Index: acl-mailbox-list.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/plugins/acl/acl-mailbox-list.c,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -d -r1.5 -r1.6
--- acl-mailbox-list.c	11 Apr 2007 11:02:31 -0000	1.5
+++ acl-mailbox-list.c	11 Apr 2007 19:33:37 -0000	1.6
@@ -2,8 +2,11 @@
 
 #include "lib.h"
 #include "array.h"
+#include "imap-match.h"
+#include "mailbox-tree.h"
 #include "mail-namespace.h"
 #include "mailbox-list-private.h"
+#include "acl-cache.h"
 #include "acl-api-private.h"
 #include "acl-plugin.h"
 
@@ -12,12 +15,23 @@
 #define ACL_LIST_CONTEXT(obj) \
 	MODULE_CONTEXT(obj, acl_mailbox_list_module)
 
+#define MAILBOX_FLAG_MATCHED 0x40000000
+
 struct acl_mailbox_list {
 	union mailbox_list_module_context module_ctx;
 
 	struct acl_storage_rights_context rights;
 };
 
+struct acl_mailbox_list_iterate_context {
+	struct mailbox_list_iterate_context ctx;
+	struct mailbox_list_iterate_context *super_ctx;
+
+	struct mailbox_tree_context *tree;
+	struct mailbox_tree_iterate_context *tree_iter;
+	struct mailbox_info info;
+};
+
 static MODULE_CONTEXT_DEFINE_INIT(acl_mailbox_list_module,
 				  &mailbox_list_module_register);
 
@@ -48,17 +62,127 @@
 						 can_see_r);
 }
 
+static bool
+acl_mailbox_try_list_fast(struct acl_mailbox_list_iterate_context *ctx,
+			  const char *mask)
+{
+	struct acl_mailbox_list *alist = ACL_LIST_CONTEXT(ctx->ctx.list);
+	struct acl_backend *backend = alist->rights.backend;
+	const unsigned int *idxp =
+		alist->rights.acl_storage_right_idx + ACL_STORAGE_RIGHT_LOOKUP;
+	const struct acl_mask *acl_mask;
+	struct acl_mailbox_list_context *nonowner_list_ctx;
+	struct imap_match_glob *glob;
+	struct mailbox_node *node;
+	const char *name;
+	char sep;
+	int try, ret;
+	bool created;
+
+	if ((ctx->ctx.flags & MAILBOX_LIST_ITER_RAW_LIST) != 0)
+		return FALSE;
+
+	if (acl_backend_get_default_rights(backend, &acl_mask) < 0 ||
+	    acl_cache_mask_isset(acl_mask, *idxp))
+		return FALSE;
+
+	/* default is to not list mailboxes. we can optimize this. */
+	t_push();
+	sep = mailbox_list_get_hierarchy_sep(ctx->ctx.list);
+	glob = imap_match_init(pool_datastack_create(), mask, TRUE, sep);
+
+	for (try = 0; try < 2; try++) {
+		nonowner_list_ctx =
+			acl_backend_nonowner_lookups_iter_init(backend);
+		ctx->tree = mailbox_tree_init(sep);
+
+		while ((ret = acl_backend_nonowner_lookups_iter_next(
+					nonowner_list_ctx, &name)) > 0) {
+			switch (imap_match(glob, name)) {
+			case IMAP_MATCH_YES:
+				node = mailbox_tree_get(ctx->tree, name,
+							&created);
+				if (created)
+					node->flags |= MAILBOX_NOCHILDREN;
+				node->flags |= MAILBOX_FLAG_MATCHED;
+				node->flags &= ~MAILBOX_NONEXISTENT;
+				break;
+			case IMAP_MATCH_PARENT:
+				node = mailbox_tree_get(ctx->tree, name,
+							&created);
+				if (created)
+					node->flags |= MAILBOX_NONEXISTENT;
+				node->flags |= MAILBOX_FLAG_MATCHED |
+					MAILBOX_CHILDREN;
+				node->flags &= ~MAILBOX_NOCHILDREN;
+				break;
+			default:
+				break;
+			}
+		}
+		if (ret == 0)
+			break;
+
+		/* try again */
+		mailbox_tree_deinit(&ctx->tree);
+		acl_backend_nonowner_lookups_iter_deinit(&nonowner_list_ctx);
+	}
+	t_pop();
+	if (ret < 0)
+		return FALSE;
+
+	ctx->tree_iter = mailbox_tree_iterate_init(ctx->tree, NULL,
+						   MAILBOX_FLAG_MATCHED);
+	return TRUE;
+}
+
+static struct mailbox_list_iterate_context *
+acl_mailbox_list_iter_init(struct mailbox_list *list, const char *mask,
+			   enum mailbox_list_iter_flags flags)
+{
+	struct acl_mailbox_list *alist = ACL_LIST_CONTEXT(list);
+	struct acl_mailbox_list_iterate_context *ctx;
+
+	ctx = i_new(struct acl_mailbox_list_iterate_context, 1);
+	ctx->ctx.list = list;
+	ctx->ctx.flags = flags;
+
+	if (!acl_mailbox_try_list_fast(ctx, mask)) {
+		ctx->super_ctx =
+			alist->module_ctx.super.iter_init(list, mask, flags);
+	}
+	return &ctx->ctx;
+}
+
 static struct mailbox_info *
-acl_mailbox_list_iter_next(struct mailbox_list_iterate_context *ctx)
+acl_mailbox_list_iter_next(struct mailbox_list_iterate_context *_ctx)
 {
-	struct acl_mailbox_list *alist = ACL_LIST_CONTEXT(ctx->list);
+	struct acl_mailbox_list_iterate_context *ctx =
+		(struct acl_mailbox_list_iterate_context *)_ctx;
+	struct acl_mailbox_list *alist = ACL_LIST_CONTEXT(_ctx->list);
 	struct mailbox_info *info;
+	struct mailbox_node *node;
 	int ret;
 
 	for (;;) {
-		info = alist->module_ctx.super.iter_next(ctx);
-		if (info == NULL)
-			return NULL;
+		if (ctx->tree_iter != NULL) {
+			node = mailbox_tree_iterate_next(ctx->tree_iter,
+							 &ctx->info.name);
+			if (node == NULL)
+				return NULL;
+			info = &ctx->info;
+			info->flags = node->flags;
+		} else {
+			info = alist->module_ctx.super.
+				iter_next(ctx->super_ctx);
+			if (info == NULL)
+				return NULL;
+		}
+
+		if ((ctx->ctx.flags & MAILBOX_LIST_ITER_RAW_LIST) != 0) {
+			/* skip ACL checks. */
+			return info;
+		}
 
 		ret = acl_mailbox_list_have_right(alist, info->name,
 						  ACL_STORAGE_RIGHT_LOOKUP,
@@ -66,14 +190,15 @@
 		if (ret > 0)
 			return info;
 		if (ret < 0) {
-			ctx->failed = TRUE;
+			ctx->ctx.failed = TRUE;
 			return NULL;
 		}
 
 		/* no permission to see this mailbox */
-		if ((ctx->flags & MAILBOX_LIST_ITER_SUBSCRIBED) != 0) {
+		if ((ctx->ctx.flags & MAILBOX_LIST_ITER_SUBSCRIBED) != 0) {
 			/* it's subscribed, show it as non-existent */
-			if ((ctx->flags & MAILBOX_LIST_ITER_FAST_FLAGS) == 0)
+			if ((ctx->ctx.flags &
+			     MAILBOX_LIST_ITER_FAST_FLAGS) == 0)
 				info->flags = MAILBOX_NONEXISTENT;
 			return info;
 		}
@@ -82,6 +207,25 @@
 	}
 }
 
+static int
+acl_mailbox_list_iter_deinit(struct mailbox_list_iterate_context *_ctx)
+{
+	struct acl_mailbox_list_iterate_context *ctx =
+		(struct acl_mailbox_list_iterate_context *)_ctx;
+	struct acl_mailbox_list *alist = ACL_LIST_CONTEXT(_ctx->list);
+	int ret = ctx->ctx.failed ? -1 : 0;
+
+	if (ctx->super_ctx != NULL) {
+		if (alist->module_ctx.super.iter_deinit(ctx->super_ctx) < 0)
+			ret = -1;
+	}
+	if (ctx->tree_iter != NULL)
+		mailbox_tree_iterate_deinit(&ctx->tree_iter);
+
+	i_free(ctx);
+	return ret;
+}
+
 static int acl_get_mailbox_name_status(struct mailbox_list *list,
 				       const char *name,
 				       enum mailbox_name_status *status)
@@ -243,7 +387,9 @@
 
 	alist = p_new(list->pool, struct acl_mailbox_list, 1);
 	alist->module_ctx.super = list->v;
+	list->v.iter_init = acl_mailbox_list_iter_init;
 	list->v.iter_next = acl_mailbox_list_iter_next;
+	list->v.iter_deinit = acl_mailbox_list_iter_deinit;
 	list->v.get_mailbox_name_status = acl_get_mailbox_name_status;
 	list->v.delete_mailbox = acl_mailbox_list_delete;
 	list->v.rename_mailbox = acl_mailbox_list_rename;

Index: acl-plugin.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/plugins/acl/acl-plugin.c,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -d -r1.5 -r1.6
--- acl-plugin.c	15 Mar 2007 17:05:44 -0000	1.5
+++ acl-plugin.c	11 Apr 2007 19:33:37 -0000	1.6
@@ -1,7 +1,6 @@
 /* Copyright (C) 2005 Timo Sirainen */
 
 #include "lib.h"
-#include "mail-storage.h"
 #include "mailbox-list-private.h"
 #include "acl-api.h"
 #include "acl-plugin.h"

Index: acl-storage.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/plugins/acl/acl-storage.c,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -d -r1.6 -r1.7
--- acl-storage.c	11 Apr 2007 11:02:31 -0000	1.6
+++ acl-storage.c	11 Apr 2007 19:33:37 -0000	1.7
@@ -3,9 +3,9 @@
 #include "lib.h"
 #include "array.h"
 #include "istream.h"
-#include "acl-api-private.h"
 #include "mail-namespace.h"
 #include "mailbox-list-private.h"
+#include "acl-api-private.h"
 #include "acl-plugin.h"
 
 struct acl_storage_module acl_storage_module =



More information about the dovecot-cvs mailing list