Mercurial > dovecot > original-hg > dovecot-1.2
changeset 8717:6f29380ba3a0 HEAD
pop3: Track \Seen flag changes in a bitmask and do the changes at QUIT.
This way RSET doesn't need to rollback the transaction.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Wed, 04 Feb 2009 15:28:31 -0500 |
parents | 8cca2bf6ab76 |
children | ea9a186d64f9 |
files | src/pop3/client.c src/pop3/client.h src/pop3/commands.c |
diffstat | 3 files changed, 28 insertions(+), 21 deletions(-) [+] |
line wrap: on
line diff
--- a/src/pop3/client.c Wed Feb 04 15:13:01 2009 -0500 +++ b/src/pop3/client.c Wed Feb 04 15:28:31 2009 -0500 @@ -197,6 +197,9 @@ return NULL; } + if (!no_flag_updates) + client->seen_bitmask = i_malloc(MSGS_BITMASK_SIZE(client)); + i_assert(my_client == NULL); my_client = client; @@ -276,6 +279,7 @@ i_free(client->message_sizes); i_free(client->deleted_bitmask); + i_free(client->seen_bitmask); if (client->io != NULL) io_remove(&client->io);
--- a/src/pop3/client.h Wed Feb 04 15:13:01 2009 -0500 +++ b/src/pop3/client.h Wed Feb 04 15:28:31 2009 -0500 @@ -6,6 +6,9 @@ typedef void command_func_t(struct client *client); +#define MSGS_BITMASK_SIZE(client) \ + (((client)->messages_count + (CHAR_BIT-1)) / CHAR_BIT) + struct client { int fd_in, fd_out; struct io *io; @@ -27,8 +30,7 @@ unsigned int uid_validity; unsigned int messages_count; - unsigned int deleted_count; - unsigned int expunged_count; + unsigned int deleted_count, expunged_count, seen_change_count; uoff_t *message_sizes; uoff_t total_size; uoff_t deleted_size; @@ -43,6 +45,7 @@ uoff_t byte_counter_offset; unsigned char *deleted_bitmask; + unsigned char *seen_bitmask; unsigned int disconnected:1; unsigned int deleted:1;
--- a/src/pop3/commands.c Wed Feb 04 15:13:01 2009 -0500 +++ b/src/pop3/commands.c Wed Feb 04 15:28:31 2009 -0500 @@ -12,9 +12,6 @@ #include "capability.h" #include "commands.h" -#define MSGS_BITMASK_SIZE(client) \ - ((client->messages_count + (CHAR_BIT-1)) / CHAR_BIT) - static const char *get_msgnum(struct client *client, const char *args, unsigned int *msgnum) { @@ -198,15 +195,12 @@ return search_args; } -static bool expunge_mails(struct client *client) +static bool update_mails(struct client *client) { struct mail_search_args *search_args; struct mail_search_context *ctx; struct mail *mail; - uint32_t idx; - - if (client->deleted_bitmask == NULL) - return TRUE; + uint32_t idx, bit; if (mailbox_is_readonly(client->mailbox)) { /* silently ignore */ @@ -220,10 +214,14 @@ mail = mail_alloc(client->trans, 0, NULL); while (mailbox_search_next(ctx, mail) > 0) { idx = mail->seq - 1; - if ((client->deleted_bitmask[idx / CHAR_BIT] & - 1 << (idx % CHAR_BIT)) != 0) { + bit = 1 << (idx % CHAR_BIT); + if (client->deleted_bitmask != NULL && + (client->deleted_bitmask[idx / CHAR_BIT] & bit) != 0) { mail_expunge(mail); client->expunged_count++; + } else if (client->seen_bitmask != NULL && + (client->seen_bitmask[idx / CHAR_BIT] & bit) != 0) { + mail_update_flags(mail, MODIFY_ADD, MAIL_SEEN); } } mail_free(&mail); @@ -233,8 +231,8 @@ static int cmd_quit(struct client *client, const char *args ATTR_UNUSED) { - if (client->deleted) { - if (!expunge_mails(client)) { + if (client->deleted || client->seen_bitmask != NULL) { + if (!update_mails(client)) { client_send_storage_error(client); client_disconnect(client, "Storage error during logout."); @@ -408,11 +406,11 @@ return ret; } - if (body_lines == (uoff_t)-1 && !no_flag_updates) { + if (body_lines == (uoff_t)-1 && client->seen_bitmask != NULL) { if ((mail_get_flags(ctx->mail) & MAIL_SEEN) == 0) { /* mark the message seen with RETR command */ - (void)mail_update_flags(ctx->mail, - MODIFY_ADD, MAIL_SEEN); + client->seen_bitmask[msgnum / CHAR_BIT] |= 1 << (msgnum % CHAR_BIT); + client->seen_change_count++; } } @@ -462,6 +460,10 @@ client->deleted_count = 0; client->deleted_size = 0; } + if (client->seen_change_count > 0) { + memset(client->seen_bitmask, 0, MSGS_BITMASK_SIZE(client)); + client->seen_change_count = 0; + } if (enable_last_command) { /* remove all \Seen flags (as specified by RFC 1460) */ @@ -475,10 +477,8 @@ mail_update_flags(mail, MODIFY_REMOVE, MAIL_SEEN); mail_free(&mail); (void)mailbox_search_deinit(&search_ctx); - } else { - /* forget all our seen flag updates. - FIXME: is this needed? it loses data added to cache file */ - mailbox_transaction_rollback(&client->trans); + + mailbox_transaction_commit(&client->trans); client->trans = mailbox_transaction_begin(client->mailbox, 0); }