changeset 3033:146897976cfa HEAD

Added mail_debug setting. Moved full_filesystem_access from global variable to flag in mail_create*() functions.
author Timo Sirainen <tss@iki.fi>
date Wed, 29 Dec 2004 21:10:25 +0200
parents bf6a77e42151
children de1b904c4df2
files dovecot-example.conf src/imap/namespace.c src/lib-storage/index/index-storage.c src/lib-storage/index/index-storage.h 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/index/mbox/mbox-storage.h src/lib-storage/mail-storage-private.h src/lib-storage/mail-storage.c src/lib-storage/mail-storage.h src/master/mail-process.c src/master/master-settings.c src/master/master-settings.h src/pop3/main.c
diffstat 16 files changed, 320 insertions(+), 122 deletions(-) [+]
line wrap: on
line diff
--- a/dovecot-example.conf	Wed Dec 29 21:09:21 2004 +0200
+++ b/dovecot-example.conf	Wed Dec 29 21:10:25 2004 +0200
@@ -177,6 +177,10 @@
 # their mail directory anyway.
 #mail_chroot = 
 
+# Enable mail process debugging. This can help you figure out why Dovecot
+# isn't finding your mails.
+#mail_debug = no
+
 # Default MAIL environment to use when it's not set. By leaving this empty
 # dovecot tries to do some automatic detection as described in
 # doc/mail-storages.txt. There's a few special variables you can use, eg.:
