changeset 4041:9d7420b0e1ef HEAD

Make life easier for plugins: - Added MAILBOX_OPEN_SAVEONLY flag for mailbox_open(), which is set when mailbox is opened only for append/copy - Added a couple of MAIL_STORAGE_ERR_* string defines that should be used when giving visible errors to clients - Added failed-flag for mailbox_list_context, which plugins can directly set to make mail_storage_mailbox_list_deinit() return failure - Added mail_storage_get_mailbox_path() and mail_storage_get_mailbox_control_dir() to return locations for mailbox directories Also be more strict when validating mailbox names.
author Timo Sirainen <timo.sirainen@movial.fi>
date Wed, 22 Feb 2006 16:52:11 +0200
parents c0d093d8b8e5
children dabe100f3c38
files src/imap/cmd-append.c src/imap/cmd-copy.c src/lib-storage/index/dbox/dbox-list.c src/lib-storage/index/dbox/dbox-storage.c src/lib-storage/index/maildir/maildir-list.c src/lib-storage/index/maildir/maildir-storage.c src/lib-storage/index/mbox/mbox-list.c src/lib-storage/index/mbox/mbox-storage.c src/lib-storage/mail-storage-private.h src/lib-storage/mail-storage.c src/lib-storage/mail-storage.h src/plugins/convert/convert-storage.c src/plugins/quota/quota-plugin.c src/plugins/zlib/zlib-plugin.c
diffstat 14 files changed, 208 insertions(+), 71 deletions(-) [+]
line wrap: on
line diff
--- a/src/imap/cmd-append.c	Wed Feb 22 15:58:43 2006 +0200
+++ b/src/imap/cmd-append.c	Wed Feb 22 16:52:11 2006 +0200
@@ -365,8 +365,8 @@
 	    mailbox_equals(cmd->client->mailbox, storage, name))
 		return cmd->client->mailbox;
 
