changeset 8411:abd0ef855a33 HEAD

Implemented imap-response-codes draft.
author Timo Sirainen <tss@iki.fi>
date Sat, 15 Nov 2008 20:59:54 +0200
parents 3c0d14ec17a5
children 6e9100795d89
files src/imap-login/client-authenticate.c src/imap/client.c src/imap/cmd-copy.c src/imap/cmd-fetch.c src/imap/cmd-search.c src/imap/cmd-status.c src/imap/commands-util.c src/lib-storage/index/cydir/cydir-storage.c src/lib-storage/index/dbox/dbox-storage.c src/lib-storage/index/index-search.c src/lib-storage/index/maildir/maildir-storage.c src/lib-storage/index/mbox/mbox-storage.c src/lib-storage/list/mailbox-list-fs.c src/lib-storage/list/mailbox-list-maildir.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.c
diffstat 19 files changed, 112 insertions(+), 35 deletions(-) [+]
line wrap: on
line diff
--- a/src/imap-login/client-authenticate.c	Sat Nov 15 20:23:46 2008 +0200
+++ b/src/imap-login/client-authenticate.c	Sat Nov 15 20:59:54 2008 +0200
@@ -18,6 +18,7 @@
 #include <stdlib.h>
 
 #define IMAP_SERVICE_NAME "imap"
+#define IMAP_AUTH_FAILED_MSG "[AUTHENTICATIONFAILED] "AUTH_FAILED_MSG
 
 const char *client_authenticate_get_capabilities(bool secured)
 {
@@ -178,10 +179,12 @@
 		reply = t_str_new(128);
 		if (reason != NULL)
 			str_printfa(reply, "NO %s", reason);
-		else if (temp || proxy_self)
-			str_append(reply, "NO "AUTH_TEMP_FAILED_MSG);
-		else
-			str_append(reply, "NO "AUTH_FAILED_MSG);
+		else if (temp || proxy_self) {
+			str_append(reply, "NO [UNAVAILABLE] "
+				   AUTH_TEMP_FAILED_MSG);
+		} else {
+			str_append(reply, "NO "IMAP_AUTH_FAILED_MSG);
+		}
 		client_send_tagline(client, str_c(reply));
 	} else {
 		/* normal login/failure */
@@ -227,8 +230,8 @@
 		}
 
 		msg = reply == SASL_SERVER_REPLY_AUTH_FAILED ? "NO " : "BAD ";
-		msg = t_strconcat(msg, data != NULL ? data : AUTH_FAILED_MSG,
-				  NULL);
+		msg = t_strconcat(msg, data != NULL ? data :
+				  IMAP_AUTH_FAILED_MSG, NULL);
 		client_send_tagline(client, msg);
 
 		if (!client->destroyed)
@@ -334,7 +337,8 @@
 			"* BAD [ALERT] Plaintext authentication is disabled, "
 			"but your client sent password in plaintext anyway. "
 			"If anyone was listening, the password was exposed.");
-		client_send_tagline(client, "NO "AUTH_PLAINTEXT_DISABLED_MSG);
+		client_send_tagline(client, "NO [CLIENTBUG] "
+				    AUTH_PLAINTEXT_DISABLED_MSG);
 		return 1;
 	}
 
--- a/src/imap/client.c	Sat Nov 15 20:23:46 2008 +0200
+++ b/src/imap/client.c	Sat Nov 15 20:59:54 2008 +0200
@@ -409,8 +409,8 @@
 	}
 
 	if (broken_client) {
-		client_send_line(cmd->client,
-			"* BAD Command pipelining results in ambiguity.");
+		client_send_line(cmd->client, "* BAD [CLIENTBUG] "
+				 "Command pipelining results in ambiguity.");
 	}
 
 	return TRUE;
--- a/src/imap/cmd-copy.c	Sat Nov 15 20:23:46 2008 +0200
+++ b/src/imap/cmd-copy.c	Sat Nov 15 20:59:54 2008 +0200
@@ -171,8 +171,8 @@
 		return cmd_sync(cmd, sync_flags, imap_flags, msg);
 	else if (ret == 0) {
 		/* some messages were expunged, sync them */
-		return cmd_sync(cmd, 0, 0,
-			"NO Some of the requested messages no longer exist.");
+		return cmd_sync(cmd, 0, 0, "NO [EXPUNGEISSUED] "
+			"Some of the requested messages no longer exist.");
 	} else {
 		client_send_storage_error(cmd, storage);
 		return TRUE;
--- a/src/imap/cmd-fetch.c	Sat Nov 15 20:23:46 2008 +0200
+++ b/src/imap/cmd-fetch.c	Sat Nov 15 20:59:54 2008 +0200
@@ -131,6 +131,11 @@
 	struct client_command_context *cmd = ctx->cmd;
 	static const char *ok_message = "OK Fetch completed.";
 
+	if (ctx->partial_fetch) {
+		ok_message = "OK [EXPUNGEISSUED] "
+			"Some messages were already expunged.";
+	}
+
 	if (imap_fetch_deinit(ctx) < 0)
 		ctx->failed = TRUE;
 
--- a/src/imap/cmd-search.c	Sat Nov 15 20:23:46 2008 +0200
+++ b/src/imap/cmd-search.c	Sat Nov 15 20:59:54 2008 +0200
@@ -366,7 +366,7 @@
 	const struct seq_range *range;
 	unsigned int count;
 	uint32_t id, id_min, id_max;
-	bool tryagain, minmax;
+	bool tryagain, minmax, lost_data;
 
 	if (cmd->cancel) {
 		(void)imap_search_deinit(ctx);
@@ -440,6 +440,7 @@
 		}
 	}
 
+	lost_data = mailbox_search_seen_lost_data(ctx->search_ctx);
 	if (imap_search_deinit(ctx) < 0) {
 		client_send_storage_error(cmd,
 			mailbox_get_storage(cmd->client->mailbox));
@@ -459,7 +460,8 @@
 	if (!cmd->uid || ctx->have_seqsets)
 		sync_flags |= MAILBOX_SYNC_FLAG_NO_EXPUNGES;
 	return cmd_sync(cmd, sync_flags, 0,
-			t_strdup_printf("OK Search completed (%d.%03d secs).",
+			t_strdup_printf("OK %sSearch completed (%d.%03d secs).",
+					lost_data ? "[EXPUNGEISSUED] " : "",
 					(int)end_time.tv_sec,
 					(int)(end_time.tv_usec/1000)));
 }
--- a/src/imap/cmd-status.c	Sat Nov 15 20:23:46 2008 +0200
+++ b/src/imap/cmd-status.c	Sat Nov 15 20:59:54 2008 +0200
@@ -13,6 +13,7 @@
 	enum mailbox_status_items items;
 	struct mail_storage *storage;
 	const char *mailbox, *real_mailbox;
+	bool selected_mailbox;
 
 	/* <mailbox> <status items> */
 	if (!client_read_args(cmd, 2, 0, &args))
@@ -33,13 +34,19 @@
 	if (storage == NULL)
 		return TRUE;
 
+	selected_mailbox = client->mailbox != NULL &&
+		mailbox_equals(client->mailbox, storage, real_mailbox);
 	if (!imap_status_get(client, storage, real_mailbox, items, &status)) {
 		client_send_storage_error(cmd, storage);
 		return TRUE;
 	}
 
 	imap_status_send(client, mailbox, items, &status);
-	client_send_tagline(cmd, "OK Status completed.");
-
+	if (!selected_mailbox)
+		client_send_tagline(cmd, "OK Status completed.");
+	else {
+		client_send_tagline(cmd, "OK [CLIENTBUG] "
+				    "Status on selected mailbox completed.");
+	}
 	return TRUE;
 }
--- a/src/imap/commands-util.c	Sat Nov 15 20:23:46 2008 +0200
+++ b/src/imap/commands-util.c	Sat Nov 15 20:59:54 2008 +0200
@@ -143,6 +143,46 @@
 	}
 }
 