--- a/src/imap/namespace.c	Wed Dec 29 21:09:21 2004 +0200
+++ b/src/imap/namespace.c	Wed Dec 29 21:10:25 2004 +0200
@@ -27,7 +27,7 @@
 
 static struct namespace *
 namespace_add_env(pool_t pool, const char *data, unsigned int num,
-		  const char *user)
+		  const char *user, enum mail_storage_flags flags)
 {
         struct namespace *ns;
         const char *sep, *type, *prefix;
@@ -55,11 +55,20 @@
 	if (prefix == NULL)
 		prefix = "";
 
+	if ((flags & MAIL_STORAGE_FLAG_DEBUG) != 0) {
+		i_info("Namespace: type=%s, prefix=%s, sep=%s, "
+		       "inbox=%s, hidden=%s, subscriptions=%s",
+		       type == NULL ? "" : type, prefix, sep == NULL ? "" : sep,
+		       inbox ? "yes" : "no",
+		       hidden ? "yes" : "no",
+		       subscriptions ? "yes" : "no");
+	}
+
 	ns->prefix = p_strdup(pool, prefix);
 	ns->inbox = inbox;
 	ns->hidden = hidden;
 	ns->subscriptions = subscriptions;
-	ns->storage = mail_storage_create_with_data(data, user);
+	ns->storage = mail_storage_create_with_data(data, user, flags);
 	if (ns->storage == NULL) {
 		i_fatal("Failed to create storage for '%s' with data: %s",
 			ns->prefix, data);
@@ -74,9 +83,16 @@
 struct namespace *namespace_init(pool_t pool, const char *user)
 {
 	struct namespace *namespaces, *ns, **ns_p;
+        enum mail_storage_flags flags;
 	const char *mail, *data;
 	unsigned int i;
 
+	flags = 0;
+	if (getenv("FULL_FILESYSTEM_ACCESS") != NULL)
+		flags |= MAIL_STORAGE_FLAG_FULL_FS_ACCESS;
+	if (getenv("DEBUG") != NULL)
+		flags |= MAIL_STORAGE_FLAG_DEBUG;
+
         namespaces = NULL; ns_p = &namespaces;
 
 	/* first try NAMESPACE_* environments */
@@ -89,7 +105,7 @@
 			break;
 
 		t_push();
-		*ns_p = namespace_add_env(pool, data, i, user);
+		*ns_p = namespace_add_env(pool, data, i, user, flags);
 		t_pop();
 
 		ns_p = &(*ns_p)->next;
@@ -108,7 +124,7 @@
 	}
 
 	ns = p_new(pool, struct namespace, 1);
-	ns->storage = mail_storage_create_with_data(mail, user);
+	ns->storage = mail_storage_create_with_data(mail, user, flags);
 	if (ns->storage == NULL) {
 		if (mail != NULL && *mail != '\0')
 			i_fatal("Failed to create storage with data: %s", mail);
--- a/src/lib-storage/index/index-storage.c	Wed Dec 29 21:09:21 2004 +0200
+++ b/src/lib-storage/index/index-storage.c	Wed Dec 29 21:10:25 2004 +0200
@@ -38,8 +38,10 @@
 static struct timeout *to_index = NULL;
 static int index_storage_refcount = 0;
 
-void index_storage_init(struct index_storage *storage __attr_unused__)
+void index_storage_init(struct index_storage *storage,
+			enum mail_storage_flags flags)
 {
+	storage->storage.flags = flags;
 	index_storage_refcount++;
 }
 
--- a/src/lib-storage/index/index-storage.h	Wed Dec 29 21:09:21 2004 +0200
+++ b/src/lib-storage/index/index-storage.h	Wed Dec 29 21:10:25 2004 +0200
@@ -132,7 +132,8 @@
 void index_storage_unref(struct mail_index *index);
 void index_storage_destroy_unrefed(void);
 
-void index_storage_init(struct index_storage *storage);
+void index_storage_init(struct index_storage *storage,
+			enum mail_storage_flags flags);
 void index_storage_deinit(struct index_storage *storage);
 
 struct index_mailbox *
--- a/src/lib-storage/index/maildir/maildir-list.c	Wed Dec 29 21:09:21 2004 +0200
+++ b/src/lib-storage/index/maildir/maildir-list.c	Wed Dec 29 21:10:25 2004 +0200
@@ -288,7 +288,8 @@
 	if ((flags & MAILBOX_LIST_SUBSCRIBED) != 0) {
 		if (!maildir_fill_subscribed(ctx, glob))
 			return &ctx->mailbox_ctx;
-	} else if (full_filesystem_access && (p = strrchr(mask, '/')) != NULL) {
+	} else if ((storage->flags & MAIL_STORAGE_FLAG_FULL_FS_ACCESS) != 0 &&
+		   (p = strrchr(mask, '/')) != NULL) {
 		dir = t_strdup_until(mask, p);
 		ctx->prefix = p_strdup_until(pool, mask, p+1);
 
--- a/src/lib-storage/index/maildir/maildir-storage.c	Wed Dec 29 21:09:21 2004 +0200
+++ b/src/lib-storage/index/maildir/maildir-storage.c	Wed Dec 29 21:10:25 2004 +0200
@@ -30,8 +30,10 @@
 static int verify_inbox(struct index_storage *storage);
 
 static struct mail_storage *
-maildir_create(const char *data, const char *user)
+maildir_create(const char *data, const char *user,
+	       enum mail_storage_flags flags)
 {
+	int debug = (flags & MAIL_STORAGE_FLAG_DEBUG) != 0;
 	struct index_storage *storage;
 	const char *root_dir, *inbox_dir, *index_dir, *control_dir;
 	const char *home, *path, *p;
@@ -41,20 +43,35 @@
 
 	if (data == NULL || *data == '\0') {
 		/* we'll need to figure out the maildir location ourself.
-		   it's either root dir if we've already chroot()ed, or
-		   $HOME/Maildir otherwise */
-		if (access("/cur", R_OK|W_OK|X_OK) == 0)
+		   It's $HOME/Maildir unless we are chrooted. */
+		if ((home = getenv("HOME")) != NULL) {
+			path = t_strconcat(home, "/Maildir", NULL);
+			if (access(path, R_OK|W_OK|X_OK) == 0) {
+				if (debug) {
+					i_info("maildir: root exists (%s)",
+					       path);
+				}
+				root_dir = path;
+			} else {
+				if (debug) {
+					i_info("maildir: access(%s, rwx): "
+					       "failed: %m", path);
+				}
+			}
+		} else {
+			if (debug)
+				i_info("maildir: HOME not set");
+		}
+
+		if (access("/cur", R_OK|W_OK|X_OK) == 0) {
+			if (debug)
+				i_info("maildir: /cur exists, assuming chroot");
 			root_dir = "/";
-		else {
-			home = getenv("HOME");
-			if (home != NULL) {
-				path = t_strconcat(home, "/Maildir", NULL);
-				if (access(path, R_OK|W_OK|X_OK) == 0)
-					root_dir = path;
-			}
 		}
 	} else {
 		/* <Maildir> [:INBOX=<dir>] [:INDEX=<dir>] [:CONTROL=<dir>] */
+		if (debug)
+			i_info("maildir: data=%s", data);
 		p = strchr(data, ':');
 		if (p == NULL)
 			root_dir = data;
@@ -74,8 +91,11 @@
 		}
 	}
 
-	if (root_dir == NULL)
+	if (root_dir == NULL) {
+		if (debug)
+			i_info("maildir: couldn't find root dir");
 		return NULL;
+	}
 
 	/* strip trailing '/' */
 	len = strlen(root_dir);
@@ -87,6 +107,13 @@
 	else if (strcmp(index_dir, "MEMORY") == 0)
 		index_dir = NULL;
 
+	if (debug) {
+		i_info("maildir: root=%s, index=%s, control=%s, inbox=%s",
+		       root_dir, index_dir == NULL ? "" : index_dir,
+		       control_dir == NULL ? "" : control_dir,
+		       inbox_dir == NULL ? "" : inbox_dir);
+	}
+
 	storage = i_new(struct index_storage, 1);
 	storage->storage = maildir_storage;
 
@@ -100,7 +127,7 @@
 	storage->control_dir = i_strdup(home_expand(control_dir));
 	storage->user = i_strdup(user);
 	storage->callbacks = i_new(struct mail_storage_callbacks, 1);
-	index_storage_init(storage);
+	index_storage_init(storage, flags);
 
 	(void)verify_inbox(storage);
 	return &storage->storage;
@@ -122,17 +149,31 @@
 	i_free(storage);
 }
 
-static int maildir_autodetect(const char *data)
+static int maildir_autodetect(const char *data, enum mail_storage_flags flags)
 {
+	int debug = (flags & MAIL_STORAGE_FLAG_DEBUG) != 0;
 	struct stat st;
+	const char *path;
 
 	data = t_strcut(data, ':');
 
-	return stat(t_strconcat(data, "/cur", NULL), &st) == 0 &&
-		S_ISDIR(st.st_mode);
+	path = t_strconcat(data, "/cur", NULL);
+	if (stat(path, &st) < 0) {
+		if (debug)
+			i_info("maildir autodetect: stat(%s) failed: %m", path);
+		return FALSE;
+	}
+
+	if (!S_ISDIR(st.st_mode)) {
+		if (debug)
+			i_info("maildir autodetect: %s not a directory", path);
+		return FALSE;
+	}
+	return TRUE;
 }
 
-static int maildir_is_valid_create_name(const char *name)
+static int maildir_is_valid_create_name(struct mail_storage *storage,
+					const char *name)
 {
 	size_t len;
 
@@ -142,7 +183,7 @@
 	    strchr(name, '*') != NULL || strchr(name, '%') != NULL)
 		return FALSE;
 
-	if (full_filesystem_access)
+	if ((storage->flags & MAIL_STORAGE_FLAG_FULL_FS_ACCESS) != 0)
 		return TRUE;
 
 	if (*name == '~' || strchr(name, '/') != NULL)
@@ -151,12 +192,13 @@
 	return TRUE;
 }
 
-static int maildir_is_valid_existing_name(const char *name)
+static int maildir_is_valid_existing_name(struct mail_storage *storage,
+					  const char *name)
 {
 	if (name[0] == '\0' || name[strlen(name)-1] == '/')
 		return FALSE;
 
-	if (full_filesystem_access)
+	if ((storage->flags & MAIL_STORAGE_FLAG_FULL_FS_ACCESS) != 0)
 		return TRUE;
 
 	if (*name == '~' || strchr(name, '/') != NULL)
@@ -181,7 +223,8 @@
 
 const char *maildir_get_path(struct index_storage *storage, const char *name)
 {
-	if (full_filesystem_access && (*name == '/' || *name == '~'))
+	if ((storage->storage.flags & MAIL_STORAGE_FLAG_FULL_FS_ACCESS) != 0 &&
+	    (*name == '/' || *name == '~'))
 		return maildir_get_absolute_path(name, FALSE);
 
 	if (strcmp(name, "INBOX") == 0) {
@@ -195,7 +238,8 @@
 static const char *
 maildir_get_unlink_path(struct index_storage *storage, const char *name)
 {
-	if (full_filesystem_access && (*name == '/' || *name == '~'))
+	if ((storage->storage.flags & MAIL_STORAGE_FLAG_FULL_FS_ACCESS) != 0 &&
+	    (*name == '/' || *name == '~'))
 		return maildir_get_absolute_path(name, TRUE);
 
 	return maildir_get_path(storage,
@@ -212,7 +256,8 @@
 	    strcmp(storage->index_dir, storage->dir) == 0)
 		return storage->dir;
 
-	if (full_filesystem_access && (*name == '/' || *name == '~'))
+	if ((storage->storage.flags & MAIL_STORAGE_FLAG_FULL_FS_ACCESS) != 0 &&
+	    (*name == '/' || *name == '~'))
 		return maildir_get_absolute_path(name, FALSE);
 
 	return t_strconcat(storage->index_dir, "/"MAILDIR_FS_SEP_S, name, NULL);
@@ -224,7 +269,8 @@
 	if (storage->control_dir == NULL)
 		return maildir_get_path(storage, name);
 
-	if (full_filesystem_access && (*name == '/' || *name == '~'))
+	if ((storage->storage.flags & MAIL_STORAGE_FLAG_FULL_FS_ACCESS) != 0 &&
+	    (*name == '/' || *name == '~'))
 		return maildir_get_absolute_path(name, FALSE);
 
 	return t_strconcat(storage->control_dir, "/"MAILDIR_FS_SEP_S,
@@ -411,7 +457,7 @@
 		return maildir_open(storage, "INBOX", flags);
 	}
 
-	if (!maildir_is_valid_existing_name(name)) {
+	if (!maildir_is_valid_existing_name(_storage, name)) {
 		mail_storage_set_error(_storage, "Invalid mailbox name");
 		return NULL;
 	}
@@ -445,7 +491,7 @@
 
 	mail_storage_clear_error(_storage);
 
-	if (!maildir_is_valid_create_name(name)) {
+	if (!maildir_is_valid_create_name(_storage, name)) {
 		mail_storage_set_error(_storage, "Invalid mailbox name");
 		return -1;
 	}
@@ -477,7 +523,7 @@
 		return -1;
 	}
 
-	if (!maildir_is_valid_existing_name(name)) {
+	if (!maildir_is_valid_existing_name(_storage, name)) {
 		mail_storage_set_error(_storage, "Invalid mailbox name");
 		return -1;
 	}
@@ -624,8 +670,8 @@
 
 	mail_storage_clear_error(_storage);
 
-	if (!maildir_is_valid_existing_name(oldname) ||
-	    !maildir_is_valid_create_name(newname)) {
+	if (!maildir_is_valid_existing_name(_storage, oldname) ||
+	    !maildir_is_valid_create_name(_storage, newname)) {
 		mail_storage_set_error(_storage, "Invalid mailbox name");
 		return -1;
 	}
@@ -693,7 +739,7 @@
 
 	mail_storage_clear_error(_storage);
 
-	if (!maildir_is_valid_existing_name(name)) {
+	if (!maildir_is_valid_existing_name(_storage, name)) {
 		*status = MAILBOX_NAME_INVALID;
 		return 0;
 	}
@@ -704,7 +750,7 @@
 		return 0;
 	}
 
-	if (!maildir_is_valid_create_name(name)) {
+	if (!maildir_is_valid_create_name(_storage, name)) {
 		*status = MAILBOX_NAME_INVALID;
 		return 0;
 	}
@@ -776,6 +822,7 @@
 	index_storage_get_last_error,
 
 	NULL,
+	0,
 	0
 };
 
--- a/src/lib-storage/index/mbox/mbox-list.c	Wed Dec 29 21:09:21 2004 +0200
+++ b/src/lib-storage/index/mbox/mbox-list.c	Wed Dec 29 21:10:25 2004 +0200
@@ -63,8 +63,8 @@
 static const char *
 mbox_get_path(struct index_storage *storage, const char *name)
 {
-	if (!full_filesystem_access || name == NULL ||
-	    (*name != '/' && *name != '~' && *name != '\0'))
+	if ((storage->storage.flags & MAIL_STORAGE_FLAG_FULL_FS_ACCESS) == 0 ||
+	    name == NULL || (*name != '/' && *name != '~' && *name != '\0'))
 		return t_strconcat(storage->dir, "/", name, NULL);
 	else
 		return home_expand(name);
@@ -116,8 +116,8 @@
 	mail_storage_clear_error(storage);
 
 	/* check that we're not trying to do any "../../" lists */
-	if (!mbox_is_valid_mask(ref) ||
-	    !mbox_is_valid_mask(mask)) {
+	if (!mbox_is_valid_mask(storage, ref) ||
+	    !mbox_is_valid_mask(storage, mask)) {
 		mail_storage_set_error(storage, "Invalid mask");
 		return &ctx->mailbox_ctx;
 	}
--- a/src/lib-storage/index/mbox/mbox-storage.c	Wed Dec 29 21:09:21 2004 +0200
+++ b/src/lib-storage/index/mbox/mbox-storage.c	Wed Dec 29 21:10:25 2004 +0200
@@ -59,79 +59,166 @@
 	return TRUE;
 }
 
-static int mbox_autodetect(const char *data)
+static int mbox_is_file(const char *path, const char *name, int debug)
 {
-	const char *path;
+	struct stat st;
+
+	if (stat(path, &st) < 0) {
+		if (debug) {
+			i_info("mbox autodetect: %s: stat(%s) failed: %m",
+			       name, path);
+		}
+		return FALSE;
+	}
+	if (S_ISDIR(st.st_mode)) {
+		if (debug) {
+			i_info("mbox autodetect: %s: is a directory (%s)",
+			       name, path);
+		}
+		return FALSE;
+	}
+	if (access(path, R_OK|W_OK) < 0) {
+		if (debug) {
+			i_info("mbox autodetect: %s: no R/W access (%s)",
+			       name, path);
+		}
+		return FALSE;
+	}
+
+	if (debug)
+		i_info("mbox autodetect: %s: yes (%s)", name, path);
+	return TRUE;
+}
+
+static int mbox_is_dir(const char *path, const char *name, int debug)
+{
 	struct stat st;
 
-	data = t_strcut(data, ':');
+	if (stat(path, &st) < 0) {
+		if (debug) {
+			i_info("mbox autodetect: %s: stat(%s) failed: %m",
+			       name, path);
+		}
+		return FALSE;
+	}
+	if (!S_ISDIR(st.st_mode)) {
+		if (debug) {
+			i_info("mbox autodetect: %s: is not a directory (%s)",
+			       name, path);
+		}
+		return FALSE;
+	}
+	if (access(path, R_OK|W_OK|X_OK) < 0) {
+		if (debug) {
+			i_info("mbox autodetect: %s: no R/W/X access (%s)",
+			       name, path);
+		}
+		return FALSE;
+	}
 
-	/* Is it INBOX file? */
-	if (*data != '\0' && stat(data, &st) == 0 && !S_ISDIR(st.st_mode) &&
-	    access(data, R_OK|W_OK) == 0)
+	if (debug)
+		i_info("mbox autodetect: %s: yes (%s)", name, path);
+	return TRUE;
+}
+
+static int mbox_autodetect(const char *data, enum mail_storage_flags flags)
+{
+	int debug = (flags & MAIL_STORAGE_FLAG_DEBUG) != 0;
+	const char *path;
+
+	path = t_strcut(data, ':');
+
+	if (debug) {
+		if (strchr(data, ':') != NULL) {
+			i_info("mbox autodetect: data=%s, splitting ':' -> %s",
+			       data, path);
+		} else {
+			i_info("mbox autodetect: data=%s", data);
+		}
+	}
+
+	if (*path != '\0' && mbox_is_file(path, "INBOX file", debug))
 		return TRUE;
 
-	/* or directory for IMAP folders? */
-	path = t_strconcat(data, "/.imap", NULL);
-	if (stat(path, &st) == 0 && S_ISDIR(st.st_mode) &&
-	    access(path, R_OK|W_OK|X_OK) == 0)
+	if (mbox_is_dir(t_strconcat(path, "/.imap", NULL), "has .imap/", debug))
 		return TRUE;
-
-	path = t_strconcat(data, "/inbox", NULL);
-	if (stat(path, &st) == 0 && !S_ISDIR(st.st_mode) &&
-	    access(path, R_OK|W_OK) == 0)
+	if (mbox_is_file(t_strconcat(path, "/inbox", NULL), "has inbox", debug))
 		return TRUE;
-
-	path = t_strconcat(data, "/mbox", NULL);
-	if (stat(path, &st) == 0 && !S_ISDIR(st.st_mode) &&
-	    access(path, R_OK|W_OK) == 0)
+	if (mbox_is_file(t_strconcat(path, "/mbox", NULL), "has mbox", debug))
 		return TRUE;
 
 	return FALSE;
 }
 
-static const char *get_root_dir(void)
+static const char *get_root_dir(enum mail_storage_flags flags)
 {
 	const char *home, *path;
-
-	if (mbox_autodetect(""))
-		return "/";
+	int debug = (flags & MAIL_STORAGE_FLAG_DEBUG) != 0;
 
 	home = getenv("HOME");
 	if (home != NULL) {
 		path = t_strconcat(home, "/mail", NULL);
-		if (access(path, R_OK|W_OK|X_OK) == 0)
+		if (access(path, R_OK|W_OK|X_OK) == 0) {
+			if (debug)
+				i_info("mbox: root exists (%s)", path);
 			return path;
+		}
+		if (debug)
+			i_info("mbox: root: access(%s, rwx) failed: %m", path);
 
 		path = t_strconcat(home, "/Mail", NULL);
-		if (access(path, R_OK|W_OK|X_OK) == 0)
+		if (access(path, R_OK|W_OK|X_OK) == 0) {
+			if (debug)
+				i_info("mbox: root exists (%s)", path);
 			return path;
+		}
+		if (debug)
+			i_info("mbox: root: access(%s, rwx) failed: %m", path);
 	}
 
+	if (debug)
+		i_info("mbox: checking if we are chrooted:");
+	if (mbox_autodetect("", flags))
+		return "/";
+
+	if (debug)
+		i_info("mbox: root directory not found");
+
 	return NULL;
 }
 
-static const char *get_inbox_file(const char *root_dir, int only_root)
+static const char *
+get_inbox_file(const char *root_dir, int only_root, int debug)
 {
 	const char *user, *path;
 
-	if (!only_root) {
-		user = getenv("USER");
-		if (user != NULL) {
-			path = t_strconcat("/var/mail/", user, NULL);
-			if (access(path, R_OK|W_OK) == 0)
-				return path;
+	if (!only_root && (user = getenv("USER")) != NULL) {
+		path = t_strconcat("/var/mail/", user, NULL);
+		if (access(path, R_OK|W_OK) == 0) {
+			if (debug)
+				i_info("mbox: INBOX exists (%s)", path);
+			return path;
+		}
+		if (debug)
+			i_info("mbox: INBOX: access(%s, rw) failed: %m", path);
 
-			path = t_strconcat("/var/spool/mail/", user, NULL);
-			if (access(path, R_OK|W_OK) == 0)
-				return path;
+		path = t_strconcat("/var/spool/mail/", user, NULL);
+		if (access(path, R_OK|W_OK) == 0) {
+			if (debug)
+				i_info("mbox: INBOX exists (%s)", path);
+			return path;
 		}
+		if (debug)
+			i_info("mbox: INBOX: access(%s, rw) failed: %m", path);
 	}
 
-	return t_strconcat(root_dir, "/inbox", NULL);
+	path = t_strconcat(root_dir, "/inbox", NULL);
+	if (debug)
+		i_info("mbox: INBOX defaulted to %s", path);
+	return path;
 }
 
-static const char *create_root_dir(void)
+static const char *create_root_dir(int debug)
 {
 	const char *home, *path;
 
@@ -148,11 +235,15 @@
 		return NULL;
 	}
 
+	if (debug)
+		i_info("mbox: root directory created: %s", path);
 	return path;
 }
 
-static struct mail_storage *mbox_create(const char *data, const char *user)
+static struct mail_storage *
+mbox_create(const char *data, const char *user, enum mail_storage_flags flags)
 {
+	int debug = (flags & MAIL_STORAGE_FLAG_DEBUG) != 0;
 	struct index_storage *storage;
 	const char *root_dir, *inbox_file, *index_dir, *p;
 	struct stat st;
@@ -165,21 +256,23 @@
 		/* we'll need to figure out the mail location ourself.
 		   it's root dir if we've already chroot()ed, otherwise
 		   either $HOME/mail or $HOME/Mail */
-		root_dir = get_root_dir();
+		root_dir = get_root_dir(flags);
 	} else {
 		/* <root folder> | <INBOX path>
 		   [:INBOX=<path>] [:INDEX=<dir>] */
+		if (debug)
+			i_info("mbox: data=%s", data);
 		p = strchr(data, ':');
 		if (p == NULL) {
 			if (stat(data, &st) < 0) {
-				i_error("Invalid mbox file %s: %m", data);
+				i_error("Invalid mbox path %s: %m", data);
 				return NULL;
 			}
 
 			if (S_ISDIR(st.st_mode))
 				root_dir = data;
 			else {
-				root_dir = get_root_dir();
+				root_dir = get_root_dir(flags);
 				inbox_file = data;
 			}
 		} else {
@@ -196,7 +289,7 @@
 	}
 
 	if (root_dir == NULL) {
-		root_dir = create_root_dir();
+		root_dir = create_root_dir(debug);
 		if (root_dir == NULL)
 			return NULL;
 	} else {
@@ -214,13 +307,19 @@
 	}
 
 	if (inbox_file == NULL)
-		inbox_file = get_inbox_file(root_dir, !autodetect);
+		inbox_file = get_inbox_file(root_dir, !autodetect, debug);
 
 	if (index_dir == NULL)
 		index_dir = root_dir;
 	else if (strcmp(index_dir, "MEMORY") == 0)
 		index_dir = NULL;
 
+	if (debug) {
+		i_info("mbox: root=%s, index=%s, inbox=%s",
+		       root_dir, index_dir == NULL ? "" : index_dir,
+		       inbox_file == NULL ? "" : inbox_file);
+	}
+
 	storage = i_new(struct index_storage, 1);
 	storage->storage = mbox_storage;
 
@@ -229,7 +328,7 @@
 	storage->index_dir = i_strdup(home_expand(index_dir));
 	storage->user = i_strdup(user);
 	storage->callbacks = i_new(struct mail_storage_callbacks, 1);
-	index_storage_init(storage);
+	index_storage_init(storage, flags);
 	return &storage->storage;
 }
 
@@ -247,12 +346,12 @@
 	i_free(storage);
 }
 
-int mbox_is_valid_mask(const char *mask)
+int mbox_is_valid_mask(struct mail_storage *storage, const char *mask)
 {
 	const char *p;
 	int newdir;
 
-	if (full_filesystem_access)
+	if ((storage->flags & MAIL_STORAGE_FLAG_FULL_FS_ACCESS) != 0)
 		return TRUE;
 
 	/* make sure it's not absolute path */
@@ -270,7 +369,8 @@
 	return TRUE;
 }
 
-static int mbox_is_valid_create_name(const char *name)
+static int mbox_is_valid_create_name(struct mail_storage *storage,
+				     const char *name)
 {
 	size_t len;
 
@@ -279,10 +379,11 @@
 	    strchr(name, '*') != NULL || strchr(name, '%') != NULL)
 		return FALSE;
 
-	return mbox_is_valid_mask(name);
+	return mbox_is_valid_mask(storage, name);
 }
 
-static int mbox_is_valid_existing_name(const char *name)
+static int mbox_is_valid_existing_name(struct mail_storage *storage,
+				       const char *name)
 {
 	size_t len;
 
@@ -290,7 +391,7 @@
 	if (name[0] == '\0' || name[len-1] == '/')
 		return FALSE;
 
-	return mbox_is_valid_mask(name);
+	return mbox_is_valid_mask(storage, name);
 }
 
 static const char *mbox_get_index_dir(struct index_storage *storage,
@@ -301,7 +402,8 @@
 	if (storage->index_dir == NULL)
 		return NULL;
 
-	if (full_filesystem_access && (*name == '/' || *name == '~')) {
+	if ((storage->storage.flags & MAIL_STORAGE_FLAG_FULL_FS_ACCESS) != 0 &&
+	    (*name == '/' || *name == '~')) {
 		name = home_expand(name);
 		p = strrchr(name, '/');
 		return t_strconcat(t_strdup_until(name, p),
@@ -361,7 +463,8 @@
 {
 	if (strcmp(name, "INBOX") == 0)
 		return storage->inbox_path;
-	if (full_filesystem_access && (*name == '/' || *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);
 }
@@ -449,7 +552,7 @@
 		return mbox_open(storage, "INBOX", flags);
 	}
 
-	if (!mbox_is_valid_existing_name(name)) {
+	if (!mbox_is_valid_existing_name(_storage, name)) {
 		mail_storage_set_error(_storage, "Invalid mailbox name");
 		return NULL;
 	}
@@ -490,7 +593,7 @@
 
 	mail_storage_clear_error(_storage);
 
-	if (!mbox_is_valid_create_name(name)) {
+	if (!mbox_is_valid_create_name(_storage, name)) {
 		mail_storage_set_error(_storage, "Invalid mailbox name");
 		return -1;
 	}
@@ -573,7 +676,7 @@
 		return -1;
 	}
 
-	if (!mbox_is_valid_existing_name(name)) {
+	if (!mbox_is_valid_existing_name(_storage, name)) {
 		mail_storage_set_error(_storage, "Invalid mailbox name");
 		return -1;
 	}
@@ -660,8 +763,8 @@
 
 	mail_storage_clear_error(_storage);
 
-	if (!mbox_is_valid_existing_name(oldname) ||
-	    !mbox_is_valid_create_name(newname)) {
+	if (!mbox_is_valid_existing_name(_storage, oldname) ||
+	    !mbox_is_valid_create_name(_storage, newname)) {
 		mail_storage_set_error(_storage, "Invalid mailbox name");
 		return -1;
 	}
@@ -757,7 +860,7 @@
 
 	mail_storage_clear_error(_storage);
 
-	if (!mbox_is_valid_existing_name(name)) {
+	if (!mbox_is_valid_existing_name(_storage, name)) {
 		*status = MAILBOX_NAME_INVALID;
 		return 0;
 	}
@@ -768,7 +871,7 @@
 		return 0;
 	}
 
-	if (!mbox_is_valid_create_name(name)) {
+	if (!mbox_is_valid_create_name(_storage, name)) {
 		*status = MAILBOX_NAME_INVALID;
 		return 0;
 	}
@@ -843,6 +946,7 @@
 	index_storage_get_last_error,
 
 	NULL,
+	0,
 	0
 };
 
--- a/src/lib-storage/index/mbox/mbox-storage.h	Wed Dec 29 21:09:21 2004 +0200
+++ b/src/lib-storage/index/mbox/mbox-storage.h	Wed Dec 29 21:10:25 2004 +0200
@@ -53,6 +53,6 @@
 int mbox_transaction_save_commit(struct mbox_save_context *ctx);
 void mbox_transaction_save_rollback(struct mbox_save_context *ctx);
 
-int mbox_is_valid_mask(const char *mask);
+int mbox_is_valid_mask(struct mail_storage *storage, const char *mask);
 
 #endif
--- a/src/lib-storage/mail-storage-private.h	Wed Dec 29 21:09:21 2004 +0200
+++ b/src/lib-storage/mail-storage-private.h	Wed Dec 29 21:10:25 2004 +0200
@@ -7,10 +7,11 @@
 	char *name;
 	char hierarchy_sep;
 
-	struct mail_storage *(*create)(const char *data, const char *user);
+	struct mail_storage *(*create)(const char *data, const char *user,
+				       enum mail_storage_flags flags);
 	void (*destroy)(struct mail_storage *storage);
 
-	int (*autodetect)(const char *data);
+	int (*autodetect)(const char *data, enum mail_storage_flags flags);
 
 	void (*set_callbacks)(struct mail_storage *storage,
 			      struct mail_storage_callbacks *callbacks,
@@ -46,6 +47,7 @@
 
 /* private: */
 	char *error;
+	enum mail_storage_flags flags;
 
 	unsigned int syntax_error:1; /* Give a BAD reply instead of NO */
 };
--- a/src/lib-storage/mail-storage.c	Wed Dec 29 21:09:21 2004 +0200
+++ b/src/lib-storage/mail-storage.c	Wed Dec 29 21:10:25 2004 +0200
@@ -19,11 +19,9 @@
 };
 
 static struct mail_storage_list *storages = NULL;
-int full_filesystem_access = FALSE;
 
 void mail_storage_init(void)
 {
-        full_filesystem_access = getenv("FULL_FILESYSTEM_ACCESS") != NULL;
 }
 
 void mail_storage_deinit(void)
@@ -69,7 +67,8 @@
 }
 
 struct mail_storage *
-mail_storage_create(const char *name, const char *data, const char *user)
+mail_storage_create(const char *name, const char *data, const char *user,
+		    enum mail_storage_flags flags)
 {
 	struct mail_storage_list *list;
 
@@ -77,20 +76,20 @@
 
 	for (list = storages; list != NULL; list = list->next) {
 		if (strcasecmp(list->storage->name, name) == 0)
-			return list->storage->create(data, user);
+			return list->storage->create(data, user, flags);
 	}
 
 	return NULL;
 }
 
 struct mail_storage *
-mail_storage_create_default(const char *user)
+mail_storage_create_default(const char *user, enum mail_storage_flags flags)
 {
 	struct mail_storage_list *list;
 	struct mail_storage *storage;
 
 	for (list = storages; list != NULL; list = list->next) {
-		storage = list->storage->create(NULL, user);
+		storage = list->storage->create(NULL, user, flags);
 		if (storage != NULL)
 			return storage;
 	}
@@ -98,12 +97,13 @@
 	return NULL;
 }
 
-static struct mail_storage *mail_storage_autodetect(const char *data)
+static struct mail_storage *
+mail_storage_autodetect(const char *data, enum mail_storage_flags flags)
 {
 	struct mail_storage_list *list;
 
 	for (list = storages; list != NULL; list = list->next) {
-		if (list->storage->autodetect(data))
+		if (list->storage->autodetect(data, flags))
 			return list->storage;
 	}
 
@@ -111,13 +111,14 @@
 }
 
 struct mail_storage *
-mail_storage_create_with_data(const char *data, const char *user)
+mail_storage_create_with_data(const char *data, const char *user,
+			      enum mail_storage_flags flags)
 {
 	struct mail_storage *storage;
 	const char *p, *name;
 
 	if (data == NULL || *data == '\0')
-		return mail_storage_create_default(user);
+		return mail_storage_create_default(user, flags);
 
 	/* check if we're in the form of mailformat:data
 	   (eg. maildir:Maildir) */
@@ -126,11 +127,11 @@
 
 	if (*p == ':') {
 		name = t_strdup_until(data, p);
-		storage = mail_storage_create(name, p+1, user);
+		storage = mail_storage_create(name, p+1, user, flags);
 	} else {
-		storage = mail_storage_autodetect(data);
+		storage = mail_storage_autodetect(data, flags);
 		if (storage != NULL)
-			storage = storage->create(data, user);
+			storage = storage->create(data, user, flags);
 	}
 
 	return storage;
--- a/src/lib-storage/mail-storage.h	Wed Dec 29 21:09:21 2004 +0200
+++ b/src/lib-storage/mail-storage.h	Wed Dec 29 21:10:25 2004 +0200
@@ -5,6 +5,13 @@
 
 #include "mail-types.h"
 
+enum mail_storage_flags {
+	/* Print debugging information while initializing the storage */
+	MAIL_STORAGE_FLAG_DEBUG			= 0x01,
+	/* Allow full filesystem access with absolute or relative paths. */
+	MAIL_STORAGE_FLAG_FULL_FS_ACCESS	= 0x02
+};
+
 enum mailbox_open_flags {
 	MAILBOX_OPEN_READONLY		= 0x01,
 	MAILBOX_OPEN_FAST		= 0x02,
@@ -156,8 +163,6 @@
 
 typedef void mailbox_notify_callback_t(struct mailbox *box, void *context);
 
-extern int full_filesystem_access;
-
 void mail_storage_init(void);
 void mail_storage_deinit(void);
 
@@ -176,12 +181,15 @@
    If namespace is non-NULL, all mailbox names are expected to begin with it.
    hierarchy_sep overrides the default separator if it's not '\0'. */
 struct mail_storage *
-mail_storage_create(const char *name, const char *data, const char *user);
+mail_storage_create(const char *name, const char *data, const char *user,
+		    enum mail_storage_flags flags);
 void mail_storage_destroy(struct mail_storage *storage);
 
-struct mail_storage *mail_storage_create_default(const char *user);
+struct mail_storage *
+mail_storage_create_default(const char *user, enum mail_storage_flags flags);
 struct mail_storage *
-mail_storage_create_with_data(const char *data, const char *user);
+mail_storage_create_with_data(const char *data, const char *user,
+			      enum mail_storage_flags flags);
 
 char mail_storage_get_hierarchy_sep(struct mail_storage *storage);
 
--- a/src/master/mail-process.c	Wed Dec 29 21:09:21 2004 +0200
+++ b/src/master/mail-process.c	Wed Dec 29 21:10:25 2004 +0200
@@ -214,6 +214,8 @@
 		env_put("MAILDIR_STAT_DIRS=1");
 	if (set->maildir_copy_with_hardlinks)
 		env_put("MAILDIR_COPY_WITH_HARDLINKS=1");
+	if (set->mail_debug)
+		env_put("DEBUG=1");
 	if (set->mail_full_filesystem_access)
 		env_put("FULL_FILESYSTEM_ACCESS=1");
 	if (set->pop3_no_flag_updates)
--- a/src/master/master-settings.c	Wed Dec 29 21:09:21 2004 +0200
+++ b/src/master/master-settings.c	Wed Dec 29 21:10:25 2004 +0200
@@ -91,6 +91,7 @@
 	DEF(SET_STR, mail_cache_fields),
 	DEF(SET_STR, mail_never_cache_fields),
 	DEF(SET_INT, mailbox_idle_check_interval),
+	DEF(SET_BOOL, mail_debug),
 	DEF(SET_BOOL, mail_full_filesystem_access),
 	DEF(SET_INT, mail_max_keyword_length),
 	DEF(SET_BOOL, mail_save_crlf),
@@ -258,6 +259,7 @@
 	MEMBER(mail_cache_fields) "flags",
 	MEMBER(mail_never_cache_fields) "imap.envelope",
 	MEMBER(mailbox_idle_check_interval) 30,
+	MEMBER(mail_debug) FALSE,
 	MEMBER(mail_full_filesystem_access) FALSE,
 	MEMBER(mail_max_keyword_length) 50,
 	MEMBER(mail_save_crlf) FALSE,
--- a/src/master/master-settings.h	Wed Dec 29 21:09:21 2004 +0200
+++ b/src/master/master-settings.h	Wed Dec 29 21:10:25 2004 +0200
@@ -62,6 +62,7 @@
 	const char *mail_cache_fields;
 	const char *mail_never_cache_fields;
 	unsigned int mailbox_idle_check_interval;
+	int mail_debug;
 	int mail_full_filesystem_access;
 	int mail_max_keyword_length;
 	int mail_save_crlf;
--- a/src/pop3/main.c	Wed Dec 29 21:09:21 2004 +0200
+++ b/src/pop3/main.c	Wed Dec 29 21:10:25 2004 +0200
@@ -141,6 +141,7 @@
 
 static int main_init(void)
 {
+        enum mail_storage_flags flags;
 	struct mail_storage *storage;
 	const char *mail;
 
@@ -172,7 +173,13 @@
 		uidl_format = "%v.%u";
 	uidl_keymask = parse_uidl_keymask(uidl_format);
 
-	storage = mail_storage_create_with_data(mail, getenv("USER"));
+	flags = 0;
+	if (getenv("FULL_FILESYSTEM_ACCESS") != NULL)
+		flags |= MAIL_STORAGE_FLAG_FULL_FS_ACCESS;
+	if (getenv("DEBUG") != NULL)
+		flags |= MAIL_STORAGE_FLAG_DEBUG;
+
+	storage = mail_storage_create_with_data(mail, getenv("USER"), flags);
 	if (storage == NULL) {
 		/* failed */
 		if (mail != NULL && *mail != '\0')