-	box = mailbox_open(storage, name, NULL, MAILBOX_OPEN_FAST |
-			   MAILBOX_OPEN_KEEP_RECENT);
+	box = mailbox_open(storage, name, NULL, MAILBOX_OPEN_SAVEONLY |
+			   MAILBOX_OPEN_FAST | MAILBOX_OPEN_KEEP_RECENT);
 	if (box == NULL) {
 		client_send_storage_error(cmd, storage);
 		return NULL;
--- a/src/imap/cmd-copy.c	Wed Feb 22 15:58:43 2006 +0200
+++ b/src/imap/cmd-copy.c	Wed Feb 22 16:52:11 2006 +0200
@@ -81,6 +81,7 @@
 		destbox = client->mailbox;
 	else {
 		destbox = mailbox_open(storage, mailbox, NULL,
+				       MAILBOX_OPEN_SAVEONLY |
 				       MAILBOX_OPEN_FAST |
 				       MAILBOX_OPEN_KEEP_RECENT);
 		if (destbox == NULL) {
--- a/src/lib-storage/index/dbox/dbox-list.c	Wed Feb 22 15:58:43 2006 +0200
+++ b/src/lib-storage/index/dbox/dbox-list.c	Wed Feb 22 16:52:11 2006 +0200
@@ -26,7 +26,7 @@
 	struct imap_match_glob *glob;
 	struct subsfile_list_context *subsfile_ctx;
 
-	bool failed, inbox_found;
+	bool inbox_found;
 
 	struct mailbox_list *(*next)(struct dbox_list_context *ctx);
 
@@ -136,7 +136,7 @@
 			subsfile_list_init(storage, path);
 		if (ctx->subsfile_ctx == NULL) {
 			ctx->next = dbox_list_next;
-			ctx->failed = TRUE;
+			ctx->mailbox_ctx.failed = TRUE;
 			return &ctx->mailbox_ctx;
 		}
 		ctx->glob = imap_match_init(default_pool, mask, TRUE, '/');
@@ -178,7 +178,7 @@
 int dbox_mailbox_list_deinit(struct mailbox_list_context *_ctx)
 {
 	struct dbox_list_context *ctx = (struct dbox_list_context *)_ctx;
-	int ret = ctx->failed ? -1 : 0;
+	int ret = ctx->mailbox_ctx.failed ? -1 : 0;
 
 	if (ctx->subsfile_ctx != NULL) {
 		if (subsfile_list_deinit(ctx->subsfile_ctx) < 0)
@@ -397,7 +397,7 @@
 			if (ret > 0)
 				return &ctx->list;
 			if (ret < 0) {
-				ctx->failed = TRUE;
+				ctx->mailbox_ctx.failed = TRUE;
 				return NULL;
 			}
 		}
--- a/src/lib-storage/index/dbox/dbox-storage.c	Wed Feb 22 15:58:43 2006 +0200
+++ b/src/lib-storage/index/dbox/dbox-storage.c	Wed Feb 22 16:52:11 2006 +0200
@@ -30,7 +30,7 @@
 	struct mail_storage *storage = &istorage->storage;
 
 	if (ENOACCESS(errno))
-		mail_storage_set_error(storage, "Permission denied");
+		mail_storage_set_error(storage, MAIL_STORAGE_ERR_NO_PERMISSION);
 	else if (ENOSPACE(errno))
 		mail_storage_set_error(storage, "Not enough disk space");
 	else if (ENOTFOUND(errno))
@@ -158,11 +158,21 @@
 	if (*mask == '/' || *mask == '~')
 		return FALSE;
 
-	/* make sure there's no "../" stuff */
+	/* make sure the mailbox name doesn't contain any foolishness:
+	   "../" could give access outside the mailbox directory.
+	   "./" and "//" could fool ACL checks. */
 	newdir = TRUE;
 	for (p = mask; *p != '\0'; p++) {
-		if (newdir && p[0] == '.' && p[1] == '.' && p[2] == '/')
-			return FALSE;
+		if (newdir) {
+			if (p[0] == '/')
+				return FALSE; /* // */
+			if (p[0] == '.') {
+				if (p[1] == '/')
+					return FALSE; /* ./ */
+				if (p[1] == '.' && p[2] == '/')
+					return FALSE; /* ../ */
+			}
+		} 
 		newdir = p[0] == '/';
 	}
 
@@ -266,6 +276,28 @@
 			   "/", name, "/"DBOX_MAILDIR_NAME, NULL);
 }
 
+static const char *
+dbox_get_mailbox_path(struct mail_storage *_storage,
+		      const char *name, bool *is_file_r)
+{
+	struct dbox_storage *storage = (struct dbox_storage *)_storage;
+	struct index_storage *istorage = INDEX_STORAGE(storage);
+
+	*is_file_r = FALSE;
+	if (*name == '\0')
+		return istorage->dir;
+	return dbox_get_path(istorage, name);
+}
+
+static const char *
+dbox_get_mailbox_control_dir(struct mail_storage *_storage, const char *name)
+{
+	struct dbox_storage *storage = (struct dbox_storage *)_storage;
+	struct index_storage *istorage = INDEX_STORAGE(storage);
+
+	return dbox_get_path(istorage, name);
+}
+
 static struct mailbox *
 dbox_open(struct dbox_storage *storage, const char *name,
 	  enum mailbox_open_flags flags)
@@ -358,8 +390,8 @@
 	if (stat(path, &st) == 0) {
 		return dbox_open(storage, name, flags);
 	} else if (errno == ENOENT) {
-		mail_storage_set_error(_storage, "Mailbox doesn't exist: %s",
-				       name);
+		mail_storage_set_error(_storage,
+			MAIL_STORAGE_ERR_MAILBOX_NOT_FOUND, name);
 		return NULL;
 	} else {
 		mail_storage_set_critical(_storage, "stat(%s) failed: %m",
@@ -421,7 +453,7 @@
 	if (stat(mail_path, &st) < 0 && ENOTFOUND(errno)) {
 		if (stat(path, &st) < 0) {
 			mail_storage_set_error(_storage,
-				"Mailbox doesn't exist: %s", name);
+				MAIL_STORAGE_ERR_MAILBOX_NOT_FOUND, name);
 			return -1;
 		}
 
@@ -517,7 +549,7 @@
 	if (rename(oldpath, newpath) < 0) {
 		if (ENOTFOUND(errno)) {
 			mail_storage_set_error(_storage,
-				"Mailbox doesn't exist: %s", oldname);
+				MAIL_STORAGE_ERR_MAILBOX_NOT_FOUND, oldname);
 		} else if (!dbox_handle_errors(storage)) {
 			mail_storage_set_critical(_storage,
 				"rename(%s, %s) failed: %m", oldpath, newpath);
@@ -614,6 +646,8 @@
 		dbox_free,
 		dbox_autodetect,
 		index_storage_set_callbacks,
+		dbox_get_mailbox_path,
+		dbox_get_mailbox_control_dir,
 		dbox_mailbox_open,
 		dbox_mailbox_create,
 		dbox_mailbox_delete,
--- a/src/lib-storage/index/maildir/maildir-list.c	Wed Feb 22 15:58:43 2006 +0200
+++ b/src/lib-storage/index/maildir/maildir-list.c	Wed Feb 22 16:52:11 2006 +0200
@@ -29,7 +29,6 @@
 	size_t parent_pos;
 	struct mailbox_node *root, *next_node;
 	struct mailbox_list list;
-	bool failed;
 };
 
 static void maildir_nodes_fix(struct mailbox_node *node, bool is_subs)
@@ -289,7 +288,7 @@
 
 	if ((flags & MAILBOX_LIST_SUBSCRIBED) != 0) {
 		if (!maildir_fill_subscribed(ctx, glob)) {
-			ctx->failed = TRUE;
+			ctx->mailbox_ctx.failed = TRUE;
 			return &ctx->mailbox_ctx;
 		}
 	} else if ((storage->flags & MAIL_STORAGE_FLAG_FULL_FS_ACCESS) != 0 &&
@@ -306,7 +305,7 @@
 	    (ctx->flags & MAILBOX_LIST_FAST_FLAGS) == 0) {
 		bool update_only = (flags & MAILBOX_LIST_SUBSCRIBED) != 0;
 		if (!maildir_fill_readdir(ctx, glob, update_only)) {
-			ctx->failed = TRUE;
+			ctx->mailbox_ctx.failed = TRUE;
 			return &ctx->mailbox_ctx;
 		}
 	}
@@ -320,7 +319,7 @@
 int maildir_mailbox_list_deinit(struct mailbox_list_context *_ctx)
 {
 	struct maildir_list_context *ctx = (struct maildir_list_context *)_ctx;
-	int ret = ctx->failed ? -1 : 0;
+	int ret = ctx->mailbox_ctx.failed ? -1 : 0;
 
 	mailbox_tree_deinit(ctx->tree_ctx);
 	pool_unref(ctx->pool);
--- a/src/lib-storage/index/maildir/maildir-storage.c	Wed Feb 22 15:58:43 2006 +0200
+++ b/src/lib-storage/index/maildir/maildir-storage.c	Wed Feb 22 16:52:11 2006 +0200
@@ -182,7 +182,13 @@
 {
 	size_t len;
 
-	len = strlen(name);
+	/* check that there are no adjacent hierarchy separators */
+	for (len = 0; name[len] != '\0'; len++) {
+		if (name[len] == MAILDIR_FS_SEP &&
+		    name[len+1] == MAILDIR_FS_SEP)
+			return FALSE;
+	}
+
 	if (len == 0 || len > MAILDIR_MAX_MAILBOX_NAME_LENGTH ||
 	    name[0] == MAILDIR_FS_SEP || name[len-1] == MAILDIR_FS_SEP)
 		return FALSE;
@@ -464,6 +470,27 @@
 	return &mbox->ibox.box;
 }
 
+static const char *
+maildir_get_mailbox_path(struct mail_storage *_storage,
+			 const char *name, bool *is_file_r)
+{
+	struct maildir_storage *storage = (struct maildir_storage *)_storage;
+	struct index_storage *istorage = INDEX_STORAGE(storage);
+
+	*is_file_r = FALSE;
+	if (*name == '\0')
+		return istorage->dir;
+	return maildir_get_path(istorage, name);
+}
+
+static const char *
+maildir_get_mailbox_control_dir(struct mail_storage *_storage, const char *name)
+{
+	struct maildir_storage *storage = (struct maildir_storage *)_storage;
+
+	return maildir_get_control_path(storage, name);
+}
+
 static struct mailbox *
 maildir_mailbox_open(struct mail_storage *_storage, const char *name,
 		     struct istream *input, enum mailbox_open_flags flags)
@@ -506,8 +533,8 @@
 
 		return maildir_open(storage, name, flags);
 	} else if (errno == ENOENT) {
-		mail_storage_set_error(_storage, "Mailbox doesn't exist: %s",
-				       name);
+		mail_storage_set_error(_storage,
+			MAIL_STORAGE_ERR_MAILBOX_NOT_FOUND, name);
 		return NULL;
 	} else {
 		mail_storage_set_critical(_storage, "stat(%s) failed: %m",
@@ -601,8 +628,8 @@
 	src = maildir_get_path(storage, name);
 	dest = maildir_get_unlink_path(storage, name);
 	if (stat(src, &st) != 0 && errno == ENOENT) {
-		mail_storage_set_error(_storage, "Mailbox doesn't exist: %s",
-				       name);
+		mail_storage_set_error(_storage,
+			MAIL_STORAGE_ERR_MAILBOX_NOT_FOUND, name);
 		return -1;
 	}
 
@@ -765,7 +792,7 @@
 			return -1;
 		if (!found && ret == 0) {
 			mail_storage_set_error(_storage,
-					       "Mailbox doesn't exist");
+				MAIL_STORAGE_ERR_MAILBOX_NOT_FOUND, oldname);
 			return -1;
 		}
 
@@ -873,13 +900,15 @@
 
 struct mail_storage maildir_storage = {
 	MEMBER(name) "maildir",
-	MEMBER(hierarchy_sep) '.',
+	MEMBER(hierarchy_sep) MAILDIR_FS_SEP,
 
 	{
 		maildir_create,
 		maildir_free,
 		maildir_autodetect,
 		index_storage_set_callbacks,
+		maildir_get_mailbox_path,
+		maildir_get_mailbox_control_dir,
 		maildir_mailbox_open,
 		maildir_mailbox_create,
 		maildir_mailbox_delete,
--- a/src/lib-storage/index/mbox/mbox-list.c	Wed Feb 22 15:58:43 2006 +0200
+++ b/src/lib-storage/index/mbox/mbox-list.c	Wed Feb 22 16:52:11 2006 +0200
@@ -32,7 +32,7 @@
 	struct imap_match_glob *glob;
 	struct subsfile_list_context *subsfile_ctx;
 
-	bool failed, inbox_found;
+	bool inbox_found;
 
 	struct mailbox_list *(*next)(struct mbox_list_context *ctx);
 
@@ -142,7 +142,7 @@
 			subsfile_list_init(storage, path);
 		if (ctx->subsfile_ctx == NULL) {
 			ctx->next = mbox_list_next;
-			ctx->failed = TRUE;
+			ctx->mailbox_ctx.failed = TRUE;
 			return &ctx->mailbox_ctx;
 		}
 		ctx->glob = imap_match_init(default_pool, mask, TRUE, '/');
@@ -184,7 +184,7 @@
 int mbox_mailbox_list_deinit(struct mailbox_list_context *_ctx)
 {
 	struct mbox_list_context *ctx = (struct mbox_list_context *)_ctx;
-	int ret = ctx->failed ? -1 : 0;
+	int ret = ctx->mailbox_ctx.failed ? -1 : 0;
 
 	if (ctx->subsfile_ctx != NULL) {
 		if (subsfile_list_deinit(ctx->subsfile_ctx) < 0)
@@ -387,7 +387,7 @@
 	else {
 		mail_storage_set_critical(ctx->mailbox_ctx.storage,
 			"stat(%s) failed: %m", ctx->istorage->inbox_path);
-		ctx->failed = TRUE;
+		ctx->mailbox_ctx.failed = TRUE;
 		return NULL;
 	}
 
@@ -412,7 +412,7 @@
 			if (ret > 0)
 				return &ctx->list;
 			if (ret < 0) {
-				ctx->failed = TRUE;
+				ctx->mailbox_ctx.failed = TRUE;
 				return NULL;
 			}
 		}
--- a/src/lib-storage/index/mbox/mbox-storage.c	Wed Feb 22 15:58:43 2006 +0200
+++ b/src/lib-storage/index/mbox/mbox-storage.c	Wed Feb 22 16:52:11 2006 +0200
@@ -59,7 +59,7 @@
 	struct mail_storage *storage = &istorage->storage;
 
 	if (ENOACCESS(errno))
-		mail_storage_set_error(storage, "Permission denied");
+		mail_storage_set_error(storage, MAIL_STORAGE_ERR_NO_PERMISSION);
 	else if (ENOSPACE(errno))
 		mail_storage_set_error(storage, "Not enough disk space");
 	else if (ENOTFOUND(errno))
@@ -370,11 +370,21 @@
 	if (*mask == '/' || *mask == '~')
 		return FALSE;
 
-	/* make sure there's no "../" stuff */
+	/* make sure the mailbox name doesn't contain any foolishness:
+	   "../" could give access outside the mailbox directory.
+	   "./" and "//" could fool ACL checks. */
 	newdir = TRUE;
 	for (p = mask; *p != '\0'; p++) {
-		if (newdir && p[0] == '.' && p[1] == '.' && p[2] == '/')
-			return FALSE;
+		if (newdir) {
+			if (p[0] == '/')
+				return FALSE; /* // */
+			if (p[0] == '.') {
+				if (p[1] == '/')
+					return FALSE; /* ./ */
+				if (p[1] == '.' && p[2] == '/')
+					return FALSE; /* ../ */
+			}
+		} 
 		newdir = p[0] == '/';
 	}
 
@@ -633,6 +643,31 @@
 	return &mbox->ibox.box;
 }
 
+static const char *
+mbox_get_mailbox_path(struct mail_storage *_storage,
+		      const char *name, bool *is_file_r)
+{
+	struct mbox_storage *storage = (struct mbox_storage *)_storage;
+	struct index_storage *istorage = INDEX_STORAGE(storage);
+
+	if (*name == '\0') {
+		*is_file_r = FALSE;
+		return istorage->dir;
+	}
+
+	*is_file_r = TRUE;
+	return mbox_get_path(istorage, name);
+}
+
+static const char *
+mbox_get_mailbox_control_dir(struct mail_storage *_storage, const char *name)
+{
+	struct mbox_storage *storage = (struct mbox_storage *)_storage;
+	struct index_storage *istorage = INDEX_STORAGE(storage);
+
+	return mbox_get_index_dir(istorage, name);
+}
+
 static struct mailbox *
 mbox_mailbox_open(struct mail_storage *_storage, const char *name,
 		  struct istream *input, enum mailbox_open_flags flags)
@@ -671,8 +706,8 @@
 	}
 
 	if (ENOTFOUND(errno)) {
-		mail_storage_set_error(_storage, "Mailbox doesn't exist: %s",
-				       name);
+		mail_storage_set_error(_storage,
+			MAIL_STORAGE_ERR_MAILBOX_NOT_FOUND, name);
 	} else if (!mbox_handle_errors(istorage)) {
 		mail_storage_set_critical(_storage, "stat(%s) failed: %m",
 					  path);
@@ -783,7 +818,7 @@
 	if (lstat(path, &st) < 0) {
 		if (ENOTFOUND(errno)) {
 			mail_storage_set_error(_storage,
-				"Mailbox doesn't exist: %s", name);
+				MAIL_STORAGE_ERR_MAILBOX_NOT_FOUND, name);
 		} else if (!mbox_handle_errors(storage)) {
 			mail_storage_set_critical(_storage,
 				"lstat() failed for %s: %m", path);
@@ -811,7 +846,7 @@
 
 		if (ENOTFOUND(errno)) {
 			mail_storage_set_error(_storage,
-				"Mailbox doesn't exist: %s", name);
+				MAIL_STORAGE_ERR_MAILBOX_NOT_FOUND, name);
 		} else if (errno == ENOTEMPTY) {
 			mail_storage_set_error(_storage,
 				"Folder %s isn't empty, can't delete it.",
@@ -827,7 +862,7 @@
 	if (unlink(path) < 0) {
 		if (ENOTFOUND(errno)) {
 			mail_storage_set_error(_storage,
-				"Mailbox doesn't exist: %s", name);
+				MAIL_STORAGE_ERR_MAILBOX_NOT_FOUND, name);
 		} else if (!mbox_handle_errors(storage)) {
 			mail_storage_set_critical(_storage,
 				"unlink() failed for %s: %m", path);
@@ -914,7 +949,7 @@
 	if (rename(oldpath, newpath) < 0) {
 		if (ENOTFOUND(errno)) {
 			mail_storage_set_error(_storage,
-				"Mailbox doesn't exist: %s", oldname);
+				MAIL_STORAGE_ERR_MAILBOX_NOT_FOUND, oldname);
 		} else if (!mbox_handle_errors(storage)) {
 			mail_storage_set_critical(_storage,
 				"rename(%s, %s) failed: %m", oldpath, newpath);
@@ -1035,6 +1070,8 @@
 		mbox_free,
 		mbox_autodetect,
 		index_storage_set_callbacks,
+		mbox_get_mailbox_path,
+		mbox_get_mailbox_control_dir,
 		mbox_mailbox_open,
 		mbox_mailbox_create,
 		mbox_mailbox_delete,
--- a/src/lib-storage/mail-storage-private.h	Wed Feb 22 15:58:43 2006 +0200
+++ b/src/lib-storage/mail-storage-private.h	Wed Feb 22 16:52:11 2006 +0200
@@ -3,6 +3,11 @@
 
 #include "mail-storage.h"
 
+/* Some error strings that should be used everywhere to avoid
+   permissions checks from revealing mailbox's existence */
+#define MAIL_STORAGE_ERR_MAILBOX_NOT_FOUND "Mailbox doesn't exist: %s"
+#define MAIL_STORAGE_ERR_NO_PERMISSION "Permission denied"
+
 /* Modules should use do "my_id = mail_storage_module_id++" and
    use objects' module_contexts[id] for their own purposes. */
 extern unsigned int mail_storage_module_id;
@@ -20,6 +25,11 @@
 			      struct mail_storage_callbacks *callbacks,
 			      void *context);
 
+	const char *(*get_mailbox_path)(struct mail_storage *storage,
+					const char *name, bool *is_file_r);
+	const char *(*get_mailbox_control_dir)(struct mail_storage *storage,
+					       const char *name);
+
 	struct mailbox *(*mailbox_open)(struct mail_storage *storage,
 					const char *name,
 					struct istream *input,
@@ -204,6 +214,7 @@
 
 struct mailbox_list_context {
 	struct mail_storage *storage;
+	bool failed;
 };
 
 struct mailbox_transaction_context {
--- a/src/lib-storage/mail-storage.c	Wed Feb 22 15:58:43 2006 +0200
+++ b/src/lib-storage/mail-storage.c	Wed Feb 22 16:52:11 2006 +0200
@@ -327,6 +327,18 @@
 					 temporary_error_r);
 }
 
+const char *mail_storage_get_mailbox_path(struct mail_storage *storage,
+					  const char *name, bool *is_file_r)
+{
+	return storage->v.get_mailbox_path(storage, name, is_file_r);
+}
+
+const char *mail_storage_get_mailbox_control_dir(struct mail_storage *storage,
+						 const char *name)
+{
+	return storage->v.get_mailbox_control_dir(storage, name);
+}
+
 struct mailbox *mailbox_open(struct mail_storage *storage, const char *name,
 			     struct istream *input,
 			     enum mailbox_open_flags flags)
--- a/src/lib-storage/mail-storage.h	Wed Feb 22 15:58:43 2006 +0200
+++ b/src/lib-storage/mail-storage.h	Wed Feb 22 16:52:11 2006 +0200
@@ -33,13 +33,15 @@
 enum mailbox_open_flags {
 	/* Mailbox must not be modified even if asked */
 	MAILBOX_OPEN_READONLY		= 0x01,
+	/* Only saving/copying mails to mailbox works. */
+	MAILBOX_OPEN_SAVEONLY		= 0x02,
 	/* Any extra time consuming operations shouldn't be performed
 	   (eg. when opening mailbox just for STATUS). */
-	MAILBOX_OPEN_FAST		= 0x02,
+	MAILBOX_OPEN_FAST		= 0x04,
 	/* Don't reset MAIL_RECENT flags when syncing */
-	MAILBOX_OPEN_KEEP_RECENT	= 0x04,
+	MAILBOX_OPEN_KEEP_RECENT	= 0x08,
 	/* Don't create index files for the mailbox */
-	MAILBOX_OPEN_NO_INDEX_FILES	= 0x08
+	MAILBOX_OPEN_NO_INDEX_FILES	= 0x10
 };
 
 enum mailbox_list_flags {
@@ -293,6 +295,17 @@
 					bool *syntax_error_r,
 					bool *temporary_error_r);
 
+/* Returns path to the given mailbox, or NULL if mailbox doesn't exist in
+   filesystem. is_file_r is set to TRUE if returned path points to a file,
+   and FALSE if it points to a directory. If name is "", the root storage
+   directory is returned. */
+const char *mail_storage_get_mailbox_path(struct mail_storage *storage,
+					  const char *name, bool *is_file_r);
+/* Returns path to the control directory of the mailbox, or NULL if mailbox
+   doesn't exist in filesystem. */
+const char *mail_storage_get_mailbox_control_dir(struct mail_storage *storage,
+						 const char *name);
+
 /* Open a mailbox. If input stream is given, mailbox is opened read-only
    using it as a backend. If storage doesn't support stream backends and its
    tried to be used, NULL is returned.
--- a/src/plugins/convert/convert-storage.c	Wed Feb 22 15:58:43 2006 +0200
+++ b/src/plugins/convert/convert-storage.c	Wed Feb 22 16:52:11 2006 +0200
@@ -229,17 +229,19 @@
 
 	if (ret == 0) {
 		/* all finished. rename the source directory to mark the
-		   move as finished. FIXME: kind of kludgy way to get the
-		   directory.. */
-		struct index_storage *index_storage =
-			(struct index_storage *)source_storage;
-		const char *dest;
+		   move as finished. */
+		const char *src, *dest;
+		bool is_file;
 
-		dest = t_strconcat(index_storage->dir, "-converted", NULL);
-		if (rename(index_storage->dir, dest) < 0) {
-			i_error("Mailbox conversion: rename(%s, %s) failed: %m",
-				index_storage->dir, dest);
-			/* return success anyway */
+		src = mail_storage_get_mailbox_path(source_storage, "",
+						    &is_file);
+		if (src != NULL) {
+			dest = t_strconcat(src, "-converted", NULL);
+			if (rename(src, dest) < 0) {
+				i_error("Mailbox conversion: "
+					"rename(%s, %s) failed: %m", src, dest);
+				/* return success anyway */
+			}
 		}
 		ret = 1;
 	}
--- a/src/plugins/quota/quota-plugin.c	Wed Feb 22 15:58:43 2006 +0200
+++ b/src/plugins/quota/quota-plugin.c	Wed Feb 22 16:52:11 2006 +0200
@@ -1,7 +1,6 @@
 /* Copyright (C) 2005 Timo Sirainen */
 
 #include "lib.h"
-#include "str.h"
 #include "mail-storage.h"
 #include "quota.h"
 #include "quota-plugin.h"
--- a/src/plugins/zlib/zlib-plugin.c	Wed Feb 22 15:58:43 2006 +0200
+++ b/src/plugins/zlib/zlib-plugin.c	Wed Feb 22 16:52:11 2006 +0200
@@ -6,9 +6,10 @@
 #include "home-expand.h"
 #include "istream.h"
 #include "mail-storage-private.h"
-#include "index-storage.h"
 #include "zlib-plugin.h"
 
+#include <fcntl.h>
+
 struct zlib_mail_storage {
 	struct mail_storage_vfuncs super;
 };
@@ -26,31 +27,30 @@
 static unsigned int zlib_storage_module_id = 0;
 static bool zlib_storage_module_id_set = FALSE;
 
-static const char *
-mbox_get_path(struct index_storage *storage, const char *name)
-{
-	if ((storage->storage.flags & MAIL_STORAGE_FLAG_FULL_FS_ACCESS) != 0 &&
-	    (*name == '/' || *name == '~'))
-		return home_expand(name);
-	return t_strconcat(storage->dir, "/", name, NULL);
-}
-
 static struct mailbox *
 zlib_mailbox_open(struct mail_storage *storage, const char *name,
 		  struct istream *input, enum mailbox_open_flags flags)
 {
-	struct index_storage *istorage = (struct index_storage *)storage;
 	struct zlib_mail_storage *qstorage = ZLIB_CONTEXT(storage);
 	struct mailbox *box;
 	struct istream *zlib_input = NULL;
 	size_t len = strlen(name);
 
-	if (input == NULL && strcmp(storage->name, "mbox") == 0 &&
-	    len > 3 && strcmp(name + len - 3, ".gz") == 0) {
-		int fd = open(mbox_get_path(istorage, name), O_RDONLY);
-		if (fd != -1) {
-			input = zlib_input =
-				i_stream_create_zlib(fd, default_pool);
+	if (input == NULL && len > 3 && strcmp(name + len - 3, ".gz") == 0) {
+		/* Looks like a .gz file */
+		const char *path;
+		bool is_file;
+
+		path = mail_storage_get_mailbox_path(storage, name, &is_file);
+		if (is_file && path != NULL) {
+			/* it's a single file mailbox. we can handle this. */
+			int fd;
+
+			fd = open(path, O_RDONLY);
+			if (fd != -1) {
+				input = zlib_input =
+					i_stream_create_zlib(fd, default_pool);
+			}
 		}
 	}