+static const char *
+get_error_string(const char *error_string, enum mail_error error)
+{
+	const char *resp_code = NULL;
+
+	switch (error) {
+	case MAIL_ERROR_NONE:
+		break;
+	case MAIL_ERROR_TEMP:
+		resp_code = "SERVERBUG";
+		break;
+	case MAIL_ERROR_NOTPOSSIBLE:
+	case MAIL_ERROR_PARAMS:
+		resp_code = "CANNOT";
+		break;
+	case MAIL_ERROR_PERM:
+		resp_code = "ACL";
+		break;
+	case MAIL_ERROR_NOSPACE:
+		resp_code = "OVERQUOTA";
+		break;
+	case MAIL_ERROR_NOTFOUND:
+		resp_code = "NONEXISTENT";
+		break;
+	case MAIL_ERROR_EXISTS:
+		resp_code = "ALREADYEXISTS";
+		break;
+	case MAIL_ERROR_EXPUNGED:
+		resp_code = "EXPUNGEISSUED";
+		break;
+	case MAIL_ERROR_INUSE:
+		resp_code = "INUSE";
+		break;
+	}
+	if (resp_code == NULL || *error_string == '[')
+		return t_strconcat("NO ", error_string, NULL);
+	else
+		return t_strdup_printf("NO [%s] %s", resp_code, error_string);
+}
+
 void client_send_list_error(struct client_command_context *cmd,
 			    struct mailbox_list *list)
 {
@@ -150,7 +190,7 @@
 	enum mail_error error;
 
 	error_string = mailbox_list_get_last_error(list, &error);
-	client_send_tagline(cmd, t_strconcat("NO ", error_string, NULL));
+	client_send_tagline(cmd, get_error_string(error_string, error));
 }
 
 void client_send_storage_error(struct client_command_context *cmd,
@@ -168,7 +208,7 @@
 	}
 
 	error_string = mail_storage_get_last_error(storage, &error);
