dovecot-2.1: Implemented IMAP SPECIAL-USE extension.

dovecot at dovecot.org dovecot at dovecot.org
Fri Dec 2 17:07:51 EET 2011


details:   http://hg.dovecot.org/dovecot-2.1/rev/32d1a903d42d
changeset: 13794:32d1a903d42d
user:      Timo Sirainen <tss at iki.fi>
date:      Fri Dec 02 17:05:31 2011 +0200
description:
Implemented IMAP SPECIAL-USE extension.

diffstat:

 configure.in                            |   2 +-
 src/imap/cmd-list.c                     |  22 ++++++++++--
 src/lib-storage/mail-storage-settings.c |  56 +++++++++++++++++++++++++++++++-
 src/lib-storage/mail-storage-settings.h |   1 +
 src/lib-storage/mail-storage.c          |   2 +-
 src/lib-storage/mail-storage.h          |   3 +
 src/lib-storage/mailbox-list-iter.c     |  51 ++++++++++++++++++++++-------
 src/lib-storage/mailbox-list-private.h  |   1 +
 src/lib-storage/mailbox-list.h          |   6 ++-
 9 files changed, 121 insertions(+), 23 deletions(-)

diffs (truncated from 351 to 300 lines):

diff -r ee783a878120 -r 32d1a903d42d configure.in
--- a/configure.in	Fri Dec 02 16:22:31 2011 +0200
+++ b/configure.in	Fri Dec 02 17:05:31 2011 +0200
@@ -2671,7 +2671,7 @@
 dnl IDLE doesn't really belong to banner. It's there just to make Blackberries
 dnl happy, because otherwise BIS server disables push email.
 capability_banner="IMAP4rev1 LITERAL+ SASL-IR LOGIN-REFERRALS ID ENABLE IDLE"
-capability="$capability_banner SORT SORT=DISPLAY THREAD=REFERENCES THREAD=REFS MULTIAPPEND UNSELECT CHILDREN NAMESPACE UIDPLUS LIST-EXTENDED I18NLEVEL=1 CONDSTORE QRESYNC ESEARCH ESORT SEARCHRES WITHIN CONTEXT=SEARCH LIST-STATUS FUZZY"
+capability="$capability_banner SORT SORT=DISPLAY THREAD=REFERENCES THREAD=REFS MULTIAPPEND UNSELECT CHILDREN NAMESPACE UIDPLUS LIST-EXTENDED I18NLEVEL=1 CONDSTORE QRESYNC ESEARCH ESORT SEARCHRES WITHIN CONTEXT=SEARCH LIST-STATUS FUZZY SPECIAL-USE"
 AC_DEFINE_UNQUOTED(CAPABILITY_STRING, "$capability", IMAP capabilities)
 AC_DEFINE_UNQUOTED(CAPABILITY_BANNER_STRING, "$capability_banner", IMAP capabilities advertised in banner) 
 
diff -r ee783a878120 -r 32d1a903d42d src/imap/cmd-list.c
--- a/src/imap/cmd-list.c	Fri Dec 02 16:22:31 2011 +0200
+++ b/src/imap/cmd-list.c	Fri Dec 02 17:05:31 2011 +0200
@@ -37,7 +37,7 @@
 
 static void
 mailbox_flags2str(struct cmd_list_context *ctx, string_t *str,
-		  enum mailbox_info_flags flags)
+		  const char *special_use, enum mailbox_info_flags flags)
 {
 	unsigned int orig_len = str_len(str);
 
@@ -76,6 +76,11 @@
 	if ((flags & MAILBOX_UNMARKED) != 0)
 		str_append(str, "\\UnMarked ");
 
+	if ((ctx->list_flags & MAILBOX_LIST_ITER_RETURN_SPECIALUSE) != 0 &&
+	    special_use != NULL) {
+		str_append(str, special_use);
+		str_append_c(str, ' ');
+	}
 	if (str_len(str) != orig_len)
 		str_truncate(str, str_len(str)-1);
 }
@@ -150,6 +155,8 @@
 			list_flags |= MAILBOX_LIST_ITER_RETURN_SUBSCRIBED;
 		else if (strcasecmp(str, "CHILDREN") == 0)
 			list_flags |= MAILBOX_LIST_ITER_RETURN_CHILDREN;
+		else if (strcasecmp(str, "SPECIAL-USE") == 0)
+			list_flags |= MAILBOX_LIST_ITER_RETURN_SPECIALUSE;
 		else if (strcasecmp(str, "STATUS") == 0 &&
 			 imap_arg_get_list(&args[1], &list_args)) {
 			if (imap_status_parse_items(ctx->cmd, list_args,
@@ -262,6 +269,7 @@
 list_namespace_send_prefix(struct cmd_list_context *ctx, bool have_children)
 {
 	struct mail_namespace *const *listed;
+	const struct mailbox_settings *mailbox_set;
 	unsigned int len;
 	enum mailbox_info_flags flags;
 	const char *name;
@@ -330,7 +338,10 @@
 	str_printfa(str, "* %s (", ctx->lsub ? "LSUB" : "LIST");
 	if (ctx->lsub)
 		flags |= MAILBOX_NONEXISTENT;
-	mailbox_flags2str(ctx, str, flags);
+	mailbox_set = (ctx->list_flags & MAILBOX_LIST_ITER_RETURN_SPECIALUSE) == 0 ? NULL :
+		mailbox_settings_find(ctx->cmd->client->user, name);
+	mailbox_flags2str(ctx, str, mailbox_set == NULL ? NULL :
+			  mailbox_set->special_use, flags);
 	str_append(str, ") ");
 	list_reply_append_ns_sep_param(str, ns_sep);
 	str_append_c(str, ' ');
@@ -447,7 +458,7 @@
 
 		str_truncate(str, 0);
 		str_printfa(str, "* %s (", ctx->lsub ? "LSUB" : "LIST");
-		mailbox_flags2str(ctx, str, flags);
+		mailbox_flags2str(ctx, str, info->special_use, flags);
 		str_append(str, ") ");
 		list_reply_append_ns_sep_param(str,
 			mail_namespace_get_sep(ctx->ns));
@@ -954,8 +965,9 @@
 		     WORKAROUND_TB_LSUB_FLAGS) == 0)
 			ctx->list_flags |= MAILBOX_LIST_ITER_RETURN_NO_FLAGS;
 	} else if (!ctx->used_listext) {
-		/* non-extended LIST - return children flags always */
-		ctx->list_flags |= MAILBOX_LIST_ITER_RETURN_CHILDREN;
+		/* non-extended LIST: use default flags */
+		ctx->list_flags |= MAILBOX_LIST_ITER_RETURN_CHILDREN |
+			MAILBOX_LIST_ITER_RETURN_SPECIALUSE;
 	}
 	ctx->list_flags |= MAILBOX_LIST_ITER_SHOW_EXISTING_PARENT;
 
diff -r ee783a878120 -r 32d1a903d42d src/lib-storage/mail-storage-settings.c
--- a/src/lib-storage/mail-storage-settings.c	Fri Dec 02 16:22:31 2011 +0200
+++ b/src/lib-storage/mail-storage-settings.c	Fri Dec 02 17:05:31 2011 +0200
@@ -150,6 +150,7 @@
 static const struct setting_define mailbox_setting_defines[] = {
 	DEF(SET_STR, name),
 	{ SET_ENUM, "auto", offsetof(struct mailbox_settings, autocreate), NULL } ,
+	DEF(SET_STR, special_use),
 
 	SETTING_DEFINE_LIST_END
 };
@@ -158,7 +159,8 @@
 	.name = "",
 	.autocreate = MAILBOX_SET_AUTO_NO":"
 		MAILBOX_SET_AUTO_CREATE":"
-		MAILBOX_SET_AUTO_SUBSCRIBE
+		MAILBOX_SET_AUTO_SUBSCRIBE,
+	.special_use = ""
 };
 
 const struct setting_parser_info mailbox_setting_parser_info = {
@@ -460,7 +462,53 @@
 	return TRUE;
 }
 
