dovecot: FLAGS/PERMENENTFLAGS weren't always sent to client earl...

dovecot at dovecot.org dovecot at dovecot.org
Sat Dec 29 07:11:16 EET 2007


details:   http://hg.dovecot.org/dovecot/rev/81f4c9689c18
changeset: 7057:81f4c9689c18
user:      Timo Sirainen <tss at iki.fi>
date:      Sat Dec 29 07:11:12 2007 +0200
description:
FLAGS/PERMENENTFLAGS weren't always sent to client early enough. Also
optimized sending keywords with FETCH FLAGS.

diffstat:

10 files changed, 88 insertions(+), 118 deletions(-)
src/imap/client.c        |    2 
src/imap/client.h        |   10 +++-
src/imap/cmd-close.c     |    1 
src/imap/cmd-select.c    |   12 ++---
src/imap/cmd-unselect.c  |    1 
src/imap/commands-util.c |   98 +++++++++++++++++++++-------------------------
src/imap/commands-util.h |   18 ++++----
src/imap/imap-fetch.c    |    7 ++-
src/imap/imap-fetch.h    |    1 
src/imap/imap-sync.c     |   56 +++++---------------------

diffs (truncated from 405 to 300 lines):

diff -r 097c70cfa55e -r 81f4c9689c18 src/imap/client.c
--- a/src/imap/client.c	Sat Dec 29 06:54:40 2007 +0200
+++ b/src/imap/client.c	Sat Dec 29 07:11:12 2007 +0200
@@ -41,7 +41,6 @@ struct client *client_create(int fd_in, 
         client->last_input = ioloop_time;
 
 	client->command_pool = pool_alloconly_create("client command", 8192);
-	client->keywords.pool = pool_alloconly_create("mailbox_keywords", 512);
 	client->namespaces = namespaces;
 
 	while (namespaces != NULL) {
@@ -144,7 +143,6 @@ void client_destroy(struct client *clien
 			i_error("close(client out) failed: %m");
 	}
 
-	pool_unref(&client->keywords.pool);
 	pool_unref(&client->command_pool);
 	i_free(client);
 
diff -r 097c70cfa55e -r 81f4c9689c18 src/imap/client.h
--- a/src/imap/client.h	Sat Dec 29 06:54:40 2007 +0200
+++ b/src/imap/client.h	Sat Dec 29 07:11:12 2007 +0200
@@ -11,9 +11,13 @@ struct imap_arg;
 struct imap_arg;
 
 struct mailbox_keywords {
-	pool_t pool; /* will be p_clear()ed when changed */
-
-	ARRAY_DEFINE(keywords, const char *);
+	/* All keyword names. The array itself exists in mail_index.
+	   Keywords are currently only appended, they're never removed. */
+	const ARRAY_TYPE(keywords) *names;
+	/* Number of keywords announced to client via FLAGS/PERMANENTFLAGS.
+	   This relies on keywords not being removed while mailbox is
+	   selected. */
+	unsigned int announce_count;
 };
 
 struct client_command_context {
diff -r 097c70cfa55e -r 81f4c9689c18 src/imap/cmd-close.c
--- a/src/imap/cmd-close.c	Sat Dec 29 06:54:40 2007 +0200
+++ b/src/imap/cmd-close.c	Sat Dec 29 07:11:12 2007 +0200
@@ -21,6 +21,7 @@ bool cmd_close(struct client_command_con
 
 	if (mailbox_close(&mailbox) < 0)
                 client_send_untagged_storage_error(client, storage);
+	client_update_mailbox_flags(client, NULL);
 
 	client_send_tagline(cmd, "OK Close completed.");
 	return TRUE;
diff -r 097c70cfa55e -r 81f4c9689c18 src/imap/cmd-select.c
--- a/src/imap/cmd-select.c	Sat Dec 29 06:54:40 2007 +0200
+++ b/src/imap/cmd-select.c	Sat Dec 29 07:11:12 2007 +0200
@@ -45,17 +45,17 @@ bool cmd_select_full(struct client_comma
 		return TRUE;
 	}
 
-	client_save_keywords(&client->keywords, status.keywords);
-	client->messages_count = status.messages;
-	client->recent_count = status.recent;
-	client->uidvalidity = status.uidvalidity;
-
 	/* set client's mailbox only after getting status to make sure
 	   we're not sending any expunge/exists replies too early to client */
 	client->mailbox = box;
 	client->select_counter++;
 
-	client_send_mailbox_flags(client, box, status.keywords);
+	client->messages_count = status.messages;
+	client->recent_count = status.recent;
+	client->uidvalidity = status.uidvalidity;
+
+	client_update_mailbox_flags(client, status.keywords);
+	client_send_mailbox_flags(client, TRUE);
 
 	client_send_line(client,
 		t_strdup_printf("* %u EXISTS", status.messages));
diff -r 097c70cfa55e -r 81f4c9689c18 src/imap/cmd-unselect.c
--- a/src/imap/cmd-unselect.c	Sat Dec 29 06:54:40 2007 +0200
+++ b/src/imap/cmd-unselect.c	Sat Dec 29 07:11:12 2007 +0200
@@ -17,6 +17,7 @@ bool cmd_unselect(struct client_command_
 	storage = mailbox_get_storage(mailbox);
 	if (mailbox_close(&mailbox) < 0)
 		client_send_untagged_storage_error(client, storage);
+	client_update_mailbox_flags(client, NULL);
 
 	client_send_tagline(cmd, "OK Unselect completed.");
 	return TRUE;
diff -r 097c70cfa55e -r 81f4c9689c18 src/imap/commands-util.c
--- a/src/imap/commands-util.c	Sat Dec 29 06:54:40 2007 +0200
+++ b/src/imap/commands-util.c	Sat Dec 29 07:11:12 2007 +0200
@@ -251,9 +251,6 @@ static const char *get_keywords_string(c
 	const char *const *names;
 	unsigned int i, count;
 
-	if (array_count(keywords) == 0)
-		return "";
-
 	str = t_str_new(256);
 	names = array_get(keywords, &count);
 	for (i = 0; i < count; i++) {
@@ -265,65 +262,62 @@ static const char *get_keywords_string(c
 
 #define SYSTEM_FLAGS "\\Answered \\Flagged \\Deleted \\Seen \\Draft"
 
-void client_send_mailbox_flags(struct client *client, struct mailbox *box,
-			       const ARRAY_TYPE(keywords) *keywords)
-{
+void client_send_mailbox_flags(struct client *client, bool selecting)
+{
+	unsigned int count = array_count(client->keywords.names);
 	const char *str;
 
-	str = get_keywords_string(keywords);
+	if (!selecting && count == client->keywords.announce_count) {
+		/* no changes to keywords and we're not selecting a mailbox */
+		return;
+	}
+
+	client->keywords.announce_count = count;
+	str = count == 0 ? "" : get_keywords_string(client->keywords.names);
 	client_send_line(client,
 		t_strconcat("* FLAGS ("SYSTEM_FLAGS, str, ")", NULL));
 
-	if (mailbox_is_readonly(box)) {
+	if (mailbox_is_readonly(client->mailbox)) {
 		client_send_line(client, "* OK [PERMANENTFLAGS ()] "
 				 "Read-only mailbox.");
 	} else {
+		bool star = mailbox_allow_new_keywords(client->mailbox);
+
 		client_send_line(client,
 			t_strconcat("* OK [PERMANENTFLAGS ("SYSTEM_FLAGS, str,
-				    mailbox_allow_new_keywords(box) ?
-				    " \\*" : "", ")] Flags permitted.", NULL));
-	}
-}
-
-bool client_save_keywords(struct mailbox_keywords *dest,
-			  const ARRAY_TYPE(keywords) *keywords)
-{
-	const char *const *names, *const *old_names;
-	unsigned int i, count, old_count;
-	bool changed;
-
-	names = array_get(keywords, &count);
-
-	/* first check if anything changes */
-	if (!array_is_created(&dest->keywords))
-		changed = count != 0;
-	else {
-		old_names = array_get(&dest->keywords, &old_count);
-		if (count != old_count)
-			changed = TRUE;
-		else {
-			changed = FALSE;
-			for (i = 0; i < count; i++) {
-				if (strcmp(names[i], old_names[i]) != 0) {
-					changed = TRUE;
-					break;
-				}
-			}
-		}
-	}
-
-	if (!changed)
-		return FALSE;
-
-	p_clear(dest->pool);
-	p_array_init(&dest->keywords, dest->pool, array_count(keywords));
-
-	for (i = 0; i < count; i++) {
-		const char *name = p_strdup(dest->pool, names[i]);
-
-		array_append(&dest->keywords, &name, 1);
-	}
-	return TRUE;
+				    star ? " \\*" : "",
+				    ")] Flags permitted.", NULL));
+	}
+}
+
+void client_update_mailbox_flags(struct client *client,
+				 const ARRAY_TYPE(keywords) *keywords)
+{
+	client->keywords.names = keywords;
+	client->keywords.announce_count = 0;
+}
+
+const char *const *
+client_get_keyword_names(struct client *client, ARRAY_TYPE(keywords) *dest,
+			 const ARRAY_TYPE(keyword_indexes) *src)
+{
+	const unsigned int *kw_indexes;
+	const char *const *all_names;
+	unsigned int i, kw_count, all_count;
+
+	client_send_mailbox_flags(client, FALSE);
+
+	all_names = array_get(client->keywords.names, &all_count);
+	kw_indexes = array_get(src, &kw_count);
+
+	/* convert indexes to names */
+	for (i = 0; i < kw_count; i++) {
+		i_assert(kw_indexes[i] < all_count);
+		array_append(dest, &all_names[kw_indexes[i]], 1);
+	}
+
+	(void)array_append_space(dest);
+	return array_idx(dest, 0);
 }
 
 bool mailbox_equals(struct mailbox *box1, struct mail_storage *storage2,
diff -r 097c70cfa55e -r 81f4c9689c18 src/imap/commands-util.h
--- a/src/imap/commands-util.h	Sat Dec 29 06:54:40 2007 +0200
+++ b/src/imap/commands-util.h	Sat Dec 29 07:11:12 2007 +0200
@@ -50,14 +50,16 @@ bool client_parse_mail_flags(struct clie
 			     enum mail_flags *flags_r,
 			     const char *const **keywords_r);
 
-/* Send FLAGS + PERMANENTFLAGS to client. */
-void client_send_mailbox_flags(struct client *client, struct mailbox *box,
-			       const ARRAY_TYPE(keywords) *keywords);
-
-/* Copy keywords into dest. dest must have been initialized. Returns TRUE if
-   keywords changed. */
-bool client_save_keywords(struct mailbox_keywords *dest,
-			  const ARRAY_TYPE(keywords) *keywords);
+/* Send FLAGS + PERMANENTFLAGS to client if they have changed,
+   or if selecting=TRUE. */
+void client_send_mailbox_flags(struct client *client, bool selecting);
+/* Update client->keywords array. Use keywords=NULL when unselecting. */
+void client_update_mailbox_flags(struct client *client,
+				 const ARRAY_TYPE(keywords) *keywords);
+/* Convert keyword indexes to keyword names in selected mailbox. */
+const char *const *
+client_get_keyword_names(struct client *client, ARRAY_TYPE(keywords) *dest,
+			 const ARRAY_TYPE(keyword_indexes) *src);
 
 bool mailbox_equals(struct mailbox *box1, struct mail_storage *storage2,
 		    const char *name2);
diff -r 097c70cfa55e -r 81f4c9689c18 src/imap/imap-fetch.c
--- a/src/imap/imap-fetch.c	Sat Dec 29 06:54:40 2007 +0200
+++ b/src/imap/imap-fetch.c	Sat Dec 29 07:11:12 2007 +0200
@@ -99,6 +99,8 @@ struct imap_fetch_context *imap_fetch_in
 	ctx->cur_str = str_new(default_pool, 8192);
 	ctx->all_headers_buf = buffer_create_dynamic(cmd->pool, 128);
 	p_array_init(&ctx->handlers, cmd->pool, 16);
+	p_array_init(&ctx->tmp_keywords, cmd->pool,
+		     client->keywords.announce_count + 8);
 	ctx->line_finished = TRUE;
 	return ctx;
 }
@@ -514,8 +516,6 @@ static int fetch_flags(struct imap_fetch
 	const char *const *keywords;
 
 	flags = mail_get_flags(mail);
-	keywords = mail_get_keywords(mail);
-
 	if (ctx->flags_update_seen && (flags & MAIL_SEEN) == 0) {
 		/* Add \Seen flag */
 		ctx->seen_flags_changed = TRUE;
@@ -524,6 +524,9 @@ static int fetch_flags(struct imap_fetch
 	} else if (ctx->flags_show_only_seen_changes) {
 		return 1;
 	}
+
+	keywords = client_get_keyword_names(ctx->client, &ctx->tmp_keywords,
+			mail_get_keyword_indexes(mail));
 
 	str_append(ctx->cur_str, "FLAGS (");
 	imap_write_flags(ctx->cur_str, flags, keywords);
diff -r 097c70cfa55e -r 81f4c9689c18 src/imap/imap-fetch.h
--- a/src/imap/imap-fetch.h	Sat Dec 29 06:54:40 2007 +0200
+++ b/src/imap/imap-fetch.h	Sat Dec 29 07:11:12 2007 +0200
@@ -51,6 +51,7 @@ struct imap_fetch_context {
 	bool skip_cr;
 	int (*cont_handler)(struct imap_fetch_context *ctx);
 
+	ARRAY_TYPE(keywords) tmp_keywords;
 	unsigned int select_counter;
 
 	unsigned int flags_have_handler:1;
diff -r 097c70cfa55e -r 81f4c9689c18 src/imap/imap-sync.c
--- a/src/imap/imap-sync.c	Sat Dec 29 06:54:40 2007 +0200
+++ b/src/imap/imap-sync.c	Sat Dec 29 07:11:12 2007 +0200
@@ -21,10 +21,8 @@ struct imap_sync_context {
 	struct mailbox_sync_context *sync_ctx;
 	struct mail *mail;
 
-	const ARRAY_TYPE(keywords) *keywords;
-	unsigned int keyword_announce_count;
-
 	struct mailbox_sync_rec sync_rec;
+	ARRAY_TYPE(keywords) tmp_keywords;
 	uint32_t seq;
 
 	unsigned int messages_count;
@@ -33,19 +31,11 @@ struct imap_sync_context {
 	unsigned int no_newmail:1;


More information about the dovecot-cvs mailing list