]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
QRESYNC: Send HIGHESTMODSEQ automatically in all tagged replies whenever it
authorTimo Sirainen <tss@iki.fi>
Wed, 11 Jun 2008 12:44:35 +0000 (15:44 +0300)
committerTimo Sirainen <tss@iki.fi>
Wed, 11 Jun 2008 12:44:35 +0000 (15:44 +0300)
seems useful.

--HG--
branch : HEAD

src/imap/client.h
src/imap/cmd-close.c
src/imap/cmd-expunge.c
src/imap/cmd-idle.c
src/imap/imap-fetch.c
src/imap/imap-sync.c
src/imap/imap-sync.h

index 644448f47f782fb1fb6f9758223c84bd957cebe9..7c00ea65c6bc2282d61931e0379896b3c2f0a07e 100644 (file)
@@ -94,6 +94,7 @@ struct client {
        unsigned int command_queue_size;
 
        uint64_t sync_last_full_modseq;
+       uint64_t highest_fetch_modseq;
 
        /* SEARCHRES extension: Last saved SEARCH result */
        ARRAY_TYPE(seq_range) search_saved_uidset;
index a850819659f7dbbb17b8788319e936e5e5fd4365..9a71625c677756687c3d242efb05f30860794a7c 100644 (file)
@@ -14,19 +14,6 @@ static void cmd_close_finish(struct client *client)
        client_update_mailbox_flags(client, NULL);
 }
 
-static bool cmd_close_callback(struct client_command_context *cmd)
-{
-       struct mailbox_status status;
-
-       mailbox_get_status(cmd->client->mailbox,
-                          STATUS_HIGHESTMODSEQ, &status);
-       cmd_close_finish(cmd->client);
-       client_send_tagline(cmd, t_strdup_printf(
-               "OK [HIGHESTMODSEQ %llu] Close completed.",
-               (unsigned long long)status.highest_modseq));
-       return TRUE;
-}
-
 bool cmd_close(struct client_command_context *cmd)
 {
        struct client *client = cmd->client;
@@ -51,8 +38,8 @@ bool cmd_close(struct client_command_context *cmd)
                   it by syncing the mailbox one last time. We wouldn't need
                   to include our own expunge in there, but it's too much
                   trouble to hide it. */
-               return cmd_sync_callback(cmd, 0, IMAP_SYNC_FLAG_SAFE,
-                                        cmd_close_callback);
+               return cmd_sync(cmd, 0, IMAP_SYNC_FLAG_SAFE,
+                               "OK Close completed.");
        } else {
                if (mailbox_sync(mailbox, 0, 0, NULL) < 0)
                        client_send_untagged_storage_error(client, storage);
index b6a8c109014dd3d2c28ed66dc0e136c656d8933a..16ede93f68f289995e330929bd978933ae4b9a82 100644 (file)
@@ -19,22 +19,6 @@ static bool cmd_expunge_callback(struct client_command_context *cmd)
        return TRUE;
 }
 
-static bool cmd_expunge_callback_qresync(struct client_command_context *cmd)
-{
-       struct mailbox_status status;
-
-       if (!cmd->client->sync_seen_expunges)
-               client_send_tagline(cmd, "OK Expunge completed.");
-       else {
-               mailbox_get_status(cmd->client->mailbox,
-                                  STATUS_HIGHESTMODSEQ, &status);
-               client_send_tagline(cmd, t_strdup_printf(
-                       "OK [HIGHESTMODSEQ %llu] Expunge completed.",
-                       (unsigned long long)status.highest_modseq));
-       }
-       return TRUE;
-}
-
 static bool cmd_expunge_finish(struct client_command_context *cmd,
                               struct mail_search_args *search_args)
 {
@@ -52,9 +36,8 @@ static bool cmd_expunge_finish(struct client_command_context *cmd,
        client->sync_seen_deletes = FALSE;
        client->sync_seen_expunges = FALSE;
        if ((client->enabled_features & MAILBOX_FEATURE_QRESYNC) != 0) {
-               return cmd_sync_callback(cmd, MAILBOX_SYNC_FLAG_EXPUNGE,
-                                        IMAP_SYNC_FLAG_SAFE,
-                                        cmd_expunge_callback_qresync);
+               return cmd_sync(cmd, MAILBOX_SYNC_FLAG_EXPUNGE,
+                               IMAP_SYNC_FLAG_SAFE, "OK Expunge completed.");
        } else {
                return cmd_sync_callback(cmd, MAILBOX_SYNC_FLAG_EXPUNGE,
                                         IMAP_SYNC_FLAG_SAFE,
index 4a06e8b27719d6fcab0b7e48e2dd87119a10a9a2..594ccac3d8be41f6e1e15af36c36af857e44b898 100644 (file)
@@ -37,7 +37,7 @@ idle_finish(struct cmd_idle_context *ctx, bool done_ok, bool free_cmd)
 
        if (ctx->sync_ctx != NULL) {
                /* we're here only in connection failure cases */
-               (void)imap_sync_deinit(ctx->sync_ctx);
+               (void)imap_sync_deinit(ctx->sync_ctx, ctx->cmd);
        }
 
        o_stream_cork(client->output);
@@ -157,7 +157,7 @@ static bool cmd_idle_continue(struct client_command_context *cmd)
                        return FALSE;
                }
 
-               if (imap_sync_deinit(ctx->sync_ctx) < 0) {
+               if (imap_sync_deinit(ctx->sync_ctx, ctx->cmd) < 0) {
                        client_send_untagged_storage_error(client,
                                mailbox_get_storage(client->mailbox));
                        mailbox_notify_changes_stop(client->mailbox);
index 7088169983abebbff546770618ca1ddec0e6d50c..7a6ec213d32d5083f4b1a34210a51a7b5d4b0ad0 100644 (file)
@@ -740,8 +740,13 @@ fetch_internaldate_init(struct imap_fetch_context *ctx, const char *name,
 static int fetch_modseq(struct imap_fetch_context *ctx, struct mail *mail,
                        void *context ATTR_UNUSED)
 {
+       uint64_t modseq;
+
+       modseq = mail_get_modseq(mail);
+       if (ctx->client->highest_fetch_modseq < modseq)
+               ctx->client->highest_fetch_modseq = modseq;
        str_printfa(ctx->cur_str, "MODSEQ %llu ",
-                   (unsigned long long)mail_get_modseq(mail));
+                   (unsigned long long)modseq);
        return 1;
 }
 
@@ -752,7 +757,6 @@ fetch_modseq_init(struct imap_fetch_context *ctx, const char *name,
        client_enable(ctx->client, MAILBOX_FEATURE_CONDSTORE);
        imap_fetch_add_handler(ctx, TRUE, FALSE, name, NULL,
                               fetch_modseq, NULL);
-       ctx->client->modseqs_sent_since_sync = TRUE;
        return TRUE;
 }
 
index d05644b8ab5e3fba18a3fbba296ef3a284ca8914..d9974bbda766bb9ef673b377a95c341f40f952c8 100644 (file)
@@ -158,7 +158,54 @@ imap_sync_init(struct client *client, struct mailbox *box,
        return ctx;
 }
 
-int imap_sync_deinit(struct imap_sync_context *ctx)
+static void
+imap_sync_send_highestmodseq(struct imap_sync_context *ctx,
+                            const struct mailbox_status *status,
+                            struct client_command_context *sync_cmd)
+{
+       struct client *client = ctx->client;
+       uint64_t send_modseq = 0;
+
+       if (status->sync_delayed_expunges &&
+           client->highest_fetch_modseq > client->sync_last_full_modseq) {
+               /* if client updates highest-modseq using returned MODSEQs
+                  it loses expunges. try to avoid this by sending it a lower
+                  pre-expunge HIGHESTMODSEQ reply. */
+               send_modseq = client->sync_last_full_modseq;
+       } else if (!status->sync_delayed_expunges &&
+                  status->highest_modseq > client->sync_last_full_modseq &&
+                  status->highest_modseq > client->highest_fetch_modseq) {
+               /* we've probably send some VANISHED or EXISTS replies which
+                  increased the highest-modseq. notify the client about
+                  this. */
+               send_modseq = status->highest_modseq;
+       }
+
+       if (send_modseq == 0) {
+               /* no sending */
+       } else if (strncmp(sync_cmd->sync->tagline, "OK ", 3) == 0 &&
+                  sync_cmd->sync->tagline[3] != '[') {
+               /* modify the tagged reply directly */
+               sync_cmd->sync->tagline = p_strdup_printf(sync_cmd->pool,
+                       "OK [HIGHESTMODSEQ %llu] %s",
+                       (unsigned long long)send_modseq,
+                       sync_cmd->sync->tagline + 3);
+       } else {
+               /* send an untagged OK reply */
+               client_send_line(client, t_strdup_printf(
+                       "* OK [HIGHESTMODSEQ %llu]",
+                       (unsigned long long)send_modseq));
+       }
+
+       if (!status->sync_delayed_expunges) {
+               /* no delayed expunges, remember this for future */
+               client->sync_last_full_modseq = status->highest_modseq;
+       }
+       client->highest_fetch_modseq = 0;
+}
+
+int imap_sync_deinit(struct imap_sync_context *ctx,
+                    struct client_command_context *sync_cmd)
 {
        struct client *client = ctx->client;
        struct mailbox_status status;
@@ -178,19 +225,6 @@ int imap_sync_deinit(struct imap_sync_context *ctx)
                return -1;
        }
 
-       if (!status.sync_delayed_expunges || status.highest_modseq == 0)
-               client->sync_last_full_modseq = status.highest_modseq;
-       else if (client->modseqs_sent_since_sync &&
-                (client->enabled_features & MAILBOX_FEATURE_QRESYNC) != 0) {
-               /* if client updates highest-modseq using returned MODSEQs
-                  it loses expunges. try to avoid this by sending it a lower
-                  pre-expunge HIGHESTMODSEQ reply. */
-               client_send_line(client, t_strdup_printf(
-                       "* OK [HIGHESTMODSEQ %llu]",
-                       (unsigned long long)client->sync_last_full_modseq));
-       }
-       client->modseqs_sent_since_sync = FALSE;
-
        ret = mailbox_transaction_commit(&ctx->t);
 
        if (status.uidvalidity != client->uidvalidity) {
@@ -217,6 +251,9 @@ int imap_sync_deinit(struct imap_sync_context *ctx)
           now it contains added/removed messages. */
        imap_sync_send_search_updates(ctx);
 
+       if ((client->enabled_features & MAILBOX_FEATURE_QRESYNC) != 0)
+               imap_sync_send_highestmodseq(ctx, &status, sync_cmd);
+
        if (array_is_created(&ctx->search_removes)) {
                array_free(&ctx->search_removes);
                array_free(&ctx->search_adds);
@@ -227,6 +264,16 @@ int imap_sync_deinit(struct imap_sync_context *ctx)
        return ret;
 }
 
+static void imap_sync_add_modseq(struct imap_sync_context *ctx, string_t *str)
+{
+       uint64_t modseq;
+
+       modseq = mail_get_modseq(ctx->mail);
+       if (ctx->client->highest_fetch_modseq < modseq)
+               ctx->client->highest_fetch_modseq = modseq;
+       str_printfa(str, "MODSEQ %llu", (unsigned long long)modseq);
+}
+
 static int imap_sync_send_flags(struct imap_sync_context *ctx, string_t *str)
 {
        enum mail_flags flags;
@@ -246,9 +293,8 @@ static int imap_sync_send_flags(struct imap_sync_context *ctx, string_t *str)
                str_printfa(str, "UID %u ", ctx->mail->uid);
        if ((mailbox_get_enabled_features(ctx->box) &
             MAILBOX_FEATURE_CONDSTORE) != 0) {
-               ctx->client->modseqs_sent_since_sync = TRUE;
-               str_printfa(str, "MODSEQ %llu ",
-                           (unsigned long long)mail_get_modseq(ctx->mail));
+               imap_sync_add_modseq(ctx, str);
+               str_append_c(str, ' ');
        }
        str_append(str, "FLAGS (");
        imap_write_flags(str, flags, keywords);
@@ -264,9 +310,8 @@ static int imap_sync_send_modseq(struct imap_sync_context *ctx, string_t *str)
        str_printfa(str, "* %u FETCH (", ctx->seq);
        if (ctx->imap_flags & IMAP_SYNC_FLAG_SEND_UID)
                str_printfa(str, "UID %u ", ctx->mail->uid);
-       str_printfa(str, "MODSEQ %llu)",
-                   (unsigned long long)mail_get_modseq(ctx->mail));
-       ctx->client->modseqs_sent_since_sync = TRUE;
+       imap_sync_add_modseq(ctx, str);
+       str_append_c(str, ')');
        return client_send_line(ctx->client, str_c(str));
 }
 
@@ -446,7 +491,7 @@ static bool cmd_sync_continue(struct client_command_context *sync_cmd)
                ctx->failed = TRUE;
 
        client->syncing = FALSE;
-       if (imap_sync_deinit(ctx) < 0) {
+       if (imap_sync_deinit(ctx, sync_cmd) < 0) {
                client_send_untagged_storage_error(client,
                        mailbox_get_storage(client->mailbox));
        }
index a91745c947498e0246dc35d0c54f25ac74f5e279..66d3fe1b0bf461bc09415e318b329192ea21cfb2 100644 (file)
@@ -13,7 +13,8 @@ struct client;
 struct imap_sync_context *
 imap_sync_init(struct client *client, struct mailbox *box,
               enum imap_sync_flags imap_flags, enum mailbox_sync_flags flags);
-int imap_sync_deinit(struct imap_sync_context *ctx);
+int imap_sync_deinit(struct imap_sync_context *ctx,
+                    struct client_command_context *sync_cmd);
 int imap_sync_more(struct imap_sync_context *ctx);
 
 bool cmd_sync(struct client_command_context *cmd, enum mailbox_sync_flags flags,