Mercurial > dovecot > original-hg > dovecot-1.2
changeset 7057:81f4c9689c18 HEAD
FLAGS/PERMENENTFLAGS weren't always sent to client early enough. Also
optimized sending keywords with FETCH FLAGS.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Sat, 29 Dec 2007 07:11:12 +0200 |
parents | 097c70cfa55e |
children | cf4cee852a05 |
files | src/imap/client.c src/imap/client.h src/imap/cmd-close.c src/imap/cmd-select.c src/imap/cmd-unselect.c src/imap/commands-util.c src/imap/commands-util.h src/imap/imap-fetch.c src/imap/imap-fetch.h src/imap/imap-sync.c |
diffstat | 10 files changed, 79 insertions(+), 109 deletions(-) [+] |
line wrap: on
line diff
--- 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 @@ 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 @@ i_error("close(client out) failed: %m"); } - pool_unref(&client->keywords.pool); pool_unref(&client->command_pool); i_free(client);
--- 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 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 {
--- 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 @@ 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;
--- 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 @@ 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));
--- 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 @@ 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;
--- 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 @@ 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 @@ #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)); + star ? " \\*" : "", + ")] Flags permitted.", NULL)); } } -bool client_save_keywords(struct mailbox_keywords *dest, - const ARRAY_TYPE(keywords) *keywords) +void client_update_mailbox_flags(struct client *client, + 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); + client->keywords.names = keywords; + client->keywords.announce_count = 0; +} - /* 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; - } - } - } +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); } - 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; + (void)array_append_space(dest); + return array_idx(dest, 0); } bool mailbox_equals(struct mailbox *box1, struct mail_storage *storage2,
--- 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 @@ 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);
--- 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 @@ 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 @@ 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; @@ -525,6 +525,9 @@ 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); str_append(ctx->cur_str, ") ");
--- 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 @@ 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;
--- 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 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 @@ unsigned int no_newmail:1; }; -static void imap_sync_send_changed_keywords(struct imap_sync_context *ctx) -{ - ctx->keyword_announce_count = array_count(ctx->keywords); - if (client_save_keywords(&ctx->client->keywords, ctx->keywords)) - client_send_mailbox_flags(ctx->client, ctx->box, ctx->keywords); -} - struct imap_sync_context * imap_sync_init(struct client *client, struct mailbox *box, enum imap_sync_flags imap_flags, enum mailbox_sync_flags flags) { struct imap_sync_context *ctx; - struct mailbox_status status; i_assert(client->mailbox == box); @@ -58,10 +48,9 @@ ctx->t = mailbox_transaction_begin(box, 0); ctx->mail = mail_alloc(ctx->t, MAIL_FETCH_FLAGS, 0); ctx->messages_count = client->messages_count; + i_array_init(&ctx->tmp_keywords, client->keywords.announce_count + 8); - mailbox_get_status(ctx->box, STATUS_KEYWORDS, &status); - ctx->keywords = status.keywords; - imap_sync_send_changed_keywords(ctx); + client_send_mailbox_flags(client, FALSE); return ctx; } @@ -103,41 +92,20 @@ } } + array_free(&ctx->tmp_keywords); i_free(ctx); return ret; } -static int imap_sync_send_flags(struct imap_sync_context *ctx, string_t *str, - ARRAY_TYPE(keywords) *keyword_names) +static int imap_sync_send_flags(struct imap_sync_context *ctx, string_t *str) { enum mail_flags flags; - const ARRAY_TYPE(keyword_indexes) *keywords; - const unsigned int *kw_indexes; - const char *const *all_names; - unsigned int i, kw_count, all_count; + const char *const *keywords; mail_set_seq(ctx->mail, ctx->seq); flags = mail_get_flags(ctx->mail); - - all_names = array_get(ctx->keywords, &all_count); - keywords = mail_get_keyword_indexes(ctx->mail); - kw_indexes = array_get(keywords, &kw_count); - - if (!array_is_created(keyword_names)) - t_array_init(keyword_names, I_MAX(kw_count, 16)); - else - array_clear(keyword_names); - /* convert indexes to names */ - for (i = 0; i < kw_count; i++) { - if (kw_indexes[i] >= ctx->keyword_announce_count) { - /* a new keyword. notify the client. */ - imap_sync_send_changed_keywords(ctx); - all_names = array_get(ctx->keywords, &all_count); - } - i_assert(kw_indexes[i] < all_count); - array_append(keyword_names, &all_names[kw_indexes[i]], 1); - } - (void)array_append_space(keyword_names); + keywords = client_get_keyword_names(ctx->client, &ctx->tmp_keywords, + mail_get_keyword_indexes(ctx->mail)); str_truncate(str, 0); str_printfa(str, "* %u FETCH (", ctx->seq); @@ -145,14 +113,13 @@ str_printfa(str, "UID %u ", ctx->mail->uid); str_append(str, "FLAGS ("); - imap_write_flags(str, flags, array_idx(keyword_names, 0)); + imap_write_flags(str, flags, keywords); str_append(str, "))"); return client_send_line(ctx->client, str_c(str)); } int imap_sync_more(struct imap_sync_context *ctx) { - ARRAY_TYPE(keywords) keyword_names = ARRAY_INIT; string_t *str; int ret = 1; @@ -188,8 +155,7 @@ if (ret <= 0) break; - ret = imap_sync_send_flags(ctx, str, - &keyword_names); + ret = imap_sync_send_flags(ctx, str); } break; case MAILBOX_SYNC_TYPE_EXPUNGE: