changeset 5613:f717fb4b31c0 HEAD

Error handling rewrite.
author Timo Sirainen <tss@iki.fi>
date Sun, 13 May 2007 20:10:48 +0300
parents 0d8f6bfb9fdb
children a4e5053fb31a
files src/deliver/deliver.c src/imap/cmd-fetch.c src/imap/commands-util.c src/imap/imap-search.c src/lib-storage/Makefile.am src/lib-storage/index/cydir/cydir-save.c src/lib-storage/index/cydir/cydir-storage.c src/lib-storage/index/dbox/dbox-save.c src/lib-storage/index/dbox/dbox-storage.c src/lib-storage/index/dbox/dbox-uidlist.c src/lib-storage/index/index-search.c src/lib-storage/index/maildir/maildir-copy.c src/lib-storage/index/maildir/maildir-save.c src/lib-storage/index/maildir/maildir-storage.c src/lib-storage/index/maildir/maildir-uidlist.c src/lib-storage/index/maildir/maildir-util.c src/lib-storage/index/mbox/mbox-file.c src/lib-storage/index/mbox/mbox-lock.c src/lib-storage/index/mbox/mbox-save.c src/lib-storage/index/mbox/mbox-storage.c src/lib-storage/index/mbox/mbox-sync.c src/lib-storage/list/mailbox-list-fs-iter.c src/lib-storage/list/mailbox-list-fs.c src/lib-storage/list/mailbox-list-maildir.c src/lib-storage/list/subscription-file.c src/lib-storage/mail-error.c src/lib-storage/mail-error.h src/lib-storage/mail-storage-private.h src/lib-storage/mail-storage.c src/lib-storage/mail-storage.h src/lib-storage/mailbox-list-private.h src/lib-storage/mailbox-list.c src/lib-storage/mailbox-list.h src/plugins/acl/acl-mailbox-list.c src/plugins/acl/acl-mailbox.c src/plugins/acl/acl-storage.c src/plugins/convert/convert-storage.c src/plugins/lazy-expunge/lazy-expunge-plugin.c src/plugins/quota/quota-storage.c src/plugins/quota/quota.c src/pop3/client.c
diffstat 41 files changed, 333 insertions(+), 298 deletions(-) [+]
line wrap: on
line diff
--- a/src/deliver/deliver.c	Sun May 13 19:53:41 2007 +0300
+++ b/src/deliver/deliver.c	Sun May 13 20:10:48 2007 +0300
@@ -81,7 +81,7 @@
 {
 	struct mail_namespace *ns;
 	struct mailbox *box;
-	bool temp;
+	enum mail_error error;
 
 	ns = mail_namespace_find(namespaces, &name);
 	if (ns == NULL) {
@@ -95,11 +95,11 @@
 	if (box != NULL || no_mailbox_autocreate)
 		return box;
 
-	(void)mail_storage_get_last_error(ns->storage, &temp);
-	if (temp)
+	(void)mail_storage_get_last_error(ns->storage, &error);
+	if (error != MAIL_ERROR_NOTFOUND)
 		return NULL;
 
-	/* probably the mailbox just doesn't exist. try creating it. */
+	/* try creating it. */
 	if (mail_storage_mailbox_create(ns->storage, name, FALSE) < 0)
 		return NULL;
 
@@ -714,25 +714,29 @@
 	}
 
 	if (ret < 0) {
-		const char *error, *msgid;
-		bool temporary_error;
+		const char *error_string, *msgid;
+		enum mail_error error;
 		int ret;
 
-		error = mail_storage_get_last_error(storage, &temporary_error);
-		if (temporary_error)
+		error_string = mail_storage_get_last_error(ns->storage, &error);
+		if (error != MAIL_ERROR_NOSPACE) {
+			/* Saving to INBOX should always work unless
+			   we're over quota. If it didn't, it's probably a
+			   configuration problem. */
 			return EX_TEMPFAIL;
+		}
 
 		msgid = mail_get_first_header(mail, "Message-ID");
 		i_info("msgid=%s: Rejected: %s",
 		       msgid == NULL ? "" : str_sanitize(msgid, 80),
-		       str_sanitize(error, 512));
+		       str_sanitize(error_string, 512));
 
 		/* we'll have to reply with permanent failure */
 		if (stderr_rejection) {
-			fprintf(stderr, "%s\n", error);
+			fprintf(stderr, "%s\n", error_string);
 			return EX_NOPERM;
 		}
-		ret = mail_send_rejection(mail, destination, error);
+		ret = mail_send_rejection(mail, destination, error_string);
 		if (ret != 0)
 			return ret < 0 ? EX_TEMPFAIL : ret;
 		/* ok, rejection sent */
--- a/src/imap/cmd-fetch.c	Sun May 13 19:53:41 2007 +0300
+++ b/src/imap/cmd-fetch.c	Sun May 13 20:10:48 2007 +0300
@@ -78,8 +78,8 @@
 
 	if (ctx->failed) {
 		struct mail_storage *storage;
-		const char *error;
-		bool temporary_error;
+		const char *error_string;
+		enum mail_error error;
 
 		if (ctx->client->output->closed) {
 			client_disconnect(cmd->client, "Disconnected");
@@ -87,11 +87,11 @@
 		}
 
                 storage = mailbox_get_storage(cmd->client->mailbox);
-		error = mail_storage_get_last_error(storage, &temporary_error);
+		error_string = mail_storage_get_last_error(storage, &error);
 
 		/* We never want to reply NO to FETCH requests,
 		   BYE is preferrable (see imap-ml for reasons). */
-		client_disconnect_with_error(cmd->client, error);
+		client_disconnect_with_error(cmd->client, error_string);
 		return TRUE;
 	}
 
--- a/src/imap/commands-util.c	Sun May 13 19:53:41 2007 +0300
+++ b/src/imap/commands-util.c	Sun May 13 20:10:48 2007 +0300
@@ -146,18 +146,18 @@
 void client_send_list_error(struct client_command_context *cmd,
 			    struct mailbox_list *list)
 {
-	const char *error;
-	bool temporary_error;
+	const char *error_string;
+	enum mail_error error;
 
-	error = mailbox_list_get_last_error(list, &temporary_error);
-	client_send_tagline(cmd, t_strconcat("NO ", error, NULL));
+	error_string = mailbox_list_get_last_error(list, &error);
+	client_send_tagline(cmd, t_strconcat("NO ", error_string, NULL));
 }
 
 void client_send_storage_error(struct client_command_context *cmd,
 			       struct mail_storage *storage)
 {
-	const char *error;
-	bool temporary_error;
+	const char *error_string;
+	enum mail_error error;
 
 	if (cmd->client->mailbox != NULL &&
 	    mailbox_is_inconsistent(cmd->client->mailbox)) {
@@ -167,15 +167,15 @@
 		return;
 	}
 
-	error = mail_storage_get_last_error(storage, &temporary_error);
-	client_send_tagline(cmd, t_strconcat("NO ", error, NULL));
+	error_string = mail_storage_get_last_error(storage, &error);
+	client_send_tagline(cmd, t_strconcat("NO ", error_string, NULL));
 }
 
 void client_send_untagged_storage_error(struct client *client,
 					struct mail_storage *storage)
 {
-	const char *error;
-	bool temporary_error;
+	const char *error_string;
+	enum mail_error error;
 
 	if (client->mailbox != NULL &&
 	    mailbox_is_inconsistent(client->mailbox)) {
@@ -185,8 +185,8 @@
 		return;
 	}
 
-	error = mail_storage_get_last_error(storage, &temporary_error);
-	client_send_line(client, t_strconcat("* NO ", error, NULL));
+	error_string = mail_storage_get_last_error(storage, &error);
+	client_send_line(client, t_strconcat("* NO ", error_string, NULL));
 }
 
 static bool is_valid_keyword(struct client_command_context *cmd,
--- a/src/imap/imap-search.c	Sun May 13 19:53:41 2007 +0300
+++ b/src/imap/imap-search.c	Sun May 13 20:10:48 2007 +0300
@@ -19,7 +19,7 @@
 		  struct mail_search_seqset **seqset_r, const char **error_r)
 {
 	struct mail_search_seqset *seqset, **p;
-	bool temporary, last;
+	bool last;
 
 	*seqset_r = imap_messageset_parse(pool, uidset);
 	if (*seqset_r == NULL) {
@@ -38,8 +38,9 @@
 		if (mailbox_get_uids(box, seqset->seq1, seqset->seq2,
 				     &seqset->seq1, &seqset->seq2) < 0) {
 			struct mail_storage *storage = mailbox_get_storage(box);
-			*error_r = mail_storage_get_last_error(storage,
-							       &temporary);
+			enum mail_error error;
+
+			*error_r = mail_storage_get_last_error(storage, &error);
 			return -1;
 		}
 
--- a/src/lib-storage/Makefile.am	Sun May 13 19:53:41 2007 +0300
+++ b/src/lib-storage/Makefile.am	Sun May 13 20:10:48 2007 +0300
@@ -11,6 +11,7 @@
 libstorage_a_SOURCES = \
 	mail.c \
 	mail-copy.c \
+	mail-error.c \
 	mail-namespace.c \
 	mail-search.c \
 	mail-storage.c \
@@ -19,6 +20,7 @@
 
 headers = \
 	mail-copy.h \
+	mail-error.h \
 	mail-namespace.h \
 	mail-search.h \
 	mail-storage.h \
--- a/src/lib-storage/index/cydir/cydir-save.c	Sun May 13 19:53:41 2007 +0300
+++ b/src/lib-storage/index/cydir/cydir-save.c	Sun May 13 20:10:48 2007 +0300
@@ -125,16 +125,14 @@
 int cydir_save_continue(struct mail_save_context *_ctx)
 {
 	struct cydir_save_context *ctx = (struct cydir_save_context *)_ctx;
+	struct mail_storage *storage = &ctx->mbox->storage->storage;
 
 	if (ctx->failed)
 		return -1;
 
 	if (o_stream_send_istream(ctx->output, ctx->input) < 0) {
-		if (ENOSPACE(ctx->output->stream_errno)) {
-			mail_storage_set_error(&ctx->mbox->storage->storage,
-					       "Not enough disk space");
-		} else {
-			mail_storage_set_critical(&ctx->mbox->storage->storage,
+		if (!mail_storage_set_error_from_errno(storage)) {
+			mail_storage_set_critical(storage,
 				"o_stream_send_istream(%s) failed: %m",
 				cydir_get_save_path(ctx, ctx->mail_count));
 		}
--- a/src/lib-storage/index/cydir/cydir-storage.c	Sun May 13 19:53:41 2007 +0300
+++ b/src/lib-storage/index/cydir/cydir-storage.c	Sun May 13 20:10:48 2007 +0300
@@ -141,16 +141,11 @@
 
 static int create_cydir(struct mail_storage *storage, const char *path)
 {
-	const char *error;
-
 	if (mkdir_parents(path, CREATE_MODE) < 0 && errno != EEXIST) {
-		if (mail_storage_errno2str(&error)) {
-			mail_storage_set_error(storage, "%s", error);
-			return -1;
+		if (!mail_storage_set_error_from_errno(storage)) {
+			mail_storage_set_critical(storage,
+				"mkdir(%s) failed: %m", path);
 		}
-
-		mail_storage_set_critical(storage, "mkdir(%s) failed: %m",
-					  path);
 		return -1;
 	}
 	return 0;
@@ -235,8 +230,8 @@
 	if (stat(path, &st) == 0) {
 		return cydir_open(storage, name, flags);
 	} else if (errno == ENOENT) {
-		mail_storage_set_error(_storage,
-			MAILBOX_LIST_ERR_MAILBOX_NOT_FOUND, name);
+		mail_storage_set_error(_storage, MAIL_ERROR_NOTFOUND,
+			T_MAIL_ERR_MAILBOX_NOT_FOUND(name));
 		return NULL;
 	} else {
 		mail_storage_set_critical(_storage, "stat(%s) failed: %m",
@@ -255,7 +250,8 @@
 	path = mailbox_list_get_path(_storage->list, name,
 				     MAILBOX_LIST_PATH_TYPE_MAILBOX);
 	if (stat(path, &st) == 0) {
-		mail_storage_set_error(_storage, "Mailbox already exists");
+		mail_storage_set_error(_storage, MAIL_ERROR_NOTPOSSIBLE,
+				       "Mailbox already exists");
 		return -1;
 	}
 
@@ -274,10 +270,7 @@
 
 	dir = opendir(path);
 	if (dir == NULL) {
-		if (errno == ENOENT) {
-			mailbox_list_set_error(list, t_strdup_printf(
-				MAILBOX_LIST_ERR_MAILBOX_NOT_FOUND, name));
-		} else {
+		if (!mailbox_list_set_error_from_errno(list)) {
 			mailbox_list_set_critical(list,
 				"opendir(%s) failed: %m", path);
 		}
@@ -327,8 +320,9 @@
 	}
 
 	if (!unlinked_something) {
-		mailbox_list_set_error(list, t_strdup_printf(
-			"Directory %s isn't empty, can't delete it.", name));
+		mailbox_list_set_error(list, MAIL_ERROR_NOTPOSSIBLE,
+			t_strdup_printf("Directory %s isn't empty, "
+					"can't delete it.", name));
 		return -1;
 	}
 	return 0;
@@ -354,8 +348,8 @@
 	/* check if the mailbox actually exists */
 	src = mailbox_list_get_path(list, name, MAILBOX_LIST_PATH_TYPE_MAILBOX);
 	if (stat(src, &st) != 0 && errno == ENOENT) {
-		mailbox_list_set_error(list, t_strdup_printf(
-			MAILBOX_LIST_ERR_MAILBOX_NOT_FOUND, name));
+		mailbox_list_set_error(list, MAIL_ERROR_NOTFOUND,
+			T_MAIL_ERR_MAILBOX_NOT_FOUND(name));
 		return -1;
 	}
 
--- a/src/lib-storage/index/dbox/dbox-save.c	Sun May 13 19:53:41 2007 +0300
+++ b/src/lib-storage/index/dbox/dbox-save.c	Sun May 13 20:10:48 2007 +0300
@@ -252,16 +252,14 @@
 int dbox_save_continue(struct mail_save_context *_ctx)
 {
 	struct dbox_save_context *ctx = (struct dbox_save_context *)_ctx;
+	struct mail_storage *storage = &ctx->mbox->storage->storage;
 
 	if (ctx->failed)
 		return -1;
 
 	if (o_stream_send_istream(ctx->file->output, ctx->input) < 0) {
-		if (ENOSPACE(ctx->file->output->stream_errno)) {
-			mail_storage_set_error(&ctx->mbox->storage->storage,
-					       "Not enough disk space");
-		} else {
-			mail_storage_set_critical(&ctx->mbox->storage->storage,
+		if (!mail_storage_set_error_from_errno(storage)) {
+			mail_storage_set_critical(storage,
 				"o_stream_send_istream(%s) failed: %m",
 				ctx->file->path);
 		}
--- a/src/lib-storage/index/dbox/dbox-storage.c	Sun May 13 19:53:41 2007 +0300
+++ b/src/lib-storage/index/dbox/dbox-storage.c	Sun May 13 20:10:48 2007 +0300
@@ -257,16 +257,11 @@
 
 static int create_dbox(struct mail_storage *storage, const char *path)
 {
-	const char *error;
-
 	if (mkdir_parents(path, CREATE_MODE) < 0 && errno != EEXIST) {
-		if (mail_storage_errno2str(&error)) {
-			mail_storage_set_error(storage, "%s", error);
-			return -1;
+		if (!mail_storage_set_error_from_errno(storage)) {
+			mail_storage_set_critical(storage,
+				"mkdir(%s) failed: %m", path);
 		}
-
-		mail_storage_set_critical(storage, "mkdir(%s) failed: %m",
-					  path);
 		return -1;
 	}
 	return 0;
@@ -391,8 +386,8 @@
 	if (stat(path, &st) == 0) {
 		return dbox_open(storage, name, flags);
 	} else if (errno == ENOENT) {
-		mail_storage_set_error(_storage,
-			MAILBOX_LIST_ERR_MAILBOX_NOT_FOUND, name);
+		mail_storage_set_error(_storage, MAIL_ERROR_NOTFOUND,
+			T_MAIL_ERR_MAILBOX_NOT_FOUND(name));
 		return NULL;
 	} else {
 		mail_storage_set_critical(_storage, "stat(%s) failed: %m",
@@ -411,7 +406,8 @@
 	path = mailbox_list_get_path(_storage->list, name,
 				     MAILBOX_LIST_PATH_TYPE_MAILBOX);
 	if (stat(path, &st) == 0) {
-		mail_storage_set_error(_storage, "Mailbox already exists");
+		mail_storage_set_error(_storage, MAIL_ERROR_NOTPOSSIBLE,
+				       "Mailbox already exists");
 		return -1;
 	}
 
@@ -423,7 +419,7 @@
 {
 	struct dbox_storage *storage = DBOX_LIST_CONTEXT(list);
 	struct stat st;
-	const char *path, *mail_path, *error;
+	const char *path, *mail_path;
 
 	/* make sure the indexes are closed before trying to delete the
 	   directory that contains them */
@@ -440,8 +436,8 @@
 	if (stat(mail_path, &st) < 0 && ENOTFOUND(errno)) {
 		if (stat(path, &st) < 0) {
 			/* doesn't exist at all */
-			mailbox_list_set_error(list, t_strdup_printf(
-				MAILBOX_LIST_ERR_MAILBOX_NOT_FOUND, name));
+			mailbox_list_set_error(list, MAIL_ERROR_NOTFOUND,
+				T_MAIL_ERR_MAILBOX_NOT_FOUND(name));
 			return -1;
 		}
 
@@ -450,9 +446,9 @@
 			return 0;
 
 		if (errno == ENOTEMPTY) {
-			mailbox_list_set_error(list, t_strdup_printf(
-				"Directory %s isn't empty, can't delete it.",
-				name));
+			mailbox_list_set_error(list, MAIL_ERROR_NOTPOSSIBLE,
+				t_strdup_printf("Directory %s isn't empty, "
+						"can't delete it.", name));
 		} else {
 			mailbox_list_set_critical(list,
 				"rmdir() failed for %s: %m", path);
@@ -463,9 +459,7 @@
 
 
 	if (unlink_directory(mail_path, TRUE) < 0) {
-		if (mail_storage_errno2str(&error))
-			mailbox_list_set_error(list, error);
-		else {
+		if (!mailbox_list_set_error_from_errno(list)) {
 			mailbox_list_set_critical(list,
 				"unlink_directory() failed for %s: %m",
 				mail_path);
--- a/src/lib-storage/index/dbox/dbox-uidlist.c	Sun May 13 19:53:41 2007 +0300
+++ b/src/lib-storage/index/dbox/dbox-uidlist.c	Sun May 13 20:10:48 2007 +0300
@@ -439,8 +439,7 @@
 	if (uidlist->lock_fd == -1) {
 		if (errno == EAGAIN) {
 			mail_storage_set_error(&mbox->storage->storage,
-				"Timeout while waiting for lock");
-			mbox->storage->storage.temporary_error = TRUE;
+				MAIL_ERROR_TEMP, MAIL_ERRSTR_LOCK_TIMEOUT);
 			return 0;
 		}
 		mail_storage_set_critical(&mbox->storage->storage,
--- a/src/lib-storage/index/index-search.c	Sun May 13 19:53:41 2007 +0300
+++ b/src/lib-storage/index/index-search.c	Sun May 13 20:10:48 2007 +0300
@@ -907,7 +907,7 @@
 
 	if (ctx->error != NULL) {
 		mail_storage_set_error(ctx->ibox->box.storage,
-				       "%s", ctx->error);
+				       MAIL_ERROR_PARAMS, ctx->error);
 	}
 
 	mail_search_args_reset(ctx->mail_ctx.args, FALSE);
--- a/src/lib-storage/index/maildir/maildir-copy.c	Sun May 13 19:53:41 2007 +0300
+++ b/src/lib-storage/index/maildir/maildir-copy.c	Sun May 13 20:10:48 2007 +0300
@@ -72,7 +72,7 @@
 
 		if (ENOSPACE(errno)) {
 			mail_storage_set_error(&mbox->storage->storage,
-					       "Not enough disk space");
+				MAIL_ERROR_NOSPACE, MAIL_ERRSTR_NO_SPACE);
 			return -1;
 		}
 
--- a/src/lib-storage/index/maildir/maildir-save.c	Sun May 13 19:53:41 2007 +0300
+++ b/src/lib-storage/index/maildir/maildir-save.c	Sun May 13 20:10:48 2007 +0300
@@ -94,7 +94,7 @@
 		ret = -1;
 		if (ENOSPACE(errno)) {
 			mail_storage_set_error(storage,
-					       "Not enough disk space");
+				MAIL_ERROR_NOSPACE, MAIL_ERRSTR_NO_SPACE);
 		} else {
 			mail_storage_set_critical(storage,
 				"rename(%s, %s) failed: %m",
@@ -378,6 +378,7 @@
 int maildir_save_continue(struct mail_save_context *_ctx)
 {
 	struct maildir_save_context *ctx = (struct maildir_save_context *)_ctx;
+	struct mail_storage *storage = &ctx->mbox->storage->storage;
 
 	if (ctx->failed)
 		return -1;
@@ -386,11 +387,8 @@
 		index_mail_cache_parse_continue(ctx->cur_dest_mail);
 
 	if (o_stream_send_istream(ctx->output, ctx->input) < 0) {
-		if (ENOSPACE(errno)) {
-			mail_storage_set_error(&ctx->mbox->storage->storage,
-					       "Not enough disk space");
-		} else {
-			mail_storage_set_critical(&ctx->mbox->storage->storage,
+		if (!mail_storage_set_error_from_errno(storage)) {
+			mail_storage_set_critical(storage,
 				"o_stream_send_istream(%s/%s) failed: %m",
 				ctx->tmpdir, ctx->file_last->basename);
 		}
@@ -466,7 +464,7 @@
 		errno = output_errno;
 		if (ENOSPACE(errno)) {
 			mail_storage_set_error(&ctx->mbox->storage->storage,
-					       "Not enough disk space");
+				MAIL_ERROR_NOSPACE, MAIL_ERRSTR_NO_SPACE);
 		} else if (errno != 0) {
 			mail_storage_set_critical(&ctx->mbox->storage->storage,
 				"write(%s) failed: %m", ctx->mbox->path);
--- a/src/lib-storage/index/maildir/maildir-storage.c	Sun May 13 19:53:41 2007 +0300
+++ b/src/lib-storage/index/maildir/maildir-storage.c	Sun May 13 20:10:48 2007 +0300
@@ -568,8 +568,8 @@
 
 		return maildir_open(storage, name, flags);
 	} else if (errno == ENOENT) {
-		mail_storage_set_error(_storage,
-			MAILBOX_LIST_ERR_MAILBOX_NOT_FOUND, name);
+		mail_storage_set_error(_storage, MAIL_ERROR_NOTFOUND,
+			T_MAIL_ERR_MAILBOX_NOT_FOUND(name));
 		return NULL;
 	} else {
 		mail_storage_set_critical(_storage, "stat(%s) failed: %m",
@@ -593,7 +593,7 @@
 	old_mask = umask(0777 ^ mode);
 	if (create_maildir(storage, dir, FALSE) < 0) {
 		if (errno == EEXIST) {
-			mail_storage_set_error(storage,
+			mail_storage_set_error(storage, MAIL_ERROR_NOTPOSSIBLE,
 					       "Mailbox already exists");
 		}
 		umask(old_mask);
@@ -643,7 +643,7 @@
 
 	if (create_maildir(_storage, path, FALSE) < 0) {
 		if (errno == EEXIST) {
-			mail_storage_set_error(_storage,
+			mail_storage_set_error(_storage, MAIL_ERROR_NOTPOSSIBLE,
 					       "Mailbox already exists");
 		}
 		return -1;
@@ -694,8 +694,8 @@
 	dir = opendir(path);
 	if (dir == NULL) {
 		if (errno == ENOENT) {
-			mailbox_list_set_error(list, t_strdup_printf(
-				MAILBOX_LIST_ERR_MAILBOX_NOT_FOUND, name));
+			mailbox_list_set_error(list, MAIL_ERROR_NOTFOUND,
+				T_MAIL_ERR_MAILBOX_NOT_FOUND(name));
 		} else {
 			mailbox_list_set_critical(list,
 				"opendir(%s) failed: %m", path);
@@ -757,8 +757,9 @@
 	}
 
 	if (!unlinked_something) {
-		mailbox_list_set_error(list, t_strdup_printf(
-			"Directory %s isn't empty, can't delete it.", name));
+		mailbox_list_set_error(list, MAIL_ERROR_NOTPOSSIBLE,
+			t_strdup_printf("Directory %s isn't empty, "
+					"can't delete it.", name));
 		return -1;
 	}
 	return 0;
@@ -785,8 +786,8 @@
 	/* check if the mailbox actually exists */
 	src = mailbox_list_get_path(list, name, MAILBOX_LIST_PATH_TYPE_MAILBOX);
 	if (stat(src, &st) != 0 && errno == ENOENT) {
-		mailbox_list_set_error(list, t_strdup_printf(
-			MAILBOX_LIST_ERR_MAILBOX_NOT_FOUND, name));
+		mailbox_list_set_error(list, MAIL_ERROR_NOTFOUND,
+			T_MAIL_ERR_MAILBOX_NOT_FOUND(name));
 		return -1;
 	}
 
@@ -805,8 +806,8 @@
 		if (errno == ENOENT) {
 			/* it was just deleted under us by
 			   another process */
-			mailbox_list_set_error(list, t_strdup_printf(
-				MAILBOX_LIST_ERR_MAILBOX_NOT_FOUND, name));
+			mailbox_list_set_error(list, MAIL_ERROR_NOTFOUND,
+				T_MAIL_ERR_MAILBOX_NOT_FOUND(name));
 			return -1;
 		}
 		if (!EDESTDIREXISTS(errno)) {
@@ -849,7 +850,7 @@
 		path2 = mailbox_list_get_path(list, NULL,
 					      MAILBOX_LIST_PATH_TYPE_MAILBOX);
 		if (strcmp(path1, path2) == 0) {
-			mailbox_list_set_error(list,
+			mailbox_list_set_error(list, MAIL_ERROR_NOTPOSSIBLE,
 				"Renaming INBOX isn't supported.");
 			return -1;
 		}
--- a/src/lib-storage/index/maildir/maildir-uidlist.c	Sun May 13 19:53:41 2007 +0300
+++ b/src/lib-storage/index/maildir/maildir-uidlist.c	Sun May 13 20:10:48 2007 +0300
@@ -103,8 +103,7 @@
 	if (fd == -1) {
 		if (errno == EAGAIN) {
 			mail_storage_set_error(&mbox->storage->storage,
-				"Timeout while waiting for lock");
-			mbox->storage->storage.temporary_error = TRUE;
+				MAIL_ERROR_TEMP, MAIL_ERRSTR_LOCK_TIMEOUT);
 			return 0;
 		}
 		mail_storage_set_critical(&mbox->storage->storage,
--- a/src/lib-storage/index/maildir/maildir-util.c	Sun May 13 19:53:41 2007 +0300
+++ b/src/lib-storage/index/maildir/maildir-util.c	Sun May 13 20:10:48 2007 +0300
@@ -135,7 +135,7 @@
 	if (fd == -1) {
 		if (ENOSPACE(errno)) {
 			mail_storage_set_error(&mbox->storage->storage,
-					       "Not enough disk space");
+				MAIL_ERROR_NOSPACE, MAIL_ERRSTR_NO_SPACE);
 		} else {
 			mail_storage_set_critical(&mbox->storage->storage,
 				"open(%s) failed: %m", str_c(path));
--- a/src/lib-storage/index/mbox/mbox-file.c	Sun May 13 19:53:41 2007 +0300
+++ b/src/lib-storage/index/mbox/mbox-file.c	Sun May 13 20:10:48 2007 +0300
@@ -171,6 +171,7 @@
 	if (istream_raw_mbox_seek(mbox->mbox_stream, offset) < 0) {
 		if (offset == 0) {
 			mail_storage_set_error(&mbox->storage->storage,
+				MAIL_ERROR_NOTPOSSIBLE,
 				"Mailbox isn't a valid mbox file");
 			return -1;
 		}
--- a/src/lib-storage/index/mbox/mbox-lock.c	Sun May 13 19:53:41 2007 +0300
+++ b/src/lib-storage/index/mbox/mbox-lock.c	Sun May 13 20:10:48 2007 +0300
@@ -263,8 +263,7 @@
 	}
 	if (ret == 0) {
 		mail_storage_set_error(&mbox->storage->storage,
-				       "Timeout while waiting for lock");
-		mbox->storage->storage.temporary_error = TRUE;
+			MAIL_ERROR_TEMP, MAIL_ERRSTR_LOCK_TIMEOUT);
 		return 0;
 	}
 	mbox->mbox_dotlocked = TRUE;
@@ -495,8 +494,7 @@
 			(void)mbox_unlock_files(&ctx);
 		if (ret == 0) {
 			mail_storage_set_error(&mbox->storage->storage,
-				"Timeout while waiting for lock");
-			mbox->storage->storage.temporary_error = TRUE;
+				MAIL_ERROR_TEMP, MAIL_ERRSTR_LOCK_TIMEOUT);
 		}
 		return ret;
 	}
--- a/src/lib-storage/index/mbox/mbox-save.c	Sun May 13 19:53:41 2007 +0300
+++ b/src/lib-storage/index/mbox/mbox-save.c	Sun May 13 20:10:48 2007 +0300
@@ -59,13 +59,7 @@
 
 static int write_error(struct mbox_save_context *ctx)
 {
-	if (ENOSPACE(errno)) {
-		mail_storage_set_error(&ctx->mbox->storage->storage,
-				       "Not enough disk space");
-	} else {
-		mbox_set_syscall_error(ctx->mbox, "write()");
-	}
-
+	mbox_set_syscall_error(ctx->mbox, "write()");
 	ctx->failed = TRUE;
 	return -1;
 }
@@ -266,10 +260,11 @@
 		    struct mbox_transaction_context *t, bool want_mail)
 {
 	struct mbox_mailbox *mbox = ctx->mbox;
+	struct mail_storage *storage = &mbox->storage->storage;
 	int ret;
 
 	if (ctx->mbox->mbox_readonly) {
-		mail_storage_set_error(&ctx->mbox->storage->storage,
+		mail_storage_set_error(storage, MAIL_ERROR_PERM,
 				       "Read-only mbox");
 		return -1;
 	}
@@ -284,8 +279,8 @@
 				/* FIXME: we shouldn't fail here. it's just
 				   a locking issue that should be possible to
 				   fix.. */
-				mail_storage_set_error(
-					&ctx->mbox->storage->storage,
+				mail_storage_set_error(storage,
+					MAIL_ERROR_NOTPOSSIBLE,
 					"Can't copy mails inside same mailbox");
 				return -1;
 			}
--- a/src/lib-storage/index/mbox/mbox-storage.c	Sun May 13 19:53:41 2007 +0300
+++ b/src/lib-storage/index/mbox/mbox-storage.c	Sun May 13 20:10:48 2007 +0300
@@ -84,7 +84,7 @@
 
 	if (ENOSPACE(errno)) {
 		mail_storage_set_error(&mbox->storage->storage,
-				       "Not enough disk space");
+			MAIL_ERROR_NOSPACE, MAIL_ERRSTR_NO_SPACE);
 	} else {
 		mail_storage_set_critical(&mbox->storage->storage,
 					  "%s failed with mbox file %s: %m",
@@ -648,7 +648,7 @@
 		  struct istream *input, enum mailbox_open_flags flags)
 {
 	struct mbox_storage *storage = (struct mbox_storage *)_storage;
-	const char *path, *error;
+	const char *path;
 	struct stat st;
 
 	if (input != NULL)
@@ -665,8 +665,9 @@
 				     MAILBOX_LIST_PATH_TYPE_MAILBOX);
 	if (stat(path, &st) == 0) {
 		if (S_ISDIR(st.st_mode)) {
-			mail_storage_set_error(_storage,
-				"Mailbox isn't selectable: %s", name);
+			mail_storage_set_error(_storage, MAIL_ERROR_NOTPOSSIBLE,
+				t_strdup_printf("Mailbox isn't selectable: %s",
+						name));
 			return NULL;
 		}
 
@@ -674,11 +675,9 @@
 	}
 
 	if (ENOTFOUND(errno)) {
-		mail_storage_set_error(_storage,
-			MAILBOX_LIST_ERR_MAILBOX_NOT_FOUND, name);
-	} else if (mail_storage_errno2str(&error))
-		mail_storage_set_error(_storage, "%s", error);
-	else {
+		mail_storage_set_error(_storage, MAIL_ERROR_NOTFOUND,
+			T_MAIL_ERR_MAILBOX_NOT_FOUND(name));
+	} else if (!mail_storage_set_error_from_errno(_storage)) {
 		mail_storage_set_critical(_storage, "stat(%s) failed: %m",
 					  path);
 	}
@@ -689,7 +688,7 @@
 static int mbox_mailbox_create(struct mail_storage *_storage, const char *name,
 			       bool directory)
 {
-	const char *path, *p, *error;
+	const char *path, *p;
 	struct stat st;
 	int fd;
 
@@ -698,17 +697,16 @@
 	path = mailbox_list_get_path(_storage->list, name,
 				     MAILBOX_LIST_PATH_TYPE_MAILBOX);
 	if (stat(path, &st) == 0) {
-		mail_storage_set_error(_storage, "Mailbox already exists");
+		mail_storage_set_error(_storage, MAIL_ERROR_NOTPOSSIBLE,
+				       "Mailbox already exists");
 		return -1;
 	}
 
 	if (errno != ENOENT) {
 		if (errno == ENOTDIR) {
-			mail_storage_set_error(_storage,
+			mail_storage_set_error(_storage, MAIL_ERROR_NOTPOSSIBLE,
 				"Mailbox doesn't allow inferior mailboxes");
-		} else if (mail_storage_errno2str(&error))
-			mail_storage_set_error(_storage, "%s", error);
-		else {
+		} else if (!mail_storage_set_error_from_errno(_storage)) {
 			mail_storage_set_critical(_storage,
 				"stat() failed for mbox file %s: %m", path);
 		}
@@ -720,9 +718,7 @@
 	if (p != NULL) {
 		p = t_strdup_until(path, p);
 		if (mkdir_parents(p, CREATE_MODE) < 0) {
-			if (mail_storage_errno2str(&error))
-				mail_storage_set_error(_storage, "%s", error);
-			else {
+			if (!mail_storage_set_error_from_errno(_storage)) {
 				mail_storage_set_critical(_storage,
 					"mkdir_parents(%s) failed: %m", p);
 			}
@@ -744,10 +740,9 @@
 
 	if (errno == EEXIST) {
 		/* mailbox was just created between stat() and open() call.. */
-		mail_storage_set_error(_storage, "Mailbox already exists");
-	} else if (mail_storage_errno2str(&error))
-		mail_storage_set_error(_storage, "%s", error);
-	else {
+		mail_storage_set_error(_storage, MAIL_ERROR_NOTPOSSIBLE,
+				       "Mailbox already exists");
+	} else if (!mail_storage_set_error_from_errno(_storage)) {
 		mail_storage_set_critical(_storage,
 			"Can't create mailbox %s: %m", name);
 	}
@@ -883,17 +878,15 @@
 {
 	struct mbox_storage *storage = MBOX_LIST_CONTEXT(list);
 	struct stat st;
-	const char *path, *index_dir, *error;
+	const char *path, *index_dir;
 
 	path = mailbox_list_get_path(list, name,
 				     MAILBOX_LIST_PATH_TYPE_MAILBOX);
 	if (lstat(path, &st) < 0) {
 		if (ENOTFOUND(errno)) {
-			mailbox_list_set_error(list, t_strdup_printf(
-				MAILBOX_LIST_ERR_MAILBOX_NOT_FOUND, name));
-		} else if (mail_storage_errno2str(&error))
-			mailbox_list_set_error(list, error);
-		else {
+			mailbox_list_set_error(list, MAIL_ERROR_NOTFOUND,
+				T_MAIL_ERR_MAILBOX_NOT_FOUND(name));
+		} else if (!mailbox_list_set_error_from_errno(list)) {
 			mailbox_list_set_critical(list,
 				"lstat() failed for %s: %m", path);
 		}
@@ -911,9 +904,7 @@
 
 		if (*index_dir != '\0' && rmdir(index_dir) < 0 &&
 		    !ENOTFOUND(errno) && errno != ENOTEMPTY) {
-			if (mail_storage_errno2str(&error))
-				mailbox_list_set_error(list, error);
-			else {
+			if (!mailbox_list_set_error_from_errno(list)) {
 				mailbox_list_set_critical(list,
 					"rmdir() failed for %s: %m", index_dir);
 			}
@@ -924,15 +915,13 @@
 			return 0;
 
 		if (ENOTFOUND(errno)) {
-			mailbox_list_set_error(list, t_strdup_printf(
-				MAILBOX_LIST_ERR_MAILBOX_NOT_FOUND, name));
+			mailbox_list_set_error(list, MAIL_ERROR_NOTFOUND,
+				T_MAIL_ERR_MAILBOX_NOT_FOUND(name));
 		} else if (errno == ENOTEMPTY) {
-			mailbox_list_set_error(list, t_strdup_printf(
-				"Directory %s isn't empty, can't delete it.",
-				name));
-		} else if (mail_storage_errno2str(&error))
-			mailbox_list_set_error(list, error);
-		else {
+			mailbox_list_set_error(list, MAIL_ERROR_NOTPOSSIBLE,
+				t_strdup_printf("Directory %s isn't empty, "
+						"can't delete it.", name));
+		} else if (!mailbox_list_set_error_from_errno(list)) {
 			mailbox_list_set_critical(list,
 				"rmdir() failed for %s: %m", path);
 		}
@@ -946,11 +935,9 @@
 
 	if (unlink(path) < 0) {
 		if (ENOTFOUND(errno)) {
-			mailbox_list_set_error(list, t_strdup_printf(
-				MAILBOX_LIST_ERR_MAILBOX_NOT_FOUND, name));
-		} else if (mail_storage_errno2str(&error))
-			mailbox_list_set_error(list, error);
-		else {
+			mailbox_list_set_error(list, MAIL_ERROR_NOTFOUND,
+				T_MAIL_ERR_MAILBOX_NOT_FOUND(name));
+		} else if (!mailbox_list_set_error_from_errno(list)) {
 			mailbox_list_set_critical(list,
 				"unlink() failed for %s: %m", path);
 		}
--- a/src/lib-storage/index/mbox/mbox-sync.c	Sun May 13 19:53:41 2007 +0300
+++ b/src/lib-storage/index/mbox/mbox-sync.c	Sun May 13 20:10:48 2007 +0300
@@ -946,6 +946,7 @@
 	if (seq == 0) {
 		if (istream_raw_mbox_seek(mbox->mbox_stream, 0) < 0) {
 			mail_storage_set_error(&mbox->storage->storage,
+				MAIL_ERROR_NOTPOSSIBLE,
 				"Mailbox isn't a valid mbox file");
 			return -1;
 		}
--- a/src/lib-storage/list/mailbox-list-fs-iter.c	Sun May 13 19:53:41 2007 +0300
+++ b/src/lib-storage/list/mailbox-list-fs-iter.c	Sun May 13 20:10:48 2007 +0300
@@ -68,7 +68,8 @@
 			/* subfolder, ignore */
 			return 0;
 		}
-		mailbox_list_set_error(list, "Access denied");
+		mailbox_list_set_error(list, MAIL_ERROR_PERM,
+				       MAIL_ERRSTR_NO_PERMISSION);
 		return -1;
 	}
 
@@ -92,7 +93,8 @@
 
 	/* check that we're not trying to do any "../../" lists */
 	if (!mailbox_list_is_valid_mask(_list, mask)) {
-		mailbox_list_set_error(_list, "Invalid mask");
+		mailbox_list_set_error(_list, MAIL_ERROR_PARAMS,
+				       "Invalid mask");
 		ctx->ctx.failed = TRUE;
 		return &ctx->ctx;
 	}
--- a/src/lib-storage/list/mailbox-list-fs.c	Sun May 13 19:53:41 2007 +0300
+++ b/src/lib-storage/list/mailbox-list-fs.c	Sun May 13 20:10:48 2007 +0300
@@ -272,19 +272,6 @@
 	return mailbox_list_delete_index_control(list, name);
 }
 
-static bool fs_handle_errors(struct mailbox_list *list)
-{
-	if (ENOACCESS(errno))
-		mailbox_list_set_error(list, MAILBOX_LIST_ERR_NO_PERMISSION);
-	else if (ENOSPACE(errno))
-		mailbox_list_set_error(list, "Not enough disk space");
-	else if (ENOTFOUND(errno))
-		mailbox_list_set_error(list, "Directory structure is broken");
-	else
-		return FALSE;
-	return TRUE;
-}
-
 static int fs_list_rename_mailbox(struct mailbox_list *list,
 				  const char *oldname, const char *newname)
 {
@@ -301,7 +288,7 @@
 	if (p != NULL) {
 		p = t_strdup_until(newpath, p);
 		if (mkdir_parents(p, CREATE_MODE) < 0) {
-			if (fs_handle_errors(list))
+			if (mailbox_list_set_error_from_errno(list))
 				return -1;
 
 			mailbox_list_set_critical(list,
@@ -315,10 +302,11 @@
 	   possibility that someone actually tries to rename two mailboxes
 	   to same new one */
 	if (lstat(newpath, &st) == 0) {
-		mailbox_list_set_error(list, "Target mailbox already exists");
+		mailbox_list_set_error(list, MAIL_ERROR_NOTPOSSIBLE,
+				       "Target mailbox already exists");
 		return -1;
 	} else if (errno == ENOTDIR) {
-		mailbox_list_set_error(list,
+		mailbox_list_set_error(list, MAIL_ERROR_NOTPOSSIBLE,
 			"Target mailbox doesn't allow inferior mailboxes");
 		return -1;
 	} else if (errno != ENOENT && errno != EACCES) {
@@ -331,9 +319,9 @@
 	   the next time it's needed. */
 	if (rename(oldpath, newpath) < 0) {
 		if (ENOTFOUND(errno)) {
-			mailbox_list_set_error(list, t_strdup_printf(
-				MAILBOX_LIST_ERR_MAILBOX_NOT_FOUND, oldname));
-		} else if (!fs_handle_errors(list)) {
+			mailbox_list_set_error(list, MAIL_ERROR_NOTFOUND,
+				T_MAIL_ERR_MAILBOX_NOT_FOUND(oldname));
+		} else if (!mailbox_list_set_error_from_errno(list)) {
 			mailbox_list_set_critical(list,
 				"rename(%s, %s) failed: %m", oldpath, newpath);
 		}
--- a/src/lib-storage/list/mailbox-list-maildir.c	Sun May 13 19:53:41 2007 +0300
+++ b/src/lib-storage/list/mailbox-list-maildir.c	Sun May 13 20:10:48 2007 +0300
@@ -383,8 +383,8 @@
 		if (ret < 0)
 			return -1;
 		if (!found && ret == 0) {
-			mailbox_list_set_error(list, t_strdup_printf(
-				MAILBOX_LIST_ERR_MAILBOX_NOT_FOUND, oldname));
+			mailbox_list_set_error(list, MAIL_ERROR_NOTFOUND,
+				T_MAIL_ERR_MAILBOX_NOT_FOUND(oldname));
 			return -1;
 		}
 
@@ -392,7 +392,8 @@
 	}
 
 	if (EDESTDIREXISTS(errno)) {
-		mailbox_list_set_error(list, "Target mailbox already exists");
+		mailbox_list_set_error(list, MAIL_ERROR_NOTPOSSIBLE,
+				       "Target mailbox already exists");
 	} else {
 		mailbox_list_set_critical(list, "rename(%s, %s) failed: %m",
 					  oldpath, newpath);
--- a/src/lib-storage/list/subscription-file.c	Sun May 13 19:53:41 2007 +0300
+++ b/src/lib-storage/list/subscription-file.c	Sun May 13 20:10:48 2007 +0300
@@ -30,9 +30,10 @@
 {
 	i_assert(function != NULL);
 
-	if (errno == EACCES)
-		mailbox_list_set_error(list, "Permission denied");
-	else {
+	if (errno == EACCES) {
+		mailbox_list_set_error(list, MAIL_ERROR_PERM,
+				       MAIL_ERRSTR_NO_PERMISSION);
+	} else {
 		mailbox_list_set_critical(list,
 			"%s failed with subscription file %s: %m",
 			function, path);
@@ -97,7 +98,7 @@
 	fd_out = file_dotlock_open(&dotlock_set, path, 0, &dotlock);
 	if (fd_out == -1) {
 		if (errno == EAGAIN) {
-			mailbox_list_set_error(list,
+			mailbox_list_set_error(list, MAIL_ERROR_TEMP,
 				"Timeout waiting for subscription file lock");
 		} else {
 			subsfile_set_syscall_error(list,
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib-storage/mail-error.c	Sun May 13 20:10:48 2007 +0300
@@ -0,0 +1,23 @@
+/* Copyright (C) 2007 Timo Sirainen */
+
+#include "lib.h"
+#include "mail-error.h"
+
+bool mail_error_from_errno(enum mail_error *error_r,
+			   const char **error_string_r)
+{
+	if (ENOACCESS(errno)) {
+		*error_r = MAIL_ERROR_PERM;
+		*error_string_r = MAIL_ERRSTR_NO_PERMISSION;
+	} else if (ENOSPACE(errno)) {
+		*error_r = MAIL_ERROR_NOSPACE;
+		*error_string_r = MAIL_ERRSTR_NO_SPACE;
+	} else if (ENOTFOUND(errno)) {
+		*error_r = MAIL_ERROR_NOTFOUND;
+		*error_string_r = errno != ELOOP ? "Not found" :
+			"Directory structure is broken";
+	} else {
+		return FALSE;
+	}
+	return TRUE;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib-storage/mail-error.h	Sun May 13 20:10:48 2007 +0300
@@ -0,0 +1,38 @@
+#ifndef __MAIL_ERROR_H
+#define __MAIL_ERROR_H
+
+/* Some error strings that should be used everywhere to avoid
+   permissions checks from revealing mailbox's existence */
+#define MAIL_ERRSTR_MAILBOX_NOT_FOUND "Mailbox doesn't exist: %s"
+#define MAIL_ERRSTR_NO_PERMISSION "Permission denied"
+
+/* And just for making error strings consistent: */
+#define MAIL_ERRSTR_NO_SPACE "Not enough disk space"
+#define MAIL_ERRSTR_LOCK_TIMEOUT "Timeout while waiting for lock"
+
+#define T_MAIL_ERR_MAILBOX_NOT_FOUND(name) \
+	t_strdup_printf(MAIL_ERRSTR_MAILBOX_NOT_FOUND, name)
+
+enum mail_error {
+	MAIL_ERROR_NONE = 0,
+
+	/* Temporary internal error */
+	MAIL_ERROR_TEMP,
+	/* It's not possible to do the wanted operation */
+	MAIL_ERROR_NOTPOSSIBLE,
+	/* Invalid parameters (eg. mailbox name not valid) */
+	MAIL_ERROR_PARAMS,
+	/* No permission to do the request */
+	MAIL_ERROR_PERM,
+	/* Out of disk space or quota */
+	MAIL_ERROR_NOSPACE,
+	/* Item (eg. mailbox) doesn't exist or it's not visible to us */
+	MAIL_ERROR_NOTFOUND
+};
+
+/* Convert errno to mail_error and an error string. Returns TRUE if successful,
+   FALSE if we couldn't handle the errno. */
+bool mail_error_from_errno(enum mail_error *error_r,
+			   const char **error_string_r);
+
+#endif
--- a/src/lib-storage/mail-storage-private.h	Sun May 13 19:53:41 2007 +0300
+++ b/src/lib-storage/mail-storage-private.h	Sun May 13 20:10:48 2007 +0300
@@ -52,7 +52,9 @@
 /* private: */
 	pool_t pool;
 
-	char *error;
+	char *error_string;
+	enum mail_error error;
+
 	struct mail_namespace *ns;
 	struct mailbox_list *list;
 
@@ -65,10 +67,6 @@
 
 	/* Module-specific contexts. See mail_storage_module_id. */
 	ARRAY_DEFINE(module_contexts, union mail_storage_module_context *);
-
-	/* Internal temporary error, as opposed to visible user errors like
-	   "permission denied" or "out of disk space" */
-	unsigned int temporary_error:1;
 };
 
 struct mailbox_vfuncs {
@@ -289,15 +287,13 @@
    but user sees only "internal error" message. */
 void mail_storage_clear_error(struct mail_storage *storage);
 void mail_storage_set_error(struct mail_storage *storage,
-			    const char *fmt, ...) __attr_format__(2, 3);
+			    enum mail_error error, const char *string);
 void mail_storage_set_critical(struct mail_storage *storage,
 			       const char *fmt, ...) __attr_format__(2, 3);
 void mail_storage_set_internal_error(struct mail_storage *storage);
-
-const char *mail_storage_class_get_last_error(struct mail_storage *storage);
+bool mail_storage_set_error_from_errno(struct mail_storage *storage);
 
 enum mailbox_list_flags
 mail_storage_get_list_flags(enum mail_storage_flags storage_flags);
-bool mail_storage_errno2str(const char **error_r);
 
 #endif
--- a/src/lib-storage/mail-storage.c	Sun May 13 19:53:41 2007 +0300
+++ b/src/lib-storage/mail-storage.c	Sun May 13 20:10:48 2007 +0300
@@ -225,7 +225,7 @@
 		storage->v.destroy(storage);
 
 	mailbox_list_deinit(storage->list);
-	i_free(storage->error);
+	i_free(storage->error_string);
 	pool_unref(storage->pool);
 
 	index_storage_destroy_unrefed();
@@ -233,23 +233,17 @@
 
 void mail_storage_clear_error(struct mail_storage *storage)
 {
-	i_free(storage->error);
-	storage->error = NULL;
+	i_free_and_null(storage->error_string);
 
-	storage->temporary_error = FALSE;
+	storage->error = MAIL_ERROR_NONE;
 }
 
-void mail_storage_set_error(struct mail_storage *storage, const char *fmt, ...)
+void mail_storage_set_error(struct mail_storage *storage,
+			    enum mail_error error, const char *string)
 {
-	va_list va;
-
-	mail_storage_clear_error(storage);
-
-	if (fmt != NULL) {
-		va_start(va, fmt);
-		storage->error = i_strdup_vprintf(fmt, va);
-		va_end(va);
-	}
+	i_free(storage->error_string);
+	storage->error_string = i_strdup(string);
+	storage->error = error;
 }
 
 void mail_storage_set_internal_error(struct mail_storage *storage)
@@ -259,11 +253,11 @@
 
 	tm = localtime(&ioloop_time);
 
-	i_free(storage->error);
-	storage->error =
+	i_free(storage->error_string);
+	storage->error_string =
 		strftime(str, sizeof(str), CRITICAL_MSG_STAMP, tm) > 0 ?
 		i_strdup(str) : i_strdup(CRITICAL_MSG);
-	storage->temporary_error = TRUE;
+	storage->error = MAIL_ERROR_TEMP;
 }
 
 void mail_storage_set_critical(struct mail_storage *storage,
@@ -313,7 +307,8 @@
 	mail_storage_clear_error(storage);
 
 	if (!mailbox_list_is_valid_create_name(storage->list, name)) {
-		mail_storage_set_error(storage, "Invalid mailbox name");
+		mail_storage_set_error(storage, MAIL_ERROR_PARAMS,
+				       "Invalid mailbox name");
 		return -1;
 	}
 
@@ -321,14 +316,15 @@
 }
 
 const char *mail_storage_get_last_error(struct mail_storage *storage,
-					bool *temporary_error_r)
+					enum mail_error *error_r)
 {
-	*temporary_error_r = storage->temporary_error;
+	*error_r = storage->error;
 
 	/* We get here only in error situations, so we have to return some
 	   error. If storage->error is NULL, it means we forgot to set it at
 	   some point.. */
-	return storage->error != NULL ? storage->error : "Unknown error";
+	return storage->error_string != NULL ? storage->error_string :
+		"Unknown internal error";
 }
 
 const char *mail_storage_get_mailbox_path(struct mail_storage *storage,
@@ -377,16 +373,15 @@
 	return list_flags;
 }
 
-bool mail_storage_errno2str(const char **error_r)
+bool mail_storage_set_error_from_errno(struct mail_storage *storage)
 {
-	if (ENOACCESS(errno))
-		*error_r = MAILBOX_LIST_ERR_NO_PERMISSION;
-	else if (ENOSPACE(errno))
-		*error_r = "Not enough disk space";
-	else if (ENOTFOUND(errno))
-		*error_r = "Directory structure is broken";
-	else
+	const char *error_string;
+	enum mail_error error;
+
+	if (!mail_error_from_errno(&error, &error_string))
 		return FALSE;
+
+	mail_storage_set_error(storage, error, error_string);
 	return TRUE;
 }
 
@@ -399,7 +394,8 @@
 	mail_storage_clear_error(storage);
 
 	if (!mailbox_list_is_valid_existing_name(storage->list, name)) {
-		mail_storage_set_error(storage, "Invalid mailbox name");
+		mail_storage_set_error(storage, MAIL_ERROR_PARAMS,
+				       "Invalid mailbox name");
 		return NULL;
 	}
 
--- a/src/lib-storage/mail-storage.h	Sun May 13 19:53:41 2007 +0300
+++ b/src/lib-storage/mail-storage.h	Sun May 13 20:10:48 2007 +0300
@@ -4,6 +4,7 @@
 struct message_size;
 
 #include "mail-types.h"
+#include "mail-error.h"
 #include "mailbox-list.h"
 
 /* If some operation is taking long, call notify_ok every n seconds. */
@@ -228,7 +229,7 @@
 
 /* Returns the error message of last occurred error. */
 const char *mail_storage_get_last_error(struct mail_storage *storage,
-					bool *temporary_error_r);
+					enum mail_error *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,
--- a/src/lib-storage/mailbox-list-private.h	Sun May 13 19:53:41 2007 +0300
+++ b/src/lib-storage/mailbox-list-private.h	Sun May 13 20:10:48 2007 +0300
@@ -1,11 +1,6 @@
 #ifndef __MAILBOX_LIST_PRIVATE_H
 #define __MAILBOX_LIST_PRIVATE_H
 
-/* Some error strings that should be used everywhere to avoid
-   permissions checks from revealing mailbox's existence */
-#define MAILBOX_LIST_ERR_MAILBOX_NOT_FOUND "Mailbox doesn't exist: %s"
-#define MAILBOX_LIST_ERR_NO_PERMISSION "Permission denied"
-
 #include "mail-namespace.h"
 #include "mailbox-list.h"
 
@@ -78,7 +73,8 @@
 	uid_t cached_uid;
 	gid_t cached_gid;
 
-	char *error;
+	char *error_string;
+	enum mail_error error;
 	bool temporary_error;
 
 	ARRAY_DEFINE(module_contexts, union mailbox_list_module_context *);
@@ -103,9 +99,11 @@
 enum mailbox_list_file_type mailbox_list_get_file_type(const struct dirent *d);
 
 void mailbox_list_clear_error(struct mailbox_list *list);
-void mailbox_list_set_error(struct mailbox_list *list, const char *error);
+void mailbox_list_set_error(struct mailbox_list *list,
+			    enum mail_error error, const char *string);
 void mailbox_list_set_critical(struct mailbox_list *list, const char *fmt, ...)
 	__attr_format__(2, 3);
 void mailbox_list_set_internal_error(struct mailbox_list *list);
+bool mailbox_list_set_error_from_errno(struct mailbox_list *list);
 
 #endif
--- a/src/lib-storage/mailbox-list.c	Sun May 13 19:53:41 2007 +0300
+++ b/src/lib-storage/mailbox-list.c	Sun May 13 20:10:48 2007 +0300
@@ -154,7 +154,7 @@
 
 void mailbox_list_deinit(struct mailbox_list *list)
 {
-	i_free_and_null(list->error);
+	i_free_and_null(list->error_string);
 
 	list->v.deinit(list);
 }
@@ -309,11 +309,13 @@
 int mailbox_list_delete_mailbox(struct mailbox_list *list, const char *name)
 {
 	if (!mailbox_list_is_valid_existing_name(list, name)) {
-		mailbox_list_set_error(list, "Invalid mailbox name");
+		mailbox_list_set_error(list, MAIL_ERROR_PARAMS,
+				       "Invalid mailbox name");
 		return -1;
 	}
 	if (strcmp(name, "INBOX") == 0) {
-		mailbox_list_set_error(list, "INBOX can't be deleted.");
+		mailbox_list_set_error(list, MAIL_ERROR_NOTPOSSIBLE,
+				       "INBOX can't be deleted.");
 		return -1;
 	}
 	return list->v.delete_mailbox(list, name);
@@ -324,7 +326,8 @@
 {
 	if (!mailbox_list_is_valid_existing_name(list, oldname) ||
 	    !mailbox_list_is_valid_create_name(list, newname)) {
-		mailbox_list_set_error(list, "Invalid mailbox name");
+		mailbox_list_set_error(list, MAIL_ERROR_PARAMS,
+				       "Invalid mailbox name");
 		return -1;
 	}
 
@@ -415,26 +418,28 @@
 }
 
 const char *mailbox_list_get_last_error(struct mailbox_list *list,
-					bool *temporary_error_r)
+					enum mail_error *error_r)
 {
-	*temporary_error_r = list->temporary_error;
+	*error_r = list->error;
 
-	return list->error;
+	return list->error_string != NULL ? list->error_string :
+		"Unknown internal list error";
 }
 
 void mailbox_list_clear_error(struct mailbox_list *list)
 {
-	i_free_and_null(list->error);
+	i_free_and_null(list->error_string);
 
-	list->temporary_error = FALSE;
+	list->error = MAIL_ERROR_NONE;
 }
 
-void mailbox_list_set_error(struct mailbox_list *list, const char *error)
+void mailbox_list_set_error(struct mailbox_list *list,
+			    enum mail_error error, const char *string)
 {
-	i_free(list->error);
-	list->error = i_strdup(error);
+	i_free(list->error_string);
+	list->error_string = i_strdup(string);
 
-	list->temporary_error = FALSE;
+	list->error = error;
 }
 
 void mailbox_list_set_internal_error(struct mailbox_list *list)
@@ -444,11 +449,11 @@
 
 	tm = localtime(&ioloop_time);
 
-	i_free(list->error);
-	list->error =
+	i_free(list->error_string);
+	list->error_string =
 		strftime(str, sizeof(str), CRITICAL_MSG_STAMP, tm) > 0 ?
 		i_strdup(str) : i_strdup(CRITICAL_MSG);
-	list->temporary_error = TRUE;
+	list->error = MAIL_ERROR_TEMP;
 }
 
 void mailbox_list_set_critical(struct mailbox_list *list, const char *fmt, ...)
@@ -464,3 +469,15 @@
 	   easier to look from log files the actual error message. */
 	mailbox_list_set_internal_error(list);
 }
+
+bool mailbox_list_set_error_from_errno(struct mailbox_list *list)
+{
+	const char *error_string;
+	enum mail_error error;
+
+	if (!mail_error_from_errno(&error, &error_string))
+		return FALSE;
+
+	mailbox_list_set_error(list, error, error_string);
+	return TRUE;
+}
--- a/src/lib-storage/mailbox-list.h	Sun May 13 19:53:41 2007 +0300
+++ b/src/lib-storage/mailbox-list.h	Sun May 13 20:10:48 2007 +0300
@@ -1,6 +1,8 @@
 #ifndef __MAILBOX_LIST_H
 #define __MAILBOX_LIST_H
 
+#include "mail-error.h"
+
 struct mail_namespace;
 struct mailbox_list;
 struct mailbox_list_iterate_context;
@@ -176,6 +178,6 @@
 
 /* Returns the error message of last occurred error. */
 const char *mailbox_list_get_last_error(struct mailbox_list *list,
-					bool *temporary_error_r);
+					enum mail_error *error_r);
 
 #endif
--- a/src/plugins/acl/acl-mailbox-list.c	Sun May 13 19:53:41 2007 +0300
+++ b/src/plugins/acl/acl-mailbox-list.c	Sun May 13 20:10:48 2007 +0300
@@ -286,11 +286,11 @@
 		if (ret < 0)
 			return -1;
 		if (can_see) {
-			mailbox_list_set_error(list,
-					       MAILBOX_LIST_ERR_NO_PERMISSION);
+			mailbox_list_set_error(list, MAIL_ERROR_PERM,
+					       MAIL_ERRSTR_NO_PERMISSION);
 		} else {
-			mailbox_list_set_error(list, t_strdup_printf(
-				MAILBOX_LIST_ERR_MAILBOX_NOT_FOUND, name));
+			mailbox_list_set_error(list, MAIL_ERROR_NOTFOUND,
+				T_MAIL_ERR_MAILBOX_NOT_FOUND(name));
 		}
 		return -1;
 	}
@@ -313,11 +313,11 @@
 		if (ret < 0)
 			return -1;
 		if (can_see) {
-			mailbox_list_set_error(list,
-					       MAILBOX_LIST_ERR_NO_PERMISSION);
+			mailbox_list_set_error(list, MAIL_ERROR_PERM,
+					       MAIL_ERRSTR_NO_PERMISSION);
 		} else {
-			mailbox_list_set_error(list, t_strdup_printf(
-				MAILBOX_LIST_ERR_MAILBOX_NOT_FOUND, oldname));
+			mailbox_list_set_error(list, MAIL_ERROR_NOTFOUND,
+				T_MAIL_ERR_MAILBOX_NOT_FOUND(oldname));
 		}
 		return 0;
 	}
@@ -334,8 +334,8 @@
 			/* Note that if the mailbox didn't have LOOKUP
 			   permission, this not reveals to user the mailbox's
 			   existence. Can't help it. */
-			mailbox_list_set_error(list,
-					       MAILBOX_LIST_ERR_NO_PERMISSION);
+			mailbox_list_set_error(list, MAIL_ERROR_PERM,
+					       MAIL_ERRSTR_NO_PERMISSION);
 		}
 		return -1;
 	}
--- a/src/plugins/acl/acl-mailbox.c	Sun May 13 19:53:41 2007 +0300
+++ b/src/plugins/acl/acl-mailbox.c	Sun May 13 20:10:48 2007 +0300
@@ -48,7 +48,8 @@
 		return -1;
 	}
 
-	mail_storage_set_error(box->storage, MAILBOX_LIST_ERR_NO_PERMISSION);
+	mail_storage_set_error(box->storage, MAIL_ERROR_PERM,
+			       MAIL_ERRSTR_NO_PERMISSION);
 	return 0;
 }
 
--- a/src/plugins/acl/acl-storage.c	Sun May 13 19:53:41 2007 +0300
+++ b/src/plugins/acl/acl-storage.c	Sun May 13 20:10:48 2007 +0300
@@ -110,11 +110,11 @@
 		if (ret < 0)
 			return NULL;
 		if (can_see) {
-			mail_storage_set_error(storage,
-					       MAILBOX_LIST_ERR_NO_PERMISSION);
+			mail_storage_set_error(storage, MAIL_ERROR_PERM,
+					       MAIL_ERRSTR_NO_PERMISSION);
 		} else {
-			mail_storage_set_error(storage,
-				MAILBOX_LIST_ERR_MAILBOX_NOT_FOUND, name);
+			mail_storage_set_error(storage, MAIL_ERROR_NOTFOUND,
+				T_MAIL_ERR_MAILBOX_NOT_FOUND(name));
 		}
 		return NULL;
 	}
@@ -145,8 +145,8 @@
 			/* Note that if the mailbox didn't have LOOKUP
 			   permission, this not reveals to user the mailbox's
 			   existence. Can't help it. */
-			mail_storage_set_error(storage,
-					       MAILBOX_LIST_ERR_NO_PERMISSION);
+			mail_storage_set_error(storage, MAIL_ERROR_PERM,
+					       MAIL_ERRSTR_NO_PERMISSION);
 		}
 		return -1;
 	}
--- a/src/plugins/convert/convert-storage.c	Sun May 13 19:53:41 2007 +0300
+++ b/src/plugins/convert/convert-storage.c	Sun May 13 20:10:48 2007 +0300
@@ -101,9 +101,9 @@
 
 static const char *storage_error(struct mail_storage *storage)
 {
-	bool temp;
+	enum mail_error error;
 
-	return mail_storage_get_last_error(storage, &temp);
+	return mail_storage_get_last_error(storage, &error);
 }
 
 static const char *
--- a/src/plugins/lazy-expunge/lazy-expunge-plugin.c	Sun May 13 19:53:41 2007 +0300
+++ b/src/plugins/lazy-expunge/lazy-expunge-plugin.c	Sun May 13 20:10:48 2007 +0300
@@ -69,7 +69,7 @@
 mailbox_open_or_create(struct mail_storage *storage, const char *name)
 {
 	struct mailbox *box;
-	bool temp;
+	enum mail_error error;
 
 	box = mailbox_open(storage, name, NULL, MAILBOX_OPEN_FAST |
 			   MAILBOX_OPEN_KEEP_RECENT |
@@ -77,11 +77,11 @@
 	if (box != NULL)
 		return box;
 
-	(void)mail_storage_get_last_error(storage, &temp);
-	if (temp)
+	(void)mail_storage_get_last_error(storage, &error);
+	if (error != MAIL_ERROR_NOTFOUND)
 		return NULL;
 
-	/* probably the mailbox just doesn't exist. try creating it. */
+	/* try creating it. */
 	if (mail_storage_mailbox_create(storage, name, FALSE) < 0)
 		return NULL;
 
@@ -428,14 +428,16 @@
 
 	/* first do the normal sanity checks */
 	if (strcmp(name, "INBOX") == 0) {
-		mailbox_list_set_error(list, "INBOX can't be deleted.");
+		mailbox_list_set_error(list, MAIL_ERROR_NOTPOSSIBLE,
+				       "INBOX can't be deleted.");
 		return -1;
 	}
 
 	if (mailbox_list_get_mailbox_name_status(list, name, &status) < 0)
 		return -1;
 	if (status == MAILBOX_NAME_INVALID) {
-		mailbox_list_set_error(list, "Invalid mailbox name");
+		mailbox_list_set_error(list, MAIL_ERROR_PARAMS,
+				       "Invalid mailbox name");
 		return -1;
 	}
 
@@ -450,8 +452,8 @@
 	if ((ret = mailbox_move(list, name, dest_list, &destname)) < 0)
 		return -1;
 	if (ret == 0) {
-		mailbox_list_set_error(list, t_strdup_printf(
-			MAILBOX_LIST_ERR_MAILBOX_NOT_FOUND, name));
+		mailbox_list_set_error(list, MAIL_ERROR_NOTFOUND,
+			T_MAIL_ERR_MAILBOX_NOT_FOUND(name));
 		return -1;
 	}
 
--- a/src/plugins/quota/quota-storage.c	Sun May 13 19:53:41 2007 +0300
+++ b/src/plugins/quota/quota-storage.c	Sun May 13 20:10:48 2007 +0300
@@ -151,11 +151,12 @@
 	if (ret > 0)
 		return 0;
 	else if (ret == 0) {
-		mail_storage_set_error(t->box->storage, "Quota exceeded");
+		mail_storage_set_error(t->box->storage, MAIL_ERROR_NOSPACE,
+				       "Quota exceeded");
 		return -1;
 	} else {
-		mail_storage_set_error(t->box->storage,
-				       "Internal quota calculation error");
+		mail_storage_set_critical(t->box->storage,
+					  "Internal quota calculation error");
 		return -1;
 	}
 }
@@ -215,10 +216,10 @@
 		ret = quota_test_alloc(qt, st->st_size, &too_large);
 		if (ret == 0) {
 			mail_storage_set_error(t->box->storage,
-					       "Quota exceeded");
+				MAIL_ERROR_NOSPACE, "Quota exceeded");
 			return -1;
 		} else if (ret < 0) {
-			mail_storage_set_error(t->box->storage,
+			mail_storage_set_critical(t->box->storage,
 				"Internal quota calculation error");
 			return -1;
 		}
--- a/src/plugins/quota/quota.c	Sun May 13 19:53:41 2007 +0300
+++ b/src/plugins/quota/quota.c	Sun May 13 20:10:48 2007 +0300
@@ -418,7 +418,7 @@
 	/* the quota information comes from userdb (or even config file),
 	   so there's really no way to support this until some major changes
 	   are done */
-	*error_r = MAILBOX_LIST_ERR_NO_PERMISSION;
+	*error_r = MAIL_ERRSTR_NO_PERMISSION;
 	return -1;
 }
 
--- a/src/pop3/client.c	Sun May 13 19:53:41 2007 +0300
+++ b/src/pop3/client.c	Sun May 13 20:10:48 2007 +0300
@@ -130,7 +130,7 @@
 	struct client *client;
         enum mailbox_open_flags flags;
 	const char *errmsg;
-	bool temporary_error;
+	enum mail_error error;
 
 	/* always use nonblocking I/O */
 	net_set_nonblock(fd_in, TRUE);
@@ -169,7 +169,7 @@
 	if (client->mailbox == NULL) {
 		errmsg = t_strdup_printf("Couldn't open INBOX: %s",
 				mail_storage_get_last_error(storage,
-							    &temporary_error));
+							    &error));
 		i_error("%s", errmsg);
 		client_send_line(client, "-ERR [IN-USE] %s", errmsg);
 		client_destroy(client, "Couldn't open INBOX");
@@ -178,7 +178,7 @@
 
 	if (!init_mailbox(client)) {
 		i_error("Couldn't init INBOX: %s",
-			mail_storage_get_last_error(storage, &temporary_error));
+			mail_storage_get_last_error(storage, &error));
 		client_destroy(client, "Mailbox init failed");
 		return NULL;
 	}
@@ -331,8 +331,7 @@
 
 void client_send_storage_error(struct client *client)
 {
-	const char *error;
-	bool temporary_error;
+	enum mail_error error;
 
 	if (mailbox_is_inconsistent(client->mailbox)) {
 		client_send_line(client, "-ERR Mailbox is in inconsistent "
@@ -341,10 +340,9 @@
 		return;
 	}
 
-	error = mail_storage_get_last_error(client->inbox_ns->storage,
-					    &temporary_error);
-	client_send_line(client, "-ERR %s", error != NULL ? error :
-			 "BUG: Unknown error");
+	client_send_line(client, "-ERR %s",
+			 mail_storage_get_last_error(client->inbox_ns->storage,
+						     &error));
 }
 
 static void client_input(struct client *client)