-	client_send_tagline(cmd, t_strconcat("NO ", error_string, NULL));
+	client_send_tagline(cmd, get_error_string(error_string, error));
 }
 
 void client_send_untagged_storage_error(struct client *client,
--- a/src/lib-storage/index/cydir/cydir-storage.c	Sat Nov 15 20:23:46 2008 +0200
+++ b/src/lib-storage/index/cydir/cydir-storage.c	Sat Nov 15 20:59:54 2008 +0200
@@ -224,7 +224,7 @@
 	path = mailbox_list_get_path(_storage->list, name,
 				     MAILBOX_LIST_PATH_TYPE_MAILBOX);
 	if (stat(path, &st) == 0) {
-		mail_storage_set_error(_storage, MAIL_ERROR_NOTPOSSIBLE,
+		mail_storage_set_error(_storage, MAIL_ERROR_EXISTS,
 				       "Mailbox already exists");
 		return -1;
 	}
@@ -293,7 +293,7 @@
 	}
 
 	if (!unlinked_something) {
-		mailbox_list_set_error(list, MAIL_ERROR_NOTPOSSIBLE,
+		mailbox_list_set_error(list, MAIL_ERROR_NOTFOUND,
 			t_strdup_printf("Directory %s isn't empty, "
 					"can't delete it.", name));
 		return -1;
--- a/src/lib-storage/index/dbox/dbox-storage.c	Sat Nov 15 20:23:46 2008 +0200
+++ b/src/lib-storage/index/dbox/dbox-storage.c	Sat Nov 15 20:59:54 2008 +0200
@@ -344,7 +344,7 @@
 				     directory ? MAILBOX_LIST_PATH_TYPE_DIR :
 				     MAILBOX_LIST_PATH_TYPE_MAILBOX);
 	if (stat(path, &st) == 0) {
-		mail_storage_set_error(_storage, MAIL_ERROR_NOTPOSSIBLE,
+		mail_storage_set_error(_storage, MAIL_ERROR_EXISTS,
 				       "Mailbox already exists");
 		return -1;
 	}
@@ -355,7 +355,7 @@
 	   it. */
 	alt_path = directory ? NULL : dbox_get_alt_path(storage, path);
 	if (alt_path != NULL && stat(alt_path, &st) == 0) {
-		mail_storage_set_error(_storage, MAIL_ERROR_NOTPOSSIBLE,
+		mail_storage_set_error(_storage, MAIL_ERROR_EXISTS,
 				       "Mailbox already exists");
 		return -1;
 	}
@@ -426,7 +426,7 @@
 	}
 
 	if (!unlinked_something) {
-		mailbox_list_set_error(list, MAIL_ERROR_NOTPOSSIBLE,
+		mailbox_list_set_error(list, MAIL_ERROR_NOTFOUND,
 			t_strdup_printf("Directory %s isn't empty, "
 					"can't delete it.", name));
 		return -1;
@@ -501,7 +501,7 @@
 	else if (errno == ENOTEMPTY) {
 		if (deleted)
 			return 0;
-		mailbox_list_set_error(list, MAIL_ERROR_NOTPOSSIBLE,
+		mailbox_list_set_error(list, MAIL_ERROR_NOTFOUND,
 			t_strdup_printf("Directory %s isn't empty, "
 					"can't delete it.", name));
 	} else if (!mailbox_list_set_error_from_errno(list)) {
@@ -547,7 +547,7 @@
 	if (stat(alt_newpath, &st) == 0) {
 		/* race condition or a directory left there lying around?
 		   safest to just report error. */
-		mailbox_list_set_error(list, MAIL_ERROR_NOTPOSSIBLE,
+		mailbox_list_set_error(list, MAIL_ERROR_EXISTS,
 				       "Target mailbox already exists");
 		return -1;
 	} else if (errno != ENOENT) {
--- a/src/lib-storage/index/index-search.c	Sat Nov 15 20:23:46 2008 +0200
+++ b/src/lib-storage/index/index-search.c	Sat Nov 15 20:59:54 2008 +0200
@@ -1207,6 +1207,9 @@
 		} else T_BEGIN {
 			ret = search_match_next(ctx) ? 1 : 0;
 
+			if (ctx->mail->expunged)
+				_ctx->seen_lost_data = TRUE;
+
 			if (ret == 0 &&
 			    search_has_static_nonmatches(_ctx->args->args)) {
 				/* if there are saved search results remember
--- a/src/lib-storage/index/maildir/maildir-storage.c	Sat Nov 15 20:23:46 2008 +0200
+++ b/src/lib-storage/index/maildir/maildir-storage.c	Sat Nov 15 20:59:54 2008 +0200
@@ -312,7 +312,7 @@
 	if (errno == EEXIST) {
 		if (verify)
 			return 0;
-		mail_storage_set_error(storage, MAIL_ERROR_NOTPOSSIBLE,
+		mail_storage_set_error(storage, MAIL_ERROR_EXISTS,
 				       "Mailbox already exists");
 	} else if (errno == ENOENT) {
 		mail_storage_set_error(storage, MAIL_ERROR_NOTFOUND,
@@ -370,7 +370,7 @@
 	ret = maildir_check_tmp(storage, dir);
 	if (ret > 0) {
 		if (!verify) {
-			mail_storage_set_error(storage, MAIL_ERROR_NOTPOSSIBLE,
+			mail_storage_set_error(storage, MAIL_ERROR_EXISTS,
 					       "Mailbox already exists");
 			return -1;
 		}
@@ -718,7 +718,7 @@
 	}
 
 	if (!unlinked_something) {
-		mailbox_list_set_error(list, MAIL_ERROR_NOTPOSSIBLE,
+		mailbox_list_set_error(list, MAIL_ERROR_NOTFOUND,
 			t_strdup_printf("Directory %s isn't empty, "
 					"can't delete it.", name));
 		return -1;
--- a/src/lib-storage/index/mbox/mbox-storage.c	Sat Nov 15 20:23:46 2008 +0200
+++ b/src/lib-storage/index/mbox/mbox-storage.c	Sat Nov 15 20:59:54 2008 +0200
@@ -715,7 +715,7 @@
 	path = mailbox_list_get_path(_storage->list, name,
 				     MAILBOX_LIST_PATH_TYPE_MAILBOX);
 	if (stat(path, &st) == 0) {
-		mail_storage_set_error(_storage, MAIL_ERROR_NOTPOSSIBLE,
+		mail_storage_set_error(_storage, MAIL_ERROR_EXISTS,
 				       "Mailbox already exists");
 		return -1;
 	}
@@ -760,7 +760,7 @@
 
 	if (errno == EEXIST) {
 		/* mailbox was just created between stat() and open() call.. */
-		mail_storage_set_error(_storage, MAIL_ERROR_NOTPOSSIBLE,
+		mail_storage_set_error(_storage, MAIL_ERROR_EXISTS,
 				       "Mailbox already exists");
 	} else if (!mail_storage_set_error_from_errno(_storage)) {
 		mail_storage_set_critical(_storage,
@@ -947,7 +947,7 @@
 			mailbox_list_set_error(list, MAIL_ERROR_NOTFOUND,
 				T_MAIL_ERR_MAILBOX_NOT_FOUND(name));
 		} else if (errno == ENOTEMPTY) {
-			mailbox_list_set_error(list, MAIL_ERROR_NOTPOSSIBLE,
+			mailbox_list_set_error(list, MAIL_ERROR_NOTFOUND,
 				t_strdup_printf("Directory %s isn't empty, "
 						"can't delete it.", name));
 		} else if (!mailbox_list_set_error_from_errno(list)) {
--- a/src/lib-storage/list/mailbox-list-fs.c	Sat Nov 15 20:23:46 2008 +0200
+++ b/src/lib-storage/list/mailbox-list-fs.c	Sat Nov 15 20:59:54 2008 +0200
@@ -305,7 +305,7 @@
 	   possibility that someone actually tries to rename two mailboxes
 	   to same new one */
 	if (lstat(newpath, &st) == 0) {
-		mailbox_list_set_error(list, MAIL_ERROR_NOTPOSSIBLE,
+		mailbox_list_set_error(list, MAIL_ERROR_EXISTS,
 				       "Target mailbox already exists");
 		return -1;
 	} else if (errno == ENOTDIR) {
--- a/src/lib-storage/list/mailbox-list-maildir.c	Sat Nov 15 20:23:46 2008 +0200
+++ b/src/lib-storage/list/mailbox-list-maildir.c	Sat Nov 15 20:59:54 2008 +0200
@@ -426,7 +426,7 @@
 	}
 
 	if (EDESTDIREXISTS(errno)) {
-		mailbox_list_set_error(list, MAIL_ERROR_NOTPOSSIBLE,
+		mailbox_list_set_error(list, MAIL_ERROR_EXISTS,
 				       "Target mailbox already exists");
 	} else {
 		mailbox_list_set_critical(list, "rename(%s, %s) failed: %m",
--- a/src/lib-storage/mail-error.h	Sat Nov 15 20:23:46 2008 +0200
+++ b/src/lib-storage/mail-error.h	Sat Nov 15 20:59:54 2008 +0200
@@ -26,10 +26,15 @@
 	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 */
+	/* Item (e.g. mailbox) doesn't exist or it's not visible to us */
 	MAIL_ERROR_NOTFOUND,
+	/* Item (e.g. mailbox) already exists */
+	MAIL_ERROR_EXISTS,
 	/* Tried to access an expunged message */
-	MAIL_ERROR_EXPUNGED
+	MAIL_ERROR_EXPUNGED,
+	/* Operation cannot be done because another session prevents it
+	   (e.g. lock timeout) */
+	MAIL_ERROR_INUSE
 };
 
 /* Convert errno to mail_error and an error string. Returns TRUE if successful,
--- a/src/lib-storage/mail-storage-private.h	Sat Nov 15 20:23:46 2008 +0200
+++ b/src/lib-storage/mail-storage-private.h	Sat Nov 15 20:59:54 2008 +0200
@@ -311,6 +311,8 @@
 
 	uint32_t seq;
 	ARRAY_DEFINE(module_contexts, union mail_search_module_context *);
+
+	unsigned int seen_lost_data:1;
 };
 
 struct mail_save_context {
--- a/src/lib-storage/mail-storage.c	Sat Nov 15 20:23:46 2008 +0200
+++ b/src/lib-storage/mail-storage.c	Sat Nov 15 20:59:54 2008 +0200
@@ -699,6 +699,11 @@
 	return ret;
 }
 
+bool mailbox_search_seen_lost_data(struct mail_search_context *ctx)
+{
+	return ctx->seen_lost_data;
+}
+
 int mailbox_search_result_build(struct mailbox_transaction_context *t,
 				struct mail_search_args *args,
 				enum mailbox_search_result_flags flags,
--- a/src/lib-storage/mail-storage.h	Sat Nov 15 20:23:46 2008 +0200
+++ b/src/lib-storage/mail-storage.h	Sat Nov 15 20:59:54 2008 +0200
@@ -431,6 +431,10 @@
    finished, and TRUE if more results will by calling the function again. */
 int mailbox_search_next_nonblock(struct mail_search_context *ctx,
 				 struct mail *mail, bool *tryagain_r);
+/* Returns TRUE if some messages were already expunged and we couldn't
+   determine correctly if those messages should have been returned in this
+   search. */
+bool mailbox_search_seen_lost_data(struct mail_search_context *ctx);
 
 /* Remember the search result for future use. This must be called before the
    first mailbox_search_next*() call. */
--- a/src/lib-storage/mailbox-list.c	Sat Nov 15 20:23:46 2008 +0200
+++ b/src/lib-storage/mailbox-list.c	Sat Nov 15 20:59:54 2008 +0200
@@ -554,7 +554,7 @@
 	if (errno == ENOTEMPTY) {
 		/* We're most likely using NFS and we can't delete
 		   .nfs* files. */
-		mailbox_list_set_error(list, MAIL_ERROR_NOTPOSSIBLE,
+		mailbox_list_set_error(list, MAIL_ERROR_INUSE,
 			"Mailbox is still open in another session, "
 			"can't delete it.");
 	} else {