]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
pop3: Track \Seen flag changes in a bitmask and do the changes at QUIT.
authorTimo Sirainen <tss@iki.fi>
Wed, 4 Feb 2009 20:28:31 +0000 (15:28 -0500)
committerTimo Sirainen <tss@iki.fi>
Wed, 4 Feb 2009 20:28:31 +0000 (15:28 -0500)
This way RSET doesn't need to rollback the transaction.

--HG--
branch : HEAD

src/pop3/client.c
src/pop3/client.h
src/pop3/commands.c

index 0da0be855f902a361e416d95b975c5757534b55b..1e18b51f175ce8d54ec1f7515e8635024cac9c58 100644 (file)
@@ -197,6 +197,9 @@ struct client *client_create(int fd_in, int fd_out, struct mail_user *user)
                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 @@ void client_destroy(struct client *client, const char *reason)
 
        i_free(client->message_sizes);
        i_free(client->deleted_bitmask);
+       i_free(client->seen_bitmask);
 
        if (client->io != NULL)
                io_remove(&client->io);
index 8e24c54a9a523a83ca3933cc9fb248dd3d7a1d7d..b0a26c94d70251df2945bc7ec8d8e426182fedb3 100644 (file)
@@ -6,6 +6,9 @@ struct mail_storage;
 
 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 @@ struct client {
 
        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 @@ struct client {
        uoff_t byte_counter_offset;
 
        unsigned char *deleted_bitmask;
+       unsigned char *seen_bitmask;
 
        unsigned int disconnected:1;
        unsigned int deleted:1;
index 162e2ce92225360d70f79b396c312aefbf105763..bb78194073b584a416fbc45f42c0f78c564f6983 100644 (file)
@@ -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 @@ pop3_search_build(struct client *client, uint32_t seq)
        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 @@ static bool expunge_mails(struct client *client)
        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 bool expunge_mails(struct client *client)
 
 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 @@ static int fetch(struct client *client, unsigned int msgnum, uoff_t body_lines)
                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 @@ static int cmd_rset(struct client *client, const char *args ATTR_UNUSED)
                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 @@ static int cmd_rset(struct client *client, const char *args ATTR_UNUSED)
                        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);
        }