-static bool mailbox_settings_check(void *_set, pool_t pool ATTR_UNUSED,
+static bool mailbox_special_use_exists(const char *name)
+{
+	if (name[0] != '\\')
+		return FALSE;
+	name++;
+
+	if (strcasecmp(name, "All") == 0)
+		return TRUE;
+	if (strcasecmp(name, "Archive") == 0)
+		return TRUE;
+	if (strcasecmp(name, "Drafts") == 0)
+		return TRUE;
+	if (strcasecmp(name, "Flagged") == 0)
+		return TRUE;
+	if (strcasecmp(name, "Junk") == 0)
+		return TRUE;
+	if (strcasecmp(name, "Sent") == 0)
+		return TRUE;
+	if (strcasecmp(name, "Trash") == 0)
+		return TRUE;
+	return FALSE;
+}
+
+static bool
+mailbox_special_use_check(struct mailbox_settings *set, pool_t pool,
+			  const char **error_r)
+{
+	const char *const *uses, *str;
+	unsigned int i;
+
+	uses = t_strsplit_spaces(set->special_use, " ");
+	for (i = 0; uses[i] != NULL; i++) {
+		if (!mailbox_special_use_exists(uses[i])) {
+			*error_r = t_strdup_printf(
+				"mailbox %s: unknown special_use: %s",
+				set->name, uses[i]);
+			return FALSE;
+		}
+	}
+	/* make sure there are no extra spaces */
+	str = t_strarray_join(uses, " ");
+	if (strcmp(str, set->special_use) != 0)
+		set->special_use = p_strdup(pool, str);
+	return TRUE;
+}
+
+static bool mailbox_settings_check(void *_set, pool_t pool,
 				   const char **error_r)
 {
 	struct mailbox_settings *set = _set;
@@ -470,6 +518,10 @@
 					   set->name);
 		return FALSE;
 	}
+	if (*set->special_use != '\0') {
+		if (!mailbox_special_use_check(set, pool, error_r))
+			return FALSE;
+	}
 	return TRUE;
 }
 
diff -r ee783a878120 -r 32d1a903d42d src/lib-storage/mail-storage-settings.h
--- a/src/lib-storage/mail-storage-settings.h	Fri Dec 02 16:22:31 2011 +0200
+++ b/src/lib-storage/mail-storage-settings.h	Fri Dec 02 17:05:31 2011 +0200
@@ -63,6 +63,7 @@
 struct mailbox_settings {
 	const char *name;
 	const char *autocreate;
+	const char *special_use;
 };
 
 struct mail_user_settings {
diff -r ee783a878120 -r 32d1a903d42d src/lib-storage/mail-storage.c
--- a/src/lib-storage/mail-storage.c	Fri Dec 02 16:22:31 2011 +0200
+++ b/src/lib-storage/mail-storage.c	Fri Dec 02 17:05:31 2011 +0200
@@ -602,7 +602,7 @@
 	return TRUE;
 }
 
-static struct mailbox_settings *
+const struct mailbox_settings *
 mailbox_settings_find(struct mail_user *user, const char *vname)
 {
 	struct mailbox_settings *const *box_set;
diff -r ee783a878120 -r 32d1a903d42d src/lib-storage/mail-storage.h
--- a/src/lib-storage/mail-storage.h	Fri Dec 02 16:22:31 2011 +0200
+++ b/src/lib-storage/mail-storage.h	Fri Dec 02 17:05:31 2011 +0200
@@ -429,6 +429,9 @@
 /* Returns the storage's settings. */
 const struct mail_storage_settings *
 mailbox_get_settings(struct mailbox *box) ATTR_PURE;
+/* Returns the mailbox's settings, or NULL if there are none. */
+const struct mailbox_settings *
+mailbox_settings_find(struct mail_user *user, const char *vname);
 
 /* Returns name of given mailbox */
 const char *mailbox_get_name(const struct mailbox *box) ATTR_PURE;
diff -r ee783a878120 -r 32d1a903d42d src/lib-storage/mailbox-list-iter.c
--- a/src/lib-storage/mailbox-list-iter.c	Fri Dec 02 16:22:31 2011 +0200
+++ b/src/lib-storage/mailbox-list-iter.c	Fri Dec 02 17:05:31 2011 +0200
@@ -3,6 +3,7 @@
 #include "lib.h"
 #include "array.h"
 #include "imap-match.h"
+#include "mail-storage.h"
 #include "mailbox-tree.h"
 #include "mailbox-list-private.h"
 
@@ -17,6 +18,7 @@
 
 struct autocreate_box {
 	const char *name;
+	const struct mailbox_settings *set;
 	enum mailbox_info_flags flags;
 	bool child_listed;
 };
@@ -103,6 +105,7 @@
 			array_append(&actx->box_sets, &box_sets[i], 1);
 			autobox = array_append_space(&actx->boxes);
 			autobox->name = box_sets[i]->name;
+			autobox->set = box_sets[i];
 		}
 	}
 }
@@ -530,18 +533,41 @@
 }
 
 static const struct mailbox_info *
+mailbox_list_iter_next_call(struct mailbox_list_iterate_context *ctx)
+{
+	const struct mailbox_info *info;
+	const struct mailbox_settings *set;
+
+	info = ctx->list->v.iter_next(ctx);
+	if (info == NULL)
+		return NULL;
+
+	ctx->list->ns->flags |= NAMESPACE_FLAG_USABLE;
+	if ((ctx->list->flags & MAILBOX_LIST_ITER_RETURN_SPECIALUSE) != 0) {
+		set = mailbox_settings_find(ctx->list->ns->user, info->name);
+		if (set != NULL && *set->special_use != '\0') {
+			ctx->specialuse_info = *info;
+			ctx->specialuse_info.special_use =
+				*set->special_use == '\0' ? NULL :
+				set->special_use;
+			info = &ctx->specialuse_info;
+		}
+	}
+	return info;
+}
+
+static const struct mailbox_info *
 autocreate_iter_next(struct mailbox_list_iterate_context *ctx)
 {
 	struct mailbox_list_autocreate_iterate_context *actx =
 		ctx->autocreate_ctx;
 	const struct mailbox_info *info;
-	const struct autocreate_box *autoboxes;
+	const struct autocreate_box *autoboxes, *autobox;
 	unsigned int count;
 
 	if (actx->idx == 0) {
-		info = ctx->list->v.iter_next(ctx);
+		info = mailbox_list_iter_next_call(ctx);
 		if (info != NULL) {
-			ctx->list->ns->flags |= NAMESPACE_FLAG_USABLE;
 			actx->new_info = *info;
 			return autocreate_iter_existing(ctx);
 		}
@@ -550,8 +576,13 @@
 	/* list missing mailboxes */
 	autoboxes = array_get(&actx->boxes, &count);
 	while (actx->idx < count) {
-		if (autocreate_iter_autobox(ctx, &autoboxes[actx->idx++]))
+		autobox = &autoboxes[actx->idx++];
+		if (autocreate_iter_autobox(ctx, autobox)) {
+			actx->new_info.special_use =
+				*autobox->set->special_use == '\0' ? NULL :
+				autobox->set->special_use;
 			return &actx->new_info;
+		}
 	}
 	i_assert(array_count(&actx->boxes) == array_count(&actx->box_sets));
 	return NULL;
@@ -560,16 +591,10 @@
 const struct mailbox_info *
 mailbox_list_iter_next(struct mailbox_list_iterate_context *ctx)
 {


More information about the dovecot-cvs